Merge remote-tracking branch 'common/android-3.4' into android-exynos-3.4
diff --git a/Documentation/contiguous-memory.txt b/Documentation/contiguous-memory.txt
new file mode 100644
index 0000000..3d9d42c
--- /dev/null
+++ b/Documentation/contiguous-memory.txt
@@ -0,0 +1,623 @@
+ -*- org -*-
+
+* Contiguous Memory Allocator
+
+ The Contiguous Memory Allocator (CMA) is a framework, which allows
+ setting up a machine-specific configuration for physically-contiguous
+ memory management. Memory for devices is then allocated according
+ to that configuration.
+
+ The main role of the framework is not to allocate memory, but to
+ parse and manage memory configurations, as well as to act as an
+ in-between between device drivers and pluggable allocators. It is
+ thus not tied to any memory allocation method or strategy.
+
+** Why is it needed?
+
+ Various devices on embedded systems have no scatter-getter and/or
+ IO map support and as such require contiguous blocks of memory to
+ operate. They include devices such as cameras, hardware video
+ decoders and encoders, etc.
+
+ Such devices often require big memory buffers (a full HD frame is,
+ for instance, more then 2 mega pixels large, i.e. more than 6 MB
+ of memory), which makes mechanisms such as kmalloc() ineffective.
+
+ Some embedded devices impose additional requirements on the
+ buffers, e.g. they can operate only on buffers allocated in
+ particular location/memory bank (if system has more than one
+ memory bank) or buffers aligned to a particular memory boundary.
+
+ Development of embedded devices have seen a big rise recently
+ (especially in the V4L area) and many such drivers include their
+ own memory allocation code. Most of them use bootmem-based methods.
+ CMA framework is an attempt to unify contiguous memory allocation
+ mechanisms and provide a simple API for device drivers, while
+ staying as customisable and modular as possible.
+
+** Design
+
+ The main design goal for the CMA was to provide a customisable and
+ modular framework, which could be configured to suit the needs of
+ individual systems. Configuration specifies a list of memory
+ regions, which then are assigned to devices. Memory regions can
+ be shared among many device drivers or assigned exclusively to
+ one. This has been achieved in the following ways:
+
+ 1. The core of the CMA does not handle allocation of memory and
+ management of free space. Dedicated allocators are used for
+ that purpose.
+
+ This way, if the provided solution does not match demands
+ imposed on a given system, one can develop a new algorithm and
+ easily plug it into the CMA framework.
+
+ The presented solution includes an implementation of a best-fit
+ algorithm.
+
+ 2. When requesting memory, devices have to introduce themselves.
+ This way CMA knows who the memory is allocated for. This
+ allows for the system architect to specify which memory regions
+ each device should use.
+
+ 3. Memory regions are grouped in various "types". When device
+ requests a chunk of memory, it can specify what type of memory
+ it needs. If no type is specified, "common" is assumed.
+
+ This makes it possible to configure the system in such a way,
+ that a single device may get memory from different memory
+ regions, depending on the "type" of memory it requested. For
+ example, a video codec driver might want to allocate some
+ shared buffers from the first memory bank and the other from
+ the second to get the highest possible memory throughput.
+
+ 4. For greater flexibility and extensibility, the framework allows
+ device drivers to register private regions of reserved memory
+ which then may be used only by them.
+
+ As an effect, if a driver would not use the rest of the CMA
+ interface, it can still use CMA allocators and other
+ mechanisms.
+
+ 4a. Early in boot process, device drivers can also request the
+ CMA framework to a reserve a region of memory for them
+ which then will be used as a private region.
+
+ This way, drivers do not need to directly call bootmem,
+ memblock or similar early allocator but merely register an
+ early region and the framework will handle the rest
+ including choosing the right early allocator.
+
+ 4. CMA allows a run-time configuration of the memory regions it
+ will use to allocate chunks of memory from. The set of memory
+ regions is given on command line so it can be easily changed
+ without the need for recompiling the kernel.
+
+ Each region has it's own size, alignment demand, a start
+ address (physical address where it should be placed) and an
+ allocator algorithm assigned to the region.
+
+ This means that there can be different algorithms running at
+ the same time, if different devices on the platform have
+ distinct memory usage characteristics and different algorithm
+ match those the best way.
+
+** Use cases
+
+ Let's analyse some imaginary system that uses the CMA to see how
+ the framework can be used and configured.
+
+
+ We have a platform with a hardware video decoder and a camera each
+ needing 20 MiB of memory in the worst case. Our system is written
+ in such a way though that the two devices are never used at the
+ same time and memory for them may be shared. In such a system the
+ following configuration would be used in the platform
+ initialisation code:
+
+ static struct cma_region regions[] = {
+ { .name = "region", .size = 20 << 20 },
+ { }
+ }
+ static const char map[] __initconst = "video,camera=region";
+
+ cma_set_defaults(regions, map);
+
+ The regions array defines a single 20-MiB region named "region".
+ The map says that drivers named "video" and "camera" are to be
+ granted memory from the previously defined region.
+
+ A shorter map can be used as well:
+
+ static const char map[] __initconst = "*=region";
+
+ The asterisk ("*") matches all devices thus all devices will use
+ the region named "region".
+
+ We can see, that because the devices share the same memory region,
+ we save 20 MiB, compared to the situation when each of the devices
+ would reserve 20 MiB of memory for itself.
+
+
+ Now, let's say that we have also many other smaller devices and we
+ want them to share some smaller pool of memory. For instance 5
+ MiB. This can be achieved in the following way:
+
+ static struct cma_region regions[] = {
+ { .name = "region", .size = 20 << 20 },
+ { .name = "common", .size = 5 << 20 },
+ { }
+ }
+ static const char map[] __initconst =
+ "video,camera=region;*=common";
+
+ cma_set_defaults(regions, map);
+
+ This instructs CMA to reserve two regions and let video and camera
+ use region "region" whereas all other devices should use region
+ "common".
+
+
+ Later on, after some development of the system, it can now run
+ video decoder and camera at the same time. The 20 MiB region is
+ no longer enough for the two to share. A quick fix can be made to
+ grant each of those devices separate regions:
+
+ static struct cma_region regions[] = {
+ { .name = "v", .size = 20 << 20 },
+ { .name = "c", .size = 20 << 20 },
+ { .name = "common", .size = 5 << 20 },
+ { }
+ }
+ static const char map[] __initconst = "video=v;camera=c;*=common";
+
+ cma_set_defaults(regions, map);
+
+ This solution also shows how with CMA you can assign private pools
+ of memory to each device if that is required.
+
+ Allocation mechanisms can be replaced dynamically in a similar
+ manner as well. Let's say that during testing, it has been
+ discovered that, for a given shared region of 40 MiB,
+ fragmentation has become a problem. It has been observed that,
+ after some time, it becomes impossible to allocate buffers of the
+ required sizes. So to satisfy our requirements, we would have to
+ reserve a larger shared region beforehand.
+
+ But fortunately, you have also managed to develop a new allocation
+ algorithm -- Neat Allocation Algorithm or "na" for short -- which
+ satisfies the needs for both devices even on a 30 MiB region. The
+ configuration can be then quickly changed to:
+
+ static struct cma_region regions[] = {
+ { .name = "region", .size = 30 << 20, .alloc_name = "na" },
+ { .name = "common", .size = 5 << 20 },
+ { }
+ }
+ static const char map[] __initconst = "video,camera=region;*=common";
+
+ cma_set_defaults(regions, map);
+
+ This shows how you can develop your own allocation algorithms if
+ the ones provided with CMA do not suit your needs and easily
+ replace them, without the need to modify CMA core or even
+ recompiling the kernel.
+
+** Technical Details
+
+*** The attributes
+
+ As shown above, CMA is configured by a two attributes: list
+ regions and map. The first one specifies regions that are to be
+ reserved for CMA. The second one specifies what regions each
+ device is assigned to.
+
+**** Regions
+
+ Regions is a list of regions terminated by a region with size
+ equal zero. The following fields may be set:
+
+ - size -- size of the region (required, must not be zero)
+ - alignment -- alignment of the region; must be power of two or
+ zero (optional)
+ - start -- where the region has to start (optional)
+ - alloc_name -- the name of allocator to use (optional)
+ - alloc -- allocator to use (optional; and besides
+ alloc_name is probably is what you want)
+
+ size, alignment and start is specified in bytes. Size will be
+ aligned up to a PAGE_SIZE. If alignment is less then a PAGE_SIZE
+ it will be set to a PAGE_SIZE. start will be aligned to
+ alignment.
+
+ If command line parameter support is enabled, this attribute can
+ also be overriden by a command line "cma" parameter. When given
+ on command line its forrmat is as follows:
+
+ regions-attr ::= [ regions [ ';' ] ]
+ regions ::= region [ ';' regions ]
+
+ region ::= REG-NAME
+ '=' size
+ [ '@' start ]
+ [ '/' alignment ]
+ [ ':' ALLOC-NAME ]
+
+ size ::= MEMSIZE // size of the region
+ start ::= MEMSIZE // desired start address of
+ // the region
+ alignment ::= MEMSIZE // alignment of the start
+ // address of the region
+
+ REG-NAME specifies the name of the region. All regions given at
+ via the regions attribute need to have a name. Moreover, all
+ regions need to have a unique name. If two regions have the same
+ name it is unspecified which will be used when requesting to
+ allocate memory from region with given name.
+
+ ALLOC-NAME specifies the name of allocator to be used with the
+ region. If no allocator name is provided, the "default"
+ allocator will be used with the region. The "default" allocator
+ is, of course, the first allocator that has been registered. ;)
+
+ size, start and alignment are specified in bytes with suffixes
+ that memparse() accept. If start is given, the region will be
+ reserved on given starting address (or at close to it as
+ possible). If alignment is specified, the region will be aligned
+ to given value.
+
+**** Map
+
+ The format of the "map" attribute is as follows:
+
+ map-attr ::= [ rules [ ';' ] ]
+ rules ::= rule [ ';' rules ]
+ rule ::= patterns '=' regions
+
+ patterns ::= pattern [ ',' patterns ]
+
+ regions ::= REG-NAME [ ',' regions ]
+ // list of regions to try to allocate memory
+ // from
+
+ pattern ::= dev-pattern [ '/' TYPE-NAME ] | '/' TYPE-NAME
+ // pattern request must match for the rule to
+ // apply; the first rule that matches is
+ // applied; if dev-pattern part is omitted
+ // value identical to the one used in previous
+ // pattern is assumed.
+
+ dev-pattern ::= PATTERN
+ // pattern that device name must match for the
+ // rule to apply; may contain question marks
+ // which mach any characters and end with an
+ // asterisk which match the rest of the string
+ // (including nothing).
+
+ It is a sequence of rules which specify what regions should given
+ (device, type) pair use. The first rule that matches is applied.
+
+ For rule to match, the pattern must match (dev, type) pair.
+ Pattern consist of the part before and after slash. The first
+ part must match device name and the second part must match kind.
+
+ If the first part is empty, the device name is assumed to match
+ iff it matched in previous pattern. If the second part is
+ omitted it will mach any type of memory requested by device.
+
+ If SysFS support is enabled, this attribute is accessible via
+ SysFS and can be changed at run-time by writing to
+ /sys/kernel/mm/contiguous/map.
+
+ If command line parameter support is enabled, this attribute can
+ also be overriden by a command line "cma.map" parameter.
+
+**** Examples
+
+ Some examples (whitespace added for better readability):
+
+ cma = r1 = 64M // 64M region
+ @512M // starting at address 512M
+ // (or at least as near as possible)
+ /1M // make sure it's aligned to 1M
+ :foo(bar); // uses allocator "foo" with "bar"
+ // as parameters for it
+ r2 = 64M // 64M region
+ /1M; // make sure it's aligned to 1M
+ // uses the first available allocator
+ r3 = 64M // 64M region
+ @512M // starting at address 512M
+ :foo; // uses allocator "foo" with no parameters
+
+ cma_map = foo = r1;
+ // device foo with kind==NULL uses region r1
+
+ foo/quaz = r2; // OR:
+ /quaz = r2;
+ // device foo with kind == "quaz" uses region r2
+
+ cma_map = foo/quaz = r1;
+ // device foo with type == "quaz" uses region r1
+
+ foo/* = r2; // OR:
+ /* = r2;
+ // device foo with any other kind uses region r2
+
+ bar = r1,r2;
+ // device bar uses region r1 or r2
+
+ baz?/a , baz?/b = r3;
+ // devices named baz? where ? is any character
+ // with type being "a" or "b" use r3
+
+*** The device and types of memory
+
+ The name of the device is taken from the device structure. It is
+ not possible to use CMA if driver does not register a device
+ (actually this can be overcome if a fake device structure is
+ provided with at least the name set).
+
+ The type of memory is an optional argument provided by the device
+ whenever it requests memory chunk. In many cases this can be
+ ignored but sometimes it may be required for some devices.
+
+ For instance, let's say that there are two memory banks and for
+ performance reasons a device uses buffers in both of them.
+ Platform defines a memory types "a" and "b" for regions in both
+ banks. The device driver would use those two types then to
+ request memory chunks from different banks. CMA attributes could
+ look as follows:
+
+ static struct cma_region regions[] = {
+ { .name = "a", .size = 32 << 20 },
+ { .name = "b", .size = 32 << 20, .start = 512 << 20 },
+ { }
+ }
+ static const char map[] __initconst = "foo/a=a;foo/b=b;*=a,b";
+
+ And whenever the driver allocated the memory it would specify the
+ kind of memory:
+
+ buffer1 = cma_alloc(dev, "a", 1 << 20, 0);
+ buffer2 = cma_alloc(dev, "b", 1 << 20, 0);
+
+ If it was needed to try to allocate from the other bank as well if
+ the dedicated one is full, the map attributes could be changed to:
+
+ static const char map[] __initconst = "foo/a=a,b;foo/b=b,a;*=a,b";
+
+ On the other hand, if the same driver was used on a system with
+ only one bank, the configuration could be changed just to:
+
+ static struct cma_region regions[] = {
+ { .name = "r", .size = 64 << 20 },
+ { }
+ }
+ static const char map[] __initconst = "*=r";
+
+ without the need to change the driver at all.
+
+*** Device API
+
+ There are three basic calls provided by the CMA framework to
+ devices. To allocate a chunk of memory cma_alloc() function needs
+ to be used:
+
+ dma_addr_t cma_alloc(const struct device *dev, const char *type,
+ size_t size, dma_addr_t alignment);
+
+ If required, device may specify alignment in bytes that the chunk
+ need to satisfy. It have to be a power of two or zero. The
+ chunks are always aligned at least to a page.
+
+ The type specifies the type of memory as described to in the
+ previous subsection. If device driver does not care about memory
+ type it can safely pass NULL as the type which is the same as
+ possing "common".
+
+ The basic usage of the function is just a:
+
+ addr = cma_alloc(dev, NULL, size, 0);
+
+ The function returns bus address of allocated chunk or a value
+ that evaluates to true if checked with IS_ERR_VALUE(), so the
+ correct way for checking for errors is:
+
+ unsigned long addr = cma_alloc(dev, NULL, size, 0);
+ if (IS_ERR_VALUE(addr))
+ /* Error */
+ return (int)addr;
+ /* Allocated */
+
+ (Make sure to include <linux/err.h> which contains the definition
+ of the IS_ERR_VALUE() macro.)
+
+
+ Allocated chunk is freed via a cma_free() function:
+
+ int cma_free(dma_addr_t addr);
+
+ It takes bus address of the chunk as an argument frees it.
+
+
+ The last function is the cma_info() which returns information
+ about regions assigned to given (dev, type) pair. Its syntax is:
+
+ int cma_info(struct cma_info *info,
+ const struct device *dev,
+ const char *type);
+
+ On successful exit it fills the info structure with lower and
+ upper bound of regions, total size and number of regions assigned
+ to given (dev, type) pair.
+
+**** Dynamic and private regions
+
+ In the basic setup, regions are provided and initialised by
+ platform initialisation code (which usually use
+ cma_set_defaults() for that purpose).
+
+ It is, however, possible to create and add regions dynamically
+ using cma_region_register() function.
+
+ int cma_region_register(struct cma_region *reg);
+
+ The region does not have to have name. If it does not, it won't
+ be accessed via standard mapping (the one provided with map
+ attribute). Such regions are private and to allocate chunk from
+ them, one needs to call:
+
+ dma_addr_t cma_alloc_from_region(struct cma_region *reg,
+ size_t size, dma_addr_t alignment);
+
+ It is just like cma_alloc() expect one specifies what region to
+ allocate memory from. The region must have been registered.
+
+**** Allocating from region specified by name
+
+ If a driver preferred allocating from a region or list of regions
+ it knows name of it can use a different call simmilar to the
+ previous:
+
+ dma_addr_t cma_alloc_from(const char *regions,
+ size_t size, dma_addr_t alignment);
+
+ The first argument is a comma-separated list of regions the
+ driver desires CMA to try and allocate from. The list is
+ terminated by a NUL byte or a semicolon.
+
+ Similarly, there is a call for requesting information about named
+ regions:
+
+ int cma_info_about(struct cma_info *info, const char *regions);
+
+ Generally, it should not be needed to use those interfaces but
+ they are provided nevertheless.
+
+**** Registering early regions
+
+ An early region is a region that is managed by CMA early during
+ boot process. It's platforms responsibility to reserve memory
+ for early regions. Later on, when CMA initialises, early regions
+ with reserved memory are registered as normal regions.
+ Registering an early region may be a way for a device to request
+ a private pool of memory without worrying about actually
+ reserving the memory:
+
+ int cma_early_region_register(struct cma_region *reg);
+
+ This needs to be done quite early on in boot process, before
+ platform traverses the cma_early_regions list to reserve memory.
+
+ When boot process ends, device driver may see whether the region
+ was reserved (by checking reg->reserved flag) and if so, whether
+ it was successfully registered as a normal region (by checking
+ the reg->registered flag). If that is the case, device driver
+ can use normal API calls to use the region.
+
+*** Allocator operations
+
+ Creating an allocator for CMA needs four functions to be
+ implemented.
+
+
+ The first two are used to initialise an allocator for given driver
+ and clean up afterwards:
+
+ int cma_foo_init(struct cma_region *reg);
+ void cma_foo_cleanup(struct cma_region *reg);
+
+ The first is called when allocator is attached to region. When
+ the function is called, the cma_region structure is fully
+ initialised (ie. starting address and size have correct values).
+ As a meter of fact, allocator should never modify the cma_region
+ structure other then the private_data field which it may use to
+ point to it's private data.
+
+ The second call cleans up and frees all resources the allocator
+ has allocated for the region. The function can assume that all
+ chunks allocated form this region have been freed thus the whole
+ region is free.
+
+
+ The two other calls are used for allocating and freeing chunks.
+ They are:
+
+ struct cma_chunk *cma_foo_alloc(struct cma_region *reg,
+ size_t size, dma_addr_t alignment);
+ void cma_foo_free(struct cma_chunk *chunk);
+
+ As names imply the first allocates a chunk and the other frees
+ a chunk of memory. It also manages a cma_chunk object
+ representing the chunk in physical memory.
+
+ Either of those function can assume that they are the only thread
+ accessing the region. Therefore, allocator does not need to worry
+ about concurrency. Moreover, all arguments are guaranteed to be
+ valid (i.e. page aligned size, a power of two alignment no lower
+ the a page size).
+
+
+ When allocator is ready, all that is left is to register it by
+ calling cma_allocator_register() function:
+
+ int cma_allocator_register(struct cma_allocator *alloc);
+
+ The argument is an structure with pointers to the above functions
+ and allocator's name. The whole call may look something like
+ this:
+
+ static struct cma_allocator alloc = {
+ .name = "foo",
+ .init = cma_foo_init,
+ .cleanup = cma_foo_cleanup,
+ .alloc = cma_foo_alloc,
+ .free = cma_foo_free,
+ };
+ return cma_allocator_register(&alloc);
+
+ The name ("foo") will be used when a this particular allocator is
+ requested as an allocator for given region.
+
+*** Integration with platform
+
+ There is one function that needs to be called form platform
+ initialisation code. That is the cma_early_regions_reserve()
+ function:
+
+ void cma_early_regions_reserve(int (*reserve)(struct cma_region *reg));
+
+ It traverses list of all of the early regions provided by platform
+ and registered by drivers and reserves memory for them. The only
+ argument is a callback function used to reserve the region.
+ Passing NULL as the argument is the same as passing
+ cma_early_region_reserve() function which uses bootmem and
+ memblock for allocating.
+
+ Alternatively, platform code could traverse the cma_early_regions
+ list by itself but this should never be necessary.
+
+
+ Platform has also a way of providing default attributes for CMA,
+ cma_set_defaults() function is used for that purpose:
+
+ int cma_set_defaults(struct cma_region *regions, const char *map)
+
+ It needs to be called after early params have been parsed but
+ prior to reserving regions. It let one specify the list of
+ regions defined by platform and the map attribute. The map may
+ point to a string in __initdata. See above in this document for
+ example usage of this function.
+
+** Future work
+
+ In the future, implementation of mechanisms that would allow the
+ free space inside the regions to be used as page cache, filesystem
+ buffers or swap devices is planned. With such mechanisms, the
+ memory would not be wasted when not used.
+
+ Because all allocations and freeing of chunks pass the CMA
+ framework it can follow what parts of the reserved memory are
+ freed and what parts are allocated. Tracking the unused memory
+ would let CMA use it for other purposes such as page cache, I/O
+ buffers, swap, etc.
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 4d291f4..38ffd0a 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -880,8 +880,6 @@
config ARCH_EXYNOS
bool "SAMSUNG EXYNOS"
select CPU_V7
- select ARCH_SPARSEMEM_ENABLE
- select ARCH_HAS_HOLES_MEMORYMODEL
select GENERIC_GPIO
select HAVE_CLK
select CLKDEV_LOOKUP
@@ -1155,7 +1153,7 @@
config ARM_NR_BANKS
int
- default 16 if ARCH_EP93XX
+ default 16 if ARCH_EP93XX || ARCH_EXYNOS
default 8
config IWMMXT
@@ -1405,6 +1403,37 @@
on systems with an outer cache, the store buffer is drained
explicitly.
+config ARM_ERRATA_766421
+ bool "ARM errata: Strongly-Ordered/Device load or NC LDREX could return incorrect data"
+ depends on CPU_V7
+ help
+ This option enables the workaround for the 766421 Cortex-A15 erratum.
+ In certain situations, a strongly ordered or device load instruction,
+ or a non-cacheable normal memory load-exclusive instruction could
+ match multiple fill buffers and return incorrect data.
+ This workaround is add DMB instruction when making any change to the
+ translation regime and before doing any new loads/stores/preloads
+ in the new translation regime.
+
+config ARM_ERRATA_773022
+ bool "ARM errata: incorrect instructions may be executed from loop buffer"
+ depends on CPU_V7
+ help
+ This option enables the workaround for the 773022 Cortex-A15 erratum.
+ In certain rare sequences of code, the loop buffer may deliver
+ incorrect instructions.
+ This workaround is to disable loop buffer.
+
+config ARM_ERRATA_774769
+ bool "ARM errata: data corruption may occur with store streaming in a system"
+ depends on CPU_V7
+ help
+ This option enables the workaround for the erratum 774769.
+ External memory may be corrupted on erratum 774769.
+ The workaround is to configure write streaming on versions of A15
+ affected by this erratum such that no streaming-write ever allocates
+ into the L2 cache.
+
endmenu
source "arch/arm/common/Kconfig"
@@ -1622,7 +1651,7 @@
config HZ
int
default 200 if ARCH_EBSA110 || ARCH_S3C24XX || ARCH_S5P64X0 || \
- ARCH_S5PV210 || ARCH_EXYNOS4
+ ARCH_S5PV210 || ARCH_EXYNOS
default OMAP_32K_TIMER_HZ if ARCH_OMAP && OMAP_32K_TIMER
default AT91_TIMER_HZ if ARCH_AT91
default SHMOBILE_TIMER_HZ if ARCH_SHMOBILE
diff --git a/arch/arm/configs/exynos5_defconfig b/arch/arm/configs/exynos5_defconfig
new file mode 100644
index 0000000..081b530
--- /dev/null
+++ b/arch/arm/configs/exynos5_defconfig
@@ -0,0 +1,308 @@
+CONFIG_EXPERIMENTAL=y
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_PANIC_TIMEOUT=5
+CONFIG_KALLSYMS_ALL=y
+# CONFIG_AIO is not set
+CONFIG_EMBEDDED=y
+# CONFIG_SLUB_DEBUG is not set
+CONFIG_MODULES=y
+CONFIG_MODULE_FORCE_LOAD=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_EFI_PARTITION=y
+CONFIG_ARCH_EXYNOS=y
+CONFIG_S3C_LOWLEVEL_UART_PORT=2
+CONFIG_S3C_ADC=y
+CONFIG_S3C24XX_PWM=y
+CONFIG_ARCH_EXYNOS5=y
+CONFIG_EXYNOS_FIQ_DEBUGGER=y
+CONFIG_MACH_SMDK5250=y
+CONFIG_ARM_TRUSTZONE=y
+CONFIG_FIQ_DEBUGGER=y
+CONFIG_FIQ_DEBUGGER_NO_SLEEP=y
+CONFIG_FIQ_DEBUGGER_CONSOLE=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_SMP=y
+CONFIG_NR_CPUS=2
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_HIGHMEM=y
+CONFIG_CMDLINE="vmalloc=512M"
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_BINFMT_MISC=y
+CONFIG_WAKELOCK=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_INET_ESP=y
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+CONFIG_IPV6=y
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_TUNNEL=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_NETFILTER=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_TPROXY=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFLOG=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_TARGET_TPROXY=y
+CONFIG_NETFILTER_XT_TARGET_TRACE=y
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_TIME=y
+CONFIG_NETFILTER_XT_MATCH_U32=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_TARGET_REJECT_SKERR=y
+CONFIG_IP_NF_TARGET_LOG=y
+CONFIG_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_RAW=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_NF_CONNTRACK_IPV6=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_TARGET_LOG=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_TARGET_REJECT=y
+CONFIG_IP6_NF_TARGET_REJECT_SKERR=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
+CONFIG_PHONET=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_SCH_INGRESS=y
+CONFIG_NET_CLS_U32=y
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_U32=y
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_POLICE=y
+CONFIG_NET_ACT_GACT=y
+CONFIG_NET_ACT_MIRRED=y
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_UID_STAT=y
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_CRYPT=y
+CONFIG_DM_UEVENT=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_KEYRESET=y
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_EGALAX_I2C=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_KEYCHORD=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_GPIO=y
+# CONFIG_VT is not set
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_SAMSUNG=y
+CONFIG_SERIAL_SAMSUNG_CONSOLE=y
+CONFIG_HW_RANDOM=y
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_S3C2410=y
+CONFIG_POWER_SUPPLY=y
+# CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+CONFIG_S3C2410_WATCHDOG=y
+CONFIG_MFD_MAX8997=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_VIDEO_DEV=y
+# CONFIG_MEDIA_TUNER_SIMPLE is not set
+# CONFIG_MEDIA_TUNER_TDA8290 is not set
+# CONFIG_MEDIA_TUNER_TDA827X is not set
+# CONFIG_MEDIA_TUNER_TDA18271 is not set
+# CONFIG_MEDIA_TUNER_TDA9887 is not set
+# CONFIG_MEDIA_TUNER_TEA5761 is not set
+# CONFIG_MEDIA_TUNER_TEA5767 is not set
+# CONFIG_MEDIA_TUNER_MT20XX is not set
+# CONFIG_MEDIA_TUNER_MT2060 is not set
+# CONFIG_MEDIA_TUNER_MT2063 is not set
+# CONFIG_MEDIA_TUNER_MT2266 is not set
+# CONFIG_MEDIA_TUNER_MT2131 is not set
+# CONFIG_MEDIA_TUNER_QT1010 is not set
+# CONFIG_MEDIA_TUNER_XC2028 is not set
+# CONFIG_MEDIA_TUNER_XC5000 is not set
+# CONFIG_MEDIA_TUNER_XC4000 is not set
+# CONFIG_MEDIA_TUNER_MXL5005S is not set
+# CONFIG_MEDIA_TUNER_MXL5007T is not set
+# CONFIG_MEDIA_TUNER_MC44S803 is not set
+# CONFIG_MEDIA_TUNER_MAX2165 is not set
+# CONFIG_MEDIA_TUNER_TDA18218 is not set
+# CONFIG_MEDIA_TUNER_TDA18212 is not set
+CONFIG_VIDEO_EXYNOS=y
+# CONFIG_VIDEO_EXYNOS_FIMC_LITE is not set
+# CONFIG_VIDEO_EXYNOS_MIPI_CSIS is not set
+CONFIG_VIDEO_EXYNOS_GSCALER=y
+CONFIG_VIDEO_EXYNOS_JPEG=y
+CONFIG_VIDEO_EXYNOS_FIMG2D=y
+CONFIG_VIDEO_EXYNOS_MFC=y
+CONFIG_VIDEO_EXYNOS_TV=y
+CONFIG_VIDEO_EXYNOS_HDMI_CEC=y
+CONFIG_VIDEO_EXYNOS_ROTATOR=y
+CONFIG_VIDEO_EXYNOS5_FIMC_IS=y
+CONFIG_VIDEO_S5K4E5=y
+CONFIG_VIDEO_S5K6A3=y
+CONFIG_ION=y
+CONFIG_ION_EXYNOS=y
+CONFIG_ION_EXYNOS_CONTIGHEAP_SIZE=100000
+CONFIG_MALI_T6XX=y
+CONFIG_MALI_LICENSE_IS_GPL=y
+CONFIG_MALI_PLATFORM_FAKE=y
+CONFIG_MALI_T6XX_ENABLE_TRACE=y
+CONFIG_MALI_PLATFORM_THIRDPARTY=y
+CONFIG_MALI_PLATFORM_THIRDPARTY_NAME="exynos5"
+CONFIG_MALI_T6XX_DVFS=y
+CONFIG_MALI_T6XX_DEBUG_SYS=y
+CONFIG_MALI_T6XX_RT_PM=y
+# CONFIG_MALI_GATOR_SUPPORT is not set
+# CONFIG_MALI_EXPERT is not set
+CONFIG_FB=y
+CONFIG_FB_S3C=y
+CONFIG_FB_MIPI_DSIM=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_LCD_CLASS_DEVICE=y
+CONFIG_LCD_PLATFORM=y
+CONFIG_LCD_MIPI_TC358764=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_GENERIC is not set
+CONFIG_BACKLIGHT_PWM=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+# CONFIG_SND_DRIVERS is not set
+# CONFIG_SND_ARM is not set
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_SAMSUNG=y
+CONFIG_SND_SOC_SAMSUNG_SMDK_WM8994=y
+# CONFIG_HID_SUPPORT is not set
+CONFIG_USB_GADGET=y
+CONFIG_USB_EXYNOS_SS_UDC=y
+CONFIG_USB_G_ANDROID=y
+CONFIG_MMC=y
+CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_CLKGATE=y
+CONFIG_MMC_EMBEDDED_SDIO=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_S3C=y
+CONFIG_MMC_SDHCI_S3C_DMA=y
+CONFIG_MMC_DW=y
+CONFIG_MMC_DW_IDMAC=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_S3C=y
+CONFIG_STAGING=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_ASHMEM=y
+CONFIG_ANDROID_LOGGER=y
+CONFIG_ANDROID_RAM_CONSOLE=y
+CONFIG_ANDROID_TIMED_GPIO=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_ANDROID_INTF_ALARM_DEV=y
+CONFIG_EXYNOS_IOMMU=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT4_FS=y
+# CONFIG_EXT4_FS_XATTR is not set
+# CONFIG_DNOTIFY is not set
+CONFIG_FUSE_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+# CONFIG_NETWORK_FILESYSTEMS is not set
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DEBUG_FS=y
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_DEBUG_PREEMPT is not set
+CONFIG_DEBUG_INFO=y
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+CONFIG_KGDB=y
+CONFIG_KGDB_KDB=y
+# CONFIG_ARM_UNWIND is not set
+CONFIG_DEBUG_USER=y
+CONFIG_CRC_CCITT=y
diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h
index 5684cbc..c52d616 100644
--- a/arch/arm/include/asm/cacheflush.h
+++ b/arch/arm/include/asm/cacheflush.h
@@ -207,6 +207,12 @@
#define flush_cache_all() __cpuc_flush_kern_all()
+#ifndef CONFIG_SMP
+#define flush_all_cpu_caches() flush_cache_all()
+#else
+extern void flush_all_cpu_caches(void);
+#endif
+
static inline void vivt_flush_cache_mm(struct mm_struct *mm)
{
if (cpumask_test_cpu(smp_processor_id(), mm_cpumask(mm)))
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index f30d683..006acbd 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -668,3 +668,13 @@
{
return -EINVAL;
}
+
+static void flush_all_cpu_cache(void *info)
+{
+ flush_cache_all();
+}
+
+void flush_all_cpu_caches(void)
+{
+ on_each_cpu(flush_all_cpu_cache, NULL, 1);
+}
diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig
index b8df521..3423296 100644
--- a/arch/arm/mach-exynos/Kconfig
+++ b/arch/arm/mach-exynos/Kconfig
@@ -11,20 +11,30 @@
menu "SAMSUNG EXYNOS SoCs Support"
+choice
+ prompt "EXYNOS System Type"
+ default ARCH_EXYNOS5
+
config ARCH_EXYNOS4
bool "SAMSUNG EXYNOS4"
- default y
select HAVE_SMP
select MIGHT_HAVE_CACHE_L2X0
+ select ARCH_SPARSEMEM_ENABLE
+ select ARCH_HAS_HOLES_MEMORYMODEL
help
Samsung EXYNOS4 SoCs based systems
config ARCH_EXYNOS5
bool "SAMSUNG EXYNOS5"
select HAVE_SMP
+ select ARCH_NEEDS_CPU_IDLE_COUPLED
+ select ARM_ERRATA_773022
+ select ARM_ERRATA_774769
help
Samsung EXYNOS5 (Cortex-A15) SoC based systems
+endchoice
+
comment "EXYNOS SoCs"
config CPU_EXYNOS4210
@@ -61,16 +71,29 @@
bool "SAMSUNG EXYNOS5250"
default y
depends on ARCH_EXYNOS5
+ select SAMSUNG_DMADEV
+ select S5P_PM if PM
+ select S5P_SLEEP if PM
+ select PM_GENERIC_DOMAINS if PM_RUNTIME
+ select ARM_ERRATA_766421
help
Enable EXYNOS5250 SoC support
+config EXYNOS_CONTENT_PATH_PROTECTION
+ bool "Exynos Content Path Protection"
+ depends on (ARM_TRUSTZONE && ARCH_EXYNOS5)
+ default n
+ help
+ Enable content path protection of EXYNOS.
+
config EXYNOS4_MCT
bool
default y
+ select HAVE_SCHED_CLOCK
help
Use MCT (Multi Core Timer) as kernel timers
-config EXYNOS4_DEV_DMA
+config EXYNOS_DEV_DMA
bool
help
Compile in amba device definitions for DMA controller
@@ -85,21 +108,65 @@
help
Common setup code for FIMD0.
-config EXYNOS4_DEV_SYSMMU
+config EXYNOS_SETUP_FIMD1
bool
help
- Common setup code for SYSTEM MMU in EXYNOS4
+ Common setup code for FIMD1.
-config EXYNOS4_DEV_DWMCI
+config EXYNOS_SETUP_ADC
+ bool
+ help
+ Common setup code for ADC.
+
+config EXYNOS4_SETUP_MIPI_DSIM
+ bool
+ depends on FB_MIPI_DSIM
+ default y
+ help
+ Common setup code for MIPI_DSIM to support mainline style fimd.
+
+config EXYNOS_SETUP_DP
+ bool
+ help
+ Common setup code for DP.
+
+config EXYNOS_DEV_SYSMMU
+ bool
+ help
+ Common setup code for SYSTEM MMU in EXYNOS
+
+config EXYNOS_DEV_DWMCI
bool
help
Compile in platform device definitions for DWMCI
+config EXYNOS4_DEV_FIMC_LITE
+ bool
+ help
+ Compile in platform device definitions for FIMC_LITE
+
+config EXYNOS4_DEV_FIMC_IS
+ bool
+ help
+ Compile in platform device definition for FIMC-IS
+
+config EXYNOS_DEV_ROTATOR
+ bool
+ help
+ Compile in platform device definitions for EXYNOS ROTATOR
+ NOTE: EXYNOS4 is not supported yet, it will be implemented.
+
config EXYNOS4_DEV_USB_OHCI
bool
help
Compile in platform device definition for USB OHCI
+config EXYNOS_DEV_SS_UDC
+ bool
+ help
+ Compile in platform device definition for EXYNOS SuperSpeed USB 3.0
+ Device controller
+
config EXYNOS4_SETUP_I2C1
bool
help
@@ -140,6 +207,11 @@
help
Common setup code for keypad.
+config EXYNOS4_SETUP_MFC
+ bool
+ help
+ Common setup code for MFC.
+
config EXYNOS4_SETUP_SDHCI
bool
select EXYNOS4_SETUP_SDHCI_GPIO
@@ -161,11 +233,55 @@
help
Common setup code for USB PHY controller
-config EXYNOS4_SETUP_SPI
+config EXYNOS4_SETUP_FIMC_IS
+ bool
+ help
+ Common setup code for the FIMC-IS-MC
+
+config EXYNOS_SETUP_SPI
bool
help
Common setup code for SPI GPIO configurations.
+config EXYNOS_FIQ_DEBUGGER
+ bool "Exynos FIQ debugger support"
+ depends on FIQ_DEBUGGER
+ default y
+ help
+ Exynos platform support for the FIQ debugger
+
+config EXYNOS5_CORESIGHT
+ bool "EXYNOS5 embedded trace support"
+ depends on ARCH_EXYNOS5
+ select OC_ETM
+ help
+ Enable embedded trace support
+
+config EXYNOS_PERSISTENT_CLOCK
+ bool
+ depends on !RTC_DRV_S3C
+ default n
+ help
+ Persistent-clock-only driver for EXYNOS RTC.
+
+config EXYNOS_DEV_TMU
+ bool
+ help
+ Compile in platform device definitions for TMU
+
+config EXYNOS_THERMAL
+ bool "Use thermal management"
+ depends on CPU_FREQ
+ help
+ Common setup code for TMU
+
+config EXYNOS5_DEV_BTS
+ bool
+ depends on ARCH_EXYNOS5
+ select S5P_DEV_BTS
+ help
+ Compile in platform device definitions for BTS devices
+
# machine support
if ARCH_EXYNOS4
@@ -202,10 +318,9 @@
select SAMSUNG_DEV_BACKLIGHT
select EXYNOS4_DEV_AHCI
select SAMSUNG_DEV_KEYPAD
- select EXYNOS4_DEV_DMA
select SAMSUNG_DEV_PWM
+ select EXYNOS_DEV_DMA
select EXYNOS4_DEV_USB_OHCI
- select EXYNOS4_DEV_SYSMMU
select EXYNOS4_SETUP_FIMD0
select EXYNOS4_SETUP_I2C1
select EXYNOS4_SETUP_KEYPAD
@@ -222,9 +337,8 @@
select S3C_DEV_HSMMC
select S3C_DEV_HSMMC2
select S3C_DEV_HSMMC3
+ select EXYNOS_DEV_DMA
select EXYNOS4_DEV_AHCI
- select EXYNOS4_DEV_DMA
- select EXYNOS4_DEV_SYSMMU
select EXYNOS4_SETUP_SDHCI
help
Machine support for Samsung ARMLEX4210 based on EXYNOS4210
@@ -254,7 +368,7 @@
select S5P_DEV_MFC
select S5P_DEV_ONENAND
select S5P_DEV_TV
- select EXYNOS4_DEV_DMA
+ select EXYNOS_DEV_DMA
select EXYNOS4_SETUP_FIMD0
select EXYNOS4_SETUP_I2C1
select EXYNOS4_SETUP_I2C3
@@ -290,7 +404,7 @@
select S5P_DEV_MFC
select S5P_DEV_USB_EHCI
select S5P_SETUP_MIPIPHY
- select EXYNOS4_DEV_DMA
+ select EXYNOS_DEV_DMA
select EXYNOS4_SETUP_FIMC
select EXYNOS4_SETUP_FIMD0
select EXYNOS4_SETUP_I2C1
@@ -325,7 +439,7 @@
select S5P_DEV_USB_EHCI
select SAMSUNG_DEV_BACKLIGHT
select SAMSUNG_DEV_PWM
- select EXYNOS4_DEV_DMA
+ select EXYNOS_DEV_DMA
select EXYNOS4_DEV_USB_OHCI
select EXYNOS4_SETUP_FIMD0
select EXYNOS4_SETUP_SDHCI
@@ -348,7 +462,7 @@
select SAMSUNG_DEV_BACKLIGHT
select SAMSUNG_DEV_KEYPAD
select SAMSUNG_DEV_PWM
- select EXYNOS4_DEV_DMA
+ select EXYNOS_DEV_DMA
select EXYNOS4_SETUP_I2C1
select EXYNOS4_SETUP_I2C3
select EXYNOS4_SETUP_I2C7
@@ -367,6 +481,61 @@
Machine support for Samsung SMDK4412
endif
+if ARCH_EXYNOS5
+
+comment "EXYNOS5250 Boards"
+
+config MACH_SMDK5250
+ bool "SMDK5250"
+ select SOC_EXYNOS5250
+ select S3C_DEV_I2C1
+ select S3C_DEV_I2C2
+ select S3C_DEV_I2C4
+ select S3C_DEV_I2C5
+ select S3C_DEV_I2C7
+ select S3C_DEV_RTC
+ select S3C_DEV_WDT
+ select S5P_DEV_MFC
+ select S5P_DEV_DP
+ select S5P_DEV_FIMD1
+ select S5P_DEV_FIMG2D
+ select S5P_DEV_TV
+ select S5P_DEV_I2C_HDMIPHY
+ select S5P_DEV_USB_EHCI
+ select S5P_GPIO_INT
+ select EXYNOS_DEV_DMA
+ select EXYNOS_DEV_SYSMMU
+ select EXYNOS_DEV_DWMCI
+ select EXYNOS_DEV_DMA
+ select EXYNOS_DEV_SS_UDC
+ select EXYNOS_DEV_DWC3
+ select EXYNOS_SETUP_ADC
+ select EXYNOS_SETUP_DP
+ select EXYNOS_SETUP_FIMD1
+ select EXYNOS_DEV_ROTATOR
+ select EXYNOS_DEV_TMU
+ select EXYNOS4_DEV_FIMC_IS
+ select EXYNOS4_DEV_USB_OHCI
+ select EXYNOS4_SETUP_I2C1
+ select EXYNOS4_SETUP_I2C2
+ select EXYNOS4_SETUP_I2C4
+ select EXYNOS4_SETUP_I2C5
+ select EXYNOS4_SETUP_I2C7
+ select EXYNOS4_SETUP_MFC
+ select EXYNOS4_SETUP_USB_PHY
+ select EXYNOS4_SETUP_FIMC_IS
+ select SAMSUNG_DEV_ADC
+ select SAMSUNG_DEV_BACKLIGHT
+ select SAMSUNG_DEV_PWM
+ select S3C64XX_DEV_SPI0
+ select S3C64XX_DEV_SPI1
+ select S3C64XX_DEV_SPI2
+ select EXYNOS_SETUP_SPI
+ select EXYNOS5_DEV_BTS
+ help
+ Machine support for Samsung SMDK5250
+endif
+
comment "Flattened Device Tree based board for EXYNOS SoCs"
config MACH_EXYNOS4_DT
@@ -392,6 +561,47 @@
Machine support for Samsung Exynos4 machine with device tree enabled.
Select this if a fdt blob is available for the EXYNOS4 SoC based board.
+config EXYNOS5_DEV_GSC
+ bool
+ depends on VIDEO_EXYNOS_GSCALER
+ default y
+ help
+ Compile in platform device definitions for GSC
+
+config EXYNOS5_SETUP_GSC
+ bool
+ depends on VIDEO_EXYNOS_GSCALER
+ default y
+ help
+ Common setup code for GSC
+
+config EXYNOS5_DEV_JPEG
+ bool
+ depends on VIDEO_EXYNOS_JPEG
+ default y
+ help
+ Compile in platform device definitions for JPEG
+
+config EXYNOS5_SETUP_JPEG
+ bool
+ depends on VIDEO_EXYNOS_JPEG
+ default y
+ help
+ Common setup code for JPEG
+
+config EXYNOS4_SETUP_CSIS
+ bool
+ depends on VIDEO_FIMC_MIPI
+ default y
+ help
+ Common setup code for MIPI-CSIS
+
+config EXYNOS5_SETUP_TVOUT
+ bool
+ default y
+ help
+ Common setup code for TVOUT
+
if ARCH_EXYNOS4
comment "Configuration for HSMMC 8-bit bus width"
diff --git a/arch/arm/mach-exynos/Makefile b/arch/arm/mach-exynos/Makefile
index 8631840..756c49d 100644
--- a/arch/arm/mach-exynos/Makefile
+++ b/arch/arm/mach-exynos/Makefile
@@ -15,14 +15,17 @@
obj-$(CONFIG_ARCH_EXYNOS) += common.o
obj-$(CONFIG_ARCH_EXYNOS4) += clock-exynos4.o
obj-$(CONFIG_ARCH_EXYNOS5) += clock-exynos5.o
+obj-$(CONFIG_ARM_TRUSTZONE) += irq-sgi.o
obj-$(CONFIG_CPU_EXYNOS4210) += clock-exynos4210.o
obj-$(CONFIG_SOC_EXYNOS4212) += clock-exynos4212.o
obj-$(CONFIG_PM) += pm.o
obj-$(CONFIG_PM_GENERIC_DOMAINS) += pm_domains.o
obj-$(CONFIG_CPU_IDLE) += cpuidle.o
+obj-$(CONFIG_ARCH_EXYNOS) += asv-exynos.o abb-exynos.o
+obj-$(CONFIG_SOC_EXYNOS5250) += asv-exynos5250.o
-obj-$(CONFIG_ARCH_EXYNOS4) += pmu.o
+obj-$(CONFIG_ARCH_EXYNOS) += pmu.o
obj-$(CONFIG_SMP) += platsmp.o headsmp.o
@@ -30,6 +33,17 @@
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
+obj-$(CONFIG_ARCH_EXYNOS) += clock-audss.o
+
+obj-$(CONFIG_EXYNOS_FIQ_DEBUGGER) += exynos_fiq_debugger.o
+
+obj-$(CONFIG_EXYNOS5_CORESIGHT) += coresight-exynos5.o
+obj-$(CONFIG_EXYNOS_PERSISTENT_CLOCK) += persistent_clock.o
+
+obj-$(CONFIG_ARM_TRUSTZONE) += smc.o
+plus_sec := $(call as-instr,.arch_extension sec,+sec)
+AFLAGS_smc.o :=-Wa,-march=armv7-a$(plus_sec)
+
# machine support
obj-$(CONFIG_MACH_SMDKC210) += mach-smdkv310.o
@@ -45,19 +59,36 @@
obj-$(CONFIG_MACH_EXYNOS4_DT) += mach-exynos4-dt.o
obj-$(CONFIG_MACH_EXYNOS5_DT) += mach-exynos5-dt.o
+obj-$(CONFIG_MACH_SMDK5250) += mach-smdk5250.o
+
# device support
obj-y += dev-uart.o
-obj-$(CONFIG_ARCH_EXYNOS4) += dev-audio.o
+obj-$(CONFIG_ARCH_EXYNOS) += dev-audio.o
obj-$(CONFIG_EXYNOS4_DEV_AHCI) += dev-ahci.o
-obj-$(CONFIG_EXYNOS4_DEV_SYSMMU) += dev-sysmmu.o
-obj-$(CONFIG_EXYNOS4_DEV_DWMCI) += dev-dwmci.o
-obj-$(CONFIG_EXYNOS4_DEV_DMA) += dma.o
+obj-$(CONFIG_EXYNOS_DEV_DWMCI) += dev-dwmci.o
+obj-$(CONFIG_EXYNOS4_DEV_FIMC_IS) += dev-fimc-is.o
+obj-$(CONFIG_EXYNOS4_DEV_FIMC_LITE) += dev-fimc-lite.o
+obj-$(CONFIG_EXYNOS5_DEV_GSC) += dev-gsc.o
+obj-$(CONFIG_EXYNOS_DEV_ROTATOR) += dev-rotator.o
+obj-$(CONFIG_EXYNOS_DEV_SYSMMU) += dev-sysmmu.o
+obj-$(CONFIG_EXYNOS_DEV_DMA) += dma.o
obj-$(CONFIG_EXYNOS4_DEV_USB_OHCI) += dev-ohci.o
+obj-$(CONFIG_EXYNOS_DEV_SS_UDC) += dev-exynos-udc.o
+obj-$(CONFIG_EXYNOS5_DEV_JPEG) += dev-jpeg.o
+obj-$(CONFIG_EXYNOS_DEV_TMU) += dev-tmu.o
+obj-$(CONFIG_EXYNOS5_DEV_BTS) += dev-bts.o
obj-$(CONFIG_ARCH_EXYNOS) += setup-i2c0.o
obj-$(CONFIG_EXYNOS4_SETUP_FIMC) += setup-fimc.o
+obj-$(CONFIG_EXYNOS4_SETUP_CSIS) += setup-csis.o
+obj-$(CONFIG_EXYNOS5_SETUP_GSC) += setup-gsc.o
obj-$(CONFIG_EXYNOS4_SETUP_FIMD0) += setup-fimd0.o
+obj-$(CONFIG_EXYNOS_SETUP_FIMD1) += setup-fimd1.o
+obj-$(CONFIG_EXYNOS_SETUP_DP) += setup-dp.o
+obj-$(CONFIG_EXYNOS4_SETUP_MIPI_DSIM) += setup-mipidsim.o
+obj-$(CONFIG_EXYNOS_CONTENT_PATH_PROTECTION) += secmem.o
+obj-$(CONFIG_EXYNOS4_SETUP_FIMC_IS) += setup-fimc-is.o
obj-$(CONFIG_EXYNOS4_SETUP_I2C1) += setup-i2c1.o
obj-$(CONFIG_EXYNOS4_SETUP_I2C2) += setup-i2c2.o
obj-$(CONFIG_EXYNOS4_SETUP_I2C3) += setup-i2c3.o
@@ -66,6 +97,14 @@
obj-$(CONFIG_EXYNOS4_SETUP_I2C6) += setup-i2c6.o
obj-$(CONFIG_EXYNOS4_SETUP_I2C7) += setup-i2c7.o
obj-$(CONFIG_EXYNOS4_SETUP_KEYPAD) += setup-keypad.o
+obj-$(CONFIG_EXYNOS4_SETUP_MFC) += setup-mfc.o
obj-$(CONFIG_EXYNOS4_SETUP_SDHCI_GPIO) += setup-sdhci-gpio.o
obj-$(CONFIG_EXYNOS4_SETUP_USB_PHY) += setup-usb-phy.o
-obj-$(CONFIG_EXYNOS4_SETUP_SPI) += setup-spi.o
+obj-$(CONFIG_EXYNOS_SETUP_SPI) += setup-spi.o
+obj-$(CONFIG_EXYNOS5_SETUP_TVOUT) += setup-tvout.o
+obj-$(CONFIG_EXYNOS_SETUP_ADC) += setup-adc.o
+obj-$(CONFIG_ION_EXYNOS) += dev-ion.o
+obj-$(CONFIG_CMA) += reserve-mem.o
+obj-$(CONFIG_EXYNOS5_SETUP_JPEG) += setup-jpeg.o
+obj-$(CONFIG_ARCH_EXYNOS5) += resetreason.o
+obj-$(CONFIG_EXYNOS_THERMAL) += tmu-exynos.o
diff --git a/arch/arm/mach-exynos/abb-exynos.c b/arch/arm/mach-exynos/abb-exynos.c
new file mode 100644
index 0000000..704fbc8
--- /dev/null
+++ b/arch/arm/mach-exynos/abb-exynos.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * EXYNOS - ABB(Adaptive Body Bias) control
+ *
+ * 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.
+*/
+
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+#include <plat/cpu.h>
+
+#include <mach/map.h>
+#include <mach/regs-pmu.h>
+#include <mach/abb-exynos.h>
+
+void set_abb_member(enum abb_member abb_target, unsigned int abb_mode_value)
+{
+ unsigned int tmp;
+
+ if (abb_mode_value != ABB_MODE_BYPASS) {
+ tmp = EXYNOS_ABB_INIT;
+ tmp |= abb_mode_value;
+ } else {
+ tmp = EXYNOS_ABB_INIT_BYPASS;
+ }
+
+ if (!soc_is_exynos5250()) {
+ switch (abb_target) {
+ case ABB_INT:
+ __raw_writel(tmp, EXYNOS4_ABB_INT);
+ break;
+ case ABB_ARM:
+ __raw_writel(tmp, EXYNOS4_ABB_ARM);
+ break;
+ case ABB_G3D:
+ __raw_writel(tmp, EXYNOS4_ABB_G3D);
+ break;
+ case ABB_MIF:
+ __raw_writel(tmp, EXYNOS4_ABB_MIF);
+ break;
+ default:
+ break;
+ }
+ } else {
+ switch (abb_target) {
+ case ABB_INT:
+ __raw_writel(tmp, EXYNOS5_ABB_INT);
+ break;
+ case ABB_ARM:
+ __raw_writel(tmp, EXYNOS5_ABB_ARM);
+ break;
+ case ABB_G3D:
+ __raw_writel(tmp, EXYNOS5_ABB_G3D);
+ break;
+ case ABB_MIF:
+ __raw_writel(tmp, EXYNOS5_ABB_MIF);
+ break;
+ default:
+ break;
+ }
+ }
+}
diff --git a/arch/arm/mach-exynos/asv-exynos.c b/arch/arm/mach-exynos/asv-exynos.c
new file mode 100644
index 0000000..cab4729
--- /dev/null
+++ b/arch/arm/mach-exynos/asv-exynos.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * EXYNOS - ASV(Adaptive Support Voltage) driver
+ *
+ * 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.
+*/
+
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+#include <plat/cpu.h>
+
+#include <mach/map.h>
+#include <mach/asv-exynos.h>
+
+static struct asv_common exynos_asv;
+
+unsigned int asv_get_volt(enum asv_type_id target_type, unsigned int target_freq)
+{
+ if (exynos_asv.init_done)
+ return exynos_asv.get_voltage(target_type, target_freq);
+
+ return 0;
+}
+
+static int __init asv_init(void)
+{
+ int ret;
+
+ if (soc_is_exynos5250()) {
+ ret = exynos5250_init_asv(&exynos_asv);
+ } else {
+ pr_err("%s: Unknown SoC type\n", __func__);
+ return -ENODEV;
+ }
+
+ if (ret)
+ pr_err("%s: initialization failed\n", __func__);
+
+ return ret;
+}
+device_initcall(asv_init);
diff --git a/arch/arm/mach-exynos/asv-exynos5250.c b/arch/arm/mach-exynos/asv-exynos5250.c
new file mode 100755
index 0000000..65c9644
--- /dev/null
+++ b/arch/arm/mach-exynos/asv-exynos5250.c
@@ -0,0 +1,282 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * EXYNOS5250 - ASV(Adaptive Support Voltage) driver
+ *
+ * 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.
+*/
+
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+#include <mach/asv-exynos.h>
+#include <mach/asv-exynos5250.h>
+
+#include <mach/map.h>
+#include <mach/regs-pmu.h>
+#include <mach/abb-exynos.h>
+
+#include <plat/cpu.h>
+
+/* ASV function for Fused Chip */
+#define IDS_ARM_OFFSET 24
+#define IDS_ARM_MASK 0xFF
+#define HPM_OFFSET 12
+#define HPM_MASK 0x1F
+#define FUSED_ASV_GROUP_OFFSET 3
+#define ARM_ORG_ASV_GROUP_OFFSET 17
+#define ARM_ORG_ASV_MASK 0xF
+#define ARM_DIFF_ASV_GROUP_OFFSET 21
+#define ARM_DIFF_ASV_MASK 0x7
+#define MIF_ORG_ASV_GROUP_OFFSET 26
+#define MIF_ORG_ASV_MASK 0x3
+#define MIF_DIFF_ASV_GROUP_OFFSET 28
+#define MIF_DIFF_ASV_MASK 0x3
+#define FUSED_MIF_VOL_LOCK_OFFSET 7
+#define FUSED_INT_VOL_LOCK_OFFSET 8
+#define FUSED_G3D_VOL_LOCK_OFFSET 9
+#define FUSED_ARM_VOL_LOCK_OFFSET 10
+#define MIF_VOL_OFFSET 50000
+#define INT_VOL_OFFSET 25000
+#define G3D_VOL_OFFSET 25000
+#define ARM_FREQ_800MHZ 800000
+#define ARM_FREQ_1000MHZ 1000000
+#define ARM_FREQ_1100MHZ 1100000
+
+#define CHIP_ID_REG (S5P_VA_CHIPID + 0x4)
+
+enum exynos5250_fused_vol_lock_t {
+ FUSED_MIF_VOL_LOCK = 0,
+ FUSED_INT_VOL_LOCK,
+ FUSED_G3D_VOL_LOCK,
+ FUSED_ARM_800MHZ_VOL_LOCK,
+ FUSED_ARM_1000MHZ_VOL_LOCK,
+ FUSED_ARM_1100MHZ_VOL_LOCK,
+ FUSED_VOL_LOCK_END,
+};
+
+static bool fused_vol_locked[FUSED_VOL_LOCK_END] =
+ {false, false, false, false, false, false};
+static unsigned int arm_vol_lock_freq;
+static int arm_vol_lock_level;
+static unsigned int asv_group[ID_END];
+
+static unsigned int exynos5250_default_asv_max_volt[] = {
+ [ID_ARM] = 1300000,
+ [ID_INT] = 1037500,
+ [ID_MIF] = 1125000,
+ [ID_G3D] = 1200000,
+};
+
+static unsigned int asv_group_nr[] = {
+ [ID_ARM] = ARM_ASV_GRP_NR,
+ [ID_INT] = INT_ASV_GRP_NR,
+ [ID_MIF] = MIF_ASV_GRP_NR,
+ [ID_G3D] = G3D_ASV_GRP_NR,
+};
+
+static unsigned int dvfs_level_nr[] = {
+ [ID_ARM] = ARM_DVFS_LEVEL_NR,
+ [ID_INT] = INT_DVFS_LEVEL_NR,
+ [ID_MIF] = MIF_DVFS_LEVEL_NR,
+ [ID_G3D] = G3D_DVFS_LEVEL_NR,
+};
+
+typedef unsigned int (*refer_table_get_asv)[MAX_ASV_GRP_NR];
+
+refer_table_get_asv refer_table[] = {
+ [ID_ARM] = arm_refer_table_get_asv,
+ [ID_INT] = int_refer_table_get_asv,
+ [ID_MIF] = mif_refer_table_get_asv,
+ [ID_G3D] = g3d_refer_table_get_asv,
+};
+
+typedef unsigned int (*asv_volt_info)[MAX_ASV_GRP_NR + 1];
+
+asv_volt_info volt_table[] = {
+ [ID_ARM] = arm_asv_volt_info,
+ [ID_INT] = int_asv_volt_info,
+ [ID_MIF] = mif_asv_volt_info,
+ [ID_G3D] = g3d_asv_volt_info,
+};
+
+static void exynos5250_pre_set_abb(unsigned int asv_group_number)
+{
+ switch (asv_group_number) {
+ case 0:
+ case 1:
+ set_abb_member(ABB_ARM, ABB_MODE_080V);
+ set_abb_member(ABB_INT, ABB_MODE_080V);
+ set_abb_member(ABB_G3D, ABB_MODE_080V);
+ break;
+ default:
+ set_abb_member(ABB_ARM, ABB_MODE_BYPASS);
+ set_abb_member(ABB_INT, ABB_MODE_BYPASS);
+ set_abb_member(ABB_G3D, ABB_MODE_BYPASS);
+ break;
+ }
+
+ set_abb_member(ABB_MIF, ABB_MODE_130V);
+}
+static unsigned int exynos5250_get_asv_group(unsigned int ids,
+ unsigned int hpm, enum asv_type_id target_type)
+{
+ unsigned int i;
+ unsigned int refer_ids;
+ unsigned int refer_hpm;
+
+ for (i = 0; i < asv_group_nr[target_type]; i++) {
+ if (target_type != ID_MIF) {
+ refer_ids = refer_table[target_type][0][i];
+ refer_hpm = refer_table[target_type][1][i];
+
+ if ((ids <= refer_ids) || (hpm <= refer_hpm))
+ return i;
+ } else {
+ refer_hpm = refer_table[target_type][0][i];
+
+ if (hpm <= refer_hpm)
+ return i;
+ }
+ }
+
+ /* Default max asv group */
+ return 0;
+}
+
+unsigned int exynos5250_get_volt(enum asv_type_id target_type, unsigned int target_freq)
+{
+ int i;
+ unsigned int group = asv_group[target_type];
+ unsigned int offset = 0;
+
+ for (i = 0; i < dvfs_level_nr[target_type]; i++) {
+ if (volt_table[target_type][i][0] == target_freq) {
+ if (target_type == ID_MIF &&
+ fused_vol_locked[FUSED_MIF_VOL_LOCK]) {
+ offset = MIF_VOL_OFFSET;
+ } else if (target_type == ID_INT &&
+ fused_vol_locked[FUSED_INT_VOL_LOCK]) {
+ offset = INT_VOL_OFFSET;
+ } else if (target_type == ID_G3D &&
+ fused_vol_locked[FUSED_G3D_VOL_LOCK]) {
+ offset = G3D_VOL_OFFSET;
+ } else if (target_type == ID_ARM) {
+ if ((fused_vol_locked[FUSED_ARM_800MHZ_VOL_LOCK] ||
+ fused_vol_locked[FUSED_ARM_1000MHZ_VOL_LOCK] ||
+ fused_vol_locked[FUSED_ARM_1100MHZ_VOL_LOCK]) &&
+ (target_freq < arm_vol_lock_freq))
+ i = arm_vol_lock_level;
+ }
+
+ return volt_table[target_type][i][group + 1] + offset;
+ }
+ }
+
+ return exynos5250_default_asv_max_volt[target_type];
+}
+
+unsigned int exynos5250_set_volt(enum asv_type_id target_type,
+ unsigned int target_freq, unsigned int group,
+ unsigned int volt)
+{
+ int i;
+
+ if (target_type >= ID_END)
+ return -EINVAL;
+
+ if (group == ~0)
+ group = asv_group[target_type];
+
+ if (group >= asv_group_nr[target_type])
+ return -EINVAL;
+
+ for (i = 0; i < dvfs_level_nr[target_type]; i++) {
+ if (volt_table[target_type][i][0] == target_freq) {
+ volt_table[target_type][i][group + 1] = volt;
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+int exynos5250_init_asv(struct asv_common *asv_info)
+{
+ int i;
+ unsigned int tmp1, tmp2;
+ unsigned hpm_value, ids_value;
+
+ /* read IDS and HPM value from CHIP ID */
+ tmp1 = __raw_readl(CHIP_ID_REG);
+
+ /* ASV group is decided by direct fused asv number
+ * or calcualting with ARM_IDS and HPM value.
+ */
+ if ((tmp1 >> FUSED_ASV_GROUP_OFFSET) & 0x1) {
+ tmp2 = __raw_readl(CHIP_ID_REG + 0x4);
+ asv_group[ID_ARM] = ((tmp1 >> ARM_ORG_ASV_GROUP_OFFSET) & ARM_ORG_ASV_MASK)
+ - ((tmp1 >> ARM_DIFF_ASV_GROUP_OFFSET) & ARM_DIFF_ASV_MASK);
+ asv_group[ID_INT] = asv_group[ID_ARM];
+ asv_group[ID_G3D] = asv_group[ID_ARM];
+ asv_group[ID_MIF] = ((tmp2 >> MIF_ORG_ASV_GROUP_OFFSET) & MIF_ORG_ASV_MASK)
+ - ((tmp2 >> MIF_DIFF_ASV_GROUP_OFFSET) & MIF_DIFF_ASV_MASK);
+ pr_info("EXYNOS5250 ASV(ARM : %d MIF : %d) using fused group\n",
+ asv_group[ID_ARM], asv_group[ID_MIF]);
+ } else {
+ hpm_value = (tmp1 >> HPM_OFFSET) & HPM_MASK;
+ ids_value = (tmp1 >> IDS_ARM_OFFSET) & IDS_ARM_MASK;
+
+ for (i = ID_ARM; i < ID_END; i++)
+ asv_group[i] = exynos5250_get_asv_group(ids_value, hpm_value, i);
+
+ pr_info("EXYNOS5250 ASV(ARM : %d MIF : %d) using IDS : %d HPM : %d\n",
+ asv_group[ID_ARM], asv_group[ID_MIF], ids_value, hpm_value);
+ }
+
+ if ((tmp1 >> FUSED_MIF_VOL_LOCK_OFFSET) & 0x1)
+ fused_vol_locked[FUSED_MIF_VOL_LOCK] = true;
+
+ if ((tmp1 >> FUSED_INT_VOL_LOCK_OFFSET) & 0x1)
+ fused_vol_locked[FUSED_INT_VOL_LOCK] = true;
+
+ if ((tmp1 >> FUSED_G3D_VOL_LOCK_OFFSET) & 0x1)
+ fused_vol_locked[FUSED_G3D_VOL_LOCK] = true;
+
+ if (((tmp1 >> FUSED_ARM_VOL_LOCK_OFFSET) & 0x3) == 0x1) {
+ fused_vol_locked[FUSED_ARM_800MHZ_VOL_LOCK] = true;
+ arm_vol_lock_freq = ARM_FREQ_800MHZ;
+ } else if (((tmp1 >> FUSED_ARM_VOL_LOCK_OFFSET) & 0x3) == 0x2) {
+ fused_vol_locked[FUSED_ARM_1000MHZ_VOL_LOCK] = true;
+ arm_vol_lock_freq = ARM_FREQ_1000MHZ;
+ } else if (((tmp1 >> FUSED_ARM_VOL_LOCK_OFFSET) & 0x3) == 0x3) {
+ fused_vol_locked[FUSED_ARM_1100MHZ_VOL_LOCK] = true;
+ arm_vol_lock_freq = ARM_FREQ_1100MHZ;
+ }
+
+ if (fused_vol_locked[FUSED_ARM_800MHZ_VOL_LOCK] ||
+ fused_vol_locked[FUSED_ARM_1000MHZ_VOL_LOCK] ||
+ fused_vol_locked[FUSED_ARM_1100MHZ_VOL_LOCK]) {
+ for (i = 0; i < dvfs_level_nr[ID_ARM]; i++) {
+ if (volt_table[ID_ARM][i][0] == arm_vol_lock_freq) {
+ arm_vol_lock_level = i;
+ break;
+ }
+ }
+ }
+
+ exynos5250_pre_set_abb(asv_group[ID_ARM]);
+
+ asv_info->get_voltage = exynos5250_get_volt;
+ asv_info->init_done = true;
+
+ return 0;
+}
diff --git a/arch/arm/mach-exynos/clock-audss.c b/arch/arm/mach-exynos/clock-audss.c
new file mode 100644
index 0000000..9dd7e25
--- /dev/null
+++ b/arch/arm/mach-exynos/clock-audss.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Clock support for EXYNOS Audio Subsystem
+ *
+ * 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.
+*/
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+
+#include <plat/clock.h>
+#include <plat/s5p-clock.h>
+#include <plat/clock-clksrc.h>
+
+#include <mach/map.h>
+#include <mach/regs-audss.h>
+
+static int exynos_clk_audss_ctrl(struct clk *clk, int enable)
+{
+ return s5p_gatectrl(EXYNOS_CLKGATE_AUDSS, clk, enable);
+}
+
+static struct clk *exynos_clkset_mout_audss_list[] = {
+ &clk_ext_xtal_mux,
+ &clk_fout_epll,
+};
+
+static struct clksrc_sources clkset_mout_audss = {
+ .sources = exynos_clkset_mout_audss_list,
+ .nr_sources = ARRAY_SIZE(exynos_clkset_mout_audss_list),
+};
+
+static struct clksrc_clk exynos_clk_mout_audss = {
+ .clk = {
+ .name = "mout_audss",
+ },
+ .sources = &clkset_mout_audss,
+ .reg_src = { .reg = EXYNOS_CLKSRC_AUDSS, .shift = 0, .size = 1 },
+};
+
+static struct clksrc_clk exynos_clk_dout_audss_srp = {
+ .clk = {
+ .name = "dout_srp",
+ .parent = &exynos_clk_mout_audss.clk,
+ },
+ .reg_div = { .reg = EXYNOS_CLKDIV_AUDSS, .shift = 0, .size = 4 },
+};
+
+static struct clksrc_clk exynos_clk_dout_audss_bus = {
+ .clk = {
+ .name = "dout_bus",
+ .parent = &exynos_clk_dout_audss_srp.clk,
+ },
+ .reg_div = { .reg = EXYNOS_CLKDIV_AUDSS, .shift = 4, .size = 4 },
+};
+
+static struct clksrc_clk exynos_clk_dout_audss_i2s = {
+ .clk = {
+ .name = "dout_i2s",
+ .parent = &exynos_clk_mout_audss.clk,
+ },
+ .reg_div = { .reg = EXYNOS_CLKDIV_AUDSS, .shift = 8, .size = 4 },
+};
+
+/* Clock initialization code */
+static struct clksrc_clk *exynos_audss_clks[] = {
+ &exynos_clk_mout_audss,
+ &exynos_clk_dout_audss_srp,
+ &exynos_clk_dout_audss_bus,
+ &exynos_clk_dout_audss_i2s,
+};
+
+static struct clk exynos_init_audss_clocks[] = {
+ {
+ .name = "srpclk",
+ .parent = &exynos_clk_dout_audss_srp.clk,
+ .enable = exynos_clk_audss_ctrl,
+ .ctrlbit = EXYNOS_AUDSS_CLKGATE_RP | EXYNOS_AUDSS_CLKGATE_UART
+ | EXYNOS_AUDSS_CLKGATE_TIMER,
+ }, {
+ .name = "iis",
+ .devname = "samsung-i2s.0",
+ .enable = exynos_clk_audss_ctrl,
+ .ctrlbit = EXYNOS_AUDSS_CLKGATE_I2SSPECIAL | EXYNOS_AUDSS_CLKGATE_I2SBUS,
+ }, {
+ .name = "iis",
+ .devname = "samsung-i2s.4",
+ .enable = exynos_clk_audss_ctrl,
+ .ctrlbit = EXYNOS_AUDSS_CLKGATE_I2SSPECIAL | EXYNOS_AUDSS_CLKGATE_I2SBUS,
+ }, {
+ .name = "pcm",
+ .devname = "samsung-pcm.0",
+ .enable = exynos_clk_audss_ctrl,
+ .ctrlbit = EXYNOS_AUDSS_CLKGATE_I2SSPECIAL | EXYNOS_AUDSS_CLKGATE_I2SBUS,
+ }, {
+ .name = "pcm",
+ .devname = "samsung-pcm.4",
+ .enable = exynos_clk_audss_ctrl,
+ .ctrlbit = EXYNOS_AUDSS_CLKGATE_I2SSPECIAL | EXYNOS_AUDSS_CLKGATE_I2SBUS,
+ },
+};
+
+void __init exynos_register_audss_clocks(void)
+{
+ int ptr;
+
+ for (ptr = 0; ptr < ARRAY_SIZE(exynos_audss_clks); ptr++)
+ s3c_register_clksrc(exynos_audss_clks[ptr], 1);
+
+ s3c_register_clocks(exynos_init_audss_clocks, ARRAY_SIZE(exynos_init_audss_clocks));
+ s3c_disable_clocks(exynos_init_audss_clocks, ARRAY_SIZE(exynos_init_audss_clocks));
+}
diff --git a/arch/arm/mach-exynos/clock-exynos4.c b/arch/arm/mach-exynos/clock-exynos4.c
index 6efd1e5..9c65d3b 100644
--- a/arch/arm/mach-exynos/clock-exynos4.c
+++ b/arch/arm/mach-exynos/clock-exynos4.c
@@ -200,12 +200,12 @@
static int exynos4_clk_hdmiphy_ctrl(struct clk *clk, int enable)
{
- return s5p_gatectrl(S5P_HDMI_PHY_CONTROL, clk, enable);
+ return s5p_gatectrl(EXYNOS_HDMI_PHY_CONTROL, clk, enable);
}
static int exynos4_clk_dac_ctrl(struct clk *clk, int enable)
{
- return s5p_gatectrl(S5P_DAC_PHY_CONTROL, clk, enable);
+ return s5p_gatectrl(EXYNOS4210_DAC_PHY_CONTROL, clk, enable);
}
/* Core list of CMU_CPU side */
@@ -678,61 +678,50 @@
.enable = exynos4_clk_ip_peril_ctrl,
.ctrlbit = (1 << 14),
}, {
- .name = "SYSMMU_MDMA",
- .enable = exynos4_clk_ip_image_ctrl,
- .ctrlbit = (1 << 5),
+ .name = SYSMMU_CLOCK_NAME,
+ .devname = SYSMMU_CLOCK_DEVNAME(mfc_lr, 0),
+ .enable = exynos4_clk_ip_mfc_ctrl,
+ .ctrlbit = (3 << 1),
}, {
- .name = "SYSMMU_FIMC0",
- .enable = exynos4_clk_ip_cam_ctrl,
- .ctrlbit = (1 << 7),
- }, {
- .name = "SYSMMU_FIMC1",
- .enable = exynos4_clk_ip_cam_ctrl,
- .ctrlbit = (1 << 8),
- }, {
- .name = "SYSMMU_FIMC2",
- .enable = exynos4_clk_ip_cam_ctrl,
- .ctrlbit = (1 << 9),
- }, {
- .name = "SYSMMU_FIMC3",
- .enable = exynos4_clk_ip_cam_ctrl,
- .ctrlbit = (1 << 10),
- }, {
- .name = "SYSMMU_JPEG",
- .enable = exynos4_clk_ip_cam_ctrl,
- .ctrlbit = (1 << 11),
- }, {
- .name = "SYSMMU_FIMD0",
- .enable = exynos4_clk_ip_lcd0_ctrl,
- .ctrlbit = (1 << 4),
- }, {
- .name = "SYSMMU_FIMD1",
- .enable = exynos4_clk_ip_lcd1_ctrl,
- .ctrlbit = (1 << 4),
- }, {
- .name = "SYSMMU_PCIe",
- .enable = exynos4_clk_ip_fsys_ctrl,
- .ctrlbit = (1 << 18),
- }, {
- .name = "SYSMMU_G2D",
- .enable = exynos4_clk_ip_image_ctrl,
- .ctrlbit = (1 << 3),
- }, {
- .name = "SYSMMU_ROTATOR",
- .enable = exynos4_clk_ip_image_ctrl,
- .ctrlbit = (1 << 4),
- }, {
- .name = "SYSMMU_TV",
+ .name = SYSMMU_CLOCK_NAME,
+ .devname = SYSMMU_CLOCK_DEVNAME(tv, 2),
.enable = exynos4_clk_ip_tv_ctrl,
.ctrlbit = (1 << 4),
}, {
- .name = "SYSMMU_MFC_L",
- .enable = exynos4_clk_ip_mfc_ctrl,
- .ctrlbit = (1 << 1),
+ .name = SYSMMU_CLOCK_NAME,
+ .devname = SYSMMU_CLOCK_DEVNAME(jpeg, 3),
+ .enable = exynos4_clk_ip_cam_ctrl,
+ .ctrlbit = (1 << 11),
}, {
- .name = "SYSMMU_MFC_R",
- .enable = exynos4_clk_ip_mfc_ctrl,
- .ctrlbit = (1 << 2),
+ .name = SYSMMU_CLOCK_NAME,
+ .devname = SYSMMU_CLOCK_DEVNAME(rot, 4),
+ .enable = exynos4_clk_ip_image_ctrl,
+ .ctrlbit = (1 << 4),
+ }, {
+ .name = SYSMMU_CLOCK_NAME,
+ .devname = SYSMMU_CLOCK_DEVNAME(fimc0, 5),
+ .enable = exynos4_clk_ip_cam_ctrl,
+ .ctrlbit = (1 << 7),
+ }, {
+ .name = SYSMMU_CLOCK_NAME,
+ .devname = SYSMMU_CLOCK_DEVNAME(fimc1, 6),
+ .enable = exynos4_clk_ip_cam_ctrl,
+ .ctrlbit = (1 << 8),
+ }, {
+ .name = SYSMMU_CLOCK_NAME,
+ .devname = SYSMMU_CLOCK_DEVNAME(fimc2, 7),
+ .enable = exynos4_clk_ip_cam_ctrl,
+ .ctrlbit = (1 << 9),
+ }, {
+ .name = SYSMMU_CLOCK_NAME,
+ .devname = SYSMMU_CLOCK_DEVNAME(fimc3, 8),
+ .enable = exynos4_clk_ip_cam_ctrl,
+ .ctrlbit = (1 << 10),
+ }, {
+ .name = SYSMMU_CLOCK_NAME,
+ .devname = SYSMMU_CLOCK_DEVNAME(fimd0, 10),
+ .enable = exynos4_clk_ip_lcd0_ctrl,
+ .ctrlbit = (1 << 4),
}
};
diff --git a/arch/arm/mach-exynos/clock-exynos5.c b/arch/arm/mach-exynos/clock-exynos5.c
index 7ac6ff4..52726d5 100644
--- a/arch/arm/mach-exynos/clock-exynos5.c
+++ b/arch/arm/mach-exynos/clock-exynos5.c
@@ -23,14 +23,77 @@
#include <plat/pm.h>
#include <mach/map.h>
-#include <mach/regs-clock.h>
#include <mach/sysmmu.h>
+#include <mach/regs-clock.h>
+
+#include <media/exynos_fimc_is.h>
#include "common.h"
#ifdef CONFIG_PM_SLEEP
static struct sleep_save exynos5_clock_save[] = {
- /* will be implemented */
+ SAVE_ITEM(EXYNOS5_CLKSRC_MASK_TOP),
+ SAVE_ITEM(EXYNOS5_CLKSRC_MASK_GSCL),
+ SAVE_ITEM(EXYNOS5_CLKSRC_MASK_DISP1_0),
+ SAVE_ITEM(EXYNOS5_CLKSRC_MASK_FSYS),
+ SAVE_ITEM(EXYNOS5_CLKSRC_MASK_MAUDIO),
+ SAVE_ITEM(EXYNOS5_CLKSRC_MASK_PERIC0),
+ SAVE_ITEM(EXYNOS5_CLKSRC_MASK_PERIC1),
+ SAVE_ITEM(EXYNOS5_CLKGATE_IP_CORE),
+ SAVE_ITEM(EXYNOS5_CLKGATE_IP_SYSRGT),
+ SAVE_ITEM(EXYNOS5_CLKGATE_IP_ACP),
+ SAVE_ITEM(EXYNOS5_CLKGATE_IP_SYSLFT),
+ SAVE_ITEM(EXYNOS5_CLKGATE_IP_GSCL),
+ SAVE_ITEM(EXYNOS5_CLKGATE_IP_DISP1),
+ SAVE_ITEM(EXYNOS5_CLKGATE_IP_MFC),
+ SAVE_ITEM(EXYNOS5_CLKGATE_IP_G3D),
+ SAVE_ITEM(EXYNOS5_CLKGATE_IP_GEN),
+ SAVE_ITEM(EXYNOS5_CLKGATE_IP_FSYS),
+ SAVE_ITEM(EXYNOS5_CLKGATE_IP_PERIC),
+ SAVE_ITEM(EXYNOS5_CLKGATE_IP_PERIS),
+ SAVE_ITEM(EXYNOS5_CLKGATE_IP_CDREX),
+ SAVE_ITEM(EXYNOS5_CLKGATE_BLOCK),
+ SAVE_ITEM(EXYNOS5_CLKGATE_BUS_SYSLFT),
+ SAVE_ITEM(EXYNOS5_CLKDIV_ACP),
+ SAVE_ITEM(EXYNOS5_CLKDIV_TOP0),
+ SAVE_ITEM(EXYNOS5_CLKDIV_TOP1),
+ SAVE_ITEM(EXYNOS5_CLKDIV_GSCL),
+ SAVE_ITEM(EXYNOS5_CLKDIV_DISP1_0),
+ SAVE_ITEM(EXYNOS5_CLKDIV_GEN),
+ SAVE_ITEM(EXYNOS5_CLKDIV_MAUDIO),
+ SAVE_ITEM(EXYNOS5_CLKDIV_FSYS0),
+ SAVE_ITEM(EXYNOS5_CLKDIV_FSYS1),
+ SAVE_ITEM(EXYNOS5_CLKDIV_FSYS2),
+ SAVE_ITEM(EXYNOS5_CLKDIV_FSYS3),
+ SAVE_ITEM(EXYNOS5_CLKDIV_PERIC0),
+ SAVE_ITEM(EXYNOS5_CLKDIV_PERIC1),
+ SAVE_ITEM(EXYNOS5_CLKDIV_PERIC2),
+ SAVE_ITEM(EXYNOS5_CLKDIV_PERIC3),
+ SAVE_ITEM(EXYNOS5_CLKDIV_PERIC4),
+ SAVE_ITEM(EXYNOS5_CLKDIV_PERIC5),
+ SAVE_ITEM(EXYNOS5_CLKDIV2_RATIO0),
+ SAVE_ITEM(EXYNOS5_CLKDIV2_RATIO1),
+ SAVE_ITEM(EXYNOS5_CLKDIV4_RATIO),
+ SAVE_ITEM(EXYNOS5_CLKSRC_TOP0),
+ SAVE_ITEM(EXYNOS5_CLKSRC_TOP1),
+ SAVE_ITEM(EXYNOS5_CLKSRC_TOP2),
+ SAVE_ITEM(EXYNOS5_CLKSRC_TOP3),
+ SAVE_ITEM(EXYNOS5_CLKSRC_GSCL),
+ SAVE_ITEM(EXYNOS5_CLKSRC_DISP1_0),
+ SAVE_ITEM(EXYNOS5_CLKSRC_MAUDIO),
+ SAVE_ITEM(EXYNOS5_CLKSRC_FSYS),
+ SAVE_ITEM(EXYNOS5_CLKSRC_PERIC0),
+ SAVE_ITEM(EXYNOS5_CLKSRC_PERIC1),
+ SAVE_ITEM(EXYNOS5_EPLL_CON0),
+ SAVE_ITEM(EXYNOS5_EPLL_CON1),
+ SAVE_ITEM(EXYNOS5_EPLL_CON2),
+ SAVE_ITEM(EXYNOS5_VPLL_CON0),
+ SAVE_ITEM(EXYNOS5_VPLL_CON1),
+ SAVE_ITEM(EXYNOS5_VPLL_CON2),
+ SAVE_ITEM(EXYNOS5_PWR_CTRL1),
+ SAVE_ITEM(EXYNOS5_PWR_CTRL2),
+ SAVE_ITEM(EXYNOS5_GPLL_CON0),
+ SAVE_ITEM(EXYNOS5_GPLL_CON1),
};
#endif
@@ -57,21 +120,99 @@
.rate = 48000000,
};
+static struct clk dummy_apb_pclk = {
+ .name = "apb_pclk",
+};
+
+struct clksrc_clk exynos5_clk_audiocdclk0 = {
+ .clk = {
+ .name = "audiocdclk",
+ .rate = 16934400,
+ },
+};
+
+static struct clk exynos5_clk_audiocdclk1 = {
+ .name = "audiocdclk",
+};
+
+static struct clk exynos5_clk_audiocdclk2 = {
+ .name = "audiocdclk",
+};
+
+static struct clk exynos5_clk_spdifcdclk = {
+ .name = "spdifcdclk",
+};
+
+/*
+ * MOUT_BPLL_FOUT
+ * No need .ctrlbit, this is always on
+ */
+static struct clk clk_fout_bpll_div2 = {
+ .name = "fout_bpll_div2",
+ .id = -1,
+};
+
+/*
+ * MOUT_MPLL_FOUT
+ * No need .ctrlbit, this is always on
+ */
+static struct clk clk_fout_mpll_div2 = {
+ .name = "fout_mpll_div2",
+ .id = -1,
+};
+
+/* GPLL clock output */
+static struct clk clk_fout_gpll = {
+ .name = "fout_gpll",
+ .id = -1,
+};
+
+/*
+ * This clock is for only mif dvfs virtually.
+ */
+static struct clk exynos5_mif_clk = {
+ .name = "mif_clk",
+ .id = -1,
+};
+
+/*
+ * This clock is for only int dvfs virtually.
+ */
+static struct clk exynos5_int_clk = {
+ .name = "int_clk",
+ .id = -1,
+};
+
static int exynos5_clksrc_mask_top_ctrl(struct clk *clk, int enable)
{
return s5p_gatectrl(EXYNOS5_CLKSRC_MASK_TOP, clk, enable);
}
+static int exynos5_clksrc_mask_peric1_ctrl(struct clk *clk, int enable)
+{
+ return s5p_gatectrl(EXYNOS5_CLKSRC_MASK_PERIC1, clk, enable);
+}
+
static int exynos5_clksrc_mask_disp1_0_ctrl(struct clk *clk, int enable)
{
return s5p_gatectrl(EXYNOS5_CLKSRC_MASK_DISP1_0, clk, enable);
}
+static int exynos5_clksrc_mask_maudio_ctrl(struct clk *clk, int enable)
+{
+ return s5p_gatectrl(EXYNOS5_CLKSRC_MASK_MAUDIO, clk, enable);
+}
+
static int exynos5_clksrc_mask_fsys_ctrl(struct clk *clk, int enable)
{
return s5p_gatectrl(EXYNOS5_CLKSRC_MASK_FSYS, clk, enable);
}
+static int exynos5_clk_ip_gscl_ctrl(struct clk *clk, int enable)
+{
+ return s5p_gatectrl(EXYNOS5_CLKGATE_IP_GSCL, clk, enable);
+}
+
static int exynos5_clksrc_mask_gscl_ctrl(struct clk *clk, int enable)
{
return s5p_gatectrl(EXYNOS5_CLKSRC_MASK_GSCL, clk, enable);
@@ -82,6 +223,16 @@
return s5p_gatectrl(EXYNOS5_CLKSRC_MASK_PERIC0, clk, enable);
}
+static int exynos5_clksrc_mask_gen_ctrl(struct clk *clk, int enable)
+{
+ return s5p_gatectrl(EXYNOS5_CLKSRC_MASK_GEN, clk, enable);
+}
+
+static int exynos5_clk_ip_acp_ctrl(struct clk *clk, int enable)
+{
+ return s5p_gatectrl(EXYNOS5_CLKGATE_IP_ACP, clk, enable);
+}
+
static int exynos5_clk_ip_core_ctrl(struct clk *clk, int enable)
{
return s5p_gatectrl(EXYNOS5_CLKGATE_IP_CORE, clk, enable);
@@ -97,6 +248,11 @@
return s5p_gatectrl(EXYNOS5_CLKGATE_IP_FSYS, clk, enable);
}
+static int exynos5_clk_ip_sysrgt_ctrl(struct clk *clk, int enable)
+{
+ return s5p_gatectrl(EXYNOS5_CLKGATE_IP_SYSRGT, clk, enable);
+}
+
static int exynos5_clk_block_ctrl(struct clk *clk, int enable)
{
return s5p_gatectrl(EXYNOS5_CLKGATE_BLOCK, clk, enable);
@@ -107,16 +263,16 @@
return s5p_gatectrl(EXYNOS5_CLKGATE_IP_GEN, clk, enable);
}
-static int exynos5_clk_ip_gps_ctrl(struct clk *clk, int enable)
-{
- return s5p_gatectrl(EXYNOS5_CLKGATE_IP_GPS, clk, enable);
-}
-
static int exynos5_clk_ip_mfc_ctrl(struct clk *clk, int enable)
{
return s5p_gatectrl(EXYNOS5_CLKGATE_IP_MFC, clk, enable);
}
+static int exynos5_clk_ip_g3d_ctrl(struct clk *clk, int enable)
+{
+ return s5p_gatectrl(EXYNOS5_CLKGATE_IP_G3D, clk, enable);
+}
+
static int exynos5_clk_ip_peric_ctrl(struct clk *clk, int enable)
{
return s5p_gatectrl(EXYNOS5_CLKGATE_IP_PERIC, clk, enable);
@@ -127,6 +283,30 @@
return s5p_gatectrl(EXYNOS5_CLKGATE_IP_PERIS, clk, enable);
}
+static int exynos5_clk_ip_isp0_ctrl(struct clk *clk, int enable)
+{
+ return s5p_gatectrl(EXYNOS5_CLKGATE_IP_ISP0, clk, enable);
+}
+
+static int exynos5_clk_ip_isp1_ctrl(struct clk *clk, int enable)
+{
+ return s5p_gatectrl(EXYNOS5_CLKGATE_IP_ISP1, clk, enable);
+}
+
+static int exynos5_clk_bus_syslft_ctrl(struct clk *clk, int enable)
+{
+ return s5p_gatectrl(EXYNOS5_CLKGATE_BUS_SYSLFT, clk, enable);
+}
+
+static int exynos5_clk_clkout_ctrl(struct clk *clk, int enable)
+{
+ /*
+ * Setting the bit disable the clock
+ * and clearing it enables the clock
+ */
+ return s5p_gatectrl(EXYNOS_PMU_DEBUG, clk, !enable);
+}
+
/* Core list of CMU_CPU side */
static struct clksrc_clk exynos5_clk_mout_apll = {
@@ -145,11 +325,41 @@
.reg_div = { .reg = EXYNOS5_CLKDIV_CPU0, .shift = 24, .size = 3 },
};
+/* Possible clock source for BPLL_FOUT Mux */
+static struct clk *exynos5_clkset_mout_bpll_fout_list[] = {
+ [0] = &clk_fout_bpll_div2,
+ [1] = &clk_fout_bpll,
+};
+
+static struct clksrc_sources exynos5_clkset_mout_bpll_fout = {
+ .sources = exynos5_clkset_mout_bpll_fout_list,
+ .nr_sources = ARRAY_SIZE(exynos5_clkset_mout_bpll_fout_list),
+};
+
+static struct clksrc_clk exynos5_clk_mout_bpll_fout = {
+ .clk = {
+ .name = "mout_bpll_fout",
+ },
+ .sources = &exynos5_clkset_mout_bpll_fout,
+ .reg_src = { .reg = EXYNOS5_PLL_DIV2_SEL, .shift = 0, .size = 1 },
+};
+
+/* Possible clock source for BPLL Mux */
+static struct clk *exynos5_clkset_mout_bpll_list[] = {
+ [0] = &clk_fin_bpll,
+ [1] = &exynos5_clk_mout_bpll_fout.clk,
+};
+
+static struct clksrc_sources exynos5_clkset_mout_bpll = {
+ .sources = exynos5_clkset_mout_bpll_list,
+ .nr_sources = ARRAY_SIZE(exynos5_clkset_mout_bpll_list),
+};
+
static struct clksrc_clk exynos5_clk_mout_bpll = {
.clk = {
.name = "mout_bpll",
},
- .sources = &clk_src_bpll,
+ .sources = &exynos5_clkset_mout_bpll,
.reg_src = { .reg = EXYNOS5_CLKSRC_CDREX, .shift = 0, .size = 1 },
};
@@ -187,14 +397,63 @@
.reg_src = { .reg = EXYNOS5_CLKSRC_TOP2, .shift = 12, .size = 1 },
};
+/* Possible clock source for MPLL_FOUT Mux */
+static struct clk *exynos5_clkset_mout_mpll_fout_list[] = {
+ [0] = &clk_fout_mpll_div2,
+ [1] = &clk_fout_mpll,
+};
+
+static struct clksrc_sources exynos5_clkset_mout_mpll_fout = {
+ .sources = exynos5_clkset_mout_mpll_fout_list,
+ .nr_sources = ARRAY_SIZE(exynos5_clkset_mout_mpll_fout_list),
+};
+
+static struct clksrc_clk exynos5_clk_mout_mpll_fout = {
+ .clk = {
+ .name = "mout_mpll_fout",
+ },
+ .sources = &exynos5_clkset_mout_mpll_fout,
+ .reg_src = { .reg = EXYNOS5_PLL_DIV2_SEL, .shift = 4, .size = 1 },
+};
+
+/* Possible clock source for MPLL Mux */
+static struct clk *exynos5_clkset_mout_mpll_list[] = {
+ [0] = &clk_fin_mpll,
+ [1] = &exynos5_clk_mout_mpll_fout.clk,
+};
+
+static struct clksrc_sources exynos5_clkset_mout_mpll = {
+ .sources = exynos5_clkset_mout_mpll_list,
+ .nr_sources = ARRAY_SIZE(exynos5_clkset_mout_mpll_list),
+};
+
struct clksrc_clk exynos5_clk_mout_mpll = {
.clk = {
.name = "mout_mpll",
},
- .sources = &clk_src_mpll,
+ .sources = &exynos5_clkset_mout_mpll,
.reg_src = { .reg = EXYNOS5_CLKSRC_CORE1, .shift = 8, .size = 1 },
};
+/* Possible clock sources for GPLL Mux */
+static struct clk *clk_src_gpll_list[] = {
+ [0] = &clk_fin_gpll,
+ [1] = &clk_fout_gpll,
+};
+
+static struct clksrc_sources clk_src_gpll = {
+ .sources = clk_src_gpll_list,
+ .nr_sources = ARRAY_SIZE(clk_src_gpll_list),
+};
+
+static struct clksrc_clk exynos5_clk_mout_gpll = {
+ .clk = {
+ .name = "mout_gpll"
+ },
+ .sources = &clk_src_gpll,
+ .reg_src = { .reg = EXYNOS5_CLKSRC_TOP2, .shift = 24, .size = 1},
+};
+
static struct clk *exynos_clkset_vpllsrc_list[] = {
[0] = &clk_fin_vpll,
[1] = &exynos5_clk_sclk_hdmi27m,
@@ -261,9 +520,30 @@
.reg_src = { .reg = EXYNOS5_CLKSRC_DISP1_0, .shift = 20, .size = 1 },
};
+static struct clk *exynos5_clkset_sclk_cec_list[] = {
+ [0] = &exynos5_clk_sclk_pixel.clk,
+ [1] = &exynos5_clk_sclk_hdmiphy,
+};
+
+static struct clksrc_sources exynos5_clkset_sclk_cec = {
+ .sources = exynos5_clkset_sclk_cec_list,
+ .nr_sources = ARRAY_SIZE(exynos5_clkset_sclk_cec_list),
+};
+
+static struct clksrc_clk exynos5_clk_sclk_cec = {
+ .clk = {
+ .name = "sclk_cec",
+ .enable = exynos5_clksrc_mask_disp1_0_ctrl,
+ .ctrlbit = (1 << 20),
+ },
+ .sources = &exynos5_clkset_sclk_cec,
+ .reg_src = { .reg = EXYNOS5_CLKSRC_DISP1_0, .shift = 20, .size = 1 },
+};
+
static struct clksrc_clk *exynos5_sclk_tv[] = {
&exynos5_clk_sclk_pixel,
&exynos5_clk_sclk_hdmi,
+ &exynos5_clk_sclk_cec,
};
static struct clk *exynos5_clk_src_mpll_user_list[] = {
@@ -300,6 +580,7 @@
},
.sources = &exynos5_clkset_mout_cpu,
.reg_src = { .reg = EXYNOS5_CLKSRC_CPU, .shift = 16, .size = 1 },
+ .reg_src_stat = {.reg = EXYNOS5_CLKMUX_STATCPU, .shift = 16, .size = 3},
};
static struct clksrc_clk exynos5_clk_dout_armclk = {
@@ -335,13 +616,13 @@
.nr_sources = ARRAY_SIZE(exynos5_clkset_cdrex_list),
};
-static struct clksrc_clk exynos5_clk_cdrex = {
+static struct clksrc_clk exynos5_clk_mclk_cdrex = {
.clk = {
- .name = "clk_cdrex",
+ .name = "mclk_cdrex",
},
.sources = &exynos5_clkset_cdrex,
.reg_src = { .reg = EXYNOS5_CLKSRC_CDREX, .shift = 4, .size = 1 },
- .reg_div = { .reg = EXYNOS5_CLKDIV_CDREX, .shift = 16, .size = 3 },
+ .reg_div = { .reg = EXYNOS5_CLKDIV_CDREX, .shift = 28, .size = 3 },
};
static struct clksrc_clk exynos5_clk_aclk_acp = {
@@ -372,12 +653,30 @@
.nr_sources = ARRAY_SIZE(exynos5_clkset_aclk_top_list),
};
-static struct clksrc_clk exynos5_clk_aclk_400 = {
+static struct clksrc_clk exynos5_clk_aclk_400_g3d_mid = {
.clk = {
- .name = "aclk_400",
+ .name = "aclk_400_g3d_mid",
},
.sources = &exynos5_clkset_aclk,
.reg_src = { .reg = EXYNOS5_CLKSRC_TOP0, .shift = 20, .size = 1 },
+};
+
+static struct clk *exynos5_clkset_aclk_g3d_list[] = {
+ [0] = &exynos5_clk_aclk_400_g3d_mid.clk,
+ [1] = &exynos5_clk_mout_gpll.clk,
+};
+
+static struct clksrc_sources exynos5_clkset_aclk_g3d = {
+ .sources = exynos5_clkset_aclk_g3d_list,
+ .nr_sources = ARRAY_SIZE(exynos5_clkset_aclk_g3d_list),
+};
+
+static struct clksrc_clk exynos5_clk_aclk_400_g3d = {
+ .clk = {
+ .name = "aclk_400_g3d",
+ },
+ .sources = &exynos5_clkset_aclk_g3d,
+ .reg_src = { .reg = EXYNOS5_CLKSRC_TOP1, .shift = 28, .size = 1 },
.reg_div = { .reg = EXYNOS5_CLKDIV_TOP0, .shift = 24, .size = 3 },
};
@@ -391,13 +690,38 @@
.nr_sources = ARRAY_SIZE(exynos5_clkset_aclk_333_166_list),
};
+static struct clksrc_clk exynos5_clk_mout_aclk_333 = {
+ .clk = {
+ .name = "mout_aclk_333",
+ },
+ .sources = &exynos5_clkset_aclk_333_166,
+ .reg_src = { .reg = EXYNOS5_CLKSRC_TOP0, .shift = 16, .size = 1 },
+};
+
+static struct clksrc_clk exynos5_clk_dout_aclk_333 = {
+ .clk = {
+ .name = "dout_aclk_333",
+ .parent = &exynos5_clk_mout_aclk_333.clk,
+ },
+ .reg_div = { .reg = EXYNOS5_CLKDIV_TOP0, .shift = 20, .size = 3 },
+};
+
+struct clk *exynos5_clkset_aclk_333_sub_list[] = {
+ [0] = &clk_ext_xtal_mux,
+ [1] = &exynos5_clk_dout_aclk_333.clk,
+};
+
+struct clksrc_sources exynos5_clkset_aclk_333_sub = {
+ .sources = exynos5_clkset_aclk_333_sub_list,
+ .nr_sources = ARRAY_SIZE(exynos5_clkset_aclk_333_sub_list),
+};
+
static struct clksrc_clk exynos5_clk_aclk_333 = {
.clk = {
.name = "aclk_333",
},
- .sources = &exynos5_clkset_aclk_333_166,
- .reg_src = { .reg = EXYNOS5_CLKSRC_TOP0, .shift = 16, .size = 1 },
- .reg_div = { .reg = EXYNOS5_CLKDIV_TOP0, .shift = 20, .size = 3 },
+ .sources = &exynos5_clkset_aclk_333_sub,
+ .reg_src = { .reg = EXYNOS5_CLKSRC_TOP3, .shift = 24, .size = 1 },
};
static struct clksrc_clk exynos5_clk_aclk_166 = {
@@ -409,6 +733,144 @@
.reg_div = { .reg = EXYNOS5_CLKDIV_TOP0, .shift = 8, .size = 3 },
};
+/* For ACLK_300_disp1_mid */
+static struct clksrc_clk exynos5_clk_mout_aclk_300_disp1_mid = {
+ .clk = {
+ .name = "mout_aclk_300_disp1_mid",
+ },
+ .sources = &exynos5_clkset_aclk,
+ .reg_src = { .reg = EXYNOS5_CLKSRC_TOP0, .shift = 14, .size = 1 },
+};
+
+static struct clk *clk_src_mid1_list[] = {
+ [0] = &exynos5_clk_sclk_vpll.clk,
+ [1] = &exynos5_clk_mout_cpll.clk,
+};
+
+static struct clksrc_sources exynos5_clkset_mid1 = {
+ .sources = clk_src_mid1_list,
+ .nr_sources = ARRAY_SIZE(clk_src_mid1_list),
+};
+
+/* For ACLK_300_disp1_mid1 */
+static struct clksrc_clk exynos5_clk_mout_aclk_300_disp1_mid1 = {
+ .clk = {
+ .name = "mout_aclk_300_disp1_mid1",
+ },
+ .sources = &exynos5_clkset_mid1,
+ .reg_src = { .reg = EXYNOS5_CLKSRC_TOP1, .shift = 8, .size = 1 },
+};
+
+/* For ACLK_300_disp1 */
+struct clk *exynos5_clkset_mout_aclk_300_disp1_list[] = {
+ [0] = &exynos5_clk_mout_aclk_300_disp1_mid.clk,
+ [1] = &exynos5_clk_mout_aclk_300_disp1_mid1.clk,
+};
+
+struct clksrc_sources exynos5_clkset_mout_aclk_300_disp1 = {
+ .sources = exynos5_clkset_mout_aclk_300_disp1_list,
+ .nr_sources = ARRAY_SIZE(exynos5_clkset_mout_aclk_300_disp1_list),
+};
+
+static struct clksrc_clk exynos5_clk_mout_aclk_300_disp1 = {
+ .clk = {
+ .name = "mout_aclk_300_disp1",
+ },
+ .sources = &exynos5_clkset_mout_aclk_300_disp1,
+ .reg_src = { .reg = EXYNOS5_CLKSRC_TOP0, .shift = 15, .size = 1 },
+};
+
+static struct clksrc_clk exynos5_clk_dout_aclk_300_disp1 = {
+ .clk = {
+ .name = "dout_aclk_300_disp1",
+ .parent = &exynos5_clk_mout_aclk_300_disp1.clk,
+ },
+ .reg_div = { .reg = EXYNOS5_CLKDIV_TOP0, .shift = 28, .size = 3 },
+};
+
+static struct clk *clk_src_aclk_300_disp1_list[] = {
+ [0] = &clk_ext_xtal_mux,
+ [1] = &exynos5_clk_dout_aclk_300_disp1.clk,
+};
+
+static struct clksrc_sources exynos5_clkset_aclk_300_disp1 = {
+ .sources = clk_src_aclk_300_disp1_list,
+ .nr_sources = ARRAY_SIZE(clk_src_aclk_300_disp1_list),
+};
+
+static struct clksrc_clk exynos5_clk_aclk_300_disp1 = {
+ .clk = {
+ .name = "aclk_300_disp1",
+ },
+ .sources = &exynos5_clkset_aclk_300_disp1,
+ .reg_src = { .reg = EXYNOS5_CLKSRC_TOP3, .shift = 6, .size = 1 },
+};
+
+
+/* For ACLK_300_gscl_mid */
+static struct clksrc_clk exynos5_clk_mout_aclk_300_gscl_mid = {
+ .clk = {
+ .name = "mout_aclk_300_gscl_mid",
+ },
+ .sources = &exynos5_clkset_aclk,
+ .reg_src = { .reg = EXYNOS5_CLKSRC_TOP0, .shift = 24, .size = 1 },
+};
+
+/* For ACLK_300_gscl_mid1 */
+static struct clksrc_clk exynos5_clk_mout_aclk_300_gscl_mid1 = {
+ .clk = {
+ .name = "mout_aclk_300_gscl_mid1",
+ },
+ .sources = &exynos5_clkset_mid1,
+ .reg_src = { .reg = EXYNOS5_CLKSRC_TOP1, .shift = 12, .size = 1 },
+};
+
+/* For ACLK_300_gscl */
+struct clk *exynos5_clkset_aclk_300_gscl_list[] = {
+ [0] = &exynos5_clk_mout_aclk_300_gscl_mid.clk,
+ [1] = &exynos5_clk_mout_aclk_300_gscl_mid1.clk,
+};
+
+struct clksrc_sources exynos5_clkset_aclk_300_gscl = {
+ .sources = exynos5_clkset_aclk_300_gscl_list,
+ .nr_sources = ARRAY_SIZE(exynos5_clkset_aclk_300_gscl_list),
+};
+
+static struct clksrc_clk exynos5_clk_mout_aclk_300_gscl = {
+ .clk = {
+ .name = "mout_aclk_300_gscl",
+ },
+ .sources = &exynos5_clkset_aclk_300_gscl,
+ .reg_src = { .reg = EXYNOS5_CLKSRC_TOP0, .shift = 25, .size = 1 },
+};
+
+static struct clksrc_clk exynos5_clk_dout_aclk_300_gscl = {
+ .clk = {
+ .name = "dout_aclk_300_gscl",
+ .parent = &exynos5_clk_mout_aclk_300_gscl.clk,
+ },
+ .reg_div = { .reg = EXYNOS5_CLKDIV_TOP1, .shift = 12, .size = 3 },
+};
+
+/* Possible clock sources for aclk_300_gscl_sub Mux */
+static struct clk *clk_src_gscl_300_list[] = {
+ [0] = &clk_ext_xtal_mux,
+ [1] = &exynos5_clk_dout_aclk_300_gscl.clk,
+};
+
+static struct clksrc_sources clk_src_gscl_300 = {
+ .sources = clk_src_gscl_300_list,
+ .nr_sources = ARRAY_SIZE(clk_src_gscl_300_list),
+};
+
+static struct clksrc_clk exynos5_clk_aclk_300_gscl = {
+ .clk = {
+ .name = "aclk_300_gscl",
+ },
+ .sources = &clk_src_gscl_300,
+ .reg_src = { .reg = EXYNOS5_CLKSRC_TOP3, .shift = 10, .size = 1 },
+};
+
static struct clksrc_clk exynos5_clk_aclk_266 = {
.clk = {
.name = "aclk_266",
@@ -420,6 +882,7 @@
static struct clksrc_clk exynos5_clk_aclk_200 = {
.clk = {
.name = "aclk_200",
+ .parent = &exynos5_clk_mout_mpll_user.clk,
},
.sources = &exynos5_clkset_aclk,
.reg_src = { .reg = EXYNOS5_CLKSRC_TOP0, .shift = 12, .size = 1 },
@@ -442,6 +905,39 @@
.reg_div = { .reg = EXYNOS5_CLKDIV_TOP0, .shift = 0, .size = 3 },
};
+/* Possible clock sources for aclk_200_disp1_sub Mux */
+static struct clk *clk_src_disp1_200_list[] = {
+ [0] = &clk_ext_xtal_mux,
+ [1] = &exynos5_clk_aclk_200.clk,
+};
+
+static struct clksrc_sources clk_src_disp1_200 = {
+ .sources = clk_src_disp1_200_list,
+ .nr_sources = ARRAY_SIZE(clk_src_disp1_200_list),
+};
+
+/* For CLKOUT */
+struct clk *exynos5_clkset_clk_clkout_list[] = {
+ /* Others are for debugging */
+ [16] = &clk_xxti,
+ [17] = &clk_xusbxti,
+};
+
+struct clksrc_sources exynos5_clkset_clk_clkout = {
+ .sources = exynos5_clkset_clk_clkout_list,
+ .nr_sources = ARRAY_SIZE(exynos5_clkset_clk_clkout_list),
+};
+
+static struct clksrc_clk exynos5_clk_clkout = {
+ .clk = {
+ .name = "clkout",
+ .enable = exynos5_clk_clkout_ctrl,
+ .ctrlbit = (1 << 0),
+ },
+ .sources = &exynos5_clkset_clk_clkout,
+ .reg_src = { .reg = EXYNOS_PMU_DEBUG, .shift = 8, .size = 5 },
+};
+
static struct clk exynos5_init_clocks_off[] = {
{
.name = "timers",
@@ -449,11 +945,46 @@
.enable = exynos5_clk_ip_peric_ctrl,
.ctrlbit = (1 << 24),
}, {
+ .name = "hdmicec",
+ .parent = &exynos5_clk_aclk_66.clk,
+ .enable = exynos5_clk_ip_peris_ctrl,
+ .ctrlbit = (1 << 16),
+ }, {
+ .name = "watchdog",
+ .parent = &exynos5_clk_aclk_66.clk,
+ .enable = exynos5_clk_ip_peris_ctrl,
+ .ctrlbit = (1 << 19),
+ }, {
.name = "rtc",
.parent = &exynos5_clk_aclk_66.clk,
.enable = exynos5_clk_ip_peris_ctrl,
.ctrlbit = (1 << 20),
}, {
+ .name = "pkey0",
+ .parent = &exynos5_clk_aclk_66.clk,
+ .enable = exynos5_clk_ip_peris_ctrl,
+ .ctrlbit = (1 << 22),
+ }, {
+ .name = "pkey1",
+ .parent = &exynos5_clk_aclk_66.clk,
+ .enable = exynos5_clk_ip_peris_ctrl,
+ .ctrlbit = (1 << 23),
+ }, {
+ .name = "monocnt",
+ .parent = &exynos5_clk_aclk_66.clk,
+ .enable = exynos5_clk_ip_peris_ctrl,
+ .ctrlbit = (1 << 24),
+ }, {
+ .name = "mipihsi",
+ .parent = &exynos5_clk_aclk_200.clk,
+ .enable = exynos5_clk_ip_fsys_ctrl,
+ .ctrlbit = (1 << 8),
+ }, {
+ .name = "rtic",
+ .parent = &exynos5_clk_aclk_200.clk,
+ .enable = exynos5_clk_ip_fsys_ctrl,
+ .ctrlbit = ((1 << 11) | (1 << 9)),
+ }, {
.name = "hsmmc",
.devname = "exynos4-sdhci.0",
.parent = &exynos5_clk_aclk_200.clk,
@@ -483,6 +1014,11 @@
.enable = exynos5_clk_ip_fsys_ctrl,
.ctrlbit = (1 << 16),
}, {
+ .name = "sromc",
+ .parent = &exynos5_clk_aclk_200.clk,
+ .enable = exynos5_clk_ip_fsys_ctrl,
+ .ctrlbit = (1 << 17),
+ }, {
.name = "sata",
.devname = "ahci",
.enable = exynos5_clk_ip_fsys_ctrl,
@@ -496,24 +1032,100 @@
.enable = exynos5_clk_ip_fsys_ctrl,
.ctrlbit = (1 << 25),
}, {
+ .name = "fimd",
+ .devname = "exynos5-fb.1",
+ .enable = exynos5_clk_ip_disp1_ctrl,
+ .ctrlbit = ((0x7 << 10) | (1 << 0)),
+ }, {
+ .name = "dp",
+ .devname = "s5p-dp",
+ .enable = exynos5_clk_ip_disp1_ctrl,
+ .ctrlbit = (1 << 4),
+ }, {
.name = "mfc",
.devname = "s5p-mfc",
.enable = exynos5_clk_ip_mfc_ctrl,
- .ctrlbit = (1 << 0),
+ .ctrlbit = ((1 << 4) | (1 << 3) | (1 << 0)),
}, {
+ .name = "g3d",
+ .devname = "mali.0",
+ .enable = exynos5_clk_ip_g3d_ctrl,
+ .ctrlbit = ((1 << 1) | (1 << 0)),
+ }, {
+ .name = "isp0",
+ .devname = FIMC_IS_MODULE_NAME,
+ .enable = exynos5_clk_ip_isp0_ctrl,
+ .ctrlbit = (0xDFFFC0FF << 0),
+ }, {
+ .name = "isp1",
+ .devname = FIMC_IS_MODULE_NAME,
+ .enable = exynos5_clk_ip_isp1_ctrl,
+ .ctrlbit = (0x3F07 << 0),
+ },{
.name = "hdmi",
- .devname = "exynos4-hdmi",
+ .devname = "exynos5-hdmi",
.enable = exynos5_clk_ip_disp1_ctrl,
.ctrlbit = (1 << 6),
}, {
.name = "mixer",
.devname = "s5p-mixer",
.enable = exynos5_clk_ip_disp1_ctrl,
+ .ctrlbit = ((0xf << 13) | (1 << 5)),
+ }, {
+ .name = "fimc-lite.0",
+ .enable = exynos5_clk_ip_gscl_ctrl,
+ .ctrlbit = ((1 << 13) | (1 << 0)),
+ }, {
+ .name = "fimc-lite.1",
+ .enable = exynos5_clk_ip_gscl_ctrl,
+ .ctrlbit = ((1 << 14) | (1 << 0)),
+ }, {
+ .name = "gscl",
+ .devname = "exynos-gsc.0",
+ .enable = exynos5_clk_ip_gscl_ctrl,
+ .ctrlbit = ((1 << 15) | (1 << 0)),
+ }, {
+ .name = "gscl",
+ .devname = "exynos-gsc.1",
+ .enable = exynos5_clk_ip_gscl_ctrl,
+ .ctrlbit = ((1 << 16) | (1 << 1)),
+ }, {
+ .name = "gscl",
+ .devname = "exynos-gsc.2",
+ .enable = exynos5_clk_ip_gscl_ctrl,
+ .ctrlbit = ((1 << 17) | (1 << 2)),
+ }, {
+ .name = "gscl",
+ .devname = "exynos-gsc.3",
+ .enable = exynos5_clk_ip_gscl_ctrl,
+ .ctrlbit = ((1 << 18) | (1 << 3)),
+ }, {
+ .name = "camif_top",
+ .enable = exynos5_clk_ip_gscl_ctrl,
+ .ctrlbit = (1 << 4),
+ }, {
+ .name = "gscl_wrap0",
+ .devname = "s5p-mipi-csis.0",
+ .enable = exynos5_clk_ip_gscl_ctrl,
.ctrlbit = (1 << 5),
}, {
+ .name = "gscl_wrap1",
+ .devname = "s5p-mipi-csis.1",
+ .enable = exynos5_clk_ip_gscl_ctrl,
+ .ctrlbit = (1 << 6),
+ }, {
+ .name = "rotator",
+ .devname = "exynos-rot",
+ .enable = exynos5_clk_ip_gen_ctrl,
+ .ctrlbit = ((1 << 11) | (1 << 1)),
+ }, {
.name = "jpeg",
.enable = exynos5_clk_ip_gen_ctrl,
- .ctrlbit = (1 << 2),
+ .ctrlbit = ((1 << 12) | (1 << 2)),
+ }, {
+ .name = "smmu_mdma1",
+ .enable = exynos5_clk_ip_gen_ctrl,
+ .ctrlbit = (1 << 9),
}, {
.name = "dsim0",
.enable = exynos5_clk_ip_disp1_ctrl,
@@ -549,17 +1161,38 @@
.enable = exynos5_clk_ip_peric_ctrl,
.ctrlbit = (1 << 27),
}, {
+ .name = "uis",
+ .devname = "exynos-uis.0",
+ .enable = exynos5_clk_ip_peric_ctrl,
+ .ctrlbit = (1 << 28),
+ }, {
+ .name = "uis",
+ .devname = "exynos-uis.1",
+ .enable = exynos5_clk_ip_peric_ctrl,
+ .ctrlbit = (1 << 29),
+ }, {
+ .name = "uis",
+ .devname = "exynos-uis.2",
+ .enable = exynos5_clk_ip_peric_ctrl,
+ .ctrlbit = (1 << 30),
+ }, {
+ .name = "uis",
+ .devname = "exynos-uis.3",
+ .enable = exynos5_clk_ip_peric_ctrl,
+ .ctrlbit = (1 << 31),
+ }, {
.name = "usbhost",
- .enable = exynos5_clk_ip_fsys_ctrl ,
+ .enable = exynos5_clk_ip_fsys_ctrl,
.ctrlbit = (1 << 18),
}, {
.name = "usbotg",
.enable = exynos5_clk_ip_fsys_ctrl,
.ctrlbit = (1 << 7),
}, {
- .name = "gps",
- .enable = exynos5_clk_ip_gps_ctrl,
- .ctrlbit = ((1 << 3) | (1 << 2) | (1 << 0)),
+ .name = "usbdrd30",
+ .parent = &exynos5_clk_aclk_200.clk,
+ .enable = exynos5_clk_ip_fsys_ctrl,
+ .ctrlbit = (1 << 19),
}, {
.name = "nfcon",
.enable = exynos5_clk_ip_fsys_ctrl,
@@ -626,44 +1259,142 @@
.ctrlbit = (1 << 13),
}, {
.name = "i2c",
- .devname = "s3c2440-hdmiphy-i2c",
+ .devname = "s3c2440-i2c.8",
.parent = &exynos5_clk_aclk_66.clk,
.enable = exynos5_clk_ip_peric_ctrl,
.ctrlbit = (1 << 14),
+ }, {
+ .name = "adc",
+ .parent = &exynos5_clk_aclk_66.clk,
+ .enable = exynos5_clk_ip_peric_ctrl,
+ .ctrlbit = (1 << 15),
+ }, {
+ .name = SYSMMU_CLOCK_NAME,
+ .devname = SYSMMU_CLOCK_DEVNAME(mfc_lr, 0),
+ .enable = &exynos5_clk_ip_mfc_ctrl,
+ .ctrlbit = (3 << 1),
+ }, {
+ .name = SYSMMU_CLOCK_NAME,
+ .devname = SYSMMU_CLOCK_DEVNAME(tv, 2),
+ .enable = &exynos5_clk_ip_disp1_ctrl,
+ .ctrlbit = (1 << 9)
+ }, {
+ .name = SYSMMU_CLOCK_NAME,
+ .devname = SYSMMU_CLOCK_DEVNAME(jpeg, 3),
+ .enable = &exynos5_clk_ip_gen_ctrl,
+ .ctrlbit = (1 << 7),
+ }, {
+ .name = SYSMMU_CLOCK_NAME,
+ .devname = SYSMMU_CLOCK_DEVNAME(rot, 4),
+ .enable = &exynos5_clk_ip_gen_ctrl,
+ .ctrlbit = (1 << 6)
+ }, {
+ .name = SYSMMU_CLOCK_NAME,
+ .devname = SYSMMU_CLOCK_DEVNAME(gsc0, 5),
+ .enable = &exynos5_clk_ip_gscl_ctrl,
+ .ctrlbit = (1 << 7),
+ }, {
+ .name = SYSMMU_CLOCK_NAME,
+ .devname = SYSMMU_CLOCK_DEVNAME(gsc1, 6),
+ .enable = &exynos5_clk_ip_gscl_ctrl,
+ .ctrlbit = (1 << 8),
+ }, {
+ .name = SYSMMU_CLOCK_NAME,
+ .devname = SYSMMU_CLOCK_DEVNAME(gsc2, 7),
+ .enable = &exynos5_clk_ip_gscl_ctrl,
+ .ctrlbit = (1 << 9),
+ }, {
+ .name = SYSMMU_CLOCK_NAME,
+ .devname = SYSMMU_CLOCK_DEVNAME(gsc3, 8),
+ .enable = &exynos5_clk_ip_gscl_ctrl,
+ .ctrlbit = (1 << 10),
+ }, {
+ .name = SYSMMU_CLOCK_NAME,
+ .devname = SYSMMU_CLOCK_DEVNAME(isp, 9),
+ .enable = &exynos5_clk_ip_isp0_ctrl,
+ .ctrlbit = (0x3F << 8),
+ }, {
+ .name = SYSMMU_CLOCK_NAME2,
+ .devname = SYSMMU_CLOCK_DEVNAME(isp, 9),
+ .enable = &exynos5_clk_ip_isp1_ctrl,
+ .ctrlbit = (0xF << 4),
+ }, {
+ .name = SYSMMU_CLOCK_NAME3,
+ .devname = SYSMMU_CLOCK_DEVNAME(isp, 9),
+ .enable = &exynos5_clk_ip_gscl_ctrl,
+ .ctrlbit = (0x203 << 11),
+ }, {
+ .name = SYSMMU_CLOCK_NAME,
+ .devname = SYSMMU_CLOCK_DEVNAME(2d, 15),
+ .enable = &exynos5_clk_ip_acp_ctrl,
+ .ctrlbit = (1 << 7)
+ }, {
+ .name = "fimg2d",
+ .devname = "s5p-fimg2d",
+ .enable = exynos5_clk_ip_acp_ctrl,
+ .ctrlbit = (1 << 3),
+ }, {
+ .name = "spi",
+ .devname = "s3c64xx-spi.0",
+ .enable = exynos5_clk_ip_peric_ctrl,
+ .ctrlbit = (1 << 16),
+ }, {
+ .name = "spi",
+ .devname = "s3c64xx-spi.1",
+ .enable = exynos5_clk_ip_peric_ctrl,
+ .ctrlbit = (1 << 17),
+ }, {
+ .name = "spi",
+ .devname = "s3c64xx-spi.2",
+ .enable = exynos5_clk_ip_peric_ctrl,
+ .ctrlbit = (1 << 18),
+ }, {
+ .name = "efclk",
+ .enable = exynos5_clk_bus_syslft_ctrl,
+ .ctrlbit = (1 << 16),
+ }, {
+ .name = "mdma",
+ .enable = exynos5_clk_ip_acp_ctrl,
+ .ctrlbit = ((1 << 1) | (1 << 8)),
}
};
static struct clk exynos5_init_clocks_on[] = {
{
.name = "uart",
- .devname = "s5pv210-uart.0",
+ .devname = "exynos4210-uart.0",
.enable = exynos5_clk_ip_peric_ctrl,
.ctrlbit = (1 << 0),
}, {
.name = "uart",
- .devname = "s5pv210-uart.1",
+ .devname = "exynos4210-uart.1",
.enable = exynos5_clk_ip_peric_ctrl,
.ctrlbit = (1 << 1),
}, {
.name = "uart",
- .devname = "s5pv210-uart.2",
+ .devname = "exynos4210-uart.2",
.enable = exynos5_clk_ip_peric_ctrl,
.ctrlbit = (1 << 2),
}, {
.name = "uart",
- .devname = "s5pv210-uart.3",
+ .devname = "exynos4210-uart.3",
.enable = exynos5_clk_ip_peric_ctrl,
.ctrlbit = (1 << 3),
}, {
.name = "uart",
- .devname = "s5pv210-uart.4",
+ .devname = "exynos4210-uart.4",
.enable = exynos5_clk_ip_peric_ctrl,
.ctrlbit = (1 << 4),
}, {
.name = "uart",
- .devname = "s5pv210-uart.5",
+ .devname = "exynos4210-uart.5",
.enable = exynos5_clk_ip_peric_ctrl,
.ctrlbit = (1 << 5),
+ }, {
+ .name = "secss",
+ .parent = &exynos5_clk_aclk_acp.clk,
+ .enable = exynos5_clk_ip_acp_ctrl,
+ .ctrlbit = (1 << 2),
}
};
@@ -685,7 +1416,134 @@
.name = "dma",
.devname = "dma-pl330.2",
.enable = exynos5_clk_ip_gen_ctrl,
- .ctrlbit = (1 << 4),
+ .ctrlbit = ((1 << 4) | (1 << 14)),
+};
+
+static struct clk exynos5_c2c_clock = {
+ .name = "c2c",
+ .devname = "samsung-c2c",
+ .enable = exynos5_clk_ip_sysrgt_ctrl,
+ .ctrlbit = ((1 << 2) | (1 << 1)),
+};
+
+static struct clk *clkset_sclk_audio0_list[] = {
+ [0] = &exynos5_clk_audiocdclk0.clk,
+ [1] = &clk_ext_xtal_mux,
+ [2] = &exynos5_clk_sclk_hdmi27m,
+ [3] = &exynos5_clk_sclk_dptxphy,
+ [4] = &exynos5_clk_sclk_usbphy,
+ [5] = &exynos5_clk_sclk_hdmiphy,
+ [6] = &exynos5_clk_mout_mpll.clk,
+ [7] = &exynos5_clk_mout_epll.clk,
+ [8] = &exynos5_clk_sclk_vpll.clk,
+ [9] = &exynos5_clk_mout_cpll.clk,
+};
+
+static struct clksrc_sources exynos5_clkset_sclk_audio0 = {
+ .sources = clkset_sclk_audio0_list,
+ .nr_sources = ARRAY_SIZE(clkset_sclk_audio0_list),
+};
+
+static struct clksrc_clk exynos5_clk_sclk_audio0 = {
+ .clk = {
+ .name = "sclk_audio",
+ .enable = exynos5_clksrc_mask_maudio_ctrl,
+ .ctrlbit = (1 << 0),
+ },
+ .sources = &exynos5_clkset_sclk_audio0,
+ .reg_src = { .reg = EXYNOS5_CLKSRC_MAUDIO, .shift = 0, .size = 4 },
+ .reg_div = { .reg = EXYNOS5_CLKDIV_MAUDIO, .shift = 0, .size = 4 },
+};
+
+static struct clk *exynos5_clkset_sclk_audio1_list[] = {
+ [0] = &exynos5_clk_audiocdclk1,
+ [1] = &clk_ext_xtal_mux,
+ [2] = &exynos5_clk_sclk_hdmi27m,
+ [3] = &exynos5_clk_sclk_dptxphy,
+ [4] = &exynos5_clk_sclk_usbphy,
+ [5] = &exynos5_clk_sclk_hdmiphy,
+ [6] = &exynos5_clk_mout_mpll.clk,
+ [7] = &exynos5_clk_mout_epll.clk,
+ [8] = &exynos5_clk_sclk_vpll.clk,
+ [9] = &exynos5_clk_mout_cpll.clk,
+};
+
+static struct clksrc_sources exynos5_clkset_sclk_audio1 = {
+ .sources = exynos5_clkset_sclk_audio1_list,
+ .nr_sources = ARRAY_SIZE(exynos5_clkset_sclk_audio1_list),
+};
+
+static struct clksrc_clk exynos5_clk_sclk_audio1 = {
+ .clk = {
+ .name = "sclk_audio1",
+ .enable = exynos5_clksrc_mask_peric1_ctrl,
+ .ctrlbit = (1 << 0),
+ },
+ .sources = &exynos5_clkset_sclk_audio1,
+ .reg_src = { .reg = EXYNOS5_CLKSRC_PERIC1, .shift = 0, .size = 4 },
+ .reg_div = { .reg = EXYNOS5_CLKDIV_PERIC4, .shift = 0, .size = 4 },
+};
+
+static struct clk *exynos5_clkset_sclk_audio2_list[] = {
+ [0] = &exynos5_clk_audiocdclk2,
+ [1] = &clk_ext_xtal_mux,
+ [2] = &exynos5_clk_sclk_hdmi27m,
+ [3] = &exynos5_clk_sclk_dptxphy,
+ [4] = &exynos5_clk_sclk_usbphy,
+ [5] = &exynos5_clk_sclk_hdmiphy,
+ [6] = &exynos5_clk_mout_mpll.clk,
+ [7] = &exynos5_clk_mout_epll.clk,
+ [8] = &exynos5_clk_sclk_vpll.clk,
+ [9] = &exynos5_clk_mout_cpll.clk,
+};
+
+static struct clksrc_sources exynos5_clkset_sclk_audio2 = {
+ .sources = exynos5_clkset_sclk_audio2_list,
+ .nr_sources = ARRAY_SIZE(exynos5_clkset_sclk_audio2_list),
+};
+
+static struct clksrc_clk exynos5_clk_sclk_audio2 = {
+ .clk = {
+ .name = "sclk_audio2",
+ .enable = exynos5_clksrc_mask_peric1_ctrl,
+ .ctrlbit = (1 << 4),
+ },
+ .sources = &exynos5_clkset_sclk_audio2,
+ .reg_src = { .reg = EXYNOS5_CLKSRC_PERIC1, .shift = 4, .size = 4 },
+ .reg_div = { .reg = EXYNOS5_CLKDIV_PERIC4, .shift = 16, .size = 4 },
+};
+
+static struct clk *exynos5_clkset_sclk_spdif_list[] = {
+ [0] = &exynos5_clk_sclk_audio0.clk,
+ [1] = &exynos5_clk_sclk_audio1.clk,
+ [2] = &exynos5_clk_sclk_audio2.clk,
+ [3] = &exynos5_clk_spdifcdclk,
+};
+
+static struct clksrc_sources exynos5_clkset_sclk_spdif = {
+ .sources = exynos5_clkset_sclk_spdif_list,
+ .nr_sources = ARRAY_SIZE(exynos5_clkset_sclk_spdif_list),
+};
+
+static struct clksrc_clk exynos5_clk_sclk_spdif = {
+ .clk = {
+ .name = "sclk_spdif",
+ .enable = exynos5_clksrc_mask_peric1_ctrl,
+ .ctrlbit = (1 << 8),
+ .ops = &s5p_sclk_spdif_ops,
+ },
+ .sources = &exynos5_clkset_sclk_spdif,
+ .reg_src = { .reg = EXYNOS5_CLKSRC_PERIC1, .shift = 8, .size = 2 },
+};
+
+struct clk *exynos5_clkset_usbdrd30_list[] = {
+ [0] = &exynos5_clk_mout_mpll.clk,
+ [1] = &exynos5_clk_mout_cpll.clk,
+};
+
+struct clksrc_sources exynos5_clkset_usbdrd30 = {
+ .sources = exynos5_clkset_usbdrd30_list,
+ .nr_sources = ARRAY_SIZE(exynos5_clkset_usbdrd30_list),
};
struct clk *exynos5_clkset_group_list[] = {
@@ -717,6 +1575,58 @@
.nr_sources = ARRAY_SIZE(clk_src_gscl_266_list),
};
+/* For ACLK_400_ISP */
+static struct clksrc_clk exynos5_clk_mout_aclk_400_isp = {
+ .clk = {
+ .name = "mout_aclk_400_isp",
+ },
+ .sources = &exynos5_clkset_aclk,
+ .reg_src = { .reg = EXYNOS5_CLKSRC_TOP1, .shift = 24, .size = 1 },
+};
+
+static struct clksrc_clk exynos5_clk_dout_aclk_400_isp = {
+ .clk = {
+ .name = "dout_aclk_400_isp",
+ .parent = &exynos5_clk_mout_aclk_400_isp.clk,
+ },
+ .reg_div = { .reg = EXYNOS5_CLKDIV_TOP1, .shift = 20, .size = 3 },
+};
+
+static struct clk *exynos5_clkset_aclk_400_isp_list[] = {
+ [0] = &clk_ext_xtal_mux,
+ [1] = &exynos5_clk_dout_aclk_400_isp.clk,
+};
+
+static struct clksrc_sources exynos5_clkset_aclk_400_isp = {
+ .sources = exynos5_clkset_aclk_400_isp_list,
+ .nr_sources = ARRAY_SIZE(exynos5_clkset_aclk_400_isp_list),
+};
+
+static struct clksrc_clk exynos5_clk_aclk_400_isp = {
+ .clk = {
+ .name = "aclk_400_isp",
+ },
+ .sources = &exynos5_clkset_aclk_400_isp,
+ .reg_src = { .reg = EXYNOS5_CLKSRC_TOP3, .shift = 20, .size = 1 },
+};
+
+static struct clksrc_clk exynos5_clk_sclk_uart_isp = {
+ .clk = {
+ .name = "sclk_uart_src_isp",
+ },
+ .sources = &exynos5_clkset_group,
+ .reg_src = { .reg = EXYNOS5_SCLK_SRC_ISP, .shift = 8, .size = 4 },
+};
+
+static struct clksrc_clk exynos5_clk_aclk_266_isp = {
+ .clk = {
+ .name = "aclk_266_isp",
+
+ },
+ .sources = &clk_src_gscl_266,
+ .reg_src = { .reg = EXYNOS5_CLKSRC_TOP3, .shift = 16, .size = 1 },
+};
+
static struct clksrc_clk exynos5_clk_dout_mmc0 = {
.clk = {
.name = "dout_mmc0",
@@ -854,6 +1764,148 @@
.reg_div = { .reg = EXYNOS5_CLKDIV_FSYS2, .shift = 24, .size = 8 },
};
+static struct clksrc_clk exynos5_clk_dout_spi0 = {
+ .clk = {
+ .name = "dout_spi0",
+ },
+ .sources = &exynos5_clkset_group,
+ .reg_src = { .reg = EXYNOS5_CLKSRC_PERIC1, .shift = 16, .size = 4 },
+ .reg_div = { .reg = EXYNOS5_CLKDIV_PERIC1, .shift = 0, .size = 4 },
+};
+
+static struct clksrc_clk exynos5_clk_dout_spi1 = {
+ .clk = {
+ .name = "dout_spi1",
+ },
+ .sources = &exynos5_clkset_group,
+ .reg_src = { .reg = EXYNOS5_CLKSRC_PERIC1, .shift = 20, .size = 4 },
+ .reg_div = { .reg = EXYNOS5_CLKDIV_PERIC1, .shift = 16, .size = 4 },
+};
+
+static struct clksrc_clk exynos5_clk_dout_spi2 = {
+ .clk = {
+ .name = "dout_spi2",
+ },
+ .sources = &exynos5_clkset_group,
+ .reg_src = { .reg = EXYNOS5_CLKSRC_PERIC1, .shift = 24, .size = 4 },
+ .reg_div = { .reg = EXYNOS5_CLKDIV_PERIC2, .shift = 0, .size = 4 },
+};
+
+static struct clksrc_clk exynos5_clk_sclk_spi0 = {
+ .clk = {
+ .name = "sclk_spi",
+ .devname = "s3c64xx-spi.0",
+ .parent = &exynos5_clk_dout_spi0.clk,
+ .enable = exynos5_clksrc_mask_peric1_ctrl,
+ .ctrlbit = (1 << 16),
+ },
+ .reg_div = { .reg = EXYNOS5_CLKDIV_PERIC1, .shift = 8, .size = 8 },
+};
+
+static struct clksrc_clk exynos5_clk_sclk_spi1 = {
+ .clk = {
+ .name = "sclk_spi",
+ .devname = "s3c64xx-spi.1",
+ .parent = &exynos5_clk_dout_spi1.clk,
+ .enable = exynos5_clksrc_mask_peric1_ctrl,
+ .ctrlbit = (1 << 20),
+ },
+ .reg_div = { .reg = EXYNOS5_CLKDIV_PERIC1, .shift = 24, .size = 8 },
+};
+
+static struct clksrc_clk exynos5_clk_sclk_spi2 = {
+ .clk = {
+ .name = "sclk_spi",
+ .devname = "s3c64xx-spi.2",
+ .parent = &exynos5_clk_dout_spi2.clk,
+ .enable = exynos5_clksrc_mask_peric1_ctrl,
+ .ctrlbit = (1 << 24),
+ },
+ .reg_div = { .reg = EXYNOS5_CLKDIV_PERIC2, .shift = 8, .size = 8 },
+};
+
+static struct clksrc_clk exynos5_clk_aclk_266_isp_div0 = {
+ .clk = {
+ .name = "aclk_266_isp_div0",
+ .parent = &exynos5_clk_aclk_266_isp.clk,
+ },
+ .reg_div = { .reg = EXYNOS5_CLKDIV_ISP0, .shift = 0, .size = 3 },
+};
+
+static struct clksrc_clk exynos5_clk_aclk_266_isp_div1 = {
+ .clk = {
+ .name = "aclk_266_isp_div1",
+ .parent = &exynos5_clk_aclk_266_isp.clk,
+ },
+ .reg_div = { .reg = EXYNOS5_CLKDIV_ISP0, .shift = 4, .size = 3 },
+};
+
+static struct clksrc_clk exynos5_clk_aclk_266_isp_divmpwm = {
+ .clk = {
+ .name = "aclk_266_isp_divmpwm",
+ .parent = &exynos5_clk_aclk_266_isp_div1.clk,
+ },
+ .reg_div = { .reg = EXYNOS5_CLKDIV_ISP2, .shift = 0, .size = 3 },
+};
+
+static struct clksrc_clk exynos5_clk_aclk_400_isp_div0 = {
+ .clk = {
+ .name = "aclk_400_isp_div0",
+ .parent = &exynos5_clk_aclk_400_isp.clk,
+ },
+ .reg_div = { .reg = EXYNOS5_CLKDIV_ISP1, .shift = 0, .size = 3 },
+};
+
+static struct clksrc_clk exynos5_clk_aclk_400_isp_div1 = {
+ .clk = {
+ .name = "aclk_400_isp_div1",
+ .parent = &exynos5_clk_aclk_400_isp.clk,
+ },
+ .reg_div = { .reg = EXYNOS5_CLKDIV_ISP1, .shift = 4, .size = 3 },
+};
+
+static struct clksrc_clk exynos5_clk_aclk_200_disp1 = {
+ .clk = {
+ .name = "aclk_200_disp1",
+ .parent = &exynos5_clk_aclk_200.clk,
+ },
+ .sources = &clk_src_disp1_200,
+ .reg_src = { .reg = EXYNOS5_CLKSRC_TOP3, .shift = 4, .size = 1 },
+};
+
+static struct clksrc_clk exynos5_clk_pclk_100_disp1 = {
+ .clk = {
+ .name = "pclk_100_disp1",
+ .parent = &exynos5_clk_aclk_200_disp1.clk,
+ },
+ .reg_div = { .reg = EXYNOS5_CLKDIV2_RATIO0, .shift = 16, .size = 2 },
+};
+
+static struct clksrc_clk exynos5_clk_aclk_266_gscl = {
+ .clk = {
+ .name = "aclk_266_gscl",
+ .parent = &exynos5_clk_aclk_266.clk,
+ },
+ .sources = &clk_src_gscl_266,
+ .reg_src = { .reg = EXYNOS5_CLKSRC_TOP3, .shift = 8, .size = 1 },
+};
+
+static struct clksrc_clk exynos5_clk_pclk_133_gscl = {
+ .clk = {
+ .name = "pclk_133_gscl",
+ .parent = &exynos5_clk_aclk_266_gscl.clk,
+ },
+ .reg_div = { .reg = EXYNOS5_CLKDIV2_RATIO0, .shift = 4, .size = 2 },
+};
+
+static struct clksrc_clk exynos5_clk_pclk_83_mfc = {
+ .clk = {
+ .name = "pclk_83_mfc",
+ .parent = &exynos5_clk_aclk_333.clk,
+ },
+ .reg_div = { .reg = EXYNOS5_CLKDIV4_RATIO, .shift = 0, .size = 2 },
+};
+
static struct clksrc_clk exynos5_clksrcs[] = {
{
.clk = {
@@ -866,7 +1918,7 @@
}, {
.clk = {
.name = "sclk_fimd",
- .devname = "s3cfb.1",
+ .devname = "exynos5-fb.1",
.enable = exynos5_clksrc_mask_disp1_0_ctrl,
.ctrlbit = (1 << 0),
},
@@ -874,15 +1926,9 @@
.reg_src = { .reg = EXYNOS5_CLKSRC_DISP1_0, .shift = 0, .size = 4 },
.reg_div = { .reg = EXYNOS5_CLKDIV_DISP1_0, .shift = 0, .size = 4 },
}, {
- .clk = {
- .name = "aclk_266_gscl",
- },
- .sources = &clk_src_gscl_266,
- .reg_src = { .reg = EXYNOS5_CLKSRC_TOP3, .shift = 8, .size = 1 },
- }, {
- .clk = {
+ .clk = {
.name = "sclk_g3d",
- .devname = "mali-t604.0",
+ .devname = "mali.0",
.enable = exynos5_clk_block_ctrl,
.ctrlbit = (1 << 1),
},
@@ -891,7 +1937,7 @@
.reg_div = { .reg = EXYNOS5_CLKDIV_TOP0, .shift = 24, .size = 3 },
}, {
.clk = {
- .name = "sclk_gscl_wrap",
+ .name = "sclk_gscl_wrap0",
.devname = "s5p-mipi-csis.0",
.enable = exynos5_clksrc_mask_gscl_ctrl,
.ctrlbit = (1 << 24),
@@ -901,7 +1947,7 @@
.reg_div = { .reg = EXYNOS5_CLKDIV_GSCL, .shift = 24, .size = 4 },
}, {
.clk = {
- .name = "sclk_gscl_wrap",
+ .name = "sclk_gscl_wrap1",
.devname = "s5p-mipi-csis.1",
.enable = exynos5_clksrc_mask_gscl_ctrl,
.ctrlbit = (1 << 28),
@@ -911,6 +1957,15 @@
.reg_div = { .reg = EXYNOS5_CLKDIV_GSCL, .shift = 28, .size = 4 },
}, {
.clk = {
+ .name = "sclk_bayer",
+ .enable = exynos5_clksrc_mask_gscl_ctrl,
+ .ctrlbit = (1 << 12),
+ },
+ .sources = &exynos5_clkset_group,
+ .reg_src = { .reg = EXYNOS5_CLKSRC_GSCL, .shift = 12, .size = 4 },
+ .reg_div = { .reg = EXYNOS5_CLKDIV_GSCL, .shift = 12, .size = 4 },
+ }, {
+ .clk = {
.name = "sclk_cam0",
.enable = exynos5_clksrc_mask_gscl_ctrl,
.ctrlbit = (1 << 16),
@@ -930,9 +1985,27 @@
}, {
.clk = {
.name = "sclk_jpeg",
- .parent = &exynos5_clk_mout_cpll.clk,
+ .enable = exynos5_clksrc_mask_gen_ctrl,
+ .ctrlbit = (1 << 0),
},
- .reg_div = { .reg = EXYNOS5_CLKDIV_GEN, .shift = 4, .size = 3 },
+ .sources = &exynos5_clkset_group,
+ .reg_src = { .reg = EXYNOS5_CLKSRC_GEN, .shift = 0, .size = 4 },
+ .reg_div = { .reg = EXYNOS5_CLKDIV_GEN, .shift = 4, .size = 4 },
+ }, {
+ .clk = {
+ .name = "sclk_usbdrd30",
+ .enable = exynos5_clksrc_mask_fsys_ctrl,
+ .ctrlbit = (1 << 28),
+ },
+ .sources = &exynos5_clkset_usbdrd30,
+ .reg_src = { .reg = EXYNOS5_CLKSRC_FSYS, .shift = 28, .size = 1 },
+ .reg_div = { .reg = EXYNOS5_CLKDIV_FSYS0, .shift = 24, .size = 4 },
+ }, {
+ .clk = {
+ .name = "sclk_uart_isp",
+ .parent = &exynos5_clk_sclk_uart_isp.clk,
+ },
+ .reg_div = { .reg = EXYNOS5_SCLK_DIV_ISP, .shift = 24, .size = 4 },
},
};
@@ -940,10 +2013,13 @@
static struct clksrc_clk *exynos5_sysclks[] = {
&exynos5_clk_mout_apll,
&exynos5_clk_sclk_apll,
+ &exynos5_clk_mout_bpll_fout,
&exynos5_clk_mout_bpll,
&exynos5_clk_mout_bpll_user,
&exynos5_clk_mout_cpll,
&exynos5_clk_mout_epll,
+ &exynos5_clk_mout_gpll,
+ &exynos5_clk_mout_mpll_fout,
&exynos5_clk_mout_mpll,
&exynos5_clk_mout_mpll_user,
&exynos5_clk_vpllsrc,
@@ -951,10 +2027,15 @@
&exynos5_clk_mout_cpu,
&exynos5_clk_dout_armclk,
&exynos5_clk_dout_arm2clk,
- &exynos5_clk_cdrex,
- &exynos5_clk_aclk_400,
+ &exynos5_clk_mclk_cdrex,
+ &exynos5_clk_aclk_400_g3d_mid,
+ &exynos5_clk_aclk_400_g3d,
+ &exynos5_clk_mout_aclk_333,
+ &exynos5_clk_dout_aclk_333,
&exynos5_clk_aclk_333,
+ &exynos5_clk_aclk_266_gscl,
&exynos5_clk_aclk_266,
+ &exynos5_clk_aclk_200_disp1,
&exynos5_clk_aclk_200,
&exynos5_clk_aclk_166,
&exynos5_clk_aclk_66_pre,
@@ -966,6 +2047,25 @@
&exynos5_clk_dout_mmc4,
&exynos5_clk_aclk_acp,
&exynos5_clk_pclk_acp,
+ &exynos5_clk_mout_aclk_300_disp1_mid,
+ &exynos5_clk_mout_aclk_300_disp1_mid1,
+ &exynos5_clk_mout_aclk_300_disp1,
+ &exynos5_clk_dout_aclk_300_disp1,
+ &exynos5_clk_aclk_300_disp1,
+ &exynos5_clk_mout_aclk_300_gscl_mid,
+ &exynos5_clk_mout_aclk_300_gscl_mid1,
+ &exynos5_clk_mout_aclk_300_gscl,
+ &exynos5_clk_dout_aclk_300_gscl,
+ &exynos5_clk_aclk_300_gscl,
+ &exynos5_clk_mout_aclk_400_isp,
+ &exynos5_clk_dout_aclk_400_isp,
+ &exynos5_clk_aclk_400_isp,
+ &exynos5_clk_aclk_266_isp,
+ &exynos5_clk_sclk_uart_isp,
+ &exynos5_clk_clkout,
+ &exynos5_clk_dout_spi0,
+ &exynos5_clk_dout_spi1,
+ &exynos5_clk_dout_spi2,
};
static struct clk *exynos5_clk_cdev[] = {
@@ -983,6 +2083,24 @@
&exynos5_clk_sclk_mmc1,
&exynos5_clk_sclk_mmc2,
&exynos5_clk_sclk_mmc3,
+ &exynos5_clk_sclk_audio0,
+ &exynos5_clk_sclk_audio1,
+ &exynos5_clk_sclk_audio2,
+ &exynos5_clk_sclk_spdif,
+ &exynos5_clk_sclk_spi0,
+ &exynos5_clk_sclk_spi1,
+ &exynos5_clk_sclk_spi2,
+ &exynos5_clk_pclk_100_disp1,
+ &exynos5_clk_pclk_133_gscl,
+ &exynos5_clk_pclk_83_mfc,
+};
+
+static struct clksrc_clk *exynos5_clksrc_aclk_isp[] = {
+ &exynos5_clk_aclk_266_isp_div0,
+ &exynos5_clk_aclk_266_isp_div1,
+ &exynos5_clk_aclk_266_isp_divmpwm,
+ &exynos5_clk_aclk_400_isp_div0,
+ &exynos5_clk_aclk_400_isp_div1,
};
static struct clk_lookup exynos5_clk_lookup[] = {
@@ -997,6 +2115,9 @@
CLKDEV_INIT("dma-pl330.0", "apb_pclk", &exynos5_clk_pdma0),
CLKDEV_INIT("dma-pl330.1", "apb_pclk", &exynos5_clk_pdma1),
CLKDEV_INIT("dma-pl330.2", "apb_pclk", &exynos5_clk_mdma1),
+ CLKDEV_INIT("s3c64xx-spi.0", "spi_busclk0", &exynos5_clk_sclk_spi0.clk),
+ CLKDEV_INIT("s3c64xx-spi.1", "spi_busclk0", &exynos5_clk_sclk_spi1.clk),
+ CLKDEV_INIT("s3c64xx-spi.2", "spi_busclk0", &exynos5_clk_sclk_spi2.clk),
};
static unsigned long exynos5_epll_get_rate(struct clk *clk)
@@ -1007,9 +2128,14 @@
static struct clk *exynos5_clks[] __initdata = {
&exynos5_clk_sclk_hdmi27m,
&exynos5_clk_sclk_hdmiphy,
+ &clk_fout_bpll_div2,
&clk_fout_bpll,
&clk_fout_cpll,
+ &clk_fout_gpll,
&exynos5_clk_armclk,
+ &clk_fout_mpll_div2,
+ &exynos5_mif_clk,
+ &exynos5_int_clk,
};
static u32 epll_div[][6] = {
@@ -1093,6 +2219,120 @@
.set_rate = exynos5_epll_set_rate,
};
+
+#define APLL_FREQ(f, a0, a1, a2, a3, a4, a5, a6, a7, b0, b1, m, p, s) \
+ { \
+ .freq = (f) * 1000000, \
+ .clk_div_cpu0 = ((a0) | (a1) << 4 | (a2) << 8 | (a3) << 12 | \
+ (a4) << 16 | (a5) << 20 | (a6) << 24 | (a7) << 28), \
+ .clk_div_cpu1 = (b0 << 0 | b1 << 4), \
+ .mps = ((m) << 16 | (p) << 8 | (s)), \
+ }
+
+static struct {
+ unsigned long freq;
+ u32 clk_div_cpu0;
+ u32 clk_div_cpu1;
+ u32 mps;
+} apll_freq[] = {
+ /*
+ * values:
+ * freq
+ * clock divider for ARM, CPUD, ACP, PERIPH, ATB, PCLK_DBG, APLL, ARM2
+ * clock divider for COPY, HPM
+ * PLL M, P, S
+ */
+ APLL_FREQ(1700, 0, 3, 7, 7, 7, 2, 5, 0, 7, 7, 425, 6, 0),
+ APLL_FREQ(1600, 0, 3, 7, 7, 7, 1, 4, 0, 7, 7, 200, 3, 0),
+ APLL_FREQ(1500, 0, 2, 7, 7, 7, 1, 4, 0, 7, 7, 250, 4, 0),
+ APLL_FREQ(1400, 0, 2, 7, 7, 6, 1, 4, 0, 7, 7, 175, 3, 0),
+ APLL_FREQ(1300, 0, 2, 7, 7, 6, 1, 3, 0, 7, 7, 325, 6, 0),
+ APLL_FREQ(1200, 0, 2, 7, 7, 5, 1, 3, 0, 7, 7, 200, 4, 0),
+ APLL_FREQ(1100, 0, 3, 7, 7, 5, 1, 3, 0, 7, 7, 275, 6, 0),
+ APLL_FREQ(1000, 0, 1, 7, 7, 4, 1, 2, 0, 7, 7, 125, 3, 0),
+ APLL_FREQ(900, 0, 1, 7, 7, 4, 1, 2, 0, 7, 7, 150, 4, 0),
+ APLL_FREQ(800, 0, 1, 7, 7, 4, 1, 2, 0, 7, 7, 100, 3, 0),
+ APLL_FREQ(700, 0, 1, 7, 7, 3, 1, 1, 0, 7, 7, 175, 3, 1),
+ APLL_FREQ(600, 0, 1, 7, 7, 3, 1, 1, 0, 7, 7, 200, 4, 1),
+ APLL_FREQ(500, 0, 1, 7, 7, 2, 1, 1, 0, 7, 7, 125, 3, 1),
+ APLL_FREQ(400, 0, 1, 7, 7, 2, 1, 1, 0, 7, 7, 100, 3, 1),
+ APLL_FREQ(300, 0, 1, 7, 7, 1, 1, 1, 0, 7, 7, 200, 4, 2),
+ APLL_FREQ(200, 0, 1, 7, 7, 1, 1, 1, 0, 7, 7, 100, 3, 2),
+};
+
+static u32 exynos5_gpll_div[][6] = {
+ /*rate, P, M, S, AFC_DNB, AFC*/
+ {1400000000, 3, 175, 0, 0, 0}, /* for 466MHz */
+ {800000000, 3, 100, 0, 0, 0}, /* for 400MHz, 200MHz */
+ {667000000, 7, 389, 1, 0, 0}, /* for 333MHz, 222MHz, 166MHz */
+ {600000000, 4, 200, 1, 0, 0}, /* for 300MHz, 200MHz, 150MHz */
+ {533000000, 12, 533, 1, 0, 0}, /* for 533MHz, 266MHz, 133MHz */
+ {450000000, 12, 450, 1, 0, 0}, /* for 450 Hz */
+ {400000000, 3, 100, 1, 0, 0},
+ {333000000, 4, 222, 2, 0, 0},
+ {200000000, 3, 100, 2, 0, 0},
+};
+
+static unsigned long exynos5_gpll_get_rate(struct clk *clk)
+{
+ return clk->rate;
+}
+
+static int exynos5_gpll_set_rate(struct clk *clk, unsigned long rate)
+{
+ unsigned int gpll_con0;
+ unsigned int locktime;
+ unsigned int tmp;
+ unsigned int i;
+
+ /* Return if nothing changed */
+ if (clk->rate == rate)
+ return 0;
+
+ gpll_con0 = __raw_readl(EXYNOS5_GPLL_CON0);
+ gpll_con0 &= ~(PLL35XX_MDIV_MASK << PLL35XX_MDIV_SHIFT | \
+ PLL35XX_PDIV_MASK << PLL35XX_PDIV_SHIFT | \
+ PLL35XX_SDIV_MASK << PLL35XX_SDIV_SHIFT);
+
+ for (i = 0; i < ARRAY_SIZE(exynos5_gpll_div); i++) {
+ if (exynos5_gpll_div[i][0] == rate) {
+ gpll_con0 |= exynos5_gpll_div[i][1] << PLL35XX_PDIV_SHIFT;
+ gpll_con0 |= exynos5_gpll_div[i][2] << PLL35XX_MDIV_SHIFT;
+ gpll_con0 |= exynos5_gpll_div[i][3] << PLL35XX_SDIV_SHIFT;
+ break;
+ }
+ }
+
+ if (i == ARRAY_SIZE(exynos5_gpll_div)) {
+ printk(KERN_ERR "%s: Invalid Clock GPLL Frequency\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ /* 250 max_cycls : specification data */
+ /* 270@p=1, 1cycle=1/24=41.6ns */
+ /* calc >> p=5, 270 * 5 = 1350cycle * 41.6ns = 56.16us */
+
+ locktime = 270 * exynos5_gpll_div[i][1] + 1;
+
+ __raw_writel(locktime, EXYNOS5_GPLL_LOCK);
+
+ __raw_writel(gpll_con0, EXYNOS5_GPLL_CON0);
+
+ do {
+ tmp = __raw_readl(EXYNOS5_GPLL_CON0);
+ } while (!(tmp & EXYNOS5_GPLLCON0_LOCKED));
+
+ clk->rate = rate;
+
+ return 0;
+}
+
+static struct clk_ops exynos5_gpll_ops = {
+ .get_rate = exynos5_gpll_get_rate,
+ .set_rate = exynos5_gpll_set_rate,
+};
+
static int xtal_rate;
static unsigned long exynos5_fout_apll_get_rate(struct clk *clk)
@@ -1100,8 +2340,403 @@
return s5p_get_pll35xx(xtal_rate, __raw_readl(EXYNOS5_APLL_CON0));
}
+static void exynos5_apll_set_clkdiv(unsigned int div_index)
+{
+ unsigned int tmp;
+
+ /* Change Divider - CPU0 */
+
+ tmp = apll_freq[div_index].clk_div_cpu0;
+
+ __raw_writel(tmp, EXYNOS5_CLKDIV_CPU0);
+
+ while (__raw_readl(EXYNOS5_CLKDIV_STATCPU0) & 0x11111111)
+ cpu_relax();
+
+ /* Change Divider - CPU1 */
+ tmp = apll_freq[div_index].clk_div_cpu1;
+
+ __raw_writel(tmp, EXYNOS5_CLKDIV_CPU1);
+
+ while (__raw_readl(EXYNOS5_CLKDIV_STATCPU1) & 0x11)
+ cpu_relax();
+}
+
+static void exynos5_apll_set_apll(unsigned int index)
+{
+ unsigned int tmp, pdiv;
+
+ /* Set APLL Lock time */
+ pdiv = ((apll_freq[index].mps >> 8) & 0x3f);
+
+ __raw_writel((pdiv * 250), EXYNOS5_APLL_LOCK);
+
+ /* Change PLL PMS values */
+ tmp = __raw_readl(EXYNOS5_APLL_CON0);
+ tmp &= ~((0x3ff << 16) | (0x3f << 8) | (0x7 << 0));
+ tmp |= apll_freq[index].mps;
+ __raw_writel(tmp, EXYNOS5_APLL_CON0);
+
+ /* wait_lock_time */
+ do {
+ cpu_relax();
+ tmp = __raw_readl(EXYNOS5_APLL_CON0);
+ } while (!(tmp & (0x1 << 29)));
+
+}
+
+static int exynos5_fout_apll_set_rate(struct clk *clk, unsigned long rate)
+{
+ int index;
+
+ for (index = 0; index < ARRAY_SIZE(apll_freq); index++)
+ if (apll_freq[index].freq == rate)
+ break;
+
+ if (index == ARRAY_SIZE(apll_freq))
+ return -EINVAL;
+
+ if (rate > clk->rate) {
+ /* Clock Configuration Procedure */
+ /* 1. Change the system clock divider values */
+ exynos5_apll_set_clkdiv(index);
+ /* 2. Change the apll m,p,s value */
+ exynos5_apll_set_apll(index);
+ } else if (rate < clk->rate) {
+ /* Clock Configuration Procedure */
+ /* 1. Change the apll m,p,s value */
+ exynos5_apll_set_apll(index);
+ /* 2. Change the system clock divider values */
+ exynos5_apll_set_clkdiv(index);
+ }
+
+ clk->rate = rate;
+
+ return 0;
+}
+
static struct clk_ops exynos5_fout_apll_ops = {
.get_rate = exynos5_fout_apll_get_rate,
+ .set_rate = exynos5_fout_apll_set_rate
+};
+
+#define MIF_FREQ(f, a0, b0, b1, b2, b3, b4, b5, c0, c1) \
+ { \
+ .freq = (f) * 1000000, \
+ .clk_div_sysrgt = (a0), \
+ .clk_div_cdrex = ((b0) << 0 | (b1) << 4 | (b2) << 16 | \
+ (b3) << 20 | (b4) << 24 | (b5) << 28), \
+ .clk_div_syslft = ((c0) << 0 | (c1) << 4), \
+ }
+
+static struct {
+ unsigned long freq;
+ u32 clk_div_sysrgt;
+ u32 clk_div_cdrex;
+ u32 clk_div_syslft;
+} mif_freq[] = {
+ /*
+ * values:
+ * freq
+ * clock divider for ACLK_R1BX
+ * clock divider for ACLK_CDREX, PCLK_CDREX, MCLK_CDREX,
+ * MCLK_DPHY, ACLK_SFRTZASCP, MCLK_CDREX2
+ * clock divider for ACLK_SYSLFT, PCLK_SYSLFT
+ */
+ MIF_FREQ(800, 1, 1, 1, 2, 0, 1, 0, 1, 1),
+ MIF_FREQ(667, 1, 1, 1, 2, 0, 1, 0, 1, 1),
+ MIF_FREQ(400, 3, 1, 3, 2, 0, 1, 1, 3, 1),
+ MIF_FREQ(160, 7, 1, 5, 2, 0, 1, 4, 7, 1),
+ MIF_FREQ(100, 7, 1, 6, 2, 0, 1, 7, 7, 1),
+};
+
+static unsigned long exynos5_mif_get_rate(struct clk *clk)
+{
+ unsigned int tmp;
+
+ tmp = __raw_readl(EXYNOS5_CLKDIV_CDREX);
+ tmp &= EXYNOS5_CLKDIV_CDREX_MCLK_CDREX2_MASK;
+ tmp >>= EXYNOS5_CLKDIV_CDREX_MCLK_CDREX2_SHIFT;
+
+ return clk_get_rate(clk->parent) / (tmp + 1);
+}
+
+static void exynos5_mif_set_clkdiv(unsigned int div_index)
+{
+ unsigned int tmp;
+
+ /* Change Divier - SYSRGT */
+ tmp = __raw_readl(EXYNOS5_CLKDIV_SYSRGT);
+ tmp &= ~EXYNOS5_CLKDIV_SYSRGT_ACLK_R1BX_MASK;
+
+ tmp |= mif_freq[div_index].clk_div_sysrgt;
+
+ __raw_writel(tmp, EXYNOS5_CLKDIV_SYSRGT);
+
+ while (__raw_readl(EXYNOS5_CLKDIV_STAT_SYSRGT) & 0x1)
+ cpu_relax();
+
+ /* Change Divider - CDREX */
+ tmp = __raw_readl(EXYNOS5_CLKDIV_CDREX);
+ tmp &= ~(EXYNOS5_CLKDIV_CDREX_ACLK_CDREX_MASK |
+ EXYNOS5_CLKDIV_CDREX_PCLK_CDREX_MASK |
+ EXYNOS5_CLKDIV_CDREX_MCLK_CDREX_MASK |
+ EXYNOS5_CLKDIV_CDREX_MCLK_DPHY_MASK |
+ EXYNOS5_CLKDIV_CDREX_ACLK_EFCON_MASK |
+ EXYNOS5_CLKDIV_CDREX_MCLK_CDREX2_MASK);
+
+ tmp |= mif_freq[div_index].clk_div_cdrex;
+
+ __raw_writel(tmp, EXYNOS5_CLKDIV_CDREX);
+
+ while (__raw_readl(EXYNOS5_CLKDIV_STAT_CDREX) & 0x11110011)
+ cpu_relax();
+
+ /* Change Divier - SYSLFT */
+ tmp = __raw_readl(EXYNOS5_CLKDIV_SYSLFT);
+
+ tmp &= ~(EXYNOS5_CLKDIV_SYSLFT_PCLK_SYSLFT_MASK |
+ EXYNOS5_CLKDIV_SYSLFT_ACLK_SYSLFT_MASK);
+
+ tmp |= mif_freq[div_index].clk_div_syslft;
+
+ __raw_writel(tmp, EXYNOS5_CLKDIV_SYSLFT);
+
+ while (__raw_readl(EXYNOS5_CLKDIV_STAT_SYSLFT) & 0x11)
+ cpu_relax();
+}
+
+static int exynos5_mif_set_rate(struct clk *clk, unsigned long rate)
+{
+ int index;
+
+ for (index = 0; index < ARRAY_SIZE(mif_freq); index++)
+ if (mif_freq[index].freq == rate)
+ break;
+
+ if (index == ARRAY_SIZE(mif_freq))
+ return -EINVAL;
+
+ /* Change the system clock divider values */
+ exynos5_mif_set_clkdiv(index);
+
+ return 0;
+}
+
+static struct clk_ops exynos5_mif_ops = {
+ .get_rate = exynos5_mif_get_rate,
+ .set_rate = exynos5_mif_set_rate
+};
+
+#define INT_FREQ(f, a0, a1, a2, a3, a4, a5, b0, b1, b2, b3, \
+ c0, c1, d0, e0) \
+ { \
+ .freq = (f) * 1000000, \
+ .clk_div_top0 = ((a0) << 0 | (a1) << 8 | (a2) << 12 | \
+ (a3) << 16 | (a4) << 20 | (a5) << 28), \
+ .clk_div_top1 = ((b0) << 12 | (b1) << 16 | (b2) << 20 | \
+ (b3) << 24), \
+ .clk_div_lex = ((c0) << 4 | (c1) << 8), \
+ .clk_div_r0x = ((d0) << 4), \
+ .clk_div_r1x = ((e0) << 4), \
+ }
+
+static struct {
+ unsigned long freq;
+ u32 clk_div_top0;
+ u32 clk_div_top1;
+ u32 clk_div_lex;
+ u32 clk_div_r0x;
+ u32 clk_div_r1x;
+} int_freq[] = {
+ /*
+ * values:
+ * freq
+ * clock divider for ACLK66, ACLK166, ACLK200, ACLK266,
+ ACLK333, ACLK300_DISP1
+ * clock divider for ACLK300_GSCL, ACLK400_IOP, ACLK400_ISP, ACLK66_PRE
+ * clock divider for PCLK_LEX, ATCLK_LEX
+ * clock divider for ACLK_PR0X
+ * clock divider for ACLK_PR1X
+ */
+ INT_FREQ(266, 1, 1, 3, 2, 0, 0, 0, 1, 1, 5, 1, 0, 1, 1),
+ INT_FREQ(200, 1, 2, 4, 3, 1, 0, 0, 3, 2, 5, 1, 0, 1, 1),
+ INT_FREQ(160, 1, 3, 4, 4, 2, 0, 0, 3, 3, 5, 1, 0, 1, 1),
+ INT_FREQ(133, 1, 3, 5, 5, 2, 1, 1, 4, 4, 5, 1, 0, 1, 1),
+ INT_FREQ(100, 1, 7, 7, 7, 7, 3, 7, 7, 7, 5, 1, 0, 1, 1),
+};
+
+static unsigned long exynos5_clk_int_get_rate(struct clk *clk)
+{
+ return clk->rate;
+}
+
+static void exynos5_int_set_clkdiv(unsigned int div_index)
+{
+ unsigned int tmp;
+
+ /* Change Divider - TOP0 */
+ tmp = __raw_readl(EXYNOS5_CLKDIV_TOP0);
+
+ tmp &= ~(EXYNOS5_CLKDIV_TOP0_ACLK266_MASK |
+ EXYNOS5_CLKDIV_TOP0_ACLK200_MASK |
+ EXYNOS5_CLKDIV_TOP0_ACLK66_MASK |
+ EXYNOS5_CLKDIV_TOP0_ACLK333_MASK |
+ EXYNOS5_CLKDIV_TOP0_ACLK166_MASK |
+ EXYNOS5_CLKDIV_TOP0_ACLK300_DISP1_MASK);
+
+ tmp |= int_freq[div_index].clk_div_top0;
+
+ __raw_writel(tmp, EXYNOS5_CLKDIV_TOP0);
+
+ while (__raw_readl(EXYNOS5_CLKDIV_STAT_TOP0) & 0x151101)
+ cpu_relax();
+
+ /* Change Divider - TOP1 */
+ tmp = __raw_readl(EXYNOS5_CLKDIV_TOP1);
+
+ tmp &= ~(EXYNOS5_CLKDIV_TOP1_ACLK400_ISP_MASK |
+ EXYNOS5_CLKDIV_TOP1_ACLK400_IOP_MASK |
+ EXYNOS5_CLKDIV_TOP1_ACLK66_PRE_MASK |
+ EXYNOS5_CLKDIV_TOP1_ACLK300_GSCL_MASK);
+
+ tmp |= int_freq[div_index].clk_div_top1;
+
+ __raw_writel(tmp, EXYNOS5_CLKDIV_TOP1);
+
+ while ((__raw_readl(EXYNOS5_CLKDIV_STAT_TOP1) & 0x1110000) &&
+ (__raw_readl(EXYNOS5_CLKDIV_STAT_TOP0) & 0x80000))
+ cpu_relax();
+
+ /* Change Divider - LEX */
+ tmp = __raw_readl(EXYNOS5_CLKDIV_LEX);
+
+ tmp &= ~(EXYNOS5_CLKDIV_LEX_ATCLK_LEX_MASK |
+ EXYNOS5_CLKDIV_LEX_PCLK_LEX_MASK);
+
+ tmp |= int_freq[div_index].clk_div_lex;
+
+ __raw_writel(tmp, EXYNOS5_CLKDIV_LEX);
+
+ while (__raw_readl(EXYNOS5_CLKDIV_STAT_LEX) & 0x110)
+ cpu_relax();
+
+ /* Change Divider - R0X */
+ tmp = __raw_readl(EXYNOS5_CLKDIV_R0X);
+
+ tmp &= ~EXYNOS5_CLKDIV_R0X_PCLK_R0X_MASK;
+
+ tmp |= int_freq[div_index].clk_div_r0x;
+
+ __raw_writel(tmp, EXYNOS5_CLKDIV_R0X);
+
+ while (__raw_readl(EXYNOS5_CLKDIV_STAT_R0X) & 0x10)
+ cpu_relax();
+
+ /* Change Divider - R1X */
+ tmp = __raw_readl(EXYNOS5_CLKDIV_R1X);
+
+ tmp &= ~EXYNOS5_CLKDIV_R1X_PCLK_R1X_MASK;
+
+ tmp |= int_freq[div_index].clk_div_r1x;
+
+ __raw_writel(tmp, EXYNOS5_CLKDIV_R1X);
+
+ while (__raw_readl(EXYNOS5_CLKDIV_STAT_R1X) & 0x10)
+ cpu_relax();
+}
+
+static int exynos5_clk_int_set_rate(struct clk *clk, unsigned long rate)
+{
+ int index;
+
+ for (index = 0; index < ARRAY_SIZE(int_freq); index++)
+ if (int_freq[index].freq == rate)
+ break;
+
+ if (index == ARRAY_SIZE(int_freq))
+ return -EINVAL;
+
+ /* Change the system clock divider values */
+ exynos5_int_set_clkdiv(index);
+
+ clk->rate = rate;
+
+ return 0;
+}
+
+static struct clk_ops exynos5_clk_int_ops = {
+ .get_rate = exynos5_clk_int_get_rate,
+ .set_rate = exynos5_clk_int_set_rate
+};
+
+static u32 exynos5_vpll_div[][8] = {
+ {268000000, 6, 268, 2, 41104, 0, 0, 0},
+};
+
+static unsigned long exynos5_vpll_get_rate(struct clk *clk)
+{
+ return clk->rate;
+}
+
+static int exynos5_vpll_set_rate(struct clk *clk, unsigned long rate)
+{
+ unsigned int vpll_con0, vpll_con1;
+ unsigned int locktime;
+ unsigned int tmp;
+ unsigned int i;
+
+ /* Return if nothing changed */
+ if (clk->rate == rate)
+ return 0;
+
+ vpll_con0 = __raw_readl(EXYNOS5_VPLL_CON0);
+ vpll_con0 &= ~(PLL36XX_MDIV_MASK << PLL36XX_MDIV_SHIFT |
+ PLL36XX_PDIV_MASK << PLL36XX_PDIV_SHIFT |
+ PLL36XX_SDIV_MASK << PLL36XX_SDIV_SHIFT);
+
+ vpll_con1 = __raw_readl(EXYNOS5_VPLL_CON1);
+ vpll_con1 &= ~(0xffff << 0);
+
+ for (i = 0; i < ARRAY_SIZE(exynos5_vpll_div); i++) {
+ if (exynos5_vpll_div[i][0] == rate) {
+ vpll_con0 |=
+ exynos5_vpll_div[i][1] << PLL36XX_PDIV_SHIFT;
+ vpll_con0 |=
+ exynos5_vpll_div[i][2] << PLL36XX_MDIV_SHIFT;
+ vpll_con0 |=
+ exynos5_vpll_div[i][3] << PLL36XX_SDIV_SHIFT;
+ vpll_con1 |= exynos5_vpll_div[i][4] << 0;
+ break;
+ }
+ }
+
+ if (i == ARRAY_SIZE(exynos5_vpll_div)) {
+ printk(KERN_ERR "%s: Invalid Clock VPLL Frequency\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ /* 3000 max_cycls : specification data */
+ locktime = 3000 * exynos5_vpll_div[i][1] + 1;
+
+ __raw_writel(locktime, EXYNOS5_VPLL_LOCK);
+
+ __raw_writel(vpll_con0, EXYNOS5_VPLL_CON0);
+ __raw_writel(vpll_con1, EXYNOS5_VPLL_CON1);
+
+ do {
+ tmp = __raw_readl(EXYNOS5_VPLL_CON0);
+ } while (!(tmp & (0x1 << EXYNOS5_VPLLCON0_LOCKED_SHIFT)));
+
+ clk->rate = rate;
+
+ return 0;
+}
+
+static struct clk_ops exynos5_vpll_ops = {
+ .get_rate = exynos5_vpll_get_rate,
+ .set_rate = exynos5_vpll_set_rate,
};
#ifdef CONFIG_PM
@@ -1134,6 +2769,7 @@
unsigned long cpll;
unsigned long mpll;
unsigned long epll;
+ unsigned long gpll;
unsigned long vpll;
unsigned long vpllsrc;
unsigned long xtal;
@@ -1166,6 +2802,7 @@
mpll = s5p_get_pll35xx(xtal, __raw_readl(EXYNOS5_MPLL_CON0));
epll = s5p_get_pll36xx(xtal, __raw_readl(EXYNOS5_EPLL_CON0),
__raw_readl(EXYNOS5_EPLL_CON1));
+ gpll = s5p_get_pll35xx(xtal, __raw_readl(EXYNOS5_GPLL_CON0));
vpllsrc = clk_get_rate(&exynos5_clk_vpllsrc.clk);
vpll = s5p_get_pll36xx(vpllsrc, __raw_readl(EXYNOS5_VPLL_CON0),
@@ -1173,19 +2810,29 @@
clk_fout_apll.ops = &exynos5_fout_apll_ops;
clk_fout_bpll.rate = bpll;
+ clk_fout_bpll_div2.rate = clk_fout_bpll.rate / 2;
clk_fout_cpll.rate = cpll;
+ clk_fout_gpll.rate = gpll;
clk_fout_mpll.rate = mpll;
+ clk_fout_mpll_div2.rate = clk_fout_mpll.rate / 2;
clk_fout_epll.rate = epll;
clk_fout_vpll.rate = vpll;
+ clk_fout_apll.rate = apll;
+
+ if (clk_set_parent(&exynos5_clk_mout_mpll.clk,
+ &exynos5_clk_mout_mpll_fout.clk))
+ printk(KERN_ERR "Unable to set parent %s of clock %s.\n",
+ exynos5_clk_mout_mpll_fout.clk.name,
+ exynos5_clk_mout_mpll.clk.name);
printk(KERN_INFO "EXYNOS5: PLL settings, A=%ld, B=%ld, C=%ld\n"
- "M=%ld, E=%ld V=%ld",
- apll, bpll, cpll, mpll, epll, vpll);
+ "M=%ld, E=%ld, V=%ld, G=%ld\n",
+ apll, bpll, cpll, mpll, epll, vpll, gpll);
armclk = clk_get_rate(&exynos5_clk_armclk);
- mout_cdrex = clk_get_rate(&exynos5_clk_cdrex.clk);
+ mout_cdrex = clk_get_rate(&exynos5_clk_mclk_cdrex.clk);
- aclk_400 = clk_get_rate(&exynos5_clk_aclk_400.clk);
+ aclk_400 = clk_get_rate(&exynos5_clk_aclk_400_g3d.clk);
aclk_333 = clk_get_rate(&exynos5_clk_aclk_333.clk);
aclk_266 = clk_get_rate(&exynos5_clk_aclk_266.clk);
aclk_200 = clk_get_rate(&exynos5_clk_aclk_200.clk);
@@ -1199,21 +2846,113 @@
aclk_333, aclk_266, aclk_200,
aclk_166, aclk_66);
-
clk_fout_epll.ops = &exynos5_epll_ops;
+ clk_fout_vpll.ops = &exynos5_vpll_ops;
+ clk_fout_gpll.ops = &exynos5_gpll_ops;
+
+ exynos5_mif_clk.ops = &exynos5_mif_ops;
+ exynos5_mif_clk.parent = &exynos5_clk_mclk_cdrex.clk;
+ exynos5_int_clk.ops = &exynos5_clk_int_ops;
+ exynos5_int_clk.rate = aclk_266;
if (clk_set_parent(&exynos5_clk_mout_epll.clk, &clk_fout_epll))
printk(KERN_ERR "Unable to set parent %s of clock %s.\n",
clk_fout_epll.name, exynos5_clk_mout_epll.clk.name);
+ if (clk_set_parent(&exynos5_clk_mout_aclk_400_isp.clk, &exynos5_clk_mout_mpll_user.clk))
+ printk(KERN_ERR "Unable to set parent %s of clock %s.\n",
+ exynos5_clk_mout_mpll_user.clk.name, exynos5_clk_mout_aclk_400_isp.clk.name);
+ if (clk_set_parent(&exynos5_clk_aclk_266_isp.clk, &exynos5_clk_aclk_266.clk))
+ printk(KERN_ERR "Unable to set parent %s of clock %s.\n",
+ exynos5_clk_aclk_266.clk.name, exynos5_clk_aclk_266_isp.clk.name);
+ if (clk_set_parent(&exynos5_clk_aclk_400_isp.clk, &exynos5_clk_dout_aclk_400_isp.clk))
+ printk(KERN_ERR "Unable to set parent %s of clock %s.\n",
+ exynos5_clk_mout_aclk_400_isp.clk.name, exynos5_clk_aclk_400_isp.clk.name);
+ if (clk_set_parent(&exynos5_clk_sclk_uart_isp.clk, &exynos5_clk_mout_mpll_user.clk))
+ printk(KERN_ERR "Unable to set parent %s of clock %s.\n",
+ exynos5_clk_mout_mpll_user.clk.name, exynos5_clk_sclk_uart_isp.clk.name);
+
+ if (clk_set_parent(&exynos5_clk_sclk_mmc0.clk,
+ &exynos5_clk_mout_mpll_user.clk))
+ printk(KERN_ERR "Unable to set parent %s of clock %s.\n",
+ exynos5_clk_mout_mpll_user.clk.name,
+ exynos5_clk_sclk_mmc0.clk.name);
+ if (clk_set_parent(&exynos5_clk_sclk_mmc1.clk,
+ &exynos5_clk_mout_mpll_user.clk))
+ printk(KERN_ERR "Unable to set parent %s of clock %s.\n",
+ exynos5_clk_mout_mpll_user.clk.name,
+ exynos5_clk_sclk_mmc1.clk.name);
+ if (clk_set_parent(&exynos5_clk_sclk_mmc2.clk,
+ &exynos5_clk_mout_mpll_user.clk))
+ printk(KERN_ERR "Unable to set parent %s of clock %s.\n",
+ exynos5_clk_mout_mpll_user.clk.name,
+ exynos5_clk_sclk_mmc2.clk.name);
+
+ clk_set_rate(&exynos5_clk_sclk_mmc0.clk, 800*MHZ);
+ clk_set_rate(&exynos5_clk_sclk_mmc1.clk, 800*MHZ);
+ clk_set_rate(&exynos5_clk_sclk_mmc2.clk, 800*MHZ);
+
+ if (clk_set_parent(&exynos5_clk_mout_aclk_300_disp1_mid1.clk, &exynos5_clk_mout_cpll.clk))
+ printk(KERN_ERR "Unable to set parent %s of clock %s.\n",
+ exynos5_clk_mout_cpll.clk.name,
+ exynos5_clk_mout_aclk_300_disp1_mid1.clk.name);
+ if (clk_set_parent(&exynos5_clk_mout_aclk_300_disp1.clk, &exynos5_clk_mout_aclk_300_disp1_mid1.clk))
+ printk(KERN_ERR "Unable to set parent %s of clock %s.\n",
+ exynos5_clk_mout_aclk_300_disp1_mid1.clk.name,
+ exynos5_clk_mout_aclk_300_disp1.clk.name);
+ if (clk_set_parent(&exynos5_clk_aclk_300_disp1.clk, &exynos5_clk_dout_aclk_300_disp1.clk))
+ printk(KERN_ERR "Unable to set parent %s of clock %s.\n",
+ exynos5_clk_dout_aclk_300_disp1.clk.name,
+ exynos5_clk_aclk_300_disp1.clk.name);
+
+ if (clk_set_parent(&exynos5_clk_mout_aclk_300_gscl_mid1.clk, &exynos5_clk_mout_cpll.clk))
+ printk(KERN_ERR "Unable to set parent %s of clock %s.\n",
+ exynos5_clk_mout_aclk_300_gscl_mid1.clk.name,
+ exynos5_clk_mout_cpll.clk.name);
+ if (clk_set_parent(&exynos5_clk_mout_aclk_300_gscl.clk, &exynos5_clk_mout_aclk_300_gscl_mid1.clk))
+ printk(KERN_ERR "Unable to set parent %s of clock %s.\n",
+ exynos5_clk_mout_aclk_300_gscl.clk.name,
+ exynos5_clk_mout_aclk_300_gscl_mid1.clk.name);
+ if (clk_set_parent(&exynos5_clk_aclk_300_gscl.clk, &exynos5_clk_dout_aclk_300_gscl.clk))
+ printk(KERN_ERR "Unable to set parent %s of clock %s.\n",
+ exynos5_clk_aclk_300_gscl.clk.name,
+ exynos5_clk_dout_aclk_300_gscl.clk.name);
+
+ clk_set_rate(&exynos5_clk_dout_aclk_300_disp1.clk, 334000000);
+ clk_set_rate(&exynos5_clk_dout_aclk_300_gscl.clk, 334000000);
+
clk_set_rate(&exynos5_clk_sclk_apll.clk, 100000000);
clk_set_rate(&exynos5_clk_aclk_266.clk, 300000000);
clk_set_rate(&exynos5_clk_aclk_acp.clk, 267000000);
clk_set_rate(&exynos5_clk_pclk_acp.clk, 134000000);
- for (ptr = 0; ptr < ARRAY_SIZE(exynos5_clksrcs); ptr++)
+ clk_set_rate(&clk_fout_vpll, 268000000);
+
+ for (ptr = 0; ptr < ARRAY_SIZE(exynos5_clksrcs); ptr++) {
+ struct clksrc_clk *clksrc;
s3c_set_clksrc(&exynos5_clksrcs[ptr], true);
+ if (exynos5_clksrcs[ptr].clk.devname &&
+ !strcmp(exynos5_clksrcs[ptr].clk.devname,
+ "dw_mmc.0")) {
+ clksrc = &exynos5_clksrcs[ptr];
+ clk_set_rate(&clksrc->clk, 800 * MHZ);
+ }
+
+ if (exynos5_clksrcs[ptr].clk.devname &&
+ !strcmp(exynos5_clksrcs[ptr].clk.devname,
+ "dw_mmc.1")) {
+ clksrc = &exynos5_clksrcs[ptr];
+ clk_set_rate(&clksrc->clk, 200 * MHZ);
+ }
+
+ if (exynos5_clksrcs[ptr].clk.devname &&
+ !strcmp(exynos5_clksrcs[ptr].clk.devname,
+ "dw_mmc.2")) {
+ clksrc = &exynos5_clksrcs[ptr];
+ clk_set_rate(&clksrc->clk, 200 * MHZ);
+ }
+ }
}
void __init exynos5_register_clocks(void)
@@ -1231,6 +2970,9 @@
for (ptr = 0; ptr < ARRAY_SIZE(exynos5_clksrc_cdev); ptr++)
s3c_register_clksrc(exynos5_clksrc_cdev[ptr], 1);
+ for (ptr = 0; ptr < ARRAY_SIZE(exynos5_clksrc_aclk_isp); ptr++)
+ s3c_register_clksrc(exynos5_clksrc_aclk_isp[ptr], 1);
+
s3c_register_clksrc(exynos5_clksrcs, ARRAY_SIZE(exynos5_clksrcs));
s3c_register_clocks(exynos5_init_clocks_on, ARRAY_SIZE(exynos5_init_clocks_on));
@@ -1242,6 +2984,12 @@
s3c_disable_clocks(exynos5_init_clocks_off, ARRAY_SIZE(exynos5_init_clocks_off));
clkdev_add_table(exynos5_clk_lookup, ARRAY_SIZE(exynos5_clk_lookup));
+ s3c24xx_register_clock(&exynos5_c2c_clock);
+ s3c_disable_clocks(&exynos5_c2c_clock, 1);
+
+ s3c_disable_clocks(&exynos5_clk_clkout.clk, 1);
register_syscore_ops(&exynos5_clock_syscore_ops);
+ s3c24xx_register_clock(&dummy_apb_pclk);
+
s3c_pwmclk_init();
}
diff --git a/arch/arm/mach-exynos/common.c b/arch/arm/mach-exynos/common.c
index 5ccd6e8..4f5d8f8 100644
--- a/arch/arm/mach-exynos/common.c
+++ b/arch/arm/mach-exynos/common.c
@@ -19,6 +19,7 @@
#include <linux/serial_core.h>
#include <linux/of.h>
#include <linux/of_irq.h>
+#include <linux/dma-mapping.h>
#include <asm/proc-fns.h>
#include <asm/exception.h>
@@ -44,6 +45,7 @@
#include <plat/fimc-core.h>
#include <plat/iic-core.h>
#include <plat/tv-core.h>
+#include <plat/ace-core.h>
#include <plat/regs-serial.h>
#include "common.h"
@@ -190,6 +192,12 @@
.pfn = __phys_to_pfn(EXYNOS4_PA_HSPHY),
.length = SZ_4K,
.type = MT_DEVICE,
+ }, {
+ .virtual = (unsigned long)S5P_VA_AUDSS,
+ .pfn = __phys_to_pfn(EXYNOS_PA_AUDSS),
+ .length = SZ_4K,
+ .type = MT_DEVICE,
+ }, {
},
};
@@ -243,6 +251,13 @@
.length = SZ_4K,
.type = MT_DEVICE,
}, {
+#ifdef CONFIG_ARM_TRUSTZONE
+ .virtual = (unsigned long)S5P_VA_SYSRAM_NS,
+ .pfn = __phys_to_pfn(EXYNOS5_PA_SYSRAM_NS),
+ .length = SZ_4K,
+ .type = MT_DEVICE,
+ }, {
+#endif
.virtual = (unsigned long)S5P_VA_CMU,
.pfn = __phys_to_pfn(EXYNOS5_PA_CMU),
.length = 144 * SZ_1K,
@@ -265,12 +280,82 @@
}, {
.virtual = (unsigned long)S5P_VA_GIC_CPU,
.pfn = __phys_to_pfn(EXYNOS5_PA_GIC_CPU),
- .length = SZ_64K,
+ .length = SZ_8K,
.type = MT_DEVICE,
}, {
.virtual = (unsigned long)S5P_VA_GIC_DIST,
.pfn = __phys_to_pfn(EXYNOS5_PA_GIC_DIST),
- .length = SZ_64K,
+ .length = SZ_4K,
+ .type = MT_DEVICE,
+ }, {
+ .virtual = (unsigned long)S3C_VA_USB_HSPHY,
+ .pfn = __phys_to_pfn(EXYNOS5_PA_HSPHY),
+ .length = SZ_4K,
+ .type = MT_DEVICE,
+ }, {
+ .virtual = (unsigned long)S5P_VA_AUDSS,
+ .pfn = __phys_to_pfn(EXYNOS_PA_AUDSS),
+ .length = SZ_4K,
+ .type = MT_DEVICE,
+ }, {
+ .virtual = (unsigned long)S5P_VA_SS_PHY,
+ .pfn = __phys_to_pfn(EXYNOS5_PA_SS_PHY),
+ .length = SZ_4K,
+ .type = MT_DEVICE,
+ }, {
+ .virtual = (unsigned long)S5P_VA_PPMU_CPU,
+ .pfn = __phys_to_pfn(EXYNOS5_PA_PPMU_CPU),
+ .length = SZ_8K,
+ .type = MT_DEVICE,
+ }, {
+ .virtual = (unsigned long)S5P_VA_PPMU_DDR_C,
+ .pfn = __phys_to_pfn(EXYNOS5_PA_PPMU_DDR_C),
+ .length = SZ_8K,
+ .type = MT_DEVICE,
+ }, {
+ .virtual = (unsigned long)S5P_VA_PPMU_DDR_R1,
+ .pfn = __phys_to_pfn(EXYNOS5_PA_PPMU_DDR_R1),
+ .length = SZ_8K,
+ .type = MT_DEVICE,
+ }, {
+ .virtual = (unsigned long)S5P_VA_PPMU_DDR_L,
+ .pfn = __phys_to_pfn(EXYNOS5_PA_PPMU_DDR_L),
+ .length = SZ_8K,
+ .type = MT_DEVICE,
+ }, {
+ .virtual = (unsigned long)S5P_VA_PPMU_RIGHT,
+ .pfn = __phys_to_pfn(EXYNOS5_PA_PPMU_RIGHT),
+ .length = SZ_8K,
+ .type = MT_DEVICE,
+ }, {
+ .virtual = (unsigned long)S5P_VA_FIMCLITE0,
+ .pfn = __phys_to_pfn(EXYNOS5_PA_FIMC_LITE0),
+ .length = SZ_4K,
+ .type = MT_DEVICE,
+ }, {
+ .virtual = (unsigned long)S5P_VA_FIMCLITE1,
+ .pfn = __phys_to_pfn(EXYNOS5_PA_FIMC_LITE1),
+ .length = SZ_4K,
+ .type = MT_DEVICE,
+ }, {
+ .virtual = (unsigned long)S5P_VA_FIMCLITE2,
+ .pfn = __phys_to_pfn(EXYNOS5_PA_FIMC_LITE2),
+ .length = SZ_4K,
+ .type = MT_DEVICE,
+ }, {
+ .virtual = (unsigned long)S5P_VA_MIPICSI0,
+ .pfn = __phys_to_pfn(EXYNOS5_PA_MIPI_CSIS0),
+ .length = SZ_4K,
+ .type = MT_DEVICE,
+ }, {
+ .virtual = (unsigned long)S5P_VA_MIPICSI1,
+ .pfn = __phys_to_pfn(EXYNOS5_PA_MIPI_CSIS1),
+ .length = SZ_4K,
+ .type = MT_DEVICE,
+ }, {
+ .virtual = (unsigned long)S5P_VA_DREXII,
+ .pfn = __phys_to_pfn(EXYNOS5_PA_DREXII),
+ .length = SZ_4K,
.type = MT_DEVICE,
},
};
@@ -343,12 +428,15 @@
static void __init exynos5_map_io(void)
{
iotable_init(exynos5_iodesc, ARRAY_SIZE(exynos5_iodesc));
+ init_consistent_dma_size(14 << 20);
s3c_device_i2c0.resource[0].start = EXYNOS5_PA_IIC(0);
s3c_device_i2c0.resource[0].end = EXYNOS5_PA_IIC(0) + SZ_4K - 1;
s3c_device_i2c0.resource[1].start = EXYNOS5_IRQ_IIC;
s3c_device_i2c0.resource[1].end = EXYNOS5_IRQ_IIC;
+ s3c_adc_setname("samsung-adc-v4");
+
s3c_sdhci_setname(0, "exynos4-sdhci");
s3c_sdhci_setname(1, "exynos4-sdhci");
s3c_sdhci_setname(2, "exynos4-sdhci");
@@ -358,6 +446,13 @@
s3c_i2c0_setname("s3c2440-i2c");
s3c_i2c1_setname("s3c2440-i2c");
s3c_i2c2_setname("s3c2440-i2c");
+
+ s5p_fb_setname(1, "exynos5-fb");
+ s5p_hdmi_setname("exynos5-hdmi");
+
+#ifdef CONFIG_S5P_DEV_ACE
+ s5p_ace_setname("exynos4-ace");
+#endif
}
static void __init exynos4_init_clocks(int xtal)
@@ -374,6 +469,7 @@
exynos4_register_clocks();
exynos4_setup_clocks();
+ exynos_register_audss_clocks();
}
static void __init exynos5_init_clocks(int xtal)
@@ -385,11 +481,13 @@
exynos5_register_clocks();
exynos5_setup_clocks();
+ exynos_register_audss_clocks();
}
#define COMBINER_ENABLE_SET 0x0
#define COMBINER_ENABLE_CLEAR 0x4
#define COMBINER_INT_STATUS 0xC
+#define COMBINER_IRQS 8
static DEFINE_SPINLOCK(irq_controller_lock);
@@ -397,30 +495,23 @@
unsigned int irq_offset;
unsigned int irq_mask;
void __iomem *base;
+ unsigned int parent_irq;
+ struct cpumask affinity[COMBINER_IRQS];
+ spinlock_t lock;
};
static struct combiner_chip_data combiner_data[MAX_COMBINER_NR];
-static inline void __iomem *combiner_base(struct irq_data *data)
+static inline bool is_max_combiner_nr_bad(unsigned int combiner_nr)
{
- struct combiner_chip_data *combiner_data =
- irq_data_get_irq_chip_data(data);
+ unsigned int max_nr;
- return combiner_data->base;
-}
+ if (soc_is_exynos5250())
+ max_nr = EXYNOS5_MAX_COMBINER_NR;
+ else
+ max_nr = EXYNOS4_MAX_COMBINER_NR;
-static void combiner_mask_irq(struct irq_data *data)
-{
- u32 mask = 1 << (data->irq % 32);
-
- __raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_CLEAR);
-}
-
-static void combiner_unmask_irq(struct irq_data *data)
-{
- u32 mask = 1 << (data->irq % 32);
-
- __raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_SET);
+ return (combiner_nr >= max_nr);
}
static void combiner_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
@@ -452,58 +543,108 @@
chained_irq_exit(chip, desc);
}
-static struct irq_chip combiner_chip = {
- .name = "COMBINER",
- .irq_mask = combiner_mask_irq,
- .irq_unmask = combiner_unmask_irq,
-};
-
static void __init combiner_cascade_irq(unsigned int combiner_nr, unsigned int irq)
{
- unsigned int max_nr;
-
- if (soc_is_exynos5250())
- max_nr = EXYNOS5_MAX_COMBINER_NR;
- else
- max_nr = EXYNOS4_MAX_COMBINER_NR;
-
- if (combiner_nr >= max_nr)
+ if (is_max_combiner_nr_bad(combiner_nr))
BUG();
if (irq_set_handler_data(irq, &combiner_data[combiner_nr]) != 0)
BUG();
irq_set_chained_handler(irq, combiner_handle_cascade_irq);
}
+static void combiner_resume(struct irq_data *data)
+{
+ struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
+
+ __raw_writel(~gc->mask_cache, gc->reg_base + COMBINER_ENABLE_CLEAR);
+ __raw_writel(gc->mask_cache, gc->reg_base + COMBINER_ENABLE_SET);
+}
+
+static int combiner_set_affinity(struct irq_data *d,
+ const struct cpumask *dest, bool force)
+{
+ struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+ struct cpumask target_affinity;
+ unsigned int i;
+ unsigned int ret;
+ unsigned long flags;
+ unsigned int sub_irq = (d->irq - gc->irq_base) % COMBINER_IRQS;
+ unsigned int combiner_nr = (unsigned int)gc->private +
+ (d->irq - gc->irq_base) / COMBINER_IRQS;
+
+ if (is_max_combiner_nr_bad(combiner_nr)) {
+ pr_err("unable to set irq affinity: bad combiner number\n");
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&combiner_data[combiner_nr].lock, flags);
+
+ cpumask_setall(&target_affinity);
+ for (i = 0; i < COMBINER_IRQS; ++i) {
+ if (unlikely(i == sub_irq))
+ cpumask_and(&target_affinity,
+ &target_affinity,
+ dest);
+ else
+ cpumask_and(&target_affinity,
+ &target_affinity,
+ &combiner_data[combiner_nr].affinity[i]);
+ }
+ if (cpumask_empty(&target_affinity)) {
+ pr_err("warning: denying unsafe change of irq cpu affinity\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = irq_set_affinity(combiner_data[combiner_nr].parent_irq,
+ &target_affinity);
+ if (ret >= 0)
+ cpumask_copy(&combiner_data[combiner_nr].affinity[sub_irq],
+ &target_affinity);
+out:
+ spin_unlock_irqrestore(&combiner_data[combiner_nr].lock, flags);
+ return ret;
+}
+
static void __init combiner_init(unsigned int combiner_nr, void __iomem *base,
- unsigned int irq_start)
+ unsigned int irq_start)
{
unsigned int i;
- unsigned int max_nr;
+ struct irq_chip_generic *gc;
+ struct irq_chip_type *ct;
- if (soc_is_exynos5250())
- max_nr = EXYNOS5_MAX_COMBINER_NR;
- else
- max_nr = EXYNOS4_MAX_COMBINER_NR;
-
- if (combiner_nr >= max_nr)
+ if (is_max_combiner_nr_bad(combiner_nr))
BUG();
-
combiner_data[combiner_nr].base = base;
combiner_data[combiner_nr].irq_offset = irq_start;
combiner_data[combiner_nr].irq_mask = 0xff << ((combiner_nr % 4) << 3);
+ combiner_data[combiner_nr].parent_irq = IRQ_SPI(combiner_nr);
+ spin_lock_init(&combiner_data[combiner_nr].lock);
+ for (i = 0; i < COMBINER_IRQS; ++i)
+ cpumask_setall(&combiner_data[combiner_nr].affinity[i]);
- /* Disable all interrupts */
+ if ((combiner_nr % 4) == 0) {
+ /* Disable all interrupts */
- __raw_writel(combiner_data[combiner_nr].irq_mask,
- base + COMBINER_ENABLE_CLEAR);
+ __raw_writel(IRQ_MSK(32), base + COMBINER_ENABLE_CLEAR);
- /* Setup the Linux IRQ subsystem */
+ gc = irq_alloc_generic_chip("combiner", 1, irq_start,
+ base, handle_level_irq);
+ if (!gc) {
+ pr_err("Failed to allocate combiner irq chip\n");
+ return;
+ }
- for (i = irq_start; i < combiner_data[combiner_nr].irq_offset
- + MAX_IRQ_IN_COMBINER; i++) {
- irq_set_chip_and_handler(i, &combiner_chip, handle_level_irq);
- irq_set_chip_data(i, &combiner_data[combiner_nr]);
- set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
+ ct = gc->chip_types;
+ ct->chip.irq_mask = irq_gc_mask_disable_reg;
+ ct->chip.irq_unmask = irq_gc_unmask_enable_reg;
+ ct->chip.irq_set_affinity = combiner_set_affinity;
+ ct->chip.irq_resume = combiner_resume;
+ ct->regs.enable = COMBINER_ENABLE_SET;
+ ct->regs.disable = COMBINER_ENABLE_CLEAR;
+ gc->private = (void *)combiner_nr;
+ irq_setup_generic_chip(gc, IRQ_MSK(32), 0,
+ IRQ_NOREQUEST | IRQ_NOPROBE, 0);
}
}
@@ -549,6 +690,8 @@
#ifdef CONFIG_OF
of_irq_init(exynos4_dt_irq_match);
+#else
+ gic_init(0, IRQ_PPI(0), S5P_VA_GIC_DIST, S5P_VA_GIC_CPU);
#endif
for (irq = 0; irq < EXYNOS5_MAX_COMBINER_NR; irq++) {
@@ -646,31 +789,6 @@
early_initcall(exynos4_l2x0_cache_init);
#endif
-static int __init exynos5_l2_cache_init(void)
-{
- unsigned int val;
-
- if (!soc_is_exynos5250())
- return 0;
-
- asm volatile("mrc p15, 0, %0, c1, c0, 0\n"
- "bic %0, %0, #(1 << 2)\n" /* cache disable */
- "mcr p15, 0, %0, c1, c0, 0\n"
- "mrc p15, 1, %0, c9, c0, 2\n"
- : "=r"(val));
-
- val |= (1 << 9) | (1 << 5) | (2 << 6) | (2 << 0);
-
- asm volatile("mcr p15, 1, %0, c9, c0, 2\n" : : "r"(val));
- asm volatile("mrc p15, 0, %0, c1, c0, 0\n"
- "orr %0, %0, #(1 << 2)\n" /* cache enable */
- "mcr p15, 0, %0, c1, c0, 0\n"
- : : "r"(val));
-
- return 0;
-}
-early_initcall(exynos5_l2_cache_init);
-
static int __init exynos_init(void)
{
printk(KERN_INFO "EXYNOS: Initializing architecture\n");
@@ -697,7 +815,7 @@
s3c24xx_init_uartdevs("exynos4210-uart", exynos4_uart_resources, cfg, no);
}
-static void __iomem *exynos_eint_base;
+void __iomem *exynos_eint_base;
static DEFINE_SPINLOCK(eint_lock);
@@ -865,6 +983,11 @@
__raw_writel(ctrl, EINT_CON(exynos_eint_base, data->irq));
spin_unlock(&eint_lock);
+ if (type & IRQ_TYPE_EDGE_BOTH)
+ __irq_set_handler_locked(data->irq, handle_edge_irq);
+ else
+ __irq_set_handler_locked(data->irq, handle_level_irq);
+
if (soc_is_exynos5250())
s3c_gpio_cfgpin(exynos5_irq_to_gpio(data->irq), S3C_GPIO_SFN(0xf));
else
diff --git a/arch/arm/mach-exynos/common.h b/arch/arm/mach-exynos/common.h
index 677b546..e4fc9b9 100644
--- a/arch/arm/mach-exynos/common.h
+++ b/arch/arm/mach-exynos/common.h
@@ -15,6 +15,7 @@
extern struct sys_timer exynos4_timer;
void exynos_init_io(struct map_desc *mach_desc, int size);
+void exynos_register_audss_clocks(void);
void exynos4_init_irq(void);
void exynos5_init_irq(void);
void exynos4_restart(char mode, const char *cmd);
diff --git a/arch/arm/mach-exynos/coresight-exynos5.c b/arch/arm/mach-exynos/coresight-exynos5.c
new file mode 100644
index 0000000..85adeb4
--- /dev/null
+++ b/arch/arm/mach-exynos/coresight-exynos5.c
@@ -0,0 +1,370 @@
+/*
+ * Copyright (C) 2012 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 <asm/hardware/coresight.h>
+#include <linux/amba/bus.h>
+#include <linux/cpu.h>
+#include <linux/cpu_pm.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/notifier.h>
+#include <linux/smp.h>
+#include <linux/syscore_ops.h>
+#include <plat/cpu.h>
+
+/* CoreSight components */
+#define CS_PTM0_BASE (0x1089c000)
+#define CS_PTM1_BASE (0x1089d000)
+#define CS_ETB_BASE (0x10881000)
+#define CS_FUNNEL_BASE (0x10884000)
+
+#define CS_PTM_COUNT 2
+
+static void __iomem *cs_etb_regs;
+static void __iomem *cs_funnel_regs;
+static void __iomem *cs_ptm_regs[CS_PTM_COUNT];
+
+static u32 cs_etb_save_state_ffcr;
+static u32 cs_etb_save_state_ctl;
+
+static struct cs_ptm_save_state {
+ u32 offset;
+ u32 val[CS_PTM_COUNT];
+} cs_ptm_save_state[] = {
+ { .offset = 0x000 * 4, }, /* ETMCR */
+ { .offset = 0x002 * 4, }, /* ETMTRIGGER */
+ { .offset = 0x004 * 4, }, /* ETMSR */
+ { .offset = 0x006 * 4, }, /* ETMTSSCR */
+ { .offset = 0x008 * 4, }, /* ETMTEEVR */
+ { .offset = 0x009 * 4, }, /* ETMTECR1 */
+ { .offset = 0x00B * 4, }, /* ETMFFLR */
+ { .offset = 0x010 * 4, }, /* ETMACVR0 */
+ { .offset = 0x011 * 4, }, /* ETMACVR1 */
+ { .offset = 0x012 * 4, }, /* ETMACVR2 */
+ { .offset = 0x013 * 4, }, /* ETMACVR3 */
+ { .offset = 0x014 * 4, }, /* ETMACVR4 */
+ { .offset = 0x015 * 4, }, /* ETMACVR5 */
+ { .offset = 0x016 * 4, }, /* ETMACVR6 */
+ { .offset = 0x017 * 4, }, /* ETMACVR7 */
+ { .offset = 0x020 * 4, }, /* ETMACTR0 */
+ { .offset = 0x021 * 4, }, /* ETMACTR1 */
+ { .offset = 0x022 * 4, }, /* ETMACTR2 */
+ { .offset = 0x023 * 4, }, /* ETMACTR3 */
+ { .offset = 0x024 * 4, }, /* ETMACTR4 */
+ { .offset = 0x025 * 4, }, /* ETMACTR5 */
+ { .offset = 0x026 * 4, }, /* ETMACTR6 */
+ { .offset = 0x027 * 4, }, /* ETMACTR7 */
+ { .offset = 0x050 * 4, }, /* ETMCNTRLDVR0 */
+ { .offset = 0x051 * 4, }, /* ETMCNTRLDVR1 */
+ { .offset = 0x054 * 4, }, /* ETMCNTENR0 */
+ { .offset = 0x055 * 4, }, /* ETMCNTENR1 */
+ { .offset = 0x058 * 4, }, /* ETMCNTRLDEVR0 */
+ { .offset = 0x059 * 4, }, /* ETMCNTRLDEVR1 */
+ { .offset = 0x05C * 4, }, /* ETMCNTVR0 */
+ { .offset = 0x05D * 4, }, /* ETMCNTVR1 */
+ { .offset = 0x060 * 4, }, /* ETMSQabEVR */
+ { .offset = 0x067 * 4, }, /* ETMSQR */
+ { .offset = 0x068 * 4, }, /* ETMEXTOUTEVR0 */
+ { .offset = 0x069 * 4, }, /* ETMEXTOUTEVR1 */
+ { .offset = 0x06C * 4, }, /* ETMCIDCVR0 */
+ { .offset = 0x06F * 4, }, /* ETMCIDCMR */
+ { .offset = 0x078 * 4, }, /* ETMSYNCFR */
+ { .offset = 0x07B * 4, }, /* ETMEXTINSELR */
+ { .offset = 0x07E * 4, }, /* ETMTSEVR */
+ { .offset = 0x07F * 4, }, /* ETMAUXCR[a] */
+ { .offset = 0x080 * 4, }, /* ETMTRACEIDR */
+ { .offset = 0x090 * 4, }, /* ETMVMIDCVR[a] */
+ { .offset = 0x3E8 * 4, }, /* ETMCLAIMSET[a] */
+ { .offset = 0x3E9 * 4, }, /* ETMCLAIMCLR[a] */
+};
+
+static void cs_unlock(void *regs)
+{
+ writel(UNLOCK_MAGIC, regs + CSMR_LOCKACCESS);
+ readl(regs + CSMR_LOCKSTATUS);
+}
+
+static void cs_relock(void *regs)
+{
+ writel(0, regs + CSMR_LOCKACCESS);
+}
+
+static struct amba_device s5p_device_etb = {
+ .dev = {
+ .init_name = "etb",
+ },
+ .res = {
+ .start = CS_ETB_BASE,
+ .end = CS_ETB_BASE + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ .periphid = 0x002bb907,
+};
+
+static struct amba_device s5p_device_ptm0 = {
+ .dev = {
+ .init_name = "ptm0",
+ },
+ .res = {
+ .start = CS_PTM0_BASE,
+ .end = CS_PTM0_BASE + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ .periphid = 0x001bb950,
+};
+
+static struct amba_device s5p_device_ptm1 = {
+ .dev = {
+ .init_name = "ptm1",
+ },
+ .res = {
+ .start = CS_PTM1_BASE,
+ .end = CS_PTM1_BASE + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ .periphid = 0x001bb950,
+};
+
+static void cs_init_static_regs(void)
+{
+ cs_unlock(cs_funnel_regs);
+
+ /*
+ * Set PTM1 to higher priority than PTM0 so cs_suspend_cpu(1)
+ * can succeed during suspend if tracing is active. This trick will
+ * not work if CPU0 is ever powered down before CPU1.
+ */
+ writel(0x00fac681, cs_funnel_regs + 0x4);
+
+ /* enable PTM0 and PTM1 (port 0 and 1) */
+ writel(0x303, cs_funnel_regs);
+
+ cs_relock(cs_funnel_regs);
+}
+
+static int cs_ptm_wait_progbit(int cpu)
+{
+ int i;
+ u32 etmsr;
+ u32 etmpdsr;
+
+ for (i = 0; i < 50000; i++) {
+ etmsr = readl(cs_ptm_regs[cpu] + ETMR_STATUS);
+ if (etmsr & ETMST_PROGBIT) {
+ pr_debug("%s: %d done, loop count %d\n",
+ __func__, cpu, i);
+ return 0;
+ }
+ udelay(10);
+ };
+ etmpdsr = readl(cs_ptm_regs[cpu] + ETMMR_PDSR);
+ pr_err("%s: cpu %d timeout, etmsr %x, etmpdsr %x\n",
+ __func__, cpu, etmsr, etmpdsr);
+ return -ETIMEDOUT;
+}
+
+static void cs_suspend_cpu(int cpu)
+{
+ int i;
+ u32 etmpdsr;
+
+ pr_debug("%s: cpu %d\n", __func__, cpu);
+ cs_unlock(cs_ptm_regs[cpu]);
+
+ etmpdsr = readl(cs_ptm_regs[cpu] + ETMMR_PDSR);
+ if (!(etmpdsr & BIT(0))) {
+ pr_err("%s: skip save: ptm%d is powered down, etmpdsr %x\n",
+ __func__, cpu, etmpdsr);
+ goto err;
+ }
+ pr_debug("%s: cpu %d, etmpdsr %x\n", __func__, cpu, etmpdsr);
+
+ /* Set OS-Lock and empty fifo */
+ writel(UNLOCK_MAGIC, cs_ptm_regs[cpu] + ETMMR_OSLAR);
+ cs_ptm_wait_progbit(cpu);
+
+ for (i = 0; i < ARRAY_SIZE(cs_ptm_save_state); i++)
+ cs_ptm_save_state[i].val[cpu] =
+ readl(cs_ptm_regs[cpu] + cs_ptm_save_state[i].offset);
+
+err:
+ cs_relock(cs_ptm_regs[cpu]);
+ pr_debug("%s: %d done\n", __func__, cpu);
+}
+
+static void cs_resume_cpu(int cpu)
+{
+ int i;
+ u32 etmpdsr;
+
+ pr_debug("%s: cpu %d\n", __func__, cpu);
+
+ cs_unlock(cs_ptm_regs[cpu]);
+
+ /* Read ETMPDSR to clear Sticky-Register-State bit */
+ etmpdsr = readl(cs_ptm_regs[cpu] + ETMMR_PDSR);
+ if (!(etmpdsr & BIT(0))) {
+ pr_err("%s: skip restore: ptm%d is powered down, etmpdsr %x\n",
+ __func__, cpu, etmpdsr);
+ goto err;
+ }
+ pr_debug("%s: cpu %d, etmpdsr %x\n", __func__, cpu, etmpdsr);
+
+ for (i = 0; i < ARRAY_SIZE(cs_ptm_save_state); i++)
+ writel(cs_ptm_save_state[i].val[cpu],
+ cs_ptm_regs[cpu] + cs_ptm_save_state[i].offset);
+
+ /* Clear OS-Lock */
+ writel(0, cs_ptm_regs[cpu] + ETMMR_OSLAR);
+
+err:
+ cs_relock(cs_ptm_regs[cpu]);
+ pr_debug("%s: cpu %d done\n", __func__, cpu);
+}
+
+static int cs_suspend(void)
+{
+ pr_debug("%s\n", __func__);
+
+ cs_unlock(cs_etb_regs);
+ cs_etb_save_state_ctl = readl(cs_etb_regs + ETBR_CTRL);
+ cs_etb_save_state_ffcr = readl(cs_etb_regs + ETBR_FORMATTERCTRL);
+ cs_relock(cs_etb_regs);
+
+ pr_debug("%s done\n", __func__);
+ return 0;
+}
+
+static void cs_resume(void)
+{
+ pr_debug("%s\n", __func__);
+
+ cs_init_static_regs();
+
+ cs_unlock(cs_etb_regs);
+ writel(cs_etb_save_state_ffcr, cs_etb_regs + ETBR_FORMATTERCTRL);
+ writel(cs_etb_save_state_ctl, cs_etb_regs + ETBR_CTRL);
+ cs_relock(cs_etb_regs);
+
+ pr_debug("%s done\n", __func__);
+}
+
+static int cs_cpu_pm_notifier(struct notifier_block *self,
+ unsigned long cmd, void *v)
+{
+ int cpu = smp_processor_id();
+ switch (cmd) {
+ case CPU_PM_ENTER:
+ cs_suspend_cpu(cpu);
+ break;
+ case CPU_PM_ENTER_FAILED:
+ case CPU_PM_EXIT:
+ cs_resume_cpu(cpu);
+ break;
+ case CPU_CLUSTER_PM_ENTER:
+ break;
+ case CPU_CLUSTER_PM_ENTER_FAILED:
+ case CPU_CLUSTER_PM_EXIT:
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+static int __cpuinit cs_cpu_notifier(struct notifier_block *nfb,
+ unsigned long action, void *hcpu)
+{
+ int cpu = (unsigned long)hcpu;
+
+ switch (action & ~CPU_TASKS_FROZEN) {
+ case CPU_STARTING:
+ case CPU_DOWN_FAILED:
+ cs_resume_cpu(cpu);
+ break;
+ case CPU_DYING:
+ cs_suspend_cpu(cpu);
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+static struct syscore_ops cs_syscore_ops = {
+ .suspend = cs_suspend,
+ .resume = cs_resume,
+};
+
+static struct notifier_block __cpuinitdata cs_cpu_pm_notifier_block = {
+ .notifier_call = cs_cpu_pm_notifier,
+};
+
+static struct notifier_block __cpuinitdata cs_cpu_notifier_block = {
+ .notifier_call = cs_cpu_notifier,
+};
+
+static int __init cs_exynos5_init(void)
+{
+ int i;
+ int ret;
+
+ if (!soc_is_exynos5250())
+ return -ENODEV;
+
+ cs_etb_regs = ioremap(CS_ETB_BASE, SZ_4K);
+ if (!cs_etb_regs)
+ return -ENOMEM;
+
+ cs_funnel_regs = ioremap(CS_FUNNEL_BASE, SZ_4K);
+ if (!cs_funnel_regs)
+ return -ENOMEM;
+
+ cs_ptm_regs[0] = ioremap(CS_PTM0_BASE, SZ_4K);
+ if (!cs_ptm_regs[0])
+ return -ENOMEM;
+
+ cs_ptm_regs[1] = ioremap(CS_PTM1_BASE, SZ_4K);
+ if (!cs_ptm_regs[1])
+ return -ENOMEM;
+
+ cs_init_static_regs();
+ for (i = 0; i < ARRAY_SIZE(cs_ptm_regs); i++) {
+ cs_unlock(cs_ptm_regs[i]);
+ writel(0, cs_ptm_regs[i] + ETMMR_OSLAR);
+ cs_relock(cs_ptm_regs[i]);
+ }
+
+ ret = cpu_pm_register_notifier(&cs_cpu_pm_notifier_block);
+ if (ret < 0)
+ return ret;
+
+ ret = register_cpu_notifier(&cs_cpu_notifier_block);
+ if (ret < 0)
+ return ret;
+
+ register_syscore_ops(&cs_syscore_ops);
+
+ ret = amba_device_register(&s5p_device_etb, &iomem_resource);
+ if (ret < 0)
+ return ret;
+ ret = amba_device_register(&s5p_device_ptm0, &iomem_resource);
+ if (ret < 0)
+ return ret;
+ ret = amba_device_register(&s5p_device_ptm1, &iomem_resource);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+subsys_initcall(cs_exynos5_init);
diff --git a/arch/arm/mach-exynos/cpuidle.c b/arch/arm/mach-exynos/cpuidle.c
index 33ab4e7..4f73dff 100644
--- a/arch/arm/mach-exynos/cpuidle.c
+++ b/arch/arm/mach-exynos/cpuidle.c
@@ -1,5 +1,4 @@
-/* linux/arch/arm/mach-exynos4/cpuidle.c
- *
+/*
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
@@ -10,128 +9,303 @@
#include <linux/kernel.h>
#include <linux/init.h>
+#include <linux/clockchips.h>
+#include <linux/cpu.h>
#include <linux/cpuidle.h>
#include <linux/cpu_pm.h>
+#include <linux/delay.h>
#include <linux/io.h>
#include <linux/export.h>
+#include <linux/moduleparam.h>
+#include <linux/ratelimit.h>
#include <linux/time.h>
+#include <linux/serial_core.h>
+#include <asm/cp15.h>
+#include <asm/cacheflush.h>
#include <asm/proc-fns.h>
#include <asm/smp_scu.h>
#include <asm/suspend.h>
#include <asm/unified.h>
+#include <asm/hardware/gic.h>
#include <mach/regs-pmu.h>
+#include <mach/regs-clock.h>
#include <mach/pmu.h>
+#include <mach/smc.h>
+#include <plat/pm.h>
#include <plat/cpu.h>
+#include <plat/regs-serial.h>
+#include <plat/regs-watchdog.h>
-#define REG_DIRECTGO_ADDR (samsung_rev() == EXYNOS4210_REV_1_1 ? \
- S5P_INFORM7 : (samsung_rev() == EXYNOS4210_REV_1_0 ? \
- (S5P_VA_SYSRAM + 0x24) : S5P_INFORM0))
-#define REG_DIRECTGO_FLAG (samsung_rev() == EXYNOS4210_REV_1_1 ? \
- S5P_INFORM6 : (samsung_rev() == EXYNOS4210_REV_1_0 ? \
- (S5P_VA_SYSRAM + 0x20) : S5P_INFORM1))
+#include <trace/events/power.h>
-#define S5P_CHECK_AFTR 0xFCBA0D10
+#ifdef CONFIG_ARM_TRUSTZONE
+#define REG_DIRECTGO_ADDR (S5P_VA_SYSRAM_NS + 0x24)
+#define REG_DIRECTGO_FLAG (S5P_VA_SYSRAM_NS + 0x20)
+#define BOOT_VECTOR (S5P_VA_SYSRAM_NS + 0x1C)
+#else
+#define REG_DIRECTGO_ADDR (S5P_VA_SYSRAM + 0x24)
+#define REG_DIRECTGO_FLAG (S5P_VA_SYSRAM + 0x20)
+#define BOOT_VECTOR S5P_VA_SYSRAM
+#endif
-static int exynos4_enter_idle(struct cpuidle_device *dev,
- struct cpuidle_driver *drv,
- int index);
-static int exynos4_enter_lowpower(struct cpuidle_device *dev,
- struct cpuidle_driver *drv,
- int index);
+static bool allow_coupled_idle = true;
+static bool allow_lpa = false;
+module_param(allow_coupled_idle, bool, 0644);
+module_param(allow_lpa, bool, 0644);
-static struct cpuidle_state exynos4_cpuidle_set[] __initdata = {
+#define EXYNOS_CHECK_DIRECTGO 0xFCBA0D10
+
+static atomic_t exynos_idle_barrier;
+static volatile bool cpu1_abort;
+#ifdef CONFIG_ARM_TRUSTZONE
+static unsigned int misc_save;
+#endif
+
+static int exynos_enter_idle(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv,
+ int index);
+static int exynos_enter_lowpower(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv,
+ int index);
+
+static inline void cpu_enter_lowpower_a9(void)
+{
+ unsigned int v;
+
+ flush_cache_all();
+ asm volatile(
+ " mcr p15, 0, %1, c7, c5, 0\n"
+ " mcr p15, 0, %1, c7, c10, 4\n"
+ /*
+ * Turn off coherency
+ */
+ " mrc p15, 0, %0, c1, c0, 1\n"
+ " bic %0, %0, %3\n"
+ " mcr p15, 0, %0, c1, c0, 1\n"
+ " mrc p15, 0, %0, c1, c0, 0\n"
+ " bic %0, %0, %2\n"
+ " mcr p15, 0, %0, c1, c0, 0\n"
+ : "=&r" (v)
+ : "r" (0), "Ir" (CR_C), "Ir" (0x40)
+ : "cc");
+}
+
+static inline void cpu_enter_lowpower_a15(void)
+{
+ unsigned int v;
+
+ asm volatile(
+ " mrc p15, 0, %0, c1, c0, 0\n"
+ " bic %0, %0, %1\n"
+ " mcr p15, 0, %0, c1, c0, 0\n"
+ : "=&r" (v)
+ : "Ir" (CR_C)
+ : "cc");
+
+ flush_cache_all();
+
+#ifdef CONFIG_ARM_TRUSTZONE
+ asm volatile("mrc p15, 0, %0, c1, c0, 1" : "=r" (misc_save));
+#endif
+
+ asm volatile(
+ /*
+ * Turn off coherency
+ */
+ " dmb\n"
+ " mrc p15, 0, %0, c1, c0, 1\n"
+ " bic %0, %0, %1\n"
+ " mcr p15, 0, %0, c1, c0, 1\n"
+ : "=&r" (v)
+ : "Ir" (0x40)
+ : "cc");
+
+ isb();
+ dsb();
+}
+
+static inline void cpu_leave_lowpower(void)
+{
+ unsigned int v;
+
+ asm volatile(
+ "mrc p15, 0, %0, c1, c0, 0\n"
+ " orr %0, %0, %1\n"
+ " mcr p15, 0, %0, c1, c0, 0\n"
+ " mrc p15, 0, %0, c1, c0, 1\n"
+ " orr %0, %0, %2\n"
+ " mcr p15, 0, %0, c1, c0, 1\n"
+ : "=&r" (v)
+ : "Ir" (CR_C), "Ir" (0x40)
+ : "cc");
+
+#ifdef CONFIG_ARM_TRUSTZONE
+ if (v != misc_save)
+ exynos_smc(SMC_CMD_REG, SMC_REG_ID_CP15(1, 0, 0, 1), misc_save, 0);
+#endif
+}
+
+struct check_reg_lpa {
+ void __iomem *check_reg;
+ unsigned int check_bit;
+};
+
+/*
+ * List of check power domain list for LPA mode
+ * These register are have to power off to enter LPA mode
+ */
+static struct check_reg_lpa exynos5_power_domain[] = {
+ {.check_reg = EXYNOS5_GSCL_STATUS, .check_bit = 0x7},
+ {.check_reg = EXYNOS5_G3D_STATUS, .check_bit = 0x7},
+};
+
+/*
+ * List of check clock gating list for LPA mode
+ * If clock of list is not gated, system can not enter LPA mode.
+ */
+static struct check_reg_lpa exynos5_clock_gating[] = {
+ {.check_reg = EXYNOS5_CLKSRC_MASK_DISP1_0, .check_bit = 0x00000001},
+ {.check_reg = EXYNOS5_CLKGATE_IP_DISP1, .check_bit = 0x00000008},
+ {.check_reg = EXYNOS5_CLKGATE_IP_MFC, .check_bit = 0x00000001},
+ {.check_reg = EXYNOS5_CLKGATE_IP_GEN, .check_bit = 0x00004016},
+ {.check_reg = EXYNOS5_CLKGATE_IP_FSYS, .check_bit = 0x00000002},
+ {.check_reg = EXYNOS5_CLKGATE_IP_PERIC, .check_bit = 0x00377FC0},
+};
+
+static int exynos_check_reg_status(struct check_reg_lpa *reg_list,
+ unsigned int list_cnt)
+{
+ unsigned int i;
+ unsigned int tmp;
+
+ for (i = 0; i < list_cnt; i++) {
+ tmp = __raw_readl(reg_list[i].check_reg);
+ if (tmp & reg_list[i].check_bit)
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+static int exynos_uart_fifo_check(void)
+{
+ int ret;
+ unsigned int check_val;
+
+ /* Check UART for console is empty */
+ check_val = __raw_readl(S5P_VA_UART(CONFIG_S3C_LOWLEVEL_UART_PORT) +
+ S3C2410_UFSTAT);
+
+ ret = ((check_val >> 16) & 0xff);
+
+ return ret;
+}
+
+static int __maybe_unused exynos_check_enter_mode(void)
+{
+ /* Check power domain */
+ if (exynos_check_reg_status(exynos5_power_domain,
+ ARRAY_SIZE(exynos5_power_domain)))
+ return EXYNOS_CHECK_DIDLE;
+
+ /* Check clock gating */
+ if (exynos_check_reg_status(exynos5_clock_gating,
+ ARRAY_SIZE(exynos5_clock_gating)))
+ return EXYNOS_CHECK_DIDLE;
+
+ return EXYNOS_CHECK_LPA;
+}
+
+static struct cpuidle_state exynos_cpuidle_set[] __initdata = {
[0] = {
- .enter = exynos4_enter_idle,
- .exit_latency = 1,
- .target_residency = 100000,
+ .enter = exynos_enter_idle,
+ .exit_latency = 10,
+ .target_residency = 10,
.flags = CPUIDLE_FLAG_TIME_VALID,
.name = "C0",
.desc = "ARM clock gating(WFI)",
},
[1] = {
- .enter = exynos4_enter_lowpower,
- .exit_latency = 300,
- .target_residency = 100000,
- .flags = CPUIDLE_FLAG_TIME_VALID,
+ .enter = exynos_enter_lowpower,
+ .exit_latency = 5000,
+ .target_residency = 10000,
+ .flags = CPUIDLE_FLAG_TIME_VALID |
+ CPUIDLE_FLAG_COUPLED,
.name = "C1",
.desc = "ARM power down",
},
};
-static DEFINE_PER_CPU(struct cpuidle_device, exynos4_cpuidle_device);
+static DEFINE_PER_CPU(struct cpuidle_device, exynos_cpuidle_device);
-static struct cpuidle_driver exynos4_idle_driver = {
- .name = "exynos4_idle",
+static struct cpuidle_driver exynos_idle_driver = {
+ .name = "exynos_idle",
.owner = THIS_MODULE,
+ .en_core_tk_irqen = true,
};
/* Ext-GIC nIRQ/nFIQ is the only wakeup source in AFTR */
-static void exynos4_set_wakeupmask(void)
+static void exynos_set_wakeupmask(void)
{
- __raw_writel(0x0000ff3e, S5P_WAKEUP_MASK);
+ __raw_writel(0x0000ff3e, EXYNOS_WAKEUP_MASK);
}
-static unsigned int g_pwr_ctrl, g_diag_reg;
-
static void save_cpu_arch_register(void)
{
- /*read power control register*/
- asm("mrc p15, 0, %0, c15, c0, 0" : "=r"(g_pwr_ctrl) : : "cc");
- /*read diagnostic register*/
- asm("mrc p15, 0, %0, c15, c0, 1" : "=r"(g_diag_reg) : : "cc");
- return;
}
static void restore_cpu_arch_register(void)
{
- /*write power control register*/
- asm("mcr p15, 0, %0, c15, c0, 0" : : "r"(g_pwr_ctrl) : "cc");
- /*write diagnostic register*/
- asm("mcr p15, 0, %0, c15, c0, 1" : : "r"(g_diag_reg) : "cc");
- return;
}
-static int idle_finisher(unsigned long flags)
+static int cpu1_idle_finisher(unsigned long flags)
{
cpu_do_idle();
return 1;
}
-static int exynos4_enter_core0_aftr(struct cpuidle_device *dev,
- struct cpuidle_driver *drv,
- int index)
+static int idle_finisher(unsigned long flags)
{
- struct timeval before, after;
- int idle_time;
+#if defined(CONFIG_ARM_TRUSTZONE)
+ exynos_smc(SMC_CMD_CPU0AFTR, 0, 0, 0);
+#else
+ cpu_do_idle();
+#endif
+ return 1;
+}
+
+static int exynos_enter_core0(enum sys_powerdown powerdown)
+{
unsigned long tmp;
- local_irq_disable();
- do_gettimeofday(&before);
-
- exynos4_set_wakeupmask();
-
- /* Set value of power down register for aftr mode */
- exynos4_sys_powerdown_conf(SYS_AFTR);
+ exynos_sys_powerdown_conf(powerdown);
__raw_writel(virt_to_phys(s3c_cpu_resume), REG_DIRECTGO_ADDR);
- __raw_writel(S5P_CHECK_AFTR, REG_DIRECTGO_FLAG);
+ __raw_writel(EXYNOS_CHECK_DIRECTGO, REG_DIRECTGO_FLAG);
save_cpu_arch_register();
/* Setting Central Sequence Register for power down mode */
- tmp = __raw_readl(S5P_CENTRAL_SEQ_CONFIGURATION);
- tmp &= ~S5P_CENTRAL_LOWPWR_CFG;
- __raw_writel(tmp, S5P_CENTRAL_SEQ_CONFIGURATION);
+ tmp = __raw_readl(EXYNOS_CENTRAL_SEQ_CONFIGURATION);
+ tmp &= ~EXYNOS_CENTRAL_LOWPWR_CFG;
+ __raw_writel(tmp, EXYNOS_CENTRAL_SEQ_CONFIGURATION);
- cpu_pm_enter();
+ if (cpu_pm_enter())
+ goto abort_cpu;
+
cpu_suspend(0, idle_finisher);
#ifdef CONFIG_SMP
- scu_enable(S5P_VA_SCU);
+#if !defined(CONFIG_ARM_TRUSTZONE)
+ if (!soc_is_exynos5250())
+ scu_enable(S5P_VA_SCU);
#endif
+#endif
+
cpu_pm_exit();
+abort_cpu:
restore_cpu_arch_register();
@@ -141,26 +315,59 @@
* S5P_CENTRAL_LOWPWR_CFG bit will not be set automatically
* in this situation.
*/
- tmp = __raw_readl(S5P_CENTRAL_SEQ_CONFIGURATION);
- if (!(tmp & S5P_CENTRAL_LOWPWR_CFG)) {
- tmp |= S5P_CENTRAL_LOWPWR_CFG;
- __raw_writel(tmp, S5P_CENTRAL_SEQ_CONFIGURATION);
+ tmp = __raw_readl(EXYNOS_CENTRAL_SEQ_CONFIGURATION);
+ if (!(tmp & EXYNOS_CENTRAL_LOWPWR_CFG)) {
+ tmp |= EXYNOS_CENTRAL_LOWPWR_CFG;
+ __raw_writel(tmp, EXYNOS_CENTRAL_SEQ_CONFIGURATION);
}
+ return 0;
+}
+
+static int exynos_enter_core0_aftr(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv,
+ int index)
+{
+ exynos_set_wakeupmask();
+
+ exynos_enter_core0(SYS_AFTR);
+
/* Clear wakeup state register */
- __raw_writel(0x0, S5P_WAKEUP_STAT);
+ __raw_writel(0x0, EXYNOS_WAKEUP_STAT);
- do_gettimeofday(&after);
-
- local_irq_enable();
- idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC +
- (after.tv_usec - before.tv_usec);
-
- dev->last_residency = idle_time;
return index;
}
-static int exynos4_enter_idle(struct cpuidle_device *dev,
+static int exynos_enter_core0_lpa(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv,
+ int index)
+{
+ /*
+ * Unmasking all wakeup source.
+ */
+ __raw_writel(0x0, EXYNOS_WAKEUP_MASK);
+
+ do {
+ /* Waiting for flushing UART fifo */
+ } while (exynos_uart_fifo_check());
+
+ exynos_enter_core0(SYS_LPA);
+
+ /* For release retention */
+ __raw_writel((1 << 28), EXYNOS_PAD_RET_GPIO_OPTION);
+ __raw_writel((1 << 28), EXYNOS_PAD_RET_UART_OPTION);
+ __raw_writel((1 << 28), EXYNOS_PAD_RET_MMCA_OPTION);
+ __raw_writel((1 << 28), EXYNOS_PAD_RET_MMCB_OPTION);
+ __raw_writel((1 << 28), EXYNOS_PAD_RET_EBIA_OPTION);
+ __raw_writel((1 << 28), EXYNOS_PAD_RET_EBIB_OPTION);
+
+ /* Clear wakeup state register */
+ __raw_writel(0x0, EXYNOS_WAKEUP_STAT);
+
+ return index;
+}
+
+static int exynos_enter_idle(struct cpuidle_device *dev,
struct cpuidle_driver *drv,
int index)
{
@@ -181,48 +388,227 @@
return index;
}
-static int exynos4_enter_lowpower(struct cpuidle_device *dev,
+void exynos_nop(void *info)
+{
+}
+
+static int exynos_enter_lowpower(struct cpuidle_device *dev,
struct cpuidle_driver *drv,
int index)
{
- int new_index = index;
+ int ret = index;
- /* This mode only can be entered when other core's are offline */
- if (num_online_cpus() > 1)
- new_index = drv->safe_state_index;
+ __raw_writel(virt_to_phys(s3c_cpu_resume), BOOT_VECTOR);
+ cpuidle_coupled_parallel_barrier(dev, &exynos_idle_barrier);
- if (new_index == 0)
- return exynos4_enter_idle(dev, drv, new_index);
- else
- return exynos4_enter_core0_aftr(dev, drv, new_index);
+ if (!allow_coupled_idle) {
+ exynos_enter_idle(dev, drv, dev->safe_state_index);
+ smp_call_function_single(!dev->cpu, exynos_nop, NULL, 0);
+ return index;
+ }
+
+ /* Both cpus will reach this point at the same time */
+ if (dev->cpu == 0) {
+ /* Idle sequence for cpu 0 */
+ if (cpu_online(1)) {
+ /* Wait for cpu1 to turn itself off */
+ while (__raw_readl(EXYNOS_ARM_CORE1_STATUS) & 3) {
+ /* cpu1 may skip idle and boot back up again */
+ if (cpu1_abort)
+ goto abort;
+
+ /*
+ * cpu1 may bounce through idle and boot back up
+ * again, getting stuck in the boot rom code
+ */
+ if (__raw_readl(BOOT_VECTOR) == 0)
+ goto abort;
+
+ cpu_relax();
+ }
+ }
+
+ watchdog_save();
+ /* Enter the final low power state */
+ if (exynos_check_enter_mode() == EXYNOS_CHECK_DIDLE || !allow_lpa)
+ ret = exynos_enter_core0_aftr(dev, drv, index);
+ else
+ ret = exynos_enter_core0_lpa(dev, drv, index);
+
+abort:
+ if (cpu_online(1)) {
+ /* Set the boot vector to something non-zero */
+ __raw_writel(virt_to_phys(s3c_cpu_resume),
+ BOOT_VECTOR);
+ dsb();
+
+ /* Turn on cpu1 and wait for it to be on */
+ __raw_writel(0x3, EXYNOS_ARM_CORE1_CONFIGURATION);
+ while ((__raw_readl(EXYNOS_ARM_CORE1_STATUS) & 3) != 3)
+ cpu_relax();
+
+#ifdef CONFIG_ARM_TRUSTZONE
+ exynos_smc(SMC_CMD_CPU1BOOT, 0, 0, 0);
+#endif
+
+ /* Wait for cpu1 to get stuck in the boot rom */
+ while ((__raw_readl(BOOT_VECTOR) != 0) && !cpu1_abort) {
+#ifdef CONFIG_ARM_TRUSTZONE
+ exynos_smc(SMC_CMD_CPU1BOOT, 0, 0, 0);
+#endif
+ cpu_relax();
+ }
+
+ if (!cpu1_abort) {
+ /* Poke cpu1 out of the boot rom */
+ __raw_writel(virt_to_phys(s3c_cpu_resume),
+ BOOT_VECTOR);
+ dsb_sev();
+ }
+
+ /* Wait for cpu1 to finish booting */
+ while (!cpu1_abort)
+ cpu_relax();
+ }
+ watchdog_restore();
+ } else {
+ /* Idle sequence for cpu 1 */
+
+ /*
+ * Turn off localtimer to prevent ticks from waking up cpu 1
+ * before cpu 0.
+ */
+ clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &dev->cpu);
+
+ if (cpu_pm_enter())
+ goto cpu1_aborted;
+
+ cpu_enter_lowpower_a15();
+
+ /* Turn off cpu 1 */
+ __raw_writel(0, EXYNOS_ARM_CORE1_CONFIGURATION);
+ cpu_suspend(0, cpu1_idle_finisher);
+
+ cpu_leave_lowpower();
+
+ cpu_pm_exit();
+ clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu);
+
+cpu1_aborted:
+ /* Notify cpu 0 that cpu 1 is awake */
+ dsb();
+ cpu1_abort = true;
+ }
+
+ cpuidle_coupled_parallel_barrier(dev, &exynos_idle_barrier);
+
+ cpu1_abort = false;
+
+ return ret;
}
-static int __init exynos4_init_cpuidle(void)
+
+static void __setup_broadcast_timer(void *arg)
{
+ unsigned long reason = (unsigned long)arg;
+ int cpu = smp_processor_id();
+
+ reason = reason ?
+ CLOCK_EVT_NOTIFY_BROADCAST_ON : CLOCK_EVT_NOTIFY_BROADCAST_OFF;
+
+ clockevents_notify(reason, &cpu);
+}
+
+static int setup_broadcast_cpuhp_notify(struct notifier_block *n,
+ unsigned long action, void *hcpu)
+{
+ int hotcpu = (unsigned long)hcpu;
+
+ switch (action & 0xf) {
+ case CPU_ONLINE:
+ smp_call_function_single(hotcpu, __setup_broadcast_timer,
+ (void *)true, 1);
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block setup_broadcast_notifier = {
+ .notifier_call = setup_broadcast_cpuhp_notify,
+};
+
+static void __init exynos5_core_down_clk(void)
+{
+ unsigned int tmp;
+
+ tmp = __raw_readl(EXYNOS5_PWR_CTRL1);
+
+ tmp &= ~(PWR_CTRL1_CORE2_DOWN_MASK | PWR_CTRL1_CORE1_DOWN_MASK);
+
+ /* set arm clock divider value on idle state */
+ tmp |= ((0x7 << PWR_CTRL1_CORE2_DOWN_RATIO) |
+ (0x7 << PWR_CTRL1_CORE1_DOWN_RATIO));
+
+ tmp |= (PWR_CTRL1_DIV2_DOWN_EN |
+ PWR_CTRL1_DIV1_DOWN_EN |
+ PWR_CTRL1_USE_CORE1_WFE |
+ PWR_CTRL1_USE_CORE0_WFE |
+ PWR_CTRL1_USE_CORE1_WFI |
+ PWR_CTRL1_USE_CORE0_WFI);
+
+ __raw_writel(tmp, EXYNOS5_PWR_CTRL1);
+
+ tmp = __raw_readl(EXYNOS5_PWR_CTRL2);
+
+ tmp &= ~(PWR_CTRL2_DUR_STANDBY2_MASK | PWR_CTRL2_DUR_STANDBY1_MASK |
+ PWR_CTRL2_CORE2_UP_MASK | PWR_CTRL2_CORE1_UP_MASK);
+
+ /* set duration value on middle wakeup step */
+ tmp |= ((0x1 << PWR_CTRL2_DUR_STANDBY2) |
+ (0x1 << PWR_CTRL2_DUR_STANDBY1));
+
+ /* set arm clock divier value on middle wakeup step */
+ tmp |= ((0x1 << PWR_CTRL2_CORE2_UP_RATIO) |
+ (0x1 << PWR_CTRL2_CORE1_UP_RATIO));
+
+ /* Set PWR_CTRL2 register to use step up for arm clock */
+ tmp |= (PWR_CTRL2_DIV2_UP_EN | PWR_CTRL2_DIV1_UP_EN);
+
+ __raw_writel(tmp, EXYNOS5_PWR_CTRL2);
+ pr_info("Exynos5 : ARM Clock down on idle mode is enabled\n");
+}
+
+static int __init exynos_init_cpuidle(void)
+{
+ int ret;
int i, max_cpuidle_state, cpu_id;
struct cpuidle_device *device;
- struct cpuidle_driver *drv = &exynos4_idle_driver;
+ struct cpuidle_driver *drv = &exynos_idle_driver;
+
+ exynos5_core_down_clk();
/* Setup cpuidle driver */
- drv->state_count = (sizeof(exynos4_cpuidle_set) /
- sizeof(struct cpuidle_state));
+ drv->state_count = ARRAY_SIZE(exynos_cpuidle_set);
+
max_cpuidle_state = drv->state_count;
for (i = 0; i < max_cpuidle_state; i++) {
- memcpy(&drv->states[i], &exynos4_cpuidle_set[i],
+ memcpy(&drv->states[i], &exynos_cpuidle_set[i],
sizeof(struct cpuidle_state));
}
drv->safe_state_index = 0;
- cpuidle_register_driver(&exynos4_idle_driver);
+ cpuidle_register_driver(&exynos_idle_driver);
+
+ on_each_cpu(__setup_broadcast_timer, (void *)true, 1);
+ ret = register_cpu_notifier(&setup_broadcast_notifier);
+ if (ret)
+ pr_err("%s: failed to register cpu notifier\n", __func__);
for_each_cpu(cpu_id, cpu_online_mask) {
- device = &per_cpu(exynos4_cpuidle_device, cpu_id);
+ device = &per_cpu(exynos_cpuidle_device, cpu_id);
device->cpu = cpu_id;
- if (cpu_id == 0)
- device->state_count = (sizeof(exynos4_cpuidle_set) /
- sizeof(struct cpuidle_state));
- else
- device->state_count = 1; /* Support IDLE only */
+ device->state_count = ARRAY_SIZE(exynos_cpuidle_set);
+ device->coupled_cpus = *cpu_possible_mask;
if (cpuidle_register_device(device)) {
printk(KERN_ERR "CPUidle register device failed\n,");
@@ -232,4 +618,4 @@
return 0;
}
-device_initcall(exynos4_init_cpuidle);
+device_initcall(exynos_init_cpuidle);
diff --git a/arch/arm/mach-exynos/dev-audio.c b/arch/arm/mach-exynos/dev-audio.c
index 7199e1a..79c0f57 100644
--- a/arch/arm/mach-exynos/dev-audio.c
+++ b/arch/arm/mach-exynos/dev-audio.c
@@ -11,12 +11,14 @@
* published by the Free Software Foundation.
*/
+#include <linux/ioport.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/gpio.h>
#include <plat/gpio-cfg.h>
#include <plat/audio.h>
+#include <plat/cpu.h>
#include <mach/map.h>
#include <mach/dma.h>
@@ -28,29 +30,44 @@
[1] = "i2sclk",
};
-static int exynos4_cfg_i2s(struct platform_device *pdev)
+struct exynos_gpio_cfg {
+ unsigned int addr;
+ unsigned int num;
+ unsigned int bit;
+};
+
+static int exynos_cfg_i2s_gpio(struct platform_device *pdev)
{
/* configure GPIO for i2s port */
- switch (pdev->id) {
- case 0:
- s3c_gpio_cfgpin_range(EXYNOS4_GPZ(0), 7, S3C_GPIO_SFN(2));
- break;
- case 1:
- s3c_gpio_cfgpin_range(EXYNOS4_GPC0(0), 5, S3C_GPIO_SFN(2));
- break;
- case 2:
- s3c_gpio_cfgpin_range(EXYNOS4_GPC1(0), 5, S3C_GPIO_SFN(4));
- break;
- default:
+ struct exynos_gpio_cfg exynos4_cfg[3] = {
+ { EXYNOS4_GPZ(0), 7, S3C_GPIO_SFN(2) },
+ { EXYNOS4_GPC0(0), 5, S3C_GPIO_SFN(2) },
+ { EXYNOS4_GPC1(0), 5, S3C_GPIO_SFN(2) }
+ };
+ struct exynos_gpio_cfg exynos5_cfg[3] = {
+ { EXYNOS5_GPZ(0), 7, S3C_GPIO_SFN(2) },
+ { EXYNOS5_GPB0(0), 5, S3C_GPIO_SFN(2) },
+ { EXYNOS5_GPB1(0), 5, S3C_GPIO_SFN(2) }
+ };
+
+ if (pdev->id < 0 || pdev->id > 2) {
printk(KERN_ERR "Invalid Device %d\n", pdev->id);
return -EINVAL;
}
+ if (soc_is_exynos5250())
+ s3c_gpio_cfgpin_range(exynos5_cfg[pdev->id].addr,
+ exynos5_cfg[pdev->id].num, exynos5_cfg[pdev->id].bit);
+
+ else /* EXYNOS4210, EXYNOS4212 and EXYNOS4412 */
+ s3c_gpio_cfgpin_range(exynos4_cfg[pdev->id].addr,
+ exynos4_cfg[pdev->id].num, exynos4_cfg[pdev->id].bit);
+
return 0;
}
static struct s3c_audio_pdata i2sv5_pdata = {
- .cfg_gpio = exynos4_cfg_i2s,
+ .cfg_gpio = exynos_cfg_i2s_gpio,
.type = {
.i2s = {
.quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI
@@ -62,26 +79,17 @@
};
static struct resource exynos4_i2s0_resource[] = {
- [0] = {
- .start = EXYNOS4_PA_I2S0,
- .end = EXYNOS4_PA_I2S0 + 0x100 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = DMACH_I2S0_TX,
- .end = DMACH_I2S0_TX,
- .flags = IORESOURCE_DMA,
- },
- [2] = {
- .start = DMACH_I2S0_RX,
- .end = DMACH_I2S0_RX,
- .flags = IORESOURCE_DMA,
- },
- [3] = {
- .start = DMACH_I2S0S_TX,
- .end = DMACH_I2S0S_TX,
- .flags = IORESOURCE_DMA,
- },
+ [0] = DEFINE_RES_MEM(EXYNOS4_PA_I2S0, 0x100),
+ [1] = DEFINE_RES_DMA(DMACH_I2S0_TX),
+ [2] = DEFINE_RES_DMA(DMACH_I2S0_RX),
+ [3] = DEFINE_RES_DMA(DMACH_I2S0S_TX),
+};
+
+static struct resource exynos5_i2s0_resource[] = {
+ [0] = DEFINE_RES_MEM(EXYNOS5_PA_I2S0, 0x100),
+ [1] = DEFINE_RES_DMA(DMACH_I2S0_TX),
+ [2] = DEFINE_RES_DMA(DMACH_I2S0_RX),
+ [3] = DEFINE_RES_DMA(DMACH_I2S0S_TX),
};
struct platform_device exynos4_device_i2s0 = {
@@ -94,13 +102,23 @@
},
};
+struct platform_device exynos5_device_i2s0 = {
+ .name = "samsung-i2s",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(exynos5_i2s0_resource),
+ .resource = exynos5_i2s0_resource,
+ .dev = {
+ .platform_data = &i2sv5_pdata,
+ },
+};
+
static const char *rclksrc_v3[] = {
[0] = "sclk_i2s",
[1] = "no_such_clock",
};
static struct s3c_audio_pdata i2sv3_pdata = {
- .cfg_gpio = exynos4_cfg_i2s,
+ .cfg_gpio = exynos_cfg_i2s_gpio,
.type = {
.i2s = {
.quirks = QUIRK_NO_MUXPSR,
@@ -110,21 +128,15 @@
};
static struct resource exynos4_i2s1_resource[] = {
- [0] = {
- .start = EXYNOS4_PA_I2S1,
- .end = EXYNOS4_PA_I2S1 + 0x100 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = DMACH_I2S1_TX,
- .end = DMACH_I2S1_TX,
- .flags = IORESOURCE_DMA,
- },
- [2] = {
- .start = DMACH_I2S1_RX,
- .end = DMACH_I2S1_RX,
- .flags = IORESOURCE_DMA,
- },
+ [0] = DEFINE_RES_MEM(EXYNOS4_PA_I2S1, 0x100),
+ [1] = DEFINE_RES_DMA(DMACH_I2S1_TX),
+ [2] = DEFINE_RES_DMA(DMACH_I2S1_RX),
+};
+
+static struct resource exynos5_i2s1_resource[] = {
+ [0] = DEFINE_RES_MEM(EXYNOS5_PA_I2S1, 0x100),
+ [1] = DEFINE_RES_DMA(DMACH_I2S1_TX),
+ [2] = DEFINE_RES_DMA(DMACH_I2S1_RX),
};
struct platform_device exynos4_device_i2s1 = {
@@ -137,22 +149,26 @@
},
};
+struct platform_device exynos5_device_i2s1 = {
+ .name = "samsung-i2s",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(exynos5_i2s1_resource),
+ .resource = exynos5_i2s1_resource,
+ .dev = {
+ .platform_data = &i2sv3_pdata,
+ },
+};
+
static struct resource exynos4_i2s2_resource[] = {
- [0] = {
- .start = EXYNOS4_PA_I2S2,
- .end = EXYNOS4_PA_I2S2 + 0x100 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = DMACH_I2S2_TX,
- .end = DMACH_I2S2_TX,
- .flags = IORESOURCE_DMA,
- },
- [2] = {
- .start = DMACH_I2S2_RX,
- .end = DMACH_I2S2_RX,
- .flags = IORESOURCE_DMA,
- },
+ [0] = DEFINE_RES_MEM(EXYNOS4_PA_I2S2, 0x100),
+ [1] = DEFINE_RES_DMA(DMACH_I2S2_TX),
+ [2] = DEFINE_RES_DMA(DMACH_I2S2_RX),
+};
+
+static struct resource exynos5_i2s2_resource[] = {
+ [0] = DEFINE_RES_MEM(EXYNOS5_PA_I2S2, 0x100),
+ [1] = DEFINE_RES_DMA(DMACH_I2S2_TX),
+ [2] = DEFINE_RES_DMA(DMACH_I2S2_RX),
};
struct platform_device exynos4_device_i2s2 = {
@@ -165,48 +181,62 @@
},
};
+struct platform_device exynos5_device_i2s2 = {
+ .name = "samsung-i2s",
+ .id = 2,
+ .num_resources = ARRAY_SIZE(exynos5_i2s2_resource),
+ .resource = exynos5_i2s2_resource,
+ .dev = {
+ .platform_data = &i2sv3_pdata,
+ },
+};
+
/* PCM Controller platform_devices */
-static int exynos4_pcm_cfg_gpio(struct platform_device *pdev)
+static int exynos_pcm_cfg_gpio(struct platform_device *pdev)
{
- switch (pdev->id) {
- case 0:
- s3c_gpio_cfgpin_range(EXYNOS4_GPZ(0), 5, S3C_GPIO_SFN(3));
- break;
- case 1:
- s3c_gpio_cfgpin_range(EXYNOS4_GPC0(0), 5, S3C_GPIO_SFN(3));
- break;
- case 2:
- s3c_gpio_cfgpin_range(EXYNOS4_GPC1(0), 5, S3C_GPIO_SFN(3));
- break;
- default:
- printk(KERN_DEBUG "Invalid PCM Controller number!");
+ /* configure GPIO for pcm port */
+ struct exynos_gpio_cfg exynos4_cfg[3] = {
+ { EXYNOS4_GPZ(0), 5, S3C_GPIO_SFN(3) },
+ { EXYNOS4_GPC0(0), 5, S3C_GPIO_SFN(3) },
+ { EXYNOS4_GPC1(0), 5, S3C_GPIO_SFN(3) }
+ };
+ struct exynos_gpio_cfg exynos5_cfg[3] = {
+ { EXYNOS5_GPZ(0), 5, S3C_GPIO_SFN(3) },
+ { EXYNOS5_GPB0(0), 5, S3C_GPIO_SFN(3) },
+ { EXYNOS5_GPB1(0), 5, S3C_GPIO_SFN(3) }
+ };
+
+ if (pdev->id < 0 || pdev->id > 2) {
+ printk(KERN_ERR "Invalid Device %d\n", pdev->id);
return -EINVAL;
}
+ if (soc_is_exynos5250())
+ s3c_gpio_cfgpin_range(exynos5_cfg[pdev->id].addr,
+ exynos5_cfg[pdev->id].num, exynos5_cfg[pdev->id].bit);
+
+ else /* EXYNOS4210, EXYNOS4212 and EXYNOS4412 */
+ s3c_gpio_cfgpin_range(exynos4_cfg[pdev->id].addr,
+ exynos4_cfg[pdev->id].num, exynos4_cfg[pdev->id].bit);
+
return 0;
}
static struct s3c_audio_pdata s3c_pcm_pdata = {
- .cfg_gpio = exynos4_pcm_cfg_gpio,
+ .cfg_gpio = exynos_pcm_cfg_gpio,
};
static struct resource exynos4_pcm0_resource[] = {
- [0] = {
- .start = EXYNOS4_PA_PCM0,
- .end = EXYNOS4_PA_PCM0 + 0x100 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = DMACH_PCM0_TX,
- .end = DMACH_PCM0_TX,
- .flags = IORESOURCE_DMA,
- },
- [2] = {
- .start = DMACH_PCM0_RX,
- .end = DMACH_PCM0_RX,
- .flags = IORESOURCE_DMA,
- },
+ [0] = DEFINE_RES_MEM(EXYNOS4_PA_PCM0, 0x100),
+ [1] = DEFINE_RES_DMA(DMACH_PCM0_TX),
+ [2] = DEFINE_RES_DMA(DMACH_PCM0_RX),
+};
+
+static struct resource exynos5_pcm0_resource[] = {
+ [0] = DEFINE_RES_MEM(EXYNOS5_PA_PCM0, 0x100),
+ [1] = DEFINE_RES_DMA(DMACH_PCM0_TX),
+ [2] = DEFINE_RES_DMA(DMACH_PCM0_RX),
};
struct platform_device exynos4_device_pcm0 = {
@@ -219,22 +249,26 @@
},
};
+struct platform_device exynos5_device_pcm0 = {
+ .name = "samsung-pcm",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(exynos5_pcm0_resource),
+ .resource = exynos5_pcm0_resource,
+ .dev = {
+ .platform_data = &s3c_pcm_pdata,
+ },
+};
+
static struct resource exynos4_pcm1_resource[] = {
- [0] = {
- .start = EXYNOS4_PA_PCM1,
- .end = EXYNOS4_PA_PCM1 + 0x100 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = DMACH_PCM1_TX,
- .end = DMACH_PCM1_TX,
- .flags = IORESOURCE_DMA,
- },
- [2] = {
- .start = DMACH_PCM1_RX,
- .end = DMACH_PCM1_RX,
- .flags = IORESOURCE_DMA,
- },
+ [0] = DEFINE_RES_MEM(EXYNOS4_PA_PCM1, 0x100),
+ [1] = DEFINE_RES_DMA(DMACH_PCM1_TX),
+ [2] = DEFINE_RES_DMA(DMACH_PCM1_RX),
+};
+
+static struct resource exynos5_pcm1_resource[] = {
+ [0] = DEFINE_RES_MEM(EXYNOS5_PA_PCM1, 0x100),
+ [1] = DEFINE_RES_DMA(DMACH_PCM1_TX),
+ [2] = DEFINE_RES_DMA(DMACH_PCM1_RX),
};
struct platform_device exynos4_device_pcm1 = {
@@ -247,22 +281,26 @@
},
};
+struct platform_device exynos5_device_pcm1 = {
+ .name = "samsung-pcm",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(exynos5_pcm1_resource),
+ .resource = exynos5_pcm1_resource,
+ .dev = {
+ .platform_data = &s3c_pcm_pdata,
+ },
+};
+
static struct resource exynos4_pcm2_resource[] = {
- [0] = {
- .start = EXYNOS4_PA_PCM2,
- .end = EXYNOS4_PA_PCM2 + 0x100 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = DMACH_PCM2_TX,
- .end = DMACH_PCM2_TX,
- .flags = IORESOURCE_DMA,
- },
- [2] = {
- .start = DMACH_PCM2_RX,
- .end = DMACH_PCM2_RX,
- .flags = IORESOURCE_DMA,
- },
+ [0] = DEFINE_RES_MEM(EXYNOS4_PA_PCM2, 0x100),
+ [1] = DEFINE_RES_DMA(DMACH_PCM2_TX),
+ [2] = DEFINE_RES_DMA(DMACH_PCM2_RX),
+};
+
+static struct resource exynos5_pcm2_resource[] = {
+ [0] = DEFINE_RES_MEM(EXYNOS5_PA_PCM2, 0x100),
+ [1] = DEFINE_RES_DMA(DMACH_PCM2_TX),
+ [2] = DEFINE_RES_DMA(DMACH_PCM2_RX),
};
struct platform_device exynos4_device_pcm2 = {
@@ -275,46 +313,43 @@
},
};
+struct platform_device exynos5_device_pcm2 = {
+ .name = "samsung-pcm",
+ .id = 2,
+ .num_resources = ARRAY_SIZE(exynos5_pcm2_resource),
+ .resource = exynos5_pcm2_resource,
+ .dev = {
+ .platform_data = &s3c_pcm_pdata,
+ },
+};
+
/* AC97 Controller platform devices */
-static int exynos4_ac97_cfg_gpio(struct platform_device *pdev)
+static int exynos_ac97_cfg_gpio(struct platform_device *pdev)
{
- return s3c_gpio_cfgpin_range(EXYNOS4_GPC0(0), 5, S3C_GPIO_SFN(4));
+ /* configure GPIO for ac97 port */
+ if (soc_is_exynos5250())
+ s3c_gpio_cfgpin_range(EXYNOS5_GPB0(0), 5, S3C_GPIO_SFN(4));
+
+ else /* EXYNOS4210, EXYNOS4212 and EXYNOS4412 */
+ s3c_gpio_cfgpin_range(EXYNOS4_GPC0(0), 5, S3C_GPIO_SFN(4));
+
+ return 0;
}
static struct resource exynos4_ac97_resource[] = {
- [0] = {
- .start = EXYNOS4_PA_AC97,
- .end = EXYNOS4_PA_AC97 + 0x100 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = DMACH_AC97_PCMOUT,
- .end = DMACH_AC97_PCMOUT,
- .flags = IORESOURCE_DMA,
- },
- [2] = {
- .start = DMACH_AC97_PCMIN,
- .end = DMACH_AC97_PCMIN,
- .flags = IORESOURCE_DMA,
- },
- [3] = {
- .start = DMACH_AC97_MICIN,
- .end = DMACH_AC97_MICIN,
- .flags = IORESOURCE_DMA,
- },
- [4] = {
- .start = EXYNOS4_IRQ_AC97,
- .end = EXYNOS4_IRQ_AC97,
- .flags = IORESOURCE_IRQ,
- },
+ [0] = DEFINE_RES_MEM(EXYNOS4_PA_AC97, 0x100),
+ [1] = DEFINE_RES_DMA(DMACH_AC97_PCMOUT),
+ [2] = DEFINE_RES_DMA(DMACH_AC97_PCMIN),
+ [3] = DEFINE_RES_DMA(DMACH_AC97_MICIN),
+ [4] = DEFINE_RES_IRQ(EXYNOS4_IRQ_AC97),
};
static struct s3c_audio_pdata s3c_ac97_pdata = {
- .cfg_gpio = exynos4_ac97_cfg_gpio,
+ .cfg_gpio = exynos_ac97_cfg_gpio,
};
-static u64 exynos4_ac97_dmamask = DMA_BIT_MASK(32);
+static u64 exynos_ac97_dmamask = DMA_BIT_MASK(32);
struct platform_device exynos4_device_ac97 = {
.name = "samsung-ac97",
@@ -323,38 +358,40 @@
.resource = exynos4_ac97_resource,
.dev = {
.platform_data = &s3c_ac97_pdata,
- .dma_mask = &exynos4_ac97_dmamask,
+ .dma_mask = &exynos_ac97_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32),
},
};
/* S/PDIF Controller platform_device */
-static int exynos4_spdif_cfg_gpio(struct platform_device *pdev)
+static int exynos_spdif_cfg_gpio(struct platform_device *pdev)
{
- s3c_gpio_cfgpin_range(EXYNOS4_GPC1(0), 2, S3C_GPIO_SFN(4));
+ /* configure GPIO for SPDIF port */
+ if (soc_is_exynos5250())
+ s3c_gpio_cfgpin_range(EXYNOS5_GPB1(0), 2, S3C_GPIO_SFN(4));
+
+ else /* EXYNOS4210, EXYNOS4212 and EXYNOS4412 */
+ s3c_gpio_cfgpin_range(EXYNOS4_GPC1(0), 2, S3C_GPIO_SFN(4));
return 0;
}
static struct resource exynos4_spdif_resource[] = {
- [0] = {
- .start = EXYNOS4_PA_SPDIF,
- .end = EXYNOS4_PA_SPDIF + 0x100 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = DMACH_SPDIF,
- .end = DMACH_SPDIF,
- .flags = IORESOURCE_DMA,
- },
+ [0] = DEFINE_RES_MEM(EXYNOS4_PA_SPDIF, 0x100),
+ [1] = DEFINE_RES_DMA(DMACH_SPDIF),
+};
+
+static struct resource exynos5_spdif_resource[] = {
+ [0] = DEFINE_RES_MEM(EXYNOS5_PA_SPDIF, 0x100),
+ [1] = DEFINE_RES_DMA(DMACH_SPDIF),
};
static struct s3c_audio_pdata samsung_spdif_pdata = {
- .cfg_gpio = exynos4_spdif_cfg_gpio,
+ .cfg_gpio = exynos_spdif_cfg_gpio,
};
-static u64 exynos4_spdif_dmamask = DMA_BIT_MASK(32);
+static u64 exynos_spdif_dmamask = DMA_BIT_MASK(32);
struct platform_device exynos4_device_spdif = {
.name = "samsung-spdif",
@@ -363,7 +400,37 @@
.resource = exynos4_spdif_resource,
.dev = {
.platform_data = &samsung_spdif_pdata,
- .dma_mask = &exynos4_spdif_dmamask,
+ .dma_mask = &exynos_spdif_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+};
+
+struct platform_device exynos5_device_spdif = {
+ .name = "samsung-spdif",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(exynos5_spdif_resource),
+ .resource = exynos5_spdif_resource,
+ .dev = {
+ .platform_data = &samsung_spdif_pdata,
+ .dma_mask = &exynos_spdif_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+};
+
+static struct resource exynos5_srp_resource[] = {
+ [0] = DEFINE_RES_MEM(EXYNOS_PA_AUDSS_INTMEM, 0x49000),
+ [1] = DEFINE_RES_MEM(EXYNOS_PA_AUDSS_COMMBOX, 0x200),
+};
+
+static u64 exynos_srp_dmamask = DMA_BIT_MASK(32);
+
+struct platform_device exynos5_device_srp = {
+ .name = "samsung-rp",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(exynos5_srp_resource),
+ .resource = exynos5_srp_resource,
+ .dev = {
+ .dma_mask = &exynos_srp_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32),
},
};
diff --git a/arch/arm/mach-exynos/dev-bts.c b/arch/arm/mach-exynos/dev-bts.c
new file mode 100644
index 0000000..2ae1fbf
--- /dev/null
+++ b/arch/arm/mach-exynos/dev-bts.c
@@ -0,0 +1,282 @@
+/* linux/arch/arm/mach-exynos/dev-bts.c
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * 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 <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+
+#include <plat/devs.h>
+#include <plat/irqs.h>
+#include <plat/cpu.h>
+#include <plat/bts.h>
+
+#include <mach/map.h>
+#include <mach/irqs.h>
+#include <mach/map.h>
+
+static struct resource exynos_bts_fbm_ddr_r1_resource[] = {
+ [0] = {
+ .start = EXYNOS5_PA_BTS_FBM_DDR_R1,
+ .end = EXYNOS5_PA_BTS_FBM_DDR_R1 + SZ_1K,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct resource exynos_bts_cpu_resource[] = {
+ [0] = {
+ .start = EXYNOS5_PA_BTS_CPU,
+ .end = EXYNOS5_PA_BTS_CPU + SZ_1K,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct resource exynos_bts_jpeg_resource[] = {
+ [0] = {
+ .start = EXYNOS5_PA_BTS_JPEG,
+ .end = EXYNOS5_PA_BTS_JPEG + SZ_1K,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct resource exynos_bts_gscl0_resource[] = {
+ [0] = {
+ .start = EXYNOS5_PA_BTS_GSCL0,
+ .end = EXYNOS5_PA_BTS_GSCL0 + SZ_1K,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct resource exynos_bts_gscl1_resource[] = {
+ [0] = {
+ .start = EXYNOS5_PA_BTS_GSCL1,
+ .end = EXYNOS5_PA_BTS_GSCL1 + SZ_1K,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct resource exynos_bts_gscl2_resource[] = {
+ [0] = {
+ .start = EXYNOS5_PA_BTS_GSCL2,
+ .end = EXYNOS5_PA_BTS_GSCL2 + SZ_1K,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct resource exynos_bts_gscl3_resource[] = {
+ [0] = {
+ .start = EXYNOS5_PA_BTS_GSCL3,
+ .end = EXYNOS5_PA_BTS_GSCL3 + SZ_1K,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct resource exynos_bts_mfc_resource[] = {
+ [0] = {
+ .start = EXYNOS5_PA_BTS_MFC0,
+ .end = EXYNOS5_PA_BTS_MFC0 + SZ_1K,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = EXYNOS5_PA_BTS_MFC1,
+ .end = EXYNOS5_PA_BTS_MFC1 + SZ_1K,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct resource exynos_bts_g3dacp_resource[] = {
+ [0] = {
+ .start = EXYNOS5_PA_BTS_G3D_ACP,
+ .end = EXYNOS5_PA_BTS_G3D_ACP + SZ_1K,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+#if defined(CONFIG_EXYNOS4_DEV_FIMC_IS)
+static struct resource exynos_bts_isp0_resource[] = {
+ [0] = {
+ .start = EXYNOS5_PA_BTS_FIMC_ISP,
+ .end = EXYNOS5_PA_BTS_FIMC_ISP + SZ_1K,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = EXYNOS5_PA_BTS_FIMC_FD,
+ .end = EXYNOS5_PA_BTS_FIMC_FD + SZ_1K,
+ .flags = IORESOURCE_MEM,
+ },
+ [2] = {
+ .start = EXYNOS5_PA_BTS_FIMC_SCALER_C,
+ .end = EXYNOS5_PA_BTS_FIMC_SCALER_C + SZ_1K,
+ .flags = IORESOURCE_MEM,
+ },
+ [3] = {
+ .start = EXYNOS5_PA_BTS_FIMC_SCALER_P,
+ .end = EXYNOS5_PA_BTS_FIMC_SCALER_P + SZ_1K,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct resource exynos_bts_isp1_resource[] = {
+ [0] = {
+ .start = EXYNOS5_PA_BTS_FIMC_ODC,
+ .end = EXYNOS5_PA_BTS_FIMC_ODC + SZ_1K,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = EXYNOS5_PA_BTS_FIMC_DIS0,
+ .end = EXYNOS5_PA_BTS_FIMC_DIS0 + SZ_1K,
+ .flags = IORESOURCE_MEM,
+ },
+ [2] = {
+ .start = EXYNOS5_PA_BTS_FIMC_DIS1,
+ .end = EXYNOS5_PA_BTS_FIMC_DIS1 + SZ_1K,
+ .flags = IORESOURCE_MEM,
+ },
+ [3] = {
+ .start = EXYNOS5_PA_BTS_FIMC_3DNR,
+ .end = EXYNOS5_PA_BTS_FIMC_3DNR + SZ_1K,
+ .flags = IORESOURCE_MEM,
+ },
+};
+#endif
+
+static struct resource exynos_bts_disp_resource[] = {
+ [0] = {
+ .start = EXYNOS5_PA_BTS_DISP10,
+ .end = EXYNOS5_PA_BTS_DISP10 + SZ_1K,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = EXYNOS5_PA_BTS_DISP11,
+ .end = EXYNOS5_PA_BTS_DISP11 + SZ_1K,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct resource exynos_bts_mixer_resource[] = {
+ [0] = {
+ .start = EXYNOS5_PA_BTS_MIXER0,
+ .end = EXYNOS5_PA_BTS_MIXER0 + SZ_1K,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = EXYNOS5_PA_BTS_MIXER1,
+ .end = EXYNOS5_PA_BTS_MIXER1 + SZ_1K,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+struct exynos_fbm_resource fbm_res[] = {
+ {
+ .port_name = BTS_FBM_G1_R,
+ .deblock_src_order = BTS_2ND_FBM_SRC,
+ }, {
+ .port_name = BTS_FBM_G1_L,
+ .deblock_src_order = BTS_1ST_FBM_SRC,
+ }
+};
+
+struct exynos_fbm_pdata fbm_pdata = {
+ .res = fbm_res,
+ .res_num = ARRAY_SIZE(fbm_res),
+};
+
+#define EXYNOS_BTS_PDATA(_name, _prio, _block, _clkname, _changable, _th_changable, _act)\
+static struct exynos_bts_pdata bts_##_name##_res = { \
+ .def_priority = _prio, \
+ .pd_name = _block, \
+ .clk_name = _clkname, \
+ .fbm = &fbm_pdata, \
+ .res_num = ARRAY_SIZE(exynos_bts_##_name##_resource), \
+ .deblock_changable = _changable, \
+ .threshold_changable = _th_changable, \
+ .traffic_control_act = _act, \
+}
+
+EXYNOS_BTS_PDATA(fbm_ddr_r1, BTS_FBM_DDR_R1, NULL, NULL, 0, 1, BTS_NO_ACTION);
+EXYNOS_BTS_PDATA(cpu, BTS_PRIOR_BE, NULL, NULL, 1, 0, BTS_NO_ACTION);
+EXYNOS_BTS_PDATA(jpeg, BTS_PRIOR_BE, "pd-gscl", "jpeg", 0, 0, BTS_NO_ACTION);
+EXYNOS_BTS_PDATA(gscl0, BTS_PRIOR_BE, "pd-gscl", "gscl", 0, 0, BTS_ON_OFF);
+EXYNOS_BTS_PDATA(gscl1, BTS_PRIOR_BE, "pd-gscl", "gscl", 0, 0, BTS_ON_OFF);
+EXYNOS_BTS_PDATA(gscl2, BTS_PRIOR_BE, "pd-gscl", "gscl", 0, 0, BTS_ON_OFF);
+EXYNOS_BTS_PDATA(gscl3, BTS_PRIOR_BE, "pd-gscl", "gscl", 0, 0, BTS_ON_OFF);
+EXYNOS_BTS_PDATA(mfc, BTS_PRIOR_BE, "pd-mfc", "mfc", 0, 0, BTS_NO_ACTION);
+EXYNOS_BTS_PDATA(g3dacp, BTS_PRIOR_BE, "pd-g3d", "g3d", 1, 0, BTS_NO_ACTION);
+#if defined(CONFIG_EXYNOS4_DEV_FIMC_IS)
+EXYNOS_BTS_PDATA(isp0, BTS_PRIOR_BE, "pd-isp", "isp0", 0, 0, BTS_CHANGE_OTHER_DEBLOCK);
+EXYNOS_BTS_PDATA(isp1, BTS_PRIOR_BE, "pd-isp", "isp1", 0, 0, BTS_CHANGE_OTHER_DEBLOCK);
+#endif
+EXYNOS_BTS_PDATA(disp, BTS_PRIOR_HARDTIME, "pd-disp1", "fimd", 0, 0, BTS_NO_ACTION);
+EXYNOS_BTS_PDATA(mixer, BTS_PRIOR_HARDTIME, "pd-disp1", "mixer", 0, 0, BTS_NO_ACTION);
+
+/* bts platform device lists */
+#define EXYNOS_BTS_DEVICE(_name, _parent, _bts_name) \
+static struct platform_device exynos_device_bts_##_name = { \
+ .name = "exynos-bts", \
+ .num_resources = ARRAY_SIZE(exynos_bts_##_name##_resource),\
+ .resource = exynos_bts_##_name##_resource, \
+ .dev = { \
+ .platform_data = &bts_##_name##_res, \
+ .parent = _parent, \
+ .init_name = _bts_name, \
+ } \
+}
+
+EXYNOS_BTS_DEVICE(disp, &s5p_device_fimd1.dev, "disp-bts");
+EXYNOS_BTS_DEVICE(mixer, &s5p_device_mixer.dev, "mixer-bts");
+EXYNOS_BTS_DEVICE(g3dacp, &exynos5_device_g3d.dev, "g3dacp-bts");
+EXYNOS_BTS_DEVICE(jpeg, NULL, "jpeg-bts");
+EXYNOS_BTS_DEVICE(gscl0, &exynos5_device_gsc0.dev, "gscl0-bts");
+EXYNOS_BTS_DEVICE(gscl1, &exynos5_device_gsc1.dev, "gscl1-bts");
+EXYNOS_BTS_DEVICE(gscl2, &exynos5_device_gsc2.dev, "gscl2-bts");
+EXYNOS_BTS_DEVICE(gscl3, &exynos5_device_gsc3.dev, "gscl3-bts");
+EXYNOS_BTS_DEVICE(mfc, &s5p_device_mfc.dev, "mfc-bts");
+#if defined(CONFIG_EXYNOS4_DEV_FIMC_IS)
+EXYNOS_BTS_DEVICE(isp0, &exynos5_device_fimc_is.dev, "isp0-bts");
+EXYNOS_BTS_DEVICE(isp1, &exynos5_device_fimc_is.dev, "isp1-bts");
+#endif
+EXYNOS_BTS_DEVICE(cpu, NULL, "cpu-bts");
+EXYNOS_BTS_DEVICE(fbm_ddr_r1, NULL, "fbm-ddr-r1-bts");
+
+static struct platform_device *exynos_bts[] __initdata = {
+ &exynos_device_bts_disp,
+ &exynos_device_bts_mixer,
+ &exynos_device_bts_cpu,
+ &exynos_device_bts_fbm_ddr_r1,
+ &exynos_device_bts_g3dacp,
+ &exynos_device_bts_jpeg,
+ &exynos_device_bts_gscl0,
+ &exynos_device_bts_gscl1,
+ &exynos_device_bts_gscl2,
+ &exynos_device_bts_gscl3,
+ &exynos_device_bts_mfc,
+#if defined(CONFIG_EXYNOS4_DEV_FIMC_IS)
+ &exynos_device_bts_isp0,
+ &exynos_device_bts_isp1,
+#endif
+};
+
+static int __init exynos_bts_init(void)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(exynos_bts); i++)
+ exynos_bts[i]->id = i;
+
+ return platform_add_devices(exynos_bts, ARRAY_SIZE(exynos_bts));
+}
+arch_initcall(exynos_bts_init);
diff --git a/arch/arm/mach-exynos/dev-dwmci.c b/arch/arm/mach-exynos/dev-dwmci.c
index 7903501..1639d1e 100644
--- a/arch/arm/mach-exynos/dev-dwmci.c
+++ b/arch/arm/mach-exynos/dev-dwmci.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/arm/mach-exynos4/dev-dwmci.c
+ * linux/arch/arm/mach-exynos/dev-dwmci.c
*
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
* http://www.samsung.com
@@ -18,58 +18,188 @@
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/mmc/dw_mmc.h>
+#include <linux/mmc/host.h>
+#include <linux/clk.h>
#include <plat/devs.h>
+#include <plat/cpu.h>
#include <mach/map.h>
-static int exynos4_dwmci_get_bus_wd(u32 slot_id)
+#define DWMCI_CLKSEL 0x09c
+
+static int exynos_dwmci_get_ocr(u32 slot_id)
+{
+ u32 ocr_avail = MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34;
+
+ return ocr_avail;
+}
+
+static int exynos_dwmci_get_bus_wd(u32 slot_id)
{
return 4;
}
-static int exynos4_dwmci_init(u32 slot_id, irq_handler_t handler, void *data)
+static int exynos_dwmci_init(u32 slot_id, irq_handler_t handler, void *data)
{
return 0;
}
-static struct resource exynos4_dwmci_resource[] = {
+static void exynos_dwmci_set_io_timing(void *data, unsigned char timing)
+{
+ struct dw_mci *host = (struct dw_mci *)data;
+ u32 clksel;
+
+ if (timing == MMC_TIMING_MMC_HS200 ||
+ timing == MMC_TIMING_UHS_SDR104) {
+ if (host->bus_hz != 200 * 1000 * 1000) {
+ host->bus_hz = 200 * 1000 * 1000;
+ clk_set_rate(host->cclk, 800 * 1000 * 1000);
+ }
+ clksel = __raw_readl(host->regs + DWMCI_CLKSEL);
+ clksel = (clksel & 0xfff8ffff) | (host->pdata->clk_drv << 16);
+ __raw_writel(clksel, host->regs + DWMCI_CLKSEL);
+ } else if (timing == MMC_TIMING_UHS_SDR50) {
+ if (host->bus_hz != 100 * 1000 * 1000) {
+ host->bus_hz = 100 * 1000 * 1000;
+ clk_set_rate(host->cclk, 400 * 1000 * 1000);
+ }
+ clksel = __raw_readl(host->regs + DWMCI_CLKSEL);
+ clksel = (clksel & 0xfff8ffff) | (host->pdata->clk_drv << 16);
+ __raw_writel(clksel, host->regs + DWMCI_CLKSEL);
+ } else if (timing == MMC_TIMING_UHS_DDR50) {
+ if (host->bus_hz != 100 * 1000 * 1000) {
+ host->bus_hz = 100 * 1000 * 1000;
+ clk_set_rate(host->cclk, 400 * 1000 * 1000);
+ host->current_speed = 0;
+ }
+ __raw_writel(host->pdata->ddr_timing,
+ host->regs + DWMCI_CLKSEL);
+ } else {
+ if (host->bus_hz != 50 * 1000 * 1000) {
+ host->bus_hz = 50 * 1000 * 1000;
+ clk_set_rate(host->cclk, 200 * 1000 * 1000);
+ }
+ __raw_writel(host->pdata->sdr_timing,
+ host->regs + DWMCI_CLKSEL);
+ }
+}
+
+static struct dw_mci_board exynos4_dwmci_pdata = {
+ .num_slots = 1,
+ .quirks = DW_MCI_QUIRK_BROKEN_CARD_DETECTION,
+ .bus_hz = 80 * 1000 * 1000,
+ .max_bus_hz = 200 * 1000 * 1000,
+ .detect_delay_ms = 200,
+ .init = exynos_dwmci_init,
+ .get_bus_wd = exynos_dwmci_get_bus_wd,
+ .set_io_timing = exynos_dwmci_set_io_timing,
+};
+
+static u64 exynos_dwmci_dmamask = DMA_BIT_MASK(32);
+
+static struct resource exynos4_dwmci_resources[] = {
[0] = DEFINE_RES_MEM(EXYNOS4_PA_DWMCI, SZ_4K),
[1] = DEFINE_RES_IRQ(EXYNOS4_IRQ_DWMCI),
};
-static struct dw_mci_board exynos4_dwci_pdata = {
- .num_slots = 1,
- .quirks = DW_MCI_QUIRK_BROKEN_CARD_DETECTION,
- .bus_hz = 80 * 1000 * 1000,
- .detect_delay_ms = 200,
- .init = exynos4_dwmci_init,
- .get_bus_wd = exynos4_dwmci_get_bus_wd,
-};
-
-static u64 exynos4_dwmci_dmamask = DMA_BIT_MASK(32);
-
struct platform_device exynos4_device_dwmci = {
.name = "dw_mmc",
.id = -1,
- .num_resources = ARRAY_SIZE(exynos4_dwmci_resource),
- .resource = exynos4_dwmci_resource,
+ .num_resources = ARRAY_SIZE(exynos4_dwmci_resources),
+ .resource = exynos4_dwmci_resources,
.dev = {
- .dma_mask = &exynos4_dwmci_dmamask,
+ .dma_mask = &exynos_dwmci_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &exynos4_dwci_pdata,
+ .platform_data = &exynos4_dwmci_pdata,
},
};
-void __init exynos4_dwmci_set_platdata(struct dw_mci_board *pd)
-{
- struct dw_mci_board *npd;
- npd = s3c_set_platdata(pd, sizeof(struct dw_mci_board),
- &exynos4_device_dwmci);
+#define EXYNOS5_DWMCI_RESOURCE(_channel) \
+static struct resource exynos5_dwmci##_channel##_resource[] = { \
+ [0] = DEFINE_RES_MEM(S3C_PA_HSMMC##_channel, SZ_4K), \
+ [1] = DEFINE_RES_IRQ(IRQ_HSMMC##_channel), \
+}
+
+EXYNOS5_DWMCI_RESOURCE(0);
+EXYNOS5_DWMCI_RESOURCE(1);
+EXYNOS5_DWMCI_RESOURCE(2);
+EXYNOS5_DWMCI_RESOURCE(3);
+
+#define EXYNOS5_DWMCI_DEF_PLATDATA(_channel) \
+struct dw_mci_board exynos5_dwmci##_channel##_def_platdata = { \
+ .num_slots = 1, \
+ .quirks = \
+ DW_MCI_QUIRK_BROKEN_CARD_DETECTION, \
+ .bus_hz = 200 * 1000 * 1000, \
+ .max_bus_hz = 200 * 1000 * 1000, \
+ .detect_delay_ms = 200, \
+ .init = exynos_dwmci_init, \
+ .get_bus_wd = exynos_dwmci_get_bus_wd, \
+ .set_io_timing = exynos_dwmci_set_io_timing, \
+ .get_ocr = exynos_dwmci_get_ocr \
+}
+
+EXYNOS5_DWMCI_DEF_PLATDATA(0);
+EXYNOS5_DWMCI_DEF_PLATDATA(1);
+EXYNOS5_DWMCI_DEF_PLATDATA(2);
+EXYNOS5_DWMCI_DEF_PLATDATA(3);
+
+#define EXYNOS5_DWMCI_PLATFORM_DEVICE(_channel) \
+struct platform_device exynos5_device_dwmci##_channel = \
+{ \
+ .name = "dw_mmc", \
+ .id = _channel, \
+ .num_resources = \
+ ARRAY_SIZE(exynos5_dwmci##_channel##_resource), \
+ .resource = exynos5_dwmci##_channel##_resource, \
+ .dev = { \
+ .dma_mask = &exynos_dwmci_dmamask,\
+ .coherent_dma_mask = DMA_BIT_MASK(32), \
+ .platform_data = \
+ &exynos5_dwmci##_channel##_def_platdata,\
+ }, \
+}
+
+EXYNOS5_DWMCI_PLATFORM_DEVICE(0);
+EXYNOS5_DWMCI_PLATFORM_DEVICE(1);
+EXYNOS5_DWMCI_PLATFORM_DEVICE(2);
+EXYNOS5_DWMCI_PLATFORM_DEVICE(3);
+
+static struct platform_device *exynos5_dwmci_devs[] = {
+ &exynos5_device_dwmci0,
+ &exynos5_device_dwmci1,
+ &exynos5_device_dwmci2,
+ &exynos5_device_dwmci3,
+};
+
+void __init exynos_dwmci_set_platdata(struct dw_mci_board *pd, u32 slot_id)
+{
+ struct dw_mci_board *npd = NULL;
+
+ if ((soc_is_exynos4210()) || soc_is_exynos4212() ||
+ soc_is_exynos4412()) {
+ npd = s3c_set_platdata(pd, sizeof(struct dw_mci_board),
+ &exynos4_device_dwmci);
+ } else if (soc_is_exynos5250()) {
+ if (slot_id < ARRAY_SIZE(exynos5_dwmci_devs))
+ npd = s3c_set_platdata(pd, sizeof(struct dw_mci_board),
+ exynos5_dwmci_devs[slot_id]);
+ else
+ pr_err("%s: slot %d is not supported\n", __func__,
+ slot_id);
+ }
+
+ if (!npd)
+ return;
if (!npd->init)
- npd->init = exynos4_dwmci_init;
+ npd->init = exynos_dwmci_init;
if (!npd->get_bus_wd)
- npd->get_bus_wd = exynos4_dwmci_get_bus_wd;
+ npd->get_bus_wd = exynos_dwmci_get_bus_wd;
+ if (!npd->set_io_timing)
+ npd->set_io_timing = exynos_dwmci_set_io_timing;
+ if (!npd->get_ocr)
+ npd->get_ocr = exynos_dwmci_get_ocr;
}
diff --git a/arch/arm/mach-exynos/dev-exynos-udc.c b/arch/arm/mach-exynos/dev-exynos-udc.c
new file mode 100644
index 0000000..9e56c36
--- /dev/null
+++ b/arch/arm/mach-exynos/dev-exynos-udc.c
@@ -0,0 +1,54 @@
+/* arch/arm/plat-samsung/dev-dwc3-exynos.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co. Ltd
+ * Author: Anton Tikhomirov <av.tikhomirov@samsung.com>
+ *
+ * Device definition for DWC EXYNOS SuperSpeed USB 3.0 DRD Controller
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_data/exynos_usb3_drd.h>
+
+#include <mach/irqs.h>
+#include <mach/map.h>
+
+#include <plat/devs.h>
+#include <plat/usb-phy.h>
+
+static struct resource exynos_ss_udc_resources[] = {
+ [0] = DEFINE_RES_MEM(EXYNOS5_PA_SS_DRD, SZ_64K),
+ [1] = DEFINE_RES_IRQ(IRQ_USB3_DRD),
+};
+
+static u64 exynos_ss_udc_dmamask = DMA_BIT_MASK(32);
+
+struct platform_device exynos_device_ss_udc = {
+ .name = "exynos-ss-udc",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(exynos_ss_udc_resources),
+ .resource = exynos_ss_udc_resources,
+ .dev = {
+ .dma_mask = &exynos_ss_udc_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+};
+
+void __init exynos_ss_udc_set_platdata(struct exynos_usb3_drd_pdata *pd)
+{
+ struct exynos_usb3_drd_pdata *npd;
+
+ npd = s3c_set_platdata(pd, sizeof(struct exynos_usb3_drd_pdata),
+ &exynos_device_ss_udc);
+
+ if (!npd->phy_init)
+ npd->phy_init = s5p_usb_phy_init;
+ if (!npd->phy_exit)
+ npd->phy_exit = s5p_usb_phy_exit;
+}
diff --git a/arch/arm/mach-exynos/dev-fimc-is.c b/arch/arm/mach-exynos/dev-fimc-is.c
new file mode 100644
index 0000000..133ac44
--- /dev/null
+++ b/arch/arm/mach-exynos/dev-fimc-is.c
@@ -0,0 +1,79 @@
+/* linux/arch/arm/plat-s5p/dev-fimc_is.c
+ *
+ * Copyright (c) 2011 Samsung Electronics
+ *
+ * Base FIMC-IS resource and device definitions
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <mach/map.h>
+#include <mach/regs-clock.h>
+#include <media/exynos_fimc_is.h>
+
+static struct resource exynos5_fimc_is_resource[] = {
+ [0] = {
+ .start = EXYNOS5_PA_FIMC_IS,
+ .end = EXYNOS5_PA_FIMC_IS + SZ_2M + SZ_256K + SZ_128K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+
+ [1] = {
+ .start = EXYNOS5_IRQ_ARMISP_GIC,
+ .end = EXYNOS5_IRQ_ARMISP_GIC,
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+ .start = EXYNOS5_IRQ_ISP_GIC,
+ .end = EXYNOS5_IRQ_ISP_GIC,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device exynos5_device_fimc_is = {
+ .name = FIMC_IS_MODULE_NAME,
+ .id = -1,
+ .num_resources = ARRAY_SIZE(exynos5_fimc_is_resource),
+ .resource = exynos5_fimc_is_resource,
+};
+
+struct exynos5_platform_fimc_is exynos5_fimc_is_default_data __initdata = {
+ .hw_ver = 15,
+};
+
+void __init exynos5_fimc_is_set_platdata(struct exynos5_platform_fimc_is *pd)
+{
+ struct exynos5_platform_fimc_is *npd;
+
+ if (!pd)
+ pd = (struct exynos5_platform_fimc_is *)
+ &exynos5_fimc_is_default_data;
+
+ npd = kmemdup(pd, sizeof(struct exynos5_platform_fimc_is), GFP_KERNEL);
+
+ if (!npd) {
+ printk(KERN_ERR "%s: no memory for platform data\n", __func__);
+ } else {
+ if (!npd->clk_cfg)
+ npd->clk_cfg = exynos5_fimc_is_cfg_clk;
+ if (!npd->clk_on)
+ npd->clk_on = exynos5_fimc_is_clk_on;
+ if (!npd->clk_off)
+ npd->clk_off = exynos5_fimc_is_clk_off;
+ if (!npd->sensor_power_on)
+ npd->sensor_power_on = exynos5_fimc_is_sensor_power_on;
+ if (!npd->sensor_power_off)
+ npd->sensor_power_off =
+ exynos5_fimc_is_sensor_power_off;
+
+
+ exynos5_device_fimc_is.dev.platform_data = npd;
+ }
+}
diff --git a/arch/arm/mach-exynos/dev-fimc-lite.c b/arch/arm/mach-exynos/dev-fimc-lite.c
new file mode 100644
index 0000000..b2d9921
--- /dev/null
+++ b/arch/arm/mach-exynos/dev-fimc-lite.c
@@ -0,0 +1,60 @@
+/* linux/arch/arm/plat-s5p/dev-fimc-lite.c
+ *
+ * Copyright (c) 2011 Samsung Electronics
+ *
+ * Base S5P FIMC-Lite resource and device definitions
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <mach/map.h>
+#include <media/exynos_flite.h>
+
+static struct resource exynos_flite0_resource[] = {
+ [0] = {
+ .start = EXYNOS5_PA_FIMC_LITE0,
+ .end = EXYNOS5_PA_FIMC_LITE0 + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_FIMC_LITE0,
+ .end = IRQ_FIMC_LITE0,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device exynos_device_flite0 = {
+ .name = "exynos-fimc-lite",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(exynos_flite0_resource),
+ .resource = exynos_flite0_resource,
+};
+
+static struct resource exynos_flite1_resource[] = {
+ [0] = {
+ .start = EXYNOS5_PA_FIMC_LITE1,
+ .end = EXYNOS5_PA_FIMC_LITE1 + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_FIMC_LITE1,
+ .end = IRQ_FIMC_LITE1,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device exynos_device_flite1 = {
+ .name = "exynos-fimc-lite",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(exynos_flite1_resource),
+ .resource = exynos_flite1_resource,
+};
+
+struct exynos_platform_flite exynos_flite0_default_data __initdata;
+struct exynos_platform_flite exynos_flite1_default_data __initdata;
diff --git a/arch/arm/mach-exynos/dev-gsc.c b/arch/arm/mach-exynos/dev-gsc.c
new file mode 100644
index 0000000..bb6403d
--- /dev/null
+++ b/arch/arm/mach-exynos/dev-gsc.c
@@ -0,0 +1,123 @@
+/* linux/arch/arm/mach-exynos/dev-gsc.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Base G-Scaler resource and device definitions
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <media/exynos_gscaler.h>
+#include <plat/devs.h>
+#include <mach/map.h>
+
+static u64 exynos5_gsc_dma_mask = DMA_BIT_MASK(32);
+
+static struct resource exynos5_gsc0_resource[] = {
+ [0] = {
+ .start = EXYNOS5_PA_GSC0,
+ .end = EXYNOS5_PA_GSC0 + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_GSC0,
+ .end = IRQ_GSC0,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device exynos5_device_gsc0 = {
+ .name = "exynos-gsc",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(exynos5_gsc0_resource),
+ .resource = exynos5_gsc0_resource,
+ .dev = {
+ .dma_mask = &exynos5_gsc_dma_mask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+};
+
+static struct resource exynos5_gsc1_resource[] = {
+ [0] = {
+ .start = EXYNOS5_PA_GSC1,
+ .end = EXYNOS5_PA_GSC1 + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_GSC1,
+ .end = IRQ_GSC1,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device exynos5_device_gsc1 = {
+ .name = "exynos-gsc",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(exynos5_gsc1_resource),
+ .resource = exynos5_gsc1_resource,
+ .dev = {
+ .dma_mask = &exynos5_gsc_dma_mask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+};
+
+static struct resource exynos5_gsc2_resource[] = {
+ [0] = {
+ .start = EXYNOS5_PA_GSC2,
+ .end = EXYNOS5_PA_GSC2 + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_GSC2,
+ .end = IRQ_GSC2,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device exynos5_device_gsc2 = {
+ .name = "exynos-gsc",
+ .id = 2,
+ .num_resources = ARRAY_SIZE(exynos5_gsc2_resource),
+ .resource = exynos5_gsc2_resource,
+ .dev = {
+ .dma_mask = &exynos5_gsc_dma_mask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+};
+
+static struct resource exynos5_gsc3_resource[] = {
+ [0] = {
+ .start = EXYNOS5_PA_GSC3,
+ .end = EXYNOS5_PA_GSC3 + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_GSC3,
+ .end = IRQ_GSC3,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device exynos5_device_gsc3 = {
+ .name = "exynos-gsc",
+ .id = 3,
+ .num_resources = ARRAY_SIZE(exynos5_gsc3_resource),
+ .resource = exynos5_gsc3_resource,
+ .dev = {
+ .dma_mask = &exynos5_gsc_dma_mask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+};
+
+struct exynos_platform_gscaler exynos_gsc0_default_data __initdata;
+struct exynos_platform_gscaler exynos_gsc1_default_data __initdata;
+struct exynos_platform_gscaler exynos_gsc2_default_data __initdata;
+struct exynos_platform_gscaler exynos_gsc3_default_data __initdata;
diff --git a/arch/arm/mach-exynos/dev-ion.c b/arch/arm/mach-exynos/dev-ion.c
new file mode 100644
index 0000000..e26912b
--- /dev/null
+++ b/arch/arm/mach-exynos/dev-ion.c
@@ -0,0 +1,43 @@
+/* linux/arch/arm/mach-exynos/dev-ion.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * 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.
+*/
+
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/ion.h>
+#include <linux/exynos_ion.h>
+#include <linux/slab.h>
+#include <mach/exynos-ion.h>
+
+
+struct ion_platform_data exynos_ion_pdata = {
+ .nr = 3,
+ .heaps = {
+ { .type = ION_HEAP_TYPE_SYSTEM,
+ .name = "ion_noncontig_heap",
+ .id = EXYNOS_ION_HEAP_SYSTEM_ID,
+ },
+ { .type = ION_HEAP_TYPE_EXYNOS,
+ .name = "exynos_noncontig_heap",
+ .id = EXYNOS_ION_HEAP_EXYNOS_ID,
+ },
+ { .type = ION_HEAP_TYPE_EXYNOS_CONTIG,
+ .name = "exynos_contig_heap",
+ .id = EXYNOS_ION_HEAP_EXYNOS_CONTIG_ID,
+ },
+ }
+};
+
+struct platform_device exynos_device_ion = {
+ .name = "ion-exynos",
+ .id = -1,
+ .dev = {
+ .platform_data = &exynos_ion_pdata,
+ }
+};
diff --git a/arch/arm/mach-exynos/dev-jpeg.c b/arch/arm/mach-exynos/dev-jpeg.c
new file mode 100644
index 0000000..514ba17
--- /dev/null
+++ b/arch/arm/mach-exynos/dev-jpeg.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * S5P series device definition for JPEG
+ *
+ * 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.
+*/
+
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <mach/map.h>
+
+static struct resource s5p_jpeg_resource[] = {
+ [0] = {
+ .start = EXYNOS5_PA_JPEG,
+ .end = EXYNOS5_PA_JPEG + SZ_64K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_JPEG,
+ .end = IRQ_JPEG,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+struct platform_device s5p_device_jpeg = {
+ .name = "s5p-jpeg",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(s5p_jpeg_resource),
+ .resource = s5p_jpeg_resource,
+};
diff --git a/arch/arm/mach-exynos/dev-ohci.c b/arch/arm/mach-exynos/dev-ohci.c
index b8e75300..050312c 100644
--- a/arch/arm/mach-exynos/dev-ohci.c
+++ b/arch/arm/mach-exynos/dev-ohci.c
@@ -21,7 +21,7 @@
#include <plat/usb-phy.h>
static struct resource exynos4_ohci_resource[] = {
- [0] = DEFINE_RES_MEM(EXYNOS4_PA_OHCI, SZ_256),
+ [0] = DEFINE_RES_MEM(EXYNOS_PA_OHCI, SZ_256),
[1] = DEFINE_RES_IRQ(IRQ_USB_HOST),
};
diff --git a/arch/arm/mach-exynos/dev-rotator.c b/arch/arm/mach-exynos/dev-rotator.c
new file mode 100644
index 0000000..f584f5e
--- /dev/null
+++ b/arch/arm/mach-exynos/dev-rotator.c
@@ -0,0 +1,36 @@
+/* linux/arch/arm/plat-s5p/dev-rotator.c
+ *
+ * Copyright (c) 2011 Samsung Electronics
+ *
+ * Base S5P Rotator resource and device definitions
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+
+#include <mach/map.h>
+
+static struct resource exynos5_rot_resource[] = {
+ [0] = DEFINE_RES_MEM(EXYNOS5_PA_ROTATOR, SZ_4K),
+ [1] = DEFINE_RES_IRQ(IRQ_ROTATOR),
+};
+
+static u64 exynos_rot_dma_mask = DMA_BIT_MASK(32);
+
+struct platform_device exynos5_device_rotator = {
+ .name = "exynos-rot",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(exynos5_rot_resource),
+ .resource = exynos5_rot_resource,
+ .dev = {
+ .dma_mask = &exynos_rot_dma_mask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+};
diff --git a/arch/arm/mach-exynos/dev-sysmmu.c b/arch/arm/mach-exynos/dev-sysmmu.c
index 781563f..7137312 100644
--- a/arch/arm/mach-exynos/dev-sysmmu.c
+++ b/arch/arm/mach-exynos/dev-sysmmu.c
@@ -1,9 +1,9 @@
-/* linux/arch/arm/mach-exynos4/dev-sysmmu.c
+/* linux/arch/arm/mach-exynos/dev-sysmmu.c
*
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2010-2012 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
- * EXYNOS4 - System MMU support
+ * EXYNOS - System MMU support
*
* 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
@@ -12,222 +12,260 @@
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
-#include <linux/export.h>
+
+#include <plat/cpu.h>
+#include <plat/devs.h>
#include <mach/map.h>
#include <mach/irqs.h>
#include <mach/sysmmu.h>
-#include <plat/s5p-clock.h>
-/* These names must be equal to the clock names in mach-exynos4/clock.c */
-const char *sysmmu_ips_name[EXYNOS4_SYSMMU_TOTAL_IPNUM] = {
- "SYSMMU_MDMA" ,
- "SYSMMU_SSS" ,
- "SYSMMU_FIMC0" ,
- "SYSMMU_FIMC1" ,
- "SYSMMU_FIMC2" ,
- "SYSMMU_FIMC3" ,
- "SYSMMU_JPEG" ,
- "SYSMMU_FIMD0" ,
- "SYSMMU_FIMD1" ,
- "SYSMMU_PCIe" ,
- "SYSMMU_G2D" ,
- "SYSMMU_ROTATOR",
- "SYSMMU_MDMA2" ,
- "SYSMMU_TV" ,
- "SYSMMU_MFC_L" ,
- "SYSMMU_MFC_R" ,
-};
+static u64 exynos_sysmmu_dma_mask = DMA_BIT_MASK(32);
-static struct resource exynos4_sysmmu_resource[] = {
- [0] = {
- .start = EXYNOS4_PA_SYSMMU_MDMA,
- .end = EXYNOS4_PA_SYSMMU_MDMA + SZ_64K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = IRQ_SYSMMU_MDMA0_0,
- .end = IRQ_SYSMMU_MDMA0_0,
- .flags = IORESOURCE_IRQ,
- },
- [2] = {
- .start = EXYNOS4_PA_SYSMMU_SSS,
- .end = EXYNOS4_PA_SYSMMU_SSS + SZ_64K - 1,
- .flags = IORESOURCE_MEM,
- },
- [3] = {
- .start = IRQ_SYSMMU_SSS_0,
- .end = IRQ_SYSMMU_SSS_0,
- .flags = IORESOURCE_IRQ,
- },
- [4] = {
- .start = EXYNOS4_PA_SYSMMU_FIMC0,
- .end = EXYNOS4_PA_SYSMMU_FIMC0 + SZ_64K - 1,
- .flags = IORESOURCE_MEM,
- },
- [5] = {
- .start = IRQ_SYSMMU_FIMC0_0,
- .end = IRQ_SYSMMU_FIMC0_0,
- .flags = IORESOURCE_IRQ,
- },
- [6] = {
- .start = EXYNOS4_PA_SYSMMU_FIMC1,
- .end = EXYNOS4_PA_SYSMMU_FIMC1 + SZ_64K - 1,
- .flags = IORESOURCE_MEM,
- },
- [7] = {
- .start = IRQ_SYSMMU_FIMC1_0,
- .end = IRQ_SYSMMU_FIMC1_0,
- .flags = IORESOURCE_IRQ,
- },
- [8] = {
- .start = EXYNOS4_PA_SYSMMU_FIMC2,
- .end = EXYNOS4_PA_SYSMMU_FIMC2 + SZ_64K - 1,
- .flags = IORESOURCE_MEM,
- },
- [9] = {
- .start = IRQ_SYSMMU_FIMC2_0,
- .end = IRQ_SYSMMU_FIMC2_0,
- .flags = IORESOURCE_IRQ,
- },
- [10] = {
- .start = EXYNOS4_PA_SYSMMU_FIMC3,
- .end = EXYNOS4_PA_SYSMMU_FIMC3 + SZ_64K - 1,
- .flags = IORESOURCE_MEM,
- },
- [11] = {
- .start = IRQ_SYSMMU_FIMC3_0,
- .end = IRQ_SYSMMU_FIMC3_0,
- .flags = IORESOURCE_IRQ,
- },
- [12] = {
- .start = EXYNOS4_PA_SYSMMU_JPEG,
- .end = EXYNOS4_PA_SYSMMU_JPEG + SZ_64K - 1,
- .flags = IORESOURCE_MEM,
- },
- [13] = {
- .start = IRQ_SYSMMU_JPEG_0,
- .end = IRQ_SYSMMU_JPEG_0,
- .flags = IORESOURCE_IRQ,
- },
- [14] = {
- .start = EXYNOS4_PA_SYSMMU_FIMD0,
- .end = EXYNOS4_PA_SYSMMU_FIMD0 + SZ_64K - 1,
- .flags = IORESOURCE_MEM,
- },
- [15] = {
- .start = IRQ_SYSMMU_LCD0_M0_0,
- .end = IRQ_SYSMMU_LCD0_M0_0,
- .flags = IORESOURCE_IRQ,
- },
- [16] = {
- .start = EXYNOS4_PA_SYSMMU_FIMD1,
- .end = EXYNOS4_PA_SYSMMU_FIMD1 + SZ_64K - 1,
- .flags = IORESOURCE_MEM,
- },
- [17] = {
- .start = IRQ_SYSMMU_LCD1_M1_0,
- .end = IRQ_SYSMMU_LCD1_M1_0,
- .flags = IORESOURCE_IRQ,
- },
- [18] = {
- .start = EXYNOS4_PA_SYSMMU_PCIe,
- .end = EXYNOS4_PA_SYSMMU_PCIe + SZ_64K - 1,
- .flags = IORESOURCE_MEM,
- },
- [19] = {
- .start = IRQ_SYSMMU_PCIE_0,
- .end = IRQ_SYSMMU_PCIE_0,
- .flags = IORESOURCE_IRQ,
- },
- [20] = {
- .start = EXYNOS4_PA_SYSMMU_G2D,
- .end = EXYNOS4_PA_SYSMMU_G2D + SZ_64K - 1,
- .flags = IORESOURCE_MEM,
- },
- [21] = {
- .start = IRQ_SYSMMU_2D_0,
- .end = IRQ_SYSMMU_2D_0,
- .flags = IORESOURCE_IRQ,
- },
- [22] = {
- .start = EXYNOS4_PA_SYSMMU_ROTATOR,
- .end = EXYNOS4_PA_SYSMMU_ROTATOR + SZ_64K - 1,
- .flags = IORESOURCE_MEM,
- },
- [23] = {
- .start = IRQ_SYSMMU_ROTATOR_0,
- .end = IRQ_SYSMMU_ROTATOR_0,
- .flags = IORESOURCE_IRQ,
- },
- [24] = {
- .start = EXYNOS4_PA_SYSMMU_MDMA2,
- .end = EXYNOS4_PA_SYSMMU_MDMA2 + SZ_64K - 1,
- .flags = IORESOURCE_MEM,
- },
- [25] = {
- .start = IRQ_SYSMMU_MDMA1_0,
- .end = IRQ_SYSMMU_MDMA1_0,
- .flags = IORESOURCE_IRQ,
- },
- [26] = {
- .start = EXYNOS4_PA_SYSMMU_TV,
- .end = EXYNOS4_PA_SYSMMU_TV + SZ_64K - 1,
- .flags = IORESOURCE_MEM,
- },
- [27] = {
- .start = IRQ_SYSMMU_TV_M0_0,
- .end = IRQ_SYSMMU_TV_M0_0,
- .flags = IORESOURCE_IRQ,
- },
- [28] = {
- .start = EXYNOS4_PA_SYSMMU_MFC_L,
- .end = EXYNOS4_PA_SYSMMU_MFC_L + SZ_64K - 1,
- .flags = IORESOURCE_MEM,
- },
- [29] = {
- .start = IRQ_SYSMMU_MFC_M0_0,
- .end = IRQ_SYSMMU_MFC_M0_0,
- .flags = IORESOURCE_IRQ,
- },
- [30] = {
- .start = EXYNOS4_PA_SYSMMU_MFC_R,
- .end = EXYNOS4_PA_SYSMMU_MFC_R + SZ_64K - 1,
- .flags = IORESOURCE_MEM,
- },
- [31] = {
- .start = IRQ_SYSMMU_MFC_M1_0,
- .end = IRQ_SYSMMU_MFC_M1_0,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-struct platform_device exynos4_device_sysmmu = {
- .name = "s5p-sysmmu",
- .id = 32,
- .num_resources = ARRAY_SIZE(exynos4_sysmmu_resource),
- .resource = exynos4_sysmmu_resource,
-};
-EXPORT_SYMBOL(exynos4_device_sysmmu);
-
-static struct clk *sysmmu_clk[S5P_SYSMMU_TOTAL_IPNUM];
-void sysmmu_clk_init(struct device *dev, sysmmu_ips ips)
-{
- sysmmu_clk[ips] = clk_get(dev, sysmmu_ips_name[ips]);
- if (IS_ERR(sysmmu_clk[ips]))
- sysmmu_clk[ips] = NULL;
- else
- clk_put(sysmmu_clk[ips]);
+#define SYSMMU_PLATFORM_DEVICE(ipname, devid) \
+static struct sysmmu_platform_data platdata_##ipname = { \
+ .dbgname = #ipname, \
+}; \
+struct platform_device SYSMMU_PLATDEV(ipname) = \
+{ \
+ .name = SYSMMU_DEVNAME_BASE, \
+ .id = devid, \
+ .dev = { \
+ .dma_mask = &exynos_sysmmu_dma_mask, \
+ .coherent_dma_mask = DMA_BIT_MASK(32), \
+ .platform_data = &platdata_##ipname, \
+ }, \
}
-void sysmmu_clk_enable(sysmmu_ips ips)
-{
- if (sysmmu_clk[ips])
- clk_enable(sysmmu_clk[ips]);
+SYSMMU_PLATFORM_DEVICE(mfc_lr, 0);
+SYSMMU_PLATFORM_DEVICE(tv, 2);
+SYSMMU_PLATFORM_DEVICE(jpeg, 3);
+SYSMMU_PLATFORM_DEVICE(rot, 4);
+SYSMMU_PLATFORM_DEVICE(fimc0, 5); /* fimc* and gsc* exist exclusively */
+SYSMMU_PLATFORM_DEVICE(fimc1, 6);
+SYSMMU_PLATFORM_DEVICE(fimc2, 7);
+SYSMMU_PLATFORM_DEVICE(fimc3, 8);
+SYSMMU_PLATFORM_DEVICE(gsc0, 5);
+SYSMMU_PLATFORM_DEVICE(gsc1, 6);
+SYSMMU_PLATFORM_DEVICE(gsc2, 7);
+SYSMMU_PLATFORM_DEVICE(gsc3, 8);
+SYSMMU_PLATFORM_DEVICE(isp, 9);
+SYSMMU_PLATFORM_DEVICE(fimd0, 10);
+SYSMMU_PLATFORM_DEVICE(fimd1, 11);
+SYSMMU_PLATFORM_DEVICE(camif0, 12);
+SYSMMU_PLATFORM_DEVICE(camif1, 13);
+SYSMMU_PLATFORM_DEVICE(camif2, 14);
+SYSMMU_PLATFORM_DEVICE(2d, 15);
+
+#define SYSMMU_RESOURCE_NAME(core, ipname) sysmmures_##core##_##ipname
+
+#define SYSMMU_RESOURCE(core, ipname) \
+ static struct resource SYSMMU_RESOURCE_NAME(core, ipname)[] __initdata =
+
+#define DEFINE_SYSMMU_RESOURCE(core, mem, irq) \
+ DEFINE_RES_MEM_NAMED(core##_PA_SYSMMU_##mem, SZ_4K, #mem), \
+ DEFINE_RES_IRQ_NAMED(core##_IRQ_SYSMMU_##irq##_0, #mem)
+
+#define SYSMMU_RESOURCE_DEFINE(core, ipname, mem, irq) \
+ SYSMMU_RESOURCE(core, ipname) { \
+ DEFINE_SYSMMU_RESOURCE(core, mem, irq) \
+ }
+
+struct sysmmu_resource_map {
+ struct platform_device *pdev;
+ struct resource *res;
+ u32 rnum;
+ struct device *pdd;
+ char *clocknames;
+ unsigned int qos;
+};
+
+#define SYSMMU_RESOURCE_MAPPING(core, ipname, resname) { \
+ .pdev = &SYSMMU_PLATDEV(ipname), \
+ .res = SYSMMU_RESOURCE_NAME(EXYNOS##core, resname), \
+ .rnum = ARRAY_SIZE(SYSMMU_RESOURCE_NAME(EXYNOS##core, resname)),\
+ .clocknames = SYSMMU_CLOCK_NAME, \
}
-void sysmmu_clk_disable(sysmmu_ips ips)
-{
- if (sysmmu_clk[ips])
- clk_disable(sysmmu_clk[ips]);
+#define SYSMMU_RESOURCE_MAPPING_MC(core, ipname, resname, pdata) { \
+ .pdev = &SYSMMU_PLATDEV(ipname), \
+ .res = SYSMMU_RESOURCE_NAME(EXYNOS##core, resname), \
+ .rnum = ARRAY_SIZE(SYSMMU_RESOURCE_NAME(EXYNOS##core, resname)),\
+ .clocknames = SYSMMU_CLOCK_NAME "," SYSMMU_CLOCK_NAME2 "," SYSMMU_CLOCK_NAME3, \
}
+
+#define SYSMMU_RESOURCE_MAPPING_QOS(core, ipname, resname, qosval) { \
+ .pdev = &SYSMMU_PLATDEV(ipname), \
+ .res = SYSMMU_RESOURCE_NAME(EXYNOS##core, resname), \
+ .rnum = ARRAY_SIZE(SYSMMU_RESOURCE_NAME(EXYNOS##core, resname)),\
+ .clocknames = SYSMMU_CLOCK_NAME, \
+ .qos = qosval, \
+}
+
+#define SYSMMU_RESOURCE_MAPPING_MC_QOS(core, ipname, resname, pdata, qosval) { \
+ .pdev = &SYSMMU_PLATDEV(ipname), \
+ .res = SYSMMU_RESOURCE_NAME(EXYNOS##core, resname), \
+ .rnum = ARRAY_SIZE(SYSMMU_RESOURCE_NAME(EXYNOS##core, resname)),\
+ .clocknames = SYSMMU_CLOCK_NAME "," SYSMMU_CLOCK_NAME2 \
+ "," SYSMMU_CLOCK_NAME3, \
+ .qos = qosval, \
+}
+
+#ifdef CONFIG_ARCH_EXYNOS4
+SYSMMU_RESOURCE_DEFINE(EXYNOS4, fimc0, FIMC0, FIMC0);
+SYSMMU_RESOURCE_DEFINE(EXYNOS4, fimc1, FIMC1, FIMC1);
+SYSMMU_RESOURCE_DEFINE(EXYNOS4, fimc2, FIMC2, FIMC2);
+SYSMMU_RESOURCE_DEFINE(EXYNOS4, fimc3, FIMC3, FIMC3);
+SYSMMU_RESOURCE_DEFINE(EXYNOS4, jpeg, JPEG, JPEG);
+SYSMMU_RESOURCE_DEFINE(EXYNOS4, 2d, G2D, 2D);
+SYSMMU_RESOURCE_DEFINE(EXYNOS4, tv, TV, TV_M0);
+SYSMMU_RESOURCE_DEFINE(EXYNOS4, 2d_acp, G2D_ACP, 2D);
+SYSMMU_RESOURCE_DEFINE(EXYNOS4, rot, ROTATOR, ROTATOR);
+SYSMMU_RESOURCE_DEFINE(EXYNOS4, fimd0, FIMD0, LCD0_M0);
+SYSMMU_RESOURCE_DEFINE(EXYNOS4, fimd1, FIMD1, LCD1_M1);
+SYSMMU_RESOURCE_DEFINE(EXYNOS4, flite0, FIMC_LITE0, FIMC_LITE0);
+SYSMMU_RESOURCE_DEFINE(EXYNOS4, flite1, FIMC_LITE1, FIMC_LITE1);
+SYSMMU_RESOURCE(EXYNOS4, mfc_lr) {
+ DEFINE_SYSMMU_RESOURCE(EXYNOS4, MFC_R, MFC_M0),
+ DEFINE_SYSMMU_RESOURCE(EXYNOS4, MFC_L, MFC_M1),
+};
+SYSMMU_RESOURCE(EXYNOS4, isp) {
+ DEFINE_SYSMMU_RESOURCE(EXYNOS4, ISP, FIMC_ISP),
+ DEFINE_SYSMMU_RESOURCE(EXYNOS4, DRC, FIMC_DRC),
+ DEFINE_SYSMMU_RESOURCE(EXYNOS4, FD, FIMC_FD),
+ DEFINE_SYSMMU_RESOURCE(EXYNOS4, ISPCPU, FIMC_CX),
+};
+
+static struct sysmmu_resource_map sysmmu_resmap4[] __initdata = {
+ SYSMMU_RESOURCE_MAPPING(4, fimc0, fimc0),
+ SYSMMU_RESOURCE_MAPPING(4, fimc1, fimc1),
+ SYSMMU_RESOURCE_MAPPING(4, fimc2, fimc2),
+ SYSMMU_RESOURCE_MAPPING(4, fimc3, fimc3),
+ SYSMMU_RESOURCE_MAPPING(4, tv, tv),
+ SYSMMU_RESOURCE_MAPPING(4, mfc_lr, mfc_lr),
+ SYSMMU_RESOURCE_MAPPING(4, rot, rot),
+ SYSMMU_RESOURCE_MAPPING(4, jpeg, jpeg),
+ SYSMMU_RESOURCE_MAPPING(4, fimd0, fimd0),
+};
+
+static struct sysmmu_resource_map sysmmu_resmap4210[] __initdata = {
+ SYSMMU_RESOURCE_MAPPING(4, 2d, 2d),
+ SYSMMU_RESOURCE_MAPPING(4, fimd1, fimd1),
+}
+
+static struct sysmmu_resource_map sysmmu_resmap4212[] __initdata = {
+ SYSMMU_RESOURCE_MAPPING(4, 2d, 2d_acp),
+ SYSMMU_RESOURCE_MAPPING(4, camif0, flite0),
+ SYSMMU_RESOURCE_MAPPING(4, camif1, flite1),
+ SYSMMU_RESOURCE_MAPPING(4, isp, isp),
+};
+#endif /* CONFIG_ARCH_EXYNOS4 */
+
+#ifdef CONFIG_ARCH_EXYNOS5
+SYSMMU_RESOURCE_DEFINE(EXYNOS5, jpeg, JPEG, JPEG);
+SYSMMU_RESOURCE_DEFINE(EXYNOS5, fimd1, FIMD1, FIMD1);
+SYSMMU_RESOURCE_DEFINE(EXYNOS5, 2d, 2D, 2D);
+SYSMMU_RESOURCE_DEFINE(EXYNOS5, rot, ROTATOR, ROTATOR);
+SYSMMU_RESOURCE_DEFINE(EXYNOS5, tv, TV, TV);
+SYSMMU_RESOURCE_DEFINE(EXYNOS5, gsc0, GSC0, GSC0);
+SYSMMU_RESOURCE_DEFINE(EXYNOS5, gsc1, GSC1, GSC1);
+SYSMMU_RESOURCE_DEFINE(EXYNOS5, gsc2, GSC2, GSC2);
+SYSMMU_RESOURCE_DEFINE(EXYNOS5, gsc3, GSC3, GSC3);
+SYSMMU_RESOURCE(EXYNOS5, mfc_lr) {
+ DEFINE_SYSMMU_RESOURCE(EXYNOS5, MFC_R, MFC_R),
+ DEFINE_SYSMMU_RESOURCE(EXYNOS5, MFC_L, MFC_L),
+};
+SYSMMU_RESOURCE(EXYNOS5, isp) {
+ DEFINE_SYSMMU_RESOURCE(EXYNOS5, ISP, ISP),
+ DEFINE_SYSMMU_RESOURCE(EXYNOS5, DRC, DRC),
+ DEFINE_SYSMMU_RESOURCE(EXYNOS5, FD, FD),
+ DEFINE_SYSMMU_RESOURCE(EXYNOS5, ISPCPU, MCUISP),
+ DEFINE_SYSMMU_RESOURCE(EXYNOS5, SCALERC, SCALERCISP),
+ DEFINE_SYSMMU_RESOURCE(EXYNOS5, SCALERP, SCALERPISP),
+ DEFINE_SYSMMU_RESOURCE(EXYNOS5, ODC, ODC),
+ DEFINE_SYSMMU_RESOURCE(EXYNOS5, DIS0, DIS0),
+ DEFINE_SYSMMU_RESOURCE(EXYNOS5, DIS1, DIS1),
+ DEFINE_SYSMMU_RESOURCE(EXYNOS5, 3DNR, 3DNR),
+ DEFINE_SYSMMU_RESOURCE(EXYNOS5, LITE0, LITE0),
+ DEFINE_SYSMMU_RESOURCE(EXYNOS5, LITE1, LITE1),
+ DEFINE_SYSMMU_RESOURCE(EXYNOS5, LITE2, LITE2),
+};
+
+static struct sysmmu_resource_map sysmmu_resmap5[] __initdata = {
+ SYSMMU_RESOURCE_MAPPING_QOS(5, jpeg, jpeg, 8),
+ SYSMMU_RESOURCE_MAPPING_QOS(5, fimd1, fimd1, 15),
+ SYSMMU_RESOURCE_MAPPING_QOS(5, 2d, 2d, 8),
+ SYSMMU_RESOURCE_MAPPING_QOS(5, rot, rot, 8),
+ SYSMMU_RESOURCE_MAPPING_QOS(5, tv, tv, 15),
+ SYSMMU_RESOURCE_MAPPING_QOS(5, gsc0, gsc0, 8),
+ SYSMMU_RESOURCE_MAPPING_QOS(5, gsc1, gsc1, 8),
+ SYSMMU_RESOURCE_MAPPING_QOS(5, gsc2, gsc2, 8),
+ SYSMMU_RESOURCE_MAPPING_QOS(5, gsc3, gsc3, 8),
+ SYSMMU_RESOURCE_MAPPING_QOS(5, mfc_lr, mfc_lr, 8),
+ SYSMMU_RESOURCE_MAPPING_MC_QOS(5, isp, isp, mc_platdata, 8),
+};
+#endif /* CONFIG_ARCH_EXYNOS5 */
+
+static int __init init_sysmmu_platform_device(void)
+{
+ int i, j;
+ struct sysmmu_resource_map *resmap[2] = {NULL, NULL};
+ int nmap[2] = {0, 0};
+
+#ifdef CONFIG_ARCH_EXYNOS5
+ if (soc_is_exynos5250()) {
+ resmap[0] = sysmmu_resmap5;
+ nmap[0] = ARRAY_SIZE(sysmmu_resmap5);
+ nmap[1] = 0;
+ }
+#endif
+
+#ifdef CONFIG_ARCH_EXYNOS4
+ if (resmap[0] == NULL) {
+ resmap[0] = sysmmu_resmap4;
+ nmap[0] = ARRAY_SIZE(sysmmu_resmap4);
+ }
+
+ if (soc_is_exynos4210()) {
+ resmap[1] = sysmmu_resmap4210;
+ nmap[1] = ARRAY_SIZE(sysmmu_resmap4210);
+ }
+
+ if (soc_is_exynos4412() || soc_is_exynos4212()) {
+ resmap[1] = sysmmu_resmap4212;
+ nmap[1] = ARRAY_SIZE(sysmmu_resmap4212);
+ }
+#endif
+
+ for (j = 0; j < 2; j++) {
+ for (i = 0; i < nmap[j]; i++) {
+ struct sysmmu_resource_map *map;
+ struct sysmmu_platform_data *platdata;
+
+ map = &resmap[j][i];
+
+ map->pdev->dev.parent = map->pdd;
+
+ platdata = map->pdev->dev.platform_data;
+ platdata->clockname = map->clocknames;
+ platdata->qos = map->qos;
+
+ if (platform_device_add_resources(map->pdev, map->res,
+ map->rnum)) {
+ pr_err("%s: Failed to add device resources for "
+ "%s.%d\n", __func__,
+ map->pdev->name, map->pdev->id);
+ continue;
+ }
+
+ if (platform_device_register(map->pdev)) {
+ pr_err("%s: Failed to register %s.%d\n",
+ __func__, map->pdev->name,
+ map->pdev->id);
+ }
+ }
+ }
+
+ return 0;
+}
+subsys_initcall(init_sysmmu_platform_device);
diff --git a/arch/arm/mach-exynos/dev-tmu.c b/arch/arm/mach-exynos/dev-tmu.c
new file mode 100644
index 0000000..6cbccf3
--- /dev/null
+++ b/arch/arm/mach-exynos/dev-tmu.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <asm/irq.h>
+
+#include <plat/devs.h>
+
+#include <mach/irqs.h>
+#include <mach/map.h>
+#include <mach/tmu.h>
+
+static struct resource tmu_resource[] = {
+ [0] = DEFINE_RES_MEM(S5P_PA_TMU, SZ_64K),
+ [1] = DEFINE_RES_IRQ(EXYNOS5_IRQ_TMU),
+};
+
+struct platform_device exynos_device_tmu = {
+ .name = "exynos_tmu",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(tmu_resource),
+ .resource = tmu_resource,
+};
+
+int exynos_tmu_get_irqno(int num)
+{
+ return platform_get_irq(&exynos_device_tmu, num);
+}
+
+struct tmu_info *exynos_tmu_get_platdata(void)
+{
+ return platform_get_drvdata(&exynos_device_tmu);
+}
+
+void __init exynos_tmu_set_platdata(struct tmu_data *pd)
+{
+ struct tmu_data *npd;
+
+ if (pd == NULL) {
+ pr_err("%s: no platform data supplied\n", __func__);
+ return;
+ }
+
+ npd = kmemdup(pd, sizeof(struct tmu_data), GFP_KERNEL);
+ if (npd == NULL)
+ pr_err("%s: no memory for platform data\n", __func__);
+
+ exynos_device_tmu.dev.platform_data = npd;
+}
diff --git a/arch/arm/mach-exynos/dma.c b/arch/arm/mach-exynos/dma.c
index 69aaa45..bc44795 100644
--- a/arch/arm/mach-exynos/dma.c
+++ b/arch/arm/mach-exynos/dma.c
@@ -1,6 +1,5 @@
-/* linux/arch/arm/mach-exynos4/dma.c
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+/*
+ * Copyright (c) 2011-2012 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Copyright (C) 2010 Samsung Electronics Co. Ltd.
@@ -103,10 +102,45 @@
DMACH_MIPI_HSI5,
};
-struct dma_pl330_platdata exynos4_pdma0_pdata;
+u8 exynos5250_pdma0_peri[] = {
+ DMACH_PCM0_RX,
+ DMACH_PCM0_TX,
+ DMACH_PCM2_RX,
+ DMACH_PCM2_TX,
+ DMACH_SPI0_RX,
+ DMACH_SPI0_TX,
+ DMACH_SPI2_RX,
+ DMACH_SPI2_TX,
+ DMACH_I2S0S_TX,
+ DMACH_I2S0_RX,
+ DMACH_I2S0_TX,
+ DMACH_I2S2_RX,
+ DMACH_I2S2_TX,
+ DMACH_UART0_RX,
+ DMACH_UART0_TX,
+ DMACH_UART2_RX,
+ DMACH_UART2_TX,
+ DMACH_UART4_RX,
+ DMACH_UART4_TX,
+ DMACH_SLIMBUS0_RX,
+ DMACH_SLIMBUS0_TX,
+ DMACH_SLIMBUS2_RX,
+ DMACH_SLIMBUS2_TX,
+ DMACH_SLIMBUS4_RX,
+ DMACH_SLIMBUS4_TX,
+ DMACH_AC97_MICIN,
+ DMACH_AC97_PCMIN,
+ DMACH_AC97_PCMOUT,
+ DMACH_MIPI_HSI0,
+ DMACH_MIPI_HSI2,
+ DMACH_MIPI_HSI4,
+ DMACH_MIPI_HSI6,
+};
-static AMBA_AHB_DEVICE(exynos4_pdma0, "dma-pl330.0", 0x00041330,
- EXYNOS4_PA_PDMA0, {EXYNOS4_IRQ_PDMA0}, &exynos4_pdma0_pdata);
+static struct dma_pl330_platdata exynos_pdma0_pdata;
+
+static AMBA_AHB_DEVICE(exynos_pdma0, "dma-pl330.0", 0x00041330,
+ 0, {EXYNOS5_IRQ_PDMA0}, &exynos_pdma0_pdata);
static u8 exynos4210_pdma1_peri[] = {
DMACH_PCM0_RX,
@@ -169,10 +203,45 @@
DMACH_MIPI_HSI7,
};
-static struct dma_pl330_platdata exynos4_pdma1_pdata;
+u8 exynos5250_pdma1_peri[] = {
+ DMACH_PCM0_RX,
+ DMACH_PCM0_TX,
+ DMACH_PCM1_RX,
+ DMACH_PCM1_TX,
+ DMACH_SPI1_RX,
+ DMACH_SPI1_TX,
+ DMACH_PWM,
+ DMACH_SPDIF,
+ DMACH_I2S0S_TX,
+ DMACH_I2S0_RX,
+ DMACH_I2S0_TX,
+ DMACH_I2S1_RX,
+ DMACH_I2S1_TX,
+ DMACH_UART0_RX,
+ DMACH_UART0_TX,
+ DMACH_UART1_RX,
+ DMACH_UART1_TX,
+ DMACH_UART3_RX,
+ DMACH_UART3_TX,
+ DMACH_SLIMBUS1_RX,
+ DMACH_SLIMBUS1_TX,
+ DMACH_SLIMBUS3_RX,
+ DMACH_SLIMBUS3_TX,
+ DMACH_SLIMBUS5_RX,
+ DMACH_SLIMBUS5_TX,
+ DMACH_SLIMBUS0AUX_RX,
+ DMACH_SLIMBUS0AUX_TX,
+ DMACH_DISP1,
+ DMACH_MIPI_HSI1,
+ DMACH_MIPI_HSI3,
+ DMACH_MIPI_HSI5,
+ DMACH_MIPI_HSI7,
+};
-static AMBA_AHB_DEVICE(exynos4_pdma1, "dma-pl330.1", 0x00041330,
- EXYNOS4_PA_PDMA1, {EXYNOS4_IRQ_PDMA1}, &exynos4_pdma1_pdata);
+struct dma_pl330_platdata exynos_pdma1_pdata;
+
+static AMBA_AHB_DEVICE(exynos_pdma1, "dma-pl330.1", 0x00041330,
+ 0, {EXYNOS5_IRQ_PDMA1}, &exynos_pdma1_pdata);
static u8 mdma_peri[] = {
DMACH_MTOM_0,
@@ -185,46 +254,72 @@
DMACH_MTOM_7,
};
-static struct dma_pl330_platdata exynos4_mdma1_pdata = {
+static struct dma_pl330_platdata exynos_mdma1_pdata = {
.nr_valid_peri = ARRAY_SIZE(mdma_peri),
.peri_id = mdma_peri,
};
-static AMBA_AHB_DEVICE(exynos4_mdma1, "dma-pl330.2", 0x00041330,
- EXYNOS4_PA_MDMA1, {EXYNOS4_IRQ_MDMA1}, &exynos4_mdma1_pdata);
+static AMBA_AHB_DEVICE(exynos_mdma1, "dma-pl330.2", 0x00041330,
+ 0, {EXYNOS5_IRQ_MDMA1}, &exynos_mdma1_pdata);
-static int __init exynos4_dma_init(void)
+static int __init exynos_dma_init(void)
{
if (of_have_populated_dt())
return 0;
if (soc_is_exynos4210()) {
- exynos4_pdma0_pdata.nr_valid_peri =
+ exynos_pdma0_pdata.nr_valid_peri =
ARRAY_SIZE(exynos4210_pdma0_peri);
- exynos4_pdma0_pdata.peri_id = exynos4210_pdma0_peri;
- exynos4_pdma1_pdata.nr_valid_peri =
+ exynos_pdma0_pdata.peri_id = exynos4210_pdma0_peri;
+ exynos_pdma1_pdata.nr_valid_peri =
ARRAY_SIZE(exynos4210_pdma1_peri);
- exynos4_pdma1_pdata.peri_id = exynos4210_pdma1_peri;
+ exynos_pdma1_pdata.peri_id = exynos4210_pdma1_peri;
} else if (soc_is_exynos4212() || soc_is_exynos4412()) {
- exynos4_pdma0_pdata.nr_valid_peri =
+ exynos_pdma0_pdata.nr_valid_peri =
ARRAY_SIZE(exynos4212_pdma0_peri);
- exynos4_pdma0_pdata.peri_id = exynos4212_pdma0_peri;
- exynos4_pdma1_pdata.nr_valid_peri =
+ exynos_pdma0_pdata.peri_id = exynos4212_pdma0_peri;
+ exynos_pdma1_pdata.nr_valid_peri =
ARRAY_SIZE(exynos4212_pdma1_peri);
- exynos4_pdma1_pdata.peri_id = exynos4212_pdma1_peri;
+ exynos_pdma1_pdata.peri_id = exynos4212_pdma1_peri;
+ } else if (soc_is_exynos5250()) {
+ exynos_pdma0_pdata.nr_valid_peri =
+ ARRAY_SIZE(exynos5250_pdma0_peri);
+ exynos_pdma0_pdata.peri_id = exynos5250_pdma0_peri;
+ exynos_pdma1_pdata.nr_valid_peri =
+ ARRAY_SIZE(exynos5250_pdma1_peri);
+ exynos_pdma1_pdata.peri_id = exynos5250_pdma1_peri;
}
- dma_cap_set(DMA_SLAVE, exynos4_pdma0_pdata.cap_mask);
- dma_cap_set(DMA_CYCLIC, exynos4_pdma0_pdata.cap_mask);
- amba_device_register(&exynos4_pdma0_device, &iomem_resource);
+ if (soc_is_exynos4210() || soc_is_exynos4212() || soc_is_exynos4412()) {
+ exynos_pdma0_device.res.start = EXYNOS4_PA_PDMA0;
+ exynos_pdma0_device.res.end = EXYNOS4_PA_PDMA0 + SZ_4K;
+ exynos_pdma0_device.irq[0] = EXYNOS4_IRQ_PDMA0;
+ exynos_pdma1_device.res.start = EXYNOS4_PA_PDMA1;
+ exynos_pdma1_device.res.end = EXYNOS4_PA_PDMA1 + SZ_4K;
+ exynos_pdma1_device.irq[0] = EXYNOS4_IRQ_PDMA1;
+ exynos_mdma1_device.res.start = EXYNOS4_PA_MDMA1;
+ exynos_mdma1_device.res.end = EXYNOS4_PA_MDMA1 + SZ_4K;
+ exynos_mdma1_device.irq[0] = EXYNOS4_IRQ_MDMA1;
+ } else if (soc_is_exynos5250()) {
+ exynos_pdma0_device.res.start = EXYNOS5_PA_PDMA0;
+ exynos_pdma0_device.res.end = EXYNOS5_PA_PDMA0 + SZ_4K;
+ exynos_pdma1_device.res.start = EXYNOS5_PA_PDMA1;
+ exynos_pdma1_device.res.end = EXYNOS5_PA_PDMA1 + SZ_4K;
+ exynos_mdma1_device.res.start = EXYNOS5_PA_MDMA1;
+ exynos_mdma1_device.res.end = EXYNOS5_PA_MDMA1 + SZ_4K;
+ }
- dma_cap_set(DMA_SLAVE, exynos4_pdma1_pdata.cap_mask);
- dma_cap_set(DMA_CYCLIC, exynos4_pdma1_pdata.cap_mask);
- amba_device_register(&exynos4_pdma1_device, &iomem_resource);
+ dma_cap_set(DMA_SLAVE, exynos_pdma0_pdata.cap_mask);
+ dma_cap_set(DMA_CYCLIC, exynos_pdma0_pdata.cap_mask);
+ amba_device_register(&exynos_pdma0_device, &iomem_resource);
- dma_cap_set(DMA_MEMCPY, exynos4_mdma1_pdata.cap_mask);
- amba_device_register(&exynos4_mdma1_device, &iomem_resource);
+ dma_cap_set(DMA_SLAVE, exynos_pdma1_pdata.cap_mask);
+ dma_cap_set(DMA_CYCLIC, exynos_pdma1_pdata.cap_mask);
+ amba_device_register(&exynos_pdma1_device, &iomem_resource);
+
+ dma_cap_set(DMA_MEMCPY, exynos_mdma1_pdata.cap_mask);
+ amba_device_register(&exynos_mdma1_device, &iomem_resource);
return 0;
}
-arch_initcall(exynos4_dma_init);
+arch_initcall(exynos_dma_init);
diff --git a/arch/arm/mach-exynos/exynos_fiq_debugger.c b/arch/arm/mach-exynos/exynos_fiq_debugger.c
new file mode 100644
index 0000000..f2b3d86
--- /dev/null
+++ b/arch/arm/mach-exynos/exynos_fiq_debugger.c
@@ -0,0 +1,214 @@
+/*
+ * Serial Debugger Interface for exynos
+ *
+ * Copyright (C) 2012 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 <linux/delay.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/stacktrace.h>
+#include <linux/uaccess.h>
+
+#include <asm/fiq_debugger.h>
+
+#include <plat/regs-serial.h>
+
+#include <mach/exynos_fiq_debugger.h>
+#include <mach/map.h>
+
+struct exynos_fiq_debugger {
+ struct fiq_debugger_pdata pdata;
+ struct platform_device *pdev;
+ void __iomem *debug_port_base;
+ u32 baud;
+ u32 frac_baud;
+};
+
+static inline struct exynos_fiq_debugger *get_dbg(struct platform_device *pdev)
+{
+ struct fiq_debugger_pdata *pdata = dev_get_platdata(&pdev->dev);
+ return container_of(pdata, struct exynos_fiq_debugger, pdata);
+}
+
+static inline void exynos_write(struct exynos_fiq_debugger *dbg,
+ unsigned int val, unsigned int off)
+{
+ __raw_writel(val, dbg->debug_port_base + off);
+}
+
+static inline unsigned int exynos_read(struct exynos_fiq_debugger *dbg,
+ unsigned int off)
+{
+ return __raw_readl(dbg->debug_port_base + off);
+}
+
+static int debug_port_init(struct platform_device *pdev)
+{
+ struct exynos_fiq_debugger *dbg = get_dbg(pdev);
+ unsigned long timeout;
+
+ exynos_write(dbg, dbg->baud, S3C2410_UBRDIV);
+ exynos_write(dbg, dbg->frac_baud, S3C2443_DIVSLOT);
+
+ /* Mask and clear all interrupts */
+ exynos_write(dbg, 0xF, S3C64XX_UINTM);
+ exynos_write(dbg, 0xF, S3C64XX_UINTP);
+
+ exynos_write(dbg, S3C2410_LCON_CS8, S3C2410_ULCON);
+ exynos_write(dbg, S5PV210_UCON_DEFAULT, S3C2410_UCON);
+ exynos_write(dbg, S5PV210_UFCON_DEFAULT, S3C2410_UFCON);
+ exynos_write(dbg, 0, S3C2410_UMCON);
+
+ /* Reset TX and RX fifos */
+ exynos_write(dbg, S5PV210_UFCON_DEFAULT | S3C2410_UFCON_RESETBOTH,
+ S3C2410_UFCON);
+
+ timeout = jiffies + HZ;
+ while (exynos_read(dbg, S3C2410_UFCON) & S3C2410_UFCON_RESETBOTH)
+ if (time_after(jiffies, timeout))
+ return -ETIMEDOUT;
+
+ /* Enable all interrupts except TX */
+ exynos_write(dbg, S3C64XX_UINTM_TXD_MSK, S3C64XX_UINTM);
+
+ return 0;
+}
+
+static int debug_getc(struct platform_device *pdev)
+{
+ struct exynos_fiq_debugger *dbg = get_dbg(pdev);
+ u32 stat;
+ int ret = FIQ_DEBUGGER_NO_CHAR;
+
+ /* Clear all pending interrupts */
+ exynos_write(dbg, 0xF, S3C64XX_UINTP);
+
+ stat = exynos_read(dbg, S3C2410_UERSTAT);
+ if (stat & S3C2410_UERSTAT_BREAK)
+ return FIQ_DEBUGGER_BREAK;
+
+ stat = exynos_read(dbg, S3C2410_UTRSTAT);
+ if (stat & S3C2410_UTRSTAT_RXDR)
+ ret = exynos_read(dbg, S3C2410_URXH);
+
+ return ret;
+}
+
+static void debug_putc(struct platform_device *pdev, unsigned int c)
+{
+ struct exynos_fiq_debugger *dbg = get_dbg(pdev);
+ int count = loops_per_jiffy;
+
+ if (exynos_read(dbg, S3C2410_ULCON) != S3C2410_LCON_CS8)
+ debug_port_init(pdev);
+
+ while (exynos_read(dbg, S3C2410_UFSTAT) & S5PV210_UFSTAT_TXFULL)
+ if (--count == 0)
+ return;
+
+ exynos_write(dbg, c, S3C2410_UTXH);
+}
+
+static void debug_flush(struct platform_device *pdev)
+{
+ struct exynos_fiq_debugger *dbg = get_dbg(pdev);
+ int count = loops_per_jiffy * HZ;
+
+ while (!(exynos_read(dbg, S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXE))
+ if (--count == 0)
+ return;
+}
+
+static int debug_suspend(struct platform_device *pdev)
+{
+ struct exynos_fiq_debugger *dbg = get_dbg(pdev);
+
+ exynos_write(dbg, 0xF, S3C64XX_UINTM);
+
+ return 0;
+}
+
+static int debug_resume(struct platform_device *pdev)
+{
+ struct exynos_fiq_debugger *dbg = get_dbg(pdev);
+
+ debug_port_init(pdev);
+
+ return 0;
+}
+
+int __init exynos_serial_debug_init(int id, bool is_fiq)
+{
+ struct exynos_fiq_debugger *dbg = NULL;
+ struct platform_device *pdev = NULL;
+ struct resource *res = NULL;
+ int ret = -ENOMEM;
+ struct resource irq_res =
+ DEFINE_RES_IRQ_NAMED(EXYNOS_IRQ_UARTx(id), "uart_irq");
+
+ if (id >= CONFIG_SERIAL_SAMSUNG_UARTS)
+ return -EINVAL;
+
+ dbg = kzalloc(sizeof(struct exynos_fiq_debugger), GFP_KERNEL);
+ if (!dbg) {
+ pr_err("exynos_fiq_debugger: failed to allocate fiq debugger\n");
+ goto err_free;
+ }
+
+ res = kmemdup(&irq_res, sizeof(struct resource), GFP_KERNEL);
+ if (!res) {
+ pr_err("exynos_fiq_debugger: failed to alloc resources\n");
+ goto err_free;
+ }
+
+ pdev = kzalloc(sizeof(struct platform_device), GFP_KERNEL);
+ if (!pdev) {
+ pr_err("exynos_fiq_debugger: failed to alloc platform device\n");
+ goto err_free;
+ };
+
+ dbg->debug_port_base = S3C_VA_UARTx(id);
+
+ pdev->name = "fiq_debugger";
+ pdev->id = id;
+ pdev->dev.platform_data = &dbg->pdata;
+ pdev->resource = res;
+ pdev->num_resources = 1;
+
+ dbg->pdata.uart_init = debug_port_init;
+ dbg->pdata.uart_getc = debug_getc;
+ dbg->pdata.uart_putc = debug_putc;
+ dbg->pdata.uart_flush = debug_flush;
+ dbg->pdata.uart_dev_suspend = debug_suspend;
+ dbg->pdata.uart_dev_resume = debug_resume;
+
+ dbg->pdev = pdev;
+
+ dbg->baud = exynos_read(dbg, S3C2410_UBRDIV);
+ dbg->frac_baud = exynos_read(dbg, S3C2443_DIVSLOT);
+
+ if (platform_device_register(pdev)) {
+ pr_err("exynos_fiq_debugger: failed to register fiq debugger\n");
+ goto err_free;
+ }
+
+ return 0;
+
+err_free:
+ kfree(pdev);
+ kfree(res);
+ kfree(dbg);
+ return ret;
+}
diff --git a/arch/arm/mach-exynos/hotplug.c b/arch/arm/mach-exynos/hotplug.c
index 9c17a0a..0788e9c 100644
--- a/arch/arm/mach-exynos/hotplug.c
+++ b/arch/arm/mach-exynos/hotplug.c
@@ -19,11 +19,12 @@
#include <asm/cp15.h>
#include <asm/smp_plat.h>
+#include <plat/cpu.h>
#include <mach/regs-pmu.h>
extern volatile int pen_release;
-static inline void cpu_enter_lowpower(void)
+static inline void cpu_enter_lowpower_a9(void)
{
unsigned int v;
@@ -45,6 +46,35 @@
: "cc");
}
+static inline void cpu_enter_lowpower_a15(void)
+{
+ unsigned int v;
+
+ asm volatile(
+ " mrc p15, 0, %0, c1, c0, 0\n"
+ " bic %0, %0, %1\n"
+ " mcr p15, 0, %0, c1, c0, 0\n"
+ : "=&r" (v)
+ : "Ir" (CR_C)
+ : "cc");
+
+ flush_cache_all();
+
+ asm volatile(
+ /*
+ * Turn off coherency
+ */
+ " mrc p15, 0, %0, c1, c0, 1\n"
+ " bic %0, %0, %1\n"
+ " mcr p15, 0, %0, c1, c0, 1\n"
+ : "=&r" (v)
+ : "Ir" (0x40)
+ : "cc");
+
+ isb();
+ dsb();
+}
+
static inline void cpu_leave_lowpower(void)
{
unsigned int v;
@@ -67,7 +97,7 @@
/* make cpu1 to be turned off at next WFI command */
if (cpu == 1)
- __raw_writel(0, S5P_ARM_CORE1_CONFIGURATION);
+ __raw_writel(0, EXYNOS_ARM_CORE1_CONFIGURATION);
/*
* here's the WFI
@@ -112,7 +142,10 @@
/*
* we're ready for shutdown now, so do it
*/
- cpu_enter_lowpower();
+ if (soc_is_exynos5250())
+ cpu_enter_lowpower_a15();
+ else
+ cpu_enter_lowpower_a9();
platform_do_lowpower(cpu, &spurious);
/*
diff --git a/arch/arm/mach-exynos/include/mach/abb-exynos.h b/arch/arm/mach-exynos/include/mach/abb-exynos.h
new file mode 100644
index 0000000..89110cb
--- /dev/null
+++ b/arch/arm/mach-exynos/include/mach/abb-exynos.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics co., ltd.
+ * http://www.samsung.com/
+ *
+ * EXYNOS - ABB header file
+ *
+ * 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.
+*/
+
+#ifndef __MACH_ABB_EXYNOS_H
+#define __MACH_ABB_EXYNOS_H __FILE__
+
+enum abb_member {
+ ABB_INT,
+ ABB_ARM,
+ ABB_G3D,
+ ABB_MIF,
+};
+extern void set_abb_member(enum abb_member abb_target,
+ unsigned int abb_mode_value);
+
+#endif /* __MACH_ABB_EXYNOS_H */
diff --git a/arch/arm/mach-exynos/include/mach/asv-exynos.h b/arch/arm/mach-exynos/include/mach/asv-exynos.h
new file mode 100644
index 0000000..f577cfd
--- /dev/null
+++ b/arch/arm/mach-exynos/include/mach/asv-exynos.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics co., ltd.
+ * http://www.samsung.com/
+ *
+ * EXYNOS - ASV header file
+ *
+ * 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.
+*/
+
+#ifndef __ASM_ARCH_ASV_EXYNOS_H
+#define __ASM_ARCH_ASV_EXYNOS_H __FILE__
+
+enum asv_type_id {
+ ID_ARM,
+ ID_INT,
+ ID_MIF,
+ ID_G3D,
+ ID_END,
+};
+
+struct asv_common {
+ bool init_done;
+ unsigned int (*get_voltage)(enum asv_type_id, unsigned int freq);
+};
+
+extern unsigned int asv_get_volt(enum asv_type_id target_type, unsigned int target_freq);
+extern int exynos5250_init_asv(struct asv_common *asv_info);
+
+#endif /* __ASM_ARCH_ASV_EXYNOS_H */
diff --git a/arch/arm/mach-exynos/include/mach/asv-exynos5250.h b/arch/arm/mach-exynos/include/mach/asv-exynos5250.h
new file mode 100644
index 0000000..0450f0b
--- /dev/null
+++ b/arch/arm/mach-exynos/include/mach/asv-exynos5250.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * EXYNOS5250 - Adaptive Support Voltage Header file
+ *
+ * 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.
+ */
+
+#ifndef __ASM_ARCH_EXYNOS5250_ASV_H
+#define __ASM_ARCH_EXYNOS5250_ASV_H __FILE__
+
+#define ARM_DVFS_LEVEL_NR 16
+#define ARM_ASV_GRP_NR 12
+#define INT_DVFS_LEVEL_NR 5
+#define INT_ASV_GRP_NR 12
+#define MIF_DVFS_LEVEL_NR 8
+#define MIF_ASV_GRP_NR 4
+#define G3D_DVFS_LEVEL_NR 7
+#define G3D_ASV_GRP_NR 12
+
+#define MAX_ASV_GRP_NR 12
+
+static unsigned int arm_refer_table_get_asv[2][MAX_ASV_GRP_NR] = {
+ { 7, 9, 10, 11, 13, 15, 17, 21, 25, 32, 39, 999},
+ { 6, 8, 9, 10, 12, 13, 14, 16, 17, 19, 20, 999},
+};
+
+static unsigned int arm_asv_volt_info[ARM_DVFS_LEVEL_NR][MAX_ASV_GRP_NR + 1] = {
+ { 1700000, 1300000, 1275000, 1275000, 1262500, 1250000, 1225000, 1212500, 1200000, 1187500, 1175000, 1150000, 1125000},
+ { 1600000, 1250000, 1225000, 1225000, 1212500, 1200000, 1187500, 1175000, 1162500, 1150000, 1137500, 1112500, 1100000},
+ { 1500000, 1225000, 1187500, 1175000, 1162500, 1150000, 1137500, 1125000, 1112500, 1100000, 1087500, 1075000, 1062500},
+ { 1400000, 1200000, 1125000, 1125000, 1125000, 1112500, 1100000, 1087500, 1075000, 1062500, 1050000, 1037500, 1025000},
+ { 1300000, 1150000, 1100000, 1100000, 1100000, 1087500, 1075000, 1062500, 1050000, 1037500, 1025000, 1012500, 1000000},
+ { 1200000, 1125000, 1075000, 1075000, 1062500, 1050000, 1037500, 1025000, 1012500, 1000000, 987500, 975000, 975000},
+ { 1100000, 1100000, 1050000, 1050000, 1037500, 1025000, 1012500, 1000000, 987500, 975000, 962500, 950000, 925000},
+ { 1000000, 1075000, 1037500, 1037500, 1012500, 1000000, 987500, 975000, 962500, 950000, 937500, 925000, 912500},
+ { 900000, 1050000, 1025000, 1012500, 987500, 975000, 962500, 950000, 937500, 925000, 912500, 912500, 900000},
+ { 800000, 1025000, 1000000, 987500, 975000, 962500, 950000, 937500, 925000, 912500, 900000, 900000, 900000},
+ { 700000, 1012500, 975000, 962500, 950000, 937500, 925000, 912500, 900000, 900000, 900000, 900000, 900000},
+ { 600000, 1000000, 962500, 950000, 937500, 925000, 912500, 900000, 900000, 900000, 900000, 900000, 900000},
+ { 500000, 975000, 950000, 937500, 925000, 912500, 900000, 900000, 900000, 900000, 900000, 900000, 887500},
+ { 400000, 950000, 937500, 925000, 912500, 900000, 900000, 900000, 900000, 900000, 900000, 887500, 887500},
+ { 300000, 937500, 925000, 912500, 900000, 900000, 900000, 900000, 900000, 900000, 887500, 887500, 875000},
+ { 200000, 925000, 912500, 900000, 900000, 900000, 900000, 900000, 900000, 887500, 887500, 875000, 875000},
+};
+
+static unsigned int int_refer_table_get_asv[2][MAX_ASV_GRP_NR] = {
+ { 7, 9, 10, 11, 13, 15, 17, 21, 25, 32, 39, 999},
+ { 6, 8, 9, 10, 12, 13, 14, 16, 17, 19, 20, 999},
+};
+
+static unsigned int int_asv_volt_info[INT_DVFS_LEVEL_NR][MAX_ASV_GRP_NR + 1] = {
+ { 266000, 1037500, 1025000, 1025000, 1012500, 1000000, 987500, 975000, 962500, 962500, 950000, 950000, 937500},
+ { 200000, 1000000, 975000, 987500, 975000, 962500, 950000, 937500, 925000, 925000, 912500, 912500, 900000},
+ { 160000, 975000, 962500, 975000, 962500, 950000, 937500, 925000, 912500, 912500, 900000, 900000, 900000},
+ { 133000, 950000, 937500, 950000, 937500, 925000, 912500, 900000, 900000, 900000, 900000, 900000, 887500},
+ { 100000, 925000, 912500, 925000, 912500, 900000, 900000, 900000, 900000, 900000, 887500, 887500, 875000},
+};
+
+static unsigned int mif_refer_table_get_asv[2][MAX_ASV_GRP_NR] = {
+ { 0, 12, 15, 999, 0, 0, 0, 0, 0, 0, 0, 0},
+ { 0, 100, 112, 999, 0, 0, 0, 0, 0, 0, 0, 0},
+};
+
+static unsigned int mif_asv_volt_info[MIF_DVFS_LEVEL_NR][MAX_ASV_GRP_NR + 1] = {
+ { 800000, 1125000, 1062500, 1037500, 987500, 0, 0, 0, 0, 0, 0, 0, 0},
+ { 733000, 1075000, 1012500, 987500, 937500, 0, 0, 0, 0, 0, 0, 0, 0},
+ { 667000, 1025000, 962500, 937500, 900000, 0, 0, 0, 0, 0, 0, 0, 0},
+ { 533000, 1025000, 962500, 937500, 900000, 0, 0, 0, 0, 0, 0, 0, 0},
+ { 400000, 1012500, 950000, 925000, 900000, 0, 0, 0, 0, 0, 0, 0, 0},
+ { 267000, 1000000, 937500, 912500, 900000, 0, 0, 0, 0, 0, 0, 0, 0},
+ { 160000, 975000, 912500, 900000, 900000, 0, 0, 0, 0, 0, 0, 0, 0},
+ { 100000, 962500, 900000, 900000, 900000, 0, 0, 0, 0, 0, 0, 0, 0},
+};
+
+static unsigned int g3d_refer_table_get_asv[2][MAX_ASV_GRP_NR] = {
+ { 7, 9, 10, 11, 13, 15, 17, 21, 25, 32, 39, 999},
+ { 6, 8, 9, 10, 12, 13, 14, 16, 17, 19, 20, 999},
+};
+
+static unsigned int g3d_asv_volt_info[G3D_DVFS_LEVEL_NR][MAX_ASV_GRP_NR + 1] = {
+ { 533000, 1200000, 1187500, 1187500, 1187500, 1175000, 1150000, 1137500, 1125000, 1125000, 1125000, 1112500, 1112500},
+ { 450000, 1150000, 1137500, 1125000, 1125000, 1112500, 1100000, 1087500, 1075000, 1075000, 1050000, 1050000, 1050000},
+ { 400000, 1125000, 1087500, 1075000, 1075000, 1075000, 1050000, 1037500, 1025000, 1012500, 1012500, 1000000, 1000000},
+ { 350000, 1075000, 1037500, 1037500, 1037500, 1025000, 1000000, 987500, 987500, 987500, 975000, 962500, 962500},
+ { 266000, 1025000, 1000000, 950000, 950000, 937500, 937500, 925000, 912500, 912500, 900000, 900000, 900000},
+ { 160000, 925000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000},
+ { 100000, 925000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 900000, 875000, 875000},
+};
+
+#endif /* EXYNOS5250_ASV_H */
diff --git a/arch/arm/mach-exynos/include/mach/cpufreq.h b/arch/arm/mach-exynos/include/mach/cpufreq.h
index 7517c3f..cefc44b 100644
--- a/arch/arm/mach-exynos/include/mach/cpufreq.h
+++ b/arch/arm/mach-exynos/include/mach/cpufreq.h
@@ -33,4 +33,6 @@
extern int exynos4210_cpufreq_init(struct exynos_dvfs_info *);
extern int exynos4x12_cpufreq_init(struct exynos_dvfs_info *);
-extern int exynos5250_cpufreq_init(struct exynos_dvfs_info *);
+extern int __init exynos5250_cpufreq_init(struct exynos_dvfs_info *);
+extern void exynos_thermal_throttle(void);
+extern void exynos_thermal_unthrottle(void);
diff --git a/arch/arm/mach-exynos/include/mach/dsim.h b/arch/arm/mach-exynos/include/mach/dsim.h
new file mode 100644
index 0000000..712d848
--- /dev/null
+++ b/arch/arm/mach-exynos/include/mach/dsim.h
@@ -0,0 +1,250 @@
+/* linux/arm/arch/mach-exynos/include/mach/dsim.h
+ *
+ * Platform data header for Samsung MIPI-DSIM.
+ *
+ * Copyright (c) 2009 Samsung Electronics
+ * InKi Dae <inki.dae@samsung.com>
+ *
+ * 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.
+*/
+
+#ifndef _DSIM_H
+#define _DSIM_H
+
+/* h/w configuration */
+#define MIPI_FIN 24000000
+#define DSIM_HEADER_FIFO_SZ 16
+#define DSIM_TIMEOUT_MS 5000
+#define DSIM_NO_OF_INTERRUPT 26
+#define DSIM_PM_STABLE_TIME 10
+
+#define DSIM_TRUE 1
+#define DSIM_FALSE 0
+
+#define CMD_LENGTH 0xf
+
+enum dsim_interface_type {
+ DSIM_COMMAND = 0,
+ DSIM_VIDEO = 1,
+};
+
+enum dsim_state {
+ DSIM_STATE_RESET = 0,
+ DSIM_STATE_INIT = 1,
+ DSIM_STATE_STOP = 2,
+ DSIM_STATE_HSCLKEN = 3,
+ DSIM_STATE_ULPS = 4,
+};
+
+enum {
+ DSIM_NONE_STATE = 0,
+ DSIM_RESUME_COMPLETE = 1,
+ DSIM_FRAME_DONE = 2,
+};
+
+enum dsim_virtual_ch_no {
+ DSIM_VIRTUAL_CH_0 = 0,
+ DSIM_VIRTUAL_CH_1 = 1,
+ DSIM_VIRTUAL_CH_2 = 2,
+ DSIM_VIRTUAL_CH_3 = 3,
+};
+
+enum dsim_video_mode_type {
+ DSIM_NON_BURST_SYNC_EVENT = 0,
+ DSIM_BURST_SYNC_EVENT = 1,
+ DSIM_NON_BURST_SYNC_PULSE = 2,
+ DSIM_BURST = 3,
+ DSIM_NON_VIDEO_MODE = 4,
+};
+
+enum dsim_fifo_state {
+ DSIM_RX_DATA_FULL = (1 << 25),
+ DSIM_RX_DATA_EMPTY = (1 << 24),
+ SFR_HEADER_FULL = (1 << 23),
+ SFR_HEADER_EMPTY = (1 << 22),
+ SFR_PAYLOAD_FULL = (1 << 21),
+ SFR_PAYLOAD_EMPTY = (1 << 20),
+ I80_HEADER_FULL = (1 << 19),
+ I80_HEADER_EMPTY = (1 << 18),
+ I80_PALOAD_FULL = (1 << 17),
+ I80_PALOAD_EMPTY = (1 << 16),
+ SUB_DISP_HEADER_FULL = (1 << 15),
+ SUB_DISP_HEADER_EMPTY = (1 << 14),
+ SUB_DISP_PAYLOAD_FULL = (1 << 13),
+ SUB_DISP_PAYLOAD_EMPTY = (1 << 12),
+ MAIN_DISP_HEADER_FULL = (1 << 11),
+ MAIN_DISP_HEADER_EMPTY = (1 << 10),
+ MAIN_DISP_PAYLOAD_FULL = (1 << 9),
+ MAIN_DISP_PAYLOAD_EMPTY = (1 << 8),
+};
+
+enum dsim_no_of_data_lane {
+ DSIM_DATA_LANE_1 = 0,
+ DSIM_DATA_LANE_2 = 1,
+ DSIM_DATA_LANE_3 = 2,
+ DSIM_DATA_LANE_4 = 3,
+};
+
+enum dsim_byte_clk_src {
+ DSIM_PLL_OUT_DIV8 = 0,
+ DSIM_EXT_CLK_DIV8 = 1,
+ DSIM_EXT_CLK_BYPASS = 2,
+};
+
+enum dsim_lane {
+ DSIM_LANE_DATA0 = (1 << 0),
+ DSIM_LANE_DATA1 = (1 << 1),
+ DSIM_LANE_DATA2 = (1 << 2),
+ DSIM_LANE_DATA3 = (1 << 3),
+ DSIM_LANE_DATA_ALL = 0xf,
+ DSIM_LANE_CLOCK = (1 << 4),
+ DSIM_LANE_ALL = DSIM_LANE_CLOCK | DSIM_LANE_DATA_ALL,
+};
+
+enum dsim_pixel_format {
+ DSIM_CMD_3BPP = 0,
+ DSIM_CMD_8BPP = 1,
+ DSIM_CMD_12BPP = 2,
+ DSIM_CMD_16BPP = 3,
+ DSIM_VID_16BPP_565 = 4,
+ DSIM_VID_18BPP_666PACKED = 5,
+ DSIM_18BPP_666LOOSELYPACKED = 6,
+ DSIM_24BPP_888 = 7,
+};
+
+enum dsim_lane_state {
+ DSIM_LANE_STATE_HS_READY,
+ DSIM_LANE_STATE_ULPS,
+ DSIM_LANE_STATE_STOP,
+ DSIM_LANE_STATE_LPDT,
+};
+
+enum dsim_transfer {
+ DSIM_TRANSFER_NEITHER = 0,
+ DSIM_TRANSFER_BYCPU = (1 << 7),
+ DSIM_TRANSFER_BYLCDC = (1 << 6),
+ DSIM_TRANSFER_BOTH = (0x3 << 6)
+};
+
+enum dsim_lane_change {
+ DSIM_NO_CHANGE = 0,
+ DSIM_DATA_LANE_CHANGE = 1,
+ DSIM_CLOCK_NALE_CHANGE = 2,
+ DSIM_ALL_LANE_CHANGE = 3,
+};
+
+enum dsim_int_src {
+ DSIM_ALL_OF_INTR = 0xffffffff,
+ DSIM_PLL_STABLE = (1 << 31),
+};
+
+enum dsim_data_id {
+ /* short packet types of packet types for command */
+ GEN_SHORT_WR_NO_PARA = 0x03,
+ GEN_SHORT_WR_1_PARA = 0x13,
+ GEN_SHORT_WR_2_PARA = 0x23,
+ GEN_RD_NO_PARA = 0x04,
+ GEN_RD_1_PARA = 0x14,
+ GEN_RD_2_PARA = 0x24,
+ DCS_WR_NO_PARA = 0x05,
+ DCS_WR_1_PARA = 0x15,
+ DCS_RD_NO_PARA = 0x06,
+ SET_MAX_RTN_PKT_SIZE = 0x37,
+
+ /* long packet types of packet types for command */
+ NULL_PKT = 0x09,
+ BLANKING_PKT = 0x19,
+ GEN_LONG_WR = 0x29,
+ DCS_LONG_WR = 0x39,
+
+ /* short packet types of generic command */
+ CMD_OFF = 0x02,
+ CMD_ON = 0x12,
+ SHUT_DOWN = 0x22,
+ TURN_ON = 0x32,
+
+ /* short packet types for video data */
+ VSYNC_START = 0x01,
+ VSYNC_END = 0x11,
+ HSYNC_START = 0x21,
+ HSYNC_END = 0x31,
+ EOT_PKT = 0x08,
+
+ /* long packet types for video data */
+ RGB565_PACKED = 0x0e,
+ RGB666_PACKED = 0x1e,
+ RGB666_LOOSLY = 0x2e,
+ RGB888_PACKED = 0x3e,
+};
+
+struct dsim_config {
+ /* only DSIM_1_03 */
+ unsigned char auto_flush;
+
+ /* only DSIM_1.02 or DSIM_1_03 */
+ unsigned char eot_disable;
+
+ /* porch option */
+ unsigned char auto_vertical_cnt; /* auto vertical cnt mode */
+ unsigned char hse; /* horizontal sync event mode */
+ unsigned char hfp; /* discard horizontal front porch time */
+ unsigned char hbp; /* discard horizontal back porch time */
+ unsigned char hsa; /* discard horizontal sync area timing */
+
+ /* data lane */
+ enum dsim_no_of_data_lane e_no_data_lane; /* number of data lane using DSI Master */
+
+ /* byte clock and escape clock */
+ enum dsim_byte_clk_src e_byte_clk;
+
+ /* pll pms value */
+ unsigned char p;
+ unsigned short m;
+ unsigned char s;
+
+ /* pll stable time */
+ unsigned int pll_stable_time;
+
+ unsigned long esc_clk;
+
+ /* BTA sequence */
+ unsigned short stop_holding_cnt;
+ unsigned char bta_timeout;
+ unsigned short rx_timeout;
+ enum dsim_video_mode_type e_lane_swap;
+};
+
+struct dsim_lcd_config {
+ enum dsim_interface_type e_interface;
+ unsigned int parameter[3];
+
+ /* lcd panel info */
+ void *lcd_panel_info;
+
+ /* platform data for lcd panel based on MIPI-DSI. */
+ void *mipi_ddi_pd;
+};
+
+struct s5p_platform_dsim {
+ char *clk_name;
+ char lcd_panel_name[64];
+ unsigned int te_irq;
+
+ struct dsim_config *dsim_info;
+ struct dsim_lcd_config *dsim_lcd_info;
+
+ void (*mipi_power) (int enable);
+ void (*enable_clk) (void *d_clk, unsigned char enable);
+ void (*part_reset) (void);
+ void (*init_d_phy) (unsigned int dsim_base);
+ void (*cfg_gpio) (void);
+};
+
+extern void s5p_dsim_enable_clk(void *d_clk, unsigned char enable);
+extern void s5p_dsim_part_reset(void);
+extern void s5p_dsim_init_d_phy(unsigned int dsim_base);
+extern void exynos4_dsim_gpio_setup_24bpp(void);
+
+#endif /* _DSIM_H */
diff --git a/arch/arm/mach-exynos/include/mach/dwmci.h b/arch/arm/mach-exynos/include/mach/dwmci.h
index 7ce6574..08e5b59 100644
--- a/arch/arm/mach-exynos/include/mach/dwmci.h
+++ b/arch/arm/mach-exynos/include/mach/dwmci.h
@@ -15,6 +15,6 @@
#include <linux/mmc/dw_mmc.h>
-extern void exynos4_dwmci_set_platdata(struct dw_mci_board *pd);
+extern void exynos_dwmci_set_platdata(struct dw_mci_board *pd, int slot_id);
#endif /* __ASM_ARM_ARCH_DWMCI_H */
diff --git a/arch/arm/mach-exynos/include/mach/exynos-ion.h b/arch/arm/mach-exynos/include/mach/exynos-ion.h
new file mode 100644
index 0000000..1fd088f
--- /dev/null
+++ b/arch/arm/mach-exynos/include/mach/exynos-ion.h
@@ -0,0 +1,21 @@
+/* linux/arch/arm/mach-exynos/include/mach/exynos-ion.h
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * 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.
+*/
+
+#ifndef __MACH_EXYNOS_ION_H_
+
+struct platform_device;
+
+#ifdef CONFIG_ION_EXYNOS
+extern struct platform_device exynos_device_ion;
+extern struct ion_platform_data exynos_ion_pdata;
+#else
+#endif
+
+#endif /* __MACH_S5PV310_ION_H_ */
diff --git a/arch/arm/mach-exynos/include/mach/exynos-mfc.h b/arch/arm/mach-exynos/include/mach/exynos-mfc.h
new file mode 100644
index 0000000..b4fb772
--- /dev/null
+++ b/arch/arm/mach-exynos/include/mach/exynos-mfc.h
@@ -0,0 +1,25 @@
+/* linux/arch/arm/plat-s5p/include/plat/s5p-mfc.h
+ *
+ * Copyright 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Header file for s5p mfc support
+ *
+ * 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.
+ */
+
+#ifndef _S5P_MFC_H
+#define _S5P_MFC_H
+
+#include <linux/platform_device.h>
+
+struct s5p_mfc_platdata {
+ int clock_rate;
+};
+
+void s5p_mfc_set_platdata(struct s5p_mfc_platdata *pd);
+void s5p_mfc_setname(struct platform_device *pdev,char *name);
+
+#endif /* _S5P_MFC_H */
diff --git a/arch/arm/mach-exynos/include/mach/exynos5_bus.h b/arch/arm/mach-exynos/include/mach/exynos5_bus.h
new file mode 100644
index 0000000..c1fa0bb
--- /dev/null
+++ b/arch/arm/mach-exynos/include/mach/exynos5_bus.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2012 Google, Inc.
+ *
+ * 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.
+*/
+
+#ifndef _MACH_EXYNOS_EXYNOS5_BUS_H_
+#define _MACH_EXYNOS_EXYNOS5_BUS_H_
+
+struct exynos5_bus_mif_platform_data {
+ unsigned long max_freq;
+};
+
+struct exynos5_bus_mif_handle;
+struct exynos5_bus_int_handle;
+
+#ifdef CONFIG_ARM_EXYNOS5_BUS_DEVFREQ
+void exynos5_mif_multiple_windows(bool state);
+void exynos5_mif_used_dev(bool power_on);
+struct exynos5_bus_mif_handle *exynos5_bus_mif_get(unsigned long min_freq);
+int exynos5_bus_mif_put(struct exynos5_bus_mif_handle *handle);
+int exynos5_bus_mif_update(struct exynos5_bus_mif_handle *handle,
+ unsigned long min_freq);
+
+static inline
+struct exynos5_bus_mif_handle *exynos5_bus_mif_min(unsigned long min_freq)
+{
+ return exynos5_bus_mif_get(min_freq);
+}
+
+struct exynos5_bus_int_handle *exynos5_bus_int_get(unsigned long min_freq,
+ bool poll);
+int exynos5_bus_int_put(struct exynos5_bus_int_handle *handle);
+
+static inline struct exynos5_bus_int_handle *exynos5_bus_int_poll(void)
+{
+ return exynos5_bus_int_get(0, true);
+}
+
+static inline
+struct exynos5_bus_int_handle *exynos5_bus_int_min(unsigned long min_freq)
+{
+ return exynos5_bus_int_get(min_freq, false);
+}
+
+void exynos5_ppmu_trace(void);
+#else
+static inline void exynos5_mif_multiple_windows(bool state)
+{
+}
+
+static inline void exynos5_mif_used_dev(bool power_on)
+{
+}
+
+static inline
+struct exynos5_bus_mif_handle *exynos5_bus_mif_get(unsigned long min_freq)
+{
+ return NULL;
+}
+
+static inline
+int exynos5_bus_mif_put(struct exynos5_bus_mif_handle *handle)
+{
+ return 0;
+}
+
+static inline
+struct exynos5_bus_mif_handle *exynos5_bus_mif_min(unsigned long min_freq)
+{
+ return NULL;
+}
+
+static inline
+struct exynos5_bus_int_handle *exynos5_bus_int_get(unsigned long min_freq,
+ bool poll)
+{
+ return NULL;
+}
+
+static inline int exynos5_bus_int_put(struct exynos5_bus_int_handle *handle)
+{
+ return 0;
+}
+
+static inline struct exynos5_bus_int_handle *exynos5_bus_int_poll(void)
+{
+ return NULL;
+}
+
+static inline
+struct exynos5_bus_int_handle *exynos5_bus_int_min(unsigned long min_freq)
+{
+ return exynos5_bus_int_get(min_freq, false);
+}
+
+static inline
+int exynos5_bus_mif_update(struct exynos5_bus_mif_handle *handle,
+ unsigned long min_freq)
+{
+ return 0;
+}
+
+static inline void exynos5_ppmu_trace(void)
+{
+}
+#endif
+#endif /* _MACH_EXYNOS_EXYNOS5_BUS_H_ */
diff --git a/arch/arm/mach-exynos/include/mach/exynos_fiq_debugger.h b/arch/arm/mach-exynos/include/mach/exynos_fiq_debugger.h
new file mode 100644
index 0000000..77ba443
--- /dev/null
+++ b/arch/arm/mach-exynos/include/mach/exynos_fiq_debugger.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2012 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __MACH_EXYNOS_FIQ_DEBUGGER_H
+#define __MACH_EXYNOS_FIQ_DEBUGGER_H
+
+#ifdef CONFIG_EXYNOS_FIQ_DEBUGGER
+int exynos_serial_debug_init(int id, bool is_fiq);
+
+#else
+static inline int exynos_serial_debug_init(int id, bool is_fiq)
+{
+ return 0;
+}
+#endif
+
+#endif
diff --git a/arch/arm/mach-exynos/include/mach/gpio.h b/arch/arm/mach-exynos/include/mach/gpio.h
index d7498af..6e3233c 100644
--- a/arch/arm/mach-exynos/include/mach/gpio.h
+++ b/arch/arm/mach-exynos/include/mach/gpio.h
@@ -12,6 +12,12 @@
#ifndef __ASM_ARCH_GPIO_H
#define __ASM_ARCH_GPIO_H __FILE__
+#include <linux/types.h>
+#include <linux/err.h>
+#include <mach/irqs.h>
+#include <plat/irqs.h>
+#include <plat/cpu.h>
+
/* Macro for EXYNOS GPIO numbering */
#define EXYNOS_GPIO_NEXT(__gpio) \
@@ -153,10 +159,10 @@
#define EXYNOS5_GPIO_B2_NR (4)
#define EXYNOS5_GPIO_B3_NR (4)
#define EXYNOS5_GPIO_C0_NR (7)
-#define EXYNOS5_GPIO_C1_NR (7)
+#define EXYNOS5_GPIO_C1_NR (4)
#define EXYNOS5_GPIO_C2_NR (7)
#define EXYNOS5_GPIO_C3_NR (7)
-#define EXYNOS5_GPIO_D0_NR (8)
+#define EXYNOS5_GPIO_D0_NR (4)
#define EXYNOS5_GPIO_D1_NR (8)
#define EXYNOS5_GPIO_Y0_NR (6)
#define EXYNOS5_GPIO_Y1_NR (4)
@@ -165,6 +171,7 @@
#define EXYNOS5_GPIO_Y4_NR (8)
#define EXYNOS5_GPIO_Y5_NR (8)
#define EXYNOS5_GPIO_Y6_NR (8)
+#define EXYNOS5_GPIO_C4_NR (7)
#define EXYNOS5_GPIO_X0_NR (8)
#define EXYNOS5_GPIO_X1_NR (8)
#define EXYNOS5_GPIO_X2_NR (8)
@@ -208,7 +215,8 @@
EXYNOS5_GPIO_Y4_START = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_Y3),
EXYNOS5_GPIO_Y5_START = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_Y4),
EXYNOS5_GPIO_Y6_START = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_Y5),
- EXYNOS5_GPIO_X0_START = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_Y6),
+ EXYNOS5_GPIO_C4_START = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_Y6),
+ EXYNOS5_GPIO_X0_START = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_C4),
EXYNOS5_GPIO_X1_START = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_X0),
EXYNOS5_GPIO_X2_START = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_X1),
EXYNOS5_GPIO_X3_START = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_X2),
@@ -251,6 +259,7 @@
#define EXYNOS5_GPY4(_nr) (EXYNOS5_GPIO_Y4_START + (_nr))
#define EXYNOS5_GPY5(_nr) (EXYNOS5_GPIO_Y5_START + (_nr))
#define EXYNOS5_GPY6(_nr) (EXYNOS5_GPIO_Y6_START + (_nr))
+#define EXYNOS5_GPC4(_nr) (EXYNOS5_GPIO_C4_START + (_nr))
#define EXYNOS5_GPX0(_nr) (EXYNOS5_GPIO_X0_START + (_nr))
#define EXYNOS5_GPX1(_nr) (EXYNOS5_GPIO_X1_START + (_nr))
#define EXYNOS5_GPX2(_nr) (EXYNOS5_GPIO_X2_START + (_nr))
@@ -283,4 +292,32 @@
#define ARCH_NR_GPIOS (CONFIG_SAMSUNG_GPIO_EXTRA + S3C_GPIO_END)
+static inline int irq_to_gpio(unsigned int irq)
+{
+ if (soc_is_exynos5250()) {
+ switch (irq) {
+ case IRQ_EINT(0) ... IRQ_EINT(7):
+ return EXYNOS5_GPX0(0) + irq - IRQ_EINT(0);
+ case IRQ_EINT(8) ... IRQ_EINT(15):
+ return EXYNOS5_GPX1(0) + irq - IRQ_EINT(8);
+ case IRQ_EINT(16) ... IRQ_EINT(23):
+ return EXYNOS5_GPX2(0) + irq - IRQ_EINT(16);
+ case IRQ_EINT(24) ... IRQ_EINT(31):
+ return EXYNOS5_GPX3(0) + irq - IRQ_EINT(24);
+ }
+ } else {
+ switch (irq) {
+ case IRQ_EINT(0) ... IRQ_EINT(7):
+ return EXYNOS4_GPX0(0) + irq - IRQ_EINT(0);
+ case IRQ_EINT(8) ... IRQ_EINT(15):
+ return EXYNOS4_GPX1(0) + irq - IRQ_EINT(8);
+ case IRQ_EINT(16) ... IRQ_EINT(23):
+ return EXYNOS4_GPX2(0) + irq - IRQ_EINT(16);
+ case IRQ_EINT(24) ... IRQ_EINT(31):
+ return EXYNOS4_GPX3(0) + irq - IRQ_EINT(24);
+ }
+ }
+ return -EINVAL;
+}
+
#endif /* __ASM_ARCH_GPIO_H */
diff --git a/arch/arm/mach-exynos/include/mach/irqs.h b/arch/arm/mach-exynos/include/mach/irqs.h
index 591e785..2f2df2e 100644
--- a/arch/arm/mach-exynos/include/mach/irqs.h
+++ b/arch/arm/mach-exynos/include/mach/irqs.h
@@ -14,6 +14,10 @@
#include <plat/irqs.h>
+/* SGI: Software Generated Interrupt */
+
+#define IRQ_SGI(x) (x)
+
/* PPI: Private Peripheral Interrupt */
#define IRQ_PPI(x) (x + 16)
@@ -89,7 +93,7 @@
#define EXYNOS4_IRQ_SPI2 IRQ_SPI(68)
#define EXYNOS4_IRQ_USB_HOST IRQ_SPI(70)
-#define EXYNOS4_IRQ_USB_HSOTG IRQ_SPI(71)
+#define EXYNOS4_IRQ_OTG IRQ_SPI(71)
#define EXYNOS4_IRQ_MODEM_IF IRQ_SPI(72)
#define EXYNOS4_IRQ_HSMMC0 IRQ_SPI(73)
#define EXYNOS4_IRQ_HSMMC1 IRQ_SPI(74)
@@ -128,7 +132,6 @@
#define EXYNOS4_IRQ_ADC1 IRQ_SPI(107)
#define EXYNOS4_IRQ_PEN1 IRQ_SPI(108)
#define EXYNOS4_IRQ_KEYPAD IRQ_SPI(109)
-#define EXYNOS4_IRQ_PMU IRQ_SPI(110)
#define EXYNOS4_IRQ_GPS IRQ_SPI(111)
#define EXYNOS4_IRQ_INTFEEDCTRL_SSS IRQ_SPI(112)
#define EXYNOS4_IRQ_SLIMBUS IRQ_SPI(113)
@@ -136,6 +139,9 @@
#define EXYNOS4_IRQ_TSI IRQ_SPI(115)
#define EXYNOS4_IRQ_SATA IRQ_SPI(116)
+#define EXYNOS4_IRQ_PMU_CPU0 COMBINER_IRQ(2, 2)
+#define EXYNOS4_IRQ_PMU_CPU1 COMBINER_IRQ(3, 2)
+
#define EXYNOS4_IRQ_SYSMMU_MDMA0_0 COMBINER_IRQ(4, 0)
#define EXYNOS4_IRQ_SYSMMU_SSS_0 COMBINER_IRQ(4, 1)
#define EXYNOS4_IRQ_SYSMMU_FIMC0_0 COMBINER_IRQ(4, 2)
@@ -158,93 +164,14 @@
#define EXYNOS4_IRQ_FIMD0_VSYNC COMBINER_IRQ(11, 1)
#define EXYNOS4_IRQ_FIMD0_SYSTEM COMBINER_IRQ(11, 2)
+#define EXYNOS4_IRQ_PMU_CPU2 COMBINER_IRQ(18, 2)
+#define EXYNOS4_IRQ_PMU_CPU3 COMBINER_IRQ(19, 2)
+
#define EXYNOS4_MAX_COMBINER_NR 16
#define EXYNOS4_IRQ_GPIO1_NR_GROUPS 16
#define EXYNOS4_IRQ_GPIO2_NR_GROUPS 9
-/*
- * For Compatibility:
- * the default is for EXYNOS4, and
- * for exynos5, should be re-mapped at function
- */
-
-#define IRQ_TIMER0_VIC EXYNOS4_IRQ_TIMER0_VIC
-#define IRQ_TIMER1_VIC EXYNOS4_IRQ_TIMER1_VIC
-#define IRQ_TIMER2_VIC EXYNOS4_IRQ_TIMER2_VIC
-#define IRQ_TIMER3_VIC EXYNOS4_IRQ_TIMER3_VIC
-#define IRQ_TIMER4_VIC EXYNOS4_IRQ_TIMER4_VIC
-
-#define IRQ_WDT EXYNOS4_IRQ_WDT
-#define IRQ_RTC_ALARM EXYNOS4_IRQ_RTC_ALARM
-#define IRQ_RTC_TIC EXYNOS4_IRQ_RTC_TIC
-#define IRQ_GPIO_XB EXYNOS4_IRQ_GPIO_XB
-#define IRQ_GPIO_XA EXYNOS4_IRQ_GPIO_XA
-
-#define IRQ_IIC EXYNOS4_IRQ_IIC
-#define IRQ_IIC1 EXYNOS4_IRQ_IIC1
-#define IRQ_IIC3 EXYNOS4_IRQ_IIC3
-#define IRQ_IIC5 EXYNOS4_IRQ_IIC5
-#define IRQ_IIC6 EXYNOS4_IRQ_IIC6
-#define IRQ_IIC7 EXYNOS4_IRQ_IIC7
-
-#define IRQ_USB_HOST EXYNOS4_IRQ_USB_HOST
-
-#define IRQ_HSMMC0 EXYNOS4_IRQ_HSMMC0
-#define IRQ_HSMMC1 EXYNOS4_IRQ_HSMMC1
-#define IRQ_HSMMC2 EXYNOS4_IRQ_HSMMC2
-#define IRQ_HSMMC3 EXYNOS4_IRQ_HSMMC3
-
-#define IRQ_MIPI_CSIS0 EXYNOS4_IRQ_MIPI_CSIS0
-
-#define IRQ_ONENAND_AUDI EXYNOS4_IRQ_ONENAND_AUDI
-
-#define IRQ_FIMC0 EXYNOS4_IRQ_FIMC0
-#define IRQ_FIMC1 EXYNOS4_IRQ_FIMC1
-#define IRQ_FIMC2 EXYNOS4_IRQ_FIMC2
-#define IRQ_FIMC3 EXYNOS4_IRQ_FIMC3
-#define IRQ_JPEG EXYNOS4_IRQ_JPEG
-#define IRQ_2D EXYNOS4_IRQ_2D
-
-#define IRQ_MIXER EXYNOS4_IRQ_MIXER
-#define IRQ_HDMI EXYNOS4_IRQ_HDMI
-#define IRQ_IIC_HDMIPHY EXYNOS4_IRQ_IIC_HDMIPHY
-#define IRQ_MFC EXYNOS4_IRQ_MFC
-#define IRQ_SDO EXYNOS4_IRQ_SDO
-
-#define IRQ_I2S0 EXYNOS4_IRQ_I2S0
-
-#define IRQ_ADC EXYNOS4_IRQ_ADC0
-#define IRQ_TC EXYNOS4_IRQ_PEN0
-
-#define IRQ_KEYPAD EXYNOS4_IRQ_KEYPAD
-#define IRQ_PMU EXYNOS4_IRQ_PMU
-
-#define IRQ_SYSMMU_MDMA0_0 EXYNOS4_IRQ_SYSMMU_MDMA0_0
-#define IRQ_SYSMMU_SSS_0 EXYNOS4_IRQ_SYSMMU_SSS_0
-#define IRQ_SYSMMU_FIMC0_0 EXYNOS4_IRQ_SYSMMU_FIMC0_0
-#define IRQ_SYSMMU_FIMC1_0 EXYNOS4_IRQ_SYSMMU_FIMC1_0
-#define IRQ_SYSMMU_FIMC2_0 EXYNOS4_IRQ_SYSMMU_FIMC2_0
-#define IRQ_SYSMMU_FIMC3_0 EXYNOS4_IRQ_SYSMMU_FIMC3_0
-#define IRQ_SYSMMU_JPEG_0 EXYNOS4_IRQ_SYSMMU_JPEG_0
-#define IRQ_SYSMMU_2D_0 EXYNOS4_IRQ_SYSMMU_2D_0
-
-#define IRQ_SYSMMU_ROTATOR_0 EXYNOS4_IRQ_SYSMMU_ROTATOR_0
-#define IRQ_SYSMMU_MDMA1_0 EXYNOS4_IRQ_SYSMMU_MDMA1_0
-#define IRQ_SYSMMU_LCD0_M0_0 EXYNOS4_IRQ_SYSMMU_LCD0_M0_0
-#define IRQ_SYSMMU_LCD1_M1_0 EXYNOS4_IRQ_SYSMMU_LCD1_M1_0
-#define IRQ_SYSMMU_TV_M0_0 EXYNOS4_IRQ_SYSMMU_TV_M0_0
-#define IRQ_SYSMMU_MFC_M0_0 EXYNOS4_IRQ_SYSMMU_MFC_M0_0
-#define IRQ_SYSMMU_MFC_M1_0 EXYNOS4_IRQ_SYSMMU_MFC_M1_0
-#define IRQ_SYSMMU_PCIE_0 EXYNOS4_IRQ_SYSMMU_PCIE_0
-
-#define IRQ_FIMD0_FIFO EXYNOS4_IRQ_FIMD0_FIFO
-#define IRQ_FIMD0_VSYNC EXYNOS4_IRQ_FIMD0_VSYNC
-#define IRQ_FIMD0_SYSTEM EXYNOS4_IRQ_FIMD0_SYSTEM
-
-#define IRQ_GPIO1_NR_GROUPS EXYNOS4_IRQ_GPIO1_NR_GROUPS
-#define IRQ_GPIO2_NR_GROUPS EXYNOS4_IRQ_GPIO2_NR_GROUPS
-
/* For EXYNOS5 SoCs */
#define EXYNOS5_IRQ_MDMA0 IRQ_SPI(33)
@@ -269,7 +196,7 @@
#define EXYNOS5_IRQ_UART1 IRQ_SPI(52)
#define EXYNOS5_IRQ_UART2 IRQ_SPI(53)
#define EXYNOS5_IRQ_UART3 IRQ_SPI(54)
-#define EXYNOS5_IRQ_UART4 IRQ_SPI(55)
+#define EXYNOS5_MONOCNT IRQ_SPI(55)
#define EXYNOS5_IRQ_IIC IRQ_SPI(56)
#define EXYNOS5_IRQ_IIC1 IRQ_SPI(57)
#define EXYNOS5_IRQ_IIC2 IRQ_SPI(58)
@@ -288,7 +215,7 @@
#define EXYNOS5_IRQ_USB_HOST IRQ_SPI(71)
#define EXYNOS5_IRQ_USB3_DRD IRQ_SPI(72)
#define EXYNOS5_IRQ_MIPI_HSI IRQ_SPI(73)
-#define EXYNOS5_IRQ_USB_HSOTG IRQ_SPI(74)
+#define EXYNOS5_IRQ_OTG IRQ_SPI(74)
#define EXYNOS5_IRQ_HSMMC0 IRQ_SPI(75)
#define EXYNOS5_IRQ_HSMMC1 IRQ_SPI(76)
#define EXYNOS5_IRQ_HSMMC2 IRQ_SPI(77)
@@ -297,6 +224,7 @@
#define EXYNOS5_IRQ_MIPICSI1 IRQ_SPI(80)
#define EXYNOS5_IRQ_EFNFCON_DMA_ABORT IRQ_SPI(81)
#define EXYNOS5_IRQ_MIPIDSI0 IRQ_SPI(82)
+#define EXYNOS5_IRQ_WDT_IOP IRQ_SPI(83)
#define EXYNOS5_IRQ_ROTATOR IRQ_SPI(84)
#define EXYNOS5_IRQ_GSC0 IRQ_SPI(85)
#define EXYNOS5_IRQ_GSC1 IRQ_SPI(86)
@@ -305,8 +233,8 @@
#define EXYNOS5_IRQ_JPEG IRQ_SPI(89)
#define EXYNOS5_IRQ_EFNFCON_DMA IRQ_SPI(90)
#define EXYNOS5_IRQ_2D IRQ_SPI(91)
-#define EXYNOS5_IRQ_SFMC0 IRQ_SPI(92)
-#define EXYNOS5_IRQ_SFMC1 IRQ_SPI(93)
+#define EXYNOS5_IRQ_EFNFCON_0 IRQ_SPI(92)
+#define EXYNOS5_IRQ_EFNFCON_1 IRQ_SPI(93)
#define EXYNOS5_IRQ_MIXER IRQ_SPI(94)
#define EXYNOS5_IRQ_HDMI IRQ_SPI(95)
#define EXYNOS5_IRQ_MFC IRQ_SPI(96)
@@ -320,7 +248,7 @@
#define EXYNOS5_IRQ_PCM2 IRQ_SPI(104)
#define EXYNOS5_IRQ_SPDIF IRQ_SPI(105)
#define EXYNOS5_IRQ_ADC0 IRQ_SPI(106)
-
+#define EXYNOS5_IRQ_ADC1 IRQ_SPI(107)
#define EXYNOS5_IRQ_SATA_PHY IRQ_SPI(108)
#define EXYNOS5_IRQ_SATA_PMEMREQ IRQ_SPI(109)
#define EXYNOS5_IRQ_CAM_C IRQ_SPI(110)
@@ -329,16 +257,21 @@
#define EXYNOS5_IRQ_DP1_INTP1 IRQ_SPI(113)
#define EXYNOS5_IRQ_CEC IRQ_SPI(114)
#define EXYNOS5_IRQ_SATA IRQ_SPI(115)
-#define EXYNOS5_IRQ_NFCON IRQ_SPI(116)
-#define EXYNOS5_IRQ_MMC44 IRQ_SPI(123)
+#define EXYNOS5_GPU_IRQ_NUMBER IRQ_SPI(117)
+#define EXYNOS5_JOB_IRQ_NUMBER IRQ_SPI(118)
+#define EXYNOS5_MMU_IRQ_NUMBER IRQ_SPI(119)
+#define EXYNOS5_IRQ_MCT_L0 IRQ_SPI(120)
+#define EXYNOS5_IRQ_MCT_L1 IRQ_SPI(121)
+
+#define EXYNOS5_IRQ_DWMCI IRQ_SPI(123)
+
#define EXYNOS5_IRQ_MDMA1 IRQ_SPI(124)
#define EXYNOS5_IRQ_FIMC_LITE0 IRQ_SPI(125)
#define EXYNOS5_IRQ_FIMC_LITE1 IRQ_SPI(126)
#define EXYNOS5_IRQ_RP_TIMER IRQ_SPI(127)
-#define EXYNOS5_IRQ_PMU COMBINER_IRQ(1, 2)
-#define EXYNOS5_IRQ_PMU_CPU1 COMBINER_IRQ(1, 6)
+#define EXYNOS5_IRQ_PMU_CPU0 COMBINER_IRQ(1, 2)
#define EXYNOS5_IRQ_SYSMMU_GSC0_0 COMBINER_IRQ(2, 0)
#define EXYNOS5_IRQ_SYSMMU_GSC0_1 COMBINER_IRQ(2, 1)
@@ -349,6 +282,8 @@
#define EXYNOS5_IRQ_SYSMMU_GSC3_0 COMBINER_IRQ(2, 6)
#define EXYNOS5_IRQ_SYSMMU_GSC3_1 COMBINER_IRQ(2, 7)
+#define EXYNOS5_IRQ_SYSMMU_LITE2_0 COMBINER_IRQ(3, 0)
+#define EXYNOS5_IRQ_SYSMMU_LITE2_1 COMBINER_IRQ(3, 1)
#define EXYNOS5_IRQ_SYSMMU_FIMD1_0 COMBINER_IRQ(3, 2)
#define EXYNOS5_IRQ_SYSMMU_FIMD1_1 COMBINER_IRQ(3, 3)
#define EXYNOS5_IRQ_SYSMMU_LITE0_0 COMBINER_IRQ(3, 4)
@@ -372,8 +307,8 @@
#define EXYNOS5_IRQ_SYSMMU_ARM_0 COMBINER_IRQ(6, 0)
#define EXYNOS5_IRQ_SYSMMU_ARM_1 COMBINER_IRQ(6, 1)
-#define EXYNOS5_IRQ_SYSMMU_MFC_L_0 COMBINER_IRQ(6, 2)
-#define EXYNOS5_IRQ_SYSMMU_MFC_L_1 COMBINER_IRQ(6, 3)
+#define EXYNOS5_IRQ_SYSMMU_MFC_R_0 COMBINER_IRQ(6, 2)
+#define EXYNOS5_IRQ_SYSMMU_MFC_R_1 COMBINER_IRQ(6, 3)
#define EXYNOS5_IRQ_SYSMMU_RTIC_0 COMBINER_IRQ(6, 4)
#define EXYNOS5_IRQ_SYSMMU_RTIC_1 COMBINER_IRQ(6, 5)
#define EXYNOS5_IRQ_SYSMMU_SSS_0 COMBINER_IRQ(6, 6)
@@ -385,11 +320,9 @@
#define EXYNOS5_IRQ_SYSMMU_MDMA1_1 COMBINER_IRQ(7, 3)
#define EXYNOS5_IRQ_SYSMMU_TV_0 COMBINER_IRQ(7, 4)
#define EXYNOS5_IRQ_SYSMMU_TV_1 COMBINER_IRQ(7, 5)
-#define EXYNOS5_IRQ_SYSMMU_GPSX_0 COMBINER_IRQ(7, 6)
-#define EXYNOS5_IRQ_SYSMMU_GPSX_1 COMBINER_IRQ(7, 7)
-#define EXYNOS5_IRQ_SYSMMU_MFC_R_0 COMBINER_IRQ(8, 5)
-#define EXYNOS5_IRQ_SYSMMU_MFC_R_1 COMBINER_IRQ(8, 6)
+#define EXYNOS5_IRQ_SYSMMU_MFC_L_0 COMBINER_IRQ(8, 5)
+#define EXYNOS5_IRQ_SYSMMU_MFC_L_1 COMBINER_IRQ(8, 6)
#define EXYNOS5_IRQ_SYSMMU_DIS1_0 COMBINER_IRQ(9, 4)
#define EXYNOS5_IRQ_SYSMMU_DIS1_1 COMBINER_IRQ(9, 5)
@@ -405,17 +338,24 @@
#define EXYNOS5_IRQ_SYSMMU_DRC_0 COMBINER_IRQ(11, 6)
#define EXYNOS5_IRQ_SYSMMU_DRC_1 COMBINER_IRQ(11, 7)
+#define EXYNOS5_IRQ_MDMA1_ABORT COMBINER_IRQ(13, 1)
+
+#define EXYNOS5_IRQ_MDMA0_ABORT COMBINER_IRQ(15, 3)
+
#define EXYNOS5_IRQ_FIMD1_FIFO COMBINER_IRQ(18, 4)
#define EXYNOS5_IRQ_FIMD1_VSYNC COMBINER_IRQ(18, 5)
#define EXYNOS5_IRQ_FIMD1_SYSTEM COMBINER_IRQ(18, 6)
+#define EXYNOS5_IRQ_ARMIOP_GIC COMBINER_IRQ(19, 0)
+#define EXYNOS5_IRQ_ARMISP_GIC COMBINER_IRQ(19, 1)
+#define EXYNOS5_IRQ_IOP_GIC COMBINER_IRQ(19, 3)
+#define EXYNOS5_IRQ_ISP_GIC COMBINER_IRQ(19, 4)
+
+#define EXYNOS5_IRQ_PMU_CPU1 COMBINER_IRQ(22, 4)
+
#define EXYNOS5_IRQ_EINT0 COMBINER_IRQ(23, 0)
-#define EXYNOS5_IRQ_MCT_L0 COMBINER_IRQ(23, 1)
-#define EXYNOS5_IRQ_MCT_L1 COMBINER_IRQ(23, 2)
#define EXYNOS5_IRQ_MCT_G0 COMBINER_IRQ(23, 3)
#define EXYNOS5_IRQ_MCT_G1 COMBINER_IRQ(23, 4)
-#define EXYNOS5_IRQ_MCT_G2 COMBINER_IRQ(23, 5)
-#define EXYNOS5_IRQ_MCT_G3 COMBINER_IRQ(23, 6)
#define EXYNOS5_IRQ_EINT1 COMBINER_IRQ(24, 0)
#define EXYNOS5_IRQ_SYSMMU_LITE1_0 COMBINER_IRQ(24, 1)
@@ -446,22 +386,222 @@
#define EXYNOS5_MAX_COMBINER_NR 32
-#define EXYNOS5_IRQ_GPIO1_NR_GROUPS 13
+#define EXYNOS5_IRQ_GPIO1_NR_GROUPS 14
#define EXYNOS5_IRQ_GPIO2_NR_GROUPS 9
#define EXYNOS5_IRQ_GPIO3_NR_GROUPS 5
#define EXYNOS5_IRQ_GPIO4_NR_GROUPS 1
+/* For Compatibility */
+
+#if defined(CONFIG_ARCH_EXYNOS4)
+
+#define IRQ_TIMER0_VIC EXYNOS4_IRQ_TIMER0_VIC
+#define IRQ_TIMER1_VIC EXYNOS4_IRQ_TIMER1_VIC
+#define IRQ_TIMER2_VIC EXYNOS4_IRQ_TIMER2_VIC
+#define IRQ_TIMER3_VIC EXYNOS4_IRQ_TIMER3_VIC
+#define IRQ_TIMER4_VIC EXYNOS4_IRQ_TIMER4_VIC
+
+#define IRQ_WDT EXYNOS4_IRQ_WDT
+#define IRQ_RTC_ALARM EXYNOS4_IRQ_RTC_ALARM
+#define IRQ_RTC_TIC EXYNOS4_IRQ_RTC_TIC
+#define IRQ_GPIO_XB EXYNOS4_IRQ_GPIO_XB
+#define IRQ_GPIO_XA EXYNOS4_IRQ_GPIO_XA
+
+#define IRQ_IIC EXYNOS4_IRQ_IIC
+#define IRQ_IIC1 EXYNOS4_IRQ_IIC1
+#define IRQ_IIC3 EXYNOS4_IRQ_IIC3
+#define IRQ_IIC5 EXYNOS4_IRQ_IIC5
+#define IRQ_IIC6 EXYNOS4_IRQ_IIC6
+#define IRQ_IIC7 EXYNOS4_IRQ_IIC7
+
+#define IRQ_I2S0 EXYNOS4_IRQ_I2S0
+
+#define IRQ_USB_HOST EXYNOS4_IRQ_USB_HOST
+#define IRQ_OTG EXYNOS4_IRQ_OTG
+
+#define IRQ_HSMMC0 EXYNOS4_IRQ_HSMMC0
+#define IRQ_HSMMC1 EXYNOS4_IRQ_HSMMC1
+#define IRQ_HSMMC2 EXYNOS4_IRQ_HSMMC2
+#define IRQ_HSMMC3 EXYNOS4_IRQ_HSMMC3
+
+#define IRQ_SPI0 EXYNOS4_IRQ_SPI0
+#define IRQ_SPI1 EXYNOS4_IRQ_SPI1
+#define IRQ_SPI2 EXYNOS4_IRQ_SPI2
+
+#define IRQ_MIPI_CSIS0 EXYNOS4_IRQ_MIPI_CSIS0
+
+#define IRQ_ONENAND_AUDI EXYNOS4_IRQ_ONENAND_AUDI
+
+#define IRQ_FIMC0 EXYNOS4_IRQ_FIMC0
+#define IRQ_FIMC1 EXYNOS4_IRQ_FIMC1
+#define IRQ_FIMC2 EXYNOS4_IRQ_FIMC2
+#define IRQ_FIMC3 EXYNOS4_IRQ_FIMC3
+#define IRQ_JPEG EXYNOS4_IRQ_JPEG
+#define IRQ_2D EXYNOS4_IRQ_2D
+
+#define IRQ_MIXER EXYNOS4_IRQ_MIXER
+#define IRQ_HDMI EXYNOS4_IRQ_HDMI
+#define IRQ_IIC_HDMIPHY EXYNOS4_IRQ_IIC_HDMIPHY
+#define IRQ_MFC EXYNOS4_IRQ_MFC
+#define IRQ_SDO EXYNOS4_IRQ_SDO
+
+#define IRQ_ADC EXYNOS4_IRQ_ADC0
+#define IRQ_TC EXYNOS4_IRQ_PEN0
+
+#define IRQ_KEYPAD EXYNOS4_IRQ_KEYPAD
+
+#define IRQ_INTFEEDCTRL_SSS EXYNOS4_IRQ_INTFEEDCTRL_SSS
+
+#define IRQ_PMU EXYNOS4_IRQ_PMU_CPU0
+#define IRQ_PMU_CPU1 EXYNOS4_IRQ_PMU_CPU1
+
+#define IRQ_SYSMMU_MDMA0_0 EXYNOS4_IRQ_SYSMMU_MDMA0_0
+#define IRQ_SYSMMU_SSS_0 EXYNOS4_IRQ_SYSMMU_SSS_0
+#define IRQ_SYSMMU_FIMC0_0 EXYNOS4_IRQ_SYSMMU_FIMC0_0
+#define IRQ_SYSMMU_FIMC1_0 EXYNOS4_IRQ_SYSMMU_FIMC1_0
+#define IRQ_SYSMMU_FIMC2_0 EXYNOS4_IRQ_SYSMMU_FIMC2_0
+#define IRQ_SYSMMU_FIMC3_0 EXYNOS4_IRQ_SYSMMU_FIMC3_0
+#define IRQ_SYSMMU_JPEG_0 EXYNOS4_IRQ_SYSMMU_JPEG_0
+#define IRQ_SYSMMU_2D_0 EXYNOS4_IRQ_SYSMMU_2D_0
+
+#define IRQ_SYSMMU_ROTATOR_0 EXYNOS4_IRQ_SYSMMU_ROTATOR_0
+#define IRQ_SYSMMU_MDMA1_0 EXYNOS4_IRQ_SYSMMU_MDMA1_0
+#define IRQ_SYSMMU_LCD0_M0_0 EXYNOS4_IRQ_SYSMMU_LCD0_M0_0
+#define IRQ_SYSMMU_LCD1_M1_0 EXYNOS4_IRQ_SYSMMU_LCD1_M1_0
+#define IRQ_SYSMMU_TV_M0_0 EXYNOS4_IRQ_SYSMMU_TV_M0_0
+#define IRQ_SYSMMU_MFC_M0_0 EXYNOS4_IRQ_SYSMMU_MFC_M0_0
+#define IRQ_SYSMMU_MFC_M1_0 EXYNOS4_IRQ_SYSMMU_MFC_M1_0
+#define IRQ_SYSMMU_PCIE_0 EXYNOS4_IRQ_SYSMMU_PCIE_0
+
+#define IRQ_FIMD0_FIFO EXYNOS4_IRQ_FIMD0_FIFO
+#define IRQ_FIMD0_VSYNC EXYNOS4_IRQ_FIMD0_VSYNC
+#define IRQ_FIMD0_SYSTEM EXYNOS4_IRQ_FIMD0_SYSTEM
+
+#define IRQ_PMU_CPU2 EXYNOS4_IRQ_PMU_CPU2
+#define IRQ_PMU_CPU3 EXYNOS4_IRQ_PMU_CPU3
+
+#define IRQ_GPIO1_NR_GROUPS EXYNOS4_IRQ_GPIO1_NR_GROUPS
+#define IRQ_GPIO2_NR_GROUPS EXYNOS4_IRQ_GPIO2_NR_GROUPS
+
+#define EXYNOS_IRQ_UARTx(x) (EXYNOS4_IRQ_UART0 + x)
+
+#elif defined(CONFIG_ARCH_EXYNOS5)
+
+#define IRQ_TIMER0_VIC EXYNOS5_IRQ_TIMER0_VIC
+#define IRQ_TIMER1_VIC EXYNOS5_IRQ_TIMER1_VIC
+#define IRQ_TIMER2_VIC EXYNOS5_IRQ_TIMER2_VIC
+#define IRQ_TIMER3_VIC EXYNOS5_IRQ_TIMER3_VIC
+#define IRQ_TIMER4_VIC EXYNOS5_IRQ_TIMER4_VIC
+
+#define IRQ_WDT EXYNOS5_IRQ_WDT
+#define IRQ_RTC_ALARM EXYNOS5_IRQ_RTC_ALARM
+#define IRQ_RTC_TIC EXYNOS5_IRQ_RTC_TIC
+#define IRQ_GPIO_XB EXYNOS5_IRQ_GPIO_XB
+#define IRQ_GPIO_XA EXYNOS5_IRQ_GPIO_XA
+
+#define IRQ_IIC EXYNOS5_IRQ_IIC
+#define IRQ_IIC1 EXYNOS5_IRQ_IIC1
+#define IRQ_IIC2 EXYNOS5_IRQ_IIC2
+#define IRQ_IIC3 EXYNOS5_IRQ_IIC3
+#define IRQ_IIC4 EXYNOS5_IRQ_IIC4
+#define IRQ_IIC5 EXYNOS5_IRQ_IIC5
+#define IRQ_IIC6 EXYNOS5_IRQ_IIC6
+#define IRQ_IIC7 EXYNOS5_IRQ_IIC7
+
+#define IRQ_AUDIO_SS EXYNOS5_IRQ_AUDIO_SS
+
+#define IRQ_I2S0 EXYNOS5_IRQ_I2S0
+
+#define IRQ_USB_HOST EXYNOS5_IRQ_USB_HOST
+#define IRQ_USB3_DRD EXYNOS5_IRQ_USB3_DRD
+#define IRQ_OTG EXYNOS5_IRQ_OTG
+
+#define IRQ_HSMMC0 EXYNOS5_IRQ_HSMMC0
+#define IRQ_HSMMC1 EXYNOS5_IRQ_HSMMC1
+#define IRQ_HSMMC2 EXYNOS5_IRQ_HSMMC2
+#define IRQ_HSMMC3 EXYNOS5_IRQ_HSMMC3
+
+#define IRQ_SPI0 EXYNOS5_IRQ_SPI0
+#define IRQ_SPI1 EXYNOS5_IRQ_SPI1
+#define IRQ_SPI2 EXYNOS5_IRQ_SPI2
+
+#define IRQ_MIPICSI0 EXYNOS5_IRQ_MIPICSI0
+#define IRQ_MIPICSI1 EXYNOS5_IRQ_MIPICSI1
+
+#define IRQ_MIPIDSI0 EXYNOS5_IRQ_MIPIDSI0
+
+#define IRQ_ROTATOR EXYNOS5_IRQ_ROTATOR
+#define IRQ_GSC0 EXYNOS5_IRQ_GSC0
+#define IRQ_GSC1 EXYNOS5_IRQ_GSC1
+#define IRQ_GSC2 EXYNOS5_IRQ_GSC2
+#define IRQ_GSC3 EXYNOS5_IRQ_GSC3
+#define IRQ_JPEG EXYNOS5_IRQ_JPEG
+#define IRQ_2D EXYNOS5_IRQ_2D
+
+#define IRQ_MIXER EXYNOS5_IRQ_MIXER
+#define IRQ_HDMI EXYNOS5_IRQ_HDMI
+#define IRQ_IIC_HDMIPHY EXYNOS5_IRQ_IIC_HDMIPHY
+#define IRQ_MFC EXYNOS5_IRQ_MFC
+
+#define IRQ_ADC EXYNOS5_IRQ_ADC0
+
+#define IRQ_INTFEEDCTRL_SSS EXYNOS5_IRQ_INTFEEDCTRL_SSS
+
+#define IRQ_PMU EXYNOS5_IRQ_PMU_CPU0
+#define IRQ_PMU_CPU1 EXYNOS5_IRQ_PMU_CPU1
+
+#define IRQ_CEC EXYNOS5_IRQ_CEC
+
+#define GPU_IRQ_NUMBER EXYNOS5_GPU_IRQ_NUMBER
+#define JOB_IRQ_NUMBER EXYNOS5_JOB_IRQ_NUMBER
+#define MMU_IRQ_NUMBER EXYNOS5_MMU_IRQ_NUMBER
+
+#define IRQ_FIMC_LITE0 EXYNOS5_IRQ_FIMC_LITE0
+#define IRQ_FIMC_LITE1 EXYNOS5_IRQ_FIMC_LITE1
+
+#define IRQ_DP EXYNOS5_IRQ_DP
+
+#define IRQ_SYSMMU_MDMA0_0 EXYNOS5_IRQ_SYSMMU_MDMA0_0
+#define IRQ_SYSMMU_SSS_0 EXYNOS5_IRQ_SYSMMU_SSS_0
+
+#define IRQ_SYSMMU_JPEG_0 EXYNOS5_IRQ_SYSMMU_JPEG_0
+#define IRQ_SYSMMU_2D_0 EXYNOS5_IRQ_SYSMMU_2D_0
+
+#define IRQ_SYSMMU_ROTATOR_0 EXYNOS5_IRQ_SYSMMU_ROTATOR_0
+#define IRQ_SYSMMU_MDMA1_0 EXYNOS5_IRQ_SYSMMU_MDMA1_0
+
+#define IRQ_FIMD1_FIFO EXYNOS5_IRQ_FIMD1_FIFO
+#define IRQ_FIMD1_VSYNC EXYNOS5_IRQ_FIMD1_VSYNC
+#define IRQ_FIMD1_SYSTEM EXYNOS5_IRQ_FIMD1_SYSTEM
+
+#define IRQ_ARMIOP_GIC EXYNOS5_IRQ_ARMIOP_GIC
+#define IRQ_ARMISP_GIC EXYNOS5_IRQ_ARMISP_GIC
+#define IRQ_IOP_GIC EXYNOS5_IRQ_IOP_GIC
+#define IRQ_ISP_GIC EXYNOS5_IRQ_ISP_GIC
+
+#define IRQ_GPIO1_NR_GROUPS EXYNOS5_IRQ_GPIO1_NR_GROUPS
+#define IRQ_GPIO2_NR_GROUPS EXYNOS5_IRQ_GPIO2_NR_GROUPS
+
+#define EXYNOS_IRQ_UARTx(x) (EXYNOS5_IRQ_UART0 + x)
+
+#endif
+
#define MAX_COMBINER_NR (EXYNOS4_MAX_COMBINER_NR > EXYNOS5_MAX_COMBINER_NR ? \
EXYNOS4_MAX_COMBINER_NR : EXYNOS5_MAX_COMBINER_NR)
#define S5P_EINT_BASE1 COMBINER_IRQ(MAX_COMBINER_NR, 0)
#define S5P_EINT_BASE2 (S5P_EINT_BASE1 + 16)
+#define IRQ_TVOUT_EXT_HPD (S5P_EINT_BASE1 + 31)
#define S5P_GPIOINT_BASE (S5P_EINT_BASE1 + 32)
#define IRQ_GPIO_END (S5P_GPIOINT_BASE + S5P_GPIOINT_COUNT)
#define IRQ_TIMER_BASE (IRQ_GPIO_END + 64)
-/* Set the default NR_IRQS */
+#define IRQ_BOARD_START (IRQ_TIMER_BASE + IRQ_TIMER_COUNT)
+#define IRQ_NR_BOARD 48
-#define NR_IRQS (IRQ_TIMER_BASE + IRQ_TIMER_COUNT)
+/* Set the default NR_IRQS */
+#define NR_IRQS (IRQ_BOARD_START + IRQ_NR_BOARD)
+
+#define FIQ_START 0
#endif /* __ASM_ARCH_IRQS_H */
diff --git a/arch/arm/mach-exynos/include/mach/map.h b/arch/arm/mach-exynos/include/mach/map.h
index 6e6d11f..ac8dc3b 100644
--- a/arch/arm/mach-exynos/include/mach/map.h
+++ b/arch/arm/mach-exynos/include/mach/map.h
@@ -26,23 +26,35 @@
#define EXYNOS4_PA_SYSRAM0 0x02025000
#define EXYNOS4_PA_SYSRAM1 0x02020000
#define EXYNOS5_PA_SYSRAM 0x02020000
+#define EXYNOS5_PA_SYSRAM_NS 0x0204F000
#define EXYNOS4_PA_FIMC0 0x11800000
#define EXYNOS4_PA_FIMC1 0x11810000
#define EXYNOS4_PA_FIMC2 0x11820000
#define EXYNOS4_PA_FIMC3 0x11830000
+#define EXYNOS4_PA_JPEG 0x11840000
+#define EXYNOS5_PA_JPEG 0x11E00000
#define EXYNOS4_PA_JPEG 0x11840000
#define EXYNOS4_PA_G2D 0x12800000
+#define EXYNOS_PA_AUDSS_INTMEM 0x03000000
+#define EXYNOS_PA_AUDSS_COMMBOX 0x03820000
+#define EXYNOS_PA_AUDSS 0x03810000
#define EXYNOS4_PA_I2S0 0x03830000
#define EXYNOS4_PA_I2S1 0xE3100000
#define EXYNOS4_PA_I2S2 0xE2A00000
+#define EXYNOS5_PA_I2S0 0x03830000
+#define EXYNOS5_PA_I2S1 0x12D60000
+#define EXYNOS5_PA_I2S2 0x12D70000
#define EXYNOS4_PA_PCM0 0x03840000
#define EXYNOS4_PA_PCM1 0x13980000
#define EXYNOS4_PA_PCM2 0x13990000
+#define EXYNOS5_PA_PCM0 0x03840000
+#define EXYNOS5_PA_PCM1 0x12D80000
+#define EXYNOS5_PA_PCM2 0x12D90000
#define EXYNOS4_PA_SROM_BANK(x) (0x04000000 + ((x) * 0x01000000))
@@ -54,6 +66,8 @@
#define EXYNOS4_PA_SYSCON 0x10010000
#define EXYNOS5_PA_SYSCON 0x10050100
+#define EXYNOS5_PA_TMU 0x10060000
+#define EXYNOS5_PA_ACE 0x10830000
#define EXYNOS4_PA_PMU 0x10020000
#define EXYNOS5_PA_PMU 0x10040000
@@ -67,6 +81,7 @@
#define EXYNOS5_PA_WATCHDOG 0x101D0000
#define EXYNOS4_PA_RTC 0x10070000
+#define EXYNOS5_PA_RTC 0x101E0000
#define EXYNOS4_PA_KEYPAD 0x100A0000
@@ -78,8 +93,8 @@
#define EXYNOS4_PA_GIC_CPU 0x10480000
#define EXYNOS4_PA_GIC_DIST 0x10490000
-#define EXYNOS5_PA_GIC_CPU 0x10480000
-#define EXYNOS5_PA_GIC_DIST 0x10490000
+#define EXYNOS5_PA_GIC_CPU 0x10482000
+#define EXYNOS5_PA_GIC_DIST 0x10481000
#define EXYNOS4_PA_COREPERI 0x10500000
#define EXYNOS4_PA_TWD 0x10500600
@@ -94,7 +109,7 @@
#define EXYNOS5_PA_PDMA0 0x121A0000
#define EXYNOS5_PA_PDMA1 0x121B0000
-#define EXYNOS4_PA_SYSMMU_MDMA 0x10A40000
+#define EXYNOS4_PA_SYSMMU_G2D_ACP 0x10A40000
#define EXYNOS4_PA_SYSMMU_SSS 0x10A50000
#define EXYNOS4_PA_SYSMMU_FIMC0 0x11A20000
#define EXYNOS4_PA_SYSMMU_FIMC1 0x11A30000
@@ -103,6 +118,12 @@
#define EXYNOS4_PA_SYSMMU_JPEG 0x11A60000
#define EXYNOS4_PA_SYSMMU_FIMD0 0x11E20000
#define EXYNOS4_PA_SYSMMU_FIMD1 0x12220000
+#define EXYNOS4_PA_SYSMMU_ISP 0x12260000
+#define EXYNOS4_PA_SYSMMU_DRC 0x12270000
+#define EXYNOS4_PA_SYSMMU_FD 0x122A0000
+#define EXYNOS4_PA_SYSMMU_ISPCPU 0x122B0000
+#define EXYNOS4_PA_SYSMMU_FIMC_LITE0 0x123B0000
+#define EXYNOS4_PA_SYSMMU_FIMC_LITE1 0x123C0000
#define EXYNOS4_PA_SYSMMU_PCIe 0x12620000
#define EXYNOS4_PA_SYSMMU_G2D 0x12A20000
#define EXYNOS4_PA_SYSMMU_ROTATOR 0x12A30000
@@ -113,6 +134,42 @@
#define EXYNOS4_PA_SPI0 0x13920000
#define EXYNOS4_PA_SPI1 0x13930000
#define EXYNOS4_PA_SPI2 0x13940000
+#define EXYNOS5_PA_SPI0 0x12D20000
+#define EXYNOS5_PA_SPI1 0x12D30000
+#define EXYNOS5_PA_SPI2 0x12D40000
+
+#define EXYNOS5_PA_SYSMMU_MDMA1 0x10A40000
+#define EXYNOS5_PA_SYSMMU_SSS 0x10A50000
+#define EXYNOS5_PA_SYSMMU_2D 0x10A60000
+#define EXYNOS5_PA_SYSMMU_MFC_R 0x11200000
+#define EXYNOS5_PA_SYSMMU_MFC_L 0x11210000
+#define EXYNOS5_PA_SYSMMU_ROTATOR 0x11D40000
+#define EXYNOS5_PA_SYSMMU_MDMA2 0x11D50000
+#define EXYNOS5_PA_SYSMMU_JPEG 0x11F20000
+#define EXYNOS5_PA_SS_UDC 0x1200C100
+#define EXYNOS5_PA_SS_DRD 0x12000000
+#define EXYNOS5_PA_SS_PHY 0x12100000
+#define EXYNOS5_PA_SYSMMU_IOP 0x12360000
+#define EXYNOS5_PA_SYSMMU_RTIC 0x12370000
+#define EXYNOS5_PA_SYSMMU_ISP 0x13260000
+#define EXYNOS5_PA_SYSMMU_DRC 0x13270000
+#define EXYNOS5_PA_SYSMMU_SCALERC 0x13280000
+#define EXYNOS5_PA_SYSMMU_SCALERP 0x13290000
+#define EXYNOS5_PA_SYSMMU_FD 0x132A0000
+#define EXYNOS5_PA_SYSMMU_ISPCPU 0x132B0000
+#define EXYNOS5_PA_SYSMMU_ODC 0x132C0000
+#define EXYNOS5_PA_SYSMMU_DIS0 0x132D0000
+#define EXYNOS5_PA_SYSMMU_DIS1 0x132E0000
+#define EXYNOS5_PA_SYSMMU_3DNR 0x132F0000
+#define EXYNOS5_PA_SYSMMU_LITE0 0x13C40000
+#define EXYNOS5_PA_SYSMMU_LITE1 0x13C50000
+#define EXYNOS5_PA_SYSMMU_LITE2 0x13CA0000
+#define EXYNOS5_PA_SYSMMU_GSC0 0x13E80000
+#define EXYNOS5_PA_SYSMMU_GSC1 0x13E90000
+#define EXYNOS5_PA_SYSMMU_GSC2 0x13EA0000
+#define EXYNOS5_PA_SYSMMU_GSC3 0x13EB0000
+#define EXYNOS5_PA_SYSMMU_FIMD1 0x14640000
+#define EXYNOS5_PA_SYSMMU_TV 0x14650000
#define EXYNOS4_PA_GPIO1 0x11400000
#define EXYNOS4_PA_GPIO2 0x11000000
@@ -122,12 +179,28 @@
#define EXYNOS5_PA_GPIO3 0x10D10000
#define EXYNOS5_PA_GPIO4 0x03860000
+#define EXYNOS5_PA_PPMU_DDR_C 0x10C40000
+#define EXYNOS5_PA_PPMU_DDR_R1 0x10C50000
+#define EXYNOS5_PA_PPMU_CPU 0x10C60000
+#define EXYNOS5_PA_PPMU_DDR_L 0x10CB0000
+#define EXYNOS5_PA_PPMU_RIGHT 0x13660000
+
+#define EXYNOS5_PA_DREXII 0x10DD0000
+
+#define EXYNOS5_PA_G3D 0x11800000
+
#define EXYNOS4_PA_MIPI_CSIS0 0x11880000
#define EXYNOS4_PA_MIPI_CSIS1 0x11890000
#define EXYNOS4_PA_FIMD0 0x11C00000
+#define EXYNOS5_PA_FIMD1 0x14400000
+#define EXYNOS5_PA_DSIM0 0x14500000
+#define EXYNOS5_PA_DP 0x145B0000
+
+#define EXYNOS5_PA_FIMG2D 0x10850000
#define EXYNOS4_PA_HSMMC(x) (0x12510000 + ((x) * 0x10000))
+#define EXYNOS5_PA_HSMMC(x) (0x12200000 + ((x) * 0x10000))
#define EXYNOS4_PA_DWMCI 0x12550000
#define EXYNOS4_PA_SATA 0x12560000
@@ -140,7 +213,14 @@
#define EXYNOS4_PA_EHCI 0x12580000
#define EXYNOS4_PA_OHCI 0x12590000
#define EXYNOS4_PA_HSPHY 0x125B0000
+#define EXYNOS4_PA_USB_HSOTG 0x12480000
+#define EXYNOS5_PA_EHCI 0x12110000
+#define EXYNOS5_PA_OHCI 0x12120000
+#define EXYNOS5_PA_HSPHY 0x12130000
+#define EXYNOS5_PA_USB_HSOTG 0x12140000
+
#define EXYNOS4_PA_MFC 0x13400000
+#define EXYNOS5_PA_MFC 0x11000000
#define EXYNOS4_PA_UART 0x13800000
#define EXYNOS5_PA_UART 0x12C00000
@@ -149,17 +229,41 @@
#define EXYNOS4_PA_MIXER 0x12C10000
#define EXYNOS4_PA_SDO 0x12C20000
#define EXYNOS4_PA_HDMI 0x12D00000
+#define EXYNOS4_PA_HDMI_CEC 0x100B0000
#define EXYNOS4_PA_IIC_HDMIPHY 0x138E0000
+#define EXYNOS5_PA_MIXER 0x14450000
+#define EXYNOS5_PA_HDMI 0x14530000
+#define EXYNOS5_PA_HDMI_CEC 0x100B0000
+#define EXYNOS5_PA_IIC_HDMIPHY 0x12CE0000
+
+#define EXYNOS5_PA_FIMC_IS 0x13000000
+
+#define EXYNOS5_PA_FIMC_LITE0 0x13C00000
+#define EXYNOS5_PA_FIMC_LITE1 0x13C10000
+#define EXYNOS5_PA_FIMC_LITE2 0x13C90000
+
+#define EXYNOS5_PA_MIPI_CSIS0 0x13C20000
+#define EXYNOS5_PA_MIPI_CSIS1 0x13C30000
+
+#define EXYNOS5_PA_GSC0 0x13E00000
+#define EXYNOS5_PA_GSC1 0x13E10000
+#define EXYNOS5_PA_GSC2 0x13E20000
+#define EXYNOS5_PA_GSC3 0x13E30000
+
+#define EXYNOS5_PA_ROTATOR 0x11C00000
+
#define EXYNOS4_PA_IIC(x) (0x13860000 + ((x) * 0x10000))
#define EXYNOS5_PA_IIC(x) (0x12C60000 + ((x) * 0x10000))
#define EXYNOS4_PA_ADC 0x13910000
#define EXYNOS4_PA_ADC1 0x13911000
+#define EXYNOS5_PA_ADC 0x12D10000
#define EXYNOS4_PA_AC97 0x139A0000
#define EXYNOS4_PA_SPDIF 0x139B0000
+#define EXYNOS5_PA_SPDIF 0x12DB0000
#define EXYNOS4_PA_TIMER 0x139D0000
#define EXYNOS5_PA_TIMER 0x12DD0000
@@ -167,12 +271,47 @@
#define EXYNOS4_PA_SDRAM 0x40000000
#define EXYNOS5_PA_SDRAM 0x40000000
+#define EXYNOS5_PA_BTS_FBM_DDR_R1 0x10C30000
+#define EXYNOS5_PA_BTS_CPU 0x10C80000
+#define EXYNOS5_PA_BTS_G3D_ACP 0x10EA0000
+#define EXYNOS5_PA_BTS_MFC0 0x11220000
+#define EXYNOS5_PA_BTS_MFC1 0x11230000
+#define EXYNOS5_PA_BTS_ROTATOR 0x11D60000
+#define EXYNOS5_PA_BTS_MDMA1 0x11D70000
+#define EXYNOS5_PA_BTS_JPEG 0x11F40000
+#define EXYNOS5_PA_BTS_GSCL0 0x13EC0000
+#define EXYNOS5_PA_BTS_GSCL1 0x13ED0000
+#define EXYNOS5_PA_BTS_GSCL2 0x13EE0000
+#define EXYNOS5_PA_BTS_GSCL3 0x13EF0000
+#define EXYNOS5_PA_BTS_DISP10 0x14660000
+#define EXYNOS5_PA_BTS_DISP11 0x14670000
+#define EXYNOS5_PA_BTS_MIXER0 0x14690000
+#define EXYNOS5_PA_BTS_MIXER1 0x146A0000
+#define EXYNOS5_PA_BTS_C2C 0x10c90000
+#define EXYNOS5_PA_BTS_FIMC_ISP 0x13300000
+#define EXYNOS5_PA_BTS_FIMC_SCALER_C 0x13320000
+#define EXYNOS5_PA_BTS_FIMC_SCALER_P 0x13330000
+#define EXYNOS5_PA_BTS_FIMC_FD 0x13340000
+#define EXYNOS5_PA_BTS_FIMC_ODC 0x13370000
+#define EXYNOS5_PA_BTS_FIMC_DIS0 0x13380000
+#define EXYNOS5_PA_BTS_FIMC_DIS1 0x13390000
+#define EXYNOS5_PA_BTS_FIMC_3DNR 0x133A0000
+
/* Compatibiltiy Defines */
+#ifdef CONFIG_ARCH_EXYNOS4
#define S3C_PA_HSMMC0 EXYNOS4_PA_HSMMC(0)
#define S3C_PA_HSMMC1 EXYNOS4_PA_HSMMC(1)
#define S3C_PA_HSMMC2 EXYNOS4_PA_HSMMC(2)
#define S3C_PA_HSMMC3 EXYNOS4_PA_HSMMC(3)
+#elif defined(CONFIG_ARCH_EXYNOS5)
+#define S3C_PA_HSMMC0 EXYNOS5_PA_HSMMC(0)
+#define S3C_PA_HSMMC1 EXYNOS5_PA_HSMMC(1)
+#define S3C_PA_HSMMC2 EXYNOS5_PA_HSMMC(2)
+#define S3C_PA_HSMMC3 EXYNOS5_PA_HSMMC(3)
+#endif
+
+#ifdef CONFIG_ARCH_EXYNOS4
#define S3C_PA_IIC EXYNOS4_PA_IIC(0)
#define S3C_PA_IIC1 EXYNOS4_PA_IIC(1)
#define S3C_PA_IIC2 EXYNOS4_PA_IIC(2)
@@ -181,13 +320,44 @@
#define S3C_PA_IIC5 EXYNOS4_PA_IIC(5)
#define S3C_PA_IIC6 EXYNOS4_PA_IIC(6)
#define S3C_PA_IIC7 EXYNOS4_PA_IIC(7)
+#endif
+
+#ifdef CONFIG_ARCH_EXYNOS5
+#define S3C_PA_IIC EXYNOS5_PA_IIC(0)
+#define S3C_PA_IIC1 EXYNOS5_PA_IIC(1)
+#define S3C_PA_IIC2 EXYNOS5_PA_IIC(2)
+#define S3C_PA_IIC3 EXYNOS5_PA_IIC(3)
+#define S3C_PA_IIC4 EXYNOS5_PA_IIC(4)
+#define S3C_PA_IIC5 EXYNOS5_PA_IIC(5)
+#define S3C_PA_IIC6 EXYNOS5_PA_IIC(6)
+#define S3C_PA_IIC7 EXYNOS5_PA_IIC(7)
+#endif
+
+#ifdef CONFIG_ARCH_EXYNOS4
#define S3C_PA_RTC EXYNOS4_PA_RTC
#define S3C_PA_WDT EXYNOS4_PA_WATCHDOG
#define S3C_PA_SPI0 EXYNOS4_PA_SPI0
#define S3C_PA_SPI1 EXYNOS4_PA_SPI1
#define S3C_PA_SPI2 EXYNOS4_PA_SPI2
+#elif CONFIG_ARCH_EXYNOS5
+#define S3C_PA_RTC EXYNOS5_PA_RTC
+#define S3C_PA_WDT EXYNOS5_PA_WATCHDOG
+#define S3C_PA_SPI0 EXYNOS5_PA_SPI0
+#define S3C_PA_SPI1 EXYNOS5_PA_SPI1
+#define S3C_PA_SPI2 EXYNOS5_PA_SPI2
+#endif
+#ifdef CONFIG_ARCH_EXYNOS4
+#define S3C_PA_USB_HSOTG EXYNOS4_PA_USB_HSOTG
+#elif CONFIG_ARCH_EXYNOS5
+#define S3C_PA_USB_HSOTG EXYNOS5_PA_USB_HSOTG
+#endif
+
+#ifdef CONFIG_ARCH_EXYNOS4
#define S5P_PA_EHCI EXYNOS4_PA_EHCI
+#elif CONFIG_ARCH_EXYNOS5
+#define S5P_PA_EHCI EXYNOS5_PA_EHCI
+#endif
#define S5P_PA_FIMC0 EXYNOS4_PA_FIMC0
#define S5P_PA_FIMC1 EXYNOS4_PA_FIMC1
#define S5P_PA_FIMC2 EXYNOS4_PA_FIMC2
@@ -195,22 +365,49 @@
#define S5P_PA_JPEG EXYNOS4_PA_JPEG
#define S5P_PA_G2D EXYNOS4_PA_G2D
#define S5P_PA_FIMD0 EXYNOS4_PA_FIMD0
-#define S5P_PA_HDMI EXYNOS4_PA_HDMI
-#define S5P_PA_IIC_HDMIPHY EXYNOS4_PA_IIC_HDMIPHY
+#define S5P_PA_FIMD1 EXYNOS5_PA_FIMD1
+#define S5P_PA_DSIM0 EXYNOS5_PA_DSIM0
+#define S5P_PA_DP EXYNOS5_PA_DP
+#define S5P_PA_FIMG2D EXYNOS5_PA_FIMG2D
+
+#ifdef CONFIG_ARCH_EXYNOS4
#define S5P_PA_MFC EXYNOS4_PA_MFC
#define S5P_PA_MIPI_CSIS0 EXYNOS4_PA_MIPI_CSIS0
#define S5P_PA_MIPI_CSIS1 EXYNOS4_PA_MIPI_CSIS1
+#define S5P_PA_SDO EXYNOS4_PA_SDO
#define S5P_PA_MIXER EXYNOS4_PA_MIXER
+#define S5P_PA_VP EXYNOS4_PA_VP
+#define S5P_PA_HDMI EXYNOS4_PA_HDMI
+#define S5P_PA_IIC_HDMIPHY EXYNOS4_PA_IIC_HDMIPHY
+#elif CONFIG_ARCH_EXYNOS5
+#define S5P_PA_MFC EXYNOS5_PA_MFC
+#define S5P_PA_MIPI_CSIS0 EXYNOS5_PA_MIPI_CSIS0
+#define S5P_PA_MIPI_CSIS1 EXYNOS5_PA_MIPI_CSIS1
+#define S5P_PA_HDMI_CEC EXYNOS5_PA_HDMI_CEC
+#define S5P_PA_MIXER EXYNOS5_PA_MIXER
+#define S5P_PA_HDMI EXYNOS5_PA_HDMI
+#define S5P_PA_IIC_HDMIPHY EXYNOS5_PA_IIC_HDMIPHY
+#endif
#define S5P_PA_ONENAND EXYNOS4_PA_ONENAND
#define S5P_PA_ONENAND_DMA EXYNOS4_PA_ONENAND_DMA
-#define S5P_PA_SDO EXYNOS4_PA_SDO
#define S5P_PA_SDRAM EXYNOS4_PA_SDRAM
-#define S5P_PA_VP EXYNOS4_PA_VP
+#ifdef CONFIG_ARCH_EXYNOS4
#define SAMSUNG_PA_ADC EXYNOS4_PA_ADC
#define SAMSUNG_PA_ADC1 EXYNOS4_PA_ADC1
+#elif CONFIG_ARCH_EXYNOS5
+#define SAMSUNG_PA_ADC EXYNOS5_PA_ADC
+#endif
#define SAMSUNG_PA_KEYPAD EXYNOS4_PA_KEYPAD
+#define S5P_PA_ACE EXYNOS5_PA_ACE
+#define S5P_PA_TMU EXYNOS5_PA_TMU
+
+#ifdef CONFIG_ARCH_EXYNOS4
+#define EXYNOS_PA_OHCI EXYNOS4_PA_OHCI
+#elif CONFIG_ARCH_EXYNOS5
+#define EXYNOS_PA_OHCI EXYNOS5_PA_OHCI
+#endif
/* Compatibility UART */
#define EXYNOS4_PA_UART0 0x13800000
diff --git a/arch/arm/mach-exynos/include/mach/memory.h b/arch/arm/mach-exynos/include/mach/memory.h
index 374ef2c..7bd7765 100644
--- a/arch/arm/mach-exynos/include/mach/memory.h
+++ b/arch/arm/mach-exynos/include/mach/memory.h
@@ -19,4 +19,6 @@
#define MAX_PHYSMEM_BITS 32
#define SECTION_SIZE_BITS 28
+#define ARCH_HAS_SG_CHAIN
+
#endif /* __ASM_ARCH_MEMORY_H */
diff --git a/arch/arm/mach-exynos/include/mach/pm-core.h b/arch/arm/mach-exynos/include/mach/pm-core.h
index 9d8da51e3..b78aba6 100644
--- a/arch/arm/mach-exynos/include/mach/pm-core.h
+++ b/arch/arm/mach-exynos/include/mach/pm-core.h
@@ -28,12 +28,13 @@
static inline void s3c_pm_arch_prepare_irqs(void)
{
unsigned int tmp;
- tmp = __raw_readl(S5P_WAKEUP_MASK);
+ tmp = __raw_readl(EXYNOS_WAKEUP_MASK);
tmp &= ~(1 << 31);
- __raw_writel(tmp, S5P_WAKEUP_MASK);
+ __raw_writel(tmp, EXYNOS_WAKEUP_MASK);
- __raw_writel(s3c_irqwake_intmask, S5P_WAKEUP_MASK);
- __raw_writel(s3c_irqwake_eintmask, S5P_EINT_WAKEUP_MASK);
+ __raw_writel(s3c_irqwake_intmask, EXYNOS_WAKEUP_MASK);
+ __raw_writel(s3c_irqwake_eintmask & 0xFFFFFFFE,
+ EXYNOS_EINT_WAKEUP_MASK);
}
static inline void s3c_pm_arch_stop_clocks(void)
diff --git a/arch/arm/mach-exynos/include/mach/pmu.h b/arch/arm/mach-exynos/include/mach/pmu.h
index e76b7fa..7703aab 100644
--- a/arch/arm/mach-exynos/include/mach/pmu.h
+++ b/arch/arm/mach-exynos/include/mach/pmu.h
@@ -1,9 +1,9 @@
-/* linux/arch/arm/mach-exynos4/include/mach/pmu.h
+/* linux/arch/arm/mach-exynos/include/mach/pmu.h
*
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
* http://www.samsung.com/
*
- * EXYNOS4210 - PMU(Power Management Unit) support
+ * EXYNOS - PMU(Power Management Unit) support
*
* 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
@@ -23,12 +23,14 @@
};
extern unsigned long l2x0_regs_phys;
-struct exynos4_pmu_conf {
+struct exynos_pmu_conf {
void __iomem *reg;
unsigned int val[NUM_SYS_POWERDOWN];
};
-extern void exynos4_sys_powerdown_conf(enum sys_powerdown mode);
+extern void exynos_sys_powerdown_conf(enum sys_powerdown mode);
+extern void exynos_xxti_sys_powerdown(bool enable);
extern void s3c_cpu_resume(void);
+extern void exynos_reset_assert_ctrl(bool on);
#endif /* __ASM_ARCH_PMU_H */
diff --git a/arch/arm/mach-exynos/include/mach/regs-audss.h b/arch/arm/mach-exynos/include/mach/regs-audss.h
index ca5a8b6..41b52b3 100644
--- a/arch/arm/mach-exynos/include/mach/regs-audss.h
+++ b/arch/arm/mach-exynos/include/mach/regs-audss.h
@@ -15,4 +15,21 @@
#define EXYNOS4_AUDSS_INT_MEM (0x03000000)
+#define EXYNOS_AUDSSREG(x) (S5P_VA_AUDSS + (x))
+
+#define EXYNOS_CLKSRC_AUDSS_OFFSET 0x0
+#define EXYNOS_CLKDIV_AUDSS_OFFSET 0x4
+#define EXYNOS_CLKGATE_AUDSS_OFFSET 0x8
+
+#define EXYNOS_CLKSRC_AUDSS EXYNOS_AUDSSREG(EXYNOS_CLKSRC_AUDSS_OFFSET)
+#define EXYNOS_CLKDIV_AUDSS EXYNOS_AUDSSREG(EXYNOS_CLKDIV_AUDSS_OFFSET)
+#define EXYNOS_CLKGATE_AUDSS EXYNOS_AUDSSREG(EXYNOS_CLKGATE_AUDSS_OFFSET)
+
+/* IP Clock Gate 0 Registers */
+#define EXYNOS_AUDSS_CLKGATE_RP (1<<0)
+#define EXYNOS_AUDSS_CLKGATE_I2SBUS (1<<2)
+#define EXYNOS_AUDSS_CLKGATE_I2SSPECIAL (1<<3)
+#define EXYNOS_AUDSS_CLKGATE_UART (1<<7)
+#define EXYNOS_AUDSS_CLKGATE_TIMER (1<<8)
+
#endif /* _PLAT_REGS_AUDSS_H */
diff --git a/arch/arm/mach-exynos/include/mach/regs-cec.h b/arch/arm/mach-exynos/include/mach/regs-cec.h
new file mode 100644
index 0000000..1b5ed09
--- /dev/null
+++ b/arch/arm/mach-exynos/include/mach/regs-cec.h
@@ -0,0 +1,93 @@
+/* linux/arch/arm/mach-exynos/include/mach/regs-cec.h
+ *
+ * Copyright (c) 2010 Samsung Electronics
+ * http://www.samsung.com/
+ *
+ * CEC register header file for Samsung TVOUT driver
+ *
+ * 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.
+ */
+
+#ifndef __ARCH_ARM_REGS_CEC_H
+#define __ARCH_ARM_REGS_CEC_H
+
+/*
+ * Register part
+ */
+#define S5P_CES_STATUS_0 (0x0000)
+#define S5P_CES_STATUS_1 (0x0004)
+#define S5P_CES_STATUS_2 (0x0008)
+#define S5P_CES_STATUS_3 (0x000C)
+#define S5P_CES_IRQ_MASK (0x0010)
+#define S5P_CES_IRQ_CLEAR (0x0014)
+#define S5P_CES_LOGIC_ADDR (0x0020)
+#define S5P_CES_DIVISOR_0 (0x0030)
+#define S5P_CES_DIVISOR_1 (0x0034)
+#define S5P_CES_DIVISOR_2 (0x0038)
+#define S5P_CES_DIVISOR_3 (0x003C)
+
+#define S5P_CES_TX_CTRL (0x0040)
+#define S5P_CES_TX_BYTES (0x0044)
+#define S5P_CES_TX_STAT0 (0x0060)
+#define S5P_CES_TX_STAT1 (0x0064)
+#define S5P_CES_TX_BUFF0 (0x0080)
+#define S5P_CES_TX_BUFF1 (0x0084)
+#define S5P_CES_TX_BUFF2 (0x0088)
+#define S5P_CES_TX_BUFF3 (0x008C)
+#define S5P_CES_TX_BUFF4 (0x0090)
+#define S5P_CES_TX_BUFF5 (0x0094)
+#define S5P_CES_TX_BUFF6 (0x0098)
+#define S5P_CES_TX_BUFF7 (0x009C)
+#define S5P_CES_TX_BUFF8 (0x00A0)
+#define S5P_CES_TX_BUFF9 (0x00A4)
+#define S5P_CES_TX_BUFF10 (0x00A8)
+#define S5P_CES_TX_BUFF11 (0x00AC)
+#define S5P_CES_TX_BUFF12 (0x00B0)
+#define S5P_CES_TX_BUFF13 (0x00B4)
+#define S5P_CES_TX_BUFF14 (0x00B8)
+#define S5P_CES_TX_BUFF15 (0x00BC)
+
+#define S5P_CES_RX_CTRL (0x00C0)
+#define S5P_CES_RX_STAT0 (0x00E0)
+#define S5P_CES_RX_STAT1 (0x00E4)
+#define S5P_CES_RX_BUFF0 (0x0100)
+#define S5P_CES_RX_BUFF1 (0x0104)
+#define S5P_CES_RX_BUFF2 (0x0108)
+#define S5P_CES_RX_BUFF3 (0x010C)
+#define S5P_CES_RX_BUFF4 (0x0110)
+#define S5P_CES_RX_BUFF5 (0x0114)
+#define S5P_CES_RX_BUFF6 (0x0118)
+#define S5P_CES_RX_BUFF7 (0x011C)
+#define S5P_CES_RX_BUFF8 (0x0120)
+#define S5P_CES_RX_BUFF9 (0x0124)
+#define S5P_CES_RX_BUFF10 (0x0128)
+#define S5P_CES_RX_BUFF11 (0x012C)
+#define S5P_CES_RX_BUFF12 (0x0130)
+#define S5P_CES_RX_BUFF13 (0x0134)
+#define S5P_CES_RX_BUFF14 (0x0138)
+#define S5P_CES_RX_BUFF15 (0x013C)
+
+#define S5P_CES_RX_FILTER_CTRL (0x0180)
+#define S5P_CES_RX_FILTER_TH (0x0184)
+
+/*
+ * Bit definition part
+ */
+#define S5P_CES_IRQ_TX_DONE (1<<0)
+#define S5P_CES_IRQ_TX_ERROR (1<<1)
+#define S5P_CES_IRQ_RX_DONE (1<<4)
+#define S5P_CES_IRQ_RX_ERROR (1<<5)
+
+#define S5P_CES_TX_CTRL_START (1<<0)
+#define S5P_CES_TX_CTRL_BCAST (1<<1)
+#define S5P_CES_TX_CTRL_RETRY (0x04<<4)
+#define S5P_CES_TX_CTRL_RESET (1<<7)
+
+#define S5P_CES_RX_CTRL_ENABLE (1<<0)
+#define S5P_CES_RX_CTRL_RESET (1<<7)
+
+#define S5P_CES_LOGIC_ADDR_MASK (0xF)
+
+#endif /* __ARCH_ARM_REGS_CEC_H */
diff --git a/arch/arm/mach-exynos/include/mach/regs-clock.h b/arch/arm/mach-exynos/include/mach/regs-clock.h
index d9578a5..c723ca3 100644
--- a/arch/arm/mach-exynos/include/mach/regs-clock.h
+++ b/arch/arm/mach-exynos/include/mach/regs-clock.h
@@ -264,64 +264,224 @@
#define EXYNOS5_CLKDIV_STATCPU0 EXYNOS_CLKREG(0x00600)
#define EXYNOS5_CLKDIV_STATCPU1 EXYNOS_CLKREG(0x00604)
+#define EXYNOS5_PWR_CTRL1 EXYNOS_CLKREG(0x01020)
+#define EXYNOS5_PWR_CTRL2 EXYNOS_CLKREG(0x01024)
+
#define EXYNOS5_MPLL_CON0 EXYNOS_CLKREG(0x04100)
#define EXYNOS5_CLKSRC_CORE1 EXYNOS_CLKREG(0x04204)
+#define EXYNOS5_CLKDIV_SYSRGT EXYNOS_CLKREG(0x04508)
+#define EXYNOS5_CLKDIV_SYSRGT_ACLK_R1BX_SHIFT (0)
+#define EXYNOS5_CLKDIV_SYSRGT_ACLK_R1BX_MASK (0x7 << EXYNOS5_CLKDIV_SYSRGT_ACLK_R1BX_SHIFT)
+
+#define EXYNOS5_CLKDIV_STAT_SYSRGT EXYNOS_CLKREG(0x04608)
+
#define EXYNOS5_CLKGATE_IP_CORE EXYNOS_CLKREG(0x04900)
+#define EXYNOS5_CLKGATE_IP_SYSRGT EXYNOS_CLKREG(0x04904)
+#define EXYNOS5_CLKGATE_IP_SYSLFT EXYNOS_CLKREG(0x08930)
#define EXYNOS5_CLKDIV_ACP EXYNOS_CLKREG(0x08500)
+#define EXYNOS5_CLKDIV_SYSLFT EXYNOS_CLKREG(0x08900)
+#define EXYNOS5_CLKDIV_SYSLFT_PCLK_SYSLFT_SHIFT (4)
+#define EXYNOS5_CLKDIV_SYSLFT_PCLK_SYSLFT_MASK (0x7 << EXYNOS5_CLKDIV_SYSLFT_PCLK_SYSLFT_SHIFT)
+#define EXYNOS5_CLKDIV_SYSLFT_ACLK_SYSLFT_SHIFT (0)
+#define EXYNOS5_CLKDIV_SYSLFT_ACLK_SYSLFT_MASK (0x7 << EXYNOS5_CLKDIV_SYSLFT_ACLK_SYSLFT_SHIFT)
-#define EXYNOS5_CLKSRC_TOP2 EXYNOS_CLKREG(0x10218)
+#define EXYNOS5_CLKDIV_STAT_SYSLFT EXYNOS_CLKREG(0x08910)
+
+#define EXYNOS5_GPLL_LOCK EXYNOS_CLKREG(0x10050)
+#define EXYNOS5_VPLL_LOCK EXYNOS_CLKREG(0x10040)
+
#define EXYNOS5_EPLL_CON0 EXYNOS_CLKREG(0x10130)
#define EXYNOS5_EPLL_CON1 EXYNOS_CLKREG(0x10134)
+#define EXYNOS5_EPLL_CON2 EXYNOS_CLKREG(0x10138)
#define EXYNOS5_VPLL_CON0 EXYNOS_CLKREG(0x10140)
#define EXYNOS5_VPLL_CON1 EXYNOS_CLKREG(0x10144)
+#define EXYNOS5_VPLL_CON2 EXYNOS_CLKREG(0x10148)
+#define EXYNOS5_GPLL_CON0 EXYNOS_CLKREG(0x10150)
+#define EXYNOS5_GPLLCON0_LOCKED (1 << 29)
+#define EXYNOS5_GPLL_CON1 EXYNOS_CLKREG(0x10154)
#define EXYNOS5_CPLL_CON0 EXYNOS_CLKREG(0x10120)
#define EXYNOS5_CLKSRC_TOP0 EXYNOS_CLKREG(0x10210)
+#define EXYNOS5_CLKSRC_TOP1 EXYNOS_CLKREG(0x10214)
+#define EXYNOS5_CLKSRC_TOP2 EXYNOS_CLKREG(0x10218)
#define EXYNOS5_CLKSRC_TOP3 EXYNOS_CLKREG(0x1021C)
#define EXYNOS5_CLKSRC_GSCL EXYNOS_CLKREG(0x10220)
#define EXYNOS5_CLKSRC_DISP1_0 EXYNOS_CLKREG(0x1022C)
+#define EXYNOS5_CLKSRC_MAUDIO EXYNOS_CLKREG(0x10240)
#define EXYNOS5_CLKSRC_FSYS EXYNOS_CLKREG(0x10244)
+#define EXYNOS5_CLKSRC_GEN EXYNOS_CLKREG(0x10248)
#define EXYNOS5_CLKSRC_PERIC0 EXYNOS_CLKREG(0x10250)
+#define EXYNOS5_CLKSRC_PERIC1 EXYNOS_CLKREG(0x10254)
+#define EXYNOS5_SCLK_SRC_ISP EXYNOS_CLKREG(0x10270)
#define EXYNOS5_CLKSRC_MASK_TOP EXYNOS_CLKREG(0x10310)
#define EXYNOS5_CLKSRC_MASK_GSCL EXYNOS_CLKREG(0x10320)
#define EXYNOS5_CLKSRC_MASK_DISP1_0 EXYNOS_CLKREG(0x1032C)
+#define EXYNOS5_CLKSRC_MASK_MAUDIO EXYNOS_CLKREG(0x10334)
#define EXYNOS5_CLKSRC_MASK_FSYS EXYNOS_CLKREG(0x10340)
+#define EXYNOS5_CLKSRC_MASK_GEN EXYNOS_CLKREG(0x10344)
#define EXYNOS5_CLKSRC_MASK_PERIC0 EXYNOS_CLKREG(0x10350)
+#define EXYNOS5_CLKSRC_MASK_PERIC1 EXYNOS_CLKREG(0x10354)
+#define EXYNOS5_CLKSRC_MASK_ISP EXYNOS_CLKREG(0x10370)
#define EXYNOS5_CLKDIV_TOP0 EXYNOS_CLKREG(0x10510)
#define EXYNOS5_CLKDIV_TOP1 EXYNOS_CLKREG(0x10514)
#define EXYNOS5_CLKDIV_GSCL EXYNOS_CLKREG(0x10520)
#define EXYNOS5_CLKDIV_DISP1_0 EXYNOS_CLKREG(0x1052C)
#define EXYNOS5_CLKDIV_GEN EXYNOS_CLKREG(0x1053C)
+#define EXYNOS5_CLKDIV_MAUDIO EXYNOS_CLKREG(0x10544)
#define EXYNOS5_CLKDIV_FSYS0 EXYNOS_CLKREG(0x10548)
#define EXYNOS5_CLKDIV_FSYS1 EXYNOS_CLKREG(0x1054C)
#define EXYNOS5_CLKDIV_FSYS2 EXYNOS_CLKREG(0x10550)
#define EXYNOS5_CLKDIV_FSYS3 EXYNOS_CLKREG(0x10554)
#define EXYNOS5_CLKDIV_PERIC0 EXYNOS_CLKREG(0x10558)
+#define EXYNOS5_CLKDIV_PERIC1 EXYNOS_CLKREG(0x1055C)
+#define EXYNOS5_CLKDIV_PERIC2 EXYNOS_CLKREG(0x10560)
+#define EXYNOS5_CLKDIV_PERIC3 EXYNOS_CLKREG(0x10564)
+#define EXYNOS5_CLKDIV_PERIC4 EXYNOS_CLKREG(0x10568)
+#define EXYNOS5_CLKDIV_PERIC5 EXYNOS_CLKREG(0x1056C)
+#define EXYNOS5_SCLK_DIV_ISP EXYNOS_CLKREG(0x10580)
+#define EXYNOS5_CLKDIV2_RATIO0 EXYNOS_CLKREG(0x10590)
+#define EXYNOS5_CLKDIV2_RATIO1 EXYNOS_CLKREG(0x10594)
+#define EXYNOS5_CLKDIV4_RATIO EXYNOS_CLKREG(0x105A0)
+#define EXYNOS5_CLKDIV_ISP0 EXYNOS_CLKREG(0x0C300)
+#define EXYNOS5_CLKDIV_ISP1 EXYNOS_CLKREG(0x0C304)
+#define EXYNOS5_CLKDIV_ISP2 EXYNOS_CLKREG(0x0C308)
#define EXYNOS5_CLKGATE_IP_ACP EXYNOS_CLKREG(0x08800)
+#define EXYNOS5_CLKGATE_IP_ISP0 EXYNOS_CLKREG(0x0C800)
+#define EXYNOS5_CLKGATE_IP_ISP1 EXYNOS_CLKREG(0x0C804)
+#define EXYNOS5_CLKGATE_SCLK_ISP EXYNOS_CLKREG(0x0C900)
#define EXYNOS5_CLKGATE_IP_GSCL EXYNOS_CLKREG(0x10920)
#define EXYNOS5_CLKGATE_IP_DISP1 EXYNOS_CLKREG(0x10928)
#define EXYNOS5_CLKGATE_IP_MFC EXYNOS_CLKREG(0x1092C)
+#define EXYNOS5_CLKGATE_IP_G3D EXYNOS_CLKREG(0x10930)
#define EXYNOS5_CLKGATE_IP_GEN EXYNOS_CLKREG(0x10934)
#define EXYNOS5_CLKGATE_IP_FSYS EXYNOS_CLKREG(0x10944)
-#define EXYNOS5_CLKGATE_IP_GPS EXYNOS_CLKREG(0x1094C)
#define EXYNOS5_CLKGATE_IP_PERIC EXYNOS_CLKREG(0x10950)
#define EXYNOS5_CLKGATE_IP_PERIS EXYNOS_CLKREG(0x10960)
#define EXYNOS5_CLKGATE_BLOCK EXYNOS_CLKREG(0x10980)
+#define EXYNOS5_CLKGATE_BUS_SYSLFT EXYNOS_CLKREG(0x08920)
+
+#define EXYNOS5_CLKOUT_CMU_TOP EXYNOS_CLKREG(0x10A00)
+
+#define EXYNOS5_CLKDIV_LEX EXYNOS_CLKREG(0x14500)
+#define EXYNOS5_CLKDIV_STAT_LEX EXYNOS_CLKREG(0x14600)
+
+#define EXYNOS5_CLKDIV_R0X EXYNOS_CLKREG(0x18500)
+#define EXYNOS5_CLKDIV_STAT_R0X EXYNOS_CLKREG(0x18600)
+
+#define EXYNOS5_CLKDIV_R1X EXYNOS_CLKREG(0x1C500)
+#define EXYNOS5_CLKDIV_STAT_R1X EXYNOS_CLKREG(0x1C600)
+
#define EXYNOS5_BPLL_CON0 EXYNOS_CLKREG(0x20110)
#define EXYNOS5_CLKSRC_CDREX EXYNOS_CLKREG(0x20200)
#define EXYNOS5_CLKDIV_CDREX EXYNOS_CLKREG(0x20500)
+#define EXYNOS5_CLKDIV_CDREX2 EXYNOS_CLKREG(0x20504)
+#define EXYNOS5_CLKDIV_STAT_CDREX EXYNOS_CLKREG(0x20600)
+#define EXYNOS5_CLKDIV_STAT_CDREX2 EXYNOS_CLKREG(0x20604)
+
+#define EXYNOS5_CLKGATE_IP_CDREX EXYNOS_CLKREG(0x20900)
+
+#define EXYNOS5_DMC_PAUSE_CTRL EXYNOS_CLKREG(0x2091C)
+#define EXYNOS5_DMC_PAUSE_ENABLE (1 << 0)
+
+#define EXYNOS5_PLL_DIV2_SEL EXYNOS_CLKREG(0x20A24)
#define EXYNOS5_EPLL_LOCK EXYNOS_CLKREG(0x10030)
+#define EXYNOS5_CLKMUX_STAT_TOP0 EXYNOS_CLKREG(0x10410)
+#define EXYNOS5_CLKDIV_STAT_TOP0 EXYNOS_CLKREG(0x10610)
+#define EXYNOS5_CLKDIV_STAT_TOP1 EXYNOS_CLKREG(0x10614)
+
#define EXYNOS5_EPLLCON0_LOCKED_SHIFT (29)
+#define EXYNOS5_CLKDIV_TOP0_ACLK300_DISP1_SHIFT (28)
+#define EXYNOS5_CLKDIV_TOP0_ACLK300_DISP1_MASK (0x7 << EXYNOS5_CLKDIV_TOP0_ACLK300_DISP1_SHIFT)
+#define EXYNOS5_CLKDIV_TOP0_ACLK400_SHIFT (24)
+#define EXYNOS5_CLKDIV_TOP0_ACLK400_MASK (0x7 << EXYNOS5_CLKDIV_TOP0_ACLK400_SHIFT)
+#define EXYNOS5_CLKDIV_TOP0_ACLK333_SHIFT (20)
+#define EXYNOS5_CLKDIV_TOP0_ACLK333_MASK (0x7 << EXYNOS5_CLKDIV_TOP0_ACLK333_SHIFT)
+#define EXYNOS5_CLKDIV_TOP0_ACLK266_SHIFT (16)
+#define EXYNOS5_CLKDIV_TOP0_ACLK266_MASK (0x7 << EXYNOS5_CLKDIV_TOP0_ACLK266_SHIFT)
+#define EXYNOS5_CLKDIV_TOP0_ACLK200_SHIFT (12)
+#define EXYNOS5_CLKDIV_TOP0_ACLK200_MASK (0x7 << EXYNOS5_CLKDIV_TOP0_ACLK200_SHIFT)
+#define EXYNOS5_CLKDIV_TOP0_ACLK166_SHIFT (8)
+#define EXYNOS5_CLKDIV_TOP0_ACLK166_MASK (0x7 << EXYNOS5_CLKDIV_TOP0_ACLK166_SHIFT)
+#define EXYNOS5_CLKDIV_TOP0_ACLK133_SHIFT (4)
+#define EXYNOS5_CLKDIV_TOP0_ACLK133_MASK (0x7 << EXYNOS5_CLKDIV_TOP0_ACLK133_SHIFT)
+#define EXYNOS5_CLKDIV_TOP0_ACLK66_SHIFT (0)
+#define EXYNOS5_CLKDIV_TOP0_ACLK66_MASK (0x7 << EXYNOS5_CLKDIV_TOP0_ACLK66_SHIFT)
+
+#define EXYNOS5_CLKDIV_TOP1_ACLK66_PRE_SHIFT (24)
+#define EXYNOS5_CLKDIV_TOP1_ACLK66_PRE_MASK (0x7 << EXYNOS5_CLKDIV_TOP1_ACLK66_PRE_SHIFT)
+#define EXYNOS5_CLKDIV_TOP1_ACLK400_ISP_SHIFT (20)
+#define EXYNOS5_CLKDIV_TOP1_ACLK400_ISP_MASK (0x7 << EXYNOS5_CLKDIV_TOP1_ACLK400_ISP_SHIFT)
+#define EXYNOS5_CLKDIV_TOP1_ACLK400_IOP_SHIFT (16)
+#define EXYNOS5_CLKDIV_TOP1_ACLK400_IOP_MASK (0x7 << EXYNOS5_CLKDIV_TOP1_ACLK400_IOP_SHIFT)
+#define EXYNOS5_CLKDIV_TOP1_ACLK300_GSCL_SHIFT (12)
+#define EXYNOS5_CLKDIV_TOP1_ACLK300_GSCL_MASK (0x7 << EXYNOS5_CLKDIV_TOP1_ACLK300_GSCL_SHIFT)
+
+#define EXYNOS5_CLKDIV_LEX_ATCLK_LEX_SHIFT (8)
+#define EXYNOS5_CLKDIV_LEX_ATCLK_LEX_MASK (0x7 << EXYNOS5_CLKDIV_LEX_ATCLK_LEX_SHIFT)
+#define EXYNOS5_CLKDIV_LEX_PCLK_LEX_SHIFT (4)
+#define EXYNOS5_CLKDIV_LEX_PCLK_LEX_MASK (0x7 << EXYNOS5_CLKDIV_LEX_PCLK_LEX_SHIFT)
+
+#define EXYNOS5_CLKDIV_R0X_PCLK_R0X_SHIFT (4)
+#define EXYNOS5_CLKDIV_R0X_PCLK_R0X_MASK (0x7 << EXYNOS5_CLKDIV_R0X_PCLK_R0X_SHIFT)
+
+#define EXYNOS5_CLKDIV_R1X_PCLK_R1X_SHIFT (4)
+#define EXYNOS5_CLKDIV_R1X_PCLK_R1X_MASK (0x7 << EXYNOS5_CLKDIV_R1X_PCLK_R1X_SHIFT)
+
+#define EXYNOS5_CLKDIV_CDREX_MCLK_CDREX2_SHIFT (28)
+#define EXYNOS5_CLKDIV_CDREX_MCLK_CDREX2_MASK (0x7 << EXYNOS5_CLKDIV_CDREX_MCLK_CDREX2_SHIFT)
+#define EXYNOS5_CLKDIV_CDREX_ACLK_EFCON_SHIFT (24)
+#define EXYNOS5_CLKDIV_CDREX_ACLK_EFCON_MASK (0x7 << EXYNOS5_CLKDIV_CDREX_ACLK_EFCON_SHIFT)
+#define EXYNOS5_CLKDIV_CDREX_MCLK_DPHY_SHIFT (20)
+#define EXYNOS5_CLKDIV_CDREX_MCLK_DPHY_MASK (0x7 << EXYNOS5_CLKDIV_CDREX_MCLK_DPHY_SHIFT)
+#define EXYNOS5_CLKDIV_CDREX_MCLK_CDREX_SHIFT (16)
+#define EXYNOS5_CLKDIV_CDREX_MCLK_CDREX_MASK (0x7 << EXYNOS5_CLKDIV_CDREX_MCLK_CDREX_SHIFT)
+#define EXYNOS5_CLKDIV_CDREX_ACLK_C2C200_SHIFT (12)
+#define EXYNOS5_CLKDIV_CDREX_ACLK_C2C200_MASK (0x7 << EXYNOS5_CLKDIV_CDREX_ACLK_C2C200_SHIFT)
+#define EXYNOS5_CLKDIV_CDREX_ACLK_CLK400_SHIFT (8)
+#define EXYNOS5_CLKDIV_CDREX_ACLK_CLK400_MASK (0x7 << EXYNOS5_CLKDIV_CDREX_ACLK_CLK400_SHIFT)
+#define EXYNOS5_CLKDIV_CDREX_PCLK_CDREX_SHIFT (4)
+#define EXYNOS5_CLKDIV_CDREX_PCLK_CDREX_MASK (0x7 << EXYNOS5_CLKDIV_CDREX_PCLK_CDREX_SHIFT)
+#define EXYNOS5_CLKDIV_CDREX_ACLK_CDREX_SHIFT (0)
+#define EXYNOS5_CLKDIV_CDREX_ACLK_CDREX_MASK (0x7 << EXYNOS5_CLKDIV_CDREX_ACLK_CDREX_SHIFT)
+
+#define EXYNOS5_CLKDIV_CDREX2_MCLK_EFPHY_SHIFT (0)
+#define EXYNOS5_CLKDIV_CDREX2_MCLK_EFPHY_MASK (0xf << EXYNOS5_CLKDIV_CDREX2_MCLK_EFPHY_SHIFT)
+
+#define EXYNOS5_VPLLCON0_LOCKED_SHIFT (29)
+
/* Compatibility defines and inclusion */
+#define PWR_CTRL1_CORE2_DOWN_RATIO (28)
+#define PWR_CTRL1_CORE2_DOWN_MASK (0x7 << PWR_CTRL1_CORE2_DOWN_RATIO)
+#define PWR_CTRL1_CORE1_DOWN_RATIO (16)
+#define PWR_CTRL1_CORE1_DOWN_MASK (0x7 << PWR_CTRL1_CORE1_DOWN_RATIO)
+#define PWR_CTRL1_DIV2_DOWN_EN (1 << 9)
+#define PWR_CTRL1_DIV1_DOWN_EN (1 << 8)
+
+#define PWR_CTRL1_USE_CORE1_WFE (1 << 5)
+#define PWR_CTRL1_USE_CORE0_WFE (1 << 4)
+
+#define PWR_CTRL1_USE_CORE1_WFI (1 << 1)
+#define PWR_CTRL1_USE_CORE0_WFI (1 << 0)
+
+#define PWR_CTRL2_DIV2_UP_EN (1 << 25)
+#define PWR_CTRL2_DIV1_UP_EN (1 << 24)
+#define PWR_CTRL2_DUR_STANDBY2 (16)
+#define PWR_CTRL2_DUR_STANDBY2_MASK (0xff << PWR_CTRL2_DUR_STANDBY2)
+#define PWR_CTRL2_DUR_STANDBY1 (8)
+#define PWR_CTRL2_DUR_STANDBY1_MASK (0xff << PWR_CTRL2_DUR_STANDBY1)
+#define PWR_CTRL2_CORE2_UP_RATIO (4)
+#define PWR_CTRL2_CORE2_UP_MASK (0x7 << PWR_CTRL2_CORE2_UP_RATIO)
+#define PWR_CTRL2_CORE1_UP_RATIO (0)
+#define PWR_CTRL2_CORE1_UP_MASK (0x7 << PWR_CTRL2_CORE1_UP_RATIO)
#include <mach/regs-pmu.h>
diff --git a/arch/arm/mach-exynos/include/mach/regs-mem.h b/arch/arm/mach-exynos/include/mach/regs-mem.h
index 0368b5a..db30a4b 100644
--- a/arch/arm/mach-exynos/include/mach/regs-mem.h
+++ b/arch/arm/mach-exynos/include/mach/regs-mem.h
@@ -20,4 +20,7 @@
#define S5P_DMC0_MEMTYPE_SHIFT 8
#define S5P_DMC0_MEMTYPE_MASK 0xF
+#define EXYNOS_DMC_TIMINGAREF_OFFSET 0x30
+#define EXYNOS_DMC_TIMINGROW_OFFSET 0x34
+
#endif /* __ASM_ARCH_REGS_MEM_H */
diff --git a/arch/arm/mach-exynos/include/mach/regs-pmu.h b/arch/arm/mach-exynos/include/mach/regs-pmu.h
index 4c53f38..434de2a 100644
--- a/arch/arm/mach-exynos/include/mach/regs-pmu.h
+++ b/arch/arm/mach-exynos/include/mach/regs-pmu.h
@@ -1,9 +1,8 @@
-/* linux/arch/arm/mach-exynos4/include/mach/regs-pmu.h
- *
- * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+/*
+ * Copyright (c) 2010-2012 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
- * EXYNOS4 - Power management unit definition
+ * EXYNOS - Power management unit definition
*
* 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
@@ -15,207 +14,452 @@
#include <mach/map.h>
-#define S5P_PMUREG(x) (S5P_VA_PMU + (x))
+#define EXYNOS_PMUREG(x) (S5P_VA_PMU + (x))
-#define S5P_CENTRAL_SEQ_CONFIGURATION S5P_PMUREG(0x0200)
+#define EXYNOS_CENTRAL_SEQ_CONFIGURATION EXYNOS_PMUREG(0x0200)
+#define EXYNOS_CENTRAL_LOWPWR_CFG (1 << 16)
-#define S5P_CENTRAL_LOWPWR_CFG (1 << 16)
+#define EXYNOS_CENTRAL_SEQ_OPTION EXYNOS_PMUREG(0x0208)
-#define S5P_CENTRAL_SEQ_OPTION S5P_PMUREG(0x0208)
+#define S5P_SWRESET EXYNOS_PMUREG(0x0400)
+#define EXYNOS_SWRESET EXYNOS_PMUREG(0x0400)
-#define S5P_USE_STANDBY_WFI0 (1 << 16)
-#define S5P_USE_STANDBY_WFI1 (1 << 17)
-#define S5P_USE_STANDBYWFI_ISP_ARM (1 << 18)
-#define S5P_USE_STANDBY_WFE0 (1 << 24)
-#define S5P_USE_STANDBY_WFE1 (1 << 25)
-#define S5P_USE_STANDBYWFE_ISP_ARM (1 << 26)
+#define EXYNOS_RST_STAT EXYNOS_PMUREG(0x0404)
-#define S5P_SWRESET S5P_PMUREG(0x0400)
-#define EXYNOS_SWRESET S5P_PMUREG(0x0400)
+#define EXYNOS_WAKEUP_STAT EXYNOS_PMUREG(0x0600)
+#define EXYNOS_EINT_WAKEUP_MASK EXYNOS_PMUREG(0x0604)
+#define EXYNOS_WAKEUP_MASK EXYNOS_PMUREG(0x0608)
-#define S5P_WAKEUP_STAT S5P_PMUREG(0x0600)
-#define S5P_EINT_WAKEUP_MASK S5P_PMUREG(0x0604)
-#define S5P_WAKEUP_MASK S5P_PMUREG(0x0608)
+#define EXYNOS_HDMI_PHY_CONTROL EXYNOS_PMUREG(0x0700)
+#define EXYNOS_HDMI_PHY_ENABLE (1 << 0)
-#define S5P_HDMI_PHY_CONTROL S5P_PMUREG(0x0700)
-#define S5P_HDMI_PHY_ENABLE (1 << 0)
-
-#define S5P_DAC_PHY_CONTROL S5P_PMUREG(0x070C)
-#define S5P_DAC_PHY_ENABLE (1 << 0)
-
-#define S5P_MIPI_DPHY_CONTROL(n) S5P_PMUREG(0x0710 + (n) * 4)
+#define S5P_MIPI_DPHY_CONTROL(n) EXYNOS_PMUREG(0x0710 + (n) * 4)
#define S5P_MIPI_DPHY_ENABLE (1 << 0)
#define S5P_MIPI_DPHY_SRESETN (1 << 1)
#define S5P_MIPI_DPHY_MRESETN (1 << 2)
-#define S5P_INFORM0 S5P_PMUREG(0x0800)
-#define S5P_INFORM1 S5P_PMUREG(0x0804)
-#define S5P_INFORM2 S5P_PMUREG(0x0808)
-#define S5P_INFORM3 S5P_PMUREG(0x080C)
-#define S5P_INFORM4 S5P_PMUREG(0x0810)
-#define S5P_INFORM5 S5P_PMUREG(0x0814)
-#define S5P_INFORM6 S5P_PMUREG(0x0818)
-#define S5P_INFORM7 S5P_PMUREG(0x081C)
+#define ABB_MODE_060V 0
+#define ABB_MODE_065V 1
+#define ABB_MODE_070V 2
+#define ABB_MODE_075V 3
+#define ABB_MODE_080V 4
+#define ABB_MODE_085V 5
+#define ABB_MODE_090V 6
+#define ABB_MODE_095V 7
+#define ABB_MODE_100V 8
+#define ABB_MODE_105V 9
+#define ABB_MODE_110V 10
+#define ABB_MODE_115V 11
+#define ABB_MODE_120V 12
+#define ABB_MODE_125V 13
+#define ABB_MODE_130V 14
+#define ABB_MODE_135V 15
+#define ABB_MODE_140V 16
+#define ABB_MODE_145V 17
+#define ABB_MODE_150V 18
+#define ABB_MODE_155V 19
+#define ABB_MODE_160V 20
+#define ABB_MODE_BYPASS 255
+#define EXYNOS_ABB_INIT (0x80000080)
+#define EXYNOS_ABB_INIT_BYPASS (0x80000000)
-#define S5P_ARM_CORE0_LOWPWR S5P_PMUREG(0x1000)
-#define S5P_DIS_IRQ_CORE0 S5P_PMUREG(0x1004)
-#define S5P_DIS_IRQ_CENTRAL0 S5P_PMUREG(0x1008)
-#define S5P_ARM_CORE1_LOWPWR S5P_PMUREG(0x1010)
-#define S5P_DIS_IRQ_CORE1 S5P_PMUREG(0x1014)
-#define S5P_DIS_IRQ_CENTRAL1 S5P_PMUREG(0x1018)
-#define S5P_ARM_COMMON_LOWPWR S5P_PMUREG(0x1080)
-#define S5P_L2_0_LOWPWR S5P_PMUREG(0x10C0)
-#define S5P_L2_1_LOWPWR S5P_PMUREG(0x10C4)
-#define S5P_CMU_ACLKSTOP_LOWPWR S5P_PMUREG(0x1100)
-#define S5P_CMU_SCLKSTOP_LOWPWR S5P_PMUREG(0x1104)
-#define S5P_CMU_RESET_LOWPWR S5P_PMUREG(0x110C)
-#define S5P_APLL_SYSCLK_LOWPWR S5P_PMUREG(0x1120)
-#define S5P_MPLL_SYSCLK_LOWPWR S5P_PMUREG(0x1124)
-#define S5P_VPLL_SYSCLK_LOWPWR S5P_PMUREG(0x1128)
-#define S5P_EPLL_SYSCLK_LOWPWR S5P_PMUREG(0x112C)
-#define S5P_CMU_CLKSTOP_GPS_ALIVE_LOWPWR S5P_PMUREG(0x1138)
-#define S5P_CMU_RESET_GPSALIVE_LOWPWR S5P_PMUREG(0x113C)
-#define S5P_CMU_CLKSTOP_CAM_LOWPWR S5P_PMUREG(0x1140)
-#define S5P_CMU_CLKSTOP_TV_LOWPWR S5P_PMUREG(0x1144)
-#define S5P_CMU_CLKSTOP_MFC_LOWPWR S5P_PMUREG(0x1148)
-#define S5P_CMU_CLKSTOP_G3D_LOWPWR S5P_PMUREG(0x114C)
-#define S5P_CMU_CLKSTOP_LCD0_LOWPWR S5P_PMUREG(0x1150)
-#define S5P_CMU_CLKSTOP_MAUDIO_LOWPWR S5P_PMUREG(0x1158)
-#define S5P_CMU_CLKSTOP_GPS_LOWPWR S5P_PMUREG(0x115C)
-#define S5P_CMU_RESET_CAM_LOWPWR S5P_PMUREG(0x1160)
-#define S5P_CMU_RESET_TV_LOWPWR S5P_PMUREG(0x1164)
-#define S5P_CMU_RESET_MFC_LOWPWR S5P_PMUREG(0x1168)
-#define S5P_CMU_RESET_G3D_LOWPWR S5P_PMUREG(0x116C)
-#define S5P_CMU_RESET_LCD0_LOWPWR S5P_PMUREG(0x1170)
-#define S5P_CMU_RESET_MAUDIO_LOWPWR S5P_PMUREG(0x1178)
-#define S5P_CMU_RESET_GPS_LOWPWR S5P_PMUREG(0x117C)
-#define S5P_TOP_BUS_LOWPWR S5P_PMUREG(0x1180)
-#define S5P_TOP_RETENTION_LOWPWR S5P_PMUREG(0x1184)
-#define S5P_TOP_PWR_LOWPWR S5P_PMUREG(0x1188)
-#define S5P_LOGIC_RESET_LOWPWR S5P_PMUREG(0x11A0)
-#define S5P_ONENAND_MEM_LOWPWR S5P_PMUREG(0x11C0)
-#define S5P_G2D_ACP_MEM_LOWPWR S5P_PMUREG(0x11C8)
-#define S5P_USBOTG_MEM_LOWPWR S5P_PMUREG(0x11CC)
-#define S5P_HSMMC_MEM_LOWPWR S5P_PMUREG(0x11D0)
-#define S5P_CSSYS_MEM_LOWPWR S5P_PMUREG(0x11D4)
-#define S5P_SECSS_MEM_LOWPWR S5P_PMUREG(0x11D8)
-#define S5P_PAD_RETENTION_DRAM_LOWPWR S5P_PMUREG(0x1200)
-#define S5P_PAD_RETENTION_MAUDIO_LOWPWR S5P_PMUREG(0x1204)
-#define S5P_PAD_RETENTION_GPIO_LOWPWR S5P_PMUREG(0x1220)
-#define S5P_PAD_RETENTION_UART_LOWPWR S5P_PMUREG(0x1224)
-#define S5P_PAD_RETENTION_MMCA_LOWPWR S5P_PMUREG(0x1228)
-#define S5P_PAD_RETENTION_MMCB_LOWPWR S5P_PMUREG(0x122C)
-#define S5P_PAD_RETENTION_EBIA_LOWPWR S5P_PMUREG(0x1230)
-#define S5P_PAD_RETENTION_EBIB_LOWPWR S5P_PMUREG(0x1234)
-#define S5P_PAD_RETENTION_ISOLATION_LOWPWR S5P_PMUREG(0x1240)
-#define S5P_PAD_RETENTION_ALV_SEL_LOWPWR S5P_PMUREG(0x1260)
-#define S5P_XUSBXTI_LOWPWR S5P_PMUREG(0x1280)
-#define S5P_XXTI_LOWPWR S5P_PMUREG(0x1284)
-#define S5P_EXT_REGULATOR_LOWPWR S5P_PMUREG(0x12C0)
-#define S5P_GPIO_MODE_LOWPWR S5P_PMUREG(0x1300)
-#define S5P_GPIO_MODE_MAUDIO_LOWPWR S5P_PMUREG(0x1340)
-#define S5P_CAM_LOWPWR S5P_PMUREG(0x1380)
-#define S5P_TV_LOWPWR S5P_PMUREG(0x1384)
-#define S5P_MFC_LOWPWR S5P_PMUREG(0x1388)
-#define S5P_G3D_LOWPWR S5P_PMUREG(0x138C)
-#define S5P_LCD0_LOWPWR S5P_PMUREG(0x1390)
-#define S5P_MAUDIO_LOWPWR S5P_PMUREG(0x1398)
-#define S5P_GPS_LOWPWR S5P_PMUREG(0x139C)
-#define S5P_GPS_ALIVE_LOWPWR S5P_PMUREG(0x13A0)
+#define EXYNOS_INFORM0 EXYNOS_PMUREG(0x0800)
+#define EXYNOS_INFORM1 EXYNOS_PMUREG(0x0804)
+#define EXYNOS_INFORM2 EXYNOS_PMUREG(0x0808)
+#define EXYNOS_INFORM3 EXYNOS_PMUREG(0x080C)
+#define EXYNOS_INFORM4 EXYNOS_PMUREG(0x0810)
+#define EXYNOS_INFORM5 EXYNOS_PMUREG(0x0814)
+#define EXYNOS_INFORM6 EXYNOS_PMUREG(0x0818)
+#define EXYNOS_INFORM7 EXYNOS_PMUREG(0x081C)
+#define EXYNOS_CHECK_SLEEP 0x00000BAD
+#define EXYNOS_CHECK_DIDLE 0xBAD00000
+#define EXYNOS_CHECK_LPA 0xABAD0000
-#define S5P_ARM_CORE0_CONFIGURATION S5P_PMUREG(0x2000)
-#define S5P_ARM_CORE0_OPTION S5P_PMUREG(0x2008)
-#define S5P_ARM_CORE1_CONFIGURATION S5P_PMUREG(0x2080)
-#define S5P_ARM_CORE1_STATUS S5P_PMUREG(0x2084)
-#define S5P_ARM_CORE1_OPTION S5P_PMUREG(0x2088)
+#define EXYNOS_PMU_DEBUG EXYNOS_PMUREG(0x0A00)
-#define S5P_ARM_COMMON_OPTION S5P_PMUREG(0x2408)
-#define S5P_TOP_PWR_OPTION S5P_PMUREG(0x2C48)
-#define S5P_CAM_OPTION S5P_PMUREG(0x3C08)
-#define S5P_TV_OPTION S5P_PMUREG(0x3C28)
-#define S5P_MFC_OPTION S5P_PMUREG(0x3C48)
-#define S5P_G3D_OPTION S5P_PMUREG(0x3C68)
-#define S5P_LCD0_OPTION S5P_PMUREG(0x3C88)
-#define S5P_LCD1_OPTION S5P_PMUREG(0x3CA8)
-#define S5P_MAUDIO_OPTION S5P_PMUREG(0x3CC8)
-#define S5P_GPS_OPTION S5P_PMUREG(0x3CE8)
-#define S5P_GPS_ALIVE_OPTION S5P_PMUREG(0x3D08)
+#define EXYNOS_ARM_CORE0_CONFIGURATION EXYNOS_PMUREG(0x2000)
+#define EXYNOS_ARM_CORE0_OPTION EXYNOS_PMUREG(0x2008)
+#define EXYNOS_ARM_CORE1_CONFIGURATION EXYNOS_PMUREG(0x2080)
+#define EXYNOS_ARM_CORE1_STATUS EXYNOS_PMUREG(0x2084)
+#define EXYNOS_ARM_CORE1_OPTION EXYNOS_PMUREG(0x2088)
+#define EXYNOS_ARM_CORE_OPTION(_nr) (EXYNOS_ARM_CORE0_OPTION \
+ + ((_nr) * 0x80))
+#define EXYNOS_USE_DELAYED_RESET_ASSERTION BIT(12)
+#define EXYNOS_ARM_CORE_STATUS(_nr) (EXYNOS_ARM_CORE0_STATUS \
+ + ((_nr) * 0x80))
+#define EXYNOS_ARM_CORE_CONFIGURATION(_nr) \
+ (EXYNOS_ARM_CORE0_CONFIGURATION + ((_nr) * 0x80))
+#define EXYNOS_CORE_LOCAL_PWR_EN 0x3
-#define S5P_PAD_RET_MAUDIO_OPTION S5P_PMUREG(0x3028)
-#define S5P_PAD_RET_GPIO_OPTION S5P_PMUREG(0x3108)
-#define S5P_PAD_RET_UART_OPTION S5P_PMUREG(0x3128)
-#define S5P_PAD_RET_MMCA_OPTION S5P_PMUREG(0x3148)
-#define S5P_PAD_RET_MMCB_OPTION S5P_PMUREG(0x3168)
-#define S5P_PAD_RET_EBIA_OPTION S5P_PMUREG(0x3188)
-#define S5P_PAD_RET_EBIB_OPTION S5P_PMUREG(0x31A8)
+#define EXYNOS_PAD_RET_MAUDIO_OPTION EXYNOS_PMUREG(0x3028)
+#define EXYNOS_PAD_RET_GPIO_OPTION EXYNOS_PMUREG(0x3108)
+#define EXYNOS_PAD_RET_UART_OPTION EXYNOS_PMUREG(0x3128)
+#define EXYNOS_PAD_RET_MMCA_OPTION EXYNOS_PMUREG(0x3148)
+#define EXYNOS_PAD_RET_MMCB_OPTION EXYNOS_PMUREG(0x3168)
+#define EXYNOS_PAD_RET_EBIA_OPTION EXYNOS_PMUREG(0x3188)
+#define EXYNOS_PAD_RET_EBIB_OPTION EXYNOS_PMUREG(0x31A8)
-#define S5P_PMU_CAM_CONF S5P_PMUREG(0x3C00)
-#define S5P_PMU_TV_CONF S5P_PMUREG(0x3C20)
-#define S5P_PMU_MFC_CONF S5P_PMUREG(0x3C40)
-#define S5P_PMU_G3D_CONF S5P_PMUREG(0x3C60)
-#define S5P_PMU_LCD0_CONF S5P_PMUREG(0x3C80)
-#define S5P_PMU_GPS_CONF S5P_PMUREG(0x3CE0)
+#define EXYNOS_PS_HOLD_CONTROL EXYNOS_PMUREG(0x330C)
-#define S5P_PMU_SATA_PHY_CONTROL_EN 0x1
-#define S5P_CORE_LOCAL_PWR_EN 0x3
-#define S5P_INT_LOCAL_PWR_EN 0x7
+/* For XXX_IP_CONFIGURATION(Power Domain) */
+#define EXYNOS_INT_LOCAL_PWR_EN 0x7
-#define S5P_CHECK_SLEEP 0x00000BAD
+/* For SYS_PWR_REG */
+#define EXYNOS_SYS_PWR_CFG (1 << 0)
+
+/* Only for EXYNOS4XXX */
+#define EXYNOS4_ABB_INT EXYNOS_PMUREG(0x0780)
+#define EXYNOS4_ABB_MIF EXYNOS_PMUREG(0x0784)
+#define EXYNOS4_ABB_G3D EXYNOS_PMUREG(0x0788)
+#define EXYNOS4_ABB_ARM EXYNOS_PMUREG(0x078C)
+
+#define EXYNOS4_ARM_CORE0_LOWPWR EXYNOS_PMUREG(0x1000)
+#define EXYNOS4_DIS_IRQ_CORE0 EXYNOS_PMUREG(0x1004)
+#define EXYNOS4_DIS_IRQ_CENTRAL0 EXYNOS_PMUREG(0x1008)
+#define EXYNOS4_ARM_CORE1_LOWPWR EXYNOS_PMUREG(0x1010)
+#define EXYNOS4_DIS_IRQ_CORE1 EXYNOS_PMUREG(0x1014)
+#define EXYNOS4_DIS_IRQ_CENTRAL1 EXYNOS_PMUREG(0x1018)
+#define EXYNOS4_ARM_COMMON_LOWPWR EXYNOS_PMUREG(0x1080)
+#define EXYNOS4_L2_0_LOWPWR EXYNOS_PMUREG(0x10C0)
+#define EXYNOS4_L2_1_LOWPWR EXYNOS_PMUREG(0x10C4)
+#define EXYNOS4_CMU_ACLKSTOP_LOWPWR EXYNOS_PMUREG(0x1100)
+#define EXYNOS4_CMU_SCLKSTOP_LOWPWR EXYNOS_PMUREG(0x1104)
+#define EXYNOS4_CMU_RESET_LOWPWR EXYNOS_PMUREG(0x110C)
+#define EXYNOS4_APLL_SYSCLK_LOWPWR EXYNOS_PMUREG(0x1120)
+#define EXYNOS4_MPLL_SYSCLK_LOWPWR EXYNOS_PMUREG(0x1124)
+#define EXYNOS4_VPLL_SYSCLK_LOWPWR EXYNOS_PMUREG(0x1128)
+#define EXYNOS4_EPLL_SYSCLK_LOWPWR EXYNOS_PMUREG(0x112C)
+#define EXYNOS4_CMU_CLKSTOP_GPS_ALIVE_LOWPWR EXYNOS_PMUREG(0x1138)
+#define EXYNOS4_CMU_RESET_GPSALIVE_LOWPWR EXYNOS_PMUREG(0x113C)
+#define EXYNOS4_CMU_CLKSTOP_CAM_LOWPWR EXYNOS_PMUREG(0x1140)
+#define EXYNOS4_CMU_CLKSTOP_TV_LOWPWR EXYNOS_PMUREG(0x1144)
+#define EXYNOS4_CMU_CLKSTOP_MFC_LOWPWR EXYNOS_PMUREG(0x1148)
+#define EXYNOS4_CMU_CLKSTOP_G3D_LOWPWR EXYNOS_PMUREG(0x114C)
+#define EXYNOS4_CMU_CLKSTOP_LCD0_LOWPWR EXYNOS_PMUREG(0x1150)
+#define EXYNOS4_CMU_CLKSTOP_MAUDIO_LOWPWR EXYNOS_PMUREG(0x1158)
+#define EXYNOS4_CMU_CLKSTOP_GPS_LOWPWR EXYNOS_PMUREG(0x115C)
+#define EXYNOS4_CMU_RESET_CAM_LOWPWR EXYNOS_PMUREG(0x1160)
+#define EXYNOS4_CMU_RESET_TV_LOWPWR EXYNOS_PMUREG(0x1164)
+#define EXYNOS4_CMU_RESET_MFC_LOWPWR EXYNOS_PMUREG(0x1168)
+#define EXYNOS4_CMU_RESET_G3D_LOWPWR EXYNOS_PMUREG(0x116C)
+#define EXYNOS4_CMU_RESET_LCD0_LOWPWR EXYNOS_PMUREG(0x1170)
+#define EXYNOS4_CMU_RESET_MAUDIO_LOWPWR EXYNOS_PMUREG(0x1178)
+#define EXYNOS4_CMU_RESET_GPS_LOWPWR EXYNOS_PMUREG(0x117C)
+#define EXYNOS4_TOP_BUS_LOWPWR EXYNOS_PMUREG(0x1180)
+#define EXYNOS4_TOP_RETENTION_LOWPWR EXYNOS_PMUREG(0x1184)
+#define EXYNOS4_TOP_PWR_LOWPWR EXYNOS_PMUREG(0x1188)
+#define EXYNOS4_LOGIC_RESET_LOWPWR EXYNOS_PMUREG(0x11A0)
+#define EXYNOS4_ONENAND_MEM_LOWPWR EXYNOS_PMUREG(0x11C0)
+#define EXYNOS4_G2D_ACP_MEM_LOWPWR EXYNOS_PMUREG(0x11C8)
+#define EXYNOS4_USBOTG_MEM_LOWPWR EXYNOS_PMUREG(0x11CC)
+#define EXYNOS4_HSMMC_MEM_LOWPWR EXYNOS_PMUREG(0x11D0)
+#define EXYNOS4_CSSYS_MEM_LOWPWR EXYNOS_PMUREG(0x11D4)
+#define EXYNOS4_SECSS_MEM_LOWPWR EXYNOS_PMUREG(0x11D8)
+#define EXYNOS4_PAD_RETENTION_DRAM_LOWPWR EXYNOS_PMUREG(0x1200)
+#define EXYNOS4_PAD_RETENTION_MAUDIO_LOWPWR EXYNOS_PMUREG(0x1204)
+#define EXYNOS4_PAD_RETENTION_GPIO_LOWPWR EXYNOS_PMUREG(0x1220)
+#define EXYNOS4_PAD_RETENTION_UART_LOWPWR EXYNOS_PMUREG(0x1224)
+#define EXYNOS4_PAD_RETENTION_MMCA_LOWPWR EXYNOS_PMUREG(0x1228)
+#define EXYNOS4_PAD_RETENTION_MMCB_LOWPWR EXYNOS_PMUREG(0x122C)
+#define EXYNOS4_PAD_RETENTION_EBIA_LOWPWR EXYNOS_PMUREG(0x1230)
+#define EXYNOS4_PAD_RETENTION_EBIB_LOWPWR EXYNOS_PMUREG(0x1234)
+#define EXYNOS4_PAD_RETENTION_ISOLATION_LOWPWR EXYNOS_PMUREG(0x1240)
+#define EXYNOS4_PAD_RETENTION_ALV_SEL_LOWPWR EXYNOS_PMUREG(0x1260)
+#define EXYNOS4_XUSBXTI_LOWPWR EXYNOS_PMUREG(0x1280)
+#define EXYNOS4_XXTI_LOWPWR EXYNOS_PMUREG(0x1284)
+#define EXYNOS4_EXT_REGULATOR_LOWPWR EXYNOS_PMUREG(0x12C0)
+#define EXYNOS4_GPIO_MODE_LOWPWR EXYNOS_PMUREG(0x1300)
+#define EXYNOS4_GPIO_MODE_MAUDIO_LOWPWR EXYNOS_PMUREG(0x1340)
+#define EXYNOS4_CAM_LOWPWR EXYNOS_PMUREG(0x1380)
+#define EXYNOS4_TV_LOWPWR EXYNOS_PMUREG(0x1384)
+#define EXYNOS4_MFC_LOWPWR EXYNOS_PMUREG(0x1388)
+#define EXYNOS4_G3D_LOWPWR EXYNOS_PMUREG(0x138C)
+#define EXYNOS4_LCD0_LOWPWR EXYNOS_PMUREG(0x1390)
+#define EXYNOS4_MAUDIO_LOWPWR EXYNOS_PMUREG(0x1398)
+#define EXYNOS4_GPS_LOWPWR EXYNOS_PMUREG(0x139C)
+#define EXYNOS4_GPS_ALIVE_LOWPWR EXYNOS_PMUREG(0x13A0)
+
+#define EXYNOS4_ARM_COMMON_OPTION EXYNOS_PMUREG(0x2408)
+#define EXYNOS4_TOP_PWR_OPTION EXYNOS_PMUREG(0x2C48)
+#define EXYNOS4_CAM_OPTION EXYNOS_PMUREG(0x3C08)
+#define EXYNOS4_TV_OPTION EXYNOS_PMUREG(0x3C28)
+#define EXYNOS4_MFC_OPTION EXYNOS_PMUREG(0x3C48)
+#define EXYNOS4_G3D_OPTION EXYNOS_PMUREG(0x3C68)
+#define EXYNOS4_LCD0_OPTION EXYNOS_PMUREG(0x3C88)
+#define EXYNOS4_MAUDIO_OPTION EXYNOS_PMUREG(0x3CC8)
+#define EXYNOS4_GPS_OPTION EXYNOS_PMUREG(0x3CE8)
+#define EXYNOS4_GPS_ALIVE_OPTION EXYNOS_PMUREG(0x3D08)
+
+#define EXYNOS4_CAM_CONFIGURATION EXYNOS_PMUREG(0x3C00)
+#define EXYNOS4_TV_CONFIGURATION EXYNOS_PMUREG(0x3C20)
+#define EXYNOS4_MFC_CONFIGURATION EXYNOS_PMUREG(0x3C40)
+#define EXYNOS4_G3D_CONFIGURATION EXYNOS_PMUREG(0x3C60)
+#define EXYNOS4_LCD0_CONFIGURATION EXYNOS_PMUREG(0x3C80)
+#define EXYNOS4_GPS_CONFIGURATION EXYNOS_PMUREG(0x3CE0)
+
+/* For EXYNOS_CENTRAL_SEQ_OPTION */
+#define EXYNOS4_USE_STANDBY_WFI0 (1 << 16)
+#define EXYNOS4_USE_STANDBY_WFI1 (1 << 17)
+#define EXYNOS4_USE_STANDBYWFI_ISP_ARM (1 << 18)
+#define EXYNOS4_USE_STANDBY_WFE0 (1 << 24)
+#define EXYNOS4_USE_STANDBY_WFE1 (1 << 25)
+#define EXYNOS4_USE_STANDBYWFE_ISP_ARM (1 << 26)
/* Only for EXYNOS4210 */
-#define S5P_USBHOST_PHY_CONTROL S5P_PMUREG(0x0708)
-#define S5P_USBHOST_PHY_ENABLE (1 << 0)
+#define EXYNOS4210_USBHOST_PHY_CONTROL EXYNOS_PMUREG(0x0708)
+#define EXYNOS4210_USBHOST_PHY_ENABLE (1 << 0)
-#define S5P_PMU_SATA_PHY_CONTROL S5P_PMUREG(0x0720)
+#define EXYNOS4210_DAC_PHY_CONTROL EXYNOS_PMUREG(0x070C)
+#define EXYNOS4210_DAC_PHY_ENABLE (1 << 0)
-#define S5P_CMU_CLKSTOP_LCD1_LOWPWR S5P_PMUREG(0x1154)
-#define S5P_CMU_RESET_LCD1_LOWPWR S5P_PMUREG(0x1174)
-#define S5P_MODIMIF_MEM_LOWPWR S5P_PMUREG(0x11C4)
-#define S5P_PCIE_MEM_LOWPWR S5P_PMUREG(0x11E0)
-#define S5P_SATA_MEM_LOWPWR S5P_PMUREG(0x11E4)
-#define S5P_LCD1_LOWPWR S5P_PMUREG(0x1394)
+#define EXYNOS4210_PMU_SATA_PHY_CONTROL EXYNOS_PMUREG(0x0720)
+#define EXYNOS4210_PMU_SATA_PHY_CONTROL_EN (1 << 0)
-#define S5P_PMU_LCD1_CONF S5P_PMUREG(0x3CA0)
+#define EXYNOS4210_CMU_CLKSTOP_LCD1_LOWPWR EXYNOS_PMUREG(0x1154)
+#define EXYNOS4210_CMU_RESET_LCD1_LOWPWR EXYNOS_PMUREG(0x1174)
+#define EXYNOS4210_MODIMIF_MEM_LOWPWR EXYNOS_PMUREG(0x11C4)
+#define EXYNOS4210_PCIE_MEM_LOWPWR EXYNOS_PMUREG(0x11E0)
+#define EXYNOS4210_SATA_MEM_LOWPWR EXYNOS_PMUREG(0x11E4)
+#define EXYNOS4210_LCD1_LOWPWR EXYNOS_PMUREG(0x1394)
-/* Only for EXYNOS4212 */
-#define S5P_ISP_ARM_LOWPWR S5P_PMUREG(0x1050)
-#define S5P_DIS_IRQ_ISP_ARM_LOCAL_LOWPWR S5P_PMUREG(0x1054)
-#define S5P_DIS_IRQ_ISP_ARM_CENTRAL_LOWPWR S5P_PMUREG(0x1058)
-#define S5P_CMU_ACLKSTOP_COREBLK_LOWPWR S5P_PMUREG(0x1110)
-#define S5P_CMU_SCLKSTOP_COREBLK_LOWPWR S5P_PMUREG(0x1114)
-#define S5P_CMU_RESET_COREBLK_LOWPWR S5P_PMUREG(0x111C)
-#define S5P_MPLLUSER_SYSCLK_LOWPWR S5P_PMUREG(0x1130)
-#define S5P_CMU_CLKSTOP_ISP_LOWPWR S5P_PMUREG(0x1154)
-#define S5P_CMU_RESET_ISP_LOWPWR S5P_PMUREG(0x1174)
-#define S5P_TOP_BUS_COREBLK_LOWPWR S5P_PMUREG(0x1190)
-#define S5P_TOP_RETENTION_COREBLK_LOWPWR S5P_PMUREG(0x1194)
-#define S5P_TOP_PWR_COREBLK_LOWPWR S5P_PMUREG(0x1198)
-#define S5P_OSCCLK_GATE_LOWPWR S5P_PMUREG(0x11A4)
-#define S5P_LOGIC_RESET_COREBLK_LOWPWR S5P_PMUREG(0x11B0)
-#define S5P_OSCCLK_GATE_COREBLK_LOWPWR S5P_PMUREG(0x11B4)
-#define S5P_HSI_MEM_LOWPWR S5P_PMUREG(0x11C4)
-#define S5P_ROTATOR_MEM_LOWPWR S5P_PMUREG(0x11DC)
-#define S5P_PAD_RETENTION_GPIO_COREBLK_LOWPWR S5P_PMUREG(0x123C)
-#define S5P_PAD_ISOLATION_COREBLK_LOWPWR S5P_PMUREG(0x1250)
-#define S5P_GPIO_MODE_COREBLK_LOWPWR S5P_PMUREG(0x1320)
-#define S5P_TOP_ASB_RESET_LOWPWR S5P_PMUREG(0x1344)
-#define S5P_TOP_ASB_ISOLATION_LOWPWR S5P_PMUREG(0x1348)
-#define S5P_ISP_LOWPWR S5P_PMUREG(0x1394)
-#define S5P_DRAM_FREQ_DOWN_LOWPWR S5P_PMUREG(0x13B0)
-#define S5P_DDRPHY_DLLOFF_LOWPWR S5P_PMUREG(0x13B4)
-#define S5P_CMU_SYSCLK_ISP_LOWPWR S5P_PMUREG(0x13B8)
-#define S5P_CMU_SYSCLK_GPS_LOWPWR S5P_PMUREG(0x13BC)
-#define S5P_LPDDR_PHY_DLL_LOCK_LOWPWR S5P_PMUREG(0x13C0)
+#define EXYNOS4210_LCD1_CONFIGURATION EXYNOS_PMUREG(0x3CA0)
+#define EXYNOS4210_LCD1_OPTION EXYNOS_PMUREG(0x3CA8)
-#define S5P_ARM_L2_0_OPTION S5P_PMUREG(0x2608)
-#define S5P_ARM_L2_1_OPTION S5P_PMUREG(0x2628)
-#define S5P_ONENAND_MEM_OPTION S5P_PMUREG(0x2E08)
-#define S5P_HSI_MEM_OPTION S5P_PMUREG(0x2E28)
-#define S5P_G2D_ACP_MEM_OPTION S5P_PMUREG(0x2E48)
-#define S5P_USBOTG_MEM_OPTION S5P_PMUREG(0x2E68)
-#define S5P_HSMMC_MEM_OPTION S5P_PMUREG(0x2E88)
-#define S5P_CSSYS_MEM_OPTION S5P_PMUREG(0x2EA8)
-#define S5P_SECSS_MEM_OPTION S5P_PMUREG(0x2EC8)
-#define S5P_ROTATOR_MEM_OPTION S5P_PMUREG(0x2F48)
+/* Only for EXYNOS4212 & EXYNOS4412 */
+#define EXYNOS4X12_ISP_ARM_LOWPWR EXYNOS_PMUREG(0x1050)
+#define EXYNOS4X12_DIS_IRQ_ISP_ARM_LOCAL_LOWPWR EXYNOS_PMUREG(0x1054)
+#define EXYNOS4X12_DIS_IRQ_ISP_ARM_CENTRAL_LOWPWR EXYNOS_PMUREG(0x1058)
+#define EXYNOS4X12_CMU_ACLKSTOP_COREBLK_LOWPWR EXYNOS_PMUREG(0x1110)
+#define EXYNOS4X12_CMU_SCLKSTOP_COREBLK_LOWPWR EXYNOS_PMUREG(0x1114)
+#define EXYNOS4X12_CMU_RESET_COREBLK_LOWPWR EXYNOS_PMUREG(0x111C)
+#define EXYNOS4X12_MPLLUSER_SYSCLK_LOWPWR EXYNOS_PMUREG(0x1130)
+#define EXYNOS4X12_CMU_CLKSTOP_ISP_LOWPWR EXYNOS_PMUREG(0x1154)
+#define EXYNOS4X12_CMU_RESET_ISP_LOWPWR EXYNOS_PMUREG(0x1174)
+#define EXYNOS4X12_TOP_BUS_COREBLK_LOWPWR EXYNOS_PMUREG(0x1190)
+#define EXYNOS4X12_TOP_RETENTION_COREBLK_LOWPWR EXYNOS_PMUREG(0x1194)
+#define EXYNOS4X12_TOP_PWR_COREBLK_LOWPWR EXYNOS_PMUREG(0x1198)
+#define EXYNOS4X12_OSCCLK_GATE_LOWPWR EXYNOS_PMUREG(0x11A4)
+#define EXYNOS4X12_LOGIC_RESET_COREBLK_LOWPWR EXYNOS_PMUREG(0x11B0)
+#define EXYNOS4X12_OSCCLK_GATE_COREBLK_LOWPWR EXYNOS_PMUREG(0x11B4)
+#define EXYNOS4X12_HSI_MEM_LOWPWR EXYNOS_PMUREG(0x11C4)
+#define EXYNOS4X12_ROTATOR_MEM_LOWPWR EXYNOS_PMUREG(0x11DC)
+#define EXYNOS4X12_PAD_RETENTION_GPIO_COREBLK_LOWPWR EXYNOS_PMUREG(0x123C)
+#define EXYNOS4X12_PAD_ISOLATION_COREBLK_LOWPWR EXYNOS_PMUREG(0x1250)
+#define EXYNOS4X12_GPIO_MODE_COREBLK_LOWPWR EXYNOS_PMUREG(0x1320)
+#define EXYNOS4X12_TOP_ASB_RESET_LOWPWR EXYNOS_PMUREG(0x1344)
+#define EXYNOS4X12_TOP_ASB_ISOLATION_LOWPWR EXYNOS_PMUREG(0x1348)
+#define EXYNOS4X12_ISP_LOWPWR EXYNOS_PMUREG(0x1394)
+#define EXYNOS4X12_DRAM_FREQ_DOWN_LOWPWR EXYNOS_PMUREG(0x13B0)
+#define EXYNOS4X12_DDRPHY_DLLOFF_LOWPWR EXYNOS_PMUREG(0x13B4)
+#define EXYNOS4X12_CMU_SYSCLK_ISP_LOWPWR EXYNOS_PMUREG(0x13B8)
+#define EXYNOS4X12_CMU_SYSCLK_GPS_LOWPWR EXYNOS_PMUREG(0x13BC)
+#define EXYNOS4X12_LPDDR_PHY_DLL_LOCK_LOWPWR EXYNOS_PMUREG(0x13C0)
+
+#define EXYNOS4X12_ARM_L2_0_OPTION EXYNOS_PMUREG(0x2608)
+#define EXYNOS4X12_ARM_L2_1_OPTION EXYNOS_PMUREG(0x2628)
+#define EXYNOS4X12_ONENAND_MEM_OPTION EXYNOS_PMUREG(0x2E08)
+#define EXYNOS4X12_HSI_MEM_OPTION EXYNOS_PMUREG(0x2E28)
+#define EXYNOS4X12_G2D_ACP_MEM_OPTION EXYNOS_PMUREG(0x2E48)
+#define EXYNOS4X12_USBOTG_MEM_OPTION EXYNOS_PMUREG(0x2E68)
+#define EXYNOS4X12_HSMMC_MEM_OPTION EXYNOS_PMUREG(0x2E88)
+#define EXYNOS4X12_CSSYS_MEM_OPTION EXYNOS_PMUREG(0x2EA8)
+#define EXYNOS4X12_SECSS_MEM_OPTION EXYNOS_PMUREG(0x2EC8)
+#define EXYNOS4X12_ROTATOR_MEM_OPTION EXYNOS_PMUREG(0x2F48)
+
+/* Only for EXYNOS5250 */
+/* for EXYNOS_WAKEUP_MASK */
+#define EXYNOS5_MASK_RTC_ALARM BIT(1)
+#define EXYNOS5_MASK_RTC_TICK BIT(2)
+#define EXYNOS5_MASK_KEY BIT(5)
+#define EXYNOS5_MASK_HSI BIT(8)
+#define EXYNOS5_MASK_MMC0 BIT(9)
+#define EXYNOS5_MASK_MMC1 BIT(10)
+#define EXYNOS5_MASK_MMC2 BIT(11)
+#define EXYNOS5_MASK_MMC3 BIT(12)
+#define EXYNOS5_MASK_I2S BIT(13)
+#define EXYNOS5_MASK_TIMER BIT(14)
+#define EXYNOS5_MASK_CEC BIT(15)
+#define EXYNOS5_MASK_EXT_GIC0_IRQ BIT(16)
+#define EXYNOS5_MASK_EXT_GIC0_FIQ BIT(17)
+#define EXYNOS5_MASK_EXT_GIC1_IRQ BIT(18)
+#define EXYNOS5_MASK_EXT_GIC1_FIQ BIT(19)
+#define EXYNOS5_MASK_C2C_RESET_REQ BIT(20)
+#define EXYNOS5_DEFAULT_WAKEUP_MASK (EXYNOS5_MASK_EXT_GIC0_IRQ |\
+ EXYNOS5_MASK_EXT_GIC0_FIQ |\
+ EXYNOS5_MASK_EXT_GIC1_IRQ |\
+ EXYNOS5_MASK_EXT_GIC1_FIQ)
+
+#define EXYNOS5_AUTOMATIC_WDT_RESET_DISABLE EXYNOS_PMUREG(0x0408)
+#define EXYNOS5_MASK_WDT_RESET_REQUEST EXYNOS_PMUREG(0x040C)
+#define EXYNOS5_SYS_WDTRESET (1 << 20)
+
+#define EXYNOS5_USBDEV_PHY_CONTROL EXYNOS_PMUREG(0x0704)
+#define EXYNOS5_USBDEV_PHY_ENABLE (1 << 0)
+
+#define EXYNOS5_USBHOST_PHY_CONTROL EXYNOS_PMUREG(0x0708)
+#define EXYNOS5_USBHOST_PHY_ENABLE (1 << 0)
+
+#define EXYNOS5_ADC_PHY_CONTROL EXYNOS_PMUREG(0x0718)
+#define EXYNOS5_ADC_PHY_ENABLE (1 << 0)
+
+#define EXYNOS5250_DPTX_PHY_CONTROL EXYNOS_PMUREG(0x0720)
+#define EXYNOS5250_DPTX_PHY_ENABLE (1 << 0)
+
+#define EXYNOS5_ABB_INT EXYNOS_PMUREG(0x0780)
+#define EXYNOS5_ABB_ARM EXYNOS_PMUREG(0x0784)
+#define EXYNOS5_ABB_G3D EXYNOS_PMUREG(0x0788)
+#define EXYNOS5_ABB_MIF EXYNOS_PMUREG(0x078C)
+
+#define EXYNOS5_ARM_CORE0_SYS_PWR_REG EXYNOS_PMUREG(0x1000)
+#define EXYNOS5_DIS_IRQ_ARM_CORE0_LOCAL_SYS_PWR_REG EXYNOS_PMUREG(0x1004)
+#define EXYNOS5_DIS_IRQ_ARM_CORE0_CENTRAL_SYS_PWR_REG EXYNOS_PMUREG(0x1008)
+#define EXYNOS5_ARM_CORE1_SYS_PWR_REG EXYNOS_PMUREG(0x1010)
+#define EXYNOS5_DIS_IRQ_ARM_CORE1_LOCAL_SYS_PWR_REG EXYNOS_PMUREG(0x1014)
+#define EXYNOS5_DIS_IRQ_ARM_CORE1_CENTRAL_SYS_PWR_REG EXYNOS_PMUREG(0x1018)
+#define EXYNOS5_FSYS_ARM_SYS_PWR_REG EXYNOS_PMUREG(0x1040)
+#define EXYNOS5_DIS_IRQ_FSYS_ARM_CENTRAL_SYS_PWR_REG EXYNOS_PMUREG(0x1048)
+#define EXYNOS5_ISP_ARM_SYS_PWR_REG EXYNOS_PMUREG(0x1050)
+#define EXYNOS5_DIS_IRQ_ISP_ARM_LOCAL_SYS_PWR_REG EXYNOS_PMUREG(0x1054)
+#define EXYNOS5_DIS_IRQ_ISP_ARM_CENTRAL_SYS_PWR_REG EXYNOS_PMUREG(0x1058)
+#define EXYNOS5_ARM_COMMON_SYS_PWR_REG EXYNOS_PMUREG(0x1080)
+#define EXYNOS5_ARM_L2_SYS_PWR_REG EXYNOS_PMUREG(0x10C0)
+#define EXYNOS5_CMU_ACLKSTOP_SYS_PWR_REG EXYNOS_PMUREG(0x1100)
+#define EXYNOS5_CMU_SCLKSTOP_SYS_PWR_REG EXYNOS_PMUREG(0x1104)
+#define EXYNOS5_CMU_RESET_SYS_PWR_REG EXYNOS_PMUREG(0x110C)
+#define EXYNOS5_CMU_ACLKSTOP_SYSMEM_SYS_PWR_REG EXYNOS_PMUREG(0x1120)
+#define EXYNOS5_CMU_SCLKSTOP_SYSMEM_SYS_PWR_REG EXYNOS_PMUREG(0x1124)
+#define EXYNOS5_CMU_RESET_SYSMEM_SYS_PWR_REG EXYNOS_PMUREG(0x112C)
+#define EXYNOS5_DRAM_FREQ_DOWN_SYS_PWR_REG EXYNOS_PMUREG(0x1130)
+#define EXYNOS5_DDRPHY_DLLOFF_SYS_PWR_REG EXYNOS_PMUREG(0x1134)
+#define EXYNOS5_DDRPHY_DLLLOCK_SYS_PWR_REG EXYNOS_PMUREG(0x1138)
+#define EXYNOS5_APLL_SYSCLK_SYS_PWR_REG EXYNOS_PMUREG(0x1140)
+#define EXYNOS5_MPLL_SYSCLK_SYS_PWR_REG EXYNOS_PMUREG(0x1144)
+#define EXYNOS5_VPLL_SYSCLK_SYS_PWR_REG EXYNOS_PMUREG(0x1148)
+#define EXYNOS5_EPLL_SYSCLK_SYS_PWR_REG EXYNOS_PMUREG(0x114C)
+#define EXYNOS5_BPLL_SYSCLK_SYS_PWR_REG EXYNOS_PMUREG(0x1150)
+#define EXYNOS5_CPLL_SYSCLK_SYS_PWR_REG EXYNOS_PMUREG(0x1154)
+#define EXYNOS5_GPLL_SYSCLK_SYS_PWR_REG EXYNOS_PMUREG(0x1158)
+#define EXYNOS5_MPLLUSER_SYSCLK_SYS_PWR_REG EXYNOS_PMUREG(0x1164)
+#define EXYNOS5_BPLLUSER_SYSCLK_SYS_PWR_REG EXYNOS_PMUREG(0x1170)
+#define EXYNOS5_TOP_BUS_SYS_PWR_REG EXYNOS_PMUREG(0x1180)
+#define EXYNOS5_TOP_RETENTION_SYS_PWR_REG EXYNOS_PMUREG(0x1184)
+#define EXYNOS5_TOP_PWR_SYS_PWR_REG EXYNOS_PMUREG(0x1188)
+#define EXYNOS5_TOP_BUS_SYSMEM_SYS_PWR_REG EXYNOS_PMUREG(0x1190)
+#define EXYNOS5_TOP_RETENTION_SYSMEM_SYS_PWR_REG EXYNOS_PMUREG(0x1194)
+#define EXYNOS5_TOP_PWR_SYSMEM_SYS_PWR_REG EXYNOS_PMUREG(0x1198)
+#define EXYNOS5_LOGIC_RESET_SYS_PWR_REG EXYNOS_PMUREG(0x11A0)
+#define EXYNOS5_OSCCLK_GATE_SYS_PWR_REG EXYNOS_PMUREG(0x11A4)
+#define EXYNOS5_LOGIC_RESET_SYSMEM_SYS_PWR_REG EXYNOS_PMUREG(0x11B0)
+#define EXYNOS5_OSCCLK_GATE_SYSMEM_SYS_PWR_REG EXYNOS_PMUREG(0x11B4)
+#define EXYNOS5_USBOTG_MEM_SYS_PWR_REG EXYNOS_PMUREG(0x11C0)
+#define EXYNOS5_G2D_MEM_SYS_PWR_REG EXYNOS_PMUREG(0x11C8)
+#define EXYNOS5_USBDRD_MEM_SYS_PWR_REG EXYNOS_PMUREG(0x11CC)
+#define EXYNOS5_SDMMC_MEM_SYS_PWR_REG EXYNOS_PMUREG(0x11D0)
+#define EXYNOS5_CSSYS_MEM_SYS_PWR_REG EXYNOS_PMUREG(0x11D4)
+#define EXYNOS5_SECSS_MEM_SYS_PWR_REG EXYNOS_PMUREG(0x11D8)
+#define EXYNOS5_ROTATOR_MEM_SYS_PWR_REG EXYNOS_PMUREG(0x11DC)
+#define EXYNOS5_INTRAM_MEM_SYS_PWR_REG EXYNOS_PMUREG(0x11E0)
+#define EXYNOS5_INTROM_MEM_SYS_PWR_REG EXYNOS_PMUREG(0x11E4)
+#define EXYNOS5_JPEG_MEM_SYS_PWR_REG EXYNOS_PMUREG(0x11E8)
+#define EXYNOS5_HSI_MEM_SYS_PWR_REG EXYNOS_PMUREG(0x11EC)
+#define EXYNOS5_MCUIOP_MEM_SYS_PWR_REG EXYNOS_PMUREG(0x11F4)
+#define EXYNOS5_SATA_MEM_SYS_PWR_REG EXYNOS_PMUREG(0x11FC)
+#define EXYNOS5_PAD_RETENTION_DRAM_SYS_PWR_REG EXYNOS_PMUREG(0x1200)
+#define EXYNOS5_PAD_RETENTION_MAU_SYS_PWR_REG EXYNOS_PMUREG(0x1204)
+#define EXYNOS5_PAD_RETENTION_EFNAND_SYS_PWR_REG EXYNOS_PMUREG(0x1208)
+#define EXYNOS5_PAD_RETENTION_GPIO_SYS_PWR_REG EXYNOS_PMUREG(0x1220)
+#define EXYNOS5_PAD_RETENTION_UART_SYS_PWR_REG EXYNOS_PMUREG(0x1224)
+#define EXYNOS5_PAD_RETENTION_MMCA_SYS_PWR_REG EXYNOS_PMUREG(0x1228)
+#define EXYNOS5_PAD_RETENTION_MMCB_SYS_PWR_REG EXYNOS_PMUREG(0x122C)
+#define EXYNOS5_PAD_RETENTION_EBIA_SYS_PWR_REG EXYNOS_PMUREG(0x1230)
+#define EXYNOS5_PAD_RETENTION_EBIB_SYS_PWR_REG EXYNOS_PMUREG(0x1234)
+#define EXYNOS5_PAD_RETENTION_SPI_SYS_PWR_REG EXYNOS_PMUREG(0x1238)
+#define EXYNOS5_PAD_RETENTION_GPIO_SYSMEM_SYS_PWR_REG EXYNOS_PMUREG(0x123C)
+#define EXYNOS5_PAD_ISOLATION_SYS_PWR_REG EXYNOS_PMUREG(0x1240)
+#define EXYNOS5_PAD_ISOLATION_SYSMEM_SYS_PWR_REG EXYNOS_PMUREG(0x1250)
+#define EXYNOS5_PAD_ALV_SEL_SYS_PWR_REG EXYNOS_PMUREG(0x1260)
+#define EXYNOS5_XUSBXTI_SYS_PWR_REG EXYNOS_PMUREG(0x1280)
+#define EXYNOS5_XXTI_SYS_PWR_REG EXYNOS_PMUREG(0x1284)
+#define EXYNOS5_EXT_REGULATOR_SYS_PWR_REG EXYNOS_PMUREG(0x12C0)
+#define EXYNOS5_GPIO_MODE_SYS_PWR_REG EXYNOS_PMUREG(0x1300)
+#define EXYNOS5_GPIO_MODE_SYSMEM_SYS_PWR_REG EXYNOS_PMUREG(0x1320)
+#define EXYNOS5_GPIO_MODE_MAU_SYS_PWR_REG EXYNOS_PMUREG(0x1340)
+#define EXYNOS5_TOP_ASB_RESET_SYS_PWR_REG EXYNOS_PMUREG(0x1344)
+#define EXYNOS5_TOP_ASB_ISOLATION_SYS_PWR_REG EXYNOS_PMUREG(0x1348)
+#define EXYNOS5_GSCL_SYS_PWR_REG EXYNOS_PMUREG(0x1400)
+#define EXYNOS5_ISP_SYS_PWR_REG EXYNOS_PMUREG(0x1404)
+#define EXYNOS5_MFC_SYS_PWR_REG EXYNOS_PMUREG(0x1408)
+#define EXYNOS5_G3D_SYS_PWR_REG EXYNOS_PMUREG(0x140C)
+#define EXYNOS5_DISP1_SYS_PWR_REG EXYNOS_PMUREG(0x1414)
+#define EXYNOS5_MAU_SYS_PWR_REG EXYNOS_PMUREG(0x1418)
+#define EXYNOS5_CMU_CLKSTOP_GSCL_SYS_PWR_REG EXYNOS_PMUREG(0x1480)
+#define EXYNOS5_CMU_CLKSTOP_ISP_SYS_PWR_REG EXYNOS_PMUREG(0x1484)
+#define EXYNOS5_CMU_CLKSTOP_MFC_SYS_PWR_REG EXYNOS_PMUREG(0x1488)
+#define EXYNOS5_CMU_CLKSTOP_G3D_SYS_PWR_REG EXYNOS_PMUREG(0x148C)
+#define EXYNOS5_CMU_CLKSTOP_DISP1_SYS_PWR_REG EXYNOS_PMUREG(0x1494)
+#define EXYNOS5_CMU_CLKSTOP_MAU_SYS_PWR_REG EXYNOS_PMUREG(0x1498)
+#define EXYNOS5_CMU_SYSCLK_GSCL_SYS_PWR_REG EXYNOS_PMUREG(0x14C0)
+#define EXYNOS5_CMU_SYSCLK_ISP_SYS_PWR_REG EXYNOS_PMUREG(0x14C4)
+#define EXYNOS5_CMU_SYSCLK_MFC_SYS_PWR_REG EXYNOS_PMUREG(0x14C8)
+#define EXYNOS5_CMU_SYSCLK_G3D_SYS_PWR_REG EXYNOS_PMUREG(0x14CC)
+#define EXYNOS5_CMU_SYSCLK_DISP1_SYS_PWR_REG EXYNOS_PMUREG(0x14D4)
+#define EXYNOS5_CMU_SYSCLK_MAU_SYS_PWR_REG EXYNOS_PMUREG(0x14D8)
+#define EXYNOS5_CMU_RESET_GSCL_SYS_PWR_REG EXYNOS_PMUREG(0x1580)
+#define EXYNOS5_CMU_RESET_ISP_SYS_PWR_REG EXYNOS_PMUREG(0x1584)
+#define EXYNOS5_CMU_RESET_MFC_SYS_PWR_REG EXYNOS_PMUREG(0x1588)
+#define EXYNOS5_CMU_RESET_G3D_SYS_PWR_REG EXYNOS_PMUREG(0x158C)
+#define EXYNOS5_CMU_RESET_DISP1_SYS_PWR_REG EXYNOS_PMUREG(0x1594)
+#define EXYNOS5_CMU_RESET_MAU_SYS_PWR_REG EXYNOS_PMUREG(0x1598)
+
+#define EXYNOS5_ARM_CORE0_OPTION EXYNOS_PMUREG(0x2008)
+#define EXYNOS5_ARM_CORE1_OPTION EXYNOS_PMUREG(0x2088)
+#define EXYNOS5_FSYS_ARM_OPTION EXYNOS_PMUREG(0x2208)
+#define EXYNOS5_ISP_ARM_CONFIGURATION EXYNOS_PMUREG(0x2280)
+#define EXYNOS5_ISP_ARM_OPTION EXYNOS_PMUREG(0x2288)
+#define EXYNOS5_ARM_COMMON_OPTION EXYNOS_PMUREG(0x2408)
+#define EXYNOS5_ARM_L2_OPTION EXYNOS_PMUREG(0x2608)
+#define EXYNOS5_USE_RETENTION BIT(4)
+#define EXYNOS5_TOP_PWR_OPTION EXYNOS_PMUREG(0x2C48)
+#define EXYNOS5_TOP_PWR_SYSMEM_OPTION EXYNOS_PMUREG(0x2CC8)
+#define EXYNOS5_LOGIC_RESET_DURATION3 EXYNOS_PMUREG(0x2D1C)
+#define EXYNOS5_DUR_WAIT_RESET_MASK 0xFFFFF
+#define EXYNOS5_DUR_WAIT_RESET_MIN 0xF
+#define EXYNOS5_JPEG_MEM_OPTION EXYNOS_PMUREG(0x2F48)
+#define EXYNOS5_PAD_RETENTION_SPI_OPTION EXYNOS_PMUREG(0x31C8)
+#define EXYNOS5_PAD_RETENTION_GPIO_SYSMEM_OPTION EXYNOS_PMUREG(0x31E8)
+#define EXYNOS5_GSCL_CONFIGURATION EXYNOS_PMUREG(0x4000)
+#define EXYNOS5_GSCL_STATUS EXYNOS_PMUREG(0x4004)
+#define EXYNOS5_ISP_CONFIGURATION EXYNOS_PMUREG(0x4020)
+#define EXYNOS5_ISP_STATUS EXYNOS_PMUREG(0x4024)
+#define EXYNOS5_GSCL_OPTION EXYNOS_PMUREG(0x4008)
+#define EXYNOS5_ISP_OPTION EXYNOS_PMUREG(0x4028)
+#define EXYNOS5_MFC_CONFIGURATION EXYNOS_PMUREG(0x4040)
+#define EXYNOS5_MFC_OPTION EXYNOS_PMUREG(0x4048)
+#define EXYNOS5_G3D_CONFIGURATION EXYNOS_PMUREG(0x4060)
+#define EXYNOS5_G3D_STATUS EXYNOS_PMUREG(0x4064)
+#define EXYNOS5_G3D_OPTION EXYNOS_PMUREG(0x4068)
+#define EXYNOS5_DISP1_CONFIGURATION EXYNOS_PMUREG(0x40A0)
+#define EXYNOS5_DISP1_STATUS EXYNOS_PMUREG(0x40A4)
+#define EXYNOS5_DISP1_OPTION EXYNOS_PMUREG(0x40A8)
+#define EXYNOS5_MAU_CONFIGURATION EXYNOS_PMUREG(0x40C0)
+#define EXYNOS5_MAU_OPTION EXYNOS_PMUREG(0x40C8)
+#define EXYNOS5_LOCAL_POWER_STATE_SHIFT (16)
+#define EXYNOS5_LOCAL_POWER_STATE_MASK (0x3f)
+#define EXYNOS5_USE_SC_COUNTER (1 << 0)
+#define EXYNOS5_USE_SC_FEEDBACK (1 << 1)
+
+#define EXYNOS5_MANUAL_L2RSTDISABLE_CONTROL (1 << 2)
+#define EXYNOS5_SKIP_DEACTIVATE_ACEACP_IN_PWDN (1 << 7)
+
+#define EXYNOS5_OPTION_USE_STANDBYWFI (1 << 16)
+#define EXYNOS5_OPTION_USE_STANDBYWFE (1 << 24)
+
+#define EXYNOS5_OPTION_USE_RETENTION (1 << 4)
+
+/* For EXYNOS_CENTRAL_SEQ_OPTION */
+#define EXYNOS5_USE_STANDBYWFI_ARM_CORE0 (1 << 16)
+#define EXYNOS5_USE_STANDBYWFI_ARM_CORE1 (1 << 17)
+#define EXYNOS5_USE_STANDBYWFE_ARM_CORE0 (1 << 24)
+#define EXYNOS5_USE_STANDBYWFE_ARM_CORE1 (1 << 25)
#endif /* __ASM_ARCH_REGS_PMU_H */
diff --git a/arch/arm/mach-exynos/include/mach/regs-sysmmu.h b/arch/arm/mach-exynos/include/mach/regs-sysmmu.h
deleted file mode 100644
index 68ff6ad..0000000
--- a/arch/arm/mach-exynos/include/mach/regs-sysmmu.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/* linux/arch/arm/mach-exynos4/include/mach/regs-sysmmu.h
- *
- * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
- * http://www.samsung.com
- *
- * EXYNOS4 - System MMU register
- *
- * 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.
-*/
-
-#ifndef __ASM_ARCH_REGS_SYSMMU_H
-#define __ASM_ARCH_REGS_SYSMMU_H __FILE__
-
-#define S5P_MMU_CTRL 0x000
-#define S5P_MMU_CFG 0x004
-#define S5P_MMU_STATUS 0x008
-#define S5P_MMU_FLUSH 0x00C
-#define S5P_PT_BASE_ADDR 0x014
-#define S5P_INT_STATUS 0x018
-#define S5P_INT_CLEAR 0x01C
-#define S5P_PAGE_FAULT_ADDR 0x024
-#define S5P_AW_FAULT_ADDR 0x028
-#define S5P_AR_FAULT_ADDR 0x02C
-#define S5P_DEFAULT_SLAVE_ADDR 0x030
-
-#endif /* __ASM_ARCH_REGS_SYSMMU_H */
diff --git a/arch/arm/mach-exynos/include/mach/regs-tmu.h b/arch/arm/mach-exynos/include/mach/regs-tmu.h
new file mode 100644
index 0000000..fa288a8
--- /dev/null
+++ b/arch/arm/mach-exynos/include/mach/regs-tmu.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * EXYNOS - Thermal Management support
+ *
+ * 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.
+ */
+
+#ifndef __ASM_ARCH_REGS_THERMAL_H
+#define __ASM_ARCH_REGS_THERMAL_H __FILE__
+
+#define TRIMINFO (0x0)
+#define TRIMINFO_CON (0x14)
+
+#define TMU_CON (0x20)
+#define TMU_STATUS (0x28)
+#define SAMPLING_INTERNAL (0x2C)
+#define CNT_VALUE0 (0x30)
+#define CNT_VALUE1 (0x34)
+#define CURRENT_TEMP (0x40)
+
+#define THD_TEMP_RISE (0x50)
+#define THD_TEMP_FALL (0x54)
+
+#define PAST_TMEP0 (0x60)
+#define PAST_TMEP1 (0x64)
+#define PAST_TMEP2 (0x68)
+#define PAST_TMEP3 (0x6C)
+
+#define INTEN (0x70)
+#define INTSTAT (0x74)
+#define INTCLEAR (0x78)
+
+#define EMUL_CON (0x80)
+
+#define TRIMINFO_RELOAD (1)
+
+#define CORE_EN (1)
+#define TRIP_EN (1<<12)
+#define TRIP_ONLYCURRENT (0<<13)
+#define TRIP_CUR_PAST3_0 (4<<13)
+#define TRIP_CUR_PAST7_0 (5<<13)
+#define TRIP_CUR_PAST11_0 (6<<13)
+#define TRIP_CUR_PAST15_0 (7<<13)
+
+#define INTEN_RISE0 (1)
+#define INTEN_RISE1 (1<<4)
+#define INTEN_RISE2 (1<<8)
+#define INTEN_FALL0 (1<<16)
+#define INTEN_FALL1 (1<<20)
+#define INTEN_FALL2 (1<<24)
+
+#define INTSTAT_RISE0 (1)
+#define INTSTAT_RISE1 (1<<4)
+#define INTSTAT_RISE2 (1<<8)
+#define INTSTAT_FALL0 (1<<16)
+#define INTSTAT_FALL1 (1<<20)
+#define INTSTAT_FALL2 (1<<24)
+
+#define TRIM_INFO_MASK (0xFF)
+
+#define INTCLEAR_RISE0 (1)
+#define INTCLEAR_RISE1 (1<<4)
+#define INTCLEAR_RISE2 (1<<8)
+#define INTCLEAR_FALL0 (1<<16)
+#define INTCLEAR_FALL1 (1<<20)
+#define INTCLEAR_FALL2 (1<<24)
+#define CLEAR_RISE_INT (INTCLEAR_RISE0 | INTCLEAR_RISE1 | \
+ INTCLEAR_RISE2)
+#define CLEAR_FALL_INT (INTCLEAR_FALL0 | INTCLEAR_FALL1 | \
+ INTCLEAR_FALL2)
+#define EMUL_EN (1)
+
+#define FREQ_IN_PLL 24000000 /* 24MHz in Hz */
+#endif
diff --git a/arch/arm/mach-exynos/include/mach/regs-usb-phy.h b/arch/arm/mach-exynos/include/mach/regs-usb-phy.h
index c337cf3..c0392ab 100644
--- a/arch/arm/mach-exynos/include/mach/regs-usb-phy.h
+++ b/arch/arm/mach-exynos/include/mach/regs-usb-phy.h
@@ -61,4 +61,87 @@
#define EXYNOS4_PHY1CON EXYNOS4_HSOTG_PHYREG(0x34)
#define FPENABLEN (1 << 0)
+/* For Exynos5 */
+#define EXYNOS5_PHY_HOST_CTRL0 EXYNOS4_HSOTG_PHYREG(0x00)
+#define HOST_CTRL0_PHYSWRSTALL (0x1 << 31)
+#define HOST_CTRL0_REFCLKSEL(val) (val << 19)
+#define EXYNOS5_CLKSEL_50M (0x7)
+#define EXYNOS5_CLKSEL_24M (0x5)
+#define EXYNOS5_CLKSEL_20M (0x4)
+#define EXYNOS5_CLKSEL_19200K (0x3)
+#define EXYNOS5_CLKSEL_12M (0x2)
+#define EXYNOS5_CLKSEL_10M (0x1)
+#define EXYNOS5_CLKSEL_9600K (0x0)
+#define HOST_CTRL0_CLKSEL_SHIFT (16)
+#define HOST_CTRL0_FSEL_MASK (0x7 << 16)
+
+#define HOST_CTRL0_COMMONON_N (0x1 << 9)
+#define HOST_CTRL0_SIDDQ (0x1 << 6)
+#define HOST_CTRL0_FORCESLEEP (0x1 << 5)
+#define HOST_CTRL0_FORCESUSPEND (0x1 << 4)
+#define HOST_CTRL0_WORDINTERFACE (0x1 << 3)
+#define HOST_CTRL0_UTMISWRST (0x1 << 2)
+#define HOST_CTRL0_LINKSWRST (0x1 << 1)
+#define HOST_CTRL0_PHYSWRST (0x1 << 0)
+
+#define EXYNOS5_PHY_HOST_TUNE0 EXYNOS4_HSOTG_PHYREG(0x04)
+#define HOST_TUNE0_TXRESTUNE(val) ((val&0x3) << 24)
+#define HOST_TUNE0_TXPREEMPULSETUNE(val) ((val&0x1) << 23)
+#define HOST_TUNE0_TXPREEMPAMPTUNE(val) ((val&0x3) << 21)
+#define HOST_TUNE0_COMPDISTUNE(val) ((val&0x7) << 18)
+#define HOST_TUNE0_OTGTUNE(val) ((val&0x7) << 15)
+#define HOST_TUNE0_SQRXTUNE(val) ((val&0x7) << 12)
+#define HOST_TUNE0_TXFSLSTUNE(val) ((val&0xf) << 8)
+#define HOST_TUNE0_TXRISETUNE(val) ((val&0x3) << 6)
+#define HOST_TUNE0_TXHSXVTUNE(val) ((val&0x3) << 4)
+#define HOST_TUNE0_TXVREFTUNE(val) ((val&0xf) << 0)
+
+#define EXYNOS5_PHY_HOST_TEST0 EXYNOS4_HSOTG_PHYREG(0x08)
+
+#define EXYNOS5_PHY_HSIC_CTRL1 EXYNOS4_HSOTG_PHYREG(0x10)
+#define EXYNOS5_PHY_HSIC_CTRL2 EXYNOS4_HSOTG_PHYREG(0x20)
+#define HSIC_CTRL_REFCLKSEL(val) ((val&0x3) << 23)
+#define HSIC_CTRL_REFCLKDIV(val) ((val&0x7f) << 16)
+#define HSIC_CTRL_SIDDQ (0x1 << 6)
+#define HSIC_CTRL_FORCESLEEP (0x1 << 5)
+#define HSIC_CTRL_FORCESUSPEND (0x1 << 4)
+#define HSIC_CTRL_WORDINTERFACE (0x1 << 3)
+#define HSIC_CTRL_UTMISWRST (0x1 << 2)
+#define HSIC_CTRL_PHYSWRST (0x1 << 0)
+
+#define EXYNOS5_PHY_HOST_EHCICTRL EXYNOS4_HSOTG_PHYREG(0x30)
+#define EHCICTRL_ENAINCRXALIGN (0x1 << 29)
+#define EHCICTRL_ENAINCR4 (0x1 << 28)
+#define EHCICTRL_ENAINCR8 (0x1 << 27)
+#define EHCICTRL_ENAINCR16 (0x1 << 26)
+
+#define EXYNOS5_PHY_HOST_OHCICTRL EXYNOS4_HSOTG_PHYREG(0x34)
+
+#define EXYNOS5_PHY_OTG_SYS EXYNOS4_HSOTG_PHYREG(0x38)
+#define OTG_SYS_PHYLINK_SW_RESET (0x1 << 14)
+#define OTG_SYS_LINK_SW_RST_UOTG (0x1 << 13)
+#define OTG_SYS_PHY0_SW_RST (0x1 << 12)
+#define OTG_SYS_REF_CLK_SEL(val) ((val&0x3) << 9)
+#define OTG_SYS_REF_CLK_SEL_MASK (0x3 << 9)
+#define OTG_SYS_IP_PULLUP_UOTG (0x1 << 8)
+#define OTG_SYS_COMMON_ON (0x1 << 7)
+#define OTG_SYS_CLKSEL_SHIFT (4)
+#define OTG_SYS_CTRL0_FSEL_MASK (0x7 << 4)
+#define OTG_SYS_FORCE_SLEEP (0x1 << 3)
+#define OTG_SYS_OTGDISABLE (0x1 << 2)
+#define OTG_SYS_SIDDQ_UOTG (0x1 << 1)
+#define OTG_SYS_FORCE_SUSPEND (0x1 << 0)
+
+#define EXYNOS5_PHY_OTG_TUNE EXYNOS4_HSOTG_PHYREG(0x40)
+#define OTG_TUNE_TXRESTUNE(val) ((val&0x3) << 25)
+#define OTG_TUNE_TXRISETUNE(val) ((val&0x3) << 23)
+#define OTG_TUNE_TXPREEMPAMPTUNE(val) ((val&0x3) << 21)
+#define OTG_TUNE_TXPREEMPULSETUNE(val) ((val&0x1) << 20)
+#define OTG_TUNE_COMPDISTUNE(val) ((val&0x7) << 17)
+#define OTG_TUNE_OTGTUNE(val) ((val&0x7) << 14)
+#define OTG_TUNE_SQRXTUNE(val) ((val&0x7) << 11)
+#define OTG_TUNE_TXFSLSTUNE(val) ((val&0xf) << 7)
+#define OTG_TUNE_TXHSXVTUNE(val) ((val&0x3) << 4)
+#define OTG_TUNE_TXVREFTUNE(val) ((val&0xf) << 0)
+
#endif /* __PLAT_S5P_REGS_USB_PHY_H */
diff --git a/arch/arm/mach-exynos/include/mach/regs-usb3-exynos-drd-phy.h b/arch/arm/mach-exynos/include/mach/regs-usb3-exynos-drd-phy.h
new file mode 100644
index 0000000..50d2954
--- /dev/null
+++ b/arch/arm/mach-exynos/include/mach/regs-usb3-exynos-drd-phy.h
@@ -0,0 +1,75 @@
+/* arch/arm/plat-samsung/include/plat/regs-usb3-exynos-udc-drd.h
+ *
+ * Copyright (c) 2011 Samsung Electronics Co. Ltd
+ * Author: Anton Tikhomirov <av.tikhomirov@samsung.com>
+ *
+ * Exynos SuperSpeed USB 3.0 DRD Controller PHY registers
+ *
+ * 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.
+*/
+
+#ifndef __PLAT_SAMSUNG_REGS_USB3_EXYNOS_DRD_PHY_H
+#define __PLAT_SAMSUNG_REGS_USB3_EXYNOS_DRD_PHY_H __FILE__
+
+#define EXYNOS_USB3_PHYREG(x) ((x) + S5P_VA_SS_PHY)
+
+
+#define EXYNOS_USB3_LINKSYSTEM EXYNOS_USB3_PHYREG(0x04)
+#define EXYNOS_USB3_PHYUTMI EXYNOS_USB3_PHYREG(0x08)
+
+#define EXYNOS_USB3_PHYUTMI_OTGDISABLE (1 << 6)
+#define EXYNOS_USB3_PHYUTMI_FORCESUSPEND (1 << 1)
+#define EXYNOS_USB3_PHYUTMI_FORCESLEEP (1 << 0)
+
+#define EXYNOS_USB3_PHYPIPE EXYNOS_USB3_PHYREG(0x0C)
+
+
+#define EXYNOS_USB3_PHYCLKRST EXYNOS_USB3_PHYREG(0x10)
+
+#define EXYNOS_USB3_PHYCLKRST_SSC_REF_CLK_SEL_MASK (0xff << 23)
+#define EXYNOS_USB3_PHYCLKRST_SSC_REF_CLK_SEL_SHIFT (23)
+#define EXYNOS_USB3_PHYCLKRST_SSC_REF_CLK_SEL_LIMIT (0xff)
+#define EXYNOS_USB3_PHYCLKRST_SSC_REF_CLK_SEL(_x) ((_x) << 23)
+
+#define EXYNOS_USB3_PHYCLKRST_SSC_RANGE_MASK (0x03 << 21)
+#define EXYNOS_USB3_PHYCLKRST_SSC_RANGE_SHIFT (21)
+#define EXYNOS_USB3_PHYCLKRST_SSC_RANGE_LIMIT (0x03)
+#define EXYNOS_USB3_PHYCLKRST_SSC_RANGE(_x) ((_x) << 21)
+
+#define EXYNOS_USB3_PHYCLKRST_SSC_EN (1 << 20)
+#define EXYNOS_USB3_PHYCLKRST_REF_SSP_EN (1 << 19)
+#define EXYNOS_USB3_PHYCLKRST_REF_CLKDIV2 (1 << 18)
+
+#define EXYNOS_USB3_PHYCLKRST_MPLL_MULTIPLIER_MASK (0x7f << 11)
+#define EXYNOS_USB3_PHYCLKRST_MPLL_MULTIPLIER_SHIFT (11)
+#define EXYNOS_USB3_PHYCLKRST_MPLL_MULTIPLIER_LIMIT (0x7f)
+#define EXYNOS_USB3_PHYCLKRST_MPLL_MULTIPLIER(_x) ((_x) << 11)
+
+#define EXYNOS_USB3_PHYCLKRST_FSEL_MASK (0x3f << 5)
+#define EXYNOS_USB3_PHYCLKRST_FSEL_SHIFT (5)
+#define EXYNOS_USB3_PHYCLKRST_FSEL_LIMIT (0x3f)
+#define EXYNOS_USB3_PHYCLKRST_FSEL(_x) ((_x) << 5)
+
+#define EXYNOS_USB3_PHYCLKRST_RETENABLEN (1 << 4)
+
+#define EXYNOS_USB3_PHYCLKRST_REFCLKSEL_MASK (0x03 << 2)
+#define EXYNOS_USB3_PHYCLKRST_REFCLKSEL_SHIFT (2)
+#define EXYNOS_USB3_PHYCLKRST_REFCLKSEL_LIMIT (0x03)
+#define EXYNOS_USB3_PHYCLKRST_REFCLKSEL(_x) ((_x) << 2)
+
+#define EXYNOS_USB3_PHYCLKRST_PORTRESET (1 << 1)
+#define EXYNOS_USB3_PHYCLKRST_COMMONONN (1 << 0)
+
+#define EXYNOS_USB3_PHYREG0 EXYNOS_USB3_PHYREG(0x14)
+#define EXYNOS_USB3_PHYREG1 EXYNOS_USB3_PHYREG(0x18)
+#define EXYNOS_USB3_PHYPARAM0 EXYNOS_USB3_PHYREG(0x1C)
+#define EXYNOS_USB3_PHYPARAM1 EXYNOS_USB3_PHYREG(0x20)
+#define EXYNOS_USB3_PHYTERM EXYNOS_USB3_PHYREG(0x24)
+#define EXYNOS_USB3_PHYTEST EXYNOS_USB3_PHYREG(0x28)
+#define EXYNOS_USB3_PHYADP EXYNOS_USB3_PHYREG(0x2C)
+#define EXYNOS_USB3_PHYBATCHG EXYNOS_USB3_PHYREG(0x30)
+#define EXYNOS_USB3_PHYRESUME EXYNOS_USB3_PHYREG(0x34)
+#define EXYNOS_USB3_LINKPORT EXYNOS_USB3_PHYREG(0x44)
+#endif /* __PLAT_SAMSUNG_REGS_USB3_EXYNOS_DRD_PHY_H */
diff --git a/arch/arm/mach-exynos/include/mach/regs-usb3-exynos-drd.h b/arch/arm/mach-exynos/include/mach/regs-usb3-exynos-drd.h
new file mode 100644
index 0000000..9ca5f49f
--- /dev/null
+++ b/arch/arm/mach-exynos/include/mach/regs-usb3-exynos-drd.h
@@ -0,0 +1,806 @@
+/* arch/arm/plat-samsung/include/plat/regs-usb3-exynos-drd.h
+ *
+ * Copyright (c) 2011 Samsung Electronics Co. Ltd
+ * Author: Anton Tikhomirov <av.tikhomirov@samsung.com>
+ *
+ * Exynos SuperSpeed USB 3.0 DRD Controller registers
+ *
+ * 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.
+ */
+
+#ifndef __SAMSUNG_PLAT_REGS_USB3_EXYNOS_DRD_H
+#define __SAMSUNG_PLAT_REGS_USB3_EXYNOS_DRD_H __FILE__
+
+#define EXYNOS_USB3_REG(x) (x)
+
+/* xHCI registers */
+
+/* Global registers */
+#define EXYNOS_USB3_GSBUSCFG0 EXYNOS_USB3_REG(0xC100)
+#define EXYNOS_USB3_GSBUSCFG0_SBusStoreAndForward (1 << 12)
+#define EXYNOS_USB3_GSBUSCFG0_DatBigEnd (1 << 11)
+#define EXYNOS_USB3_GSBUSCFG0_INCR256BrstEna (1 << 7)
+#define EXYNOS_USB3_GSBUSCFG0_INCR128BrstEna (1 << 6)
+#define EXYNOS_USB3_GSBUSCFG0_INCR64BrstEna (1 << 5)
+#define EXYNOS_USB3_GSBUSCFG0_INCR32BrstEna (1 << 4)
+#define EXYNOS_USB3_GSBUSCFG0_INCR16BrstEna (1 << 3)
+#define EXYNOS_USB3_GSBUSCFG0_INCR8BrstEna (1 << 2)
+#define EXYNOS_USB3_GSBUSCFG0_INCR4BrstEna (1 << 1)
+#define EXYNOS_USB3_GSBUSCFG0_INCRBrstEna (1 << 0)
+
+
+#define EXYNOS_USB3_GSBUSCFG1 EXYNOS_USB3_REG(0xC104)
+#define EXYNOS_USB3_GSBUSCFG1_EN1KPAGE (1 << 12)
+
+#define EXYNOS_USB3_GSBUSCFG1_BREQLIMIT_MASK (0xf << 8)
+#define EXYNOS_USB3_GSBUSCFG1_BREQLIMIT_SHIFT (8)
+#define EXYNOS_USB3_GSBUSCFG1_BREQLIMIT_LIMIT (0xf)
+#define EXYNOS_USB3_GSBUSCFG1_BREQLIMIT(_x) ((_x) << 8)
+
+
+#define EXYNOS_USB3_GTXTHRCFG EXYNOS_USB3_REG(0xC108)
+#define EXYNOS_USB3_GTXTHRCFG_USBTxPktCntSel (1 << 29)
+
+#define EXYNOS_USB3_GTXTHRCFG_USBTxPktCnt_MASK (0xf << 24)
+#define EXYNOS_USB3_GTXTHRCFG_USBTxPktCnt_SHIFT (24)
+#define EXYNOS_USB3_GTXTHRCFG_USBTxPktCnt_LIMIT (0xf)
+#define EXYNOS_USB3_GTXTHRCFG_USBTxPktCnt(_x) ((_x) << 24)
+
+#define EXYNOS_USB3_GTXTHRCFG_USBMaxTxBurstSize_MASK (0xff << 16)
+#define EXYNOS_USB3_GTXTHRCFG_USBMaxTxBurstSize_SHIFT (16)
+#define EXYNOS_USB3_GTXTHRCFG_USBMaxTxBurstSize_LIMIT (0xff)
+#define EXYNOS_USB3_GTXTHRCFG_USBMaxTxBurstSize(_x) ((_x) << 16)
+
+
+#define EXYNOS_USB3_GRXTHRCFG EXYNOS_USB3_REG(0xC10C)
+#define EXYNOS_USB3_GRXTHRCFG_USBRxPktCntSel (1 << 29)
+
+#define EXYNOS_USB3_GRXTHRCFG_USBRxPktCnt_MASK (0xf << 24)
+#define EXYNOS_USB3_GRXTHRCFG_USBRxPktCnt_SHIFT (24)
+#define EXYNOS_USB3_GRXTHRCFG_USBRxPktCnt_LIMIT (0xf)
+#define EXYNOS_USB3_GRXTHRCFG_USBRxPktCnt(_x) ((_x) << 24)
+
+#define EXYNOS_USB3_GRXTHRCFG_USBMaxRxBurstSize_MASK (0x1f << 19)
+#define EXYNOS_USB3_GRXTHRCFG_USBMaxRxBurstSize_SHIFT (19)
+#define EXYNOS_USB3_GRXTHRCFG_USBMaxRxBurstSize_LIMIT (0x1f)
+#define EXYNOS_USB3_GRXTHRCFG_USBMaxRxBurstSize(_x) ((_x) << 19)
+
+
+#define EXYNOS_USB3_GCTL EXYNOS_USB3_REG(0xC110)
+
+#define EXYNOS_USB3_GCTL_PwrDnScale_MASK (0x1fff << 19)
+#define EXYNOS_USB3_GCTL_PwrDnScale_SHIFT (19)
+#define EXYNOS_USB3_GCTL_PwrDnScale_LIMIT (0x1fff)
+#define EXYNOS_USB3_GCTL_PwrDnScale(_x) ((_x) << 19)
+
+#define EXYNOS_USB3_GCTL_U2RSTECN (1 << 16)
+
+#define EXYNOS_USB3_GCTL_FRMSCLDWN_MASK (0x3 << 14)
+#define EXYNOS_USB3_GCTL_FRMSCLDWN_SHIFT (14)
+#define EXYNOS_USB3_GCTL_FRMSCLDWN_LIMIT (0x3)
+#define EXYNOS_USB3_GCTL_FRMSCLDWN(_x) ((_x) << 14)
+
+#define EXYNOS_USB3_GCTL_PrtCapDir_MASK (0x3 << 12)
+#define EXYNOS_USB3_GCTL_PrtCapDir_SHIFT (12)
+#define EXYNOS_USB3_GCTL_PrtCapDir_LIMIT (0x3)
+#define EXYNOS_USB3_GCTL_PrtCapDir(_x) ((_x) << 12)
+
+#define EXYNOS_USB3_GCTL_CoreSoftReset (1 << 11)
+#define EXYNOS_USB3_GCTL_LocalLpBkEn (1 << 10)
+#define EXYNOS_USB3_GCTL_LpbkEn (1 << 9)
+#define EXYNOS_USB3_GCTL_DebugAttach (1 << 8)
+
+#define EXYNOS_USB3_GCTL_RAMClkSel_MASK (0x3 << 6)
+#define EXYNOS_USB3_GCTL_RAMClkSel_SHIFT (6)
+#define EXYNOS_USB3_GCTL_RAMClkSel_LIMIT (0x3)
+#define EXYNOS_USB3_GCTL_RAMClkSel(_x) ((_x) << 6)
+
+#define EXYNOS_USB3_GCTL_ScaleDown_MASK (0x3 << 4)
+#define EXYNOS_USB3_GCTL_ScaleDown_SHIFT (4)
+#define EXYNOS_USB3_GCTL_ScaleDown_LIMIT (0x3)
+#define EXYNOS_USB3_GCTL_ScaleDown(_x) ((_x) << 4)
+
+#define EXYNOS_USB3_GCTL_DisScramble (1 << 3)
+#define EXYNOS_USB3_GCTL_SsPwrClmp (1 << 2)
+#define EXYNOS_USB3_GCTL_HsFsLsPwrClmp (1 << 1)
+#define EXYNOS_USB3_GCTL_DsblClkGtng (1 << 0)
+
+
+#define EXYNOS_USB3_GEVTEN EXYNOS_USB3_REG(0xC114)
+#define EXYNOS_USB3_GEVTEN_I2CEvtEn (1 << 1)
+#define EXYNOS_USB3_GEVTEN_ULPICKEvtEn (1 << 0)
+#define EXYNOS_USB3_GEVTEN_I2CCKEvtEn (1 << 0)
+
+
+#define EXYNOS_USB3_GSTS EXYNOS_USB3_REG(0xC118)
+
+#define EXYNOS_USB3_GSTS_CBELT_MASK (0xfff << 20)
+#define EXYNOS_USB3_GSTS_CBELT_SHIFT (20)
+#define EXYNOS_USB3_GSTS_CBELT_LIMIT (0xfff)
+#define EXYNOS_USB3_GSTS_CBELT(_x) ((_x) << 20)
+
+#define EXYNOS_USB3_GSTS_OTG_IP (1 << 10)
+#define EXYNOS_USB3_GSTS_BC_IP (1 << 9)
+#define EXYNOS_USB3_GSTS_ADP_IP (1 << 8)
+#define EXYNOS_USB3_GSTS_Host_IP (1 << 7)
+#define EXYNOS_USB3_GSTS_Device_IP (1 << 6)
+#define EXYNOS_USB3_GSTS_CSRTimeout (1 << 5)
+#define EXYNOS_USB3_GSTS_BusErrAddrVld (1 << 4)
+
+#define EXYNOS_USB3_GSTS_CurMod_MASK (0x3 << 0)
+#define EXYNOS_USB3_GSTS_CurMod_SHIFT (0)
+#define EXYNOS_USB3_GSTS_CurMod_LIMIT (0x3)
+#define EXYNOS_USB3_GSTS_CurMod(_x) ((_x) << 0)
+
+
+#define EXYNOS_USB3_GSNPSID EXYNOS_USB3_REG(0xC120)
+
+
+#define EXYNOS_USB3_GGPIO EXYNOS_USB3_REG(0xC124)
+
+#define EXYNOS_USB3_GGPIO_GPO_MASK (0xffff << 16)
+#define EXYNOS_USB3_GGPIO_GPO_SHIFT (16)
+#define EXYNOS_USB3_GGPIO_GPO_LIMIT (0xffff)
+#define EXYNOS_USB3_GGPIO_GPO(_x) ((_x) << 16)
+
+#define EXYNOS_USB3_GGPIO_GPI_MASK (0xffff << 0)
+#define EXYNOS_USB3_GGPIO_GPI_SHIFT (0)
+#define EXYNOS_USB3_GGPIO_GPI_LIMIT (0xffff)
+#define EXYNOS_USB3_GGPIO_GPI(_x) ((x) << 0)
+
+
+#define EXYNOS_USB3_GUID EXYNOS_USB3_REG(0xC128)
+
+
+#define EXYNOS_USB3_GUCTL EXYNOS_USB3_REG(0xC12C)
+#define EXYNOS_USB3_GUCTL_SprsCtrlTransEn (1 << 17)
+#define EXYNOS_USB3_GUCTL_ResBwHSEPS (1 << 16)
+#define EXYNOS_USB3_GUCTL_CMdevAddr (1 << 15)
+#define EXYNOS_USB3_GUCTL_USBHstInAutoRetryEn (1 << 14)
+
+#define EXYNOS_USB3_GUCTL_USBHstInMaxBurst_MASK (0x7 << 11)
+#define EXYNOS_USB3_GUCTL_USBHstInMaxBurst_SHIFT (11)
+#define EXYNOS_USB3_GUCTL_USBHstInMaxBurst_LIMIT (0x7)
+#define EXYNOS_USB3_GUCTL_USBHstInMaxBurst(_x) ((_x) << 11)
+
+#define EXYNOS_USB3_GUCTL_DTCT_MASK (0x3 << 9)
+#define EXYNOS_USB3_GUCTL_DTCT_SHIFT (9)
+#define EXYNOS_USB3_GUCTL_DTCT_LIMIT (0x3)
+#define EXYNOS_USB3_GUCTL_DTCT(_x) ((_x) << 9)
+
+#define EXYNOS_USB3_GUCTL_DTFT_MASK (0x1ff << 0)
+#define EXYNOS_USB3_GUCTL_DTFT_SHIFT (0)
+#define EXYNOS_USB3_GUCTL_DTFT_LIMIT (0x1ff)
+#define EXYNOS_USB3_GUCTL_DTFT(_x) ((_x) << 0)
+
+/* TODO: Not finished */
+#define EXYNOS_USB3_GBUSERRADDR_31_0 EXYNOS_USB3_REG(0xC130)
+#define EXYNOS_USB3_GBUSERRADDR_63_32 EXYNOS_USB3_REG(0xC134)
+#define EXYNOS_USB3_GPRTBIMAP_31_0 EXYNOS_USB3_REG(0xC138)
+#define EXYNOS_USB3_GPRTBIMAP_63_32 EXYNOS_USB3_REG(0xC13C)
+
+#define EXYNOS_USB3_GHWPARAMS0 EXYNOS_USB3_REG(0xC140)
+#define EXYNOS_USB3_GHWPARAMS1 EXYNOS_USB3_REG(0xC144)
+#define EXYNOS_USB3_GHWPARAMS2 EXYNOS_USB3_REG(0xC148)
+#define EXYNOS_USB3_GHWPARAMS3 EXYNOS_USB3_REG(0xC14C)
+#define EXYNOS_USB3_GHWPARAMS4 EXYNOS_USB3_REG(0xC150)
+#define EXYNOS_USB3_GHWPARAMS5 EXYNOS_USB3_REG(0xC154)
+#define EXYNOS_USB3_GHWPARAMS6 EXYNOS_USB3_REG(0xC158)
+#define EXYNOS_USB3_GHWPARAMS7 EXYNOS_USB3_REG(0xC15C)
+
+#define EXYNOS_USB3_GDBGFIFOSPACE EXYNOS_USB3_REG(0xC160)
+#define EXYNOS_USB3_GDBGLTSSM EXYNOS_USB3_REG(0xC164)
+
+#define EXYNOS_USB3_GDBGLSPMUX EXYNOS_USB3_REG(0xC170)
+#define EXYNOS_USB3_GDBGLSP EXYNOS_USB3_REG(0xC174)
+#define EXYNOS_USB3_GDBGEPINFO0 EXYNOS_USB3_REG(0xC178)
+#define EXYNOS_USB3_GDBGEPINFO1 EXYNOS_USB3_REG(0xC17C)
+
+#define EXYNOS_USB3_GPRTBIMAP_HS_31_0 EXYNOS_USB3_REG(0xC180)
+#define EXYNOS_USB3_GPRTBIMAP_HS_63_32 EXYNOS_USB3_REG(0xC184)
+#define EXYNOS_USB3_GPRTBIMAP_FS_31_0 EXYNOS_USB3_REG(0xC188)
+#define EXYNOS_USB3_GPRTBIMAP_FS_63_32 EXYNOS_USB3_REG(0xC18C)
+/****************/
+
+#define EXYNOS_USB3_GUSB2PHYCFG(_a) EXYNOS_USB3_REG(0xC200 + ((_a) * 0x04))
+#define EXYNOS_USB3_GUSB2PHYCFGx_PHYSoftRst (1 << 31)
+
+#define EXYNOS_USB3_GUSB2PHYCFGx_PhyIntrNum_MASK (0x3f << 19)
+#define EXYNOS_USB3_GUSB2PHYCFGx_PhyIntrNum_SHIFT (19)
+#define EXYNOS_USB3_GUSB2PHYCFGx_PhyIntrNum_LIMIT (0x3f)
+#define EXYNOS_USB3_GUSB2PHYCFGx_PhyIntrNum(_x) ((_x) << 19)
+
+#define EXYNOS_USB3_GUSB2PHYCFGx_ULPIExtVbusIndicator (1 << 18)
+#define EXYNOS_USB3_GUSB2PHYCFGx_ULPIExtVbusDrv (1 << 17)
+#define EXYNOS_USB3_GUSB2PHYCFGx_ULPIClkSusM (1 << 16)
+#define EXYNOS_USB3_GUSB2PHYCFGx_ULPIAutoRes (1 << 15)
+#define EXYNOS_USB3_GUSB2PHYCFGx_PhyLPwrClkSel (1 << 14)
+
+#define EXYNOS_USB3_GUSB2PHYCFGx_USBTrdTim_MASK (0xf << 10)
+#define EXYNOS_USB3_GUSB2PHYCFGx_USBTrdTim_SHIFT (10)
+#define EXYNOS_USB3_GUSB2PHYCFGx_USBTrdTim_LIMIT (0xf)
+#define EXYNOS_USB3_GUSB2PHYCFGx_USBTrdTim(_x) ((_x) << 10)
+
+#define EXYNOS_USB3_GUSB2PHYCFGx_EnblSlpM (1 << 8)
+#define EXYNOS_USB3_GUSB2PHYCFGx_PHYSel (1 << 7)
+#define EXYNOS_USB3_GUSB2PHYCFGx_SusPHY (1 << 6)
+#define EXYNOS_USB3_GUSB2PHYCFGx_FSIntf (1 << 5)
+#define EXYNOS_USB3_GUSB2PHYCFGx_ULPI_UTMI_Sel (1 << 4)
+#define EXYNOS_USB3_GUSB2PHYCFGx_PHYIf (1 << 3)
+
+#define EXYNOS_USB3_GUSB2PHYCFGx_TOutCal_MASK (0x7 << 0)
+#define EXYNOS_USB3_GUSB2PHYCFGx_TOutCal_SHIFT (0)
+#define EXYNOS_USB3_GUSB2PHYCFGx_TOutCal_LIMIT (0x7)
+#define EXYNOS_USB3_GUSB2PHYCFGx_TOutCal(_x) ((_x) << 0)
+
+
+/* Reserved for future use */
+#define EXYNOS_USB3_GUSB2I2CCTL(_a) EXYNOS_USB3_REG(0xC240 + ((_a) * 0x04))
+
+
+#define EXYNOS_USB3_GUSB2PHYACC(_a) EXYNOS_USB3_REG(0xC280 + ((_a) * 0x04))
+#define EXYNOS_USB3_GUSB2PHYACCx_DisUlpiDrvr (1 << 26)
+#define EXYNOS_USB3_GUSB2PHYACCx_NewRegReq (1 << 25)
+#define EXYNOS_USB3_GUSB2PHYACCx_VStsDone (1 << 24)
+#define EXYNOS_USB3_GUSB2PHYACCx_VStsBsy (1 << 23)
+#define EXYNOS_USB3_GUSB2PHYACCx_RegWr (1 << 22)
+
+#define EXYNOS_USB3_GUSB2PHYACCx_RegAddr_MASK (0x3f << 16)
+#define EXYNOS_USB3_GUSB2PHYACCx_RegAddr_SHIFT (16)
+#define EXYNOS_USB3_GUSB2PHYACCx_RegAddr_LIMIT (0x3f)
+#define EXYNOS_USB3_GUSB2PHYACCx_RegAddr(_x) ((_x) << 16)
+
+/* Next 2 fields are overlaping. Is it error in user manual? */
+#define EXYNOS_USB3_GUSB2PHYACCx_VCtrl_MASK (0xff << 8)
+#define EXYNOS_USB3_GUSB2PHYACCx_VCtrl_SHIFT (8)
+#define EXYNOS_USB3_GUSB2PHYACCx_VCtrl_LIMIT (0xff)
+#define EXYNOS_USB3_GUSB2PHYACCx_VCtrl(_x) ((_x) << 8)
+
+#define EXYNOS_USB3_GUSB2PHYACCx_ExtRegAddr_MASK (0x3f << 8)
+#define EXYNOS_USB3_GUSB2PHYACCx_ExtRegAddr_SHIFT (8)
+#define EXYNOS_USB3_GUSB2PHYACCx_ExtRegAddr_LIMIT (0x3f)
+#define EXYNOS_USB3_GUSB2PHYACCx_ExtRegAddr(_x) ((_x) << 8)
+
+#define EXYNOS_USB3_GUSB2PHYACCx_RegData_MASK (0xff << 0)
+#define EXYNOS_USB3_GUSB2PHYACCx_RegData_SHIFT (0)
+#define EXYNOS_USB3_GUSB2PHYACCx_RegData_LIMIT (0xff)
+#define EXYNOS_USB3_GUSB2PHYACCx_RegData(_x) ((_x) << 0)
+
+
+#define EXYNOS_USB3_GUSB3PIPECTL(_a) EXYNOS_USB3_REG(0xC2C0 + ((_a) * 0x04))
+#define EXYNOS_USB3_GUSB3PIPECTLx_PHYSoftRst (1 << 31)
+#define EXYNOS_USB3_GUSB3PIPECTLx_request_p1p2p3 (1 << 24)
+#define EXYNOS_USB3_GUSB3PIPECTLx_StartRxdetU3RxDet (1 << 23)
+#define EXYNOS_USB3_GUSB3PIPECTLx_DisRxDetU3RxDet (1 << 22)
+
+#define EXYNOS_USB3_GUSB3PIPECTLx_delay_p1p2p3_MASK (0x7 << 19)
+#define EXYNOS_USB3_GUSB3PIPECTLx_delay_p1p2p3_SHIFT (19)
+#define EXYNOS_USB3_GUSB3PIPECTLx_delay_p1p2p3_LIMIT (0x7)
+#define EXYNOS_USB3_GUSB3PIPECTLx_delay_p1p2p3(_x) ((_x) << 19)
+
+/* TODO: Check naming for the next 2 fields */
+#define EXYNOS_USB3_GUSB3PIPECTLx_delay_phy_pwr_p1p2p3 (1 << 18)
+#define EXYNOS_USB3_GUSB3PIPECTLx_SuspSSPhy (1 << 17)
+
+#define EXYNOS_USB3_GUSB3PIPECTLx_DatWidth_MASK (0x3 << 15)
+#define EXYNOS_USB3_GUSB3PIPECTLx_DatWidth_SHIFT (15)
+#define EXYNOS_USB3_GUSB3PIPECTLx_DatWidth_LIMIT (0x3)
+#define EXYNOS_USB3_GUSB3PIPECTLx_DatWidth(_x) ((_x) << 15)
+
+#define EXYNOS_USB3_GUSB3PIPECTLx_AbortRxDetInU2 (1 << 14)
+#define EXYNOS_USB3_GUSB3PIPECTLx_SkipRxDet (1 << 13)
+#define EXYNOS_USB3_GUSB3PIPECTLx_LFPSP0Algn (1 << 12)
+#define EXYNOS_USB3_GUSB3PIPECTLx_P3P2TranOK (1 << 11)
+#define EXYNOS_USB3_GUSB3PIPECTLx_LFPSFilt (1 << 9)
+#define EXYNOS_USB3_GUSB3PIPECTLx_TxSwing (1 << 6)
+
+#define EXYNOS_USB3_GUSB3PIPECTLx_TxMargin_MASK (0x7 << 3)
+#define EXYNOS_USB3_GUSB3PIPECTLx_TxMargin_SHIFT (3)
+#define EXYNOS_USB3_GUSB3PIPECTLx_TxMargin_LIMIT (0x7)
+#define EXYNOS_USB3_GUSB3PIPECTLx_TxMargin(_x) ((_x) << 3)
+
+#define EXYNOS_USB3_GUSB3PIPECTLx_TxDeemphasis_MASK (0x3 << 1)
+#define EXYNOS_USB3_GUSB3PIPECTLx_TxDeemphasis_SHIFT (1)
+#define EXYNOS_USB3_GUSB3PIPECTLx_TxDeemphasis_LIMIT (0x3)
+#define EXYNOS_USB3_GUSB3PIPECTLx_TxDeemphasis(_x) ((_x) << 1)
+
+#define EXYNOS_USB3_GUSB3PIPECTLx_ElasticBufferMode (1 << 0)
+
+
+#define EXYNOS_USB3_GTXFIFOSIZ(_a) EXYNOS_USB3_REG(0xC300 + ((_a) * 0x04))
+
+#define EXYNOS_USB3_GTXFIFOSIZx_TxFStAddr_n_MASK (0xffff << 16)
+#define EXYNOS_USB3_GTXFIFOSIZx_TxFStAddr_n_SHIFT (16)
+#define EXYNOS_USB3_GTXFIFOSIZx_TxFStAddr_n_LIMIT (0xffff)
+#define EXYNOS_USB3_GTXFIFOSIZx_TxFStAddr_n(_x) ((_x) << 16)
+
+#define EXYNOS_USB3_GTXFIFOSIZx_TxFDep_n_MASK (0xffff << 0)
+#define EXYNOS_USB3_GTXFIFOSIZx_TxFDep_n_SHIFT (0)
+#define EXYNOS_USB3_GTXFIFOSIZx_TxFDep_n_LIMIT (0xffff)
+#define EXYNOS_USB3_GTXFIFOSIZx_TxFDep_n(_x) ((_x) << 0)
+
+
+#define EXYNOS_USB3_GRXFIFOSIZ(_a) EXYNOS_USB3_REG(0xC380 + ((_a) * 0x04))
+
+#define EXYNOS_USB3_GRXFIFOSIZx_RxFStAddr_n_MASK (0xffff << 16)
+#define EXYNOS_USB3_GRXFIFOSIZx_RxFStAddr_n_SHIFT (16)
+#define EXYNOS_USB3_GRXFIFOSIZx_RxFStAddr_n_LIMIT (0xffff)
+#define EXYNOS_USB3_GRXFIFOSIZx_RxFStAddr_n(_x) ((_x) << 16)
+
+#define EXYNOS_USB3_GRXFIFOSIZx_RxFDep_n_MASK (0xffff << 0)
+#define EXYNOS_USB3_GRXFIFOSIZx_RxFDep_n_SHIFT (0)
+#define EXYNOS_USB3_GRXFIFOSIZx_RxFDep_n_LIMIT (0xffff)
+#define EXYNOS_USB3_GRXFIFOSIZx_RxFDep_n(_x) ((_x) << 0)
+
+
+#define EXYNOS_USB3_GEVNTADR_31_0(_a) EXYNOS_USB3_REG(0xC400 + ((_a) * 0x10))
+#define EXYNOS_USB3_GEVNTADR_63_32(_a) EXYNOS_USB3_REG(0xC404 + ((_a) * 0x10))
+
+
+#define EXYNOS_USB3_GEVNTSIZ(_a) EXYNOS_USB3_REG(0xC408 + ((_a) * 0x10))
+#define EXYNOS_USB3_GEVNTSIZx_EvntIntMask (1 << 31)
+
+#define EXYNOS_USB3_GEVNTSIZx_EVNTSiz_MASK (0xffff << 0)
+#define EXYNOS_USB3_GEVNTSIZx_EVNTSiz_SHIFT (0)
+#define EXYNOS_USB3_GEVNTSIZx_EVNTSiz_LIMIT (0xffff)
+#define EXYNOS_USB3_GEVNTSIZx_EVNTSiz(x) ((_x) << 0)
+
+
+#define EXYNOS_USB3_GEVNTCOUNT(_a) EXYNOS_USB3_REG(0xC40C + ((_a) * 0x10))
+
+#define EXYNOS_USB3_GEVNTCOUNTx_EVNTCount_MASK (0xffff << 0)
+#define EXYNOS_USB3_GEVNTCOUNTx_EVNTCount_SHIFT (0)
+#define EXYNOS_USB3_GEVNTCOUNTx_EVNTCount_LIMIT (0xffff)
+#define EXYNOS_USB3_GEVNTCOUNTx_EVNTCount(_x) ((_x) << 0)
+
+/* Event Buffer Content for Device Endpoint-Specific Events (DEPEVT) */
+#define EXYNOS_USB3_DEPEVT_EventParam_MASK (0xffff << 16)
+#define EXYNOS_USB3_DEPEVT_EventParam_SHIFT (16)
+#define EXYNOS_USB3_DEPEVT_EventParam_LIMIT (0xffff)
+#define EXYNOS_USB3_DEPEVT_EventParam(_x) ((_x) << 16)
+
+#define EXYNOS_USB3_DEPEVT_EventStatus_MASK (0xf << 12)
+#define EXYNOS_USB3_DEPEVT_EventStatus_SHIFT (12)
+#define EXYNOS_USB3_DEPEVT_EventStatus_LIMIT (0xf)
+
+#define EXYNOS_USB3_DEPEVT_EVENT_MASK (0xf << 6)
+#define EXYNOS_USB3_DEPEVT_EVENT_SHIFT (6)
+#define EXYNOS_USB3_DEPEVT_EVENT_LIMIT (0xf)
+#define EXYNOS_USB3_DEPEVT_EVENT_EPCmdCmplt (7 << 6)
+#define EXYNOS_USB3_DEPEVT_EVENT_StreamEvt (6 << 6)
+#define EXYNOS_USB3_DEPEVT_EVENT_RxTxfifoEvt (4 << 6)
+#define EXYNOS_USB3_DEPEVT_EVENT_XferNotReady (3 << 6)
+#define EXYNOS_USB3_DEPEVT_EVENT_XferInProgress (2 << 6)
+#define EXYNOS_USB3_DEPEVT_EVENT_XferComplete (1 << 6)
+
+#define EXYNOS_USB3_DEPEVT_EPNUM_MASK (0x1f << 1)
+#define EXYNOS_USB3_DEPEVT_EPNUM_SHIFT (1)
+#define EXYNOS_USB3_DEPEVT_EPNUM_LIMIT (0x1f)
+#define EXYNOS_USB3_DEPEVT_EPNUM(_x) ((_x) << 1)
+
+/* Event Buffer Content for Device-Specific Events (DEVT) */
+#define EXYNOS_USB3_DEVT_EventParam_MASK (0xf << 16)
+#define EXYNOS_USB3_DEVT_EventParam_SHIFT (16)
+#define EXYNOS_USB3_DEVT_EventParam_LIMIT (0xf)
+#define EXYNOS_USB3_DEVT_EventParam_SS (1 << 20)
+#define EXYNOS_USB3_DEVT_EventParam(_x) ((_x) << 16)
+
+#define EXYNOS_USB3_DEVT_EVENT_MASK (0xf << 8)
+#define EXYNOS_USB3_DEVT_EVENT_SHIFT (8)
+#define EXYNOS_USB3_DEVT_EVENT_LIMIT (0xf)
+#define EXYNOS_USB3_DEVT_EVENT_VndrDevTstRcved (12 << 8)
+#define EXYNOS_USB3_DEVT_EVENT_EvntOverflow (11 << 8)
+#define EXYNOS_USB3_DEVT_EVENT_CmdCmplt (10 << 8)
+#define EXYNOS_USB3_DEVT_EVENT_ErrticErr (9 << 8)
+#define EXYNOS_USB3_DEVT_EVENT_Sof (7 << 8)
+#define EXYNOS_USB3_DEVT_EVENT_EOPF (6 << 8)
+#define EXYNOS_USB3_DEVT_EVENT_WkUpEvt (4 << 8)
+#define EXYNOS_USB3_DEVT_EVENT_ULStChng (3 << 8)
+#define EXYNOS_USB3_DEVT_EVENT_ConnectDone (2 << 8)
+#define EXYNOS_USB3_DEVT_EVENT_USBRst (1 << 8)
+#define EXYNOS_USB3_DEVT_EVENT_DisconnEvt (0 << 8)
+
+
+#define EXYNOS_USB3_GHWPARAMS8 EXYNOS_USB3_REG(0xC600)
+
+
+/* Device registers */
+#define EXYNOS_USB3_DCFG EXYNOS_USB3_REG(0xC700)
+#define EXYNOS_USB3_DCFG_IgnoreStreamPP (1 << 23)
+#define EXYNOS_USB3_DCFG_LPMCap (1 << 22)
+
+#define EXYNOS_USB3_DCFG_NumP_MASK (0x1f << 17)
+#define EXYNOS_USB3_DCFG_NumP_SHIFT (17)
+#define EXYNOS_USB3_DCFG_NumP_LIMIT (0x1f)
+#define EXYNOS_USB3_DCFG_NumP(_x) ((_x) << 17)
+
+#define EXYNOS_USB3_DCFG_IntrNum_MASK (0x1f << 12)
+#define EXYNOS_USB3_DCFG_IntrNum_SHIFT (12)
+#define EXYNOS_USB3_DCFG_IntrNum_LIMIT (0x1f)
+#define EXYNOS_USB3_DCFG_IntrNum(_x) (0x1f << 12)
+
+#define EXYNOS_USB3_DCFG_PerFrInt_MASK (0x3 << 10)
+#define EXYNOS_USB3_DCFG_PerFrInt_SHIFT (10)
+#define EXYNOS_USB3_DCFG_PerFrInt_LIMIT (0x3)
+#define EXYNOS_USB3_DCFG_PerFrInt(_x) ((_x) << 10)
+
+#define EXYNOS_USB3_DCFG_DevAddr_MASK (0x7f << 3)
+#define EXYNOS_USB3_DCFG_DevAddr_SHIFT (3)
+#define EXYNOS_USB3_DCFG_DevAddr_LIMIT (0x7f)
+#define EXYNOS_USB3_DCFG_DevAddr(_x) ((_x) << 3)
+
+#define EXYNOS_USB3_DCFG_DevSpd_MASK (0x7 << 0)
+#define EXYNOS_USB3_DCFG_DevSpd_SHIFT (0)
+#define EXYNOS_USB3_DCFG_DevSpd_LIMIT (0x7)
+#define EXYNOS_USB3_DCFG_DevSpd(_x) ((_x) << 0)
+
+
+#define EXYNOS_USB3_DCTL EXYNOS_USB3_REG(0xC704)
+#define EXYNOS_USB3_DCTL_Run_Stop (1 << 31)
+#define EXYNOS_USB3_DCTL_CSftRst (1 << 30)
+#define EXYNOS_USB3_DCTL_LSftRst (1 << 29)
+
+#define EXYNOS_USB3_DCTL_HIRD_Thres_MASK (0x1f << 24)
+#define EXYNOS_USB3_DCTL_HIRD_Thres_SHIFT (24)
+#define EXYNOS_USB3_DCTL_HIRD_Thres_LIMIT (0x1f)
+#define EXYNOS_USB3_DCTL_HIRD_Thres(_x) ((_x) << 24)
+
+#define EXYNOS_USB3_DCTL_AppL1Res (1 << 23)
+
+#define EXYNOS_USB3_DCTL_TrgtULSt_MASK (0xf << 17)
+#define EXYNOS_USB3_DCTL_TrgtULSt_SHIFT (17)
+#define EXYNOS_USB3_DCTL_TrgtULSt_LIMIT (0xf)
+#define EXYNOS_USB3_DCTL_TrgtULSt(_x) ((_x) << 17)
+
+#define EXYNOS_USB3_DCTL_InitU2Ena (1 << 12)
+#define EXYNOS_USB3_DCTL_AcceptU2Ena (1 << 11)
+#define EXYNOS_USB3_DCTL_InitU1Ena (1 << 10)
+#define EXYNOS_USB3_DCTL_AcceptU1Ena (1 << 9)
+
+#define EXYNOS_USB3_DCTL_ULStChngReq_MASK (0xf << 5)
+#define EXYNOS_USB3_DCTL_ULStChngReq_SHIFT (5)
+#define EXYNOS_USB3_DCTL_ULStChngReq_LIMIT (0xf)
+#define EXYNOS_USB3_DCTL_ULStChngReq(_x) ((_x) << 5)
+
+#define EXYNOS_USB3_DCTL_TstCtl_MASK (0xf << 1)
+#define EXYNOS_USB3_DCTL_TstCtl_SHIFT (1)
+#define EXYNOS_USB3_DCTL_TstCtl_LIMIT (0xf)
+#define EXYNOS_USB3_DCTL_TstCtl(_x) ((_x) << 1)
+
+
+#define EXYNOS_USB3_DEVTEN EXYNOS_USB3_REG(0xC708)
+#define EXYNOS_USB3_DEVTEN_VndrDevTstRcvedEn (1 << 12)
+#define EXYNOS_USB3_DEVTEN_EvntOverflowEn (1 << 11)
+#define EXYNOS_USB3_DEVTEN_CmdCmpltEn (1 << 10)
+#define EXYNOS_USB3_DEVTEN_ErrticErrEn (1 << 9)
+#define EXYNOS_USB3_DEVTEN_SofEn (1 << 7)
+#define EXYNOS_USB3_DEVTEN_EOPFEn (1 << 6)
+#define EXYNOS_USB3_DEVTEN_WkUpEvtEn (1 << 4)
+#define EXYNOS_USB3_DEVTEN_ULStCngEn (1 << 3)
+#define EXYNOS_USB3_DEVTEN_ConnectDoneEn (1 << 2)
+#define EXYNOS_USB3_DEVTEN_USBRstEn (1 << 1)
+#define EXYNOS_USB3_DEVTEN_DisconnEvtEn (1 << 0)
+
+
+#define EXYNOS_USB3_DSTS EXYNOS_USB3_REG(0xC70C)
+#define EXYNOS_USB3_DSTS_PwrUpReq (1 << 24)
+#define EXYNOS_USB3_DSTS_CoreIdle (1 << 23)
+#define EXYNOS_USB3_DSTS_DevCtrlHlt (1 << 22)
+
+#define EXYNOS_USB3_DSTS_USBLnkSt_MASK (0xf << 18)
+#define EXYNOS_USB3_DSTS_USBLnkSt_SHIFT (18)
+#define EXYNOS_USB3_DSTS_USBLnkSt_LIMIT (0xf)
+#define EXYNOS_USB3_DSTS_USBLnkSt(_x) ((_x) << 18)
+#define EXYNOS_USB3_LnkSt_LPBK (0xb)
+#define EXYNOS_USB3_LnkSt_CMPLY (0xa)
+#define EXYNOS_USB3_LnkSt_HRESET (0x9)
+#define EXYNOS_USB3_LnkSt_RECOV (0x8)
+#define EXYNOS_USB3_LnkSt_POLL (0x7)
+#define EXYNOS_USB3_LnkSt_SS_INACT (0x6)
+#define EXYNOS_USB3_LnkSt_RX_DET (0x5)
+#define EXYNOS_USB3_LnkSt_SS_DIS (0x4)
+#define EXYNOS_USB3_LnkSt_U3 (0x3)
+#define EXYNOS_USB3_LnkSt_U2 (0x2)
+#define EXYNOS_USB3_LnkSt_U1 (0x1)
+#define EXYNOS_USB3_LnkSt_U0 (0x0)
+
+#define EXYNOS_USB3_DSTS_RxFIFOEmpty (1 << 17)
+
+#define EXYNOS_USB3_DSTS_SOFFN_MASK (0x3fff << 3)
+#define EXYNOS_USB3_DSTS_SOFFN_SHIFT (3)
+#define EXYNOS_USB3_DSTS_SOFFN_LIMIT (0x3fff)
+#define EXYNOS_USB3_DSTS_SOFFN(_x) ((_x) << 3)
+
+#define EXYNOS_USB3_DSTS_ConnectSpd_MASK (0x7 << 0)
+#define EXYNOS_USB3_DSTS_ConnectSpd_SHIFT (0)
+#define EXYNOS_USB3_DSTS_ConnectSpd_LIMIT (0x7)
+#define EXYNOS_USB3_DSTS_ConnectSpd(_x) ((_x) << 0)
+
+
+#define EXYNOS_USB3_DGCMDPAR EXYNOS_USB3_REG(0xC710)
+
+
+#define EXYNOS_USB3_DGCMD EXYNOS_USB3_REG(0xC714)
+#define EXYNOS_USB3_DGCMD_CmdStatus (1 << 15)
+#define EXYNOS_USB3_DGCMD_CmdAct (1 << 10)
+#define EXYNOS_USB3_DGCMD_CmdIOC (1 << 8)
+
+#define EXYNOS_USB3_DGCMD_CmdTyp_MASK (0xff << 0)
+#define EXYNOS_USB3_DGCMD_CmdTyp_SHIFT (0)
+#define EXYNOS_USB3_DGCMD_CmdTyp_LIMIT (0xff)
+#define EXYNOS_USB3_DGCMD_CmdTyp(_x) ((_x) << 0)
+/* TODO: add device generic command descriptions */
+#define EXYNOS_USB3_DGCMD_CmdTyp_SetPerParams (0x2 << 0)
+
+/* TODO: not finished */
+#define EXYNOS_USB3_DALEPENA EXYNOS_USB3_REG(0xC720)
+
+
+#define EXYNOS_USB3_DEPCMDPAR2(_a) EXYNOS_USB3_REG(0xC800 + ((_a) * 0x10))
+
+#define EXYNOS_USB3_DEPCMDPAR1(_a) EXYNOS_USB3_REG(0xC804 + ((_a) * 0x10))
+/* DEPCFG command parameter 1 */
+#define EXYNOS_USB3_DEPCMDPAR1x_FIFO_based (1 << 31)
+#define EXYNOS_USB3_DEPCMDPAR1x_BULK_based (1 << 30)
+
+#define EXYNOS_USB3_DEPCMDPAR1x_EpNum_MASK (0xf << 26)
+#define EXYNOS_USB3_DEPCMDPAR1x_EpNum_SHIFT (26)
+#define EXYNOS_USB3_DEPCMDPAR1x_EpNum_LIMIT (0xf)
+#define EXYNOS_USB3_DEPCMDPAR1x_EpNum(_x) ((_x) << 26)
+
+#define EXYNOS_USB3_DEPCMDPAR1x_EpDir (1 << 25)
+#define EXYNOS_USB3_DEPCMDPAR1x_StrmCap (1 << 24)
+
+#define EXYNOS_USB3_DEPCMDPAR1x_bInterval_m1_MASK (0xff << 16)
+#define EXYNOS_USB3_DEPCMDPAR1x_bInterval_m1_SHIFT (16)
+#define EXYNOS_USB3_DEPCMDPAR1x_bInterval_m1_LIMIT (0xff)
+#define EXYNOS_USB3_DEPCMDPAR1x_bInterval_m1(_x) ((_x) << 16)
+
+#define EXYNOS_USB3_DEPCMDPAR1x_StreamEvtEn (1 << 13)
+#define EXYNOS_USB3_DEPCMDPAR1x_RxTxfifoEvtEn (1 << 11)
+#define EXYNOS_USB3_DEPCMDPAR1x_XferNRdyEn (1 << 10)
+#define EXYNOS_USB3_DEPCMDPAR1x_XferInProgEn (1 << 9)
+#define EXYNOS_USB3_DEPCMDPAR1x_XferCmplEn (1 << 8)
+
+#define EXYNOS_USB3_DEPCMDPAR1x_IntrNum_MASK (0x1f << 0)
+#define EXYNOS_USB3_DEPCMDPAR1x_IntrNum_SHIFT (0)
+#define EXYNOS_USB3_DEPCMDPAR1x_IntrNum_LIMIT (0x1f)
+#define EXYNOS_USB3_DEPCMDPAR1x_IntrNum(_x) ((_x) << 0)
+
+
+#define EXYNOS_USB3_DEPCMDPAR0(_a) EXYNOS_USB3_REG(0xC808 + ((_a) * 0x10))
+/* DEPCFG command parameter 0 */
+#define EXYNOS_USB3_DEPCMDPAR0x_IgnrSeqNum (1 << 31)
+
+#define EXYNOS_USB3_DEPCMDPAR0x_DataSeqNum_MASK (0x1f << 26)
+#define EXYNOS_USB3_DEPCMDPAR0x_DataSeqNum_SHIFT (26)
+#define EXYNOS_USB3_DEPCMDPAR0x_DataSeqNum_LIMIT (0x1f)
+#define EXYNOS_USB3_DEPCMDPAR0x_DataSeqNum(_x) ((_x) << 26)
+
+#define EXYNOS_USB3_DEPCMDPAR0x_BrstSiz_MASK (0xf << 22)
+#define EXYNOS_USB3_DEPCMDPAR0x_BrstSiz_SHIFT (22)
+#define EXYNOS_USB3_DEPCMDPAR0x_BrstSiz_LIMIT (0xf)
+#define EXYNOS_USB3_DEPCMDPAR0x_BrstSiz(_x) ((_x) << 22)
+
+#define EXYNOS_USB3_DEPCMDPAR0x_FIFONum_MASK (0x1f << 17)
+#define EXYNOS_USB3_DEPCMDPAR0x_FIFONum_SHIFT (17)
+#define EXYNOS_USB3_DEPCMDPAR0x_FIFONum_LIMIT (0x1f)
+#define EXYNOS_USB3_DEPCMDPAR0x_FIFONum(_x) ((_x) << 17)
+
+#define EXYNOS_USB3_DEPCMDPAR0x_MPS_MASK (0x7ff << 3)
+#define EXYNOS_USB3_DEPCMDPAR0x_MPS_SHIFT (3)
+#define EXYNOS_USB3_DEPCMDPAR0x_MPS_LIMIT (0x7ff)
+#define EXYNOS_USB3_DEPCMDPAR0x_MPS(_x) ((_x) << 3)
+
+#define EXYNOS_USB3_DEPCMDPAR0x_EPType_MASK (0x3 << 1)
+#define EXYNOS_USB3_DEPCMDPAR0x_EPType_SHIFT (1)
+#define EXYNOS_USB3_DEPCMDPAR0x_EPType_LIMIT (0x3)
+#define EXYNOS_USB3_DEPCMDPAR0x_EPType(_x) ((_x) << 1)
+
+/* DEPXFERCFG command parameter 0 */
+#define EXYNOS_USB3_DEPCMDPAR0x_NumXferRes_MASK (0xff << 0)
+#define EXYNOS_USB3_DEPCMDPAR0x_NumXferRes_SHIFT (0)
+#define EXYNOS_USB3_DEPCMDPAR0x_NumXferRes_LIMIT (0xff)
+#define EXYNOS_USB3_DEPCMDPAR0x_NumXferRes(_x) ((_x) << 0)
+
+
+#define EXYNOS_USB3_DEPCMD(_a) EXYNOS_USB3_REG(0xC80C + ((_a) * 0x10))
+
+#define EXYNOS_USB3_DEPCMDx_CommandParam_MASK (0xffff << 16)
+#define EXYNOS_USB3_DEPCMDx_CommandParam_SHIFT (16)
+#define EXYNOS_USB3_DEPCMDx_CommandParam_LIMIT (0xffff)
+#define EXYNOS_USB3_DEPCMDx_CommandParam(_x) ((_x) << 16)
+
+#define EXYNOS_USB3_DEPCMDx_EventParam_MASK (0xffff << 16)
+#define EXYNOS_USB3_DEPCMDx_EventParam_SHIFT (16)
+#define EXYNOS_USB3_DEPCMDx_EventParam_LIMIT (0xffff)
+#define EXYNOS_USB3_DEPCMDx_EventParam(_x) ((_x) << 16)
+
+#define EXYNOS_USB3_DEPCMDx_XferRscIdx_LIMIT (0x7f)
+
+#define EXYNOS_USB3_DEPCMDx_CmdStatus_MASK (0xf << 12)
+#define EXYNOS_USB3_DEPCMDx_CmdStatus_SHIFT (12)
+#define EXYNOS_USB3_DEPCMDx_CmdStatus_LIMIT (0xf)
+#define EXYNOS_USB3_DEPCMDx_CmdStatus(_x) ((_x) << 12)
+
+#define EXYNOS_USB3_DEPCMDx_HiPri_ForceRM (1 << 11)
+#define EXYNOS_USB3_DEPCMDx_CmdAct (1 << 10)
+#define EXYNOS_USB3_DEPCMDx_CmdIOC (1 << 8)
+
+#define EXYNOS_USB3_DEPCMDx_CmdTyp_MASK (0xf << 0)
+#define EXYNOS_USB3_DEPCMDx_CmdTyp_SHIFT (0)
+#define EXYNOS_USB3_DEPCMDx_CmdTyp_LIMIT (0xf)
+#define EXYNOS_USB3_DEPCMDx_CmdTyp(_x) ((_x) << 0)
+/* Physical Endpoint commands */
+#define EXYNOS_USB3_DEPCMDx_CmdTyp_DEPCFG (0x1 << 0)
+#define EXYNOS_USB3_DEPCMDx_CmdTyp_DEPXFERCFG (0x2 << 0)
+#define EXYNOS_USB3_DEPCMDx_CmdTyp_DEPGETDSEQ (0x3 << 0)
+#define EXYNOS_USB3_DEPCMDx_CmdTyp_DEPSSTALL (0x4 << 0)
+#define EXYNOS_USB3_DEPCMDx_CmdTyp_DEPCSTALL (0x5 << 0)
+#define EXYNOS_USB3_DEPCMDx_CmdTyp_DEPSTRTXFER (0x6 << 0)
+#define EXYNOS_USB3_DEPCMDx_CmdTyp_DEPUPDXFER (0x7 << 0)
+#define EXYNOS_USB3_DEPCMDx_CmdTyp_DEPENDXFER (0x8 << 0)
+#define EXYNOS_USB3_DEPCMDx_CmdTyp_DEPSTARTCFG (0x9 << 0)
+
+
+/* USB 2.0 OTG and Battery Charger registers */
+#define EXYNOS_USB3_OCFG EXYNOS_USB3_REG(0xCC00)
+#define EXYNOS_USB3_OCFG_OTG_Version (1 << 2)
+#define EXYNOS_USB3_OCFG_HNPCap (1 << 1)
+#define EXYNOS_USB3_OCFG_SRPCap (1 << 0)
+
+
+#define EXYNOS_USB3_OCTL EXYNOS_USB3_REG(0xCC04)
+#define EXYNOS_USB3_OCTL_PeriMode (1 << 6)
+#define EXYNOS_USB3_OCTL_PrtPwrCtl (1 << 5)
+#define EXYNOS_USB3_OCTL_HNPReq (1 << 4)
+#define EXYNOS_USB3_OCTL_SesReq (1 << 3)
+#define EXYNOS_USB3_OCTL_TermSelDLPulse (1 << 2)
+#define EXYNOS_USB3_OCTL_DevSetHNPEn (1 << 1)
+#define EXYNOS_USB3_OCTL_HstSetHNPEn (1 << 0)
+
+
+#define EXYNOS_USB3_OEVT EXYNOS_USB3_REG(0xCC08)
+#define EXYNOS_USB3_OEVT_DeviceMode (1 << 31)
+#define EXYNOS_USB3_OEVT_OTGConIDStsChngEvnt (1 << 24)
+#define EXYNOS_USB3_OEVT_OTGADevBHostEndEvnt (1 << 20)
+#define EXYNOS_USB3_OEVT_OTGADevHostEvnt (1 << 19)
+#define EXYNOS_USB3_OEVT_OTGADevHNPChngEvnt (1 << 18)
+#define EXYNOS_USB3_OEVT_OTGADevSRPDetEvnt (1 << 17)
+#define EXYNOS_USB3_OEVT_OTGADevSessEndDetEvnt (1 << 16)
+#define EXYNOS_USB3_OEVT_OTGBDevBHostEndEvnt (1 << 11)
+#define EXYNOS_USB3_OEVT_OTGBDevHNPChngEvnt (1 << 10)
+#define EXYNOS_USB3_OEVT_OTGBDevSessVldDetEvnt (1 << 9)
+#define EXYNOS_USB3_OEVT_OTGBDevVBUSChngEvnt (1 << 8)
+#define EXYNOS_USB3_OEVT_BSesVld (1 << 3)
+#define EXYNOS_USB3_OEVT_HstNegSts (1 << 2)
+#define EXYNOS_USB3_OEVT_SesReqSts (1 << 1)
+#define EXYNOS_USB3_OEVT_OEVTError (1 << 0)
+
+
+#define EXYNOS_USB3_OEVTEN EXYNOS_USB3_REG(0xCC0C)
+#define EXYNOS_USB3_OEVTEN_OTGConIDStsChngEvntEn (1 << 24)
+#define EXYNOS_USB3_OEVTEN_OTGADevBHostEndEvntEn (1 << 20)
+#define EXYNOS_USB3_OEVTEN_OTGADevHostEvntEn (1 << 19)
+#define EXYNOS_USB3_OEVTEN_OTGADevHNPChngEvntEn (1 << 18)
+#define EXYNOS_USB3_OEVTEN_OTGADevSRPDetEvntEn (1 << 17)
+#define EXYNOS_USB3_OEVTEN_OTGADevSessEndDetEvntEn (1 << 16)
+#define EXYNOS_USB3_OEVTEN_OTGBDevBHostEndEvntEn (1 << 11)
+#define EXYNOS_USB3_OEVTEN_OTGBDevHNPChngEvntEn (1 << 10)
+#define EXYNOS_USB3_OEVTEN_OTGBDevSessVldDetEvntEn (1 << 9)
+#define EXYNOS_USB3_OEVTEN_OTGBDevVBUSChngEvntEn (1 << 8)
+
+
+#define EXYNOS_USB3_OSTS EXYNOS_USB3_REG(0xCC10)
+
+#define EXYNOS_USB3_OSTS_OTG_state_MASK (0xf << 8)
+#define EXYNOS_USB3_OSTS_OTG_state_SHIFT (8)
+#define EXYNOS_USB3_OSTS_OTG_state_LIMIT (0xf)
+#define EXYNOS_USB3_OSTS_OTG_state(_x) ((_x) << 8)
+
+#define EXYNOS_USB3_OSTS_PeripheralState (1 << 4)
+#define EXYNOS_USB3_OSTS_xHCIPrtPower (1 << 3)
+#define EXYNOS_USB3_OSTS_BSesVld (1 << 2)
+#define EXYNOS_USB3_OSTS_VbusVld (1 << 1)
+#define EXYNOS_USB3_OSTS_ConIDSts (1 << 0)
+
+
+#define EXYNOS_USB3_ADPCFG EXYNOS_USB3_REG(0xCC20)
+
+#define EXYNOS_USB3_ADPCFG_PrbPer_MASK (0x3 << 30)
+#define EXYNOS_USB3_ADPCFG_PrbPer_SHIFT (30)
+#define EXYNOS_USB3_ADPCFG_PrbPer_LIMIT (0x3)
+#define EXYNOS_USB3_ADPCFG_PrbPer(_x) ((_x) << 30)
+
+#define EXYNOS_USB3_ADPCFG_PrbDelta_MASK (0x3 << 28)
+#define EXYNOS_USB3_ADPCFG_PrbDelta_SHIFT (28)
+#define EXYNOS_USB3_ADPCFG_PrbDelta_LIMIT (0x3)
+#define EXYNOS_USB3_ADPCFG_PrbDelta(_x) ((_x) << 28)
+
+#define EXYNOS_USB3_ADPCFG_PrbDschg_MASK (0x3 << 26)
+#define EXYNOS_USB3_ADPCFG_PrbDschg_SHIFT (26)
+#define EXYNOS_USB3_ADPCFG_PrbDschg_LIMIT (0x3)
+#define EXYNOS_USB3_ADPCFG_PrbDschg(_x) ((_x) << 26)
+
+
+#define EXYNOS_USB3_ADPCTL EXYNOS_USB3_REG(0xCC24)
+#define EXYNOS_USB3_ADPCTL_EnaPrb (1 << 28)
+#define EXYNOS_USB3_ADPCTL_EnaSns (1 << 27)
+#define EXYNOS_USB3_ADPCTL_ADPEn (1 << 26)
+#define EXYNOS_USB3_ADPCTL_ADPRes (1 << 25)
+#define EXYNOS_USB3_ADPCTL_WB (1 << 24)
+
+
+#define EXYNOS_USB3_ADPEVT EXYNOS_USB3_REG(0xCC28)
+#define EXYNOS_USB3_ADPEVT_AdpPrbEvnt (1 << 28)
+#define EXYNOS_USB3_ADPEVT_AdpSnsEvnt (1 << 27)
+#define EXYNOS_USB3_ADPEVT_AdpTmoutEvnt (1 << 26)
+#define EXYNOS_USB3_ADPEVT_ADPRstCmpltEvnt (1 << 25)
+
+#define EXYNOS_USB3_ADPEVT_RTIM_MASK (0x7ff << 0)
+#define EXYNOS_USB3_ADPEVT_RTIM_SHIFT (0)
+#define EXYNOS_USB3_ADPEVT_RTIM_LIMIT (0x7ff)
+#define EXYNOS_USB3_ADPEVT_RTIM(_x) ((_x) << 0)
+
+
+#define EXYNOS_USB3_ADPEVTEN EXYNOS_USB3_REG(0xCC2C)
+#define EXYNOS_USB3_ADPEVTEN_AdpPrbEvntEn (1 << 28)
+#define EXYNOS_USB3_ADPEVTEN_AdpSnsEvntEn (1 << 27)
+#define EXYNOS_USB3_ADPEVTEN_AdpTmoutEvntEn (1 << 26)
+#define EXYNOS_USB3_ADPEVTEN_ADPRstCmpltEvntEn (1 << 25)
+
+
+#define EXYNOS_USB3_BCFG EXYNOS_USB3_REG(0xCC30)
+#define EXYNOS_USB3_BCFG_IDDIG_SEL (1 << 1)
+#define EXYNOS_USB3_BCFG_CHIRP_EN (1 << 0)
+
+
+#define EXYNOS_USB3_BCEVT EXYNOS_USB3_REG(0xCC38)
+#define EXYNOS_USB3_BCEVT_MV_ChngEvnt (1 << 24)
+
+#define EXYNOS_USB3_BCEVT_MultValIdBc_MASK (0x1f << 0)
+#define EXYNOS_USB3_BCEVT_MultValIdBc_SHIFT (0)
+#define EXYNOS_USB3_BCEVT_MultValIdBc_LIMIT (0x1f)
+#define EXYNOS_USB3_BCEVT_MultValIdBc(_x) ((_x) << 0)
+
+
+#define EXYNOS_USB3_BCEVTEN EXYNOS_USB3_REG(0xCC3C)
+#define EXYNOS_USB3_BCEVTEN_MV_ChngEvntEn (1 << 24)
+
+/* Transfer Request Block */
+#define EXYNOS_USB3_TRB_TRBSTS_MASK (0xf << 28)
+#define EXYNOS_USB3_TRB_TRBSTS_SHIFT (28)
+#define EXYNOS_USB3_TRB_TRBSTS_LIMIT (0xf)
+#define EXYNOS_USB3_TRB_TRBSTS(_x) ((_x) << 28)
+
+#define EXYNOS_USB3_TRB_PCM1_MASK (0x3 << 24)
+#define EXYNOS_USB3_TRB_PCM1_SHIFT (24)
+#define EXYNOS_USB3_TRB_PCM1_LIMIT (0x3)
+#define EXYNOS_USB3_TRB_PCM1(_x) ((_x) << 24)
+
+#define EXYNOS_USB3_TRB_BUFSIZ_MASK (0xffffff << 0)
+#define EXYNOS_USB3_TRB_BUFSIZ_SHIFT (0)
+#define EXYNOS_USB3_TRB_BUFSIZ_LIMIT (0xffffff)
+#define EXYNOS_USB3_TRB_BUFSIZ(_x) ((_x) << 0)
+
+#define EXYNOS_USB3_TRB_StreamID_SOFNumber_MASK (0xffff << 14)
+#define EXYNOS_USB3_TRB_StreamID_SOFNumber_SHIFT (14)
+#define EXYNOS_USB3_TRB_StreamID_SOFNumber_LIMIT (0xffff)
+#define EXYNOS_USB3_TRB_StreamID_SOFNumber(_x) ((_x) << 14)
+
+#define EXYNOS_USB3_TRB_IOC (1 << 11)
+#define EXYNOS_USB3_TRB_ISP_IMI (1 << 10)
+
+#define EXYNOS_USB3_TRB_TRBCTL_MASK (0x3f << 4)
+#define EXYNOS_USB3_TRB_TRBCTL_SHIFT (4)
+#define EXYNOS_USB3_TRB_TRBCTL_LIMIT (0x3f)
+#define EXYNOS_USB3_TRB_TRBCTL(_x) ((_x) << 4)
+
+#define EXYNOS_USB3_TRB_CSP (1 << 3)
+#define EXYNOS_USB3_TRB_CHN (1 << 2)
+#define EXYNOS_USB3_TRB_LST (1 << 1)
+#define EXYNOS_USB3_TRB_HWO (1 << 0)
+
+#endif /* __SAMSUNG_PLAT_REGS_USB3_EXYNOS_DRD_H */
diff --git a/arch/arm/mach-exynos/include/mach/secmem.h b/arch/arm/mach-exynos/include/mach/secmem.h
new file mode 100644
index 0000000..2ae3339
--- /dev/null
+++ b/arch/arm/mach-exynos/include/mach/secmem.h
@@ -0,0 +1,55 @@
+/* linux/arch/arm/mach-exynos/include/mach/secmem.h
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * EXYNOS - Secure memory support
+ *
+ * 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.
+*/
+
+#ifndef __ASM_ARCH_SECMEM_H
+#define __ASM_ARCH_SECMEM_H __FILE__
+
+#if defined(CONFIG_ION)
+#include <linux/ion.h>
+#endif
+
+struct secchunk_info {
+ int index;
+ phys_addr_t base;
+ size_t size;
+};
+
+#if defined(CONFIG_ION)
+struct secfd_info {
+ int fd;
+ ion_phys_addr_t phys;
+};
+#endif
+
+struct secmem_crypto_driver_ftn {
+ int (*lock) (void);
+ int (*release) (void);
+};
+
+#if defined(CONFIG_EXYNOS_CONTENT_PATH_PROTECTION)
+void secmem_crypto_register(struct secmem_crypto_driver_ftn *ftn);
+void secmem_crypto_deregister(void);
+#else
+#define secmem_crypto_register(ftn)
+#define secmem_crypto_deregister()
+#endif
+
+#define SECMEM_IOC_CHUNKINFO _IOWR('S', 1, struct secchunk_info)
+#define SECMEM_IOC_SET_DRM_ONOFF _IOWR('S', 2, int)
+#define SECMEM_IOC_GET_DRM_ONOFF _IOWR('S', 3, int)
+#define SECMEM_IOC_GET_CRYPTO_LOCK _IOR('S', 4, int)
+#define SECMEM_IOC_RELEASE_CRYPTO_LOCK _IOR('S', 5, int)
+#if defined(CONFIG_SOC_EXYNOS5250)
+#define SECMEM_IOC_GET_FD_PHYS_ADDR _IOWR('S', 8, struct secfd_info)
+#endif
+
+#endif /* __ASM_ARCH_SECMEM_H */
diff --git a/arch/arm/mach-exynos/include/mach/smc.h b/arch/arm/mach-exynos/include/mach/smc.h
new file mode 100644
index 0000000..a162746
--- /dev/null
+++ b/arch/arm/mach-exynos/include/mach/smc.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * EXYNOS - SMC Call
+ *
+ * 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.
+*/
+
+#ifndef __ASM_ARCH_SMC_H
+#define __ASM_ARCH_SMC_H __FILE__
+
+#define SMC_CMD_INIT (-1)
+#define SMC_CMD_INFO (-2)
+/* For Power Management */
+#define SMC_CMD_SLEEP (-3)
+#define SMC_CMD_CPU1BOOT (-4)
+#define SMC_CMD_CPU0AFTR (-5)
+/* For CP15 Access */
+#define SMC_CMD_C15RESUME (-11)
+/* For L2 Cache Access */
+#define SMC_CMD_L2X0CTRL (-21)
+#define SMC_CMD_L2X0SETUP1 (-22)
+#define SMC_CMD_L2X0SETUP2 (-23)
+#define SMC_CMD_L2X0INVALL (-24)
+#define SMC_CMD_L2X0DEBUG (-25)
+
+/* For Accessing CP15/SFR (General) */
+#define SMC_CMD_REG (-101)
+
+/* MACRO for SMC_CMD_REG */
+#define SMC_REG_CLASS_CP15 (0x0 << 30)
+#define SMC_REG_CLASS_SFR_W (0x1 << 30)
+#define SMC_REG_CLASS_SFR_R (0x3 << 30)
+#define SMC_REG_CLASS_MASK (0x3 << 30)
+#define SMC_REG_ID_CP15(CRn, Op1, CRm, Op2) \
+ (SMC_REG_CLASS_CP15 | (CRn << 10) | (Op1 << 7) | (CRm << 3) | (Op2))
+#define SMC_REG_ID_SFR_W(ADDR) (SMC_REG_CLASS_SFR_W | ((ADDR) >> 2))
+#define SMC_REG_ID_SFR_R(ADDR) (SMC_REG_CLASS_SFR_R | ((ADDR) >> 2))
+
+#ifndef __ASSEMBLY__
+u32 exynos_smc(u32 cmd, u32 arg1, u32 arg2, u32 arg3);
+u32 exynos_smc_read_sfr(u32 cmd, u32 addr, u32 *val, u32 reserve);
+#endif
+
+#endif /* __ASM_ARCH_SMC_H */
diff --git a/arch/arm/mach-exynos/include/mach/spi-clocks.h b/arch/arm/mach-exynos/include/mach/spi-clocks.h
index 576efdf..c71a5fb 100644
--- a/arch/arm/mach-exynos/include/mach/spi-clocks.h
+++ b/arch/arm/mach-exynos/include/mach/spi-clocks.h
@@ -11,6 +11,6 @@
#define __ASM_ARCH_SPI_CLKS_H __FILE__
/* Must source from SCLK_SPI */
-#define EXYNOS4_SPI_SRCCLK_SCLK 0
+#define EXYNOS_SPI_SRCCLK_SCLK 0
#endif /* __ASM_ARCH_SPI_CLKS_H */
diff --git a/arch/arm/mach-exynos/include/mach/sysmmu.h b/arch/arm/mach-exynos/include/mach/sysmmu.h
index 6a5fbb5..2156a0c 100644
--- a/arch/arm/mach-exynos/include/mach/sysmmu.h
+++ b/arch/arm/mach-exynos/include/mach/sysmmu.h
@@ -1,46 +1,70 @@
-/* linux/arch/arm/mach-exynos4/include/mach/sysmmu.h
- *
- * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+/*
+ * Copyright (c) 2011-2012 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
- * Samsung sysmmu driver for EXYNOS4
+ * EXYNOS - System MMU support
*
* 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.
-*/
+ */
-#ifndef __ASM_ARM_ARCH_SYSMMU_H
-#define __ASM_ARM_ARCH_SYSMMU_H __FILE__
+#ifndef _ARM_MACH_EXYNOS_SYSMMU_H_
+#define _ARM_MACH_EXYNOS_SYSMMU_H_
-enum exynos4_sysmmu_ips {
- SYSMMU_MDMA,
- SYSMMU_SSS,
- SYSMMU_FIMC0,
- SYSMMU_FIMC1,
- SYSMMU_FIMC2,
- SYSMMU_FIMC3,
- SYSMMU_JPEG,
- SYSMMU_FIMD0,
- SYSMMU_FIMD1,
- SYSMMU_PCIe,
- SYSMMU_G2D,
- SYSMMU_ROTATOR,
- SYSMMU_MDMA2,
- SYSMMU_TV,
- SYSMMU_MFC_L,
- SYSMMU_MFC_R,
- EXYNOS4_SYSMMU_TOTAL_IPNUM,
+struct sysmmu_platform_data {
+ char *dbgname;
+ /* comma(,) separated list of clock names for clock gating */
+ char *clockname;
+ unsigned int qos;
};
-#define S5P_SYSMMU_TOTAL_IPNUM EXYNOS4_SYSMMU_TOTAL_IPNUM
+#define SYSMMU_DEVNAME_BASE "exynos-sysmmu"
-extern const char *sysmmu_ips_name[EXYNOS4_SYSMMU_TOTAL_IPNUM];
+#define SYSMMU_CLOCK_NAME "sysmmu"
+#define SYSMMU_CLOCK_NAME2 "sysmmu_mc"
+#define SYSMMU_CLOCK_NAME3 "sysmmu_mc2"
-typedef enum exynos4_sysmmu_ips sysmmu_ips;
+#ifdef CONFIG_EXYNOS_DEV_SYSMMU
+#include <linux/device.h>
+struct platform_device;
-void sysmmu_clk_init(struct device *dev, sysmmu_ips ips);
-void sysmmu_clk_enable(sysmmu_ips ips);
-void sysmmu_clk_disable(sysmmu_ips ips);
+#define SYSMMU_PLATDEV(ipname) exynos_device_sysmmu_##ipname
-#endif /* __ASM_ARM_ARCH_SYSMMU_H */
+extern struct platform_device SYSMMU_PLATDEV(mfc_lr);
+extern struct platform_device SYSMMU_PLATDEV(tv);
+extern struct platform_device SYSMMU_PLATDEV(jpeg);
+extern struct platform_device SYSMMU_PLATDEV(rot);
+extern struct platform_device SYSMMU_PLATDEV(fimc0);
+extern struct platform_device SYSMMU_PLATDEV(fimc1);
+extern struct platform_device SYSMMU_PLATDEV(fimc2);
+extern struct platform_device SYSMMU_PLATDEV(fimc3);
+extern struct platform_device SYSMMU_PLATDEV(gsc0);
+extern struct platform_device SYSMMU_PLATDEV(gsc1);
+extern struct platform_device SYSMMU_PLATDEV(gsc2);
+extern struct platform_device SYSMMU_PLATDEV(gsc3);
+extern struct platform_device SYSMMU_PLATDEV(isp);
+extern struct platform_device SYSMMU_PLATDEV(fimd0);
+extern struct platform_device SYSMMU_PLATDEV(fimd1);
+extern struct platform_device SYSMMU_PLATDEV(camif0);
+extern struct platform_device SYSMMU_PLATDEV(camif1);
+extern struct platform_device SYSMMU_PLATDEV(camif2);
+extern struct platform_device SYSMMU_PLATDEV(2d);
+
+#ifdef CONFIG_IOMMU_API
+static inline void platform_set_sysmmu(
+ struct device *sysmmu, struct device *dev)
+{
+ dev->archdata.iommu = sysmmu;
+}
+#else
+#define platform_set_sysmmu(dev, sysmmu) do { } while (0)
+#endif
+
+#else /* !CONFIG_EXYNOS_DEV_SYSMMU */
+#define platform_set_sysmmu(dev, sysmmu) do { } while (0)
+#endif
+
+#define SYSMMU_CLOCK_DEVNAME(ipname, id) (SYSMMU_DEVNAME_BASE "." #id)
+
+#endif /* _ARM_MACH_EXYNOS_SYSMMU_H_ */
diff --git a/arch/arm/mach-exynos/include/mach/tmu.h b/arch/arm/mach-exynos/include/mach/tmu.h
new file mode 100644
index 0000000..e31e94c
--- /dev/null
+++ b/arch/arm/mach-exynos/include/mach/tmu.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Header file for tmu support
+ *
+ * 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.
+ */
+
+#ifndef __ASM_ARCH_TMU_H
+#define __ASM_ARCH_TMU_H
+
+#define MUX_ADDR_VALUE 6
+#define TMU_SAVE_NUM 10
+#define TMU_DC_VALUE 25
+#define EFUSE_MIN_VALUE 40
+#define EFUSE_MAX_VALUE 100
+#define UNUSED_THRESHOLD 0xFF
+
+enum tmu_status_t {
+ TMU_STATUS_INIT = 0,
+ TMU_STATUS_NORMAL,
+ TMU_STATUS_THROTTLED,
+ TMU_STATUS_TRIPPED,
+};
+
+struct temperature_params {
+ unsigned int stop_throttle;
+ unsigned int start_throttle;
+ unsigned int start_tripping; /* temp to do tripping */
+ unsigned int start_emergency;
+ unsigned int stop_mem_throttle;
+ unsigned int start_mem_throttle;
+};
+
+struct tmu_data {
+ struct temperature_params ts;
+ unsigned int efuse_value;
+ unsigned int slope;
+ int mode;
+};
+
+struct tmu_info {
+ int id;
+ void __iomem *tmu_base;
+ struct device *dev;
+ struct resource *ioarea;
+ int irq;
+
+ unsigned int te1; /* triminfo_25 */
+ unsigned int te2; /* triminfo_85 */
+ int tmu_state;
+
+ bool mem_throttled;
+ unsigned int auto_refresh_mem_throttle;
+ unsigned int auto_refresh_normal;
+
+ /* monitoring rate */
+ unsigned int sampling_rate;
+
+ struct delayed_work polling;
+ struct delayed_work monitor;
+ unsigned int reg_save[TMU_SAVE_NUM];
+};
+
+extern void exynos_tmu_set_platdata(struct tmu_data *pd);
+extern struct tmu_info *exynos_tmu_get_platdata(void);
+extern int exynos_tmu_get_irqno(int num);
+extern struct platform_device exynos_device_tmu;
+#endif /* __ASM_ARCH_TMU_H */
diff --git a/arch/arm/mach-exynos/include/mach/videonode-exynos5.h b/arch/arm/mach-exynos/include/mach/videonode-exynos5.h
new file mode 100644
index 0000000..fc8065c
--- /dev/null
+++ b/arch/arm/mach-exynos/include/mach/videonode-exynos5.h
@@ -0,0 +1,32 @@
+/* linux/arch/arm/mach-exynos/include/mach/videonode-exynos5.h
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * EXYNOS5 - Video node definitions
+ *
+ * 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.
+*/
+
+#ifndef __MACH_VIDEONODE_EXYNOS5_H
+#define __MACH_VIDEONODE_EXYNOS5_H __FILE__
+
+#define S5P_VIDEONODE_MFC_DEC 6
+#define S5P_VIDEONODE_MFC_ENC 7
+
+#define EXYNOS_VIDEONODE_ROTATOR 21
+
+#define EXYNOS_VIDEONODE_GSC_M2M(x) (23 + (x) * 3)
+#define EXYNOS_VIDEONODE_GSC_OUT(x) (24 + (x) * 3)
+#define EXYNOS_VIDEONODE_GSC_CAP(x) (25 + (x) * 3)
+
+#define EXYNOS_VIDEONODE_FLITE(x) (36 + x)
+/* Exynos4x12 supports video, graphic0~1 layer
+ * Exynos5250 supports graphic0~3 layer */
+#define EXYNOS_VIDEONODE_MXR_GRP(x) (16 + x)
+#define EXYNOS_VIDEONODE_MXR_VIDEO 20
+#define EXYNOS_VIDEONODE_FIMC_IS (40)
+
+#endif /* __MACH_VIDEONODE_EXYNOS5_H */
diff --git a/arch/arm/mach-exynos/include/mach/videonode.h b/arch/arm/mach-exynos/include/mach/videonode.h
new file mode 100644
index 0000000..b0502d4
--- /dev/null
+++ b/arch/arm/mach-exynos/include/mach/videonode.h
@@ -0,0 +1,24 @@
+/* linux/arch/arm/mach-exynos/include/mach/videonode.h
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * EXYNOS - Video node definitions
+ *
+ * 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.
+*/
+
+#ifndef __MACH_VIDEONODE_H
+#define __MACH_VIDEONODE_H __FILE__
+
+#if defined(CONFIG_ARCH_EXYNOS4)
+#include "videonode-exynos4.h"
+#elif defined(CONFIG_ARCH_EXYNOS5)
+#include "videonode-exynos5.h"
+#else
+#error "ARCH_EXYNOS* is not defined"
+#endif
+
+#endif /* __MACH_VIDEONODE */
diff --git a/arch/arm/mach-exynos/irq-sgi.c b/arch/arm/mach-exynos/irq-sgi.c
new file mode 100644
index 0000000..ca93902
--- /dev/null
+++ b/arch/arm/mach-exynos/irq-sgi.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * htt://www.samsung.com
+ *
+ * Copyright (c) 2011 Gisecke & Devrient
+ *
+ * Based on linux/arch/arm/plat-s5p/irq-eint.c
+ *
+ * EXYNOS - Software Generated Interrupts Dummy chip support
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+
+#include <mach/regs-irq.h>
+
+static inline void exynos_irq_sgi_mask(struct irq_data *d)
+{
+ /* Do nothing, because SGIs are always enabled. */
+}
+
+static void exynos_irq_sgi_unmask(struct irq_data *d)
+{
+ /* Do nothing, because SGIs are always enabled. */
+}
+
+static inline void exynos_irq_sgi_eoi(struct irq_data *d)
+{
+ unsigned int irq = (d->irq - S5P_IRQ_OFFSET);
+
+ writel(irq, S5P_VA_GIC_CPU + GIC_CPU_EOI);
+}
+
+static int exynos_irq_sgi_set_type(struct irq_data *d, unsigned int type)
+{
+ return 0;
+}
+
+static struct irq_chip exynos_irq_sgi = {
+ .name = "exynos_sgi",
+ .irq_mask = exynos_irq_sgi_mask,
+ .irq_unmask = exynos_irq_sgi_unmask,
+ .irq_eoi = exynos_irq_sgi_eoi,
+ .irq_set_type = exynos_irq_sgi_set_type,
+};
+
+/*
+ * exynos_init_irq_sgi
+ *
+ * Setup the SGI IRQ to a dummy GIC. The interrupts use the same id
+ * as provided by get_irqnr_and_base, no demuxing is necesarry but
+ * we are handling the last 8 SGIs as normal interrupts in
+ * get_irqnr_and_base.
+ *
+ * NOTE: SGIs are bound to the CPU for which they have been generated
+ * so use with care.
+ */
+int __init exynos_init_irq_sgi(void)
+{
+ int irq;
+
+ for (irq = 8; irq <= 15; irq++) {
+ irq_set_chip_and_handler(IRQ_SGI(irq), &exynos_irq_sgi, handle_fasteoi_irq);
+ set_irq_flags(IRQ_SGI(irq), IRQF_VALID);
+ }
+
+ return 0;
+}
+arch_initcall(exynos_init_irq_sgi);
diff --git a/arch/arm/mach-exynos/mach-armlex4210.c b/arch/arm/mach-exynos/mach-armlex4210.c
index d726fcd..6ce2148 100644
--- a/arch/arm/mach-exynos/mach-armlex4210.c
+++ b/arch/arm/mach-exynos/mach-armlex4210.c
@@ -157,7 +157,6 @@
&s3c_device_hsmmc3,
&s3c_device_rtc,
&s3c_device_wdt,
- &exynos4_device_sysmmu,
&samsung_asoc_dma,
&armlex4210_smsc911x,
&exynos4_device_ahci,
diff --git a/arch/arm/mach-exynos/mach-nuri.c b/arch/arm/mach-exynos/mach-nuri.c
index ed90aef..d5981dd 100644
--- a/arch/arm/mach-exynos/mach-nuri.c
+++ b/arch/arm/mach-exynos/mach-nuri.c
@@ -48,7 +48,6 @@
#include <plat/gpio-cfg.h>
#include <plat/iic.h>
#include <plat/mfc.h>
-#include <plat/pd.h>
#include <plat/fimc-core.h>
#include <plat/camport.h>
#include <plat/mipi_csis.h>
diff --git a/arch/arm/mach-exynos/mach-origen.c b/arch/arm/mach-exynos/mach-origen.c
index 878d4c9..a734e93 100644
--- a/arch/arm/mach-exynos/mach-origen.c
+++ b/arch/arm/mach-exynos/mach-origen.c
@@ -38,7 +38,6 @@
#include <plat/clock.h>
#include <plat/gpio-cfg.h>
#include <plat/backlight.h>
-#include <plat/pd.h>
#include <plat/fb.h>
#include <plat/mfc.h>
diff --git a/arch/arm/mach-exynos/mach-smdk5250.c b/arch/arm/mach-exynos/mach-smdk5250.c
new file mode 100644
index 0000000..f4f0dfd
--- /dev/null
+++ b/arch/arm/mach-exynos/mach-smdk5250.c
@@ -0,0 +1,2113 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * 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.
+*/
+
+#include <linux/platform_device.h>
+#include <linux/serial_core.h>
+#include <linux/cma.h>
+#include <linux/gpio.h>
+#include <linux/mmc/host.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/i2c.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/fixed.h>
+#include <linux/mfd/wm8994/pdata.h>
+#include <linux/pwm_backlight.h>
+#include <linux/input.h>
+#include <linux/gpio_event.h>
+#include <linux/platform_data/exynos_usb3_drd.h>
+#include <linux/persistent_ram.h>
+#include <linux/clk.h>
+#include <linux/spi/spi.h>
+#include <linux/ion.h>
+
+#include <video/platform_lcd.h>
+#include <video/s5p-dp.h>
+
+#include <asm/mach/arch.h>
+#include <asm/hardware/gic.h>
+#include <asm/mach-types.h>
+
+#include <media/m5mols.h>
+#include <media/exynos_gscaler.h>
+#include <media/exynos_flite.h>
+#include <media/exynos_fimc_is.h>
+
+#include <plat/adc.h>
+#include <plat/clock.h>
+#include <plat/cpu.h>
+#include <plat/fb.h>
+#include <plat/dp.h>
+#include <plat/regs-serial.h>
+#include <plat/gpio-cfg.h>
+#include <plat/backlight.h>
+#include <plat/devs.h>
+#include <plat/regs-fb-v4.h>
+#include <plat/iic.h>
+#include <plat/mipi_csis.h>
+#include <plat/jpeg.h>
+#include <plat/tv-core.h>
+#include <plat/ehci.h>
+#include <plat/s3c64xx-spi.h>
+
+#include <mach/exynos_fiq_debugger.h>
+#include <mach/map.h>
+#include <mach/sysmmu.h>
+#include <mach/exynos-ion.h>
+#include <mach/exynos-mfc.h>
+#include <mach/tmu.h>
+#include <mach/dwmci.h>
+#include <mach/ohci.h>
+#include <mach/spi-clocks.h>
+
+#include <plat/dsim.h>
+#include <plat/mipi_dsi.h>
+#include <plat/fimg2d.h>
+
+#include "common.h"
+
+static struct platform_device ramconsole_device = {
+ .name = "ram_console",
+ .id = -1,
+};
+
+static struct platform_device persistent_trace_device = {
+ .name = "persistent_trace",
+ .id = -1,
+};
+
+/* Following are default values for UCON, ULCON and UFCON UART registers */
+#define SMDK5250_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | \
+ S3C2410_UCON_RXILEVEL | \
+ S3C2410_UCON_TXIRQMODE | \
+ S3C2410_UCON_RXIRQMODE | \
+ S3C2410_UCON_RXFIFO_TOI | \
+ S3C2443_UCON_RXERR_IRQEN)
+
+#define SMDK5250_ULCON_DEFAULT S3C2410_LCON_CS8
+
+#define SMDK5250_UFCON_DEFAULT (S3C2410_UFCON_FIFOMODE | \
+ S5PV210_UFCON_TXTRIG4 | \
+ S5PV210_UFCON_RXTRIG4)
+
+static struct s3c2410_uartcfg smdk5250_uartcfgs[] __initdata = {
+ [0] = {
+ .hwport = 0,
+ .flags = 0,
+ .ucon = SMDK5250_UCON_DEFAULT,
+ .ulcon = SMDK5250_ULCON_DEFAULT,
+ .ufcon = SMDK5250_UFCON_DEFAULT,
+ },
+ [1] = {
+ .hwport = 1,
+ .flags = 0,
+ .ucon = SMDK5250_UCON_DEFAULT,
+ .ulcon = SMDK5250_ULCON_DEFAULT,
+ .ufcon = SMDK5250_UFCON_DEFAULT,
+ },
+ [2] = {
+#ifndef CONFIG_EXYNOS_FIQ_DEBUGGER
+ /*
+ * Don't need to initialize hwport 2, when FIQ debugger is
+ * enabled. Because it will be handled by fiq_debugger.
+ */
+ .hwport = 2,
+ .flags = 0,
+ .ucon = SMDK5250_UCON_DEFAULT,
+ .ulcon = SMDK5250_ULCON_DEFAULT,
+ .ufcon = SMDK5250_UFCON_DEFAULT,
+ },
+ [3] = {
+#endif
+ .hwport = 3,
+ .flags = 0,
+ .ucon = SMDK5250_UCON_DEFAULT,
+ .ulcon = SMDK5250_ULCON_DEFAULT,
+ .ufcon = SMDK5250_UFCON_DEFAULT,
+ },
+};
+
+static struct gpio_event_direct_entry smdk5250_keypad_key_map[] = {
+ {
+ .gpio = EXYNOS5_GPX0(0),
+ .code = KEY_POWER,
+ }
+};
+
+static struct gpio_event_input_info smdk5250_keypad_key_info = {
+ .info.func = gpio_event_input_func,
+ .info.no_suspend = true,
+ .debounce_time.tv64 = 5 * NSEC_PER_MSEC,
+ .type = EV_KEY,
+ .keymap = smdk5250_keypad_key_map,
+ .keymap_size = ARRAY_SIZE(smdk5250_keypad_key_map)
+};
+
+static struct gpio_event_info *smdk5250_input_info[] = {
+ &smdk5250_keypad_key_info.info,
+};
+
+static struct gpio_event_platform_data smdk5250_input_data = {
+ .names = {
+ "smdk5250-keypad",
+ NULL,
+ },
+ .info = smdk5250_input_info,
+ .info_count = ARRAY_SIZE(smdk5250_input_info),
+};
+
+static struct platform_device smdk5250_input_device = {
+ .name = GPIO_EVENT_DEV_NAME,
+ .id = 0,
+ .dev = {
+ .platform_data = &smdk5250_input_data,
+ },
+};
+
+static void __init smdk5250_gpio_power_init(void)
+{
+ int err = 0;
+
+ err = gpio_request_one(EXYNOS5_GPX0(0), 0, "GPX0");
+ if (err) {
+ printk(KERN_ERR "failed to request GPX0 for "
+ "suspend/resume control\n");
+ return;
+ }
+ s3c_gpio_setpull(EXYNOS5_GPX0(0), S3C_GPIO_PULL_NONE);
+
+ gpio_free(EXYNOS5_GPX0(0));
+}
+
+#ifdef CONFIG_EXYNOS_MEDIA_DEVICE
+struct platform_device exynos_device_md0 = {
+ .name = "exynos-mdev",
+ .id = 0,
+};
+
+struct platform_device exynos_device_md1 = {
+ .name = "exynos-mdev",
+ .id = 1,
+};
+
+struct platform_device exynos_device_md2 = {
+ .name = "exynos-mdev",
+ .id = 2,
+};
+#endif
+
+#ifdef CONFIG_VIDEO_EXYNOS_FIMC_LITE
+#if defined(CONFIG_ITU_A)
+static int smdk5250_cam0_reset(int dummy)
+{
+ int err;
+ /* Camera A */
+ err = gpio_request(EXYNOS5_GPX1(2), "GPX1");
+ if (err)
+ printk(KERN_ERR "#### failed to request GPX1_2 ####\n");
+
+ s3c_gpio_setpull(EXYNOS5_GPX1(2), S3C_GPIO_PULL_NONE);
+ gpio_direction_output(EXYNOS5_GPX1(2), 0);
+ gpio_direction_output(EXYNOS5_GPX1(2), 1);
+ gpio_free(EXYNOS5_GPX1(2));
+
+ return 0;
+}
+#endif
+#if defined(CONFIG_ITU_B)
+static int smdk5250_cam1_reset(int dummy)
+{
+ int err;
+ /* Camera A */
+ err = gpio_request(EXYNOS5_GPX1(0), "GPX1");
+ if (err)
+ printk(KERN_ERR "#### failed to request GPX1_2 ####\n");
+
+ s3c_gpio_setpull(EXYNOS5_GPX1(0), S3C_GPIO_PULL_NONE);
+ gpio_direction_output(EXYNOS5_GPX1(0), 0);
+ gpio_direction_output(EXYNOS5_GPX1(0), 1);
+ gpio_free(EXYNOS5_GPX1(0));
+
+ return 0;
+}
+#endif
+
+/* 1 MIPI Cameras */
+#ifdef CONFIG_VIDEO_M5MOLS
+static struct m5mols_platform_data m5mols_platdata = {
+#ifdef CONFIG_CSI_C
+ .gpio_rst = EXYNOS5_GPX1(2), /* ISP_RESET */
+#endif
+#ifdef CONFIG_CSI_D
+ .gpio_rst = EXYNOS5_GPX1(0), /* ISP_RESET */
+#endif
+ .enable_rst = true, /* positive reset */
+ .irq = IRQ_EINT(22),
+};
+
+static struct i2c_board_info m5mols_board_info = {
+ I2C_BOARD_INFO("M5MOLS", 0x1F),
+ .platform_data = &m5mols_platdata,
+};
+#endif
+#endif /* CONFIG_VIDEO_EXYNOS_FIMC_LITE */
+
+#ifdef CONFIG_VIDEO_EXYNOS_MIPI_CSIS
+static struct regulator_consumer_supply mipi_csi_fixed_voltage_supplies[] = {
+ REGULATOR_SUPPLY("mipi_csi", "s5p-mipi-csis.0"),
+ REGULATOR_SUPPLY("mipi_csi", "s5p-mipi-csis.1"),
+};
+
+static struct regulator_init_data mipi_csi_fixed_voltage_init_data = {
+ .constraints = {
+ .always_on = 1,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(mipi_csi_fixed_voltage_supplies),
+ .consumer_supplies = mipi_csi_fixed_voltage_supplies,
+};
+
+static struct fixed_voltage_config mipi_csi_fixed_voltage_config = {
+ .supply_name = "DC_5V",
+ .microvolts = 5000000,
+ .gpio = -EINVAL,
+ .init_data = &mipi_csi_fixed_voltage_init_data,
+};
+
+static struct platform_device mipi_csi_fixed_voltage = {
+ .name = "reg-fixed-voltage",
+ .id = 3,
+ .dev = {
+ .platform_data = &mipi_csi_fixed_voltage_config,
+ },
+};
+#endif
+
+#ifdef CONFIG_VIDEO_M5MOLS
+static struct regulator_consumer_supply m5mols_fixed_voltage_supplies[] = {
+ REGULATOR_SUPPLY("core", NULL),
+ REGULATOR_SUPPLY("dig_18", NULL),
+ REGULATOR_SUPPLY("d_sensor", NULL),
+ REGULATOR_SUPPLY("dig_28", NULL),
+ REGULATOR_SUPPLY("a_sensor", NULL),
+ REGULATOR_SUPPLY("dig_12", NULL),
+};
+
+static struct regulator_init_data m5mols_fixed_voltage_init_data = {
+ .constraints = {
+ .always_on = 1,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(m5mols_fixed_voltage_supplies),
+ .consumer_supplies = m5mols_fixed_voltage_supplies,
+};
+
+static struct fixed_voltage_config m5mols_fixed_voltage_config = {
+ .supply_name = "CAM_SENSOR",
+ .microvolts = 1800000,
+ .gpio = -EINVAL,
+ .init_data = &m5mols_fixed_voltage_init_data,
+};
+
+static struct platform_device m5mols_fixed_voltage = {
+ .name = "reg-fixed-voltage",
+ .id = 4,
+ .dev = {
+ .platform_data = &m5mols_fixed_voltage_config,
+ },
+};
+#endif
+
+#if defined CONFIG_VIDEO_EXYNOS5_FIMC_IS
+static struct exynos5_platform_fimc_is exynos5_fimc_is_data;
+
+#if defined CONFIG_VIDEO_S5K4E5
+static struct exynos5_fimc_is_sensor_info s5k4e5 = {
+ .sensor_name = "S5K4E5",
+ .sensor_id = SENSOR_NAME_S5K4E5,
+#if defined CONFIG_S5K4E5_POSITION_FRONT
+ .sensor_position = SENSOR_POSITION_FRONT,
+#elif defined CONFIG_S5K4E5_POSITION_REAR
+ .sensor_position = SENSOR_POSITION_REAR,
+#endif
+#if defined CONFIG_S5K4E5_CSI_C
+ .csi_id = CSI_ID_A,
+ .flite_id = FLITE_ID_A,
+ .i2c_channel = SENSOR_CONTROL_I2C0,
+#elif defined CONFIG_S5K4E5_CSI_D
+ .csi_id = CSI_ID_B,
+ .flite_id = FLITE_ID_B,
+ .i2c_channel = SENSOR_CONTROL_I2C1,
+#endif
+ .max_width = 2560,
+ .max_height = 1920,
+ .max_frame_rate = 30,
+
+ .mipi_lanes = 2,
+ .mipi_settle = 12,
+ .mipi_align = 24,
+ .sensor_gpio = {
+ .cfg[0] = {
+ .pin = EXYNOS5_GPE0(0),
+ .name = "GPE0",
+ .value = (2<<0),
+ .act = GPIO_PULL_NONE,
+ },
+ .cfg[1] = {
+ .pin = EXYNOS5_GPE0(1),
+ .name = "GPE0",
+ .value = (2<<4),
+ .act = GPIO_PULL_NONE,
+ },
+ .cfg[2] = {
+ .pin = EXYNOS5_GPE0(2),
+ .name = "GPE0",
+ .value = (3<<8),
+ .act = GPIO_PULL_NONE,
+ },
+ .cfg[3] = {
+ .pin = EXYNOS5_GPE0(3),
+ .name = "GPE0",
+ .value = (3<<12),
+ .act = GPIO_PULL_NONE,
+ },
+ .cfg[4] = {
+ .pin = EXYNOS5_GPE0(4),
+ .name = "GPE0",
+ .value = (3<<16),
+ .act = GPIO_PULL_NONE,
+ },
+ .cfg[5] = {
+ .pin = EXYNOS5_GPE0(5),
+ .name = "GPE0",
+ .value = (3<<20),
+ .act = GPIO_PULL_NONE,
+ },
+ .cfg[6] = {
+ .pin = EXYNOS5_GPE0(6),
+ .name = "GPE0",
+ .value = (3<<24),
+ .act = GPIO_PULL_NONE,
+ },
+ .cfg[7] = {
+ .pin = EXYNOS5_GPE0(7),
+ .name = "GPE0",
+ .value = (3<<28),
+ .act = GPIO_PULL_NONE,
+ },
+ .cfg[8] = {
+ .pin = EXYNOS5_GPE1(0),
+ .name = "GPE1",
+ .value = (3<<0),
+ .act = GPIO_PULL_NONE,
+ },
+ .cfg[9] = {
+ .pin = EXYNOS5_GPE1(1),
+ .name = "GPE1",
+ .value = (3<<4),
+ .act = GPIO_PULL_NONE,
+ },
+ .cfg[10] = {
+ .pin = EXYNOS5_GPF0(0),
+ .name = "GPF0",
+ .value = (2<<0),
+ .act = GPIO_PULL_NONE,
+ },
+ .cfg[11] = {
+ .pin = EXYNOS5_GPF0(1),
+ .name = "GPF0",
+ .value = (2<<4),
+ .act = GPIO_PULL_NONE,
+ },
+ .cfg[12] = {
+ .pin = EXYNOS5_GPF0(2),
+ .name = "GPF0",
+ .value = (2<<8),
+ .act = GPIO_PULL_NONE,
+ },
+ .cfg[13] = {
+ .pin = EXYNOS5_GPF0(3),
+ .name = "GPF0",
+ .value = (2<<12),
+ .act = GPIO_PULL_NONE,
+ },
+ .cfg[14] = {
+ .pin = EXYNOS5_GPF1(0),
+ .name = "GPF1",
+ .value = (3<<0),
+ .act = GPIO_PULL_NONE,
+ },
+ .cfg[15] = {
+ .pin = EXYNOS5_GPF1(1),
+ .name = "GPF1",
+ .value = (3<<4),
+ .act = GPIO_PULL_NONE,
+ },
+ .cfg[16] = {
+ .pin = EXYNOS5_GPG2(1),
+ .name = "GPG2",
+ .value = (2<<4),
+ .act = GPIO_PULL_NONE,
+ },
+ .cfg[17] = {
+ .pin = EXYNOS5_GPH0(3),
+ .name = "GPH0",
+ .value = (2<<12),
+ .act = GPIO_PULL_NONE,
+ },
+ .reset_myself = {
+ .pin = EXYNOS5_GPX1(0),
+ .name = "GPX1",
+ .value = 0,
+ .act = GPIO_RESET,
+
+ },
+ },
+};
+#endif
+
+#if defined CONFIG_VIDEO_S5K6A3
+static struct exynos5_fimc_is_sensor_info s5k6a3 = {
+ .sensor_name = "S5K6A3",
+ .sensor_id = SENSOR_NAME_S5K6A3,
+#if defined CONFIG_S5K6A3_POSITION_FRONT
+ .sensor_position = SENSOR_POSITION_FRONT,
+#elif defined CONFIG_S5K6A3_POSITION_REAR
+ .sensor_position = SENSOR_POSITION_REAR,
+#endif
+#if defined CONFIG_S5K6A3_CSI_C
+ .csi_id = CSI_ID_A,
+ .flite_id = FLITE_ID_A,
+ .i2c_channel = SENSOR_CONTROL_I2C0,
+#elif defined CONFIG_S5K6A3_CSI_D
+ .csi_id = CSI_ID_B,
+ .flite_id = FLITE_ID_B,
+ .i2c_channel = SENSOR_CONTROL_I2C1,
+#endif
+ .max_width = 1280,
+ .max_height = 720,
+ .max_frame_rate = 30,
+
+ .mipi_lanes = 1,
+ .mipi_settle = 12,
+ .mipi_align = 24,
+ .sensor_gpio = {
+ .cfg[0] = {
+ .pin = EXYNOS5_GPE0(0),
+ .name = "GPE0",
+ .value = (2<<0),
+ .act = GPIO_PULL_NONE,
+ },
+ .cfg[1] = {
+ .pin = EXYNOS5_GPE0(1),
+ .name = "GPE0",
+ .value = (2<<4),
+ .act = GPIO_PULL_NONE,
+ },
+ .cfg[2] = {
+ .pin = EXYNOS5_GPE0(2),
+ .name = "GPE0",
+ .value = (3<<8),
+ .act = GPIO_PULL_NONE,
+ },
+ .cfg[3] = {
+ .pin = EXYNOS5_GPE0(3),
+ .name = "GPE0",
+ .value = (3<<12),
+ .act = GPIO_PULL_NONE,
+ },
+ .cfg[4] = {
+ .pin = EXYNOS5_GPE0(4),
+ .name = "GPE0",
+ .value = (3<<16),
+ .act = GPIO_PULL_NONE,
+ },
+ .cfg[5] = {
+ .pin = EXYNOS5_GPE0(5),
+ .name = "GPE0",
+ .value = (3<<20),
+ .act = GPIO_PULL_NONE,
+ },
+ .cfg[6] = {
+ .pin = EXYNOS5_GPE0(6),
+ .name = "GPE0",
+ .value = (3<<24),
+ .act = GPIO_PULL_NONE,
+ },
+ .cfg[7] = {
+ .pin = EXYNOS5_GPE0(7),
+ .name = "GPE0",
+ .value = (3<<28),
+ .act = GPIO_PULL_NONE,
+ },
+ .cfg[8] = {
+ .pin = EXYNOS5_GPE1(0),
+ .name = "GPE1",
+ .value = (3<<0),
+ .act = GPIO_PULL_NONE,
+ },
+ .cfg[9] = {
+ .pin = EXYNOS5_GPE1(1),
+ .name = "GPE1",
+ .value = (3<<4),
+ .act = GPIO_PULL_NONE,
+ },
+ .cfg[10] = {
+ .pin = EXYNOS5_GPF0(0),
+ .name = "GPF0",
+ .value = (2<<0),
+ .act = GPIO_PULL_NONE,
+ },
+ .cfg[11] = {
+ .pin = EXYNOS5_GPF0(1),
+ .name = "GPF0",
+ .value = (2<<4),
+ .act = GPIO_PULL_NONE,
+ },
+ .cfg[12] = {
+ .pin = EXYNOS5_GPF0(2),
+ .name = "GPF0",
+ .value = (2<<8),
+ .act = GPIO_PULL_NONE,
+ },
+ .cfg[13] = {
+ .pin = EXYNOS5_GPF0(3),
+ .name = "GPF0",
+ .value = (2<<12),
+ .act = GPIO_PULL_NONE,
+ },
+ .cfg[14] = {
+ .pin = EXYNOS5_GPF1(0),
+ .name = "GPF1",
+ .value = (3<<0),
+ .act = GPIO_PULL_NONE,
+ },
+ .cfg[15] = {
+ .pin = EXYNOS5_GPF1(1),
+ .name = "GPF1",
+ .value = (3<<4),
+ .act = GPIO_PULL_NONE,
+ },
+ .cfg[16] = {
+ .pin = EXYNOS5_GPG2(1),
+ .name = "GPG2",
+ .value = (2<<4),
+ .act = GPIO_PULL_NONE,
+ },
+ .cfg[17] = {
+ .pin = EXYNOS5_GPH0(3),
+ .name = "GPH0",
+ .value = (2<<12),
+ .act = GPIO_PULL_NONE,
+ },
+ .reset_myself = {
+ .pin = EXYNOS5_GPX1(2),
+ .name = "GPX1",
+ .value = 0,
+ .act = GPIO_RESET,
+
+ },
+ },
+};
+#endif
+#endif
+static struct regulator_consumer_supply wm8994_fixed_voltage0_supplies[] = {
+ REGULATOR_SUPPLY("AVDD2", "1-001a"),
+ REGULATOR_SUPPLY("CPVDD", "1-001a"),
+};
+
+static struct regulator_consumer_supply wm8994_fixed_voltage1_supplies[] = {
+ REGULATOR_SUPPLY("SPKVDD1", "1-001a"),
+ REGULATOR_SUPPLY("SPKVDD2", "1-001a"),
+};
+
+static struct regulator_consumer_supply wm8994_fixed_voltage2_supplies =
+ REGULATOR_SUPPLY("DBVDD", "1-001a");
+
+static struct regulator_init_data wm8994_fixed_voltage0_init_data = {
+ .constraints = {
+ .always_on = 1,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(wm8994_fixed_voltage0_supplies),
+ .consumer_supplies = wm8994_fixed_voltage0_supplies,
+};
+
+static struct regulator_init_data wm8994_fixed_voltage1_init_data = {
+ .constraints = {
+ .always_on = 1,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(wm8994_fixed_voltage1_supplies),
+ .consumer_supplies = wm8994_fixed_voltage1_supplies,
+};
+
+static struct regulator_init_data wm8994_fixed_voltage2_init_data = {
+ .constraints = {
+ .always_on = 1,
+ },
+ .num_consumer_supplies = 1,
+ .consumer_supplies = &wm8994_fixed_voltage2_supplies,
+};
+
+static struct fixed_voltage_config wm8994_fixed_voltage0_config = {
+ .supply_name = "VDD_1.8V",
+ .microvolts = 1800000,
+ .gpio = -EINVAL,
+ .init_data = &wm8994_fixed_voltage0_init_data,
+};
+
+static struct fixed_voltage_config wm8994_fixed_voltage1_config = {
+ .supply_name = "DC_5V",
+ .microvolts = 5000000,
+ .gpio = -EINVAL,
+ .init_data = &wm8994_fixed_voltage1_init_data,
+};
+
+static struct fixed_voltage_config wm8994_fixed_voltage2_config = {
+ .supply_name = "VDD_3.3V",
+ .microvolts = 3300000,
+ .gpio = -EINVAL,
+ .init_data = &wm8994_fixed_voltage2_init_data,
+};
+
+static struct platform_device wm8994_fixed_voltage0 = {
+ .name = "reg-fixed-voltage",
+ .id = 0,
+ .dev = {
+ .platform_data = &wm8994_fixed_voltage0_config,
+ },
+};
+
+static struct platform_device wm8994_fixed_voltage1 = {
+ .name = "reg-fixed-voltage",
+ .id = 1,
+ .dev = {
+ .platform_data = &wm8994_fixed_voltage1_config,
+ },
+};
+
+static struct platform_device wm8994_fixed_voltage2 = {
+ .name = "reg-fixed-voltage",
+ .id = 2,
+ .dev = {
+ .platform_data = &wm8994_fixed_voltage2_config,
+ },
+};
+
+static struct regulator_consumer_supply wm8994_avdd1_supply =
+ REGULATOR_SUPPLY("AVDD1", "1-001a");
+
+static struct regulator_consumer_supply wm8994_dcvdd_supply =
+ REGULATOR_SUPPLY("DCVDD", "1-001a");
+
+static struct regulator_init_data wm8994_ldo1_data = {
+ .constraints = {
+ .name = "AVDD1",
+ },
+ .num_consumer_supplies = 1,
+ .consumer_supplies = &wm8994_avdd1_supply,
+};
+
+static struct regulator_init_data wm8994_ldo2_data = {
+ .constraints = {
+ .name = "DCVDD",
+ },
+ .num_consumer_supplies = 1,
+ .consumer_supplies = &wm8994_dcvdd_supply,
+};
+
+static struct wm8994_pdata wm8994_platform_data = {
+ /* configure gpio1 function: 0x0001(Logic level input/output) */
+ .gpio_defaults[0] = 0x0001,
+ /* If the i2s0 and i2s2 is enabled simultaneously */
+ .gpio_defaults[7] = 0x8100, /* GPIO8 DACDAT3 in */
+ .gpio_defaults[8] = 0x0100, /* GPIO9 ADCDAT3 out */
+ .gpio_defaults[9] = 0x0100, /* GPIO10 LRCLK3 out */
+ .gpio_defaults[10] = 0x0100,/* GPIO11 BCLK3 out */
+ .ldo[0] = { 0, &wm8994_ldo1_data },
+ .ldo[1] = { 0, &wm8994_ldo2_data },
+};
+
+static struct i2c_board_info i2c_devs0[] __initdata = {
+ {
+ I2C_BOARD_INFO("s5m87xx", 0xCC >> 1),
+ .irq = IRQ_EINT(26),
+ },
+};
+
+static struct i2c_board_info i2c_devs1[] __initdata = {
+ {
+ I2C_BOARD_INFO("wm8994", 0x1a),
+ .platform_data = &wm8994_platform_data,
+ },
+};
+
+static struct i2c_board_info i2c_devs2[] __initdata = {
+ {
+ I2C_BOARD_INFO("exynos_hdcp", (0x74 >> 1)),
+ },
+};
+
+static struct i2c_board_info i2c_devs7[] __initdata = {
+ {
+ I2C_BOARD_INFO("egalax_i2c", 0x04),
+ .irq = IRQ_EINT(25),
+ },
+};
+
+/* ADC */
+static struct s3c_adc_platdata smdk5250_adc_data __initdata = {
+ .phy_init = s3c_adc_phy_init,
+ .phy_exit = s3c_adc_phy_exit,
+};
+
+#if defined(CONFIG_VIDEO_EXYNOS_TV) && defined(CONFIG_VIDEO_EXYNOS_HDMI)
+static struct s5p_hdmi_platdata hdmi_platdata __initdata = {
+};
+#endif
+
+#if defined(CONFIG_VIDEO_EXYNOS_TV) && defined(CONFIG_VIDEO_EXYNOS_HDMI_CEC)
+static struct s5p_platform_cec hdmi_cec_data __initdata = {
+
+};
+#endif
+
+#ifdef CONFIG_VIDEO_EXYNOS_FIMC_LITE
+static void __init smdk5250_camera_gpio_cfg(void)
+{
+ /* CAM A port(b0010) : PCLK, VSYNC, HREF, CLK_OUT */
+ s3c_gpio_cfgrange_nopull(EXYNOS5_GPH0(0), 4, S3C_GPIO_SFN(2));
+ /* CAM A port(b0010) : DATA[0-7] */
+ s3c_gpio_cfgrange_nopull(EXYNOS5_GPH1(0), 8, S3C_GPIO_SFN(2));
+ /* CAM B port(b0010) : PCLK, BAY_RGB[0-6] */
+ s3c_gpio_cfgrange_nopull(EXYNOS5_GPG0(0), 8, S3C_GPIO_SFN(2));
+ /* CAM B port(b0010) : BAY_Vsync, BAY_RGB[7-13] */
+ s3c_gpio_cfgrange_nopull(EXYNOS5_GPG1(0), 8, S3C_GPIO_SFN(2));
+ /* CAM B port(b0010) : BAY_Hsync, BAY_MCLK */
+ s3c_gpio_cfgrange_nopull(EXYNOS5_GPG2(0), 2, S3C_GPIO_SFN(2));
+ /* This is externel interrupt for m5mo */
+#ifdef CONFIG_VIDEO_M5MOLS
+ s3c_gpio_cfgpin(EXYNOS5_GPX2(6), S3C_GPIO_SFN(0xF));
+ s3c_gpio_setpull(EXYNOS5_GPX2(6), S3C_GPIO_PULL_NONE);
+#endif
+}
+#endif
+
+#if defined(CONFIG_VIDEO_EXYNOS_GSCALER) && defined(CONFIG_VIDEO_EXYNOS_FIMC_LITE)
+#if defined(CONFIG_VIDEO_M5MOLS)
+static struct exynos_isp_info m5mols = {
+ .board_info = &m5mols_board_info,
+ .cam_srclk_name = "xxti",
+ .clk_frequency = 24000000UL,
+ .bus_type = CAM_TYPE_MIPI,
+#ifdef CONFIG_CSI_C
+ .cam_clk_name = "sclk_cam0",
+ .i2c_bus_num = 4,
+ .cam_port = CAM_PORT_A, /* A-Port : 0, B-Port : 1 */
+#endif
+#ifdef CONFIG_CSI_D
+ .cam_clk_name = "sclk_cam1",
+ .i2c_bus_num = 5,
+ .cam_port = CAM_PORT_B, /* A-Port : 0, B-Port : 1 */
+#endif
+ .flags = CAM_CLK_INV_PCLK | CAM_CLK_INV_VSYNC,
+ .csi_data_align = 32,
+};
+/* This is for platdata of fimc-lite */
+static struct s3c_platform_camera flite_m5mo = {
+ .type = CAM_TYPE_MIPI,
+ .use_isp = true,
+ .inv_pclk = 1,
+ .inv_vsync = 1,
+ .inv_href = 0,
+ .inv_hsync = 0,
+};
+#endif
+
+static void __set_gsc_camera_config(struct exynos_platform_gscaler *data,
+ u32 active_index, u32 preview,
+ u32 camcording, u32 max_cam)
+{
+ data->active_cam_index = active_index;
+ data->cam_preview = preview;
+ data->cam_camcording = camcording;
+ data->num_clients = max_cam;
+}
+
+static void __set_flite_camera_config(struct exynos_platform_flite *data,
+ u32 active_index, u32 max_cam)
+{
+ data->active_cam_index = active_index;
+ data->num_clients = max_cam;
+}
+
+static void __init smdk5250_set_camera_platdata(void)
+{
+ int gsc_cam_index = 0;
+ int flite0_cam_index = 0;
+ int flite1_cam_index = 0;
+#if defined(CONFIG_VIDEO_M5MOLS)
+ exynos_gsc0_default_data.isp_info[gsc_cam_index++] = &m5mols;
+#if defined(CONFIG_CSI_C)
+ exynos_flite0_default_data.cam[flite0_cam_index] = &flite_m5mo;
+ exynos_flite0_default_data.isp_info[flite0_cam_index] = &m5mols;
+ flite0_cam_index++;
+#endif
+#if defined(CONFIG_CSI_D)
+ exynos_flite1_default_data.cam[flite1_cam_index] = &flite_m5mo;
+ exynos_flite1_default_data.isp_info[flite1_cam_index] = &m5mols;
+ flite1_cam_index++;
+#endif
+#endif
+ /* flite platdata register */
+ __set_flite_camera_config(&exynos_flite0_default_data, 0, flite0_cam_index);
+ __set_flite_camera_config(&exynos_flite1_default_data, 0, flite1_cam_index);
+
+ /* gscaler platdata register */
+ /* GSC-0 */
+ __set_gsc_camera_config(&exynos_gsc0_default_data, 0, 1, 0, gsc_cam_index);
+
+ /* GSC-1 */
+ /* GSC-2 */
+ /* GSC-3 */
+}
+#endif /* CONFIG_VIDEO_EXYNOS_GSCALER */
+
+static void exynos_dwmci0_cfg_gpio(int width)
+{
+ unsigned int gpio;
+
+ for (gpio = EXYNOS5_GPC0(0); gpio < EXYNOS5_GPC0(2); gpio++) {
+ s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
+ s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
+ s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4);
+ }
+
+ switch (width) {
+ case 8:
+ for (gpio = EXYNOS5_GPC1(0); gpio <= EXYNOS5_GPC1(3); gpio++) {
+ s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
+ s3c_gpio_setpull(gpio, S3C_GPIO_PULL_UP);
+ s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4);
+ }
+ case 4:
+ for (gpio = EXYNOS5_GPC0(3); gpio <= EXYNOS5_GPC0(6); gpio++) {
+ s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
+ s3c_gpio_setpull(gpio, S3C_GPIO_PULL_UP);
+ s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4);
+ }
+ break;
+ case 1:
+ gpio = EXYNOS5_GPC0(3);
+ s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
+ s3c_gpio_setpull(gpio, S3C_GPIO_PULL_UP);
+ s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4);
+ default:
+ break;
+ }
+}
+
+static struct dw_mci_board exynos_dwmci0_pdata __initdata = {
+ .num_slots = 1,
+ .quirks = DW_MCI_QUIRK_BROKEN_CARD_DETECTION |
+ DW_MCI_QUIRK_HIGHSPEED |
+ DW_MCI_QUIRK_NO_DETECT_EBIT,
+ .bus_hz = 200 * 1000 * 1000,
+ .max_bus_hz = 200 * 1000 * 1000,
+ .caps = MMC_CAP_UHS_DDR50 | MMC_CAP_1_8V_DDR |
+ MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23,
+ .caps2 = MMC_CAP2_HS200_1_8V_SDR | MMC_CAP2_PACKED_WR,
+ .desc_sz = 4,
+ .fifo_depth = 0x80,
+ .detect_delay_ms = 200,
+ .hclk_name = "dwmci",
+ .cclk_name = "sclk_dwmci",
+ .cfg_gpio = exynos_dwmci0_cfg_gpio,
+ .sdr_timing = 0x03020001,
+ .ddr_timing = 0x03030002,
+ .clk_drv = 0x3,
+};
+
+#ifdef CONFIG_FB_S3C
+#if defined(CONFIG_LCD_MIPI_S6E8AB0)
+static void mipi_lcd_set_power(struct plat_lcd_data *pd,
+ unsigned int power)
+{
+ /* reset */
+ gpio_request_one(EXYNOS5_GPX1(5), GPIOF_OUT_INIT_HIGH, "GPX1");
+
+ mdelay(20);
+ if (power) {
+ /* fire nRESET on power up */
+ gpio_set_value(EXYNOS5_GPX1(5), 0);
+ mdelay(20);
+ gpio_set_value(EXYNOS5_GPX1(5), 1);
+ mdelay(20);
+ gpio_free(EXYNOS5_GPX1(5));
+ } else {
+ /* fire nRESET on power off */
+ gpio_set_value(EXYNOS5_GPX1(5), 0);
+ mdelay(20);
+ gpio_set_value(EXYNOS5_GPX1(5), 1);
+ mdelay(20);
+ gpio_free(EXYNOS5_GPX1(5));
+ }
+ mdelay(20);
+ /* power */
+ gpio_request_one(EXYNOS5_GPX3(0), GPIOF_OUT_INIT_LOW, "GPX3");
+ if (power) {
+ /* fire nRESET on power up */
+ gpio_set_value(EXYNOS5_GPX3(0), 1);
+ gpio_free(EXYNOS5_GPX3(0));
+ } else {
+ /* fire nRESET on power off */
+ gpio_set_value(EXYNOS5_GPX3(0), 0);
+ gpio_free(EXYNOS5_GPX3(0));
+ }
+
+#ifndef CONFIG_BACKLIGHT_PWM
+ /* backlight */
+ gpio_request_one(EXYNOS5_GPB2(0), GPIOF_OUT_INIT_LOW, "GPB2");
+ if (power) {
+ /* fire nRESET on power up */
+ gpio_set_value(EXYNOS5_GPB2(0), 1);
+ gpio_free(EXYNOS5_GPB2(0));
+ } else {
+ /* fire nRESET on power off */
+ gpio_set_value(EXYNOS5_GPB2(0), 0);
+ gpio_free(EXYNOS5_GPB2(0));
+ }
+#endif
+}
+
+static struct plat_lcd_data smdk5250_mipi_lcd_data = {
+ .set_power = mipi_lcd_set_power,
+};
+
+static struct platform_device smdk5250_mipi_lcd = {
+ .name = "platform-lcd",
+ .dev.platform_data = &smdk5250_mipi_lcd_data,
+};
+
+static struct s3c_fb_pd_win smdk5250_fb_win0 = {
+ .win_mode = {
+ .left_margin = 0x4,
+ .right_margin = 0x4,
+ .upper_margin = 4,
+ .lower_margin = 4,
+ .hsync_len = 4,
+ .vsync_len = 4,
+ .xres = 1280,
+ .yres = 800,
+ },
+ .virtual_x = 1280,
+ .virtual_y = 800 * 2,
+ .width = 223,
+ .height = 125,
+ .max_bpp = 32,
+ .default_bpp = 24,
+};
+
+static struct s3c_fb_pd_win smdk5250_fb_win1 = {
+ .win_mode = {
+ .left_margin = 0x4,
+ .right_margin = 0x4,
+ .upper_margin = 4,
+ .lower_margin = 4,
+ .hsync_len = 4,
+ .vsync_len = 4,
+ .xres = 1280,
+ .yres = 800,
+ },
+ .virtual_x = 1280,
+ .virtual_y = 800 * 2,
+ .width = 223,
+ .height = 125,
+ .max_bpp = 32,
+ .default_bpp = 24,
+};
+
+static struct s3c_fb_pd_win smdk5250_fb_win2 = {
+ .win_mode = {
+ .left_margin = 0x4,
+ .right_margin = 0x4,
+ .upper_margin = 4,
+ .lower_margin = 4,
+ .hsync_len = 4,
+ .vsync_len = 4,
+ .xres = 1280,
+ .yres = 800,
+ },
+ .virtual_x = 1280,
+ .virtual_y = 800 * 2,
+ .width = 223,
+ .height = 125,
+ .max_bpp = 32,
+ .default_bpp = 24,
+};
+#elif defined(CONFIG_LCD_MIPI_TC358764)
+static void mipi_lcd_set_power(struct plat_lcd_data *pd,
+ unsigned int power)
+{
+ /* reset */
+ gpio_request_one(EXYNOS5_GPX1(5), GPIOF_OUT_INIT_HIGH, "GPX1");
+
+ mdelay(20);
+ if (power) {
+ /* fire nRESET on power up */
+ gpio_set_value(EXYNOS5_GPX1(5), 0);
+ mdelay(20);
+ gpio_set_value(EXYNOS5_GPX1(5), 1);
+ mdelay(20);
+ gpio_free(EXYNOS5_GPX1(5));
+ } else {
+ /* fire nRESET on power off */
+ gpio_set_value(EXYNOS5_GPX1(5), 0);
+ mdelay(20);
+ gpio_set_value(EXYNOS5_GPX1(5), 1);
+ mdelay(20);
+ gpio_free(EXYNOS5_GPX1(5));
+ }
+ mdelay(20);
+ /* power */
+ gpio_request_one(EXYNOS5_GPX3(0), GPIOF_OUT_INIT_LOW, "GPX3");
+ if (power) {
+ /* fire nRESET on power up */
+ gpio_set_value(EXYNOS5_GPX3(0), 1);
+ gpio_free(EXYNOS5_GPX3(0));
+ } else {
+ /* fire nRESET on power off */
+ gpio_set_value(EXYNOS5_GPX3(0), 0);
+ gpio_free(EXYNOS5_GPX3(0));
+ }
+
+#ifndef CONFIG_BACKLIGHT_PWM
+ /* backlight */
+ gpio_request_one(EXYNOS5_GPB2(0), GPIOF_OUT_INIT_LOW, "GPB2");
+ if (power) {
+ /* fire nRESET on power up */
+ gpio_set_value(EXYNOS5_GPB2(0), 1);
+ gpio_free(EXYNOS5_GPB2(0));
+ } else {
+ /* fire nRESET on power off */
+ gpio_set_value(EXYNOS5_GPB2(0), 0);
+ gpio_free(EXYNOS5_GPB2(0));
+ }
+#endif
+}
+
+static struct plat_lcd_data smdk5250_mipi_lcd_data = {
+ .set_power = mipi_lcd_set_power,
+};
+
+static struct platform_device smdk5250_mipi_lcd = {
+ .name = "platform-lcd",
+ .dev.platform_data = &smdk5250_mipi_lcd_data,
+};
+
+static struct s3c_fb_pd_win smdk5250_fb_win0 = {
+ .win_mode = {
+ .left_margin = 4,
+ .right_margin = 4,
+ .upper_margin = 4,
+ .lower_margin = 4,
+ .hsync_len = 4,
+ .vsync_len = 4,
+ .xres = 1280,
+ .yres = 800,
+ },
+ .virtual_x = 1280,
+ .virtual_y = 800 * 2,
+ .width = 223,
+ .height = 125,
+ .max_bpp = 32,
+ .default_bpp = 24,
+};
+
+static struct s3c_fb_pd_win smdk5250_fb_win1 = {
+ .win_mode = {
+ .left_margin = 4,
+ .right_margin = 4,
+ .upper_margin = 4,
+ .lower_margin = 4,
+ .hsync_len = 4,
+ .vsync_len = 4,
+ .xres = 1280,
+ .yres = 800,
+ },
+ .virtual_x = 1280,
+ .virtual_y = 800 * 2,
+ .width = 223,
+ .height = 125,
+ .max_bpp = 32,
+ .default_bpp = 24,
+};
+static struct s3c_fb_pd_win smdk5250_fb_win2 = {
+ .win_mode = {
+ .left_margin = 4,
+ .right_margin = 4,
+ .upper_margin = 4,
+ .lower_margin = 4,
+ .hsync_len = 4,
+ .vsync_len = 4,
+ .xres = 1280,
+ .yres = 800,
+ },
+ .virtual_x = 1280,
+ .virtual_y = 800 * 2,
+ .width = 223,
+ .height = 125,
+ .max_bpp = 32,
+ .default_bpp = 24,
+};
+#elif defined(CONFIG_S5P_DP)
+static void s5p_dp_backlight_on(void);
+static void s5p_dp_backlight_off(void);
+
+static void s5p_lcd_on(void)
+{
+#ifndef CONFIG_BACKLIGHT_PWM
+ /* LCD_PWM_IN_2.8V: LCD_B_PWM, GPB2_0 */
+ gpio_request(EXYNOS5_GPB2(0), "GPB2");
+#endif
+ /* LCD_APS_EN_2.8V: GPD0_6 */
+ gpio_request(EXYNOS5_GPD0(6), "GPD0");
+
+ /* LCD_EN: GPD0_5 */
+ gpio_request(EXYNOS5_GPD0(5), "GPD0");
+
+ /* LCD_EN: GPD0_5 */
+ gpio_direction_output(EXYNOS5_GPD0(5), 1);
+ mdelay(20);
+
+ /* LCD_APS_EN_2.8V: GPD0_6 */
+ gpio_direction_output(EXYNOS5_GPD0(6), 1);
+ mdelay(20);
+#ifndef CONFIG_BACKLIGHT_PWM
+ /* LCD_PWM_IN_2.8V: LCD_B_PWM, GPB2_0 */
+ gpio_direction_output(EXYNOS5_GPB2(0), 1);
+
+ gpio_free(EXYNOS5_GPB2(0));
+#endif
+ gpio_free(EXYNOS5_GPD0(6));
+ gpio_free(EXYNOS5_GPD0(5));
+}
+
+static void s5p_lcd_off(void)
+{
+#ifndef CONFIG_BACKLIGHT_PWM
+ /* LCD_PWM_IN_2.8V: LCD_B_PWM, GPB2_0 */
+ gpio_request(EXYNOS5_GPB2(0), "GPB2");
+#endif
+ /* LCD_APS_EN_2.8V: GPD0_6 */
+ gpio_request(EXYNOS5_GPD0(6), "GPD0");
+
+ /* LCD_EN: GPD0_5 */
+ gpio_request(EXYNOS5_GPD0(5), "GPD0");
+
+ /* LCD_EN: GPD0_5 */
+ gpio_direction_output(EXYNOS5_GPD0(5), 0);
+ mdelay(20);
+
+ /* LCD_APS_EN_2.8V: GPD0_6 */
+ gpio_direction_output(EXYNOS5_GPD0(6), 0);
+ mdelay(20);
+#ifndef CONFIG_BACKLIGHT_PWM
+ /* LCD_PWM_IN_2.8V: LCD_B_PWM, GPB2_0 */
+ gpio_direction_output(EXYNOS5_GPB2(0), 0);
+
+ gpio_free(EXYNOS5_GPB2(0));
+#endif
+ gpio_free(EXYNOS5_GPD0(6));
+ gpio_free(EXYNOS5_GPD0(5));
+}
+
+static void dp_lcd_set_power(struct plat_lcd_data *pd,
+ unsigned int power)
+{
+ if (power)
+ s5p_lcd_on();
+ else
+ s5p_lcd_off();
+}
+
+static struct plat_lcd_data smdk5250_dp_lcd_data = {
+ .set_power = dp_lcd_set_power,
+};
+
+static struct platform_device smdk5250_dp_lcd = {
+ .name = "platform-lcd",
+ .dev = {
+ .parent = &s5p_device_fimd1.dev,
+ .platform_data = &smdk5250_dp_lcd_data,
+ },
+};
+
+static struct s3c_fb_pd_win smdk5250_fb_win2 = {
+ .win_mode = {
+ .left_margin = 80,
+ .right_margin = 48,
+ .upper_margin = 37,
+ .lower_margin = 3,
+ .hsync_len = 32,
+ .vsync_len = 6,
+ .xres = 2560,
+ .yres = 1600,
+ },
+ .virtual_x = 2560,
+ .virtual_y = 1600 * 2,
+ .max_bpp = 32,
+ .default_bpp = 24,
+};
+#endif
+
+static struct s3c_fb_platdata smdk5250_lcd1_pdata __initdata = {
+#if defined(CONFIG_LCD_MIPI_S6E8AB0)
+ .win[0] = &smdk5250_fb_win0,
+ .win[1] = &smdk5250_fb_win1,
+ .win[2] = &smdk5250_fb_win2,
+#elif defined(CONFIG_LCD_MIPI_TC358764)
+ .win[0] = &smdk5250_fb_win0,
+ .win[1] = &smdk5250_fb_win1,
+ .win[2] = &smdk5250_fb_win2,
+#elif defined(CONFIG_S5P_DP)
+ .win[0] = &smdk5250_fb_win2,
+ .win[1] = &smdk5250_fb_win2,
+ .win[2] = &smdk5250_fb_win2,
+ .win[3] = &smdk5250_fb_win2,
+ .win[4] = &smdk5250_fb_win2,
+#endif
+ .default_win = 2,
+ .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
+#if defined(CONFIG_LCD_MIPI_S6E8AB0)
+ .vidcon1 = VIDCON1_INV_VCLK,
+#elif defined(CONFIG_LCD_MIPI_TC358764)
+ .vidcon1 = VIDCON1_INV_VCLK,
+#elif defined(CONFIG_S5P_DP)
+ .vidcon1 = 0,
+#endif
+ .setup_gpio = exynos5_fimd1_gpio_setup_24bpp,
+ .backlight_off = s5p_dp_backlight_off,
+ .lcd_off = s5p_lcd_off,
+};
+
+#endif
+
+#ifdef CONFIG_FB_MIPI_DSIM
+#if defined(CONFIG_LCD_MIPI_S6E8AB0)
+static struct mipi_dsim_config dsim_info = {
+ .e_interface = DSIM_VIDEO,
+ .e_pixel_format = DSIM_24BPP_888,
+ /* main frame fifo auto flush at VSYNC pulse */
+ .auto_flush = false,
+ .eot_disable = false,
+ .auto_vertical_cnt = true,
+ .hse = false,
+ .hfp = false,
+ .hbp = false,
+ .hsa = false,
+
+ .e_no_data_lane = DSIM_DATA_LANE_4,
+ .e_byte_clk = DSIM_PLL_OUT_DIV8,
+ .e_burst_mode = DSIM_BURST,
+
+ .p = 2,
+ .m = 57,
+ .s = 1,
+ /* D-PHY PLL stable time spec :min = 200usec ~ max 400usec */
+ .pll_stable_time = 500,
+
+ .esc_clk = 20 * 1000000, /* escape clk : 10MHz */
+
+ /* stop state holding counter after bta change count 0 ~ 0xfff */
+ .stop_holding_cnt = 0x0fff,
+ .bta_timeout = 0xff, /* bta timeout 0 ~ 0xff */
+ .rx_timeout = 0xffff, /* lp rx timeout 0 ~ 0xffff */
+
+ .dsim_ddi_pd = &s6e8ab0_mipi_lcd_driver,
+};
+static struct mipi_dsim_lcd_config dsim_lcd_info = {
+ .rgb_timing.left_margin = 0xa,
+ .rgb_timing.right_margin = 0xa,
+ .rgb_timing.upper_margin = 80,
+ .rgb_timing.lower_margin = 48,
+ .rgb_timing.hsync_len = 5,
+ .rgb_timing.vsync_len = 32,
+ .cpu_timing.cs_setup = 0,
+ .cpu_timing.wr_setup = 1,
+ .cpu_timing.wr_act = 0,
+ .cpu_timing.wr_hold = 0,
+ .lcd_size.width = 1280,
+ .lcd_size.height = 800,
+};
+#elif defined (CONFIG_LCD_MIPI_TC358764)
+static struct mipi_dsim_config dsim_info = {
+ .e_interface = DSIM_VIDEO,
+ .e_pixel_format = DSIM_24BPP_888,
+ /* main frame fifo auto flush at VSYNC pulse */
+ .auto_flush = false,
+ .eot_disable = false,
+ .auto_vertical_cnt = false,
+ .hse = false,
+ .hfp = false,
+ .hbp = false,
+ .hsa = false,
+
+ .e_no_data_lane = DSIM_DATA_LANE_4,
+ .e_byte_clk = DSIM_PLL_OUT_DIV8,
+ .e_burst_mode = DSIM_BURST,
+
+ .p = 3,
+ .m = 115,
+ .s = 1,
+
+ /* D-PHY PLL stable time spec :min = 200usec ~ max 400usec */
+ .pll_stable_time = 500,
+
+ .esc_clk = 0.4 * 1000000, /* escape clk : 10MHz */
+
+ /* stop state holding counter after bta change count 0 ~ 0xfff */
+ .stop_holding_cnt = 0x0f,
+ .bta_timeout = 0xff, /* bta timeout 0 ~ 0xff */
+ .rx_timeout = 0xffff, /* lp rx timeout 0 ~ 0xffff */
+
+ .dsim_ddi_pd = &tc358764_mipi_lcd_driver,
+};
+
+static struct mipi_dsim_lcd_config dsim_lcd_info = {
+ .rgb_timing.left_margin = 0x4,
+ .rgb_timing.right_margin = 0x4,
+ .rgb_timing.upper_margin = 0x4,
+ .rgb_timing.lower_margin = 0x4,
+ .rgb_timing.hsync_len = 0x4,
+ .rgb_timing.vsync_len = 0x4,
+ .cpu_timing.cs_setup = 0,
+ .cpu_timing.wr_setup = 1,
+ .cpu_timing.wr_act = 0,
+ .cpu_timing.wr_hold = 0,
+ .lcd_size.width = 1280,
+ .lcd_size.height = 800,
+};
+#endif
+
+static struct s5p_platform_mipi_dsim dsim_platform_data = {
+ .clk_name = "dsim0",
+ .dsim_config = &dsim_info,
+ .dsim_lcd_config = &dsim_lcd_info,
+
+ .part_reset = s5p_dsim_part_reset,
+ .init_d_phy = s5p_dsim_init_d_phy,
+ .get_fb_frame_done = NULL,
+ .trigger = NULL,
+ /*
+ * the stable time of needing to write data on SFR
+ * when the mipi mode becomes LP mode.
+ */
+ .delay_for_stabilization = 600,
+};
+#endif
+
+#ifdef CONFIG_S5P_DP
+static struct video_info smdk5250_dp_config = {
+ .name = "WQXGA(2560x1600) LCD, for SMDK TEST",
+
+ .h_sync_polarity = 0,
+ .v_sync_polarity = 0,
+ .interlaced = 0,
+
+ .color_space = COLOR_RGB,
+ .dynamic_range = VESA,
+ .ycbcr_coeff = COLOR_YCBCR601,
+ .color_depth = COLOR_8,
+
+ .link_rate = LINK_RATE_2_70GBPS,
+ .lane_count = LANE_COUNT4,
+};
+
+static void s5p_dp_backlight_on(void)
+{
+ /* LED_BACKLIGHT_RESET: GPX1_5 */
+ gpio_request(EXYNOS5_GPX1(5), "GPX1");
+
+ gpio_direction_output(EXYNOS5_GPX1(5), 1);
+ mdelay(20);
+
+ gpio_free(EXYNOS5_GPX1(5));
+}
+
+static void s5p_dp_backlight_off(void)
+{
+ /* LED_BACKLIGHT_RESET: GPX1_5 */
+ gpio_request(EXYNOS5_GPX1(5), "GPX1");
+
+ gpio_direction_output(EXYNOS5_GPX1(5), 0);
+ mdelay(20);
+
+ gpio_free(EXYNOS5_GPX1(5));
+}
+
+static struct s5p_dp_platdata smdk5250_dp_data __initdata = {
+ .video_info = &smdk5250_dp_config,
+ .phy_init = s5p_dp_phy_init,
+ .phy_exit = s5p_dp_phy_exit,
+ .backlight_on = s5p_dp_backlight_on,
+ .backlight_off = s5p_dp_backlight_off,
+ .lcd_on = s5p_lcd_on,
+ .lcd_off = s5p_lcd_off,
+};
+#endif
+
+#ifdef CONFIG_VIDEO_EXYNOS_FIMG2D
+static struct fimg2d_platdata fimg2d_data __initdata = {
+ .hw_ver = 0x42,
+ .gate_clkname = "fimg2d",
+};
+#endif
+
+/* LCD Backlight data */
+static struct samsung_bl_gpio_info smdk5250_bl_gpio_info = {
+ .no = EXYNOS5_GPB2(0),
+ .func = S3C_GPIO_SFN(2),
+};
+
+static struct platform_pwm_backlight_data smdk5250_bl_data = {
+ .pwm_id = 0,
+ .pwm_period_ns = 30000,
+};
+
+/* DEVFREQ controlling mif */
+static struct platform_device exynos_bus_mif_devfreq = {
+ .name = "exynos5-bus-mif",
+};
+
+/* DEVFREQ controlling int */
+static struct platform_device exynos_bus_int_devfreq = {
+ .name = "exynos5-bus-int",
+};
+
+
+static struct platform_device *smdk5250_devices[] __initdata = {
+ &ramconsole_device,
+ &persistent_trace_device,
+ &s3c_device_rtc,
+ &s3c_device_i2c0,
+ &s3c_device_i2c1,
+ &s3c_device_i2c2,
+ &s3c_device_i2c4,
+ &s3c_device_i2c5,
+ &s3c_device_i2c7,
+ &s3c_device_adc,
+ &s3c_device_wdt,
+ &smdk5250_input_device,
+#ifdef CONFIG_VIDEO_EXYNOS_MFC
+ &s5p_device_mfc,
+#endif
+#ifdef CONFIG_ION_EXYNOS
+ &exynos_device_ion,
+#endif
+#ifdef CONFIG_EXYNOS_DEV_TMU
+ &exynos_device_tmu,
+#endif
+#ifdef CONFIG_EXYNOS_MEDIA_DEVICE
+ &exynos_device_md0,
+ &exynos_device_md1,
+ &exynos_device_md2,
+#endif
+#ifdef CONFIG_VIDEO_EXYNOS5_FIMC_IS
+ &exynos5_device_fimc_is,
+#endif
+#ifdef CONFIG_VIDEO_EXYNOS_GSCALER
+ &exynos5_device_gsc0,
+ &exynos5_device_gsc1,
+ &exynos5_device_gsc2,
+ &exynos5_device_gsc3,
+#endif
+#ifdef CONFIG_VIDEO_EXYNOS_FIMC_LITE
+ &exynos_device_flite0,
+ &exynos_device_flite1,
+#endif
+#ifdef CONFIG_VIDEO_EXYNOS_MIPI_CSIS
+ &s5p_device_mipi_csis0,
+ &s5p_device_mipi_csis1,
+ &mipi_csi_fixed_voltage,
+#endif
+#ifdef CONFIG_VIDEO_EXYNOS_FIMG2D
+ &s5p_device_fimg2d,
+#endif
+ &exynos5_device_rotator,
+#ifdef CONFIG_VIDEO_M5MOLS
+ &m5mols_fixed_voltage,
+#endif
+ &exynos5_device_dwmci0,
+#ifdef CONFIG_FB_S3C
+#ifdef CONFIG_FB_MIPI_DSIM
+ &smdk5250_mipi_lcd,
+ &s5p_device_mipi_dsim,
+#endif
+ &s5p_device_fimd1,
+#ifdef CONFIG_S5P_DP
+ &s5p_device_dp,
+ &smdk5250_dp_lcd,
+#endif
+#endif
+#ifdef CONFIG_VIDEO_EXYNOS_TV
+#ifdef CONFIG_VIDEO_EXYNOS_HDMI
+ &s5p_device_hdmi,
+#endif
+#ifdef CONFIG_VIDEO_EXYNOS_HDMIPHY
+ &s5p_device_i2c_hdmiphy,
+#endif
+#ifdef CONFIG_VIDEO_EXYNOS_MIXER
+ &s5p_device_mixer,
+#endif
+#ifdef CONFIG_VIDEO_EXYNOS_HDMI_CEC
+ &s5p_device_cec,
+#endif
+#endif
+ &wm8994_fixed_voltage0,
+ &wm8994_fixed_voltage1,
+ &wm8994_fixed_voltage2,
+ &samsung_asoc_dma,
+ &samsung_asoc_idma,
+ &exynos5_device_srp,
+ &exynos5_device_i2s0,
+ &exynos5_device_pcm0,
+ &exynos5_device_spdif,
+ &s5p_device_ehci,
+ &exynos4_device_ohci,
+ &exynos_device_ss_udc,
+#ifdef CONFIG_VIDEO_EXYNOS_JPEG
+ &s5p_device_jpeg,
+#endif
+#ifdef CONFIG_S5P_DEV_ACE
+ &s5p_device_ace,
+#endif
+ &s3c64xx_device_spi0,
+ &s3c64xx_device_spi1,
+ &s3c64xx_device_spi2,
+ &exynos_bus_mif_devfreq,
+ &exynos_bus_int_devfreq,
+#ifdef CONFIG_MALI_T6XX
+ &exynos5_device_g3d,
+#endif
+};
+
+/* TMU */
+static struct tmu_data smdk5250_tmu_pdata __initdata = {
+ .ts = {
+ .stop_throttle = 78,
+ .start_throttle = 80,
+ .start_tripping = 110,
+ .start_emergency = 120,
+ .stop_mem_throttle = 80,
+ .start_mem_throttle = 85,
+ },
+
+ .efuse_value = 80,
+ .slope = 0x10608802,
+};
+
+#if defined(CONFIG_CMA)
+/* defined in arch/arm/mach-exynos/reserve-mem.c */
+extern void exynos_cma_region_reserve(struct cma_region *,
+ struct cma_region *, size_t, const char *);
+static void __init exynos_reserve_mem(void)
+{
+ static struct cma_region regions[] = {
+ {
+ .name = "ion",
+#ifdef CONFIG_ION_EXYNOS_CONTIGHEAP_SIZE
+ .size = CONFIG_ION_EXYNOS_CONTIGHEAP_SIZE * SZ_1K,
+#endif
+ .start = 0
+ },
+#ifdef CONFIG_AUDIO_SAMSUNG_MEMSIZE_SRP
+ {
+ .name = "srp",
+ .size = CONFIG_AUDIO_SAMSUNG_MEMSIZE_SRP * SZ_1K,
+ .start = 0,
+ },
+#endif
+#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
+#ifdef CONFIG_ION_EXYNOS_DRM_MFC_SH
+ {
+ .name = "drm_mfc_sh",
+ .size = SZ_1M,
+ },
+#endif
+#ifdef CONFIG_ION_EXYNOS_DRM_MSGBOX_SH
+ {
+ .name = "drm_msgbox_sh",
+ .size = SZ_1M,
+ },
+#endif
+#endif
+ {
+ .size = 0
+ },
+ };
+#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
+ static struct cma_region regions_secure[] = {
+#ifdef CONFIG_ION_EXYNOS_DRM_MEMSIZE_FIMD_VIDEO
+ {
+ .name = "drm_fimd_video",
+ .size = CONFIG_ION_EXYNOS_DRM_MEMSIZE_FIMD_VIDEO *
+ SZ_1K,
+ },
+#endif
+#ifdef CONFIG_ION_EXYNOS_DRM_MEMSIZE_MFC_OUTPUT
+ {
+ .name = "drm_mfc_output",
+ .size = CONFIG_ION_EXYNOS_DRM_MEMSIZE_MFC_OUTPUT *
+ SZ_1K,
+ },
+#endif
+#ifdef CONFIG_ION_EXYNOS_DRM_MEMSIZE_MFC_INPUT
+ {
+ .name = "drm_mfc_input",
+ .size = CONFIG_ION_EXYNOS_DRM_MEMSIZE_MFC_INPUT *
+ SZ_1K,
+ },
+#endif
+#ifdef CONFIG_ION_EXYNOS_DRM_MFC_FW
+ {
+ .name = "drm_mfc_fw",
+ .size = SZ_1M,
+ },
+#endif
+#ifdef CONFIG_ION_EXYNOS_DRM_SECTBL
+ {
+ .name = "drm_sectbl",
+ .size = SZ_1M,
+ },
+#endif
+ {
+ .size = 0
+ },
+ };
+#else /* !CONFIG_EXYNOS_CONTENT_PATH_PROTECTION */
+ struct cma_region *regions_secure = NULL;
+#endif /* CONFIG_EXYNOS_CONTENT_PATH_PROTECTION */
+ static const char map[] __initconst =
+#ifdef CONFIG_EXYNOS_C2C
+ "samsung-c2c=c2c_shdmem;"
+#endif
+ "s3cfb.0=fimd;exynos5-fb.1=fimd;"
+ "samsung-rp=srp;"
+ "exynos-gsc.0=gsc0;exynos-gsc.1=gsc1;exynos-gsc.2=gsc2;exynos-gsc.3=gsc3;"
+ "exynos-fimc-lite.0=flite0;exynos-fimc-lite.1=flite1;"
+#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
+ "ion-exynos/mfc_sh=drm_mfc_sh;"
+ "ion-exynos/msgbox_sh=drm_msgbox_sh;"
+ "ion-exynos/fimd_video=drm_fimd_video;"
+ "ion-exynos/mfc_output=drm_mfc_output;"
+ "ion-exynos/mfc_input=drm_mfc_input;"
+ "ion-exynos/mfc_fw=drm_mfc_fw;"
+ "ion-exynos/sectbl=drm_sectbl;"
+ "s5p-smem/mfc_sh=drm_mfc_sh;"
+ "s5p-smem/msgbox_sh=drm_msgbox_sh;"
+ "s5p-smem/fimd_video=drm_fimd_video;"
+ "s5p-smem/mfc_output=drm_mfc_output;"
+ "s5p-smem/mfc_input=drm_mfc_input;"
+ "s5p-smem/mfc_fw=drm_mfc_fw;"
+ "s5p-smem/sectbl=drm_sectbl;"
+#endif
+ "ion-exynos=ion;"
+ "exynos-rot=rot;"
+ "s5p-mfc-v6/f=fw;"
+ "s5p-mfc-v6/a=b1;"
+ "s5p-mixer=tv;"
+ "exynos5-fimc-is=fimc_is;";
+
+ exynos_cma_region_reserve(regions, regions_secure, 0, map);
+ ion_reserve(&exynos_ion_pdata);
+}
+#else /* !CONFIG_CMA*/
+static inline void exynos_reserve_mem(void)
+{
+}
+#endif
+
+/* USB EHCI */
+static struct s5p_ehci_platdata smdk5250_ehci_pdata;
+
+static void __init smdk5250_ehci_init(void)
+{
+ struct s5p_ehci_platdata *pdata = &smdk5250_ehci_pdata;
+
+ s5p_ehci_set_platdata(pdata);
+}
+
+/* USB OHCI */
+static struct exynos4_ohci_platdata smdk5250_ohci_pdata;
+
+static void __init smdk5250_ohci_init(void)
+{
+ struct exynos4_ohci_platdata *pdata = &smdk5250_ohci_pdata;
+
+ exynos4_ohci_set_platdata(pdata);
+}
+
+static struct exynos_usb3_drd_pdata smdk5250_ss_udc_pdata;
+
+static void __init smdk5250_ss_udc_init(void)
+{
+ struct exynos_usb3_drd_pdata *pdata = &smdk5250_ss_udc_pdata;
+
+ exynos_ss_udc_set_platdata(pdata);
+}
+
+static void __init smdk5250_dwmci_init(void)
+{
+ exynos_dwmci_set_platdata(&exynos_dwmci0_pdata, 0);
+ dev_set_name(&exynos5_device_dwmci0.dev, "exynos4-sdhci.0");
+ clk_add_alias("dwmci", "dw_mmc.0", "hsmmc", &exynos5_device_dwmci0.dev);
+ clk_add_alias("sclk_dwmci", "dw_mmc.0", "sclk_mmc",
+ &exynos5_device_dwmci0.dev);
+}
+
+#if defined(CONFIG_VIDEO_EXYNOS_MFC)
+static struct s5p_mfc_platdata smdk5250_mfc_pd = {
+ .clock_rate = 333 * MHZ,
+};
+#endif
+
+static struct s3c64xx_spi_csinfo spi0_csi[] = {
+ [0] = {
+ .line = EXYNOS5_GPA2(1),
+ .set_level = gpio_set_value,
+ .fb_delay = 0x2,
+ },
+};
+
+static struct spi_board_info spi0_board_info[] __initdata = {
+ {
+ .modalias = "spidev",
+ .platform_data = NULL,
+ .max_speed_hz = 10 * 1000 * 1000,
+ .bus_num = 0,
+ .chip_select = 0,
+ .mode = SPI_MODE_0,
+ .controller_data = &spi0_csi[0],
+ }
+};
+
+static struct s3c64xx_spi_csinfo spi1_csi[] = {
+ [0] = {
+ .line = EXYNOS5_GPA2(5),
+ .set_level = gpio_set_value,
+ .fb_delay = 0x2,
+ },
+};
+
+static struct spi_board_info spi1_board_info[] __initdata = {
+ {
+ .modalias = "spidev",
+ .platform_data = NULL,
+ .max_speed_hz = 10 * 1000 * 1000,
+ .bus_num = 1,
+ .chip_select = 0,
+ .mode = SPI_MODE_0,
+ .controller_data = &spi1_csi[0],
+ }
+};
+
+static struct s3c64xx_spi_csinfo spi2_csi[] = {
+ [0] = {
+ .line = EXYNOS5_GPB1(2),
+ .set_level = gpio_set_value,
+ .fb_delay = 0x2,
+ },
+};
+
+static struct spi_board_info spi2_board_info[] __initdata = {
+ {
+ .modalias = "spidev",
+ .platform_data = NULL,
+ .max_speed_hz = 10 * 1000 * 1000,
+ .bus_num = 2,
+ .chip_select = 0,
+ .mode = SPI_MODE_0,
+ .controller_data = &spi2_csi[0],
+ }
+};
+
+static void __init smdk5250_map_io(void)
+{
+ clk_xusbxti.rate = 24000000;
+ clk_xxti.rate = 24000000;
+ exynos_init_io(NULL, 0);
+ s3c24xx_init_clocks(clk_xusbxti.rate);
+ s3c24xx_init_uarts(smdk5250_uartcfgs, ARRAY_SIZE(smdk5250_uartcfgs));
+}
+
+static void __init exynos_sysmmu_init(void)
+{
+#ifdef CONFIG_VIDEO_EXYNOS_JPEG
+ platform_set_sysmmu(&SYSMMU_PLATDEV(jpeg).dev, &s5p_device_jpeg.dev);
+#endif
+#if defined(CONFIG_VIDEO_EXYNOS_MFC)
+ platform_set_sysmmu(&SYSMMU_PLATDEV(mfc_lr).dev, &s5p_device_mfc.dev);
+#endif
+#if defined(CONFIG_VIDEO_EXYNOS_TV) && defined(CONFIG_VIDEO_EXYNOS_MIXER)
+ platform_set_sysmmu(&SYSMMU_PLATDEV(tv).dev, &s5p_device_mixer.dev);
+#endif
+#ifdef CONFIG_VIDEO_EXYNOS_GSCALER
+ platform_set_sysmmu(&SYSMMU_PLATDEV(gsc0).dev,
+ &exynos5_device_gsc0.dev);
+ platform_set_sysmmu(&SYSMMU_PLATDEV(gsc1).dev,
+ &exynos5_device_gsc1.dev);
+ platform_set_sysmmu(&SYSMMU_PLATDEV(gsc2).dev,
+ &exynos5_device_gsc2.dev);
+ platform_set_sysmmu(&SYSMMU_PLATDEV(gsc3).dev,
+ &exynos5_device_gsc3.dev);
+#endif
+#ifdef CONFIG_VIDEO_EXYNOS_FIMC_LITE
+ platform_set_sysmmu(&SYSMMU_PLATDEV(camif0).dev,
+ &exynos_device_flite0.dev);
+ platform_set_sysmmu(&SYSMMU_PLATDEV(camif1).dev,
+ &exynos_device_flite1.dev);
+#endif
+ platform_set_sysmmu(&SYSMMU_PLATDEV(rot).dev,
+ &exynos5_device_rotator.dev);
+#ifdef CONFIG_VIDEO_EXYNOS_FIMG2D
+ platform_set_sysmmu(&SYSMMU_PLATDEV(2d).dev,
+ &s5p_device_fimg2d.dev);
+#endif
+#ifdef CONFIG_VIDEO_EXYNOS5_FIMC_IS
+ platform_set_sysmmu(&SYSMMU_PLATDEV(isp).dev,
+ &exynos5_device_fimc_is.dev);
+#endif
+}
+
+static struct persistent_ram_descriptor smdk5250_prd[] __initdata = {
+ {
+ .name = "ram_console",
+ .size = SZ_2M,
+ },
+#ifdef CONFIG_PERSISTENT_TRACER
+ {
+ .name = "persistent_trace",
+ .size = SZ_1M,
+ },
+#endif
+};
+
+static struct persistent_ram smdk5250_pr __initdata = {
+ .descs = smdk5250_prd,
+ .num_descs = ARRAY_SIZE(smdk5250_prd),
+ .start = PLAT_PHYS_OFFSET + SZ_1G + SZ_512M,
+#ifdef CONFIG_PERSISTENT_TRACER
+ .size = 3 * SZ_1M,
+#else
+ .size = SZ_2M,
+#endif
+};
+
+static void __init smdk5250_init_early(void)
+{
+ persistent_ram_early_init(&smdk5250_pr);
+}
+
+static void __init smdk5250_machine_init(void)
+{
+#ifdef CONFIG_EXYNOS_FIQ_DEBUGGER
+ exynos_serial_debug_init(2, 0);
+#endif
+
+ s3c_i2c0_set_platdata(NULL);
+ i2c_register_board_info(0, i2c_devs0, ARRAY_SIZE(i2c_devs0));
+
+ s3c_i2c1_set_platdata(NULL);
+ i2c_register_board_info(1, i2c_devs1, ARRAY_SIZE(i2c_devs1));
+
+ s3c_i2c2_set_platdata(NULL);
+ i2c_register_board_info(2, i2c_devs2, ARRAY_SIZE(i2c_devs2));
+
+ s3c_i2c4_set_platdata(NULL);
+ s3c_i2c5_set_platdata(NULL);
+ s3c_i2c7_set_platdata(NULL);
+ i2c_register_board_info(7, i2c_devs7, ARRAY_SIZE(i2c_devs7));
+
+ s3c_adc_set_platdata(&smdk5250_adc_data);
+
+ exynos_sysmmu_init();
+ smdk5250_dwmci_init();
+
+#ifdef CONFIG_VIDEO_EXYNOS_MFC
+ s5p_mfc_set_platdata(&smdk5250_mfc_pd);
+#endif
+ samsung_bl_set(&smdk5250_bl_gpio_info, &smdk5250_bl_data);
+
+#ifdef CONFIG_FB_S3C
+ s5p_fimd1_set_platdata(&smdk5250_lcd1_pdata);
+ dev_set_name(&s5p_device_fimd1.dev, "exynos5-fb.1");
+ clk_add_alias("lcd", "exynos5-fb.1", "fimd", &s5p_device_fimd1.dev);
+#endif
+#ifdef CONFIG_S5P_DP
+ s5p_dp_set_platdata(&smdk5250_dp_data);
+#endif
+#ifdef CONFIG_FB_MIPI_DSIM
+ s5p_dsim_set_platdata(&dsim_platform_data);
+#endif
+#ifdef CONFIG_EXYNOS_DEV_TMU
+ exynos_tmu_set_platdata(&smdk5250_tmu_pdata);
+#endif
+ smdk5250_gpio_power_init();
+
+ smdk5250_ehci_init();
+ smdk5250_ohci_init();
+ smdk5250_ss_udc_init();
+
+ platform_add_devices(smdk5250_devices, ARRAY_SIZE(smdk5250_devices));
+
+#ifdef CONFIG_FB_S3C
+#if defined(CONFIG_S5P_DP)
+ exynos5_fimd1_setup_clock(&s5p_device_fimd1.dev,
+ "sclk_fimd", "sclk_vpll", 268 * MHZ);
+#else
+ exynos5_fimd1_setup_clock(&s5p_device_fimd1.dev, "sclk_fimd", "mout_mpll_user",
+ 800 * MHZ);
+#endif
+#endif
+#ifdef CONFIG_VIDEO_EXYNOS_MIPI_CSIS
+ s3c_set_platdata(&s5p_mipi_csis0_default_data,
+ sizeof(s5p_mipi_csis0_default_data), &s5p_device_mipi_csis0);
+ s3c_set_platdata(&s5p_mipi_csis1_default_data,
+ sizeof(s5p_mipi_csis1_default_data), &s5p_device_mipi_csis1);
+#endif
+#ifdef CONFIG_VIDEO_EXYNOS_FIMG2D
+ s5p_fimg2d_set_platdata(&fimg2d_data);
+#endif
+#ifdef CONFIG_VIDEO_EXYNOS_FIMC_LITE
+ smdk5250_camera_gpio_cfg();
+ smdk5250_set_camera_platdata();
+ s3c_set_platdata(&exynos_flite0_default_data,
+ sizeof(exynos_flite0_default_data), &exynos_device_flite0);
+ s3c_set_platdata(&exynos_flite1_default_data,
+ sizeof(exynos_flite1_default_data), &exynos_device_flite1);
+/* In EVT0, for using camclk, gscaler clock should be enabled */
+ dev_set_name(&exynos_device_flite0.dev, "exynos-gsc.0");
+ clk_add_alias("gscl", "exynos-fimc-lite.0", "gscl",
+ &exynos_device_flite0.dev);
+ dev_set_name(&exynos_device_flite0.dev, "exynos-fimc-lite.0");
+
+ dev_set_name(&exynos_device_flite1.dev, "exynos-gsc.0");
+ clk_add_alias("gscl", "exynos-fimc-lite.1", "gscl",
+ &exynos_device_flite1.dev);
+ dev_set_name(&exynos_device_flite1.dev, "exynos-fimc-lite.1");
+#endif
+#ifdef CONFIG_VIDEO_EXYNOS5_FIMC_IS
+ dev_set_name(&exynos5_device_fimc_is.dev, "s5p-mipi-csis.0");
+ clk_add_alias("gscl_wrap0", FIMC_IS_MODULE_NAME,
+ "gscl_wrap0", &exynos5_device_fimc_is.dev);
+ clk_add_alias("sclk_gscl_wrap0", FIMC_IS_MODULE_NAME,
+ "sclk_gscl_wrap0", &exynos5_device_fimc_is.dev);
+
+ dev_set_name(&exynos5_device_fimc_is.dev, "s5p-mipi-csis.1");
+ clk_add_alias("gscl_wrap1", FIMC_IS_MODULE_NAME,
+ "gscl_wrap1", &exynos5_device_fimc_is.dev);
+ clk_add_alias("sclk_gscl_wrap1", FIMC_IS_MODULE_NAME,
+ "sclk_gscl_wrap1", &exynos5_device_fimc_is.dev);
+
+ dev_set_name(&exynos5_device_fimc_is.dev, "exynos-gsc.0");
+ clk_add_alias("gscl", FIMC_IS_MODULE_NAME,
+ "gscl", &exynos5_device_fimc_is.dev);
+ dev_set_name(&exynos5_device_fimc_is.dev, FIMC_IS_MODULE_NAME);
+
+#if defined CONFIG_VIDEO_S5K6A3
+ exynos5_fimc_is_data.sensor_info[s5k6a3.sensor_position] = &s5k6a3;
+#endif
+#if defined CONFIG_VIDEO_S5K4E5
+ exynos5_fimc_is_data.sensor_info[s5k4e5.sensor_position] = &s5k4e5;
+#endif
+
+ exynos5_fimc_is_set_platdata(&exynos5_fimc_is_data);
+#endif
+#ifdef CONFIG_VIDEO_EXYNOS_GSCALER
+ s3c_set_platdata(&exynos_gsc0_default_data, sizeof(exynos_gsc0_default_data),
+ &exynos5_device_gsc0);
+ s3c_set_platdata(&exynos_gsc1_default_data, sizeof(exynos_gsc1_default_data),
+ &exynos5_device_gsc1);
+ s3c_set_platdata(&exynos_gsc2_default_data, sizeof(exynos_gsc2_default_data),
+ &exynos5_device_gsc2);
+ s3c_set_platdata(&exynos_gsc3_default_data, sizeof(exynos_gsc3_default_data),
+ &exynos5_device_gsc3);
+#endif
+#ifdef CONFIG_VIDEO_EXYNOS_JPEG
+ exynos5_jpeg_setup_clock(&s5p_device_jpeg.dev, 150000000);
+#endif
+#if defined(CONFIG_VIDEO_EXYNOS_TV) && defined(CONFIG_VIDEO_EXYNOS_HDMI)
+ dev_set_name(&s5p_device_hdmi.dev, "exynos5-hdmi");
+ clk_add_alias("hdmi", "s5p-hdmi", "hdmi", &s5p_device_hdmi.dev);
+
+ /* direct HPD to HDMI chip */
+ gpio_request(EXYNOS5_GPX3(7), "hpd-plug");
+ gpio_direction_input(EXYNOS5_GPX3(7));
+ s3c_gpio_cfgpin(EXYNOS5_GPX3(7), S3C_GPIO_SFN(0xf));
+ s3c_gpio_setpull(EXYNOS5_GPX3(7), S3C_GPIO_PULL_NONE);
+
+ /* HDMI CEC */
+ gpio_request(EXYNOS5_GPX3(6), "hdmi-cec");
+ gpio_direction_input(EXYNOS5_GPX3(6));
+ s3c_gpio_cfgpin(EXYNOS5_GPX3(6), S3C_GPIO_SFN(0x3));
+ s3c_gpio_setpull(EXYNOS5_GPX3(6), S3C_GPIO_PULL_NONE);
+
+#if defined(CONFIG_VIDEO_EXYNOS_HDMIPHY)
+ s5p_hdmi_set_platdata(&hdmi_platdata);
+ s5p_i2c_hdmiphy_set_platdata(NULL);
+#endif
+#ifdef CONFIG_VIDEO_EXYNOS_HDMI_CEC
+ s5p_hdmi_cec_set_platdata(&hdmi_cec_data);
+#endif
+#endif
+
+ exynos_spi_clock_setup(&s3c64xx_device_spi0.dev, 0);
+ exynos_spi_clock_setup(&s3c64xx_device_spi1.dev, 1);
+ exynos_spi_clock_setup(&s3c64xx_device_spi2.dev, 2);
+
+ if (!exynos_spi_cfg_cs(spi0_csi[0].line, 0)) {
+ s3c64xx_spi0_set_platdata(&s3c64xx_spi0_pdata,
+ EXYNOS_SPI_SRCCLK_SCLK, ARRAY_SIZE(spi0_csi));
+
+ spi_register_board_info(spi0_board_info,
+ ARRAY_SIZE(spi0_board_info));
+ } else {
+ pr_err("%s: Error requesting gpio for SPI-CH0 CS\n", __func__);
+ }
+
+ if (!exynos_spi_cfg_cs(spi1_csi[0].line, 1)) {
+ s3c64xx_spi1_set_platdata(&s3c64xx_spi1_pdata,
+ EXYNOS_SPI_SRCCLK_SCLK, ARRAY_SIZE(spi1_csi));
+
+ spi_register_board_info(spi1_board_info,
+ ARRAY_SIZE(spi1_board_info));
+ } else {
+ pr_err("%s: Error requesting gpio for SPI-CH1 CS\n", __func__);
+ }
+
+ if (!exynos_spi_cfg_cs(spi2_csi[0].line, 2)) {
+ s3c64xx_spi2_set_platdata(&s3c64xx_spi2_pdata,
+ EXYNOS_SPI_SRCCLK_SCLK, ARRAY_SIZE(spi2_csi));
+
+ spi_register_board_info(spi2_board_info,
+ ARRAY_SIZE(spi2_board_info));
+ } else {
+ pr_err("%s: Error requesting gpio for SPI-CH2 CS\n", __func__);
+ }
+}
+
+MACHINE_START(SMDK5250, "SMDK5250")
+ .atag_offset = 0x100,
+ .init_early = smdk5250_init_early,
+ .init_irq = exynos5_init_irq,
+ .map_io = smdk5250_map_io,
+ .handle_irq = gic_handle_irq,
+ .init_machine = smdk5250_machine_init,
+ .timer = &exynos4_timer,
+ .restart = exynos5_restart,
+ .reserve = exynos_reserve_mem,
+MACHINE_END
diff --git a/arch/arm/mach-exynos/mach-smdkv310.c b/arch/arm/mach-exynos/mach-smdkv310.c
index 83b91fa..45e53e6 100644
--- a/arch/arm/mach-exynos/mach-smdkv310.c
+++ b/arch/arm/mach-exynos/mach-smdkv310.c
@@ -34,7 +34,6 @@
#include <plat/keypad.h>
#include <plat/sdhci.h>
#include <plat/iic.h>
-#include <plat/pd.h>
#include <plat/gpio-cfg.h>
#include <plat/backlight.h>
#include <plat/mfc.h>
@@ -281,7 +280,6 @@
&s5p_device_mfc_l,
&s5p_device_mfc_r,
&exynos4_device_spdif,
- &exynos4_device_sysmmu,
&samsung_asoc_dma,
&samsung_asoc_idma,
&s5p_device_fimd0,
diff --git a/arch/arm/mach-exynos/mct.c b/arch/arm/mach-exynos/mct.c
index 897d9a9..4bf6e3e 100644
--- a/arch/arm/mach-exynos/mct.c
+++ b/arch/arm/mach-exynos/mct.c
@@ -20,6 +20,7 @@
#include <linux/delay.h>
#include <linux/percpu.h>
+#include <asm/sched_clock.h>
#include <asm/hardware/gic.h>
#include <asm/localtimer.h>
@@ -103,8 +104,8 @@
}
}
- /* Wait maximum 1 ms until written values are applied */
- for (i = 0; i < loops_per_jiffy / 1000 * HZ; i++)
+ /* Wait until written values are applied */
+ for (i = 0; i < 0x1000; i++)
if (__raw_readl(stat_addr) & mask) {
__raw_writel(mask, stat_addr);
return;
@@ -126,6 +127,11 @@
exynos4_mct_write(reg, EXYNOS4_MCT_G_TCON);
}
+static notrace u32 exynos4_read_sched_clock(void)
+{
+ return __raw_readl(EXYNOS4_MCT_G_CNT_L);
+}
+
static cycle_t exynos4_frc_read(struct clocksource *cs)
{
unsigned int lo, hi;
@@ -160,6 +166,8 @@
if (clocksource_register_hz(&mct_frc, clk_rate))
panic("%s: can't register clocksource\n", mct_frc.name);
+
+ setup_sched_clock_needs_suspend(exynos4_read_sched_clock, 32, clk_rate);
}
static void exynos4_mct_comp0_stop(void)
@@ -283,6 +291,9 @@
tmp &= ~mask;
exynos4_mct_write(tmp, addr);
}
+
+ /* clear MCT local interrupt */
+ exynos4_mct_write(0x1, mevt->base + MCT_L_INT_CSTAT_OFFSET);
}
static void exynos4_mct_tick_start(unsigned long cycles,
@@ -311,7 +322,9 @@
{
struct mct_clock_event_device *mevt = this_cpu_ptr(&percpu_mct_tick);
- exynos4_mct_tick_start(cycles, mevt);
+ if ((evt->mode != CLOCK_EVT_MODE_SHUTDOWN)
+ && (evt->mode != CLOCK_EVT_MODE_UNUSED))
+ exynos4_mct_tick_start(cycles, mevt);
return 0;
}
@@ -331,10 +344,13 @@
exynos4_mct_tick_start(cycles_per_jiffy, mevt);
break;
+ case CLOCK_EVT_MODE_RESUME:
+ exynos4_mct_write(TICK_BASE_CNT, mevt->base + MCT_L_TCNTB_OFFSET);
+ break;
+
case CLOCK_EVT_MODE_ONESHOT:
case CLOCK_EVT_MODE_UNUSED:
case CLOCK_EVT_MODE_SHUTDOWN:
- case CLOCK_EVT_MODE_RESUME:
break;
}
}
@@ -363,7 +379,12 @@
static irqreturn_t exynos4_mct_tick_isr(int irq, void *dev_id)
{
struct mct_clock_event_device *mevt = dev_id;
- struct clock_event_device *evt = mevt->evt;
+ struct clock_event_device *evt;
+
+ if (!mevt)
+ return IRQ_NONE;
+
+ evt = mevt->evt;
exynos4_mct_tick_clear(mevt);
@@ -399,7 +420,8 @@
evt->cpumask = cpumask_of(cpu);
evt->set_next_event = exynos4_tick_set_next_event;
evt->set_mode = exynos4_tick_set_mode;
- evt->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
+ evt->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT |
+ CLOCK_EVT_FEAT_C3STOP;
evt->rating = 450;
clockevents_calc_mult_shift(evt, clk_rate / (TICK_BASE_CNT + 1), 5);
@@ -408,21 +430,26 @@
evt->min_delta_ns =
clockevent_delta2ns(0xf, evt);
- clockevents_register_device(evt);
-
exynos4_mct_write(TICK_BASE_CNT, mevt->base + MCT_L_TCNTB_OFFSET);
+ clockevents_register_device(evt);
+
if (mct_int_type == MCT_INT_SPI) {
if (cpu == 0) {
mct_tick0_event_irq.dev_id = mevt;
- evt->irq = EXYNOS4_IRQ_MCT_L0;
- setup_irq(EXYNOS4_IRQ_MCT_L0, &mct_tick0_event_irq);
+ if (soc_is_exynos5250())
+ evt->irq = EXYNOS5_IRQ_MCT_L0;
+ else
+ evt->irq = EXYNOS4_IRQ_MCT_L0;
} else {
mct_tick1_event_irq.dev_id = mevt;
- evt->irq = EXYNOS4_IRQ_MCT_L1;
- setup_irq(EXYNOS4_IRQ_MCT_L1, &mct_tick1_event_irq);
- irq_set_affinity(EXYNOS4_IRQ_MCT_L1, cpumask_of(1));
+ if (soc_is_exynos5250())
+ evt->irq = EXYNOS5_IRQ_MCT_L1;
+ else
+ evt->irq = EXYNOS4_IRQ_MCT_L1;
+ irq_set_affinity(evt->irq, cpumask_of(1));
}
+ enable_irq(evt->irq);
} else {
enable_percpu_irq(EXYNOS_IRQ_MCT_LOCALTIMER, 0);
}
@@ -432,13 +459,10 @@
static void exynos4_local_timer_stop(struct clock_event_device *evt)
{
- unsigned int cpu = smp_processor_id();
+ evt->mode = CLOCK_EVT_MODE_UNUSED;
evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt);
if (mct_int_type == MCT_INT_SPI)
- if (cpu == 0)
- remove_irq(evt->irq, &mct_tick0_event_irq);
- else
- remove_irq(evt->irq, &mct_tick1_event_irq);
+ disable_irq(evt->irq);
else
disable_percpu_irq(EXYNOS_IRQ_MCT_LOCALTIMER);
}
@@ -447,6 +471,23 @@
.setup = exynos4_local_timer_setup,
.stop = exynos4_local_timer_stop,
};
+
+static void __init exynos4_local_timer_init(void)
+{
+ if (mct_int_type == MCT_INT_SPI) {
+ if (soc_is_exynos5250()) {
+ setup_irq(EXYNOS5_IRQ_MCT_L0, &mct_tick0_event_irq);
+ disable_irq(EXYNOS5_IRQ_MCT_L0);
+ setup_irq(EXYNOS5_IRQ_MCT_L1, &mct_tick1_event_irq);
+ disable_irq(EXYNOS5_IRQ_MCT_L1);
+ } else {
+ setup_irq(EXYNOS4_IRQ_MCT_L0, &mct_tick0_event_irq);
+ disable_irq(EXYNOS4_IRQ_MCT_L0);
+ setup_irq(EXYNOS4_IRQ_MCT_L1, &mct_tick1_event_irq);
+ disable_irq(EXYNOS4_IRQ_MCT_L1);
+ }
+ }
+}
#endif /* CONFIG_LOCAL_TIMERS */
static void __init exynos4_timer_resources(void)
@@ -473,12 +514,15 @@
static void __init exynos4_timer_init(void)
{
- if (soc_is_exynos4210())
+ if (soc_is_exynos4210() || soc_is_exynos5250())
mct_int_type = MCT_INT_SPI;
else
mct_int_type = MCT_INT_PPI;
exynos4_timer_resources();
+#ifdef CONFIG_LOCAL_TIMERS
+ exynos4_local_timer_init();
+#endif
exynos4_clocksource_init();
exynos4_clockevent_init();
}
diff --git a/arch/arm/mach-exynos/persistent_clock.c b/arch/arm/mach-exynos/persistent_clock.c
new file mode 100644
index 0000000..b600545
--- /dev/null
+++ b/arch/arm/mach-exynos/persistent_clock.c
@@ -0,0 +1,195 @@
+/* arch/arm/mach-exynos/persistent_clock.c
+ *
+ * Copyright (c) 2012 Google, Inc.
+ *
+ * Based on rtc-s3c.c, which is:
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Copyright (c) 2004,2006 Simtec Electronics
+ * Ben Dooks, <ben@simtec.co.uk>
+ * http://armlinux.simtec.co.uk/
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/bcd.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+
+#include <asm/io.h>
+#include <plat/regs-rtc.h>
+
+static struct resource *exynos_rtc_mem;
+static struct clk *rtc_clk;
+static void __iomem *exynos_rtc_base;
+
+static void exynos_persistent_clock_read(struct rtc_time *rtc_tm)
+{
+ unsigned int have_retried = 0;
+ void __iomem *base = exynos_rtc_base;
+
+ clk_enable(rtc_clk);
+retry_get_time:
+ rtc_tm->tm_min = bcd2bin(readb(base + S3C2410_RTCMIN));
+ rtc_tm->tm_hour = bcd2bin(readb(base + S3C2410_RTCHOUR));
+ rtc_tm->tm_mday = bcd2bin(readb(base + S3C2410_RTCDATE));
+ rtc_tm->tm_mon = bcd2bin(readb(base + S3C2410_RTCMON));
+ rtc_tm->tm_year = bcd2bin(readb(base + S3C2410_RTCYEAR));
+ rtc_tm->tm_sec = bcd2bin(readb(base + S3C2410_RTCSEC));
+
+ if (rtc_tm->tm_sec == 0 && !have_retried) {
+ have_retried = 1;
+ goto retry_get_time;
+ }
+
+ rtc_tm->tm_year += 100;
+ rtc_tm->tm_mon -= 1;
+ clk_disable(rtc_clk);
+ return;
+}
+
+/**
+ * read_persistent_clock() - Return time from a persistent clock.
+ * @ts: timespec returns a relative timestamp, not a wall time
+ *
+ * Reads a clock that keeps relative time across suspend/resume on Exynos
+ * platforms. The clock is accurate to 1 second.
+ */
+void read_persistent_clock(struct timespec *ts)
+{
+ struct rtc_time rtc_tm;
+ unsigned long time;
+
+ if (!exynos_rtc_base) {
+ ts->tv_sec = 0;
+ ts->tv_nsec = 0;
+ return;
+ }
+
+ exynos_persistent_clock_read(&rtc_tm);
+ rtc_tm_to_time(&rtc_tm, &time);
+ ts->tv_sec = time;
+ ts->tv_nsec = 0;
+}
+
+static int __devexit exynos_persistent_clock_remove(struct platform_device *dev)
+{
+ clk_put(rtc_clk);
+ iounmap(exynos_rtc_base);
+ exynos_rtc_base = NULL;
+ release_resource(exynos_rtc_mem);
+ kfree(exynos_rtc_mem);
+ return 0;
+}
+
+static int __devinit exynos_persistent_clock_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct rtc_time tm;
+ unsigned int tmp;
+ int ret;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENOENT;
+
+ exynos_rtc_mem = request_mem_region(res->start, resource_size(res),
+ pdev->name);
+ if (!exynos_rtc_mem) {
+ ret = -ENOENT;
+ goto err_mem;
+ }
+
+ exynos_rtc_base = ioremap(res->start, resource_size(res));
+ if (!exynos_rtc_base) {
+ ret = -ENOMEM;
+ goto err_map;
+ }
+
+ rtc_clk = clk_get(&pdev->dev, "rtc");
+ if (IS_ERR(rtc_clk)) {
+ ret = PTR_ERR(rtc_clk);
+ rtc_clk = NULL;
+ goto err_clk;
+ }
+
+ clk_enable(rtc_clk);
+
+ /*
+ * initializing rtc with valid time values because of
+ * undefined reset values
+ */
+ tm.tm_year = 100;
+ tm.tm_mon = 1;
+ tm.tm_mday = 1;
+ tm.tm_hour = 0;
+ tm.tm_min = 0;
+ tm.tm_sec = 0;
+
+ /* enable rtc before writing bcd values */
+ tmp = readw(exynos_rtc_base + S3C2410_RTCCON);
+ writew(tmp | S3C2410_RTCCON_RTCEN,
+ exynos_rtc_base + S3C2410_RTCCON);
+ tmp = readw(exynos_rtc_base + S3C2410_RTCCON);
+ writew(tmp & ~S3C2410_RTCCON_CNTSEL,
+ exynos_rtc_base + S3C2410_RTCCON);
+ tmp = readw(exynos_rtc_base + S3C2410_RTCCON);
+ writew(tmp & ~S3C2410_RTCCON_CLKRST,
+ exynos_rtc_base + S3C2410_RTCCON);
+
+ writeb(bin2bcd(tm.tm_sec), exynos_rtc_base + S3C2410_RTCSEC);
+ writeb(bin2bcd(tm.tm_min), exynos_rtc_base + S3C2410_RTCMIN);
+ writeb(bin2bcd(tm.tm_hour), exynos_rtc_base + S3C2410_RTCHOUR);
+ writeb(bin2bcd(tm.tm_mday), exynos_rtc_base + S3C2410_RTCDATE);
+ writeb(bin2bcd(tm.tm_mon), exynos_rtc_base + S3C2410_RTCMON);
+ writeb(bin2bcd(1900 + tm.tm_year), exynos_rtc_base + S3C2410_RTCYEAR);
+
+ pr_debug("set time %04d.%02d.%02d %02d:%02d:%02d\n", 1900 + tm.tm_year,
+ tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
+
+ /* checking rtc time values are valid or not */
+ exynos_persistent_clock_read(&tm);
+ BUG_ON(rtc_valid_tm(&tm)) ;
+
+ tmp = readw(exynos_rtc_base + S3C2410_RTCCON);
+ tmp &= ~S3C2410_RTCCON_RTCEN;
+ writew(tmp, exynos_rtc_base + S3C2410_RTCCON);
+ clk_disable(rtc_clk);
+ return 0;
+
+err_clk:
+ iounmap(exynos_rtc_base);
+err_map:
+ release_resource(exynos_rtc_mem);
+err_mem:
+ return ret;
+}
+
+static struct platform_driver exynos_persistent_clock_driver = {
+ .probe = exynos_persistent_clock_probe,
+ .remove = __devexit_p(exynos_persistent_clock_remove),
+ .driver = {
+ .name = "persistent_clock",
+ .owner = THIS_MODULE,
+ },
+};
+
+module_platform_driver(exynos_persistent_clock_driver);
+
+MODULE_DESCRIPTION("Samsung EXYNOS RTC persistent clock only driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:persistent_clock");
diff --git a/arch/arm/mach-exynos/platsmp.c b/arch/arm/mach-exynos/platsmp.c
index 36c3984a..d98fc95 100644
--- a/arch/arm/mach-exynos/platsmp.c
+++ b/arch/arm/mach-exynos/platsmp.c
@@ -29,20 +29,26 @@
#include <mach/hardware.h>
#include <mach/regs-clock.h>
#include <mach/regs-pmu.h>
+#include <mach/smc.h>
#include <plat/cpu.h>
+#include <plat/regs-watchdog.h>
extern void exynos4_secondary_startup(void);
-#define CPU1_BOOT_REG (samsung_rev() == EXYNOS4210_REV_1_1 ? \
- S5P_INFORM5 : S5P_VA_SYSRAM)
+struct _cpu_boot_info {
+ void __iomem *boot_base;
+ void __iomem *power_base;
+};
+
+struct _cpu_boot_info cpu_boot_info[NR_CPUS];
/*
* control for which core is the next to come out of the secondary
* boot "holding pen"
*/
-volatile int __cpuinitdata pen_release = -1;
+volatile int pen_release = -1;
/*
* Write pen_release in a way that is guaranteed to be visible to all
@@ -86,9 +92,42 @@
spin_unlock(&boot_lock);
}
+static int exynos_power_up_cpu(unsigned int cpu)
+{
+ unsigned int timeout;
+ unsigned int val;
+ void __iomem *power_base = cpu_boot_info[cpu].power_base;
+
+ val = __raw_readl(power_base);
+ if (!(val & EXYNOS_CORE_LOCAL_PWR_EN)) {
+ __raw_writel(EXYNOS_CORE_LOCAL_PWR_EN, power_base);
+
+ /* wait max 10 ms until cpu is on */
+ timeout = 10;
+ while (timeout) {
+ val = __raw_readl(power_base + 0x4);
+
+ if ((val & EXYNOS_CORE_LOCAL_PWR_EN) ==
+ EXYNOS_CORE_LOCAL_PWR_EN)
+ break;
+
+ mdelay(1);
+ timeout--;
+ }
+
+ if (timeout == 0) {
+ printk(KERN_ERR "cpu%d power up failed", cpu);
+ return -ETIMEDOUT;
+ }
+ }
+
+ return 0;
+}
+
int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
{
unsigned long timeout;
+ int ret;
/*
* Set synchronisation state between this boot processor
@@ -96,6 +135,14 @@
*/
spin_lock(&boot_lock);
+ watchdog_save();
+
+ ret = exynos_power_up_cpu(cpu);
+ if (ret) {
+ spin_unlock(&boot_lock);
+ return ret;
+ }
+
/*
* The secondary processor is waiting to be released from
* the holding pen - release it, then wait for it to flag
@@ -106,27 +153,6 @@
*/
write_pen_release(cpu_logical_map(cpu));
- if (!(__raw_readl(S5P_ARM_CORE1_STATUS) & S5P_CORE_LOCAL_PWR_EN)) {
- __raw_writel(S5P_CORE_LOCAL_PWR_EN,
- S5P_ARM_CORE1_CONFIGURATION);
-
- timeout = 10;
-
- /* wait max 10 ms until cpu1 is on */
- while ((__raw_readl(S5P_ARM_CORE1_STATUS)
- & S5P_CORE_LOCAL_PWR_EN) != S5P_CORE_LOCAL_PWR_EN) {
- if (timeout-- == 0)
- break;
-
- mdelay(1);
- }
-
- if (timeout == 0) {
- printk(KERN_ERR "cpu1 power enable failed");
- spin_unlock(&boot_lock);
- return -ETIMEDOUT;
- }
- }
/*
* Send the secondary CPU a soft interrupt, thereby causing
* the boot monitor to read the system wide flags register,
@@ -137,8 +163,15 @@
while (time_before(jiffies, timeout)) {
smp_rmb();
+#ifdef CONFIG_ARM_TRUSTZONE
__raw_writel(virt_to_phys(exynos4_secondary_startup),
- CPU1_BOOT_REG);
+ S5P_VA_SYSRAM_NS + 0x1C);
+ exynos_smc(SMC_CMD_CPU1BOOT, 0, 0, 0);
+#else
+ __raw_writel(virt_to_phys(exynos4_secondary_startup),
+ cpu_boot_info[cpu].boot_base);
+#endif
+ watchdog_restore();
gic_raise_softirq(cpumask_of(cpu), 1);
if (pen_release == -1)
@@ -186,15 +219,18 @@
void __init platform_smp_prepare_cpus(unsigned int max_cpus)
{
+ int i;
+
if (!soc_is_exynos5250())
scu_enable(scu_base_addr());
- /*
- * Write the address of secondary startup into the
- * system-wide flags register. The boot monitor waits
- * until it receives a soft interrupt, and then the
- * secondary CPU branches to this address.
- */
- __raw_writel(virt_to_phys(exynos4_secondary_startup),
- CPU1_BOOT_REG);
+ for (i = 1; i < max_cpus; i++) {
+ if (soc_is_exynos4210() &&
+ (samsung_rev() == EXYNOS4210_REV_1_1))
+ cpu_boot_info[i].boot_base = EXYNOS_INFORM5;
+ else
+ cpu_boot_info[i].boot_base = S5P_VA_SYSRAM;
+
+ cpu_boot_info[i].power_base = EXYNOS_ARM_CORE_CONFIGURATION(i);
+ }
}
diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c
index 428cfeb..bff00b3 100644
--- a/arch/arm/mach-exynos/pm.c
+++ b/arch/arm/mach-exynos/pm.c
@@ -1,9 +1,9 @@
-/* linux/arch/arm/mach-exynos4/pm.c
+/* linux/arch/arm/mach-exynos/pm.c
*
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
- * EXYNOS4210 - Power Management support
+ * EXYNOS - Power Management support
*
* Based on arch/arm/mach-s3c2410/pm.c
* Copyright (c) 2006 Simtec Electronics
@@ -20,6 +20,7 @@
#include <linux/io.h>
#include <linux/err.h>
#include <linux/clk.h>
+#include <linux/interrupt.h>
#include <asm/cacheflush.h>
#include <asm/hardware/cache-l2x0.h>
@@ -29,6 +30,7 @@
#include <plat/pm.h>
#include <plat/pll.h>
#include <plat/regs-srom.h>
+#include <plat/bts.h>
#include <mach/regs-irq.h>
#include <mach/regs-gpio.h>
@@ -36,6 +38,20 @@
#include <mach/regs-pmu.h>
#include <mach/pm-core.h>
#include <mach/pmu.h>
+#include <mach/smc.h>
+
+#ifdef CONFIG_ARM_TRUSTZONE
+#define REG_INFORM0 (S5P_VA_SYSRAM_NS + 0x8)
+#define REG_INFORM1 (S5P_VA_SYSRAM_NS + 0xC)
+#else
+#define REG_INFORM0 (EXYNOS_INFORM0)
+#define REG_INFORM1 (EXYNOS_INFORM1)
+#endif
+
+#define EXYNOS_I2C_CFG (S3C_VA_SYS + 0x234)
+
+#define EXYNOS_WAKEUP_STAT_EINT (1 << 0)
+#define EXYNOS_WAKEUP_STAT_RTC_ALARM (1 << 1)
static struct sleep_save exynos4_set_clksrc[] = {
{ .reg = EXYNOS4_CLKSRC_MASK_TOP , .val = 0x00000001, },
@@ -63,145 +79,89 @@
SAVE_ITEM(EXYNOS4_VPLL_CON1),
};
-static struct sleep_save exynos4_core_save[] = {
- /* GIC side */
- SAVE_ITEM(S5P_VA_GIC_CPU + 0x000),
- SAVE_ITEM(S5P_VA_GIC_CPU + 0x004),
- SAVE_ITEM(S5P_VA_GIC_CPU + 0x008),
- SAVE_ITEM(S5P_VA_GIC_CPU + 0x00C),
- SAVE_ITEM(S5P_VA_GIC_CPU + 0x014),
- SAVE_ITEM(S5P_VA_GIC_CPU + 0x018),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0x000),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0x004),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0x100),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0x104),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0x108),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0x300),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0x304),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0x308),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0x400),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0x404),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0x408),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0x40C),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0x410),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0x414),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0x418),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0x41C),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0x420),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0x424),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0x428),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0x42C),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0x430),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0x434),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0x438),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0x43C),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0x440),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0x444),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0x448),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0x44C),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0x450),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0x454),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0x458),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0x45C),
+static struct sleep_save exynos5_set_clksrc[] = {
+ { .reg = EXYNOS5_CLKSRC_MASK_TOP, .val = 0xffffffff, },
+ { .reg = EXYNOS5_CLKSRC_MASK_GSCL, .val = 0xffffffff, },
+ { .reg = EXYNOS5_CLKSRC_MASK_DISP1_0, .val = 0xffffffff, },
+ { .reg = EXYNOS5_CLKSRC_MASK_MAUDIO, .val = 0xffffffff, },
+ { .reg = EXYNOS5_CLKSRC_MASK_FSYS, .val = 0xffffffff, },
+ { .reg = EXYNOS5_CLKSRC_MASK_PERIC0, .val = 0xffffffff, },
+ { .reg = EXYNOS5_CLKSRC_MASK_PERIC1, .val = 0xffffffff, },
+ { .reg = EXYNOS5_CLKSRC_MASK_ISP, .val = 0xffffffff, },
+};
- SAVE_ITEM(S5P_VA_GIC_DIST + 0x800),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0x804),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0x808),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0x80C),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0x810),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0x814),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0x818),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0x81C),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0x820),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0x824),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0x828),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0x82C),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0x830),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0x834),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0x838),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0x83C),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0x840),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0x844),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0x848),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0x84C),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0x850),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0x854),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0x858),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0x85C),
-
- SAVE_ITEM(S5P_VA_GIC_DIST + 0xC00),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0xC04),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0xC08),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0xC0C),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0xC10),
- SAVE_ITEM(S5P_VA_GIC_DIST + 0xC14),
-
- SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x000),
- SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x010),
- SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x020),
- SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x030),
- SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x040),
- SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x050),
- SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x060),
- SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x070),
- SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x080),
- SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x090),
-
+static struct sleep_save exynos_core_save[] = {
/* SROM side */
SAVE_ITEM(S5P_SROM_BW),
SAVE_ITEM(S5P_SROM_BC0),
SAVE_ITEM(S5P_SROM_BC1),
SAVE_ITEM(S5P_SROM_BC2),
SAVE_ITEM(S5P_SROM_BC3),
+
+ /* I2C CFG */
+ SAVE_ITEM(EXYNOS_I2C_CFG),
};
/* For Cortex-A9 Diagnostic and Power control register */
static unsigned int save_arm_register[2];
-static int exynos4_cpu_suspend(unsigned long arg)
+static int exynos_cpu_suspend(unsigned long arg)
{
+#ifdef CONFIG_CACHE_L2X0
outer_flush_all();
+#endif
+ exynos_reset_assert_ctrl(false);
+#ifdef CONFIG_ARM_TRUSTZONE
+ exynos_smc(SMC_CMD_SLEEP, 0, 0, 0);
+#else
/* issue the standby signal into the pm unit. */
cpu_do_idle();
-
- /* we should never get past here */
- panic("sleep resumed to originator?");
+#endif
+ pr_info("sleep resumed to originator?");
+ return 1; /* abort suspend */
}
-static void exynos4_pm_prepare(void)
+static void exynos_pm_prepare(void)
{
- u32 tmp;
+ unsigned int tmp;
- s3c_pm_do_save(exynos4_core_save, ARRAY_SIZE(exynos4_core_save));
- s3c_pm_do_save(exynos4_epll_save, ARRAY_SIZE(exynos4_epll_save));
- s3c_pm_do_save(exynos4_vpll_save, ARRAY_SIZE(exynos4_vpll_save));
+ /* Decides whether to use retention capability */
+ tmp = __raw_readl(EXYNOS5_ARM_L2_OPTION);
+ tmp &= ~EXYNOS5_USE_RETENTION;
+ __raw_writel(tmp, EXYNOS5_ARM_L2_OPTION);
- tmp = __raw_readl(S5P_INFORM1);
+ if (!soc_is_exynos5250()) {
+ s3c_pm_do_save(exynos4_epll_save, ARRAY_SIZE(exynos4_epll_save));
+ s3c_pm_do_save(exynos4_vpll_save, ARRAY_SIZE(exynos4_vpll_save));
+ }
/* Set value of power down register for sleep mode */
-
- exynos4_sys_powerdown_conf(SYS_SLEEP);
- __raw_writel(S5P_CHECK_SLEEP, S5P_INFORM1);
+ exynos_sys_powerdown_conf(SYS_SLEEP);
+ __raw_writel(EXYNOS_CHECK_SLEEP, REG_INFORM1);
/* ensure at least INFORM0 has the resume address */
+ __raw_writel(virt_to_phys(s3c_cpu_resume), REG_INFORM0);
- __raw_writel(virt_to_phys(s3c_cpu_resume), S5P_INFORM0);
-
- /* Before enter central sequence mode, clock src register have to set */
-
- s3c_pm_do_restore_core(exynos4_set_clksrc, ARRAY_SIZE(exynos4_set_clksrc));
+ /*
+ * Before enter central sequence mode,
+ * clock src register have to set.
+ */
+ if (!soc_is_exynos5250())
+ s3c_pm_do_restore_core(exynos4_set_clksrc,
+ ARRAY_SIZE(exynos4_set_clksrc));
if (soc_is_exynos4210())
s3c_pm_do_restore_core(exynos4210_set_clksrc, ARRAY_SIZE(exynos4210_set_clksrc));
+ s3c_pm_do_restore_core(exynos5_set_clksrc, ARRAY_SIZE(exynos5_set_clksrc));
}
-static int exynos4_pm_add(struct device *dev, struct subsys_interface *sif)
+static int exynos_pm_add(struct device *dev, struct subsys_interface *sif)
{
- pm_cpu_prep = exynos4_pm_prepare;
- pm_cpu_sleep = exynos4_cpu_suspend;
+ pm_cpu_prep = exynos_pm_prepare;
+ pm_cpu_sleep = exynos_cpu_suspend;
return 0;
}
@@ -274,124 +234,193 @@
}
static struct subsys_interface exynos4_pm_interface = {
- .name = "exynos4_pm",
+ .name = "exynos_pm",
.subsys = &exynos4_subsys,
- .add_dev = exynos4_pm_add,
+ .add_dev = exynos_pm_add,
};
-static __init int exynos4_pm_drvinit(void)
+static struct subsys_interface exynos5_pm_interface = {
+ .name = "exynos_pm",
+ .subsys = &exynos5_subsys,
+ .add_dev = exynos_pm_add,
+};
+
+static __init int exynos_pm_drvinit(void)
{
struct clk *pll_base;
- unsigned int tmp;
s3c_pm_init();
- /* All wakeup disable */
+ if (!soc_is_exynos5250()) {
+ pll_base = clk_get(NULL, "xtal");
- tmp = __raw_readl(S5P_WAKEUP_MASK);
- tmp |= ((0xFF << 8) | (0x1F << 1));
- __raw_writel(tmp, S5P_WAKEUP_MASK);
+ if (!IS_ERR(pll_base)) {
+ pll_base_rate = clk_get_rate(pll_base);
+ clk_put(pll_base);
+ }
+ }
+ if (soc_is_exynos5250())
+ return subsys_interface_register(&exynos5_pm_interface);
+ else
+ return subsys_interface_register(&exynos4_pm_interface);
+}
+arch_initcall(exynos_pm_drvinit);
- pll_base = clk_get(NULL, "xtal");
+static void exynos_show_wakeup_reason_eint(void)
+{
+ int bit;
+ int reg_eintstart;
+ long unsigned int ext_int_pend;
+ unsigned long eint_wakeup_mask;
+ bool found = 0;
+ extern void __iomem *exynos_eint_base;
- if (!IS_ERR(pll_base)) {
- pll_base_rate = clk_get_rate(pll_base);
- clk_put(pll_base);
+ eint_wakeup_mask = __raw_readl(EXYNOS_EINT_WAKEUP_MASK);
+
+ for (reg_eintstart = 0; reg_eintstart <= 31; reg_eintstart += 8) {
+ ext_int_pend =
+ __raw_readl(EINT_PEND(exynos_eint_base,
+ IRQ_EINT(reg_eintstart)));
+
+ for_each_set_bit(bit, &ext_int_pend, 8) {
+ int irq = IRQ_EINT(reg_eintstart) + bit;
+ struct irq_desc *desc = irq_to_desc(irq);
+
+ if (eint_wakeup_mask & (1 << (reg_eintstart + bit)))
+ continue;
+
+ if (desc && desc->action && desc->action->name)
+ pr_info("Resume caused by IRQ %d, %s\n", irq,
+ desc->action->name);
+ else
+ pr_info("Resume caused by IRQ %d\n", irq);
+
+ found = 1;
+ }
}
- return subsys_interface_register(&exynos4_pm_interface);
+ if (!found)
+ pr_info("Resume caused by unknown EINT\n");
}
-arch_initcall(exynos4_pm_drvinit);
-static int exynos4_pm_suspend(void)
+static void exynos_show_wakeup_reason(void)
+{
+ unsigned long wakeup_stat;
+
+ wakeup_stat = __raw_readl(EXYNOS_WAKEUP_STAT);
+
+ if (wakeup_stat & EXYNOS_WAKEUP_STAT_RTC_ALARM)
+ pr_info("Resume caused by RTC alarm\n");
+ else if (wakeup_stat & EXYNOS_WAKEUP_STAT_EINT)
+ exynos_show_wakeup_reason_eint();
+ else
+ pr_info("Resume caused by wakeup_stat=0x%08lx\n",
+ wakeup_stat);
+}
+
+
+static int exynos_pm_suspend(void)
{
unsigned long tmp;
+ s3c_pm_do_save(exynos_core_save, ARRAY_SIZE(exynos_core_save));
+
/* Setting Central Sequence Register for power down mode */
+ tmp = __raw_readl(EXYNOS_CENTRAL_SEQ_CONFIGURATION);
+ tmp &= ~EXYNOS_CENTRAL_LOWPWR_CFG;
+ __raw_writel(tmp, EXYNOS_CENTRAL_SEQ_CONFIGURATION);
- tmp = __raw_readl(S5P_CENTRAL_SEQ_CONFIGURATION);
- tmp &= ~S5P_CENTRAL_LOWPWR_CFG;
- __raw_writel(tmp, S5P_CENTRAL_SEQ_CONFIGURATION);
+ /* Setting SEQ_OPTION register */
+ tmp = (EXYNOS5_USE_STANDBYWFI_ARM_CORE0 | EXYNOS5_USE_STANDBYWFE_ARM_CORE0 |
+ EXYNOS5_USE_STANDBYWFI_ARM_CORE1 | EXYNOS5_USE_STANDBYWFE_ARM_CORE1);
+ __raw_writel(tmp, EXYNOS_CENTRAL_SEQ_OPTION);
- if (soc_is_exynos4212()) {
- tmp = __raw_readl(S5P_CENTRAL_SEQ_OPTION);
- tmp &= ~(S5P_USE_STANDBYWFI_ISP_ARM |
- S5P_USE_STANDBYWFE_ISP_ARM);
- __raw_writel(tmp, S5P_CENTRAL_SEQ_OPTION);
+ if (!soc_is_exynos5250()) {
+ /* Save Power control register */
+ asm ("mrc p15, 0, %0, c15, c0, 0"
+ : "=r" (tmp) : : "cc");
+ save_arm_register[0] = tmp;
+
+ /* Save Diagnostic register */
+ asm ("mrc p15, 0, %0, c15, c0, 1"
+ : "=r" (tmp) : : "cc");
+ save_arm_register[1] = tmp;
}
- /* Save Power control register */
- asm ("mrc p15, 0, %0, c15, c0, 0"
- : "=r" (tmp) : : "cc");
- save_arm_register[0] = tmp;
-
- /* Save Diagnostic register */
- asm ("mrc p15, 0, %0, c15, c0, 1"
- : "=r" (tmp) : : "cc");
- save_arm_register[1] = tmp;
-
return 0;
}
-static void exynos4_pm_resume(void)
+static void exynos_pm_resume(void)
{
unsigned long tmp;
+ exynos_reset_assert_ctrl(true);
+
/*
* If PMU failed while entering sleep mode, WFI will be
* ignored by PMU and then exiting cpu_do_idle().
* S5P_CENTRAL_LOWPWR_CFG bit will not be set automatically
* in this situation.
*/
- tmp = __raw_readl(S5P_CENTRAL_SEQ_CONFIGURATION);
- if (!(tmp & S5P_CENTRAL_LOWPWR_CFG)) {
- tmp |= S5P_CENTRAL_LOWPWR_CFG;
- __raw_writel(tmp, S5P_CENTRAL_SEQ_CONFIGURATION);
+ tmp = __raw_readl(EXYNOS_CENTRAL_SEQ_CONFIGURATION);
+ if (!(tmp & EXYNOS_CENTRAL_LOWPWR_CFG)) {
+ tmp |= EXYNOS_CENTRAL_LOWPWR_CFG;
+ __raw_writel(tmp, EXYNOS_CENTRAL_SEQ_CONFIGURATION);
/* No need to perform below restore code */
goto early_wakeup;
}
- /* Restore Power control register */
- tmp = save_arm_register[0];
- asm volatile ("mcr p15, 0, %0, c15, c0, 0"
- : : "r" (tmp)
- : "cc");
+ if (!soc_is_exynos5250()) {
+ /* Restore Power control register */
+ tmp = save_arm_register[0];
+ asm volatile ("mcr p15, 0, %0, c15, c0, 0"
+ : : "r" (tmp)
+ : "cc");
- /* Restore Diagnostic register */
- tmp = save_arm_register[1];
- asm volatile ("mcr p15, 0, %0, c15, c0, 1"
- : : "r" (tmp)
- : "cc");
+ /* Restore Diagnostic register */
+ tmp = save_arm_register[1];
+ asm volatile ("mcr p15, 0, %0, c15, c0, 1"
+ : : "r" (tmp)
+ : "cc");
+ }
/* For release retention */
- __raw_writel((1 << 28), S5P_PAD_RET_MAUDIO_OPTION);
- __raw_writel((1 << 28), S5P_PAD_RET_GPIO_OPTION);
- __raw_writel((1 << 28), S5P_PAD_RET_UART_OPTION);
- __raw_writel((1 << 28), S5P_PAD_RET_MMCA_OPTION);
- __raw_writel((1 << 28), S5P_PAD_RET_MMCB_OPTION);
- __raw_writel((1 << 28), S5P_PAD_RET_EBIA_OPTION);
- __raw_writel((1 << 28), S5P_PAD_RET_EBIB_OPTION);
+ __raw_writel((1 << 28), EXYNOS_PAD_RET_MAUDIO_OPTION);
+ __raw_writel((1 << 28), EXYNOS_PAD_RET_GPIO_OPTION);
+ __raw_writel((1 << 28), EXYNOS_PAD_RET_UART_OPTION);
+ __raw_writel((1 << 28), EXYNOS_PAD_RET_MMCA_OPTION);
+ __raw_writel((1 << 28), EXYNOS_PAD_RET_MMCB_OPTION);
+ __raw_writel((1 << 28), EXYNOS_PAD_RET_EBIA_OPTION);
+ __raw_writel((1 << 28), EXYNOS_PAD_RET_EBIB_OPTION);
+ __raw_writel((1 << 28), EXYNOS5_PAD_RETENTION_SPI_OPTION);
+ __raw_writel((1 << 28), EXYNOS5_PAD_RETENTION_GPIO_SYSMEM_OPTION);
- s3c_pm_do_restore_core(exynos4_core_save, ARRAY_SIZE(exynos4_core_save));
+ s3c_pm_do_restore_core(exynos_core_save, ARRAY_SIZE(exynos_core_save));
- exynos4_restore_pll();
+ bts_initialize(NULL, true);
+ if (!soc_is_exynos5250()) {
+ exynos4_restore_pll();
#ifdef CONFIG_SMP
- scu_enable(S5P_VA_SCU);
+ scu_enable(S5P_VA_SCU);
#endif
+ }
+
early_wakeup:
+ __raw_writel(0x0, REG_INFORM1);
+ exynos_show_wakeup_reason();
return;
}
-static struct syscore_ops exynos4_pm_syscore_ops = {
- .suspend = exynos4_pm_suspend,
- .resume = exynos4_pm_resume,
+static struct syscore_ops exynos_pm_syscore_ops = {
+ .suspend = exynos_pm_suspend,
+ .resume = exynos_pm_resume,
};
-static __init int exynos4_pm_syscore_init(void)
+static __init int exynos_pm_syscore_init(void)
{
- register_syscore_ops(&exynos4_pm_syscore_ops);
+ register_syscore_ops(&exynos_pm_syscore_ops);
return 0;
}
-arch_initcall(exynos4_pm_syscore_init);
+arch_initcall(exynos_pm_syscore_init);
diff --git a/arch/arm/mach-exynos/pm_domains.c b/arch/arm/mach-exynos/pm_domains.c
index 13b3068..794142f 100644
--- a/arch/arm/mach-exynos/pm_domains.c
+++ b/arch/arm/mach-exynos/pm_domains.c
@@ -19,47 +19,250 @@
#include <linux/pm_domain.h>
#include <linux/delay.h>
#include <linux/of_address.h>
+#include <linux/clk.h>
+#include <linux/list.h>
#include <mach/regs-pmu.h>
+#include <mach/regs-clock.h>
+#include <mach/exynos5_bus.h>
+#include <plat/cpu.h>
+#include <plat/clock.h>
#include <plat/devs.h>
+#include <plat/bts.h>
+
+#define MAX_PD_CLKS 2
+#define EXYNOS5_INT_MIN_FREQ 266000
/*
* Exynos specific wrapper around the generic power domain
*/
struct exynos_pm_domain {
+ struct list_head list;
void __iomem *base;
- char const *name;
bool is_off;
struct generic_pm_domain pd;
+ const char *pclk_name;
+ struct clk *pclk;
+ unsigned long saved_pclk_rate;
+ const char *clk_name[MAX_PD_CLKS];
+ struct clk *clk[MAX_PD_CLKS];
+ struct clk *saved_parent_clk[MAX_PD_CLKS];
+ struct exynos5_bus_int_handle *int_min_hd;
};
+struct exynos_pm_clk {
+ struct list_head node;
+ struct clk *clk;
+};
+
+struct exynos_pm_dev {
+ struct exynos_pm_domain *pd;
+ struct platform_device *pdev;
+ char const *con_id;
+};
+
+#define EXYNOS_PM_DEV(NAME, PD, DEV, CON) \
+static struct exynos_pm_dev exynos5_pm_dev_##NAME = { \
+ .pd = &exynos5_pd_##PD, \
+ .pdev = DEV, \
+ .con_id = CON, \
+}
+
+static void exynos_pd_clk_parent_save(struct exynos_pm_domain *pd)
+{
+ int i;
+ int r;
+
+ for (i = 0; i < MAX_PD_CLKS; i++) {
+ if (pd->clk[i]) {
+ pd->saved_parent_clk[i] = clk_get_parent(pd->clk[i]);
+ if (IS_ERR(pd->saved_parent_clk)) {
+ pr_err("Failed to save parent clk of %s for pd %s\n",
+ pd->clk_name[i], pd->pd.name);
+ pd->saved_parent_clk[i] = NULL;
+ }
+ }
+ }
+
+ if (pd->pclk) {
+ if (!pd->int_min_hd) {
+ pd->int_min_hd = exynos5_bus_int_min(EXYNOS5_INT_MIN_FREQ);
+ if (!pd->int_min_hd)
+ pr_err("Failed to request int min_freq\n");
+ }
+
+ pd->saved_pclk_rate = clk_get_rate(pd->pclk);
+ if (!pd->saved_pclk_rate) {
+ pr_err("Failed to save rate of %s for pd %s\n",
+ pd->pclk_name, pd->pd.name);
+ pd->saved_pclk_rate = 0;
+ }
+
+ r = clk_set_rate(pd->pclk, clk_get_rate(pd->pclk->parent));
+ if (r)
+ pr_err("Failed to set rate of parent clk of %s for pd %s\n",
+ pd->pclk_name, pd->pd.name);
+
+ if (pd->int_min_hd) {
+ exynos5_bus_int_put(pd->int_min_hd);
+ pd->int_min_hd = NULL;
+ }
+ }
+}
+
+static void exynos_pd_clk_parent_restore(struct exynos_pm_domain *pd)
+{
+ int i;
+ int r;
+
+ for (i = 0; i < MAX_PD_CLKS; i++) {
+ if (pd->clk[i] && pd->saved_parent_clk[i]) {
+ r = clk_set_parent(pd->clk[i], pd->saved_parent_clk[i]);
+ if (r)
+ pr_err("Failed to restore parent clk of %s for pd %s\n",
+ pd->clk_name[i], pd->pd.name);
+ pd->saved_parent_clk[i] = NULL;
+ }
+ }
+
+ if (pd->pclk) {
+ if (!pd->int_min_hd) {
+ pd->int_min_hd = exynos5_bus_int_min(EXYNOS5_INT_MIN_FREQ);
+ if (!pd->int_min_hd)
+ pr_err("Failed to request int min_freq\n");
+ }
+
+ if (pd->saved_pclk_rate) {
+ r = clk_set_rate(pd->pclk, pd->saved_pclk_rate);
+ if (r)
+ pr_err("Failed to restore rate of %s for pd %s\n",
+ pd->pclk_name, pd->pd.name);
+ pd->saved_pclk_rate = 0;
+ }
+
+ if (pd->int_min_hd) {
+ exynos5_bus_int_put(pd->int_min_hd);
+ pd->int_min_hd = NULL;
+ }
+ }
+}
+
static int exynos_pd_power(struct generic_pm_domain *domain, bool power_on)
{
- struct exynos_pm_domain *pd;
+ struct gpd_link *link;
+ struct exynos_pm_domain *pd, *spd;
+ struct exynos_pm_clk *pclk, *spclk;
void __iomem *base;
u32 timeout, pwr;
char *op;
+ int ret = 0;
pd = container_of(domain, struct exynos_pm_domain, pd);
base = pd->base;
- pwr = power_on ? S5P_INT_LOCAL_PWR_EN : 0;
+ if (!base) {
+ pr_err("%s: Failed to get %s power domain base address\n",
+ __func__, domain->name);
+ return -EINVAL;
+ }
+
+ /* Enable all the clocks of IPs in power domain */
+ list_for_each_entry(pclk, &pd->list, node) {
+ if (clk_enable(pclk->clk)) {
+ ret = -EINVAL;
+ goto unwind;
+ }
+ }
+
+ list_for_each_entry(link, &domain->master_links, master_node) {
+ spd = container_of(link->slave, struct exynos_pm_domain, pd);
+ list_for_each_entry(spclk, &spd->list, node) {
+ if (clk_enable(spclk->clk)) {
+ ret = -EINVAL;
+ goto s_unwind;
+ }
+ }
+ }
+
+ if (soc_is_exynos5250() &&
+ !power_on && base == EXYNOS5_ISP_CONFIGURATION)
+ __raw_writel(0x0, EXYNOS5_CMU_RESET_ISP_SYS_PWR_REG);
+
+ if (soc_is_exynos5250() &&
+ !power_on && base == EXYNOS5_MAU_CONFIGURATION) {
+ __raw_writel(0x0, EXYNOS5_CMU_CLKSTOP_MAU_SYS_PWR_REG);
+ __raw_writel(0x0, EXYNOS5_CMU_RESET_MAU_SYS_PWR_REG);
+ __raw_writel(0x0, EXYNOS5_PAD_RETENTION_MAU_SYS_PWR_REG);
+ }
+
+ if (!power_on)
+ exynos_pd_clk_parent_save(pd);
+
+ if (soc_is_exynos5250() &&
+ (base == EXYNOS5_MFC_CONFIGURATION ||
+ base == EXYNOS5_G3D_CONFIGURATION ||
+ base == EXYNOS5_GSCL_CONFIGURATION))
+ exynos5_mif_used_dev(power_on);
+
+ pwr = power_on ? EXYNOS_INT_LOCAL_PWR_EN : 0;
+
__raw_writel(pwr, base);
/* Wait max 1ms */
timeout = 10;
- while ((__raw_readl(base + 0x4) & S5P_INT_LOCAL_PWR_EN) != pwr) {
+ while ((__raw_readl(base + 0x4) & EXYNOS_INT_LOCAL_PWR_EN) != pwr) {
if (!timeout) {
op = (power_on) ? "enable" : "disable";
pr_err("Power domain %s %s failed\n", domain->name, op);
- return -ETIMEDOUT;
+ ret = -ETIMEDOUT;
+ break;
}
timeout--;
cpu_relax();
usleep_range(80, 100);
}
- return 0;
+
+ if (soc_is_exynos5250() && !timeout)
+ pr_err("%s power domain state (0x%02x)\n", domain->name,
+ (__raw_readl(base + 0x4) >> EXYNOS5_LOCAL_POWER_STATE_SHIFT) &
+ EXYNOS5_LOCAL_POWER_STATE_MASK);
+
+ if (power_on)
+ exynos_pd_clk_parent_restore(pd);
+
+ if (soc_is_exynos5250() &&
+ power_on && base == EXYNOS5_MAU_CONFIGURATION) {
+ __raw_writel(0x10000000, EXYNOS_PAD_RET_MAUDIO_OPTION);
+ }
+
+ /* Disable all the clocks of IPs in power domain */
+ list_for_each_entry(link, &domain->master_links, master_node) {
+ spd = container_of(link->slave, struct exynos_pm_domain, pd);
+ list_for_each_entry(spclk, &spd->list, node) {
+ clk_disable(spclk->clk);
+ }
+ }
+
+ list_for_each_entry(pclk, &pd->list, node)
+ clk_disable(pclk->clk);
+
+ bts_initialize(pd->pd.name, power_on);
+
+ return ret;
+
+s_unwind:
+ list_for_each_entry_continue_reverse(link, &domain->master_links, master_node) {
+ spd = container_of(link->slave, struct exynos_pm_domain, pd);
+ list_for_each_entry_continue_reverse(spclk, &spd->list, node) {
+ clk_disable(spclk->clk);
+ }
+ }
+unwind:
+ list_for_each_entry_continue_reverse(pclk, &pd->list, node)
+ clk_disable(pclk->clk);
+
+ return ret;
}
static int exynos_pd_power_on(struct generic_pm_domain *domain)
@@ -72,13 +275,36 @@
return exynos_pd_power(domain, false);
}
-#define EXYNOS_GPD(PD, BASE, NAME) \
+static int exynos_sub_power_on(struct generic_pm_domain *domain)
+{
+ return 0;
+}
+
+static int exynos_sub_power_off(struct generic_pm_domain *domain)
+{
+ return 0;
+}
+
+#define EXYNOS_GPD(PD, BASE, NAME, PCLK, CLKS...) \
static struct exynos_pm_domain PD = { \
+ .list = LIST_HEAD_INIT((PD).list), \
.base = (void __iomem *)BASE, \
- .name = NAME, \
.pd = { \
+ .name = NAME, \
.power_off = exynos_pd_power_off, \
- .power_on = exynos_pd_power_on, \
+ .power_on = exynos_pd_power_on, \
+ }, \
+ .pclk_name = PCLK, \
+ .clk_name = { CLKS } \
+}
+
+#define EXYNOS_SUB_GPD(PD, NAME) \
+static struct exynos_pm_domain PD = { \
+ .list = LIST_HEAD_INIT((PD).list), \
+ .pd = { \
+ .name = NAME, \
+ .power_off = exynos_sub_power_off, \
+ .power_on = exynos_sub_power_on, \
}, \
}
@@ -115,35 +341,51 @@
}
#endif /* CONFIG_OF */
+static __init void exynos_pm_add_subdomain_to_genpd(struct generic_pm_domain *genpd,
+ struct generic_pm_domain *subdomain)
+{
+ if (pm_genpd_add_subdomain(genpd, subdomain))
+ pr_info("%s: error in adding %s subdomain to %s power "
+ "domain\n", __func__, subdomain->name, genpd->name);
+}
+
static __init void exynos_pm_add_dev_to_genpd(struct platform_device *pdev,
struct exynos_pm_domain *pd)
{
if (pdev->dev.bus) {
- if (pm_genpd_add_device(&pd->pd, &pdev->dev))
+ if (!pm_genpd_add_device(&pd->pd, &pdev->dev))
+ pm_genpd_dev_need_restore(&pdev->dev, true);
+ else
pr_info("%s: error in adding %s device to %s power"
"domain\n", __func__, dev_name(&pdev->dev),
- pd->name);
+ pd->pd.name);
}
}
-EXYNOS_GPD(exynos4_pd_mfc, S5P_PMU_MFC_CONF, "pd-mfc");
-EXYNOS_GPD(exynos4_pd_g3d, S5P_PMU_G3D_CONF, "pd-g3d");
-EXYNOS_GPD(exynos4_pd_lcd0, S5P_PMU_LCD0_CONF, "pd-lcd0");
-EXYNOS_GPD(exynos4_pd_lcd1, S5P_PMU_LCD1_CONF, "pd-lcd1");
-EXYNOS_GPD(exynos4_pd_tv, S5P_PMU_TV_CONF, "pd-tv");
-EXYNOS_GPD(exynos4_pd_cam, S5P_PMU_CAM_CONF, "pd-cam");
-EXYNOS_GPD(exynos4_pd_gps, S5P_PMU_GPS_CONF, "pd-gps");
+/* For EXYNOS4 */
+EXYNOS_GPD(exynos4_pd_mfc, EXYNOS4_MFC_CONFIGURATION, "pd-mfc", NULL);
+EXYNOS_GPD(exynos4_pd_g3d, EXYNOS4_G3D_CONFIGURATION, "pd-g3d", NULL);
+EXYNOS_GPD(exynos4_pd_lcd0, EXYNOS4_LCD0_CONFIGURATION, "pd-lcd0", NULL);
+EXYNOS_GPD(exynos4_pd_tv, EXYNOS4_TV_CONFIGURATION, "pd-tv", NULL);
+EXYNOS_GPD(exynos4_pd_cam, EXYNOS4_CAM_CONFIGURATION, "pd-cam", NULL);
+EXYNOS_GPD(exynos4_pd_gps, EXYNOS4_GPS_CONFIGURATION, "pd-gps", NULL);
+
+/* For EXYNOS4210 */
+EXYNOS_GPD(exynos4210_pd_lcd1, EXYNOS4210_LCD1_CONFIGURATION, "pd-lcd1", NULL);
static struct exynos_pm_domain *exynos4_pm_domains[] = {
&exynos4_pd_mfc,
&exynos4_pd_g3d,
&exynos4_pd_lcd0,
- &exynos4_pd_lcd1,
&exynos4_pd_tv,
&exynos4_pd_cam,
&exynos4_pd_gps,
};
+static struct exynos_pm_domain *exynos4210_pm_domains[] = {
+ &exynos4210_pd_lcd1,
+};
+
static __init int exynos4_pm_init_power_domain(void)
{
int idx;
@@ -155,6 +397,11 @@
pm_genpd_init(&exynos4_pm_domains[idx]->pd, NULL,
exynos4_pm_domains[idx]->is_off);
+ if (soc_is_exynos4210())
+ for (idx = 0; idx < ARRAY_SIZE(exynos4210_pm_domains); idx++)
+ pm_genpd_init(&exynos4210_pm_domains[idx]->pd, NULL,
+ exynos4210_pm_domains[idx]->is_off);
+
#ifdef CONFIG_S5P_DEV_FIMD0
exynos_pm_add_dev_to_genpd(&s5p_device_fimd0, &exynos4_pd_lcd0);
#endif
@@ -191,7 +438,211 @@
#endif
return 0;
}
-arch_initcall(exynos4_pm_init_power_domain);
+
+/* For EXYNOS5 */
+EXYNOS_GPD(exynos5_pd_mfc, EXYNOS5_MFC_CONFIGURATION, "pd-mfc",
+ "pclk_83_mfc", "aclk_333");
+EXYNOS_GPD(exynos5_pd_maudio, EXYNOS5_MAU_CONFIGURATION, "pd-maudio", NULL);
+EXYNOS_GPD(exynos5_pd_disp1, EXYNOS5_DISP1_CONFIGURATION, "pd-disp1",
+ "pclk_100_disp1", "aclk_200_disp1", "aclk_300_disp1");
+EXYNOS_SUB_GPD(exynos5_pd_fimd1, "pd-fimd1");
+EXYNOS_SUB_GPD(exynos5_pd_hdmi, "pd-hdmi");
+EXYNOS_SUB_GPD(exynos5_pd_mixer, "pd-mixer");
+EXYNOS_SUB_GPD(exynos5_pd_dp, "pd-dp");
+EXYNOS_GPD(exynos5_pd_gscl, EXYNOS5_GSCL_CONFIGURATION, "pd-gscl",
+ "pclk_133_gscl", "aclk_266_gscl", "aclk_300_gscl");
+EXYNOS_SUB_GPD(exynos5_pd_gscl0, "pd-gscl0");
+EXYNOS_SUB_GPD(exynos5_pd_gscl1, "pd-gscl1");
+EXYNOS_SUB_GPD(exynos5_pd_gscl2, "pd-gscl2");
+EXYNOS_SUB_GPD(exynos5_pd_gscl3, "pd-gscl3");
+EXYNOS_GPD(exynos5_pd_isp, EXYNOS5_ISP_CONFIGURATION, "pd-isp", NULL);
+EXYNOS_GPD(exynos5_pd_g3d, EXYNOS5_G3D_CONFIGURATION, "pd-g3d", NULL);
+
+static struct exynos_pm_domain *exynos5_pm_domains[] = {
+ &exynos5_pd_mfc,
+ &exynos5_pd_maudio,
+ &exynos5_pd_disp1,
+ &exynos5_pd_fimd1,
+ &exynos5_pd_hdmi,
+ &exynos5_pd_mixer,
+ &exynos5_pd_dp,
+ &exynos5_pd_gscl,
+ &exynos5_pd_gscl0,
+ &exynos5_pd_gscl1,
+ &exynos5_pd_gscl2,
+ &exynos5_pd_gscl3,
+ &exynos5_pd_isp,
+ &exynos5_pd_g3d,
+};
+
+#ifdef CONFIG_S5P_DEV_MFC
+EXYNOS_PM_DEV(mfc, mfc, &s5p_device_mfc, "mfc");
+#endif
+#ifdef CONFIG_SND_SAMSUNG_I2S
+EXYNOS_PM_DEV(maudio, maudio, &exynos5_device_i2s0, NULL);
+#endif
+#ifdef CONFIG_S5P_DEV_FIMD1
+EXYNOS_PM_DEV(fimd1, fimd1, &s5p_device_fimd1, "fimd");
+#endif
+#ifdef CONFIG_S5P_DEV_TV
+EXYNOS_PM_DEV(hdmi, hdmi, &s5p_device_hdmi, NULL);
+EXYNOS_PM_DEV(mixer, mixer, &s5p_device_mixer, "mixer");
+#endif
+#ifdef CONFIG_S5P_DEV_DP
+EXYNOS_PM_DEV(dp, dp, &s5p_device_dp, "dp");
+#endif
+#ifdef CONFIG_EXYNOS5_DEV_GSC
+EXYNOS_PM_DEV(gscl0, gscl0, &exynos5_device_gsc0, "gscl");
+EXYNOS_PM_DEV(gscl1, gscl1, &exynos5_device_gsc1, "gscl");
+EXYNOS_PM_DEV(gscl2, gscl2, &exynos5_device_gsc2, "gscl");
+EXYNOS_PM_DEV(gscl3, gscl3, &exynos5_device_gsc3, "gscl");
+#endif
+#ifdef CONFIG_EXYNOS4_DEV_FIMC_IS
+EXYNOS_PM_DEV(isp, isp, &exynos5_device_fimc_is, NULL);
+#endif
+#ifdef CONFIG_MALI_T6XX
+EXYNOS_PM_DEV(g3d, g3d, &exynos5_device_g3d, "g3d");
+#endif
+
+static struct exynos_pm_dev *exynos_pm_devs[] = {
+#ifdef CONFIG_S5P_DEV_MFC
+ &exynos5_pm_dev_mfc,
+#endif
+#ifdef CONFIG_SND_SAMSUNG_I2S
+ &exynos5_pm_dev_maudio,
+#endif
+#ifdef CONFIG_S5P_DEV_FIMD1
+ &exynos5_pm_dev_fimd1,
+#endif
+#ifdef CONFIG_S5P_DEV_TV
+ &exynos5_pm_dev_hdmi,
+ &exynos5_pm_dev_mixer,
+#endif
+#ifdef CONFIG_S5P_DEV_DP
+ &exynos5_pm_dev_dp,
+#endif
+#ifdef CONFIG_EXYNOS5_DEV_GSC
+ &exynos5_pm_dev_gscl0,
+ &exynos5_pm_dev_gscl1,
+ &exynos5_pm_dev_gscl2,
+ &exynos5_pm_dev_gscl3,
+#endif
+#ifdef CONFIG_EXYNOS4_DEV_FIMC_IS
+ &exynos5_pm_dev_isp,
+#endif
+#ifdef CONFIG_MALI_T6XX
+ &exynos5_pm_dev_g3d,
+#endif
+};
+
+static void __init exynos5_add_device_to_pd(struct exynos_pm_dev **pm_dev, int size)
+{
+ struct exynos_pm_dev *tdev;
+ struct exynos_pm_clk *pclk;
+ struct clk *clk;
+ int i;
+
+ for (i = 0; i < size; i++) {
+ tdev = pm_dev[i];
+
+ if (!tdev->con_id)
+ continue;
+
+ pclk = kzalloc(sizeof(struct exynos_pm_clk), GFP_KERNEL);
+
+ if (!pclk) {
+ pr_err("Unable to create new exynos_pm_clk\n");
+ continue;
+ }
+
+ clk = clk_get(&tdev->pdev->dev, tdev->con_id);
+
+ if (!IS_ERR(clk)) {
+ pclk->clk = clk;
+ list_add(&pclk->node, &tdev->pd->list);
+ } else {
+ pr_err("Failed to get %s clock\n", dev_name(&tdev->pdev->dev));
+ kfree(pclk);
+ }
+
+ }
+}
+
+static void __init exynos5_pm_init_one_pd(struct exynos_pm_domain *pd)
+{
+ int i;
+
+ pm_genpd_init(&pd->pd, NULL, pd->is_off);
+
+ for (i = 0; i < MAX_PD_CLKS; i++)
+ if (pd->clk_name[i])
+ pd->clk[i] = clk_get(NULL, pd->clk_name[i]);
+
+ if (pd->pclk_name)
+ pd->pclk = clk_get(NULL, pd->pclk_name);
+}
+
+static int __init exynos5_pm_init_power_domain(void)
+{
+ int idx;
+
+ if (of_have_populated_dt())
+ return exynos_pm_dt_parse_domains();
+
+ for (idx = 0; idx < ARRAY_SIZE(exynos5_pm_domains); idx++)
+ exynos5_pm_init_one_pd(exynos5_pm_domains[idx]);
+
+#ifdef CONFIG_S5P_DEV_MFC
+ exynos_pm_add_dev_to_genpd(&s5p_device_mfc, &exynos5_pd_mfc);
+#endif
+#ifdef CONFIG_SND_SAMSUNG_I2S
+ exynos_pm_add_dev_to_genpd(&exynos5_device_i2s0, &exynos5_pd_maudio);
+#endif
+#ifdef CONFIG_S5P_DEV_FIMD1
+ exynos_pm_add_subdomain_to_genpd(&exynos5_pd_disp1.pd, &exynos5_pd_fimd1.pd);
+ exynos_pm_add_dev_to_genpd(&s5p_device_fimd1, &exynos5_pd_fimd1);
+#endif
+#ifdef CONFIG_S5P_DEV_TV
+ exynos_pm_add_subdomain_to_genpd(&exynos5_pd_disp1.pd, &exynos5_pd_hdmi.pd);
+ exynos_pm_add_subdomain_to_genpd(&exynos5_pd_disp1.pd, &exynos5_pd_mixer.pd);
+ exynos_pm_add_dev_to_genpd(&s5p_device_hdmi, &exynos5_pd_hdmi);
+ exynos_pm_add_dev_to_genpd(&s5p_device_mixer, &exynos5_pd_mixer);
+#endif
+#ifdef CONFIG_S5P_DEV_DP
+ exynos_pm_add_subdomain_to_genpd(&exynos5_pd_disp1.pd, &exynos5_pd_dp.pd);
+ exynos_pm_add_dev_to_genpd(&s5p_device_dp, &exynos5_pd_dp);
+#endif
+#ifdef CONFIG_EXYNOS5_DEV_GSC
+ exynos_pm_add_subdomain_to_genpd(&exynos5_pd_gscl.pd, &exynos5_pd_gscl0.pd);
+ exynos_pm_add_subdomain_to_genpd(&exynos5_pd_gscl.pd, &exynos5_pd_gscl1.pd);
+ exynos_pm_add_subdomain_to_genpd(&exynos5_pd_gscl.pd, &exynos5_pd_gscl2.pd);
+ exynos_pm_add_subdomain_to_genpd(&exynos5_pd_gscl.pd, &exynos5_pd_gscl3.pd);
+ exynos_pm_add_dev_to_genpd(&exynos5_device_gsc0, &exynos5_pd_gscl0);
+ exynos_pm_add_dev_to_genpd(&exynos5_device_gsc1, &exynos5_pd_gscl1);
+ exynos_pm_add_dev_to_genpd(&exynos5_device_gsc2, &exynos5_pd_gscl2);
+ exynos_pm_add_dev_to_genpd(&exynos5_device_gsc3, &exynos5_pd_gscl3);
+#endif
+#ifdef CONFIG_EXYNOS4_DEV_FIMC_IS
+ exynos_pm_add_dev_to_genpd(&exynos5_device_fimc_is, &exynos5_pd_isp);
+ exynos_pm_add_subdomain_to_genpd(&exynos5_pd_gscl.pd, &exynos5_pd_isp.pd);
+#endif
+#ifdef CONFIG_MALI_T6XX
+ exynos_pm_add_dev_to_genpd(&exynos5_device_g3d, &exynos5_pd_g3d);
+#endif
+
+ exynos5_add_device_to_pd(exynos_pm_devs, ARRAY_SIZE(exynos_pm_devs));
+
+ return 0;
+}
+
+static int __init exynos_pm_init_power_domain(void)
+{
+ if (soc_is_exynos5250())
+ return exynos5_pm_init_power_domain();
+ else
+ return exynos4_pm_init_power_domain();
+}
+arch_initcall(exynos_pm_init_power_domain);
static __init int exynos_pm_late_initcall(void)
{
diff --git a/arch/arm/mach-exynos/pmu.c b/arch/arm/mach-exynos/pmu.c
index bba48f5..280a6ea 100644
--- a/arch/arm/mach-exynos/pmu.c
+++ b/arch/arm/mach-exynos/pmu.c
@@ -1,9 +1,9 @@
-/* linux/arch/arm/mach-exynos4/pmu.c
+/* linux/arch/arm/mach-exynos/pmu.c
*
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
* http://www.samsung.com/
*
- * EXYNOS4210 - CPU PMU(Power Management Unit) support
+ * EXYNOS - CPU PMU(Power Management Unit) support
*
* 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
@@ -11,220 +11,466 @@
*/
#include <linux/io.h>
+#include <linux/cpumask.h>
#include <linux/kernel.h>
+#include <linux/bug.h>
#include <mach/regs-clock.h>
#include <mach/pmu.h>
-static struct exynos4_pmu_conf *exynos4_pmu_config;
+static struct exynos_pmu_conf *exynos_pmu_config;
-static struct exynos4_pmu_conf exynos4210_pmu_config[] = {
+static struct exynos_pmu_conf exynos4210_pmu_config[] = {
/* { .reg = address, .val = { AFTR, LPA, SLEEP } */
- { S5P_ARM_CORE0_LOWPWR, { 0x0, 0x0, 0x2 } },
- { S5P_DIS_IRQ_CORE0, { 0x0, 0x0, 0x0 } },
- { S5P_DIS_IRQ_CENTRAL0, { 0x0, 0x0, 0x0 } },
- { S5P_ARM_CORE1_LOWPWR, { 0x0, 0x0, 0x2 } },
- { S5P_DIS_IRQ_CORE1, { 0x0, 0x0, 0x0 } },
- { S5P_DIS_IRQ_CENTRAL1, { 0x0, 0x0, 0x0 } },
- { S5P_ARM_COMMON_LOWPWR, { 0x0, 0x0, 0x2 } },
- { S5P_L2_0_LOWPWR, { 0x2, 0x2, 0x3 } },
- { S5P_L2_1_LOWPWR, { 0x2, 0x2, 0x3 } },
- { S5P_CMU_ACLKSTOP_LOWPWR, { 0x1, 0x0, 0x0 } },
- { S5P_CMU_SCLKSTOP_LOWPWR, { 0x1, 0x0, 0x0 } },
- { S5P_CMU_RESET_LOWPWR, { 0x1, 0x1, 0x0 } },
- { S5P_APLL_SYSCLK_LOWPWR, { 0x1, 0x0, 0x0 } },
- { S5P_MPLL_SYSCLK_LOWPWR, { 0x1, 0x0, 0x0 } },
- { S5P_VPLL_SYSCLK_LOWPWR, { 0x1, 0x0, 0x0 } },
- { S5P_EPLL_SYSCLK_LOWPWR, { 0x1, 0x1, 0x0 } },
- { S5P_CMU_CLKSTOP_GPS_ALIVE_LOWPWR, { 0x1, 0x1, 0x0 } },
- { S5P_CMU_RESET_GPSALIVE_LOWPWR, { 0x1, 0x1, 0x0 } },
- { S5P_CMU_CLKSTOP_CAM_LOWPWR, { 0x1, 0x1, 0x0 } },
- { S5P_CMU_CLKSTOP_TV_LOWPWR, { 0x1, 0x1, 0x0 } },
- { S5P_CMU_CLKSTOP_MFC_LOWPWR, { 0x1, 0x1, 0x0 } },
- { S5P_CMU_CLKSTOP_G3D_LOWPWR, { 0x1, 0x1, 0x0 } },
- { S5P_CMU_CLKSTOP_LCD0_LOWPWR, { 0x1, 0x1, 0x0 } },
- { S5P_CMU_CLKSTOP_LCD1_LOWPWR, { 0x1, 0x1, 0x0 } },
- { S5P_CMU_CLKSTOP_MAUDIO_LOWPWR, { 0x1, 0x1, 0x0 } },
- { S5P_CMU_CLKSTOP_GPS_LOWPWR, { 0x1, 0x1, 0x0 } },
- { S5P_CMU_RESET_CAM_LOWPWR, { 0x1, 0x1, 0x0 } },
- { S5P_CMU_RESET_TV_LOWPWR, { 0x1, 0x1, 0x0 } },
- { S5P_CMU_RESET_MFC_LOWPWR, { 0x1, 0x1, 0x0 } },
- { S5P_CMU_RESET_G3D_LOWPWR, { 0x1, 0x1, 0x0 } },
- { S5P_CMU_RESET_LCD0_LOWPWR, { 0x1, 0x1, 0x0 } },
- { S5P_CMU_RESET_LCD1_LOWPWR, { 0x1, 0x1, 0x0 } },
- { S5P_CMU_RESET_MAUDIO_LOWPWR, { 0x1, 0x1, 0x0 } },
- { S5P_CMU_RESET_GPS_LOWPWR, { 0x1, 0x1, 0x0 } },
- { S5P_TOP_BUS_LOWPWR, { 0x3, 0x0, 0x0 } },
- { S5P_TOP_RETENTION_LOWPWR, { 0x1, 0x0, 0x1 } },
- { S5P_TOP_PWR_LOWPWR, { 0x3, 0x0, 0x3 } },
- { S5P_LOGIC_RESET_LOWPWR, { 0x1, 0x1, 0x0 } },
- { S5P_ONENAND_MEM_LOWPWR, { 0x3, 0x0, 0x0 } },
- { S5P_MODIMIF_MEM_LOWPWR, { 0x3, 0x0, 0x0 } },
- { S5P_G2D_ACP_MEM_LOWPWR, { 0x3, 0x0, 0x0 } },
- { S5P_USBOTG_MEM_LOWPWR, { 0x3, 0x0, 0x0 } },
- { S5P_HSMMC_MEM_LOWPWR, { 0x3, 0x0, 0x0 } },
- { S5P_CSSYS_MEM_LOWPWR, { 0x3, 0x0, 0x0 } },
- { S5P_SECSS_MEM_LOWPWR, { 0x3, 0x0, 0x0 } },
- { S5P_PCIE_MEM_LOWPWR, { 0x3, 0x0, 0x0 } },
- { S5P_SATA_MEM_LOWPWR, { 0x3, 0x0, 0x0 } },
- { S5P_PAD_RETENTION_DRAM_LOWPWR, { 0x1, 0x0, 0x0 } },
- { S5P_PAD_RETENTION_MAUDIO_LOWPWR, { 0x1, 0x1, 0x0 } },
- { S5P_PAD_RETENTION_GPIO_LOWPWR, { 0x1, 0x0, 0x0 } },
- { S5P_PAD_RETENTION_UART_LOWPWR, { 0x1, 0x0, 0x0 } },
- { S5P_PAD_RETENTION_MMCA_LOWPWR, { 0x1, 0x0, 0x0 } },
- { S5P_PAD_RETENTION_MMCB_LOWPWR, { 0x1, 0x0, 0x0 } },
- { S5P_PAD_RETENTION_EBIA_LOWPWR, { 0x1, 0x0, 0x0 } },
- { S5P_PAD_RETENTION_EBIB_LOWPWR, { 0x1, 0x0, 0x0 } },
- { S5P_PAD_RETENTION_ISOLATION_LOWPWR, { 0x1, 0x0, 0x0 } },
- { S5P_PAD_RETENTION_ALV_SEL_LOWPWR, { 0x1, 0x0, 0x0 } },
- { S5P_XUSBXTI_LOWPWR, { 0x1, 0x1, 0x0 } },
- { S5P_XXTI_LOWPWR, { 0x1, 0x1, 0x0 } },
- { S5P_EXT_REGULATOR_LOWPWR, { 0x1, 0x1, 0x0 } },
- { S5P_GPIO_MODE_LOWPWR, { 0x1, 0x0, 0x0 } },
- { S5P_GPIO_MODE_MAUDIO_LOWPWR, { 0x1, 0x1, 0x0 } },
- { S5P_CAM_LOWPWR, { 0x7, 0x0, 0x0 } },
- { S5P_TV_LOWPWR, { 0x7, 0x0, 0x0 } },
- { S5P_MFC_LOWPWR, { 0x7, 0x0, 0x0 } },
- { S5P_G3D_LOWPWR, { 0x7, 0x0, 0x0 } },
- { S5P_LCD0_LOWPWR, { 0x7, 0x0, 0x0 } },
- { S5P_LCD1_LOWPWR, { 0x7, 0x0, 0x0 } },
- { S5P_MAUDIO_LOWPWR, { 0x7, 0x7, 0x0 } },
- { S5P_GPS_LOWPWR, { 0x7, 0x0, 0x0 } },
- { S5P_GPS_ALIVE_LOWPWR, { 0x7, 0x0, 0x0 } },
+ { EXYNOS4_ARM_CORE0_LOWPWR, { 0x0, 0x0, 0x2 } },
+ { EXYNOS4_DIS_IRQ_CORE0, { 0x0, 0x0, 0x0 } },
+ { EXYNOS4_DIS_IRQ_CENTRAL0, { 0x0, 0x0, 0x0 } },
+ { EXYNOS4_ARM_CORE1_LOWPWR, { 0x0, 0x0, 0x2 } },
+ { EXYNOS4_DIS_IRQ_CORE1, { 0x0, 0x0, 0x0 } },
+ { EXYNOS4_DIS_IRQ_CENTRAL1, { 0x0, 0x0, 0x0 } },
+ { EXYNOS4_ARM_COMMON_LOWPWR, { 0x0, 0x0, 0x2 } },
+ { EXYNOS4_L2_0_LOWPWR, { 0x2, 0x2, 0x3 } },
+ { EXYNOS4_L2_1_LOWPWR, { 0x2, 0x2, 0x3 } },
+ { EXYNOS4_CMU_ACLKSTOP_LOWPWR, { 0x1, 0x0, 0x0 } },
+ { EXYNOS4_CMU_SCLKSTOP_LOWPWR, { 0x1, 0x0, 0x0 } },
+ { EXYNOS4_CMU_RESET_LOWPWR, { 0x1, 0x1, 0x0 } },
+ { EXYNOS4_APLL_SYSCLK_LOWPWR, { 0x1, 0x0, 0x0 } },
+ { EXYNOS4_MPLL_SYSCLK_LOWPWR, { 0x1, 0x0, 0x0 } },
+ { EXYNOS4_VPLL_SYSCLK_LOWPWR, { 0x1, 0x0, 0x0 } },
+ { EXYNOS4_EPLL_SYSCLK_LOWPWR, { 0x1, 0x1, 0x0 } },
+ { EXYNOS4_CMU_CLKSTOP_GPS_ALIVE_LOWPWR, { 0x1, 0x1, 0x0 } },
+ { EXYNOS4_CMU_RESET_GPSALIVE_LOWPWR, { 0x1, 0x1, 0x0 } },
+ { EXYNOS4_CMU_CLKSTOP_CAM_LOWPWR, { 0x1, 0x1, 0x0 } },
+ { EXYNOS4_CMU_CLKSTOP_TV_LOWPWR, { 0x1, 0x1, 0x0 } },
+ { EXYNOS4_CMU_CLKSTOP_MFC_LOWPWR, { 0x1, 0x1, 0x0 } },
+ { EXYNOS4_CMU_CLKSTOP_G3D_LOWPWR, { 0x1, 0x1, 0x0 } },
+ { EXYNOS4_CMU_CLKSTOP_LCD0_LOWPWR, { 0x1, 0x1, 0x0 } },
+ { EXYNOS4210_CMU_CLKSTOP_LCD1_LOWPWR, { 0x1, 0x1, 0x0 } },
+ { EXYNOS4_CMU_CLKSTOP_MAUDIO_LOWPWR, { 0x1, 0x1, 0x0 } },
+ { EXYNOS4_CMU_CLKSTOP_GPS_LOWPWR, { 0x1, 0x1, 0x0 } },
+ { EXYNOS4_CMU_RESET_CAM_LOWPWR, { 0x1, 0x1, 0x0 } },
+ { EXYNOS4_CMU_RESET_TV_LOWPWR, { 0x1, 0x1, 0x0 } },
+ { EXYNOS4_CMU_RESET_MFC_LOWPWR, { 0x1, 0x1, 0x0 } },
+ { EXYNOS4_CMU_RESET_G3D_LOWPWR, { 0x1, 0x1, 0x0 } },
+ { EXYNOS4_CMU_RESET_LCD0_LOWPWR, { 0x1, 0x1, 0x0 } },
+ { EXYNOS4210_CMU_RESET_LCD1_LOWPWR, { 0x1, 0x1, 0x0 } },
+ { EXYNOS4_CMU_RESET_MAUDIO_LOWPWR, { 0x1, 0x1, 0x0 } },
+ { EXYNOS4_CMU_RESET_GPS_LOWPWR, { 0x1, 0x1, 0x0 } },
+ { EXYNOS4_TOP_BUS_LOWPWR, { 0x3, 0x0, 0x0 } },
+ { EXYNOS4_TOP_RETENTION_LOWPWR, { 0x1, 0x0, 0x1 } },
+ { EXYNOS4_TOP_PWR_LOWPWR, { 0x3, 0x0, 0x3 } },
+ { EXYNOS4_LOGIC_RESET_LOWPWR, { 0x1, 0x1, 0x0 } },
+ { EXYNOS4_ONENAND_MEM_LOWPWR, { 0x3, 0x0, 0x0 } },
+ { EXYNOS4210_MODIMIF_MEM_LOWPWR, { 0x3, 0x0, 0x0 } },
+ { EXYNOS4_G2D_ACP_MEM_LOWPWR, { 0x3, 0x0, 0x0 } },
+ { EXYNOS4_USBOTG_MEM_LOWPWR, { 0x3, 0x0, 0x0 } },
+ { EXYNOS4_HSMMC_MEM_LOWPWR, { 0x3, 0x0, 0x0 } },
+ { EXYNOS4_CSSYS_MEM_LOWPWR, { 0x3, 0x0, 0x0 } },
+ { EXYNOS4_SECSS_MEM_LOWPWR, { 0x3, 0x0, 0x0 } },
+ { EXYNOS4210_PCIE_MEM_LOWPWR, { 0x3, 0x0, 0x0 } },
+ { EXYNOS4210_SATA_MEM_LOWPWR, { 0x3, 0x0, 0x0 } },
+ { EXYNOS4_PAD_RETENTION_DRAM_LOWPWR, { 0x1, 0x0, 0x0 } },
+ { EXYNOS4_PAD_RETENTION_MAUDIO_LOWPWR, { 0x1, 0x1, 0x0 } },
+ { EXYNOS4_PAD_RETENTION_GPIO_LOWPWR, { 0x1, 0x0, 0x0 } },
+ { EXYNOS4_PAD_RETENTION_UART_LOWPWR, { 0x1, 0x0, 0x0 } },
+ { EXYNOS4_PAD_RETENTION_MMCA_LOWPWR, { 0x1, 0x0, 0x0 } },
+ { EXYNOS4_PAD_RETENTION_MMCB_LOWPWR, { 0x1, 0x0, 0x0 } },
+ { EXYNOS4_PAD_RETENTION_EBIA_LOWPWR, { 0x1, 0x0, 0x0 } },
+ { EXYNOS4_PAD_RETENTION_EBIB_LOWPWR, { 0x1, 0x0, 0x0 } },
+ { EXYNOS4_PAD_RETENTION_ISOLATION_LOWPWR, { 0x1, 0x0, 0x0 } },
+ { EXYNOS4_PAD_RETENTION_ALV_SEL_LOWPWR, { 0x1, 0x0, 0x0 } },
+ { EXYNOS4_XUSBXTI_LOWPWR, { 0x1, 0x1, 0x0 } },
+ { EXYNOS4_XXTI_LOWPWR, { 0x1, 0x1, 0x0 } },
+ { EXYNOS4_EXT_REGULATOR_LOWPWR, { 0x1, 0x1, 0x0 } },
+ { EXYNOS4_GPIO_MODE_LOWPWR, { 0x1, 0x0, 0x0 } },
+ { EXYNOS4_GPIO_MODE_MAUDIO_LOWPWR, { 0x1, 0x1, 0x0 } },
+ { EXYNOS4_CAM_LOWPWR, { 0x7, 0x0, 0x0 } },
+ { EXYNOS4_TV_LOWPWR, { 0x7, 0x0, 0x0 } },
+ { EXYNOS4_MFC_LOWPWR, { 0x7, 0x0, 0x0 } },
+ { EXYNOS4_G3D_LOWPWR, { 0x7, 0x0, 0x0 } },
+ { EXYNOS4_LCD0_LOWPWR, { 0x7, 0x0, 0x0 } },
+ { EXYNOS4210_LCD1_LOWPWR, { 0x7, 0x0, 0x0 } },
+ { EXYNOS4_MAUDIO_LOWPWR, { 0x7, 0x7, 0x0 } },
+ { EXYNOS4_GPS_LOWPWR, { 0x7, 0x0, 0x0 } },
+ { EXYNOS4_GPS_ALIVE_LOWPWR, { 0x7, 0x0, 0x0 } },
{ PMU_TABLE_END,},
};
-static struct exynos4_pmu_conf exynos4212_pmu_config[] = {
- { S5P_ARM_CORE0_LOWPWR, { 0x0, 0x0, 0x2 } },
- { S5P_DIS_IRQ_CORE0, { 0x0, 0x0, 0x0 } },
- { S5P_DIS_IRQ_CENTRAL0, { 0x0, 0x0, 0x0 } },
- { S5P_ARM_CORE1_LOWPWR, { 0x0, 0x0, 0x2 } },
- { S5P_DIS_IRQ_CORE1, { 0x0, 0x0, 0x0 } },
- { S5P_DIS_IRQ_CENTRAL1, { 0x0, 0x0, 0x0 } },
- { S5P_ISP_ARM_LOWPWR, { 0x1, 0x0, 0x0 } },
- { S5P_DIS_IRQ_ISP_ARM_LOCAL_LOWPWR, { 0x0, 0x0, 0x0 } },
- { S5P_DIS_IRQ_ISP_ARM_CENTRAL_LOWPWR, { 0x0, 0x0, 0x0 } },
- { S5P_ARM_COMMON_LOWPWR, { 0x0, 0x0, 0x2 } },
- { S5P_L2_0_LOWPWR, { 0x0, 0x0, 0x3 } },
+static struct exynos_pmu_conf exynos4212_pmu_config[] = {
+ { EXYNOS4_ARM_CORE0_LOWPWR, { 0x0, 0x0, 0x2 } },
+ { EXYNOS4_DIS_IRQ_CORE0, { 0x0, 0x0, 0x0 } },
+ { EXYNOS4_DIS_IRQ_CENTRAL0, { 0x0, 0x0, 0x0 } },
+ { EXYNOS4_ARM_CORE1_LOWPWR, { 0x0, 0x0, 0x2 } },
+ { EXYNOS4_DIS_IRQ_CORE1, { 0x0, 0x0, 0x0 } },
+ { EXYNOS4_DIS_IRQ_CENTRAL1, { 0x0, 0x0, 0x0 } },
+ { EXYNOS4X12_ISP_ARM_LOWPWR, { 0x1, 0x0, 0x0 } },
+ { EXYNOS4X12_DIS_IRQ_ISP_ARM_LOCAL_LOWPWR, { 0x0, 0x0, 0x0 } },
+ { EXYNOS4X12_DIS_IRQ_ISP_ARM_CENTRAL_LOWPWR, { 0x0, 0x0, 0x0 } },
+ { EXYNOS4_ARM_COMMON_LOWPWR, { 0x0, 0x0, 0x2 } },
+ { EXYNOS4_L2_0_LOWPWR, { 0x0, 0x0, 0x3 } },
/* XXX_OPTION register should be set other field */
- { S5P_ARM_L2_0_OPTION, { 0x10, 0x10, 0x0 } },
- { S5P_L2_1_LOWPWR, { 0x0, 0x0, 0x3 } },
- { S5P_ARM_L2_1_OPTION, { 0x10, 0x10, 0x0 } },
- { S5P_CMU_ACLKSTOP_LOWPWR, { 0x1, 0x0, 0x0 } },
- { S5P_CMU_SCLKSTOP_LOWPWR, { 0x1, 0x0, 0x0 } },
- { S5P_CMU_RESET_LOWPWR, { 0x1, 0x1, 0x0 } },
- { S5P_DRAM_FREQ_DOWN_LOWPWR, { 0x1, 0x1, 0x1 } },
- { S5P_DDRPHY_DLLOFF_LOWPWR, { 0x1, 0x1, 0x1 } },
- { S5P_LPDDR_PHY_DLL_LOCK_LOWPWR, { 0x1, 0x1, 0x1 } },
- { S5P_CMU_ACLKSTOP_COREBLK_LOWPWR, { 0x1, 0x0, 0x0 } },
- { S5P_CMU_SCLKSTOP_COREBLK_LOWPWR, { 0x1, 0x0, 0x0 } },
- { S5P_CMU_RESET_COREBLK_LOWPWR, { 0x1, 0x1, 0x0 } },
- { S5P_APLL_SYSCLK_LOWPWR, { 0x1, 0x0, 0x0 } },
- { S5P_MPLL_SYSCLK_LOWPWR, { 0x1, 0x0, 0x0 } },
- { S5P_VPLL_SYSCLK_LOWPWR, { 0x1, 0x0, 0x0 } },
- { S5P_EPLL_SYSCLK_LOWPWR, { 0x1, 0x1, 0x0 } },
- { S5P_MPLLUSER_SYSCLK_LOWPWR, { 0x1, 0x0, 0x0 } },
- { S5P_CMU_CLKSTOP_GPS_ALIVE_LOWPWR, { 0x1, 0x0, 0x0 } },
- { S5P_CMU_RESET_GPSALIVE_LOWPWR, { 0x1, 0x0, 0x0 } },
- { S5P_CMU_CLKSTOP_CAM_LOWPWR, { 0x1, 0x0, 0x0 } },
- { S5P_CMU_CLKSTOP_TV_LOWPWR, { 0x1, 0x0, 0x0 } },
- { S5P_CMU_CLKSTOP_MFC_LOWPWR, { 0x1, 0x0, 0x0 } },
- { S5P_CMU_CLKSTOP_G3D_LOWPWR, { 0x1, 0x0, 0x0 } },
- { S5P_CMU_CLKSTOP_LCD0_LOWPWR, { 0x1, 0x0, 0x0 } },
- { S5P_CMU_CLKSTOP_ISP_LOWPWR, { 0x1, 0x0, 0x0 } },
- { S5P_CMU_CLKSTOP_MAUDIO_LOWPWR, { 0x1, 0x0, 0x0 } },
- { S5P_CMU_CLKSTOP_GPS_LOWPWR, { 0x1, 0x0, 0x0 } },
- { S5P_CMU_RESET_CAM_LOWPWR, { 0x1, 0x0, 0x0 } },
- { S5P_CMU_RESET_TV_LOWPWR, { 0x1, 0x0, 0x0 } },
- { S5P_CMU_RESET_MFC_LOWPWR, { 0x1, 0x0, 0x0 } },
- { S5P_CMU_RESET_G3D_LOWPWR, { 0x1, 0x0, 0x0 } },
- { S5P_CMU_RESET_LCD0_LOWPWR, { 0x1, 0x0, 0x0 } },
- { S5P_CMU_RESET_ISP_LOWPWR, { 0x1, 0x0, 0x0 } },
- { S5P_CMU_RESET_MAUDIO_LOWPWR, { 0x1, 0x1, 0x0 } },
- { S5P_CMU_RESET_GPS_LOWPWR, { 0x1, 0x0, 0x0 } },
- { S5P_TOP_BUS_LOWPWR, { 0x3, 0x0, 0x0 } },
- { S5P_TOP_RETENTION_LOWPWR, { 0x1, 0x0, 0x1 } },
- { S5P_TOP_PWR_LOWPWR, { 0x3, 0x0, 0x3 } },
- { S5P_TOP_BUS_COREBLK_LOWPWR, { 0x3, 0x0, 0x0 } },
- { S5P_TOP_RETENTION_COREBLK_LOWPWR, { 0x1, 0x0, 0x1 } },
- { S5P_TOP_PWR_COREBLK_LOWPWR, { 0x3, 0x0, 0x3 } },
- { S5P_LOGIC_RESET_LOWPWR, { 0x1, 0x1, 0x0 } },
- { S5P_OSCCLK_GATE_LOWPWR, { 0x1, 0x0, 0x1 } },
- { S5P_LOGIC_RESET_COREBLK_LOWPWR, { 0x1, 0x1, 0x0 } },
- { S5P_OSCCLK_GATE_COREBLK_LOWPWR, { 0x1, 0x0, 0x1 } },
- { S5P_ONENAND_MEM_LOWPWR, { 0x3, 0x0, 0x0 } },
- { S5P_ONENAND_MEM_OPTION, { 0x10, 0x10, 0x0 } },
- { S5P_HSI_MEM_LOWPWR, { 0x3, 0x0, 0x0 } },
- { S5P_HSI_MEM_OPTION, { 0x10, 0x10, 0x0 } },
- { S5P_G2D_ACP_MEM_LOWPWR, { 0x3, 0x0, 0x0 } },
- { S5P_G2D_ACP_MEM_OPTION, { 0x10, 0x10, 0x0 } },
- { S5P_USBOTG_MEM_LOWPWR, { 0x3, 0x0, 0x0 } },
- { S5P_USBOTG_MEM_OPTION, { 0x10, 0x10, 0x0 } },
- { S5P_HSMMC_MEM_LOWPWR, { 0x3, 0x0, 0x0 } },
- { S5P_HSMMC_MEM_OPTION, { 0x10, 0x10, 0x0 } },
- { S5P_CSSYS_MEM_LOWPWR, { 0x3, 0x0, 0x0 } },
- { S5P_CSSYS_MEM_OPTION, { 0x10, 0x10, 0x0 } },
- { S5P_SECSS_MEM_LOWPWR, { 0x3, 0x0, 0x0 } },
- { S5P_SECSS_MEM_OPTION, { 0x10, 0x10, 0x0 } },
- { S5P_ROTATOR_MEM_LOWPWR, { 0x3, 0x0, 0x0 } },
- { S5P_ROTATOR_MEM_OPTION, { 0x10, 0x10, 0x0 } },
- { S5P_PAD_RETENTION_DRAM_LOWPWR, { 0x1, 0x0, 0x0 } },
- { S5P_PAD_RETENTION_MAUDIO_LOWPWR, { 0x1, 0x1, 0x0 } },
- { S5P_PAD_RETENTION_GPIO_LOWPWR, { 0x1, 0x0, 0x0 } },
- { S5P_PAD_RETENTION_UART_LOWPWR, { 0x1, 0x0, 0x0 } },
- { S5P_PAD_RETENTION_MMCA_LOWPWR, { 0x1, 0x0, 0x0 } },
- { S5P_PAD_RETENTION_MMCB_LOWPWR, { 0x1, 0x0, 0x0 } },
- { S5P_PAD_RETENTION_EBIA_LOWPWR, { 0x1, 0x0, 0x0 } },
- { S5P_PAD_RETENTION_EBIB_LOWPWR, { 0x1, 0x0, 0x0 } },
- { S5P_PAD_RETENTION_GPIO_COREBLK_LOWPWR,{ 0x1, 0x0, 0x0 } },
- { S5P_PAD_RETENTION_ISOLATION_LOWPWR, { 0x1, 0x0, 0x0 } },
- { S5P_PAD_ISOLATION_COREBLK_LOWPWR, { 0x1, 0x0, 0x0 } },
- { S5P_PAD_RETENTION_ALV_SEL_LOWPWR, { 0x1, 0x0, 0x0 } },
- { S5P_XUSBXTI_LOWPWR, { 0x1, 0x1, 0x0 } },
- { S5P_XXTI_LOWPWR, { 0x1, 0x1, 0x0 } },
- { S5P_EXT_REGULATOR_LOWPWR, { 0x1, 0x1, 0x0 } },
- { S5P_GPIO_MODE_LOWPWR, { 0x1, 0x0, 0x0 } },
- { S5P_GPIO_MODE_COREBLK_LOWPWR, { 0x1, 0x0, 0x0 } },
- { S5P_GPIO_MODE_MAUDIO_LOWPWR, { 0x1, 0x1, 0x0 } },
- { S5P_TOP_ASB_RESET_LOWPWR, { 0x1, 0x1, 0x1 } },
- { S5P_TOP_ASB_ISOLATION_LOWPWR, { 0x1, 0x0, 0x1 } },
- { S5P_CAM_LOWPWR, { 0x7, 0x0, 0x0 } },
- { S5P_TV_LOWPWR, { 0x7, 0x0, 0x0 } },
- { S5P_MFC_LOWPWR, { 0x7, 0x0, 0x0 } },
- { S5P_G3D_LOWPWR, { 0x7, 0x0, 0x0 } },
- { S5P_LCD0_LOWPWR, { 0x7, 0x0, 0x0 } },
- { S5P_ISP_LOWPWR, { 0x7, 0x0, 0x0 } },
- { S5P_MAUDIO_LOWPWR, { 0x7, 0x7, 0x0 } },
- { S5P_GPS_LOWPWR, { 0x7, 0x0, 0x0 } },
- { S5P_GPS_ALIVE_LOWPWR, { 0x7, 0x0, 0x0 } },
- { S5P_CMU_SYSCLK_ISP_LOWPWR, { 0x1, 0x0, 0x0 } },
- { S5P_CMU_SYSCLK_GPS_LOWPWR, { 0x1, 0x0, 0x0 } },
+ { EXYNOS4X12_ARM_L2_0_OPTION, { 0x10, 0x10, 0x0 } },
+ { EXYNOS4_L2_1_LOWPWR, { 0x0, 0x0, 0x3 } },
+ { EXYNOS4X12_ARM_L2_1_OPTION, { 0x10, 0x10, 0x0 } },
+ { EXYNOS4_CMU_ACLKSTOP_LOWPWR, { 0x1, 0x0, 0x0 } },
+ { EXYNOS4_CMU_SCLKSTOP_LOWPWR, { 0x1, 0x0, 0x0 } },
+ { EXYNOS4_CMU_RESET_LOWPWR, { 0x1, 0x1, 0x0 } },
+ { EXYNOS4X12_DRAM_FREQ_DOWN_LOWPWR, { 0x1, 0x1, 0x1 } },
+ { EXYNOS4X12_DDRPHY_DLLOFF_LOWPWR, { 0x1, 0x1, 0x1 } },
+ { EXYNOS4X12_LPDDR_PHY_DLL_LOCK_LOWPWR, { 0x1, 0x1, 0x1 } },
+ { EXYNOS4X12_CMU_ACLKSTOP_COREBLK_LOWPWR, { 0x1, 0x0, 0x0 } },
+ { EXYNOS4X12_CMU_SCLKSTOP_COREBLK_LOWPWR, { 0x1, 0x0, 0x0 } },
+ { EXYNOS4X12_CMU_RESET_COREBLK_LOWPWR, { 0x1, 0x1, 0x0 } },
+ { EXYNOS4_APLL_SYSCLK_LOWPWR, { 0x1, 0x0, 0x0 } },
+ { EXYNOS4_MPLL_SYSCLK_LOWPWR, { 0x1, 0x0, 0x0 } },
+ { EXYNOS4_VPLL_SYSCLK_LOWPWR, { 0x1, 0x0, 0x0 } },
+ { EXYNOS4_EPLL_SYSCLK_LOWPWR, { 0x1, 0x1, 0x0 } },
+ { EXYNOS4X12_MPLLUSER_SYSCLK_LOWPWR, { 0x1, 0x0, 0x0 } },
+ { EXYNOS4_CMU_CLKSTOP_GPS_ALIVE_LOWPWR, { 0x1, 0x0, 0x0 } },
+ { EXYNOS4_CMU_RESET_GPSALIVE_LOWPWR, { 0x1, 0x0, 0x0 } },
+ { EXYNOS4_CMU_CLKSTOP_CAM_LOWPWR, { 0x1, 0x0, 0x0 } },
+ { EXYNOS4_CMU_CLKSTOP_TV_LOWPWR, { 0x1, 0x0, 0x0 } },
+ { EXYNOS4_CMU_CLKSTOP_MFC_LOWPWR, { 0x1, 0x0, 0x0 } },
+ { EXYNOS4_CMU_CLKSTOP_G3D_LOWPWR, { 0x1, 0x0, 0x0 } },
+ { EXYNOS4_CMU_CLKSTOP_LCD0_LOWPWR, { 0x1, 0x0, 0x0 } },
+ { EXYNOS4X12_CMU_CLKSTOP_ISP_LOWPWR, { 0x1, 0x0, 0x0 } },
+ { EXYNOS4_CMU_CLKSTOP_MAUDIO_LOWPWR, { 0x1, 0x0, 0x0 } },
+ { EXYNOS4_CMU_CLKSTOP_GPS_LOWPWR, { 0x1, 0x0, 0x0 } },
+ { EXYNOS4_CMU_RESET_CAM_LOWPWR, { 0x1, 0x0, 0x0 } },
+ { EXYNOS4_CMU_RESET_TV_LOWPWR, { 0x1, 0x0, 0x0 } },
+ { EXYNOS4_CMU_RESET_MFC_LOWPWR, { 0x1, 0x0, 0x0 } },
+ { EXYNOS4_CMU_RESET_G3D_LOWPWR, { 0x1, 0x0, 0x0 } },
+ { EXYNOS4_CMU_RESET_LCD0_LOWPWR, { 0x1, 0x0, 0x0 } },
+ { EXYNOS4X12_CMU_RESET_ISP_LOWPWR, { 0x1, 0x0, 0x0 } },
+ { EXYNOS4_CMU_RESET_MAUDIO_LOWPWR, { 0x1, 0x1, 0x0 } },
+ { EXYNOS4_CMU_RESET_GPS_LOWPWR, { 0x1, 0x0, 0x0 } },
+ { EXYNOS4_TOP_BUS_LOWPWR, { 0x3, 0x0, 0x0 } },
+ { EXYNOS4_TOP_RETENTION_LOWPWR, { 0x1, 0x0, 0x1 } },
+ { EXYNOS4_TOP_PWR_LOWPWR, { 0x3, 0x0, 0x3 } },
+ { EXYNOS4X12_TOP_BUS_COREBLK_LOWPWR, { 0x3, 0x0, 0x0 } },
+ { EXYNOS4X12_TOP_RETENTION_COREBLK_LOWPWR, { 0x1, 0x0, 0x1 } },
+ { EXYNOS4X12_TOP_PWR_COREBLK_LOWPWR, { 0x3, 0x0, 0x3 } },
+ { EXYNOS4_LOGIC_RESET_LOWPWR, { 0x1, 0x1, 0x0 } },
+ { EXYNOS4X12_OSCCLK_GATE_LOWPWR, { 0x1, 0x0, 0x1 } },
+ { EXYNOS4X12_LOGIC_RESET_COREBLK_LOWPWR, { 0x1, 0x1, 0x0 } },
+ { EXYNOS4X12_OSCCLK_GATE_COREBLK_LOWPWR, { 0x1, 0x0, 0x1 } },
+ { EXYNOS4_ONENAND_MEM_LOWPWR, { 0x3, 0x0, 0x0 } },
+ { EXYNOS4X12_ONENAND_MEM_OPTION, { 0x10, 0x10, 0x0 } },
+ { EXYNOS4X12_HSI_MEM_LOWPWR, { 0x3, 0x0, 0x0 } },
+ { EXYNOS4X12_HSI_MEM_OPTION, { 0x10, 0x10, 0x0 } },
+ { EXYNOS4_G2D_ACP_MEM_LOWPWR, { 0x3, 0x0, 0x0 } },
+ { EXYNOS4X12_G2D_ACP_MEM_OPTION, { 0x10, 0x10, 0x0 } },
+ { EXYNOS4_USBOTG_MEM_LOWPWR, { 0x3, 0x0, 0x0 } },
+ { EXYNOS4X12_USBOTG_MEM_OPTION, { 0x10, 0x10, 0x0 } },
+ { EXYNOS4_HSMMC_MEM_LOWPWR, { 0x3, 0x0, 0x0 } },
+ { EXYNOS4X12_HSMMC_MEM_OPTION, { 0x10, 0x10, 0x0 } },
+ { EXYNOS4_CSSYS_MEM_LOWPWR, { 0x3, 0x0, 0x0 } },
+ { EXYNOS4X12_CSSYS_MEM_OPTION, { 0x10, 0x10, 0x0 } },
+ { EXYNOS4_SECSS_MEM_LOWPWR, { 0x3, 0x0, 0x0 } },
+ { EXYNOS4X12_SECSS_MEM_OPTION, { 0x10, 0x10, 0x0 } },
+ { EXYNOS4X12_ROTATOR_MEM_LOWPWR, { 0x3, 0x0, 0x0 } },
+ { EXYNOS4X12_ROTATOR_MEM_OPTION, { 0x10, 0x10, 0x0 } },
+ { EXYNOS4_PAD_RETENTION_DRAM_LOWPWR, { 0x1, 0x0, 0x0 } },
+ { EXYNOS4_PAD_RETENTION_MAUDIO_LOWPWR, { 0x1, 0x1, 0x0 } },
+ { EXYNOS4_PAD_RETENTION_GPIO_LOWPWR, { 0x1, 0x0, 0x0 } },
+ { EXYNOS4_PAD_RETENTION_UART_LOWPWR, { 0x1, 0x0, 0x0 } },
+ { EXYNOS4_PAD_RETENTION_MMCA_LOWPWR, { 0x1, 0x0, 0x0 } },
+ { EXYNOS4_PAD_RETENTION_MMCB_LOWPWR, { 0x1, 0x0, 0x0 } },
+ { EXYNOS4_PAD_RETENTION_EBIA_LOWPWR, { 0x1, 0x0, 0x0 } },
+ { EXYNOS4_PAD_RETENTION_EBIB_LOWPWR, { 0x1, 0x0, 0x0 } },
+ { EXYNOS4X12_PAD_RETENTION_GPIO_COREBLK_LOWPWR, { 0x1, 0x0, 0x0 } },
+ { EXYNOS4_PAD_RETENTION_ISOLATION_LOWPWR, { 0x1, 0x0, 0x0 } },
+ { EXYNOS4X12_PAD_ISOLATION_COREBLK_LOWPWR, { 0x1, 0x0, 0x0 } },
+ { EXYNOS4_PAD_RETENTION_ALV_SEL_LOWPWR, { 0x1, 0x0, 0x0 } },
+ { EXYNOS4_XUSBXTI_LOWPWR, { 0x1, 0x1, 0x0 } },
+ { EXYNOS4_XXTI_LOWPWR, { 0x1, 0x1, 0x0 } },
+ { EXYNOS4_EXT_REGULATOR_LOWPWR, { 0x1, 0x1, 0x0 } },
+ { EXYNOS4_GPIO_MODE_LOWPWR, { 0x1, 0x0, 0x0 } },
+ { EXYNOS4X12_GPIO_MODE_COREBLK_LOWPWR, { 0x1, 0x0, 0x0 } },
+ { EXYNOS4_GPIO_MODE_MAUDIO_LOWPWR, { 0x1, 0x1, 0x0 } },
+ { EXYNOS4X12_TOP_ASB_RESET_LOWPWR, { 0x1, 0x1, 0x1 } },
+ { EXYNOS4X12_TOP_ASB_ISOLATION_LOWPWR, { 0x1, 0x0, 0x1 } },
+ { EXYNOS4_CAM_LOWPWR, { 0x7, 0x0, 0x0 } },
+ { EXYNOS4_TV_LOWPWR, { 0x7, 0x0, 0x0 } },
+ { EXYNOS4_MFC_LOWPWR, { 0x7, 0x0, 0x0 } },
+ { EXYNOS4_G3D_LOWPWR, { 0x7, 0x0, 0x0 } },
+ { EXYNOS4_LCD0_LOWPWR, { 0x7, 0x0, 0x0 } },
+ { EXYNOS4X12_ISP_LOWPWR, { 0x7, 0x0, 0x0 } },
+ { EXYNOS4_MAUDIO_LOWPWR, { 0x7, 0x7, 0x0 } },
+ { EXYNOS4_GPS_LOWPWR, { 0x7, 0x0, 0x0 } },
+ { EXYNOS4_GPS_ALIVE_LOWPWR, { 0x7, 0x0, 0x0 } },
+ { EXYNOS4X12_CMU_SYSCLK_ISP_LOWPWR, { 0x1, 0x0, 0x0 } },
+ { EXYNOS4X12_CMU_SYSCLK_GPS_LOWPWR, { 0x1, 0x0, 0x0 } },
{ PMU_TABLE_END,},
};
-void exynos4_sys_powerdown_conf(enum sys_powerdown mode)
+static struct exynos_pmu_conf exynos5250_pmu_config[] = {
+ /* { .reg = address, .val = { AFTR, LPA, SLEEP } */
+ { EXYNOS5_ARM_CORE0_SYS_PWR_REG, { 0x0, 0x0, 0x2} },
+ { EXYNOS5_DIS_IRQ_ARM_CORE0_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5_DIS_IRQ_ARM_CORE0_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5_ARM_CORE1_SYS_PWR_REG, { 0x0, 0x0, 0x2} },
+ { EXYNOS5_DIS_IRQ_ARM_CORE1_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5_DIS_IRQ_ARM_CORE1_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5_FSYS_ARM_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5_DIS_IRQ_FSYS_ARM_CENTRAL_SYS_PWR_REG, { 0x1, 0x1, 0x1} },
+ { EXYNOS5_ISP_ARM_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5_DIS_IRQ_ISP_ARM_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5_DIS_IRQ_ISP_ARM_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5_ARM_COMMON_SYS_PWR_REG, { 0x0, 0x0, 0x2} },
+ { EXYNOS5_ARM_L2_SYS_PWR_REG, { 0x0, 0x0, 0x3} },
+ { EXYNOS5_CMU_ACLKSTOP_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5_CMU_SCLKSTOP_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5_CMU_RESET_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
+ { EXYNOS5_CMU_ACLKSTOP_SYSMEM_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5_CMU_SCLKSTOP_SYSMEM_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5_CMU_RESET_SYSMEM_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
+ { EXYNOS5_DRAM_FREQ_DOWN_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
+ { EXYNOS5_DDRPHY_DLLOFF_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
+ { EXYNOS5_DDRPHY_DLLLOCK_SYS_PWR_REG, { 0x1, 0x1, 0x1} },
+ { EXYNOS5_APLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5_MPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5_VPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5_EPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
+ { EXYNOS5_BPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5_CPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5_GPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5_MPLLUSER_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5_BPLLUSER_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5_TOP_BUS_SYS_PWR_REG, { 0x3, 0x0, 0x0} },
+ { EXYNOS5_TOP_RETENTION_SYS_PWR_REG, { 0x1, 0x0, 0x1} },
+ { EXYNOS5_TOP_PWR_SYS_PWR_REG, { 0x3, 0x0, 0x3} },
+ { EXYNOS5_TOP_BUS_SYSMEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} },
+ { EXYNOS5_TOP_RETENTION_SYSMEM_SYS_PWR_REG, { 0x1, 0x0, 0x1} },
+ { EXYNOS5_TOP_PWR_SYSMEM_SYS_PWR_REG, { 0x3, 0x0, 0x3} },
+ { EXYNOS5_LOGIC_RESET_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
+ { EXYNOS5_OSCCLK_GATE_SYS_PWR_REG, { 0x1, 0x0, 0x1} },
+ { EXYNOS5_LOGIC_RESET_SYSMEM_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
+ { EXYNOS5_OSCCLK_GATE_SYSMEM_SYS_PWR_REG, { 0x1, 0x0, 0x1} },
+ { EXYNOS5_USBOTG_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} },
+ { EXYNOS5_G2D_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} },
+ { EXYNOS5_USBDRD_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} },
+ { EXYNOS5_SDMMC_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} },
+ { EXYNOS5_CSSYS_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} },
+ { EXYNOS5_SECSS_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} },
+ { EXYNOS5_ROTATOR_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} },
+ { EXYNOS5_INTRAM_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} },
+ { EXYNOS5_INTROM_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} },
+ { EXYNOS5_JPEG_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} },
+ { EXYNOS5_HSI_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} },
+ { EXYNOS5_MCUIOP_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} },
+ { EXYNOS5_SATA_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} },
+ { EXYNOS5_PAD_RETENTION_DRAM_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5_PAD_RETENTION_MAU_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
+ { EXYNOS5_PAD_RETENTION_GPIO_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5_PAD_RETENTION_UART_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5_PAD_RETENTION_MMCA_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5_PAD_RETENTION_MMCB_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5_PAD_RETENTION_EBIA_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5_PAD_RETENTION_EBIB_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5_PAD_RETENTION_SPI_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5_PAD_RETENTION_GPIO_SYSMEM_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5_PAD_ISOLATION_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5_PAD_ISOLATION_SYSMEM_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5_PAD_ALV_SEL_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5_XUSBXTI_SYS_PWR_REG, { 0x1, 0x1, 0x1} },
+ { EXYNOS5_XXTI_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
+ { EXYNOS5_EXT_REGULATOR_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
+ { EXYNOS5_GPIO_MODE_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5_GPIO_MODE_SYSMEM_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5_GPIO_MODE_MAU_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
+ { EXYNOS5_TOP_ASB_RESET_SYS_PWR_REG, { 0x1, 0x1, 0x1} },
+ { EXYNOS5_TOP_ASB_ISOLATION_SYS_PWR_REG, { 0x1, 0x0, 0x1} },
+ { EXYNOS5_GSCL_SYS_PWR_REG, { 0x7, 0x0, 0x0} },
+ { EXYNOS5_ISP_SYS_PWR_REG, { 0x7, 0x0, 0x0} },
+ { EXYNOS5_MFC_SYS_PWR_REG, { 0x7, 0x0, 0x0} },
+ { EXYNOS5_G3D_SYS_PWR_REG, { 0x7, 0x0, 0x0} },
+ { EXYNOS5_DISP1_SYS_PWR_REG, { 0x7, 0x0, 0x0} },
+ { EXYNOS5_MAU_SYS_PWR_REG, { 0x7, 0x7, 0x0} },
+ { EXYNOS5_CMU_CLKSTOP_GSCL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5_CMU_CLKSTOP_ISP_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5_CMU_CLKSTOP_MFC_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5_CMU_CLKSTOP_G3D_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5_CMU_CLKSTOP_DISP1_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5_CMU_CLKSTOP_MAU_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5_CMU_SYSCLK_GSCL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5_CMU_SYSCLK_ISP_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5_CMU_SYSCLK_MFC_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5_CMU_SYSCLK_G3D_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5_CMU_SYSCLK_DISP1_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5_CMU_SYSCLK_MAU_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5_CMU_RESET_GSCL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5_CMU_RESET_ISP_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5_CMU_RESET_MFC_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5_CMU_RESET_G3D_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5_CMU_RESET_DISP1_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5_CMU_RESET_MAU_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { PMU_TABLE_END,},
+};
+
+void __iomem *exynos5_list_feed[] = {
+ EXYNOS5_ARM_CORE0_OPTION,
+ EXYNOS5_ARM_CORE1_OPTION,
+ EXYNOS5_ARM_COMMON_OPTION,
+ EXYNOS5_GSCL_OPTION,
+ EXYNOS5_ISP_OPTION,
+ EXYNOS5_MFC_OPTION,
+ EXYNOS5_G3D_OPTION,
+ EXYNOS5_DISP1_OPTION,
+ EXYNOS5_MAU_OPTION,
+ EXYNOS5_TOP_PWR_OPTION,
+ EXYNOS5_TOP_PWR_SYSMEM_OPTION,
+};
+
+void __iomem *exynos5_list_diable_wfi_wfe[] = {
+ EXYNOS5_FSYS_ARM_OPTION,
+ EXYNOS5_ISP_ARM_OPTION,
+};
+
+void __iomem *exynos5_list_disable_pmu_reg[] = {
+ EXYNOS5_CMU_CLKSTOP_GSCL_SYS_PWR_REG,
+ EXYNOS5_CMU_CLKSTOP_ISP_SYS_PWR_REG,
+ EXYNOS5_CMU_CLKSTOP_MFC_SYS_PWR_REG,
+ EXYNOS5_CMU_CLKSTOP_G3D_SYS_PWR_REG,
+ EXYNOS5_CMU_CLKSTOP_DISP1_SYS_PWR_REG,
+ EXYNOS5_CMU_CLKSTOP_MAU_SYS_PWR_REG,
+ EXYNOS5_CMU_SYSCLK_GSCL_SYS_PWR_REG,
+ EXYNOS5_CMU_SYSCLK_ISP_SYS_PWR_REG,
+ EXYNOS5_CMU_SYSCLK_MFC_SYS_PWR_REG,
+ EXYNOS5_CMU_SYSCLK_G3D_SYS_PWR_REG,
+ EXYNOS5_CMU_SYSCLK_DISP1_SYS_PWR_REG,
+ EXYNOS5_CMU_SYSCLK_MAU_SYS_PWR_REG,
+ EXYNOS5_CMU_RESET_GSCL_SYS_PWR_REG,
+ EXYNOS5_CMU_RESET_ISP_SYS_PWR_REG,
+ EXYNOS5_CMU_RESET_MFC_SYS_PWR_REG,
+ EXYNOS5_CMU_RESET_G3D_SYS_PWR_REG,
+ EXYNOS5_CMU_RESET_DISP1_SYS_PWR_REG,
+ EXYNOS5_CMU_RESET_MAU_SYS_PWR_REG,
+ EXYNOS5_ISP_ARM_CONFIGURATION,
+};
+
+static void exynos5_init_pmu(void)
+{
+ unsigned int i;
+ unsigned int tmp;
+
+ /* Enable only SC_FEEDBACK */
+ for (i = 0 ; i < ARRAY_SIZE(exynos5_list_feed) ; i++) {
+ tmp = __raw_readl(exynos5_list_feed[i]);
+ tmp &= ~(EXYNOS5_USE_SC_COUNTER);
+ tmp |= EXYNOS5_USE_SC_FEEDBACK;
+ __raw_writel(tmp, exynos5_list_feed[i]);
+ }
+
+ /*
+ * SKIP_DEACTIVATE_ACEACP_IN_PWDN_BITFIELD Enable
+ */
+ tmp = __raw_readl(EXYNOS5_ARM_COMMON_OPTION);
+ tmp |= EXYNOS5_SKIP_DEACTIVATE_ACEACP_IN_PWDN;
+ __raw_writel(tmp, EXYNOS5_ARM_COMMON_OPTION);
+
+ /*
+ * Disable WFI/WFE on XXX_OPTION
+ */
+ for (i = 0 ; i < ARRAY_SIZE(exynos5_list_diable_wfi_wfe) ; i++) {
+ tmp = __raw_readl(exynos5_list_diable_wfi_wfe[i]);
+ tmp &= ~(EXYNOS5_OPTION_USE_STANDBYWFE |
+ EXYNOS5_OPTION_USE_STANDBYWFI);
+ __raw_writel(tmp, exynos5_list_diable_wfi_wfe[i]);
+ }
+}
+
+void exynos_sys_powerdown_conf(enum sys_powerdown mode)
{
unsigned int i;
- for (i = 0; (exynos4_pmu_config[i].reg != PMU_TABLE_END) ; i++)
- __raw_writel(exynos4_pmu_config[i].val[mode],
- exynos4_pmu_config[i].reg);
+ if (soc_is_exynos5250())
+ exynos5_init_pmu();
+
+ for (i = 0; (exynos_pmu_config[i].reg != PMU_TABLE_END) ; i++)
+ __raw_writel(exynos_pmu_config[i].val[mode],
+ exynos_pmu_config[i].reg);
}
-static int __init exynos4_pmu_init(void)
+void exynos_xxti_sys_powerdown(bool enable)
{
- exynos4_pmu_config = exynos4210_pmu_config;
+ unsigned int value;
+ void __iomem *base;
+
+ base = soc_is_exynos5250() ? EXYNOS5_XXTI_SYS_PWR_REG :
+ EXYNOS4_XXTI_LOWPWR;
+
+ value = __raw_readl(base);
+
+ if (enable)
+ value |= EXYNOS_SYS_PWR_CFG;
+ else
+ value &= ~EXYNOS_SYS_PWR_CFG;
+
+ __raw_writel(value, base);
+}
+
+void exynos_reset_assert_ctrl(bool on)
+{
+ unsigned int i;
+ unsigned int core_option;
+
+ for (i = 0; i < num_possible_cpus(); i++) {
+ core_option = __raw_readl(EXYNOS_ARM_CORE_OPTION(i));
+ core_option = on ? (core_option | EXYNOS_USE_DELAYED_RESET_ASSERTION) :
+ (core_option & ~EXYNOS_USE_DELAYED_RESET_ASSERTION);
+ __raw_writel(core_option, EXYNOS_ARM_CORE_OPTION(i));
+ }
+}
+
+static int __init exynos_pmu_init(void)
+{
+ unsigned int value;
+ unsigned int i;
if (soc_is_exynos4210()) {
- exynos4_pmu_config = exynos4210_pmu_config;
+ exynos_pmu_config = exynos4210_pmu_config;
pr_info("EXYNOS4210 PMU Initialize\n");
} else if (soc_is_exynos4212()) {
- exynos4_pmu_config = exynos4212_pmu_config;
+ exynos_pmu_config = exynos4212_pmu_config;
pr_info("EXYNOS4212 PMU Initialize\n");
+ } else if (soc_is_exynos5250()) {
+
+ /* Initialize for using delay reset assertion */
+ exynos_reset_assert_ctrl(true);
+
+ /*
+ * Set logic reset duration
+ */
+ value = __raw_readl(EXYNOS5_LOGIC_RESET_DURATION3);
+ value &= ~EXYNOS5_DUR_WAIT_RESET_MASK;
+ value |= EXYNOS5_DUR_WAIT_RESET_MIN;
+ __raw_writel(value, EXYNOS5_LOGIC_RESET_DURATION3);
+
+ /*
+ * When SYS_WDTRESET is set, watchdog timer reset request
+ * is ignored by power management unit.
+ */
+ value = __raw_readl(EXYNOS5_AUTOMATIC_WDT_RESET_DISABLE);
+ value &= ~EXYNOS5_SYS_WDTRESET;
+ __raw_writel(value, EXYNOS5_AUTOMATIC_WDT_RESET_DISABLE);
+
+ value = __raw_readl(EXYNOS5_MASK_WDT_RESET_REQUEST);
+ value &= ~EXYNOS5_SYS_WDTRESET;
+ __raw_writel(value, EXYNOS5_MASK_WDT_RESET_REQUEST);
+
+ /*
+ * Follow registers should be set with 0x0
+ */
+ for (i = 0; i < ARRAY_SIZE(exynos5_list_disable_pmu_reg); i++)
+ __raw_writel(0x0, exynos5_list_disable_pmu_reg[i]);
+
+ exynos_pmu_config = exynos5250_pmu_config;
+ pr_info("EXYNOS5250 PMU Initialize\n");
} else {
- pr_info("EXYNOS4: PMU not supported\n");
+ pr_info("EXYNOS: PMU not supported\n");
}
return 0;
}
-arch_initcall(exynos4_pmu_init);
+arch_initcall(exynos_pmu_init);
diff --git a/arch/arm/mach-exynos/reserve-mem.c b/arch/arm/mach-exynos/reserve-mem.c
new file mode 100644
index 0000000..cfb41dd
--- /dev/null
+++ b/arch/arm/mach-exynos/reserve-mem.c
@@ -0,0 +1,173 @@
+/* linux/arch/arm/mach-exynos/reserve-mem.c
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Reserve mem helper functions
+ *
+ * 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.
+ */
+
+#ifdef CONFIG_CMA_DEBUG
+#define DEBUG
+#endif
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/memblock.h>
+#include <linux/mm.h>
+#include <linux/cma.h>
+
+void __init exynos_cma_region_reserve(struct cma_region *regions_normal,
+ struct cma_region *regions_secure,
+ size_t align_secure, const char *map)
+{
+ struct cma_region *reg;
+ phys_addr_t paddr_last = PHYS_OFFSET + SZ_1G;
+
+ for (reg = regions_normal; reg->size != 0; reg++) {
+ phys_addr_t paddr;
+
+ if (!IS_ALIGNED(reg->size, PAGE_SIZE)) {
+ pr_debug("S5P/CMA: size of '%s' is NOT page-aligned\n",
+ reg->name);
+ reg->size = PAGE_ALIGN(reg->size);
+ }
+
+
+ if (reg->reserved) {
+ pr_err("S5P/CMA: '%s' alread reserved\n", reg->name);
+ continue;
+ }
+
+ if (reg->alignment) {
+ if ((reg->alignment & ~PAGE_MASK) ||
+ (reg->alignment & ~reg->alignment)) {
+ pr_err("S5P/CMA: Failed to reserve '%s': "
+ "incorrect alignment 0x%08x.\n",
+ reg->name, reg->alignment);
+ continue;
+ }
+ } else {
+ reg->alignment = PAGE_SIZE;
+ }
+
+ if (reg->start) {
+ if (!memblock_is_region_reserved(reg->start, reg->size)
+ && (memblock_reserve(reg->start, reg->size) == 0))
+ reg->reserved = 1;
+ else
+ pr_err("S5P/CMA: Failed to reserve '%s'\n",
+ reg->name);
+
+ if (reg->reserved)
+ pr_debug("S5P/CMA: "
+ "Reserved 0x%08x/0x%08x for '%s'\n",
+ reg->start, reg->size, reg->name);
+ continue;
+ }
+
+ paddr = memblock_find_in_range(0, paddr_last,
+ reg->size, reg->alignment);
+ if (paddr) {
+ if (memblock_reserve(paddr, reg->size)) {
+ pr_err("S5P/CMA: Failed to reserve '%s'\n",
+ reg->name);
+ continue;
+ }
+
+ reg->start = paddr;
+ reg->reserved = 1;
+ } else {
+ pr_err("S5P/CMA: No free space in memory for '%s'\n",
+ reg->name);
+ }
+
+ pr_debug("S5P/CMA: Reserved 0x%08x/0x%08x for '%s'\n",
+ reg->start, reg->size, reg->name);
+
+ if (cma_early_region_register(reg)) {
+ pr_err("S5P/CMA: Failed to register '%s'\n",
+ reg->name);
+ memblock_free(reg->start, reg->size);
+ } else {
+ paddr_last = min(paddr, paddr_last);
+ }
+ }
+
+ if (align_secure & ~align_secure) {
+ pr_err("S5P/CMA: "
+ "Wrong alignment requirement for secure region.\n");
+ } else if (regions_secure && regions_secure->size) {
+ size_t size_secure = 0;
+ size_t align_secure_end = align_secure;
+
+ for (reg = regions_secure; reg->size != 0; reg++)
+ size_secure += reg->size;
+
+ reg--;
+
+ /* Entire secure regions will be merged into 2
+ * consecutive regions. */
+ if (align_secure == 0) {
+ size_t size_region2;
+ size_t order_region2;
+ size_t aug_size;
+
+ align_secure = 1 <<
+ (get_order((size_secure + 1) / 2) + PAGE_SHIFT);
+ /* Calculation of a subregion size */
+ size_region2 = size_secure - align_secure;
+ order_region2 = get_order(size_region2) + PAGE_SHIFT;
+ if (order_region2 < 20)
+ order_region2 = 20; /* 1MB */
+ order_region2 -= 3; /* divide by 8 */
+ size_region2 = ALIGN(size_region2, 1 << order_region2);
+
+ aug_size = align_secure + size_region2 - size_secure;
+ if (aug_size > 0) {
+ reg->size += aug_size;
+ pr_debug("S5P/CMA: "
+ "Augmented size of '%s' by %#x B.\n",
+ reg->name, aug_size);
+ }
+ align_secure_end = 1 << order_region2;
+ }
+
+ size_secure = ALIGN(size_secure, align_secure_end);
+ pr_debug("S5P/CMA: Reserving 0x%08x (0x%08x) for secure region\n",
+ size_secure, align_secure);
+
+ paddr_last = memblock_alloc_base(size_secure, align_secure,
+ paddr_last);
+ if (paddr_last) {
+ do {
+ reg->start = paddr_last;
+ reg->reserved = 1;
+ paddr_last += reg->size;
+
+ pr_debug("S5P/CMA: "
+ "Reserved 0x%08x/0x%08x for '%s'\n",
+ reg->start, reg->size, reg->name);
+ if (cma_early_region_register(reg)) {
+ memblock_free(reg->start, reg->size);
+ pr_err("S5P/CMA: "
+ "Failed to register secure region "
+ "'%s'\n", reg->name);
+ } else {
+ size_secure -= reg->size;
+ }
+ } while (reg-- != regions_secure);
+
+ if (size_secure > 0)
+ memblock_free(paddr_last, size_secure);
+ } else {
+ pr_err("S5P/CMA: Failed to reserve secure regions\n");
+ }
+ }
+
+ if (map)
+ cma_set_defaults(NULL, map);
+}
diff --git a/arch/arm/mach-exynos/resetreason.c b/arch/arm/mach-exynos/resetreason.c
new file mode 100644
index 0000000..3129cf7
--- /dev/null
+++ b/arch/arm/mach-exynos/resetreason.c
@@ -0,0 +1,73 @@
+/*
+ * arch/arm/mach-exynos/resetreason.c
+ *
+ * Copyright (C) 2012 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/bug.h>
+#include <linux/io.h>
+#include <mach/regs-pmu.h>
+#include "resetreason.h"
+
+static char resetreason[1024];
+
+#define EXYNOS_RST_STAT_SWRESET (1<<29)
+#define EXYNOS_RST_STAT_WRSET (1<<28)
+#define EXYNOS_RST_STAT_ISP_ARM_WDTRESET (1<<26)
+#define EXYNOS_RST_STAT_FSYS_ARM_WDTRESET (1<<25)
+#define EXYNOS_RST_STAT_SYS_WDTRESET (1<<20)
+#define EXYNOS_RST_STAT_PINRESET (1<<16)
+#define EXYNOS_RST_STAT_EAGLE_WRESET1 (1<<1)
+#define EXYNOS_RST_STAT_EAGLE_WRESET0 (1<<0)
+
+static struct {
+ const char *str;
+ u32 mask;
+} resetreason_flags[] = {
+ { "software ", EXYNOS_RST_STAT_SWRESET },
+ { "warm ", EXYNOS_RST_STAT_WRSET },
+ { "ISP_ARM watchdog timer ", EXYNOS_RST_STAT_ISP_ARM_WDTRESET },
+ { "FSYS_ARM watchdog timer ", EXYNOS_RST_STAT_FSYS_ARM_WDTRESET },
+ { "system watchdog timer ", EXYNOS_RST_STAT_SYS_WDTRESET },
+ { "XnRESET pin ", EXYNOS_RST_STAT_PINRESET },
+ { "Eagle warm ", EXYNOS_RST_STAT_EAGLE_WRESET1 |
+ EXYNOS_RST_STAT_EAGLE_WRESET0 },
+};
+
+const char *exynos_get_resetreason(void)
+{
+ return resetreason;
+}
+
+static int __init resetreason_init(void)
+{
+ int i;
+ u32 reasons = __raw_readl(EXYNOS_RST_STAT);
+ char buf[128];
+
+ strlcpy(resetreason, "Last reset was ", sizeof(resetreason));
+
+ for (i = 0; i < ARRAY_SIZE(resetreason_flags); i++)
+ if (reasons & resetreason_flags[i].mask)
+ strlcat(resetreason, resetreason_flags[i].str,
+ sizeof(resetreason));
+
+ snprintf(buf, sizeof(buf), "reset (RST_STAT=0x%x)\n", reasons);
+ strlcat(resetreason, buf, sizeof(resetreason));
+ pr_info("%s", resetreason);
+ return 0;
+}
+
+postcore_initcall(resetreason_init);
diff --git a/arch/arm/mach-exynos/resetreason.h b/arch/arm/mach-exynos/resetreason.h
new file mode 100644
index 0000000..962ba91
--- /dev/null
+++ b/arch/arm/mach-exynos/resetreason.h
@@ -0,0 +1,22 @@
+/*
+ * arch/arm/mach-exynos/resetreason.h
+ *
+ * Copyright (C) 2012 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#ifndef _MACH_EXYNOS_RESETREASON_H_
+#define _MACH_EXYNOS_RESETREASON_H_
+
+const char *exynos_get_resetreason(void);
+
+#endif
diff --git a/arch/arm/mach-exynos/secmem.c b/arch/arm/mach-exynos/secmem.c
new file mode 100644
index 0000000..df6e255
--- /dev/null
+++ b/arch/arm/mach-exynos/secmem.c
@@ -0,0 +1,293 @@
+/*
+ * arch/arm/mach-exynos/secmem.c
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * 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.
+ */
+
+#include <linux/device.h>
+#include <linux/cma.h>
+#include <linux/uaccess.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/pm_runtime.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/memory.h>
+#include <asm/cacheflush.h>
+
+#include <plat/devs.h>
+
+#include <mach/secmem.h>
+#include <linux/export.h>
+
+#define SECMEM_DEV_NAME "s5p-smem"
+struct secmem_crypto_driver_ftn *crypto_driver;
+#if defined(CONFIG_ION)
+extern struct ion_device *ion_exynos;
+#endif
+
+static char *secmem_regions[] = {
+#if defined(CONFIG_SOC_EXYNOS5250)
+ "mfc_sh", /* 0 */
+ "msgbox_sh", /* 1 */
+ "fimd_video", /* 2 */
+ "mfc_output", /* 3 */
+ "mfc_input", /* 4 */
+ "mfc_fw", /* 5 */
+ "sectbl", /* 6 */
+#endif
+ NULL
+};
+
+static bool drm_onoff;
+static DEFINE_MUTEX(drm_lock);
+
+struct secmem_info {
+ struct device *dev;
+ bool drm_enabled;
+};
+
+static int secmem_open(struct inode *inode, struct file *file)
+{
+ struct miscdevice *miscdev = file->private_data;
+ struct device *dev = miscdev->this_device;
+ struct secmem_info *info;
+
+ info = kzalloc(sizeof(struct secmem_info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ info->dev = dev;
+ file->private_data = info;
+ return 0;
+}
+
+static void drm_enable_locked(struct secmem_info *info, bool enable)
+{
+ if (drm_onoff != enable) {
+ if (enable)
+ pm_runtime_forbid(info->dev->parent);
+ else
+ pm_runtime_allow(info->dev->parent);
+ drm_onoff = enable;
+ /*
+ * this will only allow this instance to turn drm_off either by
+ * calling the ioctl or by closing the fd
+ */
+ info->drm_enabled = enable;
+ } else {
+ pr_err("%s: DRM is already %s\n", __func__,
+ drm_onoff ? "on" : "off");
+ }
+}
+
+static int secmem_release(struct inode *inode, struct file *file)
+{
+ struct secmem_info *info = file->private_data;
+
+ /* disable drm if we were the one to turn it on */
+ mutex_lock(&drm_lock);
+ if (info->drm_enabled)
+ drm_enable_locked(info, false);
+ mutex_unlock(&drm_lock);
+
+ kfree(info);
+ return 0;
+}
+
+static long secmem_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ struct secmem_info *info = filp->private_data;
+
+ switch (cmd) {
+ case SECMEM_IOC_CHUNKINFO:
+ {
+ struct cma_info cinfo;
+ struct secchunk_info minfo;
+ char **mname;
+ int nbufs = 0;
+
+ for (mname = secmem_regions; *mname != NULL; mname++)
+ nbufs++;
+
+ if (nbufs == 0)
+ return -ENOMEM;
+
+ if (copy_from_user(&minfo, (void __user *)arg, sizeof(minfo)))
+ return -EFAULT;
+
+ if (minfo.index < 0)
+ return -EINVAL;
+
+ if (minfo.index >= nbufs) {
+ minfo.index = -1; /* No more memory region */
+ } else {
+
+ if (cma_info(&cinfo, info->dev,
+ secmem_regions[minfo.index]))
+ return -EINVAL;
+
+ minfo.base = cinfo.lower_bound;
+ minfo.size = cinfo.total_size;
+ }
+
+ if (copy_to_user((void __user *)arg, &minfo, sizeof(minfo)))
+ return -EFAULT;
+ break;
+ }
+#if defined(CONFIG_ION)
+ case SECMEM_IOC_GET_FD_PHYS_ADDR:
+ {
+ struct ion_client *client;
+ struct secfd_info fd_info;
+ struct ion_fd_data data;
+ size_t len;
+
+ if (copy_from_user(&fd_info, (int __user *)arg,
+ sizeof(fd_info)))
+ return -EFAULT;
+
+ client = ion_client_create(ion_exynos, "DRM");
+ if (IS_ERR(client))
+ printk(KERN_ERR "%s: Failed to get ion_client of DRM\n",
+ __func__);
+
+ data.fd = fd_info.fd;
+ data.handle = ion_import_dma_buf(client, data.fd);
+ printk(KERN_DEBUG "%s: fd from user space = %d\n",
+ __func__, fd_info.fd);
+ if (IS_ERR(data.handle))
+ printk(KERN_ERR "%s: Failed to get ion_handle of DRM\n",
+ __func__);
+
+ if (ion_phys(client, data.handle, &fd_info.phys, &len))
+ printk(KERN_ERR "%s: Failed to get phys. addr of DRM\n",
+ __func__);
+
+ printk(KERN_DEBUG "%s: physical addr from kernel space = 0x%08x\n",
+ __func__, (unsigned int)fd_info.phys);
+
+ ion_free(client, data.handle);
+ ion_client_destroy(client);
+
+ if (copy_to_user((void __user *)arg, &fd_info, sizeof(fd_info)))
+ return -EFAULT;
+ break;
+ }
+#endif
+ case SECMEM_IOC_GET_DRM_ONOFF:
+ smp_rmb();
+ if (copy_to_user((void __user *)arg, &drm_onoff, sizeof(int)))
+ return -EFAULT;
+ break;
+ case SECMEM_IOC_SET_DRM_ONOFF:
+ {
+ int val = 0;
+
+ if (copy_from_user(&val, (int __user *)arg, sizeof(int)))
+ return -EFAULT;
+
+ mutex_lock(&drm_lock);
+ if ((info->drm_enabled && !val) ||
+ (!info->drm_enabled && val)) {
+ /*
+ * 1. if we enabled drm, then disable it
+ * 2. if we don't already hdrm enabled,
+ * try to enable it.
+ */
+ drm_enable_locked(info, val);
+ }
+ mutex_unlock(&drm_lock);
+ break;
+ }
+ case SECMEM_IOC_GET_CRYPTO_LOCK:
+ {
+ int i;
+ int ret;
+
+ if (crypto_driver) {
+ for (i = 0; i < 100; i++) {
+ ret = crypto_driver->lock();
+ if (ret == 0)
+ break;
+ printk(KERN_ERR "%s : Retry to get sync lock.\n",
+ __func__);
+ }
+ return ret;
+ }
+ break;
+ }
+ case SECMEM_IOC_RELEASE_CRYPTO_LOCK:
+ {
+ if (crypto_driver)
+ return crypto_driver->release();
+ break;
+ }
+ default:
+ return -ENOTTY;
+ }
+
+ return 0;
+}
+
+void secmem_crypto_register(struct secmem_crypto_driver_ftn *ftn)
+{
+ crypto_driver = ftn;
+}
+EXPORT_SYMBOL(secmem_crypto_register);
+
+void secmem_crypto_deregister(void)
+{
+ crypto_driver = NULL;
+}
+EXPORT_SYMBOL(secmem_crypto_deregister);
+
+static const struct file_operations secmem_fops = {
+ .open = secmem_open,
+ .release = secmem_release,
+ .unlocked_ioctl = secmem_ioctl,
+};
+
+extern struct platform_device exynos5_device_gsc0;
+
+static struct miscdevice secmem = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = SECMEM_DEV_NAME,
+ .fops = &secmem_fops,
+ .parent = &exynos5_device_gsc0.dev,
+};
+
+static int __init secmem_init(void)
+{
+ int ret;
+
+ ret = misc_register(&secmem);
+ if (ret)
+ printk(KERN_ERR "%s: SECMEM can't register misc on minor=%d\n",
+ __func__, MISC_DYNAMIC_MINOR);
+ return ret;
+
+ crypto_driver = NULL;
+
+ pm_runtime_enable(secmem.this_device);
+
+ return 0;
+}
+
+static void __exit secmem_exit(void)
+{
+ __pm_runtime_disable(secmem.this_device, false);
+ misc_deregister(&secmem);
+}
+
+module_init(secmem_init);
+module_exit(secmem_exit);
diff --git a/arch/arm/mach-exynos/setup-adc.c b/arch/arm/mach-exynos/setup-adc.c
new file mode 100644
index 0000000..500bd5a
--- /dev/null
+++ b/arch/arm/mach-exynos/setup-adc.c
@@ -0,0 +1,32 @@
+/* linux/arch/arm/mach-exynos/setup-adc.c
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Base Samsung Exynos ADC configuration
+ *
+ * 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.
+*/
+
+#include <linux/io.h>
+#include <mach/regs-pmu.h>
+
+void s3c_adc_phy_init(void)
+{
+ u32 reg;
+
+ reg = __raw_readl(EXYNOS5_ADC_PHY_CONTROL);
+ reg |= EXYNOS5_ADC_PHY_ENABLE;
+ __raw_writel(reg, EXYNOS5_ADC_PHY_CONTROL);
+}
+
+void s3c_adc_phy_exit(void)
+{
+ u32 reg;
+
+ reg = __raw_readl(EXYNOS5_ADC_PHY_CONTROL);
+ reg &= ~EXYNOS5_ADC_PHY_ENABLE;
+ __raw_writel(reg, EXYNOS5_ADC_PHY_CONTROL);
+}
diff --git a/arch/arm/mach-exynos/setup-dp.c b/arch/arm/mach-exynos/setup-dp.c
new file mode 100644
index 0000000..3b89d6b
--- /dev/null
+++ b/arch/arm/mach-exynos/setup-dp.c
@@ -0,0 +1,32 @@
+/* linux/arch/arm/mach-exynos/setup-dp.c
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Base Samsung Exynos DP configuration
+ *
+ * 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.
+*/
+
+#include <linux/io.h>
+#include <mach/regs-clock.h>
+
+void s5p_dp_phy_init(void)
+{
+ u32 reg;
+
+ reg = __raw_readl(EXYNOS5250_DPTX_PHY_CONTROL);
+ reg |= EXYNOS5250_DPTX_PHY_ENABLE;
+ __raw_writel(reg, EXYNOS5250_DPTX_PHY_CONTROL);
+}
+
+void s5p_dp_phy_exit(void)
+{
+ u32 reg;
+
+ reg = __raw_readl(EXYNOS5250_DPTX_PHY_CONTROL);
+ reg &= ~EXYNOS5250_DPTX_PHY_ENABLE;
+ __raw_writel(reg, EXYNOS5250_DPTX_PHY_CONTROL);
+}
diff --git a/arch/arm/mach-exynos/setup-fimc-is.c b/arch/arm/mach-exynos/setup-fimc-is.c
new file mode 100644
index 0000000..8799c50
--- /dev/null
+++ b/arch/arm/mach-exynos/setup-fimc-is.c
@@ -0,0 +1,775 @@
+/* linux/arch/arm/mach-exynos/setup-fimc-is.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * FIMC-IS gpio and clock configuration
+ *
+ * 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.
+*/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/gpio.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/regulator/consumer.h>
+#include <linux/delay.h>
+#include <mach/regs-gpio.h>
+#include <mach/map.h>
+#include <mach/regs-clock.h>
+#include <plat/clock.h>
+#include <plat/gpio-cfg.h>
+#include <plat/map-s5p.h>
+#include <plat/cpu.h>
+#include <media/exynos_fimc_is.h>
+
+/*#define USE_UART_DEBUG*/
+
+struct platform_device; /* don't need the contents */
+
+/*------------------------------------------------------*/
+/* Exynos5 series - FIMC-IS */
+/*------------------------------------------------------*/
+static int cfg_gpio(struct gpio_set *gpio, int value)
+{
+ int ret;
+
+ pr_debug("gpio.pin:%d gpio.name:%s\n", gpio->pin, gpio->name);
+ ret = gpio_request(gpio->pin, gpio->name);
+ if (ret) {
+ pr_err("Request GPIO error(%s)\n", gpio->name);
+ return -1;
+ }
+
+ switch (gpio->act) {
+ case GPIO_PULL_NONE:
+ s3c_gpio_cfgpin(gpio->pin, value);
+ s3c_gpio_setpull(gpio->pin, S3C_GPIO_PULL_NONE);
+ break;
+ case GPIO_OUTPUT:
+ s3c_gpio_cfgpin(gpio->pin, S3C_GPIO_OUTPUT);
+ s3c_gpio_setpull(gpio->pin, S3C_GPIO_PULL_NONE);
+ gpio_set_value(gpio->pin, value);
+ break;
+ case GPIO_RESET:
+ s3c_gpio_setpull(gpio->pin, S3C_GPIO_PULL_NONE);
+ gpio_direction_output(gpio->pin, value);
+ break;
+ default:
+ pr_err("unknown act for gpio\n");
+ return -1;
+ }
+ gpio_free(gpio->pin);
+
+ return 0;
+
+}
+
+static int power_control_sensor(char *regulator_name, int on)
+{
+ struct regulator *regulator = NULL;
+
+ pr_debug("regulator:%s on:%d\n", regulator_name, on);
+ regulator = regulator_get(NULL, regulator_name);
+ if (IS_ERR(regulator)) {
+ pr_err("%s : regulator_get fail\n", __func__);
+ return PTR_ERR(regulator);
+ }
+
+ if (on)
+ regulator_enable(regulator);
+ else{
+ if (regulator_is_enabled(regulator))
+ regulator_disable(regulator);
+ }
+
+ regulator_put(regulator);
+ return 0;
+}
+
+int exynos5_fimc_is_cfg_clk(struct platform_device *pdev)
+{
+ struct clk *aclk_mcuisp = NULL;
+ struct clk *aclk_266 = NULL;
+ struct clk *aclk_mcuisp_div0 = NULL;
+ struct clk *aclk_mcuisp_div1 = NULL;
+ struct clk *aclk_266_div0 = NULL;
+ struct clk *aclk_266_div1 = NULL;
+ struct clk *aclk_266_mpwm = NULL;
+#ifdef USE_UART_DEBUG
+ struct clk *sclk_uart_isp = NULL;
+ struct clk *sclk_uart_isp_div = NULL;
+#endif
+ struct clk *mout_mpll = NULL;
+ struct clk *sclk_mipi0 = NULL;
+ struct clk *sclk_mipi1 = NULL;
+ struct clk *cam_src = NULL;
+ struct clk *cam_A_clk = NULL;
+ unsigned long mcu_isp_400;
+ unsigned long isp_266;
+ unsigned long isp_uart;
+ unsigned long mipi;
+ unsigned long xxti;
+
+ /* 1. MCUISP */
+ aclk_mcuisp = clk_get(&pdev->dev, "aclk_400_isp");
+ if (IS_ERR(aclk_mcuisp))
+ return PTR_ERR(aclk_mcuisp);
+
+ aclk_mcuisp_div0 = clk_get(&pdev->dev, "aclk_400_isp_div0");
+ if (IS_ERR(aclk_mcuisp_div0)) {
+ clk_put(aclk_mcuisp);
+ return PTR_ERR(aclk_mcuisp_div0);
+ }
+
+ aclk_mcuisp_div1 = clk_get(&pdev->dev, "aclk_400_isp_div1");
+ if (IS_ERR(aclk_mcuisp_div1)) {
+ clk_put(aclk_mcuisp);
+ clk_put(aclk_mcuisp_div0);
+ return PTR_ERR(aclk_mcuisp_div1);
+ }
+
+ clk_set_rate(aclk_mcuisp_div0, 200 * 1000000);
+ clk_set_rate(aclk_mcuisp_div1, 100 * 1000000);
+
+ mcu_isp_400 = clk_get_rate(aclk_mcuisp);
+ pr_debug("mcu_isp_400 : %ld\n", mcu_isp_400);
+
+ mcu_isp_400 = clk_get_rate(aclk_mcuisp_div0);
+ pr_debug("mcu_isp_400_div0 : %ld\n", mcu_isp_400);
+
+ mcu_isp_400 = clk_get_rate(aclk_mcuisp_div1);
+ pr_debug("aclk_mcuisp_div1 : %ld\n", mcu_isp_400);
+
+ clk_put(aclk_mcuisp);
+ clk_put(aclk_mcuisp_div0);
+ clk_put(aclk_mcuisp_div1);
+
+ /* 2. ACLK_ISP */
+ aclk_266 = clk_get(&pdev->dev, "aclk_266_isp");
+ if (IS_ERR(aclk_266))
+ return PTR_ERR(aclk_266);
+
+ aclk_266_div0 = clk_get(&pdev->dev, "aclk_266_isp_div0");
+ if (IS_ERR(aclk_266_div0)) {
+ clk_put(aclk_266);
+ return PTR_ERR(aclk_266_div0);
+ }
+
+ aclk_266_div1 = clk_get(&pdev->dev, "aclk_266_isp_div1");
+ if (IS_ERR(aclk_266_div1)) {
+ clk_put(aclk_266);
+ clk_put(aclk_266_div0);
+ return PTR_ERR(aclk_266_div1);
+ }
+
+ aclk_266_mpwm = clk_get(&pdev->dev, "aclk_266_isp_divmpwm");
+ if (IS_ERR(aclk_266_mpwm)) {
+ clk_put(aclk_266);
+ clk_put(aclk_266_div0);
+ clk_put(aclk_266_div1);
+ return PTR_ERR(aclk_266_mpwm);
+ }
+
+ clk_set_rate(aclk_266_div0, 134 * 1000000);
+ clk_set_rate(aclk_266_div1, 68 * 1000000);
+ clk_set_rate(aclk_266_mpwm, 34 * 1000000);
+
+ isp_266 = clk_get_rate(aclk_266);
+ pr_debug("isp_266 : %ld\n", isp_266);
+
+ isp_266 = clk_get_rate(aclk_266_div0);
+ pr_debug("isp_266_div0 : %ld\n", isp_266);
+
+ isp_266 = clk_get_rate(aclk_266_div1);
+ pr_debug("isp_266_div1 : %ld\n", isp_266);
+
+ isp_266 = clk_get_rate(aclk_266_mpwm);
+ pr_debug("isp_266_mpwm : %ld\n", isp_266);
+
+ clk_put(aclk_266);
+ clk_put(aclk_266_div0);
+ clk_put(aclk_266_div1);
+ clk_put(aclk_266_mpwm);
+
+#ifdef USE_UART_DEBUG
+ /* 3. UART-ISP */
+ sclk_uart_isp = clk_get(&pdev->dev, "sclk_uart_src_isp");
+ if (IS_ERR(sclk_uart_isp))
+ return PTR_ERR(sclk_uart_isp);
+
+ sclk_uart_isp_div = clk_get(&pdev->dev, "sclk_uart_isp");
+ if (IS_ERR(sclk_uart_isp_div)) {
+ clk_put(sclk_uart_isp);
+ return PTR_ERR(sclk_uart_isp_div);
+ }
+
+ clk_set_parent(sclk_uart_isp, clk_get(&pdev->dev, "mout_mpll_user"));
+ clk_set_parent(sclk_uart_isp_div, sclk_uart_isp);
+ clk_set_rate(sclk_uart_isp_div, 50 * 1000000);
+
+ isp_uart = clk_get_rate(sclk_uart_isp);
+ pr_debug("isp_uart : %ld\n", isp_uart);
+ isp_uart = clk_get_rate(sclk_uart_isp_div);
+ pr_debug("isp_uart_div : %ld\n", isp_uart);
+
+ clk_put(sclk_uart_isp);
+ clk_put(sclk_uart_isp_div);
+#endif
+
+ /* 4. MIPI-CSI */
+ mout_mpll = clk_get(&pdev->dev, "mout_mpll_user");
+ if (IS_ERR(mout_mpll))
+ return PTR_ERR(mout_mpll);
+
+ sclk_mipi0 = clk_get(&pdev->dev, "sclk_gscl_wrap0");
+ if (IS_ERR(sclk_mipi0)) {
+ clk_put(mout_mpll);
+ return PTR_ERR(sclk_mipi0);
+ }
+
+ clk_set_parent(sclk_mipi0, mout_mpll);
+ clk_set_rate(sclk_mipi0, 267 * 1000000);
+
+ clk_put(mout_mpll);
+ clk_put(sclk_mipi0);
+
+ mout_mpll = clk_get(&pdev->dev, "mout_mpll_user");
+ if (IS_ERR(mout_mpll))
+ return PTR_ERR(mout_mpll);
+
+ sclk_mipi1 = clk_get(&pdev->dev, "sclk_gscl_wrap1");
+ if (IS_ERR(sclk_mipi1)) {
+ clk_put(mout_mpll);
+ return PTR_ERR(sclk_mipi1);
+ }
+
+ clk_set_parent(sclk_mipi1, mout_mpll);
+ clk_set_rate(sclk_mipi1, 267 * 1000000);
+
+ mipi = clk_get_rate(mout_mpll);
+ pr_debug("mipi_src : %ld\n", mipi);
+ mipi = clk_get_rate(sclk_mipi1);
+ pr_debug("mipi_div : %ld\n", mipi);
+
+ clk_put(mout_mpll);
+ clk_put(sclk_mipi1);
+
+ /* 5. Camera A */
+ cam_src = clk_get(&pdev->dev, "xxti");
+ if (IS_ERR(cam_src))
+ return PTR_ERR(cam_src);
+
+ cam_A_clk = clk_get(&pdev->dev, "sclk_cam0");
+ if (IS_ERR(cam_A_clk)) {
+ clk_put(cam_src);
+ return PTR_ERR(cam_A_clk);
+ }
+
+ xxti = clk_get_rate(cam_src);
+ pr_debug("xxti : %ld\n", xxti);
+
+ clk_set_parent(cam_A_clk, cam_src);
+ clk_set_rate(cam_A_clk, 24 * 1000000);
+
+ clk_put(cam_src);
+ clk_put(cam_A_clk);
+
+ /* 6. Camera B */
+ cam_src = clk_get(&pdev->dev, "xxti");
+ if (IS_ERR(cam_src))
+ return PTR_ERR(cam_src);
+
+ cam_A_clk = clk_get(&pdev->dev, "sclk_bayer");
+ if (IS_ERR(cam_A_clk)) {
+ clk_put(cam_src);
+ return PTR_ERR(cam_A_clk);
+ }
+
+ xxti = clk_get_rate(cam_src);
+ pr_debug("xxti : %ld\n", xxti);
+
+ clk_set_parent(cam_A_clk, cam_src);
+ clk_set_rate(cam_A_clk, 24 * 1000000);
+
+ clk_put(cam_src);
+ clk_put(cam_A_clk);
+
+ return 0;
+}
+
+int exynos5_fimc_is_clk_on(struct platform_device *pdev, int sensor_id)
+{
+ struct clk *gsc_ctrl = NULL;
+ struct clk *isp_ctrl = NULL;
+ struct clk *mipi_ctrl = NULL;
+ struct clk *cam_if_top = NULL;
+ struct clk *cam_clk = NULL;
+ struct clk *isp_400_src = NULL;
+ struct clk *isp_266_src = NULL;
+ struct clk *isp_400_clk = NULL;
+ struct clk *isp_266_clk = NULL;
+ struct exynos5_platform_fimc_is *dev = pdev->dev.platform_data;
+ struct exynos5_fimc_is_sensor_info *sensor =
+ dev->sensor_info[sensor_id];
+
+ gsc_ctrl = clk_get(&pdev->dev, "gscl");
+ if (IS_ERR(gsc_ctrl))
+ return PTR_ERR(gsc_ctrl);
+
+ clk_enable(gsc_ctrl);
+ clk_put(gsc_ctrl);
+
+ isp_ctrl = clk_get(&pdev->dev, "isp0");
+ if (IS_ERR(isp_ctrl))
+ return PTR_ERR(isp_ctrl);
+
+ clk_enable(isp_ctrl);
+ clk_put(isp_ctrl);
+
+ isp_ctrl = clk_get(&pdev->dev, "isp1");
+ if (IS_ERR(isp_ctrl))
+ return PTR_ERR(isp_ctrl);
+
+ clk_enable(isp_ctrl);
+ clk_put(isp_ctrl);
+
+ cam_if_top = clk_get(&pdev->dev, "camif_top");
+ if (IS_ERR(cam_if_top))
+ return PTR_ERR(cam_if_top);
+
+ clk_enable(cam_if_top);
+ clk_put(cam_if_top);
+
+ if (sensor->csi_id == CSI_ID_A) {
+ mipi_ctrl = clk_get(&pdev->dev, "gscl_wrap0");
+ if (IS_ERR(mipi_ctrl))
+ return PTR_ERR(mipi_ctrl);
+
+ clk_enable(mipi_ctrl);
+ clk_put(mipi_ctrl);
+
+ cam_clk = clk_get(&pdev->dev, "sclk_cam0");
+ if (IS_ERR(cam_clk))
+ return PTR_ERR(cam_clk);
+
+ clk_enable(cam_clk);
+ clk_put(cam_clk);
+ }
+
+ if (sensor->csi_id == CSI_ID_B) {
+ mipi_ctrl = clk_get(&pdev->dev, "gscl_wrap1");
+ if (IS_ERR(mipi_ctrl))
+ return PTR_ERR(mipi_ctrl);
+
+ clk_enable(mipi_ctrl);
+ clk_put(mipi_ctrl);
+
+ cam_clk = clk_get(&pdev->dev, "sclk_bayer");
+ if (IS_ERR(cam_clk))
+ return PTR_ERR(cam_clk);
+
+ clk_enable(cam_clk);
+ clk_put(cam_clk);
+ }
+
+ /*isp sub src selection*/
+ isp_400_src = clk_get(&pdev->dev, "aclk_400_isp");
+ if (IS_ERR(isp_400_src))
+ return PTR_ERR(isp_400_src);
+
+ isp_266_src = clk_get(&pdev->dev, "aclk_266_isp");
+ if (IS_ERR(isp_266_src)) {
+ clk_put(isp_400_src);
+ return PTR_ERR(isp_266_src);
+ }
+
+ isp_400_clk = clk_get(&pdev->dev, "dout_aclk_400_isp");
+ if (IS_ERR(isp_400_clk)) {
+ clk_put(isp_400_src);
+ clk_put(isp_266_src);
+ return PTR_ERR(isp_400_clk);
+ }
+
+ isp_266_clk = clk_get(&pdev->dev, "aclk_266");
+ if (IS_ERR(isp_266_clk)) {
+ clk_put(isp_400_src);
+ clk_put(isp_266_src);
+ clk_put(isp_400_clk);
+ return PTR_ERR(isp_266_clk);
+ }
+
+ clk_set_parent(isp_400_src, isp_400_clk);
+ clk_set_parent(isp_266_src, isp_266_clk);
+
+ clk_put(isp_400_src);
+ clk_put(isp_266_src);
+ clk_put(isp_400_clk);
+ clk_put(isp_266_clk);
+
+ return 0;
+}
+
+int exynos5_fimc_is_clk_off(struct platform_device *pdev, int sensor_id)
+{
+ struct clk *gsc_ctrl = NULL;
+ struct clk *isp_ctrl = NULL;
+ struct clk *mipi_ctrl = NULL;
+ struct clk *cam_if_top = NULL;
+ struct clk *cam_clk = NULL;
+ struct clk *isp_400_src = NULL;
+ struct clk *isp_266_src = NULL;
+ struct clk *xtal_clk = NULL;
+ struct exynos5_platform_fimc_is *dev = pdev->dev.platform_data;
+ struct exynos5_fimc_is_sensor_info *sensor =
+ dev->sensor_info[sensor_id];
+
+ if (sensor->csi_id == CSI_ID_A) {
+ cam_clk = clk_get(&pdev->dev, "sclk_cam0");
+ if (IS_ERR(cam_clk))
+ return PTR_ERR(cam_clk);
+
+ clk_disable(cam_clk);
+ clk_put(cam_clk);
+
+ mipi_ctrl = clk_get(&pdev->dev, "gscl_wrap0");
+ if (IS_ERR(mipi_ctrl))
+ return PTR_ERR(mipi_ctrl);
+
+ clk_disable(mipi_ctrl);
+ clk_put(mipi_ctrl);
+ }
+
+ if (sensor->csi_id == CSI_ID_B) {
+ cam_clk = clk_get(&pdev->dev, "sclk_bayer");
+ if (IS_ERR(cam_clk))
+ return PTR_ERR(cam_clk);
+
+ clk_disable(cam_clk);
+ clk_put(cam_clk);
+
+ mipi_ctrl = clk_get(&pdev->dev, "gscl_wrap1");
+ if (IS_ERR(mipi_ctrl))
+ return PTR_ERR(mipi_ctrl);
+
+ clk_disable(mipi_ctrl);
+ clk_put(mipi_ctrl);
+ }
+
+ cam_if_top = clk_get(&pdev->dev, "camif_top");
+ if (IS_ERR(cam_if_top))
+ return PTR_ERR(cam_if_top);
+
+ clk_disable(cam_if_top);
+ clk_put(cam_if_top);
+
+ isp_ctrl = clk_get(&pdev->dev, "isp0");
+ if (IS_ERR(isp_ctrl))
+ return PTR_ERR(isp_ctrl);
+
+ clk_disable(isp_ctrl);
+ clk_put(isp_ctrl);
+
+ isp_ctrl = clk_get(&pdev->dev, "isp1");
+ if (IS_ERR(isp_ctrl))
+ return PTR_ERR(isp_ctrl);
+
+ clk_disable(isp_ctrl);
+ clk_put(isp_ctrl);
+
+ gsc_ctrl = clk_get(&pdev->dev, "gscl");
+ if (IS_ERR(gsc_ctrl))
+ return PTR_ERR(gsc_ctrl);
+
+ clk_disable(gsc_ctrl);
+ clk_put(gsc_ctrl);
+
+ /*isp sub src selection*/
+ isp_400_src = clk_get(&pdev->dev, "aclk_400_isp");
+ if (IS_ERR(isp_400_src))
+ return PTR_ERR(isp_400_src);
+
+ isp_266_src = clk_get(&pdev->dev, "aclk_266_isp");
+ if (IS_ERR(isp_266_src)) {
+ clk_put(isp_400_src);
+ return PTR_ERR(isp_266_src);
+ }
+
+ xtal_clk = clk_get(&pdev->dev, "ext_xtal");
+ if (IS_ERR(xtal_clk)) {
+ clk_put(isp_400_src);
+ clk_put(isp_266_src);
+ return PTR_ERR(xtal_clk);
+ }
+
+ clk_set_parent(isp_400_src, xtal_clk);
+ clk_set_parent(isp_266_src, xtal_clk);
+
+ clk_put(isp_400_src);
+ clk_put(isp_266_src);
+ clk_put(xtal_clk);
+
+ return 0;
+}
+
+/* sequence is important, don't change order */
+int exynos5_fimc_is_sensor_power_on(struct platform_device *pdev,
+ int sensor_id)
+{
+
+ struct exynos5_platform_fimc_is *dev = pdev->dev.platform_data;
+ struct exynos5_fimc_is_sensor_info *sensor =
+ dev->sensor_info[sensor_id];
+ int i;
+
+ pr_debug("exynos5_fimc_is_sensor_power_on(%d)\n",
+ sensor_id);
+ switch (sensor->sensor_id) {
+ case SENSOR_NAME_S5K4E5:
+ if (sensor->sensor_gpio.reset_peer.pin)
+ if (IS_ERR_VALUE(cfg_gpio(
+ &sensor->sensor_gpio.reset_peer, 0)))
+ goto error_sensor_power_on;
+
+ if (sensor->sensor_gpio.reset_myself.pin)
+ if (IS_ERR_VALUE(cfg_gpio(
+ &sensor->sensor_gpio.reset_myself, 0)))
+ goto error_sensor_power_on;
+
+ if (sensor->sensor_power.cam_core)
+ if (IS_ERR_VALUE(power_control_sensor(
+ sensor->sensor_power.cam_core, 1)))
+ goto error_sensor_power_on;
+ usleep_range(500, 1000);
+
+ if (sensor->sensor_gpio.power.pin)
+ if (IS_ERR_VALUE(cfg_gpio(
+ &sensor->sensor_gpio.power, 1)))
+ goto error_sensor_power_on;
+ usleep_range(500, 1000);
+
+ if (sensor->sensor_power.cam_io_myself)
+ if (IS_ERR_VALUE(power_control_sensor(
+ sensor->sensor_power.cam_io_myself, 1)))
+ goto error_sensor_power_on;
+ usleep_range(500, 1000);
+
+ if (sensor->sensor_power.cam_io_peer)
+ if (IS_ERR_VALUE(power_control_sensor(
+ sensor->sensor_power.cam_io_peer, 1)))
+ goto error_sensor_power_on;
+ usleep_range(500, 1000);
+
+ for (i = 0; i < FIMC_IS_MAX_GPIO_NUM; i++) {
+ if (!sensor->sensor_gpio.cfg[i].pin)
+ continue;
+ if (IS_ERR_VALUE(cfg_gpio(&sensor->sensor_gpio.cfg[i],
+ sensor->sensor_gpio.cfg[i].value)))
+ goto error_sensor_power_on;
+ }
+
+ if (sensor->sensor_power.cam_af)
+ if (IS_ERR_VALUE(power_control_sensor(
+ sensor->sensor_power.cam_af, 1)))
+ goto error_sensor_power_on;
+ usleep_range(500, 1000);
+
+ if (sensor->sensor_gpio.reset_myself.pin)
+ if (IS_ERR_VALUE(cfg_gpio(
+ &sensor->sensor_gpio.reset_myself, 1)))
+ goto error_sensor_power_on;
+ usleep_range(10, 100);
+
+ break;
+
+ case SENSOR_NAME_S5K6A3:
+ if (sensor->sensor_gpio.reset_peer.pin)
+ if (IS_ERR_VALUE(cfg_gpio(
+ &sensor->sensor_gpio.reset_peer, 0)))
+ goto error_sensor_power_on;
+
+ if (sensor->sensor_gpio.reset_myself.pin)
+ if (IS_ERR_VALUE(cfg_gpio(
+ &sensor->sensor_gpio.reset_myself, 0)))
+ goto error_sensor_power_on;
+
+ if (sensor->sensor_power.cam_core)
+ if (IS_ERR_VALUE(power_control_sensor(
+ sensor->sensor_power.cam_core, 1)))
+ goto error_sensor_power_on;
+ usleep_range(500, 1000);
+
+ for (i = 0; i < FIMC_IS_MAX_GPIO_NUM; i++) {
+ if (!sensor->sensor_gpio.cfg[i].pin)
+ continue;
+ if (IS_ERR_VALUE(cfg_gpio(&sensor->sensor_gpio.cfg[i],
+ sensor->sensor_gpio.cfg[i].value)))
+ goto error_sensor_power_on;
+ }
+
+ if (sensor->sensor_gpio.power.pin)
+ if (IS_ERR_VALUE(cfg_gpio(
+ &sensor->sensor_gpio.power, 1)))
+ goto error_sensor_power_on;
+ usleep_range(500, 1000);
+
+ if (sensor->sensor_power.cam_io_myself)
+ if (IS_ERR_VALUE(power_control_sensor(
+ sensor->sensor_power.cam_io_myself, 1)))
+ goto error_sensor_power_on;
+ usleep_range(500, 1000);
+
+ if (sensor->sensor_power.cam_io_peer)
+ if (IS_ERR_VALUE(power_control_sensor(
+ sensor->sensor_power.cam_io_peer, 1)))
+ goto error_sensor_power_on;
+ usleep_range(500, 1000);
+
+ if (sensor->sensor_gpio.reset_peer.pin)
+ if (IS_ERR_VALUE(cfg_gpio(
+ &sensor->sensor_gpio.reset_peer, 1)))
+ goto error_sensor_power_on;
+ usleep_range(1200, 2000); /* must stay here more than 1msec */
+
+ if (sensor->sensor_gpio.reset_peer.pin)
+ if (IS_ERR_VALUE(cfg_gpio(
+ &sensor->sensor_gpio.reset_peer, 0)))
+ goto error_sensor_power_on;
+ usleep_range(1000, 1500);
+
+ if (sensor->sensor_gpio.reset_myself.pin)
+ if (IS_ERR_VALUE(cfg_gpio(
+ &sensor->sensor_gpio.reset_myself, 1)))
+ goto error_sensor_power_on;
+ usleep_range(500, 1000);
+
+ if (sensor->sensor_gpio.reset_myself.pin)
+ if (IS_ERR_VALUE(cfg_gpio(
+ &sensor->sensor_gpio.reset_myself, 0)))
+ goto error_sensor_power_on;
+ usleep_range(500, 1000);
+
+ if (sensor->sensor_gpio.reset_myself.pin)
+ if (IS_ERR_VALUE(cfg_gpio(
+ &sensor->sensor_gpio.reset_myself, 1)))
+ goto error_sensor_power_on;
+ usleep_range(10, 100);
+
+ break;
+ default:
+ pr_err("Bad camera senosr ID(%d)",
+ sensor->sensor_id);
+ goto error_sensor_power_on;
+ }
+ return 0;
+
+error_sensor_power_on:
+ return -1;
+
+}
+
+/* sequence is important, don't change order */
+int exynos5_fimc_is_sensor_power_off(struct platform_device *pdev,
+ int sensor_id)
+{
+ struct exynos5_platform_fimc_is *dev = pdev->dev.platform_data;
+ struct exynos5_fimc_is_sensor_info *sensor
+ = dev->sensor_info[sensor_id];
+
+ pr_debug("exynos5_fimc_is_sensor_power_off(%d)\n", sensor_id);
+
+ switch (sensor->sensor_id) {
+ case SENSOR_NAME_S5K4E5:
+ if (sensor->sensor_gpio.reset_peer.pin)
+ if (IS_ERR_VALUE(cfg_gpio(
+ &sensor->sensor_gpio.reset_peer, 0)))
+ goto error_sensor_power_off;
+
+ if (sensor->sensor_gpio.reset_myself.pin)
+ if (IS_ERR_VALUE(cfg_gpio(
+ &sensor->sensor_gpio.reset_myself, 0)))
+ goto error_sensor_power_off;
+
+ if (sensor->sensor_gpio.power.pin)
+ if (IS_ERR_VALUE(cfg_gpio(
+ &sensor->sensor_gpio.power, 0)))
+ goto error_sensor_power_off;
+ usleep_range(500, 1000);
+
+ if (sensor->sensor_power.cam_core)
+ if (IS_ERR_VALUE(power_control_sensor(
+ sensor->sensor_power.cam_core, 0)))
+ goto error_sensor_power_off;
+
+ usleep_range(500, 1000);
+ if (sensor->sensor_power.cam_io_myself)
+ if (IS_ERR_VALUE(power_control_sensor(
+ sensor->sensor_power.cam_io_myself, 0)))
+ goto error_sensor_power_off;
+
+ usleep_range(500, 1000);
+ if (sensor->sensor_power.cam_io_peer)
+ if (IS_ERR_VALUE(power_control_sensor(
+ sensor->sensor_power.cam_io_peer, 0)))
+ goto error_sensor_power_off;
+
+ usleep_range(500, 1000);
+ if (sensor->sensor_power.cam_af)
+ if (IS_ERR_VALUE(power_control_sensor(
+ sensor->sensor_power.cam_af, 0)))
+ goto error_sensor_power_off;
+
+ usleep_range(500, 1000);
+ break;
+
+ case SENSOR_NAME_S5K6A3:
+ if (sensor->sensor_gpio.reset_peer.pin)
+ if (IS_ERR_VALUE(cfg_gpio(
+ &sensor->sensor_gpio.reset_peer, 0)))
+ goto error_sensor_power_off;
+
+ if (sensor->sensor_gpio.reset_myself.pin)
+ if (IS_ERR_VALUE(cfg_gpio(
+ &sensor->sensor_gpio.reset_myself, 0)))
+ goto error_sensor_power_off;
+
+ if (sensor->sensor_gpio.power.pin)
+ if (IS_ERR_VALUE(cfg_gpio(
+ &sensor->sensor_gpio.power, 0)))
+ goto error_sensor_power_off;
+ usleep_range(500, 1000);
+
+ if (sensor->sensor_power.cam_core)
+ if (IS_ERR_VALUE(power_control_sensor(
+ sensor->sensor_power.cam_core, 0)))
+ goto error_sensor_power_off;
+ usleep_range(500, 1000);
+
+ if (sensor->sensor_power.cam_io_myself)
+ if (IS_ERR_VALUE(power_control_sensor(
+ sensor->sensor_power.cam_io_myself, 0)))
+ goto error_sensor_power_off;
+ usleep_range(500, 1000);
+
+ if (sensor->sensor_power.cam_io_peer)
+ if (IS_ERR_VALUE(power_control_sensor(
+ sensor->sensor_power.cam_io_peer, 0)))
+ goto error_sensor_power_off;
+ usleep_range(500, 1000);
+ break;
+ default:
+ pr_err("Bad camera senosr ID(%d)",
+ sensor->sensor_id);
+ goto error_sensor_power_off;
+ }
+ return 0;
+
+error_sensor_power_off:
+ return -1;
+
+}
diff --git a/arch/arm/mach-exynos/setup-fimd1.c b/arch/arm/mach-exynos/setup-fimd1.c
new file mode 100644
index 0000000..5d5f8e4
--- /dev/null
+++ b/arch/arm/mach-exynos/setup-fimd1.c
@@ -0,0 +1,80 @@
+/* linux/arch/arm/mach-exynos/setup-fimd1.c
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Base Exynos FIMD 1 configuration
+ *
+ * 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.
+*/
+
+#include <linux/fb.h>
+#include <linux/gpio.h>
+#include <linux/clk.h>
+
+#include <plat/fb.h>
+#include <plat/gpio-cfg.h>
+#include <plat/clock.h>
+#include <plat/regs-fb-v4.h>
+
+#include <mach/map.h>
+
+void exynos5_fimd1_gpio_setup_24bpp(void)
+{
+ unsigned int reg;
+
+ /*
+ * Set DISP1BLK_CFG register for Display path selection
+ *
+ * FIMD of DISP1_BLK Bypass selection : DISP1BLK_CFG[15]
+ * ---------------------
+ * 0 | MIE/MDINE
+ * 1 | FIMD : selected
+ */
+ reg = __raw_readl(S3C_VA_SYS + 0x0214);
+ reg |= (1 << 15);
+ __raw_writel(reg, S3C_VA_SYS + 0x0214);
+}
+
+int __init exynos5_fimd1_setup_clock(struct device *dev, const char *bus_clk,
+ const char *parent, unsigned long clk_rate)
+{
+ struct clk *clk_parent;
+ struct clk *sclk;
+
+ sclk = clk_get(dev, bus_clk);
+ if (IS_ERR(sclk))
+ return PTR_ERR(sclk);
+
+ clk_parent = clk_get(NULL, parent);
+ if (IS_ERR(clk_parent)) {
+ clk_put(sclk);
+ return PTR_ERR(clk_parent);
+ }
+
+ if (clk_set_parent(sclk, clk_parent)) {
+ pr_err("Unable to set parent %s of clock %s.\n",
+ clk_parent->name, sclk->name);
+ clk_put(sclk);
+ clk_put(clk_parent);
+ return PTR_ERR(sclk);
+ }
+
+ if (!clk_rate)
+ clk_rate = 134000000UL;
+
+ if (clk_set_rate(sclk, clk_rate)) {
+ pr_err("%s rate change failed: %lu\n", sclk->name, clk_rate);
+ clk_put(sclk);
+ clk_put(clk_parent);
+ return PTR_ERR(sclk);
+ }
+
+ clk_put(sclk);
+ clk_put(clk_parent);
+
+ return 0;
+}
+
diff --git a/arch/arm/mach-exynos/setup-gsc.c b/arch/arm/mach-exynos/setup-gsc.c
new file mode 100644
index 0000000..404b670
--- /dev/null
+++ b/arch/arm/mach-exynos/setup-gsc.c
@@ -0,0 +1,39 @@
+/* linux/arch/arm/mach-exynos/setup-gsc.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Base Exynos5 G-Scaler clock configuration
+ *
+ * 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.
+*/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <plat/clock.h>
+#include <plat/devs.h>
+#include <mach/regs-clock.h>
+#include <mach/map.h>
+#include <media/exynos_gscaler.h>
+
+void __init exynos5_gsc_set_pdev_name(int id, char *name)
+{
+ switch (id) {
+ case 0:
+ exynos5_device_gsc0.name = name;
+ break;
+ case 1:
+ exynos5_device_gsc1.name = name;
+ break;
+ case 2:
+ exynos5_device_gsc2.name = name;
+ break;
+ case 3:
+ exynos5_device_gsc3.name = name;
+ break;
+ }
+}
diff --git a/arch/arm/mach-exynos/setup-i2c0.c b/arch/arm/mach-exynos/setup-i2c0.c
index b90d94c..5547b9e 100644
--- a/arch/arm/mach-exynos/setup-i2c0.c
+++ b/arch/arm/mach-exynos/setup-i2c0.c
@@ -21,9 +21,10 @@
void s3c_i2c0_cfg_gpio(struct platform_device *dev)
{
if (soc_is_exynos5250())
- /* will be implemented with gpio function */
- return;
+ s3c_gpio_cfgall_range(EXYNOS5_GPB3(0), 2,
+ S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP);
- s3c_gpio_cfgall_range(EXYNOS4_GPD1(0), 2,
- S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP);
+ else /* EXYNOS4210, EXYNOS4212, and EXYNOS4412 */
+ s3c_gpio_cfgall_range(EXYNOS4_GPD1(0), 2,
+ S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP);
}
diff --git a/arch/arm/mach-exynos/setup-i2c1.c b/arch/arm/mach-exynos/setup-i2c1.c
index fd7235a..882c11d 100644
--- a/arch/arm/mach-exynos/setup-i2c1.c
+++ b/arch/arm/mach-exynos/setup-i2c1.c
@@ -1,7 +1,5 @@
/*
- * linux/arch/arm/mach-exynos4/setup-i2c1.c
- *
- * Copyright (C) 2010 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2010-2012 Samsung Electronics Co., Ltd.
*
* I2C1 GPIO configuration.
*
@@ -15,9 +13,15 @@
#include <linux/gpio.h>
#include <plat/iic.h>
#include <plat/gpio-cfg.h>
+#include <plat/cpu.h>
void s3c_i2c1_cfg_gpio(struct platform_device *dev)
{
- s3c_gpio_cfgall_range(EXYNOS4_GPD1(2), 2,
- S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP);
+ if (soc_is_exynos5250())
+ s3c_gpio_cfgall_range(EXYNOS5_GPB3(2), 2,
+ S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP);
+
+ else /* EXYNOS4210, EXYNOS4212, and EXYNOS4412 */
+ s3c_gpio_cfgall_range(EXYNOS4_GPD1(2), 2,
+ S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP);
}
diff --git a/arch/arm/mach-exynos/setup-i2c2.c b/arch/arm/mach-exynos/setup-i2c2.c
index 2694b19..4cda1b2 100644
--- a/arch/arm/mach-exynos/setup-i2c2.c
+++ b/arch/arm/mach-exynos/setup-i2c2.c
@@ -1,7 +1,5 @@
/*
- * linux/arch/arm/mach-exynos4/setup-i2c2.c
- *
- * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2009-2012 Samsung Electronics Co., Ltd.
*
* I2C2 GPIO configuration.
*
@@ -15,9 +13,15 @@
#include <linux/gpio.h>
#include <plat/iic.h>
#include <plat/gpio-cfg.h>
+#include <plat/cpu.h>
void s3c_i2c2_cfg_gpio(struct platform_device *dev)
{
- s3c_gpio_cfgall_range(EXYNOS4_GPA0(6), 2,
- S3C_GPIO_SFN(3), S3C_GPIO_PULL_UP);
+ if (soc_is_exynos5250())
+ s3c_gpio_cfgall_range(EXYNOS5_GPA0(6), 2,
+ S3C_GPIO_SFN(3), S3C_GPIO_PULL_UP);
+
+ else /* EXYNOS4210, EXYNOS4212, and EXYNOS4412 */
+ s3c_gpio_cfgall_range(EXYNOS4_GPA0(6), 2,
+ S3C_GPIO_SFN(3), S3C_GPIO_PULL_UP);
}
diff --git a/arch/arm/mach-exynos/setup-i2c3.c b/arch/arm/mach-exynos/setup-i2c3.c
index 379bd30..81688f7 100644
--- a/arch/arm/mach-exynos/setup-i2c3.c
+++ b/arch/arm/mach-exynos/setup-i2c3.c
@@ -1,7 +1,5 @@
/*
- * linux/arch/arm/mach-exynos4/setup-i2c3.c
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2010-2012 Samsung Electronics Co., Ltd.
*
* I2C3 GPIO configuration.
*
@@ -15,9 +13,15 @@
#include <linux/gpio.h>
#include <plat/iic.h>
#include <plat/gpio-cfg.h>
+#include <plat/cpu.h>
void s3c_i2c3_cfg_gpio(struct platform_device *dev)
{
- s3c_gpio_cfgall_range(EXYNOS4_GPA1(2), 2,
- S3C_GPIO_SFN(3), S3C_GPIO_PULL_UP);
+ if (soc_is_exynos5250())
+ s3c_gpio_cfgall_range(EXYNOS5_GPA1(2), 2,
+ S3C_GPIO_SFN(3), S3C_GPIO_PULL_UP);
+
+ else /* EXYNOS4210, EXYNOS4212, and EXYNOS4412 */
+ s3c_gpio_cfgall_range(EXYNOS4_GPA1(2), 2,
+ S3C_GPIO_SFN(3), S3C_GPIO_PULL_UP);
}
diff --git a/arch/arm/mach-exynos/setup-i2c4.c b/arch/arm/mach-exynos/setup-i2c4.c
index 9f3c048..ff89873 100644
--- a/arch/arm/mach-exynos/setup-i2c4.c
+++ b/arch/arm/mach-exynos/setup-i2c4.c
@@ -1,7 +1,5 @@
/*
- * linux/arch/arm/mach-exynos4/setup-i2c4.c
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2010-2012 Samsung Electronics Co., Ltd.
*
* I2C4 GPIO configuration.
*
@@ -15,9 +13,22 @@
#include <linux/gpio.h>
#include <plat/iic.h>
#include <plat/gpio-cfg.h>
+#include <plat/cpu.h>
void s3c_i2c4_cfg_gpio(struct platform_device *dev)
{
- s3c_gpio_cfgall_range(EXYNOS4_GPB(2), 2,
- S3C_GPIO_SFN(3), S3C_GPIO_PULL_UP);
+ if (soc_is_exynos4210())
+ s3c_gpio_cfgall_range(EXYNOS4_GPB(2), 2,
+ S3C_GPIO_SFN(3), S3C_GPIO_PULL_UP);
+
+ else if (soc_is_exynos4212() || soc_is_exynos4412())
+ s3c_gpio_cfgall_range(EXYNOS4_GPB(0), 2,
+ S3C_GPIO_SFN(3), S3C_GPIO_PULL_UP);
+
+ else if (soc_is_exynos5250())
+ s3c_gpio_cfgall_range(EXYNOS5_GPA2(0), 2,
+ S3C_GPIO_SFN(3), S3C_GPIO_PULL_UP);
+
+ else
+ pr_err("failed to configure gpio for i2c4\n");
}
diff --git a/arch/arm/mach-exynos/setup-i2c5.c b/arch/arm/mach-exynos/setup-i2c5.c
index 77e1a1e..582b5b2 100644
--- a/arch/arm/mach-exynos/setup-i2c5.c
+++ b/arch/arm/mach-exynos/setup-i2c5.c
@@ -1,7 +1,5 @@
/*
- * linux/arch/arm/mach-exynos4/setup-i2c5.c
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2010-2012 Samsung Electronics Co., Ltd.
*
* I2C5 GPIO configuration.
*
@@ -15,9 +13,22 @@
#include <linux/gpio.h>
#include <plat/iic.h>
#include <plat/gpio-cfg.h>
+#include <plat/cpu.h>
void s3c_i2c5_cfg_gpio(struct platform_device *dev)
{
- s3c_gpio_cfgall_range(EXYNOS4_GPB(6), 2,
- S3C_GPIO_SFN(3), S3C_GPIO_PULL_UP);
+ if (soc_is_exynos4210())
+ s3c_gpio_cfgall_range(EXYNOS4_GPB(6), 2,
+ S3C_GPIO_SFN(3), S3C_GPIO_PULL_UP);
+
+ else if (soc_is_exynos4212() || soc_is_exynos4412())
+ s3c_gpio_cfgall_range(EXYNOS4_GPB(2), 2,
+ S3C_GPIO_SFN(3), S3C_GPIO_PULL_UP);
+
+ else if (soc_is_exynos5250())
+ s3c_gpio_cfgall_range(EXYNOS5_GPA2(2), 2,
+ S3C_GPIO_SFN(3), S3C_GPIO_PULL_UP);
+
+ else
+ pr_err("failed to configure gpio for i2c5\n");
}
diff --git a/arch/arm/mach-exynos/setup-i2c6.c b/arch/arm/mach-exynos/setup-i2c6.c
index 284d12b..a88fcbc 100644
--- a/arch/arm/mach-exynos/setup-i2c6.c
+++ b/arch/arm/mach-exynos/setup-i2c6.c
@@ -1,7 +1,5 @@
/*
- * linux/arch/arm/mach-exynos4/setup-i2c6.c
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2010-2012 Samsung Electronics Co., Ltd.
*
* I2C6 GPIO configuration.
*
@@ -15,9 +13,15 @@
#include <linux/gpio.h>
#include <plat/iic.h>
#include <plat/gpio-cfg.h>
+#include <plat/cpu.h>
void s3c_i2c6_cfg_gpio(struct platform_device *dev)
{
- s3c_gpio_cfgall_range(EXYNOS4_GPC1(3), 2,
- S3C_GPIO_SFN(4), S3C_GPIO_PULL_UP);
+ if (soc_is_exynos5250())
+ s3c_gpio_cfgall_range(EXYNOS5_GPB1(3), 2,
+ S3C_GPIO_SFN(4), S3C_GPIO_PULL_UP);
+
+ else /* EXYNOS4210, EXYNOS4212, and EXYNOS4412 */
+ s3c_gpio_cfgall_range(EXYNOS4_GPC1(3), 2,
+ S3C_GPIO_SFN(4), S3C_GPIO_PULL_UP);
}
diff --git a/arch/arm/mach-exynos/setup-i2c7.c b/arch/arm/mach-exynos/setup-i2c7.c
index b7611ee..0ff1b14 100644
--- a/arch/arm/mach-exynos/setup-i2c7.c
+++ b/arch/arm/mach-exynos/setup-i2c7.c
@@ -1,7 +1,5 @@
/*
- * linux/arch/arm/mach-exynos4/setup-i2c7.c
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2010-2012 Samsung Electronics Co., Ltd.
*
* I2C7 GPIO configuration.
*
@@ -15,9 +13,15 @@
#include <linux/gpio.h>
#include <plat/iic.h>
#include <plat/gpio-cfg.h>
+#include <plat/cpu.h>
void s3c_i2c7_cfg_gpio(struct platform_device *dev)
{
- s3c_gpio_cfgall_range(EXYNOS4_GPD0(2), 2,
- S3C_GPIO_SFN(3), S3C_GPIO_PULL_UP);
+ if (soc_is_exynos5250())
+ s3c_gpio_cfgall_range(EXYNOS5_GPB2(2), 2,
+ S3C_GPIO_SFN(3), S3C_GPIO_PULL_UP);
+
+ else /* EXYNOS4210, EXYNOS4212, and EXYNOS4412 */
+ s3c_gpio_cfgall_range(EXYNOS4_GPD0(2), 2,
+ S3C_GPIO_SFN(3), S3C_GPIO_PULL_UP);
}
diff --git a/arch/arm/mach-exynos/setup-jpeg.c b/arch/arm/mach-exynos/setup-jpeg.c
new file mode 100644
index 0000000..c2cdfbe
--- /dev/null
+++ b/arch/arm/mach-exynos/setup-jpeg.c
@@ -0,0 +1,130 @@
+/* linux/arch/arm/mach-exynos/setup-jpeg.c
+ *
+ * Copyright (c) 2009-2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Base Exynos4 JPEG configuration
+ *
+ * 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.
+*/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+
+#include <plat/gpio-cfg.h>
+#include <plat/clock.h>
+
+#include <mach/regs-clock.h>
+#include <mach/map.h>
+
+int __init exynos4_jpeg_setup_clock(struct device *dev,
+ unsigned long clk_rate)
+{
+ struct clk *sclk = NULL;
+ struct clk *mout_jpeg = NULL;
+ struct clk *mout_mpll = NULL;
+ int ret;
+
+ sclk = clk_get(dev, "aclk_clk_jpeg");
+ if (IS_ERR(sclk)) {
+ dev_err(dev, "failed to get aclk for jpeg\n");
+ goto err_clk1;
+ }
+
+ mout_jpeg = clk_get(dev, "mout_jpeg0");
+
+ if (IS_ERR(mout_jpeg)) {
+ dev_err(dev, "failed to get mout_jpeg0 for jpeg\n");
+ goto err_clk2;
+ }
+
+ ret = clk_set_parent(sclk, mout_jpeg);
+ if (ret < 0) {
+ dev_err(dev, "failed to clk_set_parent for jpeg\n");
+ goto err_clk2;
+ }
+
+ mout_mpll = clk_get(dev, "mout_mpll_user");
+
+ if (IS_ERR(mout_mpll)) {
+ dev_err(dev, "failed to get mout_mpll for jpeg\n");
+ goto err_clk2;
+ }
+
+ ret = clk_set_parent(mout_jpeg, mout_mpll);
+ if (ret < 0) {
+ dev_err(dev, "failed to clk_set_parent for jpeg\n");
+ goto err_clk2;
+ }
+
+ ret = clk_set_rate(sclk, clk_rate);
+ if (ret < 0) {
+ dev_err(dev, "failed to clk_set_rate of sclk for jpeg\n");
+ goto err_clk2;
+ }
+ dev_dbg(dev, "set jpeg aclk rate\n");
+
+ clk_put(mout_jpeg);
+ clk_put(mout_mpll);
+
+ ret = clk_enable(sclk);
+ if (ret < 0) {
+ dev_err(dev, "failed to clk_enable of aclk for jpeg\n");
+ goto err_clk2;
+ }
+
+ return 0;
+
+err_clk2:
+ clk_put(mout_mpll);
+err_clk1:
+ clk_put(sclk);
+
+ return -EINVAL;
+}
+
+int __init exynos5_jpeg_setup_clock(struct device *dev,
+ unsigned long clk_rate)
+{
+ struct clk *sclk;
+ struct clk *mout_user = NULL;
+ int ret;
+
+ sclk = clk_get(dev, "sclk_jpeg");
+ if (IS_ERR(sclk))
+ return PTR_ERR(sclk);
+
+ mout_user = clk_get(dev, "mout_mpll_user");
+ if (IS_ERR(mout_user)) {
+ dev_err(dev, "failed to clk_get mout_user for jpeg\n");
+ clk_put(sclk);
+ return PTR_ERR(mout_user);
+ }
+ ret = clk_set_parent(sclk, mout_user);
+ if (ret < 0) {
+ dev_err(dev, "failed to clk_set_parent for jpeg\n");
+ goto err_clk;
+ }
+
+ if (!clk_rate)
+ clk_rate = 150000000UL;
+
+ if (clk_set_rate(sclk, clk_rate)) {
+ dev_err(dev, "failed to clk_set_rate of sclk for jpeg\n");
+ goto err_clk;
+ }
+
+ clk_put(sclk);
+ clk_put(mout_user);
+
+ return 0;
+err_clk:
+ clk_put(sclk);
+ clk_put(mout_user);
+ return -EINVAL;
+}
diff --git a/arch/arm/mach-exynos/setup-mfc.c b/arch/arm/mach-exynos/setup-mfc.c
new file mode 100644
index 0000000..00e72df
--- /dev/null
+++ b/arch/arm/mach-exynos/setup-mfc.c
@@ -0,0 +1,47 @@
+/* linux/arch/arm/mach-exynos/setup-mfc.c
+ *
+ * Copyright (c) 2009-2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Base Exynos4 MFC configuration
+ *
+ * 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.
+*/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/fb.h>
+#include <linux/gpio.h>
+#include <linux/clk.h>
+
+#include <plat/fb.h>
+#include <plat/gpio-cfg.h>
+#include <plat/clock.h>
+#include <plat/cpu.h>
+#include <plat/devs.h>
+
+#include <mach/regs-clock.h>
+#include <mach/map.h>
+#include <mach/exynos-mfc.h>
+
+static struct s5p_mfc_platdata default_mfc_pd __initdata = {
+ .clock_rate = 200 * MHZ,
+};
+
+void __init s5p_mfc_set_platdata(struct s5p_mfc_platdata *pd)
+{
+ struct s5p_mfc_platdata *npd;
+
+ if (!pd)
+ pd = &default_mfc_pd;
+
+ npd = s3c_set_platdata(pd, sizeof(struct s5p_mfc_platdata),
+ &s5p_device_mfc);
+}
+
+void s5p_mfc_setname(struct platform_device *pdev, char *name)
+{
+ pdev->name = name;
+}
diff --git a/arch/arm/mach-exynos/setup-mipidsim.c b/arch/arm/mach-exynos/setup-mipidsim.c
new file mode 100644
index 0000000..e85e1e0
--- /dev/null
+++ b/arch/arm/mach-exynos/setup-mipidsim.c
@@ -0,0 +1,93 @@
+/* linux/arch/arm/mach-exynos/setup-mipidsim.c
+ *
+ * Copyright (c) 2011 Samsung Electronics
+ *
+ *
+ * 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
+ * ERCHANTABILITY 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., 59 Temple Place, Suite 330, Boston,
+ * A 02111-1307 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+
+#include <mach/map.h>
+#include <mach/regs-clock.h>
+
+#include <plat/dsim.h>
+#include <plat/clock.h>
+#include <plat/regs-mipidsim.h>
+
+#define S5P_MIPI_M_RESETN 4
+
+static int s5p_dsim_enable_d_phy(struct mipi_dsim_device *dsim,
+ unsigned int enable)
+{
+ unsigned int reg;
+#if defined(CONFIG_ARCH_EXYNOS5)
+ reg = readl(S5P_MIPI_DPHY_CONTROL(1)) & ~(1 << 0);
+ reg |= (enable << 0);
+ writel(reg, S5P_MIPI_DPHY_CONTROL(1));
+#else
+ reg = readl(S5P_MIPI_DPHY_CONTROL(0)) & ~(1 << 0);
+ reg |= (enable << 0);
+ writel(reg, S5P_MIPI_DPHY_CONTROL(0));
+#endif
+ return 0;
+}
+
+static int s5p_dsim_enable_dsi_master(struct mipi_dsim_device *dsim,
+ unsigned int enable)
+{
+ unsigned int reg;
+#if defined(CONFIG_ARCH_EXYNOS5)
+ reg = readl(S5P_MIPI_DPHY_CONTROL(1)) & ~(1 << 2);
+ reg |= (enable << 2);
+ writel(reg, S5P_MIPI_DPHY_CONTROL(1));
+#else
+ reg = readl(S5P_MIPI_DPHY_CONTROL(0)) & ~(1 << 2);
+ reg |= (enable << 2);
+ writel(reg, S5P_MIPI_DPHY_CONTROL(0));
+#endif
+ return 0;
+}
+
+int s5p_dsim_part_reset(struct mipi_dsim_device *dsim)
+{
+#if defined(CONFIG_ARCH_EXYNOS5)
+ if (dsim->id == 0)
+ writel(S5P_MIPI_M_RESETN, S5P_MIPI_DPHY_CONTROL(1));
+#else
+ if (dsim->id == 0)
+ writel(S5P_MIPI_M_RESETN, S5P_MIPI_DPHY_CONTROL(0));
+#endif
+ return 0;
+}
+
+int s5p_dsim_init_d_phy(struct mipi_dsim_device *dsim, unsigned int enable)
+{
+ /**
+ * DPHY and aster block must be enabled at the system initialization
+ * step before data access from/to DPHY begins.
+ */
+ s5p_dsim_enable_d_phy(dsim, enable);
+
+ s5p_dsim_enable_dsi_master(dsim, enable);
+ return 0;
+}
diff --git a/arch/arm/mach-exynos/setup-spi.c b/arch/arm/mach-exynos/setup-spi.c
index 833ff40e..af015d1 100644
--- a/arch/arm/mach-exynos/setup-spi.c
+++ b/arch/arm/mach-exynos/setup-spi.c
@@ -8,12 +8,73 @@
* published by the Free Software Foundation.
*/
+#include <linux/clk.h>
+#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>
+#include <plat/clock.h>
+#include <plat/cpu.h>
#include <plat/gpio-cfg.h>
#include <plat/s3c64xx-spi.h>
+#define EXYNOS_SPI_NAME_SIZE 16
+
+int exynos_spi_cfg_cs(int gpio, int ch_num)
+{
+ char cs_name[EXYNOS_SPI_NAME_SIZE];
+
+ snprintf(cs_name, EXYNOS_SPI_NAME_SIZE, "SPI_CS%d", ch_num);
+
+ if (gpio_request(gpio, cs_name))
+ return -EIO;
+
+ gpio_direction_output(gpio, 1);
+ s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(1));
+ s3c_gpio_setpull(gpio, S3C_GPIO_PULL_UP);
+ gpio_free(gpio);
+
+ return 0;
+
+}
+
+void exynos_spi_clock_setup(struct device *spi_dev, int ch_num)
+{
+ struct clk *child_clk = NULL;
+ struct clk *parent_clk = NULL;
+ char clk_name[EXYNOS_SPI_NAME_SIZE];
+
+ snprintf(clk_name, EXYNOS_SPI_NAME_SIZE, "dout_spi%d", ch_num);
+ child_clk = clk_get(spi_dev, clk_name);
+
+ if (IS_ERR(child_clk)) {
+ pr_err("%s: Failed to get %s clk\n", __func__, clk_name);
+ return;
+ }
+
+ parent_clk = clk_get(spi_dev, "mout_mpll_user");
+
+ if (IS_ERR(parent_clk)) {
+ pr_err("%s: Failed to get mout_mpll_user clk\n", __func__);
+ goto err1;
+ }
+
+ if (clk_set_parent(child_clk, parent_clk)) {
+ pr_err("%s: Unable to set parent %s of clock %s\n",
+ __func__, parent_clk->name, child_clk->name);
+ goto err2;
+ }
+
+ if (clk_set_rate(child_clk, 100 * 1000 * 1000))
+ pr_err("%s: Unable to set rate of clock %s\n",
+ __func__, child_clk->name);
+
+err2:
+ clk_put(parent_clk);
+err1:
+ clk_put(child_clk);
+}
+
#ifdef CONFIG_S3C64XX_DEV_SPI0
struct s3c64xx_spi_info s3c64xx_spi0_pdata __initdata = {
.fifo_lvl_mask = 0x1ff,
@@ -25,10 +86,26 @@
int s3c64xx_spi0_cfg_gpio(struct platform_device *dev)
{
- s3c_gpio_cfgpin(EXYNOS4_GPB(0), S3C_GPIO_SFN(2));
- s3c_gpio_setpull(EXYNOS4_GPB(0), S3C_GPIO_PULL_UP);
- s3c_gpio_cfgall_range(EXYNOS4_GPB(2), 2,
- S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP);
+ int gpio;
+
+ if (soc_is_exynos5250()) {
+ s3c_gpio_cfgpin(EXYNOS5_GPA2(0), S3C_GPIO_SFN(2));
+ s3c_gpio_setpull(EXYNOS5_GPA2(0), S3C_GPIO_PULL_UP);
+ s3c_gpio_cfgall_range(EXYNOS5_GPA2(2), 2,
+ S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP);
+
+ for (gpio = EXYNOS5_GPA2(0); gpio < EXYNOS5_GPA2(4); gpio++)
+ s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV3);
+ } else {
+ s3c_gpio_cfgpin(EXYNOS4_GPB(0), S3C_GPIO_SFN(2));
+ s3c_gpio_setpull(EXYNOS4_GPB(0), S3C_GPIO_PULL_UP);
+ s3c_gpio_cfgall_range(EXYNOS4_GPB(2), 2,
+ S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP);
+
+ for (gpio = EXYNOS4_GPB(0); gpio < EXYNOS4_GPB(4); gpio++)
+ s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV3);
+ }
+
return 0;
}
#endif
@@ -44,10 +121,26 @@
int s3c64xx_spi1_cfg_gpio(struct platform_device *dev)
{
- s3c_gpio_cfgpin(EXYNOS4_GPB(4), S3C_GPIO_SFN(2));
- s3c_gpio_setpull(EXYNOS4_GPB(4), S3C_GPIO_PULL_UP);
- s3c_gpio_cfgall_range(EXYNOS4_GPB(6), 2,
- S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP);
+ int gpio;
+
+ if (soc_is_exynos5250()) {
+ s3c_gpio_cfgpin(EXYNOS5_GPA2(4), S3C_GPIO_SFN(2));
+ s3c_gpio_setpull(EXYNOS5_GPA2(4), S3C_GPIO_PULL_UP);
+ s3c_gpio_cfgall_range(EXYNOS5_GPA2(6), 2,
+ S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP);
+
+ for (gpio = EXYNOS5_GPA2(4); gpio < EXYNOS5_GPA2(8); gpio++)
+ s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV3);
+ } else {
+ s3c_gpio_cfgpin(EXYNOS4_GPB(4), S3C_GPIO_SFN(2));
+ s3c_gpio_setpull(EXYNOS4_GPB(4), S3C_GPIO_PULL_UP);
+ s3c_gpio_cfgall_range(EXYNOS4_GPB(6), 2,
+ S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP);
+
+ for (gpio = EXYNOS4_GPB(4); gpio < EXYNOS4_GPB(8); gpio++)
+ s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV3);
+ }
+
return 0;
}
#endif
@@ -63,10 +156,26 @@
int s3c64xx_spi2_cfg_gpio(struct platform_device *dev)
{
- s3c_gpio_cfgpin(EXYNOS4_GPC1(1), S3C_GPIO_SFN(5));
- s3c_gpio_setpull(EXYNOS4_GPC1(1), S3C_GPIO_PULL_UP);
- s3c_gpio_cfgall_range(EXYNOS4_GPC1(3), 2,
- S3C_GPIO_SFN(5), S3C_GPIO_PULL_UP);
+ int gpio;
+
+ if (soc_is_exynos5250()) {
+ s3c_gpio_cfgpin(EXYNOS5_GPB1(1), S3C_GPIO_SFN(5));
+ s3c_gpio_setpull(EXYNOS5_GPB1(1), S3C_GPIO_PULL_UP);
+ s3c_gpio_cfgall_range(EXYNOS5_GPB1(3), 2,
+ S3C_GPIO_SFN(5), S3C_GPIO_PULL_UP);
+
+ for (gpio = EXYNOS5_GPB1(1); gpio < EXYNOS5_GPB1(5); gpio++)
+ s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV3);
+ } else {
+ s3c_gpio_cfgpin(EXYNOS4_GPC1(1), S3C_GPIO_SFN(5));
+ s3c_gpio_setpull(EXYNOS4_GPC1(1), S3C_GPIO_PULL_UP);
+ s3c_gpio_cfgall_range(EXYNOS4_GPC1(3), 2,
+ S3C_GPIO_SFN(5), S3C_GPIO_PULL_UP);
+
+ for (gpio = EXYNOS4_GPC1(1); gpio < EXYNOS4_GPC1(5); gpio++)
+ s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV3);
+ }
+
return 0;
}
#endif
diff --git a/arch/arm/mach-exynos/setup-tvout.c b/arch/arm/mach-exynos/setup-tvout.c
new file mode 100644
index 0000000..1d35e89
--- /dev/null
+++ b/arch/arm/mach-exynos/setup-tvout.c
@@ -0,0 +1,112 @@
+/* linux/arch/arm/mach-exynos/setup-tvout.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Base TVOUT gpio configuration
+ *
+ * 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.
+*/
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <plat/clock.h>
+#include <plat/gpio-cfg.h>
+#include <mach/regs-clock.h>
+#include <mach/regs-gpio.h>
+#include <linux/io.h>
+#include <mach/map.h>
+#include <mach/gpio.h>
+#include <plat/cpu.h>
+#include <plat/devs.h>
+#include <plat/tv-core.h>
+
+#if defined(CONFIG_ARCH_EXYNOS4)
+#define HDMI_GPX(_nr) EXYNOS4_GPX3(_nr)
+#elif defined(CONFIG_ARCH_EXYNOS5)
+#define HDMI_GPX(_nr) EXYNOS5_GPX3(_nr)
+#endif
+
+#define HDMI_PHY_CONTROL_OFFSET 0
+
+struct platform_device; /* don't need the contents */
+
+void s5p_int_src_hdmi_hpd(struct platform_device *pdev)
+{
+ s3c_gpio_cfgpin(HDMI_GPX(7), S3C_GPIO_SFN(0x3));
+ s3c_gpio_setpull(HDMI_GPX(7), S3C_GPIO_PULL_DOWN);
+}
+
+void s5p_int_src_ext_hpd(struct platform_device *pdev)
+{
+ s3c_gpio_cfgpin(HDMI_GPX(7), S3C_GPIO_SFN(0xf));
+ s3c_gpio_setpull(HDMI_GPX(7), S3C_GPIO_PULL_DOWN);
+}
+
+int s5p_hpd_read_gpio(struct platform_device *pdev)
+{
+ return gpio_get_value(HDMI_GPX(7));
+}
+
+int s5p_v4l2_hpd_read_gpio(void)
+{
+ return gpio_get_value(HDMI_GPX(7));
+}
+
+void s5p_v4l2_int_src_hdmi_hpd(void)
+{
+ s3c_gpio_cfgpin(HDMI_GPX(7), S3C_GPIO_SFN(0x3));
+ s3c_gpio_setpull(HDMI_GPX(7), S3C_GPIO_PULL_DOWN);
+}
+
+void s5p_v4l2_int_src_ext_hpd(void)
+{
+ s3c_gpio_cfgpin(HDMI_GPX(7), S3C_GPIO_SFN(0xf));
+ s3c_gpio_setpull(HDMI_GPX(7), S3C_GPIO_PULL_DOWN);
+}
+
+void s5p_cec_cfg_gpio(struct platform_device *pdev)
+{
+ s3c_gpio_cfgpin(HDMI_GPX(6), S3C_GPIO_SFN(0x3));
+ s3c_gpio_setpull(HDMI_GPX(6), S3C_GPIO_PULL_NONE);
+}
+
+void s5p_hdmiphy_enable(struct platform_device *pdev, int en)
+{
+ unsigned long val = readl(EXYNOS_HDMI_PHY_CONTROL);
+ if (en)
+ set_bit(HDMI_PHY_CONTROL_OFFSET, &val);
+ else
+ clear_bit(HDMI_PHY_CONTROL_OFFSET, &val);
+ writel(val, EXYNOS_HDMI_PHY_CONTROL);
+}
+
+#ifdef CONFIG_VIDEO_EXYNOS_TV
+void s5p_tv_setup(void)
+{
+ int ret;
+
+ /* direct HPD to HDMI chip */
+ ret = gpio_request(HDMI_GPX(7), "hpd-plug");
+ if (ret)
+ printk(KERN_ERR "failed to request HPD-plug\n");
+ gpio_direction_input(HDMI_GPX(7));
+ s3c_gpio_cfgpin(HDMI_GPX(7), S3C_GPIO_SFN(0xf));
+ s3c_gpio_setpull(HDMI_GPX(7), S3C_GPIO_PULL_NONE);
+
+ /* HDMI CEC */
+ ret = gpio_request(HDMI_GPX(6), "hdmi-cec");
+ if (ret)
+ printk(KERN_ERR "failed to request HDMI-CEC\n");
+ gpio_direction_input(HDMI_GPX(6));
+ s3c_gpio_cfgpin(HDMI_GPX(6), S3C_GPIO_SFN(0x3));
+ s3c_gpio_setpull(HDMI_GPX(6), S3C_GPIO_PULL_NONE);
+}
+#endif
diff --git a/arch/arm/mach-exynos/setup-usb-phy.c b/arch/arm/mach-exynos/setup-usb-phy.c
index 41743d2..9a76110 100644
--- a/arch/arm/mach-exynos/setup-usb-phy.c
+++ b/arch/arm/mach-exynos/setup-usb-phy.c
@@ -16,16 +16,160 @@
#include <linux/platform_device.h>
#include <mach/regs-pmu.h>
#include <mach/regs-usb-phy.h>
+#include <mach/regs-usb3-exynos-drd-phy.h>
#include <plat/cpu.h>
#include <plat/usb-phy.h>
+#include <plat/udc-hs.h>
+
+#define EXYNOS5_USB_CFG (S3C_VA_SYS + 0x230)
+#define PHY_ENABLE (1 << 0)
+#define PHY_DISABLE (0 << 0)
+
+enum usb_phy_type {
+ USB_PHY = (0x1 << 0),
+ USB_PHY0 = (0x1 << 0),
+ USB_PHY1 = (0x1 << 1),
+ USB_PHY_HSIC0 = (0x1 << 1),
+ USB_PHY_HSIC1 = (0x1 << 2),
+};
+
+struct exynos_usb_phy {
+ struct clk *phy_clk;
+ struct mutex phy_lock;
+ u32 flags;
+};
+
+static struct exynos_usb_phy usb_phy_control = {
+ .phy_lock = __MUTEX_INITIALIZER(usb_phy_control.phy_lock)
+};
static atomic_t host_usage;
+static void exynos_usb_mux_change(struct platform_device *pdev, int val)
+{
+ u32 is_host;
+
+ /*
+ * Exynos5250 has a USB 2.0 PHY for host and device.
+ * So, host and device cannot be used simultaneously except HSIC.
+ * USB mode can be changed by USB_CFG register.
+ * USB_CFG 1:host mode, 0:device mode.
+ */
+ is_host = readl(EXYNOS5_USB_CFG);
+ writel(val, EXYNOS5_USB_CFG);
+
+ if (is_host != val)
+ dev_dbg(&pdev->dev, "Change USB MUX from %s to %s",
+ is_host ? "Host" : "Device",
+ val ? "Host" : "Device");
+}
+
+static int exynos_usb_phy_clock_enable(struct platform_device *pdev)
+{
+ struct clk *clk;
+
+ if (!usb_phy_control.phy_clk) {
+ /*
+ * PHY clock domain is 'usbhost' on exynos5250.
+ * But, PHY clock domain is 'otg' on others.
+ */
+ if (soc_is_exynos5250())
+ clk = clk_get(&pdev->dev, "usbhost");
+ else
+ clk = clk_get(&pdev->dev, "otg");
+
+ if (IS_ERR(clk)) {
+ dev_err(&pdev->dev, "Failed to get phy clock\n");
+ return PTR_ERR(clk);
+ } else
+ usb_phy_control.phy_clk = clk;
+
+ }
+
+ return clk_enable(usb_phy_control.phy_clk);
+}
+
+static int exynos_usb_phy_clock_disable(struct platform_device *pdev)
+{
+ struct clk *clk;
+
+ if (!usb_phy_control.phy_clk) {
+ if (soc_is_exynos5250())
+ clk = clk_get(&pdev->dev, "usbhost");
+ else
+ clk = clk_get(&pdev->dev, "otg");
+ if (IS_ERR(clk)) {
+ dev_err(&pdev->dev, "Failed to get phy clock\n");
+ return PTR_ERR(clk);
+ } else
+ usb_phy_control.phy_clk = clk;
+ }
+
+ clk_disable(usb_phy_control.phy_clk);
+
+ return 0;
+}
+
+static u32 exynos_usb_phy_set_clock(struct platform_device *pdev)
+{
+ struct clk *ref_clk;
+ u32 refclk_freq = 0;
+
+ ref_clk = clk_get(&pdev->dev, "ext_xtal");
+
+ if (IS_ERR(ref_clk)) {
+ dev_err(&pdev->dev, "Failed to get reference clock\n");
+ return PTR_ERR(ref_clk);
+ }
+
+ switch (clk_get_rate(ref_clk)) {
+ case 96 * 100000:
+ refclk_freq = EXYNOS5_CLKSEL_9600K;
+ break;
+ case 10 * MHZ:
+ refclk_freq = EXYNOS5_CLKSEL_10M;
+ break;
+ case 12 * MHZ:
+ refclk_freq = EXYNOS5_CLKSEL_12M;
+ break;
+ case 192 * 100000:
+ refclk_freq = EXYNOS5_CLKSEL_19200K;
+ break;
+ case 20 * MHZ:
+ refclk_freq = EXYNOS5_CLKSEL_20M;
+ break;
+ case 50 * MHZ:
+ refclk_freq = EXYNOS5_CLKSEL_50M;
+ break;
+ case 24 * MHZ:
+ default:
+ /* default reference clock */
+ refclk_freq = EXYNOS5_CLKSEL_24M;
+ break;
+ }
+ clk_put(ref_clk);
+
+ return refclk_freq;
+}
+
static int exynos4_usb_host_phy_is_on(void)
{
return (readl(EXYNOS4_PHYPWR) & PHY1_STD_ANALOG_POWERDOWN) ? 0 : 1;
}
+static int exynos5_usb_host_phy20_is_on(void)
+{
+ return (readl(EXYNOS5_PHY_HOST_CTRL0) & HOST_CTRL0_PHYSWRSTALL) ? 0 : 1;
+}
+
+static void exynos_usb_phy_control(enum usb_phy_type phy_type , int on)
+{
+ if (phy_type & USB_PHY0)
+ writel(on, EXYNOS5_USBDEV_PHY_CONTROL);
+ if (phy_type & USB_PHY1)
+ writel(on, EXYNOS5_USBHOST_PHY_CONTROL);
+}
+
static int exynos4_usb_phy1_init(struct platform_device *pdev)
{
struct clk *otg_clk;
@@ -51,8 +195,9 @@
if (exynos4_usb_host_phy_is_on())
return 0;
- writel(readl(S5P_USBHOST_PHY_CONTROL) | S5P_USBHOST_PHY_ENABLE,
- S5P_USBHOST_PHY_CONTROL);
+ writel(readl(EXYNOS4210_USBHOST_PHY_CONTROL) |
+ EXYNOS4210_USBHOST_PHY_ENABLE,
+ EXYNOS4210_USBHOST_PHY_CONTROL);
/* set clock frequency for PLL */
phyclk = readl(EXYNOS4_PHYCLK) & ~CLKSEL_MASK;
@@ -125,8 +270,9 @@
writel((readl(EXYNOS4_PHYPWR) | PHY1_STD_ANALOG_POWERDOWN),
EXYNOS4_PHYPWR);
- writel(readl(S5P_USBHOST_PHY_CONTROL) & ~S5P_USBHOST_PHY_ENABLE,
- S5P_USBHOST_PHY_CONTROL);
+ writel(readl(EXYNOS4210_USBHOST_PHY_CONTROL) &
+ ~EXYNOS4210_USBHOST_PHY_ENABLE,
+ EXYNOS4210_USBHOST_PHY_CONTROL);
clk_disable(otg_clk);
clk_put(otg_clk);
@@ -134,18 +280,331 @@
return 0;
}
+static int exynos5_usb_phy20_init(struct platform_device *pdev)
+{
+ u32 refclk_freq;
+ u32 hostphy_ctrl0, otgphy_sys, hsic_ctrl, ehcictrl;
+
+ atomic_inc(&host_usage);
+
+ if (exynos5_usb_host_phy20_is_on()) {
+ dev_err(&pdev->dev, "Already power on PHY\n");
+ return 0;
+ }
+
+ exynos_usb_mux_change(pdev, 1);
+
+ exynos_usb_phy_control(USB_PHY1, PHY_ENABLE);
+
+ /* Host and Device should be set at the same time */
+ hostphy_ctrl0 = readl(EXYNOS5_PHY_HOST_CTRL0);
+ hostphy_ctrl0 &= ~(HOST_CTRL0_FSEL_MASK);
+ otgphy_sys = readl(EXYNOS5_PHY_OTG_SYS);
+ otgphy_sys &= ~(OTG_SYS_CTRL0_FSEL_MASK);
+
+ /* 2.0 phy reference clock configuration */
+ refclk_freq = exynos_usb_phy_set_clock(pdev);
+ hostphy_ctrl0 |= (refclk_freq << HOST_CTRL0_CLKSEL_SHIFT);
+ otgphy_sys |= (refclk_freq << OTG_SYS_CLKSEL_SHIFT);
+
+ /* COMMON Block configuration during suspend */
+ hostphy_ctrl0 &= ~(HOST_CTRL0_COMMONON_N);
+ otgphy_sys |= (OTG_SYS_COMMON_ON);
+
+ /* otg phy reset */
+ otgphy_sys &= ~(OTG_SYS_FORCE_SUSPEND |
+ OTG_SYS_SIDDQ_UOTG |
+ OTG_SYS_FORCE_SLEEP);
+ otgphy_sys &= ~(OTG_SYS_REF_CLK_SEL_MASK);
+ otgphy_sys |= (OTG_SYS_REF_CLK_SEL(0x2) | OTG_SYS_OTGDISABLE);
+ otgphy_sys |= (OTG_SYS_PHY0_SW_RST |
+ OTG_SYS_LINK_SW_RST_UOTG |
+ OTG_SYS_PHYLINK_SW_RESET);
+ writel(otgphy_sys, EXYNOS5_PHY_OTG_SYS);
+ udelay(10);
+ otgphy_sys &= ~(OTG_SYS_PHY0_SW_RST |
+ OTG_SYS_LINK_SW_RST_UOTG |
+ OTG_SYS_PHYLINK_SW_RESET);
+ writel(otgphy_sys, EXYNOS5_PHY_OTG_SYS);
+
+ /* host phy reset */
+ hostphy_ctrl0 &= ~(HOST_CTRL0_PHYSWRST |
+ HOST_CTRL0_PHYSWRSTALL |
+ HOST_CTRL0_SIDDQ);
+ hostphy_ctrl0 &= ~(HOST_CTRL0_FORCESUSPEND | HOST_CTRL0_FORCESLEEP);
+ hostphy_ctrl0 |= (HOST_CTRL0_LINKSWRST | HOST_CTRL0_UTMISWRST);
+ writel(hostphy_ctrl0, EXYNOS5_PHY_HOST_CTRL0);
+ udelay(10);
+ hostphy_ctrl0 &= ~(HOST_CTRL0_LINKSWRST | HOST_CTRL0_UTMISWRST);
+ writel(hostphy_ctrl0, EXYNOS5_PHY_HOST_CTRL0);
+
+ /* HSIC phy reset */
+ hsic_ctrl = (HSIC_CTRL_REFCLKDIV(0x24) | HSIC_CTRL_REFCLKSEL(0x2) |
+ HSIC_CTRL_PHYSWRST);
+ writel(hsic_ctrl, EXYNOS5_PHY_HSIC_CTRL1);
+ writel(hsic_ctrl, EXYNOS5_PHY_HSIC_CTRL2);
+ udelay(10);
+ hsic_ctrl &= ~(HSIC_CTRL_PHYSWRST);
+ writel(hsic_ctrl, EXYNOS5_PHY_HSIC_CTRL1);
+ writel(hsic_ctrl, EXYNOS5_PHY_HSIC_CTRL2);
+
+ udelay(80);
+
+ /* Enable DMA burst bus configuration */
+ ehcictrl = readl(EXYNOS5_PHY_HOST_EHCICTRL);
+ ehcictrl |= (EHCICTRL_ENAINCRXALIGN | EHCICTRL_ENAINCR4 |
+ EHCICTRL_ENAINCR8 | EHCICTRL_ENAINCR16);
+ writel(ehcictrl, EXYNOS5_PHY_HOST_EHCICTRL);
+
+ return 0;
+}
+
+static int exynos5_usb_phy20_exit(struct platform_device *pdev)
+{
+ u32 hostphy_ctrl0, otgphy_sys, hsic_ctrl;
+
+ if (atomic_dec_return(&host_usage) > 0) {
+ dev_info(&pdev->dev, "still being used\n");
+ return -EBUSY;
+ }
+
+ hsic_ctrl = (HSIC_CTRL_REFCLKDIV(0x24) |
+ HSIC_CTRL_REFCLKSEL(0x2) |
+ HSIC_CTRL_SIDDQ |
+ HSIC_CTRL_FORCESLEEP |
+ HSIC_CTRL_FORCESUSPEND);
+ writel(hsic_ctrl, EXYNOS5_PHY_HSIC_CTRL1);
+ writel(hsic_ctrl, EXYNOS5_PHY_HSIC_CTRL2);
+
+ hostphy_ctrl0 = readl(EXYNOS5_PHY_HOST_CTRL0);
+ hostphy_ctrl0 |= (HOST_CTRL0_SIDDQ);
+ hostphy_ctrl0 |= (HOST_CTRL0_FORCESUSPEND | HOST_CTRL0_FORCESLEEP);
+ hostphy_ctrl0 |= (HOST_CTRL0_PHYSWRST | HOST_CTRL0_PHYSWRSTALL);
+ writel(hostphy_ctrl0, EXYNOS5_PHY_HOST_CTRL0);
+
+ otgphy_sys = readl(EXYNOS5_PHY_OTG_SYS);
+ otgphy_sys |= (OTG_SYS_FORCE_SUSPEND |
+ OTG_SYS_SIDDQ_UOTG |
+ OTG_SYS_FORCE_SLEEP);
+ writel(otgphy_sys, EXYNOS5_PHY_OTG_SYS);
+
+ exynos_usb_phy_control(USB_PHY1, PHY_DISABLE);
+
+ return 0;
+}
+
+static int exynos_usb_dev_phy20_init(struct platform_device *pdev)
+{
+ if (exynos_usb_phy_clock_enable(pdev))
+ return -EINVAL;
+
+ exynos5_usb_phy20_init(pdev);
+
+ /* usb mode change from host to device */
+ exynos_usb_mux_change(pdev, 0);
+
+ exynos_usb_phy_clock_disable(pdev);
+
+ return 0;
+}
+
+static int exynos_usb_dev_phy20_exit(struct platform_device *pdev)
+{
+ if (exynos_usb_phy_clock_enable(pdev))
+ return -EINVAL;
+
+ exynos5_usb_phy20_exit(pdev);
+
+ /* usb mode change from device to host */
+ exynos_usb_mux_change(pdev, 1);
+
+ exynos_usb_phy_clock_disable(pdev);
+
+ return 0;
+}
+
+static int exynos5_usb_phy30_init(struct platform_device *pdev)
+{
+ u32 reg;
+
+ exynos_usb_phy_control(USB_PHY0, PHY_ENABLE);
+
+ /* Reset USB 3.0 PHY */
+ writel(0x087fffc0, EXYNOS_USB3_LINKSYSTEM);
+ writel(0x00000000, EXYNOS_USB3_PHYREG0);
+ writel(0x24d4e6e4, EXYNOS_USB3_PHYPARAM0);
+ writel(0x03fff820, EXYNOS_USB3_PHYPARAM1);
+ writel(0x00000000, EXYNOS_USB3_PHYBATCHG);
+ writel(0x00000000, EXYNOS_USB3_PHYRESUME);
+ /* REVISIT : Over-current pin is inactive on SMDK5250 */
+ if (soc_is_exynos5250())
+ writel((readl(EXYNOS_USB3_LINKPORT) & ~(0x3<<4)) |
+ (0x3<<2), EXYNOS_USB3_LINKPORT);
+
+ /* UTMI Power Control */
+ writel(EXYNOS_USB3_PHYUTMI_OTGDISABLE, EXYNOS_USB3_PHYUTMI);
+
+ /* Set 100MHz external clock */
+ reg = EXYNOS_USB3_PHYCLKRST_PORTRESET |
+ /* HS PLL uses ref_pad_clk{p,m} or ref_alt_clk_{p,m}
+ * as reference */
+ EXYNOS_USB3_PHYCLKRST_REFCLKSEL(2) |
+ /* Digital power supply in normal operating mode */
+ EXYNOS_USB3_PHYCLKRST_RETENABLEN |
+ /* 0x27-100MHz, 0x2a-24MHz, 0x31-20MHz, 0x38-19.2MHz */
+ EXYNOS_USB3_PHYCLKRST_FSEL(0x27) |
+ /* 0x19-100MHz, 0x68-24MHz, 0x7d-20Mhz */
+ EXYNOS_USB3_PHYCLKRST_MPLL_MULTIPLIER(0x19) |
+ /* Enable ref clock for SS function */
+ EXYNOS_USB3_PHYCLKRST_REF_SSP_EN |
+ /* Enable spread spectrum */
+ EXYNOS_USB3_PHYCLKRST_SSC_EN;
+
+ writel(reg, EXYNOS_USB3_PHYCLKRST);
+
+ udelay(10);
+
+ reg &= ~(EXYNOS_USB3_PHYCLKRST_PORTRESET);
+ writel(reg, EXYNOS_USB3_PHYCLKRST);
+
+ return 0;
+}
+
+static int exynos5_usb_phy30_exit(struct platform_device *pdev)
+{
+ u32 reg;
+
+ reg = EXYNOS_USB3_PHYUTMI_OTGDISABLE |
+ EXYNOS_USB3_PHYUTMI_FORCESUSPEND |
+ EXYNOS_USB3_PHYUTMI_FORCESLEEP;
+ writel(reg, EXYNOS_USB3_PHYUTMI);
+
+ exynos_usb_phy_control(USB_PHY0, PHY_DISABLE);
+
+ return 0;
+}
+
+static int s5p_usb_otg_phy_tune(struct s3c_hsotg_plat *pdata, int def_mode)
+{
+ u32 phytune;
+
+ if (!pdata)
+ return -EINVAL;
+
+ pr_debug("usb: %s read original tune\n", __func__);
+ phytune = readl(EXYNOS5_PHY_OTG_TUNE);
+ if (!pdata->def_phytune) {
+ pdata->def_phytune = phytune;
+ pr_debug("usb: %s save default phytune (0x%x)\n",
+ __func__, pdata->def_phytune);
+ }
+
+ pr_debug("usb: %s original tune=0x%x\n",
+ __func__, phytune);
+
+ pr_debug("usb: %s tune_mask=0x%x, tune=0x%x\n",
+ __func__, pdata->phy_tune_mask, pdata->phy_tune);
+
+ if (pdata->phy_tune_mask) {
+ if (def_mode) {
+ pr_debug("usb: %s set defult tune=0x%x\n",
+ __func__, pdata->def_phytune);
+ writel(pdata->def_phytune, EXYNOS5_PHY_OTG_TUNE);
+ } else {
+ phytune &= ~(pdata->phy_tune_mask);
+ phytune |= pdata->phy_tune;
+ udelay(10);
+ pr_debug("usb: %s custom tune=0x%x\n",
+ __func__, phytune);
+ writel(phytune, EXYNOS5_PHY_OTG_TUNE);
+ }
+ phytune = readl(EXYNOS5_PHY_OTG_TUNE);
+ pr_debug("usb: %s modified tune=0x%x\n",
+ __func__, phytune);
+ } else {
+ pr_debug("usb: %s default tune\n", __func__);
+ }
+
+ return 0;
+}
+
+static void set_exynos_usb_phy_tune(int type)
+{
+ u32 phytune;
+
+ if (!soc_is_exynos5250()) {
+ pr_debug("usb: %s it is not exynos5250.(t=%d)\n",
+ __func__, type);
+ return;
+ }
+
+ if (type == S5P_USB_PHY_DEVICE) {
+ phytune = readl(EXYNOS5_PHY_OTG_TUNE);
+ pr_debug("usb: %s old phy tune for device =0x%x\n",
+ __func__, phytune);
+ /* sqrxtune [13:11] 3b110 : -15% */
+ phytune &= ~OTG_TUNE_SQRXTUNE(0x7);
+ phytune |= OTG_TUNE_SQRXTUNE(0x6);
+ udelay(10);
+ writel(phytune, EXYNOS5_PHY_OTG_TUNE);
+ phytune = readl(EXYNOS5_PHY_OTG_TUNE);
+ pr_debug("usb: %s new phy tune for device =0x%x\n",
+ __func__, phytune);
+ } else if (type == S5P_USB_PHY_HOST) {
+ phytune = readl(EXYNOS5_PHY_HOST_TUNE0);
+ pr_debug("usb: %s old phy tune for host =0x%x\n",
+ __func__, phytune);
+ /* sqrxtune [14:12] 3b110 : -15% */
+ phytune &= ~HOST_TUNE0_SQRXTUNE(0x7);
+ phytune |= HOST_TUNE0_SQRXTUNE(0x6);
+ udelay(10);
+ writel(phytune, EXYNOS5_PHY_HOST_TUNE0);
+ phytune = readl(EXYNOS5_PHY_HOST_TUNE0);
+ pr_debug("usb: %s new phy tune for host =0x%x\n",
+ __func__, phytune);
+ }
+}
+
int s5p_usb_phy_init(struct platform_device *pdev, int type)
{
- if (type == S5P_USB_PHY_HOST)
- return exynos4_usb_phy1_init(pdev);
+ int ret = -EINVAL;
- return -EINVAL;
+ if (type == S5P_USB_PHY_HOST) {
+ if (soc_is_exynos5250()) {
+ ret = exynos5_usb_phy20_init(pdev);
+ set_exynos_usb_phy_tune(type);
+ } else {
+ ret = exynos4_usb_phy1_init(pdev);
+ }
+ } else if (type == S5P_USB_PHY_DEVICE) {
+ ret = exynos_usb_dev_phy20_init(pdev);
+ set_exynos_usb_phy_tune(type);
+ /* set custom usb phy tune */
+ if (pdev->dev.platform_data)
+ ret = s5p_usb_otg_phy_tune(pdev->dev.platform_data, 0);
+ } else if (type == S5P_USB_PHY_DRD)
+ ret = exynos5_usb_phy30_init(pdev);
+
+ return ret;
}
int s5p_usb_phy_exit(struct platform_device *pdev, int type)
{
- if (type == S5P_USB_PHY_HOST)
- return exynos4_usb_phy1_exit(pdev);
+ int ret = -EINVAL;
- return -EINVAL;
+ if (type == S5P_USB_PHY_HOST) {
+ if (soc_is_exynos5250())
+ ret = exynos5_usb_phy20_exit(pdev);
+ else
+ ret = exynos4_usb_phy1_exit(pdev);
+ } else if (type == S5P_USB_PHY_DEVICE) {
+ /* set custom usb phy tune */
+ if (pdev->dev.platform_data)
+ ret = s5p_usb_otg_phy_tune(pdev->dev.platform_data, 1);
+ ret = exynos_usb_dev_phy20_exit(pdev);
+ } else if (type == S5P_USB_PHY_DRD) {
+ ret = exynos5_usb_phy30_exit(pdev);
+ }
+
+ return ret;
}
diff --git a/arch/arm/mach-exynos/smc.S b/arch/arm/mach-exynos/smc.S
new file mode 100644
index 0000000..b9f3b33
--- /dev/null
+++ b/arch/arm/mach-exynos/smc.S
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2012 Google, Inc.
+ *
+ * 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.
+ */
+
+#include <linux/linkage.h>
+#include <linux/init.h>
+
+ENTRY(exynos_smc)
+ stmfd sp!, {lr}
+#if defined(CONFIG_ARM_ERRATA_766421)
+ dmb
+#endif
+ smc 0
+#if defined(CONFIG_ARM_ERRATA_766421)
+ dmb
+#endif
+ ldmfd sp!, {pc}
+ENDPROC(exynos_smc)
+
+ENTRY(exynos_smc_read_sfr)
+ stmfd sp!, {r4, lr}
+ mov r4, r2
+#if defined(CONFIG_ARM_ERRATA_766421)
+ dmb
+#endif
+ smc 0
+#if defined(CONFIG_ARM_ERRATA_766421)
+ dmb
+#endif
+ str r2, [r4]
+ ldmfd sp!, {r4, pc}
+ENDPROC(exynos_smc_read_sfr)
diff --git a/arch/arm/mach-exynos/tmu-exynos.c b/arch/arm/mach-exynos/tmu-exynos.c
new file mode 100644
index 0000000..58a31bf
--- /dev/null
+++ b/arch/arm/mach-exynos/tmu-exynos.c
@@ -0,0 +1,455 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * EXYNOS - Thermal Management support
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <linux/debugfs.h>
+
+#include <plat/cpu.h>
+
+#include <mach/regs-tmu.h>
+#include <mach/cpufreq.h>
+#include <mach/tmu.h>
+#include <mach/map.h>
+#include <mach/regs-mem.h>
+#include <mach/smc.h>
+
+static DEFINE_MUTEX(tmu_lock);
+
+static struct workqueue_struct *tmu_monitor_wq;
+
+static unsigned int get_refresh_period(unsigned int freq_ref)
+{
+ unsigned int rclk, tmp, refresh_nsec;
+
+ rclk = freq_ref / 1000000;
+
+#if defined(CONFIG_ARM_TRUSTZONE)
+ exynos_smc_read_sfr(SMC_CMD_REG,
+ SMC_REG_ID_SFR_R(EXYNOS5_PA_DREXII + EXYNOS_DMC_TIMINGAREF_OFFSET),
+ &tmp, 0);
+#else
+ tmp = __raw_readl(S5P_VA_DREXII + EXYNOS_DMC_TIMINGAREF_OFFSET);
+#endif
+ refresh_nsec = ((tmp & 0xff) * 1000) / rclk;
+
+ return refresh_nsec;
+}
+
+static void set_refresh_period(unsigned int freq_ref,
+ unsigned int refresh_nsec)
+{
+ unsigned int rclk, auto_refresh;
+
+ rclk = freq_ref / 1000000;
+ auto_refresh = ((unsigned int)(rclk * refresh_nsec / 1000));
+
+ /* change auto refresh period in TIMING_AREF register of DMC */
+#if defined(CONFIG_ARM_TRUSTZONE)
+ exynos_smc(SMC_CMD_REG,
+ SMC_REG_ID_SFR_W(EXYNOS5_PA_DREXII + EXYNOS_DMC_TIMINGAREF_OFFSET),
+ auto_refresh, 0);
+#else
+ __raw_writel(auto_refresh, S5P_VA_DREXII +
+ EXYNOS_DMC_TIMING_AREF_OFFSET);
+#endif
+}
+
+static int get_cur_temp(struct tmu_info *info)
+{
+ int curr_temp;
+ int temperature;
+
+ curr_temp = __raw_readl(info->tmu_base + CURRENT_TEMP) & 0xff;
+
+ /* compensate and calculate current temperature */
+ temperature = curr_temp - info->te1 + TMU_DC_VALUE;
+
+ return temperature;
+}
+
+static void tmu_monitor(struct work_struct *work)
+{
+ struct delayed_work *delayed_work = to_delayed_work(work);
+ struct tmu_info *info =
+ container_of(delayed_work, struct tmu_info, polling);
+ struct tmu_data *data = info->dev->platform_data;
+ int cur_temp;
+
+ cur_temp = get_cur_temp(info);
+
+ dev_dbg(info->dev, "Current: %dc, FLAG=%d\n", cur_temp, info->tmu_state);
+
+ mutex_lock(&tmu_lock);
+ switch (info->tmu_state) {
+ case TMU_STATUS_NORMAL:
+ exynos_thermal_unthrottle();
+ enable_irq(info->irq);
+ goto out;
+ case TMU_STATUS_THROTTLED:
+ if (cur_temp >= data->ts.start_tripping)
+ info->tmu_state = TMU_STATUS_TRIPPED;
+ else if (cur_temp > data->ts.stop_throttle)
+ exynos_thermal_throttle();
+ else
+ info->tmu_state = TMU_STATUS_NORMAL;
+ break;
+ case TMU_STATUS_TRIPPED:
+ if (cur_temp >= data->ts.start_emergency)
+ panic("Emergency thermal shutdown: temp=%d\n",
+ cur_temp);
+ if (cur_temp >= data->ts.start_tripping)
+ pr_err("thermal tripped: temp=%d\n", cur_temp);
+ else
+ info->tmu_state = TMU_STATUS_THROTTLED;
+ break;
+ default:
+ break;
+ }
+
+ /* Memory throttling */
+ if (cur_temp >= data->ts.start_mem_throttle &&
+ !info->mem_throttled) {
+ set_refresh_period(FREQ_IN_PLL, info->auto_refresh_mem_throttle);
+ info->mem_throttled = true;
+ dev_dbg(info->dev, "set auto refresh period %dns\n",
+ info->auto_refresh_mem_throttle);
+ } else if (cur_temp <= data->ts.stop_mem_throttle &&
+ info->mem_throttled) {
+ set_refresh_period(FREQ_IN_PLL, info->auto_refresh_normal);
+ info->mem_throttled = false;
+ dev_dbg(info->dev, "set auto refresh period %dns\n",
+ info->auto_refresh_normal);
+ }
+
+ queue_delayed_work_on(0, tmu_monitor_wq,
+ &info->polling, info->sampling_rate);
+out:
+ mutex_unlock(&tmu_lock);
+}
+
+static void pm_tmu_save(struct tmu_info *info)
+{
+ info->reg_save[0] = __raw_readl(info->tmu_base + TMU_CON);
+ info->reg_save[1] = __raw_readl(info->tmu_base + SAMPLING_INTERNAL);
+ info->reg_save[2] = __raw_readl(info->tmu_base + CNT_VALUE0);
+ info->reg_save[3] = __raw_readl(info->tmu_base + CNT_VALUE1);
+ info->reg_save[4] = __raw_readl(info->tmu_base + INTEN);
+ info->reg_save[5] = __raw_readl(info->tmu_base + THD_TEMP_RISE);
+}
+
+static void pm_tmu_restore(struct tmu_info *info)
+{
+ __raw_writel(info->reg_save[5], info->tmu_base + THD_TEMP_RISE);
+ __raw_writel(info->reg_save[4], info->tmu_base + INTEN);
+ __raw_writel(info->reg_save[3], info->tmu_base + CNT_VALUE1);
+ __raw_writel(info->reg_save[2], info->tmu_base + CNT_VALUE0);
+ __raw_writel(info->reg_save[1], info->tmu_base + SAMPLING_INTERNAL);
+ __raw_writel(info->reg_save[0], info->tmu_base + TMU_CON);
+}
+
+static int exynos_tmu_init(struct tmu_info *info)
+{
+ struct tmu_data *data = info->dev->platform_data;
+ unsigned int te_temp, con;
+ unsigned int temp_throttle, temp_trip;
+ unsigned int rising_thr;
+
+ /* must reload for using efuse value at EXYNOS4212 */
+ __raw_writel(TRIMINFO_RELOAD, info->tmu_base + TRIMINFO_CON);
+
+ /* get the compensation parameter */
+ te_temp = __raw_readl(info->tmu_base + TRIMINFO);
+ info->te1 = te_temp & TRIM_INFO_MASK;
+ info->te2 = ((te_temp >> 8) & TRIM_INFO_MASK);
+
+ if ((EFUSE_MIN_VALUE > info->te1)
+ || (info->te1 > EFUSE_MAX_VALUE)
+ || (info->te2 != 0))
+ info->te1 = data->efuse_value;
+
+ /* Map auto refresh period of normal & memory throttle mode */
+ info->auto_refresh_normal = get_refresh_period(FREQ_IN_PLL);
+ info->auto_refresh_mem_throttle = info->auto_refresh_normal / 2;
+
+ dev_info(info->dev, "Current auto refresh interval(%d nsec),"
+ " Normal auto refresh interval(%d nsec),"
+ " memory throttle auto refresh internal(%d nsec)\n",
+ get_refresh_period(FREQ_IN_PLL),
+ info->auto_refresh_normal, info->auto_refresh_mem_throttle);
+
+ /*Get rising Threshold and Set interrupt level*/
+ temp_throttle = data->ts.start_throttle
+ + info->te1 - TMU_DC_VALUE;
+ temp_trip = data->ts.start_tripping
+ + info->te1 - TMU_DC_VALUE;
+
+ rising_thr = (temp_throttle | (temp_trip << 8) |
+ (UNUSED_THRESHOLD << 16) | (UNUSED_THRESHOLD << 24));
+
+ __raw_writel(rising_thr, info->tmu_base + THD_TEMP_RISE);
+
+ /* Set TMU status */
+ info->tmu_state = TMU_STATUS_INIT;
+
+ /* To poll current temp, set sampling rate */
+ info->sampling_rate = msecs_to_jiffies(1000);
+
+ /* Need to initail regsiter setting after getting parameter info */
+ /* [28:23] vref [11:8] slope - Tunning parameter */
+ __raw_writel(data->slope, info->tmu_base + TMU_CON);
+
+ __raw_writel((CLEAR_RISE_INT | CLEAR_FALL_INT), info->tmu_base + INTCLEAR);
+
+ /* TMU core enable */
+ con = __raw_readl(info->tmu_base + TMU_CON);
+ con |= (MUX_ADDR_VALUE << 20 | CORE_EN);
+
+ __raw_writel(con, info->tmu_base + TMU_CON);
+
+ /* Because temperature sensing time is appro 940us,
+ * tmu is enabled and 1st valid sample can get 1ms after.
+ */
+ mdelay(1);
+
+ /*LEV0 LEV1 interrupt enable */
+ __raw_writel(INTEN_RISE0 | INTEN_RISE1, info->tmu_base + INTEN);
+
+ return 0;
+}
+
+static irqreturn_t tmu_irq(int irq, void *id)
+{
+ struct tmu_info *info = id;
+ unsigned int status;
+
+ disable_irq_nosync(irq);
+
+ status = __raw_readl(info->tmu_base + INTSTAT);
+ /* To handle multiple interrupt pending,
+ * interrupt by high temperature are serviced with priority.
+ */
+ if (status & INTSTAT_RISE1) {
+ dev_info(info->dev, "Tripping interrupt\n");
+ info->tmu_state = TMU_STATUS_TRIPPED;
+ __raw_writel(INTCLEAR_RISE1, info->tmu_base + INTCLEAR);
+ } else if (status & INTSTAT_RISE0) {
+ dev_info(info->dev, "Throttling interrupt\n");
+ __raw_writel(INTCLEAR_RISE0, info->tmu_base + INTCLEAR);
+ info->tmu_state = TMU_STATUS_THROTTLED;
+ } else {
+ dev_err(info->dev, "%s: TMU interrupt error. INTSTAT : %x\n", __func__, status);
+ __raw_writel(status, info->tmu_base + INTCLEAR);
+ return IRQ_HANDLED;
+ }
+
+ queue_delayed_work_on(0, tmu_monitor_wq, &info->polling, usecs_to_jiffies(0));
+
+ return IRQ_HANDLED;
+}
+
+static struct dentry *tmu_debugfs;
+
+static int tmu_debug_show(struct seq_file *s, void *unused)
+{
+ struct tmu_info *info = s->private;
+ char *cur_tmu_state;
+
+ seq_printf(s, "Current Temperature : %d\n", get_cur_temp(info));
+ switch (info->tmu_state) {
+ case TMU_STATUS_INIT:
+ case TMU_STATUS_NORMAL:
+ cur_tmu_state = "TMU_STATUS_NORMAL";
+ break;
+ case TMU_STATUS_THROTTLED:
+ cur_tmu_state = "TMU_STATUS_THROTTLED";
+ break;
+ case TMU_STATUS_TRIPPED:
+ cur_tmu_state = "TMU_STATUS_TRIPPED";
+ break;
+ default:
+ cur_tmu_state = "INVALID STATUS";
+ break;
+ }
+ seq_printf(s, "Current TMU State : %s\n", cur_tmu_state);
+ seq_printf(s, "Memory Throttling : %s\n",
+ info->mem_throttled ? "throttled" : "unthrottled");
+ seq_printf(s, "Memory throttle auto refresh time : %d ns\n",
+ info->auto_refresh_mem_throttle);
+ seq_printf(s, "Normal auto refresh time : %d ns\n", info->auto_refresh_normal);
+ seq_printf(s, "TMU monitoring sample rate : %d ms\n",
+ info->sampling_rate);
+
+ return 0;
+}
+
+static int tmu_debug_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, tmu_debug_show, inode->i_private);
+}
+
+const static struct file_operations tmu_dev_status_fops = {
+ .open = tmu_debug_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int __devinit tmu_probe(struct platform_device *pdev)
+{
+ struct tmu_info *info;
+ struct resource *res;
+ int ret;
+
+ if (dev_get_platdata(&pdev->dev) == NULL) {
+ dev_err(&pdev->dev, "No platform data\n");
+ ret = -ENODEV;
+ goto err_out;
+ }
+
+ info = devm_kzalloc(&pdev->dev, sizeof(struct tmu_info), GFP_KERNEL);
+ if (info == NULL) {
+ dev_err(&pdev->dev, "failed to alloc memory!\n");
+ ret = -ENOMEM;
+ goto err_out;
+ }
+
+ info->dev = &pdev->dev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "failed to get memory region resource\n");
+ ret = -ENODEV;
+ goto err_out;
+ }
+
+ info->tmu_base = devm_request_and_ioremap(&pdev->dev, res);
+ if (info->tmu_base == NULL) {
+ dev_err(&pdev->dev, "failed ioremap()\n");
+ ret = -ENOMEM;
+ goto err_out;
+ }
+
+ INIT_DELAYED_WORK_DEFERRABLE(&info->polling, tmu_monitor);
+
+ tmu_monitor_wq = create_freezable_workqueue("tmu");
+ if (!tmu_monitor_wq) {
+ dev_err(&pdev->dev, "Creation of tmu_monitor_wq failed\n");
+ ret = -EFAULT;
+ goto err_out;
+ }
+
+ info->irq = platform_get_irq(pdev, 0);
+ if (info->irq < 0) {
+ dev_err(&pdev->dev, "no irq for thermal\n");
+ ret = info->irq;
+ goto err_wq;
+ }
+
+ platform_set_drvdata(pdev, info);
+
+ ret = exynos_tmu_init(info);
+ if (ret < 0)
+ goto err_noinit;
+
+ ret = request_irq(info->irq, tmu_irq,
+ IRQF_DISABLED, "tmu", info);
+ if (ret) {
+ dev_err(&pdev->dev, "IRQ%d error %d\n", info->irq, ret);
+ ret = -EBUSY;
+ goto err_noinit;
+ }
+
+ tmu_debugfs =
+ debugfs_create_file("tmu_dev_status",
+ S_IRUGO, NULL, info, &tmu_dev_status_fops);
+ if (IS_ERR_OR_NULL(tmu_debugfs)) {
+ tmu_debugfs = NULL;
+ dev_err(&pdev->dev, "%s: debugfs_create_file() failed\n", __func__);
+ goto err_nodbgfs;
+ }
+
+ dev_info(&pdev->dev, "Tmu Initialization is sucessful...!\n");
+ return 0;
+
+err_nodbgfs:
+ free_irq(info->irq, NULL);
+err_noinit:
+ platform_set_drvdata(pdev, NULL);
+err_wq:
+ destroy_workqueue(tmu_monitor_wq);
+err_out:
+ dev_err(&pdev->dev, "initialization failed.\n");
+ return ret;
+}
+
+static int __devexit tmu_remove(struct platform_device *pdev)
+{
+ struct tmu_info *info = platform_get_drvdata(pdev);
+
+ cancel_delayed_work_sync(&info->polling);
+ disable_irq(info->irq);
+ free_irq(info->irq, info);
+ debugfs_remove(tmu_debugfs);
+ destroy_workqueue(tmu_monitor_wq);
+
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int tmu_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct tmu_info *info = platform_get_drvdata(pdev);
+
+ pm_tmu_save(info);
+ return 0;
+}
+
+static int tmu_resume(struct platform_device *pdev)
+{
+ struct tmu_info *info = platform_get_drvdata(pdev);
+
+ pm_tmu_restore(info);
+ return 0;
+}
+
+#else
+#define tmu_suspend NULL
+#define tmu_resume NULL
+#endif
+
+static struct platform_driver tmu_driver = {
+ .probe = tmu_probe,
+ .remove = __devexit_p(tmu_remove),
+ .suspend = tmu_suspend,
+ .resume = tmu_resume,
+ .driver = {
+ .name = "exynos_tmu",
+ .owner = THIS_MODULE,
+ },
+};
+
+module_platform_driver(tmu_driver);
+
diff --git a/arch/arm/mach-s3c24xx/include/mach/dma.h b/arch/arm/mach-s3c24xx/include/mach/dma.h
index acbdfec..c8716a0 100644
--- a/arch/arm/mach-s3c24xx/include/mach/dma.h
+++ b/arch/arm/mach-s3c24xx/include/mach/dma.h
@@ -60,6 +60,11 @@
return false;
}
+static inline bool samsung_dma_has_infiniteloop(void)
+{
+ return false;
+}
+
#include <plat/dma.h>
#define DMACH_LOW_LEVEL (1<<28) /* use this to specifiy hardware ch no */
diff --git a/arch/arm/mach-s3c64xx/include/mach/dma.h b/arch/arm/mach-s3c64xx/include/mach/dma.h
index fe1a98c..06acb91 100644
--- a/arch/arm/mach-s3c64xx/include/mach/dma.h
+++ b/arch/arm/mach-s3c64xx/include/mach/dma.h
@@ -67,6 +67,11 @@
{
return false;
}
+
+static inline bool samsung_dma_has_infiniteloop(void)
+{
+ return false;
+}
#define S3C2410_DMAF_CIRCULAR (1 << 0)
#include <plat/dma.h>
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index 7c8a7d8..14cb38a 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -629,6 +629,16 @@
comment "Processor Features"
+config ARM_TRUSTZONE
+ bool "Support TrustZone-enabled Trusted Execution Environment"
+ default n
+ help
+ Select if you want a kernel to be executed at non-secure world.
+ This option should be used with related secure bootloader and
+ TrustZone software.
+
+ If you don't know about TrustZone, say 'N'.
+
config ARM_LPAE
bool "Support for the Large Physical Address Extension"
depends on MMU && CPU_32v7 && !CPU_32v6 && !CPU_32v5 && \
diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile
index 37da2cc..3c3e047 100644
--- a/arch/arm/mm/Makefile
+++ b/arch/arm/mm/Makefile
@@ -95,7 +95,8 @@
obj-$(CONFIG_CPU_V7) += proc-v7.o
AFLAGS_proc-v6.o :=-Wa,-march=armv6
-AFLAGS_proc-v7.o :=-Wa,-march=armv7-a
+plus_sec := $(call as-instr,.arch_extension sec,+sec)
+AFLAGS_proc-v7.o :=-Wa,-march=armv7-a$(plus_sec)
obj-$(CONFIG_CACHE_FEROCEON_L2) += cache-feroceon-l2.o
obj-$(CONFIG_CACHE_L2X0) += cache-l2x0.o
diff --git a/arch/arm/mm/proc-v7-2level.S b/arch/arm/mm/proc-v7-2level.S
index 42ac069..05d8fe5 100644
--- a/arch/arm/mm/proc-v7-2level.S
+++ b/arch/arm/mm/proc-v7-2level.S
@@ -48,6 +48,8 @@
#endif
#ifdef CONFIG_ARM_ERRATA_754322
dsb
+#elif CONFIG_ARM_ERRATA_766421
+ dmb
#endif
mcr p15, 0, r1, c13, c0, 1 @ set context ID
isb
diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S
index c2e2b66..4594319 100644
--- a/arch/arm/mm/proc-v7.S
+++ b/arch/arm/mm/proc-v7.S
@@ -17,6 +17,8 @@
#include <asm/pgtable-hwdef.h>
#include <asm/pgtable.h>
+#include <mach/smc.h>
+
#include "proc-macros.S"
#ifdef CONFIG_ARM_LPAE
@@ -208,7 +210,7 @@
orreq r10, r10, #(1 << 22) @ set the Write Allocate disable bit
mcreq p15, 1, r10, c9, c0, 2 @ write the L2 cache aux ctrl register
#endif
- b 3f
+ b 4f
/* Cortex-A9 Errata */
2: ldr r10, =0x00000c09 @ Cortex-A9 primary part number
@@ -243,8 +245,48 @@
mcrlt p15, 0, r10, c15, c0, 1 @ write diagnostic register
1:
#endif
+ b 4f
-3: mov r10, #0
+ /* Cortex-A15 Errata */
+3: ldr r10, =0x00000c0f @ Cortex-A15 primary part number
+ teq r0, r10
+ bne 4f
+
+#ifdef CONFIG_ARM_TRUSTZONE
+ stmia r12, {r0-r3}
+ mov r3, #0
+#endif
+#ifdef CONFIG_ARM_ERRATA_773022
+ teq r6, #0x4 @ present in r0p4
+ mrceq p15, 0, r10, c1, c0, 1 @ read aux control register
+ orreq r10, r10, #1 << 1 @ set bit #1
+#ifdef CONFIG_ARM_TRUSTZONE
+ ldreq r0, =SMC_CMD_REG
+ ldreq r1, =SMC_REG_ID_CP15(1, 0, 0, 1)
+ moveq r2, r10
+ smceq 0
+#else
+ mcreq p15, 0, r10, c1, c0, 1 @ write aux control register
+#endif
+#endif
+#ifdef CONFIG_ARM_ERRATA_774769
+ teq r6, #0x4 @ present in r0p4
+ mrceq p15, 0, r10, c1, c0, 1 @ read aux control register
+ orreq r10, r10, #1 << 25 @ set bit #25
+#ifdef CONFIG_ARM_TRUSTZONE
+ ldreq r0, =SMC_CMD_REG
+ ldreq r1, =SMC_REG_ID_CP15(1, 0, 0, 1)
+ moveq r2, r10
+ smceq 0
+#else
+ mcreq p15, 0, r10, c1, c0, 1 @ write aux control register
+#endif
+#endif
+#ifdef CONFIG_ARM_TRUSTZONE
+ ldmia r12, {r0-r3}
+#endif
+
+4: mov r10, #0
mcr p15, 0, r10, c7, c5, 0 @ I+BTB cache invalidate
dsb
#ifdef CONFIG_MMU
diff --git a/arch/arm/plat-s5p/Kconfig b/arch/arm/plat-s5p/Kconfig
index 96bea32..73e9652 100644
--- a/arch/arm/plat-s5p/Kconfig
+++ b/arch/arm/plat-s5p/Kconfig
@@ -50,14 +50,6 @@
Common code for power management support on S5P and newer SoCs
Note: Do not select this for S5P6440 and S5P6450.
-comment "System MMU"
-
-config S5P_SYSTEM_MMU
- bool "S5P SYSTEM MMU"
- depends on ARCH_EXYNOS4
- help
- Say Y here if you want to enable System MMU
-
config S5P_SLEEP
bool
help
@@ -99,6 +91,11 @@
help
Compile in platform device definitions for FIMD controller 0
+config S5P_DEV_FIMD1
+ bool
+ help
+ Compile in platform device definitions for FIMD controller 1
+
config S5P_DEV_I2C_HDMIPHY
bool
help
@@ -116,11 +113,15 @@
config S5P_DEV_CSIS0
bool
+ depends on (VIDEO_S5P_MIPI_CSIS || VIDEO_EXYNOS_MIPI_CSIS)
+ default y
help
Compile in platform device definitions for MIPI-CSIS channel 0
config S5P_DEV_CSIS1
bool
+ depends on (VIDEO_S5P_MIPI_CSIS || VIDEO_EXYNOS_MIPI_CSIS)
+ default y
help
Compile in platform device definitions for MIPI-CSIS channel 1
@@ -136,5 +137,12 @@
config S5P_SETUP_MIPIPHY
bool
+ depends on (VIDEO_S5P_MIPI_CSIS || VIDEO_EXYNOS_MIPI_CSIS)
+ default y
help
Compile in common setup code for MIPI-CSIS and MIPI-DSIM devices
+
+config S5P_DEV_ACE
+ bool
+ help
+ Compile in common setup code for Crypto Engine devices.
diff --git a/arch/arm/plat-s5p/Makefile b/arch/arm/plat-s5p/Makefile
index 4bd8241..aa112ee 100644
--- a/arch/arm/plat-s5p/Makefile
+++ b/arch/arm/plat-s5p/Makefile
@@ -16,7 +16,6 @@
obj-y += irq.o
obj-$(CONFIG_S5P_EXT_INT) += irq-eint.o
obj-$(CONFIG_S5P_GPIO_INT) += irq-gpioint.o
-obj-$(CONFIG_S5P_SYSTEM_MMU) += sysmmu.o
obj-$(CONFIG_S5P_PM) += pm.o irq-pm.o
obj-$(CONFIG_S5P_SLEEP) += sleep.o
obj-$(CONFIG_S5P_HRT) += s5p-time.o
@@ -26,3 +25,6 @@
obj-$(CONFIG_S5P_DEV_UART) += dev-uart.o
obj-$(CONFIG_S5P_DEV_MFC) += dev-mfc.o
obj-$(CONFIG_S5P_SETUP_MIPIPHY) += setup-mipiphy.o
+obj-$(CONFIG_S5P_DEV_ACE) += dev-ace.o
+obj-$(CONFIG_S5P_DEV_CSIS0) += dev-csis0.o
+obj-$(CONFIG_S5P_DEV_CSIS1) += dev-csis1.o
diff --git a/arch/arm/plat-s5p/clock.c b/arch/arm/plat-s5p/clock.c
index f68a9bb..8a67565 100644
--- a/arch/arm/plat-s5p/clock.c
+++ b/arch/arm/plat-s5p/clock.c
@@ -40,6 +40,11 @@
.id = -1,
};
+struct clk clk_xxti= {
+ .name = "xxti",
+ .id = -1,
+};
+
struct clk s5p_clk_27m = {
.name = "clk_27m",
.id = -1,
@@ -209,7 +214,7 @@
struct clk *pclk;
int ret;
- pclk = clk_get_parent(clk);
+ pclk = __clk_get_parent(clk);
if (IS_ERR(pclk))
return -EINVAL;
@@ -224,7 +229,7 @@
struct clk *pclk;
int rate;
- pclk = clk_get_parent(clk);
+ pclk = __clk_get_parent(clk);
if (IS_ERR(pclk))
return -EINVAL;
@@ -250,6 +255,7 @@
&clk_fout_vpll,
&clk_vpll,
&clk_xusbxti,
+ &clk_xxti,
};
void __init s5p_register_clocks(unsigned long xtal_freq)
diff --git a/arch/arm/plat-s5p/dev-ace.c b/arch/arm/plat-s5p/dev-ace.c
new file mode 100644
index 0000000..fe5a3e6
--- /dev/null
+++ b/arch/arm/plat-s5p/dev-ace.c
@@ -0,0 +1,47 @@
+/*
+ * linux/arch/arm/plat-s5p/dev-ace.c
+ *
+ * Copyright (C) 2011 Samsung Electronics
+ *
+ * Base S5P Crypto Engine resource and device definitions
+ *
+ * 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.
+ */
+
+#include <linux/platform_device.h>
+
+#include <mach/map.h>
+#include <mach/irqs.h>
+
+#include <asm/sizes.h>
+
+static struct resource s5p_ace_resource[] = {
+ [0] = {
+ .start = S5P_PA_ACE,
+ .end = S5P_PA_ACE + SZ_32K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+#if defined(CONFIG_ARCH_S5PV210)
+ [1] = {
+ .start = IRQ_SSS_INT,
+ .end = IRQ_SSS_HASH,
+ .flags = IORESOURCE_IRQ,
+ },
+#elif defined(CONFIG_ARCH_EXYNOS4) || defined(CONFIG_ARCH_EXYNOS5)
+ [1] = {
+ .start = IRQ_INTFEEDCTRL_SSS,
+ .end = IRQ_INTFEEDCTRL_SSS,
+ .flags = IORESOURCE_IRQ,
+ },
+#endif
+};
+
+struct platform_device s5p_device_ace = {
+ .name = "s5p-ace",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(s5p_ace_resource),
+ .resource = s5p_ace_resource,
+};
+EXPORT_SYMBOL(s5p_device_ace);
diff --git a/arch/arm/plat-s5p/dev-csis0.c b/arch/arm/plat-s5p/dev-csis0.c
new file mode 100644
index 0000000..6531c1c
--- /dev/null
+++ b/arch/arm/plat-s5p/dev-csis0.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * S5P series device definition for MIPI-CSIS channel 0
+ *
+ * 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.
+*/
+
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <mach/map.h>
+#include <plat/mipi_csis.h>
+#include <asm-generic/sizes.h>
+
+static struct resource s5p_mipi_csis0_resource[] = {
+ [0] = {
+ .start = S5P_PA_MIPI_CSIS0,
+ .end = S5P_PA_MIPI_CSIS0 + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_MIPICSI0,
+ .end = IRQ_MIPICSI0,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+struct platform_device s5p_device_mipi_csis0 = {
+ .name = "s5p-mipi-csis",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(s5p_mipi_csis0_resource),
+ .resource = s5p_mipi_csis0_resource,
+};
+
+struct s5p_platform_mipi_csis s5p_mipi_csis0_default_data __initdata = {
+ .clk_rate = 166000000,
+ .lanes = 2,
+ .alignment = 32,
+ .hs_settle = 12,
+ .phy_enable = s5p_csis_phy_enable,
+};
diff --git a/arch/arm/plat-s5p/dev-csis1.c b/arch/arm/plat-s5p/dev-csis1.c
new file mode 100644
index 0000000..8e57bc5
--- /dev/null
+++ b/arch/arm/plat-s5p/dev-csis1.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * S5P series device definition for MIPI-CSIS channel 1
+ *
+ * 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.
+*/
+
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <mach/map.h>
+#include <plat/mipi_csis.h>
+#include <asm-generic/sizes.h>
+
+static struct resource s5p_mipi_csis1_resource[] = {
+ [0] = {
+ .start = S5P_PA_MIPI_CSIS1,
+ .end = S5P_PA_MIPI_CSIS1 + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_MIPICSI1,
+ .end = IRQ_MIPICSI1,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device s5p_device_mipi_csis1 = {
+ .name = "s5p-mipi-csis",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(s5p_mipi_csis1_resource),
+ .resource = s5p_mipi_csis1_resource,
+};
+
+struct s5p_platform_mipi_csis s5p_mipi_csis1_default_data __initdata = {
+ .clk_rate = 166000000,
+ .lanes = 2,
+ .alignment = 32,
+ .hs_settle = 12,
+ .phy_enable = s5p_csis_phy_enable,
+};
diff --git a/arch/arm/plat-s5p/irq-eint.c b/arch/arm/plat-s5p/irq-eint.c
index 139c050..d3eb5c9 100644
--- a/arch/arm/plat-s5p/irq-eint.c
+++ b/arch/arm/plat-s5p/irq-eint.c
@@ -115,6 +115,11 @@
else
printk(KERN_ERR "No such irq number %d", offs);
+ if (type & IRQ_TYPE_EDGE_BOTH)
+ __irq_set_handler_locked(data->irq, handle_edge_irq);
+ else
+ __irq_set_handler_locked(data->irq, handle_level_irq);
+
return 0;
}
diff --git a/arch/arm/plat-s5p/irq-gpioint.c b/arch/arm/plat-s5p/irq-gpioint.c
index 82c7311..d3765ac 100644
--- a/arch/arm/plat-s5p/irq-gpioint.c
+++ b/arch/arm/plat-s5p/irq-gpioint.c
@@ -74,6 +74,12 @@
gc->type_cache &= ~(0x7 << shift);
gc->type_cache |= type << shift;
writel(gc->type_cache, gc->reg_base + ct->regs.type);
+
+ if (type & IRQ_TYPE_EDGE_BOTH)
+ __irq_set_handler_locked(d->irq, handle_edge_irq);
+ else
+ __irq_set_handler_locked(d->irq, handle_level_irq);
+
return 0;
}
diff --git a/arch/arm/plat-s5p/sysmmu.c b/arch/arm/plat-s5p/sysmmu.c
deleted file mode 100644
index c8bec9c..0000000
--- a/arch/arm/plat-s5p/sysmmu.c
+++ /dev/null
@@ -1,313 +0,0 @@
-/* linux/arch/arm/plat-s5p/sysmmu.c
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- * http://www.samsung.com
- *
- * 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.
- */
-
-#include <linux/io.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <linux/export.h>
-
-#include <asm/pgtable.h>
-
-#include <mach/map.h>
-#include <mach/regs-sysmmu.h>
-#include <plat/sysmmu.h>
-
-#define CTRL_ENABLE 0x5
-#define CTRL_BLOCK 0x7
-#define CTRL_DISABLE 0x0
-
-static struct device *dev;
-
-static unsigned short fault_reg_offset[SYSMMU_FAULTS_NUM] = {
- S5P_PAGE_FAULT_ADDR,
- S5P_AR_FAULT_ADDR,
- S5P_AW_FAULT_ADDR,
- S5P_DEFAULT_SLAVE_ADDR,
- S5P_AR_FAULT_ADDR,
- S5P_AR_FAULT_ADDR,
- S5P_AW_FAULT_ADDR,
- S5P_AW_FAULT_ADDR
-};
-
-static char *sysmmu_fault_name[SYSMMU_FAULTS_NUM] = {
- "PAGE FAULT",
- "AR MULTI-HIT FAULT",
- "AW MULTI-HIT FAULT",
- "BUS ERROR",
- "AR SECURITY PROTECTION FAULT",
- "AR ACCESS PROTECTION FAULT",
- "AW SECURITY PROTECTION FAULT",
- "AW ACCESS PROTECTION FAULT"
-};
-
-static int (*fault_handlers[S5P_SYSMMU_TOTAL_IPNUM])(
- enum S5P_SYSMMU_INTERRUPT_TYPE itype,
- unsigned long pgtable_base,
- unsigned long fault_addr);
-
-/*
- * If adjacent 2 bits are true, the system MMU is enabled.
- * The system MMU is disabled, otherwise.
- */
-static unsigned long sysmmu_states;
-
-static inline void set_sysmmu_active(sysmmu_ips ips)
-{
- sysmmu_states |= 3 << (ips * 2);
-}
-
-static inline void set_sysmmu_inactive(sysmmu_ips ips)
-{
- sysmmu_states &= ~(3 << (ips * 2));
-}
-
-static inline int is_sysmmu_active(sysmmu_ips ips)
-{
- return sysmmu_states & (3 << (ips * 2));
-}
-
-static void __iomem *sysmmusfrs[S5P_SYSMMU_TOTAL_IPNUM];
-
-static inline void sysmmu_block(sysmmu_ips ips)
-{
- __raw_writel(CTRL_BLOCK, sysmmusfrs[ips] + S5P_MMU_CTRL);
- dev_dbg(dev, "%s is blocked.\n", sysmmu_ips_name[ips]);
-}
-
-static inline void sysmmu_unblock(sysmmu_ips ips)
-{
- __raw_writel(CTRL_ENABLE, sysmmusfrs[ips] + S5P_MMU_CTRL);
- dev_dbg(dev, "%s is unblocked.\n", sysmmu_ips_name[ips]);
-}
-
-static inline void __sysmmu_tlb_invalidate(sysmmu_ips ips)
-{
- __raw_writel(0x1, sysmmusfrs[ips] + S5P_MMU_FLUSH);
- dev_dbg(dev, "TLB of %s is invalidated.\n", sysmmu_ips_name[ips]);
-}
-
-static inline void __sysmmu_set_ptbase(sysmmu_ips ips, unsigned long pgd)
-{
- if (unlikely(pgd == 0)) {
- pgd = (unsigned long)ZERO_PAGE(0);
- __raw_writel(0x20, sysmmusfrs[ips] + S5P_MMU_CFG); /* 4KB LV1 */
- } else {
- __raw_writel(0x0, sysmmusfrs[ips] + S5P_MMU_CFG); /* 16KB LV1 */
- }
-
- __raw_writel(pgd, sysmmusfrs[ips] + S5P_PT_BASE_ADDR);
-
- dev_dbg(dev, "Page table base of %s is initialized with 0x%08lX.\n",
- sysmmu_ips_name[ips], pgd);
- __sysmmu_tlb_invalidate(ips);
-}
-
-void sysmmu_set_fault_handler(sysmmu_ips ips,
- int (*handler)(enum S5P_SYSMMU_INTERRUPT_TYPE itype,
- unsigned long pgtable_base,
- unsigned long fault_addr))
-{
- BUG_ON(!((ips >= SYSMMU_MDMA) && (ips < S5P_SYSMMU_TOTAL_IPNUM)));
- fault_handlers[ips] = handler;
-}
-
-static irqreturn_t s5p_sysmmu_irq(int irq, void *dev_id)
-{
- /* SYSMMU is in blocked when interrupt occurred. */
- unsigned long base = 0;
- sysmmu_ips ips = (sysmmu_ips)dev_id;
- enum S5P_SYSMMU_INTERRUPT_TYPE itype;
-
- itype = (enum S5P_SYSMMU_INTERRUPT_TYPE)
- __ffs(__raw_readl(sysmmusfrs[ips] + S5P_INT_STATUS));
-
- BUG_ON(!((itype >= 0) && (itype < 8)));
-
- dev_alert(dev, "%s occurred by %s.\n", sysmmu_fault_name[itype],
- sysmmu_ips_name[ips]);
-
- if (fault_handlers[ips]) {
- unsigned long addr;
-
- base = __raw_readl(sysmmusfrs[ips] + S5P_PT_BASE_ADDR);
- addr = __raw_readl(sysmmusfrs[ips] + fault_reg_offset[itype]);
-
- if (fault_handlers[ips](itype, base, addr)) {
- __raw_writel(1 << itype,
- sysmmusfrs[ips] + S5P_INT_CLEAR);
- dev_notice(dev, "%s from %s is resolved."
- " Retrying translation.\n",
- sysmmu_fault_name[itype], sysmmu_ips_name[ips]);
- } else {
- base = 0;
- }
- }
-
- sysmmu_unblock(ips);
-
- if (!base)
- dev_notice(dev, "%s from %s is not handled.\n",
- sysmmu_fault_name[itype], sysmmu_ips_name[ips]);
-
- return IRQ_HANDLED;
-}
-
-void s5p_sysmmu_set_tablebase_pgd(sysmmu_ips ips, unsigned long pgd)
-{
- if (is_sysmmu_active(ips)) {
- sysmmu_block(ips);
- __sysmmu_set_ptbase(ips, pgd);
- sysmmu_unblock(ips);
- } else {
- dev_dbg(dev, "%s is disabled. "
- "Skipping initializing page table base.\n",
- sysmmu_ips_name[ips]);
- }
-}
-
-void s5p_sysmmu_enable(sysmmu_ips ips, unsigned long pgd)
-{
- if (!is_sysmmu_active(ips)) {
- sysmmu_clk_enable(ips);
-
- __sysmmu_set_ptbase(ips, pgd);
-
- __raw_writel(CTRL_ENABLE, sysmmusfrs[ips] + S5P_MMU_CTRL);
-
- set_sysmmu_active(ips);
- dev_dbg(dev, "%s is enabled.\n", sysmmu_ips_name[ips]);
- } else {
- dev_dbg(dev, "%s is already enabled.\n", sysmmu_ips_name[ips]);
- }
-}
-
-void s5p_sysmmu_disable(sysmmu_ips ips)
-{
- if (is_sysmmu_active(ips)) {
- __raw_writel(CTRL_DISABLE, sysmmusfrs[ips] + S5P_MMU_CTRL);
- set_sysmmu_inactive(ips);
- sysmmu_clk_disable(ips);
- dev_dbg(dev, "%s is disabled.\n", sysmmu_ips_name[ips]);
- } else {
- dev_dbg(dev, "%s is already disabled.\n", sysmmu_ips_name[ips]);
- }
-}
-
-void s5p_sysmmu_tlb_invalidate(sysmmu_ips ips)
-{
- if (is_sysmmu_active(ips)) {
- sysmmu_block(ips);
- __sysmmu_tlb_invalidate(ips);
- sysmmu_unblock(ips);
- } else {
- dev_dbg(dev, "%s is disabled. "
- "Skipping invalidating TLB.\n", sysmmu_ips_name[ips]);
- }
-}
-
-static int s5p_sysmmu_probe(struct platform_device *pdev)
-{
- int i, ret;
- struct resource *res, *mem;
-
- dev = &pdev->dev;
-
- for (i = 0; i < S5P_SYSMMU_TOTAL_IPNUM; i++) {
- int irq;
-
- sysmmu_clk_init(dev, i);
- sysmmu_clk_disable(i);
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, i);
- if (!res) {
- dev_err(dev, "Failed to get the resource of %s.\n",
- sysmmu_ips_name[i]);
- ret = -ENODEV;
- goto err_res;
- }
-
- mem = request_mem_region(res->start, resource_size(res),
- pdev->name);
- if (!mem) {
- dev_err(dev, "Failed to request the memory region of %s.\n",
- sysmmu_ips_name[i]);
- ret = -EBUSY;
- goto err_res;
- }
-
- sysmmusfrs[i] = ioremap(res->start, resource_size(res));
- if (!sysmmusfrs[i]) {
- dev_err(dev, "Failed to ioremap() for %s.\n",
- sysmmu_ips_name[i]);
- ret = -ENXIO;
- goto err_reg;
- }
-
- irq = platform_get_irq(pdev, i);
- if (irq <= 0) {
- dev_err(dev, "Failed to get the IRQ resource of %s.\n",
- sysmmu_ips_name[i]);
- ret = -ENOENT;
- goto err_map;
- }
-
- if (request_irq(irq, s5p_sysmmu_irq, IRQF_DISABLED,
- pdev->name, (void *)i)) {
- dev_err(dev, "Failed to request IRQ for %s.\n",
- sysmmu_ips_name[i]);
- ret = -ENOENT;
- goto err_map;
- }
- }
-
- return 0;
-
-err_map:
- iounmap(sysmmusfrs[i]);
-err_reg:
- release_mem_region(mem->start, resource_size(mem));
-err_res:
- return ret;
-}
-
-static int s5p_sysmmu_remove(struct platform_device *pdev)
-{
- return 0;
-}
-int s5p_sysmmu_runtime_suspend(struct device *dev)
-{
- return 0;
-}
-
-int s5p_sysmmu_runtime_resume(struct device *dev)
-{
- return 0;
-}
-
-const struct dev_pm_ops s5p_sysmmu_pm_ops = {
- .runtime_suspend = s5p_sysmmu_runtime_suspend,
- .runtime_resume = s5p_sysmmu_runtime_resume,
-};
-
-static struct platform_driver s5p_sysmmu_driver = {
- .probe = s5p_sysmmu_probe,
- .remove = s5p_sysmmu_remove,
- .driver = {
- .owner = THIS_MODULE,
- .name = "s5p-sysmmu",
- .pm = &s5p_sysmmu_pm_ops,
- }
-};
-
-static int __init s5p_sysmmu_init(void)
-{
- return platform_driver_register(&s5p_sysmmu_driver);
-}
-arch_initcall(s5p_sysmmu_init);
diff --git a/arch/arm/plat-samsung/Kconfig b/arch/arm/plat-samsung/Kconfig
index a0ffc77d..6bd4bf68 100644
--- a/arch/arm/plat-samsung/Kconfig
+++ b/arch/arm/plat-samsung/Kconfig
@@ -281,6 +281,30 @@
Support for exporting the PWM timer blocks via the pwm device
system
+config S5P_DEV_MIPI_DSIM
+ bool
+ depends on FB_MIPI_DSIM
+ default y
+ help
+ Compile in platform device definitions for MIPI_DSIM
+ to support mainlile style fimd
+
+config S5P_DEV_DP
+ bool
+ help
+ Compile in platform device definitions for DP controller
+
+config S5P_DEV_FIMG2D
+ bool
+ help
+ Compile in platform device definitions for FIMG2D controller
+
+config S5P_DEV_BTS
+ bool
+ default n
+ help
+ Compile in platform device definitions for BTS devices
+
# DMA
config S3C_DMA
@@ -291,7 +315,7 @@
config SAMSUNG_DMADEV
bool
select DMADEVICES
- select PL330_DMA if (CPU_EXYNOS4210 || CPU_S5PV210 || CPU_S5PC100 || \
+ select PL330_DMA if (ARCH_EXYNOS5 || ARCH_EXYNOS4 || CPU_S5PV210 || CPU_S5PC100 || \
CPU_S5P6450 || CPU_S5P6440)
select ARM_AMBA
help
@@ -351,14 +375,6 @@
and above. This code allows a set of interrupt to wakeup-mask
mappings. See <plat/wakeup-mask.h>
-comment "Power Domain"
-
-config SAMSUNG_PD
- bool "Samsung Power Domain"
- depends on PM_RUNTIME
- help
- Say Y here if you want to control Power Domain by Runtime PM.
-
config DEBUG_S3C_UART
depends on PLAT_SAMSUNG
int
diff --git a/arch/arm/plat-samsung/Makefile b/arch/arm/plat-samsung/Makefile
index 6012366..825ccba 100644
--- a/arch/arm/plat-samsung/Makefile
+++ b/arch/arm/plat-samsung/Makefile
@@ -31,6 +31,9 @@
obj-y += devs.o
obj-y += dev-uart.o
+obj-$(CONFIG_S5P_DEV_MIPI_DSIM) += dev-mipidsim.o
+obj-$(CONFIG_S5P_DEV_DP) += dev-dp.o
+
obj-$(CONFIG_SAMSUNG_DEV_BACKLIGHT) += dev-backlight.o
# DMA support
@@ -47,10 +50,9 @@
obj-$(CONFIG_SAMSUNG_WAKEMASK) += wakeup-mask.o
-# PD support
-
-obj-$(CONFIG_SAMSUNG_PD) += pd.o
-
# PWM support
obj-$(CONFIG_HAVE_PWM) += pwm.o
+
+obj-$(CONFIG_S5P_DEV_FIMG2D) += dev-fimg2d.o
+obj-$(CONFIG_S5P_DEV_BTS) += bts.o
diff --git a/arch/arm/plat-samsung/adc.c b/arch/arm/plat-samsung/adc.c
index 33ecd0c..e689742 100644
--- a/arch/arm/plat-samsung/adc.c
+++ b/arch/arm/plat-samsung/adc.c
@@ -45,6 +45,7 @@
TYPE_ADCV12, /* S3C2416, S3C2450 */
TYPE_ADCV2, /* S3C64XX, S5P64X0, S5PC100 */
TYPE_ADCV3, /* S5PV210, S5PC110, EXYNOS4210 */
+ TYPE_ADCV4, /* EXYNOS4412, EXYNOS5250 */
};
struct s3c_adc_client {
@@ -73,6 +74,7 @@
spinlock_t lock;
unsigned int prescale;
+ unsigned int delay;
int irq;
struct regulator *vdd;
@@ -104,9 +106,10 @@
con &= ~S3C2410_ADCCON_MUXMASK;
con &= ~S3C2410_ADCCON_STDBM;
con &= ~S3C2410_ADCCON_STARTMASK;
+ con |= S3C2410_ADCCON_PRSCEN;
if (!client->is_ts) {
- if (cpu == TYPE_ADCV3)
+ if (cpu == TYPE_ADCV3 || cpu == TYPE_ADCV4)
writel(client->channel & 0xf, adc->regs + S5P_ADCMUX);
else if (cpu == TYPE_ADCV11 || cpu == TYPE_ADCV12)
writel(client->channel & 0xf,
@@ -129,6 +132,7 @@
static void s3c_adc_try(struct adc_device *adc)
{
struct s3c_adc_client *next = adc->ts_pend;
+ unsigned int con = readl(adc->regs + S3C2410_ADCCON);
if (!next && !list_empty(&adc_pending)) {
next = list_first_entry(&adc_pending,
@@ -143,6 +147,10 @@
s3c_adc_select(adc, next);
s3c_adc_convert(adc);
s3c_adc_dbgshow(adc);
+ } else {
+ con &= ~S3C2410_ADCCON_PRSCEN;
+ con |= S3C2410_ADCCON_STDBM;
+ writel(con, adc->regs + S3C2410_ADCCON);
}
}
@@ -157,11 +165,16 @@
return -EINVAL;
}
- if (client->is_ts && adc->ts_pend)
- return -EAGAIN;
+ if (nr_samples == 0)
+ return -EINVAL;
spin_lock_irqsave(&adc->lock, flags);
+ if (client->is_ts && adc->ts_pend) {
+ spin_unlock_irqrestore(&adc->lock, flags);
+ return -EAGAIN;
+ }
+
client->channel = channel;
client->nr_samples = nr_samples;
@@ -179,6 +192,34 @@
}
EXPORT_SYMBOL_GPL(s3c_adc_start);
+static void s3c_adc_stop(struct s3c_adc_client *client)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&adc_dev->lock, flags);
+
+ /* We should really check that nothing is in progress. */
+ if (adc_dev->cur == client)
+ adc_dev->cur = NULL;
+ if (adc_dev->ts_pend == client)
+ adc_dev->ts_pend = NULL;
+ else {
+ struct list_head *p, *n;
+ struct s3c_adc_client *tmp;
+
+ list_for_each_safe(p, n, &adc_pending) {
+ tmp = list_entry(p, struct s3c_adc_client, pend);
+ if (tmp == client)
+ list_del(&tmp->pend);
+ }
+ }
+
+ if (adc_dev->cur == NULL)
+ s3c_adc_try(adc_dev);
+
+ spin_unlock_irqrestore(&adc_dev->lock, flags);
+}
+
static void s3c_convert_done(struct s3c_adc_client *client,
unsigned v, unsigned u, unsigned *left)
{
@@ -186,29 +227,60 @@
wake_up(client->wait);
}
+/* Get the result out of the client with locking.
+ *
+ * It's expected that the irq is filling in the result of the client, so we
+ * should be locking access to it.
+ */
+static int s3c_get_result(struct s3c_adc_client *client)
+{
+ unsigned long flags;
+ int result;
+
+ spin_lock_irqsave(&adc_dev->lock, flags);
+ result = client->result;
+ spin_unlock_irqrestore(&adc_dev->lock, flags);
+
+ return result;
+}
+
int s3c_adc_read(struct s3c_adc_client *client, unsigned int ch)
{
+ unsigned long flags;
DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wake);
int ret;
+ /* Lock around access of client members. Technically all that's really
+ * required is a memory barrier after we've set all of these things
+ * (since nobody else can access this structure until it's placed
+ * into adc_pending), but it seems cleaner to just lock.
+ */
+ spin_lock_irqsave(&adc_dev->lock, flags);
client->convert_cb = s3c_convert_done;
client->wait = &wake;
client->result = -1;
+ spin_unlock_irqrestore(&adc_dev->lock, flags);
ret = s3c_adc_start(client, ch, 1);
if (ret < 0)
- goto err;
+ goto exit;
- ret = wait_event_timeout(wake, client->result >= 0, HZ / 2);
- if (client->result < 0) {
+ wait_event_timeout(wake, s3c_get_result(client) >= 0, HZ / 2);
+ ret = s3c_get_result(client);
+
+ if (ret < 0) {
+ s3c_adc_stop(client);
+ dev_warn(&adc_dev->pdev->dev, "%s: %p is timed out\n",
+ __func__, client);
ret = -ETIMEDOUT;
- goto err;
}
+exit:
+ /* Don't bother locking around this; nobody else should be carrying
+ * a pointer to the client anymore.
+ */
client->convert_cb = NULL;
- return client->result;
-err:
return ret;
}
EXPORT_SYMBOL_GPL(s3c_adc_read);
@@ -253,30 +325,7 @@
void s3c_adc_release(struct s3c_adc_client *client)
{
- unsigned long flags;
-
- spin_lock_irqsave(&adc_dev->lock, flags);
-
- /* We should really check that nothing is in progress. */
- if (adc_dev->cur == client)
- adc_dev->cur = NULL;
- if (adc_dev->ts_pend == client)
- adc_dev->ts_pend = NULL;
- else {
- struct list_head *p, *n;
- struct s3c_adc_client *tmp;
-
- list_for_each_safe(p, n, &adc_pending) {
- tmp = list_entry(p, struct s3c_adc_client, pend);
- if (tmp == client)
- list_del(&tmp->pend);
- }
- }
-
- if (adc_dev->cur == NULL)
- s3c_adc_try(adc_dev);
-
- spin_unlock_irqrestore(&adc_dev->lock, flags);
+ s3c_adc_stop(client);
kfree(client);
}
EXPORT_SYMBOL_GPL(s3c_adc_release);
@@ -284,18 +333,31 @@
static irqreturn_t s3c_adc_irq(int irq, void *pw)
{
struct adc_device *adc = pw;
- struct s3c_adc_client *client = adc->cur;
+ struct s3c_adc_client *client;
enum s3c_cpu_type cpu = platform_get_device_id(adc->pdev)->driver_data;
- unsigned data0, data1;
+ unsigned data0;
+ unsigned data1 = 0;
+ /* Need lock before accessing adc->cur; also keep for ->client
+ * access since that's accessed elsewhere in adc_read() / adc_start()
+ */
+ spin_lock(&adc->lock);
+
+ client = adc->cur;
if (!client) {
dev_warn(&adc->pdev->dev, "%s: no adc pending\n", __func__);
+ spin_unlock(&adc->lock);
goto exit;
}
data0 = readl(adc->regs + S3C2410_ADCDAT0);
- data1 = readl(adc->regs + S3C2410_ADCDAT1);
- adc_dbg(adc, "read %d: 0x%04x, 0x%04x\n", client->nr_samples, data0, data1);
+ if (cpu == TYPE_ADCV4) {
+ adc_dbg(adc, "read %d: 0x%04x\n", client->nr_samples, data0);
+ } else {
+ data1 = readl(adc->regs + S3C2410_ADCDAT1);
+ adc_dbg(adc, "read %d: 0x%04x, 0x%04x\n", client->nr_samples,
+ data0, data1);
+ }
client->nr_samples--;
@@ -317,16 +379,14 @@
client->select_cb(client, 1);
s3c_adc_convert(adc);
} else {
- spin_lock(&adc->lock);
- (client->select_cb)(client, 0);
+ client->select_cb(client, 0);
adc->cur = NULL;
-
s3c_adc_try(adc);
- spin_unlock(&adc->lock);
}
+ spin_unlock(&adc->lock);
exit:
- if (cpu == TYPE_ADCV2 || cpu == TYPE_ADCV3) {
+ if (cpu == TYPE_ADCV2 || cpu == TYPE_ADCV3 || cpu == TYPE_ADCV4) {
/* Clear ADC interrupt */
writel(0, adc->regs + S3C64XX_ADCCLRINT);
}
@@ -337,6 +397,7 @@
{
struct device *dev = &pdev->dev;
struct adc_device *adc;
+ struct s3c_adc_platdata *pdata;
struct resource *regs;
enum s3c_cpu_type cpu = platform_get_device_id(pdev)->driver_data;
int ret;
@@ -352,15 +413,15 @@
adc->pdev = pdev;
adc->prescale = S3C2410_ADCCON_PRSCVL(49);
+ adc->delay = S3C2410_ADCDLY_DELAY(1000);
adc->vdd = regulator_get(dev, "vdd");
if (IS_ERR(adc->vdd)) {
dev_err(dev, "operating without regulator \"vdd\" .\n");
- ret = PTR_ERR(adc->vdd);
- goto err_alloc;
+ adc->vdd = NULL;
}
- adc->irq = platform_get_irq(pdev, 1);
+ adc->irq = platform_get_irq_byname(pdev, "samsung-adc");
if (adc->irq <= 0) {
dev_err(dev, "failed to get adc irq\n");
ret = -ENOENT;
@@ -394,21 +455,29 @@
goto err_clk;
}
- ret = regulator_enable(adc->vdd);
- if (ret)
- goto err_ioremap;
+ if (adc->vdd) {
+ ret = regulator_enable(adc->vdd);
+ if (ret)
+ goto err_ioremap;
+ }
clk_enable(adc->clk);
+ pdata = pdev->dev.platform_data;
+ if (pdata != NULL && pdata->phy_init != NULL)
+ pdata->phy_init();
+
tmp = adc->prescale | S3C2410_ADCCON_PRSCEN;
/* Enable 12-bit ADC resolution */
if (cpu == TYPE_ADCV12)
tmp |= S3C2416_ADCCON_RESSEL;
- if (cpu == TYPE_ADCV2 || cpu == TYPE_ADCV3)
+ else if (cpu == TYPE_ADCV2 || cpu == TYPE_ADCV3 || cpu == TYPE_ADCV4)
tmp |= S3C64XX_ADCCON_RESSEL;
+ tmp |= S3C2410_ADCCON_STDBM;
writel(tmp, adc->regs + S3C2410_ADCCON);
+ writel(adc->delay, adc->regs + S3C2410_ADCDLY);
dev_info(dev, "attached adc driver\n");
@@ -425,8 +494,8 @@
err_irq:
free_irq(adc->irq, adc);
err_reg:
- regulator_put(adc->vdd);
- err_alloc:
+ if (adc->vdd)
+ regulator_put(adc->vdd);
kfree(adc);
return ret;
}
@@ -438,8 +507,10 @@
iounmap(adc->regs);
free_irq(adc->irq, adc);
clk_disable(adc->clk);
- regulator_disable(adc->vdd);
- regulator_put(adc->vdd);
+ if (adc->vdd) {
+ regulator_disable(adc->vdd);
+ regulator_put(adc->vdd);
+ }
clk_put(adc->clk);
kfree(adc);
@@ -464,7 +535,8 @@
disable_irq(adc->irq);
spin_unlock_irqrestore(&adc->lock, flags);
clk_disable(adc->clk);
- regulator_disable(adc->vdd);
+ if (adc->vdd)
+ regulator_disable(adc->vdd);
return 0;
}
@@ -478,9 +550,11 @@
int ret;
unsigned long tmp;
- ret = regulator_enable(adc->vdd);
- if (ret)
- return ret;
+ if (adc->vdd) {
+ ret = regulator_enable(adc->vdd);
+ if (ret)
+ return ret;
+ }
clk_enable(adc->clk);
enable_irq(adc->irq);
@@ -489,10 +563,11 @@
/* Enable 12-bit ADC resolution */
if (cpu == TYPE_ADCV12)
tmp |= S3C2416_ADCCON_RESSEL;
- if (cpu == TYPE_ADCV2 || cpu == TYPE_ADCV3)
+ if (cpu == TYPE_ADCV2 || cpu == TYPE_ADCV3 || cpu == TYPE_ADCV4)
tmp |= S3C64XX_ADCCON_RESSEL;
writel(tmp, adc->regs + S3C2410_ADCCON);
+ writel(adc->delay, adc->regs + S3C2410_ADCDLY);
return 0;
}
@@ -518,6 +593,9 @@
}, {
.name = "samsung-adc-v3",
.driver_data = TYPE_ADCV3,
+ }, {
+ .name = "samsung-adc-v4",
+ .driver_data = TYPE_ADCV4,
},
{ }
};
diff --git a/arch/arm/plat-samsung/bts.c b/arch/arm/plat-samsung/bts.c
new file mode 100644
index 0000000..55e3e3e
--- /dev/null
+++ b/arch/arm/plat-samsung/bts.c
@@ -0,0 +1,665 @@
+/* linux/arch/arm/plat-samsung/bts.c
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * 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 <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/list.h>
+#if defined(CONFIG_PM_RUNTIME)
+#include <linux/pm_runtime.h>
+#endif
+#include <linux/debugfs.h>
+
+#include <plat/devs.h>
+#include <plat/cpu.h>
+#include <plat/bts.h>
+#include <mach/map.h>
+
+/* BTS (Bus traffic shaper) registers */
+#define BTS_CONTROL 0x0
+#define BTS_SHAPING_ON_OFF_REG0 0x4
+#define BTS_MASTER_PRIORITY 0x8
+#define BTS_SHAPING_ON_OFF_REG1 0x44
+#define BTS_DEBLOCKING_SOURCE_SELECTION 0x50
+
+/* FBM (Flexible Blocking Monitor) registers */
+#define BTS_THRESHOLD_SEL0 0x40
+
+/*
+ * Fields of BTS_CONTROL register
+ * BTS_CTL_ENABLE indicates BTS_ON_OFF field
+ * BTS_CTL_BLOCKING indicates BLOCKING_ON_OFF field
+ * BTS_CTL_DEBLOCKING indicates DEBLOCKING_ON_OFF field
+ */
+#define BTS_CTL_ENABLE (1<<0)
+#define BTS_CTL_BLOCKING (1<<2)
+#define BTS_CTL_DEBLOCKING (1<<7)
+
+/* Fields of DEBLOCKING_SOURCE_SELECTION register */
+#define SEL_GRP0 (1<<0)
+#define SEL_LEFT0 (1<<4)
+#define SEL_RIGHT0 (1<<5)
+#define SEL_GRP1 (1<<8)
+#define SEL_LEFT1 (1<<12)
+#define SEL_RIGHT1 (1<<13)
+#define SEL_GRP2 (1<<16)
+#define SEL_LEFT2 (1<<20)
+#define SEL_RIGHT2 (1<<21)
+
+/* Shaping Value for Low priority */
+#define LOW_SHAPING_VAL0 0x0
+#define LOW_SHAPING_VAL1 0x3ff
+#define MASTER_PRIOR_NUMBER (1<<16)
+
+#define BTS_DISABLE 0
+#define BTS_ENABLE 1
+
+#define BTS_UP_THRESHOLD 0x4
+#define BTS_MIXER_THRESHOLD 0x3
+
+static LIST_HEAD(fbm_list);
+static LIST_HEAD(bts_list);
+
+/* Structure for status of a physical BTS device */
+struct exynos_bts_status {
+ enum bts_priority cur_priority;
+ enum bts_fbm_input_port fbm_src;
+ bool is_enabled;
+ bool is_blocked;
+ bool is_deblocked;
+};
+
+/* Structure for a physical BTS device */
+struct exynos_bts_local_data {
+ struct exynos_bts_status cur_status;
+ void __iomem *base;
+ enum bts_priority def_priority;
+ /*
+ * Indicate that it could be changable for selecting deblock sources
+ * in case of controlling bus traffic
+ */
+ bool deblock_changable;
+ bool threshold_changable;
+};
+
+/* Structure for a BTS driver.
+ * A BTS driver handles several physical BTS devices
+ * that are grouped together by clock and power control.
+ * bts_local_data member contains the physical device list.
+ */
+struct exynos_bts_data {
+ struct list_head node;
+ struct device *dev;
+ struct clk *clk;
+ struct exynos_bts_local_data *bts_local_data;
+ char *pd_name;
+ enum bts_traffic_control traffic_control_act;
+ u32 listnum;
+};
+
+/* Structure for FBM devices */
+struct exynos_fbm_data {
+ struct exynos_fbm_resource fbm;
+ struct list_head node;
+};
+
+/* Find FBM input port name with FBM source order */
+static enum bts_fbm_input_port find_fbm_port(enum bts_deblock_src_order fbm)
+{
+ struct exynos_fbm_data *fbm_data;
+ enum bts_fbm_input_port fbm_input_port = 0;
+
+ list_for_each_entry(fbm_data, &fbm_list, node) {
+ if (fbm & fbm_data->fbm.deblock_src_order)
+ fbm_input_port |= fbm_data->fbm.port_name;
+ }
+
+ return fbm_input_port;
+}
+
+/* Basic control of a BTS device */
+static void bts_set_control(struct exynos_bts_local_data *data,
+ enum bts_priority prior)
+{
+ u32 val = BTS_CTL_ENABLE;
+
+ data->cur_status.is_enabled = true;
+ if (prior == BTS_PRIOR_BE) {
+ val |= BTS_CTL_BLOCKING | BTS_CTL_DEBLOCKING;
+ data->cur_status.is_blocked = true;
+ data->cur_status.is_deblocked = true;
+ }
+ writel(val, data->base + BTS_CONTROL);
+}
+
+/* on/off a BTS device */
+static void bts_onoff(struct exynos_bts_local_data *data, bool on)
+{
+ u32 val = readl(data->base + BTS_CONTROL);
+ if (on) {
+ val |= BTS_CTL_ENABLE;
+ data->cur_status.is_enabled = true;
+ }
+ else {
+ val &= ~BTS_CTL_ENABLE;
+ data->cur_status.is_enabled = false;
+ }
+
+ writel(val, data->base + BTS_CONTROL);
+}
+
+/* set priority of BTS device */
+static void bts_set_priority(struct exynos_bts_local_data *data,
+ enum bts_priority prior)
+{
+ u32 val;
+
+ val = MASTER_PRIOR_NUMBER | (prior<<8) | (prior<<4) | (prior);
+ writel(val, data->base + BTS_MASTER_PRIORITY);
+ data->cur_status.cur_priority = prior;
+}
+
+/* set the blocking value for best effort IPs to BTS device */
+static void bts_set_blocking(struct exynos_bts_local_data *data)
+{
+ writel(LOW_SHAPING_VAL0, data->base + BTS_SHAPING_ON_OFF_REG0);
+ writel(LOW_SHAPING_VAL1, data->base + BTS_SHAPING_ON_OFF_REG1);
+}
+
+/* set the deblocking source according to FBM input port name */
+static void bts_set_deblocking(struct exynos_bts_local_data *data,
+ enum bts_fbm_input_port port_name)
+{
+ u32 val = 0;
+
+ if (port_name & BTS_FBM_G0_L)
+ val |= SEL_GRP0 | SEL_LEFT0;
+ if (port_name & BTS_FBM_G0_R)
+ val |= SEL_GRP0 | SEL_RIGHT0;
+ if (port_name & BTS_FBM_G1_L)
+ val |= SEL_GRP1 | SEL_LEFT1;
+ if (port_name & BTS_FBM_G1_R)
+ val |= SEL_GRP1 | SEL_RIGHT1;
+ if (port_name & BTS_FBM_G2_L)
+ val |= SEL_GRP2 | SEL_LEFT2;
+ if (port_name & BTS_FBM_G2_R)
+ val |= SEL_GRP2 | SEL_RIGHT2;
+ writel(val, data->base + BTS_DEBLOCKING_SOURCE_SELECTION);
+ data->cur_status.fbm_src = port_name;
+}
+
+/* initialize a BTS device with default bus traffic values */
+static void bts_set_default_bus_traffic(struct exynos_bts_local_data *data,
+ enum bts_priority prior)
+{
+ switch (prior) {
+ case BTS_FBM_DDR_R1:
+ data->cur_status.is_enabled = true;
+ data->cur_status.cur_priority = prior;
+ break;
+ case BTS_PRIOR_BE:
+ bts_set_blocking(data);
+ bts_set_deblocking(data, find_fbm_port(BTS_1ST_FBM_SRC));
+ case BTS_PRIOR_HARDTIME:
+ bts_set_priority(data, prior);
+ bts_set_control(data, prior);
+ break;
+ default:
+ break;
+ }
+}
+
+/* restore a BTS device with previous value */
+static void bts_restore_bus_traffic(struct exynos_bts_local_data *data)
+{
+ enum bts_priority prior = data->cur_status.cur_priority;
+
+ switch (prior) {
+ case BTS_FBM_DDR_R1:
+ data->cur_status.is_enabled = true;
+ data->cur_status.cur_priority = prior;
+ break;
+ case BTS_PRIOR_BE:
+ bts_set_blocking(data);
+ bts_set_deblocking(data, data->cur_status.fbm_src);
+ case BTS_PRIOR_HARDTIME:
+ bts_set_priority(data, prior);
+ bts_set_control(data, prior);
+ break;
+ default:
+ break;
+ }
+}
+
+/* change threshold FBM */
+void exynos_bts_change_threshold(enum bts_bw_change bw_change)
+{
+ struct exynos_bts_data *bts_data;
+ struct exynos_bts_local_data *bts_local_data;
+ char *reason;
+ int threshold;
+ int i;
+
+ list_for_each_entry(bts_data, &bts_list, node) {
+ bts_local_data = bts_data->bts_local_data;
+ for (i = 0; i < bts_data->listnum; i++) {
+ if (bts_local_data->threshold_changable) {
+ if (bw_change == BTS_INCREASE_BW) {
+ threshold = BTS_UP_THRESHOLD;
+ reason = "increasing";
+ } else if (bw_change == BTS_MIXER_BW) {
+ threshold = BTS_MIXER_THRESHOLD;
+ reason = "mixer";
+ }
+
+ writel(threshold, bts_local_data->base + BTS_THRESHOLD_SEL0);
+ pr_debug("%s: Change BTS threshold for %s BW\n",
+ dev_name(bts_data->dev), reason);
+ }
+ bts_local_data++;
+ }
+ }
+}
+
+/* change deblocking FBM source */
+static void bts_change_deblock_src(enum bts_bw_change bw_change)
+{
+ struct exynos_bts_data *bts_data;
+ struct exynos_bts_local_data *bts_local_data;
+ int i;
+
+ list_for_each_entry(bts_data, &bts_list, node) {
+ bts_local_data = bts_data->bts_local_data;
+ for (i = 0; i < bts_data->listnum; i++) {
+ if (bts_local_data->deblock_changable) {
+#if defined(CONFIG_PM_RUNTIME)
+ pm_runtime_get_sync(bts_data->dev->parent);
+#endif
+ if (bts_data->clk)
+ clk_enable(bts_data->clk);
+ bts_onoff(bts_local_data, BTS_DISABLE);
+ pr_debug("%s: Change BTS deblocking source for %s BW\n",
+ dev_name(bts_data->dev),
+ (bw_change == BTS_INCREASE_BW) ?
+ "increasing" : "decreasing");
+ bts_set_deblocking(bts_local_data,
+ find_fbm_port(
+ (bw_change == BTS_INCREASE_BW)
+ ? BTS_1ST_FBM_SRC
+ : (BTS_1ST_FBM_SRC |
+ BTS_2ND_FBM_SRC)));
+ bts_onoff(bts_local_data, BTS_ENABLE);
+ if (bts_data->clk)
+ clk_disable(bts_data->clk);
+#if defined(CONFIG_PM_RUNTIME)
+ pm_runtime_put_sync(bts_data->dev->parent);
+#endif
+ }
+ bts_local_data++;
+ }
+ }
+}
+
+/* turn physical BTS devices on/off */
+static void bts_devs_onoff(struct exynos_bts_data *bts_data, bool on)
+{
+ struct exynos_bts_local_data *bts_local_data;
+ int i;
+
+#if defined(CONFIG_PM_RUNTIME)
+ pm_runtime_get_sync(bts_data->dev->parent);
+#endif
+ if (bts_data->clk)
+ clk_enable(bts_data->clk);
+
+ bts_local_data = bts_data->bts_local_data;
+ for (i = 0; i < bts_data->listnum; i++) {
+ pr_debug("%s: BTS %sable for %s requests to memory\n",
+ dev_name(bts_data->dev), on ? "En" : "Dis", on ?
+ "blocking" : "de-blocking");
+ bts_onoff(bts_local_data, on);
+ bts_local_data++;
+ }
+
+ if (bts_data->clk)
+ clk_disable(bts_data->clk);
+#if defined(CONFIG_PM_RUNTIME)
+ pm_runtime_put_sync(bts_data->dev->parent);
+#endif
+}
+
+/* init physical bts devices */
+static void bts_devs_init(struct exynos_bts_data *bts_data)
+{
+ struct exynos_bts_local_data *bts_local_data;
+ int i;
+
+ pr_debug("%s requested %s from [%s] power domain\n",
+ dev_name(bts_data->dev), __func__, (bts_data->pd_name == NULL) ?
+ "NULL" : bts_data->pd_name);
+
+ if (bts_data->clk)
+ clk_enable(bts_data->clk);
+
+ bts_local_data = bts_data->bts_local_data;
+ for (i = 0; i < bts_data->listnum; i++) {
+ pr_debug("%s: Restore bus BW for res[%d]\n",
+ dev_name(bts_data->dev), i);
+ bts_restore_bus_traffic(bts_local_data);
+ bts_local_data++;
+ }
+
+ if (bts_data->clk)
+ clk_disable(bts_data->clk);
+}
+
+void exynos_bts_change_bus_traffic(struct device *dev,
+ enum bts_bw_change bw_change)
+{
+ struct exynos_bts_data *bts_data;
+
+ pr_debug("%s: change bus traffic to %s BW\n", dev_name(dev),
+ (bw_change == BTS_INCREASE_BW) ? "increase" : "decrease");
+ list_for_each_entry(bts_data, &bts_list, node) {
+ if (bts_data->dev->parent == dev) {
+ switch (bts_data->traffic_control_act) {
+ /*
+ * BTS_DISABLE means turning off blocking feature
+ * to increase bus bandwidth
+ */
+ case BTS_ON_OFF:
+ bts_devs_onoff(bts_data,
+ (bw_change == BTS_INCREASE_BW)
+ ? BTS_DISABLE : BTS_ENABLE);
+ break;
+ /*
+ * Increasing the caller device's bus bandwidth
+ * by decreasing others' bus bandwidth
+ */
+ case BTS_CHANGE_OTHER_DEBLOCK:
+ bts_change_deblock_src(
+ (bw_change == BTS_INCREASE_BW)
+ ? BTS_DECREASE_BW : BTS_INCREASE_BW);
+ break;
+ default:
+ dev_err(bts_data->dev,
+ "[%d] Unknown bus traffic control action\n",
+ bts_data->traffic_control_act);
+ break;
+ }
+ }
+ }
+}
+
+void exynos_bts_initialize(char *pd_name, bool power_on)
+{
+ struct exynos_bts_data *bts_data;
+ struct exynos_bts_status *cur_status;
+
+ list_for_each_entry(bts_data, &bts_list, node) {
+ if ((!pd_name && !bts_data->pd_name) ||
+ (pd_name && bts_data->pd_name &&
+ !strcmp(bts_data->pd_name, pd_name))) {
+ if (power_on) {
+ bts_devs_init(bts_data);
+ } else {
+ /*
+ * Do NOT touch HW register because BTS's master
+ * IP is already turned power off
+ */
+ cur_status = &bts_data->bts_local_data->cur_status;
+ cur_status->is_enabled = false;
+ }
+ }
+ }
+}
+
+static struct dentry *bts_debugfs;
+
+static int bts_debug_show(struct seq_file *s, void *unused)
+{
+ struct exynos_bts_data *bts_data;
+ struct exynos_bts_status *cur_status;
+
+ list_for_each_entry(bts_data, &bts_list, node) {
+ cur_status = &bts_data->bts_local_data->cur_status;
+ seq_printf(s, "%12s: BTS %3s", dev_name(bts_data->dev),
+ cur_status->is_enabled ? "ON" : "OFF\n");
+ if (!cur_status->is_enabled)
+ continue;
+ seq_printf(s, ", priority %2d, ", cur_status->cur_priority);
+ seq_printf(s, "Block %3s, Deblock %3s, Deblock src : ",
+ cur_status->is_blocked ? "ON" : "OFF",
+ cur_status->is_deblocked ? "ON" : "OFF");
+ if (cur_status->fbm_src & BTS_FBM_G0_L)
+ seq_printf(s, "%s ", "BTS_FBM_G0_L");
+ if (cur_status->fbm_src & BTS_FBM_G0_R)
+ seq_printf(s, "%s ", "BTS_FBM_G0_R");
+ if (cur_status->fbm_src & BTS_FBM_G1_L)
+ seq_printf(s, "%s ", "BTS_FBM_G1_L");
+ if (cur_status->fbm_src & BTS_FBM_G1_R)
+ seq_printf(s, "%s ", "BTS_FBM_G1_R");
+ if (cur_status->fbm_src & BTS_FBM_G2_L)
+ seq_printf(s, "%s ", "BTS_FBM_G2_L");
+ if (cur_status->fbm_src & BTS_FBM_G2_R)
+ seq_printf(s, "%s ", "BTS_FBM_G2_R");
+ seq_printf(s, " \n");
+ }
+
+ return 0;
+}
+
+static int bts_debug_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, bts_debug_show, inode->i_private);
+}
+
+const static struct file_operations bts_dev_status_fops = {
+ .open = bts_debug_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int bts_probe(struct platform_device *pdev)
+{
+ struct exynos_bts_pdata *bts_pdata;
+ struct exynos_fbm_resource *fbm_res;
+ struct exynos_bts_data *bts_data;
+ struct exynos_bts_local_data *bts_local_data, *bts_local_data_h;
+ struct exynos_fbm_data *fbm_data = NULL, *next;
+ struct resource *res = NULL;
+ struct clk *clk = NULL;
+ int i, ret = 0;
+
+ bts_pdata = pdev->dev.platform_data;
+ if (!bts_pdata) {
+ dev_err(&pdev->dev, "platform data is missed!\n");
+ return -ENODEV;
+ }
+
+ fbm_res = bts_pdata->fbm->res;
+
+ if (list_empty(&fbm_list)) {
+ for (i = 0; i < bts_pdata->fbm->res_num; i++) {
+ fbm_data = kzalloc(sizeof(struct exynos_fbm_data),
+ GFP_KERNEL);
+ if (!fbm_data) {
+ ret = -ENOMEM;
+ dev_err(&pdev->dev,
+ "failed to kzalloc() for fbm\n");
+ goto probe_err1;
+ }
+ list_add_tail(&fbm_data->node, &fbm_list);
+ fbm_data->fbm.port_name = fbm_res->port_name;
+ fbm_data->fbm.deblock_src_order =
+ fbm_res->deblock_src_order;
+ fbm_res++;
+ }
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "can't get resource!\n");
+ ret = -ENODEV;
+ goto probe_err1;
+ }
+
+ if (bts_pdata->clk_name) {
+ clk = clk_get(pdev->dev.parent, bts_pdata->clk_name);
+ if (IS_ERR(clk)) {
+ ret = -EINVAL;
+ dev_err(&pdev->dev, "failed to clk_get()\n");
+ goto probe_err1;
+ }
+ clk_enable(clk);
+ }
+
+ bts_data = kzalloc(sizeof(struct exynos_bts_data), GFP_KERNEL);
+ if (!bts_data) {
+ ret = -ENOMEM;
+ dev_err(&pdev->dev,
+ "failed to kzalloc() for exynos_bts_data\n");
+ goto probe_err2;
+ }
+ bts_data->listnum = bts_pdata->res_num;
+ bts_data->traffic_control_act = bts_pdata->traffic_control_act;
+ bts_local_data_h = bts_local_data =
+ kzalloc(sizeof(struct exynos_bts_local_data)*bts_data->listnum,
+ GFP_KERNEL);
+ if (!bts_local_data_h) {
+ ret = -ENOMEM;
+ dev_err(&pdev->dev,
+ "failed to kzalloc() for exynos_bts_local_data\n");
+ goto probe_err3;
+ }
+
+ for (i = 0; i < bts_data->listnum; i++) {
+ bts_local_data->base = ioremap(res->start, resource_size(res));
+ if (!bts_local_data->base) {
+ ret = -ENXIO;
+ dev_err(&pdev->dev, "failed to ioremap()\n");
+ goto probe_err4;
+ }
+ bts_local_data->def_priority = bts_pdata->def_priority;
+ bts_local_data->deblock_changable =
+ bts_pdata->deblock_changable;
+ bts_local_data->threshold_changable =
+ bts_pdata->threshold_changable;
+ pr_debug("%s: Set default bus BW with priority %d for res[%d]\n",
+ dev_name(&pdev->dev),
+ bts_local_data->def_priority, i);
+ bts_set_default_bus_traffic(bts_local_data,
+ bts_local_data->def_priority);
+ bts_local_data++;
+ res++;
+ }
+
+ bts_data->bts_local_data = bts_local_data_h;
+ bts_data->pd_name = bts_pdata->pd_name;
+ bts_data->clk = clk;
+ bts_data->dev = &pdev->dev;
+
+ list_add_tail(&bts_data->node, &bts_list);
+ pdev->dev.platform_data = bts_data;
+
+ if (bts_pdata->clk_name)
+ clk_disable(clk);
+ return 0;
+
+probe_err4:
+ bts_local_data = bts_local_data_h;
+ for (i = 0; i < bts_data->listnum; i++) {
+ if (bts_local_data->base)
+ iounmap(bts_local_data->base);
+ bts_local_data++;
+ }
+ kfree(bts_local_data_h);
+
+probe_err3:
+ kfree(bts_data);
+
+probe_err2:
+ if (bts_pdata->clk_name) {
+ clk_disable(clk);
+ clk_put(bts_data->clk);
+ }
+
+probe_err1:
+ list_for_each_entry_safe(fbm_data, next, &fbm_list, node) {
+ if (fbm_data) {
+ list_del(&fbm_data->node);
+ kfree(fbm_data);
+ }
+ }
+
+ return ret;
+}
+
+static int bts_remove(struct platform_device *pdev)
+{
+ struct exynos_fbm_data *fbm_data, *next;
+ struct exynos_bts_data *bts_data = pdev->dev.platform_data;
+ struct exynos_bts_local_data *bts_local_data;
+ int i;
+
+ bts_local_data = bts_data->bts_local_data;
+ for (i = 0; i < bts_data->listnum; i++) {
+ bts_local_data++;
+ iounmap(bts_local_data->base);
+ }
+ kfree(bts_data->bts_local_data);
+ list_del(&bts_data->node);
+
+ if (bts_data->clk)
+ clk_put(bts_data->clk);
+ kfree(bts_data);
+
+ if (!list_empty(&bts_list))
+ list_for_each_entry_safe(fbm_data, next, &fbm_list, node) {
+ list_del(&fbm_data->node);
+ kfree(fbm_data);
+ }
+
+ return 0;
+}
+
+static struct platform_driver bts_driver = {
+ .driver = {
+ .name = "exynos-bts"
+ },
+ .probe = bts_probe,
+ .remove = bts_remove,
+};
+
+static int __init bts_init(void)
+{
+ bts_debugfs =
+ debugfs_create_file("bts_dev_status",
+ S_IRUGO, NULL, NULL, &bts_dev_status_fops);
+ if (IS_ERR_OR_NULL(bts_debugfs)) {
+ bts_debugfs = NULL;
+ pr_err("%s: debugfs_create_file() failed\n", __func__);
+ }
+
+ return platform_driver_register(&bts_driver);
+}
+arch_initcall(bts_init);
diff --git a/arch/arm/plat-samsung/clock-clksrc.c b/arch/arm/plat-samsung/clock-clksrc.c
index 786a410..badf9f1 100644
--- a/arch/arm/plat-samsung/clock-clksrc.c
+++ b/arch/arm/plat-samsung/clock-clksrc.c
@@ -35,48 +35,13 @@
return mask << shift;
}
-static unsigned long s3c_getrate_clksrc(struct clk *clk)
-{
- struct clksrc_clk *sclk = to_clksrc(clk);
- unsigned long rate = clk_get_rate(clk->parent);
- u32 clkdiv = __raw_readl(sclk->reg_div.reg);
- u32 mask = bit_mask(sclk->reg_div.shift, sclk->reg_div.size);
-
- clkdiv &= mask;
- clkdiv >>= sclk->reg_div.shift;
- clkdiv++;
-
- rate /= clkdiv;
- return rate;
-}
-
-static int s3c_setrate_clksrc(struct clk *clk, unsigned long rate)
-{
- struct clksrc_clk *sclk = to_clksrc(clk);
- void __iomem *reg = sclk->reg_div.reg;
- unsigned int div;
- u32 mask = bit_mask(sclk->reg_div.shift, sclk->reg_div.size);
- u32 val;
-
- rate = clk_round_rate(clk, rate);
- div = clk_get_rate(clk->parent) / rate;
- if (div > (1 << sclk->reg_div.size))
- return -EINVAL;
-
- val = __raw_readl(reg);
- val &= ~mask;
- val |= (div - 1) << sclk->reg_div.shift;
- __raw_writel(val, reg);
-
- return 0;
-}
-
static int s3c_setparent_clksrc(struct clk *clk, struct clk *parent)
{
struct clksrc_clk *sclk = to_clksrc(clk);
struct clksrc_sources *srcs = sclk->sources;
u32 clksrc = __raw_readl(sclk->reg_src.reg);
u32 mask = bit_mask(sclk->reg_src.shift, sclk->reg_src.size);
+ u32 tmp;
int src_nr = -1;
int ptr;
@@ -86,17 +51,61 @@
break;
}
- if (src_nr >= 0) {
- clk->parent = parent;
+ if (src_nr < 0)
+ return -EINVAL;
- clksrc &= ~mask;
- clksrc |= src_nr << sclk->reg_src.shift;
- __raw_writel(clksrc, sclk->reg_src.reg);
- return 0;
+ clk->parent = parent;
+
+ clksrc &= ~mask;
+ clksrc |= src_nr << sclk->reg_src.shift;
+
+ __raw_writel(clksrc, sclk->reg_src.reg);
+
+ if (sclk->reg_src_stat.reg) {
+ mask = bit_mask(sclk->reg_src_stat.shift,
+ sclk->reg_src_stat.size);
+ do {
+ cpu_relax();
+ tmp = __raw_readl(sclk->reg_src_stat.reg);
+ tmp &= mask;
+ } while (tmp != BIT(src_nr + sclk->reg_src.shift));
}
- return -EINVAL;
+ return 0;
+}
+
+static struct clk *s3c_getparent_clksrc(struct clk *clk)
+{
+ struct clksrc_clk *sclk = to_clksrc(clk);
+ struct clksrc_sources *srcs = sclk->sources;
+ u32 clksrc = __raw_readl(sclk->reg_src.reg);
+ u32 mask = bit_mask(sclk->reg_src.shift, sclk->reg_src.size);
+ int src_nr;
+ struct clk *parent;
+
+ src_nr = (clksrc & mask) >> sclk->reg_src.shift;
+ if (src_nr >= srcs->nr_sources) {
+ pr_warn("%s: clock %s has invalid source %d\n", __func__,
+ clk->name, src_nr);
+ return ERR_PTR(-EINVAL);
+ }
+
+ parent = srcs->sources[src_nr];
+ if (!parent) {
+ pr_warn("%s: clock %s has null source %d\n", __func__,
+ clk->name, src_nr);
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (parent != clk->parent) {
+ pr_warn("%s: clock %s parent changed, was %s expected %s\n",
+ __func__, clk->name, parent->name,
+ clk->parent ? clk->parent->name : "(null)");
+ clk->parent = parent;
+ }
+
+ return parent;
}
static unsigned long s3c_roundrate_clksrc(struct clk *clk,
@@ -125,6 +134,50 @@
return rate;
}
+static unsigned long s3c_getrate_clksrc(struct clk *clk)
+{
+ struct clksrc_clk *sclk = to_clksrc(clk);
+ struct clk *parent;
+ unsigned long rate;
+ u32 clkdiv = __raw_readl(sclk->reg_div.reg);
+ u32 mask = bit_mask(sclk->reg_div.shift, sclk->reg_div.size);
+
+ parent = __clk_get_parent(clk);
+
+ rate = clk_get_rate(parent);
+
+ clkdiv &= mask;
+ clkdiv >>= sclk->reg_div.shift;
+ clkdiv++;
+
+ rate /= clkdiv;
+ return rate;
+}
+
+static int s3c_setrate_clksrc(struct clk *clk, unsigned long rate)
+{
+ struct clksrc_clk *sclk = to_clksrc(clk);
+ struct clk *parent;
+ void __iomem *reg = sclk->reg_div.reg;
+ unsigned int div;
+ u32 mask = bit_mask(sclk->reg_div.shift, sclk->reg_div.size);
+ u32 val;
+
+ parent = __clk_get_parent(clk);
+
+ rate = clk_round_rate(clk, rate);
+ div = clk_get_rate(parent) / rate;
+ if (div > (1 << sclk->reg_div.size))
+ return -EINVAL;
+
+ val = __raw_readl(reg);
+ val &= ~mask;
+ val |= (div - 1) << sclk->reg_div.shift;
+ __raw_writel(val, reg);
+
+ return 0;
+}
+
/* Clock initialisation code */
void __init_or_cpufreq s3c_set_clksrc(struct clksrc_clk *clk, bool announce)
@@ -160,6 +213,7 @@
static struct clk_ops clksrc_ops = {
.set_parent = s3c_setparent_clksrc,
+ .get_parent = s3c_getparent_clksrc,
.get_rate = s3c_getrate_clksrc,
.set_rate = s3c_setrate_clksrc,
.round_rate = s3c_roundrate_clksrc,
@@ -167,6 +221,7 @@
static struct clk_ops clksrc_ops_nodiv = {
.set_parent = s3c_setparent_clksrc,
+ .get_parent = s3c_getparent_clksrc,
};
static struct clk_ops clksrc_ops_nosrc = {
diff --git a/arch/arm/plat-samsung/clock.c b/arch/arm/plat-samsung/clock.c
index 65c5eca..f77b045 100644
--- a/arch/arm/plat-samsung/clock.c
+++ b/arch/arm/plat-samsung/clock.c
@@ -43,6 +43,8 @@
#include <linux/debugfs.h>
#endif
+#include <trace/events/power.h>
+
#include <mach/hardware.h>
#include <asm/irq.h>
@@ -93,8 +95,10 @@
spin_lock_irqsave(&clocks_lock, flags);
- if ((clk->usage++) == 0)
+ if ((clk->usage++) == 0) {
+ trace_clock_enable(clk->name, 1, smp_processor_id());
(clk->enable)(clk, 1);
+ }
spin_unlock_irqrestore(&clocks_lock, flags);
return 0;
@@ -109,8 +113,17 @@
spin_lock_irqsave(&clocks_lock, flags);
- if ((--clk->usage) == 0)
+ if (WARN_ON(!clk->usage)) {
+ pr_err("%s: clock, %s : %s, already disabled\n", __func__,
+ clk->devname ? clk->devname : "", clk->name);
+ spin_unlock_irqrestore(&clocks_lock, flags);
+ return;
+ }
+
+ if ((--clk->usage) == 0) {
+ trace_clock_disable(clk->name, 0, smp_processor_id());
(clk->enable)(clk, 0);
+ }
spin_unlock_irqrestore(&clocks_lock, flags);
clk_disable(clk->parent);
@@ -145,6 +158,7 @@
int clk_set_rate(struct clk *clk, unsigned long rate)
{
int ret;
+ unsigned long flags;
if (IS_ERR(clk))
return -EINVAL;
@@ -159,31 +173,55 @@
if (clk->ops == NULL || clk->ops->set_rate == NULL)
return -EINVAL;
- spin_lock(&clocks_lock);
+ spin_lock_irqsave(&clocks_lock, flags);
+ trace_clock_set_rate(clk->name, rate, smp_processor_id());
ret = (clk->ops->set_rate)(clk, rate);
- spin_unlock(&clocks_lock);
+ spin_unlock_irqrestore(&clocks_lock, flags);
return ret;
}
+struct clk *__clk_get_parent(struct clk *clk)
+{
+ if (clk->ops && clk->ops->get_parent)
+ return clk->ops->get_parent(clk);
+ else
+ return clk->parent;
+}
+
struct clk *clk_get_parent(struct clk *clk)
{
- return clk->parent;
+ struct clk *ret;
+ unsigned long flags;
+
+ if (IS_ERR(clk))
+ return ERR_PTR(EINVAL);
+
+ spin_lock_irqsave(&clocks_lock, flags);
+
+ ret = __clk_get_parent(clk);
+
+ spin_unlock_irqrestore(&clocks_lock, flags);
+
+ return ret;
}
int clk_set_parent(struct clk *clk, struct clk *parent)
{
int ret = 0;
+ unsigned long flags;
if (IS_ERR(clk))
return -EINVAL;
- spin_lock(&clocks_lock);
+ spin_lock_irqsave(&clocks_lock, flags);
- if (clk->ops && clk->ops->set_parent)
+ if (clk->ops && clk->ops->set_parent) {
+ trace_clock_set_parent(clk->name, parent->name);
ret = (clk->ops->set_parent)(clk, parent);
+ }
- spin_unlock(&clocks_lock);
+ spin_unlock_irqrestore(&clocks_lock, flags);
return ret;
}
@@ -281,6 +319,15 @@
if (clk->enable == NULL)
clk->enable = clk_null_enable;
+ /* add to the list of available clocks */
+
+ /* Quick check to see if this clock has already been registered. */
+ BUG_ON(clk->list.prev != clk->list.next);
+
+ spin_lock(&clocks_lock);
+ list_add(&clk->list, &clocks);
+ spin_unlock(&clocks_lock);
+
/* fill up the clk_lookup structure and register it*/
clk->lookup.dev_id = clk->devname;
clk->lookup.con_id = clk->name;
@@ -387,6 +434,72 @@
static struct dentry *clk_debugfs_root;
+static void clock_tree_show_one(struct seq_file *s, struct clk *c, int level)
+{
+ struct clk *child;
+ const char *state;
+ char buf[255] = { 0 };
+ int n = 0;
+
+ if (c->name)
+ n = snprintf(buf, sizeof(buf) - 1, "%s", c->name);
+
+ if (c->devname)
+ n += snprintf(buf + n, sizeof(buf) - 1 - n, ":%s", c->devname);
+
+ state = (c->usage > 0) ? "on" : "off";
+
+ seq_printf(s, "%*s%-*s %-6s %-3d %-10lu\n",
+ level * 3 + 1, "",
+ 50 - level * 3, buf,
+ state, c->usage, c->usage ? clk_get_rate(c) : 0);
+
+ list_for_each_entry(child, &clocks, list) {
+ if (child->parent != c)
+ continue;
+
+ clock_tree_show_one(s, child, level + 1);
+ }
+}
+
+static int clock_tree_show(struct seq_file *s, void *data)
+{
+ struct clk *c;
+ unsigned long flags;
+
+ seq_printf(s, " clock state ref rate\n");
+ seq_printf(s, "--------------------------------------------------------------------\n");
+
+ spin_lock_irqsave(&clocks_lock, flags);
+
+ list_for_each_entry(c, &clocks, list)
+ if (c->parent == NULL)
+ clock_tree_show_one(s, c, 0);
+
+ spin_unlock_irqrestore(&clocks_lock, flags);
+ return 0;
+}
+
+static int clock_tree_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, clock_tree_show, inode->i_private);
+}
+
+static const struct file_operations clock_tree_fops = {
+ .open = clock_tree_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int clock_rate_show(void *data, u64 *val)
+{
+ struct clk *c = data;
+ *val = clk_get_rate(c);
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(clock_rate_fops, clock_rate_show, NULL, "%llu\n");
+
static int clk_debugfs_register_one(struct clk *c)
{
int err;
@@ -395,7 +508,11 @@
char s[255];
char *p = s;
- p += sprintf(p, "%s", c->devname);
+ if (c->name)
+ p += sprintf(p, "%s", c->name);
+
+ if (c->devname)
+ p += sprintf(p, ":%s", c->devname);
d = debugfs_create_dir(s, pa ? pa->dent : clk_debugfs_root);
if (!d)
@@ -409,7 +526,7 @@
goto err_out;
}
- d = debugfs_create_u32("rate", S_IRUGO, c->dent, (u32 *)&c->rate);
+ d = debugfs_create_file("rate", S_IRUGO, c->dent, c, &clock_rate_fops);
if (!d) {
err = -ENOMEM;
goto err_out;
@@ -444,13 +561,18 @@
{
struct clk *c;
struct dentry *d;
- int err;
+ int err = -ENOMEM;
d = debugfs_create_dir("clock", NULL);
if (!d)
return -ENOMEM;
clk_debugfs_root = d;
+ d = debugfs_create_file("clock_tree", S_IRUGO, clk_debugfs_root, NULL,
+ &clock_tree_fops);
+ if (!d)
+ goto err_out;
+
list_for_each_entry(c, &clocks, list) {
err = clk_debugfs_register(c);
if (err)
diff --git a/arch/arm/plat-samsung/dev-backlight.c b/arch/arm/plat-samsung/dev-backlight.c
index 5f197dc..df312ee 100644
--- a/arch/arm/plat-samsung/dev-backlight.c
+++ b/arch/arm/plat-samsung/dev-backlight.c
@@ -20,13 +20,9 @@
#include <plat/gpio-cfg.h>
#include <plat/backlight.h>
-static int samsung_bl_init(struct device *dev)
+static int __init samsung_bl_init(struct samsung_bl_gpio_info *bl_gpio_info)
{
int ret = 0;
- struct platform_device *timer_dev =
- container_of(dev->parent, struct platform_device, dev);
- struct samsung_bl_gpio_info *bl_gpio_info =
- timer_dev->dev.platform_data;
ret = gpio_request(bl_gpio_info->no, "Backlight");
if (ret) {
@@ -40,17 +36,6 @@
return 0;
}
-static void samsung_bl_exit(struct device *dev)
-{
- struct platform_device *timer_dev =
- container_of(dev->parent, struct platform_device, dev);
- struct samsung_bl_gpio_info *bl_gpio_info =
- timer_dev->dev.platform_data;
-
- s3c_gpio_cfgpin(bl_gpio_info->no, S3C_GPIO_OUTPUT);
- gpio_free(bl_gpio_info->no);
-}
-
/* Initialize few important fields of platform_pwm_backlight_data
* structure with default values. These fields can be overridden by
* board-specific values sent from machine file.
@@ -64,8 +49,6 @@
.max_brightness = 255,
.dft_brightness = 255,
.pwm_period_ns = 78770,
- .init = samsung_bl_init,
- .exit = samsung_bl_exit,
};
static struct platform_device samsung_dfl_bl_device __initdata = {
@@ -84,6 +67,10 @@
struct platform_device *samsung_bl_device;
struct platform_pwm_backlight_data *samsung_bl_data;
+ ret = samsung_bl_init(gpio_info);
+ if (ret)
+ return;
+
samsung_bl_device = kmemdup(&samsung_dfl_bl_device,
sizeof(struct platform_device), GFP_KERNEL);
if (!samsung_bl_device) {
@@ -122,9 +109,6 @@
if (bl_data->check_fb)
samsung_bl_data->check_fb = bl_data->check_fb;
- /* Keep the GPIO info for future use */
- s3c_device_timer[samsung_bl_data->pwm_id].dev.platform_data = gpio_info;
-
/* Register the specific PWM timer dev for Backlight control */
ret = platform_device_register(
&s3c_device_timer[samsung_bl_data->pwm_id]);
diff --git a/arch/arm/plat-samsung/dev-dp.c b/arch/arm/plat-samsung/dev-dp.c
new file mode 100644
index 0000000..6ec5371
--- /dev/null
+++ b/arch/arm/plat-samsung/dev-dp.c
@@ -0,0 +1,52 @@
+/* linux/arch/arm/plat-samsung/dev-dp.c
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Base Samsung SoC DP resource and device definitions
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <video/s5p-dp.h>
+#include <mach/map.h>
+#include <plat/devs.h>
+#include <plat/dp.h>
+
+static struct resource s5p_dp_resource[] = {
+ [0] = {
+ .start = S5P_PA_DP,
+ .end = S5P_PA_DP + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_DP,
+ .end = IRQ_DP,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static u64 s5p_dp_dma_mask = DMA_BIT_MASK(32);
+
+struct platform_device s5p_device_dp = {
+ .name = "s5p-dp",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(s5p_dp_resource),
+ .resource = s5p_dp_resource,
+ .dev = {
+ .dma_mask = &s5p_dp_dma_mask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+};
+
+void __init s5p_dp_set_platdata(struct s5p_dp_platdata *pd)
+{
+ s3c_set_platdata(pd, sizeof(struct s5p_dp_platdata),
+ &s5p_device_dp);
+}
diff --git a/arch/arm/plat-samsung/dev-fimg2d.c b/arch/arm/plat-samsung/dev-fimg2d.c
new file mode 100644
index 0000000..d962215
--- /dev/null
+++ b/arch/arm/plat-samsung/dev-fimg2d.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Base S5P FIMG2D resource and device definitions
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/export.h>
+
+#include <mach/map.h>
+
+#include <plat/fimg2d.h>
+#include <plat/cpu.h>
+
+#define S5P_PA_FIMG2D_OFFSET 0x02000000
+#define S5P_PA_FIMG2D_3X (S5P_PA_FIMG2D+S5P_PA_FIMG2D_OFFSET)
+
+#ifdef CONFIG_VIDEO_EXYNOS_FIMG2D
+static struct resource s5p_fimg2d_resource[] = {
+ [0] = DEFINE_RES_MEM(S5P_PA_FIMG2D, SZ_4K),
+ [1] = DEFINE_RES_IRQ(IRQ_2D),
+};
+
+struct platform_device s5p_device_fimg2d = {
+ .name = "s5p-fimg2d",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(s5p_fimg2d_resource),
+ .resource = s5p_fimg2d_resource
+};
+EXPORT_SYMBOL(s5p_device_fimg2d);
+
+static struct fimg2d_platdata default_fimg2d_data __initdata = {
+ .parent_clkname = "mout_g2d0",
+ .clkname = "sclk_fimg2d",
+ .gate_clkname = "fimg2d",
+ .clkrate = 250 * 1000000,
+};
+
+void __init s5p_fimg2d_set_platdata(struct fimg2d_platdata *pd)
+{
+ struct fimg2d_platdata *npd;
+
+ if (soc_is_exynos4210()) {
+ s5p_fimg2d_resource[0].start = S5P_PA_FIMG2D_3X;
+ s5p_fimg2d_resource[0].end = S5P_PA_FIMG2D_3X + SZ_4K - 1;
+ }
+
+ if (!pd)
+ pd = &default_fimg2d_data;
+
+ npd = kmemdup(pd, sizeof(*pd), GFP_KERNEL);
+ if (!npd)
+ printk(KERN_ERR "no memory for fimg2d platform data\n");
+ else
+ s5p_device_fimg2d.dev.platform_data = npd;
+}
+#endif
diff --git a/arch/arm/plat-samsung/dev-mipidsim.c b/arch/arm/plat-samsung/dev-mipidsim.c
new file mode 100644
index 0000000..c8c38b5
--- /dev/null
+++ b/arch/arm/plat-samsung/dev-mipidsim.c
@@ -0,0 +1,53 @@
+/* linux/arch/arm/plat-s5p/dev-mipidsim.c
+ *
+ * Copyright (c) 2011 Samsung Electronics
+ *
+ *
+ * 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.
+*/
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/fb.h>
+
+#include <mach/map.h>
+#include <mach/irqs.h>
+#include <mach/regs-clock.h>
+
+#include <plat/devs.h>
+#include <plat/cpu.h>
+#include <plat/fb.h>
+
+#include <plat/dsim.h>
+#include <plat/mipi_dsi.h>
+
+static struct resource s5p_dsim_resource[] = {
+ [0] = {
+ .start = S5P_PA_DSIM0,
+ .end = S5P_PA_DSIM0 + SZ_64K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_MIPIDSI0,
+ .end = IRQ_MIPIDSI0,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device s5p_device_mipi_dsim = {
+ .name = "s5p-mipi-dsim",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(s5p_dsim_resource),
+ .resource = s5p_dsim_resource,
+ .dev = {
+ .platform_data = NULL,
+ },
+};
+
+void __init s5p_dsim_set_platdata(struct s5p_platform_mipi_dsim *pd) {
+ s3c_set_platdata(pd, sizeof(struct s5p_platform_mipi_dsim), &s5p_device_mipi_dsim);
+}
diff --git a/arch/arm/plat-samsung/devs.c b/arch/arm/plat-samsung/devs.c
index 8b928f9..0ca1269 100644
--- a/arch/arm/plat-samsung/devs.c
+++ b/arch/arm/plat-samsung/devs.c
@@ -64,6 +64,8 @@
#include <plat/regs-serial.h>
#include <plat/regs-spi.h>
#include <plat/s3c64xx-spi.h>
+#include <plat/tv-core.h>
+#include <plat/pwm.h>
static u64 samsung_device_dma_mask = DMA_BIT_MASK(32);
@@ -93,9 +95,10 @@
#ifdef CONFIG_PLAT_S3C24XX
static struct resource s3c_adc_resource[] = {
- [0] = DEFINE_RES_MEM(S3C24XX_PA_ADC, S3C24XX_SZ_ADC),
- [1] = DEFINE_RES_IRQ(IRQ_TC),
- [2] = DEFINE_RES_IRQ(IRQ_ADC),
+ [0] = DEFINE_RES_MEM_NAMED(S3C24XX_PA_ADC,
+ S3C24XX_SZ_ADC, "samsung-adc"),
+ [1] = DEFINE_RES_IRQ_NAMED(IRQ_TC, "samsung-tc"),
+ [2] = DEFINE_RES_IRQ_NAMED(IRQ_ADC, "samsung-adc"),
};
struct platform_device s3c_device_adc = {
@@ -108,9 +111,11 @@
#if defined(CONFIG_SAMSUNG_DEV_ADC)
static struct resource s3c_adc_resource[] = {
- [0] = DEFINE_RES_MEM(SAMSUNG_PA_ADC, SZ_256),
- [1] = DEFINE_RES_IRQ(IRQ_TC),
- [2] = DEFINE_RES_IRQ(IRQ_ADC),
+ [0] = DEFINE_RES_MEM_NAMED(SAMSUNG_PA_ADC, SZ_256, "samsung-adc"),
+#ifdef IRQ_TC
+ [1] = DEFINE_RES_IRQ_NAMED(IRQ_TC, "samsung-tc"),
+#endif
+ [2] = DEFINE_RES_IRQ_NAMED(IRQ_ADC, "samsung-adc"),
};
struct platform_device s3c_device_adc = {
@@ -119,6 +124,12 @@
.num_resources = ARRAY_SIZE(s3c_adc_resource),
.resource = s3c_adc_resource,
};
+
+void __init s3c_adc_set_platdata(struct s3c_adc_platdata *pd)
+{
+ s3c_set_platdata(pd, sizeof(struct s3c_adc_platdata),
+ &s3c_device_adc);
+}
#endif /* CONFIG_SAMSUNG_DEV_ADC */
/* Camif Controller */
@@ -342,6 +353,39 @@
}
#endif /* CONFIG_S5P_DEV_FIMD0 */
+/* FIMD1 */
+
+#ifdef CONFIG_S5P_DEV_FIMD1
+static struct resource s5p_fimd1_resource[] = {
+#ifdef CONFIG_FB_EXYNOS_FIMD_V8
+ [0] = DEFINE_RES_MEM(S5P_PA_FIMD1, SZ_256K),
+#else
+ [0] = DEFINE_RES_MEM(S5P_PA_FIMD1, SZ_32K),
+#endif
+ [1] = DEFINE_RES_IRQ(IRQ_FIMD1_VSYNC),
+ [2] = DEFINE_RES_IRQ(IRQ_FIMD1_FIFO),
+ [3] = DEFINE_RES_IRQ(IRQ_FIMD1_SYSTEM),
+ [4] = DEFINE_RES_MEM(0, SZ_1), /* to be populated later */
+};
+
+struct platform_device s5p_device_fimd1 = {
+ .name = "s5p-fb",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(s5p_fimd1_resource),
+ .resource = s5p_fimd1_resource,
+ .dev = {
+ .dma_mask = &samsung_device_dma_mask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+};
+
+void __init s5p_fimd1_set_platdata(struct s3c_fb_platdata *pd)
+{
+ s3c_set_platdata(pd, sizeof(struct s3c_fb_platdata),
+ &s5p_device_fimd1);
+}
+#endif /* CONFIG_S5P_DEV_FIMD1 */
+
/* HWMON */
#ifdef CONFIG_S3C_DEV_HWMON
@@ -507,7 +551,7 @@
struct s3c2410_platform_i2c default_i2c_data __initdata = {
.flags = 0,
.slave_addr = 0x10,
- .frequency = 100*1000,
+ .frequency = 400*1000,
.sda_delay = 100,
};
@@ -746,8 +790,8 @@
};
struct platform_device s5p_device_i2c_hdmiphy = {
- .name = "s3c2440-hdmiphy-i2c",
- .id = -1,
+ .name = "s3c2440-i2c",
+ .id = 8,
.num_resources = ARRAY_SIZE(s5p_i2c_resource),
.resource = s5p_i2c_resource,
};
@@ -763,6 +807,8 @@
pd->bus_num = 8;
else if (soc_is_s5pv210())
pd->bus_num = 3;
+ else if (soc_is_exynos5250())
+ pd->bus_num = 8;
else
pd->bus_num = 0;
}
@@ -919,36 +965,6 @@
};
#endif /* CONFIG_S5P_DEV_MFC */
-/* MIPI CSIS */
-
-#ifdef CONFIG_S5P_DEV_CSIS0
-static struct resource s5p_mipi_csis0_resource[] = {
- [0] = DEFINE_RES_MEM(S5P_PA_MIPI_CSIS0, SZ_16K),
- [1] = DEFINE_RES_IRQ(IRQ_MIPI_CSIS0),
-};
-
-struct platform_device s5p_device_mipi_csis0 = {
- .name = "s5p-mipi-csis",
- .id = 0,
- .num_resources = ARRAY_SIZE(s5p_mipi_csis0_resource),
- .resource = s5p_mipi_csis0_resource,
-};
-#endif /* CONFIG_S5P_DEV_CSIS0 */
-
-#ifdef CONFIG_S5P_DEV_CSIS1
-static struct resource s5p_mipi_csis1_resource[] = {
- [0] = DEFINE_RES_MEM(S5P_PA_MIPI_CSIS1, SZ_16K),
- [1] = DEFINE_RES_IRQ(IRQ_MIPI_CSIS1),
-};
-
-struct platform_device s5p_device_mipi_csis1 = {
- .name = "s5p-mipi-csis",
- .id = 1,
- .num_resources = ARRAY_SIZE(s5p_mipi_csis1_resource),
- .resource = s5p_mipi_csis1_resource,
-};
-#endif
-
/* NAND */
#ifdef CONFIG_S3C_DEV_NAND
@@ -1111,7 +1127,14 @@
#ifdef CONFIG_PLAT_S5P
static struct resource s5p_pmu_resource[] = {
- DEFINE_RES_IRQ(IRQ_PMU)
+ [0] = DEFINE_RES_IRQ(IRQ_PMU),
+#if CONFIG_NR_CPUS > 1
+ [1] = DEFINE_RES_IRQ(IRQ_PMU_CPU1),
+#endif
+#if CONFIG_NR_CPUS > 2
+ [2] = DEFINE_RES_IRQ(IRQ_PMU_CPU2),
+ [3] = DEFINE_RES_IRQ(IRQ_PMU_CPU3),
+#endif
};
static struct platform_device s5p_device_pmu = {
@@ -1123,7 +1146,14 @@
static int __init s5p_pmu_init(void)
{
- platform_device_register(&s5p_device_pmu);
+ int ret;
+
+ ret = platform_device_register(&s5p_device_pmu);
+ if (ret) {
+ pr_warning("s5p_pmu_init: pmu device not registered.\n");
+ return ret;
+ }
+
return 0;
}
arch_initcall(s5p_pmu_init);
@@ -1162,6 +1192,22 @@
[3] = { DEFINE_S3C_TIMER(3, IRQ_TIMER3) },
[4] = { DEFINE_S3C_TIMER(4, IRQ_TIMER4) },
};
+
+void __init samsung_pwm_set_platdata(struct samsung_pwm_platdata *pd)
+{
+ int i;
+ struct samsung_pwm_platdata *npd;
+
+ BUG_ON(!pd);
+
+ /*
+ * Each 5 PWM Timers have own platform_device, but
+ * only one platform_data is valid for all of PWMs
+ */
+ for (i = 0 ; i < 5; i++)
+ npd = s3c_set_platdata(pd, sizeof(struct samsung_pwm_platdata),
+ &s3c_device_timer[i]);
+}
#endif /* CONFIG_SAMSUNG_DEV_PWM */
/* RTC */
@@ -1312,7 +1358,8 @@
static struct resource s5p_hdmi_resources[] = {
[0] = DEFINE_RES_MEM(S5P_PA_HDMI, SZ_1M),
- [1] = DEFINE_RES_IRQ(IRQ_HDMI),
+ [1] = DEFINE_RES_IRQ(IRQ_TVOUT_EXT_HPD),
+ [2] = DEFINE_RES_IRQ(IRQ_HDMI),
};
struct platform_device s5p_device_hdmi = {
@@ -1322,6 +1369,17 @@
.resource = s5p_hdmi_resources,
};
+void __init s5p_hdmi_set_platdata(struct s5p_hdmi_platdata *pd)
+{
+ struct s5p_hdmi_platdata *npd;
+ npd = s3c_set_platdata(pd, sizeof(struct
+ s5p_hdmi_platdata),
+ &s5p_device_hdmi);
+ if (!npd->hdmiphy_enable)
+ npd->hdmiphy_enable = s5p_hdmiphy_enable;
+}
+
+#if defined(CONFIG_ARCH_EXYNOS4)
static struct resource s5p_sdo_resources[] = {
[0] = DEFINE_RES_MEM(S5P_PA_SDO, SZ_64K),
[1] = DEFINE_RES_IRQ(IRQ_SDO),
@@ -1339,6 +1397,12 @@
[1] = DEFINE_RES_MEM_NAMED(S5P_PA_VP, SZ_64K, "vp"),
[2] = DEFINE_RES_IRQ_NAMED(IRQ_MIXER, "irq"),
};
+#else
+static struct resource s5p_mixer_resources[] = {
+ [0] = DEFINE_RES_MEM_NAMED(S5P_PA_MIXER, SZ_64K, "mxr"),
+ [2] = DEFINE_RES_IRQ_NAMED(IRQ_MIXER, "irq"),
+};
+#endif
struct platform_device s5p_device_mixer = {
.name = "s5p-mixer",
@@ -1350,6 +1414,34 @@
.coherent_dma_mask = DMA_BIT_MASK(32),
}
};
+
+static struct resource s5p_cec_resources[] = {
+ [0] = DEFINE_RES_MEM_NAMED(S5P_PA_HDMI_CEC, SZ_64K, "cec"),
+ [1] = DEFINE_RES_IRQ_NAMED(IRQ_CEC, "irq"),
+};
+
+struct platform_device s5p_device_cec = {
+ .name = "s5p-tvout-cec",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(s5p_cec_resources),
+ .resource = s5p_cec_resources,
+};
+
+void __init s5p_hdmi_cec_set_platdata(struct s5p_platform_cec *pd)
+{
+ struct s5p_platform_cec *npd;
+
+ npd = kmemdup(pd, sizeof(struct s5p_platform_cec), GFP_KERNEL);
+ if (!npd)
+ printk(KERN_ERR "%s: no memory for platform data\n",
+ __func__);
+ else {
+ if (!npd->cfg_gpio)
+ npd->cfg_gpio = s5p_cec_cfg_gpio;
+ s5p_device_cec.dev.platform_data = npd;
+ }
+}
+
#endif /* CONFIG_S5P_DEV_TV */
/* USB */
@@ -1640,3 +1732,23 @@
s3c_set_platdata(pd, sizeof(*pd), &s3c64xx_device_spi2);
}
#endif /* CONFIG_S3C64XX_DEV_SPI2 */
+
+#ifdef CONFIG_MALI_T6XX
+static struct resource g3d_resource[] = {
+ [0] = DEFINE_RES_MEM(EXYNOS5_PA_G3D, (SZ_4K * 5)),
+ [1] = DEFINE_RES_IRQ(JOB_IRQ_NUMBER),
+ [2] = DEFINE_RES_IRQ(MMU_IRQ_NUMBER),
+ [3] = DEFINE_RES_IRQ(GPU_IRQ_NUMBER),
+};
+
+struct platform_device exynos5_device_g3d = {
+ .name = "mali",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(g3d_resource),
+ .resource = g3d_resource,
+ .dev = {
+ .dma_mask = &samsung_device_dma_mask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+};
+#endif /*CONFIG_MALI_T6XX*/
diff --git a/arch/arm/plat-samsung/dma-ops.c b/arch/arm/plat-samsung/dma-ops.c
index eb9f4f5..881b6ed 100644
--- a/arch/arm/plat-samsung/dma-ops.c
+++ b/arch/arm/plat-samsung/dma-ops.c
@@ -19,72 +19,80 @@
#include <mach/dma.h>
static unsigned samsung_dmadev_request(enum dma_ch dma_ch,
- struct samsung_dma_info *info)
+ struct samsung_dma_req *param)
{
- struct dma_chan *chan;
dma_cap_mask_t mask;
- struct dma_slave_config slave_config;
void *filter_param;
dma_cap_zero(mask);
- dma_cap_set(info->cap, mask);
+ dma_cap_set(param->cap, mask);
/*
* If a dma channel property of a device node from device tree is
* specified, use that as the fliter parameter.
*/
- filter_param = (dma_ch == DMACH_DT_PROP) ? (void *)info->dt_dmach_prop :
- (void *)dma_ch;
- chan = dma_request_channel(mask, pl330_filter, filter_param);
-
- if (info->direction == DMA_DEV_TO_MEM) {
- memset(&slave_config, 0, sizeof(struct dma_slave_config));
- slave_config.direction = info->direction;
- slave_config.src_addr = info->fifo;
- slave_config.src_addr_width = info->width;
- slave_config.src_maxburst = 1;
- dmaengine_slave_config(chan, &slave_config);
- } else if (info->direction == DMA_MEM_TO_DEV) {
- memset(&slave_config, 0, sizeof(struct dma_slave_config));
- slave_config.direction = info->direction;
- slave_config.dst_addr = info->fifo;
- slave_config.dst_addr_width = info->width;
- slave_config.dst_maxburst = 1;
- dmaengine_slave_config(chan, &slave_config);
- }
-
- return (unsigned)chan;
+ filter_param = (dma_ch == DMACH_DT_PROP) ?
+ (void *)param->dt_dmach_prop : (void *)dma_ch;
+ return (unsigned)dma_request_channel(mask, pl330_filter, filter_param);
}
-static int samsung_dmadev_release(unsigned ch,
- struct s3c2410_dma_client *client)
+static int samsung_dmadev_release(unsigned ch, void *param)
{
dma_release_channel((struct dma_chan *)ch);
return 0;
}
+static int samsung_dmadev_config(unsigned ch,
+ struct samsung_dma_config *param)
+{
+ struct dma_chan *chan = (struct dma_chan *)ch;
+ struct dma_slave_config slave_config;
+
+ if (param->direction == DMA_DEV_TO_MEM) {
+ memset(&slave_config, 0, sizeof(struct dma_slave_config));
+ slave_config.direction = param->direction;
+ slave_config.src_addr = param->fifo;
+ slave_config.src_addr_width = param->width;
+ slave_config.src_maxburst = 1;
+ dmaengine_slave_config(chan, &slave_config);
+ } else if (param->direction == DMA_MEM_TO_DEV) {
+ memset(&slave_config, 0, sizeof(struct dma_slave_config));
+ slave_config.direction = param->direction;
+ slave_config.dst_addr = param->fifo;
+ slave_config.dst_addr_width = param->width;
+ slave_config.dst_maxburst = 1;
+ dmaengine_slave_config(chan, &slave_config);
+ } else {
+ printk(KERN_WARNING "unsupported direction\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int samsung_dmadev_prepare(unsigned ch,
- struct samsung_dma_prep_info *info)
+ struct samsung_dma_prep *param)
{
struct scatterlist sg;
struct dma_chan *chan = (struct dma_chan *)ch;
struct dma_async_tx_descriptor *desc;
- switch (info->cap) {
+ switch (param->cap) {
case DMA_SLAVE:
sg_init_table(&sg, 1);
- sg_dma_len(&sg) = info->len;
- sg_set_page(&sg, pfn_to_page(PFN_DOWN(info->buf)),
- info->len, offset_in_page(info->buf));
- sg_dma_address(&sg) = info->buf;
+ sg_dma_len(&sg) = param->len;
+ sg_set_page(&sg, pfn_to_page(PFN_DOWN(param->buf)),
+ param->len, offset_in_page(param->buf));
+ sg_dma_address(&sg) = param->buf;
desc = dmaengine_prep_slave_sg(chan,
- &sg, 1, info->direction, DMA_PREP_INTERRUPT);
+ &sg, 1, param->direction, DMA_PREP_INTERRUPT);
break;
case DMA_CYCLIC:
- desc = dmaengine_prep_dma_cyclic(chan,
- info->buf, info->len, info->period, info->direction);
+ desc = chan->device->device_prep_dma_cyclic(chan,
+ param->buf, param->len, param->period,
+ param->direction, ¶m->infiniteloop);
break;
default:
dev_err(&chan->dev->device, "unsupported format\n");
@@ -96,8 +104,8 @@
return -EFAULT;
}
- desc->callback = info->fp;
- desc->callback_param = info->fp_param;
+ desc->callback = param->fp;
+ desc->callback_param = param->fp_param;
dmaengine_submit((struct dma_async_tx_descriptor *)desc);
@@ -111,6 +119,12 @@
return 0;
}
+static inline int samsung_dmadev_getposition(unsigned ch,
+ dma_addr_t *src, dma_addr_t *dst)
+{
+ return pl330_dma_getposition((struct dma_chan *)ch, src, dst);
+}
+
static inline int samsung_dmadev_flush(unsigned ch)
{
return dmaengine_terminate_all((struct dma_chan *)ch);
@@ -119,9 +133,11 @@
static struct samsung_dma_ops dmadev_ops = {
.request = samsung_dmadev_request,
.release = samsung_dmadev_release,
+ .config = samsung_dmadev_config,
.prepare = samsung_dmadev_prepare,
.trigger = samsung_dmadev_trigger,
.started = NULL,
+ .getposition = samsung_dmadev_getposition,
.flush = samsung_dmadev_flush,
.stop = samsung_dmadev_flush,
};
diff --git a/arch/arm/plat-samsung/include/plat/ace-core.h b/arch/arm/plat-samsung/include/plat/ace-core.h
new file mode 100644
index 0000000..7eb60b7
--- /dev/null
+++ b/arch/arm/plat-samsung/include/plat/ace-core.h
@@ -0,0 +1,26 @@
+/* linux/arch/arm/plat-s5p/include/plat/ace-core.h
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Samsung Advanced Crypto Engine core function
+ *
+ * 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.
+*/
+
+#ifndef __ASM_PLAT_ACE_CORE_H
+#define __ASM_PLAT_ACE_CORE_H __FILE__
+
+/* These functions are only for use with the core support code, such as
+ * the cpu specific initialisation code
+ */
+
+/* re-define device name depending on support. */
+static inline void s5p_ace_setname(char *name)
+{
+ s5p_device_ace.name = name;
+}
+
+#endif /* __ASM_PLAT_ACE_CORE_H */
diff --git a/arch/arm/plat-samsung/include/plat/adc.h b/arch/arm/plat-samsung/include/plat/adc.h
index b258a08..3d6d408 100644
--- a/arch/arm/plat-samsung/include/plat/adc.h
+++ b/arch/arm/plat-samsung/include/plat/adc.h
@@ -16,6 +16,11 @@
struct s3c_adc_client;
+struct s3c_adc_platdata {
+ void (*phy_init)(void);
+ void (*phy_exit)(void);
+};
+
extern int s3c_adc_start(struct s3c_adc_client *client,
unsigned int channel, unsigned int nr_samples);
@@ -32,4 +37,8 @@
extern void s3c_adc_release(struct s3c_adc_client *client);
+extern void s3c_adc_phy_init(void);
+extern void s3c_adc_phy_exit(void);
+extern void s3c_adc_set_platdata(struct s3c_adc_platdata *pd);
+
#endif /* __ASM_PLAT_ADC_H */
diff --git a/arch/arm/plat-samsung/include/plat/bts.h b/arch/arm/plat-samsung/include/plat/bts.h
new file mode 100644
index 0000000..c81c9c1
--- /dev/null
+++ b/arch/arm/plat-samsung/include/plat/bts.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * 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.
+ */
+
+#ifndef __EXYNOS_BTS_H_
+#define __EXYNOS_BTS_H_
+
+/* BTS priority values for master IP from 0 to 15 */
+enum bts_priority {
+ BTS_FBM_DDR_R1 = 0,
+ /* Best Effort */
+ BTS_PRIOR_BE = 8,
+ /* The highest priority */
+ BTS_PRIOR_HARDTIME = 15,
+};
+
+/*
+ * Some use-cases need to change the bus bandwidth of some devices to manipulate
+ * the bus traffic. So bts_bw_change says how to change the bandwidth of BTS's
+ * master IP.
+ */
+enum bts_bw_change {
+ BTS_DECREASE_BW,
+ BTS_INCREASE_BW,
+ BTS_MIXER_BW,
+};
+
+/*
+ * This order is a hardware specific recommendation about selecting deblock
+ * sources. If a BTS device needs only one FBM source for deblocking, it should
+ * select BTS_1ST_FBM_SRC first. If two FBM source needed, should select
+ * both of BTS_1ST_FBM_SRC and BTS_2ND_FBM_SRC.
+ */
+enum bts_deblock_src_order {
+ BTS_1ST_FBM_SRC = (1<<1),
+ BTS_2ND_FBM_SRC = (1<<2),
+};
+
+/*
+ * To select FBM soruce for deblocking, BTS should select the number of group
+ * and one of left and right the selected FBM belongs to. A BTS can has 6 FBM
+ * input port as an idle signal.
+ * enum bts_fbm_input_port lists up all 6 FBM input port names.
+ */
+enum bts_fbm_input_port {
+ BTS_FBM_G0_L = (1<<1),
+ BTS_FBM_G0_R = (1<<2),
+ BTS_FBM_G1_L = (1<<3),
+ BTS_FBM_G1_R = (1<<4),
+ BTS_FBM_G2_L = (1<<5),
+ BTS_FBM_G2_R = (1<<6),
+};
+
+/*
+ * Each BTS device has an action for bus traffic contorl. The BTS driver
+ * reconfigures the BTS device with it.
+ * BTS_NO_ACTION means no contol, nothing changed.
+ * BTS_ON_OFF means enabling blocking feature or not. The BTS master IP has
+ * no blocking feature if the BTS device was disabled. That's
+ * increase the bus bandwidth.
+ * BTS_CHANGE_OTHER_DEBLOCK
+ * means controling with others' BTS deviece. To increase bus
+ * bandwidth decrease others' bus bandwidth.
+ */
+enum bts_traffic_control {
+ BTS_NO_ACTION,
+ BTS_ON_OFF,
+ BTS_CHANGE_OTHER_DEBLOCK,
+};
+
+struct exynos_fbm_resource {
+ enum bts_fbm_input_port port_name;
+ enum bts_deblock_src_order deblock_src_order;
+};
+
+struct exynos_fbm_pdata {
+ struct exynos_fbm_resource *res;
+ int res_num;
+};
+
+struct exynos_bts_pdata {
+ enum bts_priority def_priority;
+ char *pd_name;
+ char *clk_name;
+ struct exynos_fbm_pdata *fbm;
+ int res_num;
+ bool deblock_changable;
+ bool threshold_changable;
+ enum bts_traffic_control traffic_control_act;
+};
+
+/* BTS API */
+/* Initialize BTS drivers only included in the same pd_block */
+void exynos_bts_initialize(char *pd_name, bool power_on);
+
+/* Change bus traffic on BTS drivers to contol bus bandwidth */
+void exynos_bts_change_bus_traffic(struct device *dev,
+ enum bts_bw_change bw_change);
+
+/* Change threshold FBM */
+void exynos_bts_change_threshold(enum bts_bw_change bw_change);
+
+#ifdef CONFIG_S5P_DEV_BTS
+#define bts_initialize(a, b) exynos_bts_initialize(a, b)
+#define bts_change_bus_traffic(a, b) exynos_bts_change_bus_traffic(a, b)
+#define bts_change_threshold(a) exynos_bts_change_threshold(a)
+#else
+#define bts_initialize(a, b) do {} while (0)
+#define bts_change_bus_traffic(a, b) do {} while (0)
+#define bts_change_threshold(a) do {} while (0)
+#endif
+#endif /* __EXYNOS_BTS_H_ */
diff --git a/arch/arm/plat-samsung/include/plat/clock-clksrc.h b/arch/arm/plat-samsung/include/plat/clock-clksrc.h
index 50a8ca7..3385000 100644
--- a/arch/arm/plat-samsung/include/plat/clock-clksrc.h
+++ b/arch/arm/plat-samsung/include/plat/clock-clksrc.h
@@ -60,6 +60,7 @@
struct clksrc_sources *sources;
struct clksrc_reg reg_src;
+ struct clksrc_reg reg_src_stat;
struct clksrc_reg reg_div;
};
diff --git a/arch/arm/plat-samsung/include/plat/clock.h b/arch/arm/plat-samsung/include/plat/clock.h
index a62753d..f1d3c9c 100644
--- a/arch/arm/plat-samsung/include/plat/clock.h
+++ b/arch/arm/plat-samsung/include/plat/clock.h
@@ -37,6 +37,7 @@
unsigned long (*get_rate)(struct clk *c);
unsigned long (*round_rate)(struct clk *c, unsigned long rate);
int (*set_parent)(struct clk *c, struct clk *parent);
+ struct clk * (*get_parent)(struct clk *c);
};
struct clk {
@@ -58,6 +59,8 @@
#endif
};
+struct clk *__clk_get_parent(struct clk*);
+
/* other clocks which may be registered by board support */
extern struct clk s3c24xx_dclk0;
@@ -88,6 +91,7 @@
extern struct clk clk_27m;
extern struct clk clk_48m;
extern struct clk clk_xusbxti;
+extern struct clk clk_xxti;
extern int clk_default_setrate(struct clk *clk, unsigned long rate);
extern struct clk_ops clk_ops_def_setrate;
diff --git a/arch/arm/plat-samsung/include/plat/cpu.h b/arch/arm/plat-samsung/include/plat/cpu.h
index 787ceac..747c27d 100644
--- a/arch/arm/plat-samsung/include/plat/cpu.h
+++ b/arch/arm/plat-samsung/include/plat/cpu.h
@@ -203,6 +203,7 @@
extern struct bus_type s5p64x0_subsys;
extern struct bus_type s5pv210_subsys;
extern struct bus_type exynos4_subsys;
+extern struct bus_type exynos5_subsys;
extern void (*s5pc1xx_idle)(void);
diff --git a/arch/arm/plat-samsung/include/plat/devs.h b/arch/arm/plat-samsung/include/plat/devs.h
index 2155d4a..dc9c971 100644
--- a/arch/arm/plat-samsung/include/plat/devs.h
+++ b/arch/arm/plat-samsung/include/plat/devs.h
@@ -84,7 +84,11 @@
extern struct platform_device s5p_device_jpeg;
extern struct platform_device s5p_device_g2d;
extern struct platform_device s5p_device_fimd0;
+extern struct platform_device s5p_device_fimd1;
+extern struct platform_device s5p_device_mipi_dsim;
+extern struct platform_device s5p_device_dp;
extern struct platform_device s5p_device_hdmi;
+extern struct platform_device s5p_device_cec;
extern struct platform_device s5p_device_i2c_hdmiphy;
extern struct platform_device s5p_device_mfc;
extern struct platform_device s5p_device_mfc_l;
@@ -94,6 +98,8 @@
extern struct platform_device s5p_device_mixer;
extern struct platform_device s5p_device_onenand;
extern struct platform_device s5p_device_sdo;
+extern struct platform_device s5p_device_ace;
+extern struct platform_device s5p_device_jpeg;
extern struct platform_device s5p6440_device_iis;
extern struct platform_device s5p6440_device_pcm;
@@ -133,12 +139,38 @@
extern struct platform_device exynos4_device_pcm2;
extern struct platform_device exynos4_device_pd[];
extern struct platform_device exynos4_device_spdif;
-extern struct platform_device exynos4_device_sysmmu;
+extern struct platform_device exynos_device_ss_udc;
+
+extern struct platform_device exynos5_device_dwmci0;
+extern struct platform_device exynos5_device_dwmci1;
+extern struct platform_device exynos5_device_dwmci2;
+extern struct platform_device exynos5_device_dwmci3;
+extern struct platform_device exynos5_device_pcm0;
+extern struct platform_device exynos5_device_pcm1;
+extern struct platform_device exynos5_device_pcm2;
+extern struct platform_device exynos5_device_srp;
+extern struct platform_device exynos5_device_i2s0;
+extern struct platform_device exynos5_device_i2s1;
+extern struct platform_device exynos5_device_i2s2;
+extern struct platform_device exynos5_device_spdif;
+extern struct platform_device exynos_device_flite0;
+extern struct platform_device exynos_device_flite1;
+extern struct platform_device exynos5_device_rotator;
+
+extern struct platform_device exynos5_device_gsc0;
+extern struct platform_device exynos5_device_gsc1;
+extern struct platform_device exynos5_device_gsc2;
+extern struct platform_device exynos5_device_gsc3;
+extern struct platform_device exynos5_device_fimc_is;
extern struct platform_device samsung_asoc_dma;
extern struct platform_device samsung_asoc_idma;
extern struct platform_device samsung_device_keypad;
+extern struct platform_device s5p_device_fimg2d;
+#ifdef CONFIG_MALI_T6XX
+extern struct platform_device exynos5_device_g3d;
+#endif
/* s3c2440 specific devices */
#ifdef CONFIG_CPU_S3C2440
diff --git a/arch/arm/plat-samsung/include/plat/dma-ops.h b/arch/arm/plat-samsung/include/plat/dma-ops.h
index 71a6827..8126c34 100644
--- a/arch/arm/plat-samsung/include/plat/dma-ops.h
+++ b/arch/arm/plat-samsung/include/plat/dma-ops.h
@@ -16,7 +16,13 @@
#include <linux/dmaengine.h>
#include <mach/dma.h>
-struct samsung_dma_prep_info {
+struct samsung_dma_req {
+ enum dma_transaction_type cap;
+ struct property *dt_dmach_prop;
+ struct s3c2410_dma_client *client;
+};
+
+struct samsung_dma_prep {
enum dma_transaction_type cap;
enum dma_transfer_direction direction;
dma_addr_t buf;
@@ -24,23 +30,23 @@
unsigned long len;
void (*fp)(void *data);
void *fp_param;
+ unsigned int infiniteloop;
};
-struct samsung_dma_info {
- enum dma_transaction_type cap;
+struct samsung_dma_config {
enum dma_transfer_direction direction;
enum dma_slave_buswidth width;
dma_addr_t fifo;
- struct s3c2410_dma_client *client;
- struct property *dt_dmach_prop;
};
struct samsung_dma_ops {
- unsigned (*request)(enum dma_ch ch, struct samsung_dma_info *info);
- int (*release)(unsigned ch, struct s3c2410_dma_client *client);
- int (*prepare)(unsigned ch, struct samsung_dma_prep_info *info);
+ unsigned (*request)(enum dma_ch ch, struct samsung_dma_req *param);
+ int (*release)(unsigned ch, void *param);
+ int (*config)(unsigned ch, struct samsung_dma_config *param);
+ int (*prepare)(unsigned ch, struct samsung_dma_prep *param);
int (*trigger)(unsigned ch);
int (*started)(unsigned ch);
+ int (*getposition)(unsigned ch, dma_addr_t *src, dma_addr_t *dst);
int (*flush)(unsigned ch);
int (*stop)(unsigned ch);
};
diff --git a/arch/arm/plat-samsung/include/plat/dma-pl330.h b/arch/arm/plat-samsung/include/plat/dma-pl330.h
index 0670f37..336437a 100644
--- a/arch/arm/plat-samsung/include/plat/dma-pl330.h
+++ b/arch/arm/plat-samsung/include/plat/dma-pl330.h
@@ -90,6 +90,7 @@
DMACH_MIPI_HSI5,
DMACH_MIPI_HSI6,
DMACH_MIPI_HSI7,
+ DMACH_DISP1,
DMACH_MTOM_0,
DMACH_MTOM_1,
DMACH_MTOM_2,
@@ -116,6 +117,11 @@
return true;
}
+static inline bool samsung_dma_has_infiniteloop(void)
+{
+ return true;
+}
+
#include <plat/dma-ops.h>
#endif /* __DMA_PL330_H_ */
diff --git a/arch/arm/plat-samsung/include/plat/dp.h b/arch/arm/plat-samsung/include/plat/dp.h
new file mode 100644
index 0000000..ee05c5c
--- /dev/null
+++ b/arch/arm/plat-samsung/include/plat/dp.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2012 Samsung Electronics Co., Ltd.
+ *
+ * Samsung SoC series DP device support
+ *
+ * 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.
+ */
+
+#ifndef PLAT_SAMSUNG_DP_H_
+#define PLAT_SAMSUNG_DP_H_ __FILE__
+
+#include <video/s5p-dp.h>
+
+extern void s5p_dp_set_platdata(struct s5p_dp_platdata *pd);
+extern void s5p_dp_phy_init(void);
+extern void s5p_dp_phy_exit(void);
+
+#endif /* PLAT_SAMSUNG_DP_H_ */
diff --git a/arch/arm/plat-samsung/include/plat/dsim.h b/arch/arm/plat-samsung/include/plat/dsim.h
new file mode 100644
index 0000000..bbfb52b
--- /dev/null
+++ b/arch/arm/plat-samsung/include/plat/dsim.h
@@ -0,0 +1,330 @@
+/* linux/arm/arch/plat-s5p/include/plat/dsim.h
+ *
+ * Platform data header for Samsung SoC MIPI-DSIM.
+ *
+ * Copyright (c) 2011 Samsung Electronics
+ *
+ * InKi Dae <inki.dae@samsung.com>
+ *
+ * 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.
+*/
+
+#ifndef _DSIM_H
+#define _DSIM_H
+
+#include <linux/device.h>
+#include <linux/fb.h>
+#include <linux/notifier.h>
+
+#include <linux/regulator/consumer.h>
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif
+
+#define to_dsim_plat(d) (to_platform_device(d)->dev.platform_data)
+
+enum mipi_dsim_interface_type {
+ DSIM_COMMAND,
+ DSIM_VIDEO
+};
+
+enum mipi_dsim_virtual_ch_no {
+ DSIM_VIRTUAL_CH_0,
+ DSIM_VIRTUAL_CH_1,
+ DSIM_VIRTUAL_CH_2,
+ DSIM_VIRTUAL_CH_3
+};
+
+enum mipi_dsim_burst_mode_type {
+ DSIM_NON_BURST_SYNC_EVENT,
+ DSIM_NON_BURST_SYNC_PULSE = 2,
+ DSIM_BURST = 1,
+ DSIM_NON_VIDEO_MODE = 4
+};
+
+enum mipi_dsim_no_of_data_lane {
+ DSIM_DATA_LANE_1,
+ DSIM_DATA_LANE_2,
+ DSIM_DATA_LANE_3,
+ DSIM_DATA_LANE_4
+};
+
+enum mipi_dsim_byte_clk_src {
+ DSIM_PLL_OUT_DIV8,
+ DSIM_EXT_CLK_DIV8,
+ DSIM_EXT_CLK_BYPASS
+};
+
+enum mipi_dsim_pixel_format {
+ DSIM_CMD_3BPP,
+ DSIM_CMD_8BPP,
+ DSIM_CMD_12BPP,
+ DSIM_CMD_16BPP,
+ DSIM_VID_16BPP_565,
+ DSIM_VID_18BPP_666PACKED,
+ DSIM_18BPP_666LOOSELYPACKED,
+ DSIM_24BPP_888
+};
+
+/**
+ * struct mipi_dsim_config - interface for configuring mipi-dsi controller.
+ *
+ * @auto_flush: enable or disable Auto flush of MD FIFO using VSYNC pulse.
+ * @eot_disable: enable or disable EoT packet in HS mode.
+ * @auto_vertical_cnt: specifies auto vertical count mode.
+ * in Video mode, the vertical line transition uses line counter
+ * configured by VSA, VBP, and Vertical resolution.
+ * If this bit is set to '1', the line counter does not use VSA and VBP
+ * registers.(in command mode, this variable is ignored)
+ * @hse: set horizontal sync event mode.
+ * In VSYNC pulse and Vporch area, MIPI DSI master transfers only HSYNC
+ * start packet to MIPI DSI slave at MIPI DSI spec1.1r02.
+ * this bit transfers HSYNC end packet in VSYNC pulse and Vporch area
+ * (in mommand mode, this variable is ignored)
+ * @hfp: specifies HFP disable mode.
+ * if this variable is set, DSI master ignores HFP area in VIDEO mode.
+ * (in command mode, this variable is ignored)
+ * @hbp: specifies HBP disable mode.
+ * if this variable is set, DSI master ignores HBP area in VIDEO mode.
+ * (in command mode, this variable is ignored)
+ * @hsa: specifies HSA disable mode.
+ * if this variable is set, DSI master ignores HSA area in VIDEO mode.
+ * (in command mode, this variable is ignored)
+ * @e_interface: specifies interface to be used.(CPU or RGB interface)
+ * @e_virtual_ch: specifies virtual channel number that main or
+ * sub diaplsy uses.
+ * @e_pixel_format: specifies pixel stream format for main or sub display.
+ * @e_burst_mode: selects Burst mode in Video mode.
+ * in Non-burst mode, RGB data area is filled with RGB data and NULL
+ * packets, according to input bandwidth of RGB interface.
+ * In Burst mode, RGB data area is filled with RGB data only.
+ * @e_no_data_lane: specifies data lane count to be used by Master.
+ * @e_byte_clk: select byte clock source. (it must be DSIM_PLL_OUT_DIV8)
+ * DSIM_EXT_CLK_DIV8 and DSIM_EXT_CLK_BYPASSS are not supported.
+ * @pll_stable_time: specifies the PLL Timer for stability of the ganerated
+ * clock(System clock cycle base)
+ * if the timer value goes to 0x00000000, the clock stable bit of
+status
+ * and interrupt register is set.
+ * @esc_clk: specifies escape clock frequency for getting the escape clock
+ * prescaler value.
+ * @stop_holding_cnt: specifies the interval value between transmitting
+ * read packet(or write "set_tear_on" command) and BTA request.
+ * after transmitting read packet or write "set_tear_on" command,
+ * BTA requests to D-PHY automatically. this counter value specifies
+ * the interval between them.
+ * @bta_timeout: specifies the timer for BTA.
+ * this register specifies time out from BTA request to change
+ * the direction with respect to Tx escape clock.
+ * @rx_timeout: specifies the timer for LP Rx mode timeout.
+ * this register specifies time out on how long RxValid deasserts,
+ * after RxLpdt asserts with respect to Tx escape clock.
+ * - RxValid specifies Rx data valid indicator.
+ * - RxLpdt specifies an indicator that D-PHY is under RxLpdt mode.
+ * - RxValid and RxLpdt specifies signal from D-PHY.
+ * @lcd_panel_info: pointer for lcd panel specific structure.
+ * this structure specifies width, height, timing and polarity and so
+on.
+ * @mipi_ddi_pd: pointer to lcd panel platform data.
+ */
+struct mipi_dsim_config {
+ unsigned char auto_flush;
+ unsigned char eot_disable;
+
+ unsigned char auto_vertical_cnt;
+ unsigned char hse;
+ unsigned char hfp;
+ unsigned char hbp;
+ unsigned char hsa;
+
+ enum mipi_dsim_interface_type e_interface;
+ enum mipi_dsim_virtual_ch_no e_virtual_ch;
+ enum mipi_dsim_pixel_format e_pixel_format;
+ enum mipi_dsim_burst_mode_type e_burst_mode;
+ enum mipi_dsim_no_of_data_lane e_no_data_lane;
+ enum mipi_dsim_byte_clk_src e_byte_clk;
+
+ unsigned char p;
+ unsigned short m;
+ unsigned char s;
+
+ unsigned int pll_stable_time;
+ unsigned long esc_clk;
+
+ unsigned short stop_holding_cnt;
+ unsigned char bta_timeout;
+ unsigned short rx_timeout;
+
+ void *lcd_panel_info;
+ void *dsim_ddi_pd;
+};
+
+/* for RGB Interface */
+struct mipi_dsi_lcd_timing {
+ int left_margin;
+ int right_margin;
+ int upper_margin;
+ int lower_margin;
+ int hsync_len;
+ int vsync_len;
+};
+
+/* for CPU Interface */
+struct mipi_dsi_cpu_timing {
+ unsigned int cs_setup;
+ unsigned int wr_setup;
+ unsigned int wr_act;
+ unsigned int wr_hold;
+};
+
+struct mipi_dsi_lcd_size {
+ unsigned int width;
+ unsigned int height;
+};
+
+struct mipi_dsim_lcd_config {
+ enum mipi_dsim_interface_type e_interface;
+ unsigned int parameter[3];
+
+ /* lcd panel info */
+ struct mipi_dsi_lcd_timing rgb_timing;
+ struct mipi_dsi_cpu_timing cpu_timing;
+ struct mipi_dsi_lcd_size lcd_size;
+ /* platform data for lcd panel based on MIPI-DSI. */
+ void *mipi_ddi_pd;
+};
+
+/**
+ * struct mipi_dsim_device - global interface for mipi-dsi driver.
+ *
+ * @dev: driver model representation of the device.
+ * @clock: pointer to MIPI-DSI clock of clock framework.
+ * @irq: interrupt number to MIPI-DSI controller.
+ * @reg_base: base address to memory mapped SRF of MIPI-DSI controller.
+ * (virtual address)
+ * @pd: pointer to MIPI-DSI driver platform data.
+ * @dsim_info: infomation for configuring mipi-dsi controller.
+ * @master_ops: callbacks to mipi-dsi operations.
+ * @lcd_info: pointer to mipi_lcd_info structure.
+ * @state: specifies status of MIPI-DSI controller.
+ * the status could be RESET, INIT, STOP, HSCLKEN and ULPS.
+ * @data_lane: specifiec enabled data lane number.
+ * this variable would be set by driver according to e_no_data_lane
+ * automatically.
+ * @e_clk_src: select byte clock source.
+ * this variable would be set by driver according to e_byte_clock
+ * automatically.
+ * @hs_clk: HS clock rate.
+ * this variable would be set by driver automatically.
+ * @byte_clk: Byte clock rate.
+ * this variable would be set by driver automatically.
+ * @escape_clk: ESCAPE clock rate.
+ * this variable would be set by driver automatically.
+ * @freq_band: indicates Bitclk frequency band for D-PHY global timing.
+ * Serial Clock(=ByteClk X 8) FreqBand[3:0]
+ * ~ 99.99 MHz 0000
+ * 100 ~ 119.99 MHz 0001
+ * 120 ~ 159.99 MHz 0010
+ * 160 ~ 199.99 MHz 0011
+ * 200 ~ 239.99 MHz 0100
+ * 140 ~ 319.99 MHz 0101
+ * 320 ~ 389.99 MHz 0110
+ * 390 ~ 449.99 MHz 0111
+ * 450 ~ 509.99 MHz 1000
+ * 510 ~ 559.99 MHz 1001
+ * 560 ~ 639.99 MHz 1010
+ * 640 ~ 689.99 MHz 1011
+ * 690 ~ 769.99 MHz 1100
+ * 770 ~ 869.99 MHz 1101
+ * 870 ~ 949.99 MHz 1110
+ * 950 ~ 1000 MHz 1111
+ * this variable would be calculated by driver automatically.
+ */
+struct mipi_dsim_device {
+ struct device *dev;
+ struct resource *res;
+ struct clk *clock;
+ unsigned int irq;
+ void __iomem *reg_base;
+
+ struct s5p_platform_mipi_dsim *pd;
+ struct mipi_dsim_config *dsim_config;
+
+ unsigned int state;
+ unsigned int data_lane;
+ enum mipi_dsim_byte_clk_src e_clk_src;
+ unsigned long hs_clk;
+ unsigned long byte_clk;
+ unsigned long escape_clk;
+ unsigned char freq_band;
+ unsigned char id;
+ struct notifier_block fb_notif;
+
+ struct mipi_dsim_lcd_driver *dsim_lcd_drv;
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ struct early_suspend early_suspend;
+#endif
+};
+
+/**
+ * struct s5p_platform_mipi_dsim - interface to platform data
+ * for mipi-dsi driver.
+ *
+ * @mipi_dsim_config: pointer of structure for configuring mipi-dsi controller.
+ * @dsim_lcd_info: pointer to structure for configuring
+ * mipi-dsi based lcd panel.
+ * @mipi_power: callback pointer for enabling or disabling mipi power.
+ * @part_reset: callback pointer for reseting mipi phy.
+ * @init_d_phy: callback pointer for enabing d_phy of dsi master.
+ * @get_fb_frame_done: callback pointer for getting frame done status of
+the
+ * display controller(FIMD).
+ * @trigger: callback pointer for triggering display controller(FIMD)
+ * in case of CPU mode.
+ * @delay_for_stabilization: specifies stable time.
+ * this delay needs when writing data on SFR
+ * after mipi mode became LP mode.
+ */
+struct s5p_platform_mipi_dsim {
+ const char clk_name[16];
+
+ struct mipi_dsim_config *dsim_config;
+ struct mipi_dsim_lcd_config *dsim_lcd_config;
+
+ unsigned int delay_for_stabilization;
+
+ int (*mipi_power) (struct mipi_dsim_device *dsim, unsigned int
+ enable);
+ int (*part_reset) (struct mipi_dsim_device *dsim);
+ int (*init_d_phy) (struct mipi_dsim_device *dsim, unsigned int enable);
+ int (*get_fb_frame_done) (struct fb_info *info);
+ void (*trigger) (struct fb_info *info);
+};
+
+/**
+ * driver structure for mipi-dsi based lcd panel.
+ *
+ * this structure should be registered by lcd panel driver.
+ * mipi-dsi driver seeks lcd panel registered through name field
+ * and calls these callback functions in appropriate time.
+ */
+
+struct mipi_dsim_lcd_driver {
+ int (*probe)(struct mipi_dsim_device *dsim);
+ int (*suspend)(struct mipi_dsim_device *dsim);
+ int (*displayon)(struct mipi_dsim_device *dsim);
+ int (*resume)(struct mipi_dsim_device *dsim);
+};
+
+/**
+ * register mipi_dsim_lcd_driver object defined by lcd panel driver
+ * to mipi-dsi driver.
+ */
+extern int s5p_dsim_part_reset(struct mipi_dsim_device *dsim);
+extern int s5p_dsim_init_d_phy(struct mipi_dsim_device *dsim,
+ unsigned int enable);
+extern void s5p_dsim_set_platdata(struct s5p_platform_mipi_dsim * pd);
+#endif /* _DSIM_H */
diff --git a/arch/arm/plat-samsung/include/plat/fb-core.h b/arch/arm/plat-samsung/include/plat/fb-core.h
index 6abcbf1..4335840 100644
--- a/arch/arm/plat-samsung/include/plat/fb-core.h
+++ b/arch/arm/plat-samsung/include/plat/fb-core.h
@@ -35,6 +35,12 @@
s5p_device_fimd0.name = name;
break;
#endif
+
+#ifdef CONFIG_S5P_DEV_FIMD1
+ case 1:
+ s5p_device_fimd1.name = name;
+ break;
+#endif
default:
printk(KERN_ERR "%s: invalid device id(%d)\n", __func__, id);
break;
diff --git a/arch/arm/plat-samsung/include/plat/fb.h b/arch/arm/plat-samsung/include/plat/fb.h
index 0fedf47..3997755 100644
--- a/arch/arm/plat-samsung/include/plat/fb.h
+++ b/arch/arm/plat-samsung/include/plat/fb.h
@@ -15,18 +15,15 @@
#ifndef __PLAT_S3C_FB_H
#define __PLAT_S3C_FB_H __FILE__
-/* S3C_FB_MAX_WIN
- * Set to the maximum number of windows that any of the supported hardware
- * can use. Since the platform data uses this for an array size, having it
- * set to the maximum of any version of the hardware can do is safe.
- */
-#define S3C_FB_MAX_WIN (5)
+#include <linux/s3c-fb.h>
/**
* struct s3c_fb_pd_win - per window setup data
* @win_mode: The display parameters to initialise (not for window 0)
* @virtual_x: The virtual X size.
* @virtual_y: The virtual Y size.
+ * @width: The width of display in mm
+ * @height: The height of display in mm
*/
struct s3c_fb_pd_win {
struct fb_videomode win_mode;
@@ -35,6 +32,8 @@
unsigned short max_bpp;
unsigned short virtual_x;
unsigned short virtual_y;
+ unsigned short width;
+ unsigned short height;
};
/**
@@ -56,6 +55,8 @@
*/
struct s3c_fb_platdata {
void (*setup_gpio)(void);
+ void (*backlight_off)(void);
+ void (*lcd_off)(void);
struct s3c_fb_pd_win *win[S3C_FB_MAX_WIN];
@@ -82,6 +83,14 @@
extern void s5p_fimd0_set_platdata(struct s3c_fb_platdata *pd);
/**
+ * s5p_fimd1_set_platdata() - Setup the FB device with platform data.
+ * @pd: The platform data to set. The data is copied from the passed structure
+ * so the machine data can mark the data __initdata so that any unused
+ * machines will end up dumping their data at runtime.
+ */
+extern void s5p_fimd1_set_platdata(struct s3c_fb_platdata *pd);
+
+/**
* s3c64xx_fb_gpio_setup_24bpp() - S3C64XX setup function for 24bpp LCD
*
* Initialise the GPIO for an 24bpp LCD display on the RGB interface.
@@ -110,10 +119,26 @@
extern void exynos4_fimd0_gpio_setup_24bpp(void);
/**
+ * exynos5_fimd1_gpio_setup_24bpp() - Exynos5 setup function for 24bpp LCD0
+ *
+ * Initialise the GPIO for an 24bpp LCD display on the RGB interface 1.
+ */
+extern void exynos5_fimd1_gpio_setup_24bpp(void);
+
+/**
* s5p64x0_fb_gpio_setup_24bpp() - S5P6440/S5P6450 setup function for 24bpp LCD
*
* Initialise the GPIO for an 24bpp LCD display on the RGB interface.
*/
extern void s5p64x0_fb_gpio_setup_24bpp(void);
+/**
+ * exynos5_fimd1_setup_clock() = Exynos5 setup function for parent clock.
+ * @dev: device pointer
+ * @parent: parent clock used for LCD pixel clock
+ * @clk_rate: clock rate for parent clock
+ */
+extern int __init exynos5_fimd1_setup_clock(struct device *dev, const char *bus_clk,
+ const char *parent, unsigned long clk_rate);
+
#endif /* __PLAT_S3C_FB_H */
diff --git a/arch/arm/plat-samsung/include/plat/fimg2d.h b/arch/arm/plat-samsung/include/plat/fimg2d.h
new file mode 100644
index 0000000..2a2e622
--- /dev/null
+++ b/arch/arm/plat-samsung/include/plat/fimg2d.h
@@ -0,0 +1,26 @@
+/* linux/arch/arm/plat-s5p/include/plat/fimg2d.h
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Platform Data Structure for Samsung Graphics 2D Hardware
+ *
+ * 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.
+*/
+
+#ifndef __ASM_ARCH_FIMG2D_H
+#define __ASM_ARCH_FIMG2D_H __FILE__
+
+struct fimg2d_platdata {
+ int hw_ver;
+ const char *parent_clkname;
+ const char *clkname;
+ const char *gate_clkname;
+ unsigned long clkrate;
+};
+
+extern void __init s5p_fimg2d_set_platdata(struct fimg2d_platdata *pd);
+
+#endif /* __ASM_ARCH_FIMG2D_H */
diff --git a/arch/arm/plat-samsung/include/plat/gpio-cfg.h b/arch/arm/plat-samsung/include/plat/gpio-cfg.h
index df8155b..8896b63 100644
--- a/arch/arm/plat-samsung/include/plat/gpio-cfg.h
+++ b/arch/arm/plat-samsung/include/plat/gpio-cfg.h
@@ -28,6 +28,8 @@
typedef unsigned int __bitwise__ samsung_gpio_pull_t;
typedef unsigned int __bitwise__ s5p_gpio_drvstr_t;
+typedef unsigned int __bitwise__ s5p_gpio_pd_cfg_t;
+typedef unsigned int __bitwise__ s5p_gpio_pd_pull_t;
/* forward declaration if gpio-core.h hasn't been included */
struct samsung_gpio_chip;
@@ -209,6 +211,65 @@
*/
extern int s5p_gpio_set_drvstr(unsigned int pin, s5p_gpio_drvstr_t drvstr);
+/* Define values for the power down configuration available for each gpio pin.
+ *
+ * These values control the state of the power down configuration resistors
+ * available on most pins on the S5P series.
+ */
+#define S5P_GPIO_PD_OUTPUT0 ((__force s5p_gpio_pd_cfg_t)0x00)
+#define S5P_GPIO_PD_OUTPUT1 ((__force s5p_gpio_pd_cfg_t)0x01)
+#define S5P_GPIO_PD_INPUT ((__force s5p_gpio_pd_cfg_t)0x02)
+#define S5P_GPIO_PD_PREV_STATE ((__force s5p_gpio_pd_cfg_t)0x03)
+
+/**
+ * s5p_gpio_set_pd_cfg() - set the configuration of a gpio power down mode
+ * @pin: The pin number to configure the pull resistor.
+ * @pd_cfg: The configuration for the pwer down mode configuration register.
+ *
+ * This function sets the configuration of the power down mode resistor for the
+ * specified pin. It will return 0 if successful, or a negative error
+ * code if the pin cannot support the requested power down mode.
+ *
+*/
+extern int s5p_gpio_set_pd_cfg(unsigned int pin, s5p_gpio_pd_cfg_t pd_cfg);
+
+/**
+ * s5p_gpio_get_pd_cfg() - get the power down mode configuration of a gpio pin
+ * @pin: The pin number to get the settings for
+ *
+ * Read the power down mode resistor value for the specified pin.
+*/
+extern s5p_gpio_pd_cfg_t s5p_gpio_get_pd_cfg(unsigned int pin);
+
+/* Define values for the power down pull-{up,down} available for each gpio pin.
+ *
+ * These values control the state of the power down mode pull-{up,down}
+ * resistors available on most pins on the S5P series.
+ */
+#define S5P_GPIO_PD_UPDOWN_DISABLE ((__force s5p_gpio_pd_pull_t)0x00)
+#define S5P_GPIO_PD_DOWN_ENABLE ((__force s5p_gpio_pd_pull_t)0x01)
+#define S5P_GPIO_PD_UP_ENABLE ((__force s5p_gpio_pd_pull_t)0x03)
+
+/**
+ * s5p_gpio_set_pd_pull() - set the pull-{up,down} of a gpio pin power down mode
+ * @pin: The pin number to configure the pull resistor.
+ * @pd_pull: The configuration for the power down mode pull resistor.
+ *
+ * This function sets the configuration of the pull-{up,down} resistor for the
+ * specified pin. It will return 0 if successful, or a negative error
+ * code if the pin cannot support the requested pull setting.
+ *
+ */
+extern int s5p_gpio_set_pd_pull(unsigned int pin, s5p_gpio_pd_pull_t pd_pull);
+
+/**
+ * s5p_gpio_get_pd_pull() - get the power down pull resistor config of gpio pin
+ * @pin: The pin number to get the settings for
+ *
+ * Read the power mode pull resistor value for the specified pin.
+ */
+extern s5p_gpio_pd_pull_t s5p_gpio_get_pd_pull(unsigned int pin);
+
/**
* s5p_register_gpio_interrupt() - register interrupt support for a gpio group
* @pin: The pin number from the group to be registered
diff --git a/arch/arm/plat-samsung/include/plat/gpio-core.h b/arch/arm/plat-samsung/include/plat/gpio-core.h
index 1fe6917..f0792ff 100644
--- a/arch/arm/plat-samsung/include/plat/gpio-core.h
+++ b/arch/arm/plat-samsung/include/plat/gpio-core.h
@@ -69,7 +69,7 @@
int group;
spinlock_t lock;
#ifdef CONFIG_PM
- u32 pm_save[4];
+ u32 pm_save[7];
#endif
};
diff --git a/arch/arm/plat-samsung/include/plat/iovmm.h b/arch/arm/plat-samsung/include/plat/iovmm.h
new file mode 100644
index 0000000..f5cb2fe
--- /dev/null
+++ b/arch/arm/plat-samsung/include/plat/iovmm.h
@@ -0,0 +1,74 @@
+/* linux/arch/arm/plat-s5p/include/plat/iovmm.h
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * 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.
+ */
+
+#ifndef __ASM_PLAT_IOVMM_H
+#define __ASM_PLAT_IOVMM_H
+
+#ifdef CONFIG_EXYNOS_IOVMM
+struct scatterlist;
+struct device;
+
+int iovmm_activate(struct device *dev);
+void iovmm_deactivate(struct device *dev);
+
+/* iovmm_map() - Maps a list of physical memory chunks
+ * @dev: the owner of the IO address space where the mapping is created
+ * @sg: list of physical memory chunks to map
+ * @offset: length in bytes where the mapping starts
+ * @size: how much memory to map in bytes. @offset + @size must not exceed
+ * total size of @sg
+ *
+ * This function returns mapped IO address in the address space of @dev.
+ * Returns minus error number if mapping fails.
+ * Caller must check its return code with IS_ERROR_VALUE() if the function
+ * succeeded.
+ *
+ * The caller of this function must ensure that iovmm_cleanup() is not called
+ * while this function is called.
+ *
+ */
+dma_addr_t iovmm_map(struct device *dev, struct scatterlist *sg, off_t offset,
+ size_t size);
+
+/* iovmm_unmap() - unmaps the given IO address
+ * @dev: the owner of the IO address space where @iova belongs
+ * @iova: IO address that needs to be unmapped and freed.
+ *
+ * The caller of this function must ensure that iovmm_cleanup() is not called
+ * while this function is called.
+ */
+void iovmm_unmap(struct device *dev, dma_addr_t iova);
+
+/* iovmm_map_oto - create one to one mapping for the given physical address
+ * @dev: the owner of the IO address space to map
+ * @phys: physical address to map
+ * @size: size of the mapping to create
+ *
+ * This function return 0 if mapping is successful. Otherwise, minus error
+ * value.
+ */
+int iovmm_map_oto(struct device *dev, phys_addr_t phys, size_t size);
+
+/* iovmm_unmap_oto - remove one to one mapping
+ * @dev: the owner ofthe IO address space
+ * @phys: physical address to remove mapping
+ */
+void iovmm_unmap_oto(struct device *dev, phys_addr_t phys);
+
+#else
+#define iovmm_activate(dev) (-ENOSYS)
+#define iovmm_deactivate(dev) do { } while (0)
+#define iovmm_map(dev, sg, offset, size) (-ENOSYS)
+#define iovmm_unmap(dev, iova) do { } while (0)
+#define iovmm_map_oto(dev, phys, size) (-ENOSYS)
+#define iovmm_unmap_oto(dev, phys) do { } while (0)
+#endif /* CONFIG_EXYNOS_IOVMM */
+
+#endif /*__ASM_PLAT_IOVMM_H*/
diff --git a/arch/arm/plat-samsung/include/plat/jpeg.h b/arch/arm/plat-samsung/include/plat/jpeg.h
new file mode 100644
index 0000000..94e8656
--- /dev/null
+++ b/arch/arm/plat-samsung/include/plat/jpeg.h
@@ -0,0 +1,17 @@
+/* linux/arch/arm/plat-samsung/include/plat/jpeg.h
+ *
+ * Copyright 201i Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * 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.
+*/
+#ifndef __ASM_PLAT_JPEG_H
+#define __ASM_PLAT_JPEG_H __FILE__
+
+int __init exynos4_jpeg_setup_clock(struct device *dev,
+ unsigned long clk_rate);
+int __init exynos5_jpeg_setup_clock(struct device *dev,
+ unsigned long clk_rate);
+#endif /*__ASM_PLAT_JPEG_H */
diff --git a/arch/arm/plat-samsung/include/plat/map-s5p.h b/arch/arm/plat-samsung/include/plat/map-s5p.h
index c2d7bda..cc375be 100644
--- a/arch/arm/plat-samsung/include/plat/map-s5p.h
+++ b/arch/arm/plat-samsung/include/plat/map-s5p.h
@@ -22,6 +22,7 @@
#define S5P_VA_GPIO3 S3C_ADDR(0x02280000)
#define S5P_VA_SYSRAM S3C_ADDR(0x02400000)
+#define S5P_VA_SYSRAM_NS S3C_ADDR(0x02410000)
#define S5P_VA_DMC0 S3C_ADDR(0x02440000)
#define S5P_VA_DMC1 S3C_ADDR(0x02480000)
#define S5P_VA_SROMC S3C_ADDR(0x024C0000)
@@ -40,6 +41,23 @@
#define S5P_VA_GIC_CPU S3C_ADDR(0x02810000)
#define S5P_VA_GIC_DIST S3C_ADDR(0x02820000)
+#define S5P_VA_PPMU_CPU S3C_ADDR(0x02830000)
+#define S5P_VA_PPMU_DDR_C S3C_ADDR(0x02832000)
+#define S5P_VA_PPMU_DDR_R1 S3C_ADDR(0x02834000)
+#define S5P_VA_PPMU_DDR_L S3C_ADDR(0x02836000)
+#define S5P_VA_PPMU_RIGHT S3C_ADDR(0x02838000)
+
+#define S5P_VA_AUDSS S3C_ADDR(0x02910000)
+
+#define S5P_VA_SS_PHY S3C_ADDR(0x02A00000)
+
+#define S5P_VA_FIMCLITE0 S3C_ADDR(0x02A10000)
+#define S5P_VA_FIMCLITE1 S3C_ADDR(0x02A20000)
+#define S5P_VA_MIPICSI0 S3C_ADDR(0x02A30000)
+#define S5P_VA_MIPICSI1 S3C_ADDR(0x02A40000)
+#define S5P_VA_FIMCLITE2 S3C_ADDR(0x02A90000)
+#define S5P_VA_DREXII S3C_ADDR(0x02AA0000)
+
#define VA_VIC(x) (S3C_VA_IRQ + ((x) * 0x10000))
#define VA_VIC0 VA_VIC(0)
#define VA_VIC1 VA_VIC(1)
diff --git a/arch/arm/plat-samsung/include/plat/mipi_csis.h b/arch/arm/plat-samsung/include/plat/mipi_csis.h
index c45b1e8..de30c24 100644
--- a/arch/arm/plat-samsung/include/plat/mipi_csis.h
+++ b/arch/arm/plat-samsung/include/plat/mipi_csis.h
@@ -39,5 +39,7 @@
* false to disable D-PHY
*/
int s5p_csis_phy_enable(struct platform_device *pdev, bool on);
+extern struct s5p_platform_mipi_csis s5p_mipi_csis0_default_data;
+extern struct s5p_platform_mipi_csis s5p_mipi_csis1_default_data;
#endif /* __PLAT_SAMSUNG_MIPI_CSIS_H_ */
diff --git a/arch/arm/plat-samsung/include/plat/mipi_dsi.h b/arch/arm/plat-samsung/include/plat/mipi_dsi.h
new file mode 100644
index 0000000..9fcde67
--- /dev/null
+++ b/arch/arm/plat-samsung/include/plat/mipi_dsi.h
@@ -0,0 +1,51 @@
+/* linux/arm/arch/mach-s5pc110/include/plat/mipi_dsi.h
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics
+ * InKi Dae <inki.dae <at> samsung.com>
+ *
+ * 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.
+*/
+
+#ifndef _MIPI_DSI_H
+#define _MIPI_DSI_H
+
+#if defined(CONFIG_LCD_MIPI_S6E8AB0)
+extern struct mipi_dsim_lcd_driver s6e8ab0_mipi_lcd_driver;
+#elif defined (CONFIG_LCD_MIPI_S6E63M0)
+extern struct mipi_dsim_lcd_driver s6e63m0_mipi_lcd_driver;
+#elif defined (CONFIG_LCD_MIPI_TC358764)
+extern struct mipi_dsim_lcd_driver tc358764_mipi_lcd_driver;
+#endif
+
+extern int s5p_mipi_dsi_wr_data(struct mipi_dsim_device *dsim,
+ unsigned int data_id, unsigned int data0, unsigned int data1);
+
+enum mipi_ddi_interface {
+ RGB_IF = 0x4000,
+ I80_IF = 0x8000,
+ YUV_601 = 0x10000,
+ YUV_656 = 0x20000,
+ MIPI_VIDEO = 0x1000,
+ MIPI_COMMAND = 0x2000,
+};
+
+enum mipi_ddi_panel_select {
+ DDI_MAIN_LCD = 0,
+ DDI_SUB_LCD = 1,
+};
+
+enum mipi_ddi_model {
+ S6DR117 = 0,
+};
+
+enum mipi_ddi_parameter {
+ /* DSIM video interface parameter */
+ DSI_VIRTUAL_CH_ID = 0,
+ DSI_FORMAT = 1,
+ DSI_VIDEO_MODE_SEL = 2,
+};
+
+#endif /* _MIPI_DSI_H */
diff --git a/arch/arm/plat-samsung/include/plat/pd.h b/arch/arm/plat-samsung/include/plat/pd.h
deleted file mode 100644
index abb4bc3..0000000
--- a/arch/arm/plat-samsung/include/plat/pd.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/* linux/arch/arm/plat-samsung/include/plat/pd.h
- *
- * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
- * http://www.samsung.com
- *
- * 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.
-*/
-
-#ifndef __ASM_PLAT_SAMSUNG_PD_H
-#define __ASM_PLAT_SAMSUNG_PD_H __FILE__
-
-struct samsung_pd_info {
- int (*enable)(struct device *dev);
- int (*disable)(struct device *dev);
- void __iomem *base;
-};
-
-enum exynos4_pd_block {
- PD_MFC,
- PD_G3D,
- PD_LCD0,
- PD_LCD1,
- PD_TV,
- PD_CAM,
- PD_GPS
-};
-
-#endif /* __ASM_PLAT_SAMSUNG_PD_H */
diff --git a/arch/arm/plat-samsung/include/plat/pm.h b/arch/arm/plat-samsung/include/plat/pm.h
index 61fc537..bf0eb20 100644
--- a/arch/arm/plat-samsung/include/plat/pm.h
+++ b/arch/arm/plat-samsung/include/plat/pm.h
@@ -133,7 +133,7 @@
#define S3C_PMDBG(fmt...) s3c_pm_dbg(fmt)
#else
-#define S3C_PMDBG(fmt...) printk(KERN_DEBUG fmt)
+#define S3C_PMDBG(fmt...) pr_debug(fmt)
#endif
#ifdef CONFIG_S3C_PM_DEBUG_LED_SMDK
diff --git a/arch/arm/plat-samsung/include/plat/pwm.h b/arch/arm/plat-samsung/include/plat/pwm.h
new file mode 100644
index 0000000..6bf2a92
--- /dev/null
+++ b/arch/arm/plat-samsung/include/plat/pwm.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * SAMSUNG PWM platform data definitions
+ *
+ * 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.
+*/
+
+#ifndef __PLAT_SAMSUNG_PWM_H
+#define __PLAT_SAMSUNG_PWM_H __FILE__
+
+#include <plat/devs.h>
+
+struct samsung_pwm_platdata {
+ unsigned int prescaler0;
+ unsigned int prescaler1;
+};
+
+extern void samsung_pwm_set_platdata(struct samsung_pwm_platdata *pd);
+
+#endif /* __PLAT_SAMSUNG_PWM_H */
diff --git a/arch/arm/plat-samsung/include/plat/regs-adc.h b/arch/arm/plat-samsung/include/plat/regs-adc.h
index 7061210..8df8863 100644
--- a/arch/arm/plat-samsung/include/plat/regs-adc.h
+++ b/arch/arm/plat-samsung/include/plat/regs-adc.h
@@ -63,6 +63,9 @@
#define S3C2410_ADCDAT1_XY_PST (0x3<<12)
#define S3C2410_ADCDAT1_YPDATA_MASK (0x03FF)
+/* ADCDLY Register Bits */
+#define S3C2410_ADCDLY_DELAY(x) (((x)&0xFFFF)<<0)
+
#endif /* __ASM_ARCH_REGS_ADC_H */
diff --git a/arch/arm/plat-samsung/include/plat/regs-dsim.h b/arch/arm/plat-samsung/include/plat/regs-dsim.h
new file mode 100644
index 0000000..f4d1eed
--- /dev/null
+++ b/arch/arm/plat-samsung/include/plat/regs-dsim.h
@@ -0,0 +1,237 @@
+/* linux/arch/arm/plat-s5p/include/plat/regs-dsim.h
+ *
+ * Register definition file for Samsung MIPI-DSIM driver
+ *
+ * InKi Dae <inki.dae@samsung.com>, Copyright (c) 2009 Samsung Electronics
+ *
+ * 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.
+*/
+
+#ifndef _REGS_DSIM_H
+#define _REGS_DSIM_H
+
+#define S5P_DSIM_STATUS (0x0) /* Status register */
+#define S5P_DSIM_SWRST (0x4) /* Software reset register */
+#define S5P_DSIM_CLKCTRL (0x8) /* Clock control register */
+#define S5P_DSIM_TIMEOUT (0xc) /* Time out register */
+#define S5P_DSIM_CONFIG (0x10) /* Configuration register */
+#define S5P_DSIM_ESCMODE (0x14) /* Escape mode register */
+#define S5P_DSIM_MDRESOL (0x18) /* Main display image resolution register */
+#define S5P_DSIM_MVPORCH (0x1c) /* Main display Vporch register */
+#define S5P_DSIM_MHPORCH (0x20) /* Main display Hporch register */
+#define S5P_DSIM_MSYNC (0x24) /* Main display sync area register */
+#define S5P_DSIM_SDRESOL (0x28) /* Sub display image resolution register */
+#define S5P_DSIM_INTSRC (0x2c) /* Interrupt source register */
+#define S5P_DSIM_INTMSK (0x30) /* Interrupt mask register */
+#define S5P_DSIM_PKTHDR (0x34) /* Packet Header FIFO register */
+#define S5P_DSIM_PAYLOAD (0x38) /* Payload FIFO register */
+#define S5P_DSIM_RXFIFO (0x3c) /* Read FIFO register */
+#define S5P_DSIM_FIFOTHLD (0x40) /* FIFO threshold level register */
+#define S5P_DSIM_FIFOCTRL (0x44) /* FIFO status and control register */
+#define S5P_DSIM_MEMACCHR (0x48) /* FIFO memory AC characteristic register */
+#define S5P_DSIM_PLLCTRL (0x4c) /* PLL control register */
+#define S5P_DSIM_PLLTMR (0x50) /* PLL timer register */
+#define S5P_DSIM_PHYACCHR (0x54) /* D-PHY AC characteristic register */
+#define S5P_DSIM_PHYACCHR1 (0x58) /* D-PHY AC characteristic register 1 */
+
+/* DSIM_SWRST */
+#define DSIM_FUNCRST (1 << 16)
+#define DSIM_SWRST (1 << 0)
+
+/* S5P_DSIM_TIMEOUT */
+#define DSIM_LPDR_TOUT_SHIFT (0)
+#define DSIM_BTA_TOUT_SHIFT (16)
+#define DSIM_LPDR_TOUT(x) (((x) & 0xffff) << DSIM_LPDR_TOUT_SHIFT)
+#define DSIM_BTA_TOUT(x) (((x) & 0xff) << DSIM_BTA_TOUT_SHIFT)
+
+/* S5P_DSIM_CLKCTRL */
+#define DSIM_ESC_PRESCALER_SHIFT (0)
+#define DSIM_LANE_ESC_CLKEN_SHIFT (19)
+#define DSIM_BYTE_CLKEN_SHIFT (24)
+#define DSIM_BYTE_CLK_SRC_SHIFT (25)
+#define DSIM_PLL_BYPASS_SHIFT (27)
+#define DSIM_ESC_CLKEN_SHIFT (28)
+#define DSIM_TX_REQUEST_HSCLK_SHIFT (31)
+#define DSIM_ESC_PRESCALER(x) (((x) & 0xffff) << DSIM_ESC_PRESCALER_SHIFT)
+#define DSIM_LANE_ESC_CLKEN(x) (((x) & 0x1f) << DSIM_LANE_ESC_CLKEN_SHIFT)
+#define DSIM_BYTE_CLK_ENABLE (1 << DSIM_BYTE_CLKEN_SHIFT)
+#define DSIM_BYTE_CLK_DISABLE (0 << DSIM_BYTE_CLKEN_SHIFT)
+#define DSIM_BYTE_CLKSRC(x) (((x) & 0x3) << DSIM_BYTE_CLK_SRC_SHIFT)
+#define DSIM_PLL_BYPASS_PLL (0 << DSIM_PLL_BYPASS_SHIFT)
+#define DSIM_PLL_BYPASS_EXTERNAL (1 << DSIM_PLL_BYPASS_SHIFT)
+#define DSIM_ESC_CLKEN_ENABLE (1 << DSIM_ESC_CLKEN_SHIFT)
+#define DSIM_ESC_CLKEN_DISABLE (0 << DSIM_ESC_CLKEN_SHIFT)
+
+/* S5P_DSIM_CONFIG */
+#define DSIM_LANE_EN_SHIFT (0)
+#define DSIM_NUM_OF_DATALANE_SHIFT (5)
+#define DSIM_SUB_PIX_FORMAT_SHIFT (8)
+#define DSIM_MAIN_PIX_FORMAT_SHIFT (12)
+#define DSIM_SUB_VC_SHIFT (16)
+#define DSIM_MAIN_VC_SHIFT (18)
+#define DSIM_HSA_MODE_SHIFT (20)
+#define DSIM_HBP_MODE_SHIFT (21)
+#define DSIM_HFP_MODE_SHIFT (22)
+#define DSIM_HSE_MODE_SHIFT (23)
+#define DSIM_AUTO_MODE_SHIFT (24)
+#define DSIM_VIDEO_MODE_SHIFT (25)
+#define DSIM_BURST_MODE_SHIFT (26)
+#define DSIM_SYNC_INFORM_SHIFT (27)
+#define DSIM_EOT_R03_SHIFT (28)
+#define DSIM_LANE_ENx(x) ((1) << x)
+#define DSIM_NUM_OF_DATA_LANE(x) ((x) << 5) /* in case of Gemunus, it should be 0x1. */
+#define DSIM_SUB_PIX_FORMAT_3BPP (0 << 8) /* command mode only */
+#define DSIM_SUB_PIX_FORMAT_8BPP (1 << 8) /* command mode only */
+#define DSIM_SUB_PIX_FORMAT_12BPP (2 << 8) /* command mode only */
+#define DSIM_SUB_PIX_FORMAT_16BPP (3 << 8) /* command mode only */
+#define DSIM_SUB_PIX_FORMAT_16BPP_RGB (4 << 8) /* video mode only */
+#define DSIM_SUB_PIX_FORMAT_18BPP_PRGB (5 << 8) /* video mode only */
+#define DSIM_SUB_PIX_FORMAT_18BPP_LRGB (6 << 8) /* common */
+#define DSIM_SUB_PIX_FORMAT_24BPP_RGB (7 << 8) /* common */
+#define DSIM_MAIN_PIX_FORMAT_3BPP (0 << 12) /* command mode only */
+#define DSIM_MAIN_PIX_FORMAT_8BPP (1 << 12) /* command mode only */
+#define DSIM_MAIN_PIX_FORMAT_12BPP (2 << 12) /* command mode only */
+#define DSIM_MAIN_PIX_FORMAT_16BPP (3 << 12) /* command mode only */
+#define DSIM_MAIN_PIX_FORMAT_16BPP_RGB (4 << 12) /* video mode only */
+#define DSIM_MAIN_PIX_FORMAT_18BPP_PRGB (5 << 12) /* video mode only */
+#define DSIM_MAIN_PIX_FORMAT_18BPP_LRGB (6 << 12) /* common */
+#define DSIM_MAIN_PIX_FORMAT_24BPP_RGB (7 << 12) /* common */
+#define DSIM_SUB_VC(x) (((x) & 0x3) << 16) /* Virtual channel number for sub display */
+#define DSIM_MAIN_VC(x) (((x) & 0x3) << 18) /* Virtual channel number for main display */
+#define DSIM_HSA_MODE_ENABLE (1 << 20)
+#define DSIM_HSA_MODE_DISABLE (0 << 20)
+#define DSIM_HBP_MODE_ENABLE (1 << 21)
+#define DSIM_HBP_MODE_DISABLE (0 << 21)
+#define DSIM_HFP_MODE_ENABLE (1 << 22)
+#define DSIM_HFP_MODE_DISABLE (0 << 22)
+#define DSIM_HSE_MODE_ENABLE (1 << 23)
+#define DSIM_HSE_MODE_DISABLE (0 << 23)
+#define DSIM_AUTO_MODE (1 << 24)
+#define DSIM_CONFIGURATION_MODE (0 << 24)
+#define DSIM_VIDEO_MODE (1 << 25)
+#define DSIM_COMMAND_MODE (0 << 25)
+#define DSIM_BURST_MODE (1 << 26)
+#define DSIM_NON_BURST_MODE (0 << 26)
+#define DSIM_SYNC_INFORM_PULSE (1 << 27)
+#define DSIM_SYNC_INFORM_EVENT (0 << 27)
+#define DSIM_EOT_R03_ENABLE (0 << 28) /* enable EoT packet generation for V1.01r11 */
+#define DSIM_EOT_R03_DISABLE (1 << 28) /* disable EoT packet generation for V1.01r03 */
+
+/* S5P_DSIM_ESCMODE */
+#define DSIM_STOP_STATE_CNT_SHIFT (21)
+#define DSIM_STOP_STATE_CNT(x) (((x) & 0x3ff) << DSIM_STOP_STATE_CNT_SHIFT)
+#define DSIM_FORCE_STOP_STATE_SHIFT (20)
+#define DSIM_FORCE_BTA_SHIFT (16)
+#define DSIM_CMD_LPDT_HS_MODE (0 << 7)
+#define DSIM_CMD_LPDT_LP_MODE (1 << 7)
+#define DSIM_TX_LPDT_HS_MODE (0 << 6)
+#define DSIM_TX_LPDT_LP_MODE (1 << 6)
+#define DSIM_TX_TRIGGER_RST_SHIFT (4)
+#define DSIM_TX_UIPS_DAT_SHIFT (3)
+#define DSIM_TX_UIPS_EXIT_SHIFT (2)
+#define DSIM_TX_UIPS_CLK_SHIFT (1)
+#define DSIM_TX_UIPS_CLK_EXIT_SHIFT (0)
+
+/* S5P_DSIM_MDRESOL */
+#define DSIM_MAIN_STAND_BY (1 << 31)
+#define DSIM_MAIN_NOT_READY (0 << 31)
+#define DSIM_MAIN_VRESOL(x) (((x) & 0x7ff) << 16)
+#define DSIM_MAIN_HRESOL(x) (((x) & 0X7ff) << 0)
+
+/* S5P_DSIM_MVPORCH */
+#define DSIM_CMD_ALLOW_SHIFT (28)
+#define DSIM_STABLE_VFP_SHIFT (16)
+#define DSIM_MAIN_VBP_SHIFT (0)
+#define DSIM_CMD_ALLOW_MASK (0xf << DSIM_CMD_ALLOW_SHIFT)
+#define DSIM_STABLE_VFP_MASK (0x7ff << DSIM_STABLE_VFP_SHIFT)
+#define DSIM_MAIN_VBP_MASK (0x7ff << DSIM_MAIN_VBP_SHIFT)
+#define DSIM_CMD_ALLOW(x) (((x) & 0xf) << DSIM_CMD_ALLOW_SHIFT)
+#define DSIM_STABLE_VFP(x) (((x) & 0x7ff) << DSIM_STABLE_VFP_SHIFT)
+#define DSIM_MAIN_VBP(x) (((x) & 0x7ff) << DSIM_MAIN_VBP_SHIFT)
+
+/* S5P_DSIM_MHPORCH */
+#define DSIM_MAIN_HFP_SHIFT (16)
+#define DSIM_MAIN_HBP_SHIFT (0)
+#define DSIM_MAIN_HFP_MASK ((0xffff) << DSIM_MAIN_HFP_SHIFT)
+#define DSIM_MAIN_HBP_MASK ((0xffff) << DSIM_MAIN_HBP_SHIFT)
+#define DSIM_MAIN_HFP(x) (((x) & 0xffff) << DSIM_MAIN_HFP_SHIFT)
+#define DSIM_MAIN_HBP(x) (((x) & 0xffff) << DSIM_MAIN_HBP_SHIFT)
+
+/* S5P_DSIM_MSYNC */
+#define DSIM_MAIN_VSA_SHIFT (22)
+#define DSIM_MAIN_HSA_SHIFT (0)
+#define DSIM_MAIN_VSA_MASK ((0x3ff) << DSIM_MAIN_VSA_SHIFT)
+#define DSIM_MAIN_HSA_MASK ((0xffff) << DSIM_MAIN_HSA_SHIFT)
+#define DSIM_MAIN_VSA(x) (((x) & 0x3ff) << DSIM_MAIN_VSA_SHIFT)
+#define DSIM_MAIN_HSA(x) (((x) & 0xffff) << DSIM_MAIN_HSA_SHIFT)
+
+/* S5P_DSIM_SDRESOL */
+#define DSIM_SUB_STANDY_SHIFT (31)
+#define DSIM_SUB_VRESOL_SHIFT (16)
+#define DSIM_SUB_HRESOL_SHIFT (0)
+#define DSIM_SUB_STANDY_MASK ((0x1) << DSIM_SUB_STANDY_SHIFT)
+#define DSIM_SUB_VRESOL_MASK ((0x7ff) << DSIM_SUB_VRESOL_SHIFT)
+#define DSIM_SUB_HRESOL_MASK ((0x7ff) << DSIM_SUB_HRESOL_SHIFT)
+#define DSIM_SUB_STANDY (1 << DSIM_SUB_STANDY_SHIFT)
+#define DSIM_SUB_NOT_READY (0 << DSIM_SUB_STANDY_SHIFT)
+#define DSIM_SUB_VRESOL(x) (((x) & 0x7ff) << DSIM_SUB_VRESOL_SHIFT)
+#define DSIM_SUB_HRESOL(x) (((x) & 0x7ff) << DSIM_SUB_HRESOL_SHIFT)
+
+/* S5P_DSIM_PKTHDR */
+#define DSIM_PACKET_HEADER_DI(x) (((x) & 0xff) << 0)
+#define DSIM_PACKET_HEADER_DAT0(x) (((x) & 0xff) << 8) /* Word count lower byte for long packet */
+#define DSIM_PACKET_HEADER_DAT1(x) (((x) & 0xff) << 16) /* Word count upper byte for long packet */
+
+/* S5P_DSIM_FIFOCTRL */
+#define DSIM_RX_FIFO (1 << 4)
+#define DSIM_TX_SFR_FIFO (1 << 3)
+#define DSIM_I80_FIFO (1 << 2)
+#define DSIM_SUB_DISP_FIFO (1 << 1)
+#define DSIM_MAIN_DISP_FIFO (1 << 0)
+
+/* S5P_DSIM_PHYACCHR */
+#define DSIM_AFC_CTL(x) (((x) & 0x7) << 5)
+#define DSIM_AFC_ENABLE (1 << 14)
+#define DSIM_AFC_DISABLE (0 << 14)
+
+/* S5P_DSIM_PLLCTRL */
+#define DSIM_PMS_SHIFT (1)
+#define DSIM_PLL_EN_SHIFT (23)
+#define DSIM_FREQ_BAND_SHIFT (24)
+#define DSIM_PMS(x) (((x) & 0x7ffff) << DSIM_PMS_SHIFT)
+#define DSIM_FREQ_BAND(x) (((x) & 0xf) << DSIM_FREQ_BAND_SHIFT)
+
+typedef enum {
+ PllStable = 1 << 31,
+ SwRstRelease = 1 << 30,
+ SFRFifoEmpty = 1 << 29,
+ BusTrunOVer = 1 << 25,
+ FrameDone = 1 << 24,
+ LpdrTout = 1 << 21,
+ TaTout = 1 << 20,
+ RxDatDone = 1 << 18,
+ RxTE = 1 << 17,
+ ErrRxEcc = 1 << 15,
+ ErrRxCRC = 1 << 14,
+ ErrEsc3 = 1 << 13,
+ ErrEsc2 = 1 << 12,
+ ErrEsc1 = 1 << 11,
+ ErrEsc0 = 1 << 10,
+ ErrSync3 = 1 << 9,
+ ErrSync2 = 1 << 8,
+ ErrSync1 = 1 << 7,
+ ErrSync0 = 1 << 6,
+ ErrControl3 = 1 << 5,
+ ErrControl2 = 1 << 4,
+ ErrControl1 = 1 << 3,
+ ErrControl0 = 1 << 2,
+ ErrContentLP0 = 1 << 1,
+ ErrContentLP1 = 1 << 0,
+
+ AllDsimIntr = 0xffffffff,
+ ErrDsimIntr = 0xffff,
+} DSIM_INTSRC;
+
+#endif /* _REGS_DSIM_H */
diff --git a/arch/arm/plat-samsung/include/plat/regs-fb-v4.h b/arch/arm/plat-samsung/include/plat/regs-fb-v4.h
index 4c3647f..b917f76 100644
--- a/arch/arm/plat-samsung/include/plat/regs-fb-v4.h
+++ b/arch/arm/plat-samsung/include/plat/regs-fb-v4.h
@@ -30,22 +30,37 @@
#define VIDCON1_FSTATUS_EVEN (1 << 15)
/* Video timing controls */
+#ifdef CONFIG_FB_EXYNOS_FIMD_V8
+#define VIDTCON0 (0x20010)
+#define VIDTCON1 (0x20014)
+#define VIDTCON2 (0x20018)
+#define VIDTCON3 (0x2001C)
+#else
#define VIDTCON0 (0x10)
#define VIDTCON1 (0x14)
#define VIDTCON2 (0x18)
+#define VIDTCON3 (0x1C)
+#endif
/* Window position controls */
#define WINCON(_win) (0x20 + ((_win) * 4))
+/* Window rgborder controls */
+
+#define WIN_RGB_ORDER(_win) (0x2020 + ((_win) * 4))
+
/* OSD1 and OSD4 do not have register D */
#define VIDOSD_BASE (0x40)
#define VIDINTCON0 (0x130)
+#define VIDINTCON1 (0x134)
/* WINCONx */
+#define WINCONx_CSC_CON_EQ709 (1 << 28)
+#define WINCONx_CSC_CON_EQ601 (0 << 28)
#define WINCONx_CSCWIDTH_MASK (0x3 << 26)
#define WINCONx_CSCWIDTH_SHIFT (26)
#define WINCONx_CSCWIDTH_WIDE (0x0 << 26)
diff --git a/arch/arm/plat-samsung/include/plat/regs-fb.h b/arch/arm/plat-samsung/include/plat/regs-fb.h
index 9a78012..4af9882 100644
--- a/arch/arm/plat-samsung/include/plat/regs-fb.h
+++ b/arch/arm/plat-samsung/include/plat/regs-fb.h
@@ -38,6 +38,7 @@
#define VIDCON0_VIDOUT_TV (0x1 << 26)
#define VIDCON0_VIDOUT_I80_LDI0 (0x2 << 26)
#define VIDCON0_VIDOUT_I80_LDI1 (0x3 << 26)
+#define VIDCON0_VIDOUT_WB (0x4 << 26)
#define VIDCON0_L1_DATA_MASK (0x7 << 23)
#define VIDCON0_L1_DATA_SHIFT (23)
@@ -81,7 +82,12 @@
#define VIDCON0_ENVID (1 << 1)
#define VIDCON0_ENVID_F (1 << 0)
+#ifdef CONFIG_FB_EXYNOS_FIMD_V8
+#define VIDCON1 (0x20004)
+#else
#define VIDCON1 (0x04)
+#endif
+
#define VIDCON1_LINECNT_MASK (0x7ff << 16)
#define VIDCON1_LINECNT_SHIFT (16)
#define VIDCON1_LINECNT_GET(_v) (((_v) >> 16) & 0x7ff)
@@ -104,13 +110,31 @@
#define VIDCON2 (0x08)
#define VIDCON2_EN601 (1 << 23)
-#define VIDCON2_TVFMTSEL_SW (1 << 14)
-
-#define VIDCON2_TVFMTSEL1_MASK (0x3 << 12)
-#define VIDCON2_TVFMTSEL1_SHIFT (12)
-#define VIDCON2_TVFMTSEL1_RGB (0x0 << 12)
-#define VIDCON2_TVFMTSEL1_YUV422 (0x1 << 12)
-#define VIDCON2_TVFMTSEL1_YUV444 (0x2 << 12)
+#define VIDCON2_RGB_ORDER_E_MASK (0x7 << 19)
+#define VIDCON2_RGB_ORDER_E_RGB (0x0 << 19)
+#define VIDCON2_RGB_ORDER_E_GBR (0x1 << 19)
+#define VIDCON2_RGB_ORDER_E_BRG (0x2 << 19)
+#define VIDCON2_RGB_ORDER_E_BGR (0x4 << 19)
+#define VIDCON2_RGB_ORDER_E_RBG (0x5 << 19)
+#define VIDCON2_RGB_ORDER_E_GRB (0x6 << 19)
+#define VIDCON2_RGB_ORDER_O_MASK (0x7 << 16)
+#define VIDCON2_RGB_ORDER_O_RGB (0x0 << 16)
+#define VIDCON2_RGB_ORDER_O_GBR (0x1 << 16)
+#define VIDCON2_RGB_ORDER_O_BRG (0x2 << 16)
+#define VIDCON2_RGB_ORDER_O_BGR (0x4 << 16)
+#define VIDCON2_RGB_ORDER_O_RBG (0x5 << 16)
+#define VIDCON2_RGB_ORDER_O_GRB (0x6 << 16)
+#define VIDCON2_WB_DISABLE (0 << 15)
+#define VIDCON2_WB_ENABLE (1 << 15)
+#define VIDCON2_WB_MASK (1 << 15)
+#define VIDCON2_TVFORMATSEL_HW (0 << 14)
+#define VIDCON2_TVFORMATSEL_SW (1 << 14)
+#define VIDCON2_TVFORMATSEL_HW_SW_MASK (1 << 14)
+#define VIDCON2_TVFORMATSEL_MASK (0x3 << 12)
+#define VIDCON2_TVFORMATSEL_SHIFT (12)
+#define VIDCON2_TVFORMATSEL_RGB (0x0 << 12)
+#define VIDCON2_TVFORMATSEL_YUV422 (0x1 << 12)
+#define VIDCON2_TVFORMATSEL_YUV444 (0x2 << 12)
#define VIDCON2_ORGYCbCr (1 << 8)
#define VIDCON2_YUVORDCrCb (1 << 7)
@@ -166,7 +190,6 @@
#define VIDTCON1_HSPW_LIMIT (0xff)
#define VIDTCON1_HSPW(_x) ((_x) << 0)
-#define VIDTCON2 (0x18)
#define VIDTCON2_LINEVAL_E(_x) ((((_x) & 0x800) >> 11) << 23)
#define VIDTCON2_LINEVAL_MASK (0x7ff << 11)
#define VIDTCON2_LINEVAL_SHIFT (11)
@@ -181,11 +204,13 @@
/* WINCONx */
-
#define WINCONx_BITSWP (1 << 18)
#define WINCONx_BYTSWP (1 << 17)
#define WINCONx_HAWSWP (1 << 16)
#define WINCONx_WSWP (1 << 15)
+#define WINCONx_ENLOCAL_MASK (0xf << 15)
+#define WINCONx_INRGB_RGB (0 << 13)
+#define WINCONx_INRGB_YCBCR (1 << 13)
#define WINCONx_BURSTLEN_MASK (0x3 << 9)
#define WINCONx_BURSTLEN_SHIFT (9)
#define WINCONx_BURSTLEN_16WORD (0x0 << 9)
@@ -205,6 +230,7 @@
#define WINCON0_BPPMODE_24BPP_888 (0xb << 2)
#define WINCON1_BLD_PIX (1 << 6)
+#define WINCON1_BLD_PLANE (0 << 6)
#define WINCON1_ALPHA_SEL (1 << 1)
#define WINCON1_BPPMODE_MASK (0xf << 2)
@@ -224,7 +250,13 @@
#define WINCON1_BPPMODE_24BPP_A1887 (0xc << 2)
#define WINCON1_BPPMODE_25BPP_A1888 (0xd << 2)
#define WINCON1_BPPMODE_28BPP_A4888 (0xd << 2)
+#define WINCON1_BPPMODE_13BPP_A1444 (0xe << 2)
+#define WINCON1_BPPMODE_16BPP_A4444 (0xe << 2)
+/* WIN_RGB_ORDERx */
+
+#define WIN_RGB_ORDER_BGR (1 << 11)
+#define WIN_RGB_ORDER_RGB (0 << 11)
/* S5PV210 */
#define SHADOWCON (0x34)
#define SHADOWCON_WINx_PROTECT(_win) (1 << (10 + (_win)))
@@ -257,28 +289,21 @@
#define VIDOSDxB_BOTRIGHT_Y_LIMIT (0x7ff)
#define VIDOSDxB_BOTRIGHT_Y(_x) (((_x) & 0x7ff) << 0)
-/* For VIDOSD[1..4]C */
-#define VIDISD14C_ALPHA0_R(_x) ((_x) << 20)
-#define VIDISD14C_ALPHA0_G_MASK (0xf << 16)
-#define VIDISD14C_ALPHA0_G_SHIFT (16)
-#define VIDISD14C_ALPHA0_G_LIMIT (0xf)
-#define VIDISD14C_ALPHA0_G(_x) ((_x) << 16)
-#define VIDISD14C_ALPHA0_B_MASK (0xf << 12)
-#define VIDISD14C_ALPHA0_B_SHIFT (12)
-#define VIDISD14C_ALPHA0_B_LIMIT (0xf)
-#define VIDISD14C_ALPHA0_B(_x) ((_x) << 12)
-#define VIDISD14C_ALPHA1_R_MASK (0xf << 8)
-#define VIDISD14C_ALPHA1_R_SHIFT (8)
-#define VIDISD14C_ALPHA1_R_LIMIT (0xf)
-#define VIDISD14C_ALPHA1_R(_x) ((_x) << 8)
-#define VIDISD14C_ALPHA1_G_MASK (0xf << 4)
-#define VIDISD14C_ALPHA1_G_SHIFT (4)
-#define VIDISD14C_ALPHA1_G_LIMIT (0xf)
-#define VIDISD14C_ALPHA1_G(_x) ((_x) << 4)
-#define VIDISD14C_ALPHA1_B_MASK (0xf << 0)
-#define VIDISD14C_ALPHA1_B_SHIFT (0)
-#define VIDISD14C_ALPHA1_B_LIMIT (0xf)
-#define VIDISD14C_ALPHA1_B(_x) ((_x) << 0)
+/* alpha when !win->variant.has_osd_alpha */
+#define VIDWxALPHAx_R(_x) (((_x) & 0xFF) << 16)
+#define VIDWxALPHAx_G(_x) (((_x) & 0xFF) << 8)
+#define VIDWxALPHAx_B(_x) (((_x) & 0xFF) << 0)
+
+/* alpha when win->variant.has_osd_alpha */
+#define VIDOSDxC_ALPHA0_R_H(_x) (((_x) & 0xF0) << 16)
+#define VIDOSDxC_ALPHA0_G_H(_x) (((_x) & 0xF0) << 12)
+#define VIDOSDxC_ALPHA0_B_H(_x) (((_x) & 0xF0) << 8)
+#define VIDOSDxC_ALPHA1_R_H(_x) (((_x) & 0xF0) << 4)
+#define VIDOSDxC_ALPHA1_G_H(_x) (((_x) & 0xF0) << 0)
+#define VIDOSDxC_ALPHA1_B_H(_x) (((_x) & 0xF0) >> 4)
+#define VIDWxALPHAx_R_L(_x) (((_x) & 0x0F) << 16)
+#define VIDWxALPHAx_G_L(_x) (((_x) & 0x0F) << 8)
+#define VIDWxALPHAx_B_L(_x) (((_x) & 0x0F) << 0)
/* Video buffer addresses */
#define VIDW_BUF_START(_buff) (0xA0 + ((_buff) * 8))
@@ -299,6 +324,10 @@
#define VIDW_BUF_SIZE_PAGEWIDTH_LIMIT (0x1fff)
#define VIDW_BUF_SIZE_PAGEWIDTH(_x) (((_x) & 0x1fff) << 0)
+#define SHD_VIDW_BUF_START(_buff) (0x40A0 + ((_buff) * 8))
+#define SHD_VIDW_BUF_END(_buff) (0x40D0 + ((_buff) * 8))
+#define SHD_VIDW_BUF_SIZE(_buff) (0x4100 + ((_buff) * 8))
+
/* Interrupt controls and status */
#define VIDINTCON0_FIFOINTERVAL_MASK (0x3f << 20)
@@ -330,6 +359,7 @@
#define VIDINTCON0_FIFIOSEL_WINDOW0 (0x1 << 5)
#define VIDINTCON0_FIFIOSEL_WINDOW1 (0x2 << 5)
+#define VIDINTCON0_INT_FIFO (1 << 1)
#define VIDINTCON0_FIFOLEVEL_MASK (0x7 << 2)
#define VIDINTCON0_FIFOLEVEL_SHIFT (2)
#define VIDINTCON0_FIFOLEVEL_TO25PC (0x0 << 2)
@@ -395,9 +425,43 @@
#define WPALCON_W0PAL_16BPP_A555 (0x5 << 0)
#define WPALCON_W0PAL_16BPP_565 (0x6 << 0)
+/* Clock gate mode control */
+#define REG_CLKGATE_MODE (0x1b0)
+#define REG_CLKGATE_MODE_AUTO_CLOCK_GATE (0 << 0)
+#define REG_CLKGATE_MODE_NON_CLOCK_GATE (1 << 0)
+
+/* Blending equation */
+#define BLENDEQ(_x) (0x240 + (_x) * 4)
+#define BLENDEQ_COEF_ZERO 0x0
+#define BLENDEQ_COEF_ONE 0x1
+#define BLENDEQ_COEF_ALPHA_A 0x2
+#define BLENDEQ_COEF_ONE_MINUS_ALPHA_A 0x3
+#define BLENDEQ_COEF_ALPHA_B 0x4
+#define BLENDEQ_COEF_ONE_MINUS_ALPHA_B 0x5
+#define BLENDEQ_COEF_ALPHA0 0x6
+#define BLENDEQ_COEF_A 0xA
+#define BLENDEQ_COEF_ONE_MINUS_A 0xB
+#define BLENDEQ_COEF_B 0xC
+#define BLENDEQ_COEF_ONE_MINUS_B 0xD
+#define BLENDEQ_Q_FUNC(_x) ((_x) << 18)
+#define BLENDEQ_Q_FUNC_MASK BLENDEQ_Q_FUNC(0xF)
+#define BLENDEQ_P_FUNC(_x) ((_x) << 12)
+#define BLENDEQ_P_FUNC_MASK BLENDEQ_P_FUNC(0xF)
+#define BLENDEQ_B_FUNC(_x) ((_x) << 6)
+#define BLENDEQ_B_FUNC_MASK BLENDEQ_B_FUNC(0xF)
+#define BLENDEQ_A_FUNC(_x) ((_x) << 0)
+#define BLENDEQ_A_FUNC_MASK BLENDEQ_A_FUNC(0xF)
+
/* Blending equation control */
#define BLENDCON (0x260)
#define BLENDCON_NEW_MASK (1 << 0)
#define BLENDCON_NEW_8BIT_ALPHA_VALUE (1 << 0)
#define BLENDCON_NEW_4BIT_ALPHA_VALUE (0 << 0)
+/* DP clock control */
+#define DPCLKCON (0x27c)
+#define DPCLKCON_ENABLE (1 << 1)
+
+/* Window alpha control */
+#define VIDW_ALPHA0(_x) (0x21C + ((_x) * 8))
+#define VIDW_ALPHA1(_x) (0x220 + ((_x) * 8))
diff --git a/arch/arm/plat-samsung/include/plat/regs-mipidsim.h b/arch/arm/plat-samsung/include/plat/regs-mipidsim.h
new file mode 100644
index 0000000..43b69cf
--- /dev/null
+++ b/arch/arm/plat-samsung/include/plat/regs-mipidsim.h
@@ -0,0 +1,149 @@
+/* linux/arch/arm/plat-s5p/include/plat/regs-mipidsim.h
+ *
+ * Register definition file for Samsung MIPI-DSIM driver
+ *
+ * Copyright (c) 2011 Samsung Electronics
+ *
+ * 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.
+*/
+
+#ifndef _REGS_MIPIDSIM_H
+#define _REGS_MIPIDSIM_H
+
+#define S5P_DSIM_STATUS (0x0) /* Status register */
+#define S5P_DSIM_SWRST (0x4) /* Software reset register */
+#define S5P_DSIM_CLKCTRL (0x8) /* Clock control register */
+#define S5P_DSIM_TIMEOUT (0xc) /* Time out register */
+#define S5P_DSIM_CONFIG (0x10) /* Configuration register */
+#define S5P_DSIM_ESCMODE (0x14) /* Escape mode register */
+
+/* Main display image resolution register */
+#define S5P_DSIM_MDRESOL (0x18)
+#define S5P_DSIM_MVPORCH (0x1c) /* Main display Vporch register */
+#define S5P_DSIM_MHPORCH (0x20) /* Main display Hporch register */
+#define S5P_DSIM_MSYNC (0x24) /* Main display sync area register
+*/
+
+/* Sub display image resolution register */
+#define S5P_DSIM_SDRESOL (0x28)
+#define S5P_DSIM_INTSRC (0x2c) /* Interrupt source
+register */
+#define S5P_DSIM_INTMSK (0x30) /* Interrupt mask register
+*/
+#define S5P_DSIM_PKTHDR (0x34) /* Packet Header FIFO
+register */
+#define S5P_DSIM_PAYLOAD (0x38) /* Payload FIFO register */
+#define S5P_DSIM_RXFIFO (0x3c) /* Read FIFO register */
+#define S5P_DSIM_FIFOTHLD (0x40) /* FIFO threshold level register */
+#define S5P_DSIM_FIFOCTRL (0x44) /* FIFO status and control register
+*/
+
+/* FIFO memory AC characteristic register */
+#define S5P_DSIM_PLLCTRL (0x4c) /* PLL control register */
+#define S5P_DSIM_PLLTMR (0x50) /* PLL timer register */
+#define S5P_DSIM_PHYACCHR (0x54) /* D-PHY AC characteristic register
+*/
+#define S5P_DSIM_PHYACCHR1 (0x58) /* D-PHY AC characteristic
+register1 */
+
+/* DSIM_STATUS */
+#define DSIM_STOP_STATE_DAT(x) (((x) & 0xf) << 0)
+#define DSIM_STOP_STATE_CLK (1 << 8)
+#define DSIM_TX_READY_HS_CLK (1 << 10)
+
+/* DSIM_SWRST */
+#define DSIM_FUNCRST (1 << 16)
+#define DSIM_SWRST (1 << 0)
+
+/* S5P_DSIM_TIMEOUT */
+#define DSIM_LPDR_TOUT_SHIFT (0)
+#define DSIM_BTA_TOUT_SHIFT (16)
+
+/* S5P_DSIM_CLKCTRL */
+#define DSIM_LANE_ESC_CLKEN_SHIFT (19)
+#define DSIM_BYTE_CLKEN_SHIFT (24)
+#define DSIM_BYTE_CLK_SRC_SHIFT (25)
+#define DSIM_PLL_BYPASS_SHIFT (27)
+#define DSIM_ESC_CLKEN_SHIFT (28)
+#define DSIM_TX_REQUEST_HSCLK_SHIFT (31)
+#define DSIM_LANE_ESC_CLKEN(x) (((x) & 0x1f) << \
+ DSIM_LANE_ESC_CLKEN_SHIFT)
+#define DSIM_BYTE_CLK_ENABLE (1 << DSIM_BYTE_CLKEN_SHIFT)
+#define DSIM_BYTE_CLK_DISABLE (0 << DSIM_BYTE_CLKEN_SHIFT)
+#define DSIM_PLL_BYPASS_EXTERNAL (1 << DSIM_PLL_BYPASS_SHIFT)
+#define DSIM_ESC_CLKEN_ENABLE (1 << DSIM_ESC_CLKEN_SHIFT)
+#define DSIM_ESC_CLKEN_DISABLE (0 << DSIM_ESC_CLKEN_SHIFT)
+
+/* S5P_DSIM_CONFIG */
+#define DSIM_NUM_OF_DATALANE_SHIFT (5)
+#define DSIM_HSA_MODE_SHIFT (20)
+#define DSIM_HBP_MODE_SHIFT (21)
+#define DSIM_HFP_MODE_SHIFT (22)
+#define DSIM_HSE_MODE_SHIFT (23)
+#define DSIM_AUTO_MODE_SHIFT (24)
+#define DSIM_LANE_ENx(x) (((x) & 0x1f) << 0)
+
+#define DSIM_NUM_OF_DATA_LANE(x) ((x) << DSIM_NUM_OF_DATALANE_SHIFT)
+
+/* S5P_DSIM_ESCMODE */
+#define DSIM_TX_LPDT_SHIFT (6)
+#define DSIM_CMD_LPDT_SHIFT (7)
+#define DSIM_TX_LPDT_LP (1 << DSIM_TX_LPDT_SHIFT)
+#define DSIM_CMD_LPDT_LP (1 << DSIM_CMD_LPDT_SHIFT)
+#define DSIM_STOP_STATE_CNT_SHIFT (21)
+#define DSIM_FORCE_STOP_STATE_SHIFT (20)
+
+/* S5P_DSIM_MDRESOL */
+#define DSIM_MAIN_STAND_BY (1 << 31)
+#define DSIM_MAIN_VRESOL(x) (((x) & 0x7ff) << 16)
+#define DSIM_MAIN_HRESOL(x) (((x) & 0X7ff) << 0)
+
+/* S5P_DSIM_MVPORCH */
+#define DSIM_CMD_ALLOW_SHIFT (28)
+#define DSIM_STABLE_VFP_SHIFT (16)
+#define DSIM_MAIN_VBP_SHIFT (0)
+#define DSIM_CMD_ALLOW_MASK (0xf << DSIM_CMD_ALLOW_SHIFT)
+#define DSIM_STABLE_VFP_MASK (0x7ff << DSIM_STABLE_VFP_SHIFT)
+#define DSIM_MAIN_VBP_MASK (0x7ff << DSIM_MAIN_VBP_SHIFT)
+
+/* S5P_DSIM_MHPORCH */
+#define DSIM_MAIN_HFP_SHIFT (16)
+#define DSIM_MAIN_HBP_SHIFT (0)
+#define DSIM_MAIN_HFP_MASK ((0xffff) << DSIM_MAIN_HFP_SHIFT)
+#define DSIM_MAIN_HBP_MASK ((0xffff) << DSIM_MAIN_HBP_SHIFT)
+
+/* S5P_DSIM_MSYNC */
+#define DSIM_MAIN_VSA_SHIFT (22)
+#define DSIM_MAIN_HSA_SHIFT (0)
+#define DSIM_MAIN_VSA_MASK ((0x3ff) << DSIM_MAIN_VSA_SHIFT)
+#define DSIM_MAIN_HSA_MASK ((0xffff) << DSIM_MAIN_HSA_SHIFT)
+
+/* S5P_DSIM_SDRESOL */
+#define DSIM_SUB_STANDY_SHIFT (31)
+#define DSIM_SUB_VRESOL_SHIFT (16)
+#define DSIM_SUB_HRESOL_SHIFT (0)
+#define DSIM_SUB_STANDY_MASK ((0x1) << DSIM_SUB_STANDY_SHIFT)
+#define DSIM_SUB_VRESOL_MASK ((0x7ff) << DSIM_SUB_VRESOL_SHIFT)
+#define DSIM_SUB_HRESOL_MASK ((0x7ff) << DSIM_SUB_HRESOL_SHIFT)
+
+/* S5P_DSIM_INTSRC */
+#define INTSRC_FRAME_DONE (1 << 24)
+#define INTSRC_PLL_STABLE (1 << 31)
+#define INTSRC_SFR_FIFO_EMPTY (1 << 29)
+
+/* S5P_DSIM_INTMSK */
+#define INTMSK_FRAME_DONE (1 << 24)
+
+/* S5P_DSIM_FIFOCTRL */
+#define SFR_HEADER_EMPTY (1 << 22)
+
+/* S5P_DSIM_PHYACCHR */
+#define DSIM_AFC_CTL(x) (((x) & 0x7) << 5)
+
+/* S5P_DSIM_PLLCTRL */
+#define DSIM_PLL_EN_SHIFT (23)
+#define DSIM_FREQ_BAND_SHIFT (24)
+
+#endif /* _REGS_MIPIDSIM_H */
diff --git a/arch/arm/plat-samsung/include/plat/regs-otg.h b/arch/arm/plat-samsung/include/plat/regs-otg.h
new file mode 100644
index 0000000..6506443
--- /dev/null
+++ b/arch/arm/plat-samsung/include/plat/regs-otg.h
@@ -0,0 +1,260 @@
+/* linux/arch/arm/plat-samsung/include/plat/regs-otg.h
+ *
+ * Copyright (C) 2004 Herbert Poetzl <herbert@13thfloor.at>
+ *
+ * This include file 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.
+*/
+
+#ifndef __ASM_ARCH_REGS_USB_OTG_HS_H
+#define __ASM_ARCH_REGS_USB_OTG_HS_H
+
+/* USB2.0 OTG Controller register */
+#define S3C_USBOTG_PHYREG(x) ((x) + S3C_VA_HSPHY)
+#define S3C_USBOTG_PHYPWR S3C_USBOTG_PHYREG(0x0)
+#define S3C_USBOTG_PHYCLK S3C_USBOTG_PHYREG(0x4)
+#define S3C_USBOTG_RSTCON S3C_USBOTG_PHYREG(0x8)
+#define S3C_USBOTG_PHY1CON S3C_USBOTG_PHYREG(0x34)
+
+/* USB2.0 OTG Controller register */
+#define S3C_USBOTGREG(x) (x)
+/* Core Global Registers */
+#define S3C_UDC_OTG_GOTGCTL S3C_USBOTGREG(0x000)
+#define S3C_UDC_OTG_GOTGINT S3C_USBOTGREG(0x004)
+#define S3C_UDC_OTG_GAHBCFG S3C_USBOTGREG(0x008)
+#define S3C_UDC_OTG_GUSBCFG S3C_USBOTGREG(0x00C)
+#define S3C_UDC_OTG_GRSTCTL S3C_USBOTGREG(0x010)
+#define S3C_UDC_OTG_GINTSTS S3C_USBOTGREG(0x014)
+#define S3C_UDC_OTG_GINTMSK S3C_USBOTGREG(0x018)
+#define S3C_UDC_OTG_GRXSTSR S3C_USBOTGREG(0x01C)
+#define S3C_UDC_OTG_GRXSTSP S3C_USBOTGREG(0x020)
+#define S3C_UDC_OTG_GRXFSIZ S3C_USBOTGREG(0x024)
+#define S3C_UDC_OTG_GNPTXFSIZ S3C_USBOTGREG(0x028)
+#define S3C_UDC_OTG_GNPTXSTS S3C_USBOTGREG(0x02C)
+
+#define S3C_UDC_OTG_HPTXFSIZ S3C_USBOTGREG(0x100)
+#define S3C_UDC_OTG_DIEPTXF(n) S3C_USBOTGREG(0x104 + (n-1)*0x4)
+
+/* Host Mode Registers */
+/* Host Global Registers */
+#define S3C_UDC_OTG_HCFG S3C_USBOTGREG(0x400)
+#define S3C_UDC_OTG_HFIR S3C_USBOTGREG(0x404)
+#define S3C_UDC_OTG_HFNUM S3C_USBOTGREG(0x408)
+#define S3C_UDC_OTG_HPTXSTS S3C_USBOTGREG(0x410)
+#define S3C_UDC_OTG_HAINT S3C_USBOTGREG(0x414)
+#define S3C_UDC_OTG_HAINTMSK S3C_USBOTGREG(0x418)
+
+/* Host Port Control & Status Registers */
+#define S3C_UDC_OTG_HPRT S3C_USBOTGREG(0x440)
+
+/* Host Channel-Specific Registers */
+#define S3C_UDC_OTG_HCCHAR0 S3C_USBOTGREG(0x500)
+#define S3C_UDC_OTG_HCSPLT0 S3C_USBOTGREG(0x504)
+#define S3C_UDC_OTG_HCINT0 S3C_USBOTGREG(0x508)
+#define S3C_UDC_OTG_HCINTMSK0 S3C_USBOTGREG(0x50C)
+#define S3C_UDC_OTG_HCTSIZ0 S3C_USBOTGREG(0x510)
+#define S3C_UDC_OTG_HCDMA0 S3C_USBOTGREG(0x514)
+
+/* Device Mode Registers */
+/*------------------------------------------------ */
+/* Device Global Registers */
+#define S3C_UDC_OTG_DCFG S3C_USBOTGREG(0x800)
+#define S3C_UDC_OTG_DCTL S3C_USBOTGREG(0x804)
+#define S3C_UDC_OTG_DSTS S3C_USBOTGREG(0x808)
+#define S3C_UDC_OTG_DIEPMSK S3C_USBOTGREG(0x810)
+#define S3C_UDC_OTG_DOEPMSK S3C_USBOTGREG(0x814)
+#define S3C_UDC_OTG_DAINT S3C_USBOTGREG(0x818)
+#define S3C_UDC_OTG_DAINTMSK S3C_USBOTGREG(0x81C)
+#define S3C_UDC_OTG_DTKNQR1 S3C_USBOTGREG(0x820)
+#define S3C_UDC_OTG_DTKNQR2 S3C_USBOTGREG(0x824)
+#define S3C_UDC_OTG_DVBUSDIS S3C_USBOTGREG(0x828)
+#define S3C_UDC_OTG_DVBUSPULSE S3C_USBOTGREG(0x82C)
+#define S3C_UDC_OTG_DTKNQR3 S3C_USBOTGREG(0x830)
+#define S3C_UDC_OTG_DTKNQR4 S3C_USBOTGREG(0x834)
+
+/*------------------------------------------------ */
+/* Device Logical IN Endpoint-Specific Registers */
+#define S3C_UDC_OTG_DIEPCTL(n) S3C_USBOTGREG(0x900 + n*0x20)
+#define S3C_UDC_OTG_DIEPINT(n) S3C_USBOTGREG(0x908 + n*0x20)
+#define S3C_UDC_OTG_DIEPTSIZ(n) S3C_USBOTGREG(0x910 + n*0x20)
+#define S3C_UDC_OTG_DIEPDMA(n) S3C_USBOTGREG(0x914 + n*0x20)
+
+/*------------------------------------------------ */
+/* Device Logical OUT Endpoint-Specific Registers */
+#define S3C_UDC_OTG_DOEPCTL(n) S3C_USBOTGREG(0xB00 + n*0x20)
+#define S3C_UDC_OTG_DOEPINT(n) S3C_USBOTGREG(0xB08 + n*0x20)
+#define S3C_UDC_OTG_DOEPTSIZ(n) S3C_USBOTGREG(0xB10 + n*0x20)
+#define S3C_UDC_OTG_DOEPDMA(n) S3C_USBOTGREG(0xB14 + n*0x20)
+
+/*------------------------------------------------ */
+/* Endpoint FIFO address */
+#define S3C_UDC_OTG_EP0_FIFO S3C_USBOTGREG(0x1000)
+#define S3C_UDC_OTG_EP1_FIFO S3C_USBOTGREG(0x2000)
+#define S3C_UDC_OTG_EP2_FIFO S3C_USBOTGREG(0x3000)
+#define S3C_UDC_OTG_EP3_FIFO S3C_USBOTGREG(0x4000)
+#define S3C_UDC_OTG_EP4_FIFO S3C_USBOTGREG(0x5000)
+#define S3C_UDC_OTG_EP5_FIFO S3C_USBOTGREG(0x6000)
+#define S3C_UDC_OTG_EP6_FIFO S3C_USBOTGREG(0x7000)
+#define S3C_UDC_OTG_EP7_FIFO S3C_USBOTGREG(0x8000)
+#define S3C_UDC_OTG_EP8_FIFO S3C_USBOTGREG(0x9000)
+#define S3C_UDC_OTG_EP9_FIFO S3C_USBOTGREG(0xA000)
+#define S3C_UDC_OTG_EP10_FIFO S3C_USBOTGREG(0xB000)
+#define S3C_UDC_OTG_EP11_FIFO S3C_USBOTGREG(0xC000)
+#define S3C_UDC_OTG_EP12_FIFO S3C_USBOTGREG(0xD000)
+#define S3C_UDC_OTG_EP13_FIFO S3C_USBOTGREG(0xE000)
+#define S3C_UDC_OTG_EP14_FIFO S3C_USBOTGREG(0xF000)
+#define S3C_UDC_OTG_EP15_FIFO S3C_USBOTGREG(0x10000)
+
+/*definitions related to CSR setting */
+
+/* S3C_UDC_OTG_GOTGCTL */
+#define B_SESSION_VALID (0x1<<19)
+#define A_SESSION_VALID (0x1<<18)
+
+/* S3C_UDC_OTG_GAHBCFG */
+#define PTXFE_HALF (0<<8)
+#define PTXFE_ZERO (1<<8)
+#define NPTXFE_HALF (0<<7)
+#define NPTXFE_ZERO (1<<7)
+#define MODE_SLAVE (0<<5)
+#define MODE_DMA (1<<5)
+#define BURST_SINGLE (0<<1)
+#define BURST_INCR (1<<1)
+#define BURST_INCR4 (3<<1)
+#define BURST_INCR8 (5<<1)
+#define BURST_INCR16 (7<<1)
+#define GBL_INT_UNMASK (1<<0)
+#define GBL_INT_MASK (0<<0)
+
+/* S3C_UDC_OTG_GRSTCTL */
+#define AHB_MASTER_IDLE (1u<<31)
+#define CORE_SOFT_RESET (0x1<<0)
+
+/* S3C_UDC_OTG_GINTSTS/S3C_UDC_OTG_GINTMSK core interrupt register */
+#define INT_RESUME (1u<<31)
+#define INT_DISCONN (0x1<<29)
+#define INT_CONN_ID_STS_CNG (0x1<<28)
+#define INT_OUT_EP (0x1<<19)
+#define INT_IN_EP (0x1<<18)
+#define INT_ENUMDONE (0x1<<13)
+#define INT_RESET (0x1<<12)
+#define INT_SUSPEND (0x1<<11)
+#define INT_EARLY_SUSPEND (0x1<<10)
+#define INT_NP_TX_FIFO_EMPTY (0x1<<5)
+#define INT_RX_FIFO_NOT_EMPTY (0x1<<4)
+#define INT_SOF (0x1<<3)
+#define INT_DEV_MODE (0x0<<0)
+#define INT_HOST_MODE (0x1<<1)
+#define INT_GOUTNakEff (0x01<<7)
+#define INT_GINNakEff (0x01<<6)
+
+#define FULL_SPEED_CONTROL_PKT_SIZE 8
+#define FULL_SPEED_BULK_PKT_SIZE 64
+
+#define HIGH_SPEED_CONTROL_PKT_SIZE 64
+#define HIGH_SPEED_BULK_PKT_SIZE 512
+
+#ifdef CONFIG_CPU_S5P6450
+#define RX_FIFO_SIZE (4096>>2)
+#define NPTX_FIFO_START_ADDR RX_FIFO_SIZE
+#define NPTX_FIFO_SIZE (4096>>2)
+#define PTX_FIFO_SIZE (1520>>2)
+#else
+#define RX_FIFO_SIZE (4096>>2)
+#define NPTX_FIFO_START_ADDR RX_FIFO_SIZE
+#define NPTX_FIFO_SIZE (4096>>2)
+#define PTX_FIFO_SIZE (1024>>2)
+#endif
+
+/* Enumeration speed */
+#define USB_HIGH_30_60MHZ (0x0<<1)
+#define USB_FULL_30_60MHZ (0x1<<1)
+#define USB_LOW_6MHZ (0x2<<1)
+#define USB_FULL_48MHZ (0x3<<1)
+
+/* S3C_UDC_OTG_GRXSTSP STATUS */
+#define OUT_PKT_RECEIVED (0x2<<17)
+#define OUT_TRANSFER_COMPLELTED (0x3<<17)
+#define SETUP_TRANSACTION_COMPLETED (0x4<<17)
+#define SETUP_PKT_RECEIVED (0x6<<17)
+#define GLOBAL_OUT_NAK (0x1<<17)
+
+/* S3C_UDC_OTG_DCTL device control register */
+#define NORMAL_OPERATION (0x1<<0)
+#define SOFT_DISCONNECT (0x1<<1)
+#define TEST_CONTROL_MASK (0x7<<4)
+#define TEST_J_MODE (0x1<<4)
+#define TEST_K_MODE (0x2<<4)
+#define TEST_SE0_NAK_MODE (0x3<<4)
+#define TEST_PACKET_MODE (0x4<<4)
+#define TEST_FORCE_ENABLE_MODE (0x5<<4)
+
+/* S3C_UDC_OTG_DAINT device all endpoint interrupt register */
+#define DAINT_OUT_BIT (16)
+#define DAINT_MASK (0xFFFF)
+
+/* S3C_UDC_OTG_DIEPCTL0/DOEPCTL0 device control
+ IN/OUT endpoint 0 control register */
+#define DEPCTL_EPENA (0x1<<31)
+#define DEPCTL_EPDIS (0x1<<30)
+#define DEPCTL_SETD1PID (0x1<<29)
+#define DEPCTL_SET_ODD_FRM (0x1<<29)
+#define DEPCTL_SETD0PID (0x1<<28)
+#define DEPCTL_SET_EVEN_FRM (0x1<<28)
+#define DEPCTL_SNAK (0x1<<27)
+#define DEPCTL_CNAK (0x1<<26)
+#define DEPCTL_STALL (0x1<<21)
+#define DEPCTL_TYPE_BIT (18)
+#define DEPCTL_TXFNUM_BIT (22)
+#define DEPCTL_TXFNUM_MASK (0xF<<22)
+#define DEPCTL_TYPE_MASK (0x3<<18)
+#define DEPCTL_CTRL_TYPE (0x0<<18)
+#define DEPCTL_ISO_TYPE (0x1<<18)
+#define DEPCTL_BULK_TYPE (0x2<<18)
+#define DEPCTL_INTR_TYPE (0x3<<18)
+#define DEPCTL_NAKSTS (0x1<<17)
+#define DEPCTL_DPID (0x1<<16)
+#define DEPCTL_EO_FRNUM (0x1<<16)
+#define DEPCTL_USBACTEP (0x1<<15)
+#define DEPCTL_NEXT_EP_BIT (11)
+#define DEPCTL_MPS_BIT (0)
+#define DEPCTL_MPS_MASK (0x7FF)
+
+#define DEPCTL0_MPS_64 (0x0<<0)
+#define DEPCTL0_MPS_32 (0x1<<0)
+#define DEPCTL0_MPS_16 (0x2<<0)
+#define DEPCTL0_MPS_8 (0x3<<0)
+#define DEPCTL_MPS_BULK_512 (512<<0)
+#define DEPCTL_MPS_INT_MPS_16 (16<<0)
+
+#define DIEPCTL0_NEXT_EP_BIT (11)
+
+/* S3C_UDC_OTG_DIEPCTLn/DOEPCTLn device control
+ IN/OUT endpoint n control register */
+
+/* S3C_UDC_OTG_DIEPMSK/DOEPMSK device
+ IN/OUT endpoint common interrupt mask register */
+/* S3C_UDC_OTG_DIEPINTn/DOEPINTn device
+ IN/OUT endpoint interrupt register */
+#define BACK2BACK_SETUP_RECEIVED (0x1<<6)
+#define INTKNEPMIS (0x1<<5)
+#define INTKN_TXFEMP (0x1<<4)
+#define NON_ISO_IN_EP_TIMEOUT (0x1<<3)
+#define CTRL_OUT_EP_SETUP_PHASE_DONE (0x1<<3)
+#define AHB_ERROR (0x1<<2)
+#define EPDISBLD (0x1<<1)
+#define TRANSFER_DONE (0x1<<0)
+
+/*DIEPTSIZ0 / DOEPTSIZ0 */
+
+/* DEPTSIZ common bit */
+#define DEPTSIZ_PKT_CNT_BIT (19)
+#define DEPTSIZ_XFER_SIZE_BIT (0)
+
+#define DEPTSIZ_SETUP_PKCNT_1 (1<<29)
+#define DEPTSIZ_SETUP_PKCNT_2 (2<<29)
+#define DEPTSIZ_SETUP_PKCNT_3 (3<<29)
+
+#endif
diff --git a/arch/arm/plat-samsung/include/plat/regs-usb3-exynos-drd-phy.h b/arch/arm/plat-samsung/include/plat/regs-usb3-exynos-drd-phy.h
new file mode 100644
index 0000000..50d2954
--- /dev/null
+++ b/arch/arm/plat-samsung/include/plat/regs-usb3-exynos-drd-phy.h
@@ -0,0 +1,75 @@
+/* arch/arm/plat-samsung/include/plat/regs-usb3-exynos-udc-drd.h
+ *
+ * Copyright (c) 2011 Samsung Electronics Co. Ltd
+ * Author: Anton Tikhomirov <av.tikhomirov@samsung.com>
+ *
+ * Exynos SuperSpeed USB 3.0 DRD Controller PHY registers
+ *
+ * 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.
+*/
+
+#ifndef __PLAT_SAMSUNG_REGS_USB3_EXYNOS_DRD_PHY_H
+#define __PLAT_SAMSUNG_REGS_USB3_EXYNOS_DRD_PHY_H __FILE__
+
+#define EXYNOS_USB3_PHYREG(x) ((x) + S5P_VA_SS_PHY)
+
+
+#define EXYNOS_USB3_LINKSYSTEM EXYNOS_USB3_PHYREG(0x04)
+#define EXYNOS_USB3_PHYUTMI EXYNOS_USB3_PHYREG(0x08)
+
+#define EXYNOS_USB3_PHYUTMI_OTGDISABLE (1 << 6)
+#define EXYNOS_USB3_PHYUTMI_FORCESUSPEND (1 << 1)
+#define EXYNOS_USB3_PHYUTMI_FORCESLEEP (1 << 0)
+
+#define EXYNOS_USB3_PHYPIPE EXYNOS_USB3_PHYREG(0x0C)
+
+
+#define EXYNOS_USB3_PHYCLKRST EXYNOS_USB3_PHYREG(0x10)
+
+#define EXYNOS_USB3_PHYCLKRST_SSC_REF_CLK_SEL_MASK (0xff << 23)
+#define EXYNOS_USB3_PHYCLKRST_SSC_REF_CLK_SEL_SHIFT (23)
+#define EXYNOS_USB3_PHYCLKRST_SSC_REF_CLK_SEL_LIMIT (0xff)
+#define EXYNOS_USB3_PHYCLKRST_SSC_REF_CLK_SEL(_x) ((_x) << 23)
+
+#define EXYNOS_USB3_PHYCLKRST_SSC_RANGE_MASK (0x03 << 21)
+#define EXYNOS_USB3_PHYCLKRST_SSC_RANGE_SHIFT (21)
+#define EXYNOS_USB3_PHYCLKRST_SSC_RANGE_LIMIT (0x03)
+#define EXYNOS_USB3_PHYCLKRST_SSC_RANGE(_x) ((_x) << 21)
+
+#define EXYNOS_USB3_PHYCLKRST_SSC_EN (1 << 20)
+#define EXYNOS_USB3_PHYCLKRST_REF_SSP_EN (1 << 19)
+#define EXYNOS_USB3_PHYCLKRST_REF_CLKDIV2 (1 << 18)
+
+#define EXYNOS_USB3_PHYCLKRST_MPLL_MULTIPLIER_MASK (0x7f << 11)
+#define EXYNOS_USB3_PHYCLKRST_MPLL_MULTIPLIER_SHIFT (11)
+#define EXYNOS_USB3_PHYCLKRST_MPLL_MULTIPLIER_LIMIT (0x7f)
+#define EXYNOS_USB3_PHYCLKRST_MPLL_MULTIPLIER(_x) ((_x) << 11)
+
+#define EXYNOS_USB3_PHYCLKRST_FSEL_MASK (0x3f << 5)
+#define EXYNOS_USB3_PHYCLKRST_FSEL_SHIFT (5)
+#define EXYNOS_USB3_PHYCLKRST_FSEL_LIMIT (0x3f)
+#define EXYNOS_USB3_PHYCLKRST_FSEL(_x) ((_x) << 5)
+
+#define EXYNOS_USB3_PHYCLKRST_RETENABLEN (1 << 4)
+
+#define EXYNOS_USB3_PHYCLKRST_REFCLKSEL_MASK (0x03 << 2)
+#define EXYNOS_USB3_PHYCLKRST_REFCLKSEL_SHIFT (2)
+#define EXYNOS_USB3_PHYCLKRST_REFCLKSEL_LIMIT (0x03)
+#define EXYNOS_USB3_PHYCLKRST_REFCLKSEL(_x) ((_x) << 2)
+
+#define EXYNOS_USB3_PHYCLKRST_PORTRESET (1 << 1)
+#define EXYNOS_USB3_PHYCLKRST_COMMONONN (1 << 0)
+
+#define EXYNOS_USB3_PHYREG0 EXYNOS_USB3_PHYREG(0x14)
+#define EXYNOS_USB3_PHYREG1 EXYNOS_USB3_PHYREG(0x18)
+#define EXYNOS_USB3_PHYPARAM0 EXYNOS_USB3_PHYREG(0x1C)
+#define EXYNOS_USB3_PHYPARAM1 EXYNOS_USB3_PHYREG(0x20)
+#define EXYNOS_USB3_PHYTERM EXYNOS_USB3_PHYREG(0x24)
+#define EXYNOS_USB3_PHYTEST EXYNOS_USB3_PHYREG(0x28)
+#define EXYNOS_USB3_PHYADP EXYNOS_USB3_PHYREG(0x2C)
+#define EXYNOS_USB3_PHYBATCHG EXYNOS_USB3_PHYREG(0x30)
+#define EXYNOS_USB3_PHYRESUME EXYNOS_USB3_PHYREG(0x34)
+#define EXYNOS_USB3_LINKPORT EXYNOS_USB3_PHYREG(0x44)
+#endif /* __PLAT_SAMSUNG_REGS_USB3_EXYNOS_DRD_PHY_H */
diff --git a/arch/arm/plat-samsung/include/plat/regs-usb3-exynos-drd.h b/arch/arm/plat-samsung/include/plat/regs-usb3-exynos-drd.h
new file mode 100644
index 0000000..9ca5f49f
--- /dev/null
+++ b/arch/arm/plat-samsung/include/plat/regs-usb3-exynos-drd.h
@@ -0,0 +1,806 @@
+/* arch/arm/plat-samsung/include/plat/regs-usb3-exynos-drd.h
+ *
+ * Copyright (c) 2011 Samsung Electronics Co. Ltd
+ * Author: Anton Tikhomirov <av.tikhomirov@samsung.com>
+ *
+ * Exynos SuperSpeed USB 3.0 DRD Controller registers
+ *
+ * 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.
+ */
+
+#ifndef __SAMSUNG_PLAT_REGS_USB3_EXYNOS_DRD_H
+#define __SAMSUNG_PLAT_REGS_USB3_EXYNOS_DRD_H __FILE__
+
+#define EXYNOS_USB3_REG(x) (x)
+
+/* xHCI registers */
+
+/* Global registers */
+#define EXYNOS_USB3_GSBUSCFG0 EXYNOS_USB3_REG(0xC100)
+#define EXYNOS_USB3_GSBUSCFG0_SBusStoreAndForward (1 << 12)
+#define EXYNOS_USB3_GSBUSCFG0_DatBigEnd (1 << 11)
+#define EXYNOS_USB3_GSBUSCFG0_INCR256BrstEna (1 << 7)
+#define EXYNOS_USB3_GSBUSCFG0_INCR128BrstEna (1 << 6)
+#define EXYNOS_USB3_GSBUSCFG0_INCR64BrstEna (1 << 5)
+#define EXYNOS_USB3_GSBUSCFG0_INCR32BrstEna (1 << 4)
+#define EXYNOS_USB3_GSBUSCFG0_INCR16BrstEna (1 << 3)
+#define EXYNOS_USB3_GSBUSCFG0_INCR8BrstEna (1 << 2)
+#define EXYNOS_USB3_GSBUSCFG0_INCR4BrstEna (1 << 1)
+#define EXYNOS_USB3_GSBUSCFG0_INCRBrstEna (1 << 0)
+
+
+#define EXYNOS_USB3_GSBUSCFG1 EXYNOS_USB3_REG(0xC104)
+#define EXYNOS_USB3_GSBUSCFG1_EN1KPAGE (1 << 12)
+
+#define EXYNOS_USB3_GSBUSCFG1_BREQLIMIT_MASK (0xf << 8)
+#define EXYNOS_USB3_GSBUSCFG1_BREQLIMIT_SHIFT (8)
+#define EXYNOS_USB3_GSBUSCFG1_BREQLIMIT_LIMIT (0xf)
+#define EXYNOS_USB3_GSBUSCFG1_BREQLIMIT(_x) ((_x) << 8)
+
+
+#define EXYNOS_USB3_GTXTHRCFG EXYNOS_USB3_REG(0xC108)
+#define EXYNOS_USB3_GTXTHRCFG_USBTxPktCntSel (1 << 29)
+
+#define EXYNOS_USB3_GTXTHRCFG_USBTxPktCnt_MASK (0xf << 24)
+#define EXYNOS_USB3_GTXTHRCFG_USBTxPktCnt_SHIFT (24)
+#define EXYNOS_USB3_GTXTHRCFG_USBTxPktCnt_LIMIT (0xf)
+#define EXYNOS_USB3_GTXTHRCFG_USBTxPktCnt(_x) ((_x) << 24)
+
+#define EXYNOS_USB3_GTXTHRCFG_USBMaxTxBurstSize_MASK (0xff << 16)
+#define EXYNOS_USB3_GTXTHRCFG_USBMaxTxBurstSize_SHIFT (16)
+#define EXYNOS_USB3_GTXTHRCFG_USBMaxTxBurstSize_LIMIT (0xff)
+#define EXYNOS_USB3_GTXTHRCFG_USBMaxTxBurstSize(_x) ((_x) << 16)
+
+
+#define EXYNOS_USB3_GRXTHRCFG EXYNOS_USB3_REG(0xC10C)
+#define EXYNOS_USB3_GRXTHRCFG_USBRxPktCntSel (1 << 29)
+
+#define EXYNOS_USB3_GRXTHRCFG_USBRxPktCnt_MASK (0xf << 24)
+#define EXYNOS_USB3_GRXTHRCFG_USBRxPktCnt_SHIFT (24)
+#define EXYNOS_USB3_GRXTHRCFG_USBRxPktCnt_LIMIT (0xf)
+#define EXYNOS_USB3_GRXTHRCFG_USBRxPktCnt(_x) ((_x) << 24)
+
+#define EXYNOS_USB3_GRXTHRCFG_USBMaxRxBurstSize_MASK (0x1f << 19)
+#define EXYNOS_USB3_GRXTHRCFG_USBMaxRxBurstSize_SHIFT (19)
+#define EXYNOS_USB3_GRXTHRCFG_USBMaxRxBurstSize_LIMIT (0x1f)
+#define EXYNOS_USB3_GRXTHRCFG_USBMaxRxBurstSize(_x) ((_x) << 19)
+
+
+#define EXYNOS_USB3_GCTL EXYNOS_USB3_REG(0xC110)
+
+#define EXYNOS_USB3_GCTL_PwrDnScale_MASK (0x1fff << 19)
+#define EXYNOS_USB3_GCTL_PwrDnScale_SHIFT (19)
+#define EXYNOS_USB3_GCTL_PwrDnScale_LIMIT (0x1fff)
+#define EXYNOS_USB3_GCTL_PwrDnScale(_x) ((_x) << 19)
+
+#define EXYNOS_USB3_GCTL_U2RSTECN (1 << 16)
+
+#define EXYNOS_USB3_GCTL_FRMSCLDWN_MASK (0x3 << 14)
+#define EXYNOS_USB3_GCTL_FRMSCLDWN_SHIFT (14)
+#define EXYNOS_USB3_GCTL_FRMSCLDWN_LIMIT (0x3)
+#define EXYNOS_USB3_GCTL_FRMSCLDWN(_x) ((_x) << 14)
+
+#define EXYNOS_USB3_GCTL_PrtCapDir_MASK (0x3 << 12)
+#define EXYNOS_USB3_GCTL_PrtCapDir_SHIFT (12)
+#define EXYNOS_USB3_GCTL_PrtCapDir_LIMIT (0x3)
+#define EXYNOS_USB3_GCTL_PrtCapDir(_x) ((_x) << 12)
+
+#define EXYNOS_USB3_GCTL_CoreSoftReset (1 << 11)
+#define EXYNOS_USB3_GCTL_LocalLpBkEn (1 << 10)
+#define EXYNOS_USB3_GCTL_LpbkEn (1 << 9)
+#define EXYNOS_USB3_GCTL_DebugAttach (1 << 8)
+
+#define EXYNOS_USB3_GCTL_RAMClkSel_MASK (0x3 << 6)
+#define EXYNOS_USB3_GCTL_RAMClkSel_SHIFT (6)
+#define EXYNOS_USB3_GCTL_RAMClkSel_LIMIT (0x3)
+#define EXYNOS_USB3_GCTL_RAMClkSel(_x) ((_x) << 6)
+
+#define EXYNOS_USB3_GCTL_ScaleDown_MASK (0x3 << 4)
+#define EXYNOS_USB3_GCTL_ScaleDown_SHIFT (4)
+#define EXYNOS_USB3_GCTL_ScaleDown_LIMIT (0x3)
+#define EXYNOS_USB3_GCTL_ScaleDown(_x) ((_x) << 4)
+
+#define EXYNOS_USB3_GCTL_DisScramble (1 << 3)
+#define EXYNOS_USB3_GCTL_SsPwrClmp (1 << 2)
+#define EXYNOS_USB3_GCTL_HsFsLsPwrClmp (1 << 1)
+#define EXYNOS_USB3_GCTL_DsblClkGtng (1 << 0)
+
+
+#define EXYNOS_USB3_GEVTEN EXYNOS_USB3_REG(0xC114)
+#define EXYNOS_USB3_GEVTEN_I2CEvtEn (1 << 1)
+#define EXYNOS_USB3_GEVTEN_ULPICKEvtEn (1 << 0)
+#define EXYNOS_USB3_GEVTEN_I2CCKEvtEn (1 << 0)
+
+
+#define EXYNOS_USB3_GSTS EXYNOS_USB3_REG(0xC118)
+
+#define EXYNOS_USB3_GSTS_CBELT_MASK (0xfff << 20)
+#define EXYNOS_USB3_GSTS_CBELT_SHIFT (20)
+#define EXYNOS_USB3_GSTS_CBELT_LIMIT (0xfff)
+#define EXYNOS_USB3_GSTS_CBELT(_x) ((_x) << 20)
+
+#define EXYNOS_USB3_GSTS_OTG_IP (1 << 10)
+#define EXYNOS_USB3_GSTS_BC_IP (1 << 9)
+#define EXYNOS_USB3_GSTS_ADP_IP (1 << 8)
+#define EXYNOS_USB3_GSTS_Host_IP (1 << 7)
+#define EXYNOS_USB3_GSTS_Device_IP (1 << 6)
+#define EXYNOS_USB3_GSTS_CSRTimeout (1 << 5)
+#define EXYNOS_USB3_GSTS_BusErrAddrVld (1 << 4)
+
+#define EXYNOS_USB3_GSTS_CurMod_MASK (0x3 << 0)
+#define EXYNOS_USB3_GSTS_CurMod_SHIFT (0)
+#define EXYNOS_USB3_GSTS_CurMod_LIMIT (0x3)
+#define EXYNOS_USB3_GSTS_CurMod(_x) ((_x) << 0)
+
+
+#define EXYNOS_USB3_GSNPSID EXYNOS_USB3_REG(0xC120)
+
+
+#define EXYNOS_USB3_GGPIO EXYNOS_USB3_REG(0xC124)
+
+#define EXYNOS_USB3_GGPIO_GPO_MASK (0xffff << 16)
+#define EXYNOS_USB3_GGPIO_GPO_SHIFT (16)
+#define EXYNOS_USB3_GGPIO_GPO_LIMIT (0xffff)
+#define EXYNOS_USB3_GGPIO_GPO(_x) ((_x) << 16)
+
+#define EXYNOS_USB3_GGPIO_GPI_MASK (0xffff << 0)
+#define EXYNOS_USB3_GGPIO_GPI_SHIFT (0)
+#define EXYNOS_USB3_GGPIO_GPI_LIMIT (0xffff)
+#define EXYNOS_USB3_GGPIO_GPI(_x) ((x) << 0)
+
+
+#define EXYNOS_USB3_GUID EXYNOS_USB3_REG(0xC128)
+
+
+#define EXYNOS_USB3_GUCTL EXYNOS_USB3_REG(0xC12C)
+#define EXYNOS_USB3_GUCTL_SprsCtrlTransEn (1 << 17)
+#define EXYNOS_USB3_GUCTL_ResBwHSEPS (1 << 16)
+#define EXYNOS_USB3_GUCTL_CMdevAddr (1 << 15)
+#define EXYNOS_USB3_GUCTL_USBHstInAutoRetryEn (1 << 14)
+
+#define EXYNOS_USB3_GUCTL_USBHstInMaxBurst_MASK (0x7 << 11)
+#define EXYNOS_USB3_GUCTL_USBHstInMaxBurst_SHIFT (11)
+#define EXYNOS_USB3_GUCTL_USBHstInMaxBurst_LIMIT (0x7)
+#define EXYNOS_USB3_GUCTL_USBHstInMaxBurst(_x) ((_x) << 11)
+
+#define EXYNOS_USB3_GUCTL_DTCT_MASK (0x3 << 9)
+#define EXYNOS_USB3_GUCTL_DTCT_SHIFT (9)
+#define EXYNOS_USB3_GUCTL_DTCT_LIMIT (0x3)
+#define EXYNOS_USB3_GUCTL_DTCT(_x) ((_x) << 9)
+
+#define EXYNOS_USB3_GUCTL_DTFT_MASK (0x1ff << 0)
+#define EXYNOS_USB3_GUCTL_DTFT_SHIFT (0)
+#define EXYNOS_USB3_GUCTL_DTFT_LIMIT (0x1ff)
+#define EXYNOS_USB3_GUCTL_DTFT(_x) ((_x) << 0)
+
+/* TODO: Not finished */
+#define EXYNOS_USB3_GBUSERRADDR_31_0 EXYNOS_USB3_REG(0xC130)
+#define EXYNOS_USB3_GBUSERRADDR_63_32 EXYNOS_USB3_REG(0xC134)
+#define EXYNOS_USB3_GPRTBIMAP_31_0 EXYNOS_USB3_REG(0xC138)
+#define EXYNOS_USB3_GPRTBIMAP_63_32 EXYNOS_USB3_REG(0xC13C)
+
+#define EXYNOS_USB3_GHWPARAMS0 EXYNOS_USB3_REG(0xC140)
+#define EXYNOS_USB3_GHWPARAMS1 EXYNOS_USB3_REG(0xC144)
+#define EXYNOS_USB3_GHWPARAMS2 EXYNOS_USB3_REG(0xC148)
+#define EXYNOS_USB3_GHWPARAMS3 EXYNOS_USB3_REG(0xC14C)
+#define EXYNOS_USB3_GHWPARAMS4 EXYNOS_USB3_REG(0xC150)
+#define EXYNOS_USB3_GHWPARAMS5 EXYNOS_USB3_REG(0xC154)
+#define EXYNOS_USB3_GHWPARAMS6 EXYNOS_USB3_REG(0xC158)
+#define EXYNOS_USB3_GHWPARAMS7 EXYNOS_USB3_REG(0xC15C)
+
+#define EXYNOS_USB3_GDBGFIFOSPACE EXYNOS_USB3_REG(0xC160)
+#define EXYNOS_USB3_GDBGLTSSM EXYNOS_USB3_REG(0xC164)
+
+#define EXYNOS_USB3_GDBGLSPMUX EXYNOS_USB3_REG(0xC170)
+#define EXYNOS_USB3_GDBGLSP EXYNOS_USB3_REG(0xC174)
+#define EXYNOS_USB3_GDBGEPINFO0 EXYNOS_USB3_REG(0xC178)
+#define EXYNOS_USB3_GDBGEPINFO1 EXYNOS_USB3_REG(0xC17C)
+
+#define EXYNOS_USB3_GPRTBIMAP_HS_31_0 EXYNOS_USB3_REG(0xC180)
+#define EXYNOS_USB3_GPRTBIMAP_HS_63_32 EXYNOS_USB3_REG(0xC184)
+#define EXYNOS_USB3_GPRTBIMAP_FS_31_0 EXYNOS_USB3_REG(0xC188)
+#define EXYNOS_USB3_GPRTBIMAP_FS_63_32 EXYNOS_USB3_REG(0xC18C)
+/****************/
+
+#define EXYNOS_USB3_GUSB2PHYCFG(_a) EXYNOS_USB3_REG(0xC200 + ((_a) * 0x04))
+#define EXYNOS_USB3_GUSB2PHYCFGx_PHYSoftRst (1 << 31)
+
+#define EXYNOS_USB3_GUSB2PHYCFGx_PhyIntrNum_MASK (0x3f << 19)
+#define EXYNOS_USB3_GUSB2PHYCFGx_PhyIntrNum_SHIFT (19)
+#define EXYNOS_USB3_GUSB2PHYCFGx_PhyIntrNum_LIMIT (0x3f)
+#define EXYNOS_USB3_GUSB2PHYCFGx_PhyIntrNum(_x) ((_x) << 19)
+
+#define EXYNOS_USB3_GUSB2PHYCFGx_ULPIExtVbusIndicator (1 << 18)
+#define EXYNOS_USB3_GUSB2PHYCFGx_ULPIExtVbusDrv (1 << 17)
+#define EXYNOS_USB3_GUSB2PHYCFGx_ULPIClkSusM (1 << 16)
+#define EXYNOS_USB3_GUSB2PHYCFGx_ULPIAutoRes (1 << 15)
+#define EXYNOS_USB3_GUSB2PHYCFGx_PhyLPwrClkSel (1 << 14)
+
+#define EXYNOS_USB3_GUSB2PHYCFGx_USBTrdTim_MASK (0xf << 10)
+#define EXYNOS_USB3_GUSB2PHYCFGx_USBTrdTim_SHIFT (10)
+#define EXYNOS_USB3_GUSB2PHYCFGx_USBTrdTim_LIMIT (0xf)
+#define EXYNOS_USB3_GUSB2PHYCFGx_USBTrdTim(_x) ((_x) << 10)
+
+#define EXYNOS_USB3_GUSB2PHYCFGx_EnblSlpM (1 << 8)
+#define EXYNOS_USB3_GUSB2PHYCFGx_PHYSel (1 << 7)
+#define EXYNOS_USB3_GUSB2PHYCFGx_SusPHY (1 << 6)
+#define EXYNOS_USB3_GUSB2PHYCFGx_FSIntf (1 << 5)
+#define EXYNOS_USB3_GUSB2PHYCFGx_ULPI_UTMI_Sel (1 << 4)
+#define EXYNOS_USB3_GUSB2PHYCFGx_PHYIf (1 << 3)
+
+#define EXYNOS_USB3_GUSB2PHYCFGx_TOutCal_MASK (0x7 << 0)
+#define EXYNOS_USB3_GUSB2PHYCFGx_TOutCal_SHIFT (0)
+#define EXYNOS_USB3_GUSB2PHYCFGx_TOutCal_LIMIT (0x7)
+#define EXYNOS_USB3_GUSB2PHYCFGx_TOutCal(_x) ((_x) << 0)
+
+
+/* Reserved for future use */
+#define EXYNOS_USB3_GUSB2I2CCTL(_a) EXYNOS_USB3_REG(0xC240 + ((_a) * 0x04))
+
+
+#define EXYNOS_USB3_GUSB2PHYACC(_a) EXYNOS_USB3_REG(0xC280 + ((_a) * 0x04))
+#define EXYNOS_USB3_GUSB2PHYACCx_DisUlpiDrvr (1 << 26)
+#define EXYNOS_USB3_GUSB2PHYACCx_NewRegReq (1 << 25)
+#define EXYNOS_USB3_GUSB2PHYACCx_VStsDone (1 << 24)
+#define EXYNOS_USB3_GUSB2PHYACCx_VStsBsy (1 << 23)
+#define EXYNOS_USB3_GUSB2PHYACCx_RegWr (1 << 22)
+
+#define EXYNOS_USB3_GUSB2PHYACCx_RegAddr_MASK (0x3f << 16)
+#define EXYNOS_USB3_GUSB2PHYACCx_RegAddr_SHIFT (16)
+#define EXYNOS_USB3_GUSB2PHYACCx_RegAddr_LIMIT (0x3f)
+#define EXYNOS_USB3_GUSB2PHYACCx_RegAddr(_x) ((_x) << 16)
+
+/* Next 2 fields are overlaping. Is it error in user manual? */
+#define EXYNOS_USB3_GUSB2PHYACCx_VCtrl_MASK (0xff << 8)
+#define EXYNOS_USB3_GUSB2PHYACCx_VCtrl_SHIFT (8)
+#define EXYNOS_USB3_GUSB2PHYACCx_VCtrl_LIMIT (0xff)
+#define EXYNOS_USB3_GUSB2PHYACCx_VCtrl(_x) ((_x) << 8)
+
+#define EXYNOS_USB3_GUSB2PHYACCx_ExtRegAddr_MASK (0x3f << 8)
+#define EXYNOS_USB3_GUSB2PHYACCx_ExtRegAddr_SHIFT (8)
+#define EXYNOS_USB3_GUSB2PHYACCx_ExtRegAddr_LIMIT (0x3f)
+#define EXYNOS_USB3_GUSB2PHYACCx_ExtRegAddr(_x) ((_x) << 8)
+
+#define EXYNOS_USB3_GUSB2PHYACCx_RegData_MASK (0xff << 0)
+#define EXYNOS_USB3_GUSB2PHYACCx_RegData_SHIFT (0)
+#define EXYNOS_USB3_GUSB2PHYACCx_RegData_LIMIT (0xff)
+#define EXYNOS_USB3_GUSB2PHYACCx_RegData(_x) ((_x) << 0)
+
+
+#define EXYNOS_USB3_GUSB3PIPECTL(_a) EXYNOS_USB3_REG(0xC2C0 + ((_a) * 0x04))
+#define EXYNOS_USB3_GUSB3PIPECTLx_PHYSoftRst (1 << 31)
+#define EXYNOS_USB3_GUSB3PIPECTLx_request_p1p2p3 (1 << 24)
+#define EXYNOS_USB3_GUSB3PIPECTLx_StartRxdetU3RxDet (1 << 23)
+#define EXYNOS_USB3_GUSB3PIPECTLx_DisRxDetU3RxDet (1 << 22)
+
+#define EXYNOS_USB3_GUSB3PIPECTLx_delay_p1p2p3_MASK (0x7 << 19)
+#define EXYNOS_USB3_GUSB3PIPECTLx_delay_p1p2p3_SHIFT (19)
+#define EXYNOS_USB3_GUSB3PIPECTLx_delay_p1p2p3_LIMIT (0x7)
+#define EXYNOS_USB3_GUSB3PIPECTLx_delay_p1p2p3(_x) ((_x) << 19)
+
+/* TODO: Check naming for the next 2 fields */
+#define EXYNOS_USB3_GUSB3PIPECTLx_delay_phy_pwr_p1p2p3 (1 << 18)
+#define EXYNOS_USB3_GUSB3PIPECTLx_SuspSSPhy (1 << 17)
+
+#define EXYNOS_USB3_GUSB3PIPECTLx_DatWidth_MASK (0x3 << 15)
+#define EXYNOS_USB3_GUSB3PIPECTLx_DatWidth_SHIFT (15)
+#define EXYNOS_USB3_GUSB3PIPECTLx_DatWidth_LIMIT (0x3)
+#define EXYNOS_USB3_GUSB3PIPECTLx_DatWidth(_x) ((_x) << 15)
+
+#define EXYNOS_USB3_GUSB3PIPECTLx_AbortRxDetInU2 (1 << 14)
+#define EXYNOS_USB3_GUSB3PIPECTLx_SkipRxDet (1 << 13)
+#define EXYNOS_USB3_GUSB3PIPECTLx_LFPSP0Algn (1 << 12)
+#define EXYNOS_USB3_GUSB3PIPECTLx_P3P2TranOK (1 << 11)
+#define EXYNOS_USB3_GUSB3PIPECTLx_LFPSFilt (1 << 9)
+#define EXYNOS_USB3_GUSB3PIPECTLx_TxSwing (1 << 6)
+
+#define EXYNOS_USB3_GUSB3PIPECTLx_TxMargin_MASK (0x7 << 3)
+#define EXYNOS_USB3_GUSB3PIPECTLx_TxMargin_SHIFT (3)
+#define EXYNOS_USB3_GUSB3PIPECTLx_TxMargin_LIMIT (0x7)
+#define EXYNOS_USB3_GUSB3PIPECTLx_TxMargin(_x) ((_x) << 3)
+
+#define EXYNOS_USB3_GUSB3PIPECTLx_TxDeemphasis_MASK (0x3 << 1)
+#define EXYNOS_USB3_GUSB3PIPECTLx_TxDeemphasis_SHIFT (1)
+#define EXYNOS_USB3_GUSB3PIPECTLx_TxDeemphasis_LIMIT (0x3)
+#define EXYNOS_USB3_GUSB3PIPECTLx_TxDeemphasis(_x) ((_x) << 1)
+
+#define EXYNOS_USB3_GUSB3PIPECTLx_ElasticBufferMode (1 << 0)
+
+
+#define EXYNOS_USB3_GTXFIFOSIZ(_a) EXYNOS_USB3_REG(0xC300 + ((_a) * 0x04))
+
+#define EXYNOS_USB3_GTXFIFOSIZx_TxFStAddr_n_MASK (0xffff << 16)
+#define EXYNOS_USB3_GTXFIFOSIZx_TxFStAddr_n_SHIFT (16)
+#define EXYNOS_USB3_GTXFIFOSIZx_TxFStAddr_n_LIMIT (0xffff)
+#define EXYNOS_USB3_GTXFIFOSIZx_TxFStAddr_n(_x) ((_x) << 16)
+
+#define EXYNOS_USB3_GTXFIFOSIZx_TxFDep_n_MASK (0xffff << 0)
+#define EXYNOS_USB3_GTXFIFOSIZx_TxFDep_n_SHIFT (0)
+#define EXYNOS_USB3_GTXFIFOSIZx_TxFDep_n_LIMIT (0xffff)
+#define EXYNOS_USB3_GTXFIFOSIZx_TxFDep_n(_x) ((_x) << 0)
+
+
+#define EXYNOS_USB3_GRXFIFOSIZ(_a) EXYNOS_USB3_REG(0xC380 + ((_a) * 0x04))
+
+#define EXYNOS_USB3_GRXFIFOSIZx_RxFStAddr_n_MASK (0xffff << 16)
+#define EXYNOS_USB3_GRXFIFOSIZx_RxFStAddr_n_SHIFT (16)
+#define EXYNOS_USB3_GRXFIFOSIZx_RxFStAddr_n_LIMIT (0xffff)
+#define EXYNOS_USB3_GRXFIFOSIZx_RxFStAddr_n(_x) ((_x) << 16)
+
+#define EXYNOS_USB3_GRXFIFOSIZx_RxFDep_n_MASK (0xffff << 0)
+#define EXYNOS_USB3_GRXFIFOSIZx_RxFDep_n_SHIFT (0)
+#define EXYNOS_USB3_GRXFIFOSIZx_RxFDep_n_LIMIT (0xffff)
+#define EXYNOS_USB3_GRXFIFOSIZx_RxFDep_n(_x) ((_x) << 0)
+
+
+#define EXYNOS_USB3_GEVNTADR_31_0(_a) EXYNOS_USB3_REG(0xC400 + ((_a) * 0x10))
+#define EXYNOS_USB3_GEVNTADR_63_32(_a) EXYNOS_USB3_REG(0xC404 + ((_a) * 0x10))
+
+
+#define EXYNOS_USB3_GEVNTSIZ(_a) EXYNOS_USB3_REG(0xC408 + ((_a) * 0x10))
+#define EXYNOS_USB3_GEVNTSIZx_EvntIntMask (1 << 31)
+
+#define EXYNOS_USB3_GEVNTSIZx_EVNTSiz_MASK (0xffff << 0)
+#define EXYNOS_USB3_GEVNTSIZx_EVNTSiz_SHIFT (0)
+#define EXYNOS_USB3_GEVNTSIZx_EVNTSiz_LIMIT (0xffff)
+#define EXYNOS_USB3_GEVNTSIZx_EVNTSiz(x) ((_x) << 0)
+
+
+#define EXYNOS_USB3_GEVNTCOUNT(_a) EXYNOS_USB3_REG(0xC40C + ((_a) * 0x10))
+
+#define EXYNOS_USB3_GEVNTCOUNTx_EVNTCount_MASK (0xffff << 0)
+#define EXYNOS_USB3_GEVNTCOUNTx_EVNTCount_SHIFT (0)
+#define EXYNOS_USB3_GEVNTCOUNTx_EVNTCount_LIMIT (0xffff)
+#define EXYNOS_USB3_GEVNTCOUNTx_EVNTCount(_x) ((_x) << 0)
+
+/* Event Buffer Content for Device Endpoint-Specific Events (DEPEVT) */
+#define EXYNOS_USB3_DEPEVT_EventParam_MASK (0xffff << 16)
+#define EXYNOS_USB3_DEPEVT_EventParam_SHIFT (16)
+#define EXYNOS_USB3_DEPEVT_EventParam_LIMIT (0xffff)
+#define EXYNOS_USB3_DEPEVT_EventParam(_x) ((_x) << 16)
+
+#define EXYNOS_USB3_DEPEVT_EventStatus_MASK (0xf << 12)
+#define EXYNOS_USB3_DEPEVT_EventStatus_SHIFT (12)
+#define EXYNOS_USB3_DEPEVT_EventStatus_LIMIT (0xf)
+
+#define EXYNOS_USB3_DEPEVT_EVENT_MASK (0xf << 6)
+#define EXYNOS_USB3_DEPEVT_EVENT_SHIFT (6)
+#define EXYNOS_USB3_DEPEVT_EVENT_LIMIT (0xf)
+#define EXYNOS_USB3_DEPEVT_EVENT_EPCmdCmplt (7 << 6)
+#define EXYNOS_USB3_DEPEVT_EVENT_StreamEvt (6 << 6)
+#define EXYNOS_USB3_DEPEVT_EVENT_RxTxfifoEvt (4 << 6)
+#define EXYNOS_USB3_DEPEVT_EVENT_XferNotReady (3 << 6)
+#define EXYNOS_USB3_DEPEVT_EVENT_XferInProgress (2 << 6)
+#define EXYNOS_USB3_DEPEVT_EVENT_XferComplete (1 << 6)
+
+#define EXYNOS_USB3_DEPEVT_EPNUM_MASK (0x1f << 1)
+#define EXYNOS_USB3_DEPEVT_EPNUM_SHIFT (1)
+#define EXYNOS_USB3_DEPEVT_EPNUM_LIMIT (0x1f)
+#define EXYNOS_USB3_DEPEVT_EPNUM(_x) ((_x) << 1)
+
+/* Event Buffer Content for Device-Specific Events (DEVT) */
+#define EXYNOS_USB3_DEVT_EventParam_MASK (0xf << 16)
+#define EXYNOS_USB3_DEVT_EventParam_SHIFT (16)
+#define EXYNOS_USB3_DEVT_EventParam_LIMIT (0xf)
+#define EXYNOS_USB3_DEVT_EventParam_SS (1 << 20)
+#define EXYNOS_USB3_DEVT_EventParam(_x) ((_x) << 16)
+
+#define EXYNOS_USB3_DEVT_EVENT_MASK (0xf << 8)
+#define EXYNOS_USB3_DEVT_EVENT_SHIFT (8)
+#define EXYNOS_USB3_DEVT_EVENT_LIMIT (0xf)
+#define EXYNOS_USB3_DEVT_EVENT_VndrDevTstRcved (12 << 8)
+#define EXYNOS_USB3_DEVT_EVENT_EvntOverflow (11 << 8)
+#define EXYNOS_USB3_DEVT_EVENT_CmdCmplt (10 << 8)
+#define EXYNOS_USB3_DEVT_EVENT_ErrticErr (9 << 8)
+#define EXYNOS_USB3_DEVT_EVENT_Sof (7 << 8)
+#define EXYNOS_USB3_DEVT_EVENT_EOPF (6 << 8)
+#define EXYNOS_USB3_DEVT_EVENT_WkUpEvt (4 << 8)
+#define EXYNOS_USB3_DEVT_EVENT_ULStChng (3 << 8)
+#define EXYNOS_USB3_DEVT_EVENT_ConnectDone (2 << 8)
+#define EXYNOS_USB3_DEVT_EVENT_USBRst (1 << 8)
+#define EXYNOS_USB3_DEVT_EVENT_DisconnEvt (0 << 8)
+
+
+#define EXYNOS_USB3_GHWPARAMS8 EXYNOS_USB3_REG(0xC600)
+
+
+/* Device registers */
+#define EXYNOS_USB3_DCFG EXYNOS_USB3_REG(0xC700)
+#define EXYNOS_USB3_DCFG_IgnoreStreamPP (1 << 23)
+#define EXYNOS_USB3_DCFG_LPMCap (1 << 22)
+
+#define EXYNOS_USB3_DCFG_NumP_MASK (0x1f << 17)
+#define EXYNOS_USB3_DCFG_NumP_SHIFT (17)
+#define EXYNOS_USB3_DCFG_NumP_LIMIT (0x1f)
+#define EXYNOS_USB3_DCFG_NumP(_x) ((_x) << 17)
+
+#define EXYNOS_USB3_DCFG_IntrNum_MASK (0x1f << 12)
+#define EXYNOS_USB3_DCFG_IntrNum_SHIFT (12)
+#define EXYNOS_USB3_DCFG_IntrNum_LIMIT (0x1f)
+#define EXYNOS_USB3_DCFG_IntrNum(_x) (0x1f << 12)
+
+#define EXYNOS_USB3_DCFG_PerFrInt_MASK (0x3 << 10)
+#define EXYNOS_USB3_DCFG_PerFrInt_SHIFT (10)
+#define EXYNOS_USB3_DCFG_PerFrInt_LIMIT (0x3)
+#define EXYNOS_USB3_DCFG_PerFrInt(_x) ((_x) << 10)
+
+#define EXYNOS_USB3_DCFG_DevAddr_MASK (0x7f << 3)
+#define EXYNOS_USB3_DCFG_DevAddr_SHIFT (3)
+#define EXYNOS_USB3_DCFG_DevAddr_LIMIT (0x7f)
+#define EXYNOS_USB3_DCFG_DevAddr(_x) ((_x) << 3)
+
+#define EXYNOS_USB3_DCFG_DevSpd_MASK (0x7 << 0)
+#define EXYNOS_USB3_DCFG_DevSpd_SHIFT (0)
+#define EXYNOS_USB3_DCFG_DevSpd_LIMIT (0x7)
+#define EXYNOS_USB3_DCFG_DevSpd(_x) ((_x) << 0)
+
+
+#define EXYNOS_USB3_DCTL EXYNOS_USB3_REG(0xC704)
+#define EXYNOS_USB3_DCTL_Run_Stop (1 << 31)
+#define EXYNOS_USB3_DCTL_CSftRst (1 << 30)
+#define EXYNOS_USB3_DCTL_LSftRst (1 << 29)
+
+#define EXYNOS_USB3_DCTL_HIRD_Thres_MASK (0x1f << 24)
+#define EXYNOS_USB3_DCTL_HIRD_Thres_SHIFT (24)
+#define EXYNOS_USB3_DCTL_HIRD_Thres_LIMIT (0x1f)
+#define EXYNOS_USB3_DCTL_HIRD_Thres(_x) ((_x) << 24)
+
+#define EXYNOS_USB3_DCTL_AppL1Res (1 << 23)
+
+#define EXYNOS_USB3_DCTL_TrgtULSt_MASK (0xf << 17)
+#define EXYNOS_USB3_DCTL_TrgtULSt_SHIFT (17)
+#define EXYNOS_USB3_DCTL_TrgtULSt_LIMIT (0xf)
+#define EXYNOS_USB3_DCTL_TrgtULSt(_x) ((_x) << 17)
+
+#define EXYNOS_USB3_DCTL_InitU2Ena (1 << 12)
+#define EXYNOS_USB3_DCTL_AcceptU2Ena (1 << 11)
+#define EXYNOS_USB3_DCTL_InitU1Ena (1 << 10)
+#define EXYNOS_USB3_DCTL_AcceptU1Ena (1 << 9)
+
+#define EXYNOS_USB3_DCTL_ULStChngReq_MASK (0xf << 5)
+#define EXYNOS_USB3_DCTL_ULStChngReq_SHIFT (5)
+#define EXYNOS_USB3_DCTL_ULStChngReq_LIMIT (0xf)
+#define EXYNOS_USB3_DCTL_ULStChngReq(_x) ((_x) << 5)
+
+#define EXYNOS_USB3_DCTL_TstCtl_MASK (0xf << 1)
+#define EXYNOS_USB3_DCTL_TstCtl_SHIFT (1)
+#define EXYNOS_USB3_DCTL_TstCtl_LIMIT (0xf)
+#define EXYNOS_USB3_DCTL_TstCtl(_x) ((_x) << 1)
+
+
+#define EXYNOS_USB3_DEVTEN EXYNOS_USB3_REG(0xC708)
+#define EXYNOS_USB3_DEVTEN_VndrDevTstRcvedEn (1 << 12)
+#define EXYNOS_USB3_DEVTEN_EvntOverflowEn (1 << 11)
+#define EXYNOS_USB3_DEVTEN_CmdCmpltEn (1 << 10)
+#define EXYNOS_USB3_DEVTEN_ErrticErrEn (1 << 9)
+#define EXYNOS_USB3_DEVTEN_SofEn (1 << 7)
+#define EXYNOS_USB3_DEVTEN_EOPFEn (1 << 6)
+#define EXYNOS_USB3_DEVTEN_WkUpEvtEn (1 << 4)
+#define EXYNOS_USB3_DEVTEN_ULStCngEn (1 << 3)
+#define EXYNOS_USB3_DEVTEN_ConnectDoneEn (1 << 2)
+#define EXYNOS_USB3_DEVTEN_USBRstEn (1 << 1)
+#define EXYNOS_USB3_DEVTEN_DisconnEvtEn (1 << 0)
+
+
+#define EXYNOS_USB3_DSTS EXYNOS_USB3_REG(0xC70C)
+#define EXYNOS_USB3_DSTS_PwrUpReq (1 << 24)
+#define EXYNOS_USB3_DSTS_CoreIdle (1 << 23)
+#define EXYNOS_USB3_DSTS_DevCtrlHlt (1 << 22)
+
+#define EXYNOS_USB3_DSTS_USBLnkSt_MASK (0xf << 18)
+#define EXYNOS_USB3_DSTS_USBLnkSt_SHIFT (18)
+#define EXYNOS_USB3_DSTS_USBLnkSt_LIMIT (0xf)
+#define EXYNOS_USB3_DSTS_USBLnkSt(_x) ((_x) << 18)
+#define EXYNOS_USB3_LnkSt_LPBK (0xb)
+#define EXYNOS_USB3_LnkSt_CMPLY (0xa)
+#define EXYNOS_USB3_LnkSt_HRESET (0x9)
+#define EXYNOS_USB3_LnkSt_RECOV (0x8)
+#define EXYNOS_USB3_LnkSt_POLL (0x7)
+#define EXYNOS_USB3_LnkSt_SS_INACT (0x6)
+#define EXYNOS_USB3_LnkSt_RX_DET (0x5)
+#define EXYNOS_USB3_LnkSt_SS_DIS (0x4)
+#define EXYNOS_USB3_LnkSt_U3 (0x3)
+#define EXYNOS_USB3_LnkSt_U2 (0x2)
+#define EXYNOS_USB3_LnkSt_U1 (0x1)
+#define EXYNOS_USB3_LnkSt_U0 (0x0)
+
+#define EXYNOS_USB3_DSTS_RxFIFOEmpty (1 << 17)
+
+#define EXYNOS_USB3_DSTS_SOFFN_MASK (0x3fff << 3)
+#define EXYNOS_USB3_DSTS_SOFFN_SHIFT (3)
+#define EXYNOS_USB3_DSTS_SOFFN_LIMIT (0x3fff)
+#define EXYNOS_USB3_DSTS_SOFFN(_x) ((_x) << 3)
+
+#define EXYNOS_USB3_DSTS_ConnectSpd_MASK (0x7 << 0)
+#define EXYNOS_USB3_DSTS_ConnectSpd_SHIFT (0)
+#define EXYNOS_USB3_DSTS_ConnectSpd_LIMIT (0x7)
+#define EXYNOS_USB3_DSTS_ConnectSpd(_x) ((_x) << 0)
+
+
+#define EXYNOS_USB3_DGCMDPAR EXYNOS_USB3_REG(0xC710)
+
+
+#define EXYNOS_USB3_DGCMD EXYNOS_USB3_REG(0xC714)
+#define EXYNOS_USB3_DGCMD_CmdStatus (1 << 15)
+#define EXYNOS_USB3_DGCMD_CmdAct (1 << 10)
+#define EXYNOS_USB3_DGCMD_CmdIOC (1 << 8)
+
+#define EXYNOS_USB3_DGCMD_CmdTyp_MASK (0xff << 0)
+#define EXYNOS_USB3_DGCMD_CmdTyp_SHIFT (0)
+#define EXYNOS_USB3_DGCMD_CmdTyp_LIMIT (0xff)
+#define EXYNOS_USB3_DGCMD_CmdTyp(_x) ((_x) << 0)
+/* TODO: add device generic command descriptions */
+#define EXYNOS_USB3_DGCMD_CmdTyp_SetPerParams (0x2 << 0)
+
+/* TODO: not finished */
+#define EXYNOS_USB3_DALEPENA EXYNOS_USB3_REG(0xC720)
+
+
+#define EXYNOS_USB3_DEPCMDPAR2(_a) EXYNOS_USB3_REG(0xC800 + ((_a) * 0x10))
+
+#define EXYNOS_USB3_DEPCMDPAR1(_a) EXYNOS_USB3_REG(0xC804 + ((_a) * 0x10))
+/* DEPCFG command parameter 1 */
+#define EXYNOS_USB3_DEPCMDPAR1x_FIFO_based (1 << 31)
+#define EXYNOS_USB3_DEPCMDPAR1x_BULK_based (1 << 30)
+
+#define EXYNOS_USB3_DEPCMDPAR1x_EpNum_MASK (0xf << 26)
+#define EXYNOS_USB3_DEPCMDPAR1x_EpNum_SHIFT (26)
+#define EXYNOS_USB3_DEPCMDPAR1x_EpNum_LIMIT (0xf)
+#define EXYNOS_USB3_DEPCMDPAR1x_EpNum(_x) ((_x) << 26)
+
+#define EXYNOS_USB3_DEPCMDPAR1x_EpDir (1 << 25)
+#define EXYNOS_USB3_DEPCMDPAR1x_StrmCap (1 << 24)
+
+#define EXYNOS_USB3_DEPCMDPAR1x_bInterval_m1_MASK (0xff << 16)
+#define EXYNOS_USB3_DEPCMDPAR1x_bInterval_m1_SHIFT (16)
+#define EXYNOS_USB3_DEPCMDPAR1x_bInterval_m1_LIMIT (0xff)
+#define EXYNOS_USB3_DEPCMDPAR1x_bInterval_m1(_x) ((_x) << 16)
+
+#define EXYNOS_USB3_DEPCMDPAR1x_StreamEvtEn (1 << 13)
+#define EXYNOS_USB3_DEPCMDPAR1x_RxTxfifoEvtEn (1 << 11)
+#define EXYNOS_USB3_DEPCMDPAR1x_XferNRdyEn (1 << 10)
+#define EXYNOS_USB3_DEPCMDPAR1x_XferInProgEn (1 << 9)
+#define EXYNOS_USB3_DEPCMDPAR1x_XferCmplEn (1 << 8)
+
+#define EXYNOS_USB3_DEPCMDPAR1x_IntrNum_MASK (0x1f << 0)
+#define EXYNOS_USB3_DEPCMDPAR1x_IntrNum_SHIFT (0)
+#define EXYNOS_USB3_DEPCMDPAR1x_IntrNum_LIMIT (0x1f)
+#define EXYNOS_USB3_DEPCMDPAR1x_IntrNum(_x) ((_x) << 0)
+
+
+#define EXYNOS_USB3_DEPCMDPAR0(_a) EXYNOS_USB3_REG(0xC808 + ((_a) * 0x10))
+/* DEPCFG command parameter 0 */
+#define EXYNOS_USB3_DEPCMDPAR0x_IgnrSeqNum (1 << 31)
+
+#define EXYNOS_USB3_DEPCMDPAR0x_DataSeqNum_MASK (0x1f << 26)
+#define EXYNOS_USB3_DEPCMDPAR0x_DataSeqNum_SHIFT (26)
+#define EXYNOS_USB3_DEPCMDPAR0x_DataSeqNum_LIMIT (0x1f)
+#define EXYNOS_USB3_DEPCMDPAR0x_DataSeqNum(_x) ((_x) << 26)
+
+#define EXYNOS_USB3_DEPCMDPAR0x_BrstSiz_MASK (0xf << 22)
+#define EXYNOS_USB3_DEPCMDPAR0x_BrstSiz_SHIFT (22)
+#define EXYNOS_USB3_DEPCMDPAR0x_BrstSiz_LIMIT (0xf)
+#define EXYNOS_USB3_DEPCMDPAR0x_BrstSiz(_x) ((_x) << 22)
+
+#define EXYNOS_USB3_DEPCMDPAR0x_FIFONum_MASK (0x1f << 17)
+#define EXYNOS_USB3_DEPCMDPAR0x_FIFONum_SHIFT (17)
+#define EXYNOS_USB3_DEPCMDPAR0x_FIFONum_LIMIT (0x1f)
+#define EXYNOS_USB3_DEPCMDPAR0x_FIFONum(_x) ((_x) << 17)
+
+#define EXYNOS_USB3_DEPCMDPAR0x_MPS_MASK (0x7ff << 3)
+#define EXYNOS_USB3_DEPCMDPAR0x_MPS_SHIFT (3)
+#define EXYNOS_USB3_DEPCMDPAR0x_MPS_LIMIT (0x7ff)
+#define EXYNOS_USB3_DEPCMDPAR0x_MPS(_x) ((_x) << 3)
+
+#define EXYNOS_USB3_DEPCMDPAR0x_EPType_MASK (0x3 << 1)
+#define EXYNOS_USB3_DEPCMDPAR0x_EPType_SHIFT (1)
+#define EXYNOS_USB3_DEPCMDPAR0x_EPType_LIMIT (0x3)
+#define EXYNOS_USB3_DEPCMDPAR0x_EPType(_x) ((_x) << 1)
+
+/* DEPXFERCFG command parameter 0 */
+#define EXYNOS_USB3_DEPCMDPAR0x_NumXferRes_MASK (0xff << 0)
+#define EXYNOS_USB3_DEPCMDPAR0x_NumXferRes_SHIFT (0)
+#define EXYNOS_USB3_DEPCMDPAR0x_NumXferRes_LIMIT (0xff)
+#define EXYNOS_USB3_DEPCMDPAR0x_NumXferRes(_x) ((_x) << 0)
+
+
+#define EXYNOS_USB3_DEPCMD(_a) EXYNOS_USB3_REG(0xC80C + ((_a) * 0x10))
+
+#define EXYNOS_USB3_DEPCMDx_CommandParam_MASK (0xffff << 16)
+#define EXYNOS_USB3_DEPCMDx_CommandParam_SHIFT (16)
+#define EXYNOS_USB3_DEPCMDx_CommandParam_LIMIT (0xffff)
+#define EXYNOS_USB3_DEPCMDx_CommandParam(_x) ((_x) << 16)
+
+#define EXYNOS_USB3_DEPCMDx_EventParam_MASK (0xffff << 16)
+#define EXYNOS_USB3_DEPCMDx_EventParam_SHIFT (16)
+#define EXYNOS_USB3_DEPCMDx_EventParam_LIMIT (0xffff)
+#define EXYNOS_USB3_DEPCMDx_EventParam(_x) ((_x) << 16)
+
+#define EXYNOS_USB3_DEPCMDx_XferRscIdx_LIMIT (0x7f)
+
+#define EXYNOS_USB3_DEPCMDx_CmdStatus_MASK (0xf << 12)
+#define EXYNOS_USB3_DEPCMDx_CmdStatus_SHIFT (12)
+#define EXYNOS_USB3_DEPCMDx_CmdStatus_LIMIT (0xf)
+#define EXYNOS_USB3_DEPCMDx_CmdStatus(_x) ((_x) << 12)
+
+#define EXYNOS_USB3_DEPCMDx_HiPri_ForceRM (1 << 11)
+#define EXYNOS_USB3_DEPCMDx_CmdAct (1 << 10)
+#define EXYNOS_USB3_DEPCMDx_CmdIOC (1 << 8)
+
+#define EXYNOS_USB3_DEPCMDx_CmdTyp_MASK (0xf << 0)
+#define EXYNOS_USB3_DEPCMDx_CmdTyp_SHIFT (0)
+#define EXYNOS_USB3_DEPCMDx_CmdTyp_LIMIT (0xf)
+#define EXYNOS_USB3_DEPCMDx_CmdTyp(_x) ((_x) << 0)
+/* Physical Endpoint commands */
+#define EXYNOS_USB3_DEPCMDx_CmdTyp_DEPCFG (0x1 << 0)
+#define EXYNOS_USB3_DEPCMDx_CmdTyp_DEPXFERCFG (0x2 << 0)
+#define EXYNOS_USB3_DEPCMDx_CmdTyp_DEPGETDSEQ (0x3 << 0)
+#define EXYNOS_USB3_DEPCMDx_CmdTyp_DEPSSTALL (0x4 << 0)
+#define EXYNOS_USB3_DEPCMDx_CmdTyp_DEPCSTALL (0x5 << 0)
+#define EXYNOS_USB3_DEPCMDx_CmdTyp_DEPSTRTXFER (0x6 << 0)
+#define EXYNOS_USB3_DEPCMDx_CmdTyp_DEPUPDXFER (0x7 << 0)
+#define EXYNOS_USB3_DEPCMDx_CmdTyp_DEPENDXFER (0x8 << 0)
+#define EXYNOS_USB3_DEPCMDx_CmdTyp_DEPSTARTCFG (0x9 << 0)
+
+
+/* USB 2.0 OTG and Battery Charger registers */
+#define EXYNOS_USB3_OCFG EXYNOS_USB3_REG(0xCC00)
+#define EXYNOS_USB3_OCFG_OTG_Version (1 << 2)
+#define EXYNOS_USB3_OCFG_HNPCap (1 << 1)
+#define EXYNOS_USB3_OCFG_SRPCap (1 << 0)
+
+
+#define EXYNOS_USB3_OCTL EXYNOS_USB3_REG(0xCC04)
+#define EXYNOS_USB3_OCTL_PeriMode (1 << 6)
+#define EXYNOS_USB3_OCTL_PrtPwrCtl (1 << 5)
+#define EXYNOS_USB3_OCTL_HNPReq (1 << 4)
+#define EXYNOS_USB3_OCTL_SesReq (1 << 3)
+#define EXYNOS_USB3_OCTL_TermSelDLPulse (1 << 2)
+#define EXYNOS_USB3_OCTL_DevSetHNPEn (1 << 1)
+#define EXYNOS_USB3_OCTL_HstSetHNPEn (1 << 0)
+
+
+#define EXYNOS_USB3_OEVT EXYNOS_USB3_REG(0xCC08)
+#define EXYNOS_USB3_OEVT_DeviceMode (1 << 31)
+#define EXYNOS_USB3_OEVT_OTGConIDStsChngEvnt (1 << 24)
+#define EXYNOS_USB3_OEVT_OTGADevBHostEndEvnt (1 << 20)
+#define EXYNOS_USB3_OEVT_OTGADevHostEvnt (1 << 19)
+#define EXYNOS_USB3_OEVT_OTGADevHNPChngEvnt (1 << 18)
+#define EXYNOS_USB3_OEVT_OTGADevSRPDetEvnt (1 << 17)
+#define EXYNOS_USB3_OEVT_OTGADevSessEndDetEvnt (1 << 16)
+#define EXYNOS_USB3_OEVT_OTGBDevBHostEndEvnt (1 << 11)
+#define EXYNOS_USB3_OEVT_OTGBDevHNPChngEvnt (1 << 10)
+#define EXYNOS_USB3_OEVT_OTGBDevSessVldDetEvnt (1 << 9)
+#define EXYNOS_USB3_OEVT_OTGBDevVBUSChngEvnt (1 << 8)
+#define EXYNOS_USB3_OEVT_BSesVld (1 << 3)
+#define EXYNOS_USB3_OEVT_HstNegSts (1 << 2)
+#define EXYNOS_USB3_OEVT_SesReqSts (1 << 1)
+#define EXYNOS_USB3_OEVT_OEVTError (1 << 0)
+
+
+#define EXYNOS_USB3_OEVTEN EXYNOS_USB3_REG(0xCC0C)
+#define EXYNOS_USB3_OEVTEN_OTGConIDStsChngEvntEn (1 << 24)
+#define EXYNOS_USB3_OEVTEN_OTGADevBHostEndEvntEn (1 << 20)
+#define EXYNOS_USB3_OEVTEN_OTGADevHostEvntEn (1 << 19)
+#define EXYNOS_USB3_OEVTEN_OTGADevHNPChngEvntEn (1 << 18)
+#define EXYNOS_USB3_OEVTEN_OTGADevSRPDetEvntEn (1 << 17)
+#define EXYNOS_USB3_OEVTEN_OTGADevSessEndDetEvntEn (1 << 16)
+#define EXYNOS_USB3_OEVTEN_OTGBDevBHostEndEvntEn (1 << 11)
+#define EXYNOS_USB3_OEVTEN_OTGBDevHNPChngEvntEn (1 << 10)
+#define EXYNOS_USB3_OEVTEN_OTGBDevSessVldDetEvntEn (1 << 9)
+#define EXYNOS_USB3_OEVTEN_OTGBDevVBUSChngEvntEn (1 << 8)
+
+
+#define EXYNOS_USB3_OSTS EXYNOS_USB3_REG(0xCC10)
+
+#define EXYNOS_USB3_OSTS_OTG_state_MASK (0xf << 8)
+#define EXYNOS_USB3_OSTS_OTG_state_SHIFT (8)
+#define EXYNOS_USB3_OSTS_OTG_state_LIMIT (0xf)
+#define EXYNOS_USB3_OSTS_OTG_state(_x) ((_x) << 8)
+
+#define EXYNOS_USB3_OSTS_PeripheralState (1 << 4)
+#define EXYNOS_USB3_OSTS_xHCIPrtPower (1 << 3)
+#define EXYNOS_USB3_OSTS_BSesVld (1 << 2)
+#define EXYNOS_USB3_OSTS_VbusVld (1 << 1)
+#define EXYNOS_USB3_OSTS_ConIDSts (1 << 0)
+
+
+#define EXYNOS_USB3_ADPCFG EXYNOS_USB3_REG(0xCC20)
+
+#define EXYNOS_USB3_ADPCFG_PrbPer_MASK (0x3 << 30)
+#define EXYNOS_USB3_ADPCFG_PrbPer_SHIFT (30)
+#define EXYNOS_USB3_ADPCFG_PrbPer_LIMIT (0x3)
+#define EXYNOS_USB3_ADPCFG_PrbPer(_x) ((_x) << 30)
+
+#define EXYNOS_USB3_ADPCFG_PrbDelta_MASK (0x3 << 28)
+#define EXYNOS_USB3_ADPCFG_PrbDelta_SHIFT (28)
+#define EXYNOS_USB3_ADPCFG_PrbDelta_LIMIT (0x3)
+#define EXYNOS_USB3_ADPCFG_PrbDelta(_x) ((_x) << 28)
+
+#define EXYNOS_USB3_ADPCFG_PrbDschg_MASK (0x3 << 26)
+#define EXYNOS_USB3_ADPCFG_PrbDschg_SHIFT (26)
+#define EXYNOS_USB3_ADPCFG_PrbDschg_LIMIT (0x3)
+#define EXYNOS_USB3_ADPCFG_PrbDschg(_x) ((_x) << 26)
+
+
+#define EXYNOS_USB3_ADPCTL EXYNOS_USB3_REG(0xCC24)
+#define EXYNOS_USB3_ADPCTL_EnaPrb (1 << 28)
+#define EXYNOS_USB3_ADPCTL_EnaSns (1 << 27)
+#define EXYNOS_USB3_ADPCTL_ADPEn (1 << 26)
+#define EXYNOS_USB3_ADPCTL_ADPRes (1 << 25)
+#define EXYNOS_USB3_ADPCTL_WB (1 << 24)
+
+
+#define EXYNOS_USB3_ADPEVT EXYNOS_USB3_REG(0xCC28)
+#define EXYNOS_USB3_ADPEVT_AdpPrbEvnt (1 << 28)
+#define EXYNOS_USB3_ADPEVT_AdpSnsEvnt (1 << 27)
+#define EXYNOS_USB3_ADPEVT_AdpTmoutEvnt (1 << 26)
+#define EXYNOS_USB3_ADPEVT_ADPRstCmpltEvnt (1 << 25)
+
+#define EXYNOS_USB3_ADPEVT_RTIM_MASK (0x7ff << 0)
+#define EXYNOS_USB3_ADPEVT_RTIM_SHIFT (0)
+#define EXYNOS_USB3_ADPEVT_RTIM_LIMIT (0x7ff)
+#define EXYNOS_USB3_ADPEVT_RTIM(_x) ((_x) << 0)
+
+
+#define EXYNOS_USB3_ADPEVTEN EXYNOS_USB3_REG(0xCC2C)
+#define EXYNOS_USB3_ADPEVTEN_AdpPrbEvntEn (1 << 28)
+#define EXYNOS_USB3_ADPEVTEN_AdpSnsEvntEn (1 << 27)
+#define EXYNOS_USB3_ADPEVTEN_AdpTmoutEvntEn (1 << 26)
+#define EXYNOS_USB3_ADPEVTEN_ADPRstCmpltEvntEn (1 << 25)
+
+
+#define EXYNOS_USB3_BCFG EXYNOS_USB3_REG(0xCC30)
+#define EXYNOS_USB3_BCFG_IDDIG_SEL (1 << 1)
+#define EXYNOS_USB3_BCFG_CHIRP_EN (1 << 0)
+
+
+#define EXYNOS_USB3_BCEVT EXYNOS_USB3_REG(0xCC38)
+#define EXYNOS_USB3_BCEVT_MV_ChngEvnt (1 << 24)
+
+#define EXYNOS_USB3_BCEVT_MultValIdBc_MASK (0x1f << 0)
+#define EXYNOS_USB3_BCEVT_MultValIdBc_SHIFT (0)
+#define EXYNOS_USB3_BCEVT_MultValIdBc_LIMIT (0x1f)
+#define EXYNOS_USB3_BCEVT_MultValIdBc(_x) ((_x) << 0)
+
+
+#define EXYNOS_USB3_BCEVTEN EXYNOS_USB3_REG(0xCC3C)
+#define EXYNOS_USB3_BCEVTEN_MV_ChngEvntEn (1 << 24)
+
+/* Transfer Request Block */
+#define EXYNOS_USB3_TRB_TRBSTS_MASK (0xf << 28)
+#define EXYNOS_USB3_TRB_TRBSTS_SHIFT (28)
+#define EXYNOS_USB3_TRB_TRBSTS_LIMIT (0xf)
+#define EXYNOS_USB3_TRB_TRBSTS(_x) ((_x) << 28)
+
+#define EXYNOS_USB3_TRB_PCM1_MASK (0x3 << 24)
+#define EXYNOS_USB3_TRB_PCM1_SHIFT (24)
+#define EXYNOS_USB3_TRB_PCM1_LIMIT (0x3)
+#define EXYNOS_USB3_TRB_PCM1(_x) ((_x) << 24)
+
+#define EXYNOS_USB3_TRB_BUFSIZ_MASK (0xffffff << 0)
+#define EXYNOS_USB3_TRB_BUFSIZ_SHIFT (0)
+#define EXYNOS_USB3_TRB_BUFSIZ_LIMIT (0xffffff)
+#define EXYNOS_USB3_TRB_BUFSIZ(_x) ((_x) << 0)
+
+#define EXYNOS_USB3_TRB_StreamID_SOFNumber_MASK (0xffff << 14)
+#define EXYNOS_USB3_TRB_StreamID_SOFNumber_SHIFT (14)
+#define EXYNOS_USB3_TRB_StreamID_SOFNumber_LIMIT (0xffff)
+#define EXYNOS_USB3_TRB_StreamID_SOFNumber(_x) ((_x) << 14)
+
+#define EXYNOS_USB3_TRB_IOC (1 << 11)
+#define EXYNOS_USB3_TRB_ISP_IMI (1 << 10)
+
+#define EXYNOS_USB3_TRB_TRBCTL_MASK (0x3f << 4)
+#define EXYNOS_USB3_TRB_TRBCTL_SHIFT (4)
+#define EXYNOS_USB3_TRB_TRBCTL_LIMIT (0x3f)
+#define EXYNOS_USB3_TRB_TRBCTL(_x) ((_x) << 4)
+
+#define EXYNOS_USB3_TRB_CSP (1 << 3)
+#define EXYNOS_USB3_TRB_CHN (1 << 2)
+#define EXYNOS_USB3_TRB_LST (1 << 1)
+#define EXYNOS_USB3_TRB_HWO (1 << 0)
+
+#endif /* __SAMSUNG_PLAT_REGS_USB3_EXYNOS_DRD_H */
diff --git a/arch/arm/plat-samsung/include/plat/regs-watchdog.h b/arch/arm/plat-samsung/include/plat/regs-watchdog.h
index 4938492..7969416 100644
--- a/arch/arm/plat-samsung/include/plat/regs-watchdog.h
+++ b/arch/arm/plat-samsung/include/plat/regs-watchdog.h
@@ -36,6 +36,16 @@
#define S3C2410_WTCON_PRESCALE(x) ((x) << 8)
#define S3C2410_WTCON_PRESCALE_MASK (0xff00)
+void s3c2410wdt_save(void);
+void s3c2410wdt_restore(void);
+
+#if defined(CONFIG_S3C_DEV_WDT)
+#define watchdog_save() s3c2410wdt_save();
+#define watchdog_restore() s3c2410wdt_restore();
+#else
+#define watchdog_save() do {} while (0)
+#define watchdog_restore() do {} while (0)
+#endif
#endif /* __ASM_ARCH_REGS_WATCHDOG_H */
diff --git a/arch/arm/plat-samsung/include/plat/s3c64xx-spi.h b/arch/arm/plat-samsung/include/plat/s3c64xx-spi.h
index fa95e9a..884587d 100644
--- a/arch/arm/plat-samsung/include/plat/s3c64xx-spi.h
+++ b/arch/arm/plat-samsung/include/plat/s3c64xx-spi.h
@@ -49,6 +49,7 @@
int num_cs;
int (*cfg_gpio)(struct platform_device *pdev);
+ void (*gpio_pull_up)(bool pull_up);
/* Following two fields are for future compatibility */
int fifo_lvl_mask;
@@ -74,6 +75,10 @@
extern void s3c64xx_spi2_set_platdata(struct s3c64xx_spi_info *pd,
int src_clk_nr, int num_cs);
+/* defined to setup chip select GPIO and clock of SPI */
+extern int exynos_spi_cfg_cs(int gpio, int ch_num);
+extern void exynos_spi_clock_setup(struct device *spi_dev, int ch_num);
+
/* defined by architecture to configure gpio */
extern int s3c64xx_spi0_cfg_gpio(struct platform_device *dev);
extern int s3c64xx_spi1_cfg_gpio(struct platform_device *dev);
diff --git a/arch/arm/plat-samsung/include/plat/s5p-clock.h b/arch/arm/plat-samsung/include/plat/s5p-clock.h
index 1de4b32..142dd80 100644
--- a/arch/arm/plat-samsung/include/plat/s5p-clock.h
+++ b/arch/arm/plat-samsung/include/plat/s5p-clock.h
@@ -20,6 +20,7 @@
#define clk_fin_apll clk_ext_xtal_mux
#define clk_fin_bpll clk_ext_xtal_mux
#define clk_fin_cpll clk_ext_xtal_mux
+#define clk_fin_gpll clk_ext_xtal_mux
#define clk_fin_mpll clk_ext_xtal_mux
#define clk_fin_epll clk_ext_xtal_mux
#define clk_fin_dpll clk_ext_xtal_mux
diff --git a/arch/arm/plat-samsung/include/plat/sysmmu.h b/arch/arm/plat-samsung/include/plat/sysmmu.h
index 5fe8ee0..8bcdc0a 100644
--- a/arch/arm/plat-samsung/include/plat/sysmmu.h
+++ b/arch/arm/plat-samsung/include/plat/sysmmu.h
@@ -1,19 +1,22 @@
-/* linux/arch/arm/plat-samsung/include/plat/sysmmu.h
- *
- * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+/*
+ * Copyright (c) 2010-2012 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
- * Samsung System MMU driver for S5P platform
+ * Samsung System MMU driver for Exynos platforms
*
* 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.
*/
-#ifndef __PLAT_SAMSUNG_SYSMMU_H
-#define __PLAT_SAMSUNG_SYSMMU_H __FILE__
+#ifndef __ASM__PLAT_SYSMMU_H
+#define __ASM__PLAT_SYSMMU_H __FILE__
-enum S5P_SYSMMU_INTERRUPT_TYPE {
+#include <linux/list.h>
+#include <linux/atomic.h>
+#include <linux/spinlock.h>
+
+enum exynos_sysmmu_inttype {
SYSMMU_PAGEFAULT,
SYSMMU_AR_MULTIHIT,
SYSMMU_AW_MULTIHIT,
@@ -22,74 +25,86 @@
SYSMMU_AR_ACCESS,
SYSMMU_AW_SECURITY,
SYSMMU_AW_PROTECTION, /* 7 */
+ SYSMMU_FAULT_UNKNOWN,
SYSMMU_FAULTS_NUM
};
-#ifdef CONFIG_S5P_SYSTEM_MMU
+struct sysmmu_drvdata;
+/*
+ * @itype: type of fault.
+ * @pgtable_base: the physical address of page table base. This is 0 if @itype
+ * is SYSMMU_BUSERROR.
+ * @fault_addr: the device (virtual) address that the System MMU tried to
+ * translated. This is 0 if @itype is SYSMMU_BUSERROR.
+ */
+typedef int (*sysmmu_fault_handler_t)(struct device *dev,
+ enum exynos_sysmmu_inttype itype,
+ unsigned long pgtable_base,
+ unsigned long fault_addr);
-#include <mach/sysmmu.h>
-
+#ifdef CONFIG_EXYNOS_IOMMU
/**
- * s5p_sysmmu_enable() - enable system mmu of ip
- * @ips: The ip connected system mmu.
- * #pgd: Base physical address of the 1st level page table
+ * exynos_sysmmu_enable() - enable system mmu
+ * @owner: The device whose System MMU is about to be enabled.
+ * @pgd: Base physical address of the 1st level page table
*
* This function enable system mmu to transfer address
- * from virtual address to physical address
+ * from virtual address to physical address.
+ * Return non-zero if it fails to enable System MMU.
*/
-void s5p_sysmmu_enable(sysmmu_ips ips, unsigned long pgd);
+int exynos_sysmmu_enable(struct device *owner, unsigned long pgd);
/**
- * s5p_sysmmu_disable() - disable sysmmu mmu of ip
- * @ips: The ip connected system mmu.
+ * exynos_sysmmu_disable() - disable sysmmu mmu of ip
+ * @owner: The device whose System MMU is about to be disabled.
*
* This function disable system mmu to transfer address
* from virtual address to physical address
*/
-void s5p_sysmmu_disable(sysmmu_ips ips);
+bool exynos_sysmmu_disable(struct device *owner);
/**
- * s5p_sysmmu_set_tablebase_pgd() - set page table base address to refer page table
- * @ips: The ip connected system mmu.
- * @pgd: The page table base address.
- *
- * This function set page table base address
- * When system mmu transfer address from virtaul address to physical address,
- * system mmu refer address information from page table
- */
-void s5p_sysmmu_set_tablebase_pgd(sysmmu_ips ips, unsigned long pgd);
-
-/**
- * s5p_sysmmu_tlb_invalidate() - flush all TLB entry in system mmu
- * @ips: The ip connected system mmu.
+ * exynos_sysmmu_tlb_invalidate() - flush all TLB entry in system mmu
+ * @owner: The device whose System MMU.
*
* This function flush all TLB entry in system mmu
*/
-void s5p_sysmmu_tlb_invalidate(sysmmu_ips ips);
+void exynos_sysmmu_tlb_invalidate(struct device *owner);
-/** s5p_sysmmu_set_fault_handler() - Fault handler for System MMUs
- * @itype: type of fault.
- * @pgtable_base: the physical address of page table base. This is 0 if @ips is
- * SYSMMU_BUSERROR.
- * @fault_addr: the device (virtual) address that the System MMU tried to
- * translated. This is 0 if @ips is SYSMMU_BUSERROR.
+/** exynos_sysmmu_set_fault_handler() - Fault handler for System MMUs
* Called when interrupt occurred by the System MMUs
* The device drivers of peripheral devices that has a System MMU can implement
* a fault handler to resolve address translation fault by System MMU.
* The meanings of return value and parameters are described below.
-
+ *
* return value: non-zero if the fault is correctly resolved.
* zero if the fault is not handled.
*/
-void s5p_sysmmu_set_fault_handler(sysmmu_ips ips,
- int (*handler)(enum S5P_SYSMMU_INTERRUPT_TYPE itype,
- unsigned long pgtable_base,
- unsigned long fault_addr));
-#else
-#define s5p_sysmmu_enable(ips, pgd) do { } while (0)
-#define s5p_sysmmu_disable(ips) do { } while (0)
-#define s5p_sysmmu_set_tablebase_pgd(ips, pgd) do { } while (0)
-#define s5p_sysmmu_tlb_invalidate(ips) do { } while (0)
-#define s5p_sysmmu_set_fault_handler(ips, handler) do { } while (0)
+void exynos_sysmmu_set_fault_handler(struct device *sysmmu,
+ sysmmu_fault_handler_t handler);
+
+/** exynos_sysmmu_set_prefbuf() - Initialize prefetch buffers of System MMU v3
+ * @owner: The device which need to set the prefetch buffers
+ * @base0: The start virtual address of the area of the @owner device that the
+ * first prefetch buffer loads translation descriptors
+ * @size0: The last virtual address of the area of the @owner device that the
+ * first prefetch buffer loads translation descriptors.
+ * @base1: The start virtual address of the area of the @owner device that the
+ * second prefetch buffer loads translation descriptors. This will be
+ * ignored if @size1 is 0 and this function assigns the 2 prefetch
+ * buffers with each half of the area specified by @base0 and @size0
+ * @size1: The last virtual address of the area of the @owner device that the
+ * prefetch buffer loads translation descriptors. This can be 0. See
+ * the description of @base1 for more information with @size1 = 0
+ */
+void exynos_sysmmu_set_prefbuf(struct device *owner,
+ unsigned long base0, unsigned long size0,
+ unsigned long base1, unsigned long size1);
+#else /* CONFIG_EXYNOS_IOMMU */
+#define exynos_sysmmu_enable(owner, pgd) do { } while (0)
+#define exynos_sysmmu_disable(owner) do { } while (0)
+#define exynos_sysmmu_tlb_invalidate(owner) do { } while (0)
+#define exynos_sysmmu_set_fault_handler(sysmmu, handler) do { } while (0)
+#define exynos_sysmmu_set_prefbuf(owner, b0, s0, b1, s1) do { } while (0)
#endif
#endif /* __ASM_PLAT_SYSMMU_H */
diff --git a/arch/arm/plat-samsung/include/plat/tv-core.h b/arch/arm/plat-samsung/include/plat/tv-core.h
index 3bc34f3c..45c1c83 100644
--- a/arch/arm/plat-samsung/include/plat/tv-core.h
+++ b/arch/arm/plat-samsung/include/plat/tv-core.h
@@ -41,4 +41,28 @@
#endif
}
+struct s5p_platform_cec {
+#ifdef CONFIG_S5P_DEV_TV
+ void (*cfg_gpio)(struct platform_device *pdev);
+#endif
+};
+
+struct s5p_hdmi_platdata {
+ void (*hdmiphy_enable)(struct platform_device *pdev, int en);
+};
+
+extern void s5p_hdmi_set_platdata(struct s5p_hdmi_platdata *pd);
+#ifdef CONFIG_S5P_DEV_TV
+extern void __init s5p_hdmi_cec_set_platdata(struct s5p_platform_cec *pd);
+extern void s5p_cec_cfg_gpio(struct platform_device *pdev);
+extern void s5p_int_src_hdmi_hpd(struct platform_device *pdev);
+extern void s5p_int_src_ext_hpd(struct platform_device *pdev);
+extern int s5p_hpd_read_gpio(struct platform_device *pdev);
+extern int s5p_v4l2_hpd_read_gpio(void);
+extern void s5p_v4l2_int_src_hdmi_hpd(void);
+extern void s5p_v4l2_int_src_ext_hpd(void);
+extern void s5p_cec_cfg_gpio(struct platform_device *pdev);
+extern void s5p_hdmiphy_enable(struct platform_device *pdev, int en);
+#endif
+
#endif /* __SAMSUNG_PLAT_TV_H */
diff --git a/arch/arm/plat-samsung/include/plat/udc-hs.h b/arch/arm/plat-samsung/include/plat/udc-hs.h
index c9e3667..a090fb4 100644
--- a/arch/arm/plat-samsung/include/plat/udc-hs.h
+++ b/arch/arm/plat-samsung/include/plat/udc-hs.h
@@ -29,6 +29,13 @@
int (*phy_init)(struct platform_device *pdev, int type);
int (*phy_exit)(struct platform_device *pdev, int type);
+
+ /* Value of USB PHY tune register */
+ unsigned int phy_tune;
+ /* Mask of USB PHY tune register */
+ unsigned int phy_tune_mask;
+ /* Default setting value of USB PHY tune */
+ unsigned int def_phytune;
};
extern void s3c_hsotg_set_platdata(struct s3c_hsotg_plat *pd);
diff --git a/arch/arm/plat-samsung/include/plat/usb-phy.h b/arch/arm/plat-samsung/include/plat/usb-phy.h
index 959bcdb..f784101 100644
--- a/arch/arm/plat-samsung/include/plat/usb-phy.h
+++ b/arch/arm/plat-samsung/include/plat/usb-phy.h
@@ -14,6 +14,7 @@
enum s5p_usb_phy_type {
S5P_USB_PHY_DEVICE,
S5P_USB_PHY_HOST,
+ S5P_USB_PHY_DRD,
};
extern int s5p_usb_phy_init(struct platform_device *pdev, int type);
diff --git a/arch/arm/plat-samsung/pd.c b/arch/arm/plat-samsung/pd.c
deleted file mode 100644
index 312b510..0000000
--- a/arch/arm/plat-samsung/pd.c
+++ /dev/null
@@ -1,95 +0,0 @@
-/* linux/arch/arm/plat-samsung/pd.c
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- * http://www.samsung.com
- *
- * Samsung Power domain support
- *
- * 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.
-*/
-
-#include <linux/init.h>
-#include <linux/export.h>
-#include <linux/platform_device.h>
-#include <linux/err.h>
-#include <linux/pm_runtime.h>
-
-#include <plat/pd.h>
-
-static int samsung_pd_probe(struct platform_device *pdev)
-{
- struct samsung_pd_info *pdata = pdev->dev.platform_data;
- struct device *dev = &pdev->dev;
-
- if (!pdata) {
- dev_err(dev, "no device data specified\n");
- return -ENOENT;
- }
-
- pm_runtime_set_active(dev);
- pm_runtime_enable(dev);
-
- dev_info(dev, "power domain registered\n");
- return 0;
-}
-
-static int __devexit samsung_pd_remove(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
-
- pm_runtime_disable(dev);
- return 0;
-}
-
-static int samsung_pd_runtime_suspend(struct device *dev)
-{
- struct samsung_pd_info *pdata = dev->platform_data;
- int ret = 0;
-
- if (pdata->disable)
- ret = pdata->disable(dev);
-
- dev_dbg(dev, "suspended\n");
- return ret;
-}
-
-static int samsung_pd_runtime_resume(struct device *dev)
-{
- struct samsung_pd_info *pdata = dev->platform_data;
- int ret = 0;
-
- if (pdata->enable)
- ret = pdata->enable(dev);
-
- dev_dbg(dev, "resumed\n");
- return ret;
-}
-
-static const struct dev_pm_ops samsung_pd_pm_ops = {
- .runtime_suspend = samsung_pd_runtime_suspend,
- .runtime_resume = samsung_pd_runtime_resume,
-};
-
-static struct platform_driver samsung_pd_driver = {
- .driver = {
- .name = "samsung-pd",
- .owner = THIS_MODULE,
- .pm = &samsung_pd_pm_ops,
- },
- .probe = samsung_pd_probe,
- .remove = __devexit_p(samsung_pd_remove),
-};
-
-static int __init samsung_pd_init(void)
-{
- int ret;
-
- ret = platform_driver_register(&samsung_pd_driver);
- if (ret)
- printk(KERN_ERR "%s: failed to add PD driver\n", __func__);
-
- return ret;
-}
-arch_initcall(samsung_pd_init);
diff --git a/arch/arm/plat-samsung/pm-gpio.c b/arch/arm/plat-samsung/pm-gpio.c
index c2ff92c..85b0777 100644
--- a/arch/arm/plat-samsung/pm-gpio.c
+++ b/arch/arm/plat-samsung/pm-gpio.c
@@ -27,6 +27,9 @@
#define OFFS_CON (0x00)
#define OFFS_DAT (0x04)
#define OFFS_UP (0x08)
+#define OFFS_DRV_SR (0x0C)
+#define OFFS_CONPDN (0x10)
+#define OFFS_PUDPDN (0x14)
static void samsung_gpio_pm_1bit_save(struct samsung_gpio_chip *chip)
{
@@ -198,6 +201,9 @@
chip->pm_save[1] = __raw_readl(chip->base + OFFS_CON);
chip->pm_save[2] = __raw_readl(chip->base + OFFS_DAT);
chip->pm_save[3] = __raw_readl(chip->base + OFFS_UP);
+ chip->pm_save[4] = __raw_readl(chip->base + OFFS_DRV_SR);
+ chip->pm_save[5] = __raw_readl(chip->base + OFFS_CONPDN);
+ chip->pm_save[6] = __raw_readl(chip->base + OFFS_PUDPDN);
if (chip->chip.ngpio > 8)
chip->pm_save[0] = __raw_readl(chip->base - 4);
@@ -296,6 +302,10 @@
chip->chip.label, old_gpcon[1],
__raw_readl(base + OFFS_CON),
old_gpdat, gps_gpdat);
+
+ __raw_writel(chip->pm_save[4], base + OFFS_DRV_SR);
+ __raw_writel(chip->pm_save[5], base + OFFS_CONPDN);
+ __raw_writel(chip->pm_save[6], base + OFFS_PUDPDN);
}
struct samsung_gpio_pm samsung_gpio_pm_4bit = {
diff --git a/arch/arm/plat-samsung/pwm-clock.c b/arch/arm/plat-samsung/pwm-clock.c
index a35ff3b..24a0756 100644
--- a/arch/arm/plat-samsung/pwm-clock.c
+++ b/arch/arm/plat-samsung/pwm-clock.c
@@ -18,6 +18,7 @@
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/io.h>
+#include <linux/spinlock.h>
#include <mach/hardware.h>
#include <mach/map.h>
@@ -74,6 +75,7 @@
*/
static struct clk clk_timer_scaler[];
+static spinlock_t pwm_clock_spinlock;
static unsigned long clk_pwm_scaler_get_rate(struct clk *clk)
{
@@ -113,7 +115,7 @@
divisor = clk_get_rate(clk->parent) / round;
divisor--;
- local_irq_save(flags);
+ spin_lock_irqsave(&pwm_clock_spinlock, flags);
tcfg0 = __raw_readl(S3C2410_TCFG0);
if (clk == &clk_timer_scaler[1]) {
@@ -125,7 +127,7 @@
}
__raw_writel(tcfg0, S3C2410_TCFG0);
- local_irq_restore(flags);
+ spin_unlock_irqrestore(&pwm_clock_spinlock, flags);
return 0;
}
@@ -214,21 +216,24 @@
return pwm_tdiv_div_bits(divclk->divisor);
}
-static void clk_pwm_tdiv_update(struct pwm_tdiv_clk *divclk)
+static void clk_pwm_tdiv_update(struct pwm_tdiv_clk *divclk, unsigned long div)
{
- unsigned long tcfg1 = __raw_readl(S3C2410_TCFG1);
- unsigned long bits = clk_pwm_tdiv_bits(divclk);
+ unsigned long tcfg1;
+ unsigned long bits;
unsigned long flags;
unsigned long shift = S3C2410_TCFG1_SHIFT(divclk->clk.id);
- local_irq_save(flags);
+ spin_lock_irqsave(&pwm_clock_spinlock, flags);
+
+ divclk->divisor = div;
+ bits = clk_pwm_tdiv_bits(divclk);
tcfg1 = __raw_readl(S3C2410_TCFG1);
tcfg1 &= ~(S3C2410_TCFG1_MUX_MASK << shift);
tcfg1 |= bits << shift;
__raw_writel(tcfg1, S3C2410_TCFG1);
- local_irq_restore(flags);
+ spin_unlock_irqrestore(&pwm_clock_spinlock, flags);
}
static int clk_pwm_tdiv_set_rate(struct clk *clk, unsigned long rate)
@@ -247,13 +252,11 @@
if (divisor > 16)
return -EINVAL;
- divclk->divisor = divisor;
-
/* Update the current MUX settings if we are currently
* selected as the clock source for this clock. */
if (!pwm_cfg_src_is_tclk(tcfg1))
- clk_pwm_tdiv_update(divclk);
+ clk_pwm_tdiv_update(divclk, divisor);
return 0;
}
@@ -355,15 +358,15 @@
else
return -EINVAL;
- clk->parent = parent;
+ spin_lock_irqsave(&pwm_clock_spinlock, flags);
- local_irq_save(flags);
+ clk->parent = parent;
tcfg1 = __raw_readl(S3C2410_TCFG1);
tcfg1 &= ~(S3C2410_TCFG1_MUX_MASK << shift);
__raw_writel(tcfg1 | bits, S3C2410_TCFG1);
- local_irq_restore(flags);
+ spin_unlock_irqrestore(&pwm_clock_spinlock, flags);
return 0;
}
@@ -443,6 +446,8 @@
unsigned int clk;
int ret;
+ spin_lock_init(&pwm_clock_spinlock);
+
clk_timers = clk_get(NULL, "timers");
if (IS_ERR(clk_timers)) {
printk(KERN_ERR "%s: no parent clock\n", __func__);
diff --git a/arch/arm/plat-samsung/pwm.c b/arch/arm/plat-samsung/pwm.c
index c559d84..c60c13e 100644
--- a/arch/arm/plat-samsung/pwm.c
+++ b/arch/arm/plat-samsung/pwm.c
@@ -19,10 +19,19 @@
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/pwm.h>
+#include <linux/spinlock.h>
#include <mach/map.h>
+#include <plat/cpu.h>
#include <plat/regs-timer.h>
+#include <plat/pwm.h>
+
+enum duty_cycle {
+ DUTY_CYCLE_ZERO,
+ DUTY_CYCLE_PULSE,
+ DUTY_CYCLE_FULL,
+};
struct pwm_device {
struct list_head list;
@@ -39,6 +48,9 @@
unsigned char running;
unsigned char use_count;
unsigned char pwm_id;
+ enum duty_cycle duty_cycle;
+
+ unsigned int tcfg0;
};
#define pwm_dbg(_pwm, msg...) dev_dbg(&(_pwm)->pdev->dev, msg)
@@ -52,6 +64,7 @@
static DEFINE_MUTEX(pwm_lock);
static LIST_HEAD(pwm_list);
+static spinlock_t pwm_spinlock;
struct pwm_device *pwm_request(int pwm_id, const char *label)
{
@@ -108,15 +121,39 @@
unsigned long flags;
unsigned long tcon;
- local_irq_save(flags);
+ spin_lock_irqsave(&pwm_spinlock, flags);
- tcon = __raw_readl(S3C2410_TCON);
- tcon |= pwm_tcon_start(pwm);
- __raw_writel(tcon, S3C2410_TCON);
+ if (soc_is_s3c24xx()) {
+ tcon = __raw_readl(S3C2410_TCON);
+ tcon |= pwm_tcon_start(pwm);
+ __raw_writel(tcon, S3C2410_TCON);
+ } else {
+ tcon = __raw_readl(S3C2410_TCON);
+ if (!(tcon & pwm_tcon_start(pwm))) {
+ tcon |= pwm_tcon_manulupdate(pwm);
+ __raw_writel(tcon, S3C2410_TCON);
- local_irq_restore(flags);
+ tcon &= ~pwm_tcon_manulupdate(pwm);
+ if (pwm->duty_cycle == DUTY_CYCLE_ZERO)
+ tcon &= ~pwm_tcon_autoreload(pwm);
+ else
+ tcon |= pwm_tcon_autoreload(pwm);
+ tcon |= pwm_tcon_start(pwm);
+ __raw_writel(tcon, S3C2410_TCON);
+ } else if (!(tcon & pwm_tcon_autoreload(pwm)) &&
+ pwm->duty_cycle != DUTY_CYCLE_ZERO) {
+ tcon |= pwm_tcon_manulupdate(pwm);
+ __raw_writel(tcon, S3C2410_TCON);
+
+ tcon &= ~pwm_tcon_manulupdate(pwm);
+ tcon |= pwm_tcon_autoreload(pwm);
+ __raw_writel(tcon, S3C2410_TCON);
+ }
+ }
pwm->running = 1;
+
+ spin_unlock_irqrestore(&pwm_spinlock, flags);
return 0;
}
@@ -127,15 +164,21 @@
unsigned long flags;
unsigned long tcon;
- local_irq_save(flags);
+ spin_lock_irqsave(&pwm_spinlock, flags);
- tcon = __raw_readl(S3C2410_TCON);
- tcon &= ~pwm_tcon_start(pwm);
- __raw_writel(tcon, S3C2410_TCON);
-
- local_irq_restore(flags);
+ if (soc_is_s3c24xx()) {
+ tcon = __raw_readl(S3C2410_TCON);
+ tcon &= ~pwm_tcon_start(pwm);
+ __raw_writel(tcon, S3C2410_TCON);
+ } else {
+ tcon = __raw_readl(S3C2410_TCON);
+ tcon &= ~pwm_tcon_autoreload(pwm);
+ __raw_writel(tcon, S3C2410_TCON);
+ }
pwm->running = 0;
+
+ spin_unlock_irqrestore(&pwm_spinlock, flags);
}
EXPORT_SYMBOL(pwm_disable);
@@ -167,6 +210,7 @@
unsigned long tcon;
unsigned long tcnt;
long tcmp;
+ enum duty_cycle duty_cycle;
/* We currently avoid using 64bit arithmetic by using the
* fact that anything faster than 1Hz is easily representable
@@ -182,65 +226,99 @@
duty_ns == pwm->duty_ns)
return 0;
- /* The TCMP and TCNT can be read without a lock, they're not
- * shared between the timers. */
-
- tcmp = __raw_readl(S3C2410_TCMPB(pwm->pwm_id));
- tcnt = __raw_readl(S3C2410_TCNTB(pwm->pwm_id));
-
period = NS_IN_HZ / period_ns;
+ /* Check to see if we are changing the clock rate of the PWM */
+
+ if (pwm->period_ns != period_ns && pwm_is_tdiv(pwm)) {
+ tin_rate = pwm_calc_tin(pwm, period);
+ clk_set_rate(pwm->clk_div, tin_rate);
+
+ pwm_dbg(pwm, "tin_rate=%lu\n", tin_rate);
+ } else {
+ tin_rate = clk_get_rate(pwm->clk);
+ }
+
+ /* Note, counters count down */
+
+ tin_ns = NS_IN_HZ / tin_rate;
+
+ tcnt = DIV_ROUND_CLOSEST(period_ns, tin_ns);
+ tcmp = DIV_ROUND_CLOSEST(duty_ns, tin_ns);
+
+ if (tcnt <= 1) {
+ /* Too small to generate a pulse */
+ return -ERANGE;
+ }
+
pwm_dbg(pwm, "duty_ns=%d, period_ns=%d (%lu)\n",
duty_ns, period_ns, period);
- /* Check to see if we are changing the clock rate of the PWM */
+ if (tcmp == 0)
+ duty_cycle = DUTY_CYCLE_ZERO;
+ else if (tcmp == tcnt)
+ duty_cycle = DUTY_CYCLE_FULL;
+ else
+ duty_cycle = DUTY_CYCLE_PULSE;
- if (pwm->period_ns != period_ns) {
- if (pwm_is_tdiv(pwm)) {
- tin_rate = pwm_calc_tin(pwm, period);
- clk_set_rate(pwm->clk_div, tin_rate);
- } else
- tin_rate = clk_get_rate(pwm->clk);
-
- pwm->period_ns = period_ns;
-
- pwm_dbg(pwm, "tin_rate=%lu\n", tin_rate);
-
- tin_ns = NS_IN_HZ / tin_rate;
- tcnt = period_ns / tin_ns;
- } else
- tin_ns = NS_IN_HZ / clk_get_rate(pwm->clk);
-
- /* Note, counters count down */
-
- tcmp = duty_ns / tin_ns;
tcmp = tcnt - tcmp;
/* the pwm hw only checks the compare register after a decrement,
so the pin never toggles if tcmp = tcnt */
if (tcmp == tcnt)
tcmp--;
- pwm_dbg(pwm, "tin_ns=%lu, tcmp=%ld/%lu\n", tin_ns, tcmp, tcnt);
+ /*
+ * PWM counts 1 hidden tick at the end of each period on S3C64XX and
+ * EXYNOS series, so tcmp and tcnt should be subtracted 1.
+ */
+ if (!soc_is_s3c24xx()) {
+ tcnt--;
+ /*
+ * tcmp can be -1. It appears 100% duty cycle and PWM never
+ * toggles when TCMPB is set to 0xFFFFFFFF (-1).
+ */
+ tcmp--;
+ }
- if (tcmp < 0)
- tcmp = 0;
+ pwm_dbg(pwm, "tin_ns=%lu, tcmp=%ld/%lu\n", tin_ns, tcmp, tcnt);
/* Update the PWM register block. */
- local_irq_save(flags);
+ spin_lock_irqsave(&pwm_spinlock, flags);
__raw_writel(tcmp, S3C2410_TCMPB(pwm->pwm_id));
__raw_writel(tcnt, S3C2410_TCNTB(pwm->pwm_id));
- tcon = __raw_readl(S3C2410_TCON);
- tcon |= pwm_tcon_manulupdate(pwm);
- tcon |= pwm_tcon_autoreload(pwm);
- __raw_writel(tcon, S3C2410_TCON);
+ if (soc_is_s3c24xx()) {
+ tcon = __raw_readl(S3C2410_TCON);
+ tcon |= pwm_tcon_manulupdate(pwm);
+ tcon |= pwm_tcon_autoreload(pwm);
+ __raw_writel(tcon, S3C2410_TCON);
- tcon &= ~pwm_tcon_manulupdate(pwm);
- __raw_writel(tcon, S3C2410_TCON);
+ tcon &= ~pwm_tcon_manulupdate(pwm);
+ __raw_writel(tcon, S3C2410_TCON);
+ } else {
+ tcon = __raw_readl(S3C2410_TCON);
+ if (pwm->running == 1 &&
+ tcon & pwm_tcon_start(pwm) &&
+ pwm->duty_cycle != duty_cycle) {
+ if (duty_cycle == DUTY_CYCLE_ZERO) {
+ tcon |= pwm_tcon_manulupdate(pwm);
+ __raw_writel(tcon, S3C2410_TCON);
- local_irq_restore(flags);
+ tcon &= ~pwm_tcon_manulupdate(pwm);
+ tcon &= ~pwm_tcon_autoreload(pwm);
+ } else {
+ tcon |= pwm_tcon_autoreload(pwm);
+ }
+ __raw_writel(tcon, S3C2410_TCON);
+ }
+ }
+ pwm->duty_ns = duty_ns;
+ pwm->period_ns = period_ns;
+ pwm->duty_cycle = duty_cycle;
+
+ spin_unlock_irqrestore(&pwm_spinlock, flags);
return 0;
}
@@ -259,13 +337,39 @@
return 0;
}
+static void s3c_pwm_init(struct pwm_device *pwm)
+{
+ unsigned long tcon;
+
+ if (soc_is_s3c24xx()) {
+ tcon = __raw_readl(S3C2410_TCON);
+ tcon |= pwm_tcon_invert(pwm);
+ __raw_writel(tcon, S3C2410_TCON);
+ } else {
+ __raw_writel(0, S3C2410_TCMPB(pwm->pwm_id));
+ __raw_writel(0, S3C2410_TCNTB(pwm->pwm_id));
+
+ tcon = __raw_readl(S3C2410_TCON);
+ tcon |= pwm_tcon_invert(pwm);
+ tcon |= pwm_tcon_manulupdate(pwm);
+ tcon &= ~pwm_tcon_autoreload(pwm);
+ tcon &= ~pwm_tcon_start(pwm);
+ __raw_writel(tcon, S3C2410_TCON);
+
+ tcon &= ~pwm_tcon_manulupdate(pwm);
+ __raw_writel(tcon, S3C2410_TCON);
+ }
+}
+
static int s3c_pwm_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct pwm_device *pwm;
+ struct samsung_pwm_platdata *pdata = pdev->dev.platform_data;
unsigned long flags;
- unsigned long tcon;
unsigned int id = pdev->id;
+ unsigned int prescaler0;
+ unsigned int prescaler1;
int ret;
if (id == 4) {
@@ -273,6 +377,24 @@
return -ENXIO;
}
+ if (pdata) {
+ prescaler0 = pdata->prescaler0;
+ prescaler1 = pdata->prescaler1;
+
+ if ((prescaler0 < 1) || (prescaler0 > 255)) {
+ dev_err(dev, "wrong prescaler0 value\n");
+ return -EINVAL;
+ }
+
+ if ((prescaler1 < 1) || (prescaler1 > 255)) {
+ dev_err(dev, "wrong prescaler1 value\n");
+ return -EINVAL;
+ }
+ } else {
+ prescaler0 = 1;
+ prescaler1 = 1;
+ }
+
pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL);
if (pwm == NULL) {
dev_err(dev, "failed to allocate pwm_device\n");
@@ -282,6 +404,11 @@
pwm->pdev = pdev;
pwm->pwm_id = id;
+ /* setup prescaler */
+ pwm->tcfg0 = (prescaler1 << S3C2410_TCFG_PRESCALER1_SHIFT) | prescaler0;
+
+ __raw_writel(pwm->tcfg0, S3C2410_TCFG0);
+
/* calculate base of control bits in TCON */
pwm->tcon_base = id == 0 ? 0 : (id * 4) + 4;
@@ -302,14 +429,11 @@
clk_enable(pwm->clk);
clk_enable(pwm->clk_div);
- local_irq_save(flags);
+ spin_lock_irqsave(&pwm_spinlock, flags);
- tcon = __raw_readl(S3C2410_TCON);
- tcon |= pwm_tcon_invert(pwm);
- __raw_writel(tcon, S3C2410_TCON);
+ s3c_pwm_init(pwm);
- local_irq_restore(flags);
-
+ spin_unlock_irqrestore(&pwm_spinlock, flags);
ret = pwm_register(pwm);
if (ret) {
@@ -358,13 +482,28 @@
static int s3c_pwm_suspend(struct platform_device *pdev, pm_message_t state)
{
struct pwm_device *pwm = platform_get_drvdata(pdev);
+ unsigned long tcon;
+
+ if (!soc_is_s3c24xx()) {
+ if (pwm->running == 0) {
+ tcon = __raw_readl(S3C2410_TCON);
+ if (pwm->duty_cycle == DUTY_CYCLE_ZERO) {
+ tcon |= pwm_tcon_manulupdate(pwm);
+ } else if (pwm->duty_cycle == DUTY_CYCLE_FULL) {
+ tcon &= pwm_tcon_invert(pwm);
+ tcon |= pwm_tcon_manulupdate(pwm);
+ }
+ tcon &= ~pwm_tcon_start(pwm);
+ __raw_writel(tcon, S3C2410_TCON);
+ }
+ }
/* No one preserve these values during suspend so reset them
* Otherwise driver leaves PWM unconfigured if same values
* passed to pwm_config
*/
- pwm->period_ns = 0;
- pwm->duty_ns = 0;
+ pwm->duty_ns = -1;
+ pwm->period_ns = -1;
return 0;
}
@@ -372,12 +511,11 @@
static int s3c_pwm_resume(struct platform_device *pdev)
{
struct pwm_device *pwm = platform_get_drvdata(pdev);
- unsigned long tcon;
- /* Restore invertion */
- tcon = __raw_readl(S3C2410_TCON);
- tcon |= pwm_tcon_invert(pwm);
- __raw_writel(tcon, S3C2410_TCON);
+ /* Restore prescaler */
+ __raw_writel(pwm->tcfg0, S3C2410_TCFG0);
+
+ s3c_pwm_init(pwm);
return 0;
}
@@ -402,6 +540,8 @@
{
int ret;
+ spin_lock_init(&pwm_spinlock);
+
clk_scaler[0] = clk_get(NULL, "pwm-scaler0");
clk_scaler[1] = clk_get(NULL, "pwm-scaler1");
diff --git a/arch/arm/plat-samsung/s3c-dma-ops.c b/arch/arm/plat-samsung/s3c-dma-ops.c
index 7814949..167dc49 100644
--- a/arch/arm/plat-samsung/s3c-dma-ops.c
+++ b/arch/arm/plat-samsung/s3c-dma-ops.c
@@ -36,30 +36,26 @@
}
static unsigned s3c_dma_request(enum dma_ch dma_ch,
- struct samsung_dma_info *info)
+ struct samsung_dma_req *param)
{
struct cb_data *data;
- if (s3c2410_dma_request(dma_ch, info->client, NULL) < 0) {
- s3c2410_dma_free(dma_ch, info->client);
+ if (s3c2410_dma_request(dma_ch, param->client, NULL) < 0) {
+ s3c2410_dma_free(dma_ch, param->client);
return 0;
}
+ if (param->cap == DMA_CYCLIC)
+ s3c2410_dma_setflags(dma_ch, S3C2410_DMAF_CIRCULAR);
+
data = kzalloc(sizeof(struct cb_data), GFP_KERNEL);
data->ch = dma_ch;
list_add_tail(&data->node, &dma_list);
- s3c2410_dma_devconfig(dma_ch, info->direction, info->fifo);
-
- if (info->cap == DMA_CYCLIC)
- s3c2410_dma_setflags(dma_ch, S3C2410_DMAF_CIRCULAR);
-
- s3c2410_dma_config(dma_ch, info->width);
-
return (unsigned)dma_ch;
}
-static int s3c_dma_release(unsigned ch, struct s3c2410_dma_client *client)
+static int s3c_dma_release(unsigned ch, void *param)
{
struct cb_data *data;
@@ -68,16 +64,24 @@
break;
list_del(&data->node);
- s3c2410_dma_free(ch, client);
+ s3c2410_dma_free(ch, param);
kfree(data);
return 0;
}
-static int s3c_dma_prepare(unsigned ch, struct samsung_dma_prep_info *info)
+static int s3c_dma_config(unsigned ch, struct samsung_dma_config *param)
+{
+ s3c2410_dma_devconfig(ch, param->direction, param->fifo);
+ s3c2410_dma_config(ch, param->width);
+
+ return 0;
+}
+
+static int s3c_dma_prepare(unsigned ch, struct samsung_dma_prep *param)
{
struct cb_data *data;
- int len = (info->cap == DMA_CYCLIC) ? info->period : info->len;
+ int len = (param->cap == DMA_CYCLIC) ? param->period : param->len;
list_for_each_entry(data, &dma_list, node)
if (data->ch == ch)
@@ -85,11 +89,11 @@
if (!data->fp) {
s3c2410_dma_set_buffdone_fn(ch, s3c_dma_cb);
- data->fp = info->fp;
- data->fp_param = info->fp_param;
+ data->fp = param->fp;
+ data->fp_param = param->fp_param;
}
- s3c2410_dma_enqueue(ch, (void *)data, info->buf, len);
+ s3c2410_dma_enqueue(ch, (void *)data, param->buf, len);
return 0;
}
@@ -104,6 +108,12 @@
return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_STARTED);
}
+static inline int s3c_dma_getposition(unsigned ch,
+dma_addr_t *src, dma_addr_t *dst)
+{
+ return s3c2410_dma_getposition(ch, src, dst);
+}
+
static inline int s3c_dma_flush(unsigned ch)
{
return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_FLUSH);
@@ -117,9 +127,11 @@
static struct samsung_dma_ops s3c_dma_ops = {
.request = s3c_dma_request,
.release = s3c_dma_release,
+ .config = s3c_dma_config,
.prepare = s3c_dma_prepare,
.trigger = s3c_dma_trigger,
.started = s3c_dma_started,
+ .getposition = s3c_dma_getposition,
.flush = s3c_dma_flush,
.stop = s3c_dma_stop,
};
diff --git a/drivers/Kconfig b/drivers/Kconfig
index a765f40..021a79c 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -142,4 +142,6 @@
source "drivers/devfreq/Kconfig"
+source "drivers/gud/Kconfig"
+
endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index b5d2823..0ddf519 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -135,3 +135,5 @@
obj-$(CONFIG_HYPERV) += hv/
obj-$(CONFIG_PM_DEVFREQ) += devfreq/
+
+obj-$(CONFIG_MOBICORE_DRIVER) += gud/
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
index 1131dd7..7c96a3a 100644
--- a/drivers/base/Kconfig
+++ b/drivers/base/Kconfig
@@ -218,4 +218,5 @@
Provides a user space API to the sw sync object.
*WARNING* improper use of this can result in deadlocking kernel
drivers from userspace.
+
endmenu
diff --git a/drivers/cpufreq/exynos-cpufreq.c b/drivers/cpufreq/exynos-cpufreq.c
index b243a7e..126aaa8 100644
--- a/drivers/cpufreq/exynos-cpufreq.c
+++ b/drivers/cpufreq/exynos-cpufreq.c
@@ -17,20 +17,39 @@
#include <linux/regulator/consumer.h>
#include <linux/cpufreq.h>
#include <linux/suspend.h>
+#include <linux/module.h>
+#include <linux/reboot.h>
+#include <linux/delay.h>
#include <mach/cpufreq.h>
#include <plat/cpu.h>
+#ifdef CONFIG_SMP
+struct lpj_info {
+ unsigned long ref;
+ unsigned int freq;
+};
+
+static struct lpj_info global_lpj_ref;
+#endif
+
+/* Use boot_freq when entering sleep mode */
+static unsigned int boot_freq;
+static unsigned int max_freq;
+static unsigned int max_thermal_freq;
+static unsigned int curr_target_freq;
+
static struct exynos_dvfs_info *exynos_info;
static struct regulator *arm_regulator;
static struct cpufreq_freqs freqs;
-static unsigned int locking_frequency;
-static bool frequency_locked;
static DEFINE_MUTEX(cpufreq_lock);
+static bool exynos_cpufreq_disable;
+static bool exynos_cpufreq_init_done;
+
int exynos_verify_speed(struct cpufreq_policy *policy)
{
return cpufreq_frequency_table_verify(policy,
@@ -42,68 +61,109 @@
return clk_get_rate(exynos_info->cpu_clk) / 1000;
}
-static int exynos_target(struct cpufreq_policy *policy,
- unsigned int target_freq,
- unsigned int relation)
+static unsigned int exynos_get_safe_armvolt(unsigned int old_index, unsigned int new_index)
{
- unsigned int index, old_index;
- unsigned int arm_volt, safe_arm_volt = 0;
- int ret = 0;
+ unsigned int safe_arm_volt = 0;
struct cpufreq_frequency_table *freq_table = exynos_info->freq_table;
unsigned int *volt_table = exynos_info->volt_table;
- unsigned int mpll_freq_khz = exynos_info->mpll_freq_khz;
- mutex_lock(&cpufreq_lock);
+ /*
+ * ARM clock source will be changed APLL to MPLL temporary
+ * To support this level, need to control regulator for
+ * reguired voltage level
+ */
- freqs.old = policy->cur;
+ if (exynos_info->need_apll_change != NULL) {
+ if (exynos_info->need_apll_change(old_index, new_index) &&
+ (freq_table[new_index].frequency < exynos_info->mpll_freq_khz) &&
+ (freq_table[old_index].frequency < exynos_info->mpll_freq_khz)) {
+ safe_arm_volt = volt_table[exynos_info->pll_safe_idx];
+ }
- if (frequency_locked && target_freq != locking_frequency) {
- ret = -EAGAIN;
+ }
+
+ return safe_arm_volt;
+}
+
+static int exynos_cpufreq_get_index(unsigned int freq)
+{
+ int i;
+
+ for (i = 0; i <= exynos_info->min_support_idx; i++)
+ if (exynos_info->freq_table[i].frequency <= freq)
+ return i;
+
+ return -EINVAL;
+}
+
+static int exynos_cpufreq_scale(unsigned int target_freq, unsigned int curr_freq)
+{
+ unsigned int *volt_table = exynos_info->volt_table;
+ int new_index, old_index;
+ unsigned int arm_volt, safe_arm_volt = 0;
+ unsigned int max_volt;
+ int ret = 0;
+
+ freqs.new = target_freq;
+
+ if (curr_freq == freqs.new)
+ goto out;
+
+ old_index = exynos_cpufreq_get_index(curr_freq);
+ if (old_index < 0) {
+ ret = old_index;
goto out;
}
- if (cpufreq_frequency_table_target(policy, freq_table,
- freqs.old, relation, &old_index)) {
- ret = -EINVAL;
+ new_index = exynos_cpufreq_get_index(freqs.new);
+ if (new_index < 0) {
+ ret = new_index;
goto out;
}
- if (cpufreq_frequency_table_target(policy, freq_table,
- target_freq, relation, &index)) {
- ret = -EINVAL;
- goto out;
- }
-
- freqs.new = freq_table[index].frequency;
- freqs.cpu = policy->cpu;
-
/*
* ARM clock source will be changed APLL to MPLL temporary
* To support this level, need to control regulator for
* required voltage level
*/
- if (exynos_info->need_apll_change != NULL) {
- if (exynos_info->need_apll_change(old_index, index) &&
- (freq_table[index].frequency < mpll_freq_khz) &&
- (freq_table[old_index].frequency < mpll_freq_khz))
- safe_arm_volt = volt_table[exynos_info->pll_safe_idx];
- }
- arm_volt = volt_table[index];
+ safe_arm_volt = exynos_get_safe_armvolt(old_index, new_index);
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ arm_volt = volt_table[new_index];
+ max_volt = volt_table[0];
/* When the new frequency is higher than current frequency */
if ((freqs.new > freqs.old) && !safe_arm_volt) {
/* Firstly, voltage up to increase frequency */
- regulator_set_voltage(arm_regulator, arm_volt,
- arm_volt);
+ ret = regulator_set_voltage(arm_regulator, arm_volt, max_volt);
+ if (ret) {
+ pr_err("%s: failed to set cpu voltage to %d\n",
+ __func__, arm_volt);
+ return ret;
+ }
}
- if (safe_arm_volt)
- regulator_set_voltage(arm_regulator, safe_arm_volt,
- safe_arm_volt);
- if (freqs.new != freqs.old)
- exynos_info->set_freq(old_index, index);
+ if (safe_arm_volt) {
+ ret = regulator_set_voltage(arm_regulator, safe_arm_volt,
+ max_volt);
+ if (ret) {
+ pr_err("%s: failed to set cpu voltage to %d\n",
+ __func__, safe_arm_volt);
+ return ret;
+ }
+ }
+
+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+ exynos_info->set_freq(old_index, new_index);
+
+#ifdef CONFIG_SMP
+ if (!global_lpj_ref.freq) {
+ global_lpj_ref.ref = loops_per_jiffy;
+ global_lpj_ref.freq = freqs.old;
+ }
+ loops_per_jiffy = cpufreq_scale(global_lpj_ref.ref, global_lpj_ref.freq,
+ freqs.new);
+#endif
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
@@ -111,16 +171,135 @@
if ((freqs.new < freqs.old) ||
((freqs.new > freqs.old) && safe_arm_volt)) {
/* down the voltage after frequency change */
- regulator_set_voltage(arm_regulator, arm_volt,
- arm_volt);
+ ret = regulator_set_voltage(arm_regulator, arm_volt, max_volt);
+ if (ret)
+ pr_err("%s: failed to set cpu voltage to %d\n",
+ __func__, arm_volt);
}
out:
+ return ret;
+}
+
+
+static int exynos_target(struct cpufreq_policy *policy,
+ unsigned int target_freq,
+ unsigned int relation)
+{
+ struct cpufreq_frequency_table *freq_table = exynos_info->freq_table;
+ unsigned int index;
+ unsigned int new_freq;
+ int ret = 0;
+
+ mutex_lock(&cpufreq_lock);
+
+ if (exynos_cpufreq_disable)
+ goto out;
+
+ freqs.old = policy->cur;
+
+ curr_target_freq = target_freq;
+
+ /*
+ * If the new frequency is more than the thermal max allowed
+ * frequency, use max_thermal_freq as a new frequency.
+ */
+ if (target_freq > max_thermal_freq)
+ target_freq = max_thermal_freq;
+
+ if (cpufreq_frequency_table_target(policy, freq_table,
+ target_freq, relation, &index)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ new_freq = freq_table[index].frequency;
+
+ exynos_cpufreq_scale(new_freq, freqs.old);
+
+out:
mutex_unlock(&cpufreq_lock);
return ret;
}
+static unsigned int exynos_thermal_lower_speed(void)
+{
+ unsigned int max = 0;
+ unsigned int curr;
+ int i;
+ struct cpufreq_frequency_table *freq_table = exynos_info->freq_table;
+
+ curr = max_thermal_freq;
+
+ for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
+ if (freq_table[i].frequency != CPUFREQ_ENTRY_INVALID &&
+ freq_table[i].frequency < curr) {
+ max = freq_table[i].frequency;
+ break;
+ }
+ }
+
+ if (!max)
+ return curr;
+
+ return max;
+}
+
+void exynos_thermal_throttle(void)
+{
+ unsigned int cur;
+
+ if (!exynos_cpufreq_init_done) {
+ pr_warn_once("%s: Thermal throttle prior to CPUFREQ ready\n",
+ __func__);
+ return;
+ }
+
+ mutex_lock(&cpufreq_lock);
+
+ max_thermal_freq = exynos_thermal_lower_speed();
+
+ pr_debug("%s: temperature too high, cpu throttle at max %u\n",
+ __func__, max_thermal_freq);
+
+ if (!exynos_cpufreq_disable) {
+ cur = exynos_getspeed(0);
+ if (cur > max_thermal_freq) {
+ freqs.old = cur;
+ exynos_cpufreq_scale(max_thermal_freq, freqs.old);
+ }
+ }
+
+ mutex_unlock(&cpufreq_lock);
+}
+
+void exynos_thermal_unthrottle(void)
+{
+
+ if (!exynos_cpufreq_init_done)
+ return;
+
+ mutex_lock(&cpufreq_lock);
+
+ if (max_thermal_freq == max_freq) {
+ pr_warn("%s: not throttling\n", __func__);
+ goto out;
+ }
+
+ max_thermal_freq = max_freq;
+
+ pr_debug("%s: temperature reduced, ending cpu throttling\n", __func__);
+
+ if (!exynos_cpufreq_disable) {
+ freqs.old = exynos_getspeed(0);
+ exynos_cpufreq_scale(curr_target_freq, freqs.old);
+ }
+
+out:
+ mutex_unlock(&cpufreq_lock);
+}
+
#ifdef CONFIG_PM
static int exynos_cpufreq_suspend(struct cpufreq_policy *policy)
{
@@ -140,8 +319,8 @@
* @pm_event
* @v
*
- * While frequency_locked == true, target() ignores every frequency but
- * locking_frequency. The locking_frequency value is the initial frequency,
+ * While cpufreq_disable == true, target() ignores every frequency but
+ * boot_freq. The boot_freq value is the initial frequency,
* which is set by the bootloader. In order to eliminate possible
* inconsistency in clock values, we save and restore frequencies during
* suspend and resume and block CPUFREQ activities. Note that the standard
@@ -151,52 +330,31 @@
static int exynos_cpufreq_pm_notifier(struct notifier_block *notifier,
unsigned long pm_event, void *v)
{
- struct cpufreq_policy *policy = cpufreq_cpu_get(0); /* boot CPU */
- static unsigned int saved_frequency;
- unsigned int temp;
+ int ret;
- mutex_lock(&cpufreq_lock);
switch (pm_event) {
case PM_SUSPEND_PREPARE:
- if (frequency_locked)
- goto out;
+ mutex_lock(&cpufreq_lock);
+ exynos_cpufreq_disable = true;
+ mutex_unlock(&cpufreq_lock);
- frequency_locked = true;
+ freqs.old = exynos_getspeed(0);
+ ret = exynos_cpufreq_scale(boot_freq, freqs.old);
- if (locking_frequency) {
- saved_frequency = exynos_getspeed(0);
+ if (ret < 0)
+ return NOTIFY_BAD;
- mutex_unlock(&cpufreq_lock);
- exynos_target(policy, locking_frequency,
- CPUFREQ_RELATION_H);
- mutex_lock(&cpufreq_lock);
- }
+ pr_debug("PM_SUSPEND_PREPARE for CPUFREQ\n");
break;
-
case PM_POST_SUSPEND:
- if (saved_frequency) {
- /*
- * While frequency_locked, only locking_frequency
- * is valid for target(). In order to use
- * saved_frequency while keeping frequency_locked,
- * we temporarly overwrite locking_frequency.
- */
- temp = locking_frequency;
- locking_frequency = saved_frequency;
+ pr_debug("PM_POST_SUSPEND for CPUFREQ\n");
- mutex_unlock(&cpufreq_lock);
- exynos_target(policy, locking_frequency,
- CPUFREQ_RELATION_H);
- mutex_lock(&cpufreq_lock);
+ mutex_lock(&cpufreq_lock);
+ exynos_cpufreq_disable = false;
+ mutex_unlock(&cpufreq_lock);
- locking_frequency = temp;
- }
- frequency_locked = false;
break;
}
-out:
- mutex_unlock(&cpufreq_lock);
-
return NOTIFY_OK;
}
@@ -207,11 +365,10 @@
static int exynos_cpufreq_cpu_init(struct cpufreq_policy *policy)
{
policy->cur = policy->min = policy->max = exynos_getspeed(policy->cpu);
+ boot_freq = exynos_getspeed(0);
cpufreq_frequency_table_get_attr(exynos_info->freq_table, policy->cpu);
- locking_frequency = exynos_getspeed(0);
-
/* set the transition latency value */
policy->cpuinfo.transition_latency = 100000;
@@ -244,6 +401,28 @@
#endif
};
+static int exynos_cpufreq_reboot_notifier_call(struct notifier_block *this,
+ unsigned long code, void *_cmd)
+{
+ int ret;
+
+ mutex_lock(&cpufreq_lock);
+ exynos_cpufreq_disable = true;
+ mutex_unlock(&cpufreq_lock);
+
+ freqs.old = exynos_getspeed(0);
+ ret = exynos_cpufreq_scale(boot_freq, freqs.old);
+
+ if (ret < 0)
+ return NOTIFY_BAD;
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block exynos_cpufreq_reboot_notifier = {
+ .notifier_call = exynos_cpufreq_reboot_notifier_call,
+};
+
static int __init exynos_cpufreq_init(void)
{
int ret = -EINVAL;
@@ -275,13 +454,21 @@
goto err_vdd_arm;
}
+ max_freq = exynos_info->freq_table[exynos_info->max_support_idx].frequency;
+ max_thermal_freq = max_freq;
+
+ exynos_cpufreq_disable = false;
+
register_pm_notifier(&exynos_cpufreq_nb);
+ register_reboot_notifier(&exynos_cpufreq_reboot_notifier);
if (cpufreq_register_driver(&exynos_driver)) {
pr_err("%s: failed to register cpufreq driver\n", __func__);
goto err_cpufreq;
}
+ exynos_cpufreq_init_done = true;
+
return 0;
err_cpufreq:
unregister_pm_notifier(&exynos_cpufreq_nb);
diff --git a/drivers/cpufreq/exynos5250-cpufreq.c b/drivers/cpufreq/exynos5250-cpufreq.c
index a883316..1cf4d59 100644
--- a/drivers/cpufreq/exynos5250-cpufreq.c
+++ b/drivers/cpufreq/exynos5250-cpufreq.c
@@ -20,6 +20,8 @@
#include <mach/map.h>
#include <mach/regs-clock.h>
#include <mach/cpufreq.h>
+#include <mach/asv-exynos.h>
+#include <mach/exynos5_bus.h>
#define CPUFREQ_LEVEL_END (L15 + 1)
@@ -29,6 +31,8 @@
static struct clk *moutcore;
static struct clk *mout_mpll;
static struct clk *mout_apll;
+static struct clk *fout_apll;
+static struct exynos5_bus_mif_handle *mif_bus_freq;
struct cpufreq_clkdiv {
unsigned int index;
@@ -58,217 +62,75 @@
{0, CPUFREQ_TABLE_END},
};
-static struct cpufreq_clkdiv exynos5250_clkdiv_table[CPUFREQ_LEVEL_END];
-
-static unsigned int clkdiv_cpu0_5250[CPUFREQ_LEVEL_END][8] = {
- /*
- * Clock divider value for following
- * { ARM, CPUD, ACP, PERIPH, ATB, PCLK_DBG, APLL, ARM2 }
- */
- { 0, 3, 7, 7, 6, 1, 3, 0 }, /* 1700 MHz - N/A */
- { 0, 3, 7, 7, 6, 1, 3, 0 }, /* 1600 MHz - N/A */
- { 0, 3, 7, 7, 5, 1, 3, 0 }, /* 1500 MHz - N/A */
- { 0, 3, 7, 7, 6, 1, 3, 0 }, /* 1400 MHz */
- { 0, 3, 7, 7, 6, 1, 3, 0 }, /* 1300 MHz */
- { 0, 3, 7, 7, 5, 1, 3, 0 }, /* 1200 MHz */
- { 0, 2, 7, 7, 5, 1, 2, 0 }, /* 1100 MHz */
- { 0, 2, 7, 7, 4, 1, 2, 0 }, /* 1000 MHz */
- { 0, 2, 7, 7, 4, 1, 2, 0 }, /* 900 MHz */
- { 0, 2, 7, 7, 3, 1, 1, 0 }, /* 800 MHz */
- { 0, 1, 7, 7, 3, 1, 1, 0 }, /* 700 MHz */
- { 0, 1, 7, 7, 2, 1, 1, 0 }, /* 600 MHz */
- { 0, 1, 7, 7, 2, 1, 1, 0 }, /* 500 MHz */
- { 0, 1, 7, 7, 1, 1, 1, 0 }, /* 400 MHz */
- { 0, 1, 7, 7, 1, 1, 1, 0 }, /* 300 MHz */
- { 0, 1, 7, 7, 1, 1, 1, 0 }, /* 200 MHz */
+/* Minimum memory throughput in megabytes per second */
+static int exynos5250_bus_table[CPUFREQ_LEVEL_END] = {
+ 800000, /* 1.7 GHz */
+ 800000, /* 1.6 GHz */
+ 800000, /* 1.5 GHz */
+ 800000, /* 1.4 GHz */
+ 667000, /* 1.3 GHz */
+ 667000, /* 1.2 GHz */
+ 667000, /* 1.1 GHz */
+ 400000, /* 1.0 GHz */
+ 400000, /* 900 MHz */
+ 400000, /* 800 MHz */
+ 160000, /* 700 MHz */
+ 160000, /* 600 MHz */
+ 160000, /* 500 MHz */
+ 0, /* 400 MHz */
+ 0, /* 300 MHz */
+ 0, /* 200 MHz */
};
-static unsigned int clkdiv_cpu1_5250[CPUFREQ_LEVEL_END][2] = {
- /* Clock divider value for following
- * { COPY, HPM }
- */
- { 0, 2 }, /* 1700 MHz - N/A */
- { 0, 2 }, /* 1600 MHz - N/A */
- { 0, 2 }, /* 1500 MHz - N/A */
- { 0, 2 }, /* 1400 MHz */
- { 0, 2 }, /* 1300 MHz */
- { 0, 2 }, /* 1200 MHz */
- { 0, 2 }, /* 1100 MHz */
- { 0, 2 }, /* 1000 MHz */
- { 0, 2 }, /* 900 MHz */
- { 0, 2 }, /* 800 MHz */
- { 0, 2 }, /* 700 MHz */
- { 0, 2 }, /* 600 MHz */
- { 0, 2 }, /* 500 MHz */
- { 0, 2 }, /* 400 MHz */
- { 0, 2 }, /* 300 MHz */
- { 0, 2 }, /* 200 MHz */
-};
-
-static unsigned int exynos5_apll_pms_table[CPUFREQ_LEVEL_END] = {
- (0), /* 1700 MHz - N/A */
- (0), /* 1600 MHz - N/A */
- (0), /* 1500 MHz - N/A */
- (0), /* 1400 MHz */
- ((325 << 16) | (6 << 8) | 0), /* 1300 MHz */
- ((200 << 16) | (4 << 8) | 0), /* 1200 MHz */
- ((275 << 16) | (6 << 8) | 0), /* 1100 MHz */
- ((125 << 16) | (3 << 8) | 0), /* 1000 MHz */
- ((150 << 16) | (4 << 8) | 0), /* 900 MHz */
- ((100 << 16) | (3 << 8) | 0), /* 800 MHz */
- ((175 << 16) | (3 << 8) | 1), /* 700 MHz */
- ((200 << 16) | (4 << 8) | 1), /* 600 MHz */
- ((125 << 16) | (3 << 8) | 1), /* 500 MHz */
- ((100 << 16) | (3 << 8) | 1), /* 400 MHz */
- ((200 << 16) | (4 << 8) | 2), /* 300 MHz */
- ((100 << 16) | (3 << 8) | 2), /* 200 MHz */
-};
-
-/* ASV group voltage table */
-static const unsigned int asv_voltage_5250[CPUFREQ_LEVEL_END] = {
- 0, 0, 0, 0, 0, 0, 0, /* 1700 MHz ~ 1100 MHz Not supported */
- 1175000, 1125000, 1075000, 1050000, 1000000,
- 950000, 925000, 925000, 900000
-};
-
-static void set_clkdiv(unsigned int div_index)
-{
- unsigned int tmp;
-
- /* Change Divider - CPU0 */
-
- tmp = exynos5250_clkdiv_table[div_index].clkdiv;
-
- __raw_writel(tmp, EXYNOS5_CLKDIV_CPU0);
-
- while (__raw_readl(EXYNOS5_CLKDIV_STATCPU0) & 0x11111111)
- cpu_relax();
-
- /* Change Divider - CPU1 */
- tmp = exynos5250_clkdiv_table[div_index].clkdiv1;
-
- __raw_writel(tmp, EXYNOS5_CLKDIV_CPU1);
-
- while (__raw_readl(EXYNOS5_CLKDIV_STATCPU1) & 0x11)
- cpu_relax();
-}
-
-static void set_apll(unsigned int new_index,
- unsigned int old_index)
-{
- unsigned int tmp, pdiv;
-
- /* 1. MUX_CORE_SEL = MPLL, ARMCLK uses MPLL for lock time */
- clk_set_parent(moutcore, mout_mpll);
-
- do {
- cpu_relax();
- tmp = (__raw_readl(EXYNOS5_CLKMUX_STATCPU) >> 16);
- tmp &= 0x7;
- } while (tmp != 0x2);
-
- /* 2. Set APLL Lock time */
- pdiv = ((exynos5_apll_pms_table[new_index] >> 8) & 0x3f);
-
- __raw_writel((pdiv * 250), EXYNOS5_APLL_LOCK);
-
- /* 3. Change PLL PMS values */
- tmp = __raw_readl(EXYNOS5_APLL_CON0);
- tmp &= ~((0x3ff << 16) | (0x3f << 8) | (0x7 << 0));
- tmp |= exynos5_apll_pms_table[new_index];
- __raw_writel(tmp, EXYNOS5_APLL_CON0);
-
- /* 4. wait_lock_time */
- do {
- cpu_relax();
- tmp = __raw_readl(EXYNOS5_APLL_CON0);
- } while (!(tmp & (0x1 << 29)));
-
- /* 5. MUX_CORE_SEL = APLL */
- clk_set_parent(moutcore, mout_apll);
-
- do {
- cpu_relax();
- tmp = __raw_readl(EXYNOS5_CLKMUX_STATCPU);
- tmp &= (0x7 << 16);
- } while (tmp != (0x1 << 16));
-
-}
-
-bool exynos5250_pms_change(unsigned int old_index, unsigned int new_index)
-{
- unsigned int old_pm = (exynos5_apll_pms_table[old_index] >> 8);
- unsigned int new_pm = (exynos5_apll_pms_table[new_index] >> 8);
-
- return (old_pm == new_pm) ? 0 : 1;
-}
-
-static void exynos5250_set_frequency(unsigned int old_index,
- unsigned int new_index)
-{
- unsigned int tmp;
-
- if (old_index > new_index) {
- if (!exynos5250_pms_change(old_index, new_index)) {
- /* 1. Change the system clock divider values */
- set_clkdiv(new_index);
- /* 2. Change just s value in apll m,p,s value */
- tmp = __raw_readl(EXYNOS5_APLL_CON0);
- tmp &= ~(0x7 << 0);
- tmp |= (exynos5_apll_pms_table[new_index] & 0x7);
- __raw_writel(tmp, EXYNOS5_APLL_CON0);
-
- } else {
- /* Clock Configuration Procedure */
- /* 1. Change the system clock divider values */
- set_clkdiv(new_index);
- /* 2. Change the apll m,p,s value */
- set_apll(new_index, old_index);
- }
- } else if (old_index < new_index) {
- if (!exynos5250_pms_change(old_index, new_index)) {
- /* 1. Change just s value in apll m,p,s value */
- tmp = __raw_readl(EXYNOS5_APLL_CON0);
- tmp &= ~(0x7 << 0);
- tmp |= (exynos5_apll_pms_table[new_index] & 0x7);
- __raw_writel(tmp, EXYNOS5_APLL_CON0);
- /* 2. Change the system clock divider values */
- set_clkdiv(new_index);
- } else {
- /* Clock Configuration Procedure */
- /* 1. Change the apll m,p,s value */
- set_apll(new_index, old_index);
- /* 2. Change the system clock divider values */
- set_clkdiv(new_index);
- }
- }
-}
-
-static void __init set_volt_table(void)
+static int __init set_volt_table(void)
{
unsigned int i;
- exynos5250_freq_table[L0].frequency = CPUFREQ_ENTRY_INVALID;
- exynos5250_freq_table[L1].frequency = CPUFREQ_ENTRY_INVALID;
- exynos5250_freq_table[L2].frequency = CPUFREQ_ENTRY_INVALID;
- exynos5250_freq_table[L3].frequency = CPUFREQ_ENTRY_INVALID;
- exynos5250_freq_table[L4].frequency = CPUFREQ_ENTRY_INVALID;
- exynos5250_freq_table[L5].frequency = CPUFREQ_ENTRY_INVALID;
- exynos5250_freq_table[L6].frequency = CPUFREQ_ENTRY_INVALID;
+ max_support_idx = L0;
- max_support_idx = L7;
+ for (i = 0; i < CPUFREQ_LEVEL_END; i++) {
+ exynos5250_volt_table[i] = asv_get_volt(ID_ARM, exynos5250_freq_table[i].frequency);
+ if (exynos5250_volt_table[i] == 0) {
+ pr_err("%s: invalid value\n", __func__);
+ return -EINVAL;
+ }
+ }
- for (i = 0 ; i < CPUFREQ_LEVEL_END ; i++)
- exynos5250_volt_table[i] = asv_voltage_5250[i];
+ return 0;
}
-int exynos5250_cpufreq_init(struct exynos_dvfs_info *info)
+static void exynos5250_set_frequency(unsigned int old_index,
+ unsigned int new_index)
{
- int i;
- unsigned int tmp;
+ /* MUX_CORE_SEL = MPLL, ARMCLK uses MPLL for lock time */
+ clk_set_parent(moutcore, mout_mpll);
+
+ if (old_index >= new_index)
+ exynos5_bus_mif_update(mif_bus_freq, exynos5250_bus_table[new_index]);
+
+ clk_set_rate(fout_apll,
+ exynos5250_freq_table[new_index].frequency * 1000);
+
+ if (old_index < new_index)
+ exynos5_bus_mif_update(mif_bus_freq, exynos5250_bus_table[new_index]);
+
+ /* MUX_CORE_SEL = APLL */
+ clk_set_parent(moutcore, mout_apll);
+}
+
+static bool exynos5250_pms_change(unsigned int old_index,
+ unsigned int new_index)
+{
+ /* Skip the apll change optimization, it won't happen very often */
+ return true;
+}
+
+int __init exynos5250_cpufreq_init(struct exynos_dvfs_info *info)
+{
unsigned long rate;
- set_volt_table();
+ if (set_volt_table())
+ return -EINVAL;
cpu_clk = clk_get(NULL, "armclk");
if (IS_ERR(cpu_clk))
@@ -288,36 +150,11 @@
if (IS_ERR(mout_apll))
goto err_mout_apll;
- for (i = L0; i < CPUFREQ_LEVEL_END; i++) {
+ fout_apll = clk_get(NULL, "fout_apll");
+ if (IS_ERR(fout_apll))
+ goto err_fout_apll;
- exynos5250_clkdiv_table[i].index = i;
-
- tmp = __raw_readl(EXYNOS5_CLKDIV_CPU0);
-
- tmp &= ~((0x7 << 0) | (0x7 << 4) | (0x7 << 8) |
- (0x7 << 12) | (0x7 << 16) | (0x7 << 20) |
- (0x7 << 24) | (0x7 << 28));
-
- tmp |= ((clkdiv_cpu0_5250[i][0] << 0) |
- (clkdiv_cpu0_5250[i][1] << 4) |
- (clkdiv_cpu0_5250[i][2] << 8) |
- (clkdiv_cpu0_5250[i][3] << 12) |
- (clkdiv_cpu0_5250[i][4] << 16) |
- (clkdiv_cpu0_5250[i][5] << 20) |
- (clkdiv_cpu0_5250[i][6] << 24) |
- (clkdiv_cpu0_5250[i][7] << 28));
-
- exynos5250_clkdiv_table[i].clkdiv = tmp;
-
- tmp = __raw_readl(EXYNOS5_CLKDIV_CPU1);
-
- tmp &= ~((0x7 << 0) | (0x7 << 4));
-
- tmp |= ((clkdiv_cpu1_5250[i][0] << 0) |
- (clkdiv_cpu1_5250[i][1] << 4));
-
- exynos5250_clkdiv_table[i].clkdiv1 = tmp;
- }
+ mif_bus_freq = exynos5_bus_mif_min(0);
info->mpll_freq_khz = rate;
/* 1000Mhz */
@@ -334,6 +171,8 @@
return 0;
+err_fout_apll:
+ clk_put(mout_apll);
err_mout_apll:
clk_put(mout_mpll);
err_mout_mpll:
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index dd414d9..dc3d0a7 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -18,7 +18,7 @@
(so called VIA PadLock ACE, Advanced Cryptography Engine)
that provides instructions for very fast cryptographic
operations with supported algorithms.
-
+
The instructions are used only when the CPU supports them.
Otherwise software encryption is used.
@@ -285,6 +285,61 @@
Select this to offload Samsung S5PV210 or S5PC110 from AES
algorithms execution.
+config CRYPTO_S5P_DEV_ACE
+ tristate "Support for Samsung ACE (Advanced Crypto Engine)"
+ depends on ARCH_EXYNOS4 || ARCH_EXYNOS5 || ARCH_S5PV210
+ select S5P_DEV_ACE
+ select CRYPTO_ALGAPI
+ help
+ Use ACE for AES (ECB, CBC, CTR) and SHA1/SHA256.
+ Available in EXYNOS4/S5PV210/S5PC110 and newer CPUs.
+
+config ACE_BC
+ bool "Support for AES block cipher (ECB, CBC, CTR mode)"
+ depends on CRYPTO_S5P_DEV_ACE
+ select CRYPTO_AES
+ select CRYPTO_BLKCIPHER
+ select CRYPTO_ECB
+ select CRYPTO_CTR
+ select CRYPTO_CBC
+ default y
+ help
+ Use ACE for ACE (ECB, CBC, CTR) for Samsung Hardware Crypto engine.
+
+config ACE_BC_ASYNC
+ bool "Support for AES async mode"
+ default y
+ depends on ACE_BC
+
+config ACE_BC_IRQMODE
+ bool "Support for AES IRQ mode"
+ default n
+ depends on ACE_BC_ASYNC
+
+config ACE_HASH_SHA1
+ bool "Support for SHA1 hash algorithm"
+ depends on CRYPTO_S5P_DEV_ACE
+ select CRYPTO_HASH
+ select CRYPTO_SHA1
+ default y
+ help
+ Use SHA1 hash algorithm for Samsung Hardware Crypto engine
+
+config ACE_HASH_SHA256
+ bool "Support for SHA256 hash algorithm"
+ depends on CRYPTO_S5P_DEV_ACE && ARCH_EXYNOS4
+ select CRYPTO_HASH
+ select CRYPTO_SHA256
+ default y
+ help
+ Use SHA256 hash algorithm for Samsung Hardware Crypto engine
+
+config ACE_DEBUG
+ bool "Debug message for crypto driver"
+ depends on CRYPTO_S5P_DEV_ACE
+ help
+ This option allows you to check the debug print message for crypto driver.
+
config CRYPTO_DEV_TEGRA_AES
tristate "Support for TEGRA AES hw engine"
depends on ARCH_TEGRA
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index f3e64ea..4fe1e44 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -13,4 +13,4 @@
obj-$(CONFIG_CRYPTO_DEV_OMAP_AES) += omap-aes.o
obj-$(CONFIG_CRYPTO_DEV_PICOXCELL) += picoxcell_crypto.o
obj-$(CONFIG_CRYPTO_DEV_S5P) += s5p-sss.o
-obj-$(CONFIG_CRYPTO_DEV_TEGRA_AES) += tegra-aes.o
+obj-$(CONFIG_CRYPTO_S5P_DEV_ACE) += ace.o
diff --git a/drivers/crypto/ace.c b/drivers/crypto/ace.c
new file mode 100644
index 0000000..4828ad6
--- /dev/null
+++ b/drivers/crypto/ace.c
@@ -0,0 +1,2612 @@
+/*
+ * Cryptographic API.
+ *
+ * Support for ACE (Advanced Crypto Engine) for S5PV210/EXYNOS4210.
+ *
+ * Copyright (c) 2011 Samsung Electronics
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/scatterlist.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/memory.h>
+#include <linux/delay.h>
+#include <linux/version.h>
+#include <linux/hrtimer.h>
+
+#include <asm/cacheflush.h>
+
+#include <crypto/aes.h>
+#include <crypto/internal/hash.h>
+#include <crypto/sha.h>
+#include <crypto/scatterwalk.h>
+
+#include <mach/secmem.h>
+
+#include "ace.h"
+#include "ace_sfr.h"
+
+#define S5P_ACE_DRIVER_NAME "s5p-ace"
+#define ACE_AES_MIN_BLOCK_SIZE 16
+
+#undef ACE_USE_ACP
+#ifdef ACE_USE_ACP
+#define PA_SSS_USER_CON 0x10010344
+#define ACE_ARCACHE 0xA
+#define ACE_AWCACHE 0xA
+#endif
+
+#undef ACE_DEBUG_HEARTBEAT
+#undef ACE_DEBUG_WATCHDOG
+
+#ifdef CONFIG_ACE_DEBUG
+#define S5P_ACE_DEBUG(args...) printk(KERN_INFO args)
+#else
+#define S5P_ACE_DEBUG(args...)
+#endif
+
+#define s5p_ace_read_sfr(_sfr_) __raw_readl(s5p_ace_dev.ace_base + (_sfr_))
+#define s5p_ace_write_sfr(_sfr_, _val_) __raw_writel((_val_), s5p_ace_dev.ace_base + (_sfr_))
+
+enum s5p_cpu_type {
+ TYPE_S5PV210,
+ TYPE_EXYNOS4,
+};
+
+enum {
+ FLAGS_BC_BUSY,
+ FLAGS_HASH_BUSY,
+ FLAGS_SUSPENDED,
+ FLAGS_USE_SW
+};
+
+static struct s5p_ace_device s5p_ace_dev;
+
+#ifdef CONFIG_ACE_BC_ASYNC
+static void s5p_ace_bc_task(unsigned long data);
+#endif
+
+#define ACE_CLOCK_ON 0
+#define ACE_CLOCK_OFF 1
+
+static int count_clk;
+static int count_clk_delta;
+
+#if defined(ACE_DEBUG_HEARTBEAT) || defined(ACE_DEBUG_WATCHDOG)
+#define ACE_HEARTBEAT_MS 10000
+#define ACE_WATCHDOG_MS 500
+
+struct timeval timestamp_base;
+struct timeval timestamp[5];
+
+static inline void s5p_ace_dump(void)
+{
+ int i;
+ char *str[] = {"request: ", "dma start: ", "dma end: ", "suspend: ", "resume: "};
+
+ for (i = 0; i < 5; i++)
+ printk(KERN_INFO "%s%5lu.%06lu\n",
+ str[i], timestamp[i].tv_sec - timestamp_base.tv_sec, timestamp[i].tv_usec);
+ printk(KERN_INFO "clock: [%d - %d]\n", count_clk, count_clk_delta);
+}
+#endif
+
+struct s5p_ace_reqctx {
+ u32 mode;
+};
+
+struct s5p_ace_device {
+ void __iomem *ace_base;
+ struct clk *clock;
+#if defined(CONFIG_ACE_BC_IRQMODE) || defined(CONFIG_ACE_HASH_IRQMODE)
+ int irq;
+#endif
+#ifdef ACE_USE_ACP
+ void __iomem *sss_usercon;
+#endif
+ spinlock_t lock;
+ unsigned long flags;
+
+ struct hrtimer timer;
+ struct work_struct work;
+#ifdef ACE_DEBUG_HEARTBEAT
+ struct hrtimer heartbeat;
+#endif
+#ifdef ACE_DEBUG_WATCHDOG
+ struct hrtimer watchdog_bc;
+#endif
+
+#ifdef CONFIG_ACE_BC_ASYNC
+ struct crypto_queue queue_bc;
+ struct tasklet_struct task_bc;
+ int rc_depth_bc;
+#endif
+
+ struct s5p_ace_aes_ctx *ctx_bc;
+
+#ifdef CONFIG_ACE_HASH_ASYNC
+ struct crypto_queue queue_hash;
+ struct tasklet_struct task_hash;
+#endif
+ enum s5p_cpu_type cputype;
+};
+
+#if defined(CONFIG_ACE_HASH_SHA1) || defined(CONFIG_ACE_HASH_SHA256)
+struct crypto_shash *sw_tfm;
+struct crypto_hash **fallback_hash;
+#endif
+struct secmem_crypto_driver_ftn secmem_ftn;
+
+static void s5p_ace_init_clock_gating(void)
+{
+ count_clk = 0;
+ count_clk_delta = 0;
+}
+
+static void s5p_ace_deferred_clock_disable(struct work_struct *work)
+{
+ unsigned long flags;
+ int tmp;
+
+ if (count_clk_delta == 0)
+ return;
+
+ spin_lock_irqsave(&s5p_ace_dev.lock, flags);
+ count_clk -= count_clk_delta;
+ count_clk_delta = 0;
+ tmp = count_clk;
+ spin_unlock_irqrestore(&s5p_ace_dev.lock, flags);
+
+ if (tmp == 0) {
+ clk_disable(s5p_ace_dev.clock);
+ S5P_ACE_DEBUG("ACE clock OFF\n");
+ }
+}
+
+static enum hrtimer_restart s5p_ace_timer_func(struct hrtimer *timer)
+{
+ S5P_ACE_DEBUG("ACE HRTIMER\n");
+
+ /* It seems that "schedule_work" is expensive. */
+ schedule_work(&s5p_ace_dev.work);
+
+ return HRTIMER_NORESTART;
+}
+
+static void s5p_ace_clock_gating(int status)
+{
+ unsigned long flags;
+ int tmp;
+
+ if (status == ACE_CLOCK_ON) {
+ spin_lock_irqsave(&s5p_ace_dev.lock, flags);
+ tmp = count_clk++;
+ spin_unlock_irqrestore(&s5p_ace_dev.lock, flags);
+
+ if (tmp == 0) {
+ clk_enable(s5p_ace_dev.clock);
+ S5P_ACE_DEBUG("ACE clock ON\n");
+ }
+ } else if (status == ACE_CLOCK_OFF) {
+ spin_lock_irqsave(&s5p_ace_dev.lock, flags);
+ if (count_clk > 1)
+ count_clk--;
+ else
+ count_clk_delta++;
+ spin_unlock_irqrestore(&s5p_ace_dev.lock, flags);
+
+ hrtimer_start(&s5p_ace_dev.timer,
+ ns_to_ktime((u64)500 * NSEC_PER_MSEC),
+ HRTIMER_MODE_REL);
+ }
+}
+
+struct s5p_ace_aes_ctx {
+ u32 keylen;
+
+ u32 sfr_ctrl;
+ u8 sfr_key[AES_MAX_KEY_SIZE];
+ u8 sfr_semikey[AES_BLOCK_SIZE];
+
+ struct crypto_blkcipher *fallback_bc;
+#ifdef CONFIG_ACE_BC_ASYNC
+ struct ablkcipher_request *req;
+ struct crypto_ablkcipher *fallback_abc;
+ struct crypto_tfm *origin_tfm;
+#else
+ struct crypto_blkcipher *origin_tfm;
+
+#endif
+ size_t total;
+ struct scatterlist *in_sg;
+ size_t in_ofs;
+ struct scatterlist *out_sg;
+ size_t out_ofs;
+
+ int directcall;
+
+ u8 *src_addr;
+ u8 *dst_addr;
+ u32 dma_size;
+ u8 tbuf[AES_BLOCK_SIZE];
+};
+
+#if defined(ACE_DEBUG_HEARTBEAT) || defined(ACE_DEBUG_WATCHDOG)
+static void s5p_ace_print_info(void)
+{
+ struct s5p_ace_aes_ctx *sctx = s5p_ace_dev.ctx_bc;
+
+ printk(KERN_INFO "flags: 0x%X\n", (u32)s5p_ace_dev.flags);
+ s5p_ace_dump();
+ if (sctx == NULL) {
+ printk(KERN_INFO "sctx == NULL\n");
+ } else {
+#ifdef CONFIG_ACE_BC_ASYNC
+ printk(KERN_INFO "sctx->req: 0x%08X\n", (u32)sctx->req);
+#endif
+ printk(KERN_INFO "sctx->total: 0x%08X\n", sctx->total);
+ printk(KERN_INFO "sctx->dma_size: 0x%08X\n", sctx->dma_size);
+ }
+}
+#endif
+
+#ifdef ACE_DEBUG_HEARTBEAT
+static enum hrtimer_restart s5p_ace_heartbeat_func(struct hrtimer *timer)
+{
+ printk(KERN_INFO "[[ACE HEARTBEAT]] -- START ----------\n");
+
+ s5p_ace_print_info();
+
+ printk(KERN_INFO "[[ACE HEARTBEAT]] -- END ------------\n");
+
+ hrtimer_start(&s5p_ace_dev.heartbeat,
+ ns_to_ktime((u64)ACE_HEARTBEAT_MS * NSEC_PER_MSEC),
+ HRTIMER_MODE_REL);
+
+ return HRTIMER_NORESTART;
+}
+#endif
+
+#ifdef ACE_DEBUG_WATCHDOG
+static enum hrtimer_restart s5p_ace_watchdog_bc_func(struct hrtimer *timer)
+{
+ printk(KERN_ERR "[[ACE WATCHDOG BC]] ============\n");
+
+ s5p_ace_print_info();
+
+ return HRTIMER_NORESTART;
+}
+#endif
+
+static void s5p_ace_resume_device(struct s5p_ace_device *dev)
+{
+ if (test_and_clear_bit(FLAGS_SUSPENDED, &dev->flags)) {
+ clear_bit(FLAGS_BC_BUSY, &dev->flags);
+ clear_bit(FLAGS_HASH_BUSY, &dev->flags);
+
+#ifdef ACE_USE_ACP
+ /* Set ARUSER[12:8] and AWUSER[4:0] */
+ writel(0x101, dev->sss_usercon
+ + (PA_SSS_USER_CON & (PAGE_SIZE - 1)));
+#endif
+ }
+}
+
+static int s5p_ace_aes_set_cipher(struct s5p_ace_aes_ctx *sctx,
+ u32 alg_id, u32 key_size)
+{
+ u32 new_status = 0;
+
+ /* Fixed setting */
+ new_status |= ACE_AES_FIFO_ON;
+
+ if (s5p_ace_dev.cputype == TYPE_S5PV210)
+ new_status |= ACE_AES_KEYCNGMODE_ON;
+
+ new_status |= ACE_AES_SWAPKEY_ON;
+ new_status |= ACE_AES_SWAPCNT_ON;
+ new_status |= ACE_AES_SWAPIV_ON;
+
+ if (s5p_ace_dev.cputype == TYPE_EXYNOS4) {
+ new_status |= ACE_AES_SWAPDO_ON;
+ new_status |= ACE_AES_SWAPDI_ON;
+ }
+
+ switch (MI_GET_MODE(alg_id)) {
+ case _MODE_ECB_:
+ new_status |= ACE_AES_OPERMODE_ECB;
+ break;
+ case _MODE_CBC_:
+ new_status |= ACE_AES_OPERMODE_CBC;
+ break;
+ case _MODE_CTR_:
+ new_status |= ACE_AES_OPERMODE_CTR;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (key_size) {
+ case 128:
+ new_status |= ACE_AES_KEYSIZE_128;
+ break;
+ case 192:
+ new_status |= ACE_AES_KEYSIZE_192;
+ break;
+ case 256:
+ new_status |= ACE_AES_KEYSIZE_256;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Set AES context */
+ sctx->sfr_ctrl = new_status;
+ sctx->keylen = key_size >> 3;
+
+ return 0;
+}
+
+/*
+ * enc: BC_MODE_ENC - encryption, BC_MODE_DEC - decryption
+ */
+static int s5p_ace_aes_set_encmode(struct s5p_ace_aes_ctx *sctx, u32 enc)
+{
+ u32 status = sctx->sfr_ctrl;
+ u32 enc_mode = ACE_AES_MODE_ENC;
+
+ if ((status & ACE_AES_OPERMODE_MASK) != ACE_AES_OPERMODE_CTR)
+ enc_mode = (enc == BC_MODE_ENC ?
+ ACE_AES_MODE_ENC : ACE_AES_MODE_DEC);
+
+ sctx->sfr_ctrl = (status & ~ACE_AES_MODE_MASK) | enc_mode;
+
+ return 0;
+}
+
+static int s5p_ace_aes_update_semikey(struct s5p_ace_aes_ctx *sctx,
+ u8 *in, u8 *out, u32 len)
+{
+ u32 *addr = (u32 *)sctx->sfr_semikey;
+ u32 tmp1, tmp2;
+
+ switch (sctx->sfr_ctrl & ACE_AES_OPERMODE_MASK) {
+ case ACE_AES_OPERMODE_ECB:
+ break;
+ case ACE_AES_OPERMODE_CBC:
+ if ((sctx->sfr_ctrl & ACE_AES_MODE_MASK) == ACE_AES_MODE_ENC)
+ memcpy(sctx->sfr_semikey, out, AES_BLOCK_SIZE);
+ else
+ memcpy(sctx->sfr_semikey, in, AES_BLOCK_SIZE);
+ break;
+ case ACE_AES_OPERMODE_CTR:
+ tmp1 = be32_to_cpu(addr[3]);
+ tmp2 = tmp1 + (len >> 4);
+ addr[3] = be32_to_cpu(tmp2);
+ if (tmp2 < tmp1) {
+ tmp1 = be32_to_cpu(addr[2]) + 1;
+ addr[2] = be32_to_cpu(tmp1);
+ if (addr[2] == 0) {
+ tmp1 = be32_to_cpu(addr[1]) + 1;
+ addr[1] = be32_to_cpu(tmp1);
+ if (addr[1] == 0) {
+ tmp1 = be32_to_cpu(addr[0]) + 1;
+ addr[0] = be32_to_cpu(tmp1);
+ }
+ }
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int s5p_ace_aes_write_sfr(struct s5p_ace_aes_ctx *sctx)
+{
+ u32 *addr;
+
+ s5p_ace_write_sfr(ACE_AES_CONTROL, sctx->sfr_ctrl);
+
+ addr = (u32 *)sctx->sfr_key;
+ switch (sctx->keylen) {
+ case 16:
+ s5p_ace_write_sfr(ACE_AES_KEY5, addr[0]);
+ s5p_ace_write_sfr(ACE_AES_KEY6, addr[1]);
+ s5p_ace_write_sfr(ACE_AES_KEY7, addr[2]);
+ s5p_ace_write_sfr(ACE_AES_KEY8, addr[3]);
+ break;
+ case 24:
+ s5p_ace_write_sfr(ACE_AES_KEY3, addr[0]);
+ s5p_ace_write_sfr(ACE_AES_KEY4, addr[1]);
+ s5p_ace_write_sfr(ACE_AES_KEY5, addr[2]);
+ s5p_ace_write_sfr(ACE_AES_KEY6, addr[3]);
+ s5p_ace_write_sfr(ACE_AES_KEY7, addr[4]);
+ s5p_ace_write_sfr(ACE_AES_KEY8, addr[5]);
+ break;
+ case 32:
+ s5p_ace_write_sfr(ACE_AES_KEY1, addr[0]);
+ s5p_ace_write_sfr(ACE_AES_KEY2, addr[1]);
+ s5p_ace_write_sfr(ACE_AES_KEY3, addr[2]);
+ s5p_ace_write_sfr(ACE_AES_KEY4, addr[3]);
+ s5p_ace_write_sfr(ACE_AES_KEY5, addr[4]);
+ s5p_ace_write_sfr(ACE_AES_KEY6, addr[5]);
+ s5p_ace_write_sfr(ACE_AES_KEY7, addr[6]);
+ s5p_ace_write_sfr(ACE_AES_KEY8, addr[7]);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ addr = (u32 *)sctx->sfr_semikey;
+ switch (sctx->sfr_ctrl & ACE_AES_OPERMODE_MASK) {
+ case ACE_AES_OPERMODE_ECB:
+ break;
+ case ACE_AES_OPERMODE_CBC:
+ s5p_ace_write_sfr(ACE_AES_IV1, addr[0]);
+ s5p_ace_write_sfr(ACE_AES_IV2, addr[1]);
+ s5p_ace_write_sfr(ACE_AES_IV3, addr[2]);
+ s5p_ace_write_sfr(ACE_AES_IV4, addr[3]);
+ break;
+ case ACE_AES_OPERMODE_CTR:
+ s5p_ace_write_sfr(ACE_AES_CNT1, addr[0]);
+ s5p_ace_write_sfr(ACE_AES_CNT2, addr[1]);
+ s5p_ace_write_sfr(ACE_AES_CNT3, addr[2]);
+ s5p_ace_write_sfr(ACE_AES_CNT4, addr[3]);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int s5p_ace_aes_engine_start(struct s5p_ace_aes_ctx *sctx,
+ u8 *out, const u8 *in, u32 len, int irqen)
+{
+ u32 reg;
+ u32 first_blklen;
+
+ if ((sctx == NULL) || (out == NULL) || (in == NULL)) {
+ printk(KERN_ERR "%s : NULL input.\n", __func__);
+ return -EINVAL;
+ }
+
+ if (len & (AES_BLOCK_SIZE - 1)) {
+ printk(KERN_ERR "Invalid len for AES engine (%d)\n", len);
+ return -EINVAL;
+ }
+
+ if (s5p_ace_aes_write_sfr(sctx) != 0)
+ return -EINVAL;
+
+ S5P_ACE_DEBUG("AES: %s, in: 0x%08X, out: 0x%08X, len: 0x%08X\n",
+ __func__, (u32)in, (u32)out, len);
+ S5P_ACE_DEBUG("AES: %s, AES_control : 0x%08X\n",
+ __func__, s5p_ace_read_sfr(ACE_AES_CONTROL));
+
+ /* Assert code */
+ reg = s5p_ace_read_sfr(ACE_AES_STATUS);
+ if ((reg & ACE_AES_BUSY_MASK) == ACE_AES_BUSY_ON)
+ return -EBUSY;
+
+ /* Flush BRDMA and BTDMA */
+ s5p_ace_write_sfr(ACE_FC_BRDMAC, ACE_FC_BRDMACFLUSH_ON);
+ s5p_ace_write_sfr(ACE_FC_BTDMAC, ACE_FC_BTDMACFLUSH_ON);
+
+ /* Select Input MUX as AES */
+ reg = s5p_ace_read_sfr(ACE_FC_FIFOCTRL);
+ reg = (reg & ~ACE_FC_SELBC_MASK) | ACE_FC_SELBC_AES;
+ s5p_ace_write_sfr(ACE_FC_FIFOCTRL, reg);
+
+ /* Stop flushing BRDMA and BTDMA */
+ reg = ACE_FC_BRDMACFLUSH_OFF;
+ if (s5p_ace_dev.cputype == TYPE_S5PV210)
+ reg |= ACE_FC_BRDMACSWAP_ON;
+
+#ifdef ACE_USE_ACP
+ reg |= ACE_ARCACHE << ACE_FC_BRDMACARCACHE_OFS;
+#endif
+ s5p_ace_write_sfr(ACE_FC_BRDMAC, reg);
+ reg = ACE_FC_BTDMACFLUSH_OFF;
+ if (s5p_ace_dev.cputype == TYPE_S5PV210)
+ reg |= ACE_FC_BTDMACSWAP_ON;
+
+#ifdef ACE_USE_ACP
+ reg |= ACE_AWCACHE << ACE_FC_BTDMACAWCACHE_OFS;
+#endif
+ s5p_ace_write_sfr(ACE_FC_BTDMAC, reg);
+
+ /* Set DMA */
+ s5p_ace_write_sfr(ACE_FC_BRDMAS, (u32)in);
+ s5p_ace_write_sfr(ACE_FC_BTDMAS, (u32)out);
+
+ if (s5p_ace_dev.cputype == TYPE_S5PV210) {
+ /* Set the length of first block (Key Change Mode On) */
+ if ((((u32)in) & (2 * AES_BLOCK_SIZE - 1)) == 0)
+ first_blklen = 2 * AES_BLOCK_SIZE;
+ else
+ first_blklen = AES_BLOCK_SIZE;
+
+ if (len <= first_blklen) {
+#ifdef CONFIG_ACE_BC_IRQMODE
+ if (irqen)
+ s5p_ace_write_sfr(ACE_FC_INTENSET, ACE_FC_BTDMA);
+#endif
+
+ /* Set DMA */
+ s5p_ace_write_sfr(ACE_FC_BRDMAL, len);
+ s5p_ace_write_sfr(ACE_FC_BTDMAL, len);
+ } else {
+ unsigned long timeout;
+
+ /* Set DMA */
+ s5p_ace_write_sfr(ACE_FC_BRDMAL, first_blklen);
+ s5p_ace_write_sfr(ACE_FC_BTDMAL, first_blklen);
+
+ timeout = jiffies + msecs_to_jiffies(10);
+ while (time_before(jiffies, timeout)) {
+ if (s5p_ace_read_sfr(ACE_FC_INTPEND) & ACE_FC_BTDMA)
+ break;
+ }
+ if (!(s5p_ace_read_sfr(ACE_FC_INTPEND) & ACE_FC_BTDMA)) {
+ printk(KERN_ERR "AES : DMA time out\n");
+ return -EBUSY;
+ }
+ s5p_ace_write_sfr(ACE_FC_INTPEND, ACE_FC_BTDMA | ACE_FC_BRDMA);
+
+ reg = sctx->sfr_ctrl;
+ reg = (reg & ~ACE_AES_KEYCNGMODE_MASK) | ACE_AES_KEYCNGMODE_OFF;
+ s5p_ace_write_sfr(ACE_AES_CONTROL, reg);
+
+#ifdef CONFIG_ACE_BC_IRQMODE
+ if (irqen)
+ s5p_ace_write_sfr(ACE_FC_INTENSET, ACE_FC_BTDMA);
+#endif
+
+ /* Set DMA */
+ s5p_ace_write_sfr(ACE_FC_BRDMAL, len - first_blklen);
+ s5p_ace_write_sfr(ACE_FC_BTDMAL, len - first_blklen);
+ }
+ } else {
+#ifdef CONFIG_ACE_BC_IRQMODE
+ if (irqen)
+ s5p_ace_write_sfr(ACE_FC_INTENSET, ACE_FC_BTDMA);
+#endif
+
+ /* Set DMA */
+ s5p_ace_write_sfr(ACE_FC_BRDMAL, len);
+ s5p_ace_write_sfr(ACE_FC_BTDMAL, len);
+ }
+
+ return 0;
+}
+
+static void s5p_ace_aes_engine_wait(struct s5p_ace_aes_ctx *sctx,
+ u8 *out, const u8 *in, u32 len)
+{
+ unsigned long timeout = jiffies + msecs_to_jiffies(10);
+ while (time_before(jiffies, timeout))
+ if (s5p_ace_read_sfr(ACE_FC_INTPEND) & ACE_FC_BTDMA)
+ break;
+ if (!(s5p_ace_read_sfr(ACE_FC_INTPEND) & ACE_FC_BTDMA))
+ printk(KERN_ERR "%s : DMA time out\n", __func__);
+ s5p_ace_write_sfr(ACE_FC_INTPEND, ACE_FC_BTDMA | ACE_FC_BRDMA);
+}
+
+void s5p_ace_sg_update(struct scatterlist **sg, size_t *offset,
+ size_t count)
+{
+ *offset += count;
+ if (*offset >= sg_dma_len(*sg)) {
+ *offset -= sg_dma_len(*sg);
+ *sg = sg_next(*sg);
+ }
+}
+
+int s5p_ace_sg_set_from_sg(struct scatterlist *dst, struct scatterlist *src,
+ u32 num)
+{
+ sg_init_table(dst, num);
+ while (num--) {
+ sg_set_page(dst, sg_page(src), sg_dma_len(src), src->offset);
+
+ src = sg_next(src);
+ dst = sg_next(dst);
+ if (!src || !dst)
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+/* Unaligned data Handling
+ * - size should be a multiple of ACE_AES_MIN_BLOCK_SIZE.
+ */
+static int s5p_ace_aes_crypt_unaligned(struct s5p_ace_aes_ctx *sctx,
+ size_t size)
+{
+ struct blkcipher_desc desc;
+ struct scatterlist in_sg[2], out_sg[2];
+ int ret;
+
+ S5P_ACE_DEBUG("%s - %s (size: %d / %d)\n", __func__,
+ sctx->fallback_bc->base.__crt_alg->cra_driver_name,
+ size, sctx->total);
+
+ desc.tfm = sctx->fallback_bc;
+ desc.info = sctx->sfr_semikey;
+ desc.flags = 0;
+
+ s5p_ace_sg_set_from_sg(in_sg, sctx->in_sg, 2);
+ in_sg->length -= sctx->in_ofs;
+ in_sg->offset += sctx->in_ofs;
+
+ s5p_ace_sg_set_from_sg(out_sg, sctx->out_sg, 2);
+ out_sg->length -= sctx->out_ofs;
+ out_sg->offset += sctx->out_ofs;
+
+ if ((sctx->sfr_ctrl & ACE_AES_MODE_MASK) == ACE_AES_MODE_ENC)
+ ret = crypto_blkcipher_encrypt_iv(
+ &desc, out_sg, in_sg, size);
+ else
+ ret = crypto_blkcipher_decrypt_iv(
+ &desc, out_sg, in_sg, size);
+
+ sctx->dma_size = 0;
+ sctx->total -= size;
+ if (!sctx->total)
+ return 0;
+
+ s5p_ace_sg_update(&sctx->in_sg, &sctx->in_ofs, size);
+ s5p_ace_sg_update(&sctx->out_sg, &sctx->out_ofs, size);
+
+ return 0;
+}
+
+static int s5p_ace_aes_crypt_dma_start(struct s5p_ace_device *dev)
+{
+ struct s5p_ace_aes_ctx *sctx = dev->ctx_bc;
+ u8 *src, *dst;
+ size_t count;
+ int i;
+ int ret;
+
+#if defined(ACE_DEBUG_HEARTBEAT) || defined(ACE_DEBUG_WATCHDOG)
+ do_gettimeofday(×tamp[1]); /* 1: dma start */
+#endif
+
+ sctx->directcall = 0;
+
+ while (1) {
+ count = sctx->total;
+ count = min(count, sg_dma_len(sctx->in_sg) - sctx->in_ofs);
+ count = min(count, sg_dma_len(sctx->out_sg) - sctx->out_ofs);
+
+ S5P_ACE_DEBUG("total_start: %d (%d)\n", sctx->total, count);
+ S5P_ACE_DEBUG(" in(ofs: %x, len: %x), %x\n",
+ sctx->in_sg->offset, sg_dma_len(sctx->in_sg),
+ sctx->in_ofs);
+ S5P_ACE_DEBUG(" out(ofs: %x, len: %x), %x\n",
+ sctx->out_sg->offset, sg_dma_len(sctx->out_sg),
+ sctx->out_ofs);
+
+ if (count > ACE_AES_MIN_BLOCK_SIZE)
+ break;
+
+ count = min(sctx->total, (size_t)ACE_AES_MIN_BLOCK_SIZE);
+ if (count & (AES_BLOCK_SIZE - 1))
+ printk(KERN_ERR "%s - Invalid count\n", __func__);
+ ret = s5p_ace_aes_crypt_unaligned(sctx, count);
+ if (!sctx->total) {
+#if defined(ACE_DEBUG_HEARTBEAT) || defined(ACE_DEBUG_WATCHDOG)
+ do_gettimeofday(×tamp[2]); /* 2: dma end */
+#endif
+#ifdef CONFIG_ACE_BC_IRQMODE
+ tasklet_schedule(&dev->task_bc);
+ return 0;
+#else
+ goto run;
+#endif
+ }
+ }
+
+ count &= ~(AES_BLOCK_SIZE - 1);
+ sctx->dma_size = count;
+
+ src = (u8 *)page_to_phys(sg_page(sctx->in_sg));
+ src += sctx->in_sg->offset + sctx->in_ofs;
+ if (!PageHighMem(sg_page(sctx->in_sg))) {
+ sctx->src_addr = (u8 *)phys_to_virt((u32)src);
+ } else {
+ sctx->src_addr = crypto_kmap(sg_page(sctx->in_sg),
+ crypto_kmap_type(0));
+ sctx->src_addr += sctx->in_sg->offset + sctx->in_ofs;
+ }
+
+ dst = (u8 *)page_to_phys(sg_page(sctx->out_sg));
+ dst += sctx->out_sg->offset + sctx->out_ofs;
+ if (!PageHighMem(sg_page(sctx->out_sg))) {
+ sctx->dst_addr = (u8 *)phys_to_virt((u32)dst);
+ } else {
+ sctx->dst_addr = crypto_kmap(sg_page(sctx->out_sg),
+ crypto_kmap_type(1));
+ sctx->dst_addr += sctx->out_sg->offset + sctx->out_ofs;
+ }
+
+ S5P_ACE_DEBUG(" phys(src: %x, dst: %x)\n", (u32)src, (u32)dst);
+ S5P_ACE_DEBUG(" virt(src: %x, dst: %x)\n",
+ (u32)sctx->src_addr, (u32)sctx->dst_addr);
+
+ if (src == dst)
+ memcpy(sctx->tbuf, sctx->src_addr + count - AES_BLOCK_SIZE,
+ AES_BLOCK_SIZE);
+
+#ifndef ACE_USE_ACP
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
+ dmac_clean_range((void *)sctx->src_addr,
+ (void *)sctx->src_addr + count);
+ dmac_clean_range((void *)sctx->dst_addr,
+ (void *)sctx->dst_addr + count);
+#else
+ dmac_map_area((void *)sctx->src_addr, count, DMA_TO_DEVICE);
+ outer_clean_range((unsigned long)src, (unsigned long)src + count);
+ dmac_map_area((void *)sctx->dst_addr, count, DMA_FROM_DEVICE);
+ outer_clean_range((unsigned long)dst, (unsigned long)dst + count);
+#endif
+#endif
+
+ for (i = 0; i < 100; i++) {
+ ret = s5p_ace_aes_engine_start(sctx, dst, src, count, 1);
+ if (ret != -EBUSY)
+ break;
+ }
+ if (i == 100) {
+ printk(KERN_ERR "%s : DMA Start Failed\n", __func__);
+ return ret;
+ }
+
+run:
+#ifdef CONFIG_ACE_BC_ASYNC
+#ifndef CONFIG_ACE_BC_IRQMODE
+ if (!ret) {
+ if ((count <= 2048) && ((s5p_ace_dev.rc_depth_bc++) < 1)) {
+ sctx->directcall = 1;
+ s5p_ace_bc_task((unsigned long)&s5p_ace_dev);
+ return ret;
+ }
+ }
+#endif
+
+ if (sctx->dma_size) {
+ if (PageHighMem(sg_page(sctx->in_sg)))
+ crypto_kunmap(sctx->src_addr, crypto_kmap_type(0));
+ if (PageHighMem(sg_page(sctx->out_sg)))
+ crypto_kunmap(sctx->dst_addr, crypto_kmap_type(1));
+ }
+
+#ifndef CONFIG_ACE_BC_IRQMODE
+ if (!ret)
+ tasklet_schedule(&dev->task_bc);
+#endif
+#endif
+ return ret;
+}
+
+static int s5p_ace_aes_crypt_dma_wait(struct s5p_ace_device *dev)
+{
+ struct s5p_ace_aes_ctx *sctx = dev->ctx_bc;
+ u8 *src, *dst;
+ u8 *src_lb_addr;
+ u32 lastblock;
+ int ret = 0;
+
+ S5P_ACE_DEBUG("%s\n", __func__);
+
+ src = (u8 *)page_to_phys(sg_page(sctx->in_sg));
+ src += sctx->in_sg->offset + sctx->in_ofs;
+ dst = (u8 *)page_to_phys(sg_page(sctx->out_sg));
+ dst += sctx->out_sg->offset + sctx->out_ofs;
+
+#ifdef CONFIG_ACE_BC_ASYNC
+ if (!sctx->directcall) {
+ if (PageHighMem(sg_page(sctx->in_sg))) {
+ sctx->src_addr = crypto_kmap(sg_page(sctx->in_sg),
+ crypto_kmap_type(0));
+ sctx->src_addr += sctx->in_sg->offset + sctx->in_ofs;
+ }
+
+ if (PageHighMem(sg_page(sctx->out_sg))) {
+ sctx->dst_addr = crypto_kmap(sg_page(sctx->out_sg),
+ crypto_kmap_type(1));
+ sctx->dst_addr += sctx->out_sg->offset + sctx->out_ofs;
+ }
+ }
+#endif
+
+#ifndef CONFIG_ACE_BC_IRQMODE
+ s5p_ace_aes_engine_wait(sctx, dst, src, sctx->dma_size);
+#endif
+
+#ifndef ACE_USE_ACP
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
+ dmac_inv_range((void *)sctx->dst_addr,
+ (void *)sctx->dst_addr + sctx->dma_size);
+#else
+ dmac_unmap_area((void *)sctx->dst_addr, sctx->dma_size,
+ DMA_FROM_DEVICE);
+ outer_inv_range((unsigned long)dst,
+ (unsigned long)dst + sctx->dma_size);
+#endif
+#endif
+
+ lastblock = sctx->dma_size - AES_BLOCK_SIZE;
+ if (src == dst)
+ src_lb_addr = sctx->tbuf;
+ else
+ src_lb_addr = sctx->src_addr + lastblock;
+ if (s5p_ace_aes_update_semikey(sctx, src_lb_addr,
+ sctx->dst_addr + lastblock,
+ sctx->dma_size) != 0)
+ return -EINVAL;
+
+ if (PageHighMem(sg_page(sctx->in_sg)))
+ crypto_kunmap(sctx->src_addr, crypto_kmap_type(0));
+ if (PageHighMem(sg_page(sctx->out_sg)))
+ crypto_kunmap(sctx->dst_addr, crypto_kmap_type(1));
+
+ sctx->total -= sctx->dma_size;
+
+ S5P_ACE_DEBUG("total_end: %d\n", sctx->total);
+
+ if (ret || !sctx->total) {
+ if (ret)
+ printk(KERN_NOTICE "err: %d\n", ret);
+ } else {
+ s5p_ace_sg_update(&sctx->in_sg, &sctx->in_ofs,
+ sctx->dma_size);
+ s5p_ace_sg_update(&sctx->out_sg, &sctx->out_ofs,
+ sctx->dma_size);
+ }
+
+#if defined(ACE_DEBUG_HEARTBEAT) || defined(ACE_DEBUG_WATCHDOG)
+ do_gettimeofday(×tamp[2]); /* 2: dma end */
+#endif
+
+ return ret;
+}
+
+#ifdef CONFIG_ACE_BC_ASYNC
+static int s5p_ace_handle_lock_req(struct s5p_ace_device *dev,
+ struct s5p_ace_aes_ctx *sctx,
+ struct ablkcipher_request *req, u32 encmode)
+{
+ int ret;
+
+ sctx->origin_tfm = req->base.tfm;
+ crypto_ablkcipher_set_flags(sctx->fallback_abc, 0);
+ ablkcipher_request_set_tfm(req, sctx->fallback_abc);
+
+ if (encmode == BC_MODE_ENC)
+ ret = crypto_ablkcipher_encrypt(req);
+ else
+ ret = crypto_ablkcipher_decrypt(req);
+
+ if (!test_and_set_bit(FLAGS_BC_BUSY, &s5p_ace_dev.flags)) {
+ sctx->req = req;
+ dev->ctx_bc = sctx;
+ tasklet_schedule(&dev->task_bc);
+ } else {
+ req->base.tfm = sctx->origin_tfm;
+ req->base.complete(&req->base, ret);
+ s5p_ace_clock_gating(ACE_CLOCK_OFF);
+ }
+
+ return ret;
+}
+
+static int s5p_ace_aes_handle_req(struct s5p_ace_device *dev)
+{
+ struct crypto_async_request *async_req;
+ struct crypto_async_request *backlog;
+ struct s5p_ace_aes_ctx *sctx;
+ struct s5p_ace_reqctx *rctx;
+ struct ablkcipher_request *req;
+ unsigned long flags;
+
+ if (dev->ctx_bc)
+ goto start;
+
+ S5P_ACE_DEBUG("%s\n", __func__);
+
+ spin_lock_irqsave(&s5p_ace_dev.lock, flags);
+ backlog = crypto_get_backlog(&dev->queue_bc);
+ async_req = crypto_dequeue_request(&dev->queue_bc);
+ S5P_ACE_DEBUG("[[ dequeue (%u) ]]\n", dev->queue_bc.qlen);
+ spin_unlock_irqrestore(&s5p_ace_dev.lock, flags);
+
+ if (!async_req) {
+ clear_bit(FLAGS_BC_BUSY, &dev->flags);
+ s5p_ace_clock_gating(ACE_CLOCK_OFF);
+ return 0;
+ }
+
+ if (backlog) {
+ S5P_ACE_DEBUG("backlog.\n");
+ backlog->complete(backlog, -EINPROGRESS);
+ }
+
+ S5P_ACE_DEBUG("get new req\n");
+
+ req = ablkcipher_request_cast(async_req);
+ sctx = crypto_ablkcipher_ctx(crypto_ablkcipher_reqtfm(req));
+
+#ifdef ACE_DEBUG_WATCHDOG
+ hrtimer_start(&s5p_ace_dev.watchdog_bc,
+ ns_to_ktime((u64)ACE_WATCHDOG_MS * NSEC_PER_MSEC),
+ HRTIMER_MODE_REL);
+#endif
+ rctx = ablkcipher_request_ctx(req);
+
+ if (s5p_ace_dev.flags & BIT_MASK(FLAGS_USE_SW)) {
+ clear_bit(FLAGS_BC_BUSY, &s5p_ace_dev.flags);
+ return s5p_ace_handle_lock_req(dev, sctx, req, rctx->mode);
+ }
+
+ /* assign new request to device */
+ sctx->req = req;
+ sctx->total = req->nbytes;
+ sctx->in_sg = req->src;
+ sctx->in_ofs = 0;
+ sctx->out_sg = req->dst;
+ sctx->out_ofs = 0;
+
+ if ((sctx->sfr_ctrl & ACE_AES_OPERMODE_MASK) != ACE_AES_OPERMODE_ECB)
+ memcpy(sctx->sfr_semikey, req->info, AES_BLOCK_SIZE);
+
+ s5p_ace_aes_set_encmode(sctx, rctx->mode);
+
+ dev->ctx_bc = sctx;
+
+start:
+ return s5p_ace_aes_crypt_dma_start(dev);
+}
+
+static void s5p_ace_bc_task(unsigned long data)
+{
+ struct s5p_ace_device *dev = (struct s5p_ace_device *)data;
+ struct s5p_ace_aes_ctx *sctx = dev->ctx_bc;
+ int ret = 0;
+
+ S5P_ACE_DEBUG("%s (total: %d, dma_size: %d)\n", __func__,
+ sctx->total, sctx->dma_size);
+
+ /* check if it is handled by SW or HW */
+ if (sctx->req->base.tfm ==
+ crypto_ablkcipher_tfm
+ (crypto_ablkcipher_crt(sctx->fallback_abc)->base)) {
+ sctx->req->base.tfm = sctx->origin_tfm;
+ sctx->req->base.complete(&sctx->req->base, ret);
+ dev->ctx_bc = NULL;
+ s5p_ace_aes_handle_req(dev);
+
+ return;
+ }
+
+ if (sctx->dma_size)
+ ret = s5p_ace_aes_crypt_dma_wait(dev);
+
+ if (!sctx->total) {
+ if ((sctx->sfr_ctrl & ACE_AES_OPERMODE_MASK)
+ != ACE_AES_OPERMODE_ECB)
+ memcpy(sctx->req->info, sctx->sfr_semikey,
+ AES_BLOCK_SIZE);
+ sctx->req->base.complete(&sctx->req->base, ret);
+ dev->ctx_bc = NULL;
+
+#ifdef ACE_DEBUG_WATCHDOG
+ hrtimer_cancel(&s5p_ace_dev.watchdog_bc);
+#endif
+ }
+
+ s5p_ace_aes_handle_req(dev);
+}
+
+static int s5p_ace_aes_crypt(struct ablkcipher_request *req, u32 encmode)
+{
+ struct s5p_ace_reqctx *rctx = ablkcipher_request_ctx(req);
+ unsigned long flags;
+ int ret;
+ unsigned long timeout;
+
+#ifdef ACE_DEBUG_WATCHDOG
+ do_gettimeofday(×tamp[0]); /* 0: request */
+#endif
+
+ S5P_ACE_DEBUG("%s (nbytes: 0x%x, mode: 0x%x)\n",
+ __func__, (u32)req->nbytes, encmode);
+
+ rctx->mode = encmode;
+
+ timeout = jiffies + msecs_to_jiffies(10);
+ while (time_before(jiffies, timeout)) {
+ if (s5p_ace_dev.queue_bc.list.prev != &req->base.list)
+ break;
+ udelay(1); /* wait */
+ }
+ if (s5p_ace_dev.queue_bc.list.prev == &req->base.list) {
+ printk(KERN_ERR "%s : Time Out.\n", __func__);
+ return -EAGAIN;
+ }
+
+ spin_lock_irqsave(&s5p_ace_dev.lock, flags);
+ ret = ablkcipher_enqueue_request(&s5p_ace_dev.queue_bc, req);
+ spin_unlock_irqrestore(&s5p_ace_dev.lock, flags);
+
+ S5P_ACE_DEBUG("[[ enqueue (%u) ]]\n", s5p_ace_dev.queue_bc.qlen);
+
+ s5p_ace_resume_device(&s5p_ace_dev);
+ if (!test_and_set_bit(FLAGS_BC_BUSY, &s5p_ace_dev.flags)) {
+ s5p_ace_clock_gating(ACE_CLOCK_ON);
+ s5p_ace_dev.rc_depth_bc = 0;
+ s5p_ace_aes_handle_req(&s5p_ace_dev);
+ }
+
+ return ret;
+}
+#else
+static int s5p_ace_handle_lock_req(struct s5p_ace_aes_ctx *sctx,
+ struct blkcipher_desc *desc,
+ struct scatterlist *sg_dst,
+ struct scatterlist *sg_src,
+ unsigned int size, int encmode)
+{
+ int ret;
+
+ sctx->origin_tfm = desc->tfm;
+ desc->tfm = sctx->fallback_bc;
+
+ if (encmode == BC_MODE_ENC)
+ ret = crypto_blkcipher_encrypt_iv(desc, sg_dst, sg_src, size);
+ else
+ ret = crypto_blkcipher_decrypt_iv(desc, sg_dst, sg_src, size);
+
+ desc->tfm = sctx->origin_tfm;
+
+ return ret;
+}
+
+static int s5p_ace_aes_crypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst, struct scatterlist *src,
+ unsigned int nbytes, int encmode)
+{
+ struct s5p_ace_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
+ int ret;
+
+#if defined(ACE_DEBUG_HEARTBEAT) || defined(ACE_DEBUG_WATCHDOG)
+ do_gettimeofday(×tamp[0]); /* 0: request */
+#endif
+
+#ifdef ACE_DEBUG_WATCHDOG
+ hrtimer_start(&s5p_ace_dev.watchdog_bc,
+ ns_to_ktime((u64)ACE_WATCHDOG_MS * NSEC_PER_MSEC),
+ HRTIMER_MODE_REL);
+#endif
+
+ sctx->total = nbytes;
+ sctx->in_sg = src;
+ sctx->in_ofs = 0;
+ sctx->out_sg = dst;
+ sctx->out_ofs = 0;
+
+ if ((sctx->sfr_ctrl & ACE_AES_OPERMODE_MASK) != ACE_AES_OPERMODE_ECB)
+ memcpy(sctx->sfr_semikey, desc->info, AES_BLOCK_SIZE);
+
+ s5p_ace_aes_set_encmode(sctx, encmode);
+
+ s5p_ace_resume_device(&s5p_ace_dev);
+ s5p_ace_clock_gating(ACE_CLOCK_ON);
+ local_bh_disable();
+ while (test_and_set_bit(FLAGS_BC_BUSY, &s5p_ace_dev.flags))
+ udelay(1);
+
+ if (s5p_ace_dev.flags & BIT_MASK(FLAGS_USE_SW)) {
+ clear_bit(FLAGS_BC_BUSY, &s5p_ace_dev.flags);
+ local_bh_enable();
+ return s5p_ace_handle_lock_req(sctx, desc, dst, src, nbytes,
+ encmode);
+ }
+
+ s5p_ace_dev.ctx_bc = sctx;
+
+ do {
+ ret = s5p_ace_aes_crypt_dma_start(&s5p_ace_dev);
+
+ if (sctx->dma_size)
+ ret = s5p_ace_aes_crypt_dma_wait(&s5p_ace_dev);
+ } while (sctx->total);
+
+ s5p_ace_dev.ctx_bc = NULL;
+
+ clear_bit(FLAGS_BC_BUSY, &s5p_ace_dev.flags);
+ local_bh_enable();
+ s5p_ace_clock_gating(ACE_CLOCK_OFF);
+
+ if ((sctx->sfr_ctrl & ACE_AES_OPERMODE_MASK) != ACE_AES_OPERMODE_ECB)
+ memcpy(desc->info, sctx->sfr_semikey, AES_BLOCK_SIZE);
+
+#ifdef ACE_DEBUG_WATCHDOG
+ hrtimer_cancel(&s5p_ace_dev.watchdog_bc);
+#endif
+
+ return ret;
+}
+#endif
+
+static int s5p_ace_aes_set_key(struct s5p_ace_aes_ctx *sctx, const u8 *key,
+ unsigned int key_len)
+{
+ memcpy(sctx->sfr_key, key, key_len);
+ crypto_blkcipher_setkey(sctx->fallback_bc, key, key_len);
+
+#ifdef CONFIG_ACE_BC_ASYNC
+ crypto_ablkcipher_setkey(sctx->fallback_abc, key, key_len);
+#endif
+
+ return 0;
+}
+
+#ifdef CONFIG_ACE_BC_ASYNC
+static int s5p_ace_ecb_aes_set_key(struct crypto_ablkcipher *tfm, const u8 *key,
+ unsigned int key_len)
+{
+ struct s5p_ace_aes_ctx *sctx = crypto_ablkcipher_ctx(tfm);
+ s5p_ace_aes_set_cipher(sctx, MI_AES_ECB, key_len * 8);
+ return s5p_ace_aes_set_key(sctx, key, key_len);
+}
+
+static int s5p_ace_cbc_aes_set_key(struct crypto_ablkcipher *tfm, const u8 *key,
+ unsigned int key_len)
+{
+ struct s5p_ace_aes_ctx *sctx = crypto_ablkcipher_ctx(tfm);
+ s5p_ace_aes_set_cipher(sctx, MI_AES_CBC, key_len * 8);
+ return s5p_ace_aes_set_key(sctx, key, key_len);
+}
+
+static int s5p_ace_ctr_aes_set_key(struct crypto_ablkcipher *tfm, const u8 *key,
+ unsigned int key_len)
+{
+ struct s5p_ace_aes_ctx *sctx = crypto_ablkcipher_ctx(tfm);
+ s5p_ace_aes_set_cipher(sctx, MI_AES_CTR, key_len * 8);
+ return s5p_ace_aes_set_key(sctx, key, key_len);
+}
+
+static int s5p_ace_ecb_aes_encrypt(struct ablkcipher_request *req)
+{
+ return s5p_ace_aes_crypt(req, BC_MODE_ENC);
+}
+
+static int s5p_ace_ecb_aes_decrypt(struct ablkcipher_request *req)
+{
+ return s5p_ace_aes_crypt(req, BC_MODE_DEC);
+}
+
+static int s5p_ace_cbc_aes_encrypt(struct ablkcipher_request *req)
+{
+ return s5p_ace_aes_crypt(req, BC_MODE_ENC);
+}
+
+static int s5p_ace_cbc_aes_decrypt(struct ablkcipher_request *req)
+{
+ return s5p_ace_aes_crypt(req, BC_MODE_DEC);
+}
+
+static int s5p_ace_ctr_aes_encrypt(struct ablkcipher_request *req)
+{
+ return s5p_ace_aes_crypt(req, BC_MODE_ENC);
+}
+
+static int s5p_ace_ctr_aes_decrypt(struct ablkcipher_request *req)
+{
+ return s5p_ace_aes_crypt(req, BC_MODE_DEC);
+}
+#else
+static int s5p_ace_ecb_aes_set_key(struct crypto_tfm *tfm, const u8 *key,
+ unsigned int key_len)
+{
+ struct s5p_ace_aes_ctx *sctx = crypto_tfm_ctx(tfm);
+ s5p_ace_aes_set_cipher(sctx, MI_AES_ECB, key_len * 8);
+ return s5p_ace_aes_set_key(sctx, key, key_len);
+}
+
+static int s5p_ace_cbc_aes_set_key(struct crypto_tfm *tfm, const u8 *key,
+ unsigned int key_len)
+{
+ struct s5p_ace_aes_ctx *sctx = crypto_tfm_ctx(tfm);
+ s5p_ace_aes_set_cipher(sctx, MI_AES_CBC, key_len * 8);
+ return s5p_ace_aes_set_key(sctx, key, key_len);
+}
+
+static int s5p_ace_ctr_aes_set_key(struct crypto_tfm *tfm, const u8 *key,
+ unsigned int key_len)
+{
+ struct s5p_ace_aes_ctx *sctx = crypto_tfm_ctx(tfm);
+ s5p_ace_aes_set_cipher(sctx, MI_AES_CTR, key_len * 8);
+ return s5p_ace_aes_set_key(sctx, key, key_len);
+}
+
+static int s5p_ace_ecb_aes_encrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst, struct scatterlist *src,
+ unsigned int nbytes)
+{
+ return s5p_ace_aes_crypt(desc, dst, src, nbytes, BC_MODE_ENC);
+}
+
+static int s5p_ace_ecb_aes_decrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst, struct scatterlist *src,
+ unsigned int nbytes)
+{
+ return s5p_ace_aes_crypt(desc, dst, src, nbytes, BC_MODE_DEC);
+}
+
+static int s5p_ace_cbc_aes_encrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst, struct scatterlist *src,
+ unsigned int nbytes)
+{
+ return s5p_ace_aes_crypt(desc, dst, src, nbytes, BC_MODE_ENC);
+}
+
+static int s5p_ace_cbc_aes_decrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst, struct scatterlist *src,
+ unsigned int nbytes)
+{
+ return s5p_ace_aes_crypt(desc, dst, src, nbytes, BC_MODE_DEC);
+}
+
+static int s5p_ace_ctr_aes_encrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst, struct scatterlist *src,
+ unsigned int nbytes)
+{
+ return s5p_ace_aes_crypt(desc, dst, src, nbytes, BC_MODE_ENC);
+}
+
+static int s5p_ace_ctr_aes_decrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst, struct scatterlist *src,
+ unsigned int nbytes)
+{
+ return s5p_ace_aes_crypt(desc, dst, src, nbytes, BC_MODE_DEC);
+}
+#endif
+
+static int s5p_ace_cra_init_tfm(struct crypto_tfm *tfm)
+{
+ const char *name = tfm->__crt_alg->cra_name;
+ struct s5p_ace_aes_ctx *sctx = crypto_tfm_ctx(tfm);
+
+ sctx->fallback_bc = crypto_alloc_blkcipher(name, 0,
+ CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK);
+
+ if (IS_ERR(sctx->fallback_bc)) {
+ printk(KERN_ERR "Error allocating fallback algo %s\n", name);
+ return PTR_ERR(sctx->fallback_bc);
+ }
+#ifdef CONFIG_ACE_BC_ASYNC
+ tfm->crt_ablkcipher.reqsize = sizeof(struct s5p_ace_reqctx);
+ sctx->fallback_abc = crypto_alloc_ablkcipher(name, 0,
+ CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK);
+
+ if (IS_ERR(sctx->fallback_abc)) {
+ printk(KERN_ERR "Error allocating abc fallback algo %s\n",
+ name);
+ return PTR_ERR(sctx->fallback_abc);
+ }
+
+#endif
+ S5P_ACE_DEBUG("%s\n", __func__);
+
+ return 0;
+}
+
+static void s5p_ace_cra_exit_tfm(struct crypto_tfm *tfm)
+{
+ struct s5p_ace_aes_ctx *sctx = crypto_tfm_ctx(tfm);
+
+ crypto_free_blkcipher(sctx->fallback_bc);
+ sctx->fallback_bc = NULL;
+
+#ifdef CONFIG_ACE_BC_ASYNC
+ crypto_free_ablkcipher(sctx->fallback_abc);
+ sctx->fallback_abc = NULL;
+#endif
+
+ S5P_ACE_DEBUG("%s\n", __func__);
+}
+
+static struct crypto_alg algs_bc[] = {
+ {
+ .cra_name = "ecb(aes)",
+ .cra_driver_name = "ecb-aes-s5p-ace",
+ .cra_priority = 300,
+#ifdef CONFIG_ACE_BC_ASYNC
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER
+ | CRYPTO_ALG_ASYNC,
+#else
+ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
+#endif
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct s5p_ace_aes_ctx),
+ .cra_alignmask = 0,
+#ifdef CONFIG_ACE_BC_ASYNC
+ .cra_type = &crypto_ablkcipher_type,
+#else
+ .cra_type = &crypto_blkcipher_type,
+#endif
+ .cra_module = THIS_MODULE,
+ .cra_init = s5p_ace_cra_init_tfm,
+ .cra_exit = s5p_ace_cra_exit_tfm,
+#ifdef CONFIG_ACE_BC_ASYNC
+ .cra_ablkcipher = {
+#else
+ .cra_blkcipher = {
+#endif
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .setkey = s5p_ace_ecb_aes_set_key,
+ .encrypt = s5p_ace_ecb_aes_encrypt,
+ .decrypt = s5p_ace_ecb_aes_decrypt,
+ }
+ },
+ {
+ .cra_name = "cbc(aes)",
+ .cra_driver_name = "cbc-aes-s5p-ace",
+ .cra_priority = 300,
+#ifdef CONFIG_ACE_BC_ASYNC
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER
+ | CRYPTO_ALG_ASYNC,
+#else
+ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
+#endif
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct s5p_ace_aes_ctx),
+ .cra_alignmask = 0,
+#ifdef CONFIG_ACE_BC_ASYNC
+ .cra_type = &crypto_ablkcipher_type,
+#else
+ .cra_type = &crypto_blkcipher_type,
+#endif
+ .cra_module = THIS_MODULE,
+ .cra_init = s5p_ace_cra_init_tfm,
+ .cra_exit = s5p_ace_cra_exit_tfm,
+#ifdef CONFIG_ACE_BC_ASYNC
+ .cra_ablkcipher = {
+#else
+ .cra_blkcipher = {
+#endif
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .ivsize = AES_BLOCK_SIZE,
+ .setkey = s5p_ace_cbc_aes_set_key,
+ .encrypt = s5p_ace_cbc_aes_encrypt,
+ .decrypt = s5p_ace_cbc_aes_decrypt,
+ }
+ },
+ {
+ .cra_name = "ctr(aes)",
+ .cra_driver_name = "ctr-aes-s5p-ace",
+ .cra_priority = 300,
+#ifdef CONFIG_ACE_BC_ASYNC
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER
+ | CRYPTO_ALG_ASYNC,
+#else
+ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
+#endif
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct s5p_ace_aes_ctx),
+ .cra_alignmask = 0,
+#ifdef CONFIG_ACE_BC_ASYNC
+ .cra_type = &crypto_ablkcipher_type,
+#else
+ .cra_type = &crypto_blkcipher_type,
+#endif
+ .cra_module = THIS_MODULE,
+ .cra_init = s5p_ace_cra_init_tfm,
+ .cra_exit = s5p_ace_cra_exit_tfm,
+#ifdef CONFIG_ACE_BC_ASYNC
+ .cra_ablkcipher = {
+#else
+ .cra_blkcipher = {
+#endif
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .ivsize = AES_BLOCK_SIZE,
+ .setkey = s5p_ace_ctr_aes_set_key,
+ .encrypt = s5p_ace_ctr_aes_encrypt,
+ .decrypt = s5p_ace_ctr_aes_decrypt,
+ }
+ }
+};
+
+#define TYPE_HASH_SHA1 0
+#define TYPE_HASH_SHA256 1
+
+#if defined(CONFIG_ACE_HASH_SHA1) || defined(CONFIG_ACE_HASH_SHA256)
+struct s5p_ace_hash_ctx {
+ u32 type;
+ u32 prelen_high;
+ u32 prelen_low;
+
+ u32 buflen;
+ u8 buffer[SHA256_BLOCK_SIZE];
+
+ u32 state[SHA256_DIGEST_SIZE / 4];
+
+ u32 sw_init;
+
+ struct shash_desc sw_desc;
+ struct sha256_state dummy;
+};
+
+/*
+ * out == NULL - This is not a final message block.
+ * Intermediate value is stored at pCtx->digest.
+ * out != NULL - This is a final message block.
+ * Digest value will be stored at out.
+ */
+static int s5p_ace_sha_engine(struct s5p_ace_hash_ctx *sctx,
+ u8 *out, const u8* in, u32 len)
+{
+ u32 reg;
+ u32 *buffer;
+ u32 block_size, digest_size;
+ u8 *in_phys;
+ int transformmode = 0;
+
+ S5P_ACE_DEBUG("Out: 0x%08X, In: 0x%08X, Len: %d\n",
+ (u32)out, (u32)in, len);
+ S5P_ACE_DEBUG("PreLen_Hi: %u, PreLen_Lo: %u\n",
+ sctx->prelen_high, sctx->prelen_low);
+
+ block_size = (sctx->type == TYPE_HASH_SHA1) ?
+ SHA1_BLOCK_SIZE : SHA256_BLOCK_SIZE;
+ digest_size = (sctx->type == TYPE_HASH_SHA1) ?
+ SHA1_DIGEST_SIZE : SHA256_DIGEST_SIZE;
+
+ if (out == NULL) {
+ if (len == 0) {
+ return 0;
+ } else if (len < digest_size) {
+ printk(KERN_ERR "%s: Invalid input\n", __func__);
+ return -EINVAL;
+ }
+ transformmode = 1;
+ }
+
+ if (len == 0) {
+ S5P_ACE_DEBUG("%s: Workaround for empty input\n", __func__);
+
+ memset(sctx->buffer, 0, block_size - 8);
+ sctx->buffer[0] = 0x80;
+ reg = cpu_to_be32(sctx->prelen_high);
+ memcpy(sctx->buffer + block_size - 8, ®, 4);
+ reg = cpu_to_be32(sctx->prelen_low);
+ memcpy(sctx->buffer + block_size - 4, ®, 4);
+
+ in = sctx->buffer;
+ len = block_size;
+ transformmode = 1;
+ }
+
+ if ((void *)in < high_memory) {
+ in_phys = (u8 *)virt_to_phys((void*)in);
+ } else {
+ struct page *page;
+ S5P_ACE_DEBUG("%s: high memory - 0x%08x\n", __func__, (u32)in);
+ page = vmalloc_to_page(in);
+ if (!page)
+ printk(KERN_ERR "ERROR: %s: Null page\n", __func__);
+ in_phys = (u8 *)page_to_phys(page);
+ in_phys += ((u32)in & ~PAGE_MASK);
+ }
+
+ /* Flush HRDMA */
+ s5p_ace_write_sfr(ACE_FC_HRDMAC, ACE_FC_HRDMACFLUSH_ON);
+ reg = ACE_FC_HRDMACFLUSH_OFF;
+ if (s5p_ace_dev.cputype == TYPE_S5PV210)
+ reg |= ACE_FC_HRDMACSWAP_ON;
+
+#ifdef ACE_USE_ACP
+ reg |= ACE_ARCACHE << ACE_FC_HRDMACARCACHE_OFS;
+#endif
+ s5p_ace_write_sfr(ACE_FC_HRDMAC, reg);
+
+ /* Set byte swap of data in */
+ if (s5p_ace_dev.cputype == TYPE_EXYNOS4)
+ s5p_ace_write_sfr(ACE_HASH_BYTESWAP, ACE_HASH_SWAPDI_ON |
+ ACE_HASH_SWAPDO_ON | ACE_HASH_SWAPIV_ON);
+ else
+ s5p_ace_write_sfr(ACE_HASH_BYTESWAP,
+ ACE_HASH_SWAPDO_ON | ACE_HASH_SWAPIV_ON);
+
+ /* Select Hash input mux as external source */
+ reg = s5p_ace_read_sfr(ACE_FC_FIFOCTRL);
+ reg = (reg & ~ACE_FC_SELHASH_MASK) | ACE_FC_SELHASH_EXOUT;
+ s5p_ace_write_sfr(ACE_FC_FIFOCTRL, reg);
+
+ /* Set Hash as SHA1 or SHA256 and start Hash engine */
+ reg = (sctx->type == TYPE_HASH_SHA1) ?
+ ACE_HASH_ENGSEL_SHA1HASH : ACE_HASH_ENGSEL_SHA256HASH;
+ reg |= ACE_HASH_STARTBIT_ON;
+ if ((sctx->prelen_low | sctx->prelen_high) != 0) {
+ reg |= ACE_HASH_USERIV_EN;
+ buffer = (u32 *)sctx->state;
+ s5p_ace_write_sfr(ACE_HASH_IV1, buffer[0]);
+ s5p_ace_write_sfr(ACE_HASH_IV2, buffer[1]);
+ s5p_ace_write_sfr(ACE_HASH_IV3, buffer[2]);
+ s5p_ace_write_sfr(ACE_HASH_IV4, buffer[3]);
+ s5p_ace_write_sfr(ACE_HASH_IV5, buffer[4]);
+
+ if (sctx->type == TYPE_HASH_SHA256) {
+ s5p_ace_write_sfr(ACE_HASH_IV6, buffer[5]);
+ s5p_ace_write_sfr(ACE_HASH_IV7, buffer[6]);
+ s5p_ace_write_sfr(ACE_HASH_IV8, buffer[7]);
+ }
+ }
+ s5p_ace_write_sfr(ACE_HASH_CONTROL, reg);
+
+ /* Enable FIFO mode */
+ s5p_ace_write_sfr(ACE_HASH_FIFO_MODE, ACE_HASH_FIFO_ON);
+
+ /* Clean data cache */
+#ifndef ACE_USE_ACP
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
+ dmac_clean_range((void *)in, (void *)in + len);
+#else
+ dmac_map_area((void *)in, len, DMA_TO_DEVICE);
+ outer_clean_range((unsigned long)in_phys, (unsigned long)in_phys + len);
+#endif
+#endif
+
+ if (transformmode) {
+ /* Set message length */
+ s5p_ace_write_sfr(ACE_HASH_MSGSIZE_LOW, 0);
+ s5p_ace_write_sfr(ACE_HASH_MSGSIZE_HIGH, 0x80000000);
+
+ /* Set pre-message length */
+ s5p_ace_write_sfr(ACE_HASH_PRELEN_LOW, 0);
+ s5p_ace_write_sfr(ACE_HASH_PRELEN_HIGH, 0);
+ } else {
+ /* Set message length */
+ s5p_ace_write_sfr(ACE_HASH_MSGSIZE_LOW, len);
+ s5p_ace_write_sfr(ACE_HASH_MSGSIZE_HIGH, 0);
+
+ /* Set pre-message length */
+ s5p_ace_write_sfr(ACE_HASH_PRELEN_LOW, sctx->prelen_low);
+ s5p_ace_write_sfr(ACE_HASH_PRELEN_HIGH, sctx->prelen_high);
+ }
+
+ /* Set HRDMA */
+ s5p_ace_write_sfr(ACE_FC_HRDMAS, (u32)in_phys);
+ s5p_ace_write_sfr(ACE_FC_HRDMAL, len);
+
+ while (!(s5p_ace_read_sfr(ACE_FC_INTPEND) & ACE_FC_HRDMA))
+ ; /* wait */
+ s5p_ace_write_sfr(ACE_FC_INTPEND, ACE_FC_HRDMA);
+
+ /*while ((s5p_ace_read_sfr(ACE_HASH_STATUS) & ACE_HASH_BUFRDY_MASK)
+ == ACE_HASH_BUFRDY_OFF); */
+
+ if (transformmode) {
+ /* Set Pause bit */
+ s5p_ace_write_sfr(ACE_HASH_CONTROL2, ACE_HASH_PAUSE_ON);
+
+ while ((s5p_ace_read_sfr(ACE_HASH_STATUS)
+ & ACE_HASH_PARTIALDONE_MASK)
+ == ACE_HASH_PARTIALDONE_OFF)
+ ; /* wait */
+ s5p_ace_write_sfr(ACE_HASH_STATUS, ACE_HASH_PARTIALDONE_ON);
+
+ if (out == NULL) {
+ /* Update chaining variables */
+ buffer = (u32 *)sctx->state;
+
+ /* Update pre-message length */
+ /* Note that the unit of pre-message length is a BIT! */
+ sctx->prelen_low += (len << 3);
+ if (sctx->prelen_low < len)
+ sctx->prelen_high++;
+ sctx->prelen_high += (len >> 29);
+ } else {
+ /* Read hash result */
+ buffer = (u32 *)out;
+ }
+ } else {
+ while ((s5p_ace_read_sfr(ACE_HASH_STATUS)
+ & ACE_HASH_MSGDONE_MASK)
+ == ACE_HASH_MSGDONE_OFF)
+ ; /* wait */
+ s5p_ace_write_sfr(ACE_HASH_STATUS, ACE_HASH_MSGDONE_ON);
+
+ /* Read hash result */
+ buffer = (u32 *)out;
+ }
+ buffer[0] = s5p_ace_read_sfr(ACE_HASH_RESULT1);
+ buffer[1] = s5p_ace_read_sfr(ACE_HASH_RESULT2);
+ buffer[2] = s5p_ace_read_sfr(ACE_HASH_RESULT3);
+ buffer[3] = s5p_ace_read_sfr(ACE_HASH_RESULT4);
+ buffer[4] = s5p_ace_read_sfr(ACE_HASH_RESULT5);
+
+ if (sctx->type == TYPE_HASH_SHA256) {
+ buffer[5] = s5p_ace_read_sfr(ACE_HASH_RESULT6);
+ buffer[6] = s5p_ace_read_sfr(ACE_HASH_RESULT7);
+ buffer[7] = s5p_ace_read_sfr(ACE_HASH_RESULT8);
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_ACE_HASH_ASYNC
+static int s5p_ace_sha1_init(struct ahash_request *req)
+{
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct s5p_ace_hash_ctx *sctx = crypto_ahash_ctx(tfm);
+
+ sctx->prelen_high = sctx->prelen_low = 0;
+ sctx->buflen = 0;
+
+ /* To Do */
+
+ return 0;
+}
+
+static int s5p_ace_sha1_update(struct ahash_request *req)
+{
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct s5p_ace_hash_ctx *sctx = crypto_ahash_ctx(tfm);
+
+ /* To Do */
+
+ return 0;
+}
+
+static int s5p_ace_sha1_final(struct ahash_request *req)
+{
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct s5p_ace_hash_ctx *sctx = crypto_ahash_ctx(tfm);
+
+ /* To Do */
+
+ return 0;
+}
+
+static int s5p_ace_sha1_finup(struct ahash_request *req)
+{
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct s5p_ace_hash_ctx *sctx = crypto_ahash_ctx(tfm);
+
+ /* To Do */
+
+ return 0;
+}
+
+static int s5p_ace_sha1_digest(struct ahash_request *req)
+{
+ s5p_ace_sha1_init(req);
+ s5p_ace_sha1_update(req);
+ s5p_ace_sha1_final(req);
+
+ return 0;
+}
+#else
+static void sha1_export_ctx_to_sw(struct shash_desc *desc)
+{
+ struct s5p_ace_hash_ctx *sctx = shash_desc_ctx(desc);
+ struct sha1_state *sw_ctx = shash_desc_ctx(&sctx->sw_desc);
+ int i;
+
+ if (sctx->prelen_low == 0 && sctx->prelen_high == 0)
+ crypto_shash_alg(&sw_tfm[sctx->type])
+ ->init(&sctx->sw_desc);
+ else {
+ for (i = 0; i < SHA1_DIGEST_SIZE/4; i++)
+ sw_ctx->state[i] = be32_to_cpu(sctx->state[i]);
+ }
+
+ sw_ctx->count = (((u64)sctx->prelen_high << 29) |
+ (sctx->prelen_low >> 3)) + sctx->buflen;
+
+ if (sctx->buflen)
+ memcpy(sw_ctx->buffer, sctx->buffer, sctx->buflen);
+}
+
+static void sha256_export_ctx_to_sw(struct shash_desc *desc)
+{
+ struct s5p_ace_hash_ctx *sctx = shash_desc_ctx(desc);
+ struct sha256_state *sw_ctx = shash_desc_ctx(&sctx->sw_desc);
+ int i;
+
+ if (sctx->prelen_low == 0 && sctx->prelen_high == 0)
+ crypto_shash_alg(&sw_tfm[sctx->type])
+ ->init(&sctx->sw_desc);
+ else {
+ for (i = 0; i < SHA256_DIGEST_SIZE/4; i++)
+ sw_ctx->state[i] = be32_to_cpu(sctx->state[i]);
+ }
+
+ sw_ctx->count = (((u64)sctx->prelen_high << 29) |
+ (sctx->prelen_low >> 3)) + sctx->buflen;
+
+ if (sctx->buflen)
+ memcpy(sw_ctx->buf, sctx->buffer, sctx->buflen);
+}
+
+static void sha1_import_ctx_from_sw(struct shash_desc *desc)
+{
+ struct s5p_ace_hash_ctx *sctx = shash_desc_ctx(desc);
+ struct sha1_state *sw_ctx = shash_desc_ctx(&sctx->sw_desc);
+ int i;
+
+ for (i = 0; i < SHA1_DIGEST_SIZE/4; i++)
+ sctx->state[i] = cpu_to_be32(sw_ctx->state[i]);
+
+ memcpy(sctx->buffer, sw_ctx->buffer, sw_ctx->count &
+ (SHA1_BLOCK_SIZE - 1));
+ sctx->buflen = sw_ctx->count & (SHA1_BLOCK_SIZE - 1);
+
+ sctx->prelen_low = (sw_ctx->count - sctx->buflen) << 3;
+ sctx->prelen_high = (sw_ctx->count - sctx->buflen) >> 29;
+}
+
+static void sha256_import_ctx_from_sw(struct shash_desc *desc)
+{
+ struct s5p_ace_hash_ctx *sctx = shash_desc_ctx(desc);
+ struct sha256_state *sw_ctx = shash_desc_ctx(&sctx->sw_desc);
+ int i;
+
+ for (i = 0; i < SHA256_DIGEST_SIZE/4; i++)
+ sctx->state[i] = cpu_to_be32(sw_ctx->state[i]);
+
+ memcpy(sctx->buffer, sw_ctx->buf, sw_ctx->count &
+ (SHA256_BLOCK_SIZE - 1));
+ sctx->buflen = sw_ctx->count & (SHA256_BLOCK_SIZE - 1);
+
+ sctx->prelen_low = (sw_ctx->count - sctx->buflen) << 3;
+ sctx->prelen_high = (sw_ctx->count - sctx->buflen) >> 29;
+}
+
+static void hash_export_ctx_to_sw(struct shash_desc *desc)
+{
+ struct s5p_ace_hash_ctx *sctx = shash_desc_ctx(desc);
+ struct sha256_state *sw_ctx = shash_desc_ctx(&sctx->sw_desc);
+
+ if (!sctx->sw_init) {
+ sw_ctx = &sctx->dummy;
+ sctx->sw_init = 1;
+ if (sctx->prelen_low == 0 && sctx->prelen_high == 0 &&
+ sctx->buflen == 0) {
+ crypto_shash_alg(&sw_tfm[sctx->type])
+ ->init(&sctx->sw_desc);
+ return;
+ }
+ }
+
+ if (sctx->type == TYPE_HASH_SHA1)
+ sha1_export_ctx_to_sw(desc);
+ else
+ sha256_export_ctx_to_sw(desc);
+}
+
+static void hash_import_ctx_from_sw(struct shash_desc *desc)
+{
+ struct s5p_ace_hash_ctx *sctx = shash_desc_ctx(desc);
+
+ if (sctx->type == TYPE_HASH_SHA1)
+ sha1_import_ctx_from_sw(desc);
+ else
+ sha256_import_ctx_from_sw(desc);
+
+}
+
+static int sha_sw_update(struct shash_desc *desc, const u8 *data, unsigned
+ int len)
+{
+ struct s5p_ace_hash_ctx *sctx = shash_desc_ctx(desc);
+
+ hash_export_ctx_to_sw(desc);
+ crypto_shash_alg(&sw_tfm[sctx->type])->update(&sctx->sw_desc, data,
+ len);
+ hash_import_ctx_from_sw(desc);
+
+ return 0;
+}
+
+static int sha_sw_final(struct shash_desc *desc, u8 *out)
+{
+ struct s5p_ace_hash_ctx *sctx = shash_desc_ctx(desc);
+
+ hash_export_ctx_to_sw(desc);
+ crypto_shash_alg(&sw_tfm[sctx->type])->final(&sctx->sw_desc, out);
+ hash_import_ctx_from_sw(desc);
+
+ return 0;
+}
+
+static int sha_sw_finup(struct shash_desc *desc, const u8 *data, unsigned int
+ len, u8 *out)
+{
+ struct s5p_ace_hash_ctx *sctx = shash_desc_ctx(desc);
+
+ hash_export_ctx_to_sw(desc);
+ crypto_shash_alg(&sw_tfm[sctx->type])->update(&sctx->sw_desc, data,
+ len);
+ crypto_shash_alg(&sw_tfm[sctx->type])->final(&sctx->sw_desc, out);
+ hash_import_ctx_from_sw(desc);
+
+ return 0;
+}
+
+static int s5p_ace_sha1_init(struct shash_desc *desc)
+{
+ struct s5p_ace_hash_ctx *sctx = shash_desc_ctx(desc);
+
+ sctx->prelen_high = sctx->prelen_low = 0;
+ sctx->buflen = 0;
+ sctx->type = TYPE_HASH_SHA1;
+ sctx->sw_init = 0;
+
+ return 0;
+}
+
+static int s5p_ace_sha256_init(struct shash_desc *desc)
+{
+ struct s5p_ace_hash_ctx *sctx = shash_desc_ctx(desc);
+
+ sctx->prelen_high = sctx->prelen_low = 0;
+ sctx->buflen = 0;
+ sctx->type = TYPE_HASH_SHA256;
+ sctx->sw_init = 0;
+
+ return 0;
+}
+
+static int s5p_ace_sha_update(struct shash_desc *desc,
+ const u8 *data, unsigned int len)
+{
+ struct s5p_ace_hash_ctx *sctx = shash_desc_ctx(desc);
+ const u8 *src;
+ int ret = 0;
+ u32 partlen, tmplen, block_size;
+
+ S5P_ACE_DEBUG("%s (buflen: 0x%x, len: 0x%x)\n",
+ __func__, sctx->buflen, len);
+
+ s5p_ace_resume_device(&s5p_ace_dev);
+ local_bh_disable();
+ while (test_and_set_bit(FLAGS_HASH_BUSY, &s5p_ace_dev.flags))
+ udelay(1);
+
+ if (s5p_ace_dev.flags & BIT_MASK(FLAGS_USE_SW)) {
+ clear_bit(FLAGS_HASH_BUSY, &s5p_ace_dev.flags);
+ local_bh_enable();
+ return sha_sw_update(desc, data, len);
+ }
+
+ partlen = sctx->buflen;
+ src = data;
+
+ block_size = (sctx->type == TYPE_HASH_SHA1) ?
+ SHA1_BLOCK_SIZE : SHA256_BLOCK_SIZE;
+ s5p_ace_clock_gating(ACE_CLOCK_ON);
+
+ if (partlen != 0) {
+ if (partlen + len < block_size) {
+ memcpy(sctx->buffer + partlen, src, len);
+ sctx->buflen += len;
+ goto out;
+ } else {
+ tmplen = block_size - partlen;
+ memcpy(sctx->buffer + partlen, src, tmplen);
+
+ ret = s5p_ace_sha_engine(sctx, NULL, sctx->buffer,
+ block_size);
+ if (ret)
+ goto out;
+
+ len -= tmplen;
+ src += tmplen;
+ }
+ }
+
+ partlen = len & (block_size - 1);
+ len -= partlen;
+ if (len > 0) {
+ ret = s5p_ace_sha_engine(sctx, NULL, src, len);
+ if (ret)
+ goto out;
+ }
+
+ memcpy(sctx->buffer, src + len, partlen);
+ sctx->buflen = partlen;
+
+out:
+ s5p_ace_clock_gating(ACE_CLOCK_OFF);
+ clear_bit(FLAGS_HASH_BUSY, &s5p_ace_dev.flags);
+ local_bh_enable();
+
+ return ret;
+}
+
+static int s5p_ace_sha_final(struct shash_desc *desc, u8 *out)
+{
+ struct s5p_ace_hash_ctx *sctx = shash_desc_ctx(desc);
+
+ S5P_ACE_DEBUG("%s (buflen: 0x%x)\n", __func__, sctx->buflen);
+
+ s5p_ace_resume_device(&s5p_ace_dev);
+ local_bh_disable();
+ while (test_and_set_bit(FLAGS_HASH_BUSY, &s5p_ace_dev.flags))
+ udelay(1);
+
+ if (s5p_ace_dev.flags & BIT_MASK(FLAGS_USE_SW)) {
+ clear_bit(FLAGS_HASH_BUSY, &s5p_ace_dev.flags);
+ local_bh_enable();
+ return sha_sw_final(desc, out);
+ }
+
+ s5p_ace_clock_gating(ACE_CLOCK_ON);
+ s5p_ace_sha_engine(sctx, out, sctx->buffer, sctx->buflen);
+ s5p_ace_clock_gating(ACE_CLOCK_OFF);
+
+ /* Wipe context */
+ memset(sctx, 0, sizeof(*sctx));
+ clear_bit(FLAGS_HASH_BUSY, &s5p_ace_dev.flags);
+ local_bh_enable();
+
+ return 0;
+}
+
+static int s5p_ace_sha_finup(struct shash_desc *desc, const u8 *data,
+ unsigned int len, u8 *out)
+{
+ struct s5p_ace_hash_ctx *sctx = shash_desc_ctx(desc);
+ const u8 *src;
+ int ret = 0;
+ u32 block_size;
+
+ S5P_ACE_DEBUG("%s (buflen: 0x%x, len: 0x%x)\n",
+ __func__, sctx->buflen, len);
+
+ s5p_ace_resume_device(&s5p_ace_dev);
+ local_bh_disable();
+ while (test_and_set_bit(FLAGS_HASH_BUSY, &s5p_ace_dev.flags))
+ udelay(1);
+
+ if (s5p_ace_dev.flags & BIT_MASK(FLAGS_USE_SW)) {
+ clear_bit(FLAGS_HASH_BUSY, &s5p_ace_dev.flags);
+ local_bh_enable();
+ return sha_sw_finup(desc, data, len, out);
+ }
+
+ src = data;
+ block_size = (sctx->type == TYPE_HASH_SHA1) ?
+ SHA1_BLOCK_SIZE : SHA256_BLOCK_SIZE;
+
+ s5p_ace_clock_gating(ACE_CLOCK_ON);
+
+ if (sctx->buflen != 0) {
+ if (sctx->buflen + len <= block_size) {
+ memcpy(sctx->buffer + sctx->buflen, src, len);
+
+ len += sctx->buflen;
+ src = sctx->buffer;
+ } else {
+ u32 copylen = block_size - sctx->buflen;
+ memcpy(sctx->buffer + sctx->buflen, src, copylen);
+
+ ret = s5p_ace_sha_engine(sctx, NULL, sctx->buffer,
+ block_size);
+ if (ret)
+ goto out;
+
+ len -= copylen;
+ src += copylen;
+ }
+ }
+
+ ret = s5p_ace_sha_engine(sctx, out, src, len);
+
+out:
+ s5p_ace_clock_gating(ACE_CLOCK_OFF);
+
+ /* Wipe context */
+ memset(sctx, 0, sizeof(*sctx));
+ clear_bit(FLAGS_HASH_BUSY, &s5p_ace_dev.flags);
+ local_bh_enable();
+
+ return ret;
+}
+
+static int s5p_ace_sha1_digest(struct shash_desc *desc, const u8 *data,
+ unsigned int len, u8 *out)
+{
+ int ret;
+
+ ret = s5p_ace_sha1_init(desc);
+ if (ret)
+ return ret;
+
+ return s5p_ace_sha_finup(desc, data, len, out);
+}
+
+static int s5p_ace_sha256_digest(struct shash_desc *desc, const u8 *data,
+ unsigned int len, u8 *out)
+{
+ int ret;
+
+ ret = s5p_ace_sha256_init(desc);
+ if (ret)
+ return ret;
+
+ return s5p_ace_sha_finup(desc, data, len, out);
+}
+
+static int s5p_ace_hash_export(struct shash_desc *desc, void *out)
+{
+ struct s5p_ace_hash_ctx *sctx = shash_desc_ctx(desc);
+ memcpy(out, sctx, sizeof(*sctx));
+ return 0;
+}
+
+static int s5p_ace_hash_import(struct shash_desc *desc, const void *in)
+{
+ struct s5p_ace_hash_ctx *sctx = shash_desc_ctx(desc);
+ memcpy(sctx, in, sizeof(*sctx));
+ return 0;
+}
+#endif
+
+static int s5p_ace_hash_cra_init(struct crypto_tfm *tfm)
+{
+#ifdef CONFIG_ACE_HASH_ASYNC
+#endif
+
+ S5P_ACE_DEBUG("%s\n", __func__);
+
+ return 0;
+}
+
+static void s5p_ace_hash_cra_exit(struct crypto_tfm *tfm)
+{
+#ifdef CONFIG_ACE_HASH_ASYNC
+#endif
+
+ S5P_ACE_DEBUG("%s\n", __func__);
+}
+
+#ifdef CONFIG_ACE_HASH_ASYNC
+static struct ahash_alg algs_hash[] = {
+ {
+ .init = s5p_ace_sha1_init,
+ .update = s5p_ace_sha_update,
+ .final = s5p_ace_sha_final,
+ .finup = s5p_ace_sha_finup,
+ .digest = s5p_ace_sha1_digest,
+ .halg.digestsize = SHA1_DIGEST_SIZE,
+ .halg.base = {
+ .cra_name = "sha1",
+ .cra_driver_name = "sha1-s5p-ace",
+ .cra_priority = 200,
+ .cra_flags = CRYPTO_ALG_TYPE_AHASH
+ | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = SHA1_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct s5p_ace_hash_ctx),
+ .cra_alignmask = 0,
+ .cra_module = THIS_MODULE,
+ .cra_init = s5p_ace_hash_cra_init,
+ .cra_exit = s5p_ace_hash_cra_exit,
+ }
+ }
+};
+#else
+static struct shash_alg algs_hash[] = {
+ {
+ .digestsize = SHA1_DIGEST_SIZE,
+ .init = s5p_ace_sha1_init,
+ .update = s5p_ace_sha_update,
+ .final = s5p_ace_sha_final,
+ .finup = s5p_ace_sha_finup,
+ .digest = s5p_ace_sha1_digest,
+ .export = s5p_ace_hash_export,
+ .import = s5p_ace_hash_import,
+ .descsize = sizeof(struct s5p_ace_hash_ctx),
+ .statesize = sizeof(struct s5p_ace_hash_ctx),
+ .base = {
+ .cra_name = "sha1",
+ .cra_driver_name = "sha1-s5p-ace",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_SHASH,
+ .cra_blocksize = SHA1_BLOCK_SIZE,
+ .cra_module = THIS_MODULE,
+ .cra_init = s5p_ace_hash_cra_init,
+ .cra_exit = s5p_ace_hash_cra_exit,
+ }
+ },
+ {
+ .digestsize = SHA256_DIGEST_SIZE,
+ .init = s5p_ace_sha256_init,
+ .update = s5p_ace_sha_update,
+ .final = s5p_ace_sha_final,
+ .finup = s5p_ace_sha_finup,
+ .digest = s5p_ace_sha256_digest,
+ .export = s5p_ace_hash_export,
+ .import = s5p_ace_hash_import,
+ .descsize = sizeof(struct s5p_ace_hash_ctx),
+ .statesize = sizeof(struct s5p_ace_hash_ctx),
+ .base = {
+ .cra_name = "sha256",
+ .cra_driver_name = "sha256-s5p-ace",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_SHASH,
+ .cra_blocksize = SHA256_BLOCK_SIZE,
+ .cra_module = THIS_MODULE,
+ .cra_init = s5p_ace_hash_cra_init,
+ .cra_exit = s5p_ace_hash_cra_exit,
+ }
+ }
+};
+#endif /* CONFIG_ACE_HASH_ASYNC */
+#endif /* CONFIG_ACE_HASH_SHA1 or CONFIG_ACE_HASH_SHA256 */
+
+#if defined(CONFIG_ACE_BC_IRQMODE) || defined(CONFIG_ACE_HASH_IRQMODE)
+static irqreturn_t s5p_ace_interrupt(int irq, void *data)
+{
+ struct s5p_ace_device *dev = data;
+
+ s5p_ace_write_sfr(ACE_FC_INTPEND,
+ ACE_FC_BRDMA | ACE_FC_BTDMA | ACE_FC_HRDMA);
+
+#ifdef CONFIG_ACE_BC_IRQMODE
+ s5p_ace_write_sfr(ACE_FC_INTENCLR, ACE_FC_BRDMA | ACE_FC_BTDMA);
+
+ tasklet_schedule(&dev->task_bc);
+#endif
+
+#ifdef CONFIG_ACE_HASH_IRQMODE
+ s5p_ace_write_sfr(ACE_FC_INTENCLR, ACE_FC_HRDMA);
+#endif
+
+ return IRQ_HANDLED;
+}
+#endif
+
+int ace_s5p_get_sync_lock(void)
+{
+ unsigned long timeout;
+ int get_lock_bc = 0, get_lock_hash = 0;
+
+ timeout = jiffies + msecs_to_jiffies(10);
+ while (time_before(jiffies, timeout)) {
+ if (!test_and_set_bit(FLAGS_BC_BUSY, &s5p_ace_dev.flags)) {
+ get_lock_bc = 1;
+ break;
+ }
+ udelay(1);
+ }
+
+ timeout = jiffies + msecs_to_jiffies(10);
+ while (time_before(jiffies, timeout)) {
+ if (!test_and_set_bit(FLAGS_HASH_BUSY, &s5p_ace_dev.flags)) {
+ get_lock_hash = 1;
+ break;
+ }
+ udelay(1);
+ }
+
+ /* set lock flag */
+ if (get_lock_bc && get_lock_hash)
+ set_bit(FLAGS_USE_SW, &s5p_ace_dev.flags);
+
+ if (get_lock_bc)
+ clear_bit(FLAGS_BC_BUSY, &s5p_ace_dev.flags);
+ if (get_lock_hash)
+ clear_bit(FLAGS_HASH_BUSY, &s5p_ace_dev.flags);
+
+ if (!(get_lock_bc && get_lock_hash))
+ return -EBUSY;
+
+ s5p_ace_clock_gating(ACE_CLOCK_ON);
+
+ return 0;
+}
+
+int ace_s5p_release_sync_lock(void)
+{
+ /* clear lock flag */
+ if (!test_and_clear_bit(FLAGS_USE_SW, &s5p_ace_dev.flags))
+ return -ENOLCK;
+
+ clear_bit(FLAGS_USE_SW, &s5p_ace_dev.flags);
+ s5p_ace_clock_gating(ACE_CLOCK_OFF);
+
+ return 0;
+}
+
+static int __init s5p_ace_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct s5p_ace_device *s5p_adt = &s5p_ace_dev;
+ int i, j, k, m;
+ int ret;
+
+#if defined(ACE_DEBUG_HEARTBEAT) || defined(ACE_DEBUG_WATCHDOG)
+ do_gettimeofday(×tamp_base);
+ for (i = 0; i < 5; i++)
+ do_gettimeofday(×tamp[i]);
+#endif
+
+ memset(s5p_adt, 0, sizeof(*s5p_adt));
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "failed to get platform resource\n");
+ return -ENOENT;
+ }
+
+ s5p_adt->ace_base = ioremap(res->start, resource_size(res));
+ if (s5p_adt->ace_base == NULL) {
+ dev_err(&pdev->dev, "failed to remap register block\n");
+ ret = -ENOMEM;
+ goto err_mem1;
+ }
+
+ s5p_adt->clock = clk_get(&pdev->dev, "secss");
+ if (IS_ERR(s5p_adt->clock)) {
+ dev_err(&pdev->dev, "failed to find clock source\n");
+ ret = -EBUSY;
+ goto err_clk;
+ }
+ s5p_ace_init_clock_gating();
+ s5p_adt->cputype = platform_get_device_id(pdev)->driver_data;
+
+#if defined(CONFIG_ACE_BC_IRQMODE) || defined(CONFIG_ACE_HASH_IRQMODE)
+ s5p_adt->irq = platform_get_irq(pdev, 0);
+ if (s5p_adt->irq < 0) {
+ dev_err(&pdev->dev, "Failed to get irq#\n");
+ s5p_adt->irq = 0;
+ ret = -ENODEV;
+ goto err_irq;
+ }
+ ret = request_irq(s5p_adt->irq, s5p_ace_interrupt, 0,
+ S5P_ACE_DRIVER_NAME, (void *)s5p_adt);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to request IRQ%d: err: %d.\n",
+ s5p_adt->irq, ret);
+ s5p_adt->irq = 0;
+ ret = -ENODEV;
+ goto err_irq;
+ }
+#endif
+
+#ifdef ACE_USE_ACP
+ s5p_adt->sss_usercon = ioremap(PA_SSS_USER_CON & PAGE_MASK, SZ_4K);
+ if (s5p_adt->sss_usercon == NULL) {
+ dev_err(&pdev->dev, "failed to remap register SSS_USER_CON\n");
+ ret = -EBUSY;
+ goto err_mem2;
+ }
+
+ /* Set ARUSER[12:8] and AWUSER[4:0] */
+ writel(0x101, s5p_adt->sss_usercon
+ + (PA_SSS_USER_CON & (PAGE_SIZE - 1)));
+#endif
+
+ spin_lock_init(&s5p_adt->lock);
+ s5p_adt->flags = 0;
+ hrtimer_init(&s5p_adt->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ s5p_adt->timer.function = s5p_ace_timer_func;
+ INIT_WORK(&s5p_adt->work, s5p_ace_deferred_clock_disable);
+#ifdef ACE_DEBUG_HEARTBEAT
+ hrtimer_init(&s5p_adt->heartbeat, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ s5p_adt->heartbeat.function = s5p_ace_heartbeat_func;
+ hrtimer_start(&s5p_ace_dev.heartbeat,
+ ns_to_ktime((u64)ACE_HEARTBEAT_MS * NSEC_PER_MSEC),
+ HRTIMER_MODE_REL);
+#endif
+#ifdef ACE_DEBUG_WATCHDOG
+ hrtimer_init(&s5p_adt->watchdog_bc, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ s5p_adt->watchdog_bc.function = s5p_ace_watchdog_bc_func;
+#endif
+
+#ifdef CONFIG_ACE_BC_ASYNC
+ crypto_init_queue(&s5p_adt->queue_bc, 1);
+ tasklet_init(&s5p_adt->task_bc, s5p_ace_bc_task,
+ (unsigned long)s5p_adt);
+#endif
+
+#ifdef CONFIG_ACE_HASH_ASYNC
+ crypto_init_queue(&s5p_adt->queue_hash, 1);
+ tasklet_init(&s5p_adt->task_hash, s5p_ace_hash_task,
+ (unsigned long)s5p_adt);
+#endif
+
+ for (i = 0; i < ARRAY_SIZE(algs_bc); i++) {
+ INIT_LIST_HEAD(&algs_bc[i].cra_list);
+ algs_bc[i].cra_flags |= CRYPTO_ALG_NEED_FALLBACK;
+ ret = crypto_register_alg(&algs_bc[i]);
+ if (ret)
+ goto err_reg_bc;
+ printk(KERN_INFO "ACE: %s\n", algs_bc[i].cra_driver_name);
+ }
+
+#if defined(CONFIG_ACE_HASH_SHA1) || defined(CONFIG_ACE_HASH_SHA256)
+ fallback_hash = (struct crypto_hash **)
+ kmalloc(sizeof(struct crypto_hash *) *
+ ARRAY_SIZE(algs_hash), GFP_KERNEL);
+ sw_tfm = (struct crypto_shash *) kmalloc(sizeof(struct crypto_shash)
+ * ARRAY_SIZE(algs_hash),
+ GFP_KERNEL);
+
+ for (m = 0; m < ARRAY_SIZE(algs_hash); m++) {
+ fallback_hash[m] =
+ crypto_alloc_hash(algs_hash[m].base.cra_name, 0,
+ CRYPTO_ALG_ASYNC);
+
+ if (IS_ERR(fallback_hash[m])) {
+ printk(KERN_ERR "failed to load transform for %s: %ld\n",
+ algs_hash[m].base.cra_name,
+ PTR_ERR(fallback_hash[m]));
+ goto err_fallback_hash;
+ }
+
+ sw_tfm[m].base.__crt_alg = fallback_hash[m]->base.__crt_alg;
+ }
+
+ for (j = 0; j < ARRAY_SIZE(algs_hash); j++) {
+#ifdef CONFIG_ACE_HASH_ASYNC
+ ret = crypto_register_ahash(&algs_hash[j]);
+#else
+ ret = crypto_register_shash(&algs_hash[j]);
+#endif
+ if (ret)
+ goto err_reg_hash;
+#ifdef CONFIG_ACE_HASH_ASYNC
+ printk(KERN_INFO "ACE: %s\n",
+ algs_hash[j].halg.base.cra_driver_name);
+#else
+ printk(KERN_INFO "ACE: %s\n",
+ algs_hash[j].base.cra_driver_name);
+#endif
+ }
+#endif
+
+ secmem_ftn.lock = &ace_s5p_get_sync_lock;
+ secmem_ftn.release = &ace_s5p_release_sync_lock;
+ secmem_crypto_register(&secmem_ftn);
+
+ printk(KERN_NOTICE "ACE driver is initialized\n");
+
+ return 0;
+
+#if defined(CONFIG_ACE_HASH_SHA1) || defined(CONFIG_ACE_HASH_SHA256)
+err_reg_hash:
+ for (k = 0; k < j; k++)
+#ifdef CONFIG_ACE_HASH_ASYNC
+ crypto_unregister_ahash(&algs_hash[k]);
+#else
+ crypto_unregister_shash(&algs_hash[k]);
+#endif
+err_fallback_hash:
+ kfree(sw_tfm);
+ for (k = 0; k < m; k++)
+ crypto_free_hash(fallback_hash[k]);
+ kfree(fallback_hash);
+#endif
+err_reg_bc:
+ for (k = 0; k < i; k++)
+ crypto_unregister_alg(&algs_bc[k]);
+#ifdef CONFIG_ACE_BC_ASYNC
+ tasklet_kill(&s5p_adt->task_bc);
+#endif
+#ifdef CONFIG_ACE_HASH_ASYNC
+ tasklet_kill(&s5p_adt->task_hash);
+#endif
+#ifdef ACE_USE_ACP
+ iounmap(s5p_adt->sss_usercon);
+err_mem2:
+#endif
+#if defined(CONFIG_ACE_BC_IRQMODE) || defined(CONFIG_ACE_HASH_IRQMODE)
+err_irq:
+ free_irq(s5p_adt->irq, (void *)s5p_adt);
+ s5p_adt->irq = 0;
+#endif
+err_clk:
+ iounmap(s5p_adt->ace_base);
+ s5p_adt->ace_base = NULL;
+err_mem1:
+
+ printk(KERN_ERR "ACE driver initialization failed.\n");
+
+ return ret;
+}
+
+static int s5p_ace_remove(struct platform_device *dev)
+{
+ struct s5p_ace_device *s5p_adt = &s5p_ace_dev;
+ int i;
+
+#ifdef ACE_DEBUG_HEARTBEAT
+ hrtimer_cancel(&s5p_adt->heartbeat);
+#endif
+
+#if defined(CONFIG_ACE_BC_IRQMODE) || defined(CONFIG_ACE_HASH_IRQMODE)
+ if (s5p_adt->irq) {
+ free_irq(s5p_adt->irq, (void *)s5p_adt);
+ s5p_adt->irq = 0;
+ }
+#endif
+
+ if (s5p_adt->clock) {
+ clk_put(s5p_adt->clock);
+ s5p_adt->clock = NULL;
+ }
+
+ if (s5p_adt->ace_base) {
+ iounmap(s5p_adt->ace_base);
+ s5p_adt->ace_base = NULL;
+ }
+
+#ifdef ACE_USE_ACP
+ if (s5p_adt->sss_usercon) {
+ iounmap(s5p_adt->sss_usercon);
+ s5p_adt->sss_usercon = NULL;
+ }
+#endif
+
+ secmem_crypto_deregister();
+
+#if defined(CONFIG_ACE_HASH_SHA1) || defined(CONFIG_ACE_HASH_SHA256)
+ kfree(sw_tfm);
+ for (i = 0; i < ARRAY_SIZE(algs_hash); i++)
+ crypto_free_hash(fallback_hash[i]);
+
+ kfree(fallback_hash);
+
+ for (i = 0; i < ARRAY_SIZE(algs_hash); i++)
+#ifdef CONFIG_ACE_HASH_ASYNC
+ crypto_unregister_ahash(&algs_hash[i]);
+#else
+ crypto_unregister_shash(&algs_hash[i]);
+#endif
+#endif
+
+ for (i = 0; i < ARRAY_SIZE(algs_bc); i++)
+ crypto_unregister_alg(&algs_bc[i]);
+
+#ifdef CONFIG_ACE_BC_ASYNC
+ tasklet_kill(&s5p_adt->task_bc);
+#endif
+#ifdef CONFIG_ACE_HASH_ASYNC
+ tasklet_kill(&s5p_adt->task_hash);
+#endif
+
+ flush_work(&s5p_ace_dev.work);
+
+ printk(KERN_INFO "ACE driver is removed\n");
+
+ return 0;
+}
+
+static int s5p_ace_suspend(struct platform_device *dev, pm_message_t state)
+{
+ unsigned long timeout;
+ int get_lock_bc = 0, get_lock_hash = 0;
+
+#if defined(ACE_DEBUG_HEARTBEAT) || defined(ACE_DEBUG_WATCHDOG)
+ do_gettimeofday(×tamp[3]); /* 3: suspend */
+#endif
+
+ timeout = jiffies + msecs_to_jiffies(10);
+ while (time_before(jiffies, timeout)) {
+ if (!test_and_set_bit(FLAGS_BC_BUSY, &s5p_ace_dev.flags)) {
+ get_lock_bc = 1;
+ break;
+ }
+ udelay(1);
+ }
+ timeout = jiffies + msecs_to_jiffies(10);
+ while (time_before(jiffies, timeout)) {
+ if (!test_and_set_bit(FLAGS_HASH_BUSY, &s5p_ace_dev.flags)) {
+ get_lock_hash = 1;
+ break;
+ }
+ udelay(1);
+ }
+
+ if (get_lock_bc && get_lock_hash) {
+ set_bit(FLAGS_SUSPENDED, &s5p_ace_dev.flags);
+ return 0;
+ }
+
+ printk(KERN_ERR "ACE: suspend: time out.\n");
+
+ if (get_lock_bc)
+ clear_bit(FLAGS_BC_BUSY, &s5p_ace_dev.flags);
+ if (get_lock_hash)
+ clear_bit(FLAGS_HASH_BUSY, &s5p_ace_dev.flags);
+
+ return -EBUSY;
+}
+
+static int s5p_ace_resume(struct platform_device *dev)
+{
+#if defined(ACE_DEBUG_HEARTBEAT) || defined(ACE_DEBUG_WATCHDOG)
+ do_gettimeofday(×tamp[4]); /* 4: resume */
+#endif
+
+ s5p_ace_resume_device(&s5p_ace_dev);
+
+ return 0;
+}
+
+static struct platform_device_id s5p_ace_driver_ids[] = {
+ {
+ .name = "s5pv210-ace",
+ .driver_data = TYPE_S5PV210,
+ }, {
+ .name = "exynos4-ace",
+ .driver_data = TYPE_EXYNOS4,
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(platform, s5p_ace_driver_ids);
+
+static struct platform_driver s5p_ace_driver = {
+ .probe = s5p_ace_probe,
+ .remove = s5p_ace_remove,
+ .suspend = s5p_ace_suspend,
+ .resume = s5p_ace_resume,
+ .id_table = s5p_ace_driver_ids,
+ .driver = {
+ .name = S5P_ACE_DRIVER_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init s5p_ace_init(void)
+{
+ printk(KERN_INFO "S5P ACE Driver, (c) 2010 Samsung Electronics\n");
+
+ return platform_driver_register(&s5p_ace_driver);
+}
+
+static void __exit s5p_ace_exit(void)
+{
+ platform_driver_unregister(&s5p_ace_driver);
+}
+
+module_init(s5p_ace_init);
+module_exit(s5p_ace_exit);
+
+MODULE_DESCRIPTION("S5P ACE(Advanced Crypto Engine) support");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Dong Jin PARK");
+
diff --git a/drivers/crypto/ace.h b/drivers/crypto/ace.h
new file mode 100644
index 0000000..8d75d14
--- /dev/null
+++ b/drivers/crypto/ace.h
@@ -0,0 +1,103 @@
+/*
+ * Cryptographic API.
+ *
+ * Support for ACE (Advanced Crypto Engine) for S5PV210/EXYNOS4210.
+ *
+ * Copyright (c) 2011 Samsung Electronics
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _CRYPTO_S5P_ACE_H
+#define _CRYPTO_S5P_ACE_H
+
+
+/*****************************************************************
+ Definition - Mechanism
+*****************************************************************/
+#define BC_MODE_ENC 0
+#define BC_MODE_DEC 1
+
+/*
+ * Mechanism ID definition
+ * : Mech. Type (8-bit) : Algorithm (8-bit) : Info (8-bit)
+ * : Reserved (8-bit)
+ */
+#define _MECH_ID_(_TYPE_, _NAME_, _MODE_) \
+ ((((_TYPE_) & 0xFF) << 24) \
+ | (((_NAME_) & 0xFF) << 16) \
+ | (((_MODE_) & 0xFF) << 8) \
+ | (((0) & 0xFF) << 0))
+
+#define MI_MASK _MECH_ID_(0xFF, 0xFF, 0xFF)
+#define MI_GET_TYPE(_t_) (((_t_) >> 24) & 0xFF)
+#define MI_GET_NAME(_n_) (((_n_) >> 16) & 0xFF)
+#define MI_GET_INFO(_i_) (((_i_) >> 8) & 0xFF)
+
+/* type (8-bits) */
+#define _TYPE_BC_ 0x01
+#define _TYPE_HASH_ 0x02
+#define _TYPE_MAC_ 0x03
+
+/* block cipher: algorithm (8-bits) */
+#define _NAME_DES_ 0x01
+#define _NAME_TDES_ 0x02
+#define _NAME_AES_ 0x03
+
+/* block cipher: mode of operation */
+#define _MODE_ECB_ 0x10
+#define _MODE_CBC_ 0x20
+#define _MODE_CTR_ 0x30
+
+/* block cipher: padding method */
+#define _PAD_NO_ 0x00
+/*#define _PAD_ZERO_ 0x01 */ /* Not supported */
+#define _PAD_PKCS7_ 0x02 /* Default padding method */
+/*#define _PAD_ANSIX923_ 0x03 */ /* Not supported */
+/*#define _PAD_ISO10126_ 0x04 */ /* Not supported */
+
+#define MI_GET_MODE(_m_) (((_m_) >> 8) & 0xF0)
+#define MI_GET_PADDING(_i_) (((_i_) >> 8) & 0x0F)
+
+#define MI_AES_ECB _MECH_ID_(_TYPE_BC_, _NAME_AES_, \
+ _MODE_ECB_ | _PAD_NO_)
+#define MI_AES_ECB_PAD _MECH_ID_(_TYPE_BC_, _NAME_AES_, \
+ _MODE_ECB_ | _PAD_PKCS7_)
+#define MI_AES_CBC _MECH_ID_(_TYPE_BC_, _NAME_AES_, \
+ _MODE_CBC_ | _PAD_NO_)
+#define MI_AES_CBC_PAD _MECH_ID_(_TYPE_BC_, _NAME_AES_, \
+ _MODE_CBC_ | _PAD_PKCS7_)
+#define MI_AES_CTR _MECH_ID_(_TYPE_BC_, _NAME_AES_, \
+ _MODE_CTR_ | _PAD_NO_)
+#define MI_AES_CTR_PAD _MECH_ID_(_TYPE_BC_, _NAME_AES_, \
+ _MODE_CTR_ | _PAD_PKCS7_)
+
+/* hash: algorithm (8-bits) */
+#define _NAME_HASH_SHA1_ 0x01
+#define _NAME_HASH_MD5_ 0x02
+
+#define MI_SHA1 _MECH_ID_(_TYPE_HASH_, _NAME_HASH_SHA1_, 0)
+#define MI_MD5 _MECH_ID_(_TYPE_HASH_, _NAME_HASH_MD5_, 0)
+
+/* hash: algorithm (8-bits) */
+#define _NAME_HMAC_SHA1_ 0x01
+
+#define MI_HMAC_SHA1 _MECH_ID_(_TYPE_MAC_, _NAME_HMAC_SHA1_, 0)
+
+/* Flag bits */
+#define FLAG_ENC_BIT (1 << 0)
+
+#endif /* _CRYPTO_S5P_ACE_H */
diff --git a/drivers/crypto/ace_sfr.h b/drivers/crypto/ace_sfr.h
new file mode 100644
index 0000000..367bc14
--- /dev/null
+++ b/drivers/crypto/ace_sfr.h
@@ -0,0 +1,497 @@
+/*
+ * Header file for Advanced Crypto Engine - SFR definitions
+ *
+ * Copyright (c) 2011 Samsung Electronics
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef __ACE_SFR_H__
+#define __ACE_SFR_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*****************************************************************
+ SFR Addresses
+*****************************************************************/
+#if defined(CONFIG_ARCH_S5PV210)
+#define ACE_SFR_BASE (0xEA000000)
+#elif defined(CONFIG_ARCH_EXYNOS4) || defined(CONFIG_ARCH_EXYNOS5)
+#define ACE_SFR_BASE (0x10830000)
+#else
+#error No ARCH is defined.
+#endif
+
+#if defined(CONFIG_ARCH_S5PV210)
+#define ACE_FC_OFFSET (0x0)
+#define ACE_AES_OFFSET (0x4000)
+#define ACE_TDES_OFFSET (0x5000)
+#define ACE_HASH_OFFSET (0x6000)
+#define ACE_PKA_OFFSET (0x7000)
+#elif defined(CONFIG_ARCH_EXYNOS4) || defined(CONFIG_ARCH_EXYNOS5)
+#define ACE_FC_OFFSET (0x0)
+#define ACE_AES_OFFSET (0x200)
+#define ACE_TDES_OFFSET (0x300)
+#define ACE_HASH_OFFSET (0x400)
+#define ACE_PKA_OFFSET (0x700)
+#endif
+
+/* Feed control registers */
+#define ACE_FC_INTSTAT (ACE_FC_OFFSET + 0x00)
+#define ACE_FC_INTENSET (ACE_FC_OFFSET + 0x04)
+#define ACE_FC_INTENCLR (ACE_FC_OFFSET + 0x08)
+#define ACE_FC_INTPEND (ACE_FC_OFFSET + 0x0C)
+#define ACE_FC_FIFOSTAT (ACE_FC_OFFSET + 0x10)
+#define ACE_FC_FIFOCTRL (ACE_FC_OFFSET + 0x14)
+#define ACE_FC_GLOBAL (ACE_FC_OFFSET + 0x18)
+#define ACE_FC_BRDMAS (ACE_FC_OFFSET + 0x20)
+#define ACE_FC_BRDMAL (ACE_FC_OFFSET + 0x24)
+#define ACE_FC_BRDMAC (ACE_FC_OFFSET + 0x28)
+#define ACE_FC_BTDMAS (ACE_FC_OFFSET + 0x30)
+#define ACE_FC_BTDMAL (ACE_FC_OFFSET + 0x34)
+#define ACE_FC_BTDMAC (ACE_FC_OFFSET + 0x38)
+#define ACE_FC_HRDMAS (ACE_FC_OFFSET + 0x40)
+#define ACE_FC_HRDMAL (ACE_FC_OFFSET + 0x44)
+#define ACE_FC_HRDMAC (ACE_FC_OFFSET + 0x48)
+#define ACE_FC_PKDMAS (ACE_FC_OFFSET + 0x50)
+#define ACE_FC_PKDMAL (ACE_FC_OFFSET + 0x54)
+#define ACE_FC_PKDMAC (ACE_FC_OFFSET + 0x58)
+#define ACE_FC_PKDMAO (ACE_FC_OFFSET + 0x5C)
+
+/* AES control registers */
+#define ACE_AES_CONTROL (ACE_AES_OFFSET + 0x00)
+#define ACE_AES_STATUS (ACE_AES_OFFSET + 0x04)
+
+#define ACE_AES_IN1 (ACE_AES_OFFSET + 0x10)
+#define ACE_AES_IN2 (ACE_AES_OFFSET + 0x14)
+#define ACE_AES_IN3 (ACE_AES_OFFSET + 0x18)
+#define ACE_AES_IN4 (ACE_AES_OFFSET + 0x1C)
+
+#define ACE_AES_OUT1 (ACE_AES_OFFSET + 0x20)
+#define ACE_AES_OUT2 (ACE_AES_OFFSET + 0x24)
+#define ACE_AES_OUT3 (ACE_AES_OFFSET + 0x28)
+#define ACE_AES_OUT4 (ACE_AES_OFFSET + 0x2C)
+
+#define ACE_AES_IV1 (ACE_AES_OFFSET + 0x30)
+#define ACE_AES_IV2 (ACE_AES_OFFSET + 0x34)
+#define ACE_AES_IV3 (ACE_AES_OFFSET + 0x38)
+#define ACE_AES_IV4 (ACE_AES_OFFSET + 0x3C)
+
+#define ACE_AES_CNT1 (ACE_AES_OFFSET + 0x40)
+#define ACE_AES_CNT2 (ACE_AES_OFFSET + 0x44)
+#define ACE_AES_CNT3 (ACE_AES_OFFSET + 0x48)
+#define ACE_AES_CNT4 (ACE_AES_OFFSET + 0x4C)
+
+#define ACE_AES_KEY1 (ACE_AES_OFFSET + 0x80)
+#define ACE_AES_KEY2 (ACE_AES_OFFSET + 0x84)
+#define ACE_AES_KEY3 (ACE_AES_OFFSET + 0x88)
+#define ACE_AES_KEY4 (ACE_AES_OFFSET + 0x8C)
+#define ACE_AES_KEY5 (ACE_AES_OFFSET + 0x90)
+#define ACE_AES_KEY6 (ACE_AES_OFFSET + 0x94)
+#define ACE_AES_KEY7 (ACE_AES_OFFSET + 0x98)
+#define ACE_AES_KEY8 (ACE_AES_OFFSET + 0x9C)
+
+/* TDES control registers */
+#define ACE_TDES_CONTROL (ACE_TDES_OFFSET + 0x00)
+#define ACE_TDES_STATUS (ACE_TDES_OFFSET + 0x04)
+
+#define ACE_TDES_KEY11 (ACE_TDES_OFFSET + 0x10)
+#define ACE_TDES_KEY12 (ACE_TDES_OFFSET + 0x14)
+#define ACE_TDES_KEY21 (ACE_TDES_OFFSET + 0x18)
+#define ACE_TDES_KEY22 (ACE_TDES_OFFSET + 0x1C)
+#define ACE_TDES_KEY31 (ACE_TDES_OFFSET + 0x20)
+#define ACE_TDES_KEY32 (ACE_TDES_OFFSET + 0x24)
+
+#define ACE_TDES_IV1 (ACE_TDES_OFFSET + 0x28)
+#define ACE_TDES_IV2 (ACE_TDES_OFFSET + 0x2C)
+
+#define ACE_TDES_IN1 (ACE_TDES_OFFSET + 0x30)
+#define ACE_TDES_IN2 (ACE_TDES_OFFSET + 0x34)
+
+#define ACE_TDES_OUT1 (ACE_TDES_OFFSET + 0x38)
+#define ACE_TDES_OUT2 (ACE_TDES_OFFSET + 0x3C)
+
+/* HASH control registers */
+#if defined(CONFIG_ARCH_S5PV210)
+#define ACE_HASH_CONTROL (ACE_HASH_OFFSET + 0x00)
+#define ACE_HASH_CONTROL2 (ACE_HASH_OFFSET + 0x04)
+#define ACE_HASH_FIFO_MODE (ACE_HASH_OFFSET + 0x08)
+#define ACE_HASH_BYTESWAP (ACE_HASH_OFFSET + 0x0C)
+#define ACE_HASH_STATUS (ACE_HASH_OFFSET + 0x10)
+#define ACE_HASH_MSGSIZE_LOW (ACE_HASH_OFFSET + 0x14)
+#define ACE_HASH_MSGSIZE_HIGH (ACE_HASH_OFFSET + 0x18)
+
+#define ACE_HASH_IN1 (ACE_HASH_OFFSET + 0x20)
+#define ACE_HASH_IN2 (ACE_HASH_OFFSET + 0x24)
+#define ACE_HASH_IN3 (ACE_HASH_OFFSET + 0x28)
+#define ACE_HASH_IN4 (ACE_HASH_OFFSET + 0x2C)
+#define ACE_HASH_IN5 (ACE_HASH_OFFSET + 0x30)
+#define ACE_HASH_IN6 (ACE_HASH_OFFSET + 0x34)
+#define ACE_HASH_IN7 (ACE_HASH_OFFSET + 0x38)
+#define ACE_HASH_IN8 (ACE_HASH_OFFSET + 0x3C)
+
+#define ACE_HASH_SEED1 (ACE_HASH_OFFSET + 0x40)
+#define ACE_HASH_SEED2 (ACE_HASH_OFFSET + 0x44)
+#define ACE_HASH_SEED3 (ACE_HASH_OFFSET + 0x48)
+#define ACE_HASH_SEED4 (ACE_HASH_OFFSET + 0x4C)
+#define ACE_HASH_SEED5 (ACE_HASH_OFFSET + 0x50)
+
+#define ACE_HASH_RESULT1 (ACE_HASH_OFFSET + 0x60)
+#define ACE_HASH_RESULT2 (ACE_HASH_OFFSET + 0x64)
+#define ACE_HASH_RESULT3 (ACE_HASH_OFFSET + 0x68)
+#define ACE_HASH_RESULT4 (ACE_HASH_OFFSET + 0x6C)
+#define ACE_HASH_RESULT5 (ACE_HASH_OFFSET + 0x70)
+
+#define ACE_HASH_PRNG1 (ACE_HASH_OFFSET + 0x80)
+#define ACE_HASH_PRNG2 (ACE_HASH_OFFSET + 0x84)
+#define ACE_HASH_PRNG3 (ACE_HASH_OFFSET + 0x88)
+#define ACE_HASH_PRNG4 (ACE_HASH_OFFSET + 0x8C)
+#define ACE_HASH_PRNG5 (ACE_HASH_OFFSET + 0x90)
+
+#define ACE_HASH_IV1 (ACE_HASH_OFFSET + 0xA0)
+#define ACE_HASH_IV2 (ACE_HASH_OFFSET + 0xA4)
+#define ACE_HASH_IV3 (ACE_HASH_OFFSET + 0xA8)
+#define ACE_HASH_IV4 (ACE_HASH_OFFSET + 0xAC)
+#define ACE_HASH_IV5 (ACE_HASH_OFFSET + 0xB0)
+
+#define ACE_HASH_PRELEN_HIGH (ACE_HASH_OFFSET + 0xC0)
+#define ACE_HASH_PRELEN_LOW (ACE_HASH_OFFSET + 0xC4)
+#elif defined(CONFIG_ARCH_EXYNOS4) || defined(CONFIG_ARCH_EXYNOS5)
+#define ACE_HASH_CONTROL (ACE_HASH_OFFSET + 0x00)
+#define ACE_HASH_CONTROL2 (ACE_HASH_OFFSET + 0x04)
+#define ACE_HASH_FIFO_MODE (ACE_HASH_OFFSET + 0x08)
+#define ACE_HASH_BYTESWAP (ACE_HASH_OFFSET + 0x0C)
+#define ACE_HASH_STATUS (ACE_HASH_OFFSET + 0x10)
+#define ACE_HASH_MSGSIZE_LOW (ACE_HASH_OFFSET + 0x20)
+#define ACE_HASH_MSGSIZE_HIGH (ACE_HASH_OFFSET + 0x24)
+#define ACE_HASH_PRELEN_LOW (ACE_HASH_OFFSET + 0x28)
+#define ACE_HASH_PRELEN_HIGH (ACE_HASH_OFFSET + 0x2C)
+
+#define ACE_HASH_IN1 (ACE_HASH_OFFSET + 0x30)
+#define ACE_HASH_IN2 (ACE_HASH_OFFSET + 0x34)
+#define ACE_HASH_IN3 (ACE_HASH_OFFSET + 0x38)
+#define ACE_HASH_IN4 (ACE_HASH_OFFSET + 0x3C)
+#define ACE_HASH_IN5 (ACE_HASH_OFFSET + 0x40)
+#define ACE_HASH_IN6 (ACE_HASH_OFFSET + 0x44)
+#define ACE_HASH_IN7 (ACE_HASH_OFFSET + 0x48)
+#define ACE_HASH_IN8 (ACE_HASH_OFFSET + 0x4C)
+#define ACE_HASH_IN9 (ACE_HASH_OFFSET + 0x50)
+#define ACE_HASH_IN10 (ACE_HASH_OFFSET + 0x54)
+#define ACE_HASH_IN11 (ACE_HASH_OFFSET + 0x58)
+#define ACE_HASH_IN12 (ACE_HASH_OFFSET + 0x5C)
+#define ACE_HASH_IN13 (ACE_HASH_OFFSET + 0x60)
+#define ACE_HASH_IN14 (ACE_HASH_OFFSET + 0x64)
+#define ACE_HASH_IN15 (ACE_HASH_OFFSET + 0x68)
+#define ACE_HASH_IN16 (ACE_HASH_OFFSET + 0x6C)
+
+#define ACE_HASH_HMAC_KEY_IN1 (ACE_HASH_OFFSET + 0x70)
+#define ACE_HASH_HMAC_KEY_IN2 (ACE_HASH_OFFSET + 0x74)
+#define ACE_HASH_HMAC_KEY_IN3 (ACE_HASH_OFFSET + 0x78)
+#define ACE_HASH_HMAC_KEY_IN4 (ACE_HASH_OFFSET + 0x7C)
+#define ACE_HASH_HMAC_KEY_IN5 (ACE_HASH_OFFSET + 0x80)
+#define ACE_HASH_HMAC_KEY_IN6 (ACE_HASH_OFFSET + 0x84)
+#define ACE_HASH_HMAC_KEY_IN7 (ACE_HASH_OFFSET + 0x88)
+#define ACE_HASH_HMAC_KEY_IN8 (ACE_HASH_OFFSET + 0x8C)
+#define ACE_HASH_HMAC_KEY_IN9 (ACE_HASH_OFFSET + 0x90)
+#define ACE_HASH_HMAC_KEY_IN10 (ACE_HASH_OFFSET + 0x94)
+#define ACE_HASH_HMAC_KEY_IN11 (ACE_HASH_OFFSET + 0x98)
+#define ACE_HASH_HMAC_KEY_IN12 (ACE_HASH_OFFSET + 0x9C)
+#define ACE_HASH_HMAC_KEY_IN13 (ACE_HASH_OFFSET + 0xA0)
+#define ACE_HASH_HMAC_KEY_IN14 (ACE_HASH_OFFSET + 0xA4)
+#define ACE_HASH_HMAC_KEY_IN15 (ACE_HASH_OFFSET + 0xA8)
+#define ACE_HASH_HMAC_KEY_IN16 (ACE_HASH_OFFSET + 0xAC)
+
+#define ACE_HASH_IV1 (ACE_HASH_OFFSET + 0xB0)
+#define ACE_HASH_IV2 (ACE_HASH_OFFSET + 0xB4)
+#define ACE_HASH_IV3 (ACE_HASH_OFFSET + 0xB8)
+#define ACE_HASH_IV4 (ACE_HASH_OFFSET + 0xBC)
+#define ACE_HASH_IV5 (ACE_HASH_OFFSET + 0xC0)
+#define ACE_HASH_IV6 (ACE_HASH_OFFSET + 0xC4)
+#define ACE_HASH_IV7 (ACE_HASH_OFFSET + 0xC8)
+#define ACE_HASH_IV8 (ACE_HASH_OFFSET + 0xCC)
+
+#define ACE_HASH_RESULT1 (ACE_HASH_OFFSET + 0x100)
+#define ACE_HASH_RESULT2 (ACE_HASH_OFFSET + 0x104)
+#define ACE_HASH_RESULT3 (ACE_HASH_OFFSET + 0x108)
+#define ACE_HASH_RESULT4 (ACE_HASH_OFFSET + 0x10C)
+#define ACE_HASH_RESULT5 (ACE_HASH_OFFSET + 0x110)
+#define ACE_HASH_RESULT6 (ACE_HASH_OFFSET + 0x114)
+#define ACE_HASH_RESULT7 (ACE_HASH_OFFSET + 0x118)
+#define ACE_HASH_RESULT8 (ACE_HASH_OFFSET + 0x11C)
+
+#define ACE_HASH_SEED1 (ACE_HASH_OFFSET + 0x140)
+#define ACE_HASH_SEED2 (ACE_HASH_OFFSET + 0x144)
+#define ACE_HASH_SEED3 (ACE_HASH_OFFSET + 0x148)
+#define ACE_HASH_SEED4 (ACE_HASH_OFFSET + 0x14C)
+#define ACE_HASH_SEED5 (ACE_HASH_OFFSET + 0x150)
+
+#define ACE_HASH_PRNG1 (ACE_HASH_OFFSET + 0x160)
+#define ACE_HASH_PRNG2 (ACE_HASH_OFFSET + 0x164)
+#define ACE_HASH_PRNG3 (ACE_HASH_OFFSET + 0x168)
+#define ACE_HASH_PRNG4 (ACE_HASH_OFFSET + 0x16C)
+#define ACE_HASH_PRNG5 (ACE_HASH_OFFSET + 0x170)
+#endif
+
+/* PKA control registers */
+#define ACE_PKA_SFR0 (ACE_PKA_OFFSET + 0x00)
+#define ACE_PKA_SFR1 (ACE_PKA_OFFSET + 0x04)
+#define ACE_PKA_SFR2 (ACE_PKA_OFFSET + 0x08)
+#define ACE_PKA_SFR3 (ACE_PKA_OFFSET + 0x0C)
+#define ACE_PKA_SFR4 (ACE_PKA_OFFSET + 0x10)
+
+
+/*****************************************************************
+ OFFSET
+*****************************************************************/
+
+/* ACE_FC_INT */
+#define ACE_FC_PKDMA (1 << 0)
+#define ACE_FC_HRDMA (1 << 1)
+#define ACE_FC_BTDMA (1 << 2)
+#define ACE_FC_BRDMA (1 << 3)
+#define ACE_FC_PRNG_ERROR (1 << 4)
+#define ACE_FC_MSG_DONE (1 << 5)
+#define ACE_FC_PRNG_DONE (1 << 6)
+#define ACE_FC_PARTIAL_DONE (1 << 7)
+
+/* ACE_FC_FIFOSTAT */
+#define ACE_FC_PKFIFO_EMPTY (1 << 0)
+#define ACE_FC_PKFIFO_FULL (1 << 1)
+#define ACE_FC_HRFIFO_EMPTY (1 << 2)
+#define ACE_FC_HRFIFO_FULL (1 << 3)
+#define ACE_FC_BTFIFO_EMPTY (1 << 4)
+#define ACE_FC_BTFIFO_FULL (1 << 5)
+#define ACE_FC_BRFIFO_EMPTY (1 << 6)
+#define ACE_FC_BRFIFO_FULL (1 << 7)
+
+/* ACE_FC_FIFOCTRL */
+#define ACE_FC_SELHASH_MASK (3 << 0)
+#define ACE_FC_SELHASH_EXOUT (0 << 0) /*independent source*/
+#define ACE_FC_SELHASH_BCIN (1 << 0) /*block cipher input*/
+#define ACE_FC_SELHASH_BCOUT (2 << 0) /*block cipher output*/
+#define ACE_FC_SELBC_MASK (1 << 2)
+#define ACE_FC_SELBC_AES (0 << 2) /* AES */
+#define ACE_FC_SELBC_DES (1 << 2) /* DES */
+
+/* ACE_FC_GLOBAL */
+#define ACE_FC_SSS_RESET (1 << 0)
+#define ACE_FC_DMA_RESET (1 << 1)
+#define ACE_FC_AES_RESET (1 << 2)
+#define ACE_FC_DES_RESET (1 << 3)
+#define ACE_FC_HASH_RESET (1 << 4)
+#define ACE_FC_AXI_ENDIAN_MASK (3 << 6)
+#define ACE_FC_AXI_ENDIAN_LE (0 << 6)
+#define ACE_FC_AXI_ENDIAN_BIBE (1 << 6)
+#define ACE_FC_AXI_ENDIAN_WIBE (2 << 6)
+
+/* Feed control - BRDMA control */
+#define ACE_FC_BRDMACFLUSH_OFF (0 << 0)
+#define ACE_FC_BRDMACFLUSH_ON (1 << 0)
+#define ACE_FC_BRDMACSWAP_ON (1 << 1)
+#define ACE_FC_BRDMACARPROT_MASK (0x7 << 2)
+#define ACE_FC_BRDMACARPROT_OFS (2)
+#define ACE_FC_BRDMACARCACHE_MASK (0xF << 5)
+#define ACE_FC_BRDMACARCACHE_OFS (5)
+
+/* Feed control - BTDMA control */
+#define ACE_FC_BTDMACFLUSH_OFF (0 << 0)
+#define ACE_FC_BTDMACFLUSH_ON (1 << 0)
+#define ACE_FC_BTDMACSWAP_ON (1 << 1)
+#define ACE_FC_BTDMACAWPROT_MASK (0x7 << 2)
+#define ACE_FC_BTDMACAWPROT_OFS (2)
+#define ACE_FC_BTDMACAWCACHE_MASK (0xF << 5)
+#define ACE_FC_BTDMACAWCACHE_OFS (5)
+
+/* Feed control - HRDMA control */
+#define ACE_FC_HRDMACFLUSH_OFF (0 << 0)
+#define ACE_FC_HRDMACFLUSH_ON (1 << 0)
+#define ACE_FC_HRDMACSWAP_ON (1 << 1)
+#define ACE_FC_HRDMACARPROT_MASK (0x7 << 2)
+#define ACE_FC_HRDMACARPROT_OFS (2)
+#define ACE_FC_HRDMACARCACHE_MASK (0xF << 5)
+#define ACE_FC_HRDMACARCACHE_OFS (5)
+
+/* Feed control - PKDMA control */
+#define ACE_FC_PKDMACBYTESWAP_ON (1 << 3)
+#define ACE_FC_PKDMACDESEND_ON (1 << 2)
+#define ACE_FC_PKDMACTRANSMIT_ON (1 << 1)
+#define ACE_FC_PKDMACFLUSH_ON (1 << 0)
+
+/* Feed control - PKDMA offset */
+#define ACE_FC_SRAMOFFSET_MASK (0xFFF)
+
+/* AES control */
+#define ACE_AES_MODE_MASK (1 << 0)
+#define ACE_AES_MODE_ENC (0 << 0)
+#define ACE_AES_MODE_DEC (1 << 0)
+#define ACE_AES_OPERMODE_MASK (3 << 1)
+#define ACE_AES_OPERMODE_ECB (0 << 1)
+#define ACE_AES_OPERMODE_CBC (1 << 1)
+#define ACE_AES_OPERMODE_CTR (2 << 1)
+#define ACE_AES_FIFO_MASK (1 << 3)
+#define ACE_AES_FIFO_OFF (0 << 3) /* CPU mode */
+#define ACE_AES_FIFO_ON (1 << 3) /* FIFO mode */
+#define ACE_AES_KEYSIZE_MASK (3 << 4)
+#define ACE_AES_KEYSIZE_128 (0 << 4)
+#define ACE_AES_KEYSIZE_192 (1 << 4)
+#define ACE_AES_KEYSIZE_256 (2 << 4)
+#define ACE_AES_KEYCNGMODE_MASK (1 << 6)
+#define ACE_AES_KEYCNGMODE_OFF (0 << 6)
+#define ACE_AES_KEYCNGMODE_ON (1 << 6)
+#define ACE_AES_SWAP_MASK (0x1F << 7)
+#define ACE_AES_SWAPKEY_OFF (0 << 7)
+#define ACE_AES_SWAPKEY_ON (1 << 7)
+#define ACE_AES_SWAPCNT_OFF (0 << 8)
+#define ACE_AES_SWAPCNT_ON (1 << 8)
+#define ACE_AES_SWAPIV_OFF (0 << 9)
+#define ACE_AES_SWAPIV_ON (1 << 9)
+#define ACE_AES_SWAPDO_OFF (0 << 10)
+#define ACE_AES_SWAPDO_ON (1 << 10)
+#define ACE_AES_SWAPDI_OFF (0 << 11)
+#define ACE_AES_SWAPDI_ON (1 << 11)
+#define ACE_AES_COUNTERSIZE_MASK (3 << 12)
+#define ACE_AES_COUNTERSIZE_128 (0 << 12)
+#define ACE_AES_COUNTERSIZE_64 (1 << 12)
+#define ACE_AES_COUNTERSIZE_32 (2 << 12)
+#define ACE_AES_COUNTERSIZE_16 (3 << 12)
+
+/* AES status */
+#define ACE_AES_OUTRDY_MASK (1 << 0)
+#define ACE_AES_OUTRDY_OFF (0 << 0)
+#define ACE_AES_OUTRDY_ON (1 << 0)
+#define ACE_AES_INRDY_MASK (1 << 1)
+#define ACE_AES_INRDY_OFF (0 << 1)
+#define ACE_AES_INRDY_ON (1 << 1)
+#define ACE_AES_BUSY_MASK (1 << 2)
+#define ACE_AES_BUSY_OFF (0 << 2)
+#define ACE_AES_BUSY_ON (1 << 2)
+
+/* TDES control */
+#define ACE_TDES_MODE_MASK (1 << 0)
+#define ACE_TDES_MODE_ENC (0 << 0)
+#define ACE_TDES_MODE_DEC (1 << 0)
+#define ACE_TDES_OPERMODE_MASK (1 << 1)
+#define ACE_TDES_OPERMODE_ECB (0 << 1)
+#define ACE_TDES_OPERMODE_CBC (1 << 1)
+#define ACE_TDES_SEL_MASK (3 << 3)
+#define ACE_TDES_SEL_DES (0 << 3)
+#define ACE_TDES_SEL_TDESEDE (1 << 3) /* TDES EDE mode */
+#define ACE_TDES_SEL_TDESEEE (3 << 3) /* TDES EEE mode */
+#define ACE_TDES_FIFO_MASK (1 << 5)
+#define ACE_TDES_FIFO_OFF (0 << 5) /* CPU mode */
+#define ACE_TDES_FIFO_ON (1 << 5) /* FIFO mode */
+#define ACE_TDES_SWAP_MASK (0xF << 6)
+#define ACE_TDES_SWAPKEY_OFF (0 << 6)
+#define ACE_TDES_SWAPKEY_ON (1 << 6)
+#define ACE_TDES_SWAPIV_OFF (0 << 7)
+#define ACE_TDES_SWAPIV_ON (1 << 7)
+#define ACE_TDES_SWAPDO_OFF (0 << 8)
+#define ACE_TDES_SWAPDO_ON (1 << 8)
+#define ACE_TDES_SWAPDI_OFF (0 << 9)
+#define ACE_TDES_SWAPDI_ON (1 << 9)
+
+/* TDES status */
+#define ACE_TDES_OUTRDY_MASK (1 << 0)
+#define ACE_TDES_OUTRDY_OFF (0 << 0)
+#define ACE_TDES_OUTRDY_ON (1 << 0)
+#define ACE_TDES_INRDY_MASK (1 << 1)
+#define ACE_TDES_INRDY_OFF (0 << 1)
+#define ACE_TDES_INRDY_ON (1 << 1)
+#define ACE_TDES_BUSY_MASK (1 << 2)
+#define ACE_TDES_BUSY_OFF (0 << 2)
+#define ACE_TDES_BUSY_ON (1 << 2)
+
+/* Hash control */
+#define ACE_HASH_ENGSEL_MASK (0xF << 0)
+#define ACE_HASH_ENGSEL_SHA1HASH (0x0 << 0)
+#define ACE_HASH_ENGSEL_SHA1HMAC (0x1 << 0)
+#define ACE_HASH_ENGSEL_SHA1HMACIN (0x1 << 0)
+#define ACE_HASH_ENGSEL_SHA1HMACOUT (0x9 << 0)
+#define ACE_HASH_ENGSEL_MD5HASH (0x2 << 0)
+#define ACE_HASH_ENGSEL_MD5HMAC (0x3 << 0)
+#define ACE_HASH_ENGSEL_MD5HMACIN (0x3 << 0)
+#define ACE_HASH_ENGSEL_MD5HMACOUT (0xB << 0)
+#define ACE_HASH_ENGSEL_SHA256HASH (0x4 << 0)
+#define ACE_HASH_ENGSEL_SHA256HMAC (0x5 << 0)
+#if defined(CONFIG_ARCH_S5PV210)
+#define ACE_HASH_ENGSEL_PRNG (0x4 << 0)
+#elif defined(CONFIG_ARCH_EXYNOS4) || defined(CONFIG_ARCH_EXYNOS5)
+#define ACE_HASH_ENGSEL_PRNG (0x8 << 0)
+#endif
+#define ACE_HASH_STARTBIT_ON (1 << 4)
+#define ACE_HASH_USERIV_EN (1 << 5)
+
+/* Hash control 2 */
+#if defined(CONFIG_ARCH_S5PV210)
+#define ACE_HASH_PAUSE_ON (1 << 3)
+#elif defined(CONFIG_ARCH_EXYNOS4) || defined(CONFIG_ARCH_EXYNOS5)
+#define ACE_HASH_PAUSE_ON (1 << 0)
+#endif
+
+/* Hash control - FIFO mode */
+#define ACE_HASH_FIFO_MASK (1 << 0)
+#define ACE_HASH_FIFO_OFF (0 << 0)
+#define ACE_HASH_FIFO_ON (1 << 0)
+
+/* Hash control - byte swap */
+#if defined(CONFIG_ARCH_S5PV210)
+#define ACE_HASH_SWAP_MASK (0x7 << 1)
+#elif defined(CONFIG_ARCH_EXYNOS4) || defined(CONFIG_ARCH_EXYNOS5)
+#define ACE_HASH_SWAP_MASK (0xF << 0)
+#endif
+#define ACE_HASH_SWAPKEY_OFF (0 << 0)
+#define ACE_HASH_SWAPKEY_ON (1 << 0)
+#define ACE_HASH_SWAPIV_OFF (0 << 1)
+#define ACE_HASH_SWAPIV_ON (1 << 1)
+#define ACE_HASH_SWAPDO_OFF (0 << 2)
+#define ACE_HASH_SWAPDO_ON (1 << 2)
+#define ACE_HASH_SWAPDI_OFF (0 << 3)
+#define ACE_HASH_SWAPDI_ON (1 << 3)
+
+/* Hash status */
+#define ACE_HASH_BUFRDY_MASK (1 << 0)
+#define ACE_HASH_BUFRDY_OFF (0 << 0)
+#define ACE_HASH_BUFRDY_ON (1 << 0)
+#define ACE_HASH_SEEDSETTING_MASK (1 << 1)
+#define ACE_HASH_SEEDSETTING_OFF (0 << 1)
+#define ACE_HASH_SEEDSETTING_ON (1 << 1)
+#define ACE_HASH_PRNGBUSY_MASK (1 << 2)
+#define ACE_HASH_PRNGBUSY_OFF (0 << 2)
+#define ACE_HASH_PRNGBUSY_ON (1 << 2)
+#define ACE_HASH_PARTIALDONE_MASK (1 << 4)
+#define ACE_HASH_PARTIALDONE_OFF (0 << 4)
+#define ACE_HASH_PARTIALDONE_ON (1 << 4)
+#define ACE_HASH_PRNGDONE_MASK (1 << 5)
+#define ACE_HASH_PRNGDONE_OFF (0 << 5)
+#define ACE_HASH_PRNGDONE_ON (1 << 5)
+#define ACE_HASH_MSGDONE_MASK (1 << 6)
+#define ACE_HASH_MSGDONE_OFF (0 << 6)
+#define ACE_HASH_MSGDONE_ON (1 << 6)
+#define ACE_HASH_PRNGERROR_MASK (1 << 7)
+#define ACE_HASH_PRNGERROR_OFF (0 << 7)
+#define ACE_HASH_PRNGERROR_ON (1 << 7)
+
+/* To Do: SFRs for PKA */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig
index 464fa21..8ab7727 100644
--- a/drivers/devfreq/Kconfig
+++ b/drivers/devfreq/Kconfig
@@ -46,6 +46,11 @@
the DEVFREQ framework returns the highest frequency available
at any time.
+config DEVFREQ_GOV_PM_QOS
+ bool "PM QOS"
+ help
+ Sets the frequency based on pm_qos throughput constraints.
+
config DEVFREQ_GOV_POWERSAVE
bool "Powersave"
help
@@ -78,4 +83,14 @@
To operate with optimal voltages, ASV support is required
(CONFIG_EXYNOS_ASV).
+config ARM_EXYNOS5_BUS_DEVFREQ
+ bool "ARM Exynos5250 Memory Bus DEVFREQ Driver"
+ depends on SOC_EXYNOS5250
+ select ARCH_HAS_OPP
+ select DEVFREQ_GOV_SIMPLE_ONDEMAND
+ help
+ This adds the DEVFREQ driver for Exynos5250 memory interface
+ (vdd_mif). It reads PPMU counters of memory controllers and
+ adjusts the operating frequencies and voltages with OPP support.
+
endif # PM_DEVFREQ
diff --git a/drivers/devfreq/Makefile b/drivers/devfreq/Makefile
index 8c46423..41d26cb 100644
--- a/drivers/devfreq/Makefile
+++ b/drivers/devfreq/Makefile
@@ -1,8 +1,11 @@
-obj-$(CONFIG_PM_DEVFREQ) += devfreq.o
+obj-$(CONFIG_PM_DEVFREQ) += devfreq.o exynos_ppmu.o
obj-$(CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND) += governor_simpleondemand.o
obj-$(CONFIG_DEVFREQ_GOV_PERFORMANCE) += governor_performance.o
+obj-$(CONFIG_DEVFREQ_GOV_PM_QOS) += governor_pm_qos.o
obj-$(CONFIG_DEVFREQ_GOV_POWERSAVE) += governor_powersave.o
obj-$(CONFIG_DEVFREQ_GOV_USERSPACE) += governor_userspace.o
# DEVFREQ Drivers
obj-$(CONFIG_ARM_EXYNOS4_BUS_DEVFREQ) += exynos4_bus.o
+obj-$(CONFIG_ARM_EXYNOS5_BUS_DEVFREQ) += exynos5_bus_mif.o exynos5_bus_int.o
+obj-$(CONFIG_ARM_EXYNOS5_BUS_DEVFREQ) += exynos5_ppmu.o
diff --git a/drivers/devfreq/exynos5_bus_int.c b/drivers/devfreq/exynos5_bus_int.c
new file mode 100644
index 0000000..558f3ad
--- /dev/null
+++ b/drivers/devfreq/exynos5_bus_int.c
@@ -0,0 +1,629 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * EXYNOS - INT clock frequency scaling support in DEVFREQ framework
+ * This version supports EXYNOS5250 only. This changes bus frequencies.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/suspend.h>
+#include <linux/opp.h>
+#include <linux/clk.h>
+#include <linux/devfreq.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/module.h>
+#include <linux/pm_qos.h>
+
+#include <mach/map.h>
+#include <mach/regs-clock.h>
+#include <mach/asv-exynos.h>
+#include <mach/exynos5_bus.h>
+
+#include "exynos_ppmu.h"
+#include "exynos5_ppmu.h"
+#include "governor.h"
+
+#define MAX_SAFEVOLT 1100000 /* 1.10V */
+
+/* Assume that the bus for mif is saturated if the utilization is 23% */
+#define INT_BUS_SATURATION_RATIO 23
+#define EXYNOS5_BUS_INT_POLL_TIME msecs_to_jiffies(100)
+
+enum int_level_idx {
+ LV_0,
+ LV_1,
+ LV_2,
+ LV_3,
+ LV_4,
+ _LV_END
+};
+
+struct busfreq_data_int {
+ struct device *dev;
+ struct devfreq *devfreq;
+ bool disabled;
+ struct regulator *vdd_int;
+ unsigned long curr_freq;
+ unsigned long curr_volt;
+ unsigned long suspend_freq;
+
+ struct mutex lock;
+ struct pm_qos_request mif_req;
+
+ struct clk *int_clk;
+
+ struct exynos5_ppmu_handle *ppmu;
+ struct delayed_work work;
+ int busy;
+};
+
+struct int_bus_opp_table {
+ unsigned int idx;
+ unsigned long clk;
+ unsigned long volt;
+};
+
+static struct int_bus_opp_table exynos5_int_opp_table[] = {
+ {LV_0, 266000, 1050000},
+ {LV_1, 200000, 1050000},
+ {LV_2, 160000, 1050000},
+ {LV_3, 133000, 1050000},
+ {LV_4, 100000, 1050000},
+ {0, 0, 0},
+};
+
+struct exynos5_bus_int_handle {
+ struct list_head node;
+ struct delayed_work work;
+ bool boost;
+ bool poll;
+ unsigned long min;
+};
+
+static struct busfreq_data_int *exynos5_bus_int_data;
+static DEFINE_MUTEX(exynos5_bus_int_data_lock);
+static LIST_HEAD(exynos5_bus_int_requests);
+static DEFINE_MUTEX(exynos5_bus_int_requests_lock);
+
+static int exynos5_int_setvolt(struct busfreq_data_int *data,
+ unsigned long volt)
+{
+ return regulator_set_voltage(data->vdd_int, volt, MAX_SAFEVOLT);
+}
+
+static int exynos5_busfreq_int_target(struct device *dev, unsigned long *_freq,
+ u32 flags)
+{
+ int err = 0;
+ struct platform_device *pdev = container_of(dev, struct platform_device,
+ dev);
+ struct busfreq_data_int *data = platform_get_drvdata(pdev);
+ struct opp *opp;
+ unsigned long old_freq, freq;
+ unsigned long volt;
+ struct exynos5_bus_int_handle *handle;
+
+ mutex_lock(&exynos5_bus_int_requests_lock);
+ list_for_each_entry(handle, &exynos5_bus_int_requests, node) {
+ if (handle->boost) {
+ *_freq = ULONG_MAX;
+ flags |= DEVFREQ_FLAG_LEAST_UPPER_BOUND;
+ break;
+ }
+ if (handle->min > *_freq) {
+ *_freq = handle->min;
+ flags &= ~DEVFREQ_FLAG_LEAST_UPPER_BOUND;
+ }
+ }
+ mutex_unlock(&exynos5_bus_int_requests_lock);
+
+ rcu_read_lock();
+ opp = devfreq_recommended_opp(dev, _freq, flags);
+ if (IS_ERR(opp)) {
+ rcu_read_unlock();
+ dev_err(dev, "%s: Invalid OPP.\n", __func__);
+ return PTR_ERR(opp);
+ }
+
+ freq = opp_get_freq(opp);
+ volt = opp_get_voltage(opp);
+ rcu_read_unlock();
+
+ mutex_lock(&data->lock);
+
+ old_freq = data->curr_freq;
+
+ if (old_freq == freq)
+ goto out;
+
+ dev_dbg(dev, "targetting %lukHz %luuV\n", freq, volt);
+
+ if (data->disabled)
+ goto out;
+
+ if (freq > exynos5_int_opp_table[_LV_END - 1].clk)
+ pm_qos_update_request(&data->mif_req,
+ data->busy * old_freq * 16 / 100000);
+ else
+ pm_qos_update_request(&data->mif_req, -1);
+
+ if (old_freq < freq)
+ err = exynos5_int_setvolt(data, volt);
+ if (err)
+ goto out;
+
+ err = clk_set_rate(data->int_clk, freq * 1000);
+
+ if (err)
+ goto out;
+
+ if (old_freq > freq)
+ err = exynos5_int_setvolt(data, volt);
+ if (err)
+ goto out;
+
+ data->curr_freq = freq;
+out:
+ mutex_unlock(&data->lock);
+ return err;
+}
+
+static int exynos5_int_get_dev_status(struct device *dev,
+ struct devfreq_dev_status *stat)
+{
+ struct platform_device *pdev = container_of(dev, struct platform_device,
+ dev);
+ struct busfreq_data_int *data = platform_get_drvdata(pdev);
+
+ stat->current_frequency = data->curr_freq;
+
+ stat->busy_time = data->busy;
+ stat->total_time = 100;
+
+ return 0;
+}
+
+static void exynos5_int_poll_start(struct busfreq_data_int *data)
+{
+ struct exynos5_bus_int_handle *handle;
+
+ mutex_lock(&exynos5_bus_int_requests_lock);
+ list_for_each_entry(handle, &exynos5_bus_int_requests, node) {
+ if (handle->poll) {
+ schedule_delayed_work(&data->work,
+ EXYNOS5_BUS_INT_POLL_TIME);
+ break;
+ }
+ }
+ mutex_unlock(&exynos5_bus_int_requests_lock);
+}
+
+static void exynos5_int_poll_stop(struct busfreq_data_int *data)
+{
+ cancel_delayed_work_sync(&data->work);
+}
+
+static void exynos5_int_trigger_poll(struct busfreq_data_int *data)
+{
+ cancel_delayed_work_sync(&data->work);
+ schedule_delayed_work(&data->work, 0);
+}
+
+static void exynos5_int_update(struct busfreq_data_int *data)
+{
+ struct exynos5_bus_int_handle *handle;
+ int ret = 0;
+ bool poll = false;
+
+ mutex_lock(&exynos5_bus_int_requests_lock);
+ list_for_each_entry(handle, &exynos5_bus_int_requests, node) {
+ if (handle->poll) {
+ poll = true;
+ break;
+ }
+ }
+ mutex_unlock(&exynos5_bus_int_requests_lock);
+
+ ret = exynos5_ppmu_get_busy(data->ppmu, PPMU_SET_RIGHT);
+ if (ret >= 0 && poll)
+ data->busy = ret;
+ else
+ data->busy = 0;
+
+ if (ret >= 0 || !poll) {
+ mutex_lock(&data->devfreq->lock);
+ update_devfreq(data->devfreq);
+ mutex_unlock(&data->devfreq->lock);
+ }
+}
+
+static void exynos5_int_poll_work(struct work_struct *work)
+{
+ struct delayed_work *dwork;
+ struct busfreq_data_int *data;
+
+ dwork = to_delayed_work(work);
+ data = container_of(dwork, struct busfreq_data_int, work);
+
+ exynos5_int_update(data);
+
+ exynos5_int_poll_start(data);
+}
+
+static void exynos5_int_cancel_boost(struct work_struct *work)
+{
+ struct delayed_work *dwork = to_delayed_work(work);
+ struct exynos5_bus_int_handle *handle;
+
+ handle = container_of(dwork, struct exynos5_bus_int_handle, work);
+
+ handle->boost = false;
+}
+
+struct exynos5_bus_int_handle *exynos5_bus_int_get(unsigned long min_freq,
+ bool poll)
+{
+ struct exynos5_bus_int_handle *handle;
+
+ handle = kzalloc(sizeof(*handle), GFP_KERNEL);
+ if (!handle)
+ return NULL;
+
+ handle->min = min_freq;
+ /* If polling, boost the frequency for the first poll cycle */
+ handle->boost = poll;
+ handle->poll = poll;
+ INIT_DELAYED_WORK_DEFERRABLE(&handle->work, exynos5_int_cancel_boost);
+
+ mutex_lock(&exynos5_bus_int_requests_lock);
+ list_add_tail(&handle->node, &exynos5_bus_int_requests);
+ mutex_unlock(&exynos5_bus_int_requests_lock);
+
+ mutex_lock(&exynos5_bus_int_data_lock);
+
+ if (exynos5_bus_int_data) {
+ cancel_delayed_work_sync(&exynos5_bus_int_data->work);
+ exynos5_int_update(exynos5_bus_int_data);
+ exynos5_int_poll_start(exynos5_bus_int_data);
+ }
+
+ mutex_unlock(&exynos5_bus_int_data_lock);
+
+ if (handle->boost)
+ schedule_delayed_work(&handle->work, EXYNOS5_BUS_INT_POLL_TIME);
+
+ return handle;
+}
+
+int exynos5_bus_int_put(struct exynos5_bus_int_handle *handle)
+{
+ mutex_lock(&exynos5_bus_int_requests_lock);
+ list_del(&handle->node);
+ mutex_unlock(&exynos5_bus_int_requests_lock);
+
+ mutex_lock(&exynos5_bus_int_data_lock);
+ if (exynos5_bus_int_data)
+ exynos5_int_trigger_poll(exynos5_bus_int_data);
+ mutex_unlock(&exynos5_bus_int_data_lock);
+
+ cancel_delayed_work_sync(&handle->work);
+ kfree(handle);
+ return 0;
+}
+
+static void exynos5_int_exit(struct device *dev)
+{
+ struct platform_device *pdev = container_of(dev, struct platform_device,
+ dev);
+ struct busfreq_data_int *data = platform_get_drvdata(pdev);
+
+ devfreq_unregister_opp_notifier(dev, data->devfreq);
+}
+
+static struct devfreq_dev_profile exynos5_devfreq_int_profile = {
+ .initial_freq = 160000,
+ .polling_ms = 0,
+ .target = exynos5_busfreq_int_target,
+ .get_dev_status = exynos5_int_get_dev_status,
+ .exit = exynos5_int_exit,
+};
+
+static int exynos5250_init_int_tables(struct busfreq_data_int *data)
+{
+ int i, err = 0;
+
+ for (i = LV_0; i < _LV_END; i++) {
+ exynos5_int_opp_table[i].volt = asv_get_volt(ID_INT, exynos5_int_opp_table[i].clk);
+ if (exynos5_int_opp_table[i].volt == 0) {
+ dev_err(data->dev, "Invalid value\n");
+ return -EINVAL;
+ }
+ }
+
+ for (i = LV_0; i < _LV_END; i++) {
+ err = opp_add(data->dev, exynos5_int_opp_table[i].clk,
+ exynos5_int_opp_table[i].volt);
+ if (err) {
+ dev_err(data->dev, "Cannot add opp entries.\n");
+ return err;
+ }
+ }
+
+ return 0;
+}
+static struct devfreq_simple_ondemand_data exynos5_int_ondemand_data = {
+ .downdifferential = 2,
+ .upthreshold = INT_BUS_SATURATION_RATIO,
+};
+
+static __devinit int exynos5_busfreq_int_probe(struct platform_device *pdev)
+{
+ struct busfreq_data_int *data;
+ struct opp *opp;
+ struct device *dev = &pdev->dev;
+ unsigned long initial_freq;
+ unsigned long initial_volt;
+ int err = 0;
+
+ data = devm_kzalloc(&pdev->dev, sizeof(struct busfreq_data_int), GFP_KERNEL);
+ if (data == NULL) {
+ dev_err(dev, "Cannot allocate memory.\n");
+ return -ENOMEM;
+ }
+
+ data->dev = dev;
+ mutex_init(&data->lock);
+
+ err = exynos5250_init_int_tables(data);
+ if (err)
+ goto err_regulator;
+
+ data->vdd_int = regulator_get(dev, "vdd_int");
+ if (IS_ERR(data->vdd_int)) {
+ dev_err(dev, "Cannot get the regulator \"vdd_int\"\n");
+ err = PTR_ERR(data->vdd_int);
+ goto err_regulator;
+ }
+
+ data->int_clk = clk_get(dev, "int_clk");
+ if (IS_ERR(data->int_clk)) {
+ dev_err(dev, "Cannot get clock \"int_clk\"\n");
+ err = PTR_ERR(data->int_clk);
+ goto err_clock;
+ }
+
+ rcu_read_lock();
+ opp = opp_find_freq_floor(dev, &exynos5_devfreq_int_profile.initial_freq);
+ if (IS_ERR(opp)) {
+ rcu_read_unlock();
+ dev_err(dev, "Invalid initial frequency %lu kHz.\n",
+ exynos5_devfreq_int_profile.initial_freq);
+ err = PTR_ERR(opp);
+ goto err_opp_add;
+ }
+ initial_freq = opp_get_freq(opp);
+ initial_volt = opp_get_voltage(opp);
+ rcu_read_unlock();
+ data->curr_freq = initial_freq;
+ data->curr_volt = initial_volt;
+
+ err = clk_set_rate(data->int_clk, initial_freq * 1000);
+ if (err) {
+ dev_err(dev, "Failed to set initial frequency\n");
+ goto err_opp_add;
+ }
+
+ err = exynos5_int_setvolt(data, initial_volt);
+ if (err)
+ goto err_opp_add;
+
+ platform_set_drvdata(pdev, data);
+
+ data->ppmu = exynos5_ppmu_get();
+ if (!data->ppmu)
+ goto err_ppmu_get;
+
+ INIT_DELAYED_WORK_DEFERRABLE(&data->work, exynos5_int_poll_work);
+
+ data->devfreq = devfreq_add_device(dev, &exynos5_devfreq_int_profile,
+ &devfreq_simple_ondemand,
+ &exynos5_int_ondemand_data);
+
+ if (IS_ERR(data->devfreq)) {
+ err = PTR_ERR(data->devfreq);
+ goto err_devfreq_add;
+ }
+
+ devfreq_register_opp_notifier(dev, data->devfreq);
+
+ pm_qos_add_request(&data->mif_req, PM_QOS_MEMORY_THROUGHPUT, -1);
+
+ mutex_lock(&exynos5_bus_int_data_lock);
+ exynos5_bus_int_data = data;
+ mutex_unlock(&exynos5_bus_int_data_lock);
+
+ exynos5_int_update(data);
+ exynos5_int_poll_start(data);
+
+ return 0;
+
+err_devfreq_add:
+ devfreq_remove_device(data->devfreq);
+err_ppmu_get:
+ platform_set_drvdata(pdev, NULL);
+err_opp_add:
+ clk_put(data->int_clk);
+err_clock:
+ regulator_put(data->vdd_int);
+err_regulator:
+ return err;
+}
+
+static __devexit int exynos5_busfreq_int_remove(struct platform_device *pdev)
+{
+ struct busfreq_data_int *data = platform_get_drvdata(pdev);
+
+ mutex_lock(&exynos5_bus_int_data_lock);
+ exynos5_bus_int_data = NULL;
+ mutex_unlock(&exynos5_bus_int_data_lock);
+
+ pm_qos_remove_request(&data->mif_req);
+ devfreq_remove_device(data->devfreq);
+ exynos5_int_poll_stop(data);
+ regulator_put(data->vdd_int);
+ clk_put(data->int_clk);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int exynos5_busfreq_int_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct opp *max_opp;
+ struct opp *opp;
+ unsigned long maxfreq = ULONG_MAX;
+ unsigned long volt;
+ unsigned long freq;
+ int err = 0;
+ struct busfreq_data_int *data = platform_get_drvdata(pdev);
+
+ exynos5_int_poll_stop(data);
+ /*
+ * Set the frequency to the maximum enabled frequency, but set the
+ * voltage to the maximum possible voltage in case the bootloader
+ * sets the frequency to maximum during resume.
+ */
+ mutex_lock(&data->lock);
+
+ data->disabled = true;
+
+ rcu_read_lock();
+ max_opp = opp_find_freq_floor(data->dev, &maxfreq);
+ if (IS_ERR(max_opp)) {
+ rcu_read_unlock();
+ err = PTR_ERR(max_opp);
+ goto unlock;
+ }
+
+ maxfreq = ULONG_MAX;
+ if (data->devfreq->max_freq)
+ maxfreq = data->devfreq->max_freq;
+
+ opp = opp_find_freq_floor(data->dev, &maxfreq);
+ if (IS_ERR(opp)) {
+ rcu_read_unlock();
+ err = PTR_ERR(opp);
+ goto unlock;
+ }
+
+ freq = opp_get_freq(opp);
+ volt = opp_get_voltage(max_opp);
+ rcu_read_unlock();
+
+ err = exynos5_int_setvolt(data, volt);
+ if (err)
+ goto unlock;
+
+ err = clk_set_rate(data->int_clk, freq * 1000);
+ if (err)
+ goto unlock;
+
+ data->suspend_freq = freq;
+
+unlock:
+ mutex_unlock(&data->lock);
+ return err;
+}
+
+static int exynos5_busfreq_int_resume_noirq(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ int err = 0;
+ struct busfreq_data_int *data = platform_get_drvdata(pdev);
+
+ /*
+ * Set the frequency to the maximum enabled frequency in case the
+ * bootloader raised it during resume.
+ */
+ mutex_lock(&data->lock);
+
+ err = clk_set_rate(data->int_clk, data->suspend_freq * 1000);
+ if (err)
+ goto unlock;
+
+unlock:
+ mutex_unlock(&data->lock);
+ return err;
+}
+
+static int exynos5_busfreq_int_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct busfreq_data_int *data = platform_get_drvdata(pdev);
+ int err = 0;
+
+ /*
+ * Restore the frequency and voltage to the values when suspend was
+ * started.
+ */
+ mutex_lock(&data->lock);
+
+ data->disabled = false;
+
+ err = clk_set_rate(data->int_clk, data->curr_freq * 1000);
+ if (err)
+ goto unlock;
+
+ err = exynos5_int_setvolt(data, data->curr_volt);
+ if (err)
+ goto unlock;
+
+unlock:
+ mutex_unlock(&data->lock);
+
+ if (!err)
+ exynos5_int_poll_start(data);
+
+ return err;
+}
+#endif
+
+static const struct dev_pm_ops exynos5_busfreq_int_pm = {
+ .suspend = exynos5_busfreq_int_suspend,
+ .resume_noirq = exynos5_busfreq_int_resume_noirq,
+ .resume = exynos5_busfreq_int_resume,
+};
+
+static struct platform_driver exynos5_busfreq_int_driver = {
+ .probe = exynos5_busfreq_int_probe,
+ .remove = __devexit_p(exynos5_busfreq_int_remove),
+ .driver = {
+ .name = "exynos5-bus-int",
+ .owner = THIS_MODULE,
+ .pm = &exynos5_busfreq_int_pm,
+ },
+};
+
+static int __init exynos5_busfreq_int_init(void)
+{
+ return platform_driver_register(&exynos5_busfreq_int_driver);
+}
+late_initcall(exynos5_busfreq_int_init);
+
+static void __exit exynos5_busfreq_int_exit(void)
+{
+ platform_driver_unregister(&exynos5_busfreq_int_driver);
+}
+module_exit(exynos5_busfreq_int_exit);
diff --git a/drivers/devfreq/exynos5_bus_mif.c b/drivers/devfreq/exynos5_bus_mif.c
new file mode 100644
index 0000000..20b5c08
--- /dev/null
+++ b/drivers/devfreq/exynos5_bus_mif.c
@@ -0,0 +1,750 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * EXYNOS - MIF clock frequency scaling support in DEVFREQ framework
+ * This version supports EXYNOS5250 only. This changes bus frequencies.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/suspend.h>
+#include <linux/opp.h>
+#include <linux/clk.h>
+#include <linux/devfreq.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/module.h>
+#include <linux/pm_qos.h>
+
+#include <mach/map.h>
+#include <mach/regs-clock.h>
+#include <mach/asv-exynos.h>
+#include <mach/abb-exynos.h>
+#include <mach/smc.h>
+#include <mach/regs-mem.h>
+#include <mach/exynos5_bus.h>
+
+#include "governor.h"
+
+#define MAX_SAFEVOLT 1200000 /* 1.2V */
+
+#define MIF_ABB_CONTROL_FREQUENCY 667000000
+#define MIF_UPPER_FREQUENCY 667000
+
+/* Assume that the bus is saturated if the utilization is 20% */
+#define MIF_BUS_SATURATION_RATIO 20
+
+enum mif_level_idx {
+ LV_0,
+ LV_1,
+ LV_2,
+ LV_3,
+ LV_4,
+ _LV_END
+};
+
+struct busfreq_data_mif {
+ struct device *dev;
+ struct devfreq *devfreq;
+ bool disabled;
+ struct regulator *vdd_mif;
+ unsigned long curr_freq;
+ unsigned long curr_volt;
+ unsigned long suspend_freq;
+
+ struct mutex lock;
+
+ struct clk *mif_clk;
+ struct clk *mclk_cdrex;
+ struct clk *mout_mpll;
+ struct clk *mout_bpll;
+};
+
+struct mif_bus_opp_table {
+ unsigned int idx;
+ unsigned long clk;
+ unsigned long volt;
+ unsigned long dmc_timingrow;
+};
+
+static struct mif_bus_opp_table exynos5_mif_opp_table[] = {
+ {LV_0, 800000, 1000000, 0x34498692},
+ {LV_1, 667000, 1000000, 0x2c48758f},
+ {LV_2, 400000, 1000000, 0x1A255349},
+ {LV_3, 160000, 1000000, 0x1A255349},
+ {LV_4, 100000, 1000000, 0x1A255349},
+ {0, 0, 0, 0},
+};
+
+struct exynos5_bus_mif_handle {
+ struct list_head node;
+ unsigned long min;
+};
+
+struct exynos5_bus_mif_handle *mif_min_hd;
+static struct busfreq_data_mif *exynos5_bus_mif_data;
+static DEFINE_MUTEX(exynos5_bus_mif_data_lock);
+static LIST_HEAD(exynos5_bus_mif_requests);
+static DEFINE_MUTEX(exynos5_bus_mif_requests_lock);
+static DEFINE_MUTEX(exynos5_bus_mif_upper_freq_lock);
+static bool multiple_windows = false;
+static unsigned int used_dev_cnt = 0;
+
+static void exynos5_mif_check_upper_freq(void)
+{
+ if (multiple_windows) {
+ if (!mif_min_hd) {
+ mif_min_hd = exynos5_bus_mif_min(MIF_UPPER_FREQUENCY);
+ if (!mif_min_hd)
+ pr_err("%s: Failed to request min_freq\n", __func__);
+ }
+ } else {
+ if (mif_min_hd) {
+ exynos5_bus_mif_put(mif_min_hd);
+ mif_min_hd = NULL;
+ }
+ }
+}
+
+void exynos5_mif_multiple_windows(bool state)
+{
+ mutex_lock(&exynos5_bus_mif_upper_freq_lock);
+
+ multiple_windows = state;
+ exynos5_mif_check_upper_freq();
+
+ mutex_unlock(&exynos5_bus_mif_upper_freq_lock);
+}
+
+void exynos5_mif_used_dev(bool power_on)
+{
+ mutex_lock(&exynos5_bus_mif_upper_freq_lock);
+
+ if (power_on)
+ used_dev_cnt++;
+ else if (used_dev_cnt > 0)
+ used_dev_cnt--;
+
+ exynos5_mif_check_upper_freq();
+
+ mutex_unlock(&exynos5_bus_mif_upper_freq_lock);
+}
+
+static int exynos5_mif_setvolt(struct busfreq_data_mif *data, unsigned long volt)
+{
+ return regulator_set_voltage(data->vdd_mif, volt, MAX_SAFEVOLT);
+}
+
+static int exynos5_mif_set_dmc_timing(unsigned int freq)
+{
+ int index;
+ unsigned int timing0 = 0;
+ unsigned int timing1 = 0;
+
+ for (index = LV_0; index < _LV_END; index++) {
+ if (freq == exynos5_mif_opp_table[index].clk)
+ break;
+ }
+
+ if (index == _LV_END)
+ return -EINVAL;
+
+#ifdef CONFIG_ARM_TRUSTZONE
+ exynos_smc_read_sfr(SMC_CMD_REG,
+ SMC_REG_ID_SFR_R(EXYNOS5_PA_DREXII +
+ EXYNOS_DMC_TIMINGROW_OFFSET),
+ &timing0, 0);
+
+ timing0 |= exynos5_mif_opp_table[index].dmc_timingrow;
+ timing1 = exynos5_mif_opp_table[index].dmc_timingrow;
+
+ exynos_smc(SMC_CMD_REG,
+ SMC_REG_ID_SFR_W(EXYNOS5_PA_DREXII +
+ EXYNOS_DMC_TIMINGROW_OFFSET),
+ timing0, 0);
+ exynos_smc(SMC_CMD_REG,
+ SMC_REG_ID_SFR_W(EXYNOS5_PA_DREXII +
+ EXYNOS_DMC_TIMINGROW_OFFSET),
+ timing1, 0);
+#else
+ timing0 = __raw_readl(S5P_VA_DREXII +
+ EXYNOS_DMC_TIMINGROW_OFFSET);
+ timing0 |= exynos5_mif_opp_table[index].dmc_timingrow;
+ timing1 = exynos5_mif_opp_table[index].dmc_timingrow;
+ __raw_writel(timing0, S5P_VA_DREXII + EXYNOS_DMC_TIMINGROW_OFFSET);
+ __raw_writel(timing1, S5P_VA_DREXII + EXYNOS_DMC_TIMINGROW_OFFSET);
+#endif
+ return 0;
+}
+static int exynos5_mif_setclk(struct busfreq_data_mif *data,
+ unsigned long new_freq)
+{
+ unsigned err = 0;
+ struct clk *old_p;
+ struct clk *new_p;
+ unsigned long old_p_rate;
+ unsigned long new_p_rate;
+ int div;
+
+ /*
+ * Dynamic ABB control according to MIF frequency
+ * MIF frquency > 667 MHz : ABB_MODE_130V
+ * MIF frquency <= 667 MHz : ABB_MODE_BYPASS
+ */
+ if (new_freq > MIF_ABB_CONTROL_FREQUENCY)
+ set_abb_member(ABB_MIF, ABB_MODE_130V);
+
+ old_p = clk_get_parent(data->mclk_cdrex);
+ if (IS_ERR(old_p))
+ return PTR_ERR(old_p);
+ old_p_rate = clk_get_rate(old_p);
+ div = DIV_ROUND_CLOSEST(old_p_rate, new_freq);
+
+ if (abs(DIV_ROUND_UP(old_p_rate, div) - new_freq) > 1000000) {
+ new_p = (old_p == data->mout_bpll) ? data->mout_mpll :
+ data->mout_bpll;
+ new_p_rate = clk_get_rate(new_p);
+
+ if (new_p_rate > old_p_rate) {
+ /*
+ * Needs to change to faster pll. Change the divider
+ * first, then switch to the new pll. This only works
+ * because the set_rate op on mif_clk doesn't know
+ * anything about its current parent, it just applies
+ * the dividers assuming the right pll has been selected
+ * for the requested frequency.
+ */
+ err = clk_set_rate(data->mif_clk, new_freq);
+ if (err) {
+ pr_info("clk_set_rate error %d\n", err);
+ goto out;
+ }
+
+ err = clk_set_parent(data->mclk_cdrex, new_p);
+ if (err) {
+ pr_info("clk_set_parent error %d\n", err);
+ goto out;
+ }
+ } else {
+ /*
+ * Needs to change to a slower pll. Switch to the new
+ * pll first, then apply the new divider.
+ */
+ err = clk_set_parent(data->mclk_cdrex, new_p);
+ if (err) {
+ pr_info("clk_set_parent error %d\n", err);
+ goto out;
+ }
+
+ err = clk_set_rate(data->mif_clk, new_freq);
+ if (err) {
+ pr_info("clk_set_rate error %d\n", err);
+ goto out;
+ }
+ }
+ } else {
+ /* No need to change pll */
+ err = clk_set_rate(data->mif_clk, new_freq);
+ }
+
+ if (new_freq <= MIF_ABB_CONTROL_FREQUENCY)
+ set_abb_member(ABB_MIF, ABB_MODE_BYPASS);
+out:
+ return err;
+}
+
+static int exynos5_busfreq_mif_target(struct device *dev, unsigned long *_freq,
+ u32 flags)
+{
+ int err = 0;
+ struct platform_device *pdev = container_of(dev, struct platform_device,
+ dev);
+ struct busfreq_data_mif *data = platform_get_drvdata(pdev);
+ struct opp *opp;
+ unsigned long old_freq, freq;
+ unsigned long volt;
+ struct exynos5_bus_mif_handle *handle;
+
+ mutex_lock(&exynos5_bus_mif_requests_lock);
+ list_for_each_entry(handle, &exynos5_bus_mif_requests, node) {
+ if (handle->min > *_freq) {
+ *_freq = handle->min;
+ flags &= ~DEVFREQ_FLAG_LEAST_UPPER_BOUND;
+ }
+ }
+ mutex_unlock(&exynos5_bus_mif_requests_lock);
+
+ mutex_lock(&data->lock);
+
+ if (data->devfreq->max_freq && *_freq > data->devfreq->max_freq) {
+ *_freq = data->devfreq->max_freq;
+ flags |= DEVFREQ_FLAG_LEAST_UPPER_BOUND;
+ }
+
+ rcu_read_lock();
+ opp = devfreq_recommended_opp(dev, _freq, flags);
+ if (IS_ERR(opp)) {
+ rcu_read_unlock();
+ dev_err(dev, "%s: Invalid OPP.\n", __func__);
+ err = PTR_ERR(opp);
+ goto out;
+ }
+
+ freq = opp_get_freq(opp);
+ volt = opp_get_voltage(opp);
+ rcu_read_unlock();
+
+ old_freq = data->curr_freq;
+
+ if (old_freq == freq)
+ goto out;
+
+ dev_dbg(dev, "targetting %lukHz %luuV\n", freq, volt);
+
+ if (data->disabled)
+ goto out;
+
+ if (old_freq < freq) {
+ err = exynos5_mif_setvolt(data, volt);
+ if (err)
+ goto out;
+ err = exynos5_mif_set_dmc_timing(freq);
+ if (err)
+ goto out;
+ }
+
+ err = exynos5_mif_setclk(data, freq * 1000);
+ if (err)
+ goto out;
+
+ if (old_freq > freq) {
+ err = exynos5_mif_set_dmc_timing(freq);
+ if (err)
+ goto out;
+ err = exynos5_mif_setvolt(data, volt);
+ if (err)
+ goto out;
+ }
+
+ data->curr_freq = freq;
+ data->curr_volt = volt;
+out:
+ mutex_unlock(&data->lock);
+ return err;
+}
+
+int exynos5_bus_mif_update(struct exynos5_bus_mif_handle *handle,
+ unsigned long min_freq)
+{
+ mutex_lock(&exynos5_bus_mif_requests_lock);
+ handle->min = min_freq;
+ mutex_unlock(&exynos5_bus_mif_requests_lock);
+
+ mutex_lock(&exynos5_bus_mif_data_lock);
+ if (exynos5_bus_mif_data) {
+ mutex_lock(&exynos5_bus_mif_data->devfreq->lock);
+ update_devfreq(exynos5_bus_mif_data->devfreq);
+ mutex_unlock(&exynos5_bus_mif_data->devfreq->lock);
+ }
+ mutex_unlock(&exynos5_bus_mif_data_lock);
+
+ return 0;
+}
+
+struct exynos5_bus_mif_handle *exynos5_bus_mif_get(unsigned long min_freq)
+{
+ struct exynos5_bus_mif_handle *handle;
+
+ handle = kzalloc(sizeof(*handle), GFP_KERNEL);
+ if (!handle)
+ return NULL;
+
+ handle->min = min_freq;
+
+ mutex_lock(&exynos5_bus_mif_requests_lock);
+ list_add_tail(&handle->node, &exynos5_bus_mif_requests);
+ mutex_unlock(&exynos5_bus_mif_requests_lock);
+
+ mutex_lock(&exynos5_bus_mif_data_lock);
+ if (exynos5_bus_mif_data) {
+ mutex_lock(&exynos5_bus_mif_data->devfreq->lock);
+ update_devfreq(exynos5_bus_mif_data->devfreq);
+ mutex_unlock(&exynos5_bus_mif_data->devfreq->lock);
+ }
+ mutex_unlock(&exynos5_bus_mif_data_lock);
+
+
+ return handle;
+}
+
+int exynos5_bus_mif_put(struct exynos5_bus_mif_handle *handle)
+{
+ int ret = 0;
+
+ mutex_lock(&exynos5_bus_mif_requests_lock);
+ list_del(&handle->node);
+ mutex_unlock(&exynos5_bus_mif_requests_lock);
+
+ mutex_lock(&exynos5_bus_mif_data_lock);
+ if (exynos5_bus_mif_data) {
+ mutex_lock(&exynos5_bus_mif_data->devfreq->lock);
+ update_devfreq(exynos5_bus_mif_data->devfreq);
+ mutex_unlock(&exynos5_bus_mif_data->devfreq->lock);
+ }
+ mutex_unlock(&exynos5_bus_mif_data_lock);
+
+ kfree(handle);
+
+ return ret;
+}
+
+
+static void exynos5_mif_exit(struct device *dev)
+{
+ struct platform_device *pdev = container_of(dev, struct platform_device,
+ dev);
+ struct busfreq_data_mif *data = platform_get_drvdata(pdev);
+
+ devfreq_unregister_opp_notifier(dev, data->devfreq);
+}
+
+static struct devfreq_dev_profile exynos5_devfreq_mif_profile = {
+ .initial_freq = 400000,
+ .target = exynos5_busfreq_mif_target,
+ .exit = exynos5_mif_exit,
+};
+
+static int exynos5250_init_mif_tables(struct busfreq_data_mif *data)
+{
+ int i, err = 0;
+
+ for (i = LV_0; i < _LV_END; i++) {
+ exynos5_mif_opp_table[i].volt = asv_get_volt(ID_MIF, exynos5_mif_opp_table[i].clk);
+ if (exynos5_mif_opp_table[i].volt == 0) {
+ dev_err(data->dev, "Invalid value for frequency %lu\n",
+ exynos5_mif_opp_table[i].clk);
+ continue;
+ }
+ err = opp_add(data->dev, exynos5_mif_opp_table[i].clk,
+ exynos5_mif_opp_table[i].volt);
+ if (err) {
+ dev_err(data->dev, "Cannot add opp entries.\n");
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+static int exynos5_bus_mif_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct opp *max_opp;
+ struct opp *opp;
+ unsigned long maxfreq = ULONG_MAX;
+ unsigned long volt;
+ unsigned long freq;
+ int err = 0;
+ struct busfreq_data_mif *data = platform_get_drvdata(pdev);
+
+ /*
+ * Set the frequency to the maximum enabled frequency, but set the
+ * voltage to the maximum possible voltage in case the bootloader
+ * sets the frequency to maximum during resume. Frequency can only
+ * go up, so set voltage and timing before clock.
+ */
+ mutex_lock(&data->lock);
+
+ data->disabled = true;
+
+ rcu_read_lock();
+ max_opp = opp_find_freq_floor(data->dev, &maxfreq);
+ if (IS_ERR(max_opp)) {
+ rcu_read_unlock();
+ err = PTR_ERR(max_opp);
+ goto unlock;
+ }
+
+ maxfreq = ULONG_MAX;
+ if (data->devfreq->max_freq)
+ maxfreq = data->devfreq->max_freq;
+
+ opp = opp_find_freq_floor(data->dev, &maxfreq);
+ if (IS_ERR(opp)) {
+ rcu_read_unlock();
+ err = PTR_ERR(opp);
+ goto unlock;
+ }
+
+ freq = opp_get_freq(opp);
+ volt = opp_get_voltage(max_opp);
+ rcu_read_unlock();
+
+ err = exynos5_mif_setvolt(data, volt);
+ if (err)
+ goto unlock;
+
+ err = exynos5_mif_set_dmc_timing(freq);
+
+ if (err)
+ goto unlock;
+
+ err = exynos5_mif_setclk(data, freq * 1000);
+ if (err)
+ goto unlock;
+
+ data->suspend_freq = freq;
+
+unlock:
+ mutex_unlock(&data->lock);
+ return err;
+}
+
+static int exynos5_bus_mif_resume_noirq(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ int err = 0;
+ struct busfreq_data_mif *data = platform_get_drvdata(pdev);
+
+ /*
+ * Set the frequency to the maximum enabled frequency in case the
+ * bootloader raised it during resume. Frequency can only go down,
+ * so set timing after updating clock.
+ */
+ mutex_lock(&data->lock);
+
+ err = exynos5_mif_set_dmc_timing(data->suspend_freq);
+ if (err)
+ goto unlock;
+
+ err = exynos5_mif_setclk(data, data->suspend_freq * 1000);
+ if (err)
+ goto unlock;
+
+unlock:
+ mutex_unlock(&data->lock);
+ return err;
+}
+
+static int exynos5_bus_mif_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct busfreq_data_mif *data = platform_get_drvdata(pdev);
+ int err = 0;
+
+ /*
+ * Restore the frequency and voltage to the values when suspend was
+ * started. Frequency can only go down, so set timing and voltage
+ * after updating clock.
+ */
+ mutex_lock(&data->lock);
+
+ data->disabled = false;
+
+ err = exynos5_mif_setclk(data, data->curr_freq * 1000);
+ if (err)
+ goto unlock;
+
+ err = exynos5_mif_set_dmc_timing(data->curr_freq);
+ if (err)
+ goto unlock;
+
+ err = exynos5_mif_setvolt(data, data->curr_volt);
+ if (err)
+ goto unlock;
+
+unlock:
+ mutex_unlock(&data->lock);
+ return err;
+}
+
+static struct devfreq_pm_qos_data exynos5_devfreq_mif_pm_qos_data = {
+ .bytes_per_sec_per_hz = 8,
+ .pm_qos_class = PM_QOS_MEMORY_THROUGHPUT,
+};
+
+static __devinit int exynos5_busfreq_mif_probe(struct platform_device *pdev)
+{
+ struct busfreq_data_mif *data;
+ struct opp *opp;
+ struct device *dev = &pdev->dev;
+ unsigned long initial_freq;
+ unsigned long initial_volt;
+ int err = 0;
+ struct exynos5_bus_mif_platform_data *pdata = pdev->dev.platform_data;
+
+ data = devm_kzalloc(&pdev->dev, sizeof(struct busfreq_data_mif), GFP_KERNEL);
+ if (data == NULL) {
+ dev_err(dev, "Cannot allocate memory.\n");
+ return -ENOMEM;
+ }
+
+ data->dev = dev;
+ mutex_init(&data->lock);
+
+ err = exynos5250_init_mif_tables(data);
+ if (err)
+ goto err_regulator;
+
+ data->vdd_mif = regulator_get(dev, "vdd_mif");
+ if (IS_ERR(data->vdd_mif)) {
+ dev_err(dev, "Cannot get the regulator \"vdd_mif\"\n");
+ err = PTR_ERR(data->vdd_mif);
+ goto err_regulator;
+ }
+
+ data->mif_clk = clk_get(dev, "mif_clk");
+ if (IS_ERR(data->mif_clk)) {
+ dev_err(dev, "Cannot get clock \"mif_clk\"\n");
+ err = PTR_ERR(data->mif_clk);
+ goto err_clock;
+ }
+
+ data->mclk_cdrex = clk_get(dev, "mclk_cdrex");
+ if (IS_ERR(data->mclk_cdrex)) {
+ dev_err(dev, "Cannot get clock \"mclk_crex\"\n");
+ err = PTR_ERR(data->mclk_cdrex);
+ goto err_mclk_cdrex;
+ }
+
+ data->mout_mpll = clk_get(dev, "mout_mpll");
+ if (IS_ERR(data->mout_mpll)) {
+ dev_err(dev, "Cannot get clock \"mout_mpll\"\n");
+ err = PTR_ERR(data->mout_mpll);
+ goto err_mout_mpll;
+ }
+
+ data->mout_bpll = clk_get(dev, "mout_bpll");
+ if (IS_ERR(data->mout_bpll)) {
+ dev_err(dev, "Cannot get clock \"mout_bpll\"\n");
+ err = PTR_ERR(data->mout_bpll);
+ goto err_mout_bpll;
+ }
+
+ if (pdata && pdata->max_freq)
+ exynos5_devfreq_mif_profile.initial_freq = pdata->max_freq;
+
+ rcu_read_lock();
+ opp = opp_find_freq_floor(dev, &exynos5_devfreq_mif_profile.initial_freq);
+ if (IS_ERR(opp)) {
+ rcu_read_unlock();
+ dev_err(dev, "Invalid initial frequency %lu kHz.\n",
+ exynos5_devfreq_mif_profile.initial_freq);
+ err = PTR_ERR(opp);
+ goto err_opp_add;
+ }
+ initial_freq = opp_get_freq(opp);
+ initial_volt = opp_get_voltage(opp);
+ rcu_read_unlock();
+
+ data->curr_freq = initial_freq;
+ data->curr_volt = initial_volt;
+
+ err = exynos5_mif_setclk(data, initial_freq * 1000);
+ if (err) {
+ dev_err(dev, "Failed to set initial frequency\n");
+ goto err_opp_add;
+ }
+
+ err = exynos5_mif_set_dmc_timing(initial_freq);
+ if (err) {
+ dev_err(dev, "Failed to set dmc timingrow\n");
+ goto err_opp_add;
+ }
+
+ err = exynos5_mif_setvolt(data, initial_volt);
+ if (err)
+ goto err_opp_add;
+
+ platform_set_drvdata(pdev, data);
+
+ data->devfreq = devfreq_add_device(dev, &exynos5_devfreq_mif_profile,
+ &devfreq_pm_qos,
+ &exynos5_devfreq_mif_pm_qos_data);
+
+ if (IS_ERR(data->devfreq)) {
+ err = PTR_ERR(data->devfreq);
+ goto err_devfreq_add;
+ }
+
+ if (pdata && pdata->max_freq)
+ data->devfreq->max_freq = pdata->max_freq;
+
+ devfreq_register_opp_notifier(dev, data->devfreq);
+
+ mutex_lock(&exynos5_bus_mif_data_lock);
+ exynos5_bus_mif_data = data;
+ mutex_unlock(&exynos5_bus_mif_data_lock);
+ return 0;
+
+err_devfreq_add:
+ devfreq_remove_device(data->devfreq);
+ platform_set_drvdata(pdev, NULL);
+err_opp_add:
+ clk_put(data->mout_bpll);
+err_mout_bpll:
+ clk_put(data->mout_mpll);
+err_mout_mpll:
+ clk_put(data->mclk_cdrex);
+err_mclk_cdrex:
+ clk_put(data->mif_clk);
+err_clock:
+ regulator_put(data->vdd_mif);
+err_regulator:
+ return err;
+}
+
+static __devexit int exynos5_busfreq_mif_remove(struct platform_device *pdev)
+{
+ struct busfreq_data_mif *data = platform_get_drvdata(pdev);
+
+ mutex_lock(&exynos5_bus_mif_data_lock);
+ exynos5_bus_mif_data = NULL;
+ mutex_unlock(&exynos5_bus_mif_data_lock);
+
+ devfreq_remove_device(data->devfreq);
+ regulator_put(data->vdd_mif);
+ clk_put(data->mif_clk);
+ clk_put(data->mclk_cdrex);
+ clk_put(data->mout_mpll);
+ clk_put(data->mout_bpll);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static const struct dev_pm_ops exynos5_bus_mif_pm_ops = {
+ .suspend = exynos5_bus_mif_suspend,
+ .resume_noirq = exynos5_bus_mif_resume_noirq,
+ .resume = exynos5_bus_mif_resume,
+};
+
+static struct platform_driver exynos5_busfreq_mif_driver = {
+ .probe = exynos5_busfreq_mif_probe,
+ .remove = __devexit_p(exynos5_busfreq_mif_remove),
+ .driver = {
+ .name = "exynos5-bus-mif",
+ .owner = THIS_MODULE,
+ .pm = &exynos5_bus_mif_pm_ops,
+ },
+};
+
+static int __init exynos5_busfreq_mif_init(void)
+{
+ return platform_driver_register(&exynos5_busfreq_mif_driver);
+}
+late_initcall(exynos5_busfreq_mif_init);
+
+static void __exit exynos5_busfreq_mif_exit(void)
+{
+ platform_driver_unregister(&exynos5_busfreq_mif_driver);
+}
+module_exit(exynos5_busfreq_mif_exit);
diff --git a/drivers/devfreq/exynos5_ppmu.c b/drivers/devfreq/exynos5_ppmu.c
new file mode 100644
index 0000000..43a0ae8
--- /dev/null
+++ b/drivers/devfreq/exynos5_ppmu.c
@@ -0,0 +1,427 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ * Jonghwan Choi <Jonghwan Choi@samsung.com>
+ *
+ * EXYNOS - PPMU polling support
+ * This version supports EXYNOS5250 only. This changes bus frequencies.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/debugfs.h>
+#include <linux/hrtimer.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+
+#include <mach/exynos5_bus.h>
+#include <mach/map.h>
+
+#include "exynos_ppmu.h"
+#include "exynos5_ppmu.h"
+
+#define CREATE_TRACE_POINTS
+#include <trace/events/memory_bus.h>
+
+#define FIXED_POINT_OFFSET 8
+#define FIXED_POINT_MASK ((1 << FIXED_POINT_OFFSET) - 1)
+
+enum exynos5_ppmu_list {
+ PPMU_DDR_C,
+ PPMU_DDR_R1,
+ PPMU_DDR_L,
+ PPMU_RIGHT,
+ PPMU_CPU,
+ PPMU_END,
+};
+
+static DEFINE_SPINLOCK(exynos5_ppmu_lock);
+static LIST_HEAD(exynos5_ppmu_handle_list);
+
+struct exynos5_ppmu_handle {
+ struct list_head node;
+ struct exynos_ppmu ppmu[PPMU_END];
+};
+
+static const char *exynos5_ppmu_name[PPMU_END] = {
+ [PPMU_DDR_C] = "DDR_C",
+ [PPMU_DDR_R1] = "DDR_R1",
+ [PPMU_DDR_L] = "DDR_L",
+ [PPMU_RIGHT] = "RIGHT",
+ [PPMU_CPU] = "CPU",
+};
+
+static struct exynos_ppmu ppmu[PPMU_END] = {
+ [PPMU_DDR_C] = {
+ .hw_base = S5P_VA_PPMU_DDR_C,
+ },
+ [PPMU_DDR_R1] = {
+ .hw_base = S5P_VA_PPMU_DDR_R1,
+ },
+ [PPMU_DDR_L] = {
+ .hw_base = S5P_VA_PPMU_DDR_L,
+ },
+ [PPMU_RIGHT] = {
+ .hw_base = S5P_VA_PPMU_RIGHT,
+ },
+ [PPMU_CPU] = {
+ .hw_base = S5P_VA_PPMU_CPU,
+ },
+};
+
+static struct exynos5_ppmu_handle *exynos5_ppmu_trace_handle;
+
+static void exynos5_ppmu_reset(struct exynos_ppmu *ppmu)
+{
+ unsigned long flags;
+
+ void __iomem *ppmu_base = ppmu->hw_base;
+
+ /* Reset PPMU */
+ exynos_ppmu_reset(ppmu_base);
+
+ /* Set PPMU Event */
+ ppmu->event[PPMU_PMNCNT0] = RD_DATA_COUNT;
+ exynos_ppmu_setevent(ppmu_base, PPMU_PMNCNT0,
+ ppmu->event[PPMU_PMNCNT0]);
+ ppmu->event[PPMU_PMCCNT1] = WR_DATA_COUNT;
+ exynos_ppmu_setevent(ppmu_base, PPMU_PMCCNT1,
+ ppmu->event[PPMU_PMCCNT1]);
+ ppmu->event[PPMU_PMNCNT3] = RDWR_DATA_COUNT;
+ exynos_ppmu_setevent(ppmu_base, PPMU_PMNCNT3,
+ ppmu->event[PPMU_PMNCNT3]);
+
+ local_irq_save(flags);
+ ppmu->reset_time = ktime_get();
+ /* Start PPMU */
+ exynos_ppmu_start(ppmu_base);
+ local_irq_restore(flags);
+}
+
+static void exynos5_ppmu_read(struct exynos_ppmu *ppmu)
+{
+ int j;
+ unsigned long flags;
+ ktime_t read_time;
+ ktime_t t;
+ u32 reg;
+
+ void __iomem *ppmu_base = ppmu->hw_base;
+
+ local_irq_save(flags);
+ read_time = ktime_get();
+ /* Stop PPMU */
+ exynos_ppmu_stop(ppmu_base);
+ local_irq_restore(flags);
+
+ /* Update local data from PPMU */
+ ppmu->ccnt = __raw_readl(ppmu_base + PPMU_CCNT);
+ reg = __raw_readl(ppmu_base + PPMU_FLAG);
+ ppmu->ccnt_overflow = reg & PPMU_CCNT_OVERFLOW;
+
+ for (j = PPMU_PMNCNT0; j < PPMU_PMNCNT_MAX; j++) {
+ if (ppmu->event[j] == 0)
+ ppmu->count[j] = 0;
+ else
+ ppmu->count[j] = exynos_ppmu_read(ppmu_base, j);
+ }
+ t = ktime_sub(read_time, ppmu->reset_time);
+ ppmu->ns = ktime_to_ns(t);
+}
+
+static void exynos5_ppmu_add(struct exynos_ppmu *to, struct exynos_ppmu *from)
+{
+ int i;
+ int j;
+
+ for (i = 0; i < PPMU_END; i++) {
+ for (j = PPMU_PMNCNT0; j < PPMU_PMNCNT_MAX; j++)
+ to[i].count[j] += from[i].count[j];
+
+ to[i].ccnt += from[i].ccnt;
+ if (to[i].ccnt < from[i].ccnt)
+ to[i].ccnt_overflow = true;
+
+ to[i].ns += from[i].ns;
+
+ if (from[i].ccnt_overflow)
+ to[i].ccnt_overflow = true;
+ }
+}
+
+static void exynos5_ppmu_handle_clear(struct exynos5_ppmu_handle *handle)
+{
+ memset(&handle->ppmu, 0, sizeof(struct exynos_ppmu) * PPMU_END);
+}
+
+static void exynos5_ppmu_update(void)
+{
+ int i;
+ struct exynos5_ppmu_handle *handle;
+
+ for (i = 0; i < PPMU_END; i++) {
+ exynos5_ppmu_read(&ppmu[i]);
+ exynos5_ppmu_reset(&ppmu[i]);
+ }
+
+ list_for_each_entry(handle, &exynos5_ppmu_handle_list, node)
+ exynos5_ppmu_add(handle->ppmu, ppmu);
+}
+
+static int exynos5_ppmu_get_filter(enum exynos_ppmu_sets filter,
+ enum exynos5_ppmu_list *start, enum exynos5_ppmu_list *end)
+{
+ switch (filter) {
+ case PPMU_SET_DDR:
+ *start = PPMU_DDR_C;
+ *end = PPMU_DDR_L;
+ break;
+ case PPMU_SET_RIGHT:
+ *start = PPMU_RIGHT;
+ *end = PPMU_RIGHT;
+ break;
+ case PPMU_SET_CPU:
+ *start = PPMU_CPU;
+ *end = PPMU_CPU;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int exynos5_ppmu_get_busy(struct exynos5_ppmu_handle *handle,
+ enum exynos_ppmu_sets filter)
+{
+ unsigned long flags;
+ int i;
+ int busy = 0;
+ int temp;
+ enum exynos5_ppmu_list start;
+ enum exynos5_ppmu_list end;
+ int ret;
+
+ ret = exynos5_ppmu_get_filter(filter, &start, &end);
+ if (ret < 0)
+ return ret;
+
+ spin_lock_irqsave(&exynos5_ppmu_lock, flags);
+
+ exynos5_ppmu_update();
+
+ for (i = start; i <= end; i++) {
+ if (handle->ppmu[i].ccnt_overflow) {
+ busy = -EOVERFLOW;
+ break;
+ }
+ temp = handle->ppmu[i].count[PPMU_PMNCNT3] * 100;
+ if (handle->ppmu[i].ccnt > 0)
+ temp /= handle->ppmu[i].ccnt;
+ if (temp > busy)
+ busy = temp;
+ }
+
+ exynos5_ppmu_handle_clear(handle);
+
+ spin_unlock_irqrestore(&exynos5_ppmu_lock, flags);
+
+ return busy;
+}
+
+void exynos5_ppmu_put(struct exynos5_ppmu_handle *handle)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&exynos5_ppmu_lock, flags);
+
+ list_del(&handle->node);
+
+ spin_unlock_irqrestore(&exynos5_ppmu_lock, flags);
+
+ kfree(handle);
+}
+
+struct exynos5_ppmu_handle *exynos5_ppmu_get(void)
+{
+ struct exynos5_ppmu_handle *handle;
+ unsigned long flags;
+
+ handle = kzalloc(sizeof(struct exynos5_ppmu_handle), GFP_KERNEL);
+ if (!handle)
+ return NULL;
+
+ spin_lock_irqsave(&exynos5_ppmu_lock, flags);
+
+ exynos5_ppmu_update();
+ list_add_tail(&handle->node, &exynos5_ppmu_handle_list);
+
+ spin_unlock_irqrestore(&exynos5_ppmu_lock, flags);
+
+ return handle;
+}
+
+void exynos5_ppmu_trace(void)
+{
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&exynos5_ppmu_lock, flags);
+
+ exynos5_ppmu_update();
+
+ for (i = 0; i < PPMU_END; i++) {
+ struct exynos_ppmu *ppmu = &exynos5_ppmu_trace_handle->ppmu[i];
+ if (!ppmu->ccnt_overflow)
+ trace_memory_bus_usage(exynos5_ppmu_name[i],
+ ppmu->count[PPMU_PMNCNT3] * 16ULL,
+ ppmu->count[PPMU_PMNCNT0] * 16ULL,
+ ppmu->count[PPMU_PMCCNT1] * 16ULL,
+ ppmu->ccnt,
+ ppmu->ns);
+ }
+
+ exynos5_ppmu_handle_clear(exynos5_ppmu_trace_handle);
+
+ spin_unlock_irqrestore(&exynos5_ppmu_lock, flags);
+}
+
+static int exynos5_ppmu_trace_init(void)
+{
+ exynos5_ppmu_trace_handle = exynos5_ppmu_get();
+ return 0;
+}
+late_initcall(exynos5_ppmu_trace_init);
+
+static void exynos5_ppmu_debug_compute(struct exynos_ppmu *ppmu,
+ enum ppmu_counter i, u32 *sat, u32 *freq, u32 *bw)
+{
+ u64 ns = ppmu->ns;
+ u32 busy = ppmu->count[i];
+ u32 total = ppmu->ccnt;
+
+ u64 s;
+ u64 f;
+ u64 b;
+
+ s = (u64)busy * 100 * (1 << FIXED_POINT_OFFSET);
+ s += total / 2;
+ do_div(s, total);
+
+ f = (u64)total * 1000 * (1 << FIXED_POINT_OFFSET);
+ f += ns / 2;
+ f = div64_u64(f, ns);
+
+ b = (u64)busy * (128 / 8) * 1000 * (1 << FIXED_POINT_OFFSET);
+ b += ns / 2;
+ b = div64_u64(b, ns);
+
+ *sat = s;
+ *freq = f;
+ *bw = b;
+}
+
+static void exynos5_ppmu_debug_show_one_counter(struct seq_file *s,
+ const char *name, const char *type, struct exynos_ppmu *ppmu,
+ enum ppmu_counter i, u32 *bw_total)
+{
+ u32 sat;
+ u32 freq;
+ u32 bw;
+
+ exynos5_ppmu_debug_compute(ppmu, i, &sat, &freq, &bw);
+
+ seq_printf(s, "%-10s %-10s %4u.%02u MBps %3u.%02u MHz %2u.%02u%%\n",
+ name, type,
+ bw >> FIXED_POINT_OFFSET,
+ (bw & FIXED_POINT_MASK) * 100 / (1 << FIXED_POINT_OFFSET),
+ freq >> FIXED_POINT_OFFSET,
+ (freq & FIXED_POINT_MASK) * 100 / (1 << FIXED_POINT_OFFSET),
+ sat >> FIXED_POINT_OFFSET,
+ (sat & FIXED_POINT_MASK) * 100 / (1 << FIXED_POINT_OFFSET));
+
+ *bw_total += bw;
+}
+
+static void exynos5_ppmu_debug_show_one(struct seq_file *s,
+ const char *name, struct exynos_ppmu *ppmu,
+ u32 *bw_total)
+{
+ exynos5_ppmu_debug_show_one_counter(s, name, "read+write",
+ ppmu, PPMU_PMNCNT3, &bw_total[PPMU_PMNCNT3]);
+ exynos5_ppmu_debug_show_one_counter(s, "", "read",
+ ppmu, PPMU_PMNCNT0, &bw_total[PPMU_PMNCNT0]);
+ exynos5_ppmu_debug_show_one_counter(s, "", "write",
+ ppmu, PPMU_PMCCNT1, &bw_total[PPMU_PMCCNT1]);
+
+}
+
+static int exynos5_ppmu_debug_show(struct seq_file *s, void *d)
+{
+ int i;
+ u32 bw_total[PPMU_PMNCNT_MAX];
+ struct exynos5_ppmu_handle *handle;
+ unsigned long flags;
+
+ memset(bw_total, 0, sizeof(bw_total));
+
+ handle = exynos5_ppmu_get();
+ msleep(100);
+
+ spin_lock_irqsave(&exynos5_ppmu_lock, flags);
+
+ exynos5_ppmu_update();
+
+ for (i = 0; i < PPMU_CPU; i++)
+ exynos5_ppmu_debug_show_one(s, exynos5_ppmu_name[i],
+ &handle->ppmu[i], bw_total);
+
+ seq_printf(s, "%-10s %-10s %4u.%02u MBps\n", "total", "read+write",
+ bw_total[PPMU_PMNCNT3] >> FIXED_POINT_OFFSET,
+ (bw_total[PPMU_PMNCNT3] & FIXED_POINT_MASK) *
+ 100 / (1 << FIXED_POINT_OFFSET));
+ seq_printf(s, "%-10s %-10s %4u.%02u MBps\n", "", "read",
+ bw_total[PPMU_PMNCNT0] >> FIXED_POINT_OFFSET,
+ (bw_total[PPMU_PMNCNT0] & FIXED_POINT_MASK) *
+ 100 / (1 << FIXED_POINT_OFFSET));
+ seq_printf(s, "%-10s %-10s %4u.%02u MBps\n", "", "write",
+ bw_total[PPMU_PMCCNT1] >> FIXED_POINT_OFFSET,
+ (bw_total[PPMU_PMCCNT1] & FIXED_POINT_MASK) *
+ 100 / (1 << FIXED_POINT_OFFSET));
+
+ seq_printf(s, "\n");
+
+ exynos5_ppmu_debug_show_one(s, exynos5_ppmu_name[PPMU_CPU],
+ &ppmu[PPMU_CPU], bw_total);
+
+ spin_unlock_irqrestore(&exynos5_ppmu_lock, flags);
+
+ exynos5_ppmu_put(handle);
+
+ return 0;
+}
+
+static int exynos5_ppmu_debug_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, exynos5_ppmu_debug_show, inode->i_private);
+}
+
+const static struct file_operations exynos5_ppmu_debug_fops = {
+ .open = exynos5_ppmu_debug_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int __init exynos5_ppmu_debug_init(void)
+{
+ debugfs_create_file("exynos5_bus", S_IRUGO, NULL, NULL,
+ &exynos5_ppmu_debug_fops);
+ return 0;
+}
+late_initcall(exynos5_ppmu_debug_init);
diff --git a/drivers/devfreq/exynos5_ppmu.h b/drivers/devfreq/exynos5_ppmu.h
new file mode 100644
index 0000000..3105ccd
--- /dev/null
+++ b/drivers/devfreq/exynos5_ppmu.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * EXYNOS5 - PPMU support
+ *
+ * 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.
+*/
+
+#ifndef __DEVFREQ_EXYNOS5_PPMU_H
+#define __DEVFREQ_EXYNOS5_PPMU_H __FILE__
+
+enum exynos_ppmu_sets {
+ PPMU_SET_DDR,
+ PPMU_SET_RIGHT,
+ PPMU_SET_CPU,
+};
+
+struct exynos5_ppmu_handle;
+
+struct exynos5_ppmu_handle *exynos5_ppmu_get(void);
+void exynos5_ppmu_put(struct exynos5_ppmu_handle *handle);
+int exynos5_ppmu_get_busy(struct exynos5_ppmu_handle *handle,
+ enum exynos_ppmu_sets filter);
+
+#endif /* __DEVFREQ_EXYNOS5_PPMU_H */
+
diff --git a/drivers/devfreq/exynos_ppmu.c b/drivers/devfreq/exynos_ppmu.c
new file mode 100644
index 0000000..fa2dfbb
--- /dev/null
+++ b/drivers/devfreq/exynos_ppmu.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * EXYNOS - PPMU support
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/err.h>
+#include <linux/io.h>
+
+#include "exynos_ppmu.h"
+
+/* For PPMU Control */
+#define PPMU_ENABLE BIT(0)
+#define PPMU_DISABLE 0x0
+#define PPMU_CYCLE_RESET BIT(1)
+#define PPMU_COUNTER_RESET BIT(2)
+
+#define PPMU_ENABLE_COUNT0 BIT(0)
+#define PPMU_ENABLE_COUNT1 BIT(1)
+#define PPMU_ENABLE_COUNT2 BIT(2)
+#define PPMU_ENABLE_COUNT3 BIT(3)
+#define PPMU_ENABLE_CYCLE BIT(31)
+
+void exynos_ppmu_reset(void __iomem *ppmu_base)
+{
+ __raw_writel(PPMU_CYCLE_RESET | PPMU_COUNTER_RESET, ppmu_base);
+ __raw_writel(PPMU_ENABLE_CYCLE |
+ PPMU_ENABLE_COUNT0 |
+ PPMU_ENABLE_COUNT1 |
+ PPMU_ENABLE_COUNT2 |
+ PPMU_ENABLE_COUNT3,
+ ppmu_base + PPMU_CNTENS);
+}
+
+void exynos_ppmu_setevent(void __iomem *ppmu_base,
+ unsigned int ch,
+ unsigned int evt)
+{
+ __raw_writel(evt, ppmu_base + PPMU_BEVTSEL(ch));
+}
+
+void exynos_ppmu_start(void __iomem *ppmu_base)
+{
+ __raw_writel(PPMU_ENABLE, ppmu_base);
+}
+
+void exynos_ppmu_stop(void __iomem *ppmu_base)
+{
+ __raw_writel(PPMU_DISABLE, ppmu_base);
+}
+
+unsigned int exynos_ppmu_read(void __iomem *ppmu_base,
+ unsigned int ch)
+{
+ unsigned int total;
+
+ if (ch == PPMU_PMNCNT3)
+ total = ((__raw_readl(ppmu_base + PMCNT_OFFSET(ch)) << 8) |
+ __raw_readl(ppmu_base + PMCNT_OFFSET(ch + 1)));
+ else
+ total = __raw_readl(ppmu_base + PMCNT_OFFSET(ch));
+
+ return total;
+}
diff --git a/drivers/devfreq/exynos_ppmu.h b/drivers/devfreq/exynos_ppmu.h
new file mode 100644
index 0000000..272b663
--- /dev/null
+++ b/drivers/devfreq/exynos_ppmu.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * EXYNOS - PPMU support
+ *
+ * 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.
+*/
+
+#ifndef __DEVFREQ_EXYNOS_PPMU_H
+#define __DEVFREQ_EXYNOS_PPMU_H __FILE__
+
+#include <linux/ktime.h>
+
+#define PPMU_CNTENS 0x10
+
+#define PPMU_FLAG 0x50
+#define PPMU_CCNT_OVERFLOW BIT(31)
+#define PPMU_CCNT 0x100
+#define PPMU_PMCNT0 0x110
+#define PPMU_PMCNT_OFFSET 0x10
+#define PMCNT_OFFSET(x) (PPMU_PMCNT0 + (PPMU_PMCNT_OFFSET * x))
+
+#define PPMU_BEVT0SEL 0x1000
+#define PPMU_BEVTSEL_OFFSET 0x100
+#define PPMU_BEVTSEL(x) (PPMU_BEVT0SEL + (ch * PPMU_BEVTSEL_OFFSET))
+
+#define PPMU_CNT_RESET 0x1800
+
+/* For Event Selection */
+#define RD_DATA_COUNT 0x5
+#define WR_DATA_COUNT 0x6
+#define RDWR_DATA_COUNT 0x7
+
+enum ppmu_counter {
+ PPMU_PMNCNT0,
+ PPMU_PMCCNT1,
+ PPMU_PMNCNT2,
+ PPMU_PMNCNT3,
+ PPMU_PMNCNT_MAX,
+};
+
+struct bus_opp_table {
+ unsigned int idx;
+ unsigned long clk;
+ unsigned long volt;
+};
+
+struct exynos_ppmu {
+ void __iomem *hw_base;
+ unsigned int ccnt;
+ unsigned int event[PPMU_PMNCNT_MAX];
+ unsigned int count[PPMU_PMNCNT_MAX];
+ unsigned long long ns;
+ ktime_t reset_time;
+ bool ccnt_overflow;
+ bool count_overflow[PPMU_PMNCNT_MAX];
+};
+
+void exynos_ppmu_reset(void __iomem *ppmu_base);
+void exynos_ppmu_setevent(void __iomem *ppmu_base,
+ unsigned int ch,
+ unsigned int evt);
+void exynos_ppmu_start(void __iomem *ppmu_base);
+void exynos_ppmu_stop(void __iomem *ppmu_base);
+unsigned int exynos_ppmu_read(void __iomem *ppmu_base,
+ unsigned int ch);
+#endif /* __DEVFREQ_EXYNOS_PPMU_H */
+
diff --git a/drivers/devfreq/governor_pm_qos.c b/drivers/devfreq/governor_pm_qos.c
new file mode 100644
index 0000000..2e3317c
--- /dev/null
+++ b/drivers/devfreq/governor_pm_qos.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2012 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 <linux/kernel.h>
+#include <linux/devfreq.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/pm_qos.h>
+#include <linux/slab.h>
+#include "governor.h"
+
+struct devfreq_pm_qos_notifier_block {
+ struct list_head node;
+ struct notifier_block nb;
+ struct devfreq *df;
+};
+
+static LIST_HEAD(devfreq_pm_qos_list);
+static DEFINE_MUTEX(devfreq_pm_qos_mutex);
+
+static int devfreq_pm_qos_func(struct devfreq *df, unsigned long *freq)
+{
+ struct devfreq_pm_qos_data *data = df->data;
+ int megabytes_per_sec;
+ unsigned long kbytes_per_sec;
+
+ megabytes_per_sec = pm_qos_request(data->pm_qos_class);
+ if (megabytes_per_sec > 0) {
+ kbytes_per_sec = megabytes_per_sec * 1000;
+ *freq = kbytes_per_sec / data->bytes_per_sec_per_hz;
+ } else {
+ *freq = 0;
+ }
+
+ return 0;
+}
+
+static int devfreq_pm_qos_notifier(struct notifier_block *nb, unsigned long val,
+ void *v)
+{
+ struct devfreq_pm_qos_notifier_block *pq_nb;
+
+ pq_nb = container_of(nb, struct devfreq_pm_qos_notifier_block, nb);
+ mutex_lock(&pq_nb->df->lock);
+ update_devfreq(pq_nb->df);
+ mutex_unlock(&pq_nb->df->lock);
+
+ return NOTIFY_OK;
+}
+
+static int devfreq_pm_qos_init(struct devfreq *df)
+{
+ int ret;
+ struct devfreq_pm_qos_notifier_block *pq_nb;
+ struct devfreq_pm_qos_data *data = df->data;
+
+ if (!data)
+ return -EINVAL;
+
+ if (!data->bytes_per_sec_per_hz)
+ return -EINVAL;
+
+ pq_nb = kzalloc(sizeof(*pq_nb), GFP_KERNEL);
+ if (!pq_nb)
+ return -ENOMEM;
+
+ pq_nb->df = df;
+ pq_nb->nb.notifier_call = devfreq_pm_qos_notifier;
+ INIT_LIST_HEAD(&pq_nb->node);
+
+ ret = pm_qos_add_notifier(data->pm_qos_class, &pq_nb->nb);
+ if (ret < 0)
+ goto err;
+
+ mutex_lock(&devfreq_pm_qos_mutex);
+ list_add_tail(&pq_nb->node, &devfreq_pm_qos_list);
+ mutex_unlock(&devfreq_pm_qos_mutex);
+
+ return 0;
+
+err:
+ kfree(pq_nb);
+
+ return ret;
+}
+
+static void devfreq_pm_qos_exit(struct devfreq *df)
+{
+ struct devfreq_pm_qos_notifier_block *pq_nb;
+ struct devfreq_pm_qos_data *data;
+
+ mutex_lock(&devfreq_pm_qos_mutex);
+
+ list_for_each_entry(pq_nb, &devfreq_pm_qos_list, node) {
+ if (pq_nb->df == df) {
+ data = pq_nb->df->data;
+ pm_qos_remove_notifier(data->pm_qos_class, &pq_nb->nb);
+ goto out;
+ }
+ }
+
+out:
+ mutex_unlock(&devfreq_pm_qos_mutex);
+}
+
+const struct devfreq_governor devfreq_pm_qos = {
+ .name = "pm_qos",
+ .get_target_freq = devfreq_pm_qos_func,
+ .init = devfreq_pm_qos_init,
+ .exit = devfreq_pm_qos_exit,
+ .no_central_polling = true,
+};
diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
index 8c44f17a..b47f0c1 100644
--- a/drivers/dma/pl330.c
+++ b/drivers/dma/pl330.c
@@ -29,6 +29,7 @@
#include <linux/of.h>
#include "dmaengine.h"
+
#define PL330_MAX_CHAN 8
#define PL330_MAX_IRQS 32
#define PL330_MAX_PERI 32
@@ -393,6 +394,7 @@
struct pl330_reqcfg *cfg;
/* Pointer to first xfer in the request. */
struct pl330_xfer *x;
+ unsigned int infiniteloop;
};
/*
@@ -1324,6 +1326,75 @@
return off;
}
+/* Returns bytes consumed */
+static inline int _loop_infiniteloop(unsigned dry_run, u8 buf[],
+ unsigned long bursts, const struct _xfer_spec *pxs, int ev)
+{
+ int cyc, off;
+ unsigned lcnt0, lcnt1, ljmp0, ljmp1, ljmpfe;
+ struct _arg_LPEND lpend;
+
+ off = 0;
+ ljmpfe = off;
+ lcnt0 = pxs->r->infiniteloop;
+
+ if (bursts > 256) {
+ lcnt1 = 256;
+ cyc = bursts / 256;
+ } else {
+ lcnt1 = bursts;
+ cyc = 1;
+ }
+
+ /* forever loop */
+ off += _emit_MOV(dry_run, &buf[off], SAR, pxs->x->src_addr);
+ off += _emit_MOV(dry_run, &buf[off], DAR, pxs->x->dst_addr);
+
+ /* loop0 */
+ off += _emit_LP(dry_run, &buf[off], 0, lcnt0);
+ ljmp0 = off;
+
+ /* loop1 */
+ off += _emit_LP(dry_run, &buf[off], 1, lcnt1);
+ ljmp1 = off;
+ off += _bursts(dry_run, &buf[off], pxs, cyc);
+ lpend.cond = ALWAYS;
+ lpend.forever = false;
+ lpend.loop = 1;
+ lpend.bjump = off - ljmp1;
+ off += _emit_LPEND(dry_run, &buf[off], &lpend);
+
+ /* remainder */
+ lcnt1 = bursts - (lcnt1 * cyc);
+
+ if (lcnt1) {
+ off += _emit_LP(dry_run, &buf[off], 1, lcnt1);
+ ljmp1 = off;
+ off += _bursts(dry_run, &buf[off], pxs, 1);
+ lpend.cond = ALWAYS;
+ lpend.forever = false;
+ lpend.loop = 1;
+ lpend.bjump = off - ljmp1;
+ off += _emit_LPEND(dry_run, &buf[off], &lpend);
+ }
+
+ off += _emit_SEV(dry_run, &buf[off], ev);
+
+ lpend.cond = ALWAYS;
+ lpend.forever = false;
+ lpend.loop = 0;
+ lpend.bjump = off - ljmp0;
+ off += _emit_LPEND(dry_run, &buf[off], &lpend);
+
+ lpend.cond = ALWAYS;
+ lpend.forever = true;
+ lpend.loop = 1;
+ lpend.bjump = off - ljmpfe;
+ off += _emit_LPEND(dry_run, &buf[off], &lpend);
+
+ return off;
+}
+
/* Returns bytes consumed and updates bursts */
static inline int _loop(unsigned dry_run, u8 buf[],
unsigned long *bursts, const struct _xfer_spec *pxs)
@@ -1403,6 +1474,20 @@
return off;
}
+static inline int _setup_xfer_infiniteloop(unsigned dry_run, u8 buf[],
+ const struct _xfer_spec *pxs, int ev)
+{
+ struct pl330_xfer *x = pxs->x;
+ u32 ccr = pxs->ccr;
+ unsigned long bursts = BYTE_TO_BURST(x->bytes, ccr);
+ int off = 0;
+
+ /* Setup Loop(s) */
+ off += _loop_infiniteloop(dry_run, &buf[off], bursts, pxs, ev);
+
+ return off;
+}
+
static inline int _setup_loops(unsigned dry_run, u8 buf[],
const struct _xfer_spec *pxs)
{
@@ -1455,21 +1540,32 @@
off += _emit_MOV(dry_run, &buf[off], CCR, pxs->ccr);
x = pxs->r->x;
- do {
+ if (!pxs->r->infiniteloop) {
+ do {
+ /* Error if xfer length is not aligned at burst size */
+ if (x->bytes % (BRST_SIZE(pxs->ccr) *
+ BRST_LEN(pxs->ccr)))
+ return -EINVAL;
+
+ pxs->x = x;
+ off += _setup_xfer(dry_run, &buf[off], pxs);
+
+ x = x->next;
+ } while (x);
+
+ /* DMASEV peripheral/event */
+ off += _emit_SEV(dry_run, &buf[off], thrd->ev);
+ /* DMAEND */
+ off += _emit_END(dry_run, &buf[off]);
+ } else {
/* Error if xfer length is not aligned at burst size */
if (x->bytes % (BRST_SIZE(pxs->ccr) * BRST_LEN(pxs->ccr)))
return -EINVAL;
pxs->x = x;
- off += _setup_xfer(dry_run, &buf[off], pxs);
-
- x = x->next;
- } while (x);
-
- /* DMASEV peripheral/event */
- off += _emit_SEV(dry_run, &buf[off], thrd->ev);
- /* DMAEND */
- off += _emit_END(dry_run, &buf[off]);
+ off += _setup_xfer_infiniteloop(dry_run, &buf[off],
+ pxs, thrd->ev);
+ }
return off;
}
@@ -1752,10 +1848,12 @@
continue;
rqdone = &thrd->req[active];
- mark_free(thrd, active);
+ if (!rqdone->r->infiniteloop) {
+ mark_free(thrd, active);
- /* Get going again ASAP */
- _start(thrd);
+ /* Get going again ASAP */
+ _start(thrd);
+ }
/* For now, just make a list of callbacks to be done */
list_add_tail(&rqdone->rqd, &pl330->req_done);
@@ -1773,7 +1871,8 @@
/* Detach the req */
r = rqdone->r;
- rqdone->r = NULL;
+ if (!r->infiniteloop)
+ rqdone->r = NULL;
spin_unlock_irqrestore(&pl330->lock, flags);
_callback(r, PL330_ERR_NONE);
@@ -2316,13 +2415,14 @@
struct dma_pl330_desc *desc, *_dt;
unsigned long flags;
LIST_HEAD(list);
-
spin_lock_irqsave(&pch->lock, flags);
/* Pick up ripe tomatoes */
list_for_each_entry_safe(desc, _dt, &pch->work_list, node)
if (desc->status == DONE) {
- if (!pch->cyclic)
+ if (pch->cyclic)
+ pch->chan.completed_cookie = desc->txd.cookie;
+ else
dma_cookie_complete(&desc->txd);
list_move_tail(&desc->node, &list);
}
@@ -2392,6 +2492,8 @@
struct dma_pl330_dmac *pdmac = pch->dmac;
unsigned long flags;
+ pm_runtime_get_sync(pdmac->pif.dev);
+
spin_lock_irqsave(&pch->lock, flags);
dma_cookie_init(chan);
@@ -2403,8 +2505,6 @@
return 0;
}
- tasklet_init(&pch->task, pl330_tasklet, (unsigned long) pch);
-
spin_unlock_irqrestore(&pch->lock, flags);
return 1;
@@ -2469,8 +2569,6 @@
spin_lock_irqsave(&pch->lock, flags);
- tasklet_kill(&pch->task);
-
pl330_release_channel(pch->pl330_chid);
pch->pl330_chid = NULL;
@@ -2478,6 +2576,8 @@
list_splice_tail_init(&pch->work_list, &pch->dmac->desc_pool);
spin_unlock_irqrestore(&pch->lock, flags);
+
+ pm_runtime_put_sync(pch->dmac->pif.dev);
}
static enum dma_status
@@ -2619,6 +2719,7 @@
desc->txd.cookie = 0;
async_tx_ack(&desc->txd);
+ desc->req.infiniteloop = 0;
desc->req.peri = peri_id ? pch->chan.chan_id : 0;
desc->rqcfg.pcfg = &pch->dmac->pif.pcfg;
@@ -2696,6 +2797,7 @@
struct dma_pl330_chan *pch = to_pchan(chan);
dma_addr_t dst;
dma_addr_t src;
+ unsigned int *infinite = context;
desc = pl330_get_desc(pch);
if (!desc) {
@@ -2727,6 +2829,7 @@
desc->rqcfg.brst_size = pch->burst_sz;
desc->rqcfg.brst_len = 1;
+ desc->req.infiniteloop = *infinite;
pch->cyclic = true;
@@ -2761,7 +2864,7 @@
burst = pi->pcfg.data_bus_width / 8;
while (burst > 1) {
- if (!(len % burst))
+ if (!(len % burst) && !(dst % burst) && !(src % burst))
break;
burst /= 2;
}
@@ -2859,6 +2962,28 @@
return IRQ_NONE;
}
+int pl330_dma_getposition(struct dma_chan *chan,
+ dma_addr_t *src, dma_addr_t *dst)
+{
+ struct dma_pl330_chan *pch = to_pchan(chan);
+ struct pl330_info *pi;
+ void __iomem *regs;
+ struct pl330_thread *thrd;
+
+ if (unlikely(!pch))
+ return -EINVAL;
+
+ thrd = pch->pl330_chid;
+ pi = &pch->dmac->pif;
+ regs = pi->base;
+
+ *src = readl(regs + SA(thrd->id));
+ *dst = readl(regs + DA(thrd->id));
+
+ return 0;
+}
+EXPORT_SYMBOL(pl330_dma_getposition);
+
static int __devinit
pl330_probe(struct amba_device *adev, const struct amba_id *id)
{
@@ -2894,29 +3019,19 @@
goto probe_err1;
}
- pdmac->clk = clk_get(&adev->dev, "dma");
- if (IS_ERR(pdmac->clk)) {
- dev_err(&adev->dev, "Cannot get operation clock.\n");
- ret = -EINVAL;
- goto probe_err2;
- }
+ pdmac->clk = adev->pclk;
amba_set_drvdata(adev, pdmac);
-#ifndef CONFIG_PM_RUNTIME
- /* enable dma clk */
- clk_enable(pdmac->clk);
-#endif
-
irq = adev->irq[0];
ret = request_irq(irq, pl330_irq_handler, 0,
dev_name(&adev->dev), pi);
if (ret)
- goto probe_err3;
+ goto probe_err2;
ret = pl330_add(pi);
if (ret)
- goto probe_err4;
+ goto probe_err3;
INIT_LIST_HEAD(&pdmac->desc_pool);
spin_lock_init(&pdmac->pool_lock);
@@ -2949,6 +3064,8 @@
pch->chan.device = pd;
pch->dmac = pdmac;
+ tasklet_init(&pch->task, pl330_tasklet, (unsigned long)pch);
+
/* Add the channel to the DMAC list */
list_add_tail(&pch->chan.device_node, &pd->channels);
}
@@ -2976,7 +3093,7 @@
ret = dma_async_device_register(pd);
if (ret) {
dev_err(&adev->dev, "unable to register DMAC\n");
- goto probe_err5;
+ goto probe_err4;
}
dev_info(&adev->dev,
@@ -2987,17 +3104,18 @@
pi->pcfg.data_bus_width / 8, pi->pcfg.num_chan,
pi->pcfg.num_peri, pi->pcfg.num_events);
+ pm_runtime_put_sync(&adev->dev);
+
return 0;
-probe_err5:
- pl330_del(pi);
probe_err4:
- free_irq(irq, pi);
+ for (i = 0; i < num_chan; i++) {
+ pch = &pdmac->peripherals[i];
+ tasklet_kill(&pch->task);
+ }
+ pl330_del(pi);
probe_err3:
-#ifndef CONFIG_PM_RUNTIME
- clk_disable(pdmac->clk);
-#endif
- clk_put(pdmac->clk);
+ free_irq(irq, pi);
probe_err2:
iounmap(pi->base);
probe_err1:
@@ -3029,6 +3147,7 @@
/* Flush the channel */
pl330_control(&pch->chan, DMA_TERMINATE_ALL, 0);
+ tasklet_kill(&pch->task);
pl330_free_chan_resources(&pch->chan);
}
@@ -3044,10 +3163,6 @@
res = &adev->res;
release_mem_region(res->start, resource_size(res));
-#ifndef CONFIG_PM_RUNTIME
- clk_disable(pdmac->clk);
-#endif
-
kfree(pdmac);
return 0;
@@ -3063,49 +3178,10 @@
MODULE_DEVICE_TABLE(amba, pl330_ids);
-#ifdef CONFIG_PM_RUNTIME
-static int pl330_runtime_suspend(struct device *dev)
-{
- struct dma_pl330_dmac *pdmac = dev_get_drvdata(dev);
-
- if (!pdmac) {
- dev_err(dev, "failed to get dmac\n");
- return -ENODEV;
- }
-
- clk_disable(pdmac->clk);
-
- return 0;
-}
-
-static int pl330_runtime_resume(struct device *dev)
-{
- struct dma_pl330_dmac *pdmac = dev_get_drvdata(dev);
-
- if (!pdmac) {
- dev_err(dev, "failed to get dmac\n");
- return -ENODEV;
- }
-
- clk_enable(pdmac->clk);
-
- return 0;
-}
-#else
-#define pl330_runtime_suspend NULL
-#define pl330_runtime_resume NULL
-#endif /* CONFIG_PM_RUNTIME */
-
-static const struct dev_pm_ops pl330_pm_ops = {
- .runtime_suspend = pl330_runtime_suspend,
- .runtime_resume = pl330_runtime_resume,
-};
-
static struct amba_driver pl330_driver = {
.drv = {
.owner = THIS_MODULE,
.name = "dma-pl330",
- .pm = &pl330_pm_ops,
},
.id_table = pl330_ids,
.probe = pl330_probe,
diff --git a/drivers/gpio/gpio-samsung.c b/drivers/gpio/gpio-samsung.c
index e991d91..2a17c86 100644
--- a/drivers/gpio/gpio-samsung.c
+++ b/drivers/gpio/gpio-samsung.c
@@ -1022,6 +1022,24 @@
}
}
+static void __init samsung_gpiolib_add_4bit_chips_no_pm(struct samsung_gpio_chip *chip,
+ int nr_chips, void __iomem *base)
+{
+ int i;
+
+ for (i = 0 ; i < nr_chips; i++, chip++) {
+ chip->chip.direction_input = samsung_gpiolib_4bit_input;
+ chip->chip.direction_output = samsung_gpiolib_4bit_output;
+
+ if (!chip->config)
+ chip->config = &samsung_gpio_cfgs[2];
+ if ((base != NULL) && (chip->base == NULL))
+ chip->base = base + ((i) * 0x20);
+
+ samsung_gpiolib_add(chip);
+ }
+}
+
static void __init samsung_gpiolib_add_4bit2_chips(struct samsung_gpio_chip *chip,
int nr_chips)
{
@@ -2465,48 +2483,61 @@
.label = "GPD1",
},
}, {
+ .config = &samsung_gpio_cfgs[8],
.chip = {
.base = EXYNOS5_GPY0(0),
.ngpio = EXYNOS5_GPIO_Y0_NR,
.label = "GPY0",
},
}, {
+ .config = &samsung_gpio_cfgs[8],
.chip = {
.base = EXYNOS5_GPY1(0),
.ngpio = EXYNOS5_GPIO_Y1_NR,
.label = "GPY1",
},
}, {
+ .config = &samsung_gpio_cfgs[8],
.chip = {
.base = EXYNOS5_GPY2(0),
.ngpio = EXYNOS5_GPIO_Y2_NR,
.label = "GPY2",
},
}, {
+ .config = &samsung_gpio_cfgs[8],
.chip = {
.base = EXYNOS5_GPY3(0),
.ngpio = EXYNOS5_GPIO_Y3_NR,
.label = "GPY3",
},
}, {
+ .config = &samsung_gpio_cfgs[8],
.chip = {
.base = EXYNOS5_GPY4(0),
.ngpio = EXYNOS5_GPIO_Y4_NR,
.label = "GPY4",
},
}, {
+ .config = &samsung_gpio_cfgs[8],
.chip = {
.base = EXYNOS5_GPY5(0),
.ngpio = EXYNOS5_GPIO_Y5_NR,
.label = "GPY5",
},
}, {
+ .config = &samsung_gpio_cfgs[8],
.chip = {
.base = EXYNOS5_GPY6(0),
.ngpio = EXYNOS5_GPIO_Y6_NR,
.label = "GPY6",
},
}, {
+ .chip = {
+ .base = EXYNOS5_GPC4(0),
+ .ngpio = EXYNOS5_GPIO_C4_NR,
+ .label = "GPC4",
+ },
+ }, {
.config = &samsung_gpio_cfgs[9],
.irq_base = IRQ_EINT(0),
.chip = {
@@ -2790,8 +2821,6 @@
#endif
} else if (soc_is_exynos4210()) {
#ifdef CONFIG_CPU_EXYNOS4210
- void __iomem *gpx_base;
-
/* gpio part1 */
gpio_base1 = ioremap(EXYNOS4_PA_GPIO1, SZ_4K);
if (gpio_base1 == NULL) {
@@ -2820,11 +2849,11 @@
goto err_ioremap2;
}
- /* need to set base address for gpx */
- chip = &exynos4_gpios_2[16];
- gpx_base = gpio_base2 + 0xC00;
- for (i = 0; i < 4; i++, chip++, gpx_base += 0x20)
- chip->base = gpx_base;
+ /* need to set base address for GPX */
+ exynos4_gpios_2[16].base = gpio_base2 + 0xC00;
+ exynos4_gpios_2[17].base = gpio_base2 + 0xC20;
+ exynos4_gpios_2[18].base = gpio_base2 + 0xC40;
+ exynos4_gpios_2[19].base = gpio_base2 + 0xC60;
chip = exynos4_gpios_2;
nr_chips = ARRAY_SIZE(exynos4_gpios_2);
@@ -2869,8 +2898,6 @@
#endif /* CONFIG_CPU_EXYNOS4210 */
} else if (soc_is_exynos5250()) {
#ifdef CONFIG_SOC_EXYNOS5250
- void __iomem *gpx_base;
-
/* gpio part1 */
gpio_base1 = ioremap(EXYNOS5_PA_GPIO1, SZ_4K);
if (gpio_base1 == NULL) {
@@ -2878,11 +2905,11 @@
goto err_ioremap1;
}
- /* need to set base address for gpx */
- chip = &exynos5_gpios_1[20];
- gpx_base = gpio_base1 + 0xC00;
- for (i = 0; i < 4; i++, chip++, gpx_base += 0x20)
- chip->base = gpx_base;
+ exynos5_gpios_1[20].base = gpio_base1 + 0x2E0; /* GPC4 */
+ exynos5_gpios_1[21].base = gpio_base1 + 0xC00; /* GPX0 */
+ exynos5_gpios_1[22].base = gpio_base1 + 0xC20; /* GPX1 */
+ exynos5_gpios_1[23].base = gpio_base1 + 0xC40; /* GPX2 */
+ exynos5_gpios_1[24].base = gpio_base1 + 0xC60; /* GPX3 */
chip = exynos5_gpios_1;
nr_chips = ARRAY_SIZE(exynos5_gpios_1);
@@ -2926,12 +2953,9 @@
goto err_ioremap3;
}
- /* need to set base address for gpv */
- exynos5_gpios_3[0].base = gpio_base3;
- exynos5_gpios_3[1].base = gpio_base3 + 0x20;
- exynos5_gpios_3[2].base = gpio_base3 + 0x60;
- exynos5_gpios_3[3].base = gpio_base3 + 0x80;
- exynos5_gpios_3[4].base = gpio_base3 + 0xC0;
+ exynos5_gpios_3[2].base = gpio_base3 + 0x60; /* GPV2 */
+ exynos5_gpios_3[3].base = gpio_base3 + 0x80; /* GPV3 */
+ exynos5_gpios_3[4].base = gpio_base3 + 0xC0; /* GPV4 */
chip = exynos5_gpios_3;
nr_chips = ARRAY_SIZE(exynos5_gpios_3);
@@ -2947,7 +2971,7 @@
samsung_gpiolib_add_4bit_chips(exynos5_gpios_3,
nr_chips, gpio_base3);
- /* gpio part4 */
+ /* gpio part4, no PM part */
gpio_base4 = ioremap(EXYNOS5_PA_GPIO4, SZ_4K);
if (gpio_base4 == NULL) {
pr_err("unable to ioremap for gpio_base4\n");
@@ -2965,8 +2989,29 @@
exynos_gpiolib_attach_ofnode(chip,
EXYNOS5_PA_GPIO4, i * 0x20);
}
+#if defined(CONFIG_PM_RUNTIME)
+ samsung_gpiolib_add_4bit_chips_no_pm(exynos5_gpios_4,
+ nr_chips, gpio_base4);
+#else
samsung_gpiolib_add_4bit_chips(exynos5_gpios_4,
nr_chips, gpio_base4);
+#endif
+#if defined(CONFIG_SOC_EXYNOS5250) && defined(CONFIG_S5P_GPIO_INT)
+ s5p_register_gpioint_bank(EXYNOS5_IRQ_GPIO_XA, 0,
+ EXYNOS5_IRQ_GPIO1_NR_GROUPS);
+ s5p_register_gpioint_bank(EXYNOS5_IRQ_GPIO_XB,
+ EXYNOS5_IRQ_GPIO1_NR_GROUPS,
+ EXYNOS5_IRQ_GPIO2_NR_GROUPS);
+ s5p_register_gpioint_bank(EXYNOS5_IRQ_GPIO_C2C,
+ EXYNOS5_IRQ_GPIO1_NR_GROUPS +
+ EXYNOS5_IRQ_GPIO2_NR_GROUPS,
+ EXYNOS5_IRQ_GPIO3_NR_GROUPS);
+ s5p_register_gpioint_bank(EXYNOS5_IRQ_GPIO,
+ EXYNOS5_IRQ_GPIO1_NR_GROUPS +
+ EXYNOS5_IRQ_GPIO2_NR_GROUPS +
+ EXYNOS5_IRQ_GPIO3_NR_GROUPS,
+ EXYNOS5_IRQ_GPIO4_NR_GROUPS);
+#endif
#endif /* CONFIG_SOC_EXYNOS5250 */
} else {
WARN(1, "Unknown SoC in gpio-samsung, no GPIOs added\n");
@@ -3186,6 +3231,102 @@
EXPORT_SYMBOL(s5p_gpio_set_drvstr);
#endif /* CONFIG_S5P_GPIO_DRVSTR */
+s5p_gpio_pd_cfg_t s5p_gpio_get_pd_cfg(unsigned int pin)
+{
+ struct samsung_gpio_chip *chip = samsung_gpiolib_getchip(pin);
+ unsigned int off;
+ void __iomem *reg;
+ int shift;
+ u32 pd_cfg;
+
+ if (!chip)
+ return -EINVAL;
+
+ off = pin - chip->chip.base;
+ shift = off * 2;
+ reg = chip->base + 0x10;
+
+ pd_cfg = __raw_readl(reg);
+ pd_cfg = pd_cfg >> shift;
+ pd_cfg &= 0x3;
+
+ return (__force s5p_gpio_pd_cfg_t)pd_cfg;
+}
+EXPORT_SYMBOL(s5p_gpio_get_pd_cfg);
+
+int s5p_gpio_set_pd_cfg(unsigned int pin, s5p_gpio_pd_cfg_t pd_cfg)
+{
+ struct samsung_gpio_chip *chip = samsung_gpiolib_getchip(pin);
+ unsigned int off;
+ void __iomem *reg;
+ int shift;
+ u32 tmp;
+
+ if (!chip)
+ return -EINVAL;
+
+ off = pin - chip->chip.base;
+ shift = off * 2;
+ reg = chip->base + 0x10;
+
+ tmp = __raw_readl(reg);
+ tmp &= ~(0x3 << shift);
+ tmp |= pd_cfg << shift;
+
+ __raw_writel(tmp, reg);
+
+ return 0;
+}
+EXPORT_SYMBOL(s5p_gpio_set_pd_cfg);
+
+s5p_gpio_pd_pull_t s5p_gpio_get_pd_pull(unsigned int pin)
+{
+ struct samsung_gpio_chip *chip = samsung_gpiolib_getchip(pin);
+ unsigned int off;
+ void __iomem *reg;
+ int shift;
+ u32 pd_pull;
+
+ if (!chip)
+ return -EINVAL;
+
+ off = pin - chip->chip.base;
+ shift = off * 2;
+ reg = chip->base + 0x14;
+
+ pd_pull = __raw_readl(reg);
+ pd_pull = pd_pull >> shift;
+ pd_pull &= 0x3;
+
+ return (__force s5p_gpio_pd_pull_t)pd_pull;
+}
+EXPORT_SYMBOL(s5p_gpio_get_pd_pull);
+
+int s5p_gpio_set_pd_pull(unsigned int pin, s5p_gpio_pd_pull_t pd_pull)
+{
+ struct samsung_gpio_chip *chip = samsung_gpiolib_getchip(pin);
+ unsigned int off;
+ void __iomem *reg;
+ int shift;
+ u32 tmp;
+
+ if (!chip)
+ return -EINVAL;
+
+ off = pin - chip->chip.base;
+ shift = off * 2;
+ reg = chip->base + 0x14;
+
+ tmp = __raw_readl(reg);
+ tmp &= ~(0x3 << shift);
+ tmp |= pd_pull << shift;
+
+ __raw_writel(tmp, reg);
+
+ return 0;
+}
+EXPORT_SYMBOL(s5p_gpio_set_pd_pull);
+
#ifdef CONFIG_PLAT_S3C24XX
unsigned int s3c2410_modify_misccr(unsigned int clear, unsigned int change)
{
diff --git a/drivers/gpu/Makefile b/drivers/gpu/Makefile
index ca2d3b3..633b375 100644
--- a/drivers/gpu/Makefile
+++ b/drivers/gpu/Makefile
@@ -1 +1 @@
-obj-y += drm/ vga/ stub/ ion/
+obj-y += drm/ vga/ stub/ ion/ arm/
diff --git a/drivers/gpu/arm/Kbuild b/drivers/gpu/arm/Kbuild
new file mode 100644
index 0000000..c14576d
--- /dev/null
+++ b/drivers/gpu/arm/Kbuild
@@ -0,0 +1,13 @@
+#
+# (C) COPYRIGHT 2012 ARM Limited. All rights reserved.
+#
+# This program is free software and is provided to you under the terms of the GNU General Public License version 2
+# as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+#
+# A copy of the licence is included with the program, and can also be obtained from Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+#
+
+
+obj-$(CONFIG_MALI_T6XX) += t6xx/
diff --git a/drivers/gpu/arm/Kconfig b/drivers/gpu/arm/Kconfig
new file mode 100644
index 0000000..e0e1577
--- /dev/null
+++ b/drivers/gpu/arm/Kconfig
@@ -0,0 +1,15 @@
+#
+# (C) COPYRIGHT 2012 ARM Limited. All rights reserved.
+#
+# This program is free software and is provided to you under the terms of the GNU General Public License version 2
+# as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+#
+# A copy of the licence is included with the program, and can also be obtained from Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+#
+
+
+menu "ARM GPU Configuration"
+source "drivers/gpu/arm/t6xx/kbase/Kconfig"
+endmenu
diff --git a/drivers/gpu/arm/t6xx/Kbuild b/drivers/gpu/arm/t6xx/Kbuild
new file mode 100644
index 0000000..f818654
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/Kbuild
@@ -0,0 +1,13 @@
+#
+# (C) COPYRIGHT 2012 ARM Limited. All rights reserved.
+#
+# This program is free software and is provided to you under the terms of the GNU General Public License version 2
+# as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+#
+# A copy of the licence is included with the program, and can also be obtained from Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+#
+
+
+obj-$(CONFIG_MALI_T6XX) += kbase/
diff --git a/drivers/gpu/arm/t6xx/kbase/Kbuild b/drivers/gpu/arm/t6xx/kbase/Kbuild
new file mode 100644
index 0000000..8069230
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/Kbuild
@@ -0,0 +1,13 @@
+#
+# (C) COPYRIGHT 2012 ARM Limited. All rights reserved.
+#
+# This program is free software and is provided to you under the terms of the GNU General Public License version 2
+# as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+#
+# A copy of the licence is included with the program, and can also be obtained from Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+#
+
+obj-y += src/
+
diff --git a/drivers/gpu/arm/t6xx/kbase/Kconfig b/drivers/gpu/arm/t6xx/kbase/Kconfig
new file mode 100644
index 0000000..8324921
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/Kconfig
@@ -0,0 +1,161 @@
+#
+# (C) COPYRIGHT 2012 ARM Limited. All rights reserved.
+#
+# This program is free software and is provided to you under the terms of the GNU General Public License version 2
+# as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+#
+# A copy of the licence is included with the program, and can also be obtained from Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+#
+
+
+menuconfig MALI_T6XX
+ tristate "Mali-T6XX support"
+ default n
+ help
+ Enable this option to build support for the ARM Mali-T6XX GPU.
+
+ To compile this driver as a module, choose M here:
+ this will generate a single module, called mali_kbase.
+
+config MALI_GATOR_SUPPORT
+ bool "Streamline Debug support"
+ depends on MALI_T6XX=m
+ default n
+ help
+ Adds diagnostic support for use with the ARM Streamline Performance Analyzer.
+ You will need the Gator device driver already loaded before loading this driver when enabling
+ Streamline debug support.
+
+config MALI_T6XX_DVFS
+ bool "Enable DVFS"
+ depends on MALI_T6XX
+ default n
+ help
+ Choose this option to enable DVFS on MALI T6XX DDK.
+
+config MALI_T6XX_DEMAND_POLICY
+ bool "Enable demand power policy by default"
+ depends on MALI_T6XX
+ default n
+ help
+ Sets the default power policy to "demand"
+
+config MALI_T6XX_RT_PM
+ bool "Enable Runtime power management"
+ depends on MALI_T6XX
+ depends on PM_RUNTIME
+ default n
+ help
+ Choose this option to enable runtime power management on vithar DDK.
+
+config MALI_T6XX_ENABLE_TRACE
+ bool "Enable kbase tracing"
+ depends on MALI_T6XX
+ default n
+ help
+ Enables tracing in the kbase. Trace log available through
+ the "mali_trace" debugfs file, when the CONFIG_DEBUG_FS is enabled
+
+config MALI_T6XX_DEBUG_SYS
+ bool "Enable sysfs for mali t6xx"
+ depends on MALI_T6XX && SYSFS
+ default n
+ help
+ Enables sysfs for mali t6xx device. Set/Monitor Mali T6xx Device
+
+# MALI_EXPERT configuration options
+
+menuconfig MALI_EXPERT
+ depends on MALI_T6XX
+ bool "Enable Expert Settings"
+ default n
+ help
+ Enabling this option and modifying the default settings may produce a driver with performance or
+ other limitations.
+
+config MALI_PLATFORM_FAKE
+ bool "Enable fake platform device support"
+ depends on MALI_T6XX && MALI_EXPERT
+ default n
+ help
+ When you start to work with the Mali-T600 Series device driver the platform-specific code of
+ the Linux kernel for your platform may not be complete. In this situation the kernel device driver
+ supports creating the platform device outside of the Linux platform-specific code.
+ Enable this option if would like to use a platform device configuration from within the device driver.
+
+choice
+ prompt "Platform configuration"
+ depends on MALI_T6XX && (MALI_PLATFORM_FAKE && MALI_EXPERT)
+ default MALI_PLATFORM_VEXPRESS
+ help
+ Select the SOC platform that contains a Mali-T6XX
+
+config MALI_PLATFORM_VEXPRESS
+ depends on ARCH_VEXPRESS && (ARCH_VEXPRESS_CA9X4 || ARCH_VEXPRESS_CA15X4)
+ bool "Versatile Express"
+config MALI_PLATFORM_GOLDFISH
+ depends on ARCH_GOLDFISH
+ bool "Android Goldfish virtual CPU"
+config MALI_PLATFORM_PBX
+ depends on ARCH_REALVIEW && REALVIEW_EB_A9MP && MACH_REALVIEW_PBX
+ bool "Realview PBX-A9"
+config MALI_PLATFORM_THIRDPARTY
+ bool "Third Party Platform"
+endchoice
+
+config MALI_PLATFORM_THIRDPARTY_NAME
+ depends on MALI_T6XX && MALI_PLATFORM_THIRDPARTY && (MALI_PLATFORM_FAKE && MALI_EXPERT)
+ string "Third party platform name"
+ help
+ Enter the name of a third party platform that is supported. The third part configuration
+ file must be in kbase/src/linux/config/tpip/mali_kbase_config_xxx.c where xxx is the name
+ specifed here.
+
+
+config MALI_DEBUG
+ bool "Debug build"
+ depends on MALI_T6XX && MALI_EXPERT
+ default n
+ help
+ Select this option for increased checking and reporting of errors.
+
+config MALI_UNCACHED
+ bool "Disable CPU caching for GPU memory regions"
+ depends on MALI_T6XX && MALI_EXPERT
+ default n
+ help
+ Select this option to disable CPU caching for all GPU memory regions.
+
+config MALI_QA_LEAK
+ bool "Enable the tracking of memory leaks"
+ depends on MALI_T6XX && MALI_EXPERT
+ default n
+ help
+ Enables additional memory leak tracking diagnostics.
+config MALI_QA_RESFAIL
+ bool "Enable simulated failures"
+ depends on MALI_T6XX && MALI_EXPERT
+ default n
+ help
+ Enables forced failures in APIs for additional test coverage
+
+config MALI_NO_MALI
+ bool "No Mali"
+ depends on MALI_T6XX && MALI_EXPERT
+ default n
+ help
+ This can be used to test the driver in a simulated environment
+ whereby the hardware is not physically present. If the hardware is physically
+ present it will not be used. This can be used to test the majority of the
+ driver without needing actual hardware or for software benchmarking.
+ All calls to the simulated hardware will complete immediatly as if the hardware
+ completed the task.
+
+config MALI_ERROR_INJECT
+ bool "Error injection"
+ depends on MALI_T6XX && MALI_EXPERT && MALI_NO_MALI
+ default n
+ help
+ Enables insertion of errors to test module failure and recovery mechanisms.
diff --git a/drivers/gpu/arm/t6xx/kbase/Makefile b/drivers/gpu/arm/t6xx/kbase/Makefile
new file mode 100644
index 0000000..26a6d43
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/Makefile
@@ -0,0 +1,97 @@
+#
+# (C) COPYRIGHT 2011-2012 ARM Limited. All rights reserved.
+#
+# This program is free software and is provided to you under the terms of the GNU General Public License version 2
+# as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+#
+# A copy of the licence is included with the program, and can also be obtained from Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+#
+
+
+# Defaults
+export PLATFORM?=dummy
+export MALI_ANDROID?=0
+export MALI_UNIT_TEST?=0
+export MALI_KERNEL_TEST_API?=0
+export MALI_MOCK_TEST?=0
+export MALI_INSTRUMENTATION_LEVEL?=0
+export MALI_CUSTOMER_RELEASE?=1
+export MALI_COVERAGE?=0
+export CONFIG_MALI_NO_MALI?=n
+export CONFIG_UMP?=m
+export CONFIG_MALI_DEBUG?=y
+export CONFIG_MALI_ERROR_INJECT?=n
+export CONFIG_MALI_QA_LEAK?=n
+export CONFIG_MALI_QA_RESFAIL?=n
+export CONFIG_MALI_PLATFORM_FAKE?=y
+export CONFIG_MALI_PLATFORM_VEXPRESS?=y
+export CONFIG_MALI_UNCACHED?=y
+export CONFIG_MALI_GATOR_SUPPORT?=y
+export CONFIG_MALI_T6XX?=m
+export CONFIG_KDS?=m
+
+ifeq ($(CONFIG_MALI_NO_MALI),y)
+ SCONS_CFLAGS+=-DCONFIG_MALI_NO_MALI
+endif
+ifeq ($(CONFIG_UMP),m)
+ SCONS_CFLAGS+=-DCONFIG_UMP
+endif
+ifeq ($(CONFIG_MALI_DEBUG),y)
+ SCONS_CFLAGS+=-DCONFIG_MALI_DEBUG
+endif
+ifeq ($(CONFIG_MALI_ERROR_INJECT),y)
+ SCONS_CFLAGS+=-DCONFIG_MALI_ERROR_INJECT
+endif
+ifeq ($(CONFIG_MALI_QA_LEAK),y)
+ SCONS_CFLAGS+=-DCONFIG_MALI_QA_LEAK
+endif
+ifeq ($(CONFIG_MALI_QA_RESFAIL),y)
+ SCONS_CFLAGS+=-DCONFIG_MALI_QA_RESFAIL
+endif
+ifeq ($(CONFIG_MALI_PLATFORM_FAKE),y)
+ SCONS_CFLAGS+=-DCONFIG_MALI_PLATFORM_FAKE
+endif
+ifeq ($(CONFIG_MALI_PLATFORM_VEXPRESS),y)
+ SCONS_CFLAGS+=-DCONFIG_MALI_PLATFORM_VEXPRESS
+endif
+ifeq ($(CONFIG_MALI_UNCACHED),y)
+ SCONS_CFLAGS+=-DCONFIG_MALI_UNCACHED
+endif
+ifeq ($(CONFIG_MALI_GATOR_SUPPORT),y)
+ SCONS_CFLAGS+=-DCONFIG_MALI_GATOR_SUPPORT
+endif
+ifeq ($(CONFIG_KDS),m)
+ SCONS_CFLAGS+=-DCONFIG_KDS
+endif
+export SCONS_CFLAGS
+
+KDIR ?= /lib/modules/$(shell uname -r)/build
+
+# MROOT defines root of kernel device driver components
+# This makefile may reside in container directory of the kernel device driver components or within the
+# 'kbase' kernel driver component itself, so we set MROOT accordingly.
+#
+ifeq ($(wildcard $(PWD)/kbase/src/Makefile),)
+MROOT=$(PWD)/../../../../../..
+else
+MROOT=$(PWD)
+endif
+
+KBASE_PATH=$(MROOT)/kernel/drivers/gpu/arm/t6xx/kbase
+UMP_PATH=$(MROOT)/kernel/drivers/base/ump
+KDS_PATH=$(MROOT)/kernel/drivers/base/kds
+OSK_PATH=$(MROOT)/kernel/drivers/gpu/arm/t6xx/kbase/osk
+
+all:
+ $(MAKE) -C $(OSK_PATH)/src/linux
+ $(MAKE) -C $(KDS_PATH)
+ $(MAKE) -C $(UMP_PATH)/src
+ $(MAKE) -C $(KBASE_PATH)/src
+
+clean:
+ $(MAKE) -C $(OSK_PATH)/src/linux clean
+ $(MAKE) -C $(KDS_PATH) clean
+ $(MAKE) -C $(UMP_PATH)/src clean
+ $(MAKE) -C $(KBASE_PATH)/src clean
diff --git a/drivers/gpu/arm/t6xx/kbase/mali_base_hwconfig.h b/drivers/gpu/arm/t6xx/kbase/mali_base_hwconfig.h
new file mode 100644
index 0000000..39034b3
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/mali_base_hwconfig.h
@@ -0,0 +1,265 @@
+/*
+ *
+ * (C) COPYRIGHT 2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file
+ * Software workarounds configuration for Hardware issues.
+ */
+
+#ifndef _BASE_HWCONFIG_H_
+#define _BASE_HWCONFIG_H_
+
+#include <malisw/mali_malisw.h>
+
+/**
+ * List of all workarounds.
+ *
+ */
+
+typedef enum base_hw_issue {
+
+ /* The current version of the model doesn't support Soft-Stop */
+ BASE_HW_ISSUE_5736,
+
+ /* Need way to guarantee that all previously-translated memory accesses are commited */
+ BASE_HW_ISSUE_6367,
+
+ /* Unaligned load stores crossing 128 bit boundaries will fail */
+ BASE_HW_ISSUE_6402,
+
+ /* On job complete with non-done the cache is not flushed */
+ BASE_HW_ISSUE_6787,
+
+ /* The clamp integer coordinate flag bit of the sampler descriptor is reserved */
+ BASE_HW_ISSUE_7144,
+
+ /* CRC computation can only happen when the bits per pixel is less than or equal to 32 */
+ BASE_HW_ISSUE_7393,
+
+ /* Write of PRFCNT_CONFIG_MODE_MANUAL to PRFCNT_CONFIG causes a instrumentation dump if
+ PRFCNT_TILER_EN is enabled */
+ BASE_HW_ISSUE_8186,
+
+ /* TIB: Reports faults from a vtile which has not yet been allocated */
+ BASE_HW_ISSUE_8245,
+
+ /* WLMA memory goes wrong when run on shader cores other than core 0. */
+ BASE_HW_ISSUE_8250,
+
+ /* Hierz doesn't work when stenciling is enabled */
+ BASE_HW_ISSUE_8260,
+
+ /* Livelock in L0 icache */
+ BASE_HW_ISSUE_8280,
+
+ /* uTLB deadlock could occur when writing to an invalid page at the same time as
+ * access to a valid page in the same uTLB cache line ( == 4 PTEs == 16K block of mapping) */
+ BASE_HW_ISSUE_8316,
+
+ /* HT: TERMINATE for RUN command ignored if previous LOAD_DESCRIPTOR is still executing */
+ BASE_HW_ISSUE_8394,
+
+ /* CSE : Sends a TERMINATED response for a task that should not be terminated */
+ /* (Note that PRLAM-8379 also uses this workaround) */
+ BASE_HW_ISSUE_8401,
+
+ /* Repeatedly Soft-stopping a job chain consisting of (Vertex Shader, Cache Flush, Tiler)
+ * jobs causes 0x58 error on tiler job. */
+ BASE_HW_ISSUE_8408,
+
+ /* Disable the Pause Buffer in the LS pipe. */
+ BASE_HW_ISSUE_8443,
+
+ /* Stencil test enable 1->0 sticks */
+ BASE_HW_ISSUE_8456,
+
+ /* Tiler heap issue using FBOs or multiple processes using the tiler simultaneously */
+ /* (Note that PRLAM-9049 also uses this work-around) */
+ BASE_HW_ISSUE_8564,
+
+ /* Livelock issue using atomic instructions (particularly when using atomic_cmpxchg as a spinlock) */
+ BASE_HW_ISSUE_8791,
+
+ /* Fused jobs are not supported (for various reasons) */
+ /* Jobs with relaxed dependencies do not support soft-stop */
+ /* (Note that PRLAM-8803, PRLAM-8393, PRLAM-8559, PRLAM-8601 & PRLAM-8607 all use this work-around) */
+ BASE_HW_ISSUE_8803,
+
+ /* Blend shader output is wrong for certain formats */
+ BASE_HW_ISSUE_8833,
+
+ /* Occlusion queries can create false 0 result in boolean and counter modes */
+ BASE_HW_ISSUE_8879,
+
+ /* Output has half intensity with blend shaders enabled on 8xMSAA. */
+ BASE_HW_ISSUE_8896,
+
+ /* 8xMSAA does not work with CRC */
+ BASE_HW_ISSUE_8975,
+
+ /* Boolean occlusion queries don't work properly due to sdc issue. */
+ BASE_HW_ISSUE_8986,
+
+ /* Change in RMUs in use causes problems related with the core's SDC */
+ BASE_HW_ISSUE_8987,
+
+ /* Occlusion query result is not updated if color writes are disabled. */
+ BASE_HW_ISSUE_9010,
+
+ /* Problem with number of work registers in the RSD if set to 0 */
+ BASE_HW_ISSUE_9275,
+
+ /* Incorrect coverage mask for 8xMSAA */
+ BASE_HW_ISSUE_9423,
+
+ /* Compute endpoint has a 4-deep queue of tasks, meaning a soft stop won't complete until all 4 tasks have completed */
+ BASE_HW_ISSUE_9435,
+
+ /* HT: Tiler returns TERMINATED for command that hasn't been terminated */
+ BASE_HW_ISSUE_9510,
+
+ /* Occasionally the GPU will issue multiple page faults for the same address before the MMU page table has been read by the GPU */
+ BASE_HW_ISSUE_9630,
+
+ /* RA DCD load request to SDC returns invalid load ignore causing colour buffer mismatch */
+ BASE_HW_ISSUE_10327,
+
+ /* The BASE_HW_ISSUE_END value must be the last issue listed in this enumeration
+ * and must be the last value in each array that contains the list of workarounds
+ * for a particular HW version.
+ */
+ BASE_HW_ISSUE_END
+} base_hw_issue;
+
+
+/**
+ * Workarounds configuration for each HW revision
+ */
+/* Mali T60x r0p0-15dev0 - 2011-W39-stable-9 */
+static const base_hw_issue base_hw_issues_t60x_r0p0_15dev0[] =
+{
+ BASE_HW_ISSUE_6367,
+ BASE_HW_ISSUE_6402,
+ BASE_HW_ISSUE_6787,
+ BASE_HW_ISSUE_7144,
+ BASE_HW_ISSUE_7393,
+ BASE_HW_ISSUE_8186,
+ BASE_HW_ISSUE_8245,
+ BASE_HW_ISSUE_8250,
+ BASE_HW_ISSUE_8260,
+ BASE_HW_ISSUE_8280,
+ BASE_HW_ISSUE_8316,
+ BASE_HW_ISSUE_8394,
+ BASE_HW_ISSUE_8401,
+ BASE_HW_ISSUE_8408,
+ BASE_HW_ISSUE_8443,
+ BASE_HW_ISSUE_8456,
+ BASE_HW_ISSUE_8564,
+ BASE_HW_ISSUE_8791,
+ BASE_HW_ISSUE_8803,
+ BASE_HW_ISSUE_8833,
+ BASE_HW_ISSUE_8896,
+ BASE_HW_ISSUE_8975,
+ BASE_HW_ISSUE_8986,
+ BASE_HW_ISSUE_8987,
+ BASE_HW_ISSUE_9010,
+ BASE_HW_ISSUE_9275,
+ BASE_HW_ISSUE_9423,
+ BASE_HW_ISSUE_9435,
+ BASE_HW_ISSUE_9510,
+ BASE_HW_ISSUE_9630,
+ /* List of hardware issues must end with BASE_HW_ISSUE_END */
+ BASE_HW_ISSUE_END
+};
+
+/* Mali T60x r0p0-00rel0 - 2011-W46-stable-13c */
+static const base_hw_issue base_hw_issues_t60x_r0p0_eac[] =
+{
+ BASE_HW_ISSUE_6367,
+ BASE_HW_ISSUE_6402,
+ BASE_HW_ISSUE_6787,
+ BASE_HW_ISSUE_7393,
+ BASE_HW_ISSUE_8564,
+ BASE_HW_ISSUE_8803,
+ BASE_HW_ISSUE_8975,
+ BASE_HW_ISSUE_9010,
+ BASE_HW_ISSUE_9275,
+ BASE_HW_ISSUE_9423,
+ BASE_HW_ISSUE_9435,
+ BASE_HW_ISSUE_9510,
+ /* List of hardware issues must end with BASE_HW_ISSUE_END */
+ BASE_HW_ISSUE_END
+};
+
+/* Mali T60x r0p1 */
+static const base_hw_issue base_hw_issues_t60x_r0p1[] =
+{
+ BASE_HW_ISSUE_6367,
+ BASE_HW_ISSUE_6402,
+ BASE_HW_ISSUE_6787,
+ BASE_HW_ISSUE_7393,
+ BASE_HW_ISSUE_8564,
+ BASE_HW_ISSUE_8803,
+ BASE_HW_ISSUE_8975,
+ BASE_HW_ISSUE_9010,
+ BASE_HW_ISSUE_9275,
+ BASE_HW_ISSUE_9435,
+ BASE_HW_ISSUE_9510,
+ /* List of hardware issues must end with BASE_HW_ISSUE_END */
+ BASE_HW_ISSUE_END
+};
+
+/* Mali T65x r0p1 */
+static const base_hw_issue base_hw_issues_t65x_r0p1[] =
+{
+ BASE_HW_ISSUE_6367,
+ BASE_HW_ISSUE_6402,
+ BASE_HW_ISSUE_6787,
+ BASE_HW_ISSUE_7393,
+ BASE_HW_ISSUE_8564,
+ BASE_HW_ISSUE_8803,
+ BASE_HW_ISSUE_8975,
+ BASE_HW_ISSUE_9010,
+ BASE_HW_ISSUE_9275,
+ BASE_HW_ISSUE_9435,
+ BASE_HW_ISSUE_9510,
+ /* List of hardware issues must end with BASE_HW_ISSUE_END */
+ BASE_HW_ISSUE_END
+};
+
+/* Mali T62x r0p0 */
+static const base_hw_issue base_hw_issues_t62x_r0p0[] =
+{
+ BASE_HW_ISSUE_6402,
+ BASE_HW_ISSUE_8803,
+ BASE_HW_ISSUE_8975,
+ BASE_HW_ISSUE_9435,
+ BASE_HW_ISSUE_10327,
+ /* List of hardware issues must end with BASE_HW_ISSUE_END */
+ BASE_HW_ISSUE_END
+};
+
+/* Mali T67x r0p0 */
+static const base_hw_issue base_hw_issues_t67x_r0p0[] =
+{
+ BASE_HW_ISSUE_6402,
+ BASE_HW_ISSUE_8803,
+ BASE_HW_ISSUE_8975,
+ BASE_HW_ISSUE_9435,
+ BASE_HW_ISSUE_10327,
+ /* List of hardware issues must end with BASE_HW_ISSUE_END */
+ BASE_HW_ISSUE_END
+};
+
+#endif /* _BASE_HWCONFIG_H_ */
diff --git a/drivers/gpu/arm/t6xx/kbase/mali_base_kernel.h b/drivers/gpu/arm/t6xx/kbase/mali_base_kernel.h
new file mode 100644
index 0000000..f4d0dd6
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/mali_base_kernel.h
@@ -0,0 +1,1527 @@
+/*
+ *
+ * (C) COPYRIGHT 2010-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file
+ * Base structures shared with the kernel.
+ */
+
+#ifndef _BASE_KERNEL_H_
+#define _BASE_KERNEL_H_
+
+/* For now we support the legacy API as well as the new API */
+#define BASE_LEGACY_JD_API 1
+
+#include <kbase/src/mali_base_mem_priv.h>
+
+/*
+ * Dependency stuff, keep it private for now. May want to expose it if
+ * we decide to make the number of semaphores a configurable
+ * option.
+ */
+#define BASE_JD_ATOM_COUNT 256
+
+#define BASEP_JD_SEM_PER_WORD_LOG2 5
+#define BASEP_JD_SEM_PER_WORD (1 << BASEP_JD_SEM_PER_WORD_LOG2)
+#define BASEP_JD_SEM_WORD_NR(x) ((x) >> BASEP_JD_SEM_PER_WORD_LOG2)
+#define BASEP_JD_SEM_MASK_IN_WORD(x) (1 << ((x) & (BASEP_JD_SEM_PER_WORD - 1)))
+#define BASEP_JD_SEM_ARRAY_SIZE BASEP_JD_SEM_WORD_NR(BASE_JD_ATOM_COUNT)
+
+#if BASE_LEGACY_JD_API
+/* Size of the ring buffer */
+#define BASEP_JCTX_RB_NRPAGES 4
+#endif /* BASE_LEGACY_JD_API */
+
+#define BASE_GPU_NUM_TEXTURE_FEATURES_REGISTERS 3
+
+#define BASE_MAX_COHERENT_GROUPS 16
+
+#if defined CDBG_ASSERT
+#define LOCAL_ASSERT CDBG_ASSERT
+#elif defined OSK_ASSERT
+#define LOCAL_ASSERT OSK_ASSERT
+#else
+#error assert macro not defined!
+#endif
+
+#if defined OSK_PAGE_MASK
+ #define LOCAL_PAGE_LSB ~OSK_PAGE_MASK
+#else
+ #include <osu/mali_osu.h>
+
+ #if defined CONFIG_CPU_PAGE_SIZE_LOG2
+ #define LOCAL_PAGE_LSB ((1ul << CONFIG_CPU_PAGE_SIZE_LOG2) - 1)
+ #else
+ #error Failed to find page size
+ #endif
+#endif
+
+/** 32/64-bit neutral way to represent pointers */
+typedef union kbase_pointer
+{
+ void * value; /**< client should store their pointers here */
+ u32 compat_value; /**< 64-bit kernels should fetch value here when handling 32-bit clients */
+ u64 sizer; /**< Force 64-bit storage for all clients regardless */
+} kbase_pointer;
+
+/**
+ * @addtogroup base_user_api User-side Base APIs
+ * @{
+ */
+
+/**
+ * @addtogroup base_user_api_memory User-side Base Memory APIs
+ * @{
+ */
+
+/**
+ * @brief Memory allocation, access/hint flags
+ *
+ * A combination of MEM_PROT/MEM_HINT flags must be passed to each allocator
+ * in order to determine the best cache policy. Some combinations are
+ * of course invalid (eg @c MEM_PROT_CPU_WR | @c MEM_HINT_CPU_RD),
+ * which defines a @a write-only region on the CPU side, which is
+ * heavily read by the CPU...
+ * Other flags are only meaningful to a particular allocator.
+ * More flags can be added to this list, as long as they don't clash
+ * (see ::BASE_MEM_FLAGS_NR_BITS for the number of the first free bit).
+ */
+typedef u32 base_mem_alloc_flags;
+
+
+/**
+ * @brief Memory allocation, access/hint flags
+ *
+ * See ::base_mem_alloc_flags.
+ *
+ */
+enum
+{
+ BASE_MEM_PROT_CPU_RD = (1U << 0), /**< Read access CPU side */
+ BASE_MEM_PROT_CPU_WR = (1U << 1), /**< Write access CPU side */
+ BASE_MEM_PROT_GPU_RD = (1U << 2), /**< Read access GPU side */
+ BASE_MEM_PROT_GPU_WR = (1U << 3), /**< Write access GPU side */
+ BASE_MEM_PROT_GPU_EX = (1U << 4), /**< Execute allowed on the GPU side */
+ BASE_MEM_CACHED_GPU = (1U << 5), /**< Should be cached */
+ BASE_MEM_CACHED_CPU = (1U << 6), /**< Should be cached */
+
+ BASEP_MEM_GROWABLE = (1U << 7), /**< Growable memory. This is a private flag that is set automatically. Not valid for PMEM. */
+ BASE_MEM_GROW_ON_GPF = (1U << 8), /**< Grow backing store on GPU Page Fault */
+
+ BASE_MEM_COHERENT_SYSTEM = (1U << 9), /**< Page coherence Outer shareable */
+ BASE_MEM_COHERENT_LOCAL = (1U << 10), /**< Page coherence Inner shareable */
+ BASE_MEM_DONT_ZERO_INIT = (1U << 11) /**< Optimization: No need to zero initialize */
+};
+
+/**
+ * @brief Memory types supported by @a base_tmem_import
+ *
+ * Each type defines what the supported handle type is.
+ *
+ * If any new type is added here ARM must be contacted
+ * to allocate a numeric value for it.
+ * Do not just add a new type without synchronizing with ARM
+ * as future releases from ARM might include other new types
+ * which could clash with your custom types.
+ */
+typedef enum base_tmem_import_type
+{
+ BASE_TMEM_IMPORT_TYPE_INVALID = 0,
+ /** UMP import. Handle type is ump_secure_id. */
+ BASE_TMEM_IMPORT_TYPE_UMP = 1,
+ /** UMM import. Handle type is a file descriptor (int) */
+ BASE_TMEM_IMPORT_TYPE_UMM = 2
+} base_tmem_import_type;
+
+/**
+ * Bits we can tag into a memory handle.
+ * We use the lower 12 bits as our handles are page-multiples, thus not using the 12 LSBs
+ */
+enum
+{
+ BASE_MEM_TAGS_MASK = ((1U << 12) - 1), /**< Mask to get hold of the tag bits/see if there are tag bits */
+ BASE_MEM_TAG_IMPORTED = (1U << 0) /**< Tagged as imported */
+ /* max 1u << 11 supported */
+};
+
+
+/**
+ * @brief Number of bits used as flags for base memory management
+ *
+ * Must be kept in sync with the ::base_mem_alloc_flags flags
+ */
+#define BASE_MEM_FLAGS_NR_BITS 12
+
+/**
+ * @brief Result codes of changing the size of the backing store allocated to a tmem region
+ */
+typedef enum base_backing_threshold_status
+{
+ BASE_BACKING_THRESHOLD_OK = 0, /**< Resize successful */
+ BASE_BACKING_THRESHOLD_ERROR_NOT_GROWABLE = -1, /**< Not a growable tmem object */
+ BASE_BACKING_THRESHOLD_ERROR_OOM = -2, /**< Increase failed due to an out-of-memory condition */
+ BASE_BACKING_THRESHOLD_ERROR_MAPPED = -3, /**< Resize attempted on buffer while it was mapped, which is not permitted */
+ BASE_BACKING_THRESHOLD_ERROR_INVALID_ARGUMENTS = -4 /**< Invalid arguments (not tmem, illegal size request, etc.) */
+} base_backing_threshold_status;
+
+/**
+ * @addtogroup base_user_api_memory_defered User-side Base Defered Memory Coherency APIs
+ * @{
+ */
+
+/**
+ * @brief a basic memory operation (sync-set).
+ *
+ * The content of this structure is private, and should only be used
+ * by the accessors.
+ */
+typedef struct base_syncset
+{
+ basep_syncset basep_sset;
+} base_syncset;
+
+/** @} end group base_user_api_memory_defered */
+
+/**
+ * Handle to represent imported memory object.
+ * Simple opague handle to imported memory, can't be used
+ * with anything but base_external_resource_init to bind to an atom.
+ */
+typedef struct base_import_handle
+{
+ struct
+ {
+ mali_addr64 handle;
+ } basep;
+} base_import_handle;
+
+
+/** @} end group base_user_api_memory */
+
+/**
+ * @addtogroup base_user_api_job_dispatch User-side Base Job Dispatcher APIs
+ * @{
+ */
+
+typedef int platform_fence_type;
+#define INVALID_PLATFORM_FENCE ((platform_fence_type)-1)
+
+/**
+ * Base stream handle.
+ *
+ * References an underlying base stream object.
+ */
+typedef struct base_stream
+{
+ struct
+ {
+ int fd;
+ }
+ basep;
+} base_stream;
+
+/**
+ * Base fence handle.
+ *
+ * References an underlying base fence object.
+ */
+typedef struct base_fence
+{
+ struct
+ {
+ int fd;
+ int stream_fd;
+ }
+ basep;
+} base_fence;
+
+#if BASE_LEGACY_JD_API
+/**
+ * @brief A pre- or post- dual dependency.
+ *
+ * This structure is used to express either
+ * @li a single or dual pre-dependency (a job depending on one or two
+ * other jobs),
+ * @li a single or dual post-dependency (a job resolving a dependency
+ * for one or two other jobs).
+ *
+ * The dependency itself is specified as a u8, where 0 indicates no
+ * dependency. A single dependency is expressed by having one of the
+ * dependencies set to 0.
+ */
+typedef struct base_jd_dep {
+ u8 dep[2]; /**< pre/post dependencies */
+} base_jd_dep;
+#endif /* BASE_LEGACY_JD_API */
+
+/**
+ * @brief Per-job data
+ *
+ * This structure is used to store per-job data, and is completly unused
+ * by the Base driver. It can be used to store things such as callback
+ * function pointer, data to handle job completion. It is guaranteed to be
+ * untouched by the Base driver.
+ */
+typedef struct base_jd_udata
+{
+ u64 blob[2]; /**< per-job data array */
+} base_jd_udata;
+
+/**
+ * @brief Job chain hardware requirements.
+ *
+ * A job chain must specify what GPU features it needs to allow the
+ * driver to schedule the job correctly. By not specifying the
+ * correct settings can/will cause an early job termination. Multiple
+ * values can be ORed together to specify multiple requirements.
+ * Special case is ::BASE_JD_REQ_DEP, which is used to express complex
+ * dependencies, and that doesn't execute anything on the hardware.
+ */
+typedef u16 base_jd_core_req;
+
+/* Requirements that come from the HW */
+#define BASE_JD_REQ_DEP 0 /**< No requirement, dependency only */
+#define BASE_JD_REQ_FS (1U << 0) /**< Requires fragment shaders */
+/**
+ * Requires compute shaders
+ * This covers any of the following Midgard Job types:
+ * - Vertex Shader Job
+ * - Geometry Shader Job
+ * - An actual Compute Shader Job
+ *
+ * Compare this with @ref BASE_JD_REQ_ONLY_COMPUTE, which specifies that the
+ * job is specifically just the "Compute Shader" job type, and not the "Vertex
+ * Shader" nor the "Geometry Shader" job type.
+ */
+#define BASE_JD_REQ_CS (1U << 1)
+#define BASE_JD_REQ_T (1U << 2) /**< Requires tiling */
+#define BASE_JD_REQ_CF (1U << 3) /**< Requires cache flushes */
+#define BASE_JD_REQ_V (1U << 4) /**< Requires value writeback */
+
+/* SW-only requirements - the HW does not expose these as part of the job slot capabilities */
+/**
+ * SW Only requirement: this job chain might not be soft-stoppable (Non-Soft
+ * Stoppable), and so must be scheduled separately from all other job-chains
+ * that are soft-stoppable.
+ *
+ * In absence of this requirement, then the job-chain is assumed to be
+ * soft-stoppable. That is, if it does not release the GPU "soon after" it is
+ * soft-stopped, then it will be killed. In contrast, NSS job chains can
+ * release the GPU "a long time after" they are soft-stopped.
+ *
+ * "soon after" and "a long time after" are implementation defined, and
+ * configurable in the device driver by the system integrator.
+ */
+#define BASE_JD_REQ_NSS (1U << 5)
+
+/**
+ * SW Only requirement: the job chain requires a coherent core group. We don't
+ * mind which coherent core group is used.
+ */
+#define BASE_JD_REQ_COHERENT_GROUP (1U << 6)
+
+/**
+ * SW Only requirement: The performance counters should be enabled only when
+ * they are needed, to reduce power consumption.
+ */
+
+#define BASE_JD_REQ_PERMON (1U << 7)
+
+/**
+ * SW Only requirement: External resources are referenced by this atom.
+ * When external resources are referenced no syncsets can be bundled with the atom
+ * but should instead be part of a NULL jobs inserted into the dependency tree.
+ * The first pre_dep object must be configured for the external resouces to use,
+ * the second pre_dep object can be used to create other dependencies.
+ */
+#define BASE_JD_REQ_EXTERNAL_RESOURCES (1U << 8)
+
+/**
+ * SW Only requirement: Software defined job. Jobs with this bit set will not be submitted
+ * to the hardware but will cause some action to happen within the driver
+ */
+#define BASE_JD_REQ_SOFT_JOB (1U << 9)
+
+#define BASE_JD_REQ_SOFT_DUMP_CPU_GPU_TIME (BASE_JD_REQ_SOFT_JOB | 0x1)
+#define BASE_JD_REQ_SOFT_FENCE_TRIGGER (BASE_JD_REQ_SOFT_JOB | 0x2)
+#define BASE_JD_REQ_SOFT_FENCE_WAIT (BASE_JD_REQ_SOFT_JOB | 0x3)
+
+
+/**
+ * HW Requirement: Requires Compute shaders (but not Vertex or Geometry Shaders)
+ *
+ * This indicates that the Job Chain contains Midgard Jobs of the 'Compute Shaders' type.
+ *
+ * In contrast to @ref BASE_JD_REQ_CS, this does \b not indicate that the Job
+ * Chain contains 'Geometry Shader' or 'Vertex Shader' jobs.
+ *
+ * @note This is a more flexible variant of the @ref BASE_CONTEXT_HINT_ONLY_COMPUTE flag,
+ * allowing specific jobs to be marked as 'Only Compute' instead of the entire context
+ */
+#define BASE_JD_REQ_ONLY_COMPUTE (1U << 10)
+
+/**
+ * HW Requirement: Use the base_jd_atom::device_nr field to specify a
+ * particular core group
+ *
+ * If both BASE_JD_REQ_COHERENT_GROUP and this flag are set, this flag takes priority
+ *
+ * This is only guaranteed to work for BASE_JD_REQ_ONLY_COMPUTE atoms.
+ */
+#define BASE_JD_REQ_SPECIFIC_COHERENT_GROUP ( 1U << 11 )
+
+/**
+ * SW Flag: If this bit is set then the successful completion of this atom
+ * will not cause an event to be sent to userspace
+ */
+#define BASE_JD_REQ_EVENT_ONLY_ON_FAILURE ( 1U << 12 )
+
+/**
+* These requirement bits are currently unused in base_jd_core_req (currently a u16)
+*/
+
+#define BASEP_JD_REQ_RESERVED_BIT13 ( 1U << 13 )
+#define BASEP_JD_REQ_RESERVED_BIT14 ( 1U << 14 )
+#define BASEP_JD_REQ_RESERVED_BIT15 ( 1U << 15 )
+
+/**
+* Mask of all the currently unused requirement bits in base_jd_core_req.
+*/
+
+#define BASEP_JD_REQ_RESERVED ( BASEP_JD_REQ_RESERVED_BIT13 |\
+ BASEP_JD_REQ_RESERVED_BIT14 | BASEP_JD_REQ_RESERVED_BIT15 )
+
+/**
+ * Mask of all bits in base_jd_core_req that control the type of the atom.
+ *
+ * This allows dependency only atoms to have flags set
+ */
+#define BASEP_JD_REQ_ATOM_TYPE ( ~(BASEP_JD_REQ_RESERVED | BASE_JD_REQ_EVENT_ONLY_ON_FAILURE |\
+ BASE_JD_REQ_EXTERNAL_RESOURCES ) )
+
+#if BASE_LEGACY_JD_API
+/**
+ * @brief A single job chain, with pre/post dependendencies and mem ops
+ *
+ * This structure is used to describe a single job-chain to be submitted
+ * as part of a bag.
+ * It contains all the necessary information for Base to take care of this
+ * job-chain, including core requirements, priority, syncsets and
+ * dependencies.
+ */
+typedef struct base_jd_atom
+{
+ mali_addr64 jc; /**< job-chain GPU address */
+ base_jd_udata udata; /**< user data */
+ base_jd_dep pre_dep; /**< pre-dependencies */
+ base_jd_dep post_dep; /**< post-dependencies */
+ base_jd_core_req core_req; /**< core requirements */
+ u16 nr_syncsets; /**< nr of syncsets following the atom */
+ u16 nr_extres; /**< nr of external resources following the atom */
+
+ /** @brief Relative priority.
+ *
+ * A positive value requests a lower priority, whilst a negative value
+ * requests a higher priority. Only privileged processes may request a
+ * higher priority. For unprivileged processes, a negative priority will
+ * be interpreted as zero.
+ */
+ s8 prio;
+
+ /**
+ * @brief Device number to use, depending on @ref base_jd_core_req flags set.
+ *
+ * When BASE_JD_REQ_SPECIFIC_COHERENT_GROUP is set, a 'device' is one of
+ * the coherent core groups, and so this targets a particular coherent
+ * core-group. They are numbered from 0 to (mali_base_gpu_coherent_group_info::num_groups - 1),
+ * and the cores targeted by this device_nr will usually be those specified by
+ * (mali_base_gpu_coherent_group_info::group[device_nr].core_mask).
+ * Further, two atoms from different processes using the same \a device_nr
+ * at the same time will always target the same coherent core-group.
+ *
+ * There are exceptions to when the device_nr is ignored:
+ * - when any process in the system uses a BASE_JD_REQ_CS or
+ * BASE_JD_REQ_ONLY_COMPUTE atom that can run on all cores across all
+ * coherency groups (i.e. also does \b not have the
+ * BASE_JD_REQ_COHERENT_GROUP or BASE_JD_REQ_SPECIFIC_COHERENT_GROUP flags
+ * set). In this case, such atoms would block device_nr==1 being used due
+ * to restrictions on affinity, perhaps indefinitely. To ensure progress is
+ * made, the atoms targeted for device_nr 1 will instead be redirected to
+ * device_nr 0
+ * - When any process in the system is using 'NSS' (BASE_JD_REQ_NSS) atoms,
+ * because there'd be very high latency on atoms targeting a coregroup
+ * that is also in use by NSS atoms. To ensure progress is
+ * made, the atoms targeted for device_nr 1 will instead be redirected to
+ * device_nr 0
+ * - During certain HW workarounds, such as BASE_HW_ISSUE_8987, where
+ * BASE_JD_REQ_ONLY_COMPUTE atoms must not use the same cores as other
+ * atoms. In this case, all atoms are targeted to device_nr == min( num_groups, 1 )
+ *
+ * Note that the 'device' number for a coherent coregroup cannot exceed
+ * (BASE_MAX_COHERENT_GROUPS - 1).
+ */
+ u8 device_nr;
+} base_jd_atom;
+#endif /* BASE_LEGACY_JD_API */
+
+typedef u8 base_atom_id; /**< Type big enough to store an atom number in */
+
+typedef struct base_jd_atom_v2
+{
+ mali_addr64 jc; /**< job-chain GPU address */
+ base_jd_core_req core_req; /**< core requirements */
+ base_jd_udata udata; /**< user data */
+ kbase_pointer extres_list; /**< list of external resources */
+ u16 nr_extres; /**< nr of external resources */
+ base_atom_id pre_dep[2]; /**< pre-dependencies */
+ base_atom_id atom_number; /**< unique number to identify the atom */
+ s8 prio; /**< priority - smaller is higher priority */
+ u8 device_nr; /**< coregroup when BASE_JD_REQ_SPECIFIC_COHERENT_GROUP specified */
+} base_jd_atom_v2;
+
+#if BASE_LEGACY_JD_API
+/* Structure definition works around the fact that C89 doesn't allow arrays of size 0 */
+typedef struct basep_jd_atom_ss
+{
+ base_jd_atom atom;
+ base_syncset syncsets[1];
+} basep_jd_atom_ss;
+#endif /* BASE_LEGACY_JD_API */
+
+typedef enum base_external_resource_access
+{
+ BASE_EXT_RES_ACCESS_SHARED,
+ BASE_EXT_RES_ACCESS_EXCLUSIVE
+} base_external_resource_access;
+
+typedef struct base_external_resource
+{
+ u64 ext_resource;
+} base_external_resource;
+
+#if BASE_LEGACY_JD_API
+/* Structure definition works around the fact that C89 doesn't allow arrays of size 0 */
+typedef struct basep_jd_atom_ext_res
+{
+ base_jd_atom atom;
+ base_external_resource resources[1];
+} basep_jd_atom_ext_res;
+
+static INLINE size_t base_jd_atom_size_ex(u32 syncset_count, u32 external_res_count)
+{
+ int size;
+
+ LOCAL_ASSERT( 0 == syncset_count || 0 == external_res_count );
+
+ size = syncset_count ? offsetof(basep_jd_atom_ss, syncsets[0]) + (sizeof(base_syncset) * syncset_count) :
+ external_res_count ? offsetof(basep_jd_atom_ext_res, resources[0]) + (sizeof(base_external_resource) * external_res_count) :
+ sizeof(base_jd_atom);
+
+ /* Atom minimum size set to 64 bytes to ensure that the maximum
+ * number of atoms in the ring buffer is limited to 256 */
+ return MAX(64, size);
+}
+
+/**
+ * @brief Atom size evaluator
+ *
+ * This function returns the size in bytes of a ::base_jd_atom
+ * containing @a n syncsets. It must be used to compute the size of a
+ * bag before allocation.
+ *
+ * @param nr the number of syncsets for this atom
+ * @return the atom size in bytes
+ */
+static INLINE size_t base_jd_atom_size(u32 nr)
+{
+ return base_jd_atom_size_ex(nr, 0);
+}
+
+/**
+ * @brief Atom syncset accessor
+ *
+ * This function returns a pointer to the nth syncset allocated
+ * together with an atom.
+ *
+ * @param[in] atom The allocated atom
+ * @param n The number of the syncset to be returned
+ * @return a pointer to the nth syncset.
+ */
+static INLINE base_syncset *base_jd_get_atom_syncset(base_jd_atom *atom, u16 n)
+{
+ LOCAL_ASSERT(atom != NULL);
+ LOCAL_ASSERT(0 == (atom->core_req & BASE_JD_REQ_EXTERNAL_RESOURCES));
+ LOCAL_ASSERT(n <= atom->nr_syncsets);
+ return &((basep_jd_atom_ss *)atom)->syncsets[n];
+}
+#endif /* BASE_LEGACY_JD_API */
+
+/**
+ * @brief Soft-atom fence trigger setup.
+ *
+ * Sets up an atom to be a SW-only atom signaling a fence
+ * when it reaches the run state.
+ *
+ * Using the existing base dependency system the fence can
+ * be set to trigger when a GPU job has finished.
+ *
+ * The base fence object must not be terminated until the atom
+ * has been submitted to @a base_jd_submit_bag and @a base_jd_submit_bag has returned.
+ *
+ * @a fence must be a valid fence set up with @a base_fence_init.
+ * Calling this function with a uninitialized fence results in undefined behavior.
+ *
+ * @param[out] atom A pre-allocated atom to configure as a fence trigger SW atom
+ * @param[in] fence The base fence object to trigger.
+ */
+static INLINE void base_jd_fence_trigger_setup(base_jd_atom * atom, base_fence * fence)
+{
+ LOCAL_ASSERT(atom);
+ LOCAL_ASSERT(fence);
+ LOCAL_ASSERT(fence->basep.fd == INVALID_PLATFORM_FENCE);
+ LOCAL_ASSERT(fence->basep.stream_fd >= 0);
+ atom->jc = (uintptr_t)fence;
+ atom->core_req = BASE_JD_REQ_SOFT_FENCE_TRIGGER;
+}
+
+static INLINE void base_jd_fence_trigger_setup_v2(base_jd_atom_v2 * atom, base_fence * fence)
+{
+ LOCAL_ASSERT(atom);
+ LOCAL_ASSERT(fence);
+ LOCAL_ASSERT(fence->basep.fd == INVALID_PLATFORM_FENCE);
+ LOCAL_ASSERT(fence->basep.stream_fd >= 0);
+ atom->jc = (uintptr_t)fence;
+ atom->core_req = BASE_JD_REQ_SOFT_FENCE_TRIGGER;
+}
+
+/**
+ * @brief Soft-atom fence wait setup.
+ *
+ * Sets up an atom to be a SW-only atom waiting on a fence.
+ * When the fence becomes triggered the atom becomes runnable
+ * and completes immediately.
+ *
+ * Using the existing base dependency system the fence can
+ * be set to block a GPU job until it has been triggered.
+ *
+ * The base fence object must not be terminated until the atom
+ * has been submitted to @a base_jd_submit_bag and @a base_jd_submit_bag has returned.
+ *
+ * @a fence must be a valid fence set up with @a base_fence_init or @a base_fence_import.
+ * Calling this function with a uninitialized fence results in undefined behavior.
+ *
+ * @param[out] atom A pre-allocated atom to configure as a fence wait SW atom
+ * @param[in] fence The base fence object to wait on
+ */
+static INLINE void base_jd_fence_wait_setup(base_jd_atom * atom, base_fence * fence)
+{
+ LOCAL_ASSERT(atom);
+ LOCAL_ASSERT(fence);
+ LOCAL_ASSERT(fence->basep.fd >= 0);
+ atom->jc = (uintptr_t)fence;
+ atom->core_req = BASE_JD_REQ_SOFT_FENCE_WAIT;
+}
+
+static INLINE void base_jd_fence_wait_setup_v2(base_jd_atom_v2 * atom, base_fence * fence)
+{
+ LOCAL_ASSERT(atom);
+ LOCAL_ASSERT(fence);
+ LOCAL_ASSERT(fence->basep.fd >= 0);
+ atom->jc = (uintptr_t)fence;
+ atom->core_req = BASE_JD_REQ_SOFT_FENCE_WAIT;
+}
+
+#if BASE_LEGACY_JD_API
+/**
+ * @brief Atom external resource accessor
+ *
+ * This functions returns a pointer to the nth external resource tracked by the atom.
+ *
+ * @param[in] atom The allocated atom
+ * @param n The number of the external resource to return a pointer to
+ * @return a pointer to the nth external resource
+ */
+static INLINE base_external_resource *base_jd_get_external_resource(base_jd_atom *atom, u16 n)
+{
+ LOCAL_ASSERT(atom != NULL);
+ LOCAL_ASSERT(BASE_JD_REQ_EXTERNAL_RESOURCES == (atom->core_req & BASE_JD_REQ_EXTERNAL_RESOURCES));
+ LOCAL_ASSERT(n <= atom->nr_extres);
+ return &((basep_jd_atom_ext_res*)atom)->resources[n];
+}
+#endif /* BASE_LEGACY_JD_API */
+
+/**
+ * @brief External resource info initialization.
+ *
+ * Sets up a external resource object to reference
+ * a memory allocation and the type of access requested.
+ *
+ * @param[in] res The resource object to initialize
+ * @param handle The handle to the imported memory object
+ * @param access The type of access requested
+ */
+static INLINE void base_external_resource_init(base_external_resource * res, base_import_handle handle, base_external_resource_access access)
+{
+ mali_addr64 address;
+ address = handle.basep.handle;
+
+ LOCAL_ASSERT(res != NULL);
+ LOCAL_ASSERT(0 == (address & LOCAL_PAGE_LSB));
+ LOCAL_ASSERT(access == BASE_EXT_RES_ACCESS_SHARED || access == BASE_EXT_RES_ACCESS_EXCLUSIVE);
+
+ res->ext_resource = address | (access & LOCAL_PAGE_LSB);
+}
+
+#if BASE_LEGACY_JD_API
+/**
+ * @brief Next atom accessor
+ *
+ * This function returns a pointer to the next allocated atom. It
+ * relies on the fact that the current atom has been correctly
+ * initialized (relies on the base_jd_atom::nr_syncsets field).
+ *
+ * @param[in] atom The allocated atom
+ * @return a pointer to the next atom.
+ */
+static INLINE base_jd_atom *base_jd_get_next_atom(base_jd_atom *atom)
+{
+ LOCAL_ASSERT(atom != NULL);
+ return (atom->core_req & BASE_JD_REQ_EXTERNAL_RESOURCES) ? (base_jd_atom *)base_jd_get_external_resource(atom, atom->nr_extres) :
+ (base_jd_atom *)base_jd_get_atom_syncset(atom, atom->nr_syncsets);
+}
+#endif /* BASE_LEGACY_JD_API */
+
+/**
+ * @brief Job chain event code bits
+ * Defines the bits used to create ::base_jd_event_code
+ */
+enum
+{
+ BASE_JD_SW_EVENT_KERNEL = (1u << 15), /**< Kernel side event */
+ BASE_JD_SW_EVENT = (1u << 14), /**< SW defined event */
+ BASE_JD_SW_EVENT_SUCCESS = (1u << 13), /**< Event idicates success (SW events only) */
+ BASE_JD_SW_EVENT_JOB = (0u << 11), /**< Job related event */
+ BASE_JD_SW_EVENT_BAG = (1u << 11), /**< Bag related event */
+ BASE_JD_SW_EVENT_INFO = (2u << 11), /**< Misc/info event */
+ BASE_JD_SW_EVENT_RESERVED = (3u << 11), /**< Reserved event type */
+ BASE_JD_SW_EVENT_TYPE_MASK = (3u << 11) /**< Mask to extract the type from an event code */
+};
+
+/**
+ * @brief Job chain event codes
+ *
+ * HW and low-level SW events are represented by event codes.
+ * The status of jobs which succeeded are also represented by
+ * an event code (see ::BASE_JD_EVENT_DONE).
+ * Events are usually reported as part of a ::base_jd_event.
+ *
+ * The event codes are encoded in the following way:
+ * @li 10:0 - subtype
+ * @li 12:11 - type
+ * @li 13 - SW success (only valid if the SW bit is set)
+ * @li 14 - SW event (HW event if not set)
+ * @li 15 - Kernel event (should never be seen in userspace)
+ *
+ * Events are split up into ranges as follows:
+ * - BASE_JD_EVENT_RANGE_\<description\>_START
+ * - BASE_JD_EVENT_RANGE_\<description\>_END
+ *
+ * \a code is in \<description\>'s range when:
+ * - <tt>BASE_JD_EVENT_RANGE_\<description\>_START <= code < BASE_JD_EVENT_RANGE_\<description\>_END </tt>
+ *
+ * Ranges can be asserted for adjacency by testing that the END of the previous
+ * is equal to the START of the next. This is useful for optimizing some tests
+ * for range.
+ *
+ * A limitation is that the last member of this enum must explicitly be handled
+ * (with an assert-unreachable statement) in switch statements that use
+ * variables of this type. Otherwise, the compiler warns that we have not
+ * handled that enum value.
+ */
+typedef enum base_jd_event_code
+{
+ /* HW defined exceptions */
+
+ /** Start of HW Non-fault status codes
+ *
+ * @note Obscurely, BASE_JD_EVENT_TERMINATED indicates a real fault,
+ * because the job was hard-stopped
+ */
+ BASE_JD_EVENT_RANGE_HW_NONFAULT_START = 0,
+
+ /* non-fatal exceptions */
+ BASE_JD_EVENT_NOT_STARTED = 0x00, /**< Can't be seen by userspace, treated as 'previous job done' */
+ BASE_JD_EVENT_DONE = 0x01,
+ BASE_JD_EVENT_STOPPED = 0x03, /**< Can't be seen by userspace, becomes TERMINATED, DONE or JOB_CANCELLED */
+ BASE_JD_EVENT_TERMINATED = 0x04, /**< This is actually a fault status code - the job was hard stopped */
+ BASE_JD_EVENT_ACTIVE = 0x08, /**< Can't be seen by userspace, jobs only returned on complete/fail/cancel */
+
+ /** End of HW Non-fault status codes
+ *
+ * @note Obscurely, BASE_JD_EVENT_TERMINATED indicates a real fault,
+ * because the job was hard-stopped
+ */
+ BASE_JD_EVENT_RANGE_HW_NONFAULT_END = 0x40,
+
+ /** Start of HW fault and SW Error status codes */
+ BASE_JD_EVENT_RANGE_HW_FAULT_OR_SW_ERROR_START = 0x40,
+
+ /* job exceptions */
+ BASE_JD_EVENT_JOB_CONFIG_FAULT = 0x40,
+ BASE_JD_EVENT_JOB_POWER_FAULT = 0x41,
+ BASE_JD_EVENT_JOB_READ_FAULT = 0x42,
+ BASE_JD_EVENT_JOB_WRITE_FAULT = 0x43,
+ BASE_JD_EVENT_JOB_AFFINITY_FAULT = 0x44,
+ BASE_JD_EVENT_JOB_BUS_FAULT = 0x48,
+ BASE_JD_EVENT_INSTR_INVALID_PC = 0x50,
+ BASE_JD_EVENT_INSTR_INVALID_ENC = 0x51,
+ BASE_JD_EVENT_INSTR_TYPE_MISMATCH = 0x52,
+ BASE_JD_EVENT_INSTR_OPERAND_FAULT = 0x53,
+ BASE_JD_EVENT_INSTR_TLS_FAULT = 0x54,
+ BASE_JD_EVENT_INSTR_BARRIER_FAULT = 0x55,
+ BASE_JD_EVENT_INSTR_ALIGN_FAULT = 0x56,
+ BASE_JD_EVENT_DATA_INVALID_FAULT = 0x58,
+ BASE_JD_EVENT_TILE_RANGE_FAULT = 0x59,
+ BASE_JD_EVENT_STATE_FAULT = 0x5A,
+ BASE_JD_EVENT_OUT_OF_MEMORY = 0x60,
+ BASE_JD_EVENT_UNKNOWN = 0x7F,
+
+ /* GPU exceptions */
+ BASE_JD_EVENT_DELAYED_BUS_FAULT = 0x80,
+ BASE_JD_EVENT_SHAREABILITY_FAULT = 0x88,
+
+ /* MMU exceptions */
+ BASE_JD_EVENT_TRANSLATION_FAULT_LEVEL1 = 0xC1,
+ BASE_JD_EVENT_TRANSLATION_FAULT_LEVEL2 = 0xC2,
+ BASE_JD_EVENT_TRANSLATION_FAULT_LEVEL3 = 0xC3,
+ BASE_JD_EVENT_TRANSLATION_FAULT_LEVEL4 = 0xC4,
+ BASE_JD_EVENT_PERMISSION_FAULT = 0xC8,
+ BASE_JD_EVENT_TRANSTAB_BUS_FAULT_LEVEL1 = 0xD1,
+ BASE_JD_EVENT_TRANSTAB_BUS_FAULT_LEVEL2 = 0xD2,
+ BASE_JD_EVENT_TRANSTAB_BUS_FAULT_LEVEL3 = 0xD3,
+ BASE_JD_EVENT_TRANSTAB_BUS_FAULT_LEVEL4 = 0xD4,
+ BASE_JD_EVENT_ACCESS_FLAG = 0xD8,
+
+ /* SW defined exceptions */
+ BASE_JD_EVENT_MEM_GROWTH_FAILED = BASE_JD_SW_EVENT | BASE_JD_SW_EVENT_JOB | 0x000,
+ BASE_JD_EVENT_TIMED_OUT = BASE_JD_SW_EVENT | BASE_JD_SW_EVENT_JOB | 0x001,
+ BASE_JD_EVENT_JOB_CANCELLED = BASE_JD_SW_EVENT | BASE_JD_SW_EVENT_JOB | 0x002,
+ BASE_JD_EVENT_JOB_INVALID = BASE_JD_SW_EVENT | BASE_JD_SW_EVENT_JOB | 0x003,
+
+ BASE_JD_EVENT_BAG_INVALID = BASE_JD_SW_EVENT | BASE_JD_SW_EVENT_BAG | 0x003,
+
+ /** End of HW fault and SW Error status codes */
+ BASE_JD_EVENT_RANGE_HW_FAULT_OR_SW_ERROR_END = BASE_JD_SW_EVENT | BASE_JD_SW_EVENT_RESERVED | 0x3FF,
+
+ /** Start of SW Success status codes */
+ BASE_JD_EVENT_RANGE_SW_SUCCESS_START = BASE_JD_SW_EVENT | BASE_JD_SW_EVENT_SUCCESS | 0x000,
+
+ BASE_JD_EVENT_PROGRESS_REPORT = BASE_JD_SW_EVENT | BASE_JD_SW_EVENT_SUCCESS | BASE_JD_SW_EVENT_JOB | 0x000,
+ BASE_JD_EVENT_BAG_DONE = BASE_JD_SW_EVENT | BASE_JD_SW_EVENT_SUCCESS | BASE_JD_SW_EVENT_BAG | 0x000,
+ BASE_JD_EVENT_DRV_TERMINATED = BASE_JD_SW_EVENT | BASE_JD_SW_EVENT_SUCCESS | BASE_JD_SW_EVENT_INFO | 0x000,
+
+ /** End of SW Success status codes */
+ BASE_JD_EVENT_RANGE_SW_SUCCESS_END = BASE_JD_SW_EVENT | BASE_JD_SW_EVENT_SUCCESS | BASE_JD_SW_EVENT_RESERVED | 0x3FF,
+
+ /** Start of Kernel-only status codes. Such codes are never returned to user-space */
+ BASE_JD_EVENT_RANGE_KERNEL_ONLY_START = BASE_JD_SW_EVENT | BASE_JD_SW_EVENT_KERNEL | 0x000,
+ BASE_JD_EVENT_REMOVED_FROM_NEXT = BASE_JD_SW_EVENT | BASE_JD_SW_EVENT_KERNEL | BASE_JD_SW_EVENT_JOB | 0x000,
+
+ /** End of Kernel-only status codes. */
+ BASE_JD_EVENT_RANGE_KERNEL_ONLY_END = BASE_JD_SW_EVENT | BASE_JD_SW_EVENT_KERNEL | BASE_JD_SW_EVENT_RESERVED | 0x3FF
+} base_jd_event_code;
+
+/**
+ * @brief Event reporting structure
+ *
+ * This structure is used by the kernel driver to report information
+ * about GPU events. The can either be HW-specific events or low-level
+ * SW events, such as job-chain completion.
+ *
+ * The event code contains an event type field which can be extracted
+ * by ANDing with ::BASE_JD_SW_EVENT_TYPE_MASK.
+ *
+ * Based on the event type base_jd_event::data holds:
+ * @li ::BASE_JD_SW_EVENT_JOB : the offset in the ring-buffer for the completed
+ * job-chain
+ * @li ::BASE_JD_SW_EVENT_BAG : The address of the ::base_jd_bag that has
+ * been completed (ie all contained job-chains have been completed).
+ * @li ::BASE_JD_SW_EVENT_INFO : base_jd_event::data not used
+ */
+#if BASE_LEGACY_JD_API
+typedef struct base_jd_event
+{
+ base_jd_event_code event_code; /**< event code */
+ void * data; /**< event specific data */
+} base_jd_event;
+#endif
+
+typedef struct base_jd_event_v2
+{
+ base_jd_event_code event_code; /**< event code */
+ base_atom_id atom_number;/**< the atom number that has completed */
+ base_jd_udata udata; /**< user data */
+} base_jd_event_v2;
+
+/**
+ * @brief Structure for BASE_JD_REQ_SOFT_DUMP_CPU_GPU_COUNTERS jobs.
+ *
+ * This structure is stored into the memory pointed to by the @c jc field of @ref base_jd_atom.
+ */
+typedef struct base_dump_cpu_gpu_counters {
+ u64 system_time;
+ u64 cycle_counter;
+ u64 sec;
+ u32 usec;
+} base_dump_cpu_gpu_counters;
+
+/** @} end group base_user_api_job_dispatch */
+
+
+#ifdef __KERNEL__
+/*
+ * The following typedefs should be removed when a midg types header is added.
+ * See MIDCOM-1657 for details.
+ */
+typedef u32 midg_product_id;
+typedef u32 midg_cache_features;
+typedef u32 midg_tiler_features;
+typedef u32 midg_mem_features;
+typedef u32 midg_mmu_features;
+typedef u32 midg_js_features;
+typedef u32 midg_as_present;
+typedef u32 midg_js_present;
+
+#define MIDG_MAX_JOB_SLOTS 16
+
+#else
+#include <midg/mali_midg.h>
+#endif
+
+/**
+ * @page page_base_user_api_gpuprops User-side Base GPU Property Query API
+ *
+ * The User-side Base GPU Property Query API encapsulates two
+ * sub-modules:
+ *
+ * - @ref base_user_api_gpuprops_dyn "Dynamic GPU Properties"
+ * - @ref base_plat_config_gpuprops "Base Platform Config GPU Properties"
+ *
+ * There is a related third module outside of Base, which is owned by the MIDG
+ * module:
+ * - @ref midg_gpuprops_static "Midgard Compile-time GPU Properties"
+ *
+ * Base only deals with properties that vary between different Midgard
+ * implementations - the Dynamic GPU properties and the Platform Config
+ * properties.
+ *
+ * For properties that are constant for the Midgard Architecture, refer to the
+ * MIDG module. However, we will discuss their relevance here <b>just to
+ * provide background information.</b>
+ *
+ * @section sec_base_user_api_gpuprops_about About the GPU Properties in Base and MIDG modules
+ *
+ * The compile-time properties (Platform Config, Midgard Compile-time
+ * properties) are exposed as pre-processor macros.
+ *
+ * Complementing the compile-time properties are the Dynamic GPU
+ * Properties, which act as a conduit for the Midgard Configuration
+ * Discovery.
+ *
+ * In general, the dynamic properties are present to verify that the platform
+ * has been configured correctly with the right set of Platform Config
+ * Compile-time Properties.
+ *
+ * As a consistant guide across the entire DDK, the choice for dynamic or
+ * compile-time should consider the following, in order:
+ * -# Can the code be written so that it doesn't need to know the
+ * implementation limits at all?
+ * -# If you need the limits, get the information from the Dynamic Property
+ * lookup. This should be done once as you fetch the context, and then cached
+ * as part of the context data structure, so it's cheap to access.
+ * -# If there's a clear and arguable inefficiency in using Dynamic Properties,
+ * then use a Compile-Time Property (Platform Config, or Midgard Compile-time
+ * property). Examples of where this might be sensible follow:
+ * - Part of a critical inner-loop
+ * - Frequent re-use throughout the driver, causing significant extra load
+ * instructions or control flow that would be worthwhile optimizing out.
+ *
+ * We cannot provide an exhaustive set of examples, neither can we provide a
+ * rule for every possible situation. Use common sense, and think about: what
+ * the rest of the driver will be doing; how the compiler might represent the
+ * value if it is a compile-time constant; whether an OEM shipping multiple
+ * devices would benefit much more from a single DDK binary, instead of
+ * insignificant micro-optimizations.
+ *
+ * @section sec_base_user_api_gpuprops_dyn Dynamic GPU Properties
+ *
+ * Dynamic GPU properties are presented in two sets:
+ * -# the commonly used properties in @ref base_gpu_props, which have been
+ * unpacked from GPU register bitfields.
+ * -# The full set of raw, unprocessed properties in @ref midg_raw_gpu_props
+ * (also a member of @ref base_gpu_props). All of these are presented in
+ * the packed form, as presented by the GPU registers themselves.
+ *
+ * @usecase The raw properties in @ref midg_raw_gpu_props are necessary to
+ * allow a user of the Mali Tools (e.g. PAT) to determine "Why is this device
+ * behaving differently?". In this case, all information about the
+ * configuration is potentially useful, but it <b>does not need to be processed
+ * by the driver</b>. Instead, the raw registers can be processed by the Mali
+ * Tools software on the host PC.
+ *
+ * The properties returned extend the Midgard Configuration Discovery
+ * registers. For example, GPU clock speed is not specified in the Midgard
+ * Architecture, but is <b>necessary for OpenCL's clGetDeviceInfo() function</b>.
+ *
+ * The GPU properties are obtained by a call to
+ * _mali_base_get_gpu_props(). This simply returns a pointer to a const
+ * base_gpu_props structure. It is constant for the life of a base
+ * context. Multiple calls to _mali_base_get_gpu_props() to a base context
+ * return the same pointer to a constant structure. This avoids cache pollution
+ * of the common data.
+ *
+ * This pointer must not be freed, because it does not point to the start of a
+ * region allocated by the memory allocator; instead, just close the @ref
+ * base_context.
+ *
+ *
+ * @section sec_base_user_api_gpuprops_config Platform Config Compile-time Properties
+ *
+ * The Platform Config File sets up gpu properties that are specific to a
+ * certain platform. Properties that are 'Implementation Defined' in the
+ * Midgard Architecture spec are placed here.
+ *
+ * @note Reference configurations are provided for Midgard Implementations, such as
+ * the Mali-T600 family. The customer need not repeat this information, and can select one of
+ * these reference configurations. For example, VA_BITS, PA_BITS and the
+ * maximum number of samples per pixel might vary between Midgard Implementations, but
+ * \b not for platforms using the Mali-T604. This information is placed in
+ * the reference configuration files.
+ *
+ * The System Integrator creates the following structure:
+ * - platform_XYZ
+ * - platform_XYZ/plat
+ * - platform_XYZ/plat/plat_config.h
+ *
+ * They then edit plat_config.h, using the example plat_config.h files as a
+ * guide.
+ *
+ * At the very least, the customer must set @ref CONFIG_GPU_CORE_TYPE, and will
+ * receive a helpful \#error message if they do not do this correctly. This
+ * selects the Reference Configuration for the Midgard Implementation. The rationale
+ * behind this decision (against asking the customer to write \#include
+ * <gpus/mali_t600.h> in their plat_config.h) is as follows:
+ * - This mechanism 'looks' like a regular config file (such as Linux's
+ * .config)
+ * - It is difficult to get wrong in a way that will produce strange build
+ * errors:
+ * - They need not know where the mali_t600.h, other_midg_gpu.h etc. files are stored - and
+ * so they won't accidentally pick another file with 'mali_t600' in its name
+ * - When the build doesn't work, the System Integrator may think the DDK is
+ * doesn't work, and attempt to fix it themselves:
+ * - For the @ref CONFIG_GPU_CORE_TYPE mechanism, the only way to get past the
+ * error is to set @ref CONFIG_GPU_CORE_TYPE, and this is what the \#error tells
+ * you.
+ * - For a \#include mechanism, checks must still be made elsewhere, which the
+ * System Integrator may try working around by setting \#defines (such as
+ * VA_BITS) themselves in their plat_config.h. In the worst case, they may
+ * set the prevention-mechanism \#define of
+ * "A_CORRECT_MIDGARD_CORE_WAS_CHOSEN".
+ * - In this case, they would believe they are on the right track, because
+ * the build progresses with their fix, but with errors elsewhere.
+ *
+ * However, there is nothing to prevent the customer using \#include to organize
+ * their own configurations files hierarchically.
+ *
+ * The mechanism for the header file processing is as follows:
+ *
+ * @dot
+ digraph plat_config_mechanism {
+ rankdir=BT
+ size="6,6"
+
+ "mali_base.h";
+ "midg/midg.h";
+
+ node [ shape=box ];
+ {
+ rank = same; ordering = out;
+
+ "midg/midg_gpu_props.h";
+ "base/midg_gpus/mali_t600.h";
+ "base/midg_gpus/other_midg_gpu.h";
+ }
+ { rank = same; "plat/plat_config.h"; }
+ {
+ rank = same;
+ "midg/midg.h" [ shape=box ];
+ gpu_chooser [ label="" style="invisible" width=0 height=0 fixedsize=true ];
+ select_gpu [ label="Mali-T600 | Other\n(select_gpu.h)" shape=polygon,sides=4,distortion=0.25 width=3.3 height=0.99 fixedsize=true ] ;
+ }
+ node [ shape=box ];
+ { rank = same; "plat/plat_config.h"; }
+ { rank = same; "mali_base.h"; }
+
+
+
+ "mali_base.h" -> "midg/midg.h" -> "midg/midg_gpu_props.h";
+ "mali_base.h" -> "plat/plat_config.h" ;
+ "mali_base.h" -> select_gpu ;
+
+ "plat/plat_config.h" -> gpu_chooser [style="dotted,bold" dir=none weight=4] ;
+ gpu_chooser -> select_gpu [style="dotted,bold"] ;
+
+ select_gpu -> "base/midg_gpus/mali_t600.h" ;
+ select_gpu -> "base/midg_gpus/other_midg_gpu.h" ;
+ }
+ @enddot
+ *
+ *
+ * @section sec_base_user_api_gpuprops_kernel Kernel Operation
+ *
+ * During Base Context Create time, user-side makes a single kernel call:
+ * - A call to fill user memory with GPU information structures
+ *
+ * The kernel-side will fill the provided the entire processed @ref base_gpu_props
+ * structure, because this information is required in both
+ * user and kernel side; it does not make sense to decode it twice.
+ *
+ * Coherency groups must be derived from the bitmasks, but this can be done
+ * kernel side, and just once at kernel startup: Coherency groups must already
+ * be known kernel-side, to support chains that specify a 'Only Coherent Group'
+ * SW requirement, or 'Only Coherent Group with Tiler' SW requirement.
+ *
+ * @section sec_base_user_api_gpuprops_cocalc Coherency Group calculation
+ * Creation of the coherent group data is done at device-driver startup, and so
+ * is one-time. This will most likely involve a loop with CLZ, shifting, and
+ * bit clearing on the L2_PRESENT or L3_PRESENT masks, depending on whether the
+ * system is L2 or L2+L3 Coherent. The number of shader cores is done by a
+ * population count, since faulty cores may be disabled during production,
+ * producing a non-contiguous mask.
+ *
+ * The memory requirements for this algoirthm can be determined either by a u64
+ * population count on the L2/L3_PRESENT masks (a LUT helper already is
+ * requried for the above), or simple assumption that there can be no more than
+ * 16 coherent groups, since core groups are typically 4 cores.
+ */
+
+
+/**
+ * @addtogroup base_user_api_gpuprops User-side Base GPU Property Query APIs
+ * @{
+ */
+
+
+/**
+ * @addtogroup base_user_api_gpuprops_dyn Dynamic HW Properties
+ * @{
+ */
+
+
+#define BASE_GPU_NUM_TEXTURE_FEATURES_REGISTERS 3
+
+#define BASE_MAX_COHERENT_GROUPS 16
+
+struct mali_base_gpu_core_props
+{
+ /**
+ * Product specific value.
+ */
+ midg_product_id product_id;
+
+ /**
+ * Status of the GPU release.
+ * No defined values, but starts at 0 and increases by one for each release
+ * status (alpha, beta, EAC, etc.).
+ * 4 bit values (0-15).
+ */
+ u16 version_status;
+
+ /**
+ * Minor release number of the GPU. "P" part of an "RnPn" release number.
+ * 8 bit values (0-255).
+ */
+ u16 minor_revision;
+
+ /**
+ * Major release number of the GPU. "R" part of an "RnPn" release number.
+ * 4 bit values (0-15).
+ */
+ u16 major_revision;
+
+ /**
+ * @usecase GPU clock speed is not specified in the Midgard Architecture, but is
+ * <b>necessary for OpenCL's clGetDeviceInfo() function</b>.
+ */
+ u32 gpu_speed_mhz;
+
+ /**
+ * @usecase GPU clock max/min speed is required for computing best/worst case
+ * in tasks as job scheduling ant irq_throttling. (It is not specified in the
+ * Midgard Architecture).
+ */
+ u32 gpu_freq_khz_max;
+ u32 gpu_freq_khz_min;
+
+ /**
+ * Size of the shader program counter, in bits.
+ */
+ u32 log2_program_counter_size;
+
+ /**
+ * TEXTURE_FEATURES_x registers, as exposed by the GPU. This is a
+ * bitpattern where a set bit indicates that the format is supported.
+ *
+ * Before using a texture format, it is recommended that the corresponding
+ * bit be checked.
+ */
+ u32 texture_features[BASE_GPU_NUM_TEXTURE_FEATURES_REGISTERS];
+
+ /**
+ * Theoretical maximum memory available to the GPU. It is unlikely that a
+ * client will be able to allocate all of this memory for their own
+ * purposes, but this at least provides an upper bound on the memory
+ * available to the GPU.
+ *
+ * This is required for OpenCL's clGetDeviceInfo() call when
+ * CL_DEVICE_GLOBAL_MEM_SIZE is requested, for OpenCL GPU devices. The
+ * client will not be expecting to allocate anywhere near this value.
+ */
+ u64 gpu_available_memory_size;
+
+ /**
+ * @usecase Version string: For use by glGetString( GL_RENDERER ); (and similar
+ * for other APIs)
+ */
+ const char * version_string;
+};
+
+/**
+ *
+ * More information is possible - but associativity and bus width are not
+ * required by upper-level apis.
+
+ */
+struct mali_base_gpu_cache_props
+{
+ u32 log2_line_size;
+ u32 log2_cache_size;
+};
+
+struct mali_base_gpu_tiler_props
+{
+ u32 bin_size_bytes; /* Max is 4*2^15 */
+ u32 max_active_levels; /* Max is 2^15 */
+};
+
+/**
+ * @brief descriptor for a coherent group
+ *
+ * \c core_mask exposes all cores in that coherent group, and \c num_cores
+ * provides a cached population-count for that mask.
+ *
+ * @note Whilst all cores are exposed in the mask, not all may be available to
+ * the application, depending on the Kernel Job Scheduler policy. Therefore,
+ * the application should not further restrict the core mask itself, as it may
+ * result in an empty core mask. However, it can guarentee that there will be
+ * at least one core available for each core group exposed .
+ *
+ * @usecase Chains marked at certain user-side priorities (e.g. the Long-running
+ * (batch) priority ) can be prevented from running on entire core groups by the
+ * Kernel Chain Scheduler policy.
+ *
+ * @note if u64s must be 8-byte aligned, then this structure has 32-bits of wastage.
+ */
+struct mali_base_gpu_coherent_group
+{
+ u64 core_mask; /**< Core restriction mask required for the group */
+ u16 num_cores; /**< Number of cores in the group */
+};
+
+/**
+ * @brief Coherency group information
+ *
+ * Note that the sizes of the members could be reduced. However, the \c group
+ * member might be 8-byte aligned to ensure the u64 core_mask is 8-byte
+ * aligned, thus leading to wastage if the other members sizes were reduced.
+ *
+ * The groups are sorted by core mask. The core masks are non-repeating and do
+ * not intersect.
+ */
+struct mali_base_gpu_coherent_group_info
+{
+ u32 num_groups;
+
+ /**
+ * Number of core groups (coherent or not) in the GPU. Equivalent to the number of L2 Caches.
+ *
+ * The GPU Counter dumping writes 2048 bytes per core group, regardless of
+ * whether the core groups are coherent or not. Hence this member is needed
+ * to calculate how much memory is required for dumping.
+ *
+ * @note Do not use it to work out how many valid elements are in the
+ * group[] member. Use num_groups instead.
+ */
+ u32 num_core_groups;
+
+ /**
+ * Coherency features of the memory, accessed by @ref midg_mem_features
+ * methods
+ */
+ midg_mem_features coherency;
+
+ /**
+ * Descriptors of coherent groups
+ */
+ struct mali_base_gpu_coherent_group group[BASE_MAX_COHERENT_GROUPS];
+};
+
+
+/**
+ * A complete description of the GPU's Hardware Configuration Discovery
+ * registers.
+ *
+ * The information is presented inefficiently for access. For frequent access,
+ * the values should be better expressed in an unpacked form in the
+ * base_gpu_props structure.
+ *
+ * @usecase The raw properties in @ref midg_raw_gpu_props are necessary to
+ * allow a user of the Mali Tools (e.g. PAT) to determine "Why is this device
+ * behaving differently?". In this case, all information about the
+ * configuration is potentially useful, but it <b>does not need to be processed
+ * by the driver</b>. Instead, the raw registers can be processed by the Mali
+ * Tools software on the host PC.
+ *
+ */
+struct midg_raw_gpu_props
+{
+ u64 shader_present;
+ u64 tiler_present;
+ u64 l2_present;
+ u64 l3_present;
+
+ midg_cache_features l2_features;
+ midg_cache_features l3_features;
+ midg_mem_features mem_features;
+ midg_mmu_features mmu_features;
+
+ midg_as_present as_present;
+
+ u32 js_present;
+ midg_js_features js_features[MIDG_MAX_JOB_SLOTS];
+ midg_tiler_features tiler_features;
+
+ u32 gpu_id;
+};
+
+
+
+/**
+ * Return structure for _mali_base_get_gpu_props().
+ *
+ */
+typedef struct mali_base_gpu_props
+{
+ struct mali_base_gpu_core_props core_props;
+ struct mali_base_gpu_cache_props l2_props;
+ struct mali_base_gpu_cache_props l3_props;
+ struct mali_base_gpu_tiler_props tiler_props;
+
+ /** This member is large, likely to be 128 bytes */
+ struct midg_raw_gpu_props raw_props;
+
+ /** This must be last member of the structure */
+ struct mali_base_gpu_coherent_group_info coherency_info;
+}base_gpu_props;
+
+/** @} end group base_user_api_gpuprops_dyn */
+
+/** @} end group base_user_api_gpuprops */
+
+/**
+ * @addtogroup base_user_api_core User-side Base core APIs
+ * @{
+ */
+
+/**
+ * \enum base_context_create_flags
+ *
+ * Flags to pass to ::base_context_init.
+ * Flags can be ORed together to enable multiple things.
+ *
+ * These share the same space as @ref basep_context_private_flags, and so must
+ * not collide with them.
+ */
+enum base_context_create_flags
+{
+ /** No flags set */
+ BASE_CONTEXT_CREATE_FLAG_NONE = 0,
+
+ /** Base context is embedded in a cctx object (flag used for CINSTR software counter macros) */
+ BASE_CONTEXT_CCTX_EMBEDDED = (1u << 0),
+
+ /** Base context is a 'System Monitor' context for Hardware counters.
+ *
+ * One important side effect of this is that job submission is disabled. */
+ BASE_CONTEXT_SYSTEM_MONITOR_SUBMIT_DISABLED = (1u << 1),
+
+ /** Base context flag indicating a 'hint' that this context uses Compute
+ * Jobs only.
+ *
+ * Specifially, this means that it only sends atoms that <b>do not</b>
+ * contain the following @ref base_jd_core_req :
+ * - BASE_JD_REQ_FS
+ * - BASE_JD_REQ_T
+ *
+ * Violation of these requirements will cause the Job-Chains to be rejected.
+ *
+ * In addition, it is inadvisable for the atom's Job-Chains to contain Jobs
+ * of the following @ref midg_job_type (whilst it may work now, it may not
+ * work in future) :
+ * - @ref MIDG_JOB_VERTEX
+ * - @ref MIDG_JOB_GEOMETRY
+ *
+ * @note An alternative to using this is to specify the BASE_JD_REQ_ONLY_COMPUTE
+ * requirement in atoms.
+ */
+ BASE_CONTEXT_HINT_ONLY_COMPUTE = (1u << 2)
+};
+
+/**
+ * Bitpattern describing the ::base_context_create_flags that can be passed to base_context_init()
+ */
+#define BASE_CONTEXT_CREATE_ALLOWED_FLAGS \
+ ( ((u32)BASE_CONTEXT_CCTX_EMBEDDED) | \
+ ((u32)BASE_CONTEXT_SYSTEM_MONITOR_SUBMIT_DISABLED) | \
+ ((u32)BASE_CONTEXT_HINT_ONLY_COMPUTE) )
+
+/**
+ * Bitpattern describing the ::base_context_create_flags that can be passed to the kernel
+ */
+#define BASE_CONTEXT_CREATE_KERNEL_FLAGS \
+ ( ((u32)BASE_CONTEXT_SYSTEM_MONITOR_SUBMIT_DISABLED) | \
+ ((u32)BASE_CONTEXT_HINT_ONLY_COMPUTE) )
+
+
+/**
+ * Private flags used on the base context
+ *
+ * These start at bit 31, and run down to zero.
+ *
+ * They share the same space as @ref base_context_create_flags, and so must
+ * not collide with them.
+ */
+enum basep_context_private_flags
+{
+ /** Private flag tracking whether job descriptor dumping is disabled */
+ BASEP_CONTEXT_FLAG_JOB_DUMP_DISABLED = (1 << 31)
+};
+
+/** @} end group base_user_api_core */
+
+/** @} end group base_user_api */
+
+/**
+ * @addtogroup base_plat_config_gpuprops Base Platform Config GPU Properties
+ * @{
+ *
+ * C Pre-processor macros are exposed here to do with Platform
+ * Config.
+ *
+ * These include:
+ * - GPU Properties that are constant on a particular Midgard Family
+ * Implementation e.g. Maximum samples per pixel on Mali-T600.
+ * - General platform config for the GPU, such as the GPU major and minor
+ * revison.
+ */
+
+/** @} end group base_plat_config_gpuprops */
+
+/**
+ * @addtogroup base_api Base APIs
+ * @{
+ */
+/**
+ * @addtogroup basecpuprops Base CPU Properties
+ * @{
+ */
+
+/**
+ * @brief CPU Property Flag for base_cpu_props::cpu_flags, indicating a
+ * Little Endian System. If not set in base_cpu_props::cpu_flags, then the
+ * system is Big Endian.
+ *
+ * The compile-time equivalent is @ref CONFIG_CPU_LITTLE_ENDIAN.
+ */
+#define BASE_CPU_PROPERTY_FLAG_LITTLE_ENDIAN F_BIT_0
+
+/** @brief Platform Dynamic CPU properties structure */
+typedef struct base_cpu_props {
+ u32 nr_cores; /**< Number of CPU cores */
+
+ /**
+ * CPU page size as a Logarithm to Base 2. The compile-time
+ * equivalent is @ref CONFIG_CPU_PAGE_SIZE_LOG2
+ */
+ u32 cpu_page_size_log2;
+
+ /**
+ * CPU L1 Data cache line size as a Logarithm to Base 2. The compile-time
+ * equivalent is @ref CONFIG_CPU_L1_DCACHE_LINE_SIZE_LOG2.
+ */
+ u32 cpu_l1_dcache_line_size_log2;
+
+ /**
+ * CPU L1 Data cache size, in bytes. The compile-time equivalient is
+ * @ref CONFIG_CPU_L1_DCACHE_SIZE.
+ *
+ * This CPU Property is mainly provided to implement OpenCL's
+ * clGetDeviceInfo(), which allows the CL_DEVICE_GLOBAL_MEM_CACHE_SIZE
+ * hint to be queried.
+ */
+ u32 cpu_l1_dcache_size;
+
+ /**
+ * CPU Property Flags bitpattern.
+ *
+ * This is a combination of bits as specified by the macros prefixed with
+ * 'BASE_CPU_PROPERTY_FLAG_'.
+ */
+ u32 cpu_flags;
+
+ /**
+ * Maximum clock speed in MHz.
+ * @usecase 'Maximum' CPU Clock Speed information is required by OpenCL's
+ * clGetDeviceInfo() function for the CL_DEVICE_MAX_CLOCK_FREQUENCY hint.
+ */
+ u32 max_cpu_clock_speed_mhz;
+
+ /**
+ * @brief Total memory, in bytes.
+ *
+ * This is the theoretical maximum memory available to the CPU. It is
+ * unlikely that a client will be able to allocate all of this memory for
+ * their own purposes, but this at least provides an upper bound on the
+ * memory available to the CPU.
+ *
+ * This is required for OpenCL's clGetDeviceInfo() call when
+ * CL_DEVICE_GLOBAL_MEM_SIZE is requested, for OpenCL CPU devices.
+ */
+ u64 available_memory_size;
+} base_cpu_props;
+/** @} end group basecpuprops */
+
+/** @} end group base_api */
+
+#endif /* _BASE_KERNEL_H_ */
diff --git a/drivers/gpu/arm/t6xx/kbase/mali_base_kernel_sync.h b/drivers/gpu/arm/t6xx/kbase/mali_base_kernel_sync.h
new file mode 100644
index 0000000..94fe868
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/mali_base_kernel_sync.h
@@ -0,0 +1,43 @@
+/*
+ *
+ * (C) COPYRIGHT 2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file
+ * Base cross-proccess sync API.
+ */
+
+#ifndef _BASE_KERNEL_SYNC_H_
+#define _BASE_KERNEL_SYNC_H_
+
+#include <linux/ioctl.h>
+
+#define STREAM_IOC_MAGIC '~'
+
+/* Fence insert.
+ *
+ * Inserts a fence on the stream operated on.
+ * Fence can be waited via a base fence wait soft-job
+ * or triggered via a base fence trigger soft-job.
+ *
+ * Fences must be cleaned up with close when no longer needed.
+ *
+ * No input/output arguments.
+ * Returns
+ * >=0 fd
+ * <0 error code
+ */
+#define STREAM_IOC_FENCE_INSERT _IO(STREAM_IOC_MAGIC, 0)
+
+#endif /* _BASE_KERNEL_SYNC_H_ */
+
diff --git a/drivers/gpu/arm/t6xx/kbase/mali_kbase_config.h b/drivers/gpu/arm/t6xx/kbase/mali_kbase_config.h
new file mode 100644
index 0000000..ef55074
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/mali_kbase_config.h
@@ -0,0 +1,794 @@
+/*
+ *
+ * (C) COPYRIGHT 2010-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_kbase_config.h
+ * Configuration API and Attributes for KBase
+ */
+
+#ifndef _KBASE_CONFIG_H_
+#define _KBASE_CONFIG_H_
+
+#include <malisw/mali_stdtypes.h>
+
+/**
+ * @addtogroup base_api
+ * @{
+ */
+
+/**
+ * @addtogroup base_kbase_api
+ * @{
+ */
+
+/**
+ * @addtogroup kbase_config Configuration API and Attributes
+ * @{
+ */
+
+#if MALI_CUSTOMER_RELEASE == 0
+/* This flag is set for internal builds so we can run tests without credentials. */
+#define KBASE_HWCNT_DUMP_BYPASS_ROOT 1
+#else
+#define KBASE_HWCNT_DUMP_BYPASS_ROOT 0
+#endif
+
+#include <linux/rbtree.h>
+
+/**
+ * Relative memory performance indicators. Enum elements should always be defined in slowest to fastest order.
+ */
+typedef enum kbase_memory_performance
+{
+ KBASE_MEM_PERF_SLOW,
+ KBASE_MEM_PERF_NORMAL,
+ KBASE_MEM_PERF_FAST,
+
+ KBASE_MEM_PERF_MAX_VALUE = KBASE_MEM_PERF_FAST
+} kbase_memory_performance;
+
+/**
+ * Device wide configuration
+ */
+enum
+{
+ /**
+ * Invalid attribute ID (reserve 0).
+ *
+ * Attached value: Ignored
+ * Default value: NA
+ * */
+ KBASE_CONFIG_ATTR_INVALID,
+
+ /**
+ * Memory resource object.
+ * Multiple resources can be listed.
+ * The resources will be used in the order listed
+ * in the configuration attribute list if they have no other
+ * preferred order based on the memory resource property list
+ * (see ::kbase_memory_attribute).
+ *
+ * Attached value: Pointer to a kbase_memory_resource object.
+ * Default value: No resources
+ * */
+
+ KBASE_CONFIG_ATTR_MEMORY_RESOURCE,
+ /**
+ * Maximum of memory which can be allocated from the OS
+ * to be used by the GPU (shared memory).
+ * This must be greater than 0 as the GPU page tables
+ * are currently stored in a shared memory allocation.
+ *
+ * Attached value: number in bytes
+ * Default value: Limited by available memory
+ */
+ KBASE_CONFIG_ATTR_MEMORY_OS_SHARED_MAX,
+
+ /**
+ * Relative performance for the GPU to access
+ * OS shared memory.
+ *
+ * Attached value: ::kbase_memory_performance member
+ * Default value: ::KBASE_MEM_PERF_NORMAL
+ */
+ KBASE_CONFIG_ATTR_MEMORY_OS_SHARED_PERF_GPU,
+
+ /**
+ * Limit (in bytes) the amount of memory a single process
+ * can allocate across all memory banks (including OS shared memory)
+ * for use by the GPU.
+ *
+ * Attached value: number in bytes
+ * Default value: Limited by available memory
+ */
+ KBASE_CONFIG_ATTR_MEMORY_PER_PROCESS_LIMIT,
+
+ /**
+ * UMP device mapping.
+ * Which UMP device this GPU should be mapped to.
+ *
+ * Attached value: UMP_DEVICE_<device>_SHIFT
+ * Default value: UMP_DEVICE_W_SHIFT
+ */
+ KBASE_CONFIG_ATTR_UMP_DEVICE,
+
+ /**
+ * Maximum frequency GPU will be clocked at. Given in kHz.
+ * This must be specified as there is no default value.
+ *
+ * Attached value: number in kHz
+ * Default value: NA
+ */
+ KBASE_CONFIG_ATTR_GPU_FREQ_KHZ_MAX,
+
+ /**
+ * Minimum frequency GPU will be clocked at. Given in kHz.
+ * This must be specified as there is no default value.
+ *
+ * Attached value: number in kHz
+ * Default value: NA
+ */
+ KBASE_CONFIG_ATTR_GPU_FREQ_KHZ_MIN,
+
+ /**
+ * Irq throttle. It is the minimum desired time in between two
+ * consecutive gpu interrupts (given in 'us'). The irq throttle
+ * gpu register will be configured after this, taking into
+ * account the configured max frequency.
+ *
+ * Attached value: number in micro seconds
+ * Default value: see DEFAULT_IRQ_THROTTLE_TIME_US
+ */
+ KBASE_CONFIG_ATTR_GPU_IRQ_THROTTLE_TIME_US,
+
+ /*** Begin Job Scheduling Configs ***/
+ /**
+ * Job Scheduler scheduling tick granuality. This is in nanoseconds to
+ * allow HR timer support.
+ *
+ * On each scheduling tick, the scheduler may decide to:
+ * -# soft stop a job (the job will be re-run later, and other jobs will
+ * be able to run on the GPU now). This effectively controls the
+ * 'timeslice' given to a job.
+ * -# hard stop a job (to kill a job if it has spent too long on the GPU
+ * and didn't soft-stop).
+ *
+ * The numbers of ticks for these events are controlled by:
+ * - @ref KBASE_CONFIG_ATTR_JS_SOFT_STOP_TICKS
+ * - @ref KBASE_CONFIG_ATTR_JS_HARD_STOP_TICKS_SS
+ * - @ref KBASE_CONFIG_ATTR_JS_HARD_STOP_TICKS_NSS
+ *
+ * A soft-stopped job will later be resumed, allowing it to use more GPU
+ * time <em>in total</em> than that defined by any of the above. However,
+ * the scheduling policy attempts to limit the amount of \em uninterrupted
+ * time spent on the GPU using the above values (that is, the 'timeslice'
+ * of a job)
+ *
+ * This value is supported by the following scheduling policies:
+ * - The Completely Fair Share (CFS) policy
+ *
+ * Attached value: unsigned 32-bit kbasep_js_device_data::scheduling_tick_ns.
+ * The value might be rounded down to lower precision. Must be non-zero
+ * after rounding.<br>
+ * Default value: @ref DEFAULT_JS_SCHEDULING_TICK_NS
+ *
+ * @note this value is allowed to be greater than
+ * @ref KBASE_CONFIG_ATTR_JS_CTX_TIMESLICE_NS. This allows jobs to run on (much)
+ * longer than the job-timeslice, but once this happens, the context gets
+ * scheduled in (much) less frequently than others that stay within the
+ * ctx-timeslice.
+ */
+ KBASE_CONFIG_ATTR_JS_SCHEDULING_TICK_NS,
+
+ /**
+ * Job Scheduler minimum number of scheduling ticks before jobs are soft-stopped.
+ *
+ * This defines the amount of time a job is allowed to stay on the GPU,
+ * before it is soft-stopped to allow other jobs to run.
+ *
+ * That is, this defines the 'timeslice' of the job. It is separate from the
+ * timeslice of the context that contains the job (see
+ * @ref KBASE_CONFIG_ATTR_JS_CTX_TIMESLICE_NS).
+ *
+ * This value is supported by the following scheduling policies:
+ * - The Completely Fair Share (CFS) policy
+ *
+ * Attached value: unsigned 32-bit kbasep_js_device_data::soft_stop_ticks<br>
+ * Default value: @ref DEFAULT_JS_SOFT_STOP_TICKS
+ *
+ * @note a value of zero means "the quickest time to soft-stop a job",
+ * which is somewhere between instant and one tick later.
+ *
+ * @note this value is allowed to be greater than
+ * @ref KBASE_CONFIG_ATTR_JS_HARD_STOP_TICKS_SS or
+ * @ref KBASE_CONFIG_ATTR_JS_HARD_STOP_TICKS_NSS. This effectively disables
+ * soft-stop, and just uses hard-stop instead. In this case, this value
+ * should be much greater than any of the hard stop values (to avoid
+ * soft-stop-after-hard-stop)
+ *
+ * @see KBASE_CONFIG_ATTR_JS_SCHEDULING_TICK_NS
+ */
+ KBASE_CONFIG_ATTR_JS_SOFT_STOP_TICKS,
+
+ /**
+ * Job Scheduler minimum number of scheduling ticks before Soft-Stoppable
+ * (BASE_JD_REQ_NSS bit \b clear) jobs are hard-stopped.
+ *
+ * This defines the amount of time a Soft-Stoppable job is allowed to spend
+ * on the GPU before it is killed. Such jobs won't be resumed if killed.
+ *
+ * This value is supported by the following scheduling policies:
+ * - The Completely Fair Share (CFS) policy
+ *
+ * Attached value: unsigned 32-bit kbasep_js_device_data::hard_stop_ticks_ss<br>
+ * Default value: @ref DEFAULT_JS_HARD_STOP_TICKS_SS
+ *
+ * @note a value of zero means "the quickest time to hard-stop a job",
+ * which is somewhere between instant and one tick later.
+ *
+ * @see KBASE_CONFIG_ATTR_JS_SCHEDULING_TICK_NS
+ */
+ KBASE_CONFIG_ATTR_JS_HARD_STOP_TICKS_SS,
+
+ /**
+ * Job Scheduler minimum number of scheduling ticks before Non-Soft-Stoppable
+ * (BASE_JD_REQ_NSS bit \b set) jobs are hard-stopped.
+ *
+ * This defines the amount of time a Non-Soft-Stoppable job is allowed to spend
+ * on the GPU before it is killed. Such jobs won't be resumed if killed.
+ *
+ * This value is supported by the following scheduling policies:
+ * - The Completely Fair Share (CFS) policy
+ *
+ * Attached value: unsigned 32-bit kbasep_js_device_data::hard_stop_ticks_nss<br>
+ * Default value: @ref DEFAULT_JS_HARD_STOP_TICKS_NSS
+ *
+ * @note a value of zero means "the quickest time to hard-stop a job",
+ * which is somewhere between instant and one tick later.
+ *
+ * @see KBASE_CONFIG_ATTR_JS_SCHEDULING_TICK_NS
+ */
+ KBASE_CONFIG_ATTR_JS_HARD_STOP_TICKS_NSS,
+
+ /**
+ * Job Scheduler timeslice that a context is scheduled in for, in nanoseconds.
+ *
+ * When a context has used up this amount of time across its jobs, it is
+ * scheduled out to let another run.
+ *
+ * @note the resolution is nanoseconds (ns) here, because that's the format
+ * often used by the OS.
+ *
+ * This value controls affects the actual time defined by the following
+ * config values:
+ * - @ref KBASE_CONFIG_ATTR_JS_CFS_CTX_RUNTIME_INIT_SLICES
+ * - @ref KBASE_CONFIG_ATTR_JS_CFS_CTX_RUNTIME_MIN_SLICES
+ *
+ * This value is supported by the following scheduling policies:
+ * - The Completely Fair Share (CFS) policy
+ *
+ * Attached value: unsigned 32-bit kbasep_js_device_data::ctx_timeslice_ns.
+ * The value might be rounded down to lower precision.<br>
+ * Default value: @ref DEFAULT_JS_CTX_TIMESLICE_NS
+ *
+ * @note a value of zero models a "Round Robin" scheduling policy, and
+ * disables @ref KBASE_CONFIG_ATTR_JS_CFS_CTX_RUNTIME_INIT_SLICES
+ * (initially causing LIFO scheduling) and
+ * @ref KBASE_CONFIG_ATTR_JS_CFS_CTX_RUNTIME_MIN_SLICES (allowing
+ * not-run-often contexts to get scheduled in quickly, but to only use
+ * a single timeslice when they get scheduled in).
+ */
+ KBASE_CONFIG_ATTR_JS_CTX_TIMESLICE_NS,
+
+ /**
+ * Job Scheduler initial runtime of a context for the CFS Policy, in time-slices.
+ *
+ * This value is relative to that of the least-run context, and defines
+ * where in the CFS queue a new context is added. A value of 1 means 'after
+ * the least-run context has used its timeslice'. Therefore, when all
+ * contexts consistently use the same amount of time, a value of 1 models a
+ * FIFO. A value of 0 would model a LIFO.
+ *
+ * The value is represented in "numbers of time slices". Multiply this
+ * value by that defined in @ref KBASE_CONFIG_ATTR_JS_CTX_TIMESLICE_NS to get
+ * the time value for this in nanoseconds.
+ *
+ * Attached value: unsigned 32-bit kbasep_js_device_data::cfs_ctx_runtime_init_slices<br>
+ * Default value: @ref DEFAULT_JS_CFS_CTX_RUNTIME_INIT_SLICES
+ */
+ KBASE_CONFIG_ATTR_JS_CFS_CTX_RUNTIME_INIT_SLICES,
+
+ /**
+ * Job Scheduler minimum runtime value of a context for CFS, in time_slices
+ * relative to that of the least-run context.
+ *
+ * This is a measure of how much preferrential treatment is given to a
+ * context that is not run very often.
+ *
+ * Specficially, this value defines how many timeslices such a context is
+ * (initially) allowed to use at once. Such contexts (e.g. 'interactive'
+ * processes) will appear near the front of the CFS queue, and can initially
+ * use more time than contexts that run continuously (e.g. 'batch'
+ * processes).
+ *
+ * This limit \b prevents a "stored-up timeslices" DoS attack, where a ctx
+ * not run for a long time attacks the system by using a very large initial
+ * number of timeslices when it finally does run.
+ *
+ * Attached value: unsigned 32-bit kbasep_js_device_data::cfs_ctx_runtime_min_slices<br>
+ * Default value: @ref DEFAULT_JS_CFS_CTX_RUNTIME_MIN_SLICES
+ *
+ * @note A value of zero allows not-run-often contexts to get scheduled in
+ * quickly, but to only use a single timeslice when they get scheduled in.
+ */
+ KBASE_CONFIG_ATTR_JS_CFS_CTX_RUNTIME_MIN_SLICES,
+
+ /**
+ * Job Scheduler minimum number of scheduling ticks before Soft-Stoppable
+ * (BASE_JD_REQ_NSS bit \b clear) jobs cause the GPU to be reset.
+ *
+ * This defines the amount of time a Soft-Stoppable job is allowed to spend
+ * on the GPU before it is assumed that the GPU has hung and needs to be reset.
+ * The assumes that the job has been hard-stopped already and so the presence of
+ * a job that has remained on the GPU for so long indicates that the GPU has in some
+ * way hung.
+ *
+ * This value is supported by the following scheduling policies:
+ * - The Completely Fair Share (CFS) policy
+ *
+ * Attached value: unsigned 32-bit kbasep_js_device_data::gpu_reset_ticks_nss<br>
+ * Default value: @ref DEFAULT_JS_RESET_TICKS_SS
+ *
+ * @see KBASE_CONFIG_ATTR_JS_SCHEDULING_TICK_NS
+ */
+ KBASE_CONFIG_ATTR_JS_RESET_TICKS_SS,
+
+ /**
+ * Job Scheduler minimum number of scheduling ticks before Non-Soft-Stoppable
+ * (BASE_JD_REQ_NSS bit \b set) jobs cause the GPU to be reset.
+ *
+ * This defines the amount of time a Non-Soft-Stoppable job is allowed to spend
+ * on the GPU before it is assumed that the GPU has hung and needs to be reset.
+ * The assumes that the job has been hard-stopped already and so the presence of
+ * a job that has remained on the GPU for so long indicates that the GPU has in some
+ * way hung.
+ *
+ * This value is supported by the following scheduling policies:
+ * - The Completely Fair Share (CFS) policy
+ *
+ * Attached value: unsigned 32-bit kbasep_js_device_data::gpu_reset_ticks_nss<br>
+ * Default value: @ref DEFAULT_JS_RESET_TICKS_NSS
+ *
+ * @see KBASE_CONFIG_ATTR_JS_SCHEDULING_TICK_NS
+ */
+ KBASE_CONFIG_ATTR_JS_RESET_TICKS_NSS,
+
+ /**
+ * Number of milliseconds given for other jobs on the GPU to be
+ * soft-stopped when the GPU needs to be reset.
+ *
+ * Attached value: number in milliseconds
+ * Default value: @ref DEFAULT_JS_RESET_TIMEOUT_MS
+ */
+ KBASE_CONFIG_ATTR_JS_RESET_TIMEOUT_MS,
+ /*** End Job Scheduling Configs ***/
+
+ /** Power management configuration
+ *
+ * Attached value: pointer to @ref kbase_pm_callback_conf
+ * Default value: See @ref kbase_pm_callback_conf
+ */
+ KBASE_CONFIG_ATTR_POWER_MANAGEMENT_CALLBACKS,
+
+ /**
+ * Boolean indicating whether the driver is configured to be secure at
+ * a potential loss of performance.
+ *
+ * This currently affects only r0p0-15dev0 HW and earlier.
+ *
+ * On r0p0-15dev0 HW and earlier, there are tradeoffs between security and
+ * performance:
+ *
+ * - When this is set to MALI_TRUE, the driver remains fully secure,
+ * but potentially loses performance compared with setting this to
+ * MALI_FALSE.
+ * - When set to MALI_FALSE, the driver is open to certain security
+ * attacks.
+ *
+ * From r0p0-00rel0 and onwards, there is no security loss by setting
+ * this to MALI_FALSE, and no performance loss by setting it to
+ * MALI_TRUE.
+ *
+ * Attached value: mali_bool value
+ * Default value: @ref DEFAULT_SECURE_BUT_LOSS_OF_PERFORMANCE
+ */
+ KBASE_CONFIG_ATTR_SECURE_BUT_LOSS_OF_PERFORMANCE,
+
+ /**
+ * A pointer to a function that calculates the CPU clock
+ * speed of the platform in MHz - see
+ * @ref kbase_cpuprops_clock_speed_function for the function
+ * prototype.
+ *
+ * Attached value: A @ref kbase_cpuprops_clock_speed_function.
+ * Default Value: Pointer to @ref DEFAULT_CPU_SPEED_FUNC -
+ * returns a clock speed of 100 MHz.
+ */
+ KBASE_CONFIG_ATTR_CPU_SPEED_FUNC,
+
+ /**
+ * A pointer to a function that calculates the GPU clock
+ * speed of the platform in MHz - see
+ * @ref kbase_gpuprops_clock_speed_function for the function
+ * prototype.
+ *
+ * Attached value: A @ref kbase_gpuprops_clock_speed_function.
+ * Default Value: NULL (in which case the driver assumes a current
+ * GPU frequency specified by KBASE_CONFIG_ATTR_GPU_FREQ_KHZ_MAX)
+ */
+ KBASE_CONFIG_ATTR_GPU_SPEED_FUNC,
+
+ /**
+ * Platform specific configuration functions
+ *
+ * Attached value: pointer to @ref kbase_platform_funcs_conf
+ * Default value: See @ref kbase_platform_funcs_conf
+ */
+ KBASE_CONFIG_ATTR_PLATFORM_FUNCS,
+
+ /**
+ * End of attribute list indicator.
+ * The configuration loader will stop processing any more elements
+ * when it encounters this attribute.
+ *
+ * Attached value: Ignored
+ * Default value: NA
+ */
+ KBASE_CONFIG_ATTR_END = 0x1FFFUL
+};
+
+enum
+{
+ /**
+ * Invalid attribute ID (reserve 0).
+ *
+ * Attached value: Ignored
+ * Default value: NA
+ */
+ KBASE_MEM_ATTR_INVALID,
+
+ /**
+ * Relative performance for the CPU to access
+ * the memory resource.
+ *
+ * Attached value: ::kbase_memory_performance member
+ * Default value: ::KBASE_MEM_PERF_NORMAL
+ */
+ KBASE_MEM_ATTR_PERF_CPU,
+
+ /**
+ * Relative performance for the GPU to access
+ * the memory resource.
+ *
+ * Attached value: ::kbase_memory_performance member
+ * Default value: ::KBASE_MEM_PERF_NORMAL
+ */
+ KBASE_MEM_ATTR_PERF_GPU,
+
+ /**
+ * End of attribute list indicator.
+ * The memory resource loader will stop processing any more
+ * elements when it encounters this attribute.
+ *
+ * Attached value: Ignored
+ * Default value: NA
+ */
+ KBASE_MEM_ATTR_END = 0x1FFFUL
+};
+
+
+/*
+ * @brief specifies a single attribute
+ *
+ * Attribute is identified by attr field. Data is either integer or a pointer to attribute-specific structure.
+ */
+typedef struct kbase_attribute
+{
+ int id;
+ uintptr_t data;
+} kbase_attribute;
+
+/*
+ * @brief Specifies dedicated memory bank
+ *
+ * Specifies base, size and attributes of a memory bank
+ */
+typedef struct kbase_memory_resource
+{
+ u64 base;
+ u64 size;
+ struct kbase_attribute * attributes;
+ const char * name;
+} kbase_memory_resource;
+
+/* Forward declaration of kbase_device */
+struct kbase_device;
+
+/*
+ * @brief Specifies the functions for platform specific initialization and termination
+ *
+ * By default no functions are required. No additional platform specific control is necessary.
+ */
+typedef struct kbase_platform_funcs_conf
+{
+ /**
+ * Function pointer for platform specific initialization or NULL if no initialization function is required.
+ * This function will be called \em before any other callbacks listed in the kbase_attribute struct (such as
+ * Power Management callbacks).
+ * The platform specific private pointer kbase_device::platform_context can be accessed (and possibly initialized) in here.
+ */
+ mali_bool (*platform_init_func)(struct kbase_device *kbdev);
+ /**
+ * Function pointer for platform specific termination or NULL if no termination function is required.
+ * This function will be called \em after any other callbacks listed in the kbase_attribute struct (such as
+ * Power Management callbacks).
+ * The platform specific private pointer kbase_device::platform_context can be accessed (and possibly terminated) in here.
+ */
+ void (*platform_term_func)(struct kbase_device *kbdev);
+
+} kbase_platform_funcs_conf;
+
+/*
+ * @brief Specifies the callbacks for power management
+ *
+ * By default no callbacks will be made and the GPU must not be powered off.
+ */
+typedef struct kbase_pm_callback_conf
+{
+ /** Callback for when the GPU is idle and the power to it can be switched off.
+ *
+ * The system integrator can decide whether to either do nothing, just switch off
+ * the clocks to the GPU, or to completely power down the GPU.
+ * The platform specific private pointer kbase_device::platform_context can be accessed and modified in here. It is the
+ * platform \em callbacks responsiblity to initialize and terminate this pointer if used (see @ref kbase_platform_funcs_conf).
+ */
+ void (*power_off_callback)(struct kbase_device *kbdev);
+
+ /** Callback for when the GPU is about to become active and power must be supplied.
+ *
+ * This function must not return until the GPU is powered and clocked sufficiently for register access to
+ * succeed. The return value specifies whether the GPU was powered down since the call to power_off_callback.
+ * If the GPU state has been lost then this function must return 1, otherwise it should return 0.
+ * The platform specific private pointer kbase_device::platform_context can be accessed and modified in here. It is the
+ * platform \em callbacks responsiblity to initialize and terminate this pointer if used (see @ref kbase_platform_funcs_conf).
+ *
+ * The return value of the first call to this function is ignored.
+ *
+ * @return 1 if the GPU state may have been lost, 0 otherwise.
+ */
+ int (*power_on_callback)(struct kbase_device *kbdev);
+
+ /** Callback for handling runtime power management initialization.
+ *
+ * The runtime power management callbacks @ref power_runtime_off_callback and @ref power_runtime_on_callback
+ * will become active from calls made to the OS from within this function.
+ * The runtime calls can be triggered by calls from @ref power_off_callback and @ref power_on_callback.
+ * Note: for linux the kernel must have CONFIG_PM_RUNTIME enabled to use this feature.
+ *
+ * @return MALI_ERROR_NONE on success, else mali_error erro code.
+ */
+ mali_error (*power_runtime_init_callback)(struct kbase_device *kbdev);
+
+ /** Callback for handling runtime power management termination.
+ *
+ * The runtime power management callbacks @ref power_runtime_off_callback and @ref power_runtime_on_callback
+ * should no longer be called by the OS on completion of this function.
+ * Note: for linux the kernel must have CONFIG_PM_RUNTIME enabled to use this feature.
+ */
+ void (*power_runtime_term_callback)(struct kbase_device *kbdev);
+
+ /** Callback for runtime power-off power management callback
+ *
+ * For linux this callback will be called by the kernel runtime_suspend callback.
+ * Note: for linux the kernel must have CONFIG_PM_RUNTIME enabled to use this feature.
+ *
+ * @return 0 on success, else OS error code.
+ */
+ void (*power_runtime_off_callback)(struct kbase_device *kbdev);
+
+ /** Callback for runtime power-on power management callback
+ *
+ * For linux this callback will be called by the kernel runtime_resume callback.
+ * Note: for linux the kernel must have CONFIG_PM_RUNTIME enabled to use this feature.
+ */
+ int (*power_runtime_on_callback)(struct kbase_device *kbdev);
+
+} kbase_pm_callback_conf;
+
+/**
+ * Type of the function pointer for KBASE_CONFIG_ATTR_CPU_SPEED_FUNC.
+ *
+ * @param clock_speed [out] Once called this will contain the current CPU clock speed in MHz.
+ * This is mainly used to implement OpenCL's clGetDeviceInfo().
+ *
+ * @return 0 on success, 1 on error.
+ */
+typedef int (*kbase_cpuprops_clock_speed_function)(u32 *clock_speed);
+
+/**
+ * Type of the function pointer for KBASE_CONFIG_ATTR_GPU_SPEED_FUNC.
+ *
+ * @param clock_speed [out] Once called this will contain the current GPU clock speed in MHz.
+ * If the system timer is not available then this function is required
+ * for the OpenCL queue profiling to return correct timing information.
+ *
+ * @return 0 on success, 1 on error. When an error is returned the caller assumes a current
+ * GPU speed as specified by KBASE_CONFIG_ATTR_GPU_FREQ_KHZ_MAX.
+ */
+typedef int (*kbase_gpuprops_clock_speed_function)(u32 *clock_speed);
+
+#ifdef CONFIG_MALI_PLATFORM_FAKE
+/*
+ * @brief Specifies start and end of I/O memory region.
+ */
+typedef struct kbase_io_memory_region
+{
+ u64 start;
+ u64 end;
+} kbase_io_memory_region;
+
+/*
+ * @brief Specifies I/O related resources like IRQs and memory region for I/O operations.
+ */
+typedef struct kbase_io_resources
+{
+ u32 job_irq_number;
+ u32 mmu_irq_number;
+ u32 gpu_irq_number;
+ kbase_io_memory_region io_memory_region;
+} kbase_io_resources;
+
+typedef struct kbase_platform_config
+{
+ const kbase_attribute *attributes;
+ const kbase_io_resources *io_resources;
+ u32 midgard_type;
+} kbase_platform_config;
+
+#endif /* CONFIG_MALI_PLATFORM_FAKE */
+/**
+ * @brief Return character string associated with the given midgard type.
+ *
+ * @param[in] midgard_type - ID of midgard type
+ *
+ * @return Pointer to NULL-terminated character array associated with the given midgard type
+ */
+const char *kbasep_midgard_type_to_string(u32 midgard_type);
+
+/**
+ * @brief Gets the count of attributes in array
+ *
+ * Function gets the count of attributes in array. Note that end of list indicator is also included.
+ *
+ * @param[in] attributes Array of attributes
+ *
+ * @return Number of attributes in the array including end of list indicator.
+ */
+int kbasep_get_config_attribute_count(const kbase_attribute *attributes);
+
+/**
+ * @brief Gets the count of attributes with specified id
+ *
+ * Function gets the count of attributes with specified id in the given attribute array
+ *
+ * @param[in] attributes Array of attributes
+ * @param[in] attribute_id Id of attributes to count
+ *
+ * @return Number of attributes in the array that have specified id
+ */
+int kbasep_get_config_attribute_count_by_id(const kbase_attribute *attributes, int attribute_id);
+
+/**
+ * @brief Gets the next config attribute with the specified ID from the array of attributes.
+ *
+ * Function gets the next attribute with specified attribute id within specified array. If no such attribute is found,
+ * NULL is returned.
+ *
+ * @param[in] attributes Array of attributes in which lookup is performed
+ * @param[in] attribute_id ID of attribute
+ *
+ * @return Pointer to the first attribute matching id or NULL if none is found.
+ */
+const kbase_attribute *kbasep_get_next_attribute(const kbase_attribute *attributes, int attribute_id);
+
+/**
+ * @brief Gets the value of a single config attribute.
+ *
+ * Function gets the value of attribute specified as parameter. If no such attribute is found in the array of
+ * attributes, default value is used.
+ *
+ * @param[in] kbdev Kbase device pointer
+ * @param[in] attributes Array of attributes in which lookup is performed
+ * @param[in] attribute_id ID of attribute
+ *
+ * @return Value of attribute with the given id
+ */
+uintptr_t kbasep_get_config_value(struct kbase_device *kbdev, const kbase_attribute *attributes, int attribute_id);
+
+/**
+ * @brief Obtain memory performance values from kbase_memory_resource structure.
+ *
+ * Function gets cpu and gpu memory performance values from memory resource structure and puts them in the variables
+ * provided as parameters. If the performance of memory bank is not in resource attributes, default value is used.
+ *
+ * @param[in] resource Structure containing information about memory bank to use
+ * @param[out] cpu_performance Pointer to variable which will hold CPU performance value
+ * @param[out] gpu_performance Pointer to variable which will hold GPU performance value
+ */
+void kbasep_get_memory_performance(const kbase_memory_resource *resource,
+ kbase_memory_performance *cpu_performance, kbase_memory_performance *gpu_performance);
+
+/**
+ * @brief Validates configuration attributes
+ *
+ * Function checks validity of given configuration attributes. It will fail on any attribute with unknown id, attribute
+ * with invalid value or attribute list that is not correctly terminated. It will also fail if
+ * KBASE_CONFIG_ATTR_GPU_FREQ_KHZ_MIN or KBASE_CONFIG_ATTR_GPU_FREQ_KHZ_MAX are not specified.
+ *
+ * @param[in] kbdev Kbase device pointer
+ * @param[in] attributes Array of attributes to validate
+ *
+ * @return MALI_TRUE if no errors have been found in the config. MALI_FALSE otherwise.
+ */
+mali_bool kbasep_validate_configuration_attributes(struct kbase_device *kbdev, const kbase_attribute *attributes);
+
+#ifdef CONFIG_MALI_PLATFORM_FAKE
+/**
+ * @brief Gets the pointer to platform config.
+ *
+ * @return Pointer to the platform config
+ */
+kbase_platform_config *kbasep_get_platform_config(void);
+#endif /* CONFIG_MALI_PLATFORM_FAKE */
+
+/**
+ * @brief Platform specific call to initialize hardware
+ *
+ * Function calls a platform defined routine if specified in the configuration attributes.
+ * The routine can initialize any hardware and context state that is required for the GPU block to function.
+ *
+ * @param[in] kbdev Kbase device pointer
+ *
+ * @return MALI_TRUE if no errors have been found in the config. MALI_FALSE otherwise.
+ */
+mali_bool kbasep_platform_device_init(struct kbase_device *kbdev);
+
+/**
+ * @brief Platform specific call to terminate hardware
+ *
+ * Function calls a platform defined routine if specified in the configuration attributes.
+ * The routine can destroy any platform specific context state and shut down any hardware functionality that are
+ * outside of the Power Management callbacks.
+ *
+ * @param[in] kbdev Kbase device pointer
+ *
+ */
+void kbasep_platform_device_term(struct kbase_device *kbdev);
+
+
+/** @} */ /* end group kbase_config */
+/** @} */ /* end group base_kbase_api */
+/** @} */ /* end group base_api */
+
+#endif /* _KBASE_CONFIG_H_ */
diff --git a/drivers/gpu/arm/t6xx/kbase/mali_uk.h b/drivers/gpu/arm/t6xx/kbase/mali_uk.h
new file mode 100644
index 0000000..e4aafd4
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/mali_uk.h
@@ -0,0 +1,150 @@
+/*
+ *
+ * (C) COPYRIGHT 2010, 2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_uk.h
+ * Types and definitions that are common across OSs for both the user
+ * and kernel side of the User-Kernel interface.
+ */
+
+#ifndef _UK_H_
+#define _UK_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+#include <malisw/mali_stdtypes.h>
+
+/**
+ * @addtogroup base_api
+ * @{
+ */
+
+/**
+ * @defgroup uk_api User-Kernel Interface API
+ *
+ * The User-Kernel Interface abstracts the communication mechanism between the user and kernel-side code of device
+ * drivers developed as part of the Midgard DDK. Currently that includes the Base driver and the UMP driver.
+ *
+ * It exposes an OS independent API to user-side code (UKU) which routes functions calls to an OS-independent
+ * kernel-side API (UKK) via an OS-specific communication mechanism.
+ *
+ * This API is internal to the Midgard DDK and is not exposed to any applications.
+ *
+ * @{
+ */
+
+/**
+ * @brief UK major version
+ */
+#define MALI_MODULE_UK_MAJOR 0
+
+/**
+ * @brief UK minor version
+ */
+#define MALI_MODULE_UK_MINOR 0
+
+/**
+ * These are identifiers for kernel-side drivers implementing a UK interface, aka UKK clients. The
+ * UK module maps this to an OS specific device name, e.g. "gpu_base" -> "GPU0:". Specify this
+ * identifier to select a UKK client to the uku_open() function.
+ *
+ * When a new UKK client driver is created a new identifier needs to be added to the uk_client_id
+ * enumeration and the uku_open() implemenation for the various OS ports need to be updated to
+ * provide a mapping of the identifier to the OS specific device name.
+ *
+ */
+typedef enum uk_client_id
+{
+ /**
+ * Value used to identify the Base driver UK client.
+ */
+ UK_CLIENT_MALI_T600_BASE,
+
+ /** The number of uk clients supported. This must be the last member of the enum */
+ UK_CLIENT_COUNT
+} uk_client_id;
+
+/**
+ * Each function callable through the UK interface has a unique number.
+ * Functions provided by UK clients start from number UK_FUNC_ID.
+ * Numbers below UK_FUNC_ID are used for internal UK functions.
+ */
+typedef enum uk_func
+{
+ UKP_FUNC_ID_CHECK_VERSION, /**< UKK Core internal function */
+ /**
+ * Each UK client numbers the functions they provide starting from
+ * number UK_FUNC_ID. This number is then eventually assigned to the
+ * id field of the uk_header structure when preparing to make a
+ * UK call. See your UK client for a list of their function numbers.
+ */
+ UK_FUNC_ID = 512
+} uk_func;
+
+/**
+ * Arguments for a UK call are stored in a structure. This structure consists
+ * of a fixed size header and a payload. The header carries a 32-bit number
+ * identifying the UK function to be called (see uk_func). When the UKK client
+ * receives this header and executed the requested UK function, it will use
+ * the same header to store the result of the function in the form of a
+ * mali_error return code. The size of this structure is such that the
+ * first member of the payload following the header can be accessed efficiently
+ * on a 32 and 64-bit kernel and the structure has the same size regardless
+ * of a 32 or 64-bit kernel. The uk_kernel_size_type type should be defined
+ * accordingly in the OS specific mali_uk_os.h header file.
+ */
+typedef union uk_header
+{
+ /**
+ * 32-bit number identifying the UK function to be called.
+ * Also see uk_func.
+ */
+ u32 id;
+ /**
+ * The mali_error return code returned by the called UK function.
+ * See the specification of the particular UK function you are
+ * calling for the meaning of the error codes returned. All
+ * UK functions return MALI_ERROR_NONE on success.
+ */
+ mali_error ret;
+ /*
+ * Used to ensure 64-bit alignment of this union. Do not remove.
+ * This field is used for padding and does not need to be initialized.
+ */
+ u64 sizer;
+} uk_header;
+
+/**
+ * This structure carries a 16-bit major and minor number and is sent along with an internal UK call
+ * used during uku_open to identify the versions of the UK module in use by the user-side and kernel-side.
+ */
+typedef struct uku_version_check_args
+{
+ uk_header header; /**< UK call header */
+ u16 major; /**< This field carries the user-side major version on input and the kernel-side major version on output */
+ u16 minor; /**< This field carries the user-side minor version on input and the kernel-side minor version on output. */
+} uku_version_check_args;
+
+/** @} end group uk_api */
+
+/** @} */ /* end group base_api */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* _UK_H_ */
diff --git a/drivers/gpu/arm/t6xx/kbase/mali_ukk.h b/drivers/gpu/arm/t6xx/kbase/mali_ukk.h
new file mode 100644
index 0000000..fff1ee9f
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/mali_ukk.h
@@ -0,0 +1,452 @@
+/*
+ *
+ * (C) COPYRIGHT 2010, 2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_ukk.h
+ * Types and definitions that are common across OSs for the kernel side of the
+ * User-Kernel interface.
+ */
+
+#ifndef _UKK_H_
+#define _UKK_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+#include <osk/mali_osk.h>
+#include <malisw/mali_stdtypes.h>
+#include <kbase/mali_uk.h>
+
+/**
+ * Incomplete definitions of ukk_session, ukk_call_context to satisfy header file dependency in plat/mali_ukk_os.h
+ */
+typedef struct ukk_session ukk_session;
+typedef struct ukk_call_context ukk_call_context;
+#include <mali_ukk_os.h> /* needed for ukkp_session definition */
+
+/**
+ * @addtogroup uk_api User-Kernel Interface API
+ * @{
+ */
+
+/**
+ * @addtogroup uk_api_kernel UKK (Kernel side)
+ * @{
+ *
+ * A kernel-side device driver implements the UK interface with the help of the UKK. The UKK
+ * is an OS independent API for kernel-side code to accept requests from the user-side to
+ * execute functions in the kernel-side device driver.
+ *
+ * A few definitions:
+ * - the kernel-side device driver implementing the UK interface is called the UKK client driver
+ * - the user-side library, application, or driver communicating with the UKK client driver is called the UKU client driver
+ * - the UKK API implementation is called the UKK core. The UKK core is linked with your UKK client driver.
+ *
+ * When a UKK client driver starts it needs to initialize the UKK core by calling ukk_start() and
+ * similarly ukk_stop() when the UKK client driver terminates. A UKK client driver is normally
+ * started by an operating system when a device boots.
+ *
+ * A UKU client driver provides services that are implemented either completely in user-space, kernel-space, or
+ * a combination of both. A UKU client driver makes UK calls to its UKK client driver to execute any functionality
+ * of services that is implemented in kernel-space.
+ *
+ * To make a UK call the UKU client driver needs to establish a connection with the UKK client driver. The UKU API
+ * provides the uku_open() call to establish this connection. Normally this results in the OS calling the open
+ * entry point of the UKK client driver. Here, the UKK client driver needs to initialize a UKK session object
+ * with ukk_session_init() to represent this connection, and register a function that will execute the UK calls
+ * requested over this connection (or UKK session). This function is called the UKK client dispatch handler.
+ *
+ * To prevent the UKU client driver executing an incompatible UK call implementation, the UKK session object
+ * stores the version of the UK calls supported by the function registered to execute the UK calls. As soon as the
+ * UKU client driver established a connection with the UKK client driver, uku_open() makes an internal UK call to
+ * request the version of the UK calls supported by the UKK client driver and will fail if the version expected
+ * by the UKU client driver is not compatible with the version supported by the UKK client driver. Internal UK calls
+ * are handled by the UKK core itself and don't reach the UKK client dispatch handler.
+ *
+ * Once the UKU client driver has established a (compatible) connection with the UKK client driver, the UKU
+ * client driver can execute UK calls by using uku_call(). This normally results in the OS calling the ioctl
+ * handler of your UKK client driver and presenting it with the UK call argument structure that was passed
+ * to uku_call(). It is the responsibility of the ioctl handler to copy the UK call argument structure from
+ * user-space to kernel-space and provide it to the UKK dispatch function, ukk_dispatch(), for execution. Depending
+ * on the particular UK call, the UKK dispatch function will either call the UKK client dispatch handler associated
+ * with the UKK session, or the UKK core dispatch handler if it is an UK internal call. When the UKK dispatch
+ * function returns, the return code of the UK call and the output and input/output parameters in the UK call argument
+ * structure will have been updated. Again, it is the responsibility of the ioctl handler to copy the updated
+ * UK call argument structure from kernel-space back to user-space.
+ *
+ * When the UKK client dispatch handler is called it is passed the UK call argument structure (along with a
+ * UK call context which is discussed later). The UKK client dispatch handler uses the uk_header structure in the
+ * UK call argument structure (which is always the first member in this structure) to determine which UK call in
+ * particular needs to be executed. The uk_header structure is a union of a 32-bit number containing the UK call
+ * function number (as defined by the UKK client driver) and a mali_error return value that will store the return
+ * value of the UK call. The 32-bit UK call function number is normally used to select a particular case in a switch
+ * statement that implements the particular UK call which finally stores the result of the UK call in the mali_error
+ * return value of the uk_header structure.
+ *
+ * A UK call implementation is provided with access to a number of objects it may need during the UK call through
+ * a UKK call context. This UKK call context currently only contains
+ * - a pointer to the UKK session for the UK call
+ *
+ * It is the responsibility of the ioctl handler to initialize a UKK call context using ukk_call_prepare() and pass
+ * it on to the UKK dispatch function. The UK call implementation then uses ukk_session_get() to retrieve the stored
+ * objects in the UKK call context. The UK call implementation normally uses the UKK session pointer returned from
+ * ukk_session_get() to access the UKK client driver's context in which the UKK session is embedded. For example:
+ * struct kbase_context {
+ * int some_kbase_context_data;
+ * int more_kbase_context_data;
+ * ukk_session ukk_session_member;
+ * } *kctx;
+ * kctx = container_of(ukk_session_get(ukk_call_ctx), kbase_context, ukk_session_member);
+ *
+ * A UK call may not use an argument structure with embedded pointers.
+ *
+ * All of this can be translated into the following minimal sample code for a UKK client driver:
+@code
+// Sample code for an imaginary UKK client driver 'TESTDRV' implementing the 'TESTDRV_UK_FOO_FUNC' UK call
+//
+#define TESTDRV_VERSION_MAJOR 0
+#define TESTDRV_VERSION_MINOR 1
+
+typedef enum testdrv_uk_function
+{
+ TESTDRV_UK_FOO_FUNC = (UK_FUNC_ID + 0)
+} testdrv_uk_function;
+
+typedef struct testdrv_uk_foo_args
+{
+ uk_header header;
+ int counters[10]; // input
+ int prev_counters[10]; // output
+} testdrv_uk_foo_args;
+
+typedef struct testdrv_session
+{
+ int counters[10];
+ ukk_session ukk_session_obj;
+} testdrv_session;
+
+testdrv_open(os_driver_context *osctx)
+{
+ testdrv_session *ts;
+ ts = kmalloc(sizeof(*ts), GFP_KERNEL);
+ ukk_session_init(&ts->ukk_session_obj, testdrv_ukk_dispatch, TESTDRV_VERSION_MAJOR, TESTDRV_VERSION_MINOR);
+ osctx->some_field = ts;
+}
+testdrv_close(os_driver_context *osctx)
+{
+ testdrv_session *ts = osctx->some_field;
+ ukk_session_term(&ts->ukk_session_obj)
+ kfree(ts);
+ osctx->some_field = NULL;
+}
+testdrv_ioctl(os_driver_context *osctx, void *user_arg, u32 args_size)
+{
+ testdrv_session *ts = osctx->some_field;
+ ukk_call_context call_ctx;
+ void *kernel_arg;
+
+ kernel_arg = os_copy_to_kernel_space(user_arg, args_size);
+
+ ukk_call_prepare(&call_ctx, &ts->ukk_session_obj);
+
+ ukk_dispatch(&call_ctx, kernel_arg, args_size);
+
+ os_copy_to_user_space(user_arg, kernel_arg, args_size);
+}
+mali_error testdrv_ukk_dispatch(ukk_call_context *call_ctx, void *arg, u32 args_size)
+{
+ uk_header *header = arg;
+ mali_error ret = MALI_ERROR_FUNCTION_FAILED;
+
+ switch(header->id)
+ {
+ case TESTDRV_UK_FOO_FUNC:
+ {
+ testdrv_uk_foo_args *foo_args = arg;
+ if (sizeof(*foo_args) == args_size)
+ {
+ mali_error result;
+ result = foo(call_ctx, foo_args);
+ header->ret = result;
+ ret = MALI_ERROR_NONE;
+ }
+ break;
+ }
+ }
+ return ret;
+}
+mali_error foo(ukk_call_context *call_ctx, testdrv_uk_foo_args *args) {
+ // foo updates the counters in the testdrv_session object and returns the old counters
+ testdrv_session *session = container_of(ukk_session_get(call_ctx), testdrv_session, ukk_session_obj);
+ memcpy(&args->prev_counters, session->counters, 10 * sizeof(int));
+ memcpy(&session->counters, &args->counters, 10 * sizeof(int));
+ return MALI_ERROR_NONE;
+}
+@endcode
+*/
+
+/**
+ * Maximum size of UK call argument structure supported by UKK clients
+ */
+#define UKK_CALL_MAX_SIZE 512
+
+/**
+ * @brief Dispatch callback of UKK client
+ *
+ * The UKK client's dispatch function is called by UKK core ukk_dispatch()
+ *
+ * The UKK client's dispatch function should return MALI_ERROR_NONE when it
+ * has accepted and executed the UK call. If the UK call is not recognized it
+ * should return MALI_ERROR_FUNCTION_FAILED.
+ *
+ * An example of a piece of code from a UKK client dispatch function:
+ * @code
+ * uk_header *header = (uk_header *)arg;
+ * switch(header->id) {
+ * case MYCLIENT_FUNCTION: {
+ * if (args_size != sizeof(myclient_function_args)) {
+ * return MALI_ERROR_FUNCTION_FAILED; // argument structure size mismatch
+ * } else {
+ * // execute UK call and store result back in header
+ * header->ret = do_my_client_function(ukk_ctx, args);
+ * return MALI_ERROR_NONE;
+ * }
+ * default:
+ * return MALI_ERROR_FUNCTION_FAILED; // UK call function number not recognized
+ * }
+ * @endcode
+ *
+ * For details, see ukk_dispatch().
+ *
+ * Debug builds will assert when a NULL pointer is passed for ukk_ctx or args, or,
+ * args_size < sizeof(uk_header).
+ *
+ * @param[in] ukk_ctx Pointer to a call context
+ * @param[in,out] args Pointer to a argument structure of a UK call
+ * @param[in] args_size Size of the argument structure (in bytes)
+ * @return MALI_ERROR_NONE on success. MALI_ERROR_FUNCTION_FAILED when the UK call was not recognized.
+ */
+typedef mali_error (*ukk_dispatch_function)(ukk_call_context * const ukk_ctx, void * const args, u32 args_size);
+
+/**
+ * Driver session related data for the UKK core.
+ */
+struct ukk_session
+{
+ /**
+ * Session data stored by the OS specific implementation of the UKK core
+ */
+ ukkp_session internal_session;
+
+ /**
+ * UKK client version supported by the call backs provided below - major number of version
+ */
+ u16 version_major;
+
+ /**
+ * UKK client version supported by the call backs provided below - minor number of version
+ */
+ u16 version_minor;
+
+ /**
+ * Function in UKK client that executes UK calls for this UKK session, see
+ * ukk_dispatch_function.
+ */
+ ukk_dispatch_function dispatch;
+};
+
+/**
+ * Stucture containing context data passed in to each UK call. Before each UK call it is initialized
+ * by the ukk_call_prepare() function. UK calls can retrieve the context data using the function
+ * ukk_session_get().
+ */
+struct ukk_call_context
+{
+ /**
+ * Pointer to UKK core session data.
+ */
+ ukk_session *ukk_session;
+};
+
+/**
+ * @brief UKK core startup
+ *
+ * Must be called during the UKK client driver initialization before accessing any UKK provided functionality.
+ *
+ * @return MALI_ERROR_NONE on success. Any other value indicates failure.
+ */
+mali_error ukk_start(void);
+
+/**
+ * @brief UKK core shutdown
+ *
+ * Must be called during the UKK client driver termination to free any resources UKK might have allocated.
+ *
+ * After this has been called no UKK functionality may be accessed.
+ */
+void ukk_stop(void);
+
+/**
+ * @brief Initialize a UKK session
+ *
+ * When a UKK client driver is opened, a UKK session object needs to be initialized to
+ * store information specific to that session with the UKK client driver.
+ *
+ * This UKK session object is normally contained in a session specific data structure created
+ * by the OS specific open entry point of the UKK client driver. The entry point of the
+ * UKK client driver that receives requests from user space to execute UK calls will
+ * need to pass on a pointer to this UKK session object to the ukk_dispatch() function to
+ * execute a UK call for the active session.
+ *
+ * A UKK session supports executing UK calls for a particular version of the UKK client driver
+ * interface. A pointer to the dispatch function that will execute the UK calls needs to
+ * be passed to ukk_session_init(), along with the version (major and minor) of the UKK client
+ * driver interface that this dispatch function supports.
+ *
+ * When the UKK client driver is closed, the initialized UKK session object needs to be
+ * terminated. See ukk_session_term().
+ *
+ * Debug builds will assert when a NULL pointer is passed for ukk_ctx or dispatch.
+ *
+ * @param[out] ukk_session Pointer to UKK session to initialize
+ * @param[in] dispatch Pointer to dispatch function to associate with the UKK session
+ * @param[in] version_major Dispatch function will handle UK calls for this major version
+ * @param[in] version_minor Dispatch function will handle UK calls for this minor version
+ * @return MALI_ERROR_NONE on success. Any other value indicates failure.
+ */
+mali_error ukk_session_init(ukk_session *ukk_session, ukk_dispatch_function dispatch, u16 version_major, u16 version_minor);
+
+/**
+ * @brief Terminates a UKK session
+ *
+ * Frees any resources allocated for the UKK session object. No UK calls for this session
+ * may be executing when calling this function. This function invalidates the UKK session
+ * object and must not be used anymore until it is initialized again with ukk_session_init().
+ *
+ * Debug builds will assert when a NULL pointer is passed for ukk_session.
+ *
+ * @param[in,out] ukk_session Pointer to UKK session to terminate
+ */
+void ukk_session_term(ukk_session *ukk_session);
+
+/**
+ * @brief Prepare a context in which to execute a UK call
+ *
+ * UK calls are passed a call context that allows them to get access to the UKK session data.
+ * Given a call context, UK calls use ukk_session_get() to get access to the UKK session data.
+ *
+ * Debug builds will assert when a NULL pointer is passed for ukk_ctx, ukk_session.
+ *
+ * @param[out] ukk_ctx Pointer to call context to initialize.
+ * @param[in] ukk_session Pointer to UKK session to associate with the call context
+ */
+void ukk_call_prepare(ukk_call_context * const ukk_ctx, ukk_session * const ukk_session);
+
+/**
+ * @brief Get the UKK session of a call context
+ *
+ * Returns the UKK session associated with a call context. See ukk_call_prepare.
+ *
+ * Debug builds will assert when a NULL pointer is passed for ukk_ctx.
+ *
+ * @param[in] ukk_ctx Pointer to call context
+ * @return Pointer to UKK session associated with the call context
+ */
+void *ukk_session_get(ukk_call_context * const ukk_ctx);
+
+/**
+ * @brief Copy data from user space to kernel space
+ *
+ * @param[in] bytes Number of bytes to copy from @ref user_buffer to @ref_kernel_buffer
+ * @param[out] kernel_buffer Pointer to data buffer in kernel space.
+ * @param[in] user_buffer Pointer to data buffer in user space.
+ *
+ * @return Returns MALI_ERROR_NONE on success.
+ */
+
+mali_error ukk_copy_from_user( size_t bytes, void * kernel_buffer, const void * const user_buffer );
+
+/**
+ * @brief Copy data from kernel space to user space
+ *
+ * @param[in] bytes Pointer to a call context
+ * @param[in] user_buffer Pointer to a call context
+ * @param[out] kernel_buffer Pointer to a call context
+ *
+ * @return Returns MALI_ERROR_NONE on success.
+ */
+
+mali_error ukk_copy_to_user( size_t bytes, void * user_buffer, const void * const kernel_buffer );
+
+/**
+ * @brief Dispatch a UK call
+ *
+ * Dispatches the UK call to the UKK client or the UKK core in case of an internal UK call. The id field
+ * in the header field of the argument structure identifies which UK call needs to be executed. Any
+ * UK call with id equal or larger than UK_FUNC_ID is dispatched to the UKK client.
+ *
+ * If the UK call was accepted by the dispatch handler of the UKK client or UKK core, this function returns
+ * with MALI_ERROR_NONE and the result of executing the UK call is stored in the header.ret field of the
+ * in the argument structure. This function returns MALI_ERROR_FUNCTION_FAILED when the UK call is not
+ * accepted by the dispatch handler.
+ *
+ * If a UK call fails while executing in the dispatch handler of the UKK client or UKK core
+ * the UK call is reponsible for cleaning up any resources it allocated up to the point a failure
+ * occurred.
+ *
+ * Before accepting a UK call, the dispatch handler of the UKK client or UKK core should compare the
+ * the size of the argument structure based on the function id in header.id with the args_size parameter.
+ * Only if they match the UK call should be attempted, otherwise MALI_ERROR_FUNCTION_FAILED
+ * should be returned.
+ *
+ * An example of a piece of code from a UKK client dispatch handler:
+ * @code
+ * uk_header *header = (uk_header *)arg;
+ * switch(header->id) {
+ * case MYCLIENT_FUNCTION: {
+ * if (args_size != sizeof(myclient_function_args)) {
+ * return MALI_ERROR_FUNCTION_FAILED; // argument structure size mismatch
+ * } else {
+ * // execute UK call and store result back in header
+ * header->ret = do_my_client_function(ukk_ctx, args);
+ * return MALI_ERROR_NONE;
+ * }
+ * default:
+ * return MALI_ERROR_FUNCTION_FAILED; // UK call function number not recognized
+ * }
+ * @endcode
+ *
+ * Debug builds will assert when a NULL pointer is passed for ukk_ctx, args or args_size
+ * is < sizeof(uk_header).
+ *
+ * @param[in] ukk_ctx Pointer to a call context
+ * @param[in,out] args Pointer to a argument structure of a UK call
+ * @param[in] args_size Size of the argument structure (in bytes)
+ * @return MALI_ERROR_NONE on success. MALI_ERROR_FUNCTION_FAILED when the UK call was not accepted
+ * by the dispatch handler of the UKK client or UKK core, or the passed in argument structure
+ * is not large enough to store the required uk_header structure.
+ */
+mali_error ukk_dispatch(ukk_call_context * const ukk_ctx, void * const args, u32 args_size);
+
+/** @} end group uk_api_kernel */
+
+/** @} end group uk_api */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* _UKK_H_ */
diff --git a/drivers/gpu/arm/t6xx/kbase/malisw/arm_cstd/arm_cstd.h b/drivers/gpu/arm/t6xx/kbase/malisw/arm_cstd/arm_cstd.h
new file mode 100644
index 0000000..720da8c
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/malisw/arm_cstd/arm_cstd.h
@@ -0,0 +1,476 @@
+/*
+ *
+ * (C) COPYRIGHT 2007-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @addtogroup malisw
+ * @{
+ */
+
+/* ============================================================================
+ Description
+============================================================================ */
+/**
+ * @defgroup arm_cstd_coding_standard ARM C standard types and constants
+ * The common files are a set of standard headers which are used by all parts
+ * of this development, describing types, and generic constants.
+ *
+ * Files in group:
+ * - arm_cstd.h
+ * - arm_cstd_compilers.h
+ * - arm_cstd_types.h
+ * - arm_cstd_types_rvct.h
+ * - arm_cstd_types_gcc.h
+ * - arm_cstd_types_msvc.h
+ * - arm_cstd_pack_push.h
+ * - arm_cstd_pack_pop.h
+ */
+
+/**
+ * @addtogroup arm_cstd_coding_standard
+ * @{
+ */
+
+#ifndef _ARM_CSTD_
+#define _ARM_CSTD_
+
+/* ============================================================================
+ Import standard C99 types
+============================================================================ */
+#include "arm_cstd_compilers.h"
+#include "arm_cstd_types.h"
+
+/* ============================================================================
+ Min and Max Values
+============================================================================ */
+#if !defined(INT8_MAX)
+ #define INT8_MAX ((int8_t) 0x7F)
+#endif
+#if !defined(INT8_MIN)
+ #define INT8_MIN (-INT8_MAX - 1)
+#endif
+
+#if !defined(INT16_MAX)
+ #define INT16_MAX ((int16_t)0x7FFF)
+#endif
+#if !defined(INT16_MIN)
+ #define INT16_MIN (-INT16_MAX - 1)
+#endif
+
+#if !defined(INT32_MAX)
+ #define INT32_MAX ((int32_t)0x7FFFFFFF)
+#endif
+#if !defined(INT32_MIN)
+ #define INT32_MIN (-INT32_MAX - 1)
+#endif
+
+#if !defined(INT64_MAX)
+ #define INT64_MAX ((int64_t)0x7FFFFFFFFFFFFFFFLL)
+#endif
+#if !defined(INT64_MIN)
+ #define INT64_MIN (-INT64_MAX - 1)
+#endif
+
+#if !defined(UINT8_MAX)
+ #define UINT8_MAX ((uint8_t) 0xFF)
+#endif
+
+#if !defined(UINT16_MAX)
+ #define UINT16_MAX ((uint16_t)0xFFFF)
+#endif
+
+#if !defined(UINT32_MAX)
+ #define UINT32_MAX ((uint32_t)0xFFFFFFFF)
+#endif
+
+#if !defined(UINT64_MAX)
+ #define UINT64_MAX ((uint64_t)0xFFFFFFFFFFFFFFFFULL)
+#endif
+
+/* fallbacks if limits.h wasn't available */
+#if !defined(UCHAR_MAX)
+ #define UCHAR_MAX ((unsigned char)~0U)
+#endif
+
+#if !defined(SCHAR_MAX)
+ #define SCHAR_MAX ((signed char)(UCHAR_MAX >> 1))
+#endif
+#if !defined(SCHAR_MIN)
+ #define SCHAR_MIN ((signed char)(-SCHAR_MAX - 1))
+#endif
+
+#if !defined(USHRT_MAX)
+ #define USHRT_MAX ((unsigned short)~0U)
+#endif
+
+#if !defined(SHRT_MAX)
+ #define SHRT_MAX ((signed short)(USHRT_MAX >> 1))
+#endif
+#if !defined(SHRT_MIN)
+ #define SHRT_MIN ((signed short)(-SHRT_MAX - 1))
+#endif
+
+#if !defined(UINT_MAX)
+ #define UINT_MAX ((unsigned int)~0U)
+#endif
+
+#if !defined(INT_MAX)
+ #define INT_MAX ((signed int)(UINT_MAX >> 1))
+#endif
+#if !defined(INT_MIN)
+ #define INT_MIN ((signed int)(-INT_MAX - 1))
+#endif
+
+#if !defined(ULONG_MAX)
+ #define ULONG_MAX ((unsigned long)~0UL)
+#endif
+
+#if !defined(LONG_MAX)
+ #define LONG_MAX ((signed long)(ULONG_MAX >> 1))
+#endif
+#if !defined(LONG_MIN)
+ #define LONG_MIN ((signed long)(-LONG_MAX - 1))
+#endif
+
+#if !defined(ULLONG_MAX)
+ #define ULLONG_MAX ((unsigned long long)~0ULL)
+#endif
+
+#if !defined(LLONG_MAX)
+ #define LLONG_MAX ((signed long long)(ULLONG_MAX >> 1))
+#endif
+#if !defined(LLONG_MIN)
+ #define LLONG_MIN ((signed long long)(-LLONG_MAX - 1))
+#endif
+
+#if !defined(SIZE_MAX)
+ #if 1 == CSTD_CPU_32BIT
+ #define SIZE_MAX UINT32_MAX
+ #elif 1 == CSTD_CPU_64BIT
+ #define SIZE_MAX UINT64_MAX
+ #endif
+#endif
+
+/* ============================================================================
+ Keywords
+============================================================================ */
+/* Portable keywords. */
+
+#if !defined(CONST)
+/**
+ * @hideinitializer
+ * Variable is a C @c const, which can be made non-const for testing purposes.
+ */
+ #define CONST const
+#endif
+
+#if !defined(STATIC)
+/**
+ * @hideinitializer
+ * Variable is a C @c static, which can be made non-static for testing
+ * purposes.
+ */
+ #define STATIC static
+#endif
+
+/**
+ * Specifies a function as being exported outside of a logical module.
+ */
+#define PUBLIC
+
+/**
+ * @def PROTECTED
+ * Specifies a a function which is internal to an logical module, but which
+ * should not be used outside of that module. This cannot be enforced by the
+ * compiler, as a module is typically more than one translation unit.
+ */
+#define PROTECTED
+
+/**
+ * Specifies a function as being internal to a translation unit. Private
+ * functions would typically be declared as STATIC, unless they are being
+ * exported for unit test purposes.
+ */
+#define PRIVATE STATIC
+
+/**
+ * Specify an assertion value which is evaluated at compile time. Recommended
+ * usage is specification of a @c static @c INLINE function containing all of
+ * the assertions thus:
+ *
+ * @code
+ * static INLINE [module]_compile_time_assertions( void )
+ * {
+ * COMPILE_TIME_ASSERT( sizeof(uintptr_t) == sizeof(intptr_t) );
+ * }
+ * @endcode
+ *
+ * @note Use @c static not @c STATIC. We never want to turn off this @c static
+ * specification for testing purposes.
+ */
+#define CSTD_COMPILE_TIME_ASSERT( expr ) \
+ do { switch(0){case 0: case (expr):;} } while( FALSE )
+
+/**
+ * @hideinitializer
+ * @deprecated Prefered form is @c CSTD_UNUSED
+ * Function-like macro for suppressing unused variable warnings. Where possible
+ * such variables should be removed; this macro is present for cases where we
+ * much support API backwards compatibility.
+ */
+#define UNUSED( x ) ((void)(x))
+
+/**
+ * @hideinitializer
+ * Function-like macro for suppressing unused variable warnings. Where possible
+ * such variables should be removed; this macro is present for cases where we
+ * much support API backwards compatibility.
+ */
+#define CSTD_UNUSED( x ) ((void)(x))
+
+/**
+ * @hideinitializer
+ * Function-like macro for use where "no behavior" is desired. This is useful
+ * when compile time macros turn a function-like macro in to a no-op, but
+ * where having no statement is otherwise invalid.
+ */
+#define CSTD_NOP( ... ) ((void)#__VA_ARGS__)
+
+/**
+ * @hideinitializer
+ * Function-like macro for converting a pointer in to a u64 for storing into
+ * an external data structure. This is commonly used when pairing a 32-bit
+ * CPU with a 64-bit peripheral, such as a Midgard GPU. C's type promotion
+ * is complex and a straight cast does not work reliably as pointers are
+ * often considered as signed.
+ */
+#define CSTD_PTR_TO_U64( x ) ((uint64_t)((uintptr_t)(x)))
+
+/**
+ * @hideinitializer
+ * Function-like macro for stringizing a single level macro.
+ * @code
+ * #define MY_MACRO 32
+ * CSTD_STR1( MY_MACRO )
+ * > "MY_MACRO"
+ * @endcode
+ */
+#define CSTD_STR1( x ) #x
+
+/**
+ * @hideinitializer
+ * Function-like macro for stringizing a macro's value. This should not be used
+ * if the macro is defined in a way which may have no value; use the
+ * alternative @c CSTD_STR2N macro should be used instead.
+ * @code
+ * #define MY_MACRO 32
+ * CSTD_STR2( MY_MACRO )
+ * > "32"
+ * @endcode
+ */
+#define CSTD_STR2( x ) CSTD_STR1( x )
+
+/**
+ * @hideinitializer
+ * Utility function for stripping the first character off a string.
+ */
+static INLINE char* arm_cstd_strstrip( char * string )
+{
+ return ++string;
+}
+
+/**
+ * @hideinitializer
+ * Function-like macro for stringizing a single level macro where the macro
+ * itself may not have a value. Parameter @c a should be set to any single
+ * character which is then stripped by the macro via an inline function. This
+ * should only be used via the @c CSTD_STR2N macro; for printing a single
+ * macro only the @c CSTD_STR1 macro is a better alternative.
+ *
+ * This macro requires run-time code to handle the case where the macro has
+ * no value (you can't concat empty strings in the preprocessor).
+ */
+#define CSTD_STR1N( a, x ) arm_cstd_strstrip( CSTD_STR1( a##x ) )
+
+/**
+ * @hideinitializer
+ * Function-like macro for stringizing a two level macro where the macro itself
+ * may not have a value.
+ * @code
+ * #define MY_MACRO 32
+ * CSTD_STR2N( MY_MACRO )
+ * > "32"
+ *
+ * #define MY_MACRO 32
+ * CSTD_STR2N( MY_MACRO )
+ * > "32"
+ * @endcode
+ */
+#define CSTD_STR2N( x ) CSTD_STR1N( _, x )
+
+/* ============================================================================
+ Validate portability constructs
+============================================================================ */
+static INLINE void arm_cstd_compile_time_assertions( void )
+{
+ CSTD_COMPILE_TIME_ASSERT( sizeof(uint8_t) == 1 );
+ CSTD_COMPILE_TIME_ASSERT( sizeof(int8_t) == 1 );
+ CSTD_COMPILE_TIME_ASSERT( sizeof(uint16_t) == 2 );
+ CSTD_COMPILE_TIME_ASSERT( sizeof(int16_t) == 2 );
+ CSTD_COMPILE_TIME_ASSERT( sizeof(uint32_t) == 4 );
+ CSTD_COMPILE_TIME_ASSERT( sizeof(int32_t) == 4 );
+ CSTD_COMPILE_TIME_ASSERT( sizeof(uint64_t) == 8 );
+ CSTD_COMPILE_TIME_ASSERT( sizeof(int64_t) == 8 );
+ CSTD_COMPILE_TIME_ASSERT( sizeof(intptr_t) == sizeof(uintptr_t) );
+
+ CSTD_COMPILE_TIME_ASSERT( 1 == TRUE );
+ CSTD_COMPILE_TIME_ASSERT( 0 == FALSE );
+
+#if 1 == CSTD_CPU_32BIT
+ CSTD_COMPILE_TIME_ASSERT( sizeof(uintptr_t) == 4 );
+#elif 1 == CSTD_CPU_64BIT
+ CSTD_COMPILE_TIME_ASSERT( sizeof(uintptr_t) == 8 );
+#endif
+
+}
+
+/* ============================================================================
+ Useful function-like macro
+============================================================================ */
+/**
+ * @brief Return the lesser of two values.
+ * As a macro it may evaluate its arguments more than once.
+ * @see CSTD_MAX
+ */
+#define CSTD_MIN( x, y ) ((x) < (y) ? (x) : (y))
+
+/**
+ * @brief Return the greater of two values.
+ * As a macro it may evaluate its arguments more than once.
+ * If called on the same two arguments as CSTD_MIN it is guaranteed to return
+ * the one that CSTD_MIN didn't return. This is significant for types where not
+ * all values are comparable e.g. NaNs in floating-point types. But if you want
+ * to retrieve the min and max of two values, consider using a conditional swap
+ * instead.
+ */
+#define CSTD_MAX( x, y ) ((x) < (y) ? (y) : (x))
+
+/**
+ * @brief Clamp value @c x to within @c min and @c max inclusive.
+ */
+#define CSTD_CLAMP( x, min, max ) ((x)<(min) ? (min):((x)>(max) ? (max):(x)))
+
+/**
+ * Flag a cast as a reinterpretation, usually of a pointer type.
+ */
+#define CSTD_REINTERPRET_CAST(type) (type)
+
+/**
+ * Flag a cast as casting away const, usually of a pointer type.
+ */
+#define CSTD_CONST_CAST(type) (type)
+
+/**
+ * Flag a cast as a (potentially complex) value conversion, usually of a
+ * numerical type.
+ */
+#define CSTD_STATIC_CAST(type) (type)
+
+/* ============================================================================
+ Useful bit constants
+============================================================================ */
+/**
+ * @cond arm_cstd_utilities
+ */
+
+/* Common bit constant values, useful in embedded programming. */
+#define F_BIT_0 ((uint32_t)0x00000001)
+#define F_BIT_1 ((uint32_t)0x00000002)
+#define F_BIT_2 ((uint32_t)0x00000004)
+#define F_BIT_3 ((uint32_t)0x00000008)
+#define F_BIT_4 ((uint32_t)0x00000010)
+#define F_BIT_5 ((uint32_t)0x00000020)
+#define F_BIT_6 ((uint32_t)0x00000040)
+#define F_BIT_7 ((uint32_t)0x00000080)
+#define F_BIT_8 ((uint32_t)0x00000100)
+#define F_BIT_9 ((uint32_t)0x00000200)
+#define F_BIT_10 ((uint32_t)0x00000400)
+#define F_BIT_11 ((uint32_t)0x00000800)
+#define F_BIT_12 ((uint32_t)0x00001000)
+#define F_BIT_13 ((uint32_t)0x00002000)
+#define F_BIT_14 ((uint32_t)0x00004000)
+#define F_BIT_15 ((uint32_t)0x00008000)
+#define F_BIT_16 ((uint32_t)0x00010000)
+#define F_BIT_17 ((uint32_t)0x00020000)
+#define F_BIT_18 ((uint32_t)0x00040000)
+#define F_BIT_19 ((uint32_t)0x00080000)
+#define F_BIT_20 ((uint32_t)0x00100000)
+#define F_BIT_21 ((uint32_t)0x00200000)
+#define F_BIT_22 ((uint32_t)0x00400000)
+#define F_BIT_23 ((uint32_t)0x00800000)
+#define F_BIT_24 ((uint32_t)0x01000000)
+#define F_BIT_25 ((uint32_t)0x02000000)
+#define F_BIT_26 ((uint32_t)0x04000000)
+#define F_BIT_27 ((uint32_t)0x08000000)
+#define F_BIT_28 ((uint32_t)0x10000000)
+#define F_BIT_29 ((uint32_t)0x20000000)
+#define F_BIT_30 ((uint32_t)0x40000000)
+#define F_BIT_31 ((uint32_t)0x80000000)
+
+/* Common 2^n size values, useful in embedded programming. */
+#define C_SIZE_1B ((uint32_t)0x00000001)
+#define C_SIZE_2B ((uint32_t)0x00000002)
+#define C_SIZE_4B ((uint32_t)0x00000004)
+#define C_SIZE_8B ((uint32_t)0x00000008)
+#define C_SIZE_16B ((uint32_t)0x00000010)
+#define C_SIZE_32B ((uint32_t)0x00000020)
+#define C_SIZE_64B ((uint32_t)0x00000040)
+#define C_SIZE_128B ((uint32_t)0x00000080)
+#define C_SIZE_256B ((uint32_t)0x00000100)
+#define C_SIZE_512B ((uint32_t)0x00000200)
+#define C_SIZE_1KB ((uint32_t)0x00000400)
+#define C_SIZE_2KB ((uint32_t)0x00000800)
+#define C_SIZE_4KB ((uint32_t)0x00001000)
+#define C_SIZE_8KB ((uint32_t)0x00002000)
+#define C_SIZE_16KB ((uint32_t)0x00004000)
+#define C_SIZE_32KB ((uint32_t)0x00008000)
+#define C_SIZE_64KB ((uint32_t)0x00010000)
+#define C_SIZE_128KB ((uint32_t)0x00020000)
+#define C_SIZE_256KB ((uint32_t)0x00040000)
+#define C_SIZE_512KB ((uint32_t)0x00080000)
+#define C_SIZE_1MB ((uint32_t)0x00100000)
+#define C_SIZE_2MB ((uint32_t)0x00200000)
+#define C_SIZE_4MB ((uint32_t)0x00400000)
+#define C_SIZE_8MB ((uint32_t)0x00800000)
+#define C_SIZE_16MB ((uint32_t)0x01000000)
+#define C_SIZE_32MB ((uint32_t)0x02000000)
+#define C_SIZE_64MB ((uint32_t)0x04000000)
+#define C_SIZE_128MB ((uint32_t)0x08000000)
+#define C_SIZE_256MB ((uint32_t)0x10000000)
+#define C_SIZE_512MB ((uint32_t)0x20000000)
+#define C_SIZE_1GB ((uint32_t)0x40000000)
+#define C_SIZE_2GB ((uint32_t)0x80000000)
+
+/**
+ * @endcond
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#endif /* End (_ARM_CSTD_) */
diff --git a/drivers/gpu/arm/t6xx/kbase/malisw/arm_cstd/arm_cstd_compilers.h b/drivers/gpu/arm/t6xx/kbase/malisw/arm_cstd/arm_cstd_compilers.h
new file mode 100644
index 0000000..e13588f
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/malisw/arm_cstd/arm_cstd_compilers.h
@@ -0,0 +1,571 @@
+/*
+ *
+ * (C) COPYRIGHT 2005-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+#ifndef _ARM_CSTD_COMPILERS_H_
+#define _ARM_CSTD_COMPILERS_H_
+
+/* ============================================================================
+ Document default definitions - assuming nothing set at this point.
+============================================================================ */
+/**
+ * @addtogroup arm_cstd_coding_standard
+ * @{
+ */
+
+/**
+ * @hideinitializer
+ * Defined with value of 1 if toolchain is Microsoft Visual Studio, 0
+ * otherwise.
+ */
+#define CSTD_TOOLCHAIN_MSVC 0
+
+/**
+ * @hideinitializer
+ * Defined with value of 1 if toolchain is the GNU Compiler Collection, 0
+ * otherwise.
+ */
+#define CSTD_TOOLCHAIN_GCC 0
+
+/**
+ * @hideinitializer
+ * Defined with value of 1 if toolchain is ARM RealView Compiler Tools, 0
+ * otherwise. Note - if running RVCT in GCC mode this define will be set to 0;
+ * @c CSTD_TOOLCHAIN_GCC and @c CSTD_TOOLCHAIN_RVCT_GCC_MODE will both be
+ * defined as 1.
+ */
+#define CSTD_TOOLCHAIN_RVCT 0
+
+/**
+ * @hideinitializer
+ * Defined with value of 1 if toolchain is ARM RealView Compiler Tools running
+ * in GCC mode, 0 otherwise.
+ */
+#define CSTD_TOOLCHAIN_RVCT_GCC_MODE 0
+
+/**
+ * @hideinitializer
+ * Defined with value of 1 if processor is an x86 32-bit machine, 0 otherwise.
+ */
+#define CSTD_CPU_X86_32 0
+
+/**
+ * @hideinitializer
+ * Defined with value of 1 if processor is an x86-64 (AMD64) machine, 0
+ * otherwise.
+ */
+#define CSTD_CPU_X86_64 0
+
+/**
+ * @hideinitializer
+ * Defined with value of 1 if processor is an ARM machine, 0 otherwise.
+ */
+#define CSTD_CPU_ARM 0
+
+/**
+ * @hideinitializer
+ * Defined with value of 1 if processor is a MIPS machine, 0 otherwise.
+ */
+#define CSTD_CPU_MIPS 0
+
+/**
+ * @hideinitializer
+ * Defined with value of 1 if CPU is 32-bit, 0 otherwise.
+ */
+#define CSTD_CPU_32BIT 0
+
+/**
+ * @hideinitializer
+ * Defined with value of 1 if CPU is 64-bit, 0 otherwise.
+ */
+#define CSTD_CPU_64BIT 0
+
+/**
+ * @hideinitializer
+ * Defined with value of 1 if processor configured as big-endian, 0 if it
+ * is little-endian.
+ */
+#define CSTD_CPU_BIG_ENDIAN 0
+
+/**
+ * @hideinitializer
+ * Defined with value of 1 if operating system is a version of Windows, 0 if
+ * it is not.
+ */
+#define CSTD_OS_WINDOWS 0
+
+/**
+ * @hideinitializer
+ * Defined with value of 1 if operating system is a 32-bit version of Windows,
+ * 0 if it is not.
+ */
+#define CSTD_OS_WIN32 0
+
+/**
+ * @hideinitializer
+ * Defined with value of 1 if operating system is a 64-bit version of Windows,
+ * 0 if it is not.
+ */
+#define CSTD_OS_WIN64 0
+
+/**
+ * @hideinitializer
+ * Defined with value of 1 if operating system is Linux, 0 if it is not.
+ */
+#define CSTD_OS_LINUX 0
+
+/**
+ * @hideinitializer
+ * Defined with value of 1 if we are compiling Linux kernel code, 0 otherwise.
+ */
+#define CSTD_OS_LINUX_KERNEL 0
+
+/**
+ * @hideinitializer
+ * Defined with value of 1 if operating system is a 32-bit version of Linux,
+ * 0 if it is not.
+ */
+#define CSTD_OS_LINUX32 0
+
+/**
+ * @hideinitializer
+ * Defined with value of 1 if operating system is a 64-bit version of Linux,
+ * 0 if it is not.
+ */
+#define CSTD_OS_LINUX64 0
+
+/**
+ * @hideinitializer
+ * Defined with value of 1 if operating system is Android, 0 if it is not.
+ */
+#define CSTD_OS_ANDROID 0
+
+/**
+ * @hideinitializer
+ * Defined with value of 1 if we are compiling Android kernel code, 0 otherwise.
+ */
+#define CSTD_OS_ANDROID_KERNEL 0
+
+/**
+ * @hideinitializer
+ * Defined with value of 1 if operating system is a 32-bit version of Android,
+ * 0 if it is not.
+ */
+#define CSTD_OS_ANDROID32 0
+
+/**
+ * @hideinitializer
+ * Defined with value of 1 if operating system is a 64-bit version of Android,
+ * 0 if it is not.
+ */
+#define CSTD_OS_ANDROID64 0
+
+/**
+ * @hideinitializer
+ * Defined with value of 1 if operating system is a version of Apple OS,
+ * 0 if it is not.
+ */
+#define CSTD_OS_APPLEOS 0
+
+/**
+ * @hideinitializer
+ * Defined with value of 1 if operating system is a 32-bit version of Apple OS,
+ * 0 if it is not.
+ */
+#define CSTD_OS_APPLEOS32 0
+
+/**
+ * @hideinitializer
+ * Defined with value of 1 if operating system is a 64-bit version of Apple OS,
+ * 0 if it is not.
+ */
+#define CSTD_OS_APPLEOS64 0
+
+/**
+ * @def CSTD_OS_SYMBIAN
+ * @hideinitializer
+ * Defined with value of 1 if operating system is Symbian, 0 if it is not.
+ */
+#define CSTD_OS_SYMBIAN 0
+
+/**
+ * @def CSTD_OS_NONE
+ * @hideinitializer
+ * Defined with value of 1 if there is no operating system (bare metal), 0
+ * otherwise
+ */
+#define CSTD_OS_NONE 0
+
+/* ============================================================================
+ Determine the compiler in use
+============================================================================ */
+#if defined(_MSC_VER)
+ #undef CSTD_TOOLCHAIN_MSVC
+ #define CSTD_TOOLCHAIN_MSVC 1
+
+#elif defined(__GNUC__)
+ #undef CSTD_TOOLCHAIN_GCC
+ #define CSTD_TOOLCHAIN_GCC 1
+
+ /* Detect RVCT pretending to be GCC. */
+ #if defined(__ARMCC_VERSION)
+ #undef CSTD_TOOLCHAIN_RVCT_GCC_MODE
+ #define CSTD_TOOLCHAIN_RVCT_GCC_MODE 1
+ #endif
+
+#elif defined(__ARMCC_VERSION)
+ #undef CSTD_TOOLCHAIN_RVCT
+ #define CSTD_TOOLCHAIN_RVCT 1
+
+#else
+ #warning "Unsupported or unknown toolchain"
+
+#endif
+
+/* ============================================================================
+ Determine the processor
+============================================================================ */
+#if 1 == CSTD_TOOLCHAIN_MSVC
+ #if defined(_M_IX86)
+ #undef CSTD_CPU_X86_32
+ #define CSTD_CPU_X86_32 1
+
+ #elif defined(_M_X64) || defined(_M_AMD64)
+ #undef CSTD_CPU_X86_64
+ #define CSTD_CPU_X86_64 1
+
+ #elif defined(_M_ARM)
+ #undef CSTD_CPU_ARM
+ #define CSTD_CPU_ARM 1
+
+ #elif defined(_M_MIPS)
+ #undef CSTD_CPU_MIPS
+ #define CSTD_CPU_MIPS 1
+
+ #else
+ #warning "Unsupported or unknown host CPU for MSVC tools"
+
+ #endif
+
+#elif 1 == CSTD_TOOLCHAIN_GCC
+ #if defined(__amd64__)
+ #undef CSTD_CPU_X86_64
+ #define CSTD_CPU_X86_64 1
+
+ #elif defined(__i386__)
+ #undef CSTD_CPU_X86_32
+ #define CSTD_CPU_X86_32 1
+
+ #elif defined(__arm__)
+ #undef CSTD_CPU_ARM
+ #define CSTD_CPU_ARM 1
+
+ #elif defined(__mips__)
+ #undef CSTD_CPU_MIPS
+ #define CSTD_CPU_MIPS 1
+
+ #else
+ #warning "Unsupported or unknown host CPU for GCC tools"
+
+ #endif
+
+#elif 1 == CSTD_TOOLCHAIN_RVCT
+ #undef CSTD_CPU_ARM
+ #define CSTD_CPU_ARM 1
+
+#else
+ #warning "Unsupported or unknown toolchain"
+
+#endif
+
+/* ============================================================================
+ Determine the Processor Endianness
+============================================================================ */
+
+#if ((1 == CSTD_CPU_X86_32) || (1 == CSTD_CPU_X86_64))
+ /* Note: x86 and x86-64 are always little endian, so leave at default. */
+
+#elif 1 == CSTD_TOOLCHAIN_RVCT
+ #if defined(__BIG_ENDIAN)
+ #undef CSTD_ENDIAN_BIG
+ #define CSTD_ENDIAN_BIG 1
+ #endif
+
+#elif ((1 == CSTD_TOOLCHAIN_GCC) && (1 == CSTD_CPU_ARM))
+ #if defined(__ARMEB__)
+ #undef CSTD_ENDIAN_BIG
+ #define CSTD_ENDIAN_BIG 1
+ #endif
+
+#elif ((1 == CSTD_TOOLCHAIN_GCC) && (1 == CSTD_CPU_MIPS))
+ #if defined(__MIPSEB__)
+ #undef CSTD_ENDIAN_BIG
+ #define CSTD_ENDIAN_BIG 1
+ #endif
+
+#elif 1 == CSTD_TOOLCHAIN_MSVC
+ /* Note: Microsoft only support little endian, so leave at default. */
+
+#else
+ #warning "Unsupported or unknown CPU"
+
+#endif
+
+/* ============================================================================
+ Determine the operating system and addressing width
+============================================================================ */
+#if 1 == CSTD_TOOLCHAIN_MSVC
+ #if defined(_WIN32) && !defined(_WIN64)
+ #undef CSTD_OS_WINDOWS
+ #define CSTD_OS_WINDOWS 1
+ #undef CSTD_OS_WIN32
+ #define CSTD_OS_WIN32 1
+ #undef CSTD_CPU_32BIT
+ #define CSTD_CPU_32BIT 1
+
+ #elif defined(_WIN32) && defined(_WIN64)
+ #undef CSTD_OS_WINDOWS
+ #define CSTD_OS_WINDOWS 1
+ #undef CSTD_OS_WIN64
+ #define CSTD_OS_WIN64 1
+ #undef CSTD_CPU_64BIT
+ #define CSTD_CPU_64BIT 1
+
+ #else
+ #warning "Unsupported or unknown host OS for MSVC tools"
+
+ #endif
+
+#elif 1 == CSTD_TOOLCHAIN_GCC
+ #if defined(_WIN32) && defined(_WIN64)
+ #undef CSTD_OS_WINDOWS
+ #define CSTD_OS_WINDOWS 1
+ #undef CSTD_OS_WIN64
+ #define CSTD_OS_WIN64 1
+ #undef CSTD_CPU_64BIT
+ #define CSTD_CPU_64BIT 1
+
+ #elif defined(_WIN32) && !defined(_WIN64)
+ #undef CSTD_OS_WINDOWS
+ #define CSTD_OS_WINDOWS 1
+ #undef CSTD_OS_WIN32
+ #define CSTD_OS_WIN32 1
+ #undef CSTD_CPU_32BIT
+ #define CSTD_CPU_32BIT 1
+
+ #elif defined(ANDROID)
+ #undef CSTD_OS_ANDROID
+ #define CSTD_OS_ANDROID 1
+
+ #if defined(__KERNEL__)
+ #undef CSTD_OS_ANDROID_KERNEL
+ #define CSTD_OS_ANDROID_KERNEL 1
+ #endif
+
+ #if defined(__LP64__) || defined(_LP64)
+ #undef CSTD_OS_ANDROID64
+ #define CSTD_OS_ANDROID64 1
+ #undef CSTD_CPU_64BIT
+ #define CSTD_CPU_64BIT 1
+ #else
+ #undef CSTD_OS_ANDROID32
+ #define CSTD_OS_ANDROID32 1
+ #undef CSTD_CPU_32BIT
+ #define CSTD_CPU_32BIT 1
+ #endif
+
+ #elif defined(__KERNEL__) || defined(__linux)
+ #undef CSTD_OS_LINUX
+ #define CSTD_OS_LINUX 1
+
+ #if defined(__KERNEL__)
+ #undef CSTD_OS_LINUX_KERNEL
+ #define CSTD_OS_LINUX_KERNEL 1
+ #endif
+
+ #if defined(__LP64__) || defined(_LP64)
+ #undef CSTD_OS_LINUX64
+ #define CSTD_OS_LINUX64 1
+ #undef CSTD_CPU_64BIT
+ #define CSTD_CPU_64BIT 1
+ #else
+ #undef CSTD_OS_LINUX32
+ #define CSTD_OS_LINUX32 1
+ #undef CSTD_CPU_32BIT
+ #define CSTD_CPU_32BIT 1
+ #endif
+
+ #elif defined(__APPLE__)
+ #undef CSTD_OS_APPLEOS
+ #define CSTD_OS_APPLEOS 1
+
+ #if defined(__LP64__) || defined(_LP64)
+ #undef CSTD_OS_APPLEOS64
+ #define CSTD_OS_APPLEOS64 1
+ #undef CSTD_CPU_64BIT
+ #define CSTD_CPU_64BIT 1
+ #else
+ #undef CSTD_OS_APPLEOS32
+ #define CSTD_OS_APPLEOS32 1
+ #undef CSTD_CPU_32BIT
+ #define CSTD_CPU_32BIT 1
+ #endif
+
+ #elif defined(__SYMBIAN32__)
+ #undef CSTD_OS_SYMBIAN
+ #define CSTD_OS_SYMBIAN 1
+ #undef CSTD_CPU_32BIT
+ #define CSTD_CPU_32BIT 1
+
+ #else
+ #undef CSTD_OS_NONE
+ #define CSTD_OS_NONE 1
+ #undef CSTD_CPU_32BIT
+ #define CSTD_CPU_32BIT 1
+
+#endif
+
+#elif 1 == CSTD_TOOLCHAIN_RVCT
+
+ #if defined(ANDROID)
+ #undef CSTD_OS_ANDROID
+ #undef CSTD_OS_ANDROID32
+ #define CSTD_OS_ANDROID 1
+ #define CSTD_OS_ANDROID32 1
+
+ #elif defined(__linux)
+ #undef CSTD_OS_LINUX
+ #undef CSTD_OS_LINUX32
+ #define CSTD_OS_LINUX 1
+ #define CSTD_OS_LINUX32 1
+
+ #elif defined(__SYMBIAN32__)
+ #undef CSTD_OS_SYMBIAN
+ #define CSTD_OS_SYMBIAN 1
+
+ #else
+ #undef CSTD_OS_NONE
+ #define CSTD_OS_NONE 1
+
+#endif
+
+#else
+ #warning "Unsupported or unknown host OS"
+
+#endif
+
+/* ============================================================================
+ Determine the correct linker symbol Import and Export Macros
+============================================================================ */
+/**
+ * @defgroup arm_cstd_linkage_specifiers Linkage Specifiers
+ * @{
+ *
+ * This set of macros contain system-dependent linkage specifiers which
+ * determine the visibility of symbols across DLL boundaries. A header for a
+ * particular DLL should define a set of local macros derived from these,
+ * and should not use these macros to decorate functions directly as there may
+ * be multiple DLLs being used.
+ *
+ * These DLL library local macros should be (with appropriate library prefix)
+ * <tt>[MY_LIBRARY]_API</tt>, <tt>[MY_LIBRARY]_IMPL</tt>, and
+ * <tt>[MY_LIBRARY]_LOCAL</tt>.
+ *
+ * - <tt>[MY_LIBRARY]_API</tt> should be use to decorate the function
+ * declarations in the header. It should be defined as either
+ * @c CSTD_LINK_IMPORT or @c CSTD_LINK_EXPORT, depending whether the
+ * current situation is a compile of the DLL itself (use export) or a
+ * compile of an external user of the DLL (use import).
+ * - <tt>[MY_LIBRARY]_IMPL</tt> should be defined as @c CSTD_LINK_IMPL
+ * and should be used to decorate the definition of functions in the C
+ * file.
+ * - <tt>[MY_LIBRARY]_LOCAL</tt> should be used to decorate function
+ * declarations which are exported across translation units within the
+ * DLL, but which are not exported outside of the DLL boundary.
+ *
+ * Functions which are @c static in either a C file or in a header file do not
+ * need any form of linkage decoration, and should therefore have no linkage
+ * macro applied to them.
+ */
+
+/**
+ * @def CSTD_LINK_IMPORT
+ * Specifies a function as being imported to a translation unit across a DLL
+ * boundary.
+ */
+
+/**
+ * @def CSTD_LINK_EXPORT
+ * Specifies a function as being exported across a DLL boundary by a
+ * translation unit.
+ */
+
+/**
+ * @def CSTD_LINK_IMPL
+ * Specifies a function which will be exported across a DLL boundary as
+ * being implemented by a translation unit.
+ */
+
+/**
+ * @def CSTD_LINK_LOCAL
+ * Specifies a function which is internal to a DLL, and which should not be
+ * exported outside of it.
+ */
+
+/**
+ * @}
+ */
+
+#if 1 == CSTD_OS_LINUX
+ #define CSTD_LINK_IMPORT __attribute__((visibility("default")))
+ #define CSTD_LINK_EXPORT __attribute__((visibility("default")))
+ #define CSTD_LINK_IMPL __attribute__((visibility("default")))
+ #define CSTD_LINK_LOCAL __attribute__((visibility("hidden")))
+
+#elif 1 == CSTD_OS_WINDOWS
+ #define CSTD_LINK_IMPORT __declspec(dllimport)
+ #define CSTD_LINK_EXPORT __declspec(dllexport)
+ #define CSTD_LINK_IMPL __declspec(dllexport)
+ #define CSTD_LINK_LOCAL
+
+#elif 1 == CSTD_OS_SYMBIAN
+ #define CSTD_LINK_IMPORT IMPORT_C
+ #define CSTD_LINK_EXPORT IMPORT_C
+ #define CSTD_LINK_IMPL EXPORT_C
+ #define CSTD_LINK_LOCAL
+
+#elif 1 == CSTD_OS_APPLEOS
+ #define CSTD_LINK_IMPORT __attribute__((visibility("default")))
+ #define CSTD_LINK_EXPORT __attribute__((visibility("default")))
+ #define CSTD_LINK_IMPL __attribute__((visibility("default")))
+ #define CSTD_LINK_LOCAL __attribute__((visibility("hidden")))
+
+#elif 1 == CSTD_OS_ANDROID
+ #define CSTD_LINK_IMPORT __attribute__((visibility("default")))
+ #define CSTD_LINK_EXPORT __attribute__((visibility("default")))
+ #define CSTD_LINK_IMPL __attribute__((visibility("default")))
+ #define CSTD_LINK_LOCAL __attribute__((visibility("hidden")))
+
+#else /* CSTD_OS_NONE */
+ #define CSTD_LINK_IMPORT
+ #define CSTD_LINK_EXPORT
+ #define CSTD_LINK_IMPL
+ #define CSTD_LINK_LOCAL
+
+#endif
+
+/**
+ * @}
+ */
+
+#endif /* End (_ARM_CSTD_COMPILERS_H_) */
diff --git a/drivers/gpu/arm/t6xx/kbase/malisw/arm_cstd/arm_cstd_pack_pop.h b/drivers/gpu/arm/t6xx/kbase/malisw/arm_cstd/arm_cstd_pack_pop.h
new file mode 100644
index 0000000..207ded2
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/malisw/arm_cstd/arm_cstd_pack_pop.h
@@ -0,0 +1,22 @@
+/*
+ *
+ * (C) COPYRIGHT 2009-2010, 2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+#ifndef _ARM_CSTD_PACK_POP_H_
+#define _ARM_CSTD_PACK_POP_H_
+
+#if 1 == CSTD_TOOLCHAIN_MSVC
+ #include <poppack.h>
+#endif
+
+#endif /* End (_ARM_CSTD_PACK_POP_H_) */
diff --git a/drivers/gpu/arm/t6xx/kbase/malisw/arm_cstd/arm_cstd_pack_push.h b/drivers/gpu/arm/t6xx/kbase/malisw/arm_cstd/arm_cstd_pack_push.h
new file mode 100644
index 0000000..2225ecb
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/malisw/arm_cstd/arm_cstd_pack_push.h
@@ -0,0 +1,22 @@
+/*
+ *
+ * (C) COPYRIGHT 2009-2010, 2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+#ifndef _ARM_CSTD_PACK_PUSH_H_
+#define _ARM_CSTD_PACK_PUSH_H_
+
+#if 1 == CSTD_TOOLCHAIN_MSVC
+ #include <pshpack1.h>
+#endif
+
+#endif /* End (_ARM_CSTD_PACK_PUSH_H_) */
diff --git a/drivers/gpu/arm/t6xx/kbase/malisw/arm_cstd/arm_cstd_types.h b/drivers/gpu/arm/t6xx/kbase/malisw/arm_cstd/arm_cstd_types.h
new file mode 100644
index 0000000..32c60e1
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/malisw/arm_cstd/arm_cstd_types.h
@@ -0,0 +1,28 @@
+/*
+ *
+ * (C) COPYRIGHT 2009-2010, 2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+#ifndef _ARM_CSTD_TYPES_H_
+#define _ARM_CSTD_TYPES_H_
+
+#if 1 == CSTD_TOOLCHAIN_MSVC
+ #include "arm_cstd_types_msvc.h"
+#elif 1 == CSTD_TOOLCHAIN_GCC
+ #include "arm_cstd_types_gcc.h"
+#elif 1 == CSTD_TOOLCHAIN_RVCT
+ #include "arm_cstd_types_rvct.h"
+#else
+ #error "Toolchain not recognized"
+#endif
+
+#endif /* End (_ARM_CSTD_TYPES_H_) */
diff --git a/drivers/gpu/arm/t6xx/kbase/malisw/arm_cstd/arm_cstd_types_gcc.h b/drivers/gpu/arm/t6xx/kbase/malisw/arm_cstd/arm_cstd_types_gcc.h
new file mode 100644
index 0000000..f6a544d
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/malisw/arm_cstd/arm_cstd_types_gcc.h
@@ -0,0 +1,87 @@
+/*
+ *
+ * (C) COPYRIGHT 2009-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+#ifndef _ARM_CSTD_TYPES_GCC_H_
+#define _ARM_CSTD_TYPES_GCC_H_
+
+/* ============================================================================
+ Type definitions
+============================================================================ */
+/* All modern versions of GCC support stdint outside of C99 Mode. */
+/* However, Linux kernel limits what headers are available! */
+#if 1 == CSTD_OS_LINUX_KERNEL
+ #include <linux/kernel.h>
+ #include <linux/types.h>
+ #include <linux/stddef.h>
+ #include <linux/version.h>
+
+ /* Fix up any types which CSTD provdes but which Linux is missing. */
+ /* Note Linux assumes pointers are "long", so this is safe. */
+ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ typedef unsigned long uintptr_t;
+ #endif
+ typedef long intptr_t;
+
+#else
+ #include <stdint.h>
+ #include <stddef.h>
+ #include <limits.h>
+#endif
+
+typedef uint32_t bool_t;
+
+#if !defined(TRUE)
+ #define TRUE ((bool_t)1)
+#endif
+
+#if !defined(FALSE)
+ #define FALSE ((bool_t)0)
+#endif
+
+/* ============================================================================
+ Keywords
+============================================================================ */
+/* Doxygen documentation for these is in the RVCT header. */
+#define ASM __asm__
+
+#define INLINE __inline__
+
+#define FORCE_INLINE __attribute__((__always_inline__)) __inline__
+
+#define NEVER_INLINE __attribute__((__noinline__))
+
+#define PURE __attribute__((__pure__))
+
+#define PACKED __attribute__((__packed__))
+
+/* GCC does not support pointers to UNALIGNED data, so we do not define it to
+ * force a compile error if this macro is used. */
+
+#define RESTRICT __restrict__
+
+/* RVCT in GCC mode does not support the CHECK_RESULT attribute. */
+#if 0 == CSTD_TOOLCHAIN_RVCT_GCC_MODE
+ #define CHECK_RESULT __attribute__((__warn_unused_result__))
+#else
+ #define CHECK_RESULT
+#endif
+
+/* RVCT in GCC mode does not support the __func__ name outside of C99. */
+#if (0 == CSTD_TOOLCHAIN_RVCT_GCC_MODE)
+ #define CSTD_FUNC __func__
+#else
+ #define CSTD_FUNC __FUNCTION__
+#endif
+
+#endif /* End (_ARM_CSTD_TYPES_GCC_H_) */
diff --git a/drivers/gpu/arm/t6xx/kbase/malisw/arm_cstd/arm_cstd_types_rvct.h b/drivers/gpu/arm/t6xx/kbase/malisw/arm_cstd/arm_cstd_types_rvct.h
new file mode 100644
index 0000000..c4eb7fc
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/malisw/arm_cstd/arm_cstd_types_rvct.h
@@ -0,0 +1,187 @@
+/*
+ *
+ * (C) COPYRIGHT 2009-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+#ifndef _ARM_CSTD_TYPES_RVCT_H_
+#define _ARM_CSTD_TYPES_RVCT_H_
+
+/* ============================================================================
+ Type definitions
+============================================================================ */
+#include <stddef.h>
+#include <limits.h>
+
+#if 199901L <= __STDC_VERSION__
+ #include <inttypes.h>
+#else
+ typedef unsigned char uint8_t;
+ typedef signed char int8_t;
+ typedef unsigned short uint16_t;
+ typedef signed short int16_t;
+ typedef unsigned int uint32_t;
+ typedef signed int int32_t;
+ typedef unsigned __int64 uint64_t;
+ typedef signed __int64 int64_t;
+ typedef ptrdiff_t intptr_t;
+ typedef size_t uintptr_t;
+#endif
+
+typedef uint32_t bool_t;
+
+#if !defined(TRUE)
+ #define TRUE ((bool_t)1)
+#endif
+
+#if !defined(FALSE)
+ #define FALSE ((bool_t)0)
+#endif
+
+/* ============================================================================
+ Keywords
+============================================================================ */
+/**
+ * @addtogroup arm_cstd_coding_standard
+ * @{
+ */
+
+/**
+ * @def ASM
+ * @hideinitializer
+ * Mark an assembler block. Such blocks are often compiler specific, so often
+ * need to be surrounded in appropriate @c ifdef and @c endif blocks
+ * using the relevant @c CSTD_TOOLCHAIN macro.
+ */
+#define ASM __asm
+
+/**
+ * @def INLINE
+ * @hideinitializer
+ * Mark a definition as something which should be inlined. This is not always
+ * possible on a given compiler, and may be disabled at lower optimization
+ * levels.
+ */
+#define INLINE __inline
+
+/**
+ * @def FORCE_INLINE
+ * @hideinitializer
+ * Mark a definition as something which should be inlined. This provides a much
+ * stronger hint to the compiler than @c INLINE, and if supported should always
+ * result in an inlined function being emitted. If not supported this falls
+ * back to using the @c INLINE definition.
+ */
+#define FORCE_INLINE __forceinline
+
+/**
+ * @def NEVER_INLINE
+ * @hideinitializer
+ * Mark a definition as something which should not be inlined. This provides a
+ * stronger hint to the compiler than the function should not be inlined,
+ * bypassing any heuristic rules the compiler normally applies. If not
+ * supported by a toolchain this falls back to being an empty macro.
+ */
+#define NEVER_INLINE __declspec(noinline)
+
+/**
+ * @def PURE
+ * @hideinitializer
+ * Denotes that a function's return is only dependent on its inputs, enabling
+ * more efficient optimizations. Falls back to an empty macro if not supported.
+ */
+#define PURE __pure
+
+/**
+ * @def PACKED
+ * @hideinitializer
+ * Denotes that a structure should be stored in a packed form. This macro must
+ * be used in conjunction with the @c arm_cstd_pack_* headers for portability:
+ *
+ * @code
+ * #include <cstd/arm_cstd_pack_push.h>
+ *
+ * struct PACKED myStruct {
+ * ...
+ * };
+ *
+ * #include <cstd/arm_cstd_pack_pop.h>
+ * PACKED
+ * @endcode
+ */
+#define PACKED __packed
+
+/**
+ * @def UNALIGNED
+ * @hideinitializer
+ * Denotes that a pointer points to a buffer with lower alignment than the
+ * natural alignment required by the C standard. This should only be used
+ * in extreme cases, as the emitted code is normally more efficient if memory
+ * is aligned.
+ *
+ * @warning This is \b NON-PORTABLE. The GNU tools are anti-unaligned pointers
+ * and have no support for such a construction.
+ */
+#define UNALIGNED __packed
+
+/**
+ * @def RESTRICT
+ * @hideinitializer
+ * Denotes that a pointer does not overlap with any other points currently in
+ * scope, increasing the range of optimizations which can be performed by the
+ * compiler.
+ *
+ * @warning Specification of @c RESTRICT is a contract between the programmer
+ * and the compiler. If you place @c RESTICT on buffers which do actually
+ * overlap the behavior is undefined, and likely to vary at different
+ * optimization levels.!
+ */
+#define RESTRICT __restrict
+
+/**
+ * @def CHECK_RESULT
+ * @hideinitializer
+ * Function attribute which causes a warning to be emitted if the compiler's
+ * return value is not used by the caller. Compiles to an empty macro if
+ * there is no supported mechanism for this check in the underlying compiler.
+ *
+ * @note At the time of writing this is only supported by GCC. RVCT does not
+ * support this attribute, even in GCC mode, so engineers are encouraged to
+ * compile their code using GCC even if primarily working with another
+ * compiler.
+ *
+ * @code
+ * CHECK_RESULT int my_func( void );
+ * @endcode
+ */
+#define CHECK_RESULT
+
+/**
+ * @def CSTD_FUNC
+ * Specify the @c CSTD_FUNC macro, a portable construct containing the name of
+ * the current function. On most compilers it is illegal to use this macro
+ * outside of a function scope. If not supported by the compiler we define
+ * @c CSTD_FUNC as an empty string.
+ *
+ * @warning Due to the implementation of this on most modern compilers this
+ * expands to a magically defined "static const" variable, not a constant
+ * string. This makes injecting @c CSTD_FUNC directly in to compile-time
+ * strings impossible, so if you want to make the function name part of a
+ * larger string you must use a printf-like function with a @c @%s template
+ * which is populated with @c CSTD_FUNC
+ */
+#define CSTD_FUNC __FUNCTION__
+
+/**
+ * @}
+ */
+
+#endif /* End (_ARM_CSTD_TYPES_RVCT_H_) */
diff --git a/drivers/gpu/arm/t6xx/kbase/malisw/mali_malisw.h b/drivers/gpu/arm/t6xx/kbase/malisw/mali_malisw.h
new file mode 100644
index 0000000..cefaef2
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/malisw/mali_malisw.h
@@ -0,0 +1,237 @@
+/*
+ *
+ * (C) COPYRIGHT 2010-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+#ifndef _MALISW_H_
+#define _MALISW_H_
+
+#define MALI_MODULE_MALISW_MAJOR 2
+#define MALI_MODULE_MALISW_MINOR 4
+
+/**
+ * @file mali_malisw.h
+ * Driver-wide include for common macros and types.
+ */
+
+/**
+ * @defgroup malisw Mali software definitions and types
+ * @{
+ */
+
+#include <stddef.h>
+
+#include "mali_stdtypes.h"
+#include "mali_version_macros.h"
+
+/** @brief Gets the container object when given a pointer to a member of an object. */
+#define CONTAINER_OF(ptr, type, member) ((type *)((char *)(ptr) - offsetof(type,member)))
+
+/** @brief Gets the number of elements of type s in a fixed length array of s */
+#define NELEMS(s) (sizeof(s)/sizeof((s)[0]))
+
+/**
+ * @brief The lesser of two values.
+ * May evaluate its arguments more than once.
+ * @see CSTD_MIN
+ */
+#define MIN(x,y) CSTD_MIN(x,y)
+
+/**
+ * @brief The greater of two values.
+ * May evaluate its arguments more than once.
+ * @see CSTD_MAX
+ */
+#define MAX(x,y) CSTD_MAX(x,y)
+
+/**
+ * @brief Clamp value x to within min and max inclusive
+ * May evaluate its arguments more than once.
+ * @see CSTD_CLAMP
+ */
+#define CLAMP( x, min, max ) CSTD_CLAMP( x, min, max )
+
+/**
+ * @brief Convert a pointer into a u64 for storing in a data structure.
+ * This is commonly used when pairing a 32-bit CPU with a 64-bit peripheral,
+ * such as a Midgard GPU. C's type promotion is complex and a straight cast
+ * does not work reliably as pointers are often considered as signed.
+ */
+#define PTR_TO_U64( x ) CSTD_PTR_TO_U64( x )
+
+/**
+ * @name Mali library linkage specifiers
+ * These directly map to the cstd versions described in detail here: @ref arm_cstd_linkage_specifiers
+ * @{
+ */
+#define MALI_IMPORT CSTD_LINK_IMPORT
+#define MALI_EXPORT CSTD_LINK_EXPORT
+#define MALI_IMPL CSTD_LINK_IMPL
+#define MALI_LOCAL CSTD_LINK_LOCAL
+
+/** @brief Decorate exported function prototypes.
+ *
+ * The file containing the implementation of the function should define this to be MALI_EXPORT before including
+ * malisw/mali_malisw.h.
+ */
+#ifndef MALI_API
+#define MALI_API MALI_IMPORT
+#endif
+/** @} */
+
+/** @name Testable static functions
+ * @{
+ *
+ * These macros can be used to allow functions to be static in release builds but exported from a shared library in unit
+ * test builds, allowing them to be tested or used to assist testing.
+ *
+ * Example mali_foo_bar.c containing the function to test:
+ *
+ * @code
+ * #define MALI_API MALI_EXPORT
+ *
+ * #include <malisw/mali_malisw.h>
+ * #include "mali_foo_testable_statics.h"
+ *
+ * MALI_TESTABLE_STATIC_IMPL void my_func()
+ * {
+ * //Implementation
+ * }
+ * @endcode
+ *
+ * Example mali_foo_testable_statics.h:
+ *
+ * @code
+ * #if 1 == MALI_UNIT_TEST
+ * #include <malisw/mali_malisw.h>
+ *
+ * MALI_TESTABLE_STATIC_API void my_func();
+ *
+ * #endif
+ * @endcode
+ *
+ * Example mali_foo_tests.c:
+ *
+ * @code
+ * #include <foo/src/mali_foo_testable_statics.h>
+ *
+ * void my_test_func()
+ * {
+ * my_func();
+ * }
+ * @endcode
+ */
+
+/** @brief Decorate testable static function implementations.
+ *
+ * A header file containing a MALI_TESTABLE_STATIC_API-decorated prototype for each static function will be required
+ * when MALI_UNIT_TEST == 1 in order to link the function from the test.
+ */
+#if 1 == MALI_UNIT_TEST
+#define MALI_TESTABLE_STATIC_IMPL MALI_IMPL
+#else
+#define MALI_TESTABLE_STATIC_IMPL static
+#endif
+
+/** @brief Decorate testable static function prototypes.
+ *
+ * @note Prototypes should @em only be declared when MALI_UNIT_TEST == 1
+ */
+#define MALI_TESTABLE_STATIC_API MALI_API
+/** @} */
+
+/** @name Testable local functions
+ * @{
+ *
+ * These macros can be used to allow functions to be local to a shared library in release builds but be exported in unit
+ * test builds, allowing them to be tested or used to assist testing.
+ *
+ * Example mali_foo_bar.c containing the function to test:
+ *
+ * @code
+ * #define MALI_API MALI_EXPORT
+ *
+ * #include <malisw/mali_malisw.h>
+ * #include "mali_foo_bar.h"
+ *
+ * MALI_TESTABLE_LOCAL_IMPL void my_func()
+ * {
+ * //Implementation
+ * }
+ * @endcode
+ *
+ * Example mali_foo_bar.h:
+ *
+ * @code
+ * #include <malisw/mali_malisw.h>
+ *
+ * MALI_TESTABLE_LOCAL_API void my_func();
+ *
+ * @endcode
+ *
+ * Example mali_foo_tests.c:
+ *
+ * @code
+ * #include <foo/src/mali_foo_bar.h>
+ *
+ * void my_test_func()
+ * {
+ * my_func();
+ * }
+ * @endcode
+ */
+
+/** @brief Decorate testable local function implementations.
+ *
+ * This can be used to have a function normally local to the shared library except in debug builds where it will be
+ * exported.
+ */
+#ifdef CONFIG_MALI_DEBUG
+#define MALI_TESTABLE_LOCAL_IMPL MALI_IMPL
+#else
+#define MALI_TESTABLE_LOCAL_IMPL MALI_LOCAL
+#endif /* CONFIG_MALI_DEBUG */
+
+/** @brief Decorate testable local function prototypes.
+ *
+ * This can be used to have a function normally local to the shared library except in debug builds where it will be
+ * exported.
+ */
+#ifdef CONFIG_MALI_DEBUG
+#define MALI_TESTABLE_LOCAL_API MALI_API
+#else
+#define MALI_TESTABLE_LOCAL_API MALI_LOCAL
+#endif /* CONFIG_MALI_DEBUG */
+/** @} */
+
+/**
+ * Flag a cast as a reinterpretation, usually of a pointer type.
+ * @see CSTD_REINTERPRET_CAST
+ */
+#define REINTERPRET_CAST(type) CSTD_REINTERPRET_CAST(type)
+
+/**
+ * Flag a cast as casting away const, usually of a pointer type.
+ * @see CSTD_CONST_CAST
+ */
+#define CONST_CAST(type) (type) CSTD_CONST_CAST(type)
+
+/**
+ * Flag a cast as a (potentially complex) value conversion, usually of a numerical type.
+ * @see CSTD_STATIC_CAST
+ */
+#define STATIC_CAST(type) (type) CSTD_STATIC_CAST(type)
+
+
+/** @} */
+
+#endif /* _MALISW_H_ */
diff --git a/drivers/gpu/arm/t6xx/kbase/malisw/mali_stdtypes.h b/drivers/gpu/arm/t6xx/kbase/malisw/mali_stdtypes.h
new file mode 100644
index 0000000..437794b
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/malisw/mali_stdtypes.h
@@ -0,0 +1,210 @@
+/*
+ *
+ * (C) COPYRIGHT 2010-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+#ifndef _MALISW_STDTYPES_H_
+#define _MALISW_STDTYPES_H_
+
+/**
+ * @file mali_stdtypes.h
+ * This file defines the standard types used by the Mali codebase.
+ */
+
+/**
+ * @addtogroup malisw
+ * @{
+ */
+
+/**
+ * @defgroup malisw_stdtypes Mali software standard types
+ *
+ * Basic driver-wide types.
+ */
+
+/**
+ * @addtogroup malisw_stdtypes
+ * @{
+ */
+
+#include "arm_cstd/arm_cstd.h"
+
+/**
+ * @name Scalar types.
+ * These are the scalar types used within the mali driver.
+ * @{
+ */
+/* Note: if compiling the Linux kernel then avoid redefining these. */
+#if 0 == CSTD_OS_LINUX_KERNEL
+ typedef uint64_t u64;
+ typedef uint32_t u32;
+ typedef uint16_t u16;
+ typedef uint8_t u8;
+
+ typedef int64_t s64;
+ typedef int32_t s32;
+ typedef int16_t s16;
+ typedef int8_t s8;
+#endif
+
+typedef double f64;
+typedef float f32;
+typedef u16 f16;
+
+typedef u32 mali_fixed16_16;
+/* @} */
+
+/**
+ * @name Boolean types.
+ * The intended use is for bool8 to be used when storing boolean values in
+ * structures, casting to mali_bool to be used in code sections.
+ * @{
+ */
+typedef bool_t mali_bool;
+typedef u8 mali_bool8;
+
+#define MALI_FALSE FALSE
+#define MALI_TRUE TRUE
+/* @} */
+
+/**
+ * @name Integer bounding values
+ * Maximum and minimum values for integer types
+ * @{
+ */
+#define U64_MAX UINT64_MAX
+#define U32_MAX UINT32_MAX
+#define U16_MAX UINT16_MAX
+#define U8_MAX UINT8_MAX
+
+#define S64_MAX INT64_MAX
+#define S64_MIN INT64_MIN
+#define S32_MAX INT32_MAX
+#define S32_MIN INT32_MIN
+#define S16_MAX INT16_MAX
+#define S16_MIN INT16_MIN
+#define S8_MAX INT8_MAX
+#define S8_MIN INT8_MIN
+/* @} */
+
+/**
+ * @name GPU address types
+ * Types for integers which hold a GPU pointer or GPU pointer offsets.
+ * @{
+ */
+typedef u64 mali_addr64;
+typedef u32 mali_addr32;
+typedef u64 mali_size64;
+typedef s64 mali_offset64;
+/* 32 bit offsets and sizes are always for native types and so use ptrdiff_t and size_t respectively */
+/* @} */
+
+/**
+ * @name Mali error types
+ * @brief The common error type for the mali drivers
+ * The mali_error type, all driver error handling should be of this type unless
+ * it must deal with a specific APIs error type.
+ * @{
+ */
+typedef enum
+{
+ /**
+ * @brief Common Mali errors for the entire driver
+ * MALI_ERROR_NONE is guaranteed to be 0.
+ * @{
+ */
+ MALI_ERROR_NONE = 0,
+ MALI_ERROR_OUT_OF_GPU_MEMORY,
+ MALI_ERROR_OUT_OF_MEMORY,
+ MALI_ERROR_FUNCTION_FAILED,
+ /* @} */
+ /**
+ * @brief Mali errors for Client APIs to pass to EGL when creating EGLImages
+ * These errors must only be returned to EGL from one of the Client APIs as part of the
+ * (clientapi)_egl_image_interface.h
+ * @{
+ */
+ MALI_ERROR_EGLP_BAD_ACCESS,
+ MALI_ERROR_EGLP_BAD_PARAMETER,
+ /* @} */
+ /**
+ * @brief Mali errors for the MCL module.
+ * These errors must only be used within the private components of the OpenCL implementation that report
+ * directly to API functions for cases where errors cannot be detected in the entrypoints file. They must
+ * not be passed between driver components.
+ * These are errors in the mali error space specifically for the MCL module, hence the MCLP prefix.
+ * @{
+ */
+ MALI_ERROR_MCLP_DEVICE_NOT_FOUND,
+ MALI_ERROR_MCLP_DEVICE_NOT_AVAILABLE,
+ MALI_ERROR_MCLP_COMPILER_NOT_AVAILABLE,
+ MALI_ERROR_MCLP_MEM_OBJECT_ALLOCATION_FAILURE,
+ MALI_ERROR_MCLP_PROFILING_INFO_NOT_AVAILABLE,
+ MALI_ERROR_MCLP_MEM_COPY_OVERLAP,
+ MALI_ERROR_MCLP_IMAGE_FORMAT_MISMATCH,
+ MALI_ERROR_MCLP_IMAGE_FORMAT_NOT_SUPPORTED,
+ MALI_ERROR_MCLP_BUILD_PROGRAM_FAILURE,
+ MALI_ERROR_MCLP_MAP_FAILURE,
+ MALI_ERROR_MCLP_MISALIGNED_SUB_BUFFER_OFFSET,
+ MALI_ERROR_MCLP_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST,
+ MALI_ERROR_MCLP_INVALID_VALUE,
+ MALI_ERROR_MCLP_INVALID_DEVICE_TYPE,
+ MALI_ERROR_MCLP_INVALID_PLATFORM,
+ MALI_ERROR_MCLP_INVALID_DEVICE,
+ MALI_ERROR_MCLP_INVALID_CONTEXT,
+ MALI_ERROR_MCLP_INVALID_QUEUE_PROPERTIES,
+ MALI_ERROR_MCLP_INVALID_COMMAND_QUEUE,
+ MALI_ERROR_MCLP_INVALID_HOST_PTR,
+ MALI_ERROR_MCLP_INVALID_MEM_OBJECT,
+ MALI_ERROR_MCLP_INVALID_IMAGE_FORMAT_DESCRIPTOR,
+ MALI_ERROR_MCLP_INVALID_IMAGE_SIZE,
+ MALI_ERROR_MCLP_INVALID_SAMPLER,
+ MALI_ERROR_MCLP_INVALID_BINARY,
+ MALI_ERROR_MCLP_INVALID_BUILD_OPTIONS,
+ MALI_ERROR_MCLP_INVALID_PROGRAM,
+ MALI_ERROR_MCLP_INVALID_PROGRAM_EXECUTABLE,
+ MALI_ERROR_MCLP_INVALID_KERNEL_NAME,
+ MALI_ERROR_MCLP_INVALID_KERNEL_DEFINITION,
+ MALI_ERROR_MCLP_INVALID_KERNEL,
+ MALI_ERROR_MCLP_INVALID_ARG_INDEX,
+ MALI_ERROR_MCLP_INVALID_ARG_VALUE,
+ MALI_ERROR_MCLP_INVALID_ARG_SIZE,
+ MALI_ERROR_MCLP_INVALID_KERNEL_ARGS,
+ MALI_ERROR_MCLP_INVALID_WORK_DIMENSION,
+ MALI_ERROR_MCLP_INVALID_WORK_GROUP_SIZE,
+ MALI_ERROR_MCLP_INVALID_WORK_ITEM_SIZE,
+ MALI_ERROR_MCLP_INVALID_GLOBAL_OFFSET,
+ MALI_ERROR_MCLP_INVALID_EVENT_WAIT_LIST,
+ MALI_ERROR_MCLP_INVALID_EVENT,
+ MALI_ERROR_MCLP_INVALID_OPERATION,
+ MALI_ERROR_MCLP_INVALID_GL_OBJECT,
+ MALI_ERROR_MCLP_INVALID_BUFFER_SIZE,
+ MALI_ERROR_MCLP_INVALID_MIP_LEVEL,
+ MALI_ERROR_MCLP_INVALID_GLOBAL_WORK_SIZE,
+ /* @} */
+ /**
+ * @brief Mali errors for the BASE module
+ * These errors must only be used within the private components of the Base implementation. They will not
+ * passed to other modules by the base driver.
+ * These are errors in the mali error space specifically for the BASE module, hence the BASEP prefix.
+ * @{
+ */
+ MALI_ERROR_BASEP_INVALID_FUNCTION
+ /* @} */
+} mali_error;
+/* @} */
+
+/* @} */
+
+/* @} */
+
+#endif /* _MALISW_STDTYPES_H_ */
diff --git a/drivers/gpu/arm/t6xx/kbase/malisw/mali_version_macros.h b/drivers/gpu/arm/t6xx/kbase/malisw/mali_version_macros.h
new file mode 100644
index 0000000..605833c
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/malisw/mali_version_macros.h
@@ -0,0 +1,243 @@
+/*
+ *
+ * (C) COPYRIGHT 2010-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+#ifndef _MALISW_VERSION_MACROS_H_
+#define _MALISW_VERSION_MACROS_H_
+
+/**
+ * @file mali_version_macros.h
+ * Mali version control macros.
+ */
+
+/**
+ * @addtogroup malisw
+ * @{
+ */
+
+/**
+ * @defgroup malisw_version Mali module version control
+ *
+ * This file provides a set of macros used to check a module's version. This
+ * version information can be used to perform compile time checks of a module's
+ * suitability for use with another.
+ *
+ * Module versions have both a Major and Minor value which specify the version
+ * of the interface only. These are defined in the following way:
+ *
+ * @li Major: This version is incremented whenever a compatibility-breaking
+ * change is made. For example, removing an interface function.
+ * @li Minor: This version is incremented whenever an interface change is made
+ * that does not break compatibility. For example, adding a new function to the
+ * interface. This value is reset to zero whenever the major number is
+ * incremented.
+ *
+ * When providing a driver module that will be used with this system, the public
+ * header must include a major and minor define of the following form:
+ *
+ * @code
+ * #define MALI_MODULE_<module>_MAJOR X
+ * #define MALI_MODULE_<module>_MINOR Y
+ * @endcode
+ * e.g. for a module CZAM with include czam/mali_czam.h
+ * @code
+ *
+ * #define MALI_MODULE_CZAM_MAJOR 1
+ * #define MALI_MODULE_CZAM_MINOR 0
+ * @endcode
+ *
+ * The version assertion macros outlined below are wrapped with a static function.
+ * This provides more useful error messages when the assertions fail, and allows
+ * the assertions to be specified adjacent to the inclusion of the module header.
+ *
+ * These macros should be used in the global scope of the file. Normal use would be:
+ *
+ * @code
+ * #include <modulex/mali_modulex.h>
+ * #include <moduley/mali_moduley.h>
+ * #include <modulez/mali_modulez.h>
+ * #include <modulez/mali_modulew.h>
+ *
+ * // This module added an enum we needed on minor 4 of major release 2
+ * MALI_MODULE_ASSERT_MAJOR_EQUALS_MINOR_AT_LEAST( MODULEW, 2, 4 )
+ *
+ * // this module really needs to be a specific version
+ * MALI_MODULE_ASSERT_EQUALS( MODULEX, 2, 0 )
+ *
+ * // 1.4 has performance problems
+ * MALI_MODULE_ASSERT_MAXIMUM( MODULEY, 1, 3 )
+ *
+ * // Major defines a backward compatible series of versions
+ * MALI_MODULE_ASSERT_MAJOR_EQUALS( MODULEZ, 1 )
+ * @endcode
+ *
+ * @par Version Assertions
+ *
+ * This module provides the following compile time version assertion macros.
+ *
+ * @li #MALI_MODULE_ASSERT_MAJOR_EQUALS_MINOR_AT_LEAST
+ * @li #MALI_MODULE_ASSERT_MAJOR_EQUALS
+ * @li #MALI_MODULE_ASSERT_EQUALS
+ * @li #MALI_MODULE_ASSERT_MINIMUM
+ * @li #MALI_MODULE_ASSERT_MAXIMUM
+ *
+ * @par Limitations
+ *
+ * To allow the macros to be placed in the global scope and report more readable
+ * errors, they produce a static function. This makes them unsuitable for use
+ * within headers as the names are only unique on the name of the module under test,
+ * the line number of the current file, and assert type (min, max, equals, ...).
+ */
+
+/**
+ * @addtogroup malisw_version
+ * @{
+ */
+
+#include "arm_cstd/arm_cstd.h"
+
+/**
+ * Private helper macro, indirection so that __LINE__ resolves correctly.
+ */
+#define MALIP_MODULE_ASSERT_FUNCTION_SIGNATURE2( module, type, line ) \
+ static INLINE void _mali_module_##module##_version_check_##type##_##line(void)
+
+#define MALIP_MODULE_ASSERT_FUNCTION_SIGNATURE( module, type, line ) \
+ MALIP_MODULE_ASSERT_FUNCTION_SIGNATURE2( module, type, line )
+
+/**
+ * @hideinitializer
+ * This macro provides a compile time assert that a module interface that has been
+ * @#included in the source base has is greater than or equal to the version specified.
+ *
+ * Expected use is for cases where a module version before the requested minimum
+ * does not support a specific function or is missing an enum affecting the code that is
+ * importing the module.
+ *
+ * It should be invoked at the global scope and ideally following straight after
+ * the module header has been included. For example:
+ *
+ * @code
+ * #include <modulex/mali_modulex.h>
+ *
+ * MALI_MODULE_ASSERT_MINIMUM( MODULEX, 1, 3 )
+ * @endcode
+ */
+#define MALI_MODULE_ASSERT_MINIMUM( module, major, minor ) \
+ MALIP_MODULE_ASSERT_FUNCTION_SIGNATURE( module, minimum, __LINE__ ) \
+ { \
+ CSTD_COMPILE_TIME_ASSERT( ( ( MALI_MODULE_##module##_MAJOR << 16 ) | MALI_MODULE_##module##_MINOR ) \
+ >= ( ( (major) << 16 ) | (minor) ) ); \
+ }
+
+/**
+ * @hideinitializer
+ * This macro provides a compile time assert that a module interface that has been
+ * @#included in the source base is less than or equal to the version specified.
+ *
+ * Expected use is for cases where a later published minor version is found to be
+ * incompatible in some way after the new minor has been issued.
+ *
+ * It should be invoked at the global scope and ideally following straight after
+ * the module header has been included. For example:
+ *
+ * @code
+ * #include <modulex/mali_modulex.h>
+ *
+ * MALI_MODULE_ASSERT_MAXIMUM( MODULEX, 1, 3 )
+ * @endcode
+ */
+#define MALI_MODULE_ASSERT_MAXIMUM( module, major, minor ) \
+ MALIP_MODULE_ASSERT_FUNCTION_SIGNATURE( module, maximum, __LINE__ ) \
+ { \
+ CSTD_COMPILE_TIME_ASSERT( ( ( MALI_MODULE_##module##_MAJOR << 16 ) | MALI_MODULE_##module##_MINOR ) \
+ <= ( ( (major) << 16 ) | (minor) ) ); \
+ }
+
+/**
+ * @hideinitializer
+ * This macro provides a compile time assert that a module interface that has been
+ * @#included in the source base is equal to the version specified.
+ *
+ * Expected use is for cases where a specific version is known to work and other
+ * versions are considered to be risky.
+ *
+ * It should be invoked at the global scope and ideally following straight after
+ * the module header has been included. For example:
+ *
+ * @code
+ * #include <modulex/mali_modulex.h>
+ *
+ * MALI_MODULE_ASSERT_EQUALS( MODULEX, 1, 3 )
+ * @endcode
+ */
+#define MALI_MODULE_ASSERT_EQUALS( module, major, minor ) \
+ MALIP_MODULE_ASSERT_FUNCTION_SIGNATURE( module, equals, __LINE__ ) \
+ { \
+ CSTD_COMPILE_TIME_ASSERT( MALI_MODULE_##module##_MAJOR == major ); \
+ CSTD_COMPILE_TIME_ASSERT( MALI_MODULE_##module##_MINOR == minor ); \
+ }
+
+/**
+ * @hideinitializer
+ * This macro provides a compile time assert that a module interface that has been
+ * @#included in the source base has a major version equal to the major version specified.
+ *
+ * Expected use is for cases where a module is considered low risk and any minor changes
+ * are not considered to be important.
+ *
+ * It should be invoked at the global scope and ideally following straight after
+ * the module header has been included. For example:
+ *
+ * @code
+ * #include <modulex/mali_modulex.h>
+ *
+ * MALI_MODULE_ASSERT_MAJOR_EQUALS( MODULEX, 1, 3 )
+ * @endcode
+ */
+#define MALI_MODULE_ASSERT_MAJOR_EQUALS( module, major ) \
+ MALIP_MODULE_ASSERT_FUNCTION_SIGNATURE( module, major_equals, __LINE__ ) \
+ { \
+ CSTD_COMPILE_TIME_ASSERT( MALI_MODULE_##module##_MAJOR == major ); \
+ }
+
+/**
+ * @hideinitializer
+ * This macro provides a compile time assert that a module interface that has been
+ * @#included in the source base has a major version equal to the major version specified
+ * and that the minor version is at least that which is specified.
+ *
+ * Expected use is for cases where a major revision is suitable from a specific minor
+ * revision but future major versions are a risk.
+ *
+ * It should be invoked at the global scope and ideally following straight after
+ * the module header has been included. For example:
+ *
+ * @code
+ * #include <modulex/mali_modulex.h>
+ *
+ * MALI_MODULE_ASSERT_MAJOR_EQUALS_MINOR_AT_LEAST( MODULEX, 1, 3 )
+ * @endcode
+ */
+#define MALI_MODULE_ASSERT_MAJOR_EQUALS_MINOR_AT_LEAST( module, major, minor ) \
+ MALIP_MODULE_ASSERT_FUNCTION_SIGNATURE( module, major_equals_minor_at_least, __LINE__ ) \
+ { \
+ CSTD_COMPILE_TIME_ASSERT( MALI_MODULE_##module##_MAJOR == major ); \
+ CSTD_COMPILE_TIME_ASSERT( MALI_MODULE_##module##_MINOR >= minor ); \
+ }
+
+/* @} */
+
+/* @} */
+
+#endif /* _MALISW_VERSION_MACROS_H_ */
diff --git a/drivers/gpu/arm/t6xx/kbase/osk/include/mali_osk_atomics.h b/drivers/gpu/arm/t6xx/kbase/osk/include/mali_osk_atomics.h
new file mode 100644
index 0000000..960abff
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/osk/include/mali_osk_atomics.h
@@ -0,0 +1,212 @@
+/*
+ *
+ * (C) COPYRIGHT 2008-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_osk_atomics.h
+ * Implementation of the OS abstraction layer for the kernel device driver
+ */
+
+#ifndef _OSK_ATOMICS_H_
+#define _OSK_ATOMICS_H_
+
+#ifndef _OSK_H_
+#error "Include mali_osk.h directly"
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+ * @addtogroup base_api
+ * @{
+ */
+
+/**
+ * @addtogroup base_osk_api
+ * @{
+ */
+
+/**
+ * @defgroup oskatomic Atomic Access
+ *
+ * @anchor oskatomic_important
+ * @par Important Information on Atomic variables
+ *
+ * Atomic variables are objects that can be modified by only one thread at a time.
+ * For use in SMP systems, strongly ordered access is enforced using memory
+ * barriers.
+ *
+ * An atomic variable implements an unsigned integer counter which is exactly
+ * 32 bits long. Arithmetic on it is the same as on u32 values, which is the
+ * arithmetic of integers modulo 2^32. For example, incrementing past
+ * 0xFFFFFFFF rolls over to 0, decrementing past 0 rolls over to
+ * 0xFFFFFFFF. That is, overflow is a well defined condition (unlike signed
+ * integer arithmetic in C).
+ */
+/** @{ */
+
+/** @brief Subtract a value from an atomic variable and return the new value.
+ *
+ * It is a programming error to pass an invalid pointer (including NULL)
+ * through the \a atom parameter.
+ *
+ * @note Please refer to @see oskatomic_important Important Information on Atomic
+ * variables.
+ *
+ * @param atom pointer to an atomic variable
+ * @param value value to subtract from \a atom
+ * @return value of atomic variable after \a value has been subtracted from it.
+ */
+OSK_STATIC_INLINE u32 osk_atomic_sub(osk_atomic *atom, u32 value);
+
+/** @brief Add a value to an atomic variable and return the new value.
+ *
+ * It is a programming error to pass an invalid pointer (including NULL)
+ * through the \a atom parameter.
+ *
+ * @note Please refer to @see oskatomic_important Important Information on Atomic
+ * variables.
+ *
+ * @param atom pointer to an atomic variable
+ * @param value value to add to \a atom
+ * @return value of atomic variable after \a value has been added to it.
+ */
+OSK_STATIC_INLINE u32 osk_atomic_add(osk_atomic *atom, u32 value);
+
+/** @brief Decrement an atomic variable and return its decremented value.
+ *
+ * It is a programming error to pass an invalid pointer (including NULL)
+ * through the \a atom parameter.
+ *
+ * @note Please refer to @see oskatomic_important Important Information on Atomic
+ * variables.
+ *
+ * @param atom pointer to an atomic variable
+ * @return decremented value of atomic variable
+ */
+OSK_STATIC_INLINE u32 osk_atomic_dec(osk_atomic *atom);
+
+/** @brief Increment an atomic variable and return its incremented value.
+ *
+ * It is a programming error to pass an invalid pointer (including NULL)
+ * through the \a atom parameter.
+ *
+ * @note Please refer to @see oskatomic_important Important Information on Atomic
+ * variables.
+ *
+ * @param atom pointer to an atomic variable
+ * @return incremented value of atomic variable
+ */
+OSK_STATIC_INLINE u32 osk_atomic_inc(osk_atomic *atom);
+
+/** @brief Sets the value of an atomic variable.
+ *
+ * Note: if the value of the atomic variable is set as part of a read-modify-write
+ * operation and multiple threads have access to the atomic variable at that time,
+ * please use osk_atomic_compare_and_swap() instead, which can ensure no other
+ * process changed the atomic variable during the read-write-modify operation.
+ *
+ * It is a programming error to pass an invalid pointer (including NULL)
+ * through the \a atom parameter.
+ *
+ * @note Please refer to @see oskatomic_important Important Information on Atomic
+ * variables.
+ *
+ * @param atom pointer to an atomic variable
+ * @param value the value to set
+ */
+OSK_STATIC_INLINE void osk_atomic_set(osk_atomic *atom, u32 value);
+
+/** @brief Return the value of an atomic variable.
+ *
+ * It is a programming error to pass an invalid pointer (including NULL)
+ * through the \a atom parameter.
+ *
+ * @note Please refer to @see oskatomic_important Important Information on Atomic
+ * variables.
+ *
+ * @param atom pointer to an atomic variable
+ * @return value of the atomic variable
+ */
+OSK_STATIC_INLINE u32 osk_atomic_get(osk_atomic *atom);
+
+/** @brief Compare the value of an atomic variable, and atomically exchange it
+ * if the comparison succeeds.
+ *
+ * This function implements the Atomic Compare-And-Swap operation (CAS) which
+ * allows atomically performing a read-modify-write operation on atomic variables.
+ * The CAS operation is suited for implementing synchronization primitives such
+ * as semaphores and mutexes, as well as lock-free and wait-free algorithms.
+ *
+ * It atomically does the following: compare \a atom with \a old_value and sets \a
+ * atom to \a new_value if the comparison was true.
+ *
+ * Regardless of the outcome of the comparison, the initial value of \a atom is
+ * returned - hence the reason for this being a 'swap' operation. If the value
+ * returned is equal to \a old_value, then the atomic operation succeeded. Any
+ * other value shows that the atomic operation failed, and should be repeated
+ * based upon the returned value.
+ *
+ * For example:
+@code
+typedef struct my_data
+{
+ osk_atomic index;
+ object objects[10];
+} data;
+u32 index, old_index, new_index;
+
+// Updates the index into an array of objects based on the current indexed object.
+// If another process updated the index in the mean time, the index will not be
+// updated and we try again based on the updated index.
+
+index = osk_atomic_get(&data.index);
+do {
+ old_index = index;
+ new_index = calc_new_index(&data.objects[old_index]);
+ index = osk_atomic_compare_and_swap(&data.index, old_index, new_index)
+} while (index != old_index);
+
+@endcode
+ *
+ * It is a programming error to pass an invalid pointer (including NULL)
+ * through the \a atom parameter.
+ *
+ * @note Please refer to @see oskatomic_important Important Information on Atomic
+ * variables.
+ *
+ * @param atom pointer to an atomic variable
+ * @param old_value The value to make the comparison with \a atom
+ * @param new_value The value to atomically write to atom, depending on whether
+ * the comparison succeeded.
+ * @return The \em initial value of \a atom, before the operation commenced.
+ */
+OSK_STATIC_INLINE u32 osk_atomic_compare_and_swap(osk_atomic * atom, u32 old_value, u32 new_value) CHECK_RESULT;
+
+/** @} */ /* end group oskatomic */
+
+/** @} */ /* end group base_osk_api */
+
+/** @} */ /* end group base_api */
+
+/* pull in the arch header with the implementation */
+#include <osk/mali_osk_arch_atomics.h>
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _OSK_ATOMICS_H_ */
diff --git a/drivers/gpu/arm/t6xx/kbase/osk/include/mali_osk_bitops.h b/drivers/gpu/arm/t6xx/kbase/osk/include/mali_osk_bitops.h
new file mode 100644
index 0000000..696799b
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/osk/include/mali_osk_bitops.h
@@ -0,0 +1,235 @@
+/*
+ *
+ * (C) COPYRIGHT 2008-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_osk_bitops.h
+ * Implementation of the OS abstraction layer for the kernel device driver
+ */
+
+#ifndef _OSK_BITOPS_H_
+#define _OSK_BITOPS_H_
+
+#ifndef _OSK_H_
+#error "Include mali_osk.h directly"
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <osk/mali_osk_arch_bitops.h>
+
+/**
+ * @addtogroup base_api
+ * @{
+ */
+
+/**
+ * @addtogroup base_osk_api
+ * @{
+ */
+
+/** @defgroup oskbitops Bit-operations
+ *
+ * These bit-operations do not work atomically, and so locks must be used if
+ * atomicity is required.
+ *
+ * Reference implementations for Little Endian are provided, and so it should
+ * not normally be necessary to re-implement these. Efficient bit-twiddling
+ * techniques are used where possible, implemented in portable C.
+ *
+ * Note that these reference implementations rely on osk_clz() being
+ * implemented.
+ *
+ * @{
+ */
+
+/**
+ * @brief Tests if a bit is set in a unsigned long value (internal function)
+ * @param[in] bit bit number to test [0..OSK_BITS_PER_LONG-1], starting from the (Little-endian) least significant bit
+ * @param[in] value unsigned long value
+ * @return zero if bit was clear, non-zero if set. Do not rely on the return
+ * value being related to the actual word under test.
+ */
+OSK_STATIC_INLINE unsigned long oskp_test_bit(unsigned long bit, unsigned long value)
+{
+ OSK_ASSERT( bit < OSK_BITS_PER_LONG );
+
+ return value & (1UL << bit);
+}
+
+/**
+ * @brief Find the first zero bit in a unsigned long value
+ * @param[in] value unsigned long value
+ * @return a postive number [0..OSK_BITS_PER_LONG-1], starting from the least significant bit,
+ * indicating the first zero bit found, or a negative number if no zero bit was found.
+ */
+CHECK_RESULT OSK_STATIC_INLINE long oskp_find_first_zero_bit(unsigned long value)
+{
+ unsigned long inverted;
+ unsigned long negated;
+ unsigned long isolated;
+ unsigned long leading_zeros;
+
+ /* Begin with xxx...x0yyy...y, where ys are 1, number of ys is in range 0..31/63 */
+ inverted = ~value; /* zzz...z1000...0 */
+ /* Using count_trailing_zeros on inverted value -
+ * See ARM System Developers Guide for details of count_trailing_zeros */
+
+ /* Isolate the zero: it is preceeded by a run of 1s, so add 1 to it */
+ negated = (unsigned long)-inverted ; /* -a == ~a + 1 (mod 2^n) for n-bit numbers */
+ /* negated = xxx...x1000...0 */
+
+ isolated = negated & inverted ; /* xxx...x1000...0 & zzz...z1000...0, zs are ~xs */
+ /* And so the first zero bit is in the same position as the 1 == number of 1s that preceeded it
+ * Note that the output is zero if value was all 1s */
+
+ leading_zeros = osk_clz( isolated );
+
+ return (OSK_BITS_PER_LONG - 1) - leading_zeros;
+}
+
+/**
+ * @brief Clear a bit in a sequence of unsigned longs
+ * @param[in] nr bit number to clear, starting from the (Little-endian) least
+ * significant bit
+ * @param[in,out] addr starting point for counting.
+ */
+OSK_STATIC_INLINE void osk_bitarray_clear_bit(unsigned long nr, unsigned long *addr )
+{
+ OSK_ASSERT(NULL != addr);
+ addr += nr / OSK_BITS_PER_LONG; /* find the correct word */
+ nr = nr & (OSK_BITS_PER_LONG - 1); /* The bit number within the word */
+ *addr &= ~(1UL << nr);
+}
+
+/**
+ * @brief Set a bit in a sequence of unsigned longs
+ * @param[in] nr bit number to set, starting from the (Little-endian) least
+ * significant bit
+ * @param[in,out] addr starting point for counting.
+ */
+OSK_STATIC_INLINE void osk_bitarray_set_bit(unsigned long nr, unsigned long *addr)
+{
+ OSK_ASSERT(NULL != addr);
+ addr += nr / OSK_BITS_PER_LONG; /* find the correct word */
+ nr = nr & (OSK_BITS_PER_LONG - 1); /* The bit number within the word */
+ *addr |= (1UL << nr);
+}
+
+/**
+ * @brief Test a bit in a sequence of unsigned longs
+ * @param[in] nr bit number to test, starting from the (Little-endian) least
+ * significant bit
+ * @param[in,out] addr starting point for counting.
+ * @return zero if bit was clear, non-zero if set. Do not rely on the return
+ * value being related to the actual word under test.
+ */
+CHECK_RESULT OSK_STATIC_INLINE unsigned long osk_bitarray_test_bit(unsigned long nr, unsigned long *addr)
+{
+ OSK_ASSERT(NULL != addr);
+ addr += nr / OSK_BITS_PER_LONG; /* find the correct word */
+ nr = nr & (OSK_BITS_PER_LONG - 1); /* The bit number within the word */
+ return *addr & (1UL << nr);
+}
+
+/**
+ * @brief Find the first zero bit in a sequence of unsigned longs
+ * @param[in] addr starting point for search.
+ * @param[in] maxbit the maximum number of bits to search
+ * @return the number of the first zero bit found, or maxbit if none were found
+ * in the specified range.
+ */
+CHECK_RESULT unsigned long osk_bitarray_find_first_zero_bit(const unsigned long *addr, unsigned long maxbit);
+
+/**
+ * @brief Find the first set bit in a unsigned long
+ * @param val value to find first set bit in
+ * @return the number of the set bit found (starting from 0), -1 if no bits set
+ */
+CHECK_RESULT OSK_STATIC_INLINE long osk_find_first_set_bit(unsigned long val)
+{
+ return (OSK_BITS_PER_LONG - 1) - osk_clz( val & -val );
+}
+
+/**
+ * @brief Count leading zeros in an unsigned long
+ *
+ * Same behavior as ARM CLZ instruction.
+ *
+ * Returns the number of binary zero bits before the first (most significant)
+ * binary one bit in \a val.
+ *
+ * If \a val is zero, this function returns the number of bits in an unsigned
+ * long, ie. sizeof(unsigned long) * 8.
+ *
+ * @param val unsigned long value to count leading zeros in
+ * @return the number of leading zeros
+ */
+CHECK_RESULT OSK_STATIC_INLINE long osk_clz(unsigned long val);
+
+/**
+ * @brief Count leading zeros in an u64
+ *
+ * Same behavior as ARM CLZ instruction.
+ *
+ * Returns the number of binary zero bits before the first (most significant)
+ * binary one bit in \a val.
+ *
+ * If \a val is zero, this function returns the number of bits in an u64,
+ * ie. sizeof(u64) * 8 = 64
+ *
+ * Note that on platforms where an unsigned long is 64 bits then this is the same as osk_clz.
+ *
+ * @param val value to count leading zeros in
+ * @return the number of leading zeros
+ */
+CHECK_RESULT OSK_STATIC_INLINE long osk_clz_64(u64 val);
+
+/**
+ * @brief Count the number of bits set in an unsigned long
+ *
+ * This returns the number of bits set in a unsigned long value.
+ *
+ * @param val The value to count bits set in
+ * @return The number of bits set in \c val.
+ */
+OSK_STATIC_INLINE int osk_count_set_bits(unsigned long val) CHECK_RESULT;
+
+/**
+ * @brief Count the number of bits set in an u64
+ *
+ * This returns the number of bits set in a u64 value.
+ *
+ * @param val The value to count bits set in
+ * @return The number of bits set in \c val.
+ */
+CHECK_RESULT OSK_STATIC_INLINE int osk_count_set_bits64(u64 val)
+{
+ return osk_count_set_bits(val & U32_MAX)
+ + osk_count_set_bits((val >> 32) & U32_MAX);
+}
+
+/** @} */ /* end group oskbitops */
+
+/** @} */ /* end group base_osk_api */
+
+/** @} */ /* end group base_api */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _OSK_BITOPS_H_ */
diff --git a/drivers/gpu/arm/t6xx/kbase/osk/include/mali_osk_credentials.h b/drivers/gpu/arm/t6xx/kbase/osk/include/mali_osk_credentials.h
new file mode 100644
index 0000000..d1366b5
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/osk/include/mali_osk_credentials.h
@@ -0,0 +1,91 @@
+/*
+ *
+ * (C) COPYRIGHT 2008-2011 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_osk_credentials.h
+ * Implementation of the OS abstraction layer for the kernel device driver
+ */
+
+#ifndef _OSK_CREDENTIALS_H_
+#define _OSK_CREDENTIALS_H_
+
+#ifndef _OSK_H_
+#error "Include mali_osk.h directly"
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+ * @addtogroup base_api
+ * @{
+ */
+
+/**
+ * @addtogroup base_osk_api
+ * @{
+ */
+
+/**
+ * @defgroup oskcredentials Credentials Access
+ */
+/** @{ */
+
+/** @brief Check if the caller is privileged.
+ *
+ * @return MALI_TRUE if the caller is privileged.
+ */
+OSK_STATIC_INLINE mali_bool osk_is_privileged(void);
+
+#define OSK_PROCESS_PRIORITY_MIN ( -20 )
+#define OSK_PROCESS_PRIORITY_MAX ( 19 )
+
+typedef struct osk_process_priority
+{
+ /* MALI_TRUE if process is using a realtime scheduling policy */
+ mali_bool is_realtime;
+ /* The process priority in the range of OSK_PROCESS_PRIORITY_MIN
+ and OSK_PROCESS_PRIORITY_MAX. */
+ int priority;
+} osk_process_priority;
+
+/** @brief Check if the caller is using a realtime scheduling policy
+ *
+ * @return MALI_TRUE if process is running a realtime policy.
+ */
+OSK_STATIC_INLINE mali_bool osk_is_policy_realtime(void);
+
+/** @brief Retrieve the calling process priority and policy
+ *
+ * @param[out] prio structure to contain the process policy type
+ * and priority number
+ */
+OSK_STATIC_INLINE void osk_get_process_priority(osk_process_priority *prio);
+
+/** @} */ /* end group oskcredentials */
+
+/** @} */ /* end group base_osk_api */
+
+/** @} */ /* end group base_api */
+
+/* pull in the arch header with the implementation */
+#include <osk/mali_osk_arch_credentials.h>
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _OSK_CREDENTIALS_H_ */
diff --git a/drivers/gpu/arm/t6xx/kbase/osk/include/mali_osk_debug.h b/drivers/gpu/arm/t6xx/kbase/osk/include/mali_osk_debug.h
new file mode 100644
index 0000000..fbb1ee7
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/osk/include/mali_osk_debug.h
@@ -0,0 +1,375 @@
+/*
+ *
+ * (C) COPYRIGHT 2010-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+#ifndef _OSK_DEBUG_H_
+#define _OSK_DEBUG_H_
+
+#ifndef _OSK_H_
+#error "Include mali_osk.h directly"
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stdarg.h>
+#include <malisw/mali_malisw.h>
+
+/**
+ * @addtogroup base_api
+ * @{
+ */
+
+/**
+ * @addtogroup base_osk_api
+ * @{
+ */
+
+/**
+ * @addtogroup oskdebug Debug
+ *
+ * OSK debug macros for asserts and debug messages. Mimics CDBG functionality.
+ *
+ * @{
+ */
+
+/**
+ * @brief OSK module IDs
+ */
+typedef enum
+{
+ OSK_UNKNOWN = 0, /**< @brief Unknown module */
+ OSK_OSK, /**< @brief ID of OSK module */
+ OSK_UKK, /**< @brief ID of UKK module */
+ OSK_BASE_MMU, /**< @brief ID of Base MMU */
+ OSK_BASE_JD, /**< @brief ID of Base Job Dispatch */
+ OSK_BASE_JM, /**< @brief ID of Base Job Manager */
+ OSK_BASE_CORE, /**< @brief ID of Base Core */
+ OSK_BASE_MEM, /**< @brief ID of Base Memory */
+ OSK_BASE_EVENT, /**< @brief ID of Base Event */
+ OSK_BASE_CTX, /**< @brief ID of Base Context */
+ OSK_BASE_PM, /**< @brief ID of Base Power Management */
+ OSK_UMP, /**< @brief ID of UMP module */
+ OSK_MODULES_ALL /**< @brief Select all the modules at once / Also gives the number of modules in the enum */
+} osk_module;
+
+/**
+ * Debug messages are sent to a particular channel (info, warn or error) or to all channels
+ */
+#define OSK_CHANNEL_INFO OSKP_CHANNEL_INFO /**< @brief No output*/
+#define OSK_CHANNEL_WARN OSKP_CHANNEL_WARN /**< @brief Standard output*/
+#define OSK_CHANNEL_ERROR OSKP_CHANNEL_ERROR /**< @brief Error output*/
+#define OSK_CHANNEL_RAW OSKP_CHANNEL_RAW /**< @brief Raw output*/
+#define OSK_CHANNEL_ALL OSKP_CHANNEL_ALL /**< @brief All the channels at the same time*/
+
+/** Function type that is called on an OSK_ASSERT() or OSK_ASSERT_MSG() */
+typedef void (osk_debug_assert_hook)( void * );
+
+typedef struct oskp_debug_assert_cb
+{
+ osk_debug_assert_hook *func;
+ void *param;
+} oskp_debug_assert_cb;
+
+/**
+ * @def OSK_DISABLE_ASSERTS
+ *
+ * @brief Indicates whether asserts are in use and evaluate their
+ * expressions. 0 indicates they are, any other value indicates that they are
+ * not.
+ */
+
+/**
+ * @def OSK_ASSERT_MSG(expr, ...)
+ * @brief Prints the given message if @a expr is false
+ *
+ * @note This macro does nothing if the flag @see OSK_DISABLE_ASSERTS is set to 1
+ *
+ * @param expr Boolean expression
+ * @param ... Message to display when @a expr is false, as a format string followed by format arguments.
+ * The format string and format arguments needs to be enclosed by parentheses.
+ * See oskp_validate_format_string for a list of supported format specifiers.
+ */
+#define OSK_ASSERT_MSG(expr, ...) OSKP_ASSERT_MSG(expr, __VA_ARGS__)
+
+/**
+ * @def OSK_ASSERT(expr)
+ * @brief Prints the expression @a expr if @a expr is false
+ *
+ * @note This macro does nothing if the flag @see OSK_DISABLE_ASSERTS is set to 1
+ *
+ * @param expr Boolean expression
+ */
+#define OSK_ASSERT(expr) OSKP_ASSERT(expr)
+
+/**
+ * @def OSK_INTERNAL_ASSERT(expr)
+ * @brief Asserts if @a expr is false.
+ * This assert function is for internal use of OSK functions which themselves are used to implement
+ * the OSK_ASSERT functionality. These functions should use OSK_INTERNAL_ASSERT which does not use
+ * any OSK functions to prevent ending up in a recursive loop.
+ *
+ * @note This macro does nothing if the flag @see OSK_DISABLE_ASSERTS is set to 1
+ *
+ * @param expr Boolean expression
+ */
+#define OSK_INTERNAL_ASSERT(expr) OSKP_INTERNAL_ASSERT(expr)
+
+/**
+ * @def OSK_DEBUG_CODE( X )
+ * @brief Executes the code inside the macro only in debug mode
+ *
+ * @param X Code to compile only in debug mode.
+ */
+#define OSK_DEBUG_CODE( X ) OSKP_DEBUG_CODE( X )
+
+/**
+ * @def OSK_PRINT(module, ...)
+ * @brief Prints given message
+ *
+ * Example:
+ * @code OSK_PRINT(OSK_BASE_MEM, " %d blocks could not be allocated", mem_allocated); @endcode will print:
+ * \n
+ * "10 blocks could not be allocated\n"
+ *
+ * @param module Name of the module which prints the message.
+ * @param ... Format string followed by a varying number of parameters
+ * See oskp_validate_format_string for a list of supported format specifiers.
+ */
+#define OSK_PRINT(module, ...) OSKP_PRINT_RAW(module, __VA_ARGS__)
+
+/**
+ * @def OSKP_PRINT_INFO(module, ...)
+ * @brief Prints "MALI<INFO,module_name>: " followed by the given message.
+ *
+ * Example:
+ * @code OSK_PRINT_INFO(OSK_BASE_MEM, " %d blocks could not be allocated", mem_allocated); @endcode will print:
+ * \n
+ * "MALI<INFO,BASE_MEM>: 10 blocks could not be allocated"\n
+ *
+ * @note Only gets compiled in for debug builds
+ *
+ * @param module Name of the module which prints the message.
+ * @param ... Format string followed by a varying number of parameters
+ * See oskp_validate_format_string for a list of supported format specifiers.
+ */
+#define OSK_PRINT_INFO(module, ...) OSKP_PRINT_INFO(module, __VA_ARGS__)
+
+/**
+ * @def OSK_PRINT_WARN(module, ...)
+ * @brief Prints "MALI<WARN,module_name>: " followed by the given message.
+ *
+ * Example:
+ * @code OSK_PRINT_WARN(OSK_BASE_MEM, " %d blocks could not be allocated", mem_allocated); @endcode will print:
+ * \n
+ * "MALI<WARN,BASE_MEM>: 10 blocks could not be allocated"\n
+ *
+ * @note Only gets compiled in for debug builds
+ *
+ * @param module Name of the module which prints the message.
+ * @param ... Format string followed by a varying number of parameters
+ * See oskp_validate_format_string for a list of supported format specifiers.
+ */
+#define OSK_PRINT_WARN(module, ...) OSKP_PRINT_WARN(module, __VA_ARGS__)
+
+/**
+ * @def OSK_PRINT_ERROR(module, ...)
+ * @brief Prints "MALI<ERROR,module_name>: " followed by the given message.
+ *
+ * Example:
+ * @code OSK_PRINT_ERROR(OSK_BASE_MEM, " %d blocks could not be allocated", mem_allocated); @endcode will print:
+ * \n
+ * "MALI<ERROR,BASE_MEM>: 10 blocks could not be allocated"\n
+ *
+ * @param module Name of the module which prints the message.
+ * @param ... Format string followed by a varying number of parameters
+ * See oskp_validate_format_string for a list of supported format specifiers.
+ */
+#define OSK_PRINT_ERROR(module, ...) OSKP_PRINT_ERROR(module, __VA_ARGS__)
+
+/**
+ * @def OSK_PRINT_ALLOW(module, channel)
+ * @brief Allow the given module to print on the given channel
+ * @note If @see OSK_USE_RUNTIME_CONFIG is disabled then this macro doesn't do anything
+ * @note Only gets compiled in for debug builds
+ * @param module is a @see osk_module
+ * @param channel is one of @see OSK_CHANNEL_INFO, @see OSK_CHANNEL_WARN, @see OSK_CHANNEL_ERROR,
+ * @see OSK_CHANNEL_ALL
+ * @return MALI_TRUE if the module is allowed to print on the channel.
+ */
+#define OSK_PRINT_ALLOW(module, channel) OSKP_PRINT_ALLOW(module, channel)
+
+/**
+ * @def OSK_PRINT_BLOCK(module, channel)
+ * @brief Prevent the given module from printing on the given channel
+ * @note If @see OSK_USE_RUNTIME_CONFIG is disabled then this macro doesn't do anything
+ * @note Only gets compiled in for debug builds
+ * @param module is a @see osk_module
+ * @param channel is one of @see OSK_CHANNEL_INFO, @see OSK_CHANNEL_WARN, @see OSK_CHANNEL_ERROR,
+ * @see OSK_CHANNEL_ALL
+ * @return MALI_TRUE if the module is allowed to print on the channel.
+ */
+#define OSK_PRINT_BLOCK(module, channel) OSKP_PRINT_BLOCK(module, channel)
+
+/**
+ * @brief Register a function to call on ASSERT
+ *
+ * Such functions will \b only be called during Debug mode, and for debugging
+ * features \b only. Do not rely on them to be called in general use.
+ *
+ * To disable the hook, supply NULL to \a func.
+ *
+ * @note This function is not thread-safe, and should only be used to
+ * register/deregister once in the module's lifetime.
+ *
+ * @param[in] func the function to call when an assert is triggered.
+ * @param[in] param the parameter to pass to \a func when calling it
+ */
+void osk_debug_assert_register_hook( osk_debug_assert_hook *func, void *param );
+
+/**
+ * @brief Call a debug assert hook previously registered with osk_debug_assert_register_hook()
+ *
+ * @note This function is not thread-safe with respect to multiple threads
+ * registering functions and parameters with
+ * osk_debug_assert_register_hook(). Otherwise, thread safety is the
+ * responsibility of the registered hook.
+ */
+void oskp_debug_assert_call_hook( void );
+
+/**
+ * @brief Convert a module id into a module name.
+ *
+ * @param module ID of the module to convert
+ * @note module names are stored in : @see oskp_str_modules.
+ * @return the name of the given module ID as a string of characters.
+ */
+const char* oskp_module_to_str(const osk_module module);
+
+/**
+ * @brief Validate the format string
+ *
+ * Validates the printf style format string against the formats
+ * that are supported by the OSK_PRINT macros. If an invalid
+ * format is used, a warning message is printed identifying
+ * the unsupported format specifier.
+ *
+ * Supported length and specifiers in the format string are:
+ *
+ * "d", "ld", "lld",
+ * "x", "lx", "llx",
+ * "X", "lX", "llX",
+ * "p",
+ * "c",
+ * "s"
+ *
+ * Notes:
+ * - in release builds this function does nothing.
+ * - this function takes a variable number of arguments to
+ * ease using it with variadic macros. Only the format
+ * argument is used though.
+ *
+ * @param format format string
+ *
+ */
+void oskp_validate_format_string(const char *format, ...);
+
+/**
+ * @brief printf-style string formatting.
+ *
+ * Refer to the cutils specification for restrictions on the format string.
+ *
+ * @param str output buffer
+ * @param size size of the output buffer in bytes (incl. eos)
+ * @param format the format string
+ * See oskp_validate_format_string for a list of supported
+ * format specifiers.
+ * @param [in] ... The variadic arguments
+ *
+ * @return The number of characters written on success, or a negative value
+ * on failure.
+ */
+s32 osk_snprintf(char *str, size_t size, const char *format, ...);
+
+/**
+ * @brief Get thread information for the current thread
+ *
+ * The information is for debug purposes only. For example, the current CPU for
+ * the thread could've changed by the time you access the returned information.
+ *
+ * On systems that support 64-bit thread IDs, the thread ID will be
+ * truncated. Therefore, this only gives an appoximate guide as to which thread
+ * is making the call.
+ *
+ * @param[out] thread_id first 32-bits of the current thread's ID
+ * @param[out] cpu_nr the CPU that the thread was probably executing on at the
+ * time of the call.
+ */
+OSK_STATIC_INLINE void osk_debug_get_thread_info( u32 *thread_id, u32 *cpu_nr );
+
+/**
+ * @def OSK_ASSERT_MUTEX_IS_LOCKED(lock)
+ * @brief Asserts that mutex @e lock is locked.
+ *
+ * User backend checks if the mutex is locked by current thread.
+ * Kernel backend checks if the mutex is locked by any thread of execution - this might lead to
+ * false negatives (the test will pass, though it should fail).
+ *
+ * @param lock osk mutex
+ */
+#define OSK_ASSERT_MUTEX_IS_LOCKED(lock) OSKP_ASSERT_MUTEX_IS_LOCKED(lock)
+
+/**
+ * @def OSK_ASSERT_SPINLOCK_IS_LOCKED(lock)
+ * @brief Asserts that spinlock @e lock is locked.
+ *
+ * User backend checks if the spinlock is locked by current thread.
+ * Kernel backend checks if the spinlock is locked by any thread of execution - this might lead to
+ * false negatives (the test will pass, though it should fail).
+ *
+ * @note Kernel backend requires LOCKDEP to be enabled in kernel config.
+ *
+ * @param lock osk spinlock
+ */
+#define OSK_ASSERT_SPINLOCK_IS_LOCKED(lock) OSKP_ASSERT_SPINLOCK_IS_LOCKED(lock)
+
+/**
+ * @def OSK_ASSERT_SPINLOCK_IRQ_IS_LOCKED(lock)
+ * @brief Asserts that spinlock @e lock is locked.
+ *
+ * User backend checks if the spinlock is locked by current thread.
+ * Kernel backend checks if the spinlock is locked by any thread of execution - this might lead to
+ * false negatives (the test will pass, though it should fail).
+ *
+ * @note Kernel backend requires LOCKDEP to be enabled in kernel config.
+ *
+ * @param lock osk spinlock irq
+ */
+#define OSK_ASSERT_SPINLOCK_IRQ_IS_LOCKED(lock) OSKP_ASSERT_SPINLOCK_IRQ_IS_LOCKED(lock)
+
+/* @} */ /* end group oskdebug */
+
+/** @} */ /* end group base_osk_api */
+
+/** @} */ /* end group base_api */
+
+#include <osk/mali_osk_arch_debug.h>
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _OSK_DEBUG_H_ */
+
diff --git a/drivers/gpu/arm/t6xx/kbase/osk/include/mali_osk_failure.h b/drivers/gpu/arm/t6xx/kbase/osk/include/mali_osk_failure.h
new file mode 100644
index 0000000..7bd521e
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/osk/include/mali_osk_failure.h
@@ -0,0 +1,168 @@
+/*
+ *
+ * (C) COPYRIGHT 2011-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+#ifndef _OSK_FAILURE_H_
+#define _OSK_FAILURE_H_
+/** @file mali_osk_failure.h
+ *
+ * Base kernel side failure simulation mechanism interface.
+ *
+ * Provides a mechanism to simulate failure of
+ * functions which use the OSK_SIMULATE_FAILURE macro. This is intended to
+ * exercise error-handling paths during testing.
+ */
+#include <malisw/mali_malisw.h>
+#include "osk/include/mali_osk_debug.h"
+
+/**
+ * @addtogroup base_api Base APIs
+ * @{
+ */
+
+/**
+ * @addtogroup base_osk_api Kernel-side OSK APIs
+ * @{
+ */
+
+/**
+ * @addtogroup osk_failure Simulated failure
+ * @{
+ */
+
+/**
+ * @addtogroup osk_failure_public Public
+ * @{
+ */
+/**
+ * @brief Decide whether or not to simulate a failure in a given module
+ *
+ * Functions that can return a failure indication should use this macro to
+ * decide whether to do so in cases where no genuine failure occurred. This
+ * allows testing of error-handling paths in callers of those functions. A
+ * module ID must be specified to ensure that failures are only simulated in
+ * those modules for which they have been enabled.
+ *
+ * If it evaluates as MALI_TRUE, a message may be printed giving the location
+ * of the macro usage.
+ *
+ * A break point set on the oskp_failure function will halt execution
+ * before this macro evaluates as MALI_TRUE.
+ *
+ * @param[in] module Numeric ID of the module using the macro
+ *
+ * @return MALI_FALSE if execution should continue as normal; otherwise
+ * a failure should be simulated by the code using this macro.
+ *
+ * @note Unless simulation of failures was enabled at compilation time, this
+ * macro always evaluates as MALI_FALSE.
+ */
+#if OSK_SIMULATE_FAILURES
+#define OSK_SIMULATE_FAILURE( module ) \
+ ( OSKP_SIMULATE_FAILURE_IS_ENABLED( (module), OSK_CHANNEL_INFO ) && \
+ oskp_is_failure_on() &&\
+ oskp_simulate_failure( module, OSKP_PRINT_TRACE, OSKP_PRINT_FUNCTION ) )
+#else
+#define OSK_SIMULATE_FAILURE( module ) \
+ ( CSTD_NOP( module ), MALI_FALSE )
+#endif
+
+
+/**
+ * @brief Get the number of potential failures
+ *
+ * This function can be used to find out the total number of potential
+ * failures during a test, before using @ref osk_set_failure_range to
+ * set the number of successes to allow. This allows testing of error-
+ * handling paths to be parallelized (in different processes) by sub-
+ * dividing the range of successes to allow before provoking a failure.
+ *
+ * @return The number of times the @ref OSK_SIMULATE_FAILURE macro has been
+ * evaluated since the counter was last reset.
+ */
+u64 osk_get_potential_failures( void );
+
+/**
+ * @brief Set the range of failures to simulate
+ *
+ * This function configures a range of potential failures to be tested by
+ * simulating actual failure. The @ref OSK_SIMULATE_FAILURE macro will
+ * evaluate as MALI_FALSE for the first @p start evaluations after the range
+ * is set; then as MALI_TRUE for the next @p end - @p start evaluations;
+ * finally, as MALI_FALSE after being evaluated @p end times (until the
+ * mechanism is reset). @p end must be greater than or equal to @p start.
+ *
+ * This function also resets the count of successes allowed so far.
+ *
+ * @param[in] start Number of potential failures to count before simulating
+ * the first failure, or U64_MAX to never fail.
+ * @param[in] end Number of potential failures to count before allowing
+ * resumption of success, or U64_MAX to fail all after
+ * @p first.
+ */
+void osk_set_failure_range( u64 start, u64 end );
+
+/**
+ * @brief Find out whether a failure was simulated
+ *
+ * This function can be used to find out whether an apparent failure was
+ * genuine or simulated by @ref OSK_SIMULATE_FAILURE macro.
+ *
+ * @return MALI_FALSE unless a failure was simulated since the last call to
+ * the @ref osk_set_failure_range function.
+ * @since 2.3
+ */
+mali_bool osk_failure_simulated( void );
+
+/** @} */
+/* end public*/
+
+/**
+ * @addtogroup osk_failure_private Private
+ * @{
+ */
+
+/**
+ * @brief Decide whether or not to simulate a failure
+ *
+ * @param[in] module Numeric ID of the module that can fail
+ * @param[in] trace Pointer to string giving the location in the source code
+ * @param[in] function Pointer to name of the calling function
+ *
+ * @return MALI_FALSE if execution should continue as normal; otherwise
+ * a failure should be simulated by the calling code.
+ */
+
+mali_bool oskp_simulate_failure( osk_module module,
+ const char *trace,
+ const char *function );
+mali_bool oskp_is_failure_on(void);
+void oskp_failure_init( void );
+void oskp_failure_term( void );
+/** @} */
+/* end osk_failure_private group*/
+
+/** @} */
+/* end osk_failure group*/
+
+/** @} */
+/* end group base_osk_api*/
+
+/** @} */
+/* end group base_api*/
+
+
+
+
+#endif /* _OSK_FAILURE_H_ */
+
diff --git a/drivers/gpu/arm/t6xx/kbase/osk/include/mali_osk_lists.h b/drivers/gpu/arm/t6xx/kbase/osk/include/mali_osk_lists.h
new file mode 100644
index 0000000..99178e6
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/osk/include/mali_osk_lists.h
@@ -0,0 +1,981 @@
+/*
+ *
+ * (C) COPYRIGHT 2008-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_osk_lists.h
+ * Implementation of the OS abstraction layer for the kernel device driver.
+ * Note that the OSK list implementation is copied from the CUTILS
+ * doubly linked list (DLIST) implementation.
+ */
+
+#ifndef _OSK_LISTS_H_
+#define _OSK_LISTS_H_
+
+#ifndef _OSK_H_
+#error "Include mali_osk.h directly"
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <osk/mali_osk_common.h>
+
+/**
+ * @addtogroup base_api
+ * @{
+ */
+
+/**
+ * @addtogroup base_osk_api
+ * @{
+ */
+
+/**
+ * @addtogroup osk_dlist Doubly-linked list
+ * @{
+ */
+/**
+ * @addtogroup osk_dlist_public Public
+ * @{
+ */
+/**
+ * @brief Item of a list
+ *
+ * @note Can be integrated inside a wider structure.
+ */
+typedef struct osk_dlist_item
+{
+ struct
+ {
+ struct osk_dlist_item *next; /**< @private */
+ struct osk_dlist_item *prev; /**< @private */
+ }oskp; /**< @private*/
+}osk_dlist_item;
+
+/**
+ * @brief Doubly-linked list
+ */
+typedef struct osk_dlist
+{
+ struct
+ {
+ struct osk_dlist_item *front; /**< @private */
+ struct osk_dlist_item *back; /**< @private */
+ }oskp; /**< @private*/
+}osk_dlist;
+
+/**
+ * @brief Test if @c container_ptr is the back of the list
+ *
+ * @param [in] container_ptr Pointer to the front of the container to test.
+ * @param [in] attribute Attribute of the container of type @c osk_dlist_item
+ *
+ * @note An assert is triggered if @a container_ptr is NULL.
+ * @note If @c attribute is invalid then the behavior is undefined.
+ *
+ * @return Returns MALI_TRUE if @c container_ptr is the back of the list.
+ */
+#define OSK_DLIST_IS_BACK(container_ptr, attribute)\
+ (NULL == (OSK_CHECK_PTR(container_ptr))->attribute.oskp.next)
+
+/**
+ * @brief Test if @c container_ptr is the front of the list
+ *
+ * @param [in] container_ptr Pointer to the front of the container to test.
+ * @param [in] attribute Attribute of the container of type @c osk_dlist_item
+ *
+ * @note An assert is triggered if @a container_ptr is NULL.
+ * @note If @c attribute is invalid then the behavior is undefined.
+ *
+ * @return Returns MALI_TRUE if @c container_ptr is the front of the list.
+ */
+#define OSK_DLIST_IS_FRONT(container_ptr, attribute)\
+ (NULL == (OSK_CHECK_PTR(container_ptr))->attribute.oskp.prev)
+
+/**
+ * @brief Test if @c container_ptr is valid
+ *
+ * @param [in] container_ptr Pointer to the front of the container to test.
+ * @param [in] attribute Attribute of the container of type @c osk_dlist_item
+ *
+ * @note If @c attribute is invalid then the behavior is undefined.
+ *
+ * @return Returns MALI_TRUE if @c container_ptr is valid or MALI_FALSE otherwise.
+ */
+#define OSK_DLIST_IS_VALID(container_ptr, attribute)\
+ ( NULL != (container_ptr) )
+
+/**
+ * @brief Return the next item in the list
+ *
+ * @param [in] container_ptr Pointer to an item of type @c type
+ * @param [in] type Type of the container
+ * @param [in] attribute Attribute of the container of type @c osk_dlist_item
+ *
+ * @return A pointer to the next container item, or @c NULL.
+
+ * @note If this macro evaluates as null then the back of the list has been reached.
+ * @note An assert is triggered if @a container_ptr is NULL.
+ * @note If @c type or @c attribute is invalid then the behavior is undefined.
+ */
+#define OSK_DLIST_NEXT(container_ptr, type, attribute)\
+ ( OSK_DLIST_IS_BACK( container_ptr, attribute ) ?\
+ NULL :CONTAINER_OF( (container_ptr)->attribute.oskp.next, type, attribute ) )
+
+/**
+ * @brief Return MALI_TRUE if the list is empty
+ *
+ * @param [in] osk_dlist_ptr Pointer to the @c osk_dlist to test.
+ *
+ * @note An assert is triggered if @a osk_dlist_ptr is NULL.
+ *
+ * @return Returns MALI_TRUE if @c osk_dlist_ptr is an empty list.
+ */
+#define OSK_DLIST_IS_EMPTY(osk_dlist_ptr)\
+ (NULL == OSK_CHECK_PTR(osk_dlist_ptr)->oskp.front)
+
+/**
+ * @brief Return the previous item in the list
+ *
+ * @param [in] container_ptr Pointer to an item of type @c type
+ * @param [in] type Type of the container
+ * @param [in] attribute Attribute of the container of type @c osk_dlist_item
+ *
+ * @return A pointer to the previous container item, or @c NULL.
+
+ * @note If this macro evaluates as null then the front of the list has been reached.
+ * @note An assert is triggered if @a container_ptr is NULL.
+ * @note If @c type or @c attribute is invalid then the behavior is undefined.
+ */
+#define OSK_DLIST_PREV(container_ptr, type, attribute)\
+ ( OSK_DLIST_IS_FRONT( container_ptr, attribute ) ?\
+ NULL : CONTAINER_OF( (container_ptr)->attribute.oskp.prev, type, attribute) )
+
+/**
+ * @brief Return the front container of the list
+ *
+ * @param [in] osk_dlist_ptr Pointer to a list
+ * @param [in] type Type of the list container
+ * @param [in] attribute Attribute of the container of type @c osk_dlist_item
+ *
+ * @return A pointer to the front container item, or @c NULL.
+
+ * @note If this macro evaluates as null then the list is empty.
+ * @note An assert is triggered if @a osk_dlist_ptr is NULL.
+ * @note If @c type or @c attribute is invalid then the behavior is undefined.
+ */
+#define OSK_DLIST_FRONT(osk_dlist_ptr, type, attribute)\
+ ( OSK_CHECK_PTR( osk_dlist_ptr )->oskp.front == NULL ?\
+ NULL : CONTAINER_OF( (osk_dlist_ptr)->oskp.front, type, attribute ) )
+
+/**
+ * @brief Check whether or not @c container_ptr is a member of @c osk_dlist_ptr.
+ *
+ * @param [in] osk_dlist_ptr Pointer to a list
+ * @param [in] container_ptr Pointer to the item to check.
+ * @param [in] attribute Attribute of the container of type @c osk_dlist_item
+ *
+ * @return MALI_TRUE if @c container_ptr is a member of @c osk_dlist_ptr, MALI_FALSE if not.
+ *
+ * @note An assert is triggered if @c osk_dlist_ptr is NULL.
+ * @note An assert is triggered if @c container_to_remove_ptr is NULL.
+ * @note If @c attribute is invalid then the behavior is undefined.
+ */
+#define OSK_DLIST_MEMBER_OF(osk_dlist_ptr, container_ptr, attribute)\
+ oskp_dlist_member_of(osk_dlist_ptr, &(OSK_CHECK_PTR(container_ptr))->attribute)
+
+/**
+ * @brief Return the back container of the list
+ *
+ * @param [in] osk_dlist_ptr Pointer to a list
+ * @param [in] type Type of the list container
+ * @param [in] attribute Attribute of the container of type @c osk_dlist_item
+ *
+ * @return A pointer to the back container item, or @c NULL.
+ *
+ * @note If this macro evaluates as null then the list is empty.
+ * @note An assert is triggered if @a osk_dlist_ptr is NULL.
+ * @note If @c type or @c attribute is invalid then the behavior is undefined.
+ */
+#define OSK_DLIST_BACK(osk_dlist_ptr, type, attribute)\
+ ( OSK_CHECK_PTR( osk_dlist_ptr )->oskp.back == NULL ?\
+ NULL : CONTAINER_OF( (osk_dlist_ptr)->oskp.back, type, attribute) )
+
+/**
+ * @brief Initialize a list
+ *
+ * @param [out] osk_dlist_ptr Pointer to a osk_dlist
+ *
+ * @note An assert is triggered if @c osk_dlist_ptr is NULL.
+ */
+#define OSK_DLIST_INIT(osk_dlist_ptr)\
+ do\
+ {\
+ OSK_CHECK_PTR(osk_dlist_ptr); \
+ (osk_dlist_ptr)->oskp.front = NULL; \
+ (osk_dlist_ptr)->oskp.back = NULL;\
+ }while(MALI_FALSE)
+
+/**
+ * @brief Append @c container_to_insert_ptr at the back of @c osk_dlist_ptr
+ *
+ * The front and the back of the list are automatically adjusted.
+ *
+ * @param [in, out] osk_dlist_ptr Pointer to a list
+ * @param [in, out] container_to_insert_ptr Pointer to an item to insert of type @c type.
+ * @param [in] type Type of the list container
+ * @param [in] attribute Attribute of the container of type @c osk_dlist_item
+ *
+ * @note An assert is triggered if @c osk_dlist_ptr is NULL.
+ * @note An assert is triggered if @c container_to_insert_ptr is NULL or if it already belongs to the list.
+ * @note If @c type or @c attribute is invalid then the behavior is undefined.
+ */
+#define OSK_DLIST_PUSH_BACK(osk_dlist_ptr, container_to_insert_ptr, type, attribute)\
+ OSK_DLIST_INSERT_BEFORE(osk_dlist_ptr, container_to_insert_ptr, NULL, type, attribute)
+
+/**
+ * @brief Insert @c container_to_insert_ptr at the front of @c osk_dlist_ptr
+ *
+ * The front and the back of the list are automatically adjusted.
+ *
+ * @param [in, out] osk_dlist_ptr Pointer to a list
+ * @param [in, out] container_to_insert_ptr Pointer to an item to insert of type @c type.
+ * @param [in] type Type of the list container
+ * @param [in] attribute Attribute of the container of type @c osk_dlist_item
+ *
+ * @note An assert is triggered if @c osk_dlist_ptr is NULL.
+ * @note An assert is triggered if @c container_to_insert_ptr is NULL or if it already belongs to the list.
+ * @note If @c type or @c attribute is invalid then the behavior is undefined.
+ */
+#define OSK_DLIST_PUSH_FRONT(osk_dlist_ptr, container_to_insert_ptr, type, attribute)\
+ OSK_DLIST_INSERT_AFTER(osk_dlist_ptr, container_to_insert_ptr, NULL, type, attribute)
+
+ /**
+ * @brief Remove the back of @c osk_dlist_ptr and return the element just removed
+ *
+ * The front and the back of the list are automatically adjusted.
+ *
+ * @param [in, out] osk_dlist_ptr Pointer to a list
+ * @param [in] type Type of the list container
+ * @param [in] attribute Attribute of the container of type @c osk_dlist_item
+ *
+ * @return A pointer to a container item.
+ *
+ * @note If @c OSK_DLIST_IS_VALID returns MALI_FALSE when testing the returned pointer then the list is empty
+ * @note An assert is triggered if @c osk_dlist_ptr is NULL or empty.
+ * @note If @c type or @c attribute is invalid then the behavior is undefined.
+ */
+#define OSK_DLIST_POP_BACK(osk_dlist_ptr, type, attribute, err)\
+ CONTAINER_OF(\
+ oskp_dlist_remove_debug(\
+ osk_dlist_ptr, \
+ &OSK_CHECK_PTR( OSK_DLIST_BACK(osk_dlist_ptr, type, attribute) )->attribute, &err), \
+ type, \
+ attribute)
+ /**
+ * @brief Remove the front of @c osk_dlist_ptr and return the element just removed
+ *
+ * The front and the back of the list are automatically adjusted.
+ *
+ * @note The list must contain at least one item.
+ *
+ * @param [in, out] osk_dlist_ptr Pointer to a list
+ * @param [in] type Type of the list container
+ * @param [in] attribute Attribute of the container of type @c osk_dlist_item
+ *
+ * @return A pointer to a container item.
+ *
+ * @note An assert is triggered if @c osk_dlist_ptr is NULL or empty.
+ * @note If @c type or @c attribute is invalid then the behavior is undefined.
+ */
+#define OSK_DLIST_POP_FRONT(osk_dlist_ptr, type, attribute, err)\
+ CONTAINER_OF(\
+ oskp_dlist_remove_debug(\
+ osk_dlist_ptr, \
+ &OSK_CHECK_PTR( OSK_DLIST_FRONT(osk_dlist_ptr, type, attribute) )->attribute, &err), \
+ type, \
+ attribute)
+
+/**
+ * @brief Append @c container_to_insert_ptr after @c container_pos_ptr in @c osk_dlist_ptr
+ *
+ * @note Insert the new element at the list front if @c container_pos_ptr is NULL.
+ *
+ * The front and the back of the list are automatically adjusted.
+ *
+ * @param [in, out] osk_dlist_ptr Pointer to a list
+ * @param [in, out] container_to_insert_ptr Pointer to an item to insert of type @c type.
+ * @param [in, out] container_pos_ptr Pointer to the item of type @c type after which inserting the new item.
+ * @param [in] type Type of the list container
+ * @param [in] attribute Attribute of the container of type @c osk_dlist_item
+ *
+ * @note An assert is triggered if @c osk_dlist_ptr is NULL.
+ * @note An assert is triggered if @c container_pos_ptr is not NULL and not a member of the list.
+ * @note An assert is triggered if @c container_to_insert_ptr is NULL or if it already belongs to the list.
+ * @note If @c type or @c attribute is invalid then the behavior is undefined.
+ */
+#define OSK_DLIST_INSERT_AFTER(osk_dlist_ptr, container_to_insert_ptr, container_pos_ptr, type, attribute)\
+ oskp_dlist_insert_after(\
+ osk_dlist_ptr, \
+ &(OSK_CHECK_PTR(container_to_insert_ptr))->attribute, \
+ &((type*)container_pos_ptr)->attribute, \
+ container_pos_ptr)
+/**
+ * @brief Append @c container_to_insert_ptr before @c container_pos_ptr in @c osk_dlist_ptr
+ *
+ * @note Insert the new element at the list back if @c container_pos_ptr is NULL.
+ *
+ * The front and the back of the list are automatically adjusted.
+ *
+ * @param [in, out] osk_dlist_ptr Pointer to a list
+ * @param [in, out] container_to_insert_ptr Pointer to an item to insert of type @c type.
+ * @param [in, out] container_pos_ptr Pointer to the item of type @c type before which inserting the new item.
+ * @param [in] type Type of the list container
+ * @param [in] attribute Attribute of the container of type @c osk_dlist_item
+ *
+ * @note An assert is triggered if @c osk_dlist_ptr is NULL.
+ * @note An assert is triggered if @c container_pos_ptr is not NULL and not a member of the list.
+ * @note An assert is triggered if @c container_to_insert_ptr is NULL or if it already belongs to the list.
+ * @note If @c type or @c attribute is invalid then the behavior is undefined.
+ */
+
+#define OSK_DLIST_INSERT_BEFORE(osk_dlist_ptr, container_to_insert_ptr, container_pos_ptr, type, attribute)\
+ oskp_dlist_insert_before(\
+ osk_dlist_ptr, \
+ &(OSK_CHECK_PTR(container_to_insert_ptr))->attribute, \
+ &((type*)container_pos_ptr)->attribute, \
+ container_pos_ptr)
+
+/**
+ * @brief Remove an item container from a doubly-linked list and return a pointer to the element
+ * which was next in the list.
+ *
+ * The front and the back of the list are automatically adjusted.
+ *
+ * @param [in, out] osk_dlist_ptr Pointer to a list
+ * @param [in, out] container_to_remove_ptr Pointer to an item to remove of type @c type.
+ * @param [in] type Type of the list container
+ * @param [in] attribute Attribute of the container of type @c osk_dlist_item
+ *
+ * @return A pointer to the item container that was immediately after the one
+ * removed from the list, or @c NULL.
+ *
+ * @note If this macro evaluates as null then the back of the list has been reached.
+ * @note An assert is triggered if @c osk_dlist_ptr is NULL.
+ * @note An assert is triggered if @c container_to_remove_ptr is NULL or if it doesn't belong to the list.
+ * @note If @c type or @c attribute is invalid then the behavior is undefined.
+
+ * @pre @p osk_dlist_ptr must have been initialized by @ref OSK_DLIST_INIT.
+ * @pre @p container_to_remove_ptr must be a member of list @p osk_dlist_ptr.
+ * @post @p container_to_remove_ptr is no longer a member of list @p osk_dlist_ptr.
+ *
+ */
+
+#define OSK_DLIST_REMOVE_AND_RETURN_NEXT(osk_dlist_ptr, container_to_remove_ptr, type, attribute)\
+ ( OSK_DLIST_IS_BACK( container_to_remove_ptr, attribute ) ?\
+ ( oskp_dlist_remove( osk_dlist_ptr, &( container_to_remove_ptr )->attribute ), NULL ) :\
+ CONTAINER_OF( oskp_dlist_remove_and_return_next( osk_dlist_ptr,\
+ &( container_to_remove_ptr )->attribute ),\
+ type,\
+ attribute ) )
+
+/**
+ * @brief Remove an item container from a doubly-linked list.
+ *
+ * The front and the back of the list are automatically adjusted.
+ *
+ * @param [in, out] osk_dlist_ptr Pointer to a list
+ * @param [in, out] container_to_remove_ptr Pointer to an item to remove of type @c type.
+ * @param [in] attribute Attribute of the container of type @c osk_dlist_item
+ *
+ * @note An assert error is triggered if @c osk_dlist_ptr is NULL.
+ * @note An assert error is triggered if @c container_to_remove_ptr is NULL or if it doesn't belong to the list.
+ * @note If @c attribute is invalid then the behavior is undefined.
+ *
+ * @pre @p osk_dlist_ptr must have been initialized by @ref OSK_DLIST_INIT.
+ * @pre @p container_to_remove_ptr must be a member of list @p osk_dlist_ptr.
+ * @post @p container_to_remove_ptr is no longer a member of list @p osk_dlist_ptr.
+ */
+#define OSK_DLIST_REMOVE(osk_dlist_ptr, container_to_remove_ptr, attribute, error)\
+ oskp_dlist_remove_item_debug(osk_dlist_ptr, &((OSK_CHECK_PTR(container_to_remove_ptr))->attribute), &error)
+
+/**
+ * @brief Remove an item container from a doubly-linked list and return a pointer to the element which was the
+ * previous one in the list.
+ *
+ * The front and the back of the list are automatically adjusted.
+ *
+ * @param [in, out] osk_dlist_ptr Pointer to a list
+ * @param [in, out] container_to_remove_ptr Pointer to an item to remove of type @c type.
+ * @param [in] type Type of the list container
+ * @param [in] attribute Attribute of the container of type @c osk_dlist_item
+ *
+ * @return A pointer to the item container that was immediately before the one
+ * removed from the list, or @c NULL.
+ *
+ * @note If this macro evaluates as null then the front of the list has been reached.
+ * @note An assert is triggered if @c osk_dlist_ptr is NULL.
+ * @note An assert is triggered if @c container_to_remove_ptr is NULL or if it doesn't belong to the list.
+ * @note If @c type or @c attribute is invalid then the behavior is undefined.
+ *
+ * @pre @p osk_dlist_ptr must have been initialized by @ref OSK_DLIST_INIT.
+ * @pre @p container_to_remove_ptr must be a member of list @p osk_dlist_ptr.
+ * @post @p container_to_remove_ptr is no longer a member of list @p osk_dlist_ptr.
+ */
+
+#define OSK_DLIST_REMOVE_AND_RETURN_PREV(osk_dlist_ptr, container_to_remove_ptr, type, attribute)\
+ ( OSK_DLIST_IS_FRONT( container_to_remove_ptr, attribute ) ?\
+ ( oskp_dlist_remove( osk_dlist_ptr, &( container_to_remove_ptr )->attribute ), NULL ) :\
+ CONTAINER_OF( oskp_dlist_remove_and_return_prev( osk_dlist_ptr,\
+ &( container_to_remove_ptr )->attribute ),\
+ type,\
+ attribute ) )
+
+
+/**
+ * @brief Remove and call the destructor function for every item in the list, walking from start to end.
+ *
+ * @param [in, out] osk_dlist_ptr Pointer to the list to empty
+ * @param [in] type Type of the list container.
+ * @param [in] attribute Attribute of the container of type @c osk_dlist_item
+ * @param [in] destructor_func Destructor function called for every item present in the list.
+ *
+ * This function has to be of the form void func(type* item);
+ *
+ * @note An assert is triggered if @c osk_dlist_ptr is NULL.
+ * @note An assert is triggered if @c destructor_func is NULL.
+ * @note If @c type or @c attribute is invalid then the behavior is undefined.
+ */
+#define OSK_DLIST_EMPTY_LIST(osk_dlist_ptr, type, attribute, destructor_func)\
+ do\
+ {\
+ type* oskp_it;\
+ OSK_ASSERT(NULL != osk_dlist_ptr); \
+ OSK_ASSERT(NULL != destructor_func); \
+ oskp_it = OSK_DLIST_FRONT(osk_dlist_ptr, type, attribute);\
+ while ( oskp_it != NULL )\
+ {\
+ type* to_delete = oskp_it;\
+ oskp_it = OSK_DLIST_REMOVE_AND_RETURN_NEXT(osk_dlist_ptr, oskp_it, type, attribute);\
+ destructor_func(to_delete);\
+ }\
+ }while(MALI_FALSE)
+
+/**
+ * @brief Remove and call the destructor function for every item in the list, walking from the end and to the front.
+ *
+ * @param [in, out] osk_dlist_ptr Pointer to the list to empty
+ * @param [in] type Type of the list container.
+ * @param [in] attribute Attribute of the container of type @c osk_dlist_item
+ * @param [in] destructor_func Destructor function called for every item present in the list.
+ *
+ * This function has to be of the form void func(type* item);
+ *
+ * @note An assert is triggered if @c osk_dlist_ptr is NULL.
+ * @note An assert is triggered if @c destructor_func is NULL.
+ * @note If @c type or @c attribute is invalid then the behavior is undefined.
+ */
+
+#define OSK_DLIST_EMPTY_LIST_REVERSE(osk_dlist_ptr, type, attribute, destructor_func)\
+ do\
+ {\
+ type* oskp_it;\
+ OSK_ASSERT(NULL != osk_dlist_ptr); \
+ OSK_ASSERT(NULL != destructor_func); \
+ oskp_it = OSK_DLIST_BACK(osk_dlist_ptr, type, attribute);\
+ while ( oskp_it != NULL )\
+ {\
+ type* to_delete = oskp_it;\
+ oskp_it = OSK_DLIST_REMOVE_AND_RETURN_PREV(osk_dlist_ptr, oskp_it, type, attribute);\
+ destructor_func(to_delete);\
+ }\
+ }while(MALI_FALSE)
+
+
+
+/**
+ * @brief Iterate forward through each container item of the given list
+ *
+ * @param [in, out] osk_dlist_ptr Pointer to a list
+ * @param [in] type Container type of the list
+ * @param [in] attribute Attribute of the container of type @c osk_dlist_item
+ * @param [out] container_iterator Iterator variable of type "type*" to use to iterate through the list.
+ *
+ * @note An assert is triggered if @c osk_dlist_ptr is NULL.
+ * @note If @c type or @c attribute is invalid then the behavior is undefined.
+ */
+#define OSK_DLIST_FOREACH(osk_dlist_ptr, type, attribute, container_iterator)\
+ OSK_ASSERT(NULL != osk_dlist_ptr); \
+ for(\
+ container_iterator = OSK_DLIST_FRONT(osk_dlist_ptr, type, attribute);\
+ NULL != container_iterator; \
+ container_iterator = OSK_DLIST_NEXT(container_iterator, type, attribute))
+
+/**
+ * @brief Reverse iterate through each container item of the given list
+ *
+ * @param [in, out] osk_dlist_ptr Pointer to a list
+ * @param [in] type Container type of the list
+ * @param [in] attribute Attribute of the container of type @c osk_dlist_item
+ * @param [out] container_iterator Iterator variable of type "type*" to use to iterate through the list.
+ *
+ * @note An assert is triggered if @c osk_dlist_ptr is NULL.
+ * @note If @c type or @c attribute is invalid then the behavior is undefined.
+ */
+#define OSK_DLIST_FOREACH_REVERSE(osk_dlist_ptr, type, attribute, container_iterator)\
+ OSK_ASSERT(NULL != osk_dlist_ptr); \
+ for(\
+ container_iterator = OSK_DLIST_BACK(osk_dlist_ptr, type, attribute);\
+ NULL != container_iterator; \
+ container_iterator = OSK_DLIST_PREV(container_iterator, type, attribute))
+
+/**
+ * @}
+ */
+/* End osk_dlist_public */
+/**
+ * @addtogroup osk_dlist_private Private
+ * @{
+ */
+
+/**
+ * @brief Insert a new item after an existing one.
+ *
+ * @param [in, out] list_ptr Pointer to the list the new item is going to be added to.
+ * @param [in, out] item_to_insert New item to insert in the list.
+ * @param [in, out] position Position after which to add the new item.
+ * @param [in] previous If this argument is NULL then @c position is ignored and the
+ * new item is added to the front.
+ *
+ * @note An assert is triggered if @c list_ptr is NULL.
+ * @note An assert is triggered if @c previous is NULL and @c position is NULL.
+ */
+OSK_STATIC_INLINE void oskp_dlist_insert_after(osk_dlist * const list_ptr, osk_dlist_item * const item_to_insert,
+ osk_dlist_item * const position, const void * previous);
+
+/**
+ * @brief Insert a new item before an existing one.
+ *
+ * @param [in, out] list_ptr Pointer to the list the new item is going to be added to.
+ * @param [in, out] item_to_insert New item to insert in the list.
+ * @param [in, out] position Position before which to add the new item.
+ * @param [in] previous If this argument is NULL then @c position is ignored and the new
+ * item is added to the back
+ *
+ * @note An assert is triggered if @c list_ptr is NULL.
+ * @note An assert is triggered if @c previous is NULL and @c position is NULL.
+ */
+
+OSK_STATIC_INLINE void oskp_dlist_insert_before(osk_dlist * const list_ptr, osk_dlist_item* const item_to_insert,
+ osk_dlist_item * const position, const void * previous);
+
+/**
+ * @brief Remove a given item from the list and return the item which was next in the list
+ *
+ * @param [in, out] list_ptr List from which the item needs to be removed
+ * @param [in, out] item_to_remove Item to remove from the list
+ *
+ * @return A pointer to the item which was next in the list. Return NULL if the back has just been removed.
+ *
+ * @note An assert is triggered if @c list_ptr is NULL.
+ * @note An assert is triggered if @c item_to_remove is not a member of @c list_ptr
+
+ */
+OSK_STATIC_INLINE osk_dlist_item* oskp_dlist_remove_and_return_next(osk_dlist * const list_ptr,
+ osk_dlist_item * const item_to_remove) CHECK_RESULT;
+
+/**
+ * @brief Remove a given item from the list and return the item which was before in the list
+ *
+ * @param [in, out] list_ptr List from which the item needs to be removed
+ * @param [in, out] item_to_remove Item to remove from the list
+ *
+ * @return A pointer to the item which was before in the list. Return NULL if the front has just been removed.
+ *
+ * @note An assert is triggered if @c list_ptr is NULL.
+ * @note An assert is triggered if @c item_to_remove is not a member of @c list_ptr
+ */
+OSK_STATIC_INLINE osk_dlist_item* oskp_dlist_remove_and_return_prev(osk_dlist * const list_ptr,
+ osk_dlist_item * const item_to_remove) CHECK_RESULT;
+
+/**
+ * @brief Remove a given item from the list and return it.
+ *
+ * @param [in, out] list_ptr List from which the item needs to be removed
+ * @param [in, out] item_to_remove Item to remove from the list
+ *
+ * @return A pointer to the item which has been removed from the list.
+ *
+ * @note An assert is triggered if @c list_ptr is NULL.
+ * @note An assert is triggered if @c item_to_remove is not a member of @c list_ptr
+ */
+
+OSK_STATIC_INLINE osk_dlist_item* oskp_dlist_remove(osk_dlist * const list_ptr,
+ osk_dlist_item * const item_to_remove);
+
+OSK_STATIC_INLINE osk_dlist_item* oskp_dlist_remove_debug(osk_dlist * const list_ptr,
+ osk_dlist_item * const item_to_remove, int *err);
+
+/**
+ * @brief Check that @c item is a member of the @c list
+ *
+ * @param [in] list Metadata of the list
+ * @param [in] item Item to check
+ *
+ * @note An assert error is triggered if @c list is NULL.
+ *
+ * @return MALI_TRUE if @c item is a member of @c list or MALI_FALSE otherwise.
+ */
+OSK_STATIC_INLINE mali_bool oskp_dlist_member_of(const osk_dlist* const list, const osk_dlist_item* const item) CHECK_RESULT;
+
+/**
+ * @brief remove @c item_to_remove from @c front
+ *
+ * @param [in, out] front List from which the item needs to be removed
+ * @param [in, out] item_to_remove Item to remove from the list.
+ *
+ * @note An assert is triggered if @c list_ptr is NULL.
+ * @note An assert is triggered if @c item_to_remove is not a member of @c list_ptr
+ */
+OSK_STATIC_INLINE void oskp_dlist_remove_item(osk_dlist* const front, osk_dlist_item* const item_to_remove);
+
+OSK_STATIC_INLINE void oskp_dlist_remove_item_debug(osk_dlist* const front, osk_dlist_item* const item_to_remove, int *error);
+
+/**
+ * @}
+ */
+/* end osk_dlist_private */
+/**
+ * @}
+ */
+/* end osk_dlist group */
+
+/**
+ * @addtogroup osk_dlist Doubly-linked list
+ * @{
+ */
+/**
+ * @addtogroup osk_dlist_private Private
+ * @{
+ */
+
+CHECK_RESULT OSK_STATIC_INLINE mali_bool oskp_dlist_member_of(const osk_dlist* const list, const osk_dlist_item* const item)
+{
+ mali_bool return_value = MALI_FALSE;
+ const osk_dlist_item* it;
+
+ OSK_ASSERT(NULL != list);
+
+ it = list->oskp.front;
+ while(NULL != it)
+ {
+ if(item == it)
+ {
+ return_value = MALI_TRUE;
+ break;
+ }
+
+ it = it->oskp.next;
+ }
+ return return_value;
+}
+
+OSK_STATIC_INLINE void oskp_dlist_insert_before(osk_dlist * const front, osk_dlist_item * const item_to_insert,
+ osk_dlist_item * const position, const void * previous)
+{
+ OSK_ASSERT(NULL != front);
+ OSK_ASSERT(NULL != item_to_insert);
+ OSK_ASSERT((NULL == previous) || (NULL != position));
+ OSK_ASSERT(MALI_FALSE == oskp_dlist_member_of(front, item_to_insert));
+
+ if(NULL == previous)
+ {
+ item_to_insert->oskp.prev = front->oskp.back;
+
+ /*if there are some other items in the list, update their links.*/
+ if(NULL != front->oskp.back)
+ {
+ front->oskp.back->oskp.next = item_to_insert;
+ }
+ item_to_insert->oskp.next = NULL;
+ front->oskp.back = item_to_insert;
+ }
+ else
+ {
+ /* insertion at a position which is not the back*/
+ OSK_ASSERT(MALI_FALSE != oskp_dlist_member_of(front, position));
+
+ item_to_insert->oskp.prev = position->oskp.prev;
+ item_to_insert->oskp.next = position;
+ position->oskp.prev = item_to_insert;
+
+ /*if there are some other items in the list, update their links.*/
+ if(NULL != item_to_insert->oskp.prev)
+ {
+ item_to_insert->oskp.prev->oskp.next = item_to_insert;
+ }
+
+ }
+
+ /* Did the element inserted became the new front */
+ if(front->oskp.front == item_to_insert->oskp.next)
+ {
+ front->oskp.front = item_to_insert;
+ }
+}
+
+OSK_STATIC_INLINE
+void oskp_dlist_insert_after(osk_dlist * const front, osk_dlist_item * const item_to_insert,
+ osk_dlist_item * const position, const void * previous)
+{
+ OSK_ASSERT(NULL != front);
+ OSK_ASSERT(NULL != item_to_insert);
+ OSK_ASSERT((NULL == previous) || (NULL != position));
+ OSK_ASSERT(MALI_FALSE == oskp_dlist_member_of(front, item_to_insert));
+
+ if(NULL == previous)
+ {
+ item_to_insert->oskp.next = front->oskp.front;
+
+ /*if there are some other items in the list, update their links.*/
+ if(NULL != front->oskp.front)
+ {
+ front->oskp.front->oskp.prev = item_to_insert;
+ }
+ item_to_insert->oskp.prev = NULL;
+ front->oskp.front = item_to_insert;
+ }
+ else
+ {
+ /* insertion at a position which is not the front */
+ OSK_ASSERT(MALI_FALSE != oskp_dlist_member_of(front, position));
+
+ item_to_insert->oskp.next = position->oskp.next;
+ item_to_insert->oskp.prev = position;
+ position->oskp.next = item_to_insert;
+
+ /*if the item has not been inserted at the back, then update the links of the next item*/
+ if(NULL != item_to_insert->oskp.next)
+ {
+ item_to_insert->oskp.next->oskp.prev = item_to_insert;
+ }
+ }
+
+ /* Is the item inserted the new back ?*/
+ if(front->oskp.back == item_to_insert->oskp.prev)
+ {
+ front->oskp.back = item_to_insert;
+ }
+}
+
+OSK_STATIC_INLINE
+void oskp_dlist_remove_item_debug(osk_dlist* const front, osk_dlist_item* const item_to_remove, int *error)
+{
+ OSK_ASSERT(NULL != front);
+ OSK_ASSERT(NULL != item_to_remove);
+ OSK_ASSERT(MALI_TRUE == oskp_dlist_member_of(front, item_to_remove));
+
+ /* if the item to remove is the current front*/
+ if( front->oskp.front == item_to_remove )
+ {
+ /* then make the front point to the next item*/
+ front->oskp.front = item_to_remove->oskp.next;
+ }
+ else
+ {
+ /* else just the previous item point to the next one*/
+ item_to_remove->oskp.prev->oskp.next = item_to_remove->oskp.next;
+ }
+
+ /* if the item to remove is the current back*/
+ if(front->oskp.back == item_to_remove)
+ {
+ /* then make the back point to the previous item*/
+ front->oskp.back = item_to_remove->oskp.prev;
+ }
+ else
+ {
+ /* else just the next item point to the previous one*/
+ if (!item_to_remove->oskp.next)
+ {
+ osk_dlist_item * item;
+ int i;
+
+ /* bad node, log the contents of the list */
+
+ printk(KERN_ERR "Removing bad node %p, dumping list, forward walk\n", item_to_remove);
+ item = front->oskp.front;
+ i = 0;
+ while (item)
+ {
+ printk(KERN_ERR "list item %d: %p <- %p -> %p\n", i, item->oskp.prev, item, item->oskp.next);
+ item = item->oskp.next;
+ i++;
+ }
+
+ printk(KERN_ERR "Removing bad node, dumping list, reverse walk\n");
+ item = front->oskp.back;
+ i = 0;
+ while (item)
+ {
+ printk(KERN_ERR "list item %d: %p <- %p -> %p\n", i, item->oskp.prev, item, item->oskp.next);
+ item = item->oskp.prev;
+ i++;
+ }
+ *error = 1;
+ return;
+ }
+ item_to_remove->oskp.next->oskp.prev = item_to_remove->oskp.prev;
+ }
+
+ *error = 0;
+ item_to_remove->oskp.next = NULL;
+ item_to_remove->oskp.prev = NULL;
+}
+
+OSK_STATIC_INLINE
+void oskp_dlist_remove_item(osk_dlist* const front, osk_dlist_item* const item_to_remove)
+{
+ OSK_ASSERT(NULL != front);
+ OSK_ASSERT(NULL != item_to_remove);
+ OSK_ASSERT(MALI_TRUE == oskp_dlist_member_of(front, item_to_remove));
+
+ /* if the item to remove is the current front*/
+ if( front->oskp.front == item_to_remove )
+ {
+ /* then make the front point to the next item*/
+ front->oskp.front = item_to_remove->oskp.next;
+ }
+ else
+ {
+ /* else just the previous item point to the next one*/
+ item_to_remove->oskp.prev->oskp.next = item_to_remove->oskp.next;
+ }
+
+ /* if the item to remove is the current back*/
+ if(front->oskp.back == item_to_remove)
+ {
+ /* then make the back point to the previous item*/
+ front->oskp.back = item_to_remove->oskp.prev;
+ }
+ else
+ {
+ /* else just the next item point to the previous one*/
+ if (!item_to_remove->oskp.next)
+ {
+ osk_dlist_item * item;
+ int i;
+
+ /* bad node, log the contents of the list */
+
+ printk(KERN_ERR "Removing bad node %p, dumping list, forward walk\n", item_to_remove);
+ item = front->oskp.front;
+ i = 0;
+ while (item)
+ {
+ printk(KERN_ERR "list item %d: %p <- %p -> %p\n", i, item->oskp.prev, item, item->oskp.next);
+ item = item->oskp.next;
+ i++;
+ }
+
+ printk(KERN_ERR "Removing bad node, dumping list, reverse walk\n");
+ item = front->oskp.back;
+ i = 0;
+ while (item)
+ {
+ printk(KERN_ERR "list item %d: %p <- %p -> %p\n", i, item->oskp.prev, item, item->oskp.next);
+ item = item->oskp.prev;
+ i++;
+ }
+
+ }
+ item_to_remove->oskp.next->oskp.prev = item_to_remove->oskp.prev;
+ }
+
+ item_to_remove->oskp.next = NULL;
+ item_to_remove->oskp.prev = NULL;
+}
+
+OSK_STATIC_INLINE
+osk_dlist_item* oskp_dlist_remove_debug(osk_dlist * const front, osk_dlist_item * const item_to_remove, int *err)
+{
+ oskp_dlist_remove_item_debug(front, item_to_remove, err);
+
+ item_to_remove->oskp.next = NULL;
+ item_to_remove->oskp.prev = NULL;
+
+ return item_to_remove;
+}
+
+OSK_STATIC_INLINE
+osk_dlist_item* oskp_dlist_remove(osk_dlist * const front, osk_dlist_item * const item_to_remove)
+{
+ oskp_dlist_remove_item(front, item_to_remove);
+
+ item_to_remove->oskp.next = NULL;
+ item_to_remove->oskp.prev = NULL;
+
+ return item_to_remove;
+}
+
+
+CHECK_RESULT OSK_STATIC_INLINE
+osk_dlist_item* oskp_dlist_remove_and_return_next(osk_dlist * const front,
+ osk_dlist_item * const item_to_remove)
+{
+ osk_dlist_item *next;
+
+ OSK_ASSERT(NULL != front);
+ OSK_ASSERT(NULL != item_to_remove);
+
+ next = item_to_remove->oskp.next;
+ oskp_dlist_remove_item(front, item_to_remove);
+ return next;
+}
+
+CHECK_RESULT OSK_STATIC_INLINE
+osk_dlist_item* oskp_dlist_remove_and_return_prev(osk_dlist * const front,
+ osk_dlist_item * const item_to_remove)
+{
+ osk_dlist_item *prev;
+
+ OSK_ASSERT(NULL != front);
+ OSK_ASSERT(NULL != item_to_remove);
+
+ prev = item_to_remove->oskp.prev;
+ oskp_dlist_remove_item(front, item_to_remove);
+ return prev;
+}
+
+/**
+ * @}
+ */
+/* end osk_dlist_private */
+
+/**
+ * @}
+ */
+/* end osk_dlist group */
+
+/** @} */ /* end group base_osk_api */
+
+/** @} */ /* end group base_api */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _OSK_LISTS_H_ */
diff --git a/drivers/gpu/arm/t6xx/kbase/osk/include/mali_osk_lock_order.h b/drivers/gpu/arm/t6xx/kbase/osk/include/mali_osk_lock_order.h
new file mode 100644
index 0000000..87ac1bb
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/osk/include/mali_osk_lock_order.h
@@ -0,0 +1,257 @@
+/*
+ *
+ * (C) COPYRIGHT 2010-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+#ifndef _OSK_LOCK_ORDER_H_
+#define _OSK_LOCK_ORDER_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+ * @addtogroup base_api
+ * @{
+ */
+
+/**
+ * @addtogroup base_osk_api
+ * @{
+ */
+
+/**
+ * @addtogroup oskmutex_lockorder
+ * @{
+ */
+
+/**
+ * @anchor oskmutex_lockorder
+ * @par Lock ordering for Mutexes and Spinlocks
+ *
+ * When an OSK Rwlock, Mutex or Spinlock is initialized, it is given a locking order.
+ * This is a number that is checked in QA builds to detect possible deadlock
+ * conditions. The order is checked when a thread calls
+ * osk_rwlock_read_lock() / osk_rwlock_write_lock() / osk_mutex_lock() /
+ * osk_spinlock_lock() / osk_spinlock_irq_lock(). If the calling
+ * thread already holds a lock with an order less than that of the object being
+ * locked, an assertion failure will occur.
+ *
+ * Lock ordering must be respected between OSK Rwlocks, Mutexes, and Spinlocks.
+ * That is, when obtaining an OSK Rwlock, Mutex or Spinlock, its lock order
+ * must be lower than any other OSK Rwlock, Mutex or Spinlock held by the current thread.
+ *
+ */
+/** @{ */
+
+typedef enum
+{
+ /**
+ * Reserved mutex order, indicating that the mutex will be the last to be
+ * locked, and all other OSK mutexes are obtained before this one.
+ *
+ * All other lock orders must be after this one, because we use this to
+ * ASSERT that lock orders are >= OSK_LOCK_ORDER_LAST
+ */
+ OSK_LOCK_ORDER_LAST = 0,
+
+ /**
+ * Lock order for umpp_descriptor_mapping.
+ *
+ * This lock is always obtained last: no other locks are obtained whilst
+ * operating on a descriptor mapping, and so this should be as high as
+ * possible in this enum (lower in number) than any other lock held by UMP.
+ *
+ * It can have the same order as any other lock in UMP that is always
+ * obtained last.
+ */
+ OSK_LOCK_ORDER_UMP_DESCRIPTOR_MAPPING,
+
+ /**
+ * Lock order for mutex protecting umpp_device::secure_id_map (this is in
+ * the 'single global UMP device').
+ *
+ * This must be obtained after (lower in number than) the
+ * OSK_LOCK_ORDER_UMP_SESSION_LOCK, since the allocation is often looked up
+ * in secure_id_map while manipulating the umpp_session::memory_usage list.
+ */
+ OSK_LOCK_ORDER_UMP_IDMAP_LOCK,
+
+ /**
+ * Lock order for mutex protecting the umpp_session::memory_usage list
+ */
+ OSK_LOCK_ORDER_UMP_SESSION_LOCK,
+
+
+ /**
+ *
+ */
+ OSK_LOCK_ORDER_OSK_FAILURE,
+
+ /**
+ * For the power management metrics system
+ */
+ OSK_LOCK_ORDER_PM_METRICS,
+
+ /**
+ * For fast queue management, with very little processing and
+ * no other lock held within the critical section.
+ */
+ OSK_LOCK_ORDER_QUEUE = OSK_LOCK_ORDER_PM_METRICS,
+
+ /**
+ * For register trace buffer access in kernel space
+ */
+
+ OSK_LOCK_ORDER_TB,
+
+ /**
+ * For KBASE_TRACE_ADD<...> macros
+ */
+ OSK_LOCK_ORDER_TRACE,
+
+ /**
+ * For modification of the MMU mask register, which is done as a read-modify-write
+ */
+ OSK_LOCK_ORDER_MMU_MASK,
+ /**
+ * For access and modification to the power state of a device
+ */
+ OSK_LOCK_ORDER_POWER_MGMT = OSK_LOCK_ORDER_MMU_MASK,
+
+ /**
+ * For access to active_count in kbase_pm_device_data
+ */
+ OSK_LOCK_ORDER_POWER_MGMT_ACTIVE = OSK_LOCK_ORDER_POWER_MGMT,
+
+ /**
+ * For access to gpu_cycle_counter_requests in kbase_pm_device_data
+ */
+ OSK_LOCK_ORDER_POWER_MGMT_GPU_CYCLE_COUNTER,
+ /**
+ * For the resources used during MMU pf or low-level job handling
+ */
+ OSK_LOCK_ORDER_JS_RUNPOOL_IRQ,
+
+ /**
+ * For job slot management
+ *
+ * This is an IRQ lock, and so must be held after all sleeping locks
+ */
+ OSK_LOCK_ORDER_JSLOT,
+
+ /**
+ * For hardware counters collection setup
+ */
+ OSK_LOCK_ORDER_HWCNT,
+
+ /**
+ * For use when zapping a context (see kbase_jd_zap_context)
+ */
+ OSK_LOCK_ORDER_JD_ZAP_CONTEXT,
+
+ /**
+ * AS lock, used to access kbase_as structure.
+ *
+ * This must be held after:
+ * - Job Scheduler Run Pool lock (OSK_LOCK_ORDER_RUNPOOL)
+ *
+ * This is an IRQ lock, and so must be held after all sleeping locks
+ *
+ * @since OSU 1.9
+ */
+ OSK_LOCK_ORDER_AS,
+
+ /**
+ * Job Scheduling Run Pool lock
+ *
+ * This must be held after:
+ * - Job Scheduling Context Lock (OSK_LOCK_ORDER_JS_CTX)
+ * - Job Slot management lock (OSK_LOCK_ORDER_JSLOT)
+ *
+ * This is an IRQ lock, and so must be held after all sleeping locks
+ *
+ */
+ OSK_LOCK_ORDER_JS_RUNPOOL,
+
+
+ /**
+ * Job Scheduling Policy Queue lock
+ *
+ * This must be held after Job Scheduling Context Lock (OSK_LOCK_ORDER_JS_CTX).
+ *
+ * Currently, there's no restriction on holding this at the same time as the JSLOT/JS_RUNPOOL locks - but, this doesn't happen anyway.
+ *
+ */
+ OSK_LOCK_ORDER_JS_QUEUE,
+
+ /**
+ * Job Scheduling Context Lock
+ *
+ * This must be held after Job Dispatch lock (OSK_LOCK_ORDER_JCTX), but before:
+ * - The Job Slot lock (OSK_LOCK_ORDER_JSLOT)
+ * - The Run Pool lock (OSK_LOCK_ORDER_JS_RUNPOOL)
+ * - The Policy Queue lock (OSK_LOCK_ORDER_JS_QUEUE)
+ *
+ * In addition, it must be held before the VM Region Lock (OSK_LOCK_ORDER_MEM_REG),
+ * because at some point need to modify the MMU registers to update the address
+ * space on scheduling in the context.
+ *
+ */
+ OSK_LOCK_ORDER_JS_CTX,
+
+ /**
+ * For memory mapping management
+ */
+ OSK_LOCK_ORDER_MEM_REG,
+
+ /**
+ * For job dispatch management
+ */
+ OSK_LOCK_ORDER_JCTX,
+
+ /**
+ * Register queue lock for model
+ */
+ OSK_LOCK_ORDER_BASE_REG_QUEUE,
+
+#ifdef CONFIG_MALI_T6XX_RT_PM
+ /**
+ * System power for mali-t604
+ */
+ OSK_LOCK_ORDER_CMU_PMU,
+#endif
+
+ /**
+ * Reserved mutex order, indicating that the mutex will be the first to be
+ * locked, and all other OSK mutexes are obtained after this one.
+ *
+ * All other lock orders must be before this one, because we use this to
+ * ASSERT that lock orders are <= OSK_LOCK_ORDER_FIRST
+ */
+ OSK_LOCK_ORDER_FIRST
+} osk_lock_order;
+
+/** @} */
+
+/** @} */ /* end group oskmutex_lockorder */
+
+/** @} */ /* end group base_osk_api */
+
+/** @} */ /* end group base_api */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _OSK_LOCK_ORDER_H_ */
diff --git a/drivers/gpu/arm/t6xx/kbase/osk/include/mali_osk_locks.h b/drivers/gpu/arm/t6xx/kbase/osk/include/mali_osk_locks.h
new file mode 100644
index 0000000..31a1a23
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/osk/include/mali_osk_locks.h
@@ -0,0 +1,675 @@
+/*
+ *
+ * (C) COPYRIGHT 2010-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+#ifndef _OSK_LOCKS_H_
+#define _OSK_LOCKS_H_
+
+#ifndef _OSK_H_
+#error "Include mali_osk.h directly"
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+ * @addtogroup base_api
+ * @{
+ */
+
+/**
+ * @addtogroup base_osk_api
+ * @{
+ */
+
+/**
+ * @defgroup osklocks Mutual Exclusion
+ *
+ * A read/write lock (rwlock) is used to control access to a shared resource,
+ * where multiple threads are allowed to read from the shared resource, but
+ * only one thread is allowed to write to the shared resources at any one time.
+ * A thread must specify the type of access (read/write) when locking the
+ * rwlock. If a rwlock is locked for write access, other threads that attempt
+ * to lock the same rwlock will block. If a rwlock is locked for read access,
+ * threads that attempts to lock the rwlock for write access, will block until
+ * until all threads with read access have unlocked the rwlock.
+
+ * @note If an OS does not provide a synchronisation object to implement a
+ * rwlock, a OSK mutex can be used instead for its implementation. This would
+ * only allow one reader or writer to access the shared resources at any one
+ * time.
+ *
+ * A mutex is used to control access to a shared resource, where only one
+ * thread is allowed access at any one time. A thread must lock the mutex
+ * to gain access; other threads that attempt to lock the same mutex will
+ * block. Mutexes can only be unlocked by the thread that holds the lock.
+ *
+ * @note OSK mutexes are intended for use in a situation where access to the
+ * shared resource is likely to be contended. OSK mutexes make use of the
+ * mutual exclusion primitives provided by the target OS, which often
+ * are considered "heavyweight".
+ *
+ * Spinlocks are also used to control access to a shared resource and
+ * enforce that only one thread has access at any one time. They differ from
+ * OSK mutexes in that they poll the mutex to obtain the lock. This makes a
+ * spinlock especially suited for contexts where you are not allowed to block
+ * while waiting for access to the shared resource. A OSK mutex could not be
+ * used in such a context as it can block while trying to obtain the mutex.
+ *
+ * A spinlock should be held for the minimum time possible, as in the contended
+ * case threads will not sleep but poll and therefore use CPU-cycles.
+ *
+ * While holding a spinlock, you must not sleep. You must not obtain a rwlock,
+ * mutex or do anything else that might block your thread. This is to prevent another
+ * thread trying to lock the same spinlock while your thread holds the spinlock,
+ * which could take a very long time (as it requires your thread to get scheduled
+ * in again and unlock the spinlock) or could even deadlock your system.
+ *
+ * Spinlocks are considered 'lightweight': for the uncontended cases, the mutex
+ * can be obtained quickly. For the lightly-contended cases on Multiprocessor
+ * systems, the mutex can be obtained quickly without resorting to
+ * "heavyweight" OS primitives.
+ *
+ * Two types of spinlocks are provided. A type that is safe to use when sharing
+ * a resource with an interrupt service routine, and one that should only be
+ * used to share the resource between threads. The former should be used to
+ * prevent deadlock between a thread that holds a spinlock while an
+ * interrupt occurs and the interrupt service routine trying to obtain the same
+ * spinlock too.
+ *
+ * @anchor oskmutex_spinlockdetails
+ * @par Important details of OSK Spinlocks.
+ *
+ * OSK spinlocks are not intended for high-contention cases. If high-contention
+ * usecases occurs frequently for a particular spinlock, then it is wise to
+ * consider using an OSK Mutex instead.
+ *
+ * @note An especially important reason for not using OSK Spinlocks in highly
+ * contended cases is that they defeat the OS's Priority Inheritance mechanisms
+ * that would normally alleviate Priority Inversion problems. This is because
+ * once the spinlock is obtained, the OS usually does not know which thread has
+ * obtained the lock, and so cannot know which thread must have its priority
+ * boosted to alleviate the Priority Inversion.
+ *
+ * As a guide, use a spinlock when CPU-bound for a short period of time
+ * (thousands of cycles). CPU-bound operations include reading/writing of
+ * memory or registers. Do not use a spinlock when IO bound (e.g. user input,
+ * buffered IO reads/writes, calls involving significant device driver IO
+ * calls).
+ */
+/** @{ */
+
+/**
+ * @brief Initialize a mutex
+ *
+ * Initialize a mutex structure. If the function returns successfully, the
+ * mutex is in the unlocked state.
+ *
+ * The caller must allocate the memory for the @see osk_mutex
+ * structure, which is then populated within this function. If the OS-specific
+ * mutex referenced from the structure cannot be initialized, an error is
+ * returned.
+ *
+ * The mutex must be terminated when no longer required, by using
+ * osk_mutex_term(). Otherwise, a resource leak may result in the OS.
+ *
+ * The mutex is initialized with a lock order parameter, \a order. Refer to
+ * @see oskmutex_lockorder for more information on Rwlock/Mutex/Spinlock lock
+ * ordering.
+ *
+ * It is a programming error to pass an invalid pointer (including NULL)
+ * through the \a lock parameter.
+ *
+ * It is a programming error to attempt to initialize a mutex that is
+ * currently initialized.
+ *
+ * @param[out] lock pointer to an uninitialized mutex structure
+ * @param[in] order the locking order of the mutex
+ * @return OSK_ERR_NONE on success, any other value indicates a failure.
+ */
+OSK_STATIC_INLINE osk_error osk_mutex_init(osk_mutex * const lock, osk_lock_order order) CHECK_RESULT;
+
+/**
+ * @brief Terminate a mutex
+ *
+ * Terminate the mutex pointed to by \a lock, which must be
+ * a pointer to a valid unlocked mutex. When the mutex is terminated, the
+ * OS-specific mutex is freed.
+ *
+ * It is a programming error to pass an invalid pointer (including NULL)
+ * through the \a lock parameter.
+ *
+ * It is a programming error to attempt to terminate a mutex that is currently
+ * terminated.
+ *
+ * @illegal It is illegal to call osk_mutex_term() on a locked mutex.
+ *
+ * @param[in] lock pointer to a valid mutex structure
+ */
+OSK_STATIC_INLINE void osk_mutex_term(osk_mutex * lock);
+
+/**
+ * @brief Lock a mutex
+ *
+ * Lock the mutex pointed to by \a lock. If the mutex is currently unlocked,
+ * the calling thread returns with the mutex locked. If a second thread
+ * attempts to lock the same mutex, it blocks until the first thread
+ * unlocks the mutex. If two or more threads are blocked waiting on the first
+ * thread to unlock the mutex, it is undefined as to which thread is unblocked
+ * when the first thread unlocks the mutex.
+ *
+ * It is a programming error to pass an invalid pointer (including NULL)
+ * through the \a lock parameter.
+ *
+ * It is a programming error to lock a mutex or spinlock with an order that is
+ * higher than any mutex or spinlock held by the current thread. Mutexes and
+ * spinlocks must be locked in the order of highest to lowest, to prevent
+ * deadlocks. Refer to @see oskmutex_lockorder for more information.
+ *
+ * It is a programming error to exit a thread while it has a locked mutex.
+ *
+ * It is a programming error to lock a mutex from an ISR context. In an ISR
+ * context you are not allowed to block what osk_mutex_lock() potentially does.
+ *
+ * @illegal It is illegal to call osk_mutex_lock() on a mutex that is currently
+ * locked by the caller thread. That is, it is illegal for the same thread to
+ * lock a mutex twice, without unlocking it in between.
+ *
+ * @param[in] lock pointer to a valid mutex structure
+ */
+OSK_STATIC_INLINE void osk_mutex_lock(osk_mutex * lock);
+
+/**
+ * @brief Unlock a mutex
+ *
+ * Unlock the mutex pointed to by \a lock. The calling thread must be the
+ * same thread that locked the mutex. If no other threads are waiting on the
+ * mutex to be unlocked, the function returns immediately, with the mutex
+ * unlocked. If one or more threads are waiting on the mutex to be unlocked,
+ * then this function returns, and a thread waiting on the mutex can be
+ * unblocked. It is undefined as to which thread is unblocked.
+ *
+ * @note It is not defined \em when a waiting thread is unblocked. For example,
+ * a thread calling osk_mutex_unlock() followed by osk_mutex_lock() may (or may
+ * not) obtain the lock again, preventing other threads from being
+ * released. Neither the 'immediately releasing', nor the 'delayed releasing'
+ * behavior of osk_mutex_unlock() can be relied upon. If such behavior is
+ * required, then you must implement it yourself, such as by using a second
+ * synchronization primitive.
+ *
+ * It is a programming error to pass an invalid pointer (including NULL)
+ * through the \a lock parameter.
+ *
+ * @illegal It is illegal for a thread to call osk_mutex_unlock() on a mutex
+ * that it has not locked, even if that mutex is currently locked by another
+ * thread. That is, it is illegal for any thread other than the 'owner' of the
+ * mutex to unlock it. And, you must not unlock an already unlocked mutex.
+ *
+ * @param[in] lock pointer to a valid mutex structure
+ */
+OSK_STATIC_INLINE void osk_mutex_unlock(osk_mutex * lock);
+
+/**
+ * @brief Initialize a spinlock
+ *
+ * Initialize a spinlock. If the function returns successfully, the
+ * spinlock is in the unlocked state.
+ *
+ * @note If the spinlock is used for sharing a resource with an interrupt service
+ * routine, use the IRQ safe variant of the spinlock, see osk_spinlock_irq.
+ * The IRQ safe variant should be used in that situation to prevent
+ * deadlock between a thread/ISR that holds a spinlock while an interrupt occurs
+ * and the interrupt service routine trying to obtain the same spinlock too.
+
+ * The caller must allocate the memory for the @see osk_spinlock
+ * structure, which is then populated within this function. If the OS-specific
+ * spinlock referenced from the structure cannot be initialized, an error is
+ * returned.
+ *
+ * The spinlock must be terminated when no longer required, by using
+ * osk_spinlock_term(). Otherwise, a resource leak may result in the OS.
+ *
+ * The spinlock is initialized with a lock order parameter, \a order. Refer to
+ * @see oskmutex_lockorder for more information on Rwlock/Mutex/Spinlock lock
+ * ordering.
+ *
+ * It is a programming error to pass an invalid pointer (including NULL)
+ * through the \a lock parameter.
+ *
+ * It is a programming error to attempt to initialize a spinlock that is
+ * currently initialized.
+ *
+ * @param[out] lock pointer to a spinlock structure
+ * @param[in] order the locking order of the spinlock
+ * @return OSK_ERR_NONE on success, any other value indicates a failure.
+ */
+OSK_STATIC_INLINE osk_error osk_spinlock_init(osk_spinlock * const lock, osk_lock_order order) CHECK_RESULT;
+
+/**
+ * @brief Terminate a spinlock
+ *
+ * Terminates the spinlock and releases any associated resources.
+ * The spinlock must be in an unlocked state.
+ *
+ * Terminate the spinlock pointed to by \a lock, which must be
+ * a pointer to a valid unlocked spinlock. When the spinlock is terminated, the
+ * OS-specific spinlock is freed.
+ *
+ * It is a programming error to pass an invalid pointer (including NULL)
+ * through the \a lock parameter.
+ *
+ * It is a programming error to attempt to terminate a spinlock that is currently
+ * terminated.
+ *
+ * @illegal It is illegal to call osk_spinlock_term() on a locked spinlock.
+ * @param[in] lock pointer to a valid spinlock structure
+ */
+OSK_STATIC_INLINE void osk_spinlock_term(osk_spinlock * lock);
+
+/**
+ * @brief Lock a spinlock
+ *
+ * Lock the spinlock pointed to by \a lock. If the spinlock is currently unlocked,
+ * the calling thread returns with the spinlock locked. If a second thread
+ * attempts to lock the same spinlock, it polls the spinlock until the first thread
+ * unlocks the spinlock. If two or more threads are polling the spinlock waiting
+ * on the first thread to unlock the spinlock, it is undefined as to which thread
+ * will lock the spinlock when the first thread unlocks the spinlock.
+ *
+ * While the spinlock is locked by the calling thread, the spinlock implementation
+ * should prevent any possible deadlock issues arising from another thread on the
+ * same CPU trying to lock the same spinlock.
+ *
+ * While holding a spinlock, you must not sleep. You must not obtain a rwlock,
+ * mutex or do anything else that might block your thread. This is to prevent another
+ * thread trying to lock the same spinlock while your thread holds the spinlock,
+ * which could take a very long time (as it requires your thread to get scheduled
+ * in again and unlock the spinlock) or could even deadlock your system.
+ *
+ * It is a programming error to pass an invalid pointer (including NULL)
+ * through the \a lock parameter.
+ *
+ * It is a programming error to lock a spinlock, rwlock or mutex with an order that
+ * is higher than any spinlock, rwlock, or mutex held by the current thread. Spinlocks,
+ * Rwlocks, and Mutexes must be locked in the order of highest to lowest, to prevent
+ * deadlocks. Refer to @see oskmutex_lockorder for more information.
+ *
+ * It is a programming error to exit a thread while it has a locked spinlock.
+ *
+ * It is a programming error to lock a spinlock from an ISR context. Use the IRQ
+ * safe spinlock type instead.
+ *
+ * @illegal It is illegal to call osk_spinlock_lock() on a spinlock that is currently
+ * locked by the caller thread. That is, it is illegal for the same thread to
+ * lock a spinlock twice, without unlocking it in between.
+ *
+ * @param[in] lock pointer to a valid spinlock structure
+ */
+OSK_STATIC_INLINE void osk_spinlock_lock(osk_spinlock * lock);
+
+/**
+ * @brief Unlock a spinlock
+ *
+ * Unlock the spinlock pointed to by \a lock. The calling thread must be the
+ * same thread that locked the spinlock. If no other threads are polling the
+ * spinlock waiting on the spinlock to be unlocked, the function returns
+ * immediately, with the spinlock unlocked. If one or more threads are polling
+ * the spinlock waiting on the spinlock to be unlocked, then this function
+ * returns, and a thread waiting on the spinlock can stop polling and continue
+ * with the spinlock locked. It is undefined as to which thread this is.
+ *
+ * @note It is not defined \em when a waiting thread continues. For example,
+ * a thread calling osk_spinlock_unlock() followed by osk_spinlock_lock() may (or may
+ * not) obtain the spinlock again, preventing other threads from continueing.
+ * Neither the 'immediately releasing', nor the 'delayed releasing'
+ * behavior of osk_spinlock_unlock() can be relied upon. If such behavior is
+ * required, then you must implement it yourself, such as by using a second
+ * synchronization primitive.
+ *
+ * It is a programming error to pass an invalid pointer (including NULL)
+ * through the \a lock parameter.
+ *
+ * @illegal It is illegal for a thread to call osk_spinlock_unlock() on a spinlock
+ * that it has not locked, even if that spinlock is currently locked by another
+ * thread. That is, it is illegal for any thread other than the 'owner' of the
+ * spinlock to unlock it. And, you must not unlock an already unlocked spinlock.
+ *
+ * @param[in] lock pointer to a valid spinlock structure
+ */
+OSK_STATIC_INLINE void osk_spinlock_unlock(osk_spinlock * lock);
+
+/**
+ * @brief Initialize an IRQ safe spinlock
+ *
+ * Initialize an IRQ safe spinlock. If the function returns successfully, the
+ * spinlock is in the unlocked state.
+ *
+ * This variant of spinlock is used for sharing a resource with an interrupt
+ * service routine. The IRQ safe variant should be used in this siutation to
+ * prevent deadlock between a thread/ISR that holds a spinlock while an interrupt
+ * occurs and the interrupt service routine trying to obtain the same spinlock
+ * too. If the spinlock is not used to share a resource with an interrupt service
+ * routine, one should use the osk_spinlock instead of the osk_spinlock_irq
+ * variant, see osk_spinlock_init().
+
+ * The caller must allocate the memory for the @see osk_spinlock_irq
+ * structure, which is then populated within this function. If the OS-specific
+ * spinlock referenced from the structure cannot be initialized, an error is
+ * returned.
+ *
+ * The spinlock must be terminated when no longer required, by using
+ * osk_spinlock_irq_term(). Otherwise, a resource leak may result in the OS.
+ *
+ * The spinlock is initialized with a lock order parameter, \a order. Refer to
+ * @see oskmutex_lockorder for more information on Rwlock/Mutex/Spinlock lock
+ * ordering.
+ *
+ * It is a programming error to pass an invalid pointer (including NULL)
+ * through the \a lock parameter.
+ *
+ * It is a programming error to attempt to initialize a spinlock that is
+ * currently initialized.
+ *
+ * @param[out] lock pointer to a IRQ safe spinlock structure
+ * @param[in] order the locking order of the IRQ safe spinlock
+ * @return OSK_ERR_NONE on success, any other value indicates a failure.
+ */
+OSK_STATIC_INLINE osk_error osk_spinlock_irq_init(osk_spinlock_irq * const lock, osk_lock_order order) CHECK_RESULT;
+
+/**
+ * @brief Terminate an IRQ safe spinlock
+ *
+ * Terminate the IRQ safe spinlock pointed to by \a lock, which must be
+ * a pointer to a valid unlocked IRQ safe spinlock. When the IRQ safe spinlock
+ * is terminated, the OS-specific spinlock is freed.
+ *
+ * It is a programming error to pass an invalid pointer (including NULL)
+ * through the \a lock parameter.
+ *
+ * It is a programming error to attempt to terminate a IRQ safe pinlock that is
+ * currently terminated.
+ *
+ * @param[in] lock pointer to a valid IRQ safe spinlock structure
+ */
+OSK_STATIC_INLINE void osk_spinlock_irq_term(osk_spinlock_irq * lock);
+
+/**
+ * @brief Lock an IRQ safe spinlock
+ *
+ * Lock the IRQ safe spinlock (from here on refered to as 'spinlock') pointed to
+ * by \a lock. If the spinlock is currently unlocked, the calling thread returns
+ * with the spinlock locked. If a second thread attempts to lock the same spinlock,
+ * it polls the spinlock until the first thread unlocks the spinlock. If two or
+ * more threads are polling the spinlock waiting on the first thread to unlock the
+ * spinlock, it is undefined as to which thread will lock the spinlock when the
+ * first thread unlocks the spinlock.
+ *
+ * While the spinlock is locked by the calling thread, the spinlock implementation
+ * should prevent any possible deadlock issues arising from another thread on the
+ * same CPU trying to lock the same spinlock.
+ *
+ * While holding a spinlock, you must not sleep. You must not obtain a rwlock,
+ * mutex or do anything else that might block your thread. This is to prevent another
+ * thread trying to lock the same spinlock while your thread holds the spinlock,
+ * which could take a very long time (as it requires your thread to get scheduled
+ * in again and unlock the spinlock) or could even deadlock your system.
+ *
+ * It is a programming error to pass an invalid pointer (including NULL)
+ * through the \a lock parameter.
+ *
+ * It is a programming error to lock a spinlock, rwlock or mutex with an order that
+ * is higher than any spinlock, rwlock, or mutex held by the current thread. Spinlocks,
+ * Rwlocks, and Mutexes must be locked in the order of highest to lowest, to prevent
+ * deadlocks. Refer to @see oskmutex_lockorder for more information.
+ *
+ * It is a programming error to exit a thread while it has a locked spinlock.
+ *
+ * @illegal It is illegal to call osk_spinlock_irq_lock() on a spinlock that is
+ * currently locked by the caller thread. That is, it is illegal for the same thread
+ * to lock a spinlock twice, without unlocking it in between.
+ *
+ * @param[in] lock pointer to a valid IRQ safe spinlock structure
+ */
+OSK_STATIC_INLINE void osk_spinlock_irq_lock(osk_spinlock_irq * lock);
+
+/**
+ * @brief Unlock an IRQ safe spinlock
+ *
+ * Unlock the IRQ safe spinlock (from hereon refered to as 'spinlock') pointed to
+ * by \a lock. The calling thread/ISR must be the same thread/ISR that locked the
+ * spinlock. If no other threads/ISRs are polling the spinlock waiting on the spinlock
+ * to be unlocked, the function returns* immediately, with the spinlock unlocked. If
+ * one or more threads/ISRs are polling the spinlock waiting on the spinlock to be unlocked,
+ * then this function returns, and a thread/ISR waiting on the spinlock can stop polling
+ * and continue with the spinlock locked. It is undefined as to which thread/ISR this is.
+ *
+ * @note It is not defined \em when a waiting thread/ISR continues. For example,
+ * a thread/ISR calling osk_spinlock_irq_unlock() followed by osk_spinlock_irq_lock() may
+ * (or may not) obtain the spinlock again, preventing other threads from continueing.
+ * Neither the 'immediately releasing', nor the 'delayed releasing'
+ * behavior of osk_spinlock_irq_unlock() can be relied upon. If such behavior is
+ * required, then you must implement it yourself, such as by using a second
+ * synchronization primitive.
+ *
+ * It is a programming error to pass an invalid pointer (including NULL)
+ * through the \a lock parameter.
+ *
+ * @illegal It is illegal for a thread to call osk_spinlock_irq_unlock() on a spinlock
+ * that it has not locked, even if that spinlock is currently locked by another
+ * thread. That is, it is illegal for any thread other than the 'owner' of the
+ * spinlock to unlock it. And, you must not unlock an already unlocked spinlock.
+ *
+ * @param[in] lock pointer to a valid IRQ safe spinlock structure
+ */
+OSK_STATIC_INLINE void osk_spinlock_irq_unlock(osk_spinlock_irq * lock);
+
+/**
+ * @brief Initialize a rwlock
+ *
+ * Read/write locks allow multiple readers to obtain the lock (shared access),
+ * or one writer to obtain the lock (exclusive access).
+ * Read/write locks are created in an unlocked state.
+ *
+ * Initialize a rwlock structure. If the function returns successfully, the
+ * rwlock is in the unlocked state.
+ *
+ * The caller must allocate the memory for the @see osk_rwlock
+ * structure, which is then populated within this function. If the OS-specific
+ * rwlock referenced from the structure cannot be initialized, an error is
+ * returned.
+ *
+ * The rwlock must be terminated when no longer required, by using
+ * osk_rwlock_term(). Otherwise, a resource leak may result in the OS.
+ *
+ * The rwlock is initialized with a lock order parameter, \a order. Refer to
+ * @see oskmutex_lockorder for more information on Rwlock/Mutex/Spinlock lock
+ * ordering.
+ *
+ * It is a programming error to pass an invalid pointer (including NULL)
+ * through the \a lock parameter.
+ *
+ * It is a programming error to attempt to initialize a rwlock that is
+ * currently initialized.
+ *
+ * @param[out] lock pointer to a rwlock structure
+ * @param[in] order the locking order of the rwlock
+ * @return OSK_ERR_NONE on success, any other value indicates a failure.
+ */
+OSK_STATIC_INLINE osk_error osk_rwlock_init(osk_rwlock * const lock, osk_lock_order order) CHECK_RESULT;
+
+/**
+ * @brief Terminate a rwlock
+ *
+ * Terminate the rwlock pointed to by \a lock, which must be
+ * a pointer to a valid unlocked rwlock. When the rwlock is terminated, the
+ * OS-specific rwlock is freed.
+ *
+ * It is a programming error to pass an invalid pointer (including NULL)
+ * through the \a lock parameter.
+ *
+ * It is a programming error to attempt to terminate a rwlock that is currently
+ * terminated.
+ *
+ * @illegal It is illegal to call osk_rwlock_term() on a locked rwlock.
+ *
+ * @param[in] lock pointer to a valid rwlock structure
+ */
+OSK_STATIC_INLINE void osk_rwlock_term(osk_rwlock * lock);
+
+/**
+ * @brief Lock a rwlock for read access
+ *
+ * Lock the rwlock pointed to by \a lock for read access. A rwlock may
+ * be locked for read access by multiple threads. If the mutex
+ * mutex is not locked for exclusive write access, the calling thread
+ * returns with the rwlock locked for read access. If the mutex is
+ * currently locked for exclusive write access, the calling thread blocks
+ * until the thread with exclusive write access unlocks the rwlock.
+ * If multiple threads are blocked waiting for read access or exclusive
+ * write access to the rwlock, it is undefined as to which thread is
+ * unblocked when the rwlock is unlocked (by the thread with exclusive
+ * write access).
+ *
+ * It is a programming error to pass an invalid pointer (including NULL)
+ * through the \a lock parameter.
+ *
+ * It is a programming error to lock a rwlock, mutex or spinlock with an order that is
+ * higher than any rwlock, mutex or spinlock held by the current thread. Rwlocks, mutexes and
+ * spinlocks must be locked in the order of highest to lowest, to prevent
+ * deadlocks. Refer to @see oskmutex_lockorder for more information.
+ *
+ * It is a programming error to exit a thread while it has a locked rwlock.
+ *
+ * It is a programming error to lock a rwlock from an ISR context. In an ISR
+ * context you are not allowed to block what osk_rwlock_read_lock() potentially does.
+ *
+ * @illegal It is illegal to call osk_rwlock_read_lock() on a rwlock that is currently
+ * locked by the caller thread. That is, it is illegal for the same thread to
+ * lock a rwlock twice, without unlocking it in between.
+ * @param[in] lock pointer to a valid rwlock structure
+ */
+OSK_STATIC_INLINE void osk_rwlock_read_lock(osk_rwlock * lock);
+
+/**
+ * @brief Unlock a rwlock for read access
+ *
+ * Unlock the rwlock pointed to by \a lock. The calling thread must be the
+ * same thread that locked the rwlock for read access. If no other threads
+ * are waiting on the rwlock to be unlocked, the function returns
+ * immediately, with the rwlock unlocked. If one or more threads are waiting
+ * on the rwlock to be unlocked for write access, and the calling thread
+ * is the last thread holding the rwlock for read access, then this function
+ * returns, and a thread waiting on the rwlock for write access can be
+ * unblocked. It is undefined as to which thread is unblocked.
+ *
+ * @note It is not defined \em when a waiting thread is unblocked. For example,
+ * a thread calling osk_rwlock_read_unlock() followed by osk_rwlock_read_lock()
+ * may (or may not) obtain the lock again, preventing other threads from being
+ * released. Neither the 'immediately releasing', nor the 'delayed releasing'
+ * behavior of osk_rwlock_read_unlock() can be relied upon. If such behavior is
+ * required, then you must implement it yourself, such as by using a second
+ * synchronization primitve.
+ *
+ * It is a programming error to pass an invalid pointer (including NULL)
+ * through the \a lock parameter.
+ *
+ * @illegal It is illegal for a thread to call osk_rwlock_read_unlock() on a
+ * rwlock that it has not locked, even if that rwlock is currently locked by another
+ * thread. That is, it is illegal for any thread other than the 'owner' of the
+ * rwlock to unlock it. And, you must not unlock an already unlocked rwlock.
+
+ * @param[in] lock pointer to a valid rwlock structure
+ */
+OSK_STATIC_INLINE void osk_rwlock_read_unlock(osk_rwlock * lock);
+
+/**
+ * @brief Lock a rwlock for exclusive write access
+ *
+ * Lock the rwlock pointed to by \a lock for exclusive write access. If the
+ * rwlock is currently unlocked, the calling thread returns with the rwlock
+ * locked. If the rwlock is currently locked, the calling thread blocks
+ * until the last thread with read access or the thread with exclusive write
+ * access unlocks the rwlock. If multiple threads are blocked waiting
+ * for exclusive write access to the rwlock, it is undefined as to which
+ * thread is unblocked when the rwlock is unlocked (by either the last thread
+ * thread with read access or the thread with exclusive write access).
+ *
+ * It is a programming error to pass an invalid pointer (including NULL)
+ * through the \a lock parameter.
+ *
+ * It is a programming error to lock a rwlock, mutex or spinlock with an order that is
+ * higher than any rwlock, mutex or spinlock held by the current thread. Rwlocks, mutexes and
+ * spinlocks must be locked in the order of highest to lowest, to prevent
+ * deadlocks. Refer to @see oskmutex_lockorder for more information.
+ *
+ * It is a programming error to exit a thread while it has a locked rwlock.
+ *
+ * It is a programming error to lock a rwlock from an ISR context. In an ISR
+ * context you are not allowed to block what osk_rwlock_write_lock() potentially does.
+ *
+ * @illegal It is illegal to call osk_rwlock_write_lock() on a rwlock that is currently
+ * locked by the caller thread. That is, it is illegal for the same thread to
+ * lock a rwlock twice, without unlocking it in between.
+ *
+ * @param[in] lock pointer to a valid rwlock structure
+ */
+OSK_STATIC_INLINE void osk_rwlock_write_lock(osk_rwlock * lock);
+
+/**
+ * @brief Unlock a rwlock for exclusive write access
+ *
+ * Unlock the rwlock pointed to by \a lock. The calling thread must be the
+ * same thread that locked the rwlock for exclusive write access. If no
+ * other threads are waiting on the rwlock to be unlocked, the function returns
+ * immediately, with the rwlock unlocked. If one or more threads are waiting
+ * on the rwlock to be unlocked, then this function returns, and a thread
+ * waiting on the rwlock can be unblocked. It is undefined as to which
+ * thread is unblocked.
+ *
+ * @note It is not defined \em when a waiting thread is unblocked. For example,
+ * a thread calling osk_rwlock_write_unlock() followed by osk_rwlock_write_lock()
+ * may (or may not) obtain the lock again, preventing other threads from being
+ * released. Neither the 'immediately releasing', nor the 'delayed releasing'
+ * behavior of osk_rwlock_write_unlock() can be relied upon. If such behavior is
+ * required, then you must implement it yourself, such as by using a second
+ * synchronization primitve.
+ *
+ * It is a programming error to pass an invalid pointer (including NULL)
+ * through the \a lock parameter.
+ *
+ * @illegal It is illegal for a thread to call osk_rwlock_write_unlock() on a
+ * rwlock that it has not locked, even if that rwlock is currently locked by another
+ * thread. That is, it is illegal for any thread other than the 'owner' of the
+ * rwlock to unlock it. And, you must not unlock an already unlocked rwlock.
+ *
+ * @param[in] lock pointer to a valid read/write lock structure
+ */
+OSK_STATIC_INLINE void osk_rwlock_write_unlock(osk_rwlock * lock);
+
+/* @} */ /* end group osklocks */
+
+/** @} */ /* end group base_osk_api */
+
+/** @} */ /* end group base_api */
+
+/* pull in the arch header with the implementation */
+#include <osk/mali_osk_arch_locks.h>
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _OSK_LOCKS_H_ */
diff --git a/drivers/gpu/arm/t6xx/kbase/osk/include/mali_osk_low_level_mem.h b/drivers/gpu/arm/t6xx/kbase/osk/include/mali_osk_low_level_mem.h
new file mode 100644
index 0000000..0a76c828
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/osk/include/mali_osk_low_level_mem.h
@@ -0,0 +1,198 @@
+/*
+ *
+ * (C) COPYRIGHT 2010-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_osk_low_level_mem.h
+ *
+ * Defines the kernel low level memory abstraction layer for the base
+ * driver.
+ */
+
+#ifndef _OSK_LOW_LEVEL_MEM_H_
+#define _OSK_LOW_LEVEL_MEM_H_
+
+#ifndef _OSK_H_
+#error "Include mali_osk.h directly"
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+ * @addtogroup base_api
+ * @{
+ */
+
+/**
+ * @addtogroup base_osk_api
+ * @{
+ */
+
+/**
+ * @addtogroup osklowlevelmem Low level memory
+ *
+ * Provides functions to allocate physical memory and ensure cache coherency.
+ *
+ * @{
+ */
+
+/**
+ * CPU virtual address
+ */
+typedef void *osk_virt_addr;
+
+/**
+ * @brief Map a physical page into the kernel
+ *
+ * Maps a physical page that was previously allocated by osk_phy_pages_alloc()
+ * with a physical allocator setup for allocating pages for use by the kernel,
+ * @see osk_phy_allocator_init().
+ *
+ * Notes:
+ * - Kernel virtual memory is limited. Limit the number of pages mapped into
+ * the kernel and limit the duration of the mapping.
+ *
+ * @param[in] page physical address of the page to unmap
+ * @return CPU virtual address in the kernel, NULL in case of a failure.
+ */
+OSK_STATIC_INLINE void *osk_kmap(osk_phy_addr page) CHECK_RESULT;
+
+/**
+ * @brief Unmap a physical page from the kernel
+ *
+ * Unmaps a previously mapped physical page (with osk_kmap) from the kernel.
+ *
+ * @param[in] page physical address of the page to unmap
+ * @param[in] mapping virtual address of the mapping to unmap
+ */
+OSK_STATIC_INLINE void osk_kunmap(osk_phy_addr page, void * mapping);
+
+/**
+ * @brief Map a physical page into the kernel
+ *
+ * Maps a physical page that was previously allocated by osk_phy_pages_alloc()
+ * with a physical allocator setup for allocating pages for use by the kernel,
+ * @see osk_phy_allocator_init().
+ *
+ * Notes:
+ * @li Used for mapping a single page for a very short duration
+ * @li The system only supports limited number of atomic mappings,
+ * so use should be limited
+ * @li The caller must not sleep until after the osk_kunmap_atomic is called.
+ * @li It may be assumed that osk_k[un]map_atomic will not fail.
+ *
+ * @param[in] page physical address of the page to unmap
+ * @return CPU virtual address in the kernel, NULL in case of a failure.
+ */
+OSK_STATIC_INLINE void *osk_kmap_atomic(osk_phy_addr page) CHECK_RESULT;
+
+/**
+ * @brief Unmap a physical page from the kernel
+ *
+ * Unmaps a previously mapped physical page (with osk_kmap_atomic) from the kernel.
+ *
+ * @param[in] page physical address of the page to unmap
+ * @param[in] mapping virtual address of the mapping to unmap
+ */
+OSK_STATIC_INLINE void osk_kunmap_atomic(osk_phy_addr page, void * mapping);
+
+/**
+ * A pointer to a cache synchronization function, either osk_sync_to_cpu()
+ * or osk_sync_to_memory().
+ */
+typedef void (*osk_sync_kmem_fn)(osk_phy_addr, osk_virt_addr, size_t);
+
+/**
+ * @brief Synchronize a memory area for other system components usage
+ *
+ * Performs the necessary memory coherency operations on a given memory area,
+ * such that after the call, changes in memory are correctly seen by other
+ * system components. Any change made to memory after that call may not be seen
+ * by other system components.
+ *
+ * In effect:
+ * - all CPUs will perform a cache clean operation on their inner & outer data caches
+ * - any write buffers are drained (including that of outer cache controllers)
+ *
+ * This function waits until all operations have completed.
+ *
+ * The area is restricted to one page or less and must not cross a page boundary.
+ * The offset within the page is aligned to cache line size and size is ensured
+ * to be a multiple of the cache line size.
+ *
+ * Both physical and virtual address of the area need to be provided to support OS
+ * cache flushing APIs that either use the virtual or the physical address. When
+ * called from OS specific code it is allowed to only provide the address that
+ * is actually used by the specific OS and leave the other address as 0.
+ *
+ * @param[in] paddr physical address
+ * @param[in] vaddr CPU virtual address valid in the current user VM or the kernel VM
+ * @param[in] sz size of the area, <= OSK_PAGE_SIZE.
+ */
+OSK_STATIC_INLINE void osk_sync_to_memory(osk_phy_addr paddr, osk_virt_addr vaddr, size_t sz);
+
+/**
+ * @brief Synchronize a memory area for CPU usage
+ *
+ * Performs the necessary memory coherency operations on a given memory area,
+ * such that after the call, changes in memory are correctly seen by any CPU.
+ * Any change made to this area by any CPU before this call may be lost.
+ *
+ * In effect:
+ * - all CPUs will perform a cache clean & invalidate operation on their inner &
+ * outer data caches.
+ *
+ * @note Stricly only an invalidate operation is required but by cleaning the cache
+ * too we prevent loosing changes made to the memory area due to software bugs. By
+ * having these changes cleaned from the cache it allows us to catch the memory
+ * area getting corrupted with the help of watch points. In correct operation the
+ * clean & invalidate operation would not be more expensive than an invalidate
+ * operation. Also note that for security reasons, it is dangerous to expose a
+ * cache 'invalidate only' operation to user space.
+ *
+ * - any read buffers are flushed (including that of outer cache controllers)
+ *
+ * This function waits until all operations have completed.
+ *
+ * The area is restricted to one page or less and must not cross a page boundary.
+ * The offset within the page is aligned to cache line size and size is ensured
+ * to be a multiple of the cache line size.
+ *
+ * Both physical and virtual address of the area need to be provided to support OS
+ * cache flushing APIs that either use the virtual or the physical address. When
+ * called from OS specific code it is allowed to only provide the address that
+ * is actually used by the specific OS and leave the other address as 0.
+ *
+ * @param[in] paddr physical address
+ * @param[in] vaddr CPU virtual address valid in the current user VM or the kernel VM
+ * @param[in] sz size of the area, <= OSK_PAGE_SIZE.
+ */
+OSK_STATIC_INLINE void osk_sync_to_cpu(osk_phy_addr paddr, osk_virt_addr vaddr, size_t sz);
+
+/** @} */ /* end group osklowlevelmem */
+
+/** @} */ /* end group base_osk_api */
+
+/** @} */ /* end group base_api */
+
+/* pull in the arch header with the implementation */
+#include <osk/mali_osk_arch_low_level_mem.h>
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _OSK_LOW_LEVEL_MEM_ */
diff --git a/drivers/gpu/arm/t6xx/kbase/osk/include/mali_osk_math.h b/drivers/gpu/arm/t6xx/kbase/osk/include/mali_osk_math.h
new file mode 100644
index 0000000..3a2a1c1
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/osk/include/mali_osk_math.h
@@ -0,0 +1,82 @@
+/*
+ *
+ * (C) COPYRIGHT 2010-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_osk_math.h
+ * Implementation of the OS abstraction layer for the kernel device driver
+ */
+
+#ifndef _OSK_MATH_H_
+#define _OSK_MATH_H_
+
+#ifndef _OSK_H_
+#error "Include mali_osk.h directly"
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+ * @addtogroup base_api
+ * @{
+ */
+
+/**
+ * @addtogroup base_osk_api
+ * @{
+ */
+
+/**
+ * @addtogroup oskmath Math
+ *
+ * Math related functions for which no commmon behavior exists on OS.
+ *
+ * @{
+ */
+
+/**
+ * @brief Divide a 64-bit value with a 32-bit divider
+ *
+ * Performs an (unsigned) integer division of a 64-bit value
+ * with a 32-bit divider and returns the 64-bit result and
+ * 32-bit remainder.
+ *
+ * Provided as part of the OSK as not all OSs support 64-bit
+ * division in an uniform way. Currently required to support
+ * printing 64-bit numbers in the OSK debug message functions.
+ *
+ * @param[in,out] value pointer to a 64-bit value to be divided by
+ * \a divisor. The integer result of the division
+ * is stored in \a value on output.
+ * @param[in] divisor 32-bit divisor
+ * @return 32-bit remainder of the division
+ */
+OSK_STATIC_INLINE u32 osk_divmod6432(u64 *value, u32 divisor);
+
+/** @} */ /* end group oskmath */
+
+/** @} */ /* end group base_osk_api */
+
+/** @} */ /* end group base_api */
+
+/* pull in the arch header with the implementation */
+#include <osk/mali_osk_arch_math.h>
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _OSK_MATH_H_ */
diff --git a/drivers/gpu/arm/t6xx/kbase/osk/include/mali_osk_mem.h b/drivers/gpu/arm/t6xx/kbase/osk/include/mali_osk_mem.h
new file mode 100644
index 0000000..5663362
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/osk/include/mali_osk_mem.h
@@ -0,0 +1,268 @@
+/*
+ *
+ * (C) COPYRIGHT 2008-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_osk_mem.h
+ * Implementation of the OS abstraction layer for the kernel device driver
+ */
+
+#ifndef _OSK_MEM_H_
+#define _OSK_MEM_H_
+
+#ifndef _OSK_H_
+#error "Include mali_osk.h directly"
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* pull in the arch header with the implementation */
+#include <osk/mali_osk_arch_mem.h>
+
+/**
+ * @addtogroup base_api
+ * @{
+ */
+
+/**
+ * @addtogroup base_osk_api
+ * @{
+ */
+
+/**
+ * @addtogroup oskmem Memory
+ *
+ * Provides C standard library style memory allocation functions (e.g. malloc, free).
+ *
+ * @{
+ */
+
+/**
+ * @brief Allocate kernel heap memory
+ *
+ * Returns a buffer capable of containing at least \a size bytes. The
+ * contents of the buffer are undefined.
+ *
+ * The buffer is suitably aligned for storage and subsequent access of every
+ * type that the compiler supports. Therefore, the pointer to the start of the
+ * buffer may be cast into any pointer type, and be subsequently accessed from
+ * such a pointer, without loss of information.
+ *
+ * When the buffer is no longer in use, it must be freed with osk_free().
+ * Failure to do so will cause a memory leak.
+ *
+ * @note For the implementor: most toolchains supply memory allocation
+ * functions that meet the compiler's alignment requirements. Therefore, there
+ * is often no need to write code to align the pointer returned by your
+ * system's memory allocator. Refer to your system's memory allocator for more
+ * information (e.g. the malloc() function, if used).
+ *
+ * The buffer can be accessed by all threads in the kernel. You need
+ * not free the buffer from the same thread that allocated the memory.
+ *
+ * May block while allocating memory and is therefore not allowed in interrupt
+ * service routines.
+ *
+ * @illegal It is illegal to call osk_malloc() with \a size == 0.
+ *
+ * @param size Number of bytes to allocate
+ * @return On success, the buffer allocated. NULL on failure.
+ *
+ */
+OSK_STATIC_INLINE void *osk_malloc(size_t size) CHECK_RESULT;
+
+/**
+ * @brief Allocate and zero kernel heap memory
+ *
+ * Returns a buffer capable of containing at least \a size bytes.
+ * The buffer is initialized to zero.
+ *
+ * The buffer is suitably aligned for storage and subsequent access of every
+ * type that the compiler supports. Therefore, the pointer to the start of the
+ * buffer may be cast into any pointer type, and be subsequently accessed from
+ * such a pointer, without loss of information.
+ *
+ * When the buffer is no longer in use, it must be freed with osk_free().
+ * Failure to do so will cause a memory leak.
+ *
+ * @note For the implementor: most toolchains supply memory allocation
+ * functions that meet the compiler's alignment requirements. Therefore, there
+ * is often no need to write code to align the pointer returned by your
+ * system's memory allocator. Refer to your system's memory allocator for more
+ * information (e.g. the malloc() function, if used).
+ *
+ * The buffer can be accessed by all threads in the kernel. You need
+ * not free the buffer from the same thread that allocated the memory.
+ *
+ * May block while allocating memory and is therefore not allowed in interrupt
+ * service routines.
+ *
+ * @illegal It is illegal to call osk_calloc() with \a size == 0.
+ *
+ * @param[in] size number of bytes to allocate
+ * @return On success, the zero initialized buffer allocated. NULL on failure
+ */
+OSK_STATIC_INLINE void *osk_calloc(size_t size);
+
+/**
+ * @brief Free kernel heap memory
+ *
+ * Reclaims the buffer pointed to by the parameter \a ptr for the kernel.
+ * All memory returned from osk_malloc() and osk_calloc() must
+ * be freed before the kernel driver exits. Otherwise, a memory leak will
+ * occur.
+ *
+ * Memory must be freed once. It is an error to free the same non-NULL pointer
+ * more than once.
+ *
+ * It is legal to free the NULL pointer.
+ *
+ * @param[in] ptr Pointer to buffer to free
+ *
+ * May block while freeing memory and is therefore not allowed in interrupt
+ * service routines.
+ *
+ * @param[in] ptr pointer to memory previously allocated by
+ * osk_malloc() or osk_calloc(). If ptr is NULL no operation
+ * is performed.
+ */
+OSK_STATIC_INLINE void osk_free(void * ptr);
+
+/**
+ * @brief Allocate kernel memory at page granularity suitable for mapping into user space
+ *
+ * Allocates a number of pages from kernel virtual memory to store at least \a size bytes.
+ *
+ * The allocated memory is aligned to OSK_PAGE_SIZE bytes and is allowed to be mapped
+ * into user space with read/write access.
+ *
+ * The allocated memory is initialized to zero to prevent any data leaking from kernel space.
+ * One needs to be aware not to store any kernel objects or pointers here as these
+ * could be modified by the user at any time.
+ *
+ * If \a size is not a multiple of OSK_PAGE_SIZE, the last page of the allocation is
+ * only partially used. It is not allowed to store any data in the unused area of the
+ * last page.
+ *
+ * @illegal It is illegal to call osk_vmalloc() with \a size == 0.
+
+ * May block while allocating memory and is therefore not allowed in interrupt
+ * service routines.
+ *
+ * @param[in] size number of bytes to allocate (will be rounded up to
+ * a multiple of OSK_PAGE_SIZE).
+ * @return pointer to allocated memory, NULL on failure
+ */
+OSK_STATIC_INLINE void *osk_vmalloc(size_t size) CHECK_RESULT;
+
+/**
+ * @brief Free kernel memory
+ *
+ * Releases memory to the kernel, previously allocated with osk_vmalloc().
+ * The same pointer returned from osk_vmalloc() needs to be provided --
+ * freeing portions of an allocation is not allowed.
+ *
+ * May block while freeing memory and is therefore not allowed in interrupt
+ * service routines.
+ *
+ * @param[in] vaddr pointer to memory previously allocated by osk_vmalloc().
+ * If vaddr is NULL no operation is performed.
+ */
+OSK_STATIC_INLINE void osk_vfree(void *vaddr);
+
+#ifndef OSK_MEMSET
+/** @brief Fills memory.
+ *
+ * Sets the first \a size bytes of the block of memory pointed to by \a ptr to
+ * the specified value
+ * @param[out] ptr Pointer to the block of memory to fill.
+ * @param[in] chr Value to be set, passed as an int. The byte written into
+ * memory will be the smallest positive integer equal to (\a
+ * chr mod 256).
+ * @param[in] size Number of bytes to be set to the value.
+ * @return \a ptr is always passed through unmodified
+ *
+ * @note the prototype of the function is:
+ * @code void *OSK_MEMSET( void *ptr, int chr, size_t size ); @endcode
+ */
+#define OSK_MEMSET( ptr, chr, size ) You_must_define_the_OSK_MEMSET_macro_in_the_platform_layer
+
+#error You must define the OSK_MEMSET macro in the mali_osk_arch_mem.h layer.
+
+/* The definition was only provided for documentation purposes; remove it now. */
+#undef OSK_MEMSET
+#endif /* OSK_MEMSET */
+
+#ifndef OSK_MEMCPY
+/** @brief Copies memory.
+ *
+ * Copies the \a len bytes from the buffer pointed by the parameter \a src
+ * directly to the buffer pointed by \a dst.
+ *
+ * @illegal It is illegal to call OSK_MEMCPY with \a src overlapping \a
+ * dst anywhere in \a len bytes.
+ *
+ * @param[out] dst Pointer to the destination array where the content is to be copied.
+ * @param[in] src Pointer to the source of data to be copied.
+ * @param[in] len Number of bytes to copy.
+ * @return \a dst is always passed through unmodified.
+ *
+ * @note the prototype of the function is:
+ * @code void *OSK_MEMCPY( void *dst, CONST void *src, size_t len ); @endcode
+ */
+#define OSK_MEMCPY( dst, src, len ) You_must_define_the_OSK_MEMCPY_macro_in_the_platform_layer
+
+#error You must define the OSK_MEMCPY macro in the mali_osk_arch_mem.h file.
+
+/* The definition was only provided for documentation purposes; remove it now. */
+#undef OSK_MEMCPY
+#endif /* OSK_MEMCPY */
+
+#ifndef OSK_MEMCMP
+/** @brief Compare memory areas
+ *
+ * Compares \a len bytes of the memory areas pointed by the parameter \a s1 and
+ * \a s2.
+ *
+ * @param[in] s1 Pointer to the first area of memory to compare.
+ * @param[in] s2 Pointer to the second area of memory to compare.
+ * @param[in] len Number of bytes to compare.
+ * @return an integer less than, equal to, or greater than zero if the first
+ * \a len bytes of s1 is found, respectively, to be less than, to match, or
+ * be greater than the first \a len bytes of s2.
+ *
+ * @note the prototype of the function is:
+ * @code int OSK_MEMCMP( CONST void *s1, CONST void *s2, size_t len ); @endcode
+ */
+#define OSK_MEMCMP( s1, s2, len ) You_must_define_the_OSK_MEMCMP_macro_in_the_platform_layer
+
+#error You must define the OSK_MEMCMP macro in the mali_osk_arch_mem.h file.
+
+/* The definition was only provided for documentation purposes; remove it now. */
+#undef OSK_MEMCMP
+#endif /* OSK_MEMCMP */
+
+/** @} */ /* end group oskmem */
+
+/** @} */ /* end group base_osk_api */
+
+/** @} */ /* end group base_api */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _OSK_MEM_H_ */
diff --git a/drivers/gpu/arm/t6xx/kbase/osk/include/mali_osk_power.h b/drivers/gpu/arm/t6xx/kbase/osk/include/mali_osk_power.h
new file mode 100644
index 0000000..96ac4b3
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/osk/include/mali_osk_power.h
@@ -0,0 +1,75 @@
+/*
+ *
+ * (C) COPYRIGHT 2010-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+#ifndef _OSK_POWER_H_
+#define _OSK_POWER_H_
+
+/**
+ * @addtogroup base_api
+ * @{
+ */
+
+/**
+ * @addtogroup base_osk_api
+ * @{
+ */
+
+/**
+ * @addtogroup oskpower Power management
+ *
+ * Some OS need to approve power state changes to a device, either to
+ * control power to a bus the device resides on, or to give the OS
+ * power manager the chance to see if the power state change is allowed
+ * for the current OS power management policy.
+ *
+ * @{
+ */
+
+/**
+ * @brief Request and perform a change in the power state of the device
+ *
+ * A function to request the OS to perform a change the power state of a device. This
+ * function returns when the power state change has completed.
+ *
+ * This allows the OS to control the power for the bus on which the GPU device resides,
+ * and the OS power manager can verify changing the power state is allowed according to
+ * its own power management policy (the OS may have been informed that an application will
+ * make heavy use of the GPU soon). As a result of the request the OS is likely to
+ * request the GPU device driver to actually perform the power state change (in Windows
+ * CE for instance, the OS power manager will issue an IOCTL_POWER_SET to actually make
+ * the GPU device change the power state).
+ *
+ * The result of the request is either success (the GPU device driver has successfully
+ * completed the power state change for the GPU device), refused (the OS didn't allow
+ * the power state change), or failure (the GPU device driver encountered an error
+ * changing the power state).
+ *
+ * @param[in,out] info OS specific information necessary to control power to the device
+ * @param[in] state power state to switch to (off, idle, or active)
+ * @return OSK_POWER_REQUEST_FINISHED when the driver successfully completed the power
+ * state change for the device, OSK_POWER_REQUEST_FAILED when it failed, or
+ * OSK_POWER_REQUEST_REFUSED when the OS didn't allow the power state change.
+ */
+OSK_STATIC_INLINE osk_power_request_result osk_power_request(osk_power_info *info, osk_power_state state) CHECK_RESULT;
+
+/* @} */ /* end group oskpower */
+
+/** @} */ /* end group base_osk_api */
+
+/** @} */ /* end group base_api */
+
+/* pull in the arch header with the implementation */
+#include <osk/mali_osk_arch_power.h>
+
+#endif /* _OSK_POWER_H_ */
diff --git a/drivers/gpu/arm/t6xx/kbase/osk/include/mali_osk_time.h b/drivers/gpu/arm/t6xx/kbase/osk/include/mali_osk_time.h
new file mode 100644
index 0000000..101bf31
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/osk/include/mali_osk_time.h
@@ -0,0 +1,141 @@
+/*
+ *
+ * (C) COPYRIGHT 2010-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_osk_time.h
+ * Implementation of the OS abstraction layer for the kernel device driver
+ */
+
+#ifndef _OSK_TIME_H_
+#define _OSK_TIME_H_
+
+#ifndef _OSK_H_
+#error "Include mali_osk.h directly"
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+ * @addtogroup base_api
+ * @{
+ */
+
+/**
+ * @addtogroup base_osk_api
+ * @{
+ */
+
+/**
+ * @addtogroup osktime Time
+ *
+ * A set of time functions based on the OS tick timer which allow
+ * - retrieving the current tick count
+ * - determining if a deadline has passed
+ * - calculating the elapsed time between two tick counts
+ * - converting a time interval to a tick count
+ *
+ * Used in combination with scheduling timers, or determining duration of certain actions (timeouts, profiling).
+ * @{
+ */
+
+/**
+ * @brief Get current tick count
+ *
+ * Retrieves the current tick count in the OS native resolution. Use in
+ * combination with osk_time_after() to determine if current time has
+ * passed a deadline, or to determine the elapsed time with osk_time_tickstoms()
+ * and osk_time_after().
+ *
+ * The tick count resolution is 32-bit or higher, supporting a 1000Hz tick count
+ * of 2^32/1000*60*60*24 ~= 49.7 days before the counter wraps.
+ *
+ * @return current tick count
+ */
+OSK_STATIC_INLINE osk_ticks osk_time_now(void) CHECK_RESULT;
+
+/**
+ * @brief Convert milliseconds to ticks
+ *
+ * Converts \a ms milliseconds to ticks.
+ *
+ * Intended use of this function is to convert small timeout periods or
+ * calculate nearby deadlines (e.g. osk_ticks_now() + osk_time_mstoticks(50)).
+ *
+ * Supports converting a period of up to 2^32/1000*60*60*24 ~= 49.7 days
+ * in the case of a 1000Hz OS tick timer.
+ *
+ * @param[in] ms number of millisecons to convert to ticks
+ * @return number of ticks in \a ms milliseconds
+ */
+OSK_STATIC_INLINE u32 osk_time_mstoticks(u32 ms) CHECK_RESULT;
+
+/**
+ * @brief Calculate elapsed time
+ *
+ * Calculates elapsed time in milliseconds between tick \a ticka and \a tickb,
+ * taking into account that the tick counter may have wrapped. Note that
+ * \a tickb must be later than \a ticka in time.
+ *
+ * @param[in] ticka a tick count value (as returned from osk_time_now())
+ * @param[in] tickb a tick count value (as returned from osk_time_now())
+ * @return elapsed time in milliseconds
+ */
+OSK_STATIC_INLINE u32 osk_time_elapsed(osk_ticks ticka, osk_ticks tickb) CHECK_RESULT;
+
+/**
+ * @brief Determines which tick count is later in time
+ *
+ * Determines if \a ticka comes after \a tickb in time. Handles the case where
+ * the tick counter may have wrapped.
+ *
+ * Intended use of this function is to determine if a deadline has passed
+ * or to determine how the difference between two tick count values should
+ * be calculated.
+ *
+ * @param[in] ticka a tick count value (as returned from osk_time_now())
+ * @param[in] tickb a tick count value (as returned from osk_time_now())
+ * @return MALI_TRUE when \a ticka is after \a tickb in time.
+ * @return MALI_FALSE when \a tickb is after \a ticka in time.
+ */
+OSK_STATIC_INLINE mali_bool osk_time_after(osk_ticks ticka, osk_ticks tickb) CHECK_RESULT;
+
+/**
+ * @brief Retrieve current "wall clock" time
+ *
+ * This function returns the current time in a format that userspace can also
+ * produce and allows direct comparison of events in the kernel with events
+ * that userspace controls.
+ *
+ * @param[in] ts An osk_timespec structure
+ */
+OSK_STATIC_INLINE void osk_gettimeofday(osk_timeval *ts);
+
+/* @} */ /* end group osktime */
+
+/** @} */ /* end group base_osk_api */
+
+/** @} */ /* end group base_api */
+
+/* pull in the arch header with the implementation */
+#include <osk/mali_osk_arch_time.h>
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _OSK_TIME_H_ */
diff --git a/drivers/gpu/arm/t6xx/kbase/osk/include/mali_osk_timers.h b/drivers/gpu/arm/t6xx/kbase/osk/include/mali_osk_timers.h
new file mode 100644
index 0000000..098e0f4
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/osk/include/mali_osk_timers.h
@@ -0,0 +1,264 @@
+/*
+ *
+ * (C) COPYRIGHT 2010-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_osk_timers.h
+ * Implementation of the OS abstraction layer for the kernel device driver
+ */
+
+#ifndef _OSK_TIMERS_H_
+#define _OSK_TIMERS_H_
+
+#ifndef _OSK_H_
+#error "Include mali_osk.h directly"
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+ * @addtogroup base_api
+ * @{
+ */
+
+/**
+ * @addtogroup base_osk_api
+ * @{
+ */
+
+/**
+ * @addtogroup osktimers Timers
+ *
+ * A set of functions to control a one-shot timer. Timer expirations are
+ * set relative to current time at millisecond resolution. A minimum time
+ * period of 1 millisecond needs to be observed -- immediate firing of
+ * timers is not supported. A user-supplied function is called with a
+ * user-supplied argument when the timer expires. The expiration time
+ * of a timer cannot be changed once started - a timer first needs to
+ * be stopped before it can be started with another timer expiration.
+ *
+ * Examples of use: watchdog timeout on job execution duration,
+ * a job progress checker, power management profile timeouts.
+ *
+ * @{
+ */
+
+/**
+ * @brief Initializes a timer
+ *
+ * Initializes a timer. The timer is not started yet.
+ *
+ * Note For timers created on stack @ref osk_timer_on_stack_init() should be used.
+ *
+ * The timer may be reinitialized but only after having called osk_timer_term()
+ * on \a tim.
+ *
+ * It is a programming error to pass a NULL pointer for \a tim. This will raise
+ * an assertion in debug builds.
+ *
+ * @param[out] tim an osk timer object to initialize
+ * @return OSK_ERR_NONE on success. Any other value indicates failure.
+ */
+OSK_STATIC_INLINE osk_error osk_timer_init(osk_timer * const tim) CHECK_RESULT;
+
+/**
+ * @brief Initializes a timer on stack
+ *
+ * Initializes a timer created on stack. The timer is not started yet.
+ *
+ * The timer may be reinitialized but only after having called osk_timer_term()
+ * on \a tim.
+ *
+ * It is a programming error to pass a NULL pointer for \a tim. This will raise
+ * an assertion in debug builds.
+ *
+ * @param[out] tim an osk timer object to initialize
+ * @return OSK_ERR_NONE on success. Any other value indicates failure.
+ */
+OSK_STATIC_INLINE osk_error osk_timer_on_stack_init(osk_timer * const tim) CHECK_RESULT;
+
+/**
+ * @brief Starts a timer
+ *
+ * Starts a timer. When the timer expires in \a delay milliseconds, the
+ * registered callback function will be called with the user supplied
+ * argument.
+ *
+ * The callback needs to be registered with osk_timer_callback_set()
+ * at least once during the lifetime of timer \a tim and before starting
+ * the timer.
+ *
+ * You cannot start a timer that has been started already. A timer needs
+ * to be stopped before starting it again.
+ *
+ * A timer cannot expire immediately. The minimum \a delay value is 1.
+ *
+ * A timer may fail to start and is important to check the result of this
+ * function to prevent waiting for a callback that will never get called.
+ *
+ * It is a programming error to pass a NULL pointer for \a tim or to specify
+ * 0 for \a delay. This will raise an assertion in debug builds.
+ *
+ * @param[in] tim an initialized osk timer object
+ * @param[in] delay timer expiration in milliseconds, at least 1.
+ * @return OSK_ERR_NONE on success. Any other value indicates failure.
+ */
+OSK_STATIC_INLINE osk_error osk_timer_start(osk_timer *tim, u32 delay) CHECK_RESULT;
+
+/**
+ * @brief Starts a timer using a high-resolution parameter
+ *
+ * This is identical to osk_timer_start(), except that the argument is
+ * expressed in nanoseconds.
+ *
+ * @note whilst the parameter is high-resolution, the actual resolution of the
+ * timer may be much more coarse than nanoseconds. In this case, \a delay_ns
+ * will be rounded up to the timer resolution.
+ *
+ * It is a programming error to pass a NULL pointer for \a tim or to specify
+ * 0 for \a delay_ns. This will raise an assertion in debug builds.
+ *
+ * @param[in] tim an initialized osk timer object
+ * @param[in] delay_ns timer expiration in nanoseconds, at least 1.
+ * @return OSK_ERR_NONE on success. Any other value indicates failure.
+ */
+OSK_STATIC_INLINE osk_error osk_timer_start_ns(osk_timer *tim, u64 delay_ns) CHECK_RESULT;
+
+/**
+ * @brief Modifies a timer's timeout
+ *
+ * See \a osk_timer_start for details.
+ *
+ * The only difference of this function from \a osk_timer_start is:
+ * If the timer was already set to expire the timer is modified to expire in \a new_delay milliseconds.
+ *
+ * It is a programming error to pass a NULL pointer for \a tim or to specify
+ * 0 for \a new_delay. This will raise an assertion in debug builds.
+ *
+ * @param[in] tim an initialized osk timer object
+ * @param[in] new_delay timer expiration in milliseconds, at least 1.
+ * @return OSK_ERR_NONE on success. Any other value indicates failure.
+ */
+OSK_STATIC_INLINE osk_error osk_timer_modify(osk_timer *tim, u32 new_delay) CHECK_RESULT;
+
+/**
+ * @brief Modifies a timer's timeout using a high-resolution parameter
+ *
+ * This is identical to osk_timer_modify(), except that the argument is
+ * expressed in nanoseconds.
+ *
+ * @note whilst the parameter is high-resolution, the actual resolution of the
+ * timer may be much more coarse than nanoseconds. In this case, \a new_delay_ns
+ * will be rounded up to the timer resolution.
+ *
+ * It is a programming error to pass a NULL pointer for \a tim or to specify
+ * 0 for \a new_delay_ns. This will raise an assertion in debug builds.
+ *
+ * @param[in] tim an initialized osk timer object
+ * @param[in] new_delay_ns timer expiration in nanoseconds, at least 1.
+ * @return OSK_ERR_NONE on success. Any other value indicates failure.
+ */
+OSK_STATIC_INLINE osk_error osk_timer_modify_ns(osk_timer *tim, u64 new_delay_ns) CHECK_RESULT;
+
+/**
+ * @brief Stops a timer
+ *
+ * Stops a timer. If the timer already expired this will have no
+ * effect. If the callback for the timer is currently executing,
+ * this function will block on its completion.
+ *
+ * A non-expired timer will have to be stopped before it can be
+ * started again with osk_timer_start().
+ *
+ * It is a programming error to pass a NULL pointer for \a tim. This will raise
+ * an assertion in debug builds.
+ *
+ * @param[in] tim an initialized osk timer object
+ */
+OSK_STATIC_INLINE void osk_timer_stop(osk_timer *tim);
+
+/**
+ * @brief Registers a callback function with a timer
+ *
+ * Registers a callback function to be called when the timer expires.
+ * The callback function is called with the provided \a data argument.
+ * The timer should be stopped when registering the callback.
+ *
+ * The code executing within the timer call back is limited as it
+ * is assumed it executes in an IRQ context:
+ * - Access to user space is not allowed - there is no process context
+ * - It is not allowed to call any function that may block
+ * - Only spinlocks or atomics may be used to access shared data structures
+ *
+ * If a timer requires more work to be done than can be achieved in an IRQ
+ * context, then it should defer the work to an OSK workqueue.
+ *
+ * It is a programming error to pass a NULL pointer for \a tim, \a callback.
+ * This will raise an assertion in debug builds. NULL is allowed for \a data.
+ *
+ * @param[in] tim an initialized osk timer object
+ * @param[in] callback timer callback function
+ * @param[in] data argument to pass to timer callback
+ */
+OSK_STATIC_INLINE void osk_timer_callback_set(osk_timer *tim, osk_timer_callback callback, void *data);
+
+/**
+ * @brief Terminates a timer
+ *
+ * Frees any resources allocated for a timer. A timer needs to be
+ * stopped with osk_timer_stop() before a timer can be terminated.
+ *
+ * Note For timers created on stack @ref osk_timer_on_stack_term() should be used.
+ *
+ * A timer may be reinitialized after it has been terminated.
+ *
+ * It is a programming error to pass a NULL pointer for \a tim. This will raise
+ * an assertion in debug builds.
+ *
+ * @param[in] tim an initialized osk timer object
+ */
+OSK_STATIC_INLINE void osk_timer_term(osk_timer *tim);
+
+/**
+ * @brief Terminates a timer on stack
+ *
+ * Frees any resources allocated for a timer created on stack. A timer needs to be
+ * stopped with osk_timer_stop() before a timer can be terminated.
+ *
+ * A timer may be reinitialized after it has been terminated.
+ *
+ * It is a programming error to pass a NULL pointer for \a tim. This will raise
+ * an assertion in debug builds.
+ *
+ * @param[in] tim an initialized osk timer object
+ */
+OSK_STATIC_INLINE void osk_timer_on_stack_term(osk_timer *tim);
+
+/* @} */ /* end group osktimers */
+
+/** @} */ /* end group base_osk_api */
+
+/** @} */ /* end group base_api */
+
+/* pull in the arch header with the implementation */
+#include <osk/mali_osk_arch_timers.h>
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _OSK_TIMERS_H_ */
diff --git a/drivers/gpu/arm/t6xx/kbase/osk/include/mali_osk_types.h b/drivers/gpu/arm/t6xx/kbase/osk/include/mali_osk_types.h
new file mode 100644
index 0000000..8bd232f
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/osk/include/mali_osk_types.h
@@ -0,0 +1,92 @@
+/*
+ *
+ * (C) COPYRIGHT 2010-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+#ifndef _OSK_TYPES_H_
+#define _OSK_TYPES_H_
+
+#ifndef _OSK_H_
+#error "Include mali_osk.h directly"
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+typedef enum osk_error
+{
+ OSK_ERR_NONE, /**< Success */
+ OSK_ERR_FAIL, /**< Unclassified failure */
+ OSK_ERR_MAP, /**< Memory mapping operation failed */
+ OSK_ERR_ALLOC, /**< Memory allocation failed */
+ OSK_ERR_ACCESS /**< Permissions to access an object failed */
+} osk_error;
+
+#define OSK_STATIC_INLINE static __inline
+#define OSK_BITS_PER_LONG (8 * sizeof(unsigned long))
+#define OSK_ULONG_MAX (~0UL)
+
+/**
+ * OSK workqueue flags
+ *
+ * Flags specifying the kind of workqueue to create. Flags can be combined.
+ */
+
+/**
+ * By default a work queue guarantees non-reentrace on the same CPU.
+ * When the OSK_WORKQ_NON_REENTRANT flag is set, this guarantee is
+ * extended to all CPUs.
+ */
+#define OSK_WORKQ_NON_REENTRANT (1 << 0)
+/**
+ * Work units submitted to a high priority queue start execution as soon
+ * as resources are available.
+ */
+#define OSK_WORKQ_HIGH_PRIORITY (1 << 1)
+/**
+ * Ensures there is always a thread available to run tasks on this queue. This
+ * flag should be set if the work queue is involved in reclaiming memory when
+ * its work units run.
+ */
+#define OSK_WORKQ_RESCUER (1 << 2)
+
+/**
+ * Prototype for a function called when a OSK timer expires. See osk_timer_callback_set()
+ * that registers the callback function with a OSK timer.
+ */
+typedef void (*osk_timer_callback)(void *);
+
+typedef enum osk_power_state
+{
+ OSK_POWER_STATE_OFF, /**< Device is off */
+ OSK_POWER_STATE_IDLE, /**< Device is idle */
+ OSK_POWER_STATE_ACTIVE /**< Device is active */
+} osk_power_state;
+
+typedef enum osk_power_request_result
+{
+ OSK_POWER_REQUEST_FINISHED, /**< The driver successfully completed the power state change for the device */
+ OSK_POWER_REQUEST_FAILED, /**< The driver for the device encountered an error changing the power state */
+ OSK_POWER_REQUEST_REFUSED /**< The OS didn't allow the power state change for the device */
+} osk_power_request_result;
+
+
+#include <osk/mali_osk_arch_types.h>
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _OSK_TYPES_H_ */
+
diff --git a/drivers/gpu/arm/t6xx/kbase/osk/include/mali_osk_waitq.h b/drivers/gpu/arm/t6xx/kbase/osk/include/mali_osk_waitq.h
new file mode 100644
index 0000000..c6e0195
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/osk/include/mali_osk_waitq.h
@@ -0,0 +1,134 @@
+/*
+ *
+ * (C) COPYRIGHT 2010-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_osk_waitq.h
+ * Implementation of the OS abstraction layer for the kernel device driver
+ */
+
+#ifndef _OSK_WAITQ_H_
+#define _OSK_WAITQ_H_
+
+#ifndef _OSK_H_
+#error "Include mali_osk.h directly"
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+ * @addtogroup base_api
+ * @{
+ */
+
+/**
+ * @addtogroup base_osk_api
+ * @{
+ */
+
+/**
+ * @addtogroup oskwaitq Wait queue
+ *
+ * A waitqueue is used to wait for a specific condition to become true.
+ * The waitqueue has a flag that needs to be set when the condition
+ * becomes true and cleared when the condition becomes false.
+ *
+ * Threads wait for the specific condition to become true by calling
+ * osk_waitq_wait(). If the condition is already true osk_waitq_wait()
+ * will return immediately.
+ *
+ * When a thread causes the specific condition to become true, it needs
+ * to set the waitqueue flag with osk_waitq_set(), which will wakeup
+ * all threads waiting on the waitqueue.
+ *
+ * When a thread causes the specific condition to become false, it needs
+ * to clear the waitqueue flag with osk_waitq_clear().
+ *
+ * @{
+ */
+
+/**
+ * @brief Initialize a wait queue
+ *
+ * Initializes a waitqueue. The waitqueue flag is cleared assuming the
+ * specific condition associated with the waitqueue is false.
+ *
+ * @param[out] wq wait queue to initialize
+ * @return OSK_ERROR_NONE on success. Any other value indicates failure.
+ */
+OSK_STATIC_INLINE osk_error osk_waitq_init(osk_waitq * const wq) CHECK_RESULT;
+
+/**
+ * @brief Wait until waitqueue flag is set
+ *
+ * Blocks until a thread signals the waitqueue that the condition has
+ * become true. Use osk_waitq_set() to set the waitqueue flag to signal
+ * the condition has become true. If the condition is already true,
+ * this function will return immediately.
+ *
+ * @param[in] wq initialized waitqueue
+ */
+OSK_STATIC_INLINE void osk_waitq_wait(osk_waitq *wq);
+
+/**
+ * @brief Set the waitqueue flag
+ *
+ * Signals the waitqueue that the condition associated with the waitqueue
+ * has become true. All threads on the waitqueue will be woken up. The
+ * waitqueue flag is set.
+ *
+ * @param[in] wq initialized waitqueue
+ */
+OSK_STATIC_INLINE void osk_waitq_set(osk_waitq *wq);
+
+/**
+ * @brief Clear the waitqueue flag
+ *
+ * Signals the waitqueue that the condition associated with the waitqueue
+ * has become false. The waitqueue flag is reset (cleared).
+ *
+ * @param[in] wq initialized waitqueue
+ */
+OSK_STATIC_INLINE void osk_waitq_clear(osk_waitq *wq);
+
+/**
+ * @brief Terminate a wait queue
+ *
+ * Frees any resources allocated for a waitqueue.
+ *
+ * No threads are allowed to be waiting on the waitqueue when terminating
+ * the waitqueue. If there are waiting threads, they should be woken up
+ * first by setting the waitqueue flag with osk_waitq_set() after which
+ * they must cease using the waitqueue.
+ *
+ * @param[in] wq initialized waitqueue
+ */
+OSK_STATIC_INLINE void osk_waitq_term(osk_waitq *wq);
+
+/* @} */ /* end group oskwaitq */
+
+/** @} */ /* end group base_osk_api */
+
+/** @} */ /* end group base_api */
+
+/* pull in the arch header with the implementation */
+#include <osk/mali_osk_arch_waitq.h>
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _OSK_WAITQ_H_ */
diff --git a/drivers/gpu/arm/t6xx/kbase/osk/include/mali_osk_workq.h b/drivers/gpu/arm/t6xx/kbase/osk/include/mali_osk_workq.h
new file mode 100644
index 0000000..0312755
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/osk/include/mali_osk_workq.h
@@ -0,0 +1,188 @@
+/*
+ *
+ * (C) COPYRIGHT 2010-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+#ifndef _OSK_WORKQ_H
+#define _OSK_WORKQ_H
+
+#ifndef _OSK_H_
+#error "Include mali_osk.h directly"
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* pull in the arch header with the implementation */
+#include <osk/mali_osk_arch_workq.h>
+
+/**
+ * @addtogroup base_api
+ * @{
+ */
+
+/**
+ * @addtogroup base_osk_api
+ * @{
+ */
+
+/**
+ * @addtogroup oskworkqueue Work queue
+ *
+ * A workqueue is a queue of functions that will be invoked by one or more worker threads
+ * at some future time. Functions are invoked in FIFO order by each worker thread. However,
+ * overall execution of work is <b>not guaranteed to occur in FIFO order</b>, because two or
+ * more worker threads may be processing items concurrently from the same work queue.
+ *
+ * Each function that is submitted to the workqueue needs to be represented by a work unit
+ * (osk_workq_work). When a function is invoked, a pointer to the work unit is passed to the
+ * invoked function. A work unit needs to be embedded within the object that the invoked
+ * function needs to operate on, so that the invoked function can determine a pointer to the
+ * object it needs to operate on.
+ *
+ * @{
+ */
+
+/**
+ * @brief Initialize a work queue
+ *
+ * Initializes an empty work queue. One or more threads within the system will
+ * be servicing the work units submitted to the work queue.
+ *
+ * It is a programming error to pass an invalid pointer (including NULL) for the
+ * wq parameter. Passing NULL will assert in debug builds.
+ *
+ * It is a programming error to pass an invalid pointer (including NULL) for the
+ * name parameter. Passing NULL will assert in debug builds.
+ *
+ * It is a programming error to pass a value for flags other than a combination
+ * of the OSK_WORK_ constants or 0. Doing so will assert in debug builds.
+ *
+ * @param[out] wq workqueue to initialize
+ * @param[in] name The name for the queue (may be visible in the process list)
+ * @param[in] flags flags specifying behavior of work queue, see OSK_WORKQ_ constants.
+ * @return OSK_ERR_NONE on success. Any other value indicates failure.
+ */
+OSK_STATIC_INLINE osk_error osk_workq_init(osk_workq * const wq, const char *name, u32 flags) CHECK_RESULT;
+
+/**
+ * @brief Terminate a work queue
+ *
+ * Stops accepting new work and waits until the work queue is empty and
+ * all work has been completed, then frees any resources allocated for the workqueue.
+ *
+ * @param[in] wq intialized workqueue
+ */
+OSK_STATIC_INLINE void osk_workq_term(osk_workq *wq);
+
+/**
+ * @brief (Re)initialize a work object
+ *
+ * Sets up a work object to call the given function pointer.
+ * See \a osk_workq_work_init_on_stack if the work object
+ * is a stack object
+ * The function \a fn needs to match the prototype: void fn(osk_workq_work *).
+ *
+ * It is a programming error to pass an invalid pointer (including NULL) for
+ * any parameter. Passing NULL will assert in debug builds.
+ *
+ * @param[out] wk work unit to be initialized
+ * @param[in] fn function to be invoked at some future time
+ */
+OSK_STATIC_INLINE void osk_workq_work_init(osk_workq_work * const wk, osk_workq_fn fn);
+
+/**
+ * @brief (Re)initialize a work object allocated on the stack
+ *
+ * Sets up a work object to call the given function pointer.
+ * Special version needed for work objects on the stack.
+ * The function \a fn needs to match the prototype: void fn(osk_workq_work *).
+ *
+ * It is a programming error to pass an invalid pointer (including NULL) for
+ * any parameter. Passing NULL will assert in debug builds.
+ *
+ * @param[out] wk work unit to be initialized
+ * @param[in] fn function to be invoked at some future time
+ */
+OSK_STATIC_INLINE void osk_workq_work_init_on_stack(osk_workq_work * const wk, osk_workq_fn fn);
+
+
+/**
+ * @brief Submit work to a work queue
+ *
+ * Adds work (a work unit) to a work queue.
+ *
+ * The work unit (osk_workq_work) represents a function \a fn to be invoked at some
+ * future time. The invoked function \a fn is set via \a osk_workq_work_init or
+ * \a osk_workq_work_init_on_stack if the work object resides on the stack.
+ *
+ * The work unit should be embedded within the object that the invoked function needs
+ * to operate on, so that the invoked function can determine a pointer to the object
+ * it needs to operate on.
+ *
+ * osk_workq_submit() must be callable from IRQ context (it may not block nor access user space)
+ *
+ * The work unit memory \a wk needs to remain allocated until the function \a fn has been invoked.
+ *
+ * It is a programming error to pass an invalid pointer (including NULL) for
+ * any parameter. Passing NULL will assert in debug builds.
+ *
+ * @param[in] wq intialized workqueue
+ * @param[out] wk initialized work object to submit
+ */
+OSK_STATIC_INLINE void osk_workq_submit(osk_workq *wq, osk_workq_work * const wk);
+
+/**
+ * @brief Flush a work queue
+ *
+ * All work units submitted to \a wq before this call will be complete by the
+ * time this function returns. The work units are guaranteed to be completed
+ * across the pool of worker threads.
+ *
+ * However, if a thread submits new work units to \a wq during the flush, then
+ * this function will not prevent those work units from running, nor will it
+ * guarantee to wait until after those work units are complete.
+ *
+ * Providing that no other thread attempts to submit work units to \a wq during
+ * or after this call, then it is guaranteed that no worker thread is executing
+ * any work from \a wq.
+ *
+ * @note The caller must ensure that they hold no locks that are also obtained
+ * by any work units on \a wq. Otherwise, a deadlock \b will occur.
+ *
+ * @note In addition, you must never call osk_workq_flush() from within any
+ * work unit, since this would cause a deadlock. Whilst it would normally be
+ * possible for a work unit to flush a different work queue, this may still
+ * cause a deadlock when the underlying implementation is using a single
+ * work queue for all work queues in the system.
+ *
+ * It is a programming error to pass an invalid pointer (including NULL) for
+ * any parameter. Passing NULL will assert in debug builds.
+ *
+ * @param[in] wq intialized workqueue to flush
+ */
+OSK_STATIC_INLINE void osk_workq_flush(osk_workq *wq);
+
+/** @} */ /* end group oskworkqueue */
+
+/** @} */ /* end group base_osk_api */
+
+/** @} */ /* end group base_api */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _OSK_WORKQ_H */
diff --git a/drivers/gpu/arm/t6xx/kbase/osk/mali_osk.h b/drivers/gpu/arm/t6xx/kbase/osk/mali_osk.h
new file mode 100644
index 0000000..6fb0ec1
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/osk/mali_osk.h
@@ -0,0 +1,52 @@
+/*
+ *
+ * (C) COPYRIGHT 2010-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+#ifndef _OSK_H_
+#define _OSK_H_
+
+/**
+ * @addtogroup base_api
+ * @{
+ */
+
+/**
+ * @defgroup base_osk_api Kernel-side OSK APIs
+ */
+
+/** @} */ /* end group base_api */
+
+#include "include/mali_osk_types.h"
+#include "include/mali_osk_debug.h"
+#ifdef CONFIG_MALI_QA_RESFAIL
+#include "include/mali_osk_failure.h"
+#endif /* CONFIG_MALI_QA_RESFAIL */
+#include "include/mali_osk_math.h"
+#include "include/mali_osk_lists.h"
+#include "include/mali_osk_lock_order.h"
+#include "include/mali_osk_locks.h"
+#include "include/mali_osk_atomics.h"
+#include "include/mali_osk_timers.h"
+#include "include/mali_osk_time.h"
+#include "include/mali_osk_bitops.h"
+#include "include/mali_osk_workq.h"
+#include "include/mali_osk_mem.h"
+#include "include/mali_osk_low_level_mem.h"
+#ifdef CONFIG_MALI_QA_LEAK
+#include "include/mali_osk_mem_wrappers.h"
+#endif /* CONFIG_MALI_QA_LEAK */
+#include "include/mali_osk_waitq.h"
+#include "include/mali_osk_power.h"
+#include "include/mali_osk_credentials.h"
+
+#endif /* _OSK_H_ */
diff --git a/drivers/gpu/arm/t6xx/kbase/osk/mali_osk_common.h b/drivers/gpu/arm/t6xx/kbase/osk/mali_osk_common.h
new file mode 100644
index 0000000..c3c8cf9
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/osk/mali_osk_common.h
@@ -0,0 +1,47 @@
+/*
+ *
+ * (C) COPYRIGHT 2010-2011 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_osk_common.h
+ * This header defines macros shared by the Common Layer public interfaces for
+ * all utilities, to ensure they are available even if a client does not include
+ * the convenience header mali_osk.h.
+ */
+
+#ifndef _OSK_COMMON_H_
+#define _OSK_COMMON_H_
+
+#include <osk/include/mali_osk_debug.h>
+
+/**
+ * @private
+ */
+static INLINE mali_bool oskp_ptr_is_null(const void* ptr)
+{
+ CSTD_UNUSED(ptr);
+ OSK_ASSERT(ptr != NULL);
+ return MALI_FALSE;
+}
+
+/**
+ * @brief Check if a pointer is NULL, if so an assert is triggered, otherwise the pointer itself is returned.
+ *
+ * @param [in] ptr Pointer to test
+ *
+ * @return @c ptr if it's not NULL.
+ */
+#define OSK_CHECK_PTR(ptr)\
+ (oskp_ptr_is_null(ptr) ? NULL : ptr)
+
+#endif /* _OSK_COMMON_H_ */
diff --git a/drivers/gpu/arm/t6xx/kbase/osk/src/common/mali_osk_bitops_cmn.c b/drivers/gpu/arm/t6xx/kbase/osk/src/common/mali_osk_bitops_cmn.c
new file mode 100644
index 0000000..671219d
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/osk/src/common/mali_osk_bitops_cmn.c
@@ -0,0 +1,46 @@
+/*
+ *
+ * (C) COPYRIGHT 2008-2011 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+
+#include <osk/mali_osk.h>
+
+unsigned long osk_bitarray_find_first_zero_bit(const unsigned long *addr, unsigned long maxbit)
+{
+ unsigned long total;
+
+ OSK_ASSERT(NULL != addr);
+
+ for ( total = 0; total < maxbit; total += OSK_BITS_PER_LONG, ++addr )
+ {
+ if (OSK_ULONG_MAX != *addr)
+ {
+ int result;
+ result = oskp_find_first_zero_bit( *addr );
+ /* non-negative signifies the bit was found */
+ if ( result >= 0 )
+ {
+ total += (unsigned long)result;
+ break;
+ }
+ }
+ }
+
+ /* Now check if we reached maxbit or above */
+ if ( total >= maxbit )
+ {
+ total = maxbit;
+ }
+
+ return total; /* either the found bit nr, or maxbit if not found */
+}
diff --git a/drivers/gpu/arm/t6xx/kbase/osk/src/common/mali_osk_compile_asserts.h b/drivers/gpu/arm/t6xx/kbase/osk/src/common/mali_osk_compile_asserts.h
new file mode 100644
index 0000000..fc8d36d
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/osk/src/common/mali_osk_compile_asserts.h
@@ -0,0 +1,26 @@
+/*
+ *
+ * (C) COPYRIGHT 2011 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file osk/src/common/mali_osk_compile_asserts.h
+ *
+ * Private definitions of compile time asserts.
+ **/
+
+/**
+ * Unreachable function needed to check values at compile-time, in both debug
+ * and release builds
+ */
+void oskp_cmn_compile_time_assertions(void);
+
diff --git a/drivers/gpu/arm/t6xx/kbase/osk/src/common/mali_osk_debug_cmn.c b/drivers/gpu/arm/t6xx/kbase/osk/src/common/mali_osk_debug_cmn.c
new file mode 100644
index 0000000..35e32da
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/osk/src/common/mali_osk_debug_cmn.c
@@ -0,0 +1,129 @@
+/*
+ *
+ * (C) COPYRIGHT 2008-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+
+#include <osk/mali_osk.h>
+#include "mali_osk_compile_asserts.h"
+
+/**
+ * @brief Contains the module names (modules in the same order as for the osk_module enumeration)
+ * @sa oskp_module_to_str
+ */
+static const char* CONST oskp_str_modules[] =
+{
+ "UNKNOWN", /**< Unknown module */
+ "OSK", /**< OSK */
+ "UKK", /**< UKK */
+ "BASE_MMU", /**< Base MMU */
+ "BASE_JD", /**< Base Job Dispatch */
+ "BASE_JM", /**< Base Job Manager */
+ "BASE_CORE", /**< Base Core */
+ "BASE_MEM", /**< Base Memory */
+ "BASE_EVENT", /**< Base Event */
+ "BASE_CTX", /**< Base Context */
+ "BASE_PM", /**< Base Power Management */
+ "UMP", /**< UMP */
+};
+
+#define MODULE_STRING_ARRAY_SIZE (sizeof(oskp_str_modules)/sizeof(oskp_str_modules[0]))
+
+INLINE void oskp_cmn_compile_time_assertions(void)
+{
+ /*
+ * If this assert triggers you have forgotten to update oskp_str_modules
+ * when you added a module to the osk_module enum
+ * */
+ CSTD_COMPILE_TIME_ASSERT(OSK_MODULES_ALL == MODULE_STRING_ARRAY_SIZE );
+}
+
+const char* oskp_module_to_str(const osk_module module)
+{
+ if( MODULE_STRING_ARRAY_SIZE <= module)
+ {
+ return "";
+ }
+ return oskp_str_modules[module];
+}
+
+void oskp_validate_format_string(const char *format, ...)
+{
+#ifdef CONFIG_MALI_DEBUG
+ char c;
+ static const char *supported[] =
+ {
+ "d", "ld", "lld",
+ "x", "lx", "llx",
+ "X", "lX", "llX",
+ "u", "lu", "llu",
+ "p",
+ "c",
+ "s",
+ };
+ static const unsigned char sizes[] = { 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 1, 1 };
+
+ unsigned int i;
+
+ /* %[flags][width][.precision][length]specifier */
+
+ while ( (c = *format++) )
+ {
+ if (c == '%')
+ {
+ c = *format;
+
+ if (c == '\0')
+ {
+ /* Unsupported format */
+ OSK_PRINT_WARN(OSK_OSK, "OSK Format specification not complete (%% not followed by anything)\n");
+ return;
+ }
+ else if (c != '%')
+ {
+ /* Skip to the [length]specifier part assuming it starts with
+ * an alphabetic character and flags, width, precision do not
+ * contain alphabetic characters.
+ */
+ do
+ {
+ if ((c >= 'a' && c <= 'z') || c == 'X')
+ {
+ /* Match supported formats with current position in format string */
+ for (i = 0; i < NELEMS(supported); i++)
+ {
+ if (strncmp(format, supported[i], sizes[i]) == 0)
+ {
+ /* Supported format */
+ break;
+ }
+ }
+
+ if (i == NELEMS(supported))
+ {
+ /* Unsupported format */
+ OSK_PRINT_WARN(OSK_OSK, "OSK Format string specifier not supported (starting at '%s')\n", format);
+ return;
+ }
+
+ /* Start looking for next '%' */
+ break;
+ }
+ } while ( (c = *++format) );
+ }
+ }
+ }
+#else
+ CSTD_UNUSED(format);
+#endif /* CONFIG_MALI_DEBUG */
+}
+
diff --git a/drivers/gpu/arm/t6xx/kbase/osk/src/linux/Makefile b/drivers/gpu/arm/t6xx/kbase/osk/src/linux/Makefile
new file mode 100644
index 0000000..5a28182
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/osk/src/linux/Makefile
@@ -0,0 +1,54 @@
+#
+# (C) COPYRIGHT 2010-2012 ARM Limited. All rights reserved.
+#
+# This program is free software and is provided to you under the terms of the GNU General Public License version 2
+# as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+#
+# A copy of the licence is included with the program, and can also be obtained from Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+#
+
+
+ifneq ($(KERNELRELEASE),)
+
+# kernel/drivers/gpu/arm/t6xx
+RELATIVE_ROOT=../../../../../../../../..
+ROOT=$(KBUILD_EXTMOD)/$(RELATIVE_ROOT)
+OSK_PATH=$(ROOT)/kernel/drivers/gpu/arm/t6xx/kbase/osk
+
+EXTRA_CFLAGS += \
+ -I$(ROOT)/kernel/drivers/gpu/arm/t6xx/kbase \
+ -DMALI_UNIT_TEST=$(MALI_UNIT_TEST) \
+ $(SCONS_CFLAGS)
+
+include $(OSK_PATH)/src/linux/Makefile.osk
+
+SRC=\
+ mali_osk_debug.c \
+ ../common/mali_osk_bitops_cmn.c \
+ ../common/mali_osk_debug_cmn.c
+
+ifeq ($(CONFIG_MALI_QA_RESFAIL), y)
+SRC += ../common/mali_osk_failure.c
+endif
+
+ifeq ($(CONFIG_MALI_QA_LEAK), y)
+SRC += ../common/mali_osk_mem_track.c
+endif
+
+SRC += mali_osk_timers.c
+
+lib-y := $(SRC:.c=.o)
+
+else
+
+KDIR ?= /lib/modules/$(shell uname -r)/build
+
+all:
+ $(MAKE) -C $(KDIR) M=$(CURDIR) $(SCONS_CONFIGS)
+
+clean:
+ $(MAKE) -C $(KDIR) M=$(CURDIR) clean
+
+endif
diff --git a/drivers/gpu/arm/t6xx/kbase/osk/src/linux/Makefile.osk b/drivers/gpu/arm/t6xx/kbase/osk/src/linux/Makefile.osk
new file mode 100644
index 0000000..ff39bc0
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/osk/src/linux/Makefile.osk
@@ -0,0 +1,13 @@
+#
+# (C) COPYRIGHT 2010-2012 ARM Limited. All rights reserved.
+#
+# This program is free software and is provided to you under the terms of the GNU General Public License version 2
+# as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+#
+# A copy of the licence is included with the program, and can also be obtained from Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+#
+
+
+EXTRA_CFLAGS += -I$(ROOT) -I$(OSK_PATH)/.. -I$(OSK_PATH)/src/linux/include
diff --git a/drivers/gpu/arm/t6xx/kbase/osk/src/linux/include/osk/mali_osk_arch_atomics.h b/drivers/gpu/arm/t6xx/kbase/osk/src/linux/include/osk/mali_osk_arch_atomics.h
new file mode 100644
index 0000000..7cda96c
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/osk/src/linux/include/osk/mali_osk_arch_atomics.h
@@ -0,0 +1,69 @@
+/*
+ *
+ * (C) COPYRIGHT 2008-2011 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file
+ * Implementation of the OS abstraction layer for the kernel device driver
+ */
+
+#ifndef _OSK_ARCH_ATOMICS_H_
+#define _OSK_ARCH_ATOMICS_H_
+
+#ifndef _OSK_H_
+#error "Include mali_osk.h directly"
+#endif
+
+OSK_STATIC_INLINE u32 osk_atomic_sub(osk_atomic * atom, u32 value)
+{
+ OSK_ASSERT(NULL != atom);
+ return atomic_sub_return(value, atom);
+}
+
+OSK_STATIC_INLINE u32 osk_atomic_add(osk_atomic * atom, u32 value)
+{
+ OSK_ASSERT(NULL != atom);
+ return atomic_add_return(value, atom);
+}
+
+OSK_STATIC_INLINE u32 osk_atomic_dec(osk_atomic * atom)
+{
+ OSK_ASSERT(NULL != atom);
+ return osk_atomic_sub(atom, 1);
+}
+
+OSK_STATIC_INLINE u32 osk_atomic_inc(osk_atomic * atom)
+{
+ OSK_ASSERT(NULL != atom);
+ return osk_atomic_add(atom, 1);
+}
+
+OSK_STATIC_INLINE void osk_atomic_set(osk_atomic * atom, u32 value)
+{
+ OSK_ASSERT(NULL != atom);
+ atomic_set(atom, value);
+}
+
+OSK_STATIC_INLINE u32 osk_atomic_get(osk_atomic * atom)
+{
+ OSK_ASSERT(NULL != atom);
+ return atomic_read(atom);
+}
+
+OSK_STATIC_INLINE u32 osk_atomic_compare_and_swap(osk_atomic * atom, u32 old_value, u32 new_value)
+{
+ OSK_ASSERT(NULL != atom);
+ return atomic_cmpxchg(atom, old_value, new_value);
+}
+
+#endif /* _OSK_ARCH_ATOMICS_H_ */
diff --git a/drivers/gpu/arm/t6xx/kbase/osk/src/linux/include/osk/mali_osk_arch_bitops.h b/drivers/gpu/arm/t6xx/kbase/osk/src/linux/include/osk/mali_osk_arch_bitops.h
new file mode 100644
index 0000000..9b7eb5d
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/osk/src/linux/include/osk/mali_osk_arch_bitops.h
@@ -0,0 +1,51 @@
+/*
+ *
+ * (C) COPYRIGHT 2008-2011 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file
+ * Implementation of the OS abstraction layer for the kernel device driver
+ */
+
+#ifndef _OSK_ARCH_BITOPS_H_
+#define _OSK_ARCH_BITOPS_H_
+
+#ifndef _OSK_H_
+#error "Include mali_osk.h directly"
+#endif
+
+#include <linux/bitops.h>
+
+OSK_STATIC_INLINE long osk_clz(unsigned long val)
+{
+ return OSK_BITS_PER_LONG - fls_long(val);
+}
+
+OSK_STATIC_INLINE long osk_clz_64(u64 val)
+{
+ return 64 - fls64(val);
+}
+
+OSK_STATIC_INLINE int osk_count_set_bits(unsigned long val)
+{
+ /* note: __builtin_popcountl() not available in kernel */
+ int count = 0;
+ while (val)
+ {
+ count++;
+ val &= (val-1);
+ }
+ return count;
+}
+
+#endif /* _OSK_ARCH_BITOPS_H_ */
diff --git a/drivers/gpu/arm/t6xx/kbase/osk/src/linux/include/osk/mali_osk_arch_credentials.h b/drivers/gpu/arm/t6xx/kbase/osk/src/linux/include/osk/mali_osk_arch_credentials.h
new file mode 100644
index 0000000..3581558
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/osk/src/linux/include/osk/mali_osk_arch_credentials.h
@@ -0,0 +1,86 @@
+/*
+ *
+ * (C) COPYRIGHT 2008-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file
+ * Implementation of the OS abstraction layer for the kernel device driver
+ */
+
+#ifndef _OSK_ARCH_CREDENTIALS_H_
+#define _OSK_ARCH_CREDENTIALS_H_
+
+#ifndef _OSK_H_
+#error "Include mali_osk.h directly"
+#endif
+
+#include <linux/cred.h>
+
+OSK_STATIC_INLINE mali_bool osk_is_privileged(void)
+{
+ mali_bool is_privileged = MALI_FALSE;
+
+ /* Check if the caller is root */
+ if (current_euid() == 0)
+ {
+ is_privileged = MALI_TRUE;
+ }
+
+ return is_privileged;
+}
+
+OSK_STATIC_INLINE mali_bool osk_is_policy_realtime(void)
+{
+ int policy = current->policy;
+
+ if (policy == SCHED_FIFO || policy == SCHED_RR)
+ {
+ return MALI_TRUE;
+ }
+
+ return MALI_FALSE;
+}
+
+OSK_STATIC_INLINE void osk_get_process_priority(osk_process_priority *prio)
+{
+ /* Note that we return the current process priority.
+ * If called from a kernel thread the priority returned
+ * will be the kernel thread priority and not the user
+ * process that is currently submitting jobs to the scheduler.
+ */
+ OSK_ASSERT(prio);
+
+ if(osk_is_policy_realtime())
+ {
+ prio->is_realtime = MALI_TRUE;
+ /* NOTE: realtime range was in the range 0..99 (lowest to highest) so we invert
+ * the priority and scale to -20..0 to normalize the result with the NICE range
+ */
+ prio->priority = (((MAX_RT_PRIO-1) - current->rt_priority) / 5) - 20;
+ /* Realtime range returned:
+ * -20 - highest priority
+ * 0 - lowest priority
+ */
+ }
+ else
+ {
+ prio->is_realtime = MALI_FALSE;
+ prio->priority = (current->static_prio - MAX_RT_PRIO) - 20;
+ /* NICE range returned:
+ * -20 - highest priority
+ * +19 - lowest priority
+ */
+ }
+}
+
+#endif /* _OSK_ARCH_CREDENTIALS_H_ */
diff --git a/drivers/gpu/arm/t6xx/kbase/osk/src/linux/include/osk/mali_osk_arch_debug.h b/drivers/gpu/arm/t6xx/kbase/osk/src/linux/include/osk/mali_osk_arch_debug.h
new file mode 100644
index 0000000..cd93f33
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/osk/src/linux/include/osk/mali_osk_arch_debug.h
@@ -0,0 +1,679 @@
+/*
+ *
+ * (C) COPYRIGHT 2010-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file
+ * Implementation of the OS abstraction layer for the kernel device driver
+ */
+
+#ifndef _OSK_ARCH_DEBUG_H_
+#define _OSK_ARCH_DEBUG_H_
+
+#include <malisw/mali_stdtypes.h>
+#include "mali_osk_arch_types.h"
+
+#if MALI_UNIT_TEST
+/* Kernel testing helpers */
+
+/** Callback to run during kassertp_test_exit() */
+typedef void (*kassert_test_cb)(void *);
+
+void kassert_test_init(void);
+void kassert_test_term(void);
+void kassert_test_wait(void);
+void kassert_test_signal(void);
+mali_bool kassert_test_has_asserted(void);
+void kassert_test_register_cb(kassert_test_cb cb, void *param);
+void kassertp_test_exit(void);
+#endif
+
+/** Maximum number of bytes (incl. end of string character) supported in the generated debug output string */
+#define OSK_DEBUG_MESSAGE_SIZE 256
+
+/**
+ * All OSKP_ASSERT* and OSKP_PRINT_* macros will eventually call OSKP_PRINT to output messages
+ */
+void oskp_debug_print(const char *fmt, ...);
+#define OSKP_PRINT(...) oskp_debug_print(__VA_ARGS__)
+
+/**
+ * Insert a breakpoint to cause entry in an attached debugger. However, since there is
+ * no API available to trigger entry in a debugger, we dereference a NULL
+ * pointer which should cause an exception and enter a debugger.
+ */
+#define OSKP_BREAKPOINT() *(int *)0 = 0
+
+/**
+ * Quit the driver and halt.
+ */
+#define OSKP_QUIT() BUG()
+
+/**
+ * Print a backtrace
+ */
+#define OSKP_TRACE() WARN_ON(1)
+
+#define OSKP_CHANNEL_INFO ((u32)0x00000001) /**< @brief No output*/
+#define OSKP_CHANNEL_WARN ((u32)0x00000002) /**< @brief Standard output*/
+#define OSKP_CHANNEL_ERROR ((u32)0x00000004) /**< @brief Error output*/
+#define OSKP_CHANNEL_RAW ((u32)0x00000008) /**< @brief Raw output*/
+#define OSKP_CHANNEL_ALL ((u32)0xFFFFFFFF) /**< @brief All the channels at the same time*/
+
+/** @brief Disable the asserts tests if set to 1. Default is to disable the asserts in release. */
+#ifndef OSK_DISABLE_ASSERTS
+#ifdef CONFIG_MALI_DEBUG
+#define OSK_DISABLE_ASSERTS 0
+#else
+#define OSK_DISABLE_ASSERTS 1
+#endif
+#endif /* OSK_DISABLE_ASSERTS */
+
+/* Lock order assertion check requires macro to define the order variable on the stack */
+#if OSK_DISABLE_ASSERTS == 0
+#define OSK_ORDER_VAR_DEFINITION(order) osk_lock_order __oskp_order__ = (order);
+#else
+#define OSK_ORDER_VAR_DEFINITION(order) CSTD_NOP()
+#endif
+
+/** @brief If equals to 0, a trace containing the file, line, and function will be displayed before each message. */
+#define OSK_SKIP_TRACE 0
+
+/** @brief If different from 0, the trace will only contain the file and line. */
+#define OSK_SKIP_FUNCTION_NAME 0
+
+/** @brief Variable to set the permissions per module and per channel.
+ */
+#define OSK_MODULES_PERMISSIONS "ALL_ALL"
+
+/** @brief String terminating every message printed by the debug API */
+#define OSK_STOP_MSG "\n"
+
+/** @brief Enables support for runtime configuration if set to 1.
+ */
+#define OSK_USE_RUNTIME_CONFIG 0
+
+/**< @brief Enables simulation of failures (for testing) if non-zero */
+#ifdef CONFIG_MALI_QA_RESFAIL
+#define OSK_SIMULATE_FAILURES 1
+#else
+#define OSK_SIMULATE_FAILURES 0
+#endif
+
+#define OSK_ACTION_IGNORE 0 /**< @brief The given message is ignored then the execution continues*/
+#define OSK_ACTION_PRINT_AND_CONTINUE 1 /**< @brief The given message is printed then the execution continues*/
+#define OSK_ACTION_PRINT_AND_BREAK 2 /**< @brief The given message is printed then a break point is triggered*/
+#define OSK_ACTION_PRINT_AND_QUIT 3 /**< @brief The given message is printed then the execution is stopped*/
+#define OSK_ACTION_PRINT_AND_TRACE 4 /**< @brief The given message and a backtrace is printed then the execution continues*/
+
+/**
+ * @def OSK_ON_INFO
+ * @brief Defines the API behavior when @ref OSK_PRINT_INFO() is called
+ * @note Must be set to one of the following values: @see OSK_ACTION_PRINT_AND_CONTINUE,
+ * @note @ref OSK_ACTION_PRINT_AND_BREAK, @see OSK_ACTION_PRINT_AND_QUIT, @see OSK_ACTION_IGNORE
+ *
+ * @def OSK_ON_WARN
+ * @brief Defines the API behavior when @see OSK_PRINT_WARN() is called
+ * @note Must be set to one of the following values: @see OSK_ACTION_PRINT_AND_CONTINUE,
+ * @note @see OSK_ACTION_PRINT_AND_BREAK, @see OSK_ACTION_PRINT_AND_QUIT, @see OSK_ACTION_IGNORE
+ *
+ * @def OSK_ON_ERROR
+ * @brief Defines the API behavior when @see OSK_PRINT_ERROR() is called
+ * @note Must be set to one of the following values: @see OSK_ACTION_PRINT_AND_CONTINUE,
+ * @note @see OSK_ACTION_PRINT_AND_BREAK, @see OSK_ACTION_PRINT_AND_QUIT, @see OSK_ACTION_IGNORE
+ *
+ * @def OSK_ON_ASSERT
+ * @brief Defines the API behavior when @see OSKP_PRINT_ASSERT() is called
+ * @note Must be set to one of the following values: @see OSK_ACTION_PRINT_AND_CONTINUE,
+ * @note @see OSK_ACTION_PRINT_AND_BREAK, @see OSK_ACTION_PRINT_AND_QUIT, @see OSK_ACTION_IGNORE
+ *
+ * @def OSK_ON_RAW
+ * @brief Defines the API behavior when @see OSKP_PRINT_RAW() is called
+ * @note Must be set to one of the following values: @see OSK_ACTION_PRINT_AND_CONTINUE,
+ * @note @see OSK_ACTION_PRINT_AND_BREAK, @see OSK_ACTION_PRINT_AND_QUIT, @see OSK_ACTION_IGNORE
+ *
+ *
+ */
+#ifdef CONFIG_MALI_DEBUG
+ #define OSK_ON_INFO OSK_ACTION_IGNORE
+ #define OSK_ON_WARN OSK_ACTION_PRINT_AND_CONTINUE
+ #define OSK_ON_ASSERT OSK_ACTION_PRINT_AND_QUIT
+ #define OSK_ON_ERROR OSK_ACTION_PRINT_AND_CONTINUE
+ #define OSK_ON_RAW OSK_ACTION_PRINT_AND_CONTINUE
+#else
+ #define OSK_ON_INFO OSK_ACTION_IGNORE
+ #define OSK_ON_WARN OSK_ACTION_IGNORE
+ #define OSK_ON_ASSERT OSK_ACTION_IGNORE
+ #define OSK_ON_ERROR OSK_ACTION_PRINT_AND_CONTINUE
+ #define OSK_ON_RAW OSK_ACTION_PRINT_AND_CONTINUE
+#endif /* CONFIG_MALI_DEBUG */
+
+#if MALI_UNIT_TEST
+#define OSKP_KERNEL_TEST_ASSERT() kassertp_test_exit()
+#else
+#define OSKP_KERNEL_TEST_ASSERT() CSTD_NOP()
+#endif
+
+/**
+ * OSK_ASSERT macros do nothing if the flag @see OSK_DISABLE_ASSERTS is set to 1
+ */
+#if OSK_DISABLE_ASSERTS
+ #define OSKP_ASSERT(expr) CSTD_NOP()
+ #define OSKP_INTERNAL_ASSERT(expr) CSTD_NOP()
+ #define OSKP_ASSERT_MSG(expr, ...) CSTD_NOP()
+#else /* OSK_DISABLE_ASSERTS */
+
+/**
+ * @def OSKP_ASSERT_MSG(expr, ...)
+ * @brief Calls @see OSKP_PRINT_ASSERT and prints the given message if @a expr is false
+ *
+ * @note This macro does nothing if the flag @see OSK_DISABLE_ASSERTS is set to 1
+ *
+ * @param expr Boolean expression
+ * @param ... Message to display when @a expr is false, as a format string followed by format arguments.
+ */
+#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
+#define OSKP_ASSERT_MSG(expr, ...)\
+ do\
+ {\
+ _Pragma("GCC diagnostic push")\
+ _Pragma("GCC diagnostic ignored \"-Waddress\"")\
+ if(MALI_FALSE == (expr))\
+ {\
+ OSKP_PRINT_ASSERT(__VA_ARGS__);\
+ }\
+ _Pragma("GCC diagnostic pop")\
+ }while(MALI_FALSE)
+#else
+#define OSKP_ASSERT_MSG(expr, ...)\
+ do\
+ {\
+ if(MALI_FALSE == (expr))\
+ {\
+ OSKP_PRINT_ASSERT(__VA_ARGS__);\
+ }\
+ }while(MALI_FALSE)
+#endif /* (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) */
+
+/**
+ * @def OSKP_ASSERT(expr)
+ * @brief Calls @see OSKP_PRINT_ASSERT and prints the expression @a expr if @a expr is false
+ *
+ * @note This macro does nothing if the flag @see OSK_DISABLE_ASSERTS is set to 1
+ *
+ * @param expr Boolean expression
+ */
+#define OSKP_ASSERT(expr)\
+ OSKP_ASSERT_MSG(expr, #expr)
+
+/**
+ * @def OSKP_INTERNAL_ASSERT(expr)
+ * @brief Calls @see OSKP_BREAKPOINT if @a expr is false
+ * This assert function is for internal use of OSK functions which themselves are used to implement
+ * the OSK_ASSERT functionality. These functions should use OSK_INTERNAL_ASSERT which does not use
+ * any OSK functions to prevent ending up in a recursive loop.
+ *
+ * @note This macro does nothing if the flag @see OSK_DISABLE_ASSERTS is set to 1
+ *
+ * @param expr Boolean expression
+ */
+#define OSKP_INTERNAL_ASSERT(expr)\
+ do\
+ {\
+ if(MALI_FALSE == (expr))\
+ {\
+ OSKP_BREAKPOINT();\
+ }\
+ }while(MALI_FALSE)
+
+
+/**
+ * @def OSK_CALL_ASSERT_HOOK()
+ * @brief Calls oskp_debug_assert_call_hook
+ * This will call oskp_debug_assert_call_hook to perform any registered action required
+ * on assert.
+ *
+ * @note This macro does nothing if the flag @see CONFIG_MALI_DEBUG is not set.
+ *
+ */
+
+#ifdef CONFIG_MALI_DEBUG
+#define OSK_CALL_ASSERT_HOOK()\
+ oskp_debug_assert_call_hook()
+#else
+#define OSK_CALL_ASSERT_HOOK()\
+ CSTD_NOP()
+#endif /* CONFIG_MALI_DEBUG */
+
+/**
+ * @def OSKP_PRINT_ASSERT(...)
+ * @brief Prints "MALI<ASSERT>" followed by trace, function name and the given message.
+ *
+ * The behavior of this function is defined by the macro @see OSK_ON_ASSERT.
+ *
+ * @note This macro does nothing if the flag @see OSK_DISABLE_ASSERTS is set to 1
+ *
+ * Example: OSKP_PRINT_ASSERT(" %d blocks could not be allocated", mem_alocated) will print:\n
+ * "MALI<ASSERT> In file <path> line: <line number> function:<function name> 10 blocks could not be allocated"
+ *
+ * @note Depending on the values of @see OSK_SKIP_FUNCTION_NAME and @see OSK_SKIP_TRACE the trace will be displayed
+ * before the message.
+ *
+ * @param ... Message to print, passed as a format string followed by format arguments.
+ */
+#define OSKP_PRINT_ASSERT(...)\
+ do\
+ {\
+ OSKP_ASSERT_OUT(OSKP_PRINT_TRACE, OSKP_PRINT_FUNCTION, __VA_ARGS__);\
+ OSK_CALL_ASSERT_HOOK();\
+ OSKP_KERNEL_TEST_ASSERT();\
+ OSKP_ASSERT_ACTION();\
+ }while(MALI_FALSE)
+
+#endif
+
+/**
+ * @def OSKP_DEBUG_CODE( X )
+ * @brief Executes the code inside the macro only in debug mode
+ *
+ * @param X Code to compile only in debug mode.
+ */
+#ifdef CONFIG_MALI_DEBUG
+ #define OSKP_DEBUG_CODE( X ) X
+#else
+ #define OSKP_DEBUG_CODE( X ) CSTD_NOP()
+#endif /* CONFIG_MALI_DEBUG */
+
+/**
+ * @def OSKP_ASSERT_ACTION
+ * @brief (Private) Action associated to the @see OSKP_PRINT_ASSERT event.
+ */
+/* Configure the post display action */
+#if OSK_ON_ASSERT == OSK_ACTION_PRINT_AND_BREAK
+ #define OSKP_ASSERT_ACTION OSKP_BREAKPOINT
+#elif OSK_ON_ASSERT == OSK_ACTION_PRINT_AND_QUIT
+ #define OSKP_ASSERT_ACTION OSKP_QUIT
+#elif OSK_ON_ASSERT == OSK_ACTION_PRINT_AND_TRACE
+ #define OSKP_ASSERT_ACTION OSKP_TRACE
+#elif OSK_ON_ASSERT == OSK_ACTION_PRINT_AND_CONTINUE || OSK_ON_ASSERT == OSK_ACTION_IGNORE
+ #define OSKP_ASSERT_ACTION() CSTD_NOP()
+#else
+ #error invalid value for OSK_ON_ASSERT
+#endif
+
+/**
+ * @def OSKP_RAW_ACTION
+ * @brief (Private) Action associated to the @see OSK_PRINT_RAW event.
+ */
+/* Configure the post display action */
+#if OSK_ON_RAW == OSK_ACTION_PRINT_AND_BREAK
+ #define OSKP_RAW_ACTION OSKP_BREAKPOINT
+#elif OSK_ON_RAW == OSK_ACTION_PRINT_AND_QUIT
+ #define OSKP_RAW_ACTION OSKP_QUIT
+#elif OSK_ON_RAW == OSK_ACTION_PRINT_AND_TRACE
+ #define OSKP_RAW_ACTION OSKP_TRACE
+#elif OSK_ON_RAW == OSK_ACTION_PRINT_AND_CONTINUE || OSK_ON_RAW == OSK_ACTION_IGNORE
+ #define OSKP_RAW_ACTION() CSTD_NOP()
+#else
+ #error invalid value for OSK_ON_RAW
+#endif
+
+/**
+ * @def OSKP_INFO_ACTION
+ * @brief (Private) Action associated to the @see OSK_PRINT_INFO event.
+ */
+/* Configure the post display action */
+#if OSK_ON_INFO == OSK_ACTION_PRINT_AND_BREAK
+ #define OSKP_INFO_ACTION OSKP_BREAKPOINT
+#elif OSK_ON_INFO == OSK_ACTION_PRINT_AND_QUIT
+ #define OSKP_INFO_ACTION OSKP_QUIT
+#elif OSK_ON_INFO == OSK_ACTION_PRINT_AND_TRACE
+ #define OSKP_INFO_ACTION OSKP_TRACE
+#elif OSK_ON_INFO == OSK_ACTION_PRINT_AND_CONTINUE || OSK_ON_INFO == OSK_ACTION_IGNORE
+ #define OSKP_INFO_ACTION() CSTD_NOP()
+#else
+ #error invalid value for OSK_ON_INFO
+#endif
+
+/**
+ * @def OSKP_ERROR_ACTION
+ * @brief (Private) Action associated to the @see OSK_PRINT_ERROR event.
+ */
+/* Configure the post display action */
+#if OSK_ON_ERROR == OSK_ACTION_PRINT_AND_BREAK
+ #define OSKP_ERROR_ACTION OSKP_BREAKPOINT
+#elif OSK_ON_ERROR == OSK_ACTION_PRINT_AND_QUIT
+ #define OSKP_ERROR_ACTION OSKP_QUIT
+#elif OSK_ON_ERROR == OSK_ACTION_PRINT_AND_TRACE
+ #define OSKP_ERROR_ACTION OSKP_TRACE
+#elif OSK_ON_ERROR == OSK_ACTION_PRINT_AND_CONTINUE || OSK_ON_ERROR == OSK_ACTION_IGNORE
+ #define OSKP_ERROR_ACTION() CSTD_NOP()
+#else
+ #error invalid value for OSK_ON_ERROR
+#endif
+
+/**
+ * @def OSKP_WARN_ACTION
+ * @brief (Private) Action associated to the @see OSK_PRINT_WARN event.
+ */
+/* Configure the post display action */
+#if OSK_ON_WARN == OSK_ACTION_PRINT_AND_BREAK
+ #define OSKP_WARN_ACTION OSKP_BREAKPOINT
+#elif OSK_ON_WARN == OSK_ACTION_PRINT_AND_QUIT
+ #define OSKP_WARN_ACTION OSKP_QUIT
+#elif OSK_ON_WARN == OSK_ACTION_PRINT_AND_TRACE
+ #define OSKP_WARN_ACTION OSKP_TRACE
+#elif OSK_ON_WARN == OSK_ACTION_PRINT_AND_CONTINUE || OSK_ON_WARN == OSK_ACTION_IGNORE
+ #define OSKP_WARN_ACTION() CSTD_NOP()
+#else
+ #error invalid value for OSK_ON_WARN
+#endif
+
+/**
+ * @def OSKP_PRINT_RAW(module, ...)
+ * @brief Prints given message
+ *
+ * The behavior of this function is defined by macro @see OSK_ON_RAW
+ *
+ * Example:
+ * @code OSKP_PRINT_RAW(OSK_BASE_MEM, " %d blocks could not be allocated", mem_allocated); @endcode will print:
+ * \n
+ * "10 blocks could not be allocated"
+ *
+ * @param module Name of the module which prints the message.
+ * @param ... Format string followed by a varying number of parameters
+ */
+#define OSKP_PRINT_RAW(module, ...)\
+ do\
+ {\
+ if(MALI_FALSE != OSKP_PRINT_IS_ALLOWED( (module), OSK_CHANNEL_RAW))\
+ {\
+ OSKP_RAW_OUT(oskp_module_to_str( (module) ), \
+ OSKP_PRINT_TRACE, OSKP_PRINT_FUNCTION, __VA_ARGS__ );\
+ }\
+ OSKP_RAW_ACTION();\
+ }while(MALI_FALSE)
+
+/**
+ * @def OSKP_PRINT_INFO(module, ...)
+ * @brief Prints "MALI<INFO,module_name>: " followed by the given message.
+ *
+ * The behavior of this function is defined by the macro @see OSK_ON_INFO
+ *
+ * Example:
+ * @code OSKP_PRINT_INFO(OSK_BASE_MEM, " %d blocks could not be allocated", mem_allocated); @endcode will print:
+ * \n
+ * "MALI<INFO,BASE_MEM>: 10 blocks could not be allocated"\n
+ *
+ * @param module Name of the module which prints the message.
+ * @param ... Format string followed by a varying number of parameters
+ */
+#define OSKP_PRINT_INFO(module, ...)\
+ do\
+ {\
+ if(MALI_FALSE != OSKP_PRINT_IS_ALLOWED( (module), OSK_CHANNEL_INFO))\
+ {\
+ OSKP_INFO_OUT(oskp_module_to_str( (module) ), \
+ OSKP_PRINT_TRACE, OSKP_PRINT_FUNCTION, __VA_ARGS__ );\
+ }\
+ OSKP_INFO_ACTION();\
+ }while(MALI_FALSE)
+
+/**
+ * @def OSKP_PRINT_WARN(module, ...)
+ * @brief Prints "MALI<WARN,module_name>: " followed by the given message.
+ *
+ * The behavior of this function is defined by the macro @see OSK_ON_WARN
+ *
+ * Example:
+ * @code OSK_PRINT_WARN(OSK_BASE_MEM, " %d blocks could not be allocated", mem_allocated);@endcode will print: \n
+ * "MALI<WARN,BASE_MEM>: 10 blocks could not be allocated"\n
+ *
+ * @param module Name of the module which prints the message.
+ * @param ... Format string followed by a varying number of parameters
+ */
+#define OSKP_PRINT_WARN(module, ...)\
+ do\
+ {\
+ if(MALI_FALSE != OSKP_PRINT_IS_ALLOWED( (module), OSK_CHANNEL_WARN))\
+ {\
+ OSKP_WARN_OUT(oskp_module_to_str( (module) ), \
+ OSKP_PRINT_TRACE, OSKP_PRINT_FUNCTION, __VA_ARGS__ );\
+ }\
+ OSKP_WARN_ACTION();\
+ }while(MALI_FALSE)
+
+/**
+ * @def OSKP_PRINT_ERROR(module, ...)
+ * @brief Prints "MALI<ERROR,module_name>: " followed by the given message.
+ *
+ * The behavior of this function is defined by the macro @see OSK_ON_ERROR
+ *
+ * Example:
+ * @code OSKP_PRINT_ERROR(OSK_BASE_MEM, " %d blocks could not be allocated", mem_allocated); @endcode will print:
+ * \n
+ * "MALI<ERROR,BASE_MEM>: 10 blocks could not be allocated"\n
+ *
+ * @param module Name of the module which prints the message.
+ * @param ... Format string followed by a varying number of parameters
+ */
+#define OSKP_PRINT_ERROR(module, ...)\
+ do\
+ {\
+ if(MALI_FALSE != OSKP_PRINT_IS_ALLOWED( (module), OSK_CHANNEL_ERROR))\
+ {\
+ OSKP_ERROR_OUT(oskp_module_to_str( (module) ), \
+ OSKP_PRINT_TRACE, OSKP_PRINT_FUNCTION, __VA_ARGS__ );\
+ }\
+ OSKP_ERROR_ACTION();\
+ }while(MALI_FALSE)
+
+/**
+ * @def OSKP_PRINT_TRACE
+ * @brief Private macro containing the format of the trace to display before every message
+ * @sa OSK_SKIP_TRACE, OSK_SKIP_FUNCTION_NAME
+ */
+#if OSK_SKIP_TRACE == 0
+ #define OSKP_PRINT_TRACE \
+ "In file: " __FILE__ " line: " CSTD_STR2(__LINE__)
+ #if OSK_SKIP_FUNCTION_NAME == 0
+ #define OSKP_PRINT_FUNCTION CSTD_FUNC
+ #else
+ #define OSKP_PRINT_FUNCTION ""
+ #endif
+#else
+ #define OSKP_PRINT_TRACE ""
+#endif
+
+/**
+ * @def OSKP_PRINT_ALLOW(module, channel)
+ * @brief Allow the given module to print on the given channel
+ * @note If @see OSK_USE_RUNTIME_CONFIG is disabled then this macro doesn't do anything
+ * @param module is a @see osk_module
+ * @param channel is one of @see OSK_CHANNEL_INFO, @see OSK_CHANNEL_WARN, @see OSK_CHANNEL_ERROR,
+ * @see OSK_CHANNEL_ALL
+ * @return MALI_TRUE if the module is allowed to print on the channel.
+ */
+/**
+ * @def OSKP_PRINT_BLOCK(module, channel)
+ * @brief Prevent the given module from printing on the given channel
+ * @note If @see OSK_USE_RUNTIME_CONFIG is disabled then this macro doesn't do anything
+ * @param module is a @see osk_module
+ * @param channel is one of @see OSK_CHANNEL_INFO, @see OSK_CHANNEL_WARN, @see OSK_CHANNEL_ERROR,
+ * @see OSK_CHANNEL_ALL
+ * @return MALI_TRUE if the module is allowed to print on the channel.
+ */
+#if OSK_USE_RUNTIME_CONFIG
+ #define OSKP_PRINT_ALLOW(module, channel) oskp_debug_print_allow( (module), (channel) )
+ #define OSKP_PRINT_BLOCK(module, channel) oskp_debug_print_block( (module), (channel) )
+#else
+ #define OSKP_PRINT_ALLOW(module, channel) CSTD_NOP()
+ #define OSKP_PRINT_BLOCK(module, channel) CSTD_NOP()
+#endif
+
+/**
+ * @def OSKP_RAW_OUT(module, trace, ...)
+ * @brief (Private) system printing function associated to the @see OSK_PRINT_RAW event.
+ * @param module module ID
+ * @param trace location in the code from where the message is printed
+ * @param function function from where the message is printed
+ * @param ... Format string followed by format arguments.
+ */
+/* Select the correct system output function*/
+#if OSK_ON_RAW != OSK_ACTION_IGNORE
+ #define OSKP_RAW_OUT(module, trace, function, ...)\
+ do\
+ {\
+ OSKP_PRINT(__VA_ARGS__);\
+ OSKP_PRINT(OSK_STOP_MSG);\
+ }while(MALI_FALSE)
+#else
+ #define OSKP_RAW_OUT(module, trace, function, ...) CSTD_NOP()
+#endif
+
+
+/**
+ * @def OSKP_INFO_OUT(module, trace, ...)
+ * @brief (Private) system printing function associated to the @see OSK_PRINT_INFO event.
+ * @param module module ID
+ * @param trace location in the code from where the message is printed
+ * @param function function from where the message is printed
+ * @param ... Format string followed by format arguments.
+ */
+/* Select the correct system output function*/
+#if OSK_ON_INFO != OSK_ACTION_IGNORE
+ #define OSKP_INFO_OUT(module, trace, function, ...)\
+ do\
+ {\
+ /* Split up in several lines to prevent hitting max 128 chars limit of OSK print function */ \
+ OSKP_PRINT("Mali<INFO,%s>: ", module);\
+ OSKP_PRINT(__VA_ARGS__);\
+ OSKP_PRINT(OSK_STOP_MSG);\
+ }while(MALI_FALSE)
+#else
+ #define OSKP_INFO_OUT(module, trace, function, ...) CSTD_NOP()
+#endif
+
+/**
+ * @def OSKP_ASSERT_OUT(trace, function, ...)
+ * @brief (Private) system printing function associated to the @see OSKP_PRINT_ASSERT event.
+ * @param trace location in the code from where the message is printed
+ * @param function function from where the message is printed
+ * @param ... Format string followed by format arguments.
+ * @note function parameter cannot be concatenated with other strings
+ */
+/* Select the correct system output function*/
+#if OSK_ON_ASSERT != OSK_ACTION_IGNORE
+ #define OSKP_ASSERT_OUT(trace, function, ...)\
+ do\
+ {\
+ /* Split up in several lines to prevent hitting max 128 chars limit of OSK print function */ \
+ OSKP_PRINT("Mali<ASSERT>: %s function:%s ", trace, function);\
+ OSKP_PRINT(__VA_ARGS__);\
+ OSKP_PRINT(OSK_STOP_MSG);\
+ }while(MALI_FALSE)
+#else
+ #define OSKP_ASSERT_OUT(trace, function, ...) CSTD_NOP()
+#endif
+
+/**
+ * @def OSKP_WARN_OUT(module, trace, ...)
+ * @brief (Private) system printing function associated to the @see OSK_PRINT_WARN event.
+ * @param module module ID
+ * @param trace location in the code from where the message is printed
+ * @param function function from where the message is printed
+ * @param ... Format string followed by format arguments.
+ * @note function parameter cannot be concatenated with other strings
+ */
+/* Select the correct system output function*/
+#if OSK_ON_WARN != OSK_ACTION_IGNORE
+ #define OSKP_WARN_OUT(module, trace, function, ...)\
+ do\
+ {\
+ /* Split up in several lines to prevent hitting max 128 chars limit of OSK print function */ \
+ OSKP_PRINT("Mali<WARN,%s>: ", module);\
+ OSKP_PRINT(__VA_ARGS__);\
+ OSKP_PRINT(OSK_STOP_MSG);\
+ }while(MALI_FALSE)
+#else
+ #define OSKP_WARN_OUT(module, trace, function, ...) CSTD_NOP()
+#endif
+
+/**
+ * @def OSKP_ERROR_OUT(module, trace, ...)
+ * @brief (Private) system printing function associated to the @see OSK_PRINT_ERROR event.
+ * @param module module ID
+ * @param trace location in the code from where the message is printed
+ * @param function function from where the message is printed
+ * @param ... Format string followed by format arguments.
+ * @note function parameter cannot be concatenated with other strings
+ */
+/* Select the correct system output function*/
+#if OSK_ON_ERROR != OSK_ACTION_IGNORE
+ #define OSKP_ERROR_OUT(module, trace, function, ...)\
+ do\
+ {\
+ /* Split up in several lines to prevent hitting max 128 chars limit of OSK print function */ \
+ OSKP_PRINT("Mali<ERROR,%s>: ", module);\
+ OSKP_PRINT(__VA_ARGS__);\
+ OSKP_PRINT(OSK_STOP_MSG);\
+ }while(MALI_FALSE)
+#else
+ #define OSKP_ERROR_OUT(module, trace, function, ...) CSTD_NOP()
+#endif
+
+/**
+ * @def OSKP_PRINT_IS_ALLOWED(module, channel)
+ * @brief function or constant indicating if the given module is allowed to print on the given channel
+ * @note If @see OSK_USE_RUNTIME_CONFIG is disabled then this macro is set to MALI_TRUE to avoid any overhead
+ * @param module is a @see osk_module
+ * @param channel is one of @see OSK_CHANNEL_INFO, @see OSK_CHANNEL_WARN, @see OSK_CHANNEL_ERROR,
+ * @see OSK_CHANNEL_ALL
+ * @return MALI_TRUE if the module is allowed to print on the channel.
+ */
+#if OSK_USE_RUNTIME_CONFIG
+ #define OSKP_PRINT_IS_ALLOWED(module, channel) oskp_is_allowed_to_print( (module), (channel) )
+#else
+ #define OSKP_PRINT_IS_ALLOWED(module, channel) MALI_TRUE
+#endif
+
+/**
+ * @def OSKP_SIMULATE_FAILURE_IS_ENABLED(module, feature)
+ * @brief Macro that evaluates as true if the specified feature is enabled for the given module
+ * @note If @ref OSK_USE_RUNTIME_CONFIG is disabled then this macro always evaluates as true.
+ * @param[in] module is a @ref cdbg_module
+ * @param[in] channel is one of @see OSK_CHANNEL_INFO, @see OSK_CHANNEL_WARN, @see OSK_CHANNEL_ERROR,
+ * @return MALI_TRUE if the feature is enabled
+ */
+#if OSK_USE_RUNTIME_CONFIG
+#define OSKP_SIMULATE_FAILURE_IS_ENABLED(module, channel) oskp_is_allowed_to_simulate_failure( (module), (channel) )
+#else
+#define OSKP_SIMULATE_FAILURE_IS_ENABLED(module, channel) MALI_TRUE
+#endif
+
+OSK_STATIC_INLINE void osk_debug_get_thread_info( u32 *thread_id, u32 *cpu_nr )
+{
+ OSK_ASSERT( thread_id != NULL );
+ OSK_ASSERT( cpu_nr != NULL );
+
+ /* This implementation uses the PID as shown in ps listings.
+ * On 64-bit systems, this could narrow from signed 64-bit to unsigned 32-bit */
+ *thread_id = (u32)task_pid_nr(current);
+
+ /* On 64-bit systems, this could narrow from unsigned 64-bit to unsigned 32-bit */
+ *cpu_nr = (u32)task_cpu(current);
+}
+
+
+#endif /* _OSK_ARCH_DEBUG_H_ */
+
diff --git a/drivers/gpu/arm/t6xx/kbase/osk/src/linux/include/osk/mali_osk_arch_locks.h b/drivers/gpu/arm/t6xx/kbase/osk/src/linux/include/osk/mali_osk_arch_locks.h
new file mode 100644
index 0000000..993e15d
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/osk/src/linux/include/osk/mali_osk_arch_locks.h
@@ -0,0 +1,240 @@
+/*
+ *
+ * (C) COPYRIGHT 2008-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file
+ * Implementation of the OS abstraction layer for the kernel device driver
+ */
+
+#ifndef _OSK_ARCH_LOCKS_H_
+#define _OSK_ARCH_LOCKS_H_
+
+#ifndef _OSK_H_
+#error "Include mali_osk.h directly"
+#endif
+
+#include <linux/lockdep.h>
+
+/**
+ * Private macro to safely allow asserting on a mutex/rwlock/spinlock/irq
+ * spinlock pointer whilst still allowing its name to appear during
+ * CONFIG_PROVE_LOCKING.
+ *
+ * It's safe because \a lock can safely have side-effects.
+ *
+ * Makes use of a GNU C extension, but this macro is only needed under Linux
+ * anyway.
+ *
+ * NOTE: the local variable must not conflict with an identifier in a wider
+ * scope
+ *
+ * NOTE: Due to the way this is used in this file, this definition must persist
+ * outside of this file
+ */
+#define OSKP_LOCK_PTR_ASSERT( lock ) \
+ ({ \
+ __typeof__( lock ) __oskp_lock__ = ( lock ); \
+ OSK_ASSERT( NULL != __oskp_lock__ ); \
+ __oskp_lock__; })
+
+/*
+ * A definition must be provided of each lock init function to eliminate
+ * warnings. They'lll be hidden by subsequent macro definitions
+ */
+
+OSK_STATIC_INLINE osk_error osk_rwlock_init(osk_rwlock * const lock, osk_lock_order order)
+{
+ OSK_ASSERT_MSG( MALI_FALSE,
+ "FATAL: this definition of osk_rwlock_init() should've been uncallable - a macro redefines it\n" );
+ CSTD_UNUSED( lock );
+ CSTD_UNUSED( order );
+ return OSK_ERR_FAIL;
+}
+
+OSK_STATIC_INLINE osk_error osk_mutex_init(osk_mutex * const lock, osk_lock_order order)
+{
+ OSK_ASSERT_MSG( MALI_FALSE,
+ "FATAL: this definition of osk_mutex_init() should've been uncallable - a macro redefines it\n" );
+ CSTD_UNUSED( lock );
+ CSTD_UNUSED( order );
+ return OSK_ERR_FAIL;
+}
+
+OSK_STATIC_INLINE osk_error osk_spinlock_init(osk_spinlock * const lock, osk_lock_order order)
+{
+ OSK_ASSERT_MSG( MALI_FALSE,
+ "FATAL: this definition of osk_spinlock_init() should've been uncallable - a macro redefines it\n" );
+ CSTD_UNUSED( lock );
+ CSTD_UNUSED( order );
+ return OSK_ERR_FAIL;
+}
+
+OSK_STATIC_INLINE osk_error osk_spinlock_irq_init(osk_spinlock_irq * const lock, osk_lock_order order)
+{
+ OSK_ASSERT_MSG( MALI_FALSE,
+ "FATAL: this definition of osk_spinlock_irq_init() should've been uncallable - a macro redefines it\n" );
+ CSTD_UNUSED( lock );
+ CSTD_UNUSED( order );
+ return OSK_ERR_FAIL;
+}
+
+/*
+ * End of 'dummy' definitions
+ */
+
+/* Note: This uses a GNU C Extension to allow Linux's CONFIG_PROVE_LOCKING to work correctly
+ *
+ * This is not required outside of Linux
+ *
+ * NOTE: the local variable must not conflict with an identifier in a wider scope */
+#define osk_rwlock_init( ARG_LOCK, ARG_ORDER ) \
+ ({ \
+ OSK_ORDER_VAR_DEFINITION(ARG_ORDER); \
+ OSK_ASSERT( OSK_LOCK_ORDER_LAST <= __oskp_order__ && __oskp_order__ <= OSK_LOCK_ORDER_FIRST ); \
+ OSKP_LOCK_PTR_ASSERT( (ARG_LOCK) ); \
+ init_rwsem( (ARG_LOCK) ); \
+ OSK_ERR_NONE;})
+
+OSK_STATIC_INLINE void osk_rwlock_term(osk_rwlock * lock)
+{
+ OSK_ASSERT(NULL != lock);
+ /* nop */
+}
+
+OSK_STATIC_INLINE void osk_rwlock_read_lock(osk_rwlock * lock)
+{
+ OSK_ASSERT(NULL != lock);
+ down_read(lock);
+}
+
+OSK_STATIC_INLINE void osk_rwlock_read_unlock(osk_rwlock * lock)
+{
+ OSK_ASSERT(NULL != lock);
+ up_read(lock);
+}
+
+OSK_STATIC_INLINE void osk_rwlock_write_lock(osk_rwlock * lock)
+{
+ OSK_ASSERT(NULL != lock);
+ down_write(lock);
+}
+
+OSK_STATIC_INLINE void osk_rwlock_write_unlock(osk_rwlock * lock)
+{
+ OSK_ASSERT(NULL != lock);
+ up_write(lock);
+}
+
+/* Note: This uses a GNU C Extension to allow Linux's CONFIG_PROVE_LOCKING to work correctly
+ *
+ * This is not required outside of Linux
+ *
+ * NOTE: the local variable must not conflict with an identifier in a wider scope */
+#define osk_mutex_init( ARG_LOCK, ARG_ORDER ) \
+ ({ \
+ OSK_ORDER_VAR_DEFINITION(ARG_ORDER); \
+ OSK_ASSERT( OSK_LOCK_ORDER_LAST <= __oskp_order__ && __oskp_order__ <= OSK_LOCK_ORDER_FIRST ); \
+ OSKP_LOCK_PTR_ASSERT( (ARG_LOCK) ); \
+ mutex_init( (ARG_LOCK) ); \
+ OSK_ERR_NONE;})
+
+
+OSK_STATIC_INLINE void osk_mutex_term(osk_mutex * lock)
+{
+ OSK_ASSERT(NULL != lock);
+ return; /* nop */
+}
+
+OSK_STATIC_INLINE void osk_mutex_lock(osk_mutex * lock)
+{
+ OSK_ASSERT(NULL != lock);
+ mutex_lock(lock);
+}
+
+OSK_STATIC_INLINE void osk_mutex_unlock(osk_mutex * lock)
+{
+ OSK_ASSERT(NULL != lock);
+ mutex_unlock(lock);
+}
+
+#define OSKP_ASSERT_MUTEX_IS_LOCKED(lock) \
+ OSK_ASSERT(0 != mutex_is_locked(lock))
+
+/* Note: This uses a GNU C Extension to allow Linux's CONFIG_PROVE_LOCKING to work correctly
+ *
+ * This is not required outside of Linux
+ *
+ * NOTE: the local variable must not conflict with an identifier in a wider scope */
+#define osk_spinlock_init( ARG_LOCK, ARG_ORDER ) \
+ ({ \
+ OSK_ORDER_VAR_DEFINITION(ARG_ORDER); \
+ OSK_ASSERT( OSK_LOCK_ORDER_LAST <= __oskp_order__ && __oskp_order__ <= OSK_LOCK_ORDER_FIRST ); \
+ OSKP_LOCK_PTR_ASSERT( (ARG_LOCK) ); \
+ spin_lock_init( (ARG_LOCK) ); \
+ OSK_ERR_NONE;})
+
+OSK_STATIC_INLINE void osk_spinlock_term(osk_spinlock * lock)
+{
+ OSK_ASSERT(NULL != lock);
+ /* nop */
+}
+
+OSK_STATIC_INLINE void osk_spinlock_lock(osk_spinlock * lock)
+{
+ OSK_ASSERT(NULL != lock);
+ spin_lock(lock);
+}
+
+OSK_STATIC_INLINE void osk_spinlock_unlock(osk_spinlock * lock)
+{
+ OSK_ASSERT(NULL != lock);
+ spin_unlock(lock);
+}
+
+#define OSKP_ASSERT_SPINLOCK_IS_LOCKED(lock) lockdep_assert_held(lock)
+#define OSKP_ASSERT_SPINLOCK_IRQ_IS_LOCKED(lock_irq) lockdep_assert_held(&(lock_irq)->lock)
+
+/* Note: This uses a GNU C Extension to allow Linux's CONFIG_PROVE_LOCKING to work correctly
+ *
+ * This is not required outside of Linux
+ *
+ * NOTE: the local variable must not conflict with an identifier in a wider scope */
+#define osk_spinlock_irq_init( ARG_LOCK, ARG_ORDER ) \
+ ({ \
+ OSK_ORDER_VAR_DEFINITION(ARG_ORDER); \
+ OSK_ASSERT( OSK_LOCK_ORDER_LAST <= __oskp_order__ && __oskp_order__ <= OSK_LOCK_ORDER_FIRST ); \
+ OSKP_LOCK_PTR_ASSERT( (ARG_LOCK) ); \
+ spin_lock_init( &(ARG_LOCK)->lock ); \
+ OSK_ERR_NONE;})
+
+OSK_STATIC_INLINE void osk_spinlock_irq_term(osk_spinlock_irq * lock)
+{
+ OSK_ASSERT(NULL != lock);
+}
+
+OSK_STATIC_INLINE void osk_spinlock_irq_lock(osk_spinlock_irq * lock)
+{
+ unsigned long flags;
+ OSK_ASSERT(NULL != lock);
+ spin_lock_irqsave(&lock->lock, flags);
+ lock->flags = flags;
+}
+
+OSK_STATIC_INLINE void osk_spinlock_irq_unlock(osk_spinlock_irq * lock)
+{
+ OSK_ASSERT(NULL != lock);
+ spin_unlock_irqrestore(&lock->lock, lock->flags);
+}
+
+#endif /* _OSK_ARCH_LOCKS_H_ */
diff --git a/drivers/gpu/arm/t6xx/kbase/osk/src/linux/include/osk/mali_osk_arch_low_level_mem.h b/drivers/gpu/arm/t6xx/kbase/osk/src/linux/include/osk/mali_osk_arch_low_level_mem.h
new file mode 100644
index 0000000..ce682b0
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/osk/src/linux/include/osk/mali_osk_arch_low_level_mem.h
@@ -0,0 +1,111 @@
+/*
+ *
+ * (C) COPYRIGHT 2008-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file
+ * Implementation of the OS abstraction layer for the kernel device driver
+ */
+
+#ifndef _OSK_ARCH_LOW_LEVEL_MEM_H_
+#define _OSK_ARCH_LOW_LEVEL_MEM_H_
+
+#ifndef _OSK_H_
+#error "Include mali_osk.h directly"
+#endif
+
+#include <linux/mm.h>
+#include <linux/highmem.h>
+#include <linux/dma-mapping.h>
+
+OSK_STATIC_INLINE osk_error oskp_phy_dedicated_allocator_request_memory(osk_phy_addr mem,u32 nr_pages, const char* name)
+{
+ if(OSK_SIMULATE_FAILURE(OSK_OSK))
+ {
+ return OSK_ERR_FAIL;
+ }
+
+ if (NULL != request_mem_region(mem, nr_pages << OSK_PAGE_SHIFT , name))
+ {
+ return OSK_ERR_NONE;
+ }
+ return OSK_ERR_FAIL;
+}
+
+OSK_STATIC_INLINE void oskp_phy_dedicated_allocator_release_memory(osk_phy_addr mem,u32 nr_pages)
+{
+ release_mem_region(mem, nr_pages << OSK_PAGE_SHIFT);
+}
+
+
+static inline void *osk_kmap(osk_phy_addr page)
+{
+ if(OSK_SIMULATE_FAILURE(OSK_OSK))
+ {
+ return NULL;
+ }
+
+ return kmap(pfn_to_page(PFN_DOWN(page)));
+}
+
+static inline void osk_kunmap(osk_phy_addr page, void * mapping)
+{
+ kunmap(pfn_to_page(PFN_DOWN(page)));
+}
+
+static inline void *osk_kmap_atomic(osk_phy_addr page)
+{
+ /**
+ * Note: kmap_atomic should never fail and so OSK_SIMULATE_FAILURE is not
+ * included for this function call.
+ */
+ return kmap_atomic(pfn_to_page(PFN_DOWN(page)));
+}
+
+static inline void osk_kunmap_atomic(osk_phy_addr page, void *mapping)
+{
+ kunmap_atomic(mapping);
+}
+
+static inline void osk_sync_to_memory(osk_phy_addr paddr, osk_virt_addr vaddr, size_t sz)
+{
+#ifdef CONFIG_ARM
+ dmac_flush_range(vaddr, vaddr+sz-1);
+ outer_flush_range(paddr, paddr+sz-1);
+#elif defined(CONFIG_X86)
+ struct scatterlist scl = {0, };
+ sg_set_page(&scl, pfn_to_page(PFN_DOWN(paddr)), sz,
+ paddr & (PAGE_SIZE -1 ));
+ dma_sync_sg_for_cpu(NULL, &scl, 1, DMA_TO_DEVICE);
+ mb(); /* for outer_sync (if needed) */
+#else
+#error Implement cache maintenance for your architecture here
+#endif
+}
+
+static inline void osk_sync_to_cpu(osk_phy_addr paddr, osk_virt_addr vaddr, size_t sz)
+{
+#ifdef CONFIG_ARM
+ dmac_flush_range(vaddr, vaddr+sz-1);
+ outer_flush_range(paddr, paddr+sz-1);
+#elif defined(CONFIG_X86)
+ struct scatterlist scl = {0, };
+ sg_set_page(&scl, pfn_to_page(PFN_DOWN(paddr)), sz,
+ paddr & (PAGE_SIZE -1 ));
+ dma_sync_sg_for_cpu(NULL, &scl, 1, DMA_FROM_DEVICE);
+#else
+#error Implement cache maintenance for your architecture here
+#endif
+}
+
+#endif /* _OSK_ARCH_LOW_LEVEL_MEM_H_ */
diff --git a/drivers/gpu/arm/t6xx/kbase/osk/src/linux/include/osk/mali_osk_arch_math.h b/drivers/gpu/arm/t6xx/kbase/osk/src/linux/include/osk/mali_osk_arch_math.h
new file mode 100644
index 0000000..5ece04b
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/osk/src/linux/include/osk/mali_osk_arch_math.h
@@ -0,0 +1,42 @@
+/*
+ *
+ * (C) COPYRIGHT 2010-2011 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file
+ * Implementation of the OS abstraction layer for the kernel device driver
+ */
+
+#ifndef _OSK_ARCH_MATH_H
+#define _OSK_ARCH_MATH_H
+
+#ifndef _OSK_H_
+#error "Include mali_osk.h directly"
+#endif
+
+#include <asm/div64.h>
+
+OSK_STATIC_INLINE u32 osk_divmod6432(u64 *value, u32 divisor)
+{
+ u64 v;
+ u32 r;
+
+ OSK_ASSERT(NULL != value);
+
+ v = *value;
+ r = do_div(v, divisor);
+ *value = v;
+ return r;
+}
+
+#endif /* _OSK_ARCH_MATH_H_ */
diff --git a/drivers/gpu/arm/t6xx/kbase/osk/src/linux/include/osk/mali_osk_arch_mem.h b/drivers/gpu/arm/t6xx/kbase/osk/src/linux/include/osk/mali_osk_arch_mem.h
new file mode 100644
index 0000000..4517c61
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/osk/src/linux/include/osk/mali_osk_arch_mem.h
@@ -0,0 +1,83 @@
+/*
+ *
+ * (C) COPYRIGHT 2008-2011 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file
+ * Implementation of the OS abstraction layer for the kernel device driver
+ */
+
+#ifndef _OSK_ARCH_MEM_H_
+#define _OSK_ARCH_MEM_H_
+
+#ifndef _OSK_H_
+#error "Include mali_osk.h directly"
+#endif
+
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+
+OSK_STATIC_INLINE void * osk_malloc(size_t size)
+{
+ OSK_ASSERT(0 != size);
+
+ if(OSK_SIMULATE_FAILURE(OSK_OSK))
+ {
+ return NULL;
+ }
+
+ return kmalloc(size, GFP_KERNEL);
+}
+
+OSK_STATIC_INLINE void * osk_calloc(size_t size)
+{
+ OSK_ASSERT(0 != size);
+
+ if(OSK_SIMULATE_FAILURE(OSK_OSK))
+ {
+ return NULL;
+ }
+
+ return kzalloc(size, GFP_KERNEL);
+}
+
+OSK_STATIC_INLINE void osk_free(void * ptr)
+{
+ kfree(ptr);
+}
+
+OSK_STATIC_INLINE void * osk_vmalloc(size_t size)
+{
+ OSK_ASSERT(0 != size);
+
+ if(OSK_SIMULATE_FAILURE(OSK_OSK))
+ {
+ return NULL;
+ }
+
+ return vmalloc_user(size);
+}
+
+OSK_STATIC_INLINE void osk_vfree(void * ptr)
+{
+ vfree(ptr);
+}
+
+#define OSK_MEMCPY( dst, src, len ) memcpy(dst, src, len)
+
+#define OSK_MEMCMP( s1, s2, len ) memcmp(s1, s2, len)
+
+#define OSK_MEMSET( ptr, chr, size ) memset(ptr, chr, size)
+
+
+#endif /* _OSK_ARCH_MEM_H_ */
diff --git a/drivers/gpu/arm/t6xx/kbase/osk/src/linux/include/osk/mali_osk_arch_power.h b/drivers/gpu/arm/t6xx/kbase/osk/src/linux/include/osk/mali_osk_arch_power.h
new file mode 100644
index 0000000..e75477d
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/osk/src/linux/include/osk/mali_osk_arch_power.h
@@ -0,0 +1,46 @@
+/*
+ *
+ * (C) COPYRIGHT 2010-2011 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file
+ * Implementation of the OS abstraction layer for the kernel device driver
+ */
+
+#ifndef _OSK_ARCH_POWER_H_
+#define _OSK_ARCH_POWER_H_
+
+#include <linux/pm_runtime.h>
+
+OSK_STATIC_INLINE osk_power_request_result osk_power_request(osk_power_info *info, osk_power_state state)
+{
+ osk_power_request_result request_result = OSK_POWER_REQUEST_FINISHED;
+
+ OSK_ASSERT(NULL != info);
+
+ switch(state)
+ {
+ case OSK_POWER_STATE_OFF:
+ /* request OS to suspend device*/
+ break;
+ case OSK_POWER_STATE_IDLE:
+ /* request OS to idle device */
+ break;
+ case OSK_POWER_STATE_ACTIVE:
+ /* request OS to resume device */
+ break;
+ }
+ return request_result;
+}
+
+#endif
diff --git a/drivers/gpu/arm/t6xx/kbase/osk/src/linux/include/osk/mali_osk_arch_time.h b/drivers/gpu/arm/t6xx/kbase/osk/src/linux/include/osk/mali_osk_arch_time.h
new file mode 100644
index 0000000..1a66d64
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/osk/src/linux/include/osk/mali_osk_arch_time.h
@@ -0,0 +1,56 @@
+/*
+ *
+ * (C) COPYRIGHT 2010-2011 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file
+ * Implementation of the OS abstraction layer for the kernel device driver
+ */
+
+#ifndef _OSK_ARCH_TIME_H
+#define _OSK_ARCH_TIME_H
+
+#ifndef _OSK_H_
+#error "Include mali_osk.h directly"
+#endif
+
+OSK_STATIC_INLINE osk_ticks osk_time_now(void)
+{
+ return jiffies;
+}
+
+OSK_STATIC_INLINE u32 osk_time_mstoticks(u32 ms)
+{
+ return msecs_to_jiffies(ms);
+}
+
+OSK_STATIC_INLINE u32 osk_time_elapsed(osk_ticks ticka, osk_ticks tickb)
+{
+ return jiffies_to_msecs((long)tickb - (long)ticka);
+}
+
+OSK_STATIC_INLINE mali_bool osk_time_after(osk_ticks ticka, osk_ticks tickb)
+{
+ return time_after(ticka, tickb);
+}
+
+OSK_STATIC_INLINE void osk_gettimeofday(osk_timeval *tv)
+{
+ struct timespec ts;
+ getnstimeofday(&ts);
+
+ tv->tv_sec = ts.tv_sec;
+ tv->tv_usec = ts.tv_nsec/1000;
+}
+
+#endif /* _OSK_ARCH_TIME_H_ */
diff --git a/drivers/gpu/arm/t6xx/kbase/osk/src/linux/include/osk/mali_osk_arch_timers.h b/drivers/gpu/arm/t6xx/kbase/osk/src/linux/include/osk/mali_osk_arch_timers.h
new file mode 100644
index 0000000..59afb84
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/osk/src/linux/include/osk/mali_osk_arch_timers.h
@@ -0,0 +1,169 @@
+/*
+ *
+ * (C) COPYRIGHT 2010-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file
+ * Implementation of the OS abstraction layer for the kernel device driver
+ */
+
+#ifndef _OSK_ARCH_TIMERS_H
+#define _OSK_ARCH_TIMERS_H
+
+#ifndef _OSK_H_
+#error "Include mali_osk.h directly"
+#endif
+
+#ifdef CONFIG_MALI_DEBUG
+void oskp_debug_test_timer_stats( void );
+#endif
+
+enum hrtimer_restart oskp_timer_callback_wrapper( struct hrtimer * hr_timer );
+
+OSK_STATIC_INLINE osk_error osk_timer_init(osk_timer * const tim)
+{
+ OSK_ASSERT(NULL != tim);
+
+ OSK_DEBUG_CODE( oskp_debug_test_timer_stats() );
+
+ hrtimer_init(&tim->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ tim->timer.function = NULL;
+
+ OSK_DEBUG_CODE( tim->active = MALI_FALSE );
+ OSK_ASSERT(0 == object_is_on_stack(tim));
+ return OSK_ERR_NONE;
+}
+
+OSK_STATIC_INLINE osk_error osk_timer_on_stack_init(osk_timer * const tim)
+{
+ OSK_ASSERT(NULL != tim);
+ hrtimer_init_on_stack(&tim->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ tim->timer.function = NULL;
+
+ OSK_DEBUG_CODE( tim->active = MALI_FALSE );
+ OSK_ASSERT(0 != object_is_on_stack(tim));
+ return OSK_ERR_NONE;
+}
+
+OSK_STATIC_INLINE osk_error osk_timer_start(osk_timer *tim, u32 delay)
+{
+ osk_error err;
+ u64 delay_ns = delay * (u64)1000000U;
+
+ err = osk_timer_start_ns( tim, delay_ns );
+
+ return err;
+}
+
+OSK_STATIC_INLINE osk_error osk_timer_start_ns(osk_timer *tim, u64 delay_ns)
+{
+ ktime_t kdelay;
+ int was_active;
+ OSK_ASSERT(NULL != tim);
+ OSK_ASSERT(NULL != tim->timer.function);
+ OSK_ASSERT(delay_ns != 0);
+
+ kdelay = ns_to_ktime( delay_ns );
+
+ was_active = hrtimer_start( &tim->timer, kdelay, HRTIMER_MODE_REL );
+
+ OSK_ASSERT( was_active == 0 ); /* You cannot start a timer that has already been started */
+
+ CSTD_UNUSED( was_active );
+ OSK_DEBUG_CODE( tim->active = MALI_TRUE );
+ return OSK_ERR_NONE;
+}
+
+OSK_STATIC_INLINE osk_error osk_timer_modify(osk_timer *tim, u32 new_delay)
+{
+ osk_error err;
+ u64 delay_ns = new_delay * (u64)1000000U;
+
+ err = osk_timer_modify_ns( tim, delay_ns );
+ return err;
+}
+
+OSK_STATIC_INLINE osk_error osk_timer_modify_ns(osk_timer *tim, u64 new_delay_ns)
+{
+ ktime_t kdelay;
+ int was_active;
+ OSK_ASSERT(NULL != tim);
+ OSK_ASSERT(NULL != tim->timer.function);
+ OSK_ASSERT(0 != new_delay_ns);
+
+ kdelay = ns_to_ktime( new_delay_ns );
+
+ /* hrtimers will stop the existing timer if it's running on any cpu, so
+ * it's safe just to start the timer again: */
+ was_active = hrtimer_start( &tim->timer, kdelay, HRTIMER_MODE_REL );
+
+ CSTD_UNUSED( was_active );
+ OSK_DEBUG_CODE( tim->active = MALI_TRUE );
+ return OSK_ERR_NONE;
+}
+
+OSK_STATIC_INLINE void osk_timer_stop(osk_timer *tim)
+{
+ int was_active;
+ OSK_ASSERT(NULL != tim);
+ OSK_ASSERT(NULL != tim->timer.function);
+
+ was_active = hrtimer_cancel(&tim->timer);
+
+ CSTD_UNUSED( was_active );
+ OSK_DEBUG_CODE( tim->active = MALI_FALSE );
+}
+
+OSK_STATIC_INLINE void osk_timer_callback_set(osk_timer *tim, osk_timer_callback callback, void *data)
+{
+ OSK_ASSERT(NULL != tim);
+ OSK_ASSERT(NULL != callback);
+ OSK_DEBUG_CODE(
+ if (MALI_FALSE == tim->active)
+ {
+ }
+ );
+
+ tim->timer.function = &oskp_timer_callback_wrapper;
+
+ /* osk_timer_callback uses void * for the callback parameter instead of unsigned long in Linux */
+ tim->callback = callback;
+ tim->data = data;
+}
+
+OSK_STATIC_INLINE void osk_timer_term(osk_timer *tim)
+{
+ OSK_ASSERT(NULL != tim);
+ OSK_ASSERT(0 == object_is_on_stack(tim));
+ OSK_DEBUG_CODE(
+ if (MALI_FALSE == tim->active)
+ {
+ }
+ );
+ /* Nothing to do */
+}
+
+OSK_STATIC_INLINE void osk_timer_on_stack_term(osk_timer *tim)
+{
+ OSK_ASSERT(NULL != tim);
+ OSK_ASSERT(0 != object_is_on_stack(tim));
+ OSK_DEBUG_CODE(
+ if (MALI_FALSE == tim->active)
+ {
+ }
+ );
+ destroy_hrtimer_on_stack(&tim->timer);
+}
+
+#endif /* _OSK_ARCH_TIMERS_H_ */
+
diff --git a/drivers/gpu/arm/t6xx/kbase/osk/src/linux/include/osk/mali_osk_arch_types.h b/drivers/gpu/arm/t6xx/kbase/osk/src/linux/include/osk/mali_osk_arch_types.h
new file mode 100644
index 0000000..f15e8ba
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/osk/src/linux/include/osk/mali_osk_arch_types.h
@@ -0,0 +1,141 @@
+/*
+ *
+ * (C) COPYRIGHT 2010-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file
+ * Implementation of the OS abstraction layer for the kernel device driver
+ */
+
+#ifndef _OSK_ARCH_TYPES_H_
+#define _OSK_ARCH_TYPES_H_
+
+#include <linux/version.h> /* version detection */
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/rwsem.h>
+#include <linux/wait.h>
+#include <linux/hrtimer.h>
+#include <linux/workqueue.h>
+#include <linux/mm_types.h>
+#include <asm/atomic.h>
+#include <linux/sched.h>
+
+#include <malisw/mali_malisw.h>
+
+ /* This will have to agree with the OSU definition of the CPU page size: CONFIG_CPU_PAGE_SIZE_LOG2 */
+#define OSK_PAGE_SHIFT PAGE_SHIFT
+#define OSK_PAGE_SIZE PAGE_SIZE
+#define OSK_PAGE_MASK PAGE_MASK
+
+/** Number of CPU Cores */
+#define OSK_NUM_CPUS NR_CPUS
+
+/** Total amount of memory, in pages */
+#define OSK_MEM_PAGES totalram_pages
+
+/**
+ * @def OSK_L1_DCACHE_LINE_SIZE_LOG2
+ * @brief CPU L1 Data Cache Line size, in the form of a Logarithm to base 2.
+ *
+ * Must agree with the OSU definition: CONFIG_CPU_L1_DCACHE_LINE_SIZE_LOG2.
+ */
+#define OSK_L1_DCACHE_LINE_SIZE_LOG2 6
+
+/**
+ * @def OSK_L1_DCACHE_SIZE
+ * @brief CPU L1 Data Cache size, in bytes.
+ *
+ * Must agree with the OSU definition: CONFIG_CPU_L1_DCACHE_SIZE.
+ */
+#define OSK_L1_DCACHE_SIZE ((u32)0x00008000)
+
+
+#define OSK_MIN(x,y) min((x), (y))
+
+typedef spinlock_t osk_spinlock;
+typedef struct osk_spinlock_irq {
+ spinlock_t lock;
+ unsigned long flags;
+} osk_spinlock_irq;
+
+typedef struct mutex osk_mutex;
+typedef struct rw_semaphore osk_rwlock;
+
+typedef atomic_t osk_atomic;
+
+typedef struct osk_waitq
+{
+ /**
+ * set to MALI_TRUE when the waitq is signaled; set to MALI_FALSE when
+ * not signaled.
+ *
+ * This does not require locking for the setter, clearer and waiter.
+ * Here's why:
+ * - The only sensible use of a waitq is for operations to occur in
+ * strict order, without possibility of race between the callers of
+ * osk_waitq_set() and osk_waitq_clear() (the setter and clearer).
+ * Effectively, the clear must cause a later set to occur.
+ * - When the clear/set operations occur in different threads, some
+ * form of communication needs to happen for the clear to cause the
+ * signal to occur later.
+ * - This itself \b must involve a memory barrier, and so the clear is
+ * guarenteed to be observed by the waiter such that it is before the set.
+ * (and the set is observed after the clear).
+ *
+ * For example, running a GPU job might clear a "there are jobs in
+ * flight" waitq. Running the job must issue an register write, (and
+ * likely a post to a workqueue due to IRQ handling). Those operations
+ * must cause a data barrier to occur. During IRQ handling/workqueue
+ * processing, we might then set the waitq, and this happens after the
+ * barrier. Hence, the set and clear are observed in strict order.
+ */
+ mali_bool signaled;
+ wait_queue_head_t wq; /**< threads waiting for flag to be signalled */
+} osk_waitq;
+
+typedef struct osk_timer {
+ struct hrtimer timer;
+ osk_timer_callback callback;
+ void *data;
+#ifdef CONFIG_MALI_DEBUG
+ mali_bool active;
+#endif /* CONFIG_MALI_DEBUG */
+} osk_timer;
+
+typedef struct page osk_page;
+typedef struct vm_area_struct osk_vma;
+
+typedef unsigned long osk_ticks; /* 32-bit resolution deemed to be sufficient */
+
+/* Separate definitions for the following, to avoid wrapper functions for GPL drivers */
+typedef work_func_t osk_workq_fn;
+
+typedef struct work_struct osk_workq_work;
+
+typedef struct osk_workq
+{
+ struct workqueue_struct *wqs;
+} osk_workq;
+
+typedef struct device osk_power_info;
+
+typedef struct timeval osk_timeval;
+
+/**
+ * Physical address
+ */
+typedef phys_addr_t osk_phy_addr;
+
+#endif /* _OSK_ARCH_TYPES_H_ */
+
diff --git a/drivers/gpu/arm/t6xx/kbase/osk/src/linux/include/osk/mali_osk_arch_waitq.h b/drivers/gpu/arm/t6xx/kbase/osk/src/linux/include/osk/mali_osk_arch_waitq.h
new file mode 100644
index 0000000..605ec26
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/osk/src/linux/include/osk/mali_osk_arch_waitq.h
@@ -0,0 +1,69 @@
+/*
+ *
+ * (C) COPYRIGHT 2010-2011 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file
+ * Implementation of the OS abstraction layer for the kernel device driver
+ */
+
+#ifndef _OSK_ARCH_WAITQ_H
+#define _OSK_ARCH_WAITQ_H
+
+#ifndef _OSK_H_
+#error "Include mali_osk.h directly"
+#endif
+
+#include <linux/wait.h>
+#include <linux/sched.h>
+
+/*
+ * Note:
+ *
+ * We do not need locking on the signalled member (see its doxygen description)
+ */
+
+OSK_STATIC_INLINE osk_error osk_waitq_init(osk_waitq * const waitq)
+{
+ OSK_ASSERT(NULL != waitq);
+ waitq->signaled = MALI_FALSE;
+ init_waitqueue_head(&waitq->wq);
+ return OSK_ERR_NONE;
+}
+
+OSK_STATIC_INLINE void osk_waitq_wait(osk_waitq *waitq)
+{
+ OSK_ASSERT(NULL != waitq);
+ wait_event(waitq->wq, waitq->signaled != MALI_FALSE);
+}
+
+OSK_STATIC_INLINE void osk_waitq_set(osk_waitq *waitq)
+{
+ OSK_ASSERT(NULL != waitq);
+ waitq->signaled = MALI_TRUE;
+ wake_up(&waitq->wq);
+}
+
+OSK_STATIC_INLINE void osk_waitq_clear(osk_waitq *waitq)
+{
+ OSK_ASSERT(NULL != waitq);
+ waitq->signaled = MALI_FALSE;
+}
+
+OSK_STATIC_INLINE void osk_waitq_term(osk_waitq *waitq)
+{
+ OSK_ASSERT(NULL != waitq);
+ /* NOP on Linux */
+}
+
+#endif /* _OSK_ARCH_WAITQ_H_ */
diff --git a/drivers/gpu/arm/t6xx/kbase/osk/src/linux/include/osk/mali_osk_arch_workq.h b/drivers/gpu/arm/t6xx/kbase/osk/src/linux/include/osk/mali_osk_arch_workq.h
new file mode 100644
index 0000000..d97793c
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/osk/src/linux/include/osk/mali_osk_arch_workq.h
@@ -0,0 +1,127 @@
+/*
+ *
+ * (C) COPYRIGHT 2010-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file
+ * Implementation of the OS abstraction layer for the kernel device driver
+ */
+
+#ifndef _OSK_ARCH_WORKQ_H_
+#define _OSK_ARCH_WORKQ_H_
+
+#include <linux/version.h> /* version detection */
+#include "osk/include/mali_osk_failure.h"
+
+OSK_STATIC_INLINE osk_error osk_workq_init(osk_workq * const wq, const char *name, u32 flags)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36))
+ unsigned int wqflags = 0;
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)) */
+
+ OSK_ASSERT(NULL != wq);
+ OSK_ASSERT(NULL != name);
+ OSK_ASSERT(0 == (flags & ~(OSK_WORKQ_NON_REENTRANT|OSK_WORKQ_HIGH_PRIORITY|OSK_WORKQ_RESCUER)));
+
+ if(OSK_SIMULATE_FAILURE(OSK_OSK))
+ {
+ return OSK_ERR_FAIL;
+ }
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)
+ if (flags & OSK_WORKQ_NON_REENTRANT)
+ {
+ wqflags |= WQ_NON_REENTRANT;
+ }
+ if (flags & OSK_WORKQ_HIGH_PRIORITY)
+ {
+ wqflags |= WQ_HIGHPRI;
+ }
+ if (flags & OSK_WORKQ_RESCUER)
+ {
+ wqflags |= WQ_RESCUER;
+ }
+
+ wq->wqs = alloc_workqueue(name, wqflags, 1);
+#else
+ if (flags & OSK_WORKQ_NON_REENTRANT)
+ {
+ wq->wqs = create_singlethread_workqueue(name);
+ }
+ else
+ {
+ wq->wqs = create_workqueue(name);
+ }
+#endif
+ if (NULL == wq->wqs)
+ {
+ return OSK_ERR_FAIL;
+ }
+ return OSK_ERR_NONE;
+}
+
+OSK_STATIC_INLINE void osk_workq_term(osk_workq *wq)
+{
+ OSK_ASSERT(NULL != wq);
+ destroy_workqueue(wq->wqs);
+}
+
+OSK_STATIC_INLINE void osk_workq_work_init(osk_workq_work * const wk, osk_workq_fn fn)
+{
+ work_func_t func_to_call_first;
+ struct work_struct *os_work;
+ OSK_ASSERT(NULL != wk);
+ OSK_ASSERT(NULL != fn);
+ OSK_ASSERT(0 == object_is_on_stack(wk));
+
+ func_to_call_first = fn;
+ os_work = wk;
+
+ INIT_WORK(os_work, func_to_call_first);
+}
+
+OSK_STATIC_INLINE void osk_workq_work_init_on_stack(osk_workq_work * const wk, osk_workq_fn fn)
+{
+ work_func_t func_to_call_first;
+ struct work_struct *os_work;
+ OSK_ASSERT(NULL != wk);
+ OSK_ASSERT(NULL != fn);
+ OSK_ASSERT(0 != object_is_on_stack(wk));
+
+ func_to_call_first = fn;
+ os_work = wk;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)
+ INIT_WORK_ONSTACK(os_work, func_to_call_first);
+#else
+ INIT_WORK_ON_STACK(os_work, func_to_call_first);
+#endif
+}
+
+OSK_STATIC_INLINE void osk_workq_submit(osk_workq *wq, osk_workq_work * const wk)
+{
+ OSK_ASSERT(NULL != wk);
+ OSK_ASSERT(NULL != wq);
+
+ queue_work(wq->wqs, wk);
+}
+
+OSK_STATIC_INLINE void osk_workq_flush(osk_workq *wq)
+{
+ OSK_ASSERT(NULL != wq);
+
+ flush_workqueue(wq->wqs);
+}
+
+
+#endif
diff --git a/drivers/gpu/arm/t6xx/kbase/osk/src/linux/mali_osk_debug.c b/drivers/gpu/arm/t6xx/kbase/osk/src/linux/mali_osk_debug.c
new file mode 100644
index 0000000..2d1b2a0
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/osk/src/linux/mali_osk_debug.c
@@ -0,0 +1,56 @@
+/*
+ *
+ * (C) COPYRIGHT 2010-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+#include <osk/mali_osk.h>
+
+oskp_debug_assert_cb oskp_debug_assert_registered_cb =
+{
+ NULL,
+ NULL
+};
+
+void oskp_debug_print(const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ oskp_validate_format_string(format);
+ vprintk(format, args);
+ va_end(args);
+}
+
+s32 osk_snprintf(char *str, size_t size, const char *format, ...)
+{
+ va_list args;
+ s32 ret;
+ va_start(args, format);
+ oskp_validate_format_string(format);
+ ret = vsnprintf(str, size, format, args);
+ va_end(args);
+ return ret;
+}
+
+void osk_debug_assert_register_hook( osk_debug_assert_hook *func, void *param )
+{
+ oskp_debug_assert_registered_cb.func = func;
+ oskp_debug_assert_registered_cb.param = param;
+}
+
+void oskp_debug_assert_call_hook( void )
+{
+ if ( oskp_debug_assert_registered_cb.func != NULL )
+ {
+ oskp_debug_assert_registered_cb.func( oskp_debug_assert_registered_cb.param );
+ }
+}
+
diff --git a/drivers/gpu/arm/t6xx/kbase/osk/src/linux/mali_osk_timers.c b/drivers/gpu/arm/t6xx/kbase/osk/src/linux/mali_osk_timers.c
new file mode 100644
index 0000000..fba8540
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/osk/src/linux/mali_osk_timers.c
@@ -0,0 +1,111 @@
+/*
+ *
+ * (C) COPYRIGHT 2011-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+#include <osk/mali_osk.h>
+
+#ifdef CONFIG_MALI_DEBUG
+#include <linux/delay.h>
+
+#define TIMER_PERIOD_NS 100
+#define TIMER_TEST_TIME_MS 1000
+typedef struct oskp_time_test
+{
+ osk_timer timer;
+ u32 val;
+ mali_bool should_stop;
+} oskp_time_test;
+
+static mali_bool oskp_timer_has_been_checked = MALI_FALSE;
+#endif /* CONFIG_MALI_DEBUG */
+
+enum hrtimer_restart oskp_timer_callback_wrapper( struct hrtimer * hr_timer )
+{
+ osk_timer *tim;
+
+ tim = CONTAINER_OF( hr_timer, osk_timer, timer );
+ tim->callback( tim->data );
+
+ return HRTIMER_NORESTART;
+}
+
+#ifdef CONFIG_MALI_DEBUG
+static void oskp_check_timer_callback( void *data )
+{
+ oskp_time_test *time_tester = (oskp_time_test*)data;
+
+ (time_tester->val)++;
+
+ if ( time_tester->should_stop == MALI_FALSE )
+ {
+ osk_error err;
+ err = osk_timer_start_ns( &time_tester->timer, TIMER_PERIOD_NS );
+ if ( err != OSK_ERR_NONE )
+ {
+ OSK_PRINT_WARN( OSK_BASE_CORE, "OSK Timer couldn't restart - testing stats will be inaccurate" );
+ }
+ }
+}
+
+void oskp_debug_test_timer_stats( void )
+{
+ oskp_time_test time_tester;
+ osk_ticks start_timestamp;
+ osk_ticks end_timestamp;
+ u32 msec_elapsed;
+ osk_error err;
+
+ if ( oskp_timer_has_been_checked != MALI_FALSE )
+ {
+ return;
+ }
+ oskp_timer_has_been_checked = MALI_TRUE;
+
+ OSK_MEMSET( &time_tester, 0, sizeof(time_tester) );
+
+ err = osk_timer_on_stack_init( &time_tester.timer );
+ if ( err != OSK_ERR_NONE )
+ {
+ goto fail_init;
+ }
+
+ osk_timer_callback_set( &time_tester.timer, &oskp_check_timer_callback, &time_tester );
+
+ start_timestamp = osk_time_now();
+ err = osk_timer_start_ns( &time_tester.timer, TIMER_PERIOD_NS );
+ if ( err != OSK_ERR_NONE )
+ {
+ goto fail_start;
+ }
+
+ msleep( TIMER_TEST_TIME_MS );
+
+ time_tester.should_stop = MALI_TRUE;
+
+ osk_timer_stop( &time_tester.timer );
+ end_timestamp = osk_time_now();
+
+ msec_elapsed = osk_time_elapsed( start_timestamp, end_timestamp );
+
+ OSK_PRINT( OSK_BASE_CORE, "OSK Timer did %d iterations in %dms", time_tester.val, msec_elapsed );
+
+ osk_timer_on_stack_term( &time_tester.timer );
+ return;
+
+ fail_start:
+ osk_timer_on_stack_term( &time_tester.timer );
+ fail_init:
+ OSK_PRINT_WARN( OSK_BASE_CORE, "OSK Timer couldn't init/start for testing stats" );
+ return;
+}
+#endif /* CONFIG_MALI_DEBUG */
diff --git a/drivers/gpu/arm/t6xx/kbase/platform_dummy/mali_ukk_os.h b/drivers/gpu/arm/t6xx/kbase/platform_dummy/mali_ukk_os.h
new file mode 100644
index 0000000..fb201899
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/platform_dummy/mali_ukk_os.h
@@ -0,0 +1,49 @@
+/*
+ *
+ * (C) COPYRIGHT 2010, 2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_ukk_os.h
+ * Types and definitions that are common for Linux OSs for the kernel side of the
+ * User-Kernel interface.
+ */
+
+#ifndef _UKK_OS_H_ /* Linux version */
+#define _UKK_OS_H_
+
+#include <linux/fs.h>
+
+/**
+ * @addtogroup uk_api User-Kernel Interface API
+ * @{
+ */
+
+/**
+ * @addtogroup uk_api_kernel UKK (Kernel side)
+ * @{
+ */
+
+/**
+ * Internal OS specific data structure associated with each UKK session. Part
+ * of a ukk_session object.
+ */
+typedef struct ukkp_session
+{
+ int dummy; /**< No internal OS specific data at this time */
+} ukkp_session;
+
+/** @} end group uk_api_kernel */
+
+/** @} end group uk_api */
+
+#endif /* _UKK_OS_H__ */
diff --git a/drivers/gpu/arm/t6xx/kbase/src/Kbuild b/drivers/gpu/arm/t6xx/kbase/src/Kbuild
new file mode 100644
index 0000000..f073cc0
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/Kbuild
@@ -0,0 +1,172 @@
+#
+# (C) COPYRIGHT 2012 ARM Limited. All rights reserved.
+#
+# This program is free software and is provided to you under the terms of the GNU General Public License version 2
+# as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+#
+# A copy of the licence is included with the program, and can also be obtained from Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+#
+
+
+# Driver version string which is returned to userspace via an ioctl
+MALI_RELEASE_NAME ?= "r1p2-02dev0"
+
+# Paths required for build
+KBASE_PATH = $(src)/../..
+KBASE_SRC_PATH = $(src)/..
+KBASE_PLATFORM_PATH = $(KBASE_SRC_PATH)/platform_dummy
+OSK_PATH = $(src)/../osk/src/linux/include
+UMP_PATH = $(src)/../../../../../base
+
+ifeq ($(CONFIG_MALI_ERROR_INJECTION),y)
+MALI_ERROR_INJECT_ON = 1
+endif
+
+# Set up defaults if not defined by build system
+MALI_CUSTOMER_RELEASE ?= 0
+MALI_UNIT_TEST ?= 0
+MALI_KERNEL_TEST_API ?= 0
+MALI_ERROR_INJECT_ON ?= 0
+MALI_MOCK_TEST ?= 0
+MALI_COVERAGE ?= 0
+MALI_INSTRUMENTATION_LEVEL ?= 0
+
+
+# Set up our defines, which will be passed to gcc
+DEFINES = \
+ -DMALI_CUSTOMER_RELEASE=$(MALI_CUSTOMER_RELEASE) \
+ -DMALI_KERNEL_TEST_API=$(MALI_KERNEL_TEST_API) \
+ -DMALI_UNIT_TEST=$(MALI_UNIT_TEST) \
+ -DMALI_ERROR_INJECT_ON=$(MALI_ERROR_INJECT_ON) \
+ -DMALI_MOCK_TEST=$(MALI_MOCK_TEST) \
+ -DMALI_COVERAGE=$(MALI_COVERAGE) \
+ -DMALI_KBASE_SRC_LINUX_PATH=$(src)/linux \
+ -DMALI_INSTRUMENTATION_LEVEL=$(MALI_INSTRUMENTATION_LEVEL) \
+ -DMALI_RELEASE_NAME=\"$(MALI_RELEASE_NAME)\"
+
+# Use our defines when compiling
+ccflags-y += $(DEFINES) -I$(KBASE_PATH) -I$(KBASE_SRC_PATH) -I$(KBASE_PLATFORM_PATH) -I$(OSK_PATH) -I$(UMP_PATH)
+
+SRC := \
+ common/mali_kbase_device.c \
+ common/mali_kbase_cache_policy.c \
+ common/mali_kbase_mem.c \
+ common/mali_kbase_mmu.c \
+ common/mali_kbase_jd.c \
+ common/mali_kbase_jm.c \
+ common/mali_kbase_cpuprops.c \
+ common/mali_kbase_gpuprops.c \
+ common/mali_kbase_js.c \
+ common/mali_kbase_js_affinity.c \
+ common/mali_kbase_js_ctx_attr.c \
+ common/mali_kbase_pm.c \
+ common/mali_kbase_event.c \
+ common/mali_kbase_context.c \
+ common/mali_kbase_pm.c \
+ common/mali_kbase_pm_driver.c \
+ common/mali_kbase_pm_metrics.c \
+ common/mali_kbase_pm_always_on.c \
+ common/mali_kbase_pm_coarse_demand.c \
+ common/mali_kbase_pm_demand.c \
+ common/mali_kbase_config.c \
+ common/mali_kbase_security.c \
+ common/mali_kbase_instr.c \
+ common/mali_kbase_softjobs.c \
+ common/mali_kbase_8401_workaround.c \
+ common/mali_kbase_ukk.c \
+ common/mali_kbase_hw.c \
+ linux/mali_kbase_ukk_os.c \
+ linux/mali_kbase_mem_linux.c \
+ linux/mali_kbase_core_linux.c \
+ linux/mali_kbase_config_linux.c \
+ linux/mali_kbase_sync.c \
+ linux/mali_kbase_sync_user.c \
+ ../osk/src/linux/mali_osk_timers.c \
+ ../osk/src/linux/mali_osk_debug.c \
+ ../osk/src/common/mali_osk_bitops_cmn.c \
+ ../osk/src/common/mali_osk_debug_cmn.c
+
+# Job Scheduler Policy: Completely Fair Scheduler
+SRC += common/mali_kbase_js_policy_cfs.c
+
+# ensure GPL version of malisw gets pulled in
+ccflags-y += -I$(KBASE_PATH)
+
+ifeq ($(CONFIG_MALI_NO_MALI),y)
+ # Dummy model
+ SRC += common/mali_kbase_model_dummy.c
+ SRC += linux/mali_kbase_model_linux.c
+ # HW error simulation
+ SRC += common/mali_kbase_model_error_generator.c
+endif
+
+ifeq ($(MALI_MOCK_TEST),1)
+ # Test functionality
+ SRC += ../tests/internal/src/mock/mali_kbase_pm_driver_mock.c
+endif
+
+need_mem_track_file = 0
+ifeq ($(CONFIG_MALI_QA_LEAK),y)
+ # Memory leak tracking
+ need_mem_track_file = 1
+ SRC += ../osk/src/common/mali_osk_mem_track.c
+endif
+
+ifeq ($(CONFIG_MALI_QA_RESFAIL),y)
+ # Simulated resource failure
+ need_mem_track_file = 1
+ SRC += ../osk/src/common/mali_osk_failure.c
+endif
+
+ifeq ($(need_mem_track_file),1)
+ SRC += common/mali_kbase_mem_track.c
+endif
+
+# in-tree/out-of-tree logic needs to be slightly different to determine if a file is present
+ifeq ($(KBUILD_EXTMOD),)
+# in-tree
+MALI_METRICS_PATH = $(srctree)/drivers/gpu/arm/t6xx/kbase/src/linux
+else
+# out-of-tree
+MALI_METRICS_PATH = $(KBUILD_EXTMOD)/linux
+endif
+
+# Use vsync metrics example using PL111 driver, if available
+ifeq ($(wildcard $(MALI_METRICS_PATH)/mali_kbase_pm_metrics_linux.c),)
+ SRC += common/mali_kbase_pm_metrics_dummy.c
+else
+ SRC += linux/mali_kbase_pm_metrics_linux.c
+endif
+
+ifeq ($(CONFIG_MALI_PLATFORM_VEXPRESS),y)
+ SRC += linux/config/mali_kbase_config_vexpress.c \
+ linux/config/mali_kbase_cpu_vexpress.c
+endif
+
+ifeq ($(CONFIG_MALI_PLATFORM_GOLDFISH),y)
+ SRC += linux/config/mali_kbase_config_goldfish.c
+endif
+
+ifeq ($(CONFIG_MALI_PLATFORM_PBX),y)
+ SRC += linux/config/mali_kbase_config_pbx.c
+endif
+
+ifeq ($(CONFIG_MALI_PLATFORM_PANDA),y)
+ SRC += linux/config/mali_kbase_config_panda.c
+endif
+
+ifeq ($(CONFIG_MALI_PLATFORM_THIRDPARTY),y)
+# remove begin and end quotes from the Kconfig string type
+platform_name := $(shell echo $(CONFIG_MALI_PLATFORM_THIRDPARTY_NAME))
+ SRC += linux/config/tpip/mali_kbase_config_$(platform_name).c
+endif
+
+# Tell the Linux build system from which .o file to create the kernel module
+obj-$(CONFIG_MALI_T6XX) += mali_kbase.o
+obj-$(CONFIG_MALI_T6XX) += platform/mali_kbase_platform.o
+obj-$(CONFIG_MALI_T6XX) += platform/mali_kbase_dvfs.o
+
+# Tell the Linux build system to enable building of our .c files
+mali_kbase-y := $(SRC:.c=.o)
diff --git a/drivers/gpu/arm/t6xx/kbase/src/Makefile b/drivers/gpu/arm/t6xx/kbase/src/Makefile
new file mode 100644
index 0000000..5e4b4e7b
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/Makefile
@@ -0,0 +1,33 @@
+#
+# (C) COPYRIGHT 2010-2012 ARM Limited. All rights reserved.
+#
+# This program is free software and is provided to you under the terms of the GNU General Public License version 2
+# as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+#
+# A copy of the licence is included with the program, and can also be obtained from Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+#
+
+
+KDIR ?= /lib/modules/$(shell uname -r)/build
+
+UMP_PATH_RELATIVE = $(CURDIR)/../../../../../base/ump
+KBASE_PATH_RELATIVE = $(CURDIR)/../../kbase
+KDS_PATH_RELATIVE = $(CURDIR)/../../../../../..
+OSK_PATH = $(ROOT)/kernel/drivers/gpu/arm/t6xx/kbase/osk
+EXTRA_SYMBOLS = $(UMP_PATH_RELATIVE)/src/Module.symvers
+
+ifeq ($(MALI_UNIT_TEST), 1)
+ EXTRA_SYMBOLS += $(KBASE_PATH_RELATIVE)/tests/internal/src/kernel_assert_module/linux/Module.symvers
+endif
+
+# GPL driver supports KDS
+EXTRA_SYMBOLS += $(KDS_PATH_RELATIVE)/drivers/base/kds/Module.symvers
+
+# we get the symbols from modules using KBUILD_EXTRA_SYMBOLS to prevent warnings about unknown functions
+all:
+ $(MAKE) -C $(KDIR) M=$(CURDIR) EXTRA_CFLAGS="-I$(CURDIR)/../../../../../../include $(SCONS_CFLAGS)" $(SCONS_CONFIGS) KBUILD_EXTRA_SYMBOLS="$(EXTRA_SYMBOLS)" modules
+
+clean:
+ $(MAKE) -C $(KDIR) M=$(CURDIR) clean
diff --git a/drivers/gpu/arm/t6xx/kbase/src/Makefile.kbase b/drivers/gpu/arm/t6xx/kbase/src/Makefile.kbase
new file mode 100644
index 0000000..769ab4b
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/Makefile.kbase
@@ -0,0 +1,13 @@
+#
+# (C) COPYRIGHT 2010 ARM Limited. All rights reserved.
+#
+# This program is free software and is provided to you under the terms of the GNU General Public License version 2
+# as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+#
+# A copy of the licence is included with the program, and can also be obtained from Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+#
+
+EXTRA_CFLAGS += -I$(ROOT) -I$(KBASE_PATH)/.. -I$(OSK_PATH)/src/linux/include -I$(KBASE_PATH)/platform_$(PLATFORM)
+
diff --git a/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase.h b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase.h
new file mode 100644
index 0000000..1101ca5
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase.h
@@ -0,0 +1,355 @@
+/*
+ *
+ * (C) COPYRIGHT 2010-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+#ifndef _KBASE_H_
+#define _KBASE_H_
+
+#include <malisw/mali_malisw.h>
+#include <osk/mali_osk.h>
+#include <kbase/mali_ukk.h>
+
+#include <kbase/mali_base_kernel.h>
+#include <kbase/src/common/mali_kbase_uku.h>
+#include <kbase/src/linux/mali_kbase_linux.h>
+
+#include "mali_kbase_pm.h"
+#include "mali_kbase_defs.h"
+#include "mali_kbase_js.h"
+#include "mali_kbase_mem.h"
+#include "mali_kbase_security.h"
+
+#include "mali_kbase_cpuprops.h"
+#include "mali_kbase_gpuprops.h"
+
+/**
+ * @page page_base_kernel_main Kernel-side Base (KBase) APIs
+ *
+ * The Kernel-side Base (KBase) APIs are divided up as follows:
+ * - @subpage page_kbase_js_policy
+ */
+
+/**
+ * @defgroup base_kbase_api Kernel-side Base (KBase) APIs
+ */
+
+kbase_device *kbase_device_alloc(void);
+/* note: configuration attributes member of kbdev needs to have been setup before calling kbase_device_init */
+mali_error kbase_device_init(kbase_device *kbdev);
+void kbase_device_term(kbase_device *kbdev);
+void kbase_device_free(kbase_device *kbdev);
+int kbase_device_has_feature(kbase_device *kbdev, u32 feature);
+kbase_midgard_type kbase_device_get_type(kbase_device *kbdev);
+struct kbase_device *kbase_find_device(int minor); /* Only needed for gator integration */
+
+/**
+ * Ensure that all IRQ handlers have completed execution
+ *
+ * @param kbdev The kbase device
+ */
+void kbase_synchronize_irqs(kbase_device *kbdev);
+
+kbase_context *kbase_create_context(kbase_device *kbdev);
+void kbase_destroy_context(kbase_context *kctx);
+mali_error kbase_context_set_create_flags(kbase_context *kctx, u32 flags);
+
+mali_error kbase_instr_hwcnt_setup(kbase_context * kctx, kbase_uk_hwcnt_setup * setup);
+mali_error kbase_instr_hwcnt_enable(kbase_context * kctx, kbase_uk_hwcnt_setup * setup);
+mali_error kbase_instr_hwcnt_disable(kbase_context * kctx);
+mali_error kbase_instr_hwcnt_clear(kbase_context * kctx);
+mali_error kbase_instr_hwcnt_dump(kbase_context * kctx);
+mali_error kbase_instr_hwcnt_dump_irq(kbase_context * kctx);
+mali_bool kbase_instr_hwcnt_dump_complete(kbase_context * kctx, mali_bool *success);
+
+void kbase_clean_caches_done(kbase_device *kbdev);
+
+/**
+ * The GPU has completed performance count sampling successfully.
+ */
+void kbase_instr_hwcnt_sample_done(kbase_device *kbdev);
+
+mali_error kbase_create_os_context(kbase_os_context *osctx);
+void kbase_destroy_os_context(kbase_os_context *osctx);
+
+mali_error kbase_jd_init(kbase_context *kctx);
+void kbase_jd_exit(kbase_context *kctx);
+mali_error kbase_jd_submit(kbase_context *kctx, const kbase_uk_job_submit *user_bag);
+void kbase_jd_done(kbase_jd_atom *katom, int slot_nr, ktime_t *end_timestamp, mali_bool start_new_jobs);
+void kbase_jd_cancel(kbase_jd_atom *katom);
+void kbase_jd_flush_workqueues(kbase_context *kctx);
+void kbase_jd_zap_context(kbase_context *kctx);
+mali_bool jd_done_nolock(kbase_jd_atom *katom);
+void kbase_jd_free_external_resources(kbase_jd_atom *katom);
+
+mali_error kbase_job_slot_init(kbase_device *kbdev);
+void kbase_job_slot_halt(kbase_device *kbdev);
+void kbase_job_slot_term(kbase_device *kbdev);
+void kbase_job_done(kbase_device *kbdev, u32 done);
+void kbase_job_zap_context(kbase_context *kctx);
+
+void kbase_job_slot_softstop(kbase_device *kbdev, int js, kbase_jd_atom *target_katom);
+void kbase_job_slot_hardstop(kbase_context *kctx, int js, kbase_jd_atom *target_katom);
+
+void kbase_event_post(kbase_context *ctx, kbase_jd_atom *event);
+int kbase_event_dequeue(kbase_context *ctx, base_jd_event_v2 *uevent);
+int kbase_event_pending(kbase_context *ctx);
+mali_error kbase_event_init(kbase_context *kctx);
+void kbase_event_close(kbase_context *kctx);
+void kbase_event_cleanup(kbase_context *kctx);
+void kbase_event_wakeup(kbase_context *kctx);
+
+int kbase_process_soft_job(kbase_jd_atom *katom);
+mali_error kbase_prepare_soft_job(kbase_jd_atom *katom);
+void kbase_finish_soft_job(kbase_jd_atom *katom);
+void kbase_cancel_soft_job(kbase_jd_atom *katom);
+
+/* api used internally for register access. Contains validation and tracing */
+void kbase_reg_write(kbase_device *kbdev, u16 offset, u32 value, kbase_context * kctx);
+u32 kbase_reg_read(kbase_device *kbdev, u16 offset, kbase_context * kctx);
+void kbase_device_trace_register_access(kbase_context * kctx, kbase_reg_access_type type, u16 reg_offset, u32 reg_value);
+void kbase_device_trace_buffer_install(kbase_context * kctx, u32 * tb, size_t size);
+void kbase_device_trace_buffer_uninstall(kbase_context * kctx);
+
+/* api to be ported per OS, only need to do the raw register access */
+void kbase_os_reg_write(kbase_device *kbdev, u16 offset, u32 value);
+u32 kbase_os_reg_read(kbase_device *kbdev, u16 offset);
+
+/** Report a GPU fault.
+ *
+ * This function is called from the interrupt handler when a GPU fault occurs.
+ * It reports the details of the fault using OSK_PRINT_WARN.
+ *
+ * @param kbdev The kbase device that the GPU fault occurred from.
+ * @param multiple Zero if only GPU_FAULT was raised, non-zero if MULTIPLE_GPU_FAULTS was also set
+ */
+void kbase_report_gpu_fault(kbase_device *kbdev, int multiple);
+
+/** Kill all jobs that are currently running from a context
+ *
+ * This is used in response to a page fault to remove all jobs from the faulting context from the hardware.
+ *
+ * @param kctx The context to kill jobs from
+ */
+void kbase_job_kill_jobs_from_context(kbase_context *kctx);
+
+/**
+ * GPU interrupt handler
+ *
+ * This function is called from the interrupt handler when a GPU irq is to be handled.
+ *
+ * @param kbdev The kbase device to handle an IRQ for
+ * @param val The value of the GPU IRQ status register which triggered the call
+ */
+void kbase_gpu_interrupt(kbase_device * kbdev, u32 val);
+
+/**
+ * Prepare for resetting the GPU.
+ * This function just soft-stops all the slots to ensure that as many jobs as possible are saved.
+ *
+ * The function returns a boolean which should be interpreted as follows:
+ * - MALI_TRUE - Prepared for reset, kbase_reset_gpu should be called.
+ * - MALI_FALSE - Another thread is performing a reset, kbase_reset_gpu should not be called.
+ *
+ * @return See description
+ */
+mali_bool kbase_prepare_to_reset_gpu(kbase_device *kbdev);
+
+/**
+ * Pre-locked version of @a kbase_prepare_to_reset_gpu.
+ *
+ * Identical to @a kbase_prepare_to_reset_gpu, except that the
+ * kbasep_js_device_data::runpool_irq::lock is externally locked.
+ *
+ * @see kbase_prepare_to_reset_gpu
+ */
+mali_bool kbase_prepare_to_reset_gpu_locked(kbase_device *kbdev);
+
+/** Reset the GPU
+ *
+ * This function should be called after kbase_prepare_to_reset_gpu iff it returns MALI_TRUE.
+ * It should never be called without a corresponding call to kbase_prepare_to_reset_gpu.
+ *
+ * After this function is called (or not called if kbase_prepare_to_reset_gpu returned MALI_FALSE),
+ * the caller should wait for kbdev->reset_waitq to be signalled to know when the reset has completed.
+ */
+void kbase_reset_gpu(kbase_device *kbdev);
+
+/**
+ * Pre-locked version of @a kbase_reset_gpu.
+ *
+ * Identical to @a kbase_reset_gpu, except that the
+ * kbasep_js_device_data::runpool_irq::lock is externally locked.
+ *
+ * @see kbase_reset_gpu
+ */
+void kbase_reset_gpu_locked(kbase_device *kbdev);
+
+
+/** Returns the name associated with a Mali exception code
+ *
+ * @param[in] exception_code exception code
+ * @return name associated with the exception code
+ */
+const char *kbase_exception_name(u32 exception_code);
+
+
+void kbasep_list_trace_add(u8 tracepoint_id, kbase_device *kbdev, kbase_jd_atom *katom,
+ osk_dlist *list_id, mali_bool action, u8 list_type);
+
+void kbasep_list_trace_dump(kbase_device *kbdev);
+
+#if KBASE_TRACE_ENABLE != 0
+/** Add trace values about a job-slot
+ *
+ * @note Any functions called through this macro will still be evaluated in
+ * Release builds (CONFIG_MALI_DEBUG not defined). Therefore, when KBASE_TRACE_ENABLE == 0 any
+ * functions called to get the parameters supplied to this macro must:
+ * - be static or static inline
+ * - must just return 0 and have no other statements present in the body.
+ */
+#define KBASE_TRACE_ADD_SLOT( kbdev, code, ctx, katom, gpu_addr, jobslot ) \
+ kbasep_trace_add( kbdev, KBASE_TRACE_CODE(code), ctx, katom, gpu_addr, \
+ KBASE_TRACE_FLAG_JOBSLOT, 0, jobslot, 0 )
+
+/** Add trace values about a job-slot, with info
+ *
+ * @note Any functions called through this macro will still be evaluated in
+ * Release builds (CONFIG_MALI_DEBUG not defined). Therefore, when KBASE_TRACE_ENABLE == 0 any
+ * functions called to get the parameters supplied to this macro must:
+ * - be static or static inline
+ * - must just return 0 and have no other statements present in the body.
+ */
+#define KBASE_TRACE_ADD_SLOT_INFO( kbdev, code, ctx, katom, gpu_addr, jobslot, info_val ) \
+ kbasep_trace_add( kbdev, KBASE_TRACE_CODE(code), ctx, katom, gpu_addr, \
+ KBASE_TRACE_FLAG_JOBSLOT, 0, jobslot, info_val )
+
+
+/** Add trace values about a ctx refcount
+ *
+ * @note Any functions called through this macro will still be evaluated in
+ * Release builds (CONFIG_MALI_DEBUG not defined). Therefore, when KBASE_TRACE_ENABLE == 0 any
+ * functions called to get the parameters supplied to this macro must:
+ * - be static or static inline
+ * - must just return 0 and have no other statements present in the body.
+ */
+#define KBASE_TRACE_ADD_REFCOUNT( kbdev, code, ctx, katom, gpu_addr, refcount ) \
+ kbasep_trace_add( kbdev, KBASE_TRACE_CODE(code), ctx, katom, gpu_addr, \
+ KBASE_TRACE_FLAG_REFCOUNT, refcount, 0, 0 )
+/** Add trace values about a ctx refcount, and info
+ *
+ * @note Any functions called through this macro will still be evaluated in
+ * Release builds (CONFIG_MALI_DEBUG not defined). Therefore, when KBASE_TRACE_ENABLE == 0 any
+ * functions called to get the parameters supplied to this macro must:
+ * - be static or static inline
+ * - must just return 0 and have no other statements present in the body.
+ */
+#define KBASE_TRACE_ADD_REFCOUNT_INFO( kbdev, code, ctx, katom, gpu_addr, refcount, info_val ) \
+ kbasep_trace_add( kbdev, KBASE_TRACE_CODE(code), ctx, katom, gpu_addr, \
+ KBASE_TRACE_FLAG_REFCOUNT, refcount, 0, info_val )
+
+/** Add trace values (no slot or refcount)
+ *
+ * @note Any functions called through this macro will still be evaluated in
+ * Release builds (CONFIG_MALI_DEBUG not defined). Therefore, when KBASE_TRACE_ENABLE == 0 any
+ * functions called to get the parameters supplied to this macro must:
+ * - be static or static inline
+ * - must just return 0 and have no other statements present in the body.
+ */
+#define KBASE_TRACE_ADD( kbdev, code, ctx, katom, gpu_addr, info_val ) \
+ kbasep_trace_add( kbdev, KBASE_TRACE_CODE(code), ctx, katom, gpu_addr, \
+ 0, 0, 0, info_val )
+
+/** Clear the trace */
+#define KBASE_TRACE_CLEAR( kbdev ) \
+ kbasep_trace_clear( kbdev )
+
+/** Dump the slot trace */
+#define KBASE_TRACE_DUMP( kbdev ) \
+ kbasep_trace_dump( kbdev )
+
+/** PRIVATE - do not use directly. Use KBASE_TRACE_ADD() instead */
+void kbasep_trace_add(kbase_device *kbdev, kbase_trace_code code, void *ctx, kbase_jd_atom *katom, u64 gpu_addr,
+ u8 flags, int refcount, int jobslot, u32 info_val );
+/** PRIVATE - do not use directly. Use KBASE_TRACE_CLEAR() instead */
+void kbasep_trace_clear(kbase_device *kbdev);
+#else /* KBASE_TRACE_ENABLE != 0 */
+#define KBASE_TRACE_ADD_SLOT( kbdev, code, ctx, katom, gpu_addr, jobslot )\
+ do{\
+ CSTD_UNUSED(kbdev);\
+ CSTD_NOP(code);\
+ CSTD_UNUSED(ctx);\
+ CSTD_UNUSED(katom);\
+ CSTD_UNUSED(gpu_addr);\
+ CSTD_UNUSED(jobslot);\
+ }while(0)
+
+#define KBASE_TRACE_ADD_SLOT_INFO( kbdev, code, ctx, katom, gpu_addr, jobslot, info_val )\
+ do{\
+ CSTD_UNUSED(kbdev);\
+ CSTD_NOP(code);\
+ CSTD_UNUSED(ctx);\
+ CSTD_UNUSED(katom);\
+ CSTD_UNUSED(gpu_addr);\
+ CSTD_UNUSED(jobslot);\
+ CSTD_UNUSED(info_val);\
+ CSTD_NOP(0);\
+ }while(0)
+
+#define KBASE_TRACE_ADD_REFCOUNT( kbdev, code, ctx, katom, gpu_addr, refcount )\
+ do{\
+ CSTD_UNUSED(kbdev);\
+ CSTD_NOP(code);\
+ CSTD_UNUSED(ctx);\
+ CSTD_UNUSED(katom);\
+ CSTD_UNUSED(gpu_addr);\
+ CSTD_UNUSED(refcount);\
+ CSTD_NOP(0);\
+ }while(0)
+
+#define KBASE_TRACE_ADD_REFCOUNT_INFO( kbdev, code, ctx, katom, gpu_addr, refcount, info_val )\
+ do{\
+ CSTD_UNUSED(kbdev);\
+ CSTD_NOP(code);\
+ CSTD_UNUSED(ctx);\
+ CSTD_UNUSED(katom);\
+ CSTD_UNUSED(gpu_addr);\
+ CSTD_UNUSED(info_val);\
+ CSTD_NOP(0);\
+ }while(0)
+
+#define KBASE_TRACE_ADD( kbdev, code, subcode, ctx, katom, val )\
+ do{\
+ CSTD_UNUSED(kbdev);\
+ CSTD_NOP(code);\
+ CSTD_UNUSED(subcode);\
+ CSTD_UNUSED(ctx);\
+ CSTD_UNUSED(katom);\
+ CSTD_UNUSED(val);\
+ CSTD_NOP(0);\
+ }while(0)
+
+#define KBASE_TRACE_CLEAR( kbdev )\
+ do{\
+ CSTD_UNUSED(kbdev);\
+ CSTD_NOP(0);\
+ }while(0)
+#define KBASE_TRACE_DUMP( kbdev )\
+ do{\
+ CSTD_UNUSED(kbdev);\
+ CSTD_NOP(0);\
+ }while(0)
+
+#endif /* KBASE_TRACE_ENABLE != 0 */
+/** PRIVATE - do not use directly. Use KBASE_TRACE_DUMP() instead */
+void kbasep_trace_dump(kbase_device *kbdev);
+#endif
diff --git a/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_8401_workaround.c b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_8401_workaround.c
new file mode 100644
index 0000000..c5e1536
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_8401_workaround.c
@@ -0,0 +1,443 @@
+/*
+ *
+ * (C) COPYRIGHT 2011-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_kbase_8401_workaround.c
+ * Functions related to working around BASE_HW_ISSUE_8401
+ */
+
+#include <kbase/src/common/mali_kbase.h>
+#include <kbase/src/common/mali_kbase_defs.h>
+#include <kbase/src/common/mali_kbase_jm.h>
+#include <kbase/src/common/mali_kbase_8401_workaround.h>
+
+#define WORKAROUND_PAGE_OFFSET (2)
+#define URT_POINTER_INDEX (20)
+#define RMU_POINTER_INDEX (23)
+#define RSD_POINTER_INDEX (24)
+#define TSD_POINTER_INDEX (31)
+
+static const u32 compute_job_32bit_header[] =
+{
+ /* Job Descriptor Header */
+
+ /* Job Status */
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ /* Flags and Indices */
+ /* job_type = compute shader job */
+ 0x00000008, 0x00000000,
+ /* Pointer to next job */
+ 0x00000000,
+ /* Reserved */
+ 0x00000000,
+ /* Job Dimension Data */
+ 0x0000000f, 0x21040842,
+ /* Task Split */
+ 0x08000000,
+ /* Reserved */
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+
+ /* Draw Call Descriptor - 32 bit (Must be aligned to a 64-byte boundry) */
+
+ /* Flags */
+ 0x00000004,
+ /* Primary Attribute Offset */
+ 0x00000000,
+ /* Primitive Index Base Value */
+ 0x00000000,
+
+ /* Pointer To Vertex Position Array (64-byte alignment) */
+ 0x00000000,
+ /* Pointer To Uniform Remapping Table (8-byte alignment) */
+ 0,
+ /* Pointer To Image Descriptor Pointer Table */
+ 0x00000000,
+ /* Pointer To Sampler Array */
+ 0x00000000,
+ /* Pointer To Register-Mapped Uniform Data Area (16-byte alignment) */
+ 0,
+ /* Pointer To Renderer State Descriptor (64-byte alignment) */
+ 0,
+ /* Pointer To Primary Attribute Buffer Array */
+ 0x00000000,
+ /* Pointer To Primary Attribute Array */
+ 0x00000000,
+ /* Pointer To Secondary Attribute Buffer Array */
+ 0x00000000,
+ /* Pointer To Secondary Attribute Array */
+ 0x00000000,
+ /* Pointer To Viewport Descriptor */
+ 0x00000000,
+ /* Pointer To Occlusion Query Result */
+ 0x00000000,
+ /* Pointer To Thread Storage (64 byte alignment) */
+ 0,
+};
+
+
+static const u32 compute_job_32bit_urt[] =
+{
+ /* Uniform Remapping Table Entry */
+ 0, 0,
+};
+
+
+static const u32 compute_job_32bit_rmu[] =
+{
+ /* Register Mapped Uniform Data Area (16 byte aligned), an array of 128-bit
+ * register values.
+ *
+ * NOTE: this is also used as the URT pointer, so the first 16-byte entry
+ * must be all zeros.
+ *
+ * For BASE_HW_ISSUE_8987, we place 16 RMUs here, because this should only
+ * be run concurrently with other GLES jobs (i.e. FS jobs from slot 0).
+ */
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000
+};
+
+static const u32 compute_job_32bit_rsd[] =
+{
+ /* Renderer State Descriptor */
+
+ /* Shader program inital PC (low) */
+ 0x00000001,
+ /* Shader program initial PC (high) */
+ 0x00000000,
+ /* Image descriptor array sizes */
+ 0x00000000,
+ /* Attribute array sizes */
+ 0x00000000,
+ /* Uniform array size and Shader Flags */
+ /* Flags set: R, D, SE, Reg Uniforms==16, FPM==OpenCL */
+ 0x42003800,
+ /* Depth bias */
+ 0x00000000,
+ /* Depth slope bias */
+ 0x00000000,
+ /* Depth bias clamp */
+ 0x00000000,
+ /* Multisample Write Mask and Flags */
+ 0x00000000,
+ /* Stencil Write Masks and Alpha parameters */
+ 0x00000000,
+ /* Stencil tests - forward facing */
+ 0x00000000,
+ /* Stencel tests - back facing */
+ 0x00000000,
+ /* Alpha Test Reference Value */
+ 0x00000000,
+ /* Thread Balancing Information */
+ 0x00000000,
+ /* Blend Parameters or Pointer (low) */
+ 0x00000000,
+ /* Blend Parameters or Pointer (high) */
+ 0x00000000,
+};
+
+static const u32 compute_job_32bit_tsd[] =
+{
+ /* Thread Storage Descriptor */
+
+ /* Thread Local Storage Sizes */
+ 0x00000000,
+ /* Workgroup Local Memory Area Flags */
+ 0x0000001f,
+ /* Pointer to Local Storage Area */
+ 0x00021000, 0x00000001,
+ /* Pointer to Workgroup Local Storage Area */
+ 0x00000000, 0x00000000,
+ /* Pointer to Shader Exception Handler */
+ 0x00000000, 0x00000000
+};
+
+static kbase_jd_atom dummy_job_atom[KBASE_8401_WORKAROUND_COMPUTEJOB_COUNT];
+
+/**
+ * Initialize the compute job sturcture.
+ */
+
+static void kbasep_8401_workaround_update_job_pointers(u32 *dummy_compute_job, int page_nr)
+{
+ u32 base_address = (page_nr+WORKAROUND_PAGE_OFFSET)*PAGE_SIZE;
+ u8 *dummy_job = (u8*) dummy_compute_job;
+ u8 *dummy_job_urt;
+ u8 *dummy_job_rmu;
+ u8 *dummy_job_rsd;
+ u8 *dummy_job_tsd;
+
+ OSK_ASSERT(dummy_compute_job);
+
+ /* determin where each job section goes taking alignment restrictions into consideration */
+ dummy_job_urt = (u8*) ((((uintptr_t)dummy_job + sizeof(compute_job_32bit_header))+7) & ~7);
+ dummy_job_rmu = (u8*) ((((uintptr_t)dummy_job_urt + sizeof(compute_job_32bit_urt))+15) & ~15);
+ dummy_job_rsd = (u8*) ((((uintptr_t)dummy_job_rmu + sizeof(compute_job_32bit_rmu))+63) & ~63);
+ dummy_job_tsd = (u8*) ((((uintptr_t)dummy_job_rsd + sizeof(compute_job_32bit_rsd))+63) & ~63);
+
+ /* Make sure the job fits within a single page */
+ OSK_ASSERT(PAGE_SIZE > ((dummy_job_tsd+sizeof(compute_job_32bit_tsd)) - dummy_job));
+
+ /* Copy the job sections to the allocated memory */
+ memcpy(dummy_job, compute_job_32bit_header, sizeof(compute_job_32bit_header));
+ memcpy(dummy_job_urt, compute_job_32bit_urt, sizeof(compute_job_32bit_urt));
+ memcpy(dummy_job_rmu, compute_job_32bit_rmu, sizeof(compute_job_32bit_rmu));
+ memcpy(dummy_job_rsd, compute_job_32bit_rsd, sizeof(compute_job_32bit_rsd));
+ memcpy(dummy_job_tsd, compute_job_32bit_tsd, sizeof(compute_job_32bit_tsd));
+
+ /* Update header pointers */
+ *(dummy_compute_job + URT_POINTER_INDEX) = (dummy_job_urt - dummy_job) + base_address;
+ *(dummy_compute_job + RMU_POINTER_INDEX) = (dummy_job_rmu - dummy_job) + base_address;
+ *(dummy_compute_job + RSD_POINTER_INDEX) = (dummy_job_rsd - dummy_job) + base_address;
+ *(dummy_compute_job + TSD_POINTER_INDEX) = (dummy_job_tsd - dummy_job) + base_address;
+ /* Update URT pointer */
+ *((u32*)dummy_job_urt+0) = (((dummy_job_rmu - dummy_job) + base_address) << 8) & 0xffffff00;
+ *((u32*)dummy_job_urt+1) = (((dummy_job_rmu - dummy_job) + base_address) >> 24) & 0xff;
+}
+
+/**
+ * Initialize the memory for 8401 workaround.
+ */
+
+mali_error kbasep_8401_workaround_init(kbase_device *kbdev)
+{
+ kbasep_js_device_data *js_devdata;
+ kbase_context *workaround_kctx;
+ int i;
+ u16 as_present_mask;
+
+ OSK_ASSERT(kbdev);
+ OSK_ASSERT(kbdev->workaround_kctx == NULL);
+
+ js_devdata = &kbdev->js_data;
+
+ /* For this workaround we reserve one address space to allow us to
+ * submit a special job independent of other contexts */
+ --(kbdev->nr_hw_address_spaces);
+
+ if ( kbdev->nr_user_address_spaces == (kbdev->nr_hw_address_spaces + 1) )
+ {
+ /* Only update nr_user_address_spaces if it was unchanged - to ensure
+ * HW workarounds that have modified this will still work */
+ --(kbdev->nr_user_address_spaces);
+ }
+ OSK_ASSERT( kbdev->nr_user_address_spaces <= kbdev->nr_hw_address_spaces );
+
+ /* Recalculate the free address spaces bit-pattern */
+ as_present_mask = (1U << kbdev->nr_hw_address_spaces) - 1;
+ js_devdata->as_free &= as_present_mask;
+
+ workaround_kctx = kbase_create_context(kbdev);
+ if(!workaround_kctx)
+ {
+ return MALI_ERROR_FUNCTION_FAILED;
+ }
+
+ /* Allocate the pages required to contain the job */
+ if (MALI_ERROR_NONE != kbase_mem_allocator_alloc(&workaround_kctx->osalloc, KBASE_8401_WORKAROUND_COMPUTEJOB_COUNT, kbdev->workaround_compute_job_pa, KBASE_REG_MUST_ZERO))
+ {
+ goto no_pages;
+ }
+
+ /* Get virtual address of mapped memory and write a compute job for each page */
+ for(i = 0; i < KBASE_8401_WORKAROUND_COMPUTEJOB_COUNT; i++)
+ {
+ kbdev->workaround_compute_job_va[i] = osk_kmap(kbdev->workaround_compute_job_pa[i]);
+ if(NULL == kbdev->workaround_compute_job_va[i])
+ {
+ goto page_free;
+ }
+
+ /* Generate the compute job data */
+ kbasep_8401_workaround_update_job_pointers((u32*)kbdev->workaround_compute_job_va[i], i);
+ }
+
+ /* Insert pages to the gpu mmu. */
+ kbase_mmu_insert_pages(workaround_kctx,
+ /* vpfn = page number */
+ (u64)WORKAROUND_PAGE_OFFSET,
+ /* physical address */
+ kbdev->workaround_compute_job_pa,
+ /* number of pages */
+ KBASE_8401_WORKAROUND_COMPUTEJOB_COUNT,
+ /* flags */
+ KBASE_REG_GPU_RD|KBASE_REG_CPU_RD|KBASE_REG_CPU_WR|KBASE_REG_GPU_WR);
+
+ kbdev->workaround_kctx = workaround_kctx;
+ return MALI_ERROR_NONE;
+page_free:
+ while(i--)
+ {
+ osk_kunmap(kbdev->workaround_compute_job_pa[i], kbdev->workaround_compute_job_va[i]);
+ }
+ kbase_mem_allocator_free(&workaround_kctx->osalloc, KBASE_8401_WORKAROUND_COMPUTEJOB_COUNT, kbdev->workaround_compute_job_pa);
+no_pages:
+ kbase_destroy_context(workaround_kctx);
+
+ return MALI_ERROR_FUNCTION_FAILED;
+}
+
+/**
+ * Free up the memory used by 8401 workaround.
+ **/
+
+void kbasep_8401_workaround_term(kbase_device *kbdev)
+{
+ kbasep_js_device_data *js_devdata;
+ int i;
+ u16 restored_as;
+
+ OSK_ASSERT(kbdev);
+ OSK_ASSERT(kbdev->workaround_kctx);
+
+ js_devdata = &kbdev->js_data;
+
+ for(i = 0; i < KBASE_8401_WORKAROUND_COMPUTEJOB_COUNT; i++)
+ {
+ osk_kunmap(kbdev->workaround_compute_job_pa[i], kbdev->workaround_compute_job_va[i]);
+ }
+
+ kbase_mem_allocator_free(&kbdev->workaround_kctx->osalloc, KBASE_8401_WORKAROUND_COMPUTEJOB_COUNT, kbdev->workaround_compute_job_pa);
+
+ kbase_destroy_context(kbdev->workaround_kctx);
+ kbdev->workaround_kctx = NULL;
+
+ /* Free up the workaround address space */
+ kbdev->nr_hw_address_spaces++;
+
+ if ( kbdev->nr_user_address_spaces == (kbdev->nr_hw_address_spaces - 1) )
+ {
+ /* Only update nr_user_address_spaces if it was unchanged - to ensure
+ * HW workarounds that have modified this will still work */
+ ++(kbdev->nr_user_address_spaces);
+ }
+ OSK_ASSERT( kbdev->nr_user_address_spaces <= kbdev->nr_hw_address_spaces );
+
+ /* Recalculate the free address spaces bit-pattern */
+ restored_as = (1U << kbdev->nr_hw_address_spaces);
+ js_devdata->as_free |= restored_as;
+}
+
+/**
+ * Submit the 8401 workaround job.
+ *
+ * Important for BASE_HW_ISSUE_8987: This job always uses 16 RMUs
+ * - Therefore, on slot[1] it will always use the same number of RMUs as another
+ * GLES job.
+ * - On slot[2], no other job (GLES or otherwise) will be running on the
+ * cores, by virtue of it being slot[2]. Therefore, any value of RMUs is
+ * acceptable.
+ */
+void kbasep_8401_submit_dummy_job(kbase_device *kbdev, int js)
+{
+ u32 cfg;
+ mali_addr64 jc;
+ u32 pgd_high;
+
+ /* While this workaround is active we reserve the last address space just for submitting the dummy jobs */
+ int as = kbdev->nr_hw_address_spaces;
+
+ /* Don't issue compute jobs on job slot 0 */
+ OSK_ASSERT(js != 0);
+ OSK_ASSERT(js < KBASE_8401_WORKAROUND_COMPUTEJOB_COUNT);
+
+ /* Job chain GPU address */
+ jc = (js+WORKAROUND_PAGE_OFFSET)*PAGE_SIZE; /* GPU phys address (see kbase_mmu_insert_pages call in kbasep_8401_workaround_init*/
+
+ /* Clear the job status words which may contain values from a previous job completion */
+ memset(kbdev->workaround_compute_job_va[js], 0, 4*sizeof(u32));
+
+ /* Get the affinity of the previous job */
+ dummy_job_atom[js].affinity = ((u64)kbase_reg_read(kbdev, JOB_SLOT_REG(js, JSn_AFFINITY_LO), NULL)) |
+ (((u64)kbase_reg_read(kbdev, JOB_SLOT_REG(js, JSn_AFFINITY_HI), NULL)) << 32);
+
+ /* Don't submit a compute job if the affinity was previously zero (i.e. no jobs have run yet on this slot) */
+ if(!dummy_job_atom[js].affinity)
+ {
+ return;
+ }
+
+ /* Ensure that our page tables are programmed into the MMU */
+ kbase_reg_write(kbdev, MMU_AS_REG(as, ASn_TRANSTAB_LO),
+ (kbdev->workaround_kctx->pgd & ASn_TRANSTAB_ADDR_SPACE_MASK) | ASn_TRANSTAB_READ_INNER
+ | ASn_TRANSTAB_ADRMODE_TABLE, NULL);
+
+ /* Need to use a conditional expression to avoid "right shift count >= width of type"
+ * error when using an if statement - although the size_of condition is evaluated at compile
+ * time the unused branch is not removed until after it is type-checked and the error
+ * produced.
+ */
+ pgd_high = sizeof(kbdev->workaround_kctx->pgd) > 4 ? (kbdev->workaround_kctx->pgd >> 32) : 0;
+ kbase_reg_write(kbdev, MMU_AS_REG(as, ASn_TRANSTAB_HI), pgd_high, NULL);
+
+ kbase_reg_write(kbdev, MMU_AS_REG(as, ASn_MEMATTR_LO), ASn_MEMATTR_IMPL_DEF_CACHE_POLICY, NULL);
+ kbase_reg_write(kbdev, MMU_AS_REG(as, ASn_MEMATTR_HI), ASn_MEMATTR_IMPL_DEF_CACHE_POLICY, NULL);
+ kbase_reg_write(kbdev, MMU_AS_REG(as, ASn_COMMAND), ASn_COMMAND_UPDATE, NULL);
+
+ kbase_reg_write(kbdev, JOB_SLOT_REG(js, JSn_HEAD_NEXT_LO), jc & 0xFFFFFFFF, NULL);
+ kbase_reg_write(kbdev, JOB_SLOT_REG(js, JSn_HEAD_NEXT_HI), jc >> 32, NULL);
+
+ kbase_reg_write(kbdev, JOB_SLOT_REG(js, JSn_AFFINITY_NEXT_LO), dummy_job_atom[js].affinity & 0xFFFFFFFF, NULL);
+ kbase_reg_write(kbdev, JOB_SLOT_REG(js, JSn_AFFINITY_NEXT_HI), dummy_job_atom[js].affinity >> 32, NULL);
+
+ /* start MMU, medium priority, cache clean/flush on end, clean/flush on start */
+ cfg = as | JSn_CONFIG_END_FLUSH_CLEAN_INVALIDATE | JSn_CONFIG_START_MMU
+ | JSn_CONFIG_START_FLUSH_CLEAN_INVALIDATE | JSn_CONFIG_THREAD_PRI(8);
+ kbase_reg_write(kbdev, JOB_SLOT_REG(js, JSn_CONFIG_NEXT), cfg, NULL);
+
+ KBASE_TRACE_ADD_SLOT( kbdev, JM_SUBMIT, NULL, 0, jc, js );
+
+ kbase_reg_write(kbdev, JOB_SLOT_REG(js, JSn_COMMAND_NEXT), JSn_COMMAND_START, NULL);
+ /* Report that the job has been submitted */
+ kbasep_jm_enqueue_submit_slot(&kbdev->jm_slots[js], &dummy_job_atom[js]);
+}
+
+/**
+ * Check if the katom given is a dummy compute job.
+ */
+mali_bool kbasep_8401_is_workaround_job(kbase_jd_atom *katom)
+{
+ int i;
+
+ /* Note: we don't check the first dummy_job_atom as slot 0 is never used for the workaround */
+ for(i = 1; i < KBASE_8401_WORKAROUND_COMPUTEJOB_COUNT; i++)
+ {
+ if(katom == &dummy_job_atom[i])
+ {
+ /* This is a dummy job */
+ return MALI_TRUE;
+ }
+ }
+
+ /* This is a real job */
+ return MALI_FALSE;
+}
+
diff --git a/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_8401_workaround.h b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_8401_workaround.h
new file mode 100644
index 0000000..1831299
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_8401_workaround.h
@@ -0,0 +1,29 @@
+/*
+ *
+ * (C) COPYRIGHT 2011-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_kbase_8401_workaround.h
+ * Functions related to working around BASE_HW_ISSUE_8401
+ */
+
+#ifndef _KBASE_8401_WORKAROUND_H_
+#define _KBASE_8401_WORKAROUND_H_
+
+mali_error kbasep_8401_workaround_init(kbase_device *kbdev);
+void kbasep_8401_workaround_term(kbase_device *kbdev);
+void kbasep_8401_submit_dummy_job(kbase_device *kbdev, int js);
+mali_bool kbasep_8401_is_workaround_job(kbase_jd_atom *katom);
+
+#endif /* _KBASE_8401_WORKAROUND_H_ */
+
diff --git a/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_cache_policy.c b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_cache_policy.c
new file mode 100644
index 0000000..1f274a6
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_cache_policy.c
@@ -0,0 +1,44 @@
+/*
+ *
+ * (C) COPYRIGHT 2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_kbase_cache_policy.h
+ * Cache Policy API.
+ */
+
+#include "mali_kbase_cache_policy.h"
+
+/*
+ * The output flags should be a combination of the following values:
+ * KBASE_REG_CPU_CACHED: CPU cache should be enabled
+ * KBASE_REG_GPU_CACHED: GPU cache should be enabled
+ */
+u32 kbase_cache_enabled(u32 flags, u32 nr_pages)
+{
+ u32 cache_flags = 0;
+
+ CSTD_UNUSED(nr_pages);
+
+ if (flags & BASE_MEM_CACHED_CPU)
+ {
+ cache_flags |= KBASE_REG_CPU_CACHED;
+ }
+
+ if (flags & BASE_MEM_CACHED_GPU)
+ {
+ cache_flags |= KBASE_REG_GPU_CACHED;
+ }
+
+ return cache_flags;
+}
diff --git a/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_cache_policy.h b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_cache_policy.h
new file mode 100644
index 0000000..cf2eb5f
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_cache_policy.h
@@ -0,0 +1,43 @@
+/*
+ *
+ * (C) COPYRIGHT 2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_kbase_cache_policy.h
+ * Cache Policy API.
+ */
+
+#ifndef _KBASE_CACHE_POLICY_H_
+#define _KBASE_CACHE_POLICY_H_
+
+#include <malisw/mali_malisw.h>
+#include "mali_kbase.h"
+#include <kbase/mali_base_kernel.h>
+
+/**
+ * @brief Choose the cache policy for a specific region
+ *
+ * Tells whether the CPU and GPU caches should be enabled or not for a specific region.
+ * This function can be modified to customize the cache policy depending on the flags
+ * and size of the region.
+ *
+ * @param[in] flags flags describing attributes of the region
+ * @param[in] nr_pages total number of pages (backed or not) for the region
+ *
+ * @return a combination of KBASE_REG_CPU_CACHED and KBASE_REG_GPU_CACHED depending
+ * on the cache policy
+ */
+u32 kbase_cache_enabled(u32 flags, u32 nr_pages);
+
+#endif /* _KBASE_CACHE_POLICY_H_ */
+
diff --git a/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_config.c b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_config.c
new file mode 100644
index 0000000..f6c2557
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_config.c
@@ -0,0 +1,680 @@
+/*
+ *
+ * (C) COPYRIGHT 2011-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+#include <kbase/src/common/mali_kbase.h>
+#include <kbase/src/common/mali_kbase_defs.h>
+#include <kbase/src/common/mali_kbase_cpuprops.h>
+#include <osk/mali_osk.h>
+#ifdef CONFIG_UMP
+#include <linux/ump-common.h>
+#endif /* CONFIG_UMP */
+
+/* Specifies how many attributes are permitted in the config (excluding terminating attribute).
+ * This is used in validation function so we can detect if configuration is properly terminated. This value can be
+ * changed if we need to introduce more attributes or many memory regions need to be defined */
+#define ATTRIBUTE_COUNT_MAX 32
+
+/* right now we allow only 2 memory attributes (excluding termination attribute) */
+#define MEMORY_ATTRIBUTE_COUNT_MAX 2
+
+/* Limits for gpu frequency configuration parameters. These will use for config validation. */
+#define MAX_GPU_ALLOWED_FREQ_KHZ 1000000
+#define MIN_GPU_ALLOWED_FREQ_KHZ 1
+
+/* Default irq throttle time. This is the default desired minimum time in between two consecutive
+ * interrupts from the gpu. The irq throttle gpu register is set after this value. */
+#define DEFAULT_IRQ_THROTTLE_TIME_US 20
+
+/*** Begin Scheduling defaults ***/
+
+/**
+ * Default scheduling tick granuality, in nanoseconds
+ */
+#define DEFAULT_JS_SCHEDULING_TICK_NS 100000000u /* 100ms */
+
+/**
+ * Default minimum number of scheduling ticks before jobs are soft-stopped.
+ *
+ * This defines the time-slice for a job (which may be different from that of a context)
+ */
+#define DEFAULT_JS_SOFT_STOP_TICKS 1 /* Between 0.1 and 0.2s before soft-stop */
+
+/**
+ * Default minimum number of scheduling ticks before Soft-Stoppable
+ * (BASE_JD_REQ_NSS bit clear) jobs are hard-stopped
+ */
+#define DEFAULT_JS_HARD_STOP_TICKS_SS_HW_ISSUE_8408 12 /* 1.2s before hard-stop, for a certain GLES2 test at 128x128 (bound by combined vertex+tiler job) */
+#define DEFAULT_JS_HARD_STOP_TICKS_SS 2 /* Between 0.2 and 0.3s before hard-stop */
+
+/**
+ * Default minimum number of scheduling ticks before Non-Soft-Stoppable
+ * (BASE_JD_REQ_NSS bit set) jobs are hard-stopped
+ */
+#define DEFAULT_JS_HARD_STOP_TICKS_NSS 600 /* 60s @ 100ms tick */
+
+/**
+ * Default minimum number of scheduling ticks before the GPU is reset
+ * to clear a "stuck" Soft-Stoppable job
+ */
+#define DEFAULT_JS_RESET_TICKS_SS_HW_ISSUE_8408 18 /* 1.8s before resetting GPU, for a certain GLES2 test at 128x128 (bound by combined vertex+tiler job) */
+#define DEFAULT_JS_RESET_TICKS_SS 3 /* 0.3-0.4s before GPU is reset */
+
+/**
+ * Default minimum number of scheduling ticks before the GPU is reset
+ * to clear a "stuck" Non-Soft-Stoppable job
+ */
+#define DEFAULT_JS_RESET_TICKS_NSS 601 /* 60.1s @ 100ms tick */
+
+/**
+ * Number of milliseconds given for other jobs on the GPU to be
+ * soft-stopped when the GPU needs to be reset.
+ */
+#define DEFAULT_JS_RESET_TIMEOUT_MS 3000
+
+/**
+ * Default timeslice that a context is scheduled in for, in nanoseconds.
+ *
+ * When a context has used up this amount of time across its jobs, it is
+ * scheduled out to let another run.
+ *
+ * @note the resolution is nanoseconds (ns) here, because that's the format
+ * often used by the OS.
+ */
+#define DEFAULT_JS_CTX_TIMESLICE_NS 50000000 /* 0.05s - at 20fps a ctx does at least 1 frame before being scheduled out. At 40fps, 2 frames, etc */
+
+/**
+ * Default initial runtime of a context for CFS, in ticks.
+ *
+ * This value is relative to that of the least-run context, and defines where
+ * in the CFS queue a new context is added.
+ */
+#define DEFAULT_JS_CFS_CTX_RUNTIME_INIT_SLICES 1
+
+/**
+ * Default minimum runtime value of a context for CFS, in ticks.
+ *
+ * This value is relative to that of the least-run context. This prevents
+ * "stored-up timeslices" DoS attacks.
+ */
+#define DEFAULT_JS_CFS_CTX_RUNTIME_MIN_SLICES 2
+
+/**
+ * Default setting for whether to prefer security or performance.
+ *
+ * Currently affects only r0p0-15dev0 HW and earlier.
+ */
+#define DEFAULT_SECURE_BUT_LOSS_OF_PERFORMANCE MALI_FALSE
+
+/*** End Scheduling defaults ***/
+
+/**
+ * Default value for KBASE_CONFIG_ATTR_CPU_SPEED_FUNC.
+ * Points to @ref kbase_cpuprops_get_default_clock_speed.
+ */
+#define DEFAULT_CPU_SPEED_FUNC ((uintptr_t)kbase_cpuprops_get_default_clock_speed)
+
+#ifdef CONFIG_MALI_PLATFORM_FAKE
+
+extern kbase_platform_config platform_config;
+kbase_platform_config *kbasep_get_platform_config(void)
+{
+ return &platform_config;
+}
+#endif /* CONFIG_MALI_PLATFORM_FAKE */
+
+int kbasep_get_config_attribute_count(const kbase_attribute *attributes)
+{
+ int count = 1;
+
+ OSK_ASSERT(attributes != NULL);
+
+ while (attributes->id != KBASE_CONFIG_ATTR_END)
+ {
+ attributes++;
+ count++;
+ }
+
+ return count;
+}
+
+int kbasep_get_config_attribute_count_by_id(const kbase_attribute *attributes, int attribute_id)
+{
+ int count = 0;
+ OSK_ASSERT(attributes != NULL);
+
+ while (attributes->id != KBASE_CONFIG_ATTR_END)
+ {
+ if (attributes->id == attribute_id)
+ {
+ count++;
+ }
+ attributes++;
+ }
+
+ return count;
+}
+
+const kbase_attribute *kbasep_get_next_attribute(const kbase_attribute *attributes, int attribute_id)
+{
+ OSK_ASSERT(attributes != NULL);
+
+ while (attributes->id != KBASE_CONFIG_ATTR_END)
+ {
+ if (attributes->id == attribute_id)
+ {
+ return attributes;
+ }
+ attributes++;
+ }
+ return NULL;
+}
+KBASE_EXPORT_TEST_API(kbasep_get_next_attribute)
+
+uintptr_t kbasep_get_config_value(struct kbase_device *kbdev, const kbase_attribute *attributes, int attribute_id)
+{
+ const kbase_attribute *attr;
+
+ OSK_ASSERT(attributes != NULL);
+
+ attr = kbasep_get_next_attribute(attributes, attribute_id);
+ if (attr != NULL)
+ {
+ return attr->data;
+ }
+
+ /* default values */
+ switch (attribute_id)
+ {
+ case KBASE_CONFIG_ATTR_MEMORY_PER_PROCESS_LIMIT:
+ return (uintptr_t)-1;
+#ifdef CONFIG_UMP
+ case KBASE_CONFIG_ATTR_UMP_DEVICE:
+ return UMP_DEVICE_W_SHIFT;
+#endif /* CONFIG_UMP */
+ case KBASE_CONFIG_ATTR_MEMORY_OS_SHARED_MAX:
+ return (uintptr_t)-1;
+ case KBASE_CONFIG_ATTR_MEMORY_OS_SHARED_PERF_GPU:
+ return KBASE_MEM_PERF_NORMAL;
+ case KBASE_CONFIG_ATTR_GPU_IRQ_THROTTLE_TIME_US:
+ return DEFAULT_IRQ_THROTTLE_TIME_US;
+ /* Begin scheduling defaults */
+ case KBASE_CONFIG_ATTR_JS_SCHEDULING_TICK_NS:
+ return DEFAULT_JS_SCHEDULING_TICK_NS;
+ case KBASE_CONFIG_ATTR_JS_SOFT_STOP_TICKS:
+ return DEFAULT_JS_SOFT_STOP_TICKS;
+ case KBASE_CONFIG_ATTR_JS_HARD_STOP_TICKS_SS:
+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8408))
+ {
+ return DEFAULT_JS_HARD_STOP_TICKS_SS_HW_ISSUE_8408;
+ }
+ else
+ {
+ return DEFAULT_JS_HARD_STOP_TICKS_SS;
+ }
+ case KBASE_CONFIG_ATTR_JS_HARD_STOP_TICKS_NSS:
+ return DEFAULT_JS_HARD_STOP_TICKS_NSS;
+ case KBASE_CONFIG_ATTR_JS_CTX_TIMESLICE_NS:
+ return DEFAULT_JS_CTX_TIMESLICE_NS;
+ case KBASE_CONFIG_ATTR_JS_CFS_CTX_RUNTIME_INIT_SLICES:
+ return DEFAULT_JS_CFS_CTX_RUNTIME_INIT_SLICES;
+ case KBASE_CONFIG_ATTR_JS_CFS_CTX_RUNTIME_MIN_SLICES:
+ return DEFAULT_JS_CFS_CTX_RUNTIME_MIN_SLICES;
+ case KBASE_CONFIG_ATTR_JS_RESET_TICKS_SS:
+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8408))
+ {
+ return DEFAULT_JS_RESET_TICKS_SS_HW_ISSUE_8408;
+ }
+ else
+ {
+ return DEFAULT_JS_RESET_TICKS_SS;
+ }
+ case KBASE_CONFIG_ATTR_JS_RESET_TICKS_NSS:
+ return DEFAULT_JS_RESET_TICKS_NSS;
+ case KBASE_CONFIG_ATTR_JS_RESET_TIMEOUT_MS:
+ return DEFAULT_JS_RESET_TIMEOUT_MS;
+ /* End scheduling defaults */
+ case KBASE_CONFIG_ATTR_POWER_MANAGEMENT_CALLBACKS:
+ return 0;
+ case KBASE_CONFIG_ATTR_PLATFORM_FUNCS:
+ return 0;
+ case KBASE_CONFIG_ATTR_SECURE_BUT_LOSS_OF_PERFORMANCE:
+ return DEFAULT_SECURE_BUT_LOSS_OF_PERFORMANCE;
+ case KBASE_CONFIG_ATTR_CPU_SPEED_FUNC:
+ return DEFAULT_CPU_SPEED_FUNC;
+ case KBASE_CONFIG_ATTR_GPU_SPEED_FUNC:
+ return 0;
+ default:
+ OSK_PRINT_ERROR(OSK_BASE_CORE,
+ "kbasep_get_config_value. Cannot get value of attribute with id=%d and no default value defined",
+ attribute_id);
+ return 0;
+ }
+}
+KBASE_EXPORT_TEST_API(kbasep_get_config_value)
+
+mali_bool kbasep_platform_device_init(kbase_device *kbdev)
+{
+ kbase_platform_funcs_conf *platform_funcs;
+
+ if (OSK_SIMULATE_FAILURE(OSK_BASE_CORE))
+ {
+ return MALI_FALSE;
+ }
+
+ platform_funcs = (kbase_platform_funcs_conf *) kbasep_get_config_value(kbdev, kbdev->config_attributes, KBASE_CONFIG_ATTR_PLATFORM_FUNCS);
+ if(platform_funcs)
+ {
+ if(platform_funcs->platform_init_func)
+ {
+ return platform_funcs->platform_init_func(kbdev);
+ }
+ }
+ return MALI_TRUE;
+}
+
+void kbasep_platform_device_term(kbase_device *kbdev)
+{
+ kbase_platform_funcs_conf *platform_funcs;
+
+ platform_funcs = (kbase_platform_funcs_conf *) kbasep_get_config_value(kbdev, kbdev->config_attributes, KBASE_CONFIG_ATTR_PLATFORM_FUNCS);
+ if(platform_funcs)
+ {
+ if(platform_funcs->platform_term_func)
+ {
+ platform_funcs->platform_term_func(kbdev);
+ }
+ }
+}
+
+void kbasep_get_memory_performance(const kbase_memory_resource *resource, kbase_memory_performance *cpu_performance,
+ kbase_memory_performance *gpu_performance)
+{
+ kbase_attribute *attributes;
+
+ OSK_ASSERT(resource != NULL);
+ OSK_ASSERT(cpu_performance != NULL );
+ OSK_ASSERT(gpu_performance != NULL);
+
+ attributes = resource->attributes;
+ *cpu_performance = *gpu_performance = KBASE_MEM_PERF_NORMAL; /* default performance */
+
+ if (attributes == NULL)
+ {
+ return;
+ }
+
+ while (attributes->id != KBASE_CONFIG_ATTR_END)
+ {
+ if (attributes->id == KBASE_MEM_ATTR_PERF_GPU)
+ {
+ *gpu_performance = (kbase_memory_performance) attributes->data;
+ }
+ else if (attributes->id == KBASE_MEM_ATTR_PERF_CPU)
+ {
+ *cpu_performance = (kbase_memory_performance) attributes->data;
+ }
+ attributes++;
+ }
+}
+
+#ifdef CONFIG_UMP
+static mali_bool kbasep_validate_ump_device(int ump_device)
+{
+ mali_bool valid;
+
+ if (OSK_SIMULATE_FAILURE(OSK_BASE_CORE))
+ {
+ return MALI_FALSE;
+ }
+
+ switch (ump_device)
+ {
+ case UMP_DEVICE_W_SHIFT:
+ case UMP_DEVICE_X_SHIFT:
+ case UMP_DEVICE_Y_SHIFT:
+ case UMP_DEVICE_Z_SHIFT:
+ valid = MALI_TRUE;
+ break;
+ default:
+ valid = MALI_FALSE;
+ break;
+ }
+ return valid;
+}
+#endif /* CONFIG_UMP */
+
+static mali_bool kbasep_validate_memory_performance(kbase_memory_performance performance)
+{
+ if (OSK_SIMULATE_FAILURE(OSK_BASE_CORE))
+ {
+ return MALI_FALSE;
+ }
+ return performance <= KBASE_MEM_PERF_MAX_VALUE;
+}
+
+static mali_bool kbasep_validate_memory_resource(const kbase_memory_resource *memory_resource)
+{
+ OSK_ASSERT(memory_resource != NULL);
+
+ if (OSK_SIMULATE_FAILURE(OSK_BASE_CORE))
+ {
+ return MALI_FALSE;
+ }
+
+ if (memory_resource->name == NULL)
+ {
+ OSK_PRINT_WARN(OSK_BASE_CORE, "Unnamed memory region found");
+ return MALI_FALSE;
+ }
+
+ if (memory_resource->base & ((1 << PAGE_SHIFT) - 1))
+ {
+ OSK_PRINT_WARN(OSK_BASE_CORE, "Base address of \"%s\" memory region is not page aligned", memory_resource->name);
+ return MALI_FALSE;
+ }
+
+ if (memory_resource->size & ((1 << PAGE_SHIFT) - 1))
+ {
+ OSK_PRINT_WARN(OSK_BASE_CORE, "Size of \"%s\" memory region is not a multiple of page size", memory_resource->name);
+ return MALI_FALSE;
+ }
+
+ if (memory_resource->attributes != NULL) /* we allow NULL attribute list */
+ {
+ int i;
+
+ for (i = 0; memory_resource->attributes[i].id != KBASE_MEM_ATTR_END; i++)
+ {
+ if (i >= MEMORY_ATTRIBUTE_COUNT_MAX)
+ {
+ OSK_PRINT_WARN(OSK_BASE_CORE, "More than MEMORY_ATTRIBUTE_COUNT_MAX=%d configuration attributes defined. Is memory attribute list properly terminated?",
+ MEMORY_ATTRIBUTE_COUNT_MAX);
+ return MALI_FALSE;
+ }
+ switch(memory_resource->attributes[i].id)
+ {
+ case KBASE_MEM_ATTR_PERF_CPU:
+ if (MALI_TRUE != kbasep_validate_memory_performance(
+ (kbase_memory_performance)memory_resource->attributes[i].data))
+ {
+ OSK_PRINT_WARN(OSK_BASE_CORE, "CPU performance of \"%s\" region is invalid: %d",
+ memory_resource->name, (kbase_memory_performance)memory_resource->attributes[i].data);
+ return MALI_FALSE;
+ }
+ break;
+
+ case KBASE_MEM_ATTR_PERF_GPU:
+ if (MALI_TRUE != kbasep_validate_memory_performance(
+ (kbase_memory_performance)memory_resource->attributes[i].data))
+ {
+ OSK_PRINT_WARN(OSK_BASE_CORE, "GPU performance of \"%s\" region is invalid: %d",
+ memory_resource->name, (kbase_memory_performance)memory_resource->attributes[i].data);
+ return MALI_FALSE;
+ }
+ break;
+ default:
+ OSK_PRINT_WARN(OSK_BASE_CORE, "Invalid memory attribute found in \"%s\" memory region: %d",
+ memory_resource->name, memory_resource->attributes[i].id);
+ return MALI_FALSE;
+ }
+ }
+ }
+
+ return MALI_TRUE;
+}
+
+
+static mali_bool kbasep_validate_gpu_clock_freq(kbase_device *kbdev, const kbase_attribute *attributes)
+{
+ uintptr_t freq_min = kbasep_get_config_value(kbdev, attributes, KBASE_CONFIG_ATTR_GPU_FREQ_KHZ_MIN);
+ uintptr_t freq_max = kbasep_get_config_value(kbdev, attributes, KBASE_CONFIG_ATTR_GPU_FREQ_KHZ_MAX);
+
+ if (OSK_SIMULATE_FAILURE(OSK_BASE_CORE))
+ {
+ return MALI_FALSE;
+ }
+
+ if ((freq_min > MAX_GPU_ALLOWED_FREQ_KHZ) ||
+ (freq_min < MIN_GPU_ALLOWED_FREQ_KHZ) ||
+ (freq_max > MAX_GPU_ALLOWED_FREQ_KHZ) ||
+ (freq_max < MIN_GPU_ALLOWED_FREQ_KHZ) ||
+ (freq_min > freq_max))
+ {
+ OSK_PRINT_WARN(OSK_BASE_CORE, "Invalid GPU frequencies found in configuration: min=%ldkHz, max=%ldkHz.", freq_min, freq_max);
+ return MALI_FALSE;
+ }
+
+ return MALI_TRUE;
+}
+
+static mali_bool kbasep_validate_pm_callback(const kbase_pm_callback_conf *callbacks)
+{
+ if (OSK_SIMULATE_FAILURE(OSK_BASE_PM))
+ {
+ return MALI_FALSE;
+ }
+
+ if (callbacks == NULL)
+ {
+ /* Having no callbacks is valid */
+ return MALI_TRUE;
+ }
+
+ if ((callbacks->power_off_callback != NULL && callbacks->power_on_callback == NULL) ||
+ (callbacks->power_off_callback == NULL && callbacks->power_on_callback != NULL))
+ {
+ OSK_PRINT_WARN(OSK_BASE_CORE, "Invalid power management callbacks: Only one of power_off_callback and power_on_callback was specified");
+ return MALI_FALSE;
+ }
+ return MALI_TRUE;
+}
+
+static mali_bool kbasep_validate_cpu_speed_func(kbase_cpuprops_clock_speed_function fcn)
+{
+ if (OSK_SIMULATE_FAILURE(OSK_BASE_CORE))
+ {
+ return MALI_FALSE;
+ }
+ return fcn != NULL;
+}
+
+mali_bool kbasep_validate_configuration_attributes(kbase_device *kbdev, const kbase_attribute *attributes)
+{
+ int i;
+ mali_bool had_gpu_freq_min = MALI_FALSE, had_gpu_freq_max = MALI_FALSE;
+
+ OSK_ASSERT(attributes);
+
+ if (OSK_SIMULATE_FAILURE(OSK_BASE_CORE))
+ {
+ return MALI_FALSE;
+ }
+
+ for (i = 0; attributes[i].id != KBASE_CONFIG_ATTR_END; i++)
+ {
+ if (i >= ATTRIBUTE_COUNT_MAX)
+ {
+ OSK_PRINT_WARN(OSK_BASE_CORE, "More than ATTRIBUTE_COUNT_MAX=%d configuration attributes defined. Is attribute list properly terminated?",
+ ATTRIBUTE_COUNT_MAX);
+ return MALI_FALSE;
+ }
+
+ switch (attributes[i].id)
+ {
+ case KBASE_CONFIG_ATTR_MEMORY_RESOURCE:
+ if (MALI_FALSE == kbasep_validate_memory_resource((kbase_memory_resource *)attributes[i].data))
+ {
+ OSK_PRINT_WARN(OSK_BASE_CORE, "Invalid memory region found in configuration");
+ return MALI_FALSE;
+ }
+ break;
+
+ case KBASE_CONFIG_ATTR_MEMORY_OS_SHARED_MAX:
+ /* Some shared memory is required for GPU page tables, see MIDBASE-1534 */
+ if ( 0 == attributes[i].data )
+ {
+ OSK_PRINT_WARN(OSK_BASE_CORE, "Maximum OS Shared Memory Maximum is set to 0 which is not supported");
+ return MALI_FALSE;
+ }
+ break;
+
+ case KBASE_CONFIG_ATTR_MEMORY_OS_SHARED_PERF_GPU:
+ if (MALI_FALSE == kbasep_validate_memory_performance((kbase_memory_performance)attributes[i].data))
+ {
+ OSK_PRINT_WARN(OSK_BASE_CORE, "Shared OS memory GPU performance attribute has invalid value: %d",
+ (kbase_memory_performance)attributes[i].data);
+ return MALI_FALSE;
+ }
+ break;
+
+ case KBASE_CONFIG_ATTR_MEMORY_PER_PROCESS_LIMIT:
+ /* any value is allowed */
+ break;
+#ifdef CONFIG_UMP
+ case KBASE_CONFIG_ATTR_UMP_DEVICE:
+ if (MALI_FALSE == kbasep_validate_ump_device(attributes[i].data))
+ {
+ OSK_PRINT_WARN(OSK_BASE_CORE, "Unknown UMP device found in configuration: %d",
+ (int)attributes[i].data);
+ return MALI_FALSE;
+ }
+ break;
+#endif /* CONFIG_UMP */
+
+ case KBASE_CONFIG_ATTR_GPU_FREQ_KHZ_MIN:
+ had_gpu_freq_min = MALI_TRUE;
+ if (MALI_FALSE == kbasep_validate_gpu_clock_freq(kbdev, attributes))
+ {
+ /* Warning message handled by kbasep_validate_gpu_clock_freq() */
+ return MALI_FALSE;
+ }
+ break;
+
+ case KBASE_CONFIG_ATTR_GPU_FREQ_KHZ_MAX:
+ had_gpu_freq_max = MALI_TRUE;
+ if (MALI_FALSE == kbasep_validate_gpu_clock_freq(kbdev, attributes))
+ {
+ /* Warning message handled by kbasep_validate_gpu_clock_freq() */
+ return MALI_FALSE;
+ }
+ break;
+
+ /* Only non-zero unsigned 32-bit values accepted */
+ case KBASE_CONFIG_ATTR_JS_SCHEDULING_TICK_NS:
+ #if CSTD_CPU_64BIT
+ if ( attributes[i].data == 0u || (u64)attributes[i].data > (u64)U32_MAX )
+ #else
+ if ( attributes[i].data == 0u )
+ #endif
+ {
+ OSK_PRINT_WARN(OSK_BASE_CORE, "Invalid Job Scheduling Configuration attribute for "
+ "KBASE_CONFIG_ATTR_JS_SCHEDULING_TICKS_NS: %d",
+ (int)attributes[i].data);
+ return MALI_FALSE;
+ }
+ break;
+
+ /* All these Job Scheduling attributes are FALLTHROUGH: only unsigned 32-bit values accepted */
+ case KBASE_CONFIG_ATTR_JS_SOFT_STOP_TICKS:
+ case KBASE_CONFIG_ATTR_JS_HARD_STOP_TICKS_SS:
+ case KBASE_CONFIG_ATTR_JS_HARD_STOP_TICKS_NSS:
+ case KBASE_CONFIG_ATTR_JS_RESET_TICKS_SS:
+ case KBASE_CONFIG_ATTR_JS_RESET_TICKS_NSS:
+ case KBASE_CONFIG_ATTR_JS_RESET_TIMEOUT_MS:
+ case KBASE_CONFIG_ATTR_JS_CTX_TIMESLICE_NS:
+ case KBASE_CONFIG_ATTR_JS_CFS_CTX_RUNTIME_INIT_SLICES:
+ case KBASE_CONFIG_ATTR_JS_CFS_CTX_RUNTIME_MIN_SLICES:
+ #if CSTD_CPU_64BIT
+ if ( (u64)attributes[i].data > (u64)U32_MAX )
+ {
+ OSK_PRINT_WARN(OSK_BASE_CORE, "Job Scheduling Configuration attribute exceeds 32-bits: "
+ "id==%d val==%d",
+ attributes[i].id, (int)attributes[i].data);
+ return MALI_FALSE;
+ }
+ #endif
+ break;
+
+ case KBASE_CONFIG_ATTR_GPU_IRQ_THROTTLE_TIME_US:
+ #if CSTD_CPU_64BIT
+ if ( (u64)attributes[i].data > (u64)U32_MAX )
+ {
+ OSK_PRINT_WARN(OSK_BASE_CORE, "IRQ throttle time attribute exceeds 32-bits: "
+ "id==%d val==%d",
+ attributes[i].id, (int)attributes[i].data);
+ return MALI_FALSE;
+ }
+ #endif
+ break;
+
+ case KBASE_CONFIG_ATTR_POWER_MANAGEMENT_CALLBACKS:
+ if (MALI_FALSE == kbasep_validate_pm_callback((kbase_pm_callback_conf*)attributes[i].data))
+ {
+ /* Warning message handled by kbasep_validate_pm_callback() */
+ return MALI_FALSE;
+ }
+ break;
+
+ case KBASE_CONFIG_ATTR_SECURE_BUT_LOSS_OF_PERFORMANCE:
+ if ( attributes[i].data != MALI_TRUE && attributes[i].data != MALI_FALSE )
+ {
+ OSK_PRINT_WARN(OSK_BASE_CORE,
+ "Value for KBASE_CONFIG_ATTR_SECURE_BUT_LOSS_OF_PERFORMANCE was not "
+ "MALI_TRUE or MALI_FALSE: %u",
+ (unsigned int)attributes[i].data);
+ return MALI_FALSE;
+ }
+ break;
+
+ case KBASE_CONFIG_ATTR_CPU_SPEED_FUNC:
+ if (MALI_FALSE == kbasep_validate_cpu_speed_func((kbase_cpuprops_clock_speed_function)attributes[i].data))
+ {
+ OSK_PRINT_WARN(OSK_BASE_CORE, "Invalid function pointer in KBASE_CONFIG_ATTR_CPU_SPEED_FUNC");
+ return MALI_FALSE;
+ }
+ break;
+
+ case KBASE_CONFIG_ATTR_GPU_SPEED_FUNC:
+ if (0 == attributes[i].data)
+ {
+ OSK_PRINT_WARN(OSK_BASE_CORE, "Invalid function pointer in KBASE_CONFIG_ATTR_GPU_SPEED_FUNC");
+ return MALI_FALSE;
+ }
+ break;
+
+ case KBASE_CONFIG_ATTR_PLATFORM_FUNCS:
+ /* any value is allowed */
+ break;
+
+ default:
+ OSK_PRINT_WARN(OSK_BASE_CORE, "Invalid attribute found in configuration: %d", attributes[i].id);
+ return MALI_FALSE;
+ }
+ }
+
+ if(!had_gpu_freq_min)
+ {
+ OSK_PRINT_WARN(OSK_BASE_CORE, "Configuration does not include mandatory attribute KBASE_CONFIG_ATTR_GPU_FREQ_KHZ_MIN");
+ return MALI_FALSE;
+ }
+
+ if(!had_gpu_freq_max)
+ {
+ OSK_PRINT_WARN(OSK_BASE_CORE, "Configuration does not include mandatory attribute KBASE_CONFIG_ATTR_GPU_FREQ_KHZ_MAX");
+ return MALI_FALSE;
+ }
+
+ return MALI_TRUE;
+}
+
diff --git a/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_context.c b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_context.c
new file mode 100644
index 0000000..50cf2cf
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_context.c
@@ -0,0 +1,235 @@
+/*
+ *
+ * (C) COPYRIGHT 2010-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_kbase_context.c
+ * Base kernel context APIs
+ */
+
+#include <kbase/src/common/mali_kbase.h>
+#include <kbase/src/common/mali_midg_regmap.h>
+
+/**
+ * @brief Create a kernel base context.
+ *
+ * Allocate and init a kernel base context. Calls
+ * kbase_create_os_context() to setup OS specific structures.
+ */
+kbase_context *kbase_create_context(kbase_device *kbdev)
+{
+ kbase_context *kctx;
+ mali_error mali_err;
+
+ OSK_ASSERT(kbdev != NULL);
+
+ /* zero-inited as lot of code assume it's zero'ed out on create */
+ if(OSK_SIMULATE_FAILURE(OSK_OSK))
+ {
+ kctx = NULL;
+ }
+ else
+ {
+ kctx = vzalloc(sizeof(*kctx));
+ }
+
+ if (!kctx)
+ goto out;
+
+ kctx->kbdev = kbdev;
+ kctx->as_nr = KBASEP_AS_NR_INVALID;
+ atomic_set(&kctx->setup_complete, 0);
+ atomic_set(&kctx->setup_in_progress, 0);
+ kctx->keep_gpu_powered = MALI_FALSE;
+
+ spin_lock_init(&kctx->mm_update_lock);
+ kctx->process_mm = NULL;
+ atomic_set(&kctx->nonmapped_pages, 0);
+
+ if (MALI_ERROR_NONE != kbase_mem_allocator_init(&kctx->osalloc, 16384))
+ {
+ goto free_kctx;
+ }
+
+ kctx->pgd_allocator = &kctx->osalloc;
+
+ if (kbase_mem_usage_init(&kctx->usage, kctx->kbdev->memdev.per_process_memory_limit >> PAGE_SHIFT))
+ {
+ goto free_allocator;
+ }
+
+ if (kbase_jd_init(kctx))
+ goto free_memctx;
+
+ mali_err = kbasep_js_kctx_init( kctx );
+ if ( MALI_ERROR_NONE != mali_err )
+ {
+ goto free_jd; /* safe to call kbasep_js_kctx_term in this case */
+ }
+
+ mali_err = kbase_event_init(kctx);
+ if (MALI_ERROR_NONE != mali_err)
+ goto free_jd;
+
+ mutex_init(&kctx->reg_lock);
+
+ OSK_DLIST_INIT(&kctx->waiting_soft_jobs);
+
+ mali_err = kbase_mmu_init(kctx);
+ if(MALI_ERROR_NONE != mali_err)
+ goto free_event;
+
+ kctx->pgd = kbase_mmu_alloc_pgd(kctx);
+ if (!kctx->pgd)
+ goto free_mmu;
+
+ if (kbase_create_os_context(&kctx->osctx))
+ goto free_pgd;
+
+ /* Make sure page 0 is not used... */
+ if(kbase_region_tracker_init(kctx))
+ goto free_osctx;
+
+ return kctx;
+
+free_osctx:
+ kbase_destroy_os_context(&kctx->osctx);
+free_pgd:
+ kbase_mmu_free_pgd(kctx);
+free_mmu:
+ kbase_mmu_term(kctx);
+free_event:
+ kbase_event_cleanup(kctx);
+free_jd:
+ /* Safe to call this one even when didn't initialize (assuming kctx was sufficiently zeroed) */
+ kbasep_js_kctx_term(kctx);
+ kbase_jd_exit(kctx);
+free_memctx:
+ kbase_mem_usage_term(&kctx->usage);
+free_allocator:
+ kbase_mem_allocator_term(&kctx->osalloc);
+free_kctx:
+ vfree(kctx);
+out:
+ return NULL;
+
+}
+KBASE_EXPORT_SYMBOL(kbase_create_context)
+
+/**
+ * @brief Destroy a kernel base context.
+ *
+ * Destroy a kernel base context. Calls kbase_destroy_os_context() to
+ * free OS specific structures. Will release all outstanding regions.
+ */
+void kbase_destroy_context(kbase_context *kctx)
+{
+ kbase_device *kbdev;
+
+ OSK_ASSERT(NULL != kctx);
+
+ kbdev = kctx->kbdev;
+ OSK_ASSERT(NULL != kbdev);
+
+ KBASE_TRACE_ADD( kbdev, CORE_CTX_DESTROY, kctx, NULL, 0u, 0u );
+
+ /* Ensure the core is powered up for the destroy process */
+ kbase_pm_context_active(kbdev);
+
+ if(kbdev->hwcnt.kctx == kctx)
+ {
+ /* disable the use of the hw counters if the app didn't use the API correctly or crashed */
+ KBASE_TRACE_ADD( kbdev, CORE_CTX_HWINSTR_TERM, kctx, NULL, 0u, 0u );
+ OSK_PRINT_WARN(OSK_BASE_CTX,
+ "The privileged process asking for instrumentation forgot to disable it "
+ "before exiting. Will end instrumentation for them" );
+ kbase_instr_hwcnt_disable(kctx);
+ }
+
+ kbase_jd_zap_context(kctx);
+ kbase_event_cleanup(kctx);
+
+ kbase_gpu_vm_lock(kctx);
+
+ /* MMU is disabled as part of scheduling out the context */
+ kbase_mmu_free_pgd(kctx);
+ kbase_region_tracker_term(kctx);
+ kbase_destroy_os_context(&kctx->osctx);
+ kbase_gpu_vm_unlock(kctx);
+
+ /* Safe to call this one even when didn't initialize (assuming kctx was sufficiently zeroed) */
+ kbasep_js_kctx_term(kctx);
+
+ kbase_jd_exit(kctx);
+
+ kbase_pm_context_idle(kbdev);
+
+ kbase_mmu_term(kctx);
+
+ kbase_mem_usage_term(&kctx->usage);
+
+ if (kctx->keep_gpu_powered)
+ {
+ kbase_pm_context_idle(kbdev);
+ }
+ WARN_ON(atomic_read(&kctx->nonmapped_pages) != 0);
+
+ kbase_mem_allocator_term(&kctx->osalloc);
+ vfree(kctx);
+}
+KBASE_EXPORT_SYMBOL(kbase_destroy_context)
+
+/**
+ * Set creation flags on a context
+ */
+mali_error kbase_context_set_create_flags(kbase_context *kctx, u32 flags)
+{
+ mali_error err = MALI_ERROR_NONE;
+ kbasep_js_kctx_info *js_kctx_info;
+ OSK_ASSERT(NULL != kctx);
+
+ if (OSK_SIMULATE_FAILURE(OSK_BASE_CTX))
+ {
+ return MALI_ERROR_FUNCTION_FAILED;
+ }
+
+ js_kctx_info = &kctx->jctx.sched_info;
+
+ /* Validate flags */
+ if ( flags != (flags & BASE_CONTEXT_CREATE_KERNEL_FLAGS) )
+ {
+ err = MALI_ERROR_FUNCTION_FAILED;
+ goto out;
+ }
+
+ mutex_lock( &js_kctx_info->ctx.jsctx_mutex );
+
+ /* Translate the flags */
+ if ( (flags & BASE_CONTEXT_SYSTEM_MONITOR_SUBMIT_DISABLED) == 0 )
+ {
+ js_kctx_info->ctx.flags &= ~((u32)KBASE_CTX_FLAG_SUBMIT_DISABLED);
+ }
+
+ if ( (flags & BASE_CONTEXT_HINT_ONLY_COMPUTE) != 0 )
+ {
+ js_kctx_info->ctx.flags |= (u32)KBASE_CTX_FLAG_HINT_ONLY_COMPUTE;
+ }
+
+ /* Latch the initial attributes into the Job Scheduler */
+ kbasep_js_ctx_attr_set_initial_attrs( kctx->kbdev, kctx );
+
+ mutex_unlock( &js_kctx_info->ctx.jsctx_mutex );
+out:
+ return err;
+}
+KBASE_EXPORT_SYMBOL(kbase_context_set_create_flags)
diff --git a/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_cpuprops.c b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_cpuprops.c
new file mode 100644
index 0000000..68d7c390
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_cpuprops.c
@@ -0,0 +1,60 @@
+/*
+ *
+ * (C) COPYRIGHT 2011-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_kbase_cpuprops.c
+ * Base kernel property query APIs
+ */
+
+#include "mali_kbase.h"
+#include "mali_kbase_cpuprops.h"
+#include "mali_kbase_uku.h"
+#include <kbase/mali_kbase_config.h>
+#include <osk/mali_osk.h>
+
+int kbase_cpuprops_get_default_clock_speed(u32 *clock_speed)
+{
+ OSK_ASSERT( NULL != clock_speed );
+
+ *clock_speed = 100;
+ return 0;
+}
+
+mali_error kbase_cpuprops_uk_get_props(kbase_context *kctx, kbase_uk_cpuprops * kbase_props)
+{
+ int result;
+ kbase_cpuprops_clock_speed_function kbase_cpuprops_uk_get_clock_speed;
+
+ if (OSK_SIMULATE_FAILURE(OSK_BASE_CORE))
+ {
+ return MALI_ERROR_FUNCTION_FAILED;
+ }
+
+ kbase_props->props.cpu_l1_dcache_line_size_log2 = OSK_L1_DCACHE_LINE_SIZE_LOG2;
+ kbase_props->props.cpu_l1_dcache_size = OSK_L1_DCACHE_SIZE;
+ kbase_props->props.cpu_flags = BASE_CPU_PROPERTY_FLAG_LITTLE_ENDIAN;
+
+ kbase_props->props.nr_cores = NR_CPUS;
+ kbase_props->props.cpu_page_size_log2 = PAGE_SHIFT;
+ kbase_props->props.available_memory_size = totalram_pages << PAGE_SHIFT;
+
+ kbase_cpuprops_uk_get_clock_speed = (kbase_cpuprops_clock_speed_function)kbasep_get_config_value( kctx->kbdev, kctx->kbdev->config_attributes, KBASE_CONFIG_ATTR_CPU_SPEED_FUNC );
+ result = kbase_cpuprops_uk_get_clock_speed(&kbase_props->props.max_cpu_clock_speed_mhz);
+ if (result != 0)
+ {
+ return MALI_ERROR_FUNCTION_FAILED;
+ }
+
+ return MALI_ERROR_NONE;
+}
diff --git a/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_cpuprops.h b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_cpuprops.h
new file mode 100644
index 0000000..1c00179
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_cpuprops.h
@@ -0,0 +1,51 @@
+/*
+ *
+ * (C) COPYRIGHT 2011-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_kbase_cpuprops.h
+ * Base kernel property query APIs
+ */
+
+#ifndef _KBASE_CPUPROPS_H_
+#define _KBASE_CPUPROPS_H_
+
+#include <malisw/mali_malisw.h>
+
+/* Forward declarations */
+struct kbase_uk_cpuprops;
+
+/**
+ * @brief Default implementation of @ref KBASE_CONFIG_ATTR_CPU_SPEED_FUNC.
+ *
+ * This function sets clock_speed to 100, so will be an underestimate for
+ * any real system.
+ *
+ * See @ref kbase_cpuprops_clock_speed_function for details on the parameters
+ * and return value.
+ */
+int kbase_cpuprops_get_default_clock_speed(u32 *clock_speed);
+
+/**
+ * @brief Provides CPU properties data.
+ *
+ * Fill the kbase_uk_cpuprops with values from CPU configuration.
+ *
+ * @param kctx The kbase context
+ * @param kbase_props A copy of the kbase_uk_cpuprops structure from userspace
+ *
+ * @return MALI_ERROR_NONE on success. Any other value indicates failure.
+ */
+mali_error kbase_cpuprops_uk_get_props(kbase_context *kctx, struct kbase_uk_cpuprops* kbase_props);
+
+#endif /*_KBASE_CPUPROPS_H_*/
diff --git a/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_defs.h b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_defs.h
new file mode 100644
index 0000000..5ee6790
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_defs.h
@@ -0,0 +1,681 @@
+/*
+ *
+ * (C) COPYRIGHT 2011-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_kbase_defs.h
+ *
+ * Defintions (types, defines, etcs) common to Kbase. They are placed here to
+ * allow the hierarchy of header files to work.
+ */
+
+#ifndef _KBASE_DEFS_H_
+#define _KBASE_DEFS_H_
+
+#define KBASE_LIST_TRACE_ENABLE 1
+
+#include <kbase/mali_kbase_config.h>
+#include <kbase/mali_base_hwconfig.h>
+#include <osk/mali_osk.h>
+
+#include <asm/atomic.h>
+
+#include <linux/hrtimer.h>
+#include <linux/ktime.h>
+#include <linux/mempool.h>
+#include <linux/slab.h>
+
+#ifdef CONFIG_KDS
+#include <linux/kds.h>
+#endif /* CONFIG_KDS */
+
+#ifdef CONFIG_SYNC
+#include <linux/sync.h>
+#endif /* CONFIG_SYNC */
+
+/** Enable SW tracing when set */
+#ifdef CONFIG_MALI_T6XX_ENABLE_TRACE
+#define KBASE_TRACE_ENABLE 1
+#endif /* CONFIG_MALI_T6XX_ENABLE_TRACE */
+
+#ifndef KBASE_TRACE_ENABLE
+#ifdef CONFIG_MALI_DEBUG
+#define KBASE_TRACE_ENABLE 1
+#else
+#define KBASE_TRACE_ENABLE 0
+#endif /* CONFIG_MALI_DEBUG */
+#endif /* KBASE_TRACE_ENABLE */
+
+/** Dump Job slot trace on error (only active if KBASE_TRACE_ENABLE != 0) */
+#define KBASE_TRACE_DUMP_ON_JOB_SLOT_ERROR 1
+
+/**
+ * Number of milliseconds before resetting the GPU when a job cannot be "zapped" from the hardware.
+ * Note that the time is actually ZAP_TIMEOUT+SOFT_STOP_RESET_TIMEOUT between the context zap starting and the GPU
+ * actually being reset to give other contexts time for their jobs to be soft-stopped and removed from the hardware
+ * before resetting.
+ */
+#define ZAP_TIMEOUT 1000
+
+/**
+ * Prevent soft-stops from occuring in scheduling situations
+ *
+ * This is not due to HW issues, but when scheduling is desired to be more predictable.
+ *
+ * Therefore, soft stop may still be disabled due to HW issues.
+ *
+ * @note Soft stop will still be used for non-scheduling purposes e.g. when terminating a context.
+ *
+ * @note if not in use, define this value to 0 instead of \#undef'ing it
+ */
+#define KBASE_DISABLE_SCHEDULING_SOFT_STOPS 0
+
+/**
+ * Prevent hard-stops from occuring in scheduling situations
+ *
+ * This is not due to HW issues, but when scheduling is desired to be more predictable.
+ *
+ * @note Hard stop will still be used for non-scheduling purposes e.g. when terminating a context.
+ *
+ * @note if not in use, define this value to 0 instead of \#undef'ing it
+ */
+#define KBASE_DISABLE_SCHEDULING_HARD_STOPS 0
+
+/* Forward declarations+defintions */
+typedef struct kbase_context kbase_context;
+typedef struct kbase_jd_atom kbasep_jd_atom;
+typedef struct kbase_device kbase_device;
+
+/**
+ * The maximum number of Job Slots to support in the Hardware.
+ *
+ * You can optimize this down if your target devices will only ever support a
+ * small number of job slots.
+ */
+#define BASE_JM_MAX_NR_SLOTS 16
+
+/**
+ * The maximum number of Address Spaces to support in the Hardware.
+ *
+ * You can optimize this down if your target devices will only ever support a
+ * small number of Address Spaces
+ */
+#define BASE_MAX_NR_AS 16
+
+/* mmu */
+#define ENTRY_IS_ATE 1ULL
+#define ENTRY_IS_INVAL 2ULL
+#define ENTRY_IS_PTE 3ULL
+
+#define MIDGARD_MMU_VA_BITS 48
+
+#define ENTRY_ATTR_BITS (7ULL << 2) /* bits 4:2 */
+#define ENTRY_RD_BIT (1ULL << 6)
+#define ENTRY_WR_BIT (1ULL << 7)
+#define ENTRY_SHARE_BITS (3ULL << 8) /* bits 9:8 */
+#define ENTRY_ACCESS_BIT (1ULL << 10)
+#define ENTRY_NX_BIT (1ULL << 54)
+
+#define ENTRY_FLAGS_MASK (ENTRY_ATTR_BITS | ENTRY_RD_BIT | ENTRY_WR_BIT | ENTRY_SHARE_BITS | ENTRY_ACCESS_BIT | ENTRY_NX_BIT)
+
+#if MIDGARD_MMU_VA_BITS > 39
+#define MIDGARD_MMU_TOPLEVEL 0
+#else
+#define MIDGARD_MMU_TOPLEVEL 1
+#endif
+
+#define GROWABLE_FLAGS_REQUIRED (KBASE_REG_PF_GROW | KBASE_REG_ZONE_TMEM)
+#define GROWABLE_FLAGS_MASK (GROWABLE_FLAGS_REQUIRED | KBASE_REG_FREE)
+
+/** setting in kbase_context::as_nr that indicates it's invalid */
+#define KBASEP_AS_NR_INVALID (-1)
+
+#define KBASE_LOCK_REGION_MAX_SIZE (63)
+#define KBASE_LOCK_REGION_MIN_SIZE (11)
+
+#define KBASE_TRACE_SIZE_LOG2 8 /* 256 entries */
+#define KBASE_TRACE_SIZE (1 << KBASE_TRACE_SIZE_LOG2)
+#define KBASE_TRACE_MASK ((1 << KBASE_TRACE_SIZE_LOG2)-1)
+
+#define KBASE_LIST_TRACE_SIZE (1 << KBASE_TRACE_SIZE_LOG2)
+
+#include "mali_kbase_js_defs.h"
+
+/**
+ * @brief States to model state machine processed by kbasep_js_job_check_ref_cores(), which
+ * handles retaining cores for power management and affinity management.
+ *
+ * The state @ref KBASE_ATOM_COREREF_STATE_RECHECK_AFFINITY prevents an attack
+ * where lots of atoms could be submitted before powerup, and each has an
+ * affinity chosen that causes other atoms to have an affinity
+ * violation. Whilst the affinity was not causing violations at the time it
+ * was chosen, it could cause violations thereafter. For example, 1000 jobs
+ * could have had their affinity chosen during the powerup time, so any of
+ * those 1000 jobs could cause an affinity violation later on.
+ *
+ * The attack would otherwise occur because other atoms/contexts have to wait for:
+ * -# the currently running atoms (which are causing the violation) to
+ * finish
+ * -# and, the atoms that had their affinity chosen during powerup to
+ * finish. These are run preferrentially because they don't cause a
+ * violation, but instead continue to cause the violation in others.
+ * -# or, the attacker is scheduled out (which might not happen for just 2
+ * contexts)
+ *
+ * By re-choosing the affinity (which is designed to avoid violations at the
+ * time it's chosen), we break condition (2) of the wait, which minimizes the
+ * problem to just waiting for current jobs to finish (which can be bounded if
+ * the Job Scheduling Policy has a timer).
+ */
+typedef enum
+{
+ /** Starting state: No affinity chosen, and cores must be requested. kbase_jd_atom::affinity==0 */
+ KBASE_ATOM_COREREF_STATE_NO_CORES_REQUESTED,
+ /** Cores requested, but waiting for them to be powered. Requested cores given by kbase_jd_atom::affinity */
+ KBASE_ATOM_COREREF_STATE_WAITING_FOR_REQUESTED_CORES,
+ /** Cores given by kbase_jd_atom::affinity are powered, but affinity might be out-of-date, so must recheck */
+ KBASE_ATOM_COREREF_STATE_RECHECK_AFFINITY,
+ /** Cores given by kbase_jd_atom::affinity are powered, and affinity is up-to-date, but must check for violations */
+ KBASE_ATOM_COREREF_STATE_CHECK_AFFINITY_VIOLATIONS,
+ /** Cores are powered, kbase_jd_atom::affinity up-to-date, no affinity violations: atom can be submitted to HW */
+ KBASE_ATOM_COREREF_STATE_READY
+
+} kbase_atom_coreref_state;
+
+typedef enum
+{
+ /** Atom is not used */
+ KBASE_JD_ATOM_STATE_UNUSED,
+ /** Atom is queued in JD */
+ KBASE_JD_ATOM_STATE_QUEUED,
+ /** Atom has been given to JS (is runnable/running) */
+ KBASE_JD_ATOM_STATE_IN_JS,
+ /** Atom has been completed, but not yet handed back to userspace */
+ KBASE_JD_ATOM_STATE_COMPLETED
+} kbase_jd_atom_state;
+
+typedef struct kbase_jd_atom kbase_jd_atom;
+
+
+struct kbase_jd_atom {
+ struct work_struct work;
+ ktime_t start_timestamp;
+
+ base_jd_udata udata;
+ kbase_context *kctx;
+
+ osk_dlist dep_head[2];
+ osk_dlist_item dep_item[2];
+ kbase_jd_atom *dep_atom[2];
+
+ u16 nr_extres;
+ base_external_resource *extres;
+
+ u32 device_nr;
+ u64 affinity;
+ u64 jc;
+ kbase_atom_coreref_state coreref_state;
+#ifdef CONFIG_KDS
+ struct kds_resource_set * kds_rset;
+ mali_bool kds_dep_satisfied;
+#endif /* CONFIG_KDS */
+#ifdef CONFIG_SYNC
+ struct sync_fence *fence;
+ struct sync_fence_waiter sync_waiter;
+#endif /* CONFIG_SYNC */
+
+ /* Note: refer to kbasep_js_atom_retained_state, which will take a copy of some of the following members */
+ base_jd_event_code event_code;
+ base_jd_core_req core_req; /**< core requirements */
+ /** Job Slot to retry submitting to if submission from IRQ handler failed
+ *
+ * NOTE: see if this can be unified into the another member e.g. the event */
+ int retry_submit_on_slot;
+
+ kbasep_js_policy_job_info sched_info;
+ /* atom priority scaled to nice range with +20 offset 0..39 */
+ int nice_prio;
+
+ int poking; /* BASE_HW_ISSUE_8316 */
+
+ wait_queue_head_t completed;
+ kbase_jd_atom_state status;
+};
+
+/*
+ * Theory of operations:
+ *
+ * Atom objects are statically allocated within the context structure.
+ *
+ * Each atom is the head of two lists, one for the "left" set of dependencies, one for the "right" set.
+ */
+
+#define KBASE_JD_DEP_QUEUE_SIZE 256
+
+typedef struct kbase_jd_context {
+ struct mutex lock;
+ kbasep_js_kctx_info sched_info;
+ kbase_jd_atom atoms[BASE_JD_ATOM_COUNT];
+
+ /** Tracks all job-dispatch jobs. This includes those not tracked by
+ * the scheduler: 'not ready to run' and 'dependency-only' jobs. */
+ u32 job_nr;
+
+ /** Waitq that reflects whether there are no jobs (including SW-only
+ * dependency jobs). This is set when no jobs are present on the ctx,
+ * and clear when there are jobs.
+ *
+ * @note: Job Dispatcher knows about more jobs than the Job Scheduler:
+ * the Job Scheduler is unaware of jobs that are blocked on dependencies,
+ * and SW-only dependency jobs.
+ *
+ * This waitq can be waited upon to find out when the context jobs are all
+ * done/cancelled (including those that might've been blocked on
+ * dependencies) - and so, whether it can be terminated. However, it should
+ * only be terminated once it is neither present in the policy-queue (see
+ * kbasep_js_policy_try_evict_ctx() ) nor the run-pool (see
+ * kbasep_js_kctx_info::ctx::is_scheduled).
+ *
+ * Since the waitq is only set under kbase_jd_context::lock,
+ * the waiter should also briefly obtain and drop kbase_jd_context::lock to
+ * guarentee that the setter has completed its work on the kbase_context
+ *
+ * This must be updated atomically with:
+ * - kbase_jd_context::job_nr */
+ wait_queue_head_t zero_jobs_wait;
+
+ /** Job Done workqueue. */
+ struct workqueue_struct *job_done_wq;
+
+ spinlock_t tb_lock;
+ u32 *tb;
+ size_t tb_wrap_offset;
+
+#ifdef CONFIG_KDS
+ struct kds_callback kds_cb;
+#endif /* CONFIG_KDS */
+} kbase_jd_context;
+
+typedef struct kbase_jm_slot
+{
+ /* The number of slots must be a power of two */
+#define BASE_JM_SUBMIT_SLOTS 16
+#define BASE_JM_SUBMIT_SLOTS_MASK (BASE_JM_SUBMIT_SLOTS - 1)
+
+ kbase_jd_atom *submitted[BASE_JM_SUBMIT_SLOTS];
+
+ u8 submitted_head;
+ u8 submitted_nr;
+
+} kbase_jm_slot;
+
+typedef enum kbase_midgard_type
+{
+ KBASE_MALI_T601,
+ KBASE_MALI_T604,
+ KBASE_MALI_T608,
+ KBASE_MALI_COUNT
+} kbase_midgard_type;
+
+typedef struct kbase_device_info
+{
+ kbase_midgard_type dev_type;
+ u32 features;
+} kbase_device_info;
+
+/**
+ * Important: Our code makes assumptions that a kbase_as structure is always at
+ * kbase_device->as[number]. This is used to recover the containing
+ * kbase_device from a kbase_as structure.
+ *
+ * Therefore, kbase_as structures must not be allocated anywhere else.
+ */
+typedef struct kbase_as
+{
+ int number;
+
+ struct workqueue_struct *pf_wq;
+ struct work_struct work_pagefault;
+ struct work_struct work_busfault;
+ mali_addr64 fault_addr;
+ struct mutex transaction_mutex;
+
+ /* BASE_HW_ISSUE_8316 */
+ struct workqueue_struct *poke_wq;
+ struct work_struct poke_work;
+ atomic_t poke_refcount;
+ struct hrtimer poke_timer;
+} kbase_as;
+
+/* tracking of memory usage */
+typedef struct kbasep_mem_usage
+{
+ u32 max_pages;
+ atomic_t cur_pages;
+} kbasep_mem_usage;
+
+ /**
+ * Instrumentation State Machine States:
+ * DISABLED - requires instrumentation to be enabled
+ * IDLE - state machine is active and ready for a command.
+ * DUMPING - hardware is currently dumping a frame.
+ * POSTCLEANING- hardware is currently cleaning and invalidating caches.
+ * PRECLEANING - same as POSTCLEANING, except on completion, state machine will transiton to CLEANED instead of IDLE.
+ * CLEANED - cache clean completed, waiting for Instrumentation setup.
+ * ERROR - an error has occured during DUMPING (page fault).
+ */
+
+typedef enum
+{
+ KBASE_INSTR_STATE_DISABLED = 0,
+ KBASE_INSTR_STATE_IDLE,
+ KBASE_INSTR_STATE_DUMPING,
+ KBASE_INSTR_STATE_CLEANED,
+ KBASE_INSTR_STATE_PRECLEANING,
+ KBASE_INSTR_STATE_POSTCLEANING,
+ KBASE_INSTR_STATE_RESETTING,
+ KBASE_INSTR_STATE_FAULT
+
+} kbase_instr_state;
+
+
+typedef struct kbasep_mem_device
+{
+#ifdef CONFIG_UMP
+ u32 ump_device_id; /* Which UMP device this GPU should be mapped to.
+ Read-only, copied from platform configuration on startup.*/
+#endif /* CONFIG_UMP */
+
+ u32 per_process_memory_limit; /* How much memory (in bytes) a single process can access.
+ Read-only, copied from platform configuration on startup. */
+ kbasep_mem_usage usage; /* Tracks usage of OS shared memory. Initialized with platform
+ configuration data, updated when OS memory is allocated/freed.*/
+} kbasep_mem_device;
+
+/* raw page handling */
+typedef struct kbase_mem_allocator
+{
+ atomic_t free_list_size;
+ unsigned int free_list_max_size;
+ struct mutex free_list_lock;
+ struct list_head free_list_head;
+ struct shrinker free_list_reclaimer;
+} kbase_mem_allocator;
+
+#define KBASE_TRACE_CODE( X ) KBASE_TRACE_CODE_ ## X
+
+typedef enum
+{
+ /* IMPORTANT: USE OF SPECIAL #INCLUDE OF NON-STANDARD HEADER FILE
+ * THIS MUST BE USED AT THE START OF THE ENUM */
+#define KBASE_TRACE_CODE_MAKE_CODE( X ) KBASE_TRACE_CODE( X )
+#include "mali_kbase_trace_defs.h"
+#undef KBASE_TRACE_CODE_MAKE_CODE
+ /* Comma on its own, to extend the list */
+ ,
+ /* Must be the last in the enum */
+ KBASE_TRACE_CODE_COUNT
+} kbase_trace_code;
+
+#define KBASE_TRACE_FLAG_REFCOUNT (((u8)1) << 0)
+#define KBASE_TRACE_FLAG_JOBSLOT (((u8)1) << 1)
+
+typedef struct kbase_trace
+{
+ struct timespec timestamp;
+ u32 thread_id;
+ u32 cpu;
+ void *ctx;
+ kbase_jd_atom *katom;
+ u64 gpu_addr;
+ u32 info_val;
+ u8 code;
+ u8 jobslot;
+ u8 refcount;
+ u8 flags;
+} kbase_trace;
+
+#define KBASE_TRACE_LIST_ADD MALI_TRUE
+#define KBASE_TRACE_LIST_DEL MALI_FALSE
+
+#define KBASE_TRACE_LIST_DEP_HEAD_0 0
+#define KBASE_TRACE_LIST_COMPLETED_JOBS 1
+#define KBASE_TRACE_LIST_RUNNABLE_JOBS 2
+#define KBASE_TRACE_LIST_WAITING_SOFT_JOBS 3
+#define KBASE_TRACE_LIST_EVENT_LIST 4
+
+
+typedef struct kbase_list_trace
+{
+ struct timespec timestamp;
+ u8 tracepoint_id;
+ kbase_jd_atom *katom;
+ osk_dlist *list_id;
+ mali_bool action;
+ u8 list_type;
+} kbase_list_trace;
+
+struct kbase_device {
+ /** jm_slots is protected by kbasep_js_device_data::runpool_irq::lock */
+ kbase_jm_slot jm_slots[BASE_JM_MAX_NR_SLOTS];
+ s8 slot_submit_count_irq[BASE_JM_MAX_NR_SLOTS];
+ kbase_os_device osdev;
+ kbase_pm_device_data pm;
+ kbasep_js_device_data js_data;
+ kbasep_mem_device memdev;
+
+ kbase_as as[BASE_MAX_NR_AS];
+
+ spinlock_t mmu_mask_change;
+
+ kbase_gpu_props gpu_props;
+
+ /** List of SW workarounds for HW issues */
+ unsigned long hw_issues_mask[(BASE_HW_ISSUE_END + OSK_BITS_PER_LONG - 1)/OSK_BITS_PER_LONG];
+
+ /* Cached present bitmaps - these are the same as the corresponding hardware registers */
+ u64 shader_present_bitmap;
+ u64 tiler_present_bitmap;
+ u64 l2_present_bitmap;
+ u64 l3_present_bitmap;
+
+ /* Bitmaps of cores that are currently in use (running jobs).
+ * These should be kept up to date by the job scheduler.
+ *
+ * pm.power_change_lock should be held when accessing these members.
+ *
+ * kbase_pm_check_transitions should be called when bits are cleared to
+ * update the power management system and allow transitions to occur. */
+ u64 shader_inuse_bitmap;
+ u64 tiler_inuse_bitmap;
+
+ /* Refcount for cores in use */
+ u32 shader_inuse_cnt[64];
+ u32 tiler_inuse_cnt[64];
+
+ /* Bitmaps of cores the JS needs for jobs ready to run */
+ u64 shader_needed_bitmap;
+ u64 tiler_needed_bitmap;
+
+ /* Refcount for cores needed */
+ u32 shader_needed_cnt[64];
+ u32 tiler_needed_cnt[64];
+
+ /* Refcount for tracking users of the l2 cache, e.g. when using hardware counter instrumentation. */
+ u32 l2_users_count;
+
+ /* Bitmaps of cores that are currently available (powered up and the power policy is happy for jobs to be
+ * submitted to these cores. These are updated by the power management code. The job scheduler should avoid
+ * submitting new jobs to any cores that are not marked as available.
+ *
+ * pm.power_change_lock should be held when accessing these members.
+ */
+ u64 shader_available_bitmap;
+ u64 tiler_available_bitmap;
+
+ s8 nr_hw_address_spaces; /**< Number of address spaces in the GPU (constant after driver initialisation) */
+ s8 nr_user_address_spaces; /**< Number of address spaces available to user contexts */
+
+ /* Structure used for instrumentation and HW counters dumping */
+ struct {
+ /* The lock should be used when accessing any of the following members */
+ spinlock_t lock;
+
+ kbase_context *kctx;
+ u64 addr;
+ wait_queue_head_t wait;
+ int triggered;
+ kbase_instr_state state;
+ } hwcnt;
+
+ /* Set when we're about to reset the GPU */
+ atomic_t reset_gpu;
+#define KBASE_RESET_GPU_NOT_PENDING 0 /* The GPU reset isn't pending */
+#define KBASE_RESET_GPU_PREPARED 1 /* kbase_prepare_to_reset_gpu has been called */
+#define KBASE_RESET_GPU_COMMITTED 2 /* kbase_reset_gpu has been called - the reset will now definitely happen
+ * within the timeout period */
+#define KBASE_RESET_GPU_HAPPENING 3 /* The GPU reset process is currently occuring (timeout has expired or
+ * kbasep_try_reset_gpu_early was called) */
+
+ /* Work queue and work item for performing the reset in */
+ struct workqueue_struct *reset_workq;
+ struct work_struct reset_work;
+ wait_queue_head_t reset_wait;
+ struct hrtimer reset_timer;
+
+ /*value to be written to the irq_throttle register each time an irq is served */
+ atomic_t irq_throttle_cycles;
+
+ const kbase_attribute *config_attributes;
+
+ /* >> BASE_HW_ISSUE_8401 >> */
+#define KBASE_8401_WORKAROUND_COMPUTEJOB_COUNT 3
+ kbase_context *workaround_kctx;
+ osk_virt_addr workaround_compute_job_va[KBASE_8401_WORKAROUND_COMPUTEJOB_COUNT];
+ osk_phy_addr workaround_compute_job_pa[KBASE_8401_WORKAROUND_COMPUTEJOB_COUNT];
+ /* << BASE_HW_ISSUE_8401 << */
+
+#if KBASE_TRACE_ENABLE != 0
+ spinlock_t trace_lock;
+ u16 trace_first_out;
+ u16 trace_next_in;
+ kbase_trace *trace_rbuf;
+#endif
+#if KBASE_LIST_TRACE_ENABLE != 0
+ spinlock_t trace_lists_lock;
+ u16 trace_lists_first_out;
+ u16 trace_lists_next_in;
+ kbase_list_trace *trace_lists_rbuf;
+#endif
+
+#if MALI_CUSTOMER_RELEASE == 0
+ /* This is used to override the current job scheduler values for
+ * KBASE_CONFIG_ATTR_JS_STOP_STOP_TICKS_SS
+ * KBASE_CONFIG_ATTR_JS_HARD_STOP_TICKS_SS
+ * KBASE_CONFIG_ATTR_JS_HARD_STOP_TICKS_NSS
+ * KBASE_CONFIG_ATTR_JS_RESET_TICKS_SS
+ * KBASE_CONFIG_ATTR_JS_RESET_TICKS_NSS.
+ *
+ * These values are set via the js_timeouts sysfs file.
+ */
+ u32 js_soft_stop_ticks;
+ u32 js_hard_stop_ticks_ss;
+ u32 js_hard_stop_ticks_nss;
+ u32 js_reset_ticks_ss;
+ u32 js_reset_ticks_nss;
+#endif
+ /* Platform specific private data to be accessed by mali_kbase_config_xxx.c only */
+ void *platform_context;
+#ifdef CONFIG_MALI_T6XX_RT_PM
+ struct delayed_work runtime_pm_workqueue;
+#endif
+};
+
+struct kbase_context
+{
+ kbase_device *kbdev;
+ osk_phy_addr pgd;
+ osk_dlist event_list;
+ struct mutex event_mutex;
+ mali_bool event_closed;
+ osk_workq event_workq;
+
+ atomic_t setup_complete;
+ atomic_t setup_in_progress;
+
+ mali_bool keep_gpu_powered;
+
+ u64 *mmu_teardown_pages;
+
+ struct mutex reg_lock; /* To be converted to a rwlock? */
+ struct rb_root reg_rbtree; /* Red-Black tree of GPU regions (live regions) */
+
+ kbase_os_context osctx;
+ kbase_jd_context jctx;
+ kbasep_mem_usage usage;
+ atomic_t nonmapped_pages;
+ ukk_session ukk_session;
+ kbase_mem_allocator osalloc;
+ kbase_mem_allocator * pgd_allocator;
+
+ osk_dlist waiting_soft_jobs;
+
+ /** This is effectively part of the Run Pool, because it only has a valid
+ * setting (!=KBASEP_AS_NR_INVALID) whilst the context is scheduled in
+ *
+ * The kbasep_js_device_data::runpool_irq::lock must be held whilst accessing
+ * this.
+ *
+ * If the context relating to this as_nr is required, you must use
+ * kbasep_js_runpool_retain_ctx() to ensure that the context doesn't disappear
+ * whilst you're using it. Alternatively, just hold the kbasep_js_device_data::runpool_irq::lock
+ * to ensure the context doesn't disappear (but this has restrictions on what other locks
+ * you can take whilst doing this) */
+ int as_nr;
+
+ /* NOTE:
+ *
+ * Flags are in jctx.sched_info.ctx.flags
+ * Mutable flags *must* be accessed under jctx.sched_info.ctx.jsctx_mutex
+ *
+ * All other flags must be added there */
+
+ spinlock_t mm_update_lock;
+ struct mm_struct * process_mm;
+};
+
+typedef enum kbase_reg_access_type
+{
+ REG_READ,
+ REG_WRITE
+} kbase_reg_access_type;
+
+
+typedef enum kbase_share_attr_bits
+{
+ /* (1ULL << 8) bit is reserved */
+ SHARE_BOTH_BITS = (2ULL << 8), /* inner and outer shareable coherency */
+ SHARE_INNER_BITS = (3ULL << 8) /* inner shareable coherency */
+} kbase_share_attr_bits;
+
+/* Conversion helpers for setting up high resolution timers */
+#define HR_TIMER_DELAY_MSEC(x) (ns_to_ktime((x)*1000000U ))
+#define HR_TIMER_DELAY_NSEC(x) (ns_to_ktime(x))
+
+/* Maximum number of loops polling the GPU for a cache flush before we assume it must have completed */
+#define KBASE_CLEAN_CACHE_MAX_LOOPS 100000
+/* Maximum number of loops polling the GPU for an AS flush to complete before we assume the GPU has hung */
+#define KBASE_AS_FLUSH_MAX_LOOPS 100000
+
+#endif /* _KBASE_DEFS_H_ */
+
diff --git a/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_device.c b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_device.c
new file mode 100644
index 0000000..f3dfd53
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_device.c
@@ -0,0 +1,864 @@
+/*
+ *
+ * (C) COPYRIGHT 2010-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/**
+ * @file mali_kbase_device.c
+ * Base kernel device APIs
+ */
+#ifdef __KERNEL__
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#endif
+
+#include <kbase/src/common/mali_kbase.h>
+#include <kbase/src/common/mali_kbase_defs.h>
+#include <kbase/src/common/mali_kbase_hw.h>
+
+/* NOTE: Magic - 0x45435254 (TRCE in ASCII).
+ * Supports tracing feature provided in the base module.
+ * Please keep it in sync with the value of base module.
+ */
+#define TRACE_BUFFER_HEADER_SPECIAL 0x45435254
+
+#ifdef CONFIG_MALI_PLATFORM_CONFIG_VEXPRESS
+#ifdef CONFIG_MALI_PLATFORM_FAKE
+extern kbase_attribute config_attributes_hw_issue_8408[];
+#endif /* CONFIG_MALI_PLATFORM_FAKE */
+#endif /* CONFIG_MALI_PLATFORM_CONFIG_VEXPRESS */
+
+
+#if KBASE_TRACE_ENABLE != 0
+STATIC CONST char *kbasep_trace_code_string[] =
+{
+ /* IMPORTANT: USE OF SPECIAL #INCLUDE OF NON-STANDARD HEADER FILE
+ * THIS MUST BE USED AT THE START OF THE ARRAY */
+#define KBASE_TRACE_CODE_MAKE_CODE( X ) # X
+#include "mali_kbase_trace_defs.h"
+#undef KBASE_TRACE_CODE_MAKE_CODE
+};
+#endif
+
+STATIC mali_error kbasep_trace_init( kbase_device *kbdev );
+STATIC void kbasep_trace_term( kbase_device *kbdev );
+STATIC void kbasep_trace_hook_wrapper( void *param );
+static void kbasep_trace_debugfs_init(kbase_device *kbdev);
+
+STATIC mali_error kbasep_list_trace_init( kbase_device *kbdev );
+STATIC void kbasep_list_trace_term( kbase_device *kbdev );
+
+void kbasep_as_do_poke(struct work_struct *work);
+enum hrtimer_restart kbasep_reset_timer_callback(struct hrtimer *data);
+void kbasep_reset_timeout_worker(struct work_struct *data);
+
+kbase_device *kbase_device_alloc(void)
+{
+ if(OSK_SIMULATE_FAILURE(OSK_OSK))
+ {
+ return NULL;
+ }
+ else
+ {
+ return kzalloc(sizeof(kbase_device), GFP_KERNEL);
+ }
+}
+
+mali_error kbase_device_init(kbase_device *kbdev)
+{
+ int i; /* i used after the for loop, don't reuse ! */
+
+ spin_lock_init(&kbdev->mmu_mask_change);
+
+ /* Initialize platform specific context */
+ if(MALI_FALSE == kbasep_platform_device_init(kbdev))
+ {
+ goto fail;
+ }
+
+ /* Ensure we can access the GPU registers */
+ kbase_pm_register_access_enable(kbdev);
+
+ /* Get the list of workarounds for issues on the current HW (identified by the GPU_ID register) */
+ if (MALI_ERROR_NONE != kbase_hw_set_issues_mask(kbdev))
+ {
+ kbase_pm_register_access_disable(kbdev);
+ goto free_platform;
+ }
+
+ /* Find out GPU properties based on the GPU feature registers */
+ kbase_gpuprops_set(kbdev);
+
+ kbdev->nr_hw_address_spaces = kbdev->gpu_props.num_address_spaces;
+
+ /* We're done accessing the GPU registers for now. */
+ kbase_pm_register_access_disable(kbdev);
+
+ for (i = 0; i < kbdev->nr_hw_address_spaces; i++)
+ {
+ const char format[] = "mali_mmu%d";
+ char name[sizeof(format)];
+ const char poke_format[] = "mali_mmu%d_poker"; /* BASE_HW_ISSUE_8316 */
+ char poke_name[sizeof(poke_format)]; /* BASE_HW_ISSUE_8316 */
+
+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8316))
+ {
+ if (0 > osk_snprintf(poke_name, sizeof(poke_name), poke_format, i))
+ {
+ goto free_workqs;
+ }
+ }
+
+ if (0 > osk_snprintf(name, sizeof(name), format, i))
+ {
+ goto free_workqs;
+ }
+
+ kbdev->as[i].number = i;
+ kbdev->as[i].fault_addr = 0ULL;
+ /* Simulate failure to create the workqueue */
+ if(OSK_SIMULATE_FAILURE(OSK_BASE_CORE))
+ {
+ kbdev->as[i].pf_wq = NULL;
+ goto free_workqs;
+ }
+ kbdev->as[i].pf_wq = alloc_workqueue(name, 0, 1);
+ if (NULL == kbdev->as[i].pf_wq)
+ {
+ goto free_workqs;
+ }
+
+ mutex_init(&kbdev->as[i].transaction_mutex);
+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8316))
+ {
+ struct hrtimer * poking_timer = &kbdev->as[i].poke_timer;
+
+ /* Simulate failure to create the workqueue */
+ if(OSK_SIMULATE_FAILURE(OSK_BASE_CORE))
+ {
+ kbdev->as[i].poke_wq = NULL;
+ destroy_workqueue(kbdev->as[i].pf_wq);
+ goto free_workqs;
+ }
+ kbdev->as[i].poke_wq = alloc_workqueue(poke_name, 0, 1);
+ if (NULL == kbdev->as[i].poke_wq)
+ {
+ destroy_workqueue(kbdev->as[i].pf_wq);
+ goto free_workqs;
+ }
+ OSK_ASSERT(0 == object_is_on_stack(&kbdev->as[i].poke_work));
+ INIT_WORK(&kbdev->as[i].poke_work, kbasep_as_do_poke);
+
+ hrtimer_init(poking_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+
+ poking_timer->function = kbasep_as_poke_timer_callback;
+
+ atomic_set(&kbdev->as[i].poke_refcount, 0);
+ }
+ }
+ /* don't change i after this point */
+
+ spin_lock_init(&kbdev->hwcnt.lock);
+
+ kbdev->hwcnt.state = KBASE_INSTR_STATE_DISABLED;
+ init_waitqueue_head(&kbdev->reset_wait);
+ init_waitqueue_head(&kbdev->hwcnt.wait);
+ kbdev->hwcnt.triggered = 0;
+
+ /* Simulate failure to create the workqueue */
+ if(OSK_SIMULATE_FAILURE(OSK_BASE_CORE))
+ {
+ kbdev->reset_workq = NULL;
+ goto free_workqs;
+ }
+
+ kbdev->reset_workq = alloc_workqueue("Mali reset workqueue", 0, 1);
+ if (NULL == kbdev->reset_workq)
+ {
+ goto free_workqs;
+ }
+
+ OSK_ASSERT(0 == object_is_on_stack(&kbdev->reset_work));
+ INIT_WORK(&kbdev->reset_work, kbasep_reset_timeout_worker);
+
+ hrtimer_init(&kbdev->reset_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ kbdev->reset_timer.function=kbasep_reset_timer_callback;
+
+ if (( kbasep_trace_init( kbdev ) != MALI_ERROR_NONE ) || (kbasep_list_trace_init (kbdev) != MALI_ERROR_NONE))
+ {
+ goto free_reset_workq;
+ }
+
+ osk_debug_assert_register_hook( &kbasep_trace_hook_wrapper, kbdev );
+
+#ifdef CONFIG_MALI_PLATFORM_CONFIG_VEXPRESS
+#ifdef CONFIG_MALI_PLATFORM_FAKE
+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8408))
+ {
+ /* BASE_HW_ISSUE_8408 requires a configuration with different timeouts for
+ * the vexpress platform */
+ kbdev->config_attributes = config_attributes_hw_issue_8408;
+ }
+#endif /* CONFIG_MALI_PLATFORM_FAKE */
+#endif /* CONFIG_MALI_PLATFORM_CONFIG_VEXPRESS */
+
+ return MALI_ERROR_NONE;
+
+free_reset_workq:
+ destroy_workqueue(kbdev->reset_workq);
+free_workqs:
+ while (i > 0)
+ {
+ i--;
+ destroy_workqueue(kbdev->as[i].pf_wq);
+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8316))
+ {
+ destroy_workqueue(kbdev->as[i].poke_wq);
+ }
+ }
+free_platform:
+ kbasep_platform_device_term(kbdev);
+fail:
+ return MALI_ERROR_FUNCTION_FAILED;
+}
+
+void kbase_device_term(kbase_device *kbdev)
+{
+ int i;
+
+ OSK_ASSERT(kbdev);
+#if KBASE_TRACE_ENABLE != 0
+ osk_debug_assert_register_hook( NULL, NULL );
+#endif
+
+ kbasep_trace_term( kbdev );
+ kbasep_list_trace_term( kbdev );
+
+ destroy_workqueue(kbdev->reset_workq);
+
+ for (i = 0; i < kbdev->nr_hw_address_spaces; i++)
+ {
+ destroy_workqueue(kbdev->as[i].pf_wq);
+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8316))
+ {
+ destroy_workqueue(kbdev->as[i].poke_wq);
+ }
+ }
+
+ kbasep_platform_device_term(kbdev);
+}
+
+void kbase_device_free(kbase_device *kbdev)
+{
+ kfree(kbdev);
+}
+
+void kbase_device_trace_buffer_install(kbase_context * kctx, u32 * tb, size_t size)
+{
+ unsigned long flags;
+ OSK_ASSERT(kctx);
+ OSK_ASSERT(tb);
+
+ /* set up the header */
+ /* magic number in the first 4 bytes */
+ tb[0] = TRACE_BUFFER_HEADER_SPECIAL;
+ /* Store (write offset = 0, wrap counter = 0, transaction active = no)
+ * write offset 0 means never written.
+ * Offsets 1 to (wrap_offset - 1) used to store values when trace started
+ */
+ tb[1] = 0;
+
+ /* install trace buffer */
+ spin_lock_irqsave(&kctx->jctx.tb_lock, flags);
+ kctx->jctx.tb_wrap_offset = size / 8;
+ kctx->jctx.tb = tb;
+ spin_unlock_irqrestore(&kctx->jctx.tb_lock, flags);
+}
+
+void kbase_device_trace_buffer_uninstall(kbase_context * kctx)
+{
+ unsigned long flags;
+ OSK_ASSERT(kctx);
+ spin_lock_irqsave(&kctx->jctx.tb_lock, flags);
+ kctx->jctx.tb = NULL;
+ kctx->jctx.tb_wrap_offset = 0;
+ spin_unlock_irqrestore(&kctx->jctx.tb_lock, flags);
+}
+
+void kbase_device_trace_register_access(kbase_context * kctx, kbase_reg_access_type type, u16 reg_offset, u32 reg_value)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&kctx->jctx.tb_lock, flags);
+ if (kctx->jctx.tb)
+ {
+ u16 wrap_count;
+ u16 write_offset;
+ u32 * tb = kctx->jctx.tb;
+ u32 header_word;
+
+ header_word = tb[1];
+ OSK_ASSERT(0 == (header_word & 0x1));
+
+ wrap_count = (header_word >> 1) & 0x7FFF;
+ write_offset = (header_word >> 16) & 0xFFFF;
+
+ /* mark as transaction in progress */
+ tb[1] |= 0x1;
+ mb();
+
+ /* calculate new offset */
+ write_offset++;
+ if (write_offset == kctx->jctx.tb_wrap_offset)
+ {
+ /* wrap */
+ write_offset = 1;
+ wrap_count++;
+ wrap_count &= 0x7FFF; /* 15bit wrap counter */
+ }
+
+ /* store the trace entry at the selected offset */
+ tb[write_offset * 2 + 0] = (reg_offset & ~0x3) | ((type == REG_WRITE) ? 0x1 : 0x0);
+ tb[write_offset * 2 + 1] = reg_value;
+
+ mb();
+
+ /* new header word */
+ header_word = (write_offset << 16) | (wrap_count << 1) | 0x0; /* transaction complete */
+ tb[1] = header_word;
+ }
+ spin_unlock_irqrestore(&kctx->jctx.tb_lock, flags);
+}
+
+void kbase_reg_write(kbase_device *kbdev, u16 offset, u32 value, kbase_context * kctx)
+{
+ OSK_ASSERT(kbdev->pm.gpu_powered);
+ OSK_ASSERT(kctx==NULL || kctx->as_nr != KBASEP_AS_NR_INVALID);
+ OSK_PRINT_INFO(OSK_BASE_CORE, "w: reg %04x val %08x", offset, value);
+ kbase_os_reg_write(kbdev, offset, value);
+ if (kctx && kctx->jctx.tb) kbase_device_trace_register_access(kctx, REG_WRITE, offset, value);
+}
+KBASE_EXPORT_TEST_API(kbase_reg_write)
+
+u32 kbase_reg_read(kbase_device *kbdev, u16 offset, kbase_context * kctx)
+{
+ u32 val;
+ OSK_ASSERT(kbdev->pm.gpu_powered);
+ OSK_ASSERT(kctx==NULL || kctx->as_nr != KBASEP_AS_NR_INVALID);
+ val = kbase_os_reg_read(kbdev, offset);
+ OSK_PRINT_INFO(OSK_BASE_CORE, "r: reg %04x val %08x", offset, val);
+ if (kctx && kctx->jctx.tb) kbase_device_trace_register_access(kctx, REG_READ, offset, val);
+ return val;
+}
+KBASE_EXPORT_TEST_API(kbase_reg_read)
+
+void kbase_report_gpu_fault(kbase_device *kbdev, int multiple)
+{
+ u32 status;
+ u64 address;
+
+ status = kbase_reg_read(kbdev, GPU_CONTROL_REG(GPU_FAULTSTATUS), NULL);
+ address = (u64)kbase_reg_read(kbdev, GPU_CONTROL_REG(GPU_FAULTADDRESS_HI), NULL) << 32;
+ address |= kbase_reg_read(kbdev, GPU_CONTROL_REG(GPU_FAULTADDRESS_LO), NULL);
+
+ OSK_PRINT_WARN(OSK_BASE_CORE, "GPU Fault 0x08%x (%s) at 0x%016llx", status, kbase_exception_name(status), address);
+ if (multiple)
+ {
+ OSK_PRINT_WARN(OSK_BASE_CORE, "There were multiple GPU faults - some have not been reported\n");
+ }
+}
+
+void kbase_gpu_interrupt(kbase_device * kbdev, u32 val)
+{
+ KBASE_TRACE_ADD( kbdev, CORE_GPU_IRQ, NULL, NULL, 0u, val );
+ if (val & GPU_FAULT)
+ {
+ kbase_report_gpu_fault(kbdev, val & MULTIPLE_GPU_FAULTS);
+ }
+
+ if (val & RESET_COMPLETED)
+ {
+ kbase_pm_reset_done(kbdev);
+ }
+
+ if (val & PRFCNT_SAMPLE_COMPLETED)
+ {
+ kbase_instr_hwcnt_sample_done(kbdev);
+ }
+
+ if (val & CLEAN_CACHES_COMPLETED)
+ {
+ kbase_clean_caches_done(kbdev);
+ }
+
+ kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_IRQ_CLEAR), val, NULL);
+
+ /* kbase_pm_check_transitions must be called after the IRQ has been cleared. This is because it might trigger
+ * further power transitions and we don't want to miss the interrupt raised to notify us that these further
+ * transitions have finished.
+ */
+ if (val & POWER_CHANGED_ALL)
+ {
+ kbase_pm_check_transitions(kbdev);
+ }
+}
+
+
+/*
+ * Device trace functions
+ */
+#if KBASE_TRACE_ENABLE != 0
+
+STATIC mali_error kbasep_trace_init( kbase_device *kbdev )
+{
+ void *rbuf;
+
+ if(OSK_SIMULATE_FAILURE(OSK_OSK))
+ {
+ rbuf = NULL;
+ }
+ else
+ {
+ rbuf = kmalloc(sizeof(kbase_trace)*KBASE_TRACE_SIZE, GFP_KERNEL);
+ }
+
+ if (!rbuf)
+ return MALI_ERROR_FUNCTION_FAILED;
+
+ kbdev->trace_rbuf = rbuf;
+ spin_lock_init(&kbdev->trace_lock);
+ kbasep_trace_debugfs_init(kbdev);
+ return MALI_ERROR_NONE;
+}
+
+STATIC void kbasep_trace_term( kbase_device *kbdev )
+{
+ kfree( kbdev->trace_rbuf );
+}
+
+void kbasep_trace_format_msg(kbase_trace *trace_msg, char *buffer, int len)
+{
+ s32 written = 0;
+
+ /* Initial part of message */
+ written += MAX( osk_snprintf(buffer+written, MAX(len-written,0),
+ "%d.%.6d,%d,%d,%s,%p,",
+ trace_msg->timestamp.tv_sec,
+ trace_msg->timestamp.tv_nsec / 1000,
+ trace_msg->thread_id,
+ trace_msg->cpu,
+ kbasep_trace_code_string[trace_msg->code],
+ trace_msg->ctx), 0);
+
+
+ if (trace_msg->katom != NULL)
+ {
+ kbase_jd_atom *atom = trace_msg->katom;
+ int atom_number = atom - &atom->kctx->jctx.atoms[0];
+ written += MAX( osk_snprintf(buffer+written, MAX((int)len-written,0),
+ "atom %d (ud: 0x%llx 0x%llx)",
+ atom_number, atom->udata.blob[0], atom->udata.blob[1]), 0);
+ }
+
+ written += MAX( osk_snprintf(buffer+written, MAX((int)len-written,0),
+ ",%.8llx,",
+ trace_msg->gpu_addr ), 0 );
+ /* NOTE: Could add function callbacks to handle different message types */
+ if ( (trace_msg->flags & KBASE_TRACE_FLAG_JOBSLOT) != MALI_FALSE )
+ {
+ /* Jobslot present */
+ written += MAX( osk_snprintf(buffer+written, MAX((int)len-written,0),
+ "%d", trace_msg->jobslot), 0 );
+ }
+ written += MAX( osk_snprintf(buffer+written, MAX((int)len-written,0),
+ ","), 0 );
+
+ if ( (trace_msg->flags & KBASE_TRACE_FLAG_REFCOUNT) != MALI_FALSE )
+ {
+ /* Refcount present */
+ written += MAX( osk_snprintf(buffer+written, MAX((int)len-written,0),
+ "%d", trace_msg->refcount), 0 );
+ }
+ written += MAX( osk_snprintf(buffer+written, MAX((int)len-written,0),
+ ",", trace_msg->jobslot), 0 );
+
+ /* Rest of message */
+ written += MAX( osk_snprintf(buffer+written, MAX((int)len-written,0),
+ "0x%.8x", trace_msg->info_val), 0 );
+
+}
+
+void kbasep_trace_dump_msg( kbase_trace *trace_msg )
+{
+ char buffer[OSK_DEBUG_MESSAGE_SIZE];
+
+ kbasep_trace_format_msg(trace_msg, buffer, OSK_DEBUG_MESSAGE_SIZE);
+ OSK_PRINT( OSK_BASE_CORE, "%s", buffer );
+}
+
+void kbasep_trace_add(kbase_device *kbdev, kbase_trace_code code, void *ctx, kbase_jd_atom *katom, u64 gpu_addr,
+ u8 flags, int refcount, int jobslot, u32 info_val )
+{
+ unsigned long irqflags;
+ kbase_trace *trace_msg;
+
+ spin_lock_irqsave( &kbdev->trace_lock, irqflags);
+
+ trace_msg = &kbdev->trace_rbuf[kbdev->trace_next_in];
+
+ /* Fill the message */
+ osk_debug_get_thread_info( &trace_msg->thread_id, &trace_msg->cpu );
+
+ getnstimeofday(&trace_msg->timestamp);
+
+ trace_msg->code = code;
+ trace_msg->ctx = ctx;
+ trace_msg->katom = katom;
+ trace_msg->gpu_addr = gpu_addr;
+ trace_msg->jobslot = jobslot;
+ trace_msg->refcount = MIN((unsigned int)refcount, 0xFF) ;
+ trace_msg->info_val = info_val;
+ trace_msg->flags = flags;
+
+ /* Update the ringbuffer indices */
+ kbdev->trace_next_in = (kbdev->trace_next_in + 1) & KBASE_TRACE_MASK;
+ if ( kbdev->trace_next_in == kbdev->trace_first_out )
+ {
+ kbdev->trace_first_out = (kbdev->trace_first_out + 1) & KBASE_TRACE_MASK;
+ }
+
+ /* Done */
+
+ spin_unlock_irqrestore( &kbdev->trace_lock, irqflags);
+}
+
+void kbasep_trace_clear(kbase_device *kbdev)
+{
+ unsigned long flags;
+ spin_lock_irqsave( &kbdev->trace_lock, flags);
+ kbdev->trace_first_out = kbdev->trace_next_in;
+ spin_unlock_irqrestore( &kbdev->trace_lock, flags);
+}
+
+void kbasep_trace_dump(kbase_device *kbdev)
+{
+ unsigned long flags;
+ u32 start;
+ u32 end;
+
+
+ OSK_PRINT( OSK_BASE_CORE, "Dumping trace:\nsecs,nthread,cpu,code,ctx,katom,gpu_addr,jobslot,refcount,info_val");
+ spin_lock_irqsave( &kbdev->trace_lock, flags);
+ start = kbdev->trace_first_out;
+ end = kbdev->trace_next_in;
+
+ while (start != end)
+ {
+ kbase_trace *trace_msg = &kbdev->trace_rbuf[start];
+ kbasep_trace_dump_msg( trace_msg );
+
+ start = (start + 1) & KBASE_TRACE_MASK;
+ }
+ OSK_PRINT( OSK_BASE_CORE, "TRACE_END");
+
+ spin_unlock_irqrestore( &kbdev->trace_lock, flags);
+
+ KBASE_TRACE_CLEAR(kbdev);
+}
+
+STATIC void kbasep_trace_hook_wrapper( void *param )
+{
+ kbase_device *kbdev = (kbase_device*)param;
+ kbasep_trace_dump( kbdev );
+}
+
+#ifdef CONFIG_DEBUG_FS
+struct trace_seq_state {
+ kbase_trace trace_buf[KBASE_TRACE_SIZE];;
+ u32 start;
+ u32 end;
+};
+
+void *kbasep_trace_seq_start(struct seq_file *s, loff_t *pos)
+{
+ struct trace_seq_state *state = s->private;
+
+ if (*pos >= KBASE_TRACE_SIZE)
+ return NULL;
+
+ return state;
+}
+
+void kbasep_trace_seq_stop(struct seq_file *s, void *data)
+{
+}
+
+void *kbasep_trace_seq_next(struct seq_file *s, void *data, loff_t *pos)
+{
+ struct trace_seq_state *state = s->private;
+ int i = (state->start + *pos) & KBASE_TRACE_MASK;
+ if (i == state->end)
+ return NULL;
+
+ (*pos)++;
+
+ return &state->trace_buf[i];
+}
+
+int kbasep_trace_seq_show(struct seq_file *s, void *data)
+{
+ kbase_trace *trace_msg = data;
+ char buffer[OSK_DEBUG_MESSAGE_SIZE];
+
+ kbasep_trace_format_msg(trace_msg, buffer, OSK_DEBUG_MESSAGE_SIZE);
+ seq_printf(s, "%s\n", buffer);
+ return 0;
+}
+
+static const struct seq_operations kbasep_trace_seq_ops = {
+ .start = kbasep_trace_seq_start,
+ .next = kbasep_trace_seq_next,
+ .stop = kbasep_trace_seq_stop,
+ .show = kbasep_trace_seq_show,
+};
+
+static int kbasep_trace_debugfs_open(struct inode *inode, struct file *file)
+{
+ unsigned long flags;
+ kbase_device *kbdev = inode->i_private;
+ struct trace_seq_state *state;
+
+ state = __seq_open_private(file, &kbasep_trace_seq_ops, sizeof(*state));
+ if (!state)
+ return -ENOMEM;
+
+ spin_lock_irqsave(&kbdev->trace_lock, flags);
+ state->start = kbdev->trace_first_out;
+ state->end = kbdev->trace_next_in;
+ memcpy(state->trace_buf, kbdev->trace_rbuf, sizeof(state->trace_buf));
+ spin_unlock_irqrestore(&kbdev->trace_lock, flags);
+
+ return 0;
+}
+
+static const struct file_operations kbasep_trace_debugfs_fops = {
+ .open = kbasep_trace_debugfs_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release_private,
+};
+
+static void kbasep_trace_debugfs_init(kbase_device *kbdev)
+{
+ debugfs_create_file("mali_trace", S_IRUGO, NULL, kbdev,
+ &kbasep_trace_debugfs_fops);
+}
+#else
+static void kbasep_trace_debugfs_init(kbase_device *kbdev)
+{
+
+}
+#endif /* CONFIG_DEBUG_FS */
+
+#else /* KBASE_TRACE_ENABLE != 0 */
+STATIC mali_error kbasep_trace_init( kbase_device *kbdev )
+{
+ CSTD_UNUSED(kbdev);
+ return MALI_ERROR_NONE;
+}
+
+STATIC void kbasep_trace_term( kbase_device *kbdev )
+{
+ CSTD_UNUSED(kbdev);
+}
+
+STATIC void kbasep_trace_hook_wrapper( void *param )
+{
+ CSTD_UNUSED(param);
+}
+
+void kbasep_trace_add(kbase_device *kbdev, kbase_trace_code code, void *ctx, kbase_jd_atom *katom, u64 gpu_addr,
+ u8 flags, int refcount, int jobslot, u32 info_val )
+{
+ CSTD_UNUSED(kbdev);
+ CSTD_UNUSED(code);
+ CSTD_UNUSED(ctx);
+ CSTD_UNUSED(katom);
+ CSTD_UNUSED(gpu_addr);
+ CSTD_UNUSED(flags);
+ CSTD_UNUSED(refcount);
+ CSTD_UNUSED(jobslot);
+ CSTD_UNUSED(info_val);
+}
+
+void kbasep_trace_clear(kbase_device *kbdev)
+{
+ CSTD_UNUSED(kbdev);
+}
+
+void kbasep_trace_dump(kbase_device *kbdev)
+{
+ CSTD_UNUSED(kbdev);
+}
+#endif /* KBASE_TRACE_ENABLE != 0 */
+
+#if KBASE_LIST_TRACE_ENABLE != 0
+
+STATIC mali_error kbasep_list_trace_init(kbase_device *kbdev)
+{
+ void *rbuf;
+
+ if(OSK_SIMULATE_FAILURE(OSK_OSK))
+ {
+ rbuf = NULL;
+ }
+ else
+ {
+ rbuf = kmalloc(sizeof(kbase_list_trace)*KBASE_LIST_TRACE_SIZE, GFP_KERNEL);
+ }
+
+ if (!rbuf)
+ return MALI_ERROR_FUNCTION_FAILED;
+
+ kbdev->trace_lists_rbuf = rbuf;
+ kbdev->trace_lists_next_in = 0;
+ kbdev->trace_lists_first_out = 0;
+ spin_lock_init(&kbdev->trace_lists_lock);
+ return MALI_ERROR_NONE;
+}
+
+STATIC void kbasep_list_trace_term(kbase_device *kbdev)
+{
+ kfree( kbdev->trace_lists_rbuf );
+}
+
+void kbasep_list_trace_add(u8 tracepoint_id, kbase_device *kbdev, kbase_jd_atom *katom,
+ osk_dlist *list_id, mali_bool action, u8 list_type)
+{
+ kbase_list_trace *trace_entry;
+ unsigned long flags;
+
+ spin_lock_irqsave( &kbdev->trace_lists_lock, flags);
+ trace_entry = &kbdev->trace_lists_rbuf[kbdev->trace_lists_next_in];
+
+ getnstimeofday(&trace_entry->timestamp);
+ trace_entry->tracepoint_id = tracepoint_id;
+ trace_entry->katom = katom;
+ trace_entry->list_id = list_id;
+ trace_entry->action = action;
+ trace_entry->list_type = list_type;
+ kbdev->trace_lists_next_in = (kbdev->trace_lists_next_in + 1) % KBASE_LIST_TRACE_SIZE;
+ if ( kbdev->trace_lists_next_in == kbdev->trace_lists_first_out )
+ {
+ kbdev->trace_lists_first_out = (kbdev->trace_lists_first_out + 1) % KBASE_LIST_TRACE_SIZE;
+ }
+ spin_unlock_irqrestore( &kbdev->trace_lists_lock, flags);
+}
+
+void kbasep_list_trace_dump(kbase_device *kbdev)
+{
+ unsigned long flags;
+ u32 start;
+ u32 end;
+
+ printk(KERN_ERR "**********************************************");
+ printk(KERN_ERR "Dumping list trace:\n Timestamp(ns)\t| tracepoint_id\t| katom\t| list\t| action\t| list type");
+ spin_lock_irqsave( &kbdev->trace_lists_lock, flags);
+ start = kbdev->trace_lists_first_out;
+ end = kbdev->trace_lists_next_in;
+
+ while (start != end)
+ {
+ kbase_list_trace *trace_msg = &kbdev->trace_lists_rbuf[start];
+ char list_type[20];
+ char action[10];
+
+ switch(trace_msg->list_type) {
+ case KBASE_TRACE_LIST_DEP_HEAD_0:
+ strcpy(list_type, "dep_head[0]");
+ break;
+ case KBASE_TRACE_LIST_COMPLETED_JOBS:
+ strcpy(list_type, "completed_jobs");
+ break;
+ case KBASE_TRACE_LIST_RUNNABLE_JOBS:
+ strcpy(list_type, "runnable_jobs");
+ break;
+ case KBASE_TRACE_LIST_WAITING_SOFT_JOBS:
+ strcpy(list_type, "waiting_soft_jobs");
+ break;
+ case KBASE_TRACE_LIST_EVENT_LIST:
+ strcpy(list_type, "event_list");
+ break;
+ default:
+ strcpy(list_type, "undefined_list_type");
+ break;
+ }
+
+ switch(trace_msg->action) {
+ case KBASE_TRACE_LIST_ADD:
+ strcpy(action, "add");
+ break;
+ case KBASE_TRACE_LIST_DEL:
+ strcpy(action, "delete");
+ break;
+ default:
+ strcpy(action, "invalid");
+ break;
+ }
+
+ printk(KERN_ERR "| %d.%.6d\t| %u\t| %p\t| %p\t| %s\t| %s\t|", (int)trace_msg->timestamp.tv_sec,
+ (int)(trace_msg->timestamp.tv_nsec / 1000),
+ trace_msg->tracepoint_id,
+ trace_msg->katom,
+ trace_msg->list_id,
+ action,
+ list_type);
+
+ start = (start + 1) & KBASE_TRACE_MASK;
+ }
+ printk(KERN_ERR "************ list trace end *****************");
+
+ kbdev->trace_lists_first_out = kbdev->trace_lists_next_in;
+ spin_unlock_irqrestore( &kbdev->trace_lists_lock, flags);
+}
+
+
+
+#else /*KBASE_LIST_TRACE_ENABLE != 0*/
+
+STATIC mali_error kbasep_list_trace_init(kbase_device *kbdev)
+{
+ CSTD_UNUSED(kbdev);
+ return MALI_ERROR_NONE;
+}
+
+STATIC void kbasep_list_trace_term(kbase_device *kbdev)
+{
+ CSTD_UNUSED(kbdev);
+}
+
+void kbasep_list_trace_add(u8 tracepoint_id, kbase_device *kbdev, kbase_jd_atom *katom,
+ osk_dlist *list_id, mali_bool action, u8 list_type)
+{
+ CSTD_UNUSED(tracepoint_id);
+ CSTD_UNUSED(kbdev);
+ CSTD_UNUSED(katom);
+ CSTD_UNUSED(list_id);
+ CSTD_UNUSED(action);
+ CSTD_UNUSED(list_type);
+}
+
+void kbasep_list_trace_dump(kbase_device *kbdev)
+{
+ CSTD_UNUSED(kbdev);
+}
+#endif /*KBASE_LIST_TRACE_ENABLE != 0*/
+
+
+
diff --git a/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_event.c b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_event.c
new file mode 100644
index 0000000..808eac2
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_event.c
@@ -0,0 +1,183 @@
+/*
+ *
+ * (C) COPYRIGHT 2010-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+#include <kbase/src/common/mali_kbase.h>
+
+#define beenthere(f, a...) pr_debug("%s:" f, __func__, ##a)
+
+STATIC base_jd_udata kbase_event_process(kbase_context *kctx, kbase_jd_atom *katom)
+{
+ base_jd_udata data;
+
+ OSK_ASSERT(kctx != NULL);
+ OSK_ASSERT(katom != NULL);
+ OSK_ASSERT(katom->status == KBASE_JD_ATOM_STATE_COMPLETED);
+
+ data = katom->udata;
+
+ katom->status = KBASE_JD_ATOM_STATE_UNUSED;
+
+ wake_up(&katom->completed);
+
+ return data;
+}
+
+int kbase_event_pending(kbase_context *ctx)
+{
+ int ret;
+
+ OSK_ASSERT(ctx);
+
+ mutex_lock(&ctx->event_mutex);
+ ret = (MALI_FALSE == OSK_DLIST_IS_EMPTY(&ctx->event_list)) || (MALI_TRUE == ctx->event_closed);
+ mutex_unlock(&ctx->event_mutex);
+
+ return ret;
+}
+KBASE_EXPORT_TEST_API(kbase_event_pending)
+
+int kbase_event_dequeue(kbase_context *ctx, base_jd_event_v2 *uevent)
+{
+ kbase_jd_atom *atom;
+ kbase_jd_atom *trace_atom;
+ int err;
+
+ OSK_ASSERT(ctx);
+
+ mutex_lock(&ctx->event_mutex);
+
+ if (OSK_DLIST_IS_EMPTY(&ctx->event_list))
+ {
+ if (ctx->event_closed)
+ {
+ /* generate the BASE_JD_EVENT_DRV_TERMINATED message on the fly */
+ mutex_unlock(&ctx->event_mutex);
+ uevent->event_code = BASE_JD_EVENT_DRV_TERMINATED;
+ memset(&uevent->udata, 0, sizeof(uevent->udata));
+ beenthere("event system closed, returning BASE_JD_EVENT_DRV_TERMINATED(0x%X)\n", BASE_JD_EVENT_DRV_TERMINATED);
+ return 0;
+ }
+ else
+ {
+ mutex_unlock(&ctx->event_mutex);
+ return -1;
+ }
+ }
+
+ /* normal event processing */
+ trace_atom = OSK_DLIST_FRONT(&ctx->event_list, kbase_jd_atom, dep_item[0]);
+ kbasep_list_trace_add(0, ctx->kbdev, trace_atom, &ctx->event_list, KBASE_TRACE_LIST_DEL, KBASE_TRACE_LIST_EVENT_LIST);
+ atom = OSK_DLIST_POP_FRONT(&ctx->event_list, kbase_jd_atom, dep_item[0], err);
+ if (err) {
+ kbasep_list_trace_dump(ctx->kbdev);
+ BUG();
+ }
+
+ mutex_unlock(&ctx->event_mutex);
+
+ beenthere("event dequeuing %p\n", (void*)atom);
+ uevent->event_code = atom->event_code;
+ uevent->atom_number = (atom - ctx->jctx.atoms);
+ uevent->udata = kbase_event_process(ctx, atom);
+
+ return 0;
+}
+KBASE_EXPORT_TEST_API(kbase_event_dequeue)
+
+static void kbase_event_post_worker(osk_workq_work *data)
+{
+ kbase_jd_atom *atom = CONTAINER_OF(data, kbase_jd_atom, work);
+ kbase_context *ctx = atom->kctx;
+
+ if (atom->core_req & BASE_JD_REQ_EXTERNAL_RESOURCES)
+ {
+ kbase_jd_free_external_resources(atom);
+ }
+
+ if (atom->core_req & BASE_JD_REQ_EVENT_ONLY_ON_FAILURE)
+ {
+ if (atom->event_code == BASE_JD_EVENT_DONE)
+ {
+ /* Don't report the event */
+ kbase_event_process(ctx, atom);
+ return;
+ }
+ }
+
+ kbasep_list_trace_add(1, ctx->kbdev, atom, &ctx->event_list, KBASE_TRACE_LIST_ADD, KBASE_TRACE_LIST_EVENT_LIST);
+ mutex_lock(&ctx->event_mutex);
+ OSK_DLIST_PUSH_BACK(&ctx->event_list, atom, kbase_jd_atom, dep_item[0]);
+ mutex_unlock(&ctx->event_mutex);
+
+ kbase_event_wakeup(ctx);
+}
+
+void kbase_event_post(kbase_context *ctx, kbase_jd_atom *atom)
+{
+ OSK_ASSERT(ctx);
+ OSK_ASSERT(atom);
+
+ osk_workq_work_init(&atom->work, kbase_event_post_worker);
+ osk_workq_submit(&ctx->event_workq, &atom->work);
+}
+KBASE_EXPORT_TEST_API(kbase_event_post)
+
+void kbase_event_close(kbase_context * kctx)
+{
+ mutex_lock(&kctx->event_mutex);
+ kctx->event_closed = MALI_TRUE;
+ mutex_unlock(&kctx->event_mutex);
+ kbase_event_wakeup(kctx);
+}
+
+mali_error kbase_event_init(kbase_context *kctx)
+{
+ osk_error osk_err;
+
+ OSK_ASSERT(kctx);
+ OSK_DLIST_INIT(&kctx->event_list);
+ mutex_init(&kctx->event_mutex);
+ kctx->event_closed = MALI_FALSE;
+
+ osk_err = osk_workq_init(&kctx->event_workq, "kbase_event", OSK_WORKQ_RESCUER);
+ if (OSK_ERR_NONE != osk_err)
+ {
+ return MALI_ERROR_FUNCTION_FAILED;
+ }
+
+ return MALI_ERROR_NONE;
+}
+KBASE_EXPORT_TEST_API(kbase_event_init)
+
+void kbase_event_cleanup(kbase_context *kctx)
+{
+ OSK_ASSERT(kctx);
+
+ osk_workq_flush(&kctx->event_workq);
+ osk_workq_term(&kctx->event_workq);
+
+ /* We use kbase_event_dequeue to remove the remaining events as that
+ * deals with all the cleanup needed for the atoms.
+ *
+ * Note: use of kctx->event_list without a lock is safe because this must be the last
+ * thread using it (because we're about to terminate the lock)
+ */
+ while (!OSK_DLIST_IS_EMPTY(&kctx->event_list))
+ {
+ base_jd_event_v2 event;
+ kbase_event_dequeue(kctx, &event);
+ }
+}
+KBASE_EXPORT_TEST_API(kbase_event_cleanup)
+
diff --git a/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_gator.h b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_gator.h
new file mode 100644
index 0000000..2e8bec9
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_gator.h
@@ -0,0 +1,29 @@
+/*
+ *
+ * (C) COPYRIGHT 2011-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+#ifdef CONFIG_MALI_GATOR_SUPPORT
+#define GATOR_MAKE_EVENT(type,number) (((type) << 24) | ((number) << 16))
+#define GATOR_JOB_SLOT_START 1
+#define GATOR_JOB_SLOT_STOP 2
+#define GATOR_JOB_SLOT_SOFT_STOPPED 3
+void kbase_trace_mali_job_slots_event(u32 event, const kbase_context * kctx);
+void kbase_trace_mali_pm_status(u32 event, u64 value);
+void kbase_trace_mali_pm_power_off(u32 event, u64 value);
+void kbase_trace_mali_pm_power_on(u32 event, u64 value);
+void kbase_trace_mali_page_fault_insert_pages(int event, u32 value);
+void kbase_trace_mali_mmu_as_in_use(int event);
+void kbase_trace_mali_mmu_as_released(int event);
+void kbase_trace_mali_total_alloc_pages_change(long long int event);
+#endif
+
diff --git a/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_gpuprops.c b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_gpuprops.c
new file mode 100644
index 0000000..7b6965c
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_gpuprops.c
@@ -0,0 +1,302 @@
+/*
+ *
+ * (C) COPYRIGHT 2011-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_kbase_gpuprops.c
+ * Base kernel property query APIs
+ */
+
+#include <kbase/src/common/mali_kbase.h>
+#include <kbase/src/common/mali_midg_regmap.h>
+#include <kbase/src/common/mali_kbase_gpuprops.h>
+
+/**
+ * @brief Extracts bits from a 32-bit bitfield.
+ * @hideinitializer
+ *
+ * @param[in] value The value from which to extract bits.
+ * @param[in] offset The first bit to extract (0 being the LSB).
+ * @param[in] size The number of bits to extract.
+ * @return Bits [@a offset, @a offset + @a size) from @a value.
+ *
+ * @pre offset + size <= 32.
+ */
+/* from mali_cdsb.h */
+#define KBASE_UBFX32(value, offset, size) \
+ (((u32)(value) >> (u32)(offset)) & (u32)((1ULL << (u32)(size)) - 1))
+
+mali_error kbase_gpuprops_uk_get_props(kbase_context *kctx, kbase_uk_gpuprops * kbase_props)
+{
+ kbase_gpuprops_clock_speed_function get_gpu_speed_mhz;
+ u32 gpu_speed_mhz;
+ int rc = 1;
+
+ OSK_ASSERT(NULL != kctx);
+ OSK_ASSERT(NULL != kbase_props);
+
+ if (OSK_SIMULATE_FAILURE(OSK_BASE_CORE))
+ {
+ return MALI_ERROR_FUNCTION_FAILED;
+ }
+
+ /* Current GPU speed is requested from the system integrator via the KBASE_CONFIG_ATTR_GPU_SPEED_FUNC function.
+ * If that function fails, or the function is not provided by the system integrator, we report the maximum
+ * GPU speed as specified by KBASE_CONFIG_ATTR_GPU_FREQ_KHZ_MAX.
+ */
+ get_gpu_speed_mhz = (kbase_gpuprops_clock_speed_function)kbasep_get_config_value(kctx->kbdev, kctx->kbdev->config_attributes, KBASE_CONFIG_ATTR_GPU_SPEED_FUNC);
+ if (get_gpu_speed_mhz != NULL)
+ {
+ rc = get_gpu_speed_mhz(&gpu_speed_mhz);
+#ifdef CONFIG_MALI_DEBUG
+ /* Issue a warning message when the reported GPU speed falls outside the min/max range */
+ if (rc == 0)
+ {
+ u32 gpu_speed_khz = gpu_speed_mhz * 1000;
+ if (gpu_speed_khz < kctx->kbdev->gpu_props.props.core_props.gpu_freq_khz_min ||
+ gpu_speed_khz > kctx->kbdev->gpu_props.props.core_props.gpu_freq_khz_max)
+ {
+ OSK_PRINT_WARN(OSK_BASE_CORE, "GPU Speed is outside of min/max range (got %lu Khz, min %lu Khz, max %lu Khz)\n",
+ gpu_speed_khz,
+ kctx->kbdev->gpu_props.props.core_props.gpu_freq_khz_min,
+ kctx->kbdev->gpu_props.props.core_props.gpu_freq_khz_max);
+ }
+ }
+#endif /* CONFIG_MALI_DEBUG */
+ }
+ if (rc != 0)
+ {
+ gpu_speed_mhz = kctx->kbdev->gpu_props.props.core_props.gpu_freq_khz_max / 1000;
+ }
+
+ kctx->kbdev->gpu_props.props.core_props.gpu_speed_mhz = gpu_speed_mhz;
+
+ memcpy(&kbase_props->props, &kctx->kbdev->gpu_props.props, sizeof(kbase_props->props));
+
+ return MALI_ERROR_NONE;
+}
+
+STATIC void kbase_gpuprops_dump_registers(kbase_device * kbdev, kbase_gpuprops_regdump * regdump)
+{
+ int i;
+
+ OSK_ASSERT(NULL != kbdev);
+ OSK_ASSERT(NULL != regdump);
+
+ /* Fill regdump with the content of the relevant registers */
+ regdump->gpu_id = kbase_os_reg_read(kbdev, GPU_CONTROL_REG(GPU_ID));
+ regdump->l2_features = kbase_os_reg_read(kbdev, GPU_CONTROL_REG(L2_FEATURES));
+ regdump->l3_features = kbase_os_reg_read(kbdev, GPU_CONTROL_REG(L3_FEATURES));
+ regdump->tiler_features = kbase_os_reg_read(kbdev, GPU_CONTROL_REG(TILER_FEATURES));
+ regdump->mem_features = kbase_os_reg_read(kbdev, GPU_CONTROL_REG(MEM_FEATURES));
+ regdump->mmu_features = kbase_os_reg_read(kbdev, GPU_CONTROL_REG(MMU_FEATURES));
+ regdump->as_present = kbase_os_reg_read(kbdev, GPU_CONTROL_REG(AS_PRESENT));
+ regdump->js_present = kbase_os_reg_read(kbdev, GPU_CONTROL_REG(JS_PRESENT));
+
+ for(i = 0; i < MIDG_MAX_JOB_SLOTS; i++)
+ {
+ regdump->js_features[i] = kbase_os_reg_read(kbdev, GPU_CONTROL_REG(JS_FEATURES_REG(i)));
+ }
+
+ for(i = 0; i < BASE_GPU_NUM_TEXTURE_FEATURES_REGISTERS; i++)
+ {
+ regdump->texture_features[i] = kbase_os_reg_read(kbdev, GPU_CONTROL_REG(TEXTURE_FEATURES_REG(i)));
+ }
+
+ regdump->shader_present_lo = kbase_os_reg_read(kbdev, GPU_CONTROL_REG(SHADER_PRESENT_LO));
+ regdump->shader_present_hi = kbase_os_reg_read(kbdev, GPU_CONTROL_REG(SHADER_PRESENT_HI));
+
+ regdump->tiler_present_lo = kbase_os_reg_read(kbdev, GPU_CONTROL_REG(TILER_PRESENT_LO));
+ regdump->tiler_present_hi = kbase_os_reg_read(kbdev, GPU_CONTROL_REG(TILER_PRESENT_HI));
+
+ regdump->l2_present_lo = kbase_os_reg_read(kbdev, GPU_CONTROL_REG(L2_PRESENT_LO));
+ regdump->l2_present_hi = kbase_os_reg_read(kbdev, GPU_CONTROL_REG(L2_PRESENT_HI));
+
+ regdump->l3_present_lo = kbase_os_reg_read(kbdev, GPU_CONTROL_REG(L3_PRESENT_LO));
+ regdump->l3_present_hi = kbase_os_reg_read(kbdev, GPU_CONTROL_REG(L3_PRESENT_HI));
+}
+
+STATIC void kbase_gpuprops_construct_coherent_groups(base_gpu_props * const props)
+{
+ struct mali_base_gpu_coherent_group *current_group;
+ u64 group_present;
+ u64 group_mask;
+ u64 first_set, first_set_prev;
+ u32 num_groups = 0;
+
+ OSK_ASSERT(NULL != props);
+
+ props->coherency_info.coherency = props->raw_props.mem_features;
+ props->coherency_info.num_core_groups = osk_count_set_bits64(props->raw_props.l2_present);
+
+ if (props->coherency_info.coherency & GROUPS_L3_COHERENT)
+ {
+ /* Group is l3 coherent */
+ group_present = props->raw_props.l3_present;
+ }
+ else if (props->coherency_info.coherency & GROUPS_L2_COHERENT)
+ {
+ /* Group is l2 coherent */
+ group_present = props->raw_props.l2_present;
+ }
+ else
+ {
+ /* Group is l1 coherent */
+ group_present = props->raw_props.shader_present;
+ }
+
+ /*
+ * The coherent group mask can be computed from the l2/l3 present
+ * register.
+ *
+ * For the coherent group n:
+ * group_mask[n] = (first_set[n] - 1) & ~(first_set[n-1] - 1)
+ * where first_set is group_present with only its nth set-bit kept
+ * (i.e. the position from where a new group starts).
+ *
+ * For instance if the groups are l2 coherent and l2_present=0x0..01111:
+ * The first mask is:
+ * group_mask[1] = (first_set[1] - 1) & ~(first_set[0] - 1)
+ * = (0x0..010 - 1) & ~(0x0..01 - 1)
+ * = 0x0..00f
+ * The second mask is:
+ * group_mask[2] = (first_set[2] - 1) & ~(first_set[1] - 1)
+ * = (0x0..100 - 1) & ~(0x0..010 - 1)
+ * = 0x0..0f0
+ * And so on until all the bits from group_present have been cleared
+ * (i.e. there is no group left).
+ */
+
+ current_group = props->coherency_info.group;
+ first_set = group_present & ~(group_present - 1);
+
+ while (group_present != 0 && num_groups < BASE_MAX_COHERENT_GROUPS)
+ {
+ group_present -= first_set; /* Clear the current group bit */
+ first_set_prev = first_set;
+
+ first_set = group_present & ~(group_present - 1);
+ group_mask = (first_set - 1) & ~(first_set_prev - 1);
+
+ /* Populate the coherent_group structure for each group */
+ current_group->core_mask = group_mask & props->raw_props.shader_present;
+ current_group->num_cores = osk_count_set_bits64(current_group->core_mask);
+
+ num_groups++;
+ current_group++;
+ }
+
+ if (group_present != 0)
+ {
+ OSK_PRINT_WARN(OSK_BASE_CORE, "Too many coherent groups (keeping only %d groups).\n", BASE_MAX_COHERENT_GROUPS);
+ }
+
+ props->coherency_info.num_groups = num_groups;
+}
+
+/**
+ * @brief Get the GPU configuration
+ *
+ * Fill the base_gpu_props structure with values from the GPU configuration registers
+ *
+ * @param gpu_props The base_gpu_props structure
+ * @param kbdev The kbase_device structure for the device
+ */
+static void kbase_gpuprops_get_props(base_gpu_props * gpu_props, kbase_device * kbdev)
+{
+ kbase_gpuprops_regdump regdump;
+ int i;
+
+ OSK_ASSERT(NULL != kbdev);
+ OSK_ASSERT(NULL != gpu_props);
+
+ /* Dump relevant registers */
+ kbase_gpuprops_dump_registers(kbdev, ®dump);
+
+ /* Populate the base_gpu_props structure */
+ gpu_props->core_props.version_status = KBASE_UBFX32(regdump.gpu_id, 0U, 4);
+ gpu_props->core_props.minor_revision = KBASE_UBFX32(regdump.gpu_id, 4U, 8);
+ gpu_props->core_props.major_revision = KBASE_UBFX32(regdump.gpu_id, 12U, 4);
+ gpu_props->core_props.product_id = KBASE_UBFX32(regdump.gpu_id, 16U, 16);
+ gpu_props->core_props.log2_program_counter_size = KBASE_GPU_PC_SIZE_LOG2;
+ gpu_props->core_props.gpu_available_memory_size = totalram_pages << PAGE_SHIFT;
+
+ for(i = 0; i < BASE_GPU_NUM_TEXTURE_FEATURES_REGISTERS; i++)
+ {
+ gpu_props->core_props.texture_features[i] = regdump.texture_features[i];
+ }
+
+ gpu_props->l2_props.log2_line_size = KBASE_UBFX32(regdump.l2_features, 0U, 8);
+ gpu_props->l2_props.log2_cache_size = KBASE_UBFX32(regdump.l2_features, 16U, 8);
+
+ gpu_props->l3_props.log2_line_size = KBASE_UBFX32(regdump.l3_features, 0U, 8);
+ gpu_props->l3_props.log2_cache_size = KBASE_UBFX32(regdump.l3_features, 16U, 8);
+
+ gpu_props->tiler_props.bin_size_bytes = 1 << KBASE_UBFX32(regdump.tiler_features, 0U, 6);
+ gpu_props->tiler_props.max_active_levels = KBASE_UBFX32(regdump.tiler_features, 8U, 4);
+
+ gpu_props->raw_props.gpu_id = regdump.gpu_id;
+ gpu_props->raw_props.tiler_features = regdump.tiler_features;
+ gpu_props->raw_props.mem_features = regdump.mem_features;
+ gpu_props->raw_props.mmu_features = regdump.mmu_features;
+ gpu_props->raw_props.l2_features = regdump.l2_features;
+ gpu_props->raw_props.l3_features = regdump.l3_features;
+
+ gpu_props->raw_props.as_present = regdump.as_present;
+ gpu_props->raw_props.js_present = regdump.js_present;
+ gpu_props->raw_props.shader_present = ((u64)regdump.shader_present_hi << 32) + regdump.shader_present_lo;
+ gpu_props->raw_props.tiler_present = ((u64)regdump.tiler_present_hi << 32) + regdump.tiler_present_lo;
+ gpu_props->raw_props.l2_present = ((u64)regdump.l2_present_hi << 32) + regdump.l2_present_lo;
+ gpu_props->raw_props.l3_present = ((u64)regdump.l3_present_hi << 32) + regdump.l3_present_lo;
+
+ for(i = 0; i < MIDG_MAX_JOB_SLOTS; i++)
+ {
+ gpu_props->raw_props.js_features[i] = regdump.js_features[i];
+ }
+
+ /* Initialize the coherent_group structure for each group */
+ kbase_gpuprops_construct_coherent_groups(gpu_props);
+}
+
+void kbase_gpuprops_set(kbase_device *kbdev)
+{
+ kbase_gpu_props *gpu_props;
+ struct midg_raw_gpu_props *raw;
+
+ OSK_ASSERT(NULL != kbdev);
+ gpu_props = &kbdev->gpu_props;
+ raw = &gpu_props->props.raw_props;
+
+ /* Initialize the base_gpu_props structure */
+ kbase_gpuprops_get_props(&gpu_props->props, kbdev);
+
+ /* Populate kbase-only fields */
+ gpu_props->l2_props.associativity = KBASE_UBFX32(raw->l2_features, 8U, 8);
+ gpu_props->l2_props.external_bus_width = KBASE_UBFX32(raw->l2_features, 24U, 8);
+
+ gpu_props->l3_props.associativity = KBASE_UBFX32(raw->l3_features, 8U, 8);
+ gpu_props->l3_props.external_bus_width = KBASE_UBFX32(raw->l3_features, 24U, 8);
+
+ gpu_props->mem.core_group = KBASE_UBFX32(raw->mem_features, 0U, 1);
+ gpu_props->mem.supergroup = KBASE_UBFX32(raw->mem_features, 1U, 1);
+
+ gpu_props->mmu.va_bits = KBASE_UBFX32(raw->mmu_features, 0U, 8);
+ gpu_props->mmu.pa_bits = KBASE_UBFX32(raw->mmu_features, 8U, 8);
+
+ gpu_props->num_cores = osk_count_set_bits64(raw->shader_present);
+ gpu_props->num_core_groups = osk_count_set_bits64(raw->l2_present);
+ gpu_props->num_supergroups = osk_count_set_bits64(raw->l3_present);
+ gpu_props->num_address_spaces = osk_count_set_bits(raw->as_present);
+ gpu_props->num_job_slots = osk_count_set_bits(raw->js_present);
+}
+
diff --git a/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_gpuprops.h b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_gpuprops.h
new file mode 100644
index 0000000..7d25d23
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_gpuprops.h
@@ -0,0 +1,51 @@
+/*
+ *
+ * (C) COPYRIGHT 2011-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_kbase_gpuprops.h
+ * Base kernel property query APIs
+ */
+
+#ifndef _KBASE_GPUPROPS_H_
+#define _KBASE_GPUPROPS_H_
+
+#include "mali_kbase_gpuprops_types.h"
+
+/* Forward definition - see mali_kbase.h */
+struct kbase_device;
+
+/**
+ * @brief Set up Kbase GPU properties.
+ *
+ * Set up Kbase GPU properties with information from the GPU registers
+ *
+ * @param kbdev The kbase_device structure for the device
+ */
+void kbase_gpuprops_set(struct kbase_device *kbdev);
+
+/**
+ * @brief Provide GPU properties to userside through UKU call.
+ *
+ * Fill the kbase_uk_gpuprops with values from GPU configuration registers.
+ *
+ * @param kctx The kbase_context structure
+ * @param kbase_props A copy of the kbase_uk_gpuprops structure from userspace
+ *
+ * @return MALI_ERROR_NONE on success. Any other value indicates failure.
+ */
+mali_error kbase_gpuprops_uk_get_props(kbase_context *kctx, kbase_uk_gpuprops * kbase_props);
+
+
+#endif /* _KBASE_GPUPROPS_H_ */
+
diff --git a/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_gpuprops_types.h b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_gpuprops_types.h
new file mode 100644
index 0000000..b725ba3
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_gpuprops_types.h
@@ -0,0 +1,100 @@
+/*
+ *
+ * (C) COPYRIGHT 2011-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_kbase_gpuprops_types.h
+ * Base kernel property query APIs
+ */
+
+#ifndef _KBASE_GPUPROPS_TYPES_H_
+#define _KBASE_GPUPROPS_TYPES_H_
+
+#include <kbase/mali_base_kernel.h>
+
+#define KBASE_GPU_SPEED_MHZ 123
+#define KBASE_GPU_PC_SIZE_LOG2 16U
+
+typedef struct kbase_gpuprops_regdump
+{
+ u32 gpu_id;
+ u32 l2_features;
+ u32 l3_features;
+ u32 tiler_features;
+ u32 mem_features;
+ u32 mmu_features;
+ u32 as_present;
+ u32 js_present;
+
+ u32 js_features[MIDG_MAX_JOB_SLOTS];
+
+ u32 texture_features[BASE_GPU_NUM_TEXTURE_FEATURES_REGISTERS];
+
+ u32 shader_present_lo;
+ u32 shader_present_hi;
+
+ u32 tiler_present_lo;
+ u32 tiler_present_hi;
+
+ u32 l2_present_lo;
+ u32 l2_present_hi;
+
+ u32 l3_present_lo;
+ u32 l3_present_hi;
+}kbase_gpuprops_regdump;
+
+typedef struct kbase_gpu_cache_props
+{
+ u8 associativity;
+ u8 external_bus_width;
+}kbase_gpu_cache_props;
+
+typedef struct kbase_gpu_mem_props
+{
+ u8 core_group;
+ u8 supergroup;
+}kbase_gpu_mem_props;
+
+typedef struct kbase_gpu_mmu_props
+{
+ u8 va_bits;
+ u8 pa_bits;
+}kbase_gpu_mmu_props;
+
+typedef struct mali_kbase_gpu_props
+{
+ /* kernel-only properties */
+ u8 num_cores;
+ u8 num_core_groups;
+ u8 num_supergroups;
+ u8 num_address_spaces;
+ u8 num_job_slots;
+
+ kbase_gpu_cache_props l2_props;
+ kbase_gpu_cache_props l3_props;
+
+ kbase_gpu_mem_props mem;
+ kbase_gpu_mmu_props mmu;
+
+ /**
+ * Implementation specific irq throttle value (us), should be adjusted during integration.
+ */
+ int irq_throttle_time_us;
+
+ /* Properties shared with userspace */
+ base_gpu_props props;
+}kbase_gpu_props;
+
+
+
+#endif /* _KBASE_GPUPROPS_TYPES_H_ */
diff --git a/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_hw.c b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_hw.c
new file mode 100644
index 0000000..fe3a506
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_hw.c
@@ -0,0 +1,76 @@
+/*
+ *
+ * (C) COPYRIGHT 2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file
+ * Run-time work-arounds helpers
+ */
+
+#include <kbase/mali_base_hwconfig.h>
+#include <kbase/src/common/mali_midg_regmap.h>
+#include "mali_kbase.h"
+#include "mali_kbase_hw.h"
+
+mali_error kbase_hw_set_issues_mask(kbase_device *kbdev)
+{
+ const base_hw_issue *issues;
+ u32 gpu_id;
+
+ if (OSK_SIMULATE_FAILURE(OSK_BASE_CORE))
+ {
+ return MALI_ERROR_FUNCTION_FAILED;
+ }
+
+ gpu_id = kbase_os_reg_read(kbdev, GPU_CONTROL_REG(GPU_ID));
+
+ switch (gpu_id)
+ {
+ case GPU_ID_MAKE(GPU_ID_PI_T60X, 0, 0, GPU_ID_S_15DEV0):
+ issues = base_hw_issues_t60x_r0p0_15dev0;
+ break;
+ case GPU_ID_MAKE(GPU_ID_PI_T60X, 0, 0, GPU_ID_S_EAC):
+ issues = base_hw_issues_t60x_r0p0_eac;
+ break;
+ case GPU_ID_MAKE(GPU_ID_PI_T60X, 0, 1, 0):
+ issues = base_hw_issues_t60x_r0p1;
+ break;
+ case GPU_ID_MAKE(GPU_ID_PI_T65X, 0, 1, 0):
+ issues = base_hw_issues_t65x_r0p1;
+ break;
+ case GPU_ID_MAKE(GPU_ID_PI_T62X, 0, 0, 0):
+ case GPU_ID_MAKE(GPU_ID_PI_T62X, 0, 0, 1):
+ issues = base_hw_issues_t62x_r0p0;
+ break;
+ case GPU_ID_MAKE(GPU_ID_PI_T67X, 0, 0, 0):
+ case GPU_ID_MAKE(GPU_ID_PI_T67X, 0, 0, 1):
+ issues = base_hw_issues_t67x_r0p0;
+ break;
+ default:
+ OSK_PRINT_ERROR(OSK_BASE_CORE, "Unknown GPU ID %x", gpu_id);
+ return MALI_ERROR_FUNCTION_FAILED;
+ }
+
+ OSK_PRINT_INFO(OSK_BASE_CORE, "GPU identified as 0x%04x r%dp%d status %d",
+ (gpu_id & GPU_ID_VERSION_PRODUCT_ID) >> GPU_ID_VERSION_PRODUCT_ID_SHIFT,
+ (gpu_id & GPU_ID_VERSION_MAJOR) >> GPU_ID_VERSION_MAJOR_SHIFT,
+ (gpu_id & GPU_ID_VERSION_MINOR) >> GPU_ID_VERSION_MINOR_SHIFT,
+ (gpu_id & GPU_ID_VERSION_STATUS) >> GPU_ID_VERSION_STATUS_SHIFT);
+
+ for (; *issues != BASE_HW_ISSUE_END; issues++)
+ {
+ osk_bitarray_set_bit(*issues, &kbdev->hw_issues_mask[0]);
+ }
+
+ return MALI_ERROR_NONE;
+}
diff --git a/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_hw.h b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_hw.h
new file mode 100644
index 0000000..e5694ce
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_hw.h
@@ -0,0 +1,37 @@
+/*
+ *
+ * (C) COPYRIGHT 2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file
+ * Run-time work-arounds helpers
+ */
+
+#ifndef _KBASE_HW_H_
+#define _KBASE_HW_H_
+
+#include <osk/mali_osk.h>
+#include "mali_kbase_defs.h"
+
+/**
+ * @brief Tell whether a work-around should be enabled
+ */
+#define kbase_hw_has_issue(kbdev, issue)\
+ osk_bitarray_test_bit(issue, &(kbdev)->hw_issues_mask[0])
+
+/**
+ * @brief Set the HW issues mask depending on the GPU ID
+ */
+mali_error kbase_hw_set_issues_mask(kbase_device *kbdev);
+
+#endif /* _KBASE_HW_H_ */
diff --git a/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_instr.c b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_instr.c
new file mode 100644
index 0000000..e06d41d4
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_instr.c
@@ -0,0 +1,511 @@
+/*
+ *
+ * (C) COPYRIGHT 2011-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_kbase_instr.c
+ * Base kernel instrumentation APIs.
+ */
+
+#include <kbase/src/common/mali_kbase.h>
+#include <kbase/src/common/mali_midg_regmap.h>
+
+/**
+ * @brief Issue Cache Clean & Invalidate command to hardware
+ */
+static void kbasep_instr_hwcnt_cacheclean(kbase_device *kbdev)
+{
+ u32 irq_mask;
+
+ OSK_ASSERT(NULL != kbdev);
+
+ /* Enable interrupt */
+ irq_mask = kbase_reg_read(kbdev,GPU_CONTROL_REG(GPU_IRQ_MASK),NULL);
+ kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_IRQ_MASK), irq_mask | CLEAN_CACHES_COMPLETED, NULL);
+ /* clean&invalidate the caches so we're sure the mmu tables for the dump buffer is valid */
+ kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_COMMAND), GPU_COMMAND_CLEAN_INV_CACHES, NULL);
+}
+
+/**
+ * @brief Enable HW counters collection
+ *
+ * Note: will wait for a cache clean to complete
+ */
+mali_error kbase_instr_hwcnt_enable(kbase_context * kctx, kbase_uk_hwcnt_setup * setup)
+{
+ unsigned long flags;
+ mali_error err = MALI_ERROR_FUNCTION_FAILED;
+ kbasep_js_device_data *js_devdata;
+ mali_bool access_allowed;
+ u32 irq_mask;
+ kbase_device *kbdev;
+
+ OSK_ASSERT(NULL != kctx);
+ kbdev = kctx->kbdev;
+ OSK_ASSERT(NULL != kbdev);
+ OSK_ASSERT(NULL != setup);
+
+ js_devdata = &kbdev->js_data;
+ OSK_ASSERT(NULL != js_devdata);
+
+ /* Determine if the calling task has access to this capability */
+ access_allowed = kbase_security_has_capability(kctx, KBASE_SEC_INSTR_HW_COUNTERS_COLLECT, KBASE_SEC_FLAG_NOAUDIT);
+ if (MALI_FALSE == access_allowed)
+ {
+ goto out;
+ }
+
+ if ((setup->dump_buffer == 0ULL) ||
+ (setup->dump_buffer & (2048-1)))
+ {
+ /* alignment failure */
+ goto out;
+ }
+
+ /* Mark the context as active so the GPU is kept turned on */
+ kbase_pm_context_active(kbdev);
+
+ spin_lock_irqsave(&kbdev->hwcnt.lock, flags);
+
+ if (kbdev->hwcnt.state == KBASE_INSTR_STATE_RESETTING)
+ {
+ /* GPU is being reset*/
+ spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags);
+ wait_event(kbdev->hwcnt.wait, kbdev->hwcnt.triggered != 0);
+ spin_lock_irqsave(&kbdev->hwcnt.lock, flags);
+ }
+
+
+ if (kbdev->hwcnt.state != KBASE_INSTR_STATE_DISABLED)
+ {
+ /* Instrumentation is already enabled */
+ spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags);
+ kbase_pm_context_idle(kbdev);
+ goto out;
+ }
+
+ if ( MALI_ERROR_NONE != kbase_pm_request_cores(kbdev,
+ kbase_pm_get_present_cores(kbdev, KBASE_PM_CORE_SHADER ),
+ kbase_pm_get_present_cores(kbdev, KBASE_PM_CORE_TILER ) ) )
+ {
+ spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags);
+ kbase_pm_context_idle(kbdev);
+ goto out;
+ }
+
+ /* Enable interrupt */
+ irq_mask = kbase_reg_read(kbdev,GPU_CONTROL_REG(GPU_IRQ_MASK),NULL);
+ kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_IRQ_MASK), irq_mask | PRFCNT_SAMPLE_COMPLETED, NULL);
+
+ /* In use, this context is the owner */
+ kbdev->hwcnt.kctx = kctx;
+ /* Remember the dump address so we can reprogram it later */
+ kbdev->hwcnt.addr = setup->dump_buffer;
+
+ /* Precleaning so that state does not transition to IDLE */
+ kbdev->hwcnt.state = KBASE_INSTR_STATE_PRECLEANING;
+ kbdev->hwcnt.triggered = 0;
+
+ spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags);
+
+ /* Clean&invalidate the caches so we're sure the mmu tables for the dump buffer is valid */
+ kbasep_instr_hwcnt_cacheclean(kbdev);
+ /* Wait for cacheclean to complete */
+ wait_event(kbdev->hwcnt.wait, kbdev->hwcnt.triggered != 0);
+ OSK_ASSERT(kbdev->hwcnt.state == KBASE_INSTR_STATE_CLEANED);
+
+ /* Schedule the context in */
+ kbasep_js_schedule_privileged_ctx(kbdev, kctx);
+
+ /* Configure */
+ kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_BASE_LO), setup->dump_buffer & 0xFFFFFFFF, kctx);
+ kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_BASE_HI), setup->dump_buffer >> 32, kctx);
+ kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_JM_EN), setup->jm_bm, kctx);
+ kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_SHADER_EN), setup->shader_bm, kctx);
+ kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_L3_CACHE_EN), setup->l3_cache_bm, kctx);
+ kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_MMU_L2_EN), setup->mmu_l2_bm, kctx);
+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8186))
+ {
+ kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_TILER_EN), 0, kctx);
+ }
+
+ kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_CONFIG), (kctx->as_nr << PRFCNT_CONFIG_AS_SHIFT) | PRFCNT_CONFIG_MODE_MANUAL, kctx);
+ kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_TILER_EN), setup->tiler_bm, kctx);
+
+ spin_lock_irqsave(&kbdev->hwcnt.lock, flags);
+
+ if (kbdev->hwcnt.state == KBASE_INSTR_STATE_RESETTING)
+ {
+ /* GPU is being reset*/
+ spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags);
+ wait_event(kbdev->hwcnt.wait, kbdev->hwcnt.triggered != 0);
+ spin_lock_irqsave(&kbdev->hwcnt.lock, flags);
+ }
+
+ kbdev->hwcnt.state = KBASE_INSTR_STATE_IDLE;
+ kbdev->hwcnt.triggered = 1;
+ wake_up(&kbdev->hwcnt.wait);
+
+ spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags);
+
+ err = MALI_ERROR_NONE;
+
+ OSK_PRINT_INFO( OSK_BASE_CORE, "HW counters dumping set-up for context %p", kctx);
+
+out:
+ return err;
+}
+KBASE_EXPORT_SYMBOL(kbase_instr_hwcnt_enable)
+
+/**
+ * @brief Disable HW counters collection
+ *
+ * Note: might sleep, waiting for an ongoing dump to complete
+ */
+mali_error kbase_instr_hwcnt_disable(kbase_context * kctx)
+{
+ unsigned long flags;
+ mali_error err = MALI_ERROR_FUNCTION_FAILED;
+ u32 irq_mask;
+ kbase_device *kbdev;
+
+ OSK_ASSERT(NULL != kctx);
+ kbdev = kctx->kbdev;
+ OSK_ASSERT(NULL != kbdev);
+
+ while (1)
+ {
+ spin_lock_irqsave(&kbdev->hwcnt.lock, flags);
+
+ if (kbdev->hwcnt.state == KBASE_INSTR_STATE_DISABLED)
+ {
+ /* Instrumentation is not enabled */
+ spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags);
+ goto out;
+ }
+
+ if (kbdev->hwcnt.kctx != kctx)
+ {
+ /* Instrumentation has been setup for another context */
+ spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags);
+ goto out;
+ }
+
+ if (kbdev->hwcnt.state == KBASE_INSTR_STATE_IDLE)
+ {
+ break;
+ }
+
+ spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags);
+
+ /* Ongoing dump/setup - wait for its completion */
+ wait_event(kbdev->hwcnt.wait, kbdev->hwcnt.triggered != 0);
+
+
+ }
+
+ kbdev->hwcnt.state = KBASE_INSTR_STATE_DISABLED;
+ kbdev->hwcnt.triggered = 0;
+
+ /* Disable interrupt */
+ irq_mask = kbase_reg_read(kbdev,GPU_CONTROL_REG(GPU_IRQ_MASK),NULL);
+ kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_IRQ_MASK), irq_mask & ~PRFCNT_SAMPLE_COMPLETED, NULL);
+
+ /* Disable the counters */
+ kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_CONFIG), 0, kctx);
+
+ kbdev->hwcnt.kctx = NULL;
+ kbdev->hwcnt.addr = 0ULL;
+
+ kbase_pm_unrequest_cores(kbdev,
+ kbase_pm_get_present_cores(kbdev, KBASE_PM_CORE_SHADER ),
+ kbase_pm_get_present_cores(kbdev, KBASE_PM_CORE_TILER ) );
+
+ spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags);
+
+ /* Release the context, this implicitly (and indirectly) calls kbase_pm_context_idle */
+ kbasep_js_release_privileged_ctx(kbdev, kctx);
+
+ OSK_PRINT_INFO( OSK_BASE_CORE, "HW counters dumping disabled for context %p", kctx);
+
+ err = MALI_ERROR_NONE;
+
+out:
+ return err;
+}
+KBASE_EXPORT_SYMBOL(kbase_instr_hwcnt_disable)
+
+/**
+ * @brief Configure HW counters collection
+ */
+mali_error kbase_instr_hwcnt_setup(kbase_context * kctx, kbase_uk_hwcnt_setup * setup)
+{
+ mali_error err = MALI_ERROR_FUNCTION_FAILED;
+ kbase_device *kbdev;
+
+ OSK_ASSERT(NULL != kctx);
+
+ kbdev = kctx->kbdev;
+ OSK_ASSERT(NULL != kbdev);
+
+ if (NULL == setup)
+ {
+ /* Bad parameter - abort */
+ goto out;
+ }
+
+ if (setup->dump_buffer != 0ULL)
+ {
+ /* Enable HW counters */
+ err = kbase_instr_hwcnt_enable(kctx, setup);
+ }
+ else
+ {
+ /* Disable HW counters */
+ err = kbase_instr_hwcnt_disable(kctx);
+ }
+
+out:
+ return err;
+}
+
+/**
+ * @brief Issue Dump command to hardware
+ */
+mali_error kbase_instr_hwcnt_dump_irq(kbase_context * kctx)
+{
+ unsigned long flags;
+ mali_error err = MALI_ERROR_FUNCTION_FAILED;
+ kbase_device *kbdev;
+
+ OSK_ASSERT(NULL != kctx);
+ kbdev = kctx->kbdev;
+ OSK_ASSERT(NULL != kbdev);
+
+ spin_lock_irqsave(&kbdev->hwcnt.lock, flags);
+
+ OSK_ASSERT(kbdev->hwcnt.state != KBASE_INSTR_STATE_RESETTING);
+
+ if (kbdev->hwcnt.kctx != kctx)
+ {
+ /* The instrumentation has been setup for another context */
+ goto unlock;
+ }
+
+ if (kbdev->hwcnt.state != KBASE_INSTR_STATE_IDLE)
+ {
+ /* HW counters are disabled or another dump is ongoing */
+ goto unlock;
+ }
+
+ kbdev->hwcnt.triggered = 0;
+
+ /* Mark that we're dumping - the PF handler can signal that we faulted */
+ kbdev->hwcnt.state = KBASE_INSTR_STATE_DUMPING;
+
+ /* Reconfigure the dump address */
+ kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_BASE_LO), kbdev->hwcnt.addr & 0xFFFFFFFF, NULL);
+ kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_BASE_HI), kbdev->hwcnt.addr >> 32, NULL);
+
+ /* Start dumping */
+ kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_COMMAND), GPU_COMMAND_PRFCNT_SAMPLE, kctx);
+
+ OSK_PRINT_INFO( OSK_BASE_CORE, "HW counters dumping done for context %p", kctx);
+
+ err = MALI_ERROR_NONE;
+
+unlock:
+ spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags);
+ return err;
+}
+KBASE_EXPORT_SYMBOL(kbase_instr_hwcnt_dump_irq)
+
+/**
+ * @brief Tell whether the HW counters dump has completed
+ *
+ * Notes:
+ * - does not sleep
+ * - success will be set to MALI_TRUE if the dump succeeded or
+ * MALI_FALSE on failure
+ */
+mali_bool kbase_instr_hwcnt_dump_complete(kbase_context * kctx, mali_bool *success)
+{
+ unsigned long flags;
+ mali_bool complete = MALI_FALSE;
+ kbase_device *kbdev;
+
+ OSK_ASSERT(NULL != kctx);
+ kbdev = kctx->kbdev;
+ OSK_ASSERT(NULL != kbdev);
+ OSK_ASSERT(NULL != success);
+
+ spin_lock_irqsave(&kbdev->hwcnt.lock, flags);
+
+ if (kbdev->hwcnt.state == KBASE_INSTR_STATE_IDLE)
+ {
+ *success = MALI_TRUE;
+ complete = MALI_TRUE;
+ }
+ else if (kbdev->hwcnt.state == KBASE_INSTR_STATE_FAULT)
+ {
+ *success = MALI_FALSE;
+ complete = MALI_TRUE;
+ kbdev->hwcnt.state = KBASE_INSTR_STATE_IDLE;
+ }
+
+ spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags);
+
+ return complete;
+}
+KBASE_EXPORT_SYMBOL(kbase_instr_hwcnt_dump_complete)
+
+/**
+ * @brief Issue Dump command to hardware and wait for completion
+ */
+mali_error kbase_instr_hwcnt_dump(kbase_context * kctx)
+{
+ unsigned long flags;
+ mali_error err = MALI_ERROR_FUNCTION_FAILED;
+ kbase_device *kbdev;
+
+ OSK_ASSERT(NULL != kctx);
+ kbdev = kctx->kbdev;
+ OSK_ASSERT(NULL != kbdev);
+
+ err = kbase_instr_hwcnt_dump_irq(kctx);
+ if (MALI_ERROR_NONE != err)
+ {
+ /* Can't dump HW counters */
+ goto out;
+ }
+
+ /* Wait for dump & cacheclean to complete */
+ wait_event(kbdev->hwcnt.wait, kbdev->hwcnt.triggered != 0);
+
+ spin_lock_irqsave(&kbdev->hwcnt.lock, flags);
+
+ if (kbdev->hwcnt.state == KBASE_INSTR_STATE_RESETTING)
+ {
+ /* GPU is being reset*/
+ spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags);
+ wait_event(kbdev->hwcnt.wait, kbdev->hwcnt.triggered != 0);
+ spin_lock_irqsave(&kbdev->hwcnt.lock, flags);
+ }
+
+ if (kbdev->hwcnt.state == KBASE_INSTR_STATE_FAULT)
+ {
+ err = MALI_ERROR_FUNCTION_FAILED;
+ kbdev->hwcnt.state = KBASE_INSTR_STATE_IDLE;
+ }
+ else
+ {
+ /* Dump done */
+ OSK_ASSERT(kbdev->hwcnt.state == KBASE_INSTR_STATE_IDLE);
+ err = MALI_ERROR_NONE;
+ }
+
+ spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags);
+out:
+ return err;
+}
+KBASE_EXPORT_SYMBOL(kbase_instr_hwcnt_dump)
+
+/**
+ * @brief Clear the HW counters
+ */
+mali_error kbase_instr_hwcnt_clear(kbase_context * kctx)
+{
+ unsigned long flags;
+ mali_error err = MALI_ERROR_FUNCTION_FAILED;
+ kbase_device *kbdev;
+
+ OSK_ASSERT(NULL != kctx);
+ kbdev = kctx->kbdev;
+ OSK_ASSERT(NULL != kbdev);
+
+ spin_lock_irqsave(&kbdev->hwcnt.lock, flags);
+
+ if (kbdev->hwcnt.state == KBASE_INSTR_STATE_RESETTING)
+ {
+ /* GPU is being reset*/
+ spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags);
+ wait_event(kbdev->hwcnt.wait, kbdev->hwcnt.triggered != 0);
+ spin_lock_irqsave(&kbdev->hwcnt.lock, flags);
+ }
+
+ /* Check it's the context previously set up and we're not already dumping */
+ if (kbdev->hwcnt.kctx != kctx ||
+ kbdev->hwcnt.state != KBASE_INSTR_STATE_IDLE)
+ {
+ goto out;
+ }
+
+ /* Clear the counters */
+ kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_COMMAND), GPU_COMMAND_PRFCNT_CLEAR, kctx);
+
+ err = MALI_ERROR_NONE;
+
+out:
+ spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags);
+ return err;
+}
+KBASE_EXPORT_SYMBOL(kbase_instr_hwcnt_clear)
+
+/**
+ * @brief Dump complete interrupt received
+ */
+void kbase_instr_hwcnt_sample_done(kbase_device *kbdev)
+{
+ if (kbdev->hwcnt.state == KBASE_INSTR_STATE_FAULT)
+ {
+ kbdev->hwcnt.triggered = 1;
+ wake_up(&kbdev->hwcnt.wait);
+ }
+ else
+ {
+ /* Always clean and invalidate the cache after a successful dump */
+ kbdev->hwcnt.state = KBASE_INSTR_STATE_POSTCLEANING;
+ kbasep_instr_hwcnt_cacheclean(kbdev);
+ }
+}
+
+/**
+ * @brief Cache clean interrupt received
+ */
+void kbase_clean_caches_done(kbase_device *kbdev)
+{
+ u32 irq_mask;
+
+ if (kbdev->hwcnt.state != KBASE_INSTR_STATE_DISABLED)
+ {
+ /* Disable interrupt */
+ irq_mask = kbase_reg_read(kbdev,GPU_CONTROL_REG(GPU_IRQ_MASK),NULL);
+ kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_IRQ_MASK), irq_mask & ~CLEAN_CACHES_COMPLETED, NULL);
+
+ if (kbdev->hwcnt.state == KBASE_INSTR_STATE_PRECLEANING)
+ {
+ /* Don't return IDLE as we need kbase_instr_hwcnt_setup to continue rather than
+ allow access to another waiting thread */
+ kbdev->hwcnt.state = KBASE_INSTR_STATE_CLEANED;
+ }
+ else
+ {
+ /* All finished and idle */
+ kbdev->hwcnt.state = KBASE_INSTR_STATE_IDLE;
+ }
+
+ kbdev->hwcnt.triggered = 1;
+ wake_up(&kbdev->hwcnt.wait);
+
+ }
+}
diff --git a/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_jd.c b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_jd.c
new file mode 100644
index 0000000..eed02b4
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_jd.c
@@ -0,0 +1,1392 @@
+/*
+ *
+ * (C) COPYRIGHT 2010-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+#if defined(CONFIG_DMA_SHARED_BUFFER)
+#include <linux/dma-buf.h>
+#endif /* defined(CONFIG_DMA_SHARED_BUFFER)*/
+#ifdef CONFIG_COMPAT
+#include <linux/compat.h>
+#endif
+#include <kbase/src/common/mali_kbase.h>
+#include <kbase/src/common/mali_kbase_uku.h>
+#include <kbase/src/common/mali_kbase_js_affinity.h>
+#ifdef CONFIG_UMP
+#include <linux/ump.h>
+#endif /* CONFIG_UMP */
+
+#define beenthere(f, a...) OSK_PRINT_INFO(OSK_BASE_JD, "%s:" f, __func__, ##a)
+
+/*
+ * This is the kernel side of the API. Only entry points are:
+ * - kbase_jd_submit(): Called from userspace to submit a single bag
+ * - kbase_jd_done(): Called from interrupt context to track the
+ * completion of a job.
+ * Callouts:
+ * - to the job manager (enqueue a job)
+ * - to the event subsystem (signals the completion/failure of bag/job-chains).
+ */
+
+static void *get_compat_pointer(const kbase_pointer *p)
+{
+#ifdef CONFIG_COMPAT
+ if (is_compat_task())
+ {
+ return (void*)p->compat_value;
+ }
+ else
+#endif
+ {
+ return p->value;
+ }
+}
+
+/* Runs an atom, either by handing to the JS or by immediately running it in the case of soft-jobs
+ *
+ * Returns whether the JS needs a reschedule.
+ *
+ * Note that the caller must also check the atom status and
+ * if it is KBASE_JD_ATOM_STATE_COMPLETED must call jd_done_nolock
+ */
+static int jd_run_atom(kbase_jd_atom *katom)
+{
+ kbase_context *kctx = katom->kctx;
+ OSK_ASSERT(katom->status != KBASE_JD_ATOM_STATE_UNUSED);
+
+ if ((katom->core_req & BASEP_JD_REQ_ATOM_TYPE) == BASE_JD_REQ_DEP)
+ {
+ /* Dependency only atom */
+ katom->status = KBASE_JD_ATOM_STATE_COMPLETED;
+ return 0;
+ }
+ else if (katom->core_req & BASE_JD_REQ_SOFT_JOB)
+ {
+ /* Soft-job */
+ if (kbase_process_soft_job(katom) == 0)
+ {
+ kbase_finish_soft_job(katom);
+ katom->status = KBASE_JD_ATOM_STATE_COMPLETED;
+ }
+ else
+ {
+ /* The job has not completed */
+ kbasep_list_trace_add(2, kctx->kbdev, katom, &kctx->waiting_soft_jobs, KBASE_TRACE_LIST_ADD, KBASE_TRACE_LIST_WAITING_SOFT_JOBS);
+ OSK_DLIST_PUSH_BACK(&kctx->waiting_soft_jobs, katom,
+ kbase_jd_atom, dep_item[0]);
+ }
+ return 0;
+ }
+ katom->status = KBASE_JD_ATOM_STATE_IN_JS;
+ /* Queue an action about whether we should try scheduling a context */
+ return kbasep_js_add_job( kctx, katom );
+}
+
+#ifdef CONFIG_KDS
+static void kds_dep_clear(void * callback_parameter, void * callback_extra_parameter)
+{
+ kbase_jd_atom * katom;
+ kbase_jd_context * ctx;
+
+ katom = (kbase_jd_atom*)callback_parameter;
+ OSK_ASSERT(katom);
+ ctx = &katom->kctx->jctx;
+
+ mutex_lock(&ctx->lock);
+
+ if (katom->kds_dep_satisfied)
+ {
+ /* KDS resource has already been satisfied (e.g. due to zapping) */
+ goto out;
+ }
+
+ /* This atom's KDS dependency has now been met */
+ katom->kds_dep_satisfied = MALI_TRUE;
+
+ /* Check whether the atom's other dependencies were already met */
+ if (!katom->dep_atom[0] && !katom->dep_atom[1])
+ {
+ /* katom dep complete, run it */
+ mali_bool resched;
+
+ resched = jd_run_atom(katom);
+
+ if (katom->status == KBASE_JD_ATOM_STATE_COMPLETED)
+ {
+ /* The atom has already finished */
+ resched |= jd_done_nolock(katom);
+ }
+
+ if (resched)
+ {
+ kbasep_js_try_schedule_head_ctx(katom->kctx->kbdev);
+ }
+ }
+out:
+ mutex_unlock(&ctx->lock);
+}
+#endif /* CONFIG_KDS */
+
+#ifdef CONFIG_DMA_SHARED_BUFFER
+static mali_error kbase_jd_umm_map(kbase_context * kctx, struct kbase_va_region * reg)
+{
+ struct sg_table * st;
+ struct scatterlist * s;
+ int i;
+ osk_phy_addr * pa;
+ mali_error err;
+
+ OSK_ASSERT(NULL == reg->imported_metadata.umm.st);
+ st = dma_buf_map_attachment(reg->imported_metadata.umm.dma_attachment, DMA_BIDIRECTIONAL);
+
+ if (!st)
+ {
+ return MALI_ERROR_FUNCTION_FAILED;
+ }
+
+ /* save for later */
+ reg->imported_metadata.umm.st = st;
+
+ pa = kbase_get_phy_pages(reg);
+ OSK_ASSERT(pa);
+
+ for_each_sg(st->sgl, s, st->nents, i)
+ {
+ int j;
+ size_t pages = PFN_DOWN(sg_dma_len(s));
+
+ for (j = 0; j < pages; j++)
+ *pa++ = sg_dma_address(s) + (j << PAGE_SHIFT);
+ }
+
+ err = kbase_mmu_insert_pages(kctx, reg->start_pfn, kbase_get_phy_pages(reg), reg->nr_alloc_pages, reg->flags | KBASE_REG_GPU_WR | KBASE_REG_GPU_RD);
+
+ if (MALI_ERROR_NONE != err)
+ {
+ dma_buf_unmap_attachment(reg->imported_metadata.umm.dma_attachment, reg->imported_metadata.umm.st, DMA_BIDIRECTIONAL);
+ reg->imported_metadata.umm.st = NULL;
+ }
+
+ return err;
+}
+
+static void kbase_jd_umm_unmap(kbase_context * kctx, struct kbase_va_region * reg)
+{
+ OSK_ASSERT(kctx);
+ OSK_ASSERT(reg);
+ OSK_ASSERT(reg->imported_metadata.umm.dma_attachment);
+ OSK_ASSERT(reg->imported_metadata.umm.st);
+ kbase_mmu_teardown_pages(kctx, reg->start_pfn, reg->nr_alloc_pages);
+ dma_buf_unmap_attachment(reg->imported_metadata.umm.dma_attachment, reg->imported_metadata.umm.st, DMA_BIDIRECTIONAL);
+ reg->imported_metadata.umm.st = NULL;
+}
+#endif /* CONFIG_DMA_SHARED_BUFFER */
+
+void kbase_jd_free_external_resources(kbase_jd_atom *katom)
+{
+#ifdef CONFIG_KDS
+ if (katom->kds_rset)
+ {
+ kds_resource_set_release(&katom->kds_rset);
+ }
+#endif /* CONFIG_KDS */
+}
+
+static void kbase_jd_post_external_resources(kbase_jd_atom * katom)
+{
+ OSK_ASSERT(katom);
+ OSK_ASSERT(katom->core_req & BASE_JD_REQ_EXTERNAL_RESOURCES);
+
+#ifdef CONFIG_KDS
+ if (katom->kds_rset)
+ {
+ /* Prevent the KDS resource from triggering the atom in case of zapping */
+ katom->kds_dep_satisfied = MALI_TRUE;
+ }
+#endif /* CONFIG_KDS */
+
+#if defined(CONFIG_DMA_SHARED_BUFFER) || defined(CONFIG_MALI_DEBUG)
+ /* Lock also used in debug mode just for lock order checking */
+ kbase_gpu_vm_lock(katom->kctx);
+#endif /* defined(CONFIG_DMA_SHARED_BUFFER) || defined(CONFIG_MALI_DEBUG) */
+ /* only roll back if extres is non-NULL */
+ if (katom->extres)
+ {
+#ifdef CONFIG_DMA_SHARED_BUFFER
+ u32 res_no;
+ res_no = katom->nr_extres;
+ while (res_no-- > 0)
+ {
+ base_external_resource * res;
+ kbase_va_region * reg;
+
+ res = &katom->extres[res_no];
+ reg = kbase_region_tracker_find_region_enclosing_address(katom->kctx, res->ext_resource & ~BASE_EXT_RES_ACCESS_EXCLUSIVE);
+ /* if reg wasn't found then it has been freed while the job ran */
+ if (reg)
+ {
+ if (1 == reg->imported_metadata.umm.current_mapping_usage_count--)
+ {
+ /* last job using */
+ kbase_jd_umm_unmap(katom->kctx, reg);
+ }
+ }
+ }
+#endif /* CONFIG_DMA_SHARED_BUFFER */
+ kfree(katom->extres);
+ katom->extres = NULL;
+ }
+#if defined(CONFIG_DMA_SHARED_BUFFER) || defined(CONFIG_MALI_DEBUG)
+ /* Lock also used in debug mode just for lock order checking */
+ kbase_gpu_vm_unlock(katom->kctx);
+#endif /* defined(CONFIG_DMA_SHARED_BUFFER) || defined(CONFIG_MALI_DEBUG) */
+}
+
+#if defined(CONFIG_DMA_SHARED_BUFFER_USES_KDS) || defined(CONFIG_KDS)
+static void add_kds_resource(struct kds_resource *kds_res, struct kds_resource ** kds_resources, u32 *kds_res_count,
+ unsigned long * kds_access_bitmap, mali_bool exclusive)
+{
+ u32 i;
+
+ for(i = 0; i < *kds_res_count; i++)
+ {
+ if (kds_resources[i] == kds_res)
+ {
+ /* Duplicate resource, ignore */
+ return;
+ }
+ }
+
+ kds_resources[*kds_res_count] = kds_res;
+ if (exclusive)
+ osk_bitarray_set_bit(*kds_res_count, kds_access_bitmap);
+ (*kds_res_count)++;
+}
+#endif /* defined(CONFIG_DMA_SHARED_BUFFER_USES_KDS) || defined(CONFIG_KDS) */
+
+static mali_error kbase_jd_pre_external_resources(kbase_jd_atom * katom, const base_jd_atom_v2 *user_atom)
+{
+ mali_error err_ret_val = MALI_ERROR_FUNCTION_FAILED;
+ u32 res_no;
+#ifdef CONFIG_KDS
+ u32 kds_res_count = 0;
+ struct kds_resource ** kds_resources = NULL;
+ unsigned long * kds_access_bitmap = NULL;
+#endif /* CONFIG_KDS */
+
+ OSK_ASSERT(katom);
+ OSK_ASSERT(katom->core_req & BASE_JD_REQ_EXTERNAL_RESOURCES);
+
+ if (!katom->nr_extres)
+ {
+ /* no resources encoded, early out */
+ return MALI_ERROR_FUNCTION_FAILED;
+ }
+
+ katom->extres = kmalloc(sizeof(base_external_resource)*katom->nr_extres, GFP_KERNEL);
+ if (NULL == katom->extres)
+ {
+ err_ret_val = MALI_ERROR_OUT_OF_MEMORY;
+ goto early_err_out;
+ }
+
+ if (ukk_copy_from_user(sizeof(base_external_resource)*katom->nr_extres,
+ katom->extres,
+ get_compat_pointer(&user_atom->extres_list)) != MALI_ERROR_NONE)
+ {
+ err_ret_val = MALI_ERROR_FUNCTION_FAILED;
+ goto early_err_out;
+ }
+
+#ifdef CONFIG_KDS
+ /* assume we have to wait for all */
+ if(OSK_SIMULATE_FAILURE(OSK_OSK))
+ {
+ kds_resources = NULL;
+ }
+ else
+ {
+ OSK_ASSERT(0 != katom->nr_extres);
+ kds_resources = kmalloc(sizeof(struct kds_resource *) * katom->nr_extres, GFP_KERNEL);
+ }
+
+ if (NULL == kds_resources)
+ {
+ err_ret_val = MALI_ERROR_OUT_OF_MEMORY;
+ goto early_err_out;
+ }
+
+ if(OSK_SIMULATE_FAILURE(OSK_OSK))
+ {
+ kds_access_bitmap = NULL;
+ }
+ else
+ {
+ OSK_ASSERT(0 != katom->nr_extres);
+ kds_access_bitmap = kzalloc(sizeof(unsigned long) * ((katom->nr_extres + OSK_BITS_PER_LONG - 1) / OSK_BITS_PER_LONG), GFP_KERNEL);
+ }
+
+ if (NULL == kds_access_bitmap)
+ {
+ err_ret_val = MALI_ERROR_OUT_OF_MEMORY;
+ goto early_err_out;
+ }
+#endif /* CONFIG_KDS */
+
+#if defined(CONFIG_DMA_SHARED_BUFFER) || defined(CONFIG_MALI_DEBUG)
+ /* need to keep the GPU VM locked while we set up UMM buffers */
+ /* Lock also used in debug mode just for lock order checking */
+ kbase_gpu_vm_lock(katom->kctx);
+#endif /* defined(CONFIG_DMA_SHARED_BUFFER) || defined(CONFIG_MALI_DEBUG) */
+
+ for (res_no = 0; res_no < katom->nr_extres; res_no++)
+ {
+ base_external_resource * res;
+ kbase_va_region * reg;
+
+ res = &katom->extres[res_no];
+ reg = kbase_region_tracker_find_region_enclosing_address(katom->kctx, res->ext_resource & ~BASE_EXT_RES_ACCESS_EXCLUSIVE);
+ /* did we find a matching region object? */
+ if (NULL == reg)
+ {
+ /* roll back */
+ goto failed_loop;
+ }
+
+ /* decide what needs to happen for this resource */
+ switch (reg->imported_type)
+ {
+ case BASE_TMEM_IMPORT_TYPE_UMP:
+ {
+#if defined(CONFIG_KDS) && defined(CONFIG_UMP)
+ struct kds_resource * kds_res;
+ kds_res = ump_dd_kds_resource_get(reg->imported_metadata.ump_handle);
+ if (kds_res)
+ {
+ add_kds_resource(kds_res, kds_resources, &kds_res_count, kds_access_bitmap,
+ katom->extres[res_no].ext_resource & BASE_EXT_RES_ACCESS_EXCLUSIVE);
+ }
+#endif /*defined(CONFIG_KDS) && defined(CONFIG_UMP)*/
+ break;
+ }
+#ifdef CONFIG_DMA_SHARED_BUFFER
+ case BASE_TMEM_IMPORT_TYPE_UMM:
+ {
+#ifdef CONFIG_DMA_SHARED_BUFFER_USES_KDS
+ struct kds_resource *kds_res;
+ kds_res = get_dma_buf_kds_resource(reg->imported_metadata.umm.dma_buf);
+ if (kds_res)
+ {
+ add_kds_resource(kds_res, kds_resources, &kds_res_count, kds_access_bitmap,
+ katom->extres[res_no].ext_resource & BASE_EXT_RES_ACCESS_EXCLUSIVE);
+ }
+#endif
+ reg->imported_metadata.umm.current_mapping_usage_count++;
+ if (1 == reg->imported_metadata.umm.current_mapping_usage_count)
+ {
+ /* use a local variable to not pollute err_ret_val
+ * with a potential success value as some other gotos depend
+ * on the default error code stored in err_ret_val */
+ mali_error tmp;
+ tmp = kbase_jd_umm_map(katom->kctx, reg);
+ if (MALI_ERROR_NONE != tmp)
+ {
+ /* failed to map this buffer, roll back */
+ err_ret_val = tmp;
+ goto failed_loop;
+ }
+ }
+ break;
+ }
+#endif
+ default:
+ goto failed_loop;
+ }
+ }
+ /* successfully parsed the extres array */
+#if defined(CONFIG_DMA_SHARED_BUFFER) || defined(CONFIG_MALI_DEBUG)
+ /* drop the vm lock before we call into kds */
+ /* Lock also used in debug mode just for lock order checking */
+ kbase_gpu_vm_unlock(katom->kctx);
+#endif /* defined(CONFIG_DMA_SHARED_BUFFER) || defined(CONFIG_MALI_DEBUG) */
+
+#ifdef CONFIG_KDS
+ if (kds_res_count)
+ {
+ /* We have resources to wait for with kds */
+ katom->kds_dep_satisfied = MALI_FALSE;
+ if (kds_async_waitall(&katom->kds_rset, KDS_FLAG_LOCKED_IGNORE, &katom->kctx->jctx.kds_cb,
+ katom, NULL, kds_res_count, kds_access_bitmap, kds_resources))
+ {
+ goto failed_kds_setup;
+ }
+ }
+ else
+ {
+ /* Nothing to wait for, so kds dep met */
+ katom->kds_dep_satisfied = MALI_TRUE;
+ }
+ kfree(kds_resources);
+ kfree(kds_access_bitmap);
+#endif /* CONFIG_KDS */
+
+ /* all done OK */
+ return MALI_ERROR_NONE;
+
+
+/* error handling section */
+
+#ifdef CONFIG_KDS
+failed_kds_setup:
+
+#if defined(CONFIG_DMA_SHARED_BUFFER) || defined(CONFIG_MALI_DEBUG)
+ /* lock before we unmap */
+ /* Lock also used in debug mode just for lock order checking */
+ kbase_gpu_vm_lock(katom->kctx);
+#endif /* defined(CONFIG_DMA_SHARED_BUFFER) || defined(CONFIG_MALI_DEBUG) */
+#endif /* CONFIG_KDS */
+
+failed_loop:
+#ifdef CONFIG_DMA_SHARED_BUFFER
+ /* undo the loop work */
+ while (res_no-- > 0)
+ {
+ base_external_resource * res;
+ kbase_va_region * reg;
+
+ res = &katom->extres[res_no];
+ reg = kbase_region_tracker_find_region_enclosing_address(katom->kctx, res->ext_resource & ~BASE_EXT_RES_ACCESS_EXCLUSIVE);
+ /* if reg wasn't found then it has been freed when we set up kds */
+ if (reg)
+ {
+ reg->imported_metadata.umm.current_mapping_usage_count--;
+ if (0 == reg->imported_metadata.umm.current_mapping_usage_count)
+ {
+ kbase_jd_umm_unmap(katom->kctx, reg);
+ }
+ }
+ }
+#endif /* CONFIG_DMA_SHARED_BUFFER */
+#if defined(CONFIG_DMA_SHARED_BUFFER) || defined(CONFIG_MALI_DEBUG)
+ /* Lock also used in debug mode just for lock order checking */
+ kbase_gpu_vm_unlock(katom->kctx);
+#endif /* defined(CONFIG_DMA_SHARED_BUFFER) || defined(CONFIG_MALI_DEBUG) */
+
+early_err_out:
+ if (katom->extres)
+ {
+ kfree(katom->extres);
+ katom->extres = NULL;
+ }
+#ifdef CONFIG_KDS
+ if (kds_resources)
+ {
+ kfree(kds_resources);
+ }
+ if (kds_access_bitmap)
+ {
+ kfree(kds_access_bitmap);
+ }
+#endif /* CONFIG_KDS */
+ return err_ret_val;
+}
+
+STATIC INLINE void jd_resolve_dep(osk_dlist *out_list, kbase_jd_atom *katom, u8 d)
+{
+ u8 other_d = !d;
+
+ while (!OSK_DLIST_IS_EMPTY(&katom->dep_head[d]))
+ {
+ int err_1;
+ kbase_jd_atom *dep_atom;
+ kbase_jd_atom *trace_atom;
+
+ if (d == 0) {
+ trace_atom = OSK_DLIST_FRONT(&katom->dep_head[d], kbase_jd_atom, dep_item[d]);
+ kbasep_list_trace_add(3, trace_atom->kctx->kbdev, trace_atom, &katom->dep_head[d], KBASE_TRACE_LIST_DEL, KBASE_TRACE_LIST_DEP_HEAD_0);
+ }
+ dep_atom = OSK_DLIST_POP_FRONT(&katom->dep_head[d], kbase_jd_atom, dep_item[d], err_1);
+ if (err_1 && (d == 0)) {
+ kbasep_list_trace_dump(trace_atom->kctx->kbdev);
+ BUG();
+ }
+
+ dep_atom->dep_atom[d] = NULL;
+
+ if (katom->event_code != BASE_JD_EVENT_DONE)
+ {
+ /* Atom failed, so remove the other dependencies and immediately fail the atom */
+ if (dep_atom->dep_atom[other_d])
+ {
+ int err;
+ if (other_d == 0)
+ kbasep_list_trace_add(4, dep_atom->kctx->kbdev, dep_atom, &dep_atom->dep_atom[other_d]->dep_head[other_d], KBASE_TRACE_LIST_DEL, KBASE_TRACE_LIST_DEP_HEAD_0);
+ OSK_DLIST_REMOVE(&dep_atom->dep_atom[other_d]->dep_head[other_d], dep_atom, dep_item[other_d], err);
+ if (err) {
+ kbasep_list_trace_dump(dep_atom->kctx->kbdev);
+ BUG();
+ }
+ dep_atom->dep_atom[other_d] = NULL;
+ }
+
+#ifdef CONFIG_KDS
+ if (!dep_atom->kds_dep_satisfied)
+ {
+ /* Just set kds_dep_satisfied to true. If the callback happens after this then it will early out and
+ * do nothing. If the callback doesn't happen then kbase_jd_post_external_resources will clean up
+ */
+ dep_atom->kds_dep_satisfied = MALI_TRUE;
+ }
+#endif
+
+ dep_atom->event_code = katom->event_code;
+ OSK_ASSERT(dep_atom->status != KBASE_JD_ATOM_STATE_UNUSED);
+ dep_atom->status = KBASE_JD_ATOM_STATE_COMPLETED;
+
+ kbasep_list_trace_add(5, dep_atom->kctx->kbdev, dep_atom, out_list, KBASE_TRACE_LIST_ADD, KBASE_TRACE_LIST_RUNNABLE_JOBS);
+ OSK_DLIST_PUSH_FRONT(out_list, dep_atom, kbase_jd_atom, dep_item[0]);
+ }
+ else if (!dep_atom->dep_atom[other_d])
+ {
+#ifdef CONFIG_KDS
+ if (dep_atom->kds_dep_satisfied)
+#endif
+ {
+ kbasep_list_trace_add(6, dep_atom->kctx->kbdev, dep_atom, out_list, KBASE_TRACE_LIST_ADD, KBASE_TRACE_LIST_RUNNABLE_JOBS);
+ OSK_DLIST_PUSH_FRONT(out_list, dep_atom, kbase_jd_atom, dep_item[0]);
+ }
+ }
+ }
+}
+KBASE_EXPORT_TEST_API(jd_resolve_dep)
+
+/*
+ * Perform the necessary handling of an atom that has finished running
+ * on the GPU.
+ *
+ * Note that if this is a soft-job that has had kbase_prepare_soft_job called on it then the caller
+ * is responsible for calling kbase_finish_soft_job *before* calling this function.
+ *
+ * The caller must hold the kbase_jd_context.lock.
+ */
+mali_bool jd_done_nolock(kbase_jd_atom *katom)
+{
+ struct kbase_context *kctx = katom->kctx;
+ osk_dlist completed_jobs;
+ osk_dlist runnable_jobs;
+ mali_bool need_to_try_schedule_context = MALI_FALSE;
+ int i;
+
+ OSK_DLIST_INIT(&completed_jobs);
+ OSK_DLIST_INIT(&runnable_jobs);
+
+ OSK_ASSERT(katom->status != KBASE_JD_ATOM_STATE_UNUSED);
+
+ /* This is needed in case an atom is failed due to being invalid, this
+ * can happen *before* the jobs that the atom depends on have completed */
+ for(i = 0; i < 2; i++)
+ {
+ if (katom->dep_atom[i]) {
+ int err;
+ if (i == 0)
+ kbasep_list_trace_add(7, katom->kctx->kbdev, katom, &katom->dep_atom[i]->dep_head[i], KBASE_TRACE_LIST_DEL, KBASE_TRACE_LIST_DEP_HEAD_0);
+ OSK_DLIST_REMOVE(&katom->dep_atom[i]->dep_head[i], katom, dep_item[i], err);
+ if (err) {
+ kbasep_list_trace_dump(katom->kctx->kbdev);
+ BUG();
+ }
+ katom->dep_atom[i] = NULL;
+ }
+ }
+
+ katom->status = KBASE_JD_ATOM_STATE_COMPLETED;
+ kbasep_list_trace_add(8, katom->kctx->kbdev, katom, &completed_jobs, KBASE_TRACE_LIST_ADD, KBASE_TRACE_LIST_COMPLETED_JOBS);
+ OSK_DLIST_PUSH_BACK(&completed_jobs, katom, kbase_jd_atom, dep_item[0]);
+
+ while(!OSK_DLIST_IS_EMPTY(&completed_jobs))
+ {
+ int err;
+ kbase_jd_atom *katom_aux = OSK_DLIST_BACK(&completed_jobs, kbase_jd_atom, dep_item[0]);
+ kbasep_list_trace_add(9, katom_aux->kctx->kbdev, katom_aux, &completed_jobs, KBASE_TRACE_LIST_DEL, KBASE_TRACE_LIST_COMPLETED_JOBS);
+ katom = OSK_DLIST_POP_BACK(&completed_jobs, kbase_jd_atom, dep_item[0], err);
+ if (err) {
+ kbasep_list_trace_dump(katom->kctx->kbdev);
+ BUG();
+ }
+ OSK_ASSERT(katom->status == KBASE_JD_ATOM_STATE_COMPLETED);
+
+ for(i = 0; i < 2; i++)
+ {
+ jd_resolve_dep(&runnable_jobs, katom, i);
+ }
+
+ while (!OSK_DLIST_IS_EMPTY(&runnable_jobs))
+ {
+ int err;
+ kbase_jd_atom *node;
+ kbase_jd_atom *katom_aux = OSK_DLIST_BACK(&runnable_jobs, kbase_jd_atom, dep_item[0]);
+ kbasep_list_trace_add(10, katom_aux->kctx->kbdev, katom_aux, &runnable_jobs, KBASE_TRACE_LIST_DEL, KBASE_TRACE_LIST_RUNNABLE_JOBS);
+ node = OSK_DLIST_POP_BACK(&runnable_jobs, kbase_jd_atom, dep_item[0], err);
+ if (err) {
+ kbasep_list_trace_dump(node->kctx->kbdev);
+ BUG();
+ }
+ OSK_ASSERT(node->status != KBASE_JD_ATOM_STATE_UNUSED);
+
+ if (katom->event_code == BASE_JD_EVENT_DONE)
+ {
+ need_to_try_schedule_context |= jd_run_atom(node);
+ }
+ else
+ {
+ node->event_code = katom->event_code;
+ node->status = KBASE_JD_ATOM_STATE_COMPLETED;
+
+ if (node->core_req & BASE_JD_REQ_SOFT_JOB)
+ {
+ kbase_finish_soft_job(node);
+ }
+ }
+
+ if (node->status == KBASE_JD_ATOM_STATE_COMPLETED)
+ {
+ kbasep_list_trace_add(11, node->kctx->kbdev, node, &completed_jobs, KBASE_TRACE_LIST_ADD, KBASE_TRACE_LIST_COMPLETED_JOBS);
+ OSK_DLIST_PUSH_BACK(&completed_jobs, node, kbase_jd_atom, dep_item[0]);
+ }
+ }
+
+ if (katom->core_req & BASE_JD_REQ_EXTERNAL_RESOURCES)
+ {
+ kbase_jd_post_external_resources(katom);
+ }
+
+ kbase_event_post(kctx, katom);
+
+ /* Decrement and check the TOTAL number of jobs. This includes
+ * those not tracked by the scheduler: 'not ready to run' and
+ * 'dependency-only' jobs. */
+ if (--kctx->jctx.job_nr == 0)
+ {
+ /* All events are safely queued now, and we can signal any waiter
+ * that we've got no more jobs (so we can be safely terminated) */
+ wake_up(&kctx->jctx.zero_jobs_wait);
+ }
+ }
+
+ return need_to_try_schedule_context;
+}
+KBASE_EXPORT_TEST_API(jd_done_nolock)
+
+static mali_bool jd_submit_atom(kbase_context *kctx, const base_jd_atom_v2 *user_atom)
+{
+ kbase_jd_context *jctx = &kctx->jctx;
+ kbase_jd_atom *katom;
+ base_jd_core_req core_req;
+ base_atom_id atom_number = user_atom->atom_number;
+ int queued = 0;
+ int i;
+ mali_bool ret;
+
+ katom = &jctx->atoms[atom_number];
+
+ mutex_lock(&jctx->lock);
+ while (katom->status != KBASE_JD_ATOM_STATE_UNUSED)
+ {
+ /* Atom number is already in use, wait for the atom to complete */
+ mutex_unlock(&jctx->lock);
+ if (wait_event_killable(katom->completed, katom->status == KBASE_JD_ATOM_STATE_UNUSED))
+ {
+ /* We're being killed so the result code doesn't really matter */
+ return MALI_FALSE;
+ }
+ mutex_lock(&jctx->lock);
+ }
+
+ /* Update the TOTAL number of jobs. This includes those not tracked by
+ * the scheduler: 'not ready to run' and 'dependency-only' jobs. */
+ jctx->job_nr++;
+
+ core_req = user_atom->core_req;
+
+ if (kbase_hw_has_issue(kctx->kbdev, BASE_HW_ISSUE_8987))
+ {
+ /* For this HW workaround, we scheduled differently on the 'ONLY_COMPUTE'
+ * flag, at the expense of ignoring the NSS flag.
+ *
+ * NOTE: We could allow the NSS flag still (and just ensure that we still
+ * submit on slot 2 when the NSS flag is set), but we don't because:
+ * - If we only have NSS contexts, the NSS jobs get all the cores, delaying
+ * a non-NSS context from getting cores for a long time.
+ * - A single compute context won't be subject to any timers anyway -
+ * only when there are >1 contexts (GLES *or* CL) will it get subject to
+ * timers.
+ */
+ core_req &= ~((base_jd_core_req)BASE_JD_REQ_NSS);
+ }
+
+ katom->udata = user_atom->udata;
+ katom->kctx = kctx;
+ katom->nr_extres = user_atom->nr_extres;
+ katom->extres = NULL;
+ katom->device_nr = user_atom->device_nr;
+ katom->affinity = 0;
+ katom->jc = user_atom->jc;
+ katom->coreref_state= KBASE_ATOM_COREREF_STATE_NO_CORES_REQUESTED;
+ katom->core_req = core_req;
+ katom->nice_prio = user_atom->prio;
+#ifdef CONFIG_KDS
+ /* Start by assuming that the KDS dependencies are satisfied,
+ * kbase_jd_pre_external_resources will correct this if there are dependencies */
+ katom->kds_dep_satisfied = MALI_TRUE;
+ katom->kds_rset = NULL;
+#endif /* CONFIG_KDS */
+
+ /* Add dependencies */
+ for(i = 0; i < 2; i++)
+ {
+ int dep_atom_number = user_atom->pre_dep[i];
+ katom->dep_atom[i] = NULL;
+ if (dep_atom_number)
+ {
+ kbase_jd_atom *dep_atom = &jctx->atoms[dep_atom_number];
+
+ if (dep_atom->status == KBASE_JD_ATOM_STATE_UNUSED ||
+ dep_atom->status == KBASE_JD_ATOM_STATE_COMPLETED)
+ {
+ if (dep_atom->event_code != BASE_JD_EVENT_DONE)
+ {
+ if (i == 1 && katom->dep_atom[0])
+ {
+ int err;
+ /* Remove the previous dependency */
+ kbasep_list_trace_add(12, katom->kctx->kbdev, katom, &katom->dep_atom[0]->dep_head[0], KBASE_TRACE_LIST_DEL, KBASE_TRACE_LIST_DEP_HEAD_0);
+ OSK_DLIST_REMOVE(&katom->dep_atom[0]->dep_head[0], katom, dep_item[0], err);
+ if (err) {
+ kbasep_list_trace_dump(katom->kctx->kbdev);
+ BUG();
+ }
+ katom->dep_atom[0] = NULL;
+ }
+ /* Atom has completed, propagate the error code if any */
+ katom->event_code = dep_atom->event_code;
+ katom->status = KBASE_JD_ATOM_STATE_QUEUED;
+ ret = jd_done_nolock(katom);
+ goto out;
+ }
+ }
+ else
+ {
+ /* Atom is in progress, add this atom to the list */
+ if (i == 0)
+ kbasep_list_trace_add(13, katom->kctx->kbdev, katom, &dep_atom->dep_head[i], KBASE_TRACE_LIST_ADD, KBASE_TRACE_LIST_DEP_HEAD_0);
+ OSK_DLIST_PUSH_BACK(&dep_atom->dep_head[i], katom, kbase_jd_atom, dep_item[i]);
+ katom->dep_atom[i] = dep_atom;
+ queued = 1;
+ }
+ }
+ }
+
+ /* These must occur after the above loop to ensure that an atom that
+ * depends on a previous atom with the same number behaves as expected */
+ katom->event_code = BASE_JD_EVENT_DONE;
+ katom->status = KBASE_JD_ATOM_STATE_QUEUED;
+
+ /*
+ * If the priority is increased we need to check the caller has security caps to do this, if
+ * priority is decreased then this is ok as the result will have no negative impact on other
+ * processes running.
+ */
+ if( 0 > katom->nice_prio)
+ {
+ mali_bool access_allowed;
+ access_allowed = kbase_security_has_capability(kctx, KBASE_SEC_MODIFY_PRIORITY, KBASE_SEC_FLAG_NOAUDIT);
+ if(!access_allowed)
+ {
+ /* For unprivileged processes - a negative priority is interpreted as zero */
+ katom->nice_prio = 0;
+ }
+ }
+
+ /* Scale priority range to use NICE range */
+ if(katom->nice_prio)
+ {
+ /* Remove sign for calculation */
+ int nice_priority = katom->nice_prio+128;
+ /* Fixed point maths to scale from ..255 to 0..39 (NICE range with +20 offset) */
+ katom->nice_prio = (((20<<16)/128)*nice_priority)>>16;
+ }
+
+ if (katom->core_req & BASE_JD_REQ_EXTERNAL_RESOURCES)
+ {
+ /* handle what we need to do to access the external resources */
+ if (MALI_ERROR_NONE != kbase_jd_pre_external_resources(katom, user_atom))
+ {
+ /* setup failed (no access, bad resource, unknown resource types, etc.) */
+ katom->event_code = BASE_JD_EVENT_JOB_INVALID;
+ ret = jd_done_nolock(katom);
+ goto out;
+ }
+ }
+
+ /* Initialize the jobscheduler policy for this atom. Function will
+ * return error if the atom is malformed.
+ *
+ * Soft-jobs never enter the job scheduler but have their own initialize method.
+ *
+ * If either fail then we immediately complete the atom with an error.
+ */
+ if ((katom->core_req & BASE_JD_REQ_SOFT_JOB) == 0)
+ {
+ kbasep_js_policy *js_policy = &(kctx->kbdev->js_data.policy);
+ if (MALI_ERROR_NONE != kbasep_js_policy_init_job( js_policy, kctx, katom ))
+ {
+ katom->event_code = BASE_JD_EVENT_JOB_INVALID;
+ ret = jd_done_nolock(katom);
+ goto out;
+ }
+ }
+ else
+ {
+ /* Soft-job */
+ if (MALI_ERROR_NONE != kbase_prepare_soft_job(katom))
+ {
+ katom->event_code = BASE_JD_EVENT_JOB_INVALID;
+ ret = jd_done_nolock(katom);
+ goto out;
+ }
+ }
+
+ if (queued)
+ {
+ ret = MALI_FALSE;
+ goto out;
+ }
+#ifdef CONFIG_KDS
+ if (!katom->kds_dep_satisfied)
+ {
+ /* Queue atom due to KDS dependency */
+ ret = MALI_FALSE;
+ goto out;
+ }
+#endif /* CONFIG_KDS */
+
+ if (katom->core_req & BASE_JD_REQ_SOFT_JOB)
+ {
+ if (kbase_process_soft_job(katom) == 0)
+ {
+ kbase_finish_soft_job(katom);
+ ret = jd_done_nolock(katom);
+ goto out;
+ }
+ /* The job has not yet completed */
+ kbasep_list_trace_add(14, kctx->kbdev, katom, &kctx->waiting_soft_jobs, KBASE_TRACE_LIST_ADD, KBASE_TRACE_LIST_WAITING_SOFT_JOBS);
+ OSK_DLIST_PUSH_BACK(&kctx->waiting_soft_jobs, katom, kbase_jd_atom, dep_item[0]);
+ ret = MALI_FALSE;
+ }
+ else if ((katom->core_req & BASEP_JD_REQ_ATOM_TYPE) != BASE_JD_REQ_DEP)
+ {
+ katom->status = KBASE_JD_ATOM_STATE_IN_JS;
+ ret = kbasep_js_add_job( kctx, katom );
+ }
+ else
+ {
+ /* This is a pure dependency. Resolve it immediately */
+ ret = jd_done_nolock(katom);
+ }
+
+out:
+ mutex_unlock(&jctx->lock);
+ return ret;
+}
+
+mali_error kbase_jd_submit(kbase_context *kctx, const kbase_uk_job_submit *submit_data)
+{
+ mali_error err = MALI_ERROR_NONE;
+ int i;
+ mali_bool need_to_try_schedule_context = MALI_FALSE;
+ kbase_device *kbdev;
+ void * user_addr;
+
+ /*
+ * kbase_jd_submit isn't expected to fail and so all errors with the jobs
+ * are reported by immediately falling them (through event system)
+ */
+ kbdev = kctx->kbdev;
+
+ beenthere("%s", "Enter");
+
+ if ((kctx->jctx.sched_info.ctx.flags & KBASE_CTX_FLAG_SUBMIT_DISABLED) != 0)
+ {
+ OSK_PRINT_ERROR(OSK_BASE_JD, "Attempt to submit to a context that has SUBMIT_DISABLED set on it");
+ return MALI_ERROR_FUNCTION_FAILED;
+ }
+
+ if (submit_data->stride != sizeof(base_jd_atom_v2))
+ {
+ OSK_PRINT_ERROR(OSK_BASE_JD, "Stride passed to job_submit doesn't match kernel");
+ return MALI_ERROR_FUNCTION_FAILED;
+ }
+
+ user_addr = get_compat_pointer(&submit_data->addr);
+
+ for(i = 0; i < submit_data->nr_atoms; i++)
+ {
+ base_jd_atom_v2 user_atom;
+
+ if (ukk_copy_from_user(sizeof(user_atom), &user_atom, user_addr) != MALI_ERROR_NONE)
+ {
+ err = MALI_ERROR_FUNCTION_FAILED;
+ break;
+ }
+
+ user_addr = (void*)((uintptr_t)user_addr + submit_data->stride);
+
+ need_to_try_schedule_context |= jd_submit_atom(kctx, &user_atom);
+ }
+
+ if ( need_to_try_schedule_context )
+ {
+ kbasep_js_try_schedule_head_ctx( kbdev );
+ }
+
+ return err;
+}
+KBASE_EXPORT_TEST_API(kbase_jd_submit)
+
+/**
+ * This function:
+ * - requeues the job from the runpool (if it was soft-stopped/removed from NEXT registers)
+ * - removes it from the system if it finished/failed/was cancelled.
+ * - resolves dependencies to add dependent jobs to the context, potentially starting them if necessary (which may add more references to the context)
+ * - releases the reference to the context from the no-longer-running job.
+ * - Handles retrying submission outside of IRQ context if it failed from within IRQ context.
+ */
+static void jd_done_worker(struct work_struct *data)
+{
+ kbase_jd_atom *katom = container_of(data, kbase_jd_atom, work);
+ kbase_jd_context *jctx;
+ kbase_context *kctx;
+ kbasep_js_kctx_info *js_kctx_info;
+ kbasep_js_policy *js_policy;
+ kbase_device *kbdev;
+ kbasep_js_device_data *js_devdata;
+ u64 cache_jc = katom->jc;
+ kbasep_js_atom_retained_state katom_retained_state;
+
+ /* Soft jobs should never reach this function */
+ OSK_ASSERT( (katom->core_req & BASE_JD_REQ_SOFT_JOB) == 0);
+
+ kctx = katom->kctx;
+ jctx = &kctx->jctx;
+ kbdev = kctx->kbdev;
+ js_kctx_info = &kctx->jctx.sched_info;
+
+ js_devdata = &kbdev->js_data;
+ js_policy = &kbdev->js_data.policy;
+
+ KBASE_TRACE_ADD( kbdev, JD_DONE_WORKER, kctx, katom, katom->jc, 0 );
+ /*
+ * Begin transaction on JD context and JS context
+ */
+ mutex_lock( &jctx->lock );
+ mutex_lock( &js_kctx_info->ctx.jsctx_mutex );
+
+ /* This worker only gets called on contexts that are scheduled *in*. This is
+ * because it only happens in response to an IRQ from a job that was
+ * running.
+ */
+ OSK_ASSERT( js_kctx_info->ctx.is_scheduled != MALI_FALSE );
+
+ /* Release cores this job was using (this might power down unused cores, and
+ * cause extra latency if a job submitted here - such as depenedent jobs -
+ * would use those cores) */
+ kbasep_js_job_check_deref_cores(kbdev, katom);
+
+ /* Retain state before the katom disappears */
+ kbasep_js_atom_retained_state_copy( &katom_retained_state, katom );
+
+ if ( !kbasep_js_has_atom_finished(&katom_retained_state) )
+ {
+ unsigned long flags;
+ /* Requeue the atom on soft-stop / removed from NEXT registers */
+ OSK_PRINT_INFO(OSK_BASE_JM, "JS: Soft Stopped/Removed from next %p on Ctx %p; Requeuing", kctx );
+
+ mutex_lock( &js_devdata->runpool_mutex );
+ kbasep_js_clear_job_retry_submit( katom );
+
+ spin_lock_irqsave( &js_devdata->runpool_irq.lock, flags);
+ kbasep_js_policy_enqueue_job( js_policy, katom );
+ spin_unlock_irqrestore( &js_devdata->runpool_irq.lock, flags);
+
+ /* A STOPPED/REMOVED job must cause a re-submit to happen, in case it
+ * was the last job left. Crucially, work items on work queues can run
+ * out of order e.g. on different CPUs, so being able to submit from
+ * the IRQ handler is not a good indication that we don't need to run
+ * jobs; the submitted job could be processed on the work-queue
+ * *before* the stopped job, even though it was submitted after. */
+ {
+ int tmp;
+ OSK_ASSERT( kbasep_js_get_atom_retry_submit_slot( &katom_retained_state, &tmp ) != MALI_FALSE );
+ CSTD_UNUSED( tmp );
+ }
+
+ mutex_unlock( &js_devdata->runpool_mutex );
+ mutex_unlock( &js_kctx_info->ctx.jsctx_mutex );
+ }
+ else
+ {
+ /* Remove the job from the system for all other reasons */
+ mali_bool need_to_try_schedule_context;
+
+ kbasep_js_remove_job( kbdev, kctx, katom );
+ mutex_unlock( &js_kctx_info->ctx.jsctx_mutex );
+ /* jd_done_nolock() requires the jsctx_mutex lock to be dropped */
+
+ need_to_try_schedule_context = jd_done_nolock(katom);
+
+ /* This ctx is already scheduled in, so return value guarenteed FALSE */
+ OSK_ASSERT( need_to_try_schedule_context == MALI_FALSE );
+ }
+ /* katom may have been freed now, do not use! */
+
+ /*
+ * Transaction complete
+ */
+ mutex_unlock( &jctx->lock );
+
+ /* Job is now no longer running, so can now safely release the context
+ * reference, and handle any actions that were logged against the atom's retained state */
+ kbasep_js_runpool_release_ctx_and_katom_retained_state( kbdev, kctx, &katom_retained_state );
+
+ KBASE_TRACE_ADD( kbdev, JD_DONE_WORKER_END, kctx, katom, cache_jc, 0 );
+}
+
+/**
+ * Work queue job cancel function
+ * Only called as part of 'Zapping' a context (which occurs on termination)
+ * Operates serially with the jd_done_worker() on the work queue.
+ *
+ * This can only be called on contexts that aren't scheduled.
+ *
+ * @note We don't need to release most of the resources that would occur on
+ * kbase_jd_done() or jd_done_worker(), because the atoms here must not be
+ * running (by virtue of only being called on contexts that aren't
+ * scheduled). The only resources that are an exception to this are:
+ * - those held by kbasep_js_job_check_ref_cores(), because these resources are
+ * held for non-running atoms as well as running atoms.
+ */
+static void jd_cancel_worker(struct work_struct *data)
+{
+ kbase_jd_atom *katom = container_of(data, kbase_jd_atom, work);
+ kbase_jd_context *jctx;
+ kbase_context *kctx;
+ kbasep_js_kctx_info *js_kctx_info;
+ mali_bool need_to_try_schedule_context;
+ kbase_device *kbdev;
+
+ /* Soft jobs should never reach this function */
+ OSK_ASSERT( (katom->core_req & BASE_JD_REQ_SOFT_JOB) == 0);
+
+ kctx = katom->kctx;
+ kbdev = kctx->kbdev;
+ jctx = &kctx->jctx;
+ js_kctx_info = &kctx->jctx.sched_info;
+
+ KBASE_TRACE_ADD( kbdev, JD_CANCEL_WORKER, kctx, katom, katom->jc, 0 );
+
+ /* This only gets called on contexts that are scheduled out. Hence, we must
+ * make sure we don't de-ref the number of running jobs (there aren't
+ * any), nor must we try to schedule out the context (it's already
+ * scheduled out).
+ */
+ OSK_ASSERT( js_kctx_info->ctx.is_scheduled == MALI_FALSE );
+
+ /* Release cores this job was using (this might power down unused cores) */
+ kbasep_js_job_check_deref_cores(kctx->kbdev, katom);
+
+ /* Scheduler: Remove the job from the system */
+ mutex_lock( &js_kctx_info->ctx.jsctx_mutex );
+ kbasep_js_remove_cancelled_job( kbdev, kctx, katom );
+ mutex_unlock( &js_kctx_info->ctx.jsctx_mutex );
+
+ mutex_lock(&jctx->lock);
+
+ need_to_try_schedule_context = jd_done_nolock(katom);
+ /* Because we're zapping, we're not adding any more jobs to this ctx, so no need to
+ * schedule the context. There's also no need for the jsctx_mutex to have been taken
+ * around this too. */
+ OSK_ASSERT( need_to_try_schedule_context == MALI_FALSE );
+
+ /* katom may have been freed now, do not use! */
+ mutex_unlock(&jctx->lock);
+
+}
+
+/**
+ * @brief Complete a job that has been removed from the Hardware
+ *
+ * This must be used whenever a job has been removed from the Hardware, e.g.:
+ * - An IRQ indicates that the job finished (for both error and 'done' codes)
+ * - The job was evicted from the JSn_HEAD_NEXT registers during a Soft/Hard stop.
+ *
+ * Some work is carried out immediately, and the rest is deferred onto a workqueue
+ *
+ * This can be called safely from atomic context.
+ *
+ * The caller must hold kbasep_js_device_data::runpool_irq::lock
+ *
+ */
+void kbase_jd_done(kbase_jd_atom *katom, int slot_nr, ktime_t *end_timestamp, mali_bool start_new_jobs)
+{
+ kbase_context *kctx;
+ kbase_device *kbdev;
+ OSK_ASSERT(katom);
+ kctx = katom->kctx;
+ OSK_ASSERT(kctx);
+ kbdev = kctx->kbdev;
+ OSK_ASSERT(kbdev);
+
+ KBASE_TRACE_ADD( kbdev, JD_DONE, kctx, katom, katom->jc, 0 );
+
+ kbasep_js_job_done_slot_irq( katom, slot_nr, end_timestamp, start_new_jobs );
+
+ OSK_ASSERT(0 == object_is_on_stack(&katom->work));
+ INIT_WORK(&katom->work, jd_done_worker);
+ queue_work(kctx->jctx.job_done_wq, &katom->work);
+}
+KBASE_EXPORT_TEST_API(kbase_jd_done)
+
+
+void kbase_jd_cancel(kbase_jd_atom *katom)
+{
+ kbase_context *kctx;
+ kbasep_js_kctx_info *js_kctx_info;
+ kbase_device *kbdev;
+ OSK_ASSERT(NULL != katom);
+ kctx = katom->kctx;
+ OSK_ASSERT(NULL != kctx);
+
+ js_kctx_info = &kctx->jctx.sched_info;
+ kbdev = kctx->kbdev;
+
+ KBASE_TRACE_ADD( kbdev, JD_CANCEL, kctx, katom, katom->jc, 0 );
+
+ /* This should only be done from a context that is not scheduled */
+ OSK_ASSERT( js_kctx_info->ctx.is_scheduled == MALI_FALSE );
+
+ katom->event_code = BASE_JD_EVENT_JOB_CANCELLED;
+
+ OSK_ASSERT(0 == object_is_on_stack(&katom->work));
+ INIT_WORK(&katom->work, jd_cancel_worker);
+ queue_work(kctx->jctx.job_done_wq, &katom->work);
+}
+
+void kbase_jd_flush_workqueues(kbase_context *kctx)
+{
+ kbase_device *kbdev;
+ int i;
+
+ OSK_ASSERT( kctx );
+
+ kbdev = kctx->kbdev;
+ OSK_ASSERT( kbdev );
+
+ flush_workqueue( kctx->jctx.job_done_wq );
+
+ /* Flush all workqueues, for simplicity */
+ for (i = 0; i < kbdev->nr_hw_address_spaces; i++)
+ {
+ flush_workqueue( kbdev->as[i].pf_wq );
+ }
+}
+
+typedef struct zap_reset_data
+{
+ /* The stages are:
+ * 1. The timer has never been called
+ * 2. The zap has timed out, all slots are soft-stopped - the GPU reset will happen.
+ * The GPU has been reset when kbdev->reset_waitq is signalled
+ *
+ * (-1 - The timer has been cancelled)
+ */
+ int stage;
+ kbase_device *kbdev;
+ struct hrtimer timer;
+ spinlock_t lock;
+} zap_reset_data;
+
+static enum hrtimer_restart zap_timeout_callback( struct hrtimer * timer )
+{
+ zap_reset_data *reset_data = container_of( timer, zap_reset_data, timer );
+ kbase_device *kbdev = reset_data->kbdev;
+ unsigned long flags;
+
+ spin_lock_irqsave(&reset_data->lock, flags);
+
+ if (reset_data->stage == -1)
+ {
+ goto out;
+ }
+
+ if (kbase_prepare_to_reset_gpu(kbdev))
+ {
+ OSK_PRINT_WARN(OSK_BASE_JD, "NOTE: GPU will now be reset as a workaround for a hardware issue");
+ kbase_reset_gpu(kbdev);
+ }
+
+ reset_data->stage = 2;
+
+out:
+ spin_unlock_irqrestore(&reset_data->lock, flags);
+
+ return HRTIMER_NORESTART;
+}
+
+void kbase_jd_zap_context(kbase_context *kctx)
+{
+ kbase_device *kbdev;
+ zap_reset_data reset_data;
+ unsigned long flags;
+ kbase_jd_atom *katom;
+ OSK_ASSERT(kctx);
+
+ kbdev = kctx->kbdev;
+
+ KBASE_TRACE_ADD( kbdev, JD_ZAP_CONTEXT, kctx, NULL, 0u, 0u );
+ kbase_job_zap_context(kctx);
+
+ mutex_lock(&kctx->jctx.lock);
+ OSK_DLIST_FOREACH(&kctx->waiting_soft_jobs, kbase_jd_atom, dep_item[0], katom)
+ {
+ kbase_cancel_soft_job(katom);
+ }
+ mutex_unlock(&kctx->jctx.lock);
+
+ hrtimer_init_on_stack(&reset_data.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL );
+ reset_data.timer.function = zap_timeout_callback;
+
+ spin_lock_init(&reset_data.lock);
+
+ reset_data.kbdev = kbdev;
+ reset_data.stage = 1;
+
+ hrtimer_start(&reset_data.timer, HR_TIMER_DELAY_MSEC(ZAP_TIMEOUT), HRTIMER_MODE_REL);
+
+ /* Wait for all jobs to finish, and for the context to be not-scheduled
+ * (due to kbase_job_zap_context(), we also guarentee it's not in the JS
+ * policy queue either */
+ wait_event(kctx->jctx.zero_jobs_wait, kctx->jctx.job_nr == 0);
+ wait_event(kctx->jctx.sched_info.ctx.is_scheduled_wait, kctx->jctx.sched_info.ctx.is_scheduled == MALI_FALSE);
+
+ spin_lock_irqsave(&reset_data.lock, flags);
+ if (reset_data.stage == 1)
+ {
+ /* The timer hasn't run yet - so cancel it */
+ reset_data.stage = -1;
+ }
+ spin_unlock_irqrestore(&reset_data.lock, flags);
+
+ hrtimer_cancel(&reset_data.timer);
+
+ if (reset_data.stage == 2)
+ {
+ /* The reset has already started.
+ * Wait for the reset to complete
+ */
+ wait_event(kbdev->reset_wait, atomic_read(&kbdev->reset_gpu) == KBASE_RESET_GPU_NOT_PENDING);
+ }
+ destroy_hrtimer_on_stack(&reset_data.timer);
+
+ OSK_PRINT_INFO(OSK_BASE_JM, "Zap: Finished Context %p", kctx );
+
+ /* Ensure that the signallers of the waitqs have finished */
+ mutex_lock(&kctx->jctx.lock);
+ mutex_lock(&kctx->jctx.sched_info.ctx.jsctx_mutex);
+ mutex_unlock(&kctx->jctx.sched_info.ctx.jsctx_mutex);
+ mutex_unlock(&kctx->jctx.lock);
+}
+KBASE_EXPORT_TEST_API(kbase_jd_zap_context)
+
+mali_error kbase_jd_init(kbase_context *kctx)
+{
+ int i;
+ mali_error mali_err = MALI_ERROR_NONE;
+#ifdef CONFIG_KDS
+ int err;
+#endif /* CONFIG_KDS */
+
+ OSK_ASSERT(kctx);
+
+ /* Simulate failure to create the workqueue */
+ if(OSK_SIMULATE_FAILURE(OSK_BASE_JD))
+ {
+ kctx->jctx.job_done_wq = NULL;
+ mali_err = MALI_ERROR_OUT_OF_MEMORY;
+ goto out1;
+ }
+ kctx->jctx.job_done_wq = alloc_workqueue("mali_jd", 0, 1);
+ if (NULL == kctx->jctx.job_done_wq)
+ {
+ mali_err = MALI_ERROR_OUT_OF_MEMORY;
+ goto out1;
+ }
+
+ for (i = 0; i < BASE_JD_ATOM_COUNT; i++)
+ {
+ init_waitqueue_head(&kctx->jctx.atoms[i].completed);
+
+ OSK_DLIST_INIT(&kctx->jctx.atoms[i].dep_head[0]);
+ OSK_DLIST_INIT(&kctx->jctx.atoms[i].dep_head[1]);
+
+ /* Catch userspace attempting to use an atom which doesn't exist as a pre-dependency */
+ kctx->jctx.atoms[i].event_code = BASE_JD_EVENT_JOB_INVALID;
+ kctx->jctx.atoms[i].status = KBASE_JD_ATOM_STATE_UNUSED;
+ }
+
+ mutex_init(&kctx->jctx.lock);
+
+ init_waitqueue_head(&kctx->jctx.zero_jobs_wait);
+
+ spin_lock_init(&kctx->jctx.tb_lock);
+
+#ifdef CONFIG_KDS
+ err = kds_callback_init(&kctx->jctx.kds_cb, 0, kds_dep_clear);
+ if (0 != err)
+ {
+ mali_err = MALI_ERROR_FUNCTION_FAILED;
+ goto out2;
+ }
+#endif /* CONFIG_KDS */
+
+ kctx->jctx.job_nr = 0;
+
+ return MALI_ERROR_NONE;
+
+#ifdef CONFIG_KDS
+out2:
+#endif /* CONFIG_KDS */
+ destroy_workqueue(kctx->jctx.job_done_wq);
+out1:
+ return mali_err;
+}
+KBASE_EXPORT_TEST_API(kbase_jd_init)
+
+void kbase_jd_exit(kbase_context *kctx)
+{
+ OSK_ASSERT(kctx);
+
+#ifdef CONFIG_KDS
+ kds_callback_term(&kctx->jctx.kds_cb);
+#endif /* CONFIG_KDS */
+ /* Work queue is emptied by this */
+ destroy_workqueue(kctx->jctx.job_done_wq);
+}
+KBASE_EXPORT_TEST_API(kbase_jd_exit)
diff --git a/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_jm.c b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_jm.c
new file mode 100644
index 0000000..1a71552
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_jm.c
@@ -0,0 +1,1278 @@
+/*
+ *
+ * (C) COPYRIGHT 2010-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_kbase_jm.c
+ * Base kernel job manager APIs
+ */
+
+#include <kbase/src/common/mali_kbase.h>
+#include <kbase/src/common/mali_midg_regmap.h>
+#include <kbase/src/common/mali_kbase_gator.h>
+#include <kbase/src/common/mali_kbase_js_affinity.h>
+#include <kbase/src/common/mali_kbase_8401_workaround.h>
+#include <kbase/src/common/mali_kbase_hw.h>
+
+#include "mali_kbase_jm.h"
+
+#define beenthere(f, a...) OSK_PRINT_INFO(OSK_BASE_JM, "%s:" f, __func__, ##a)
+
+static void kbasep_try_reset_gpu_early(kbase_device *kbdev);
+
+static void kbase_job_hw_submit(kbase_device *kbdev, kbase_jd_atom *katom, int js)
+{
+ kbase_context *kctx;
+ u32 cfg;
+ u64 jc_head = katom->jc;
+
+ OSK_ASSERT(kbdev);
+ OSK_ASSERT(katom);
+
+ kctx = katom->kctx;
+
+ /* Command register must be available */
+ OSK_ASSERT(kbasep_jm_is_js_free(kbdev, js, kctx));
+ /* Affinity is not violating */
+ kbase_js_debug_log_current_affinities( kbdev );
+ OSK_ASSERT(!kbase_js_affinity_would_violate(kbdev, js, katom->affinity));
+
+ kbase_reg_write(kbdev, JOB_SLOT_REG(js, JSn_HEAD_NEXT_LO), jc_head & 0xFFFFFFFF, kctx);
+ kbase_reg_write(kbdev, JOB_SLOT_REG(js, JSn_HEAD_NEXT_HI), jc_head >> 32, kctx);
+
+ kbase_reg_write(kbdev, JOB_SLOT_REG(js, JSn_AFFINITY_NEXT_LO), katom->affinity & 0xFFFFFFFF, kctx);
+ kbase_reg_write(kbdev, JOB_SLOT_REG(js, JSn_AFFINITY_NEXT_HI), katom->affinity >> 32, kctx);
+
+ /* start MMU, medium priority, cache clean/flush on end, clean/flush on start */
+ cfg = kctx->as_nr | JSn_CONFIG_END_FLUSH_CLEAN_INVALIDATE | JSn_CONFIG_START_MMU
+ | JSn_CONFIG_START_FLUSH_CLEAN_INVALIDATE | JSn_CONFIG_THREAD_PRI(8);
+
+ kbase_reg_write(kbdev, JOB_SLOT_REG(js, JSn_CONFIG_NEXT), cfg, kctx);
+
+ /* Write an approximate start timestamp.
+ * It's approximate because there might be a job in the HEAD register. In
+ * such cases, we'll try to make a better approximation in the IRQ handler
+ * (up to the KBASE_JS_IRQ_THROTTLE_TIME_US). */
+ katom->start_timestamp = ktime_get();
+
+ /* GO ! */
+ OSK_PRINT_INFO(OSK_BASE_JM, "JS: Submitting atom %p from ctx %p to js[%d] with head=0x%llx, affinity=0x%llx",
+ katom, kctx, js, jc_head, katom->affinity );
+
+ KBASE_TRACE_ADD_SLOT_INFO( kbdev, JM_SUBMIT, kctx, katom, jc_head, js, (u32)katom->affinity );
+
+#ifdef CONFIG_MALI_GATOR_SUPPORT
+ kbase_trace_mali_job_slots_event(GATOR_MAKE_EVENT(GATOR_JOB_SLOT_START, js), kctx);
+#endif /* CONFIG_MALI_GATOR_SUPPORT */
+ kbase_reg_write(kbdev, JOB_SLOT_REG(js, JSn_COMMAND_NEXT), JSn_COMMAND_START, katom->kctx);
+}
+
+void kbase_job_submit_nolock(kbase_device *kbdev, kbase_jd_atom *katom, int js)
+{
+ kbase_jm_slot *jm_slots;
+
+ OSK_ASSERT(kbdev);
+
+ jm_slots = kbdev->jm_slots;
+
+ /*
+ * We can have:
+ * - one job already done (pending interrupt),
+ * - one running,
+ * - one ready to be run.
+ * Hence a maximum of 3 inflight jobs. We have a 4 job
+ * queue, which I hope will be enough...
+ */
+ kbasep_jm_enqueue_submit_slot( &jm_slots[js], katom );
+ kbase_job_hw_submit(kbdev, katom, js);
+}
+
+void kbase_job_done_slot(kbase_device *kbdev, int s, u32 completion_code, u64 job_tail, ktime_t *end_timestamp)
+{
+ kbase_jm_slot *slot;
+ kbase_jd_atom *katom;
+ mali_addr64 jc_head;
+ kbase_context *kctx;
+
+ OSK_ASSERT(kbdev);
+
+ if (completion_code != BASE_JD_EVENT_DONE)
+ printk(KERN_ERR "t6xx: GPU fault 0x%02lx from job slot %d\n", (unsigned long)completion_code, s);
+
+ /* IMPORTANT: this function must only contain work necessary to complete a
+ * job from a Real IRQ (and not 'fake' completion, e.g. from
+ * Soft-stop). For general work that must happen no matter how the job was
+ * removed from the hardware, place it in kbase_jd_done() */
+
+ slot = &kbdev->jm_slots[s];
+ katom = kbasep_jm_dequeue_submit_slot( slot );
+
+ /* If the katom completed is because it's a dummy job for HW workarounds, then take no further action */
+ if(kbasep_jm_is_dummy_workaround_job(kbdev, katom))
+ {
+ KBASE_TRACE_ADD_SLOT_INFO( kbdev, JM_JOB_DONE, NULL, NULL, 0, s, completion_code );
+ return;
+ }
+
+ jc_head = katom->jc;
+ kctx = katom->kctx;
+
+ KBASE_TRACE_ADD_SLOT_INFO( kbdev, JM_JOB_DONE, kctx, katom, jc_head, s, completion_code );
+
+ if ( completion_code != BASE_JD_EVENT_DONE && completion_code != BASE_JD_EVENT_STOPPED )
+ {
+
+#if KBASE_TRACE_DUMP_ON_JOB_SLOT_ERROR != 0
+ KBASE_TRACE_DUMP( kbdev );
+#endif
+ }
+ if (job_tail != 0)
+ {
+ mali_bool was_updated = (job_tail != jc_head);
+ /* Some of the job has been executed, so we update the job chain address to where we should resume from */
+ katom->jc = job_tail;
+ if ( was_updated )
+ {
+ KBASE_TRACE_ADD_SLOT( kbdev, JM_UPDATE_HEAD, kctx, katom, job_tail, s );
+ }
+ }
+
+ /* Only update the event code for jobs that weren't cancelled */
+ if ( katom->event_code != BASE_JD_EVENT_JOB_CANCELLED )
+ {
+ katom->event_code = (base_jd_event_code)completion_code;
+ }
+ kbase_device_trace_register_access(kctx, REG_WRITE , JOB_CONTROL_REG(JOB_IRQ_CLEAR), 1 << s);
+
+ /* Complete the job, with start_new_jobs = MALI_TRUE
+ *
+ * Also defer remaining work onto the workqueue:
+ * - Re-queue Soft-stopped jobs
+ * - For any other jobs, queue the job back into the dependency system
+ * - Schedule out the parent context if necessary, and schedule a new one in.
+ */
+ kbase_jd_done( katom, s, end_timestamp, MALI_TRUE );
+}
+
+/**
+ * Update the start_timestamp of the job currently in the HEAD, based on the
+ * fact that we got an IRQ for the previous set of completed jobs.
+ *
+ * The estimate also takes into account the KBASE_JS_IRQ_THROTTLE_TIME_US and
+ * the time the job was submitted, to work out the best estimate (which might
+ * still result in an over-estimate to the calculated time spent)
+ */
+STATIC void kbasep_job_slot_update_head_start_timestamp( kbase_device *kbdev, kbase_jm_slot *slot, ktime_t end_timestamp )
+{
+ OSK_ASSERT(slot);
+
+ if ( kbasep_jm_nr_jobs_submitted( slot ) > 0 )
+ {
+ kbase_jd_atom *katom;
+ ktime_t new_timestamp;
+ ktime_t timestamp_diff;
+ katom = kbasep_jm_peek_idx_submit_slot( slot, 0 ); /* The atom in the HEAD */
+
+ OSK_ASSERT( katom != NULL );
+
+ if ( kbasep_jm_is_dummy_workaround_job( kbdev, katom ) != MALI_FALSE )
+ {
+ /* Don't access the members of HW workaround 'dummy' jobs */
+ return;
+ }
+
+ /* Account for any IRQ Throttle time - makes an overestimate of the time spent by the job */
+ new_timestamp = ktime_sub_ns( end_timestamp, KBASE_JS_IRQ_THROTTLE_TIME_US * 1000 );
+ timestamp_diff = ktime_sub( new_timestamp, katom->start_timestamp );
+ if ( ktime_to_ns( timestamp_diff ) >= 0 )
+ {
+ /* Only update the timestamp if it's a better estimate than what's currently stored.
+ * This is because our estimate that accounts for the throttle time may be too much
+ * of an overestimate */
+ katom->start_timestamp = new_timestamp;
+ }
+ }
+}
+
+void kbase_job_done(kbase_device *kbdev, u32 done)
+{
+ unsigned long flags;
+ int i;
+ u32 count = 0;
+ ktime_t end_timestamp = ktime_get();
+ kbasep_js_device_data *js_devdata;
+
+ OSK_ASSERT(kbdev);
+ js_devdata = &kbdev->js_data;
+
+ KBASE_TRACE_ADD( kbdev, JM_IRQ, NULL, NULL, 0, done );
+
+ memset( &kbdev->slot_submit_count_irq[0], 0, sizeof(kbdev->slot_submit_count_irq) );
+
+ /* write irq throttle register, this will prevent irqs from occurring until
+ * the given number of gpu clock cycles have passed */
+ {
+ int irq_throttle_cycles = atomic_read( &kbdev->irq_throttle_cycles );
+ kbase_reg_write( kbdev, JOB_CONTROL_REG( JOB_IRQ_THROTTLE ), irq_throttle_cycles, NULL );
+ }
+
+ spin_lock_irqsave(&js_devdata->runpool_irq.lock, flags);
+
+ while (done) {
+ kbase_jm_slot *slot;
+ u32 failed = done >> 16;
+
+ /* treat failed slots as finished slots */
+ u32 finished = (done & 0xFFFF) | failed;
+
+ /* Note: This is inherently unfair, as we always check
+ * for lower numbered interrupts before the higher
+ * numbered ones.*/
+ i = osk_find_first_set_bit(finished);
+ OSK_ASSERT(i >= 0);
+
+ slot = &kbdev->jm_slots[i];
+
+ do {
+ int nr_done;
+ u32 active;
+ u32 completion_code = BASE_JD_EVENT_DONE; /* assume OK */
+ u64 job_tail = 0;
+
+ if (failed & (1u << i))
+ {
+ /* read out the job slot status code if the job slot reported failure */
+ completion_code = kbase_reg_read(kbdev, JOB_SLOT_REG(i, JSn_STATUS), NULL);
+
+ switch(completion_code)
+ {
+ case BASE_JD_EVENT_STOPPED:
+#ifdef CONFIG_MALI_GATOR_SUPPORT
+ kbase_trace_mali_job_slots_event(GATOR_MAKE_EVENT(GATOR_JOB_SLOT_SOFT_STOPPED, i), NULL);
+#endif /* CONFIG_MALI_GATOR_SUPPORT */
+ /* Soft-stopped job - read the value of JS<n>_TAIL so that the job chain can be resumed */
+ job_tail = (u64)kbase_reg_read(kbdev, JOB_SLOT_REG(i, JSn_TAIL_LO), NULL) |
+ ((u64)kbase_reg_read(kbdev, JOB_SLOT_REG(i, JSn_TAIL_HI), NULL) << 32);
+ break;
+ default:
+ OSK_PRINT_WARN(OSK_BASE_JD, "error detected from slot %d, job status 0x%08x (%s)",
+ i, completion_code, kbase_exception_name(completion_code));
+ }
+
+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_6787))
+ {
+ /* Limit the number of loops to avoid a hang if the interrupt is missed */
+ u32 max_loops = KBASE_CLEAN_CACHE_MAX_LOOPS;
+
+ /* cache flush when jobs complete with non-done codes */
+ /* use GPU_COMMAND completion solution */
+ /* clean & invalidate the caches */
+ kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_COMMAND), 8, NULL);
+
+ /* wait for cache flush to complete before continuing */
+ while(--max_loops &&
+ (kbase_reg_read(kbdev, GPU_CONTROL_REG(GPU_IRQ_RAWSTAT), NULL) & CLEAN_CACHES_COMPLETED) == 0)
+ {
+ }
+
+ /* clear the CLEAN_CACHES_COMPLETED irq*/
+ kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_IRQ_CLEAR), CLEAN_CACHES_COMPLETED, NULL);
+ }
+ }
+
+ kbase_reg_write(kbdev, JOB_CONTROL_REG(JOB_IRQ_CLEAR), done & ((1 << i) | (1 << (i + 16))), NULL);
+ active = kbase_reg_read(kbdev, JOB_CONTROL_REG(JOB_IRQ_JS_STATE), NULL);
+
+ if (((active >> i) & 1) == 0 && (((done >> (i+16)) & 1) == 0))
+ {
+ /* There is a potential race we must work around:
+ *
+ * 1. A job slot has a job in both current and next registers
+ * 2. The job in current completes successfully, the IRQ handler reads RAWSTAT
+ * and calls this function with the relevant bit set in "done"
+ * 3. The job in the next registers becomes the current job on the GPU
+ * 4. Sometime before the JOB_IRQ_CLEAR line above the job on the GPU _fails_
+ * 5. The IRQ_CLEAR clears the done bit but not the failed bit. This atomically sets
+ * JOB_IRQ_JS_STATE. However since both jobs have now completed the relevant bits
+ * for the slot are set to 0.
+ *
+ * If we now did nothing then we'd incorrectly assume that _both_ jobs had completed
+ * successfully (since we haven't yet observed the fail bit being set in RAWSTAT).
+ *
+ * So at this point if there are no active jobs left we check to see if RAWSTAT has a failure
+ * bit set for the job slot. If it does we know that there has been a new failure that we
+ * didn't previously know about, so we make sure that we record this in active (but we wait
+ * for the next loop to deal with it).
+ *
+ * If we were handling a job failure (i.e. done has the relevant high bit set) then we know that
+ * the value read back from JOB_IRQ_JS_STATE is the correct number of remaining jobs because
+ * the failed job will have prevented any futher jobs from starting execution.
+ */
+ u32 rawstat = kbase_reg_read(kbdev, JOB_CONTROL_REG(JOB_IRQ_RAWSTAT), NULL);
+
+ if ((rawstat >> (i+16)) & 1)
+ {
+ /* There is a failed job that we've missed - add it back to active */
+ active |= (1u << i);
+ }
+ }
+
+ OSK_PRINT_INFO(OSK_BASE_JM, "Job ended with status 0x%08X\n", completion_code);
+
+ nr_done = kbasep_jm_nr_jobs_submitted( slot );
+ nr_done -= (active >> i) & 1;
+ nr_done -= (active >> (i + 16)) & 1;
+
+ if (nr_done <= 0)
+ {
+ OSK_PRINT_WARN(OSK_BASE_JM,
+ "Spurious interrupt on slot %d",
+ i);
+ goto spurious;
+ }
+
+ count += nr_done;
+
+ while (nr_done) {
+ if (nr_done == 1)
+ {
+ kbase_job_done_slot(kbdev, i, completion_code, job_tail, &end_timestamp);
+ }
+ else
+ {
+ /* More than one job has completed. Since this is not the last job being reported this time it
+ * must have passed. This is because the hardware will not allow further jobs in a job slot to
+ * complete until the faile job is cleared from the IRQ status.
+ */
+ kbase_job_done_slot(kbdev, i, BASE_JD_EVENT_DONE, 0, &end_timestamp);
+ }
+ nr_done--;
+ }
+
+spurious:
+ done = kbase_reg_read(kbdev, JOB_CONTROL_REG(JOB_IRQ_RAWSTAT), NULL);
+
+ failed = done >> 16;
+ finished = (done & 0xFFFF) | failed;
+ } while (finished & (1 << i));
+
+ kbasep_job_slot_update_head_start_timestamp( kbdev, slot, end_timestamp );
+ }
+ spin_unlock_irqrestore(&js_devdata->runpool_irq.lock, flags);
+
+ if (atomic_read(&kbdev->reset_gpu) == KBASE_RESET_GPU_COMMITTED)
+ {
+ /* If we're trying to reset the GPU then we might be able to do it early
+ * (without waiting for a timeout) because some jobs have completed
+ */
+ kbasep_try_reset_gpu_early(kbdev);
+ }
+
+ KBASE_TRACE_ADD( kbdev, JM_IRQ_END, NULL, NULL, 0, count );
+}
+KBASE_EXPORT_TEST_API(kbase_job_done)
+
+
+static mali_bool kbasep_soft_stop_allowed(kbase_device *kbdev, u16 core_reqs)
+{
+ mali_bool soft_stops_allowed = MALI_TRUE;
+
+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8408))
+ {
+ if ((core_reqs & BASE_JD_REQ_T) != 0)
+ {
+ soft_stops_allowed = MALI_FALSE;
+ }
+ }
+ return soft_stops_allowed;
+}
+
+static mali_bool kbasep_hard_stop_allowed(kbase_device *kbdev, u16 core_reqs)
+{
+ mali_bool hard_stops_allowed = MALI_TRUE;
+
+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8394))
+ {
+ if ((core_reqs & BASE_JD_REQ_T) != 0)
+ {
+ hard_stops_allowed = MALI_FALSE;
+ }
+ }
+ return hard_stops_allowed;
+}
+
+static void kbasep_job_slot_soft_or_hard_stop_do_action(kbase_device *kbdev, int js, u32 action,
+ u16 core_reqs, kbase_context *kctx )
+{
+#if KBASE_TRACE_ENABLE
+ u32 status_reg_before;
+ u64 job_in_head_before;
+ u32 status_reg_after;
+
+ /* Check the head pointer */
+ job_in_head_before = ((u64)kbase_reg_read(kbdev, JOB_SLOT_REG(js, JSn_HEAD_LO), NULL))
+ | (((u64)kbase_reg_read(kbdev, JOB_SLOT_REG(js, JSn_HEAD_HI), NULL)) << 32);
+ status_reg_before = kbase_reg_read(kbdev, JOB_SLOT_REG(js, JSn_STATUS), NULL );
+#endif
+
+ if (action == JSn_COMMAND_SOFT_STOP)
+ {
+ mali_bool soft_stop_allowed = kbasep_soft_stop_allowed( kbdev, core_reqs );
+ if (!soft_stop_allowed)
+ {
+#ifdef CONFIG_MALI_DEBUG
+ OSK_PRINT(OSK_BASE_JM, "Attempt made to soft-stop a job that cannot be soft-stopped. core_reqs = 0x%X", (unsigned int) core_reqs);
+#endif /* CONFIG_MALI_DEBUG */
+ return;
+ }
+ }
+
+ if (action == JSn_COMMAND_HARD_STOP)
+ {
+ mali_bool hard_stop_allowed = kbasep_hard_stop_allowed( kbdev, core_reqs );
+ if (!hard_stop_allowed)
+ {
+ /* Jobs can be hard-stopped for the following reasons:
+ * * CFS decides the job has been running too long (and soft-stop has not occurred).
+ * In this case the GPU will be reset by CFS if the job remains on the GPU.
+ *
+ * * The context is destroyed, kbase_jd_zap_context will attempt to hard-stop the job. However
+ * it also has a watchdog which will cause the GPU to be reset if the job remains on the GPU.
+ *
+ * * An (unhandled) MMU fault occurred. As long as BASE_HW_ISSUE_8245 is defined then
+ * the GPU will be reset.
+ *
+ * All three cases result in the GPU being reset if the hard-stop fails,
+ * so it is safe to just return and ignore the hard-stop request.
+ */
+ OSK_PRINT_WARN(OSK_BASE_JM, "Attempt made to hard-stop a job that cannot be hard-stopped. core_reqs = 0x%X", (unsigned int) core_reqs);
+ return;
+ }
+ }
+
+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8316) && action == JSn_COMMAND_SOFT_STOP)
+ {
+ int i;
+ kbase_jm_slot *slot;
+ slot = &kbdev->jm_slots[js];
+
+ for (i = 0; i < kbasep_jm_nr_jobs_submitted(slot); i++)
+ {
+ kbase_jd_atom *katom;
+ kbase_as * as;
+
+ katom = kbasep_jm_peek_idx_submit_slot(slot, i);
+
+ OSK_ASSERT(katom);
+
+ if ( kbasep_jm_is_dummy_workaround_job( kbdev, katom ) != MALI_FALSE )
+ {
+ /* Don't access the members of HW workaround 'dummy' jobs
+ *
+ * This assumes that such jobs can't cause HW_ISSUE_8316, and could only be blocked
+ * by other jobs causing HW_ISSUE_8316 (which will get poked/or eventually get killed) */
+ continue;
+ }
+
+ if ( !katom->poking )
+ {
+ OSK_ASSERT(katom->kctx);
+ OSK_ASSERT(katom->kctx->as_nr != KBASEP_AS_NR_INVALID);
+
+ katom->poking = 1;
+ as = &kbdev->as[katom->kctx->as_nr];
+ kbase_as_poking_timer_retain(as);
+ }
+ }
+ }
+
+ kbase_reg_write(kbdev, JOB_SLOT_REG(js, JSn_COMMAND), action, kctx);
+
+#if KBASE_TRACE_ENABLE
+ status_reg_after = kbase_reg_read(kbdev, JOB_SLOT_REG(js, JSn_STATUS), NULL );
+ if (status_reg_after == BASE_JD_EVENT_ACTIVE)
+ {
+ kbase_jm_slot *slot;
+ kbase_jd_atom *head;
+ kbase_context *head_kctx;
+
+ slot = &kbdev->jm_slots[js];
+ head = kbasep_jm_peek_idx_submit_slot( slot, slot->submitted_nr-1 );
+ head_kctx = head->kctx;
+
+ /* We don't need to check kbasep_jm_is_dummy_workaround_job( head ) here:
+ * - Members are not indirected through
+ * - The members will all be zero anyway
+ */
+ if ( status_reg_before == BASE_JD_EVENT_ACTIVE )
+ {
+ KBASE_TRACE_ADD_SLOT( kbdev, JM_CHECK_HEAD, head_kctx, head, job_in_head_before, js );
+ }
+ else
+ {
+ KBASE_TRACE_ADD_SLOT( kbdev, JM_CHECK_HEAD, NULL, NULL, 0, js );
+ }
+ if (action == JSn_COMMAND_SOFT_STOP)
+ {
+ KBASE_TRACE_ADD_SLOT( kbdev, JM_SOFTSTOP, head_kctx, head, head->jc, js );
+ }
+ else
+ {
+ KBASE_TRACE_ADD_SLOT( kbdev, JM_HARDSTOP, head_kctx, head, head->jc, js );
+ }
+ }
+ else
+ {
+ if ( status_reg_before == BASE_JD_EVENT_ACTIVE )
+ {
+ KBASE_TRACE_ADD_SLOT( kbdev, JM_CHECK_HEAD, NULL, NULL, job_in_head_before, js );
+ }
+ else
+ {
+ KBASE_TRACE_ADD_SLOT( kbdev, JM_CHECK_HEAD, NULL, NULL, 0, js );
+ }
+
+ if (action == JSn_COMMAND_SOFT_STOP)
+ {
+ KBASE_TRACE_ADD_SLOT( kbdev, JM_SOFTSTOP, NULL, NULL, 0, js );
+ }
+ else
+ {
+ KBASE_TRACE_ADD_SLOT( kbdev, JM_HARDSTOP, NULL, NULL, 0, js );
+ }
+ }
+#endif
+}
+
+/* Helper macros used by kbasep_job_slot_soft_or_hard_stop */
+#define JM_SLOT_MAX_JOB_SUBMIT_REGS 2
+#define JM_JOB_IS_CURRENT_JOB_INDEX(n) (1 == n) /* Index of the last job to process */
+#define JM_JOB_IS_NEXT_JOB_INDEX(n) (2 == n) /* Index of the prior to last job to process */
+
+/** Soft or hard-stop a slot
+ *
+ * This function safely ensures that the correct job is either hard or soft-stopped.
+ * It deals with evicting jobs from the next registers where appropriate.
+ *
+ * This does not attempt to stop or evict jobs that are 'dummy' jobs for HW workarounds.
+ *
+ * @param kbdev The kbase device
+ * @param kctx The context to soft/hard-stop job(s) from (or NULL is all jobs should be targeted)
+ * @param js The slot that the job(s) are on
+ * @param target_katom The atom that should be targeted (or NULL if all jobs from the context should be targeted)
+ * @param action The action to perform, either JSn_COMMAND_HARD_STOP or JSn_COMMAND_SOFT_STOP
+ */
+static void kbasep_job_slot_soft_or_hard_stop(kbase_device *kbdev, kbase_context *kctx, int js,
+ kbase_jd_atom *target_katom, u32 action)
+{
+ kbase_jd_atom *katom;
+ u8 i;
+ u8 jobs_submitted;
+ kbase_jm_slot *slot;
+ u16 core_reqs;
+ kbasep_js_device_data *js_devdata;
+
+
+ OSK_ASSERT(action == JSn_COMMAND_HARD_STOP || action == JSn_COMMAND_SOFT_STOP);
+ OSK_ASSERT(kbdev);
+ js_devdata = &kbdev->js_data;
+
+ slot = &kbdev->jm_slots[js];
+ OSK_ASSERT(slot);
+ lockdep_assert_held(&js_devdata->runpool_irq.lock);
+
+ jobs_submitted = kbasep_jm_nr_jobs_submitted( slot );
+ KBASE_TRACE_ADD_SLOT_INFO( kbdev, JM_SLOT_SOFT_OR_HARD_STOP, kctx, NULL, 0u, js, jobs_submitted );
+
+ if (jobs_submitted > JM_SLOT_MAX_JOB_SUBMIT_REGS)
+ {
+ i = jobs_submitted - JM_SLOT_MAX_JOB_SUBMIT_REGS;
+ }
+ else
+ {
+ i = 0;
+ }
+
+ /* Loop through all jobs that have been submitted to the slot and haven't completed */
+ for(;i < jobs_submitted;i++)
+ {
+ katom = kbasep_jm_peek_idx_submit_slot( slot, i );
+
+ if (kctx && katom->kctx != kctx)
+ {
+ continue;
+ }
+ if (target_katom && katom != target_katom)
+ {
+ continue;
+ }
+ if ( kbasep_jm_is_dummy_workaround_job( kbdev, katom ) )
+ {
+ continue;
+ }
+
+ core_reqs = katom->core_req;
+
+ if (JM_JOB_IS_CURRENT_JOB_INDEX(jobs_submitted - i))
+ {
+ /* The last job in the slot, check if there is a job in the next register */
+ if (kbase_reg_read(kbdev, JOB_SLOT_REG(js, JSn_COMMAND_NEXT), NULL) == 0)
+ {
+ kbasep_job_slot_soft_or_hard_stop_do_action(kbdev, js, action, core_reqs, katom->kctx);
+ }
+ else
+ {
+ /* The job is in the next registers */
+ beenthere("clearing job from next registers on slot %d", js);
+ kbase_reg_write(kbdev, JOB_SLOT_REG(js, JSn_COMMAND_NEXT), JSn_COMMAND_NOP, NULL);
+
+ /* Check to see if we did remove a job from the next registers */
+ if (kbase_reg_read(kbdev, JOB_SLOT_REG(js, JSn_HEAD_NEXT_LO), NULL) != 0 ||
+ kbase_reg_read(kbdev, JOB_SLOT_REG(js, JSn_HEAD_NEXT_HI), NULL) != 0)
+ {
+ /* The job was successfully cleared from the next registers, requeue it */
+ kbase_jd_atom *dequeued_katom = kbasep_jm_dequeue_tail_submit_slot( slot );
+ OSK_ASSERT(dequeued_katom == katom);
+ jobs_submitted --;
+
+ /* Set the next registers to NULL */
+ kbase_reg_write(kbdev, JOB_SLOT_REG(js, JSn_HEAD_NEXT_LO), 0, NULL);
+ kbase_reg_write(kbdev, JOB_SLOT_REG(js, JSn_HEAD_NEXT_HI), 0, NULL);
+
+ KBASE_TRACE_ADD_SLOT( kbdev, JM_SLOT_EVICT, dequeued_katom->kctx, dequeued_katom, dequeued_katom->jc, js );
+
+ dequeued_katom->event_code = BASE_JD_EVENT_REMOVED_FROM_NEXT;
+ /* Complete the job, indicate it took no time, but require start_new_jobs == MALI_FALSE
+ * to prevent this slot being resubmitted to until we've dropped the lock */
+ kbase_jd_done(dequeued_katom, js, NULL, MALI_FALSE);
+ }
+ else
+ {
+ /* The job transitioned into the current registers before we managed to evict it,
+ * in this case we fall back to soft/hard-stopping the job */
+ beenthere("missed job in next register, soft/hard-stopping slot %d", js);
+ kbasep_job_slot_soft_or_hard_stop_do_action(kbdev, js, action, core_reqs, katom->kctx);
+ }
+ }
+ }
+ else if (JM_JOB_IS_NEXT_JOB_INDEX(jobs_submitted-i))
+ {
+ /* There's a job after this one, check to see if that job is in the next registers */
+ if (kbase_reg_read(kbdev, JOB_SLOT_REG(js, JSn_COMMAND_NEXT), NULL) != 0)
+ {
+ kbase_jd_atom *check_next_atom;
+ /* It is - we should remove that job and soft/hard-stop the slot */
+
+ /* Only proceed when the next jobs isn't a HW workaround 'dummy' job
+ *
+ * This can't be an ASSERT due to MMU fault code:
+ * - This first hard-stops the job that caused the fault
+ * - Under HW Issue 8401, this inserts a dummy workaround job into NEXT
+ * - Under HW Issue 8245, it will then reset the GPU
+ * - This causes a Soft-stop to occur on all slots
+ * - By the time of the soft-stop, we may (depending on timing) still have:
+ * - The original job in HEAD, if it's not finished the hard-stop
+ * - The dummy workaround job in NEXT
+ *
+ * Other cases could be coded in future that cause back-to-back Soft/Hard
+ * stops with dummy workaround jobs in place, e.g. MMU handler code and Job
+ * Scheduler watchdog timer running in parallel.
+ *
+ * Note, the index i+1 is valid to peek from: i == jobs_submitted-2, therefore
+ * i+1 == jobs_submitted-1 */
+ check_next_atom = kbasep_jm_peek_idx_submit_slot( slot, i+1 );
+ if ( kbasep_jm_is_dummy_workaround_job( kbdev, check_next_atom ) != MALI_FALSE )
+ {
+ continue;
+ }
+
+ beenthere("clearing job from next registers on slot %d", js);
+ kbase_reg_write(kbdev, JOB_SLOT_REG(js, JSn_COMMAND_NEXT), JSn_COMMAND_NOP, NULL);
+
+ /* Check to see if we did remove a job from the next registers */
+ if (kbase_reg_read(kbdev, JOB_SLOT_REG(js, JSn_HEAD_NEXT_LO), NULL) != 0 ||
+ kbase_reg_read(kbdev, JOB_SLOT_REG(js, JSn_HEAD_NEXT_HI), NULL) != 0)
+ {
+ /* We did remove a job from the next registers, requeue it */
+ kbase_jd_atom *dequeued_katom = kbasep_jm_dequeue_tail_submit_slot( slot );
+ OSK_ASSERT(dequeued_katom != NULL);
+ jobs_submitted --;
+
+ /* Set the next registers to NULL */
+ kbase_reg_write(kbdev, JOB_SLOT_REG(js, JSn_HEAD_NEXT_LO), 0, NULL);
+ kbase_reg_write(kbdev, JOB_SLOT_REG(js, JSn_HEAD_NEXT_HI), 0, NULL);
+
+ KBASE_TRACE_ADD_SLOT( kbdev, JM_SLOT_EVICT, dequeued_katom->kctx, dequeued_katom, dequeued_katom->jc, js );
+
+ dequeued_katom->event_code = BASE_JD_EVENT_REMOVED_FROM_NEXT;
+ /* Complete the job, indicate it took no time, but require start_new_jobs == MALI_FALSE
+ * to prevent this slot being resubmitted to until we've dropped the lock */
+ kbase_jd_done(dequeued_katom, js, NULL, MALI_FALSE);
+ }
+ else
+ {
+ /* We missed the job, that means the job we're interested in left the hardware before
+ * we managed to do anything, so we can proceed to the next job */
+ continue;
+ }
+
+ /* Next is now free, so we can soft/hard-stop the slot */
+ beenthere("soft/hard-stopped slot %d (there was a job in next which was successfully cleared)\n", js);
+ kbasep_job_slot_soft_or_hard_stop_do_action(kbdev, js, action, core_reqs, katom->kctx);
+ }
+ /* If there was no job in the next registers, then the job we were
+ * interested in has finished, so we need not take any action
+ */
+ }
+ }
+}
+
+void kbase_job_kill_jobs_from_context(kbase_context *kctx)
+{
+ unsigned long flags;
+ kbase_device *kbdev;
+ kbasep_js_device_data *js_devdata;
+ int i;
+
+ OSK_ASSERT( kctx != NULL );
+ kbdev = kctx->kbdev;
+ OSK_ASSERT( kbdev != NULL );
+ js_devdata = &kbdev->js_data;
+
+ /* Cancel any remaining running jobs for this kctx */
+ spin_lock_irqsave(&js_devdata->runpool_irq.lock, flags);
+ for (i = 0; i < kbdev->gpu_props.num_job_slots; i++)
+ {
+ kbase_job_slot_hardstop(kctx, i, NULL);
+ }
+ spin_unlock_irqrestore(&js_devdata->runpool_irq.lock, flags);
+}
+
+void kbase_job_zap_context(kbase_context *kctx)
+{
+ kbase_device *kbdev;
+ kbasep_js_device_data *js_devdata;
+ kbasep_js_kctx_info *js_kctx_info;
+ int i;
+ mali_bool evict_success;
+
+ OSK_ASSERT( kctx != NULL );
+ kbdev = kctx->kbdev;
+ OSK_ASSERT( kbdev != NULL );
+ js_devdata = &kbdev->js_data;
+ js_kctx_info = &kctx->jctx.sched_info;
+
+
+ /*
+ * Critical assumption: No more submission is possible outside of the
+ * workqueue. This is because the OS *must* prevent U/K calls (IOCTLs)
+ * whilst the kbase_context is terminating.
+ */
+
+
+ /* First, atomically do the following:
+ * - mark the context as dying
+ * - try to evict it from the policy queue */
+
+ mutex_lock( &js_kctx_info->ctx.jsctx_mutex );
+ js_kctx_info->ctx.is_dying = MALI_TRUE;
+
+ OSK_PRINT_INFO(OSK_BASE_JM, "Zap: Try Evict Ctx %p", kctx );
+ mutex_lock( &js_devdata->queue_mutex );
+ evict_success = kbasep_js_policy_try_evict_ctx( &js_devdata->policy, kctx );
+ mutex_unlock( &js_devdata->queue_mutex );
+
+ mutex_unlock( &js_kctx_info->ctx.jsctx_mutex );
+
+ /* locks must be dropped by this point, to prevent deadlock on flush */
+ OSK_PRINT_INFO(OSK_BASE_JM, "Zap: Flush Workqueue Ctx %p", kctx );
+ KBASE_TRACE_ADD( kbdev, JM_FLUSH_WORKQS, kctx, NULL, 0u, 0u );
+ kbase_jd_flush_workqueues( kctx );
+ KBASE_TRACE_ADD( kbdev, JM_FLUSH_WORKQS_DONE, kctx, NULL, 0u, 0u );
+
+ /*
+ * At this point we know that:
+ * - If eviction succeeded, it was in the policy queue, but now no longer is
+ * - If eviction failed, then it wasn't in the policy queue. It is one of the following:
+ * - a. it didn't have any jobs, and so is not in the Policy Queue or the
+ * Run Pool (no work required)
+ * - b. it was in the process of a scheduling transaction - but this can only
+ * happen as a result of the work-queue. Two options:
+ * - i. it is now scheduled by the time of the flush - case d.
+ * - ii. it is evicted from the Run Pool due to having to roll-back a transaction
+ * - c. it is about to be scheduled out.
+ * - In this case, we've marked it as dying, so the schedule-out code
+ * marks all jobs for killing, evicts it from the Run Pool, and does *not*
+ * place it back on the Policy Queue. The workqueue flush ensures this has
+ * completed
+ * - d. it is scheduled, and may or may not be running jobs
+ * - e. it was scheduled, but didn't get scheduled out during flushing of
+ * the workqueues. By the time we obtain the jsctx_mutex again, it may've
+ * been scheduled out
+ *
+ */
+
+ mutex_lock( &js_kctx_info->ctx.jsctx_mutex );
+ if ( evict_success != MALI_FALSE || js_kctx_info->ctx.is_scheduled == MALI_FALSE )
+ {
+ /* The following events require us to kill off remaining jobs and
+ * update PM book-keeping:
+ * - we evicted it correctly (it must have jobs to be in the Policy Queue)
+ *
+ * These events need no action:
+ * - Case a: it didn't have any jobs, and was never in the Queue
+ * - Case b-ii: scheduling transaction was partially rolled-back (this
+ * already cancels the jobs and pm-idles the ctx)
+ * - Case c: scheduled out and killing of all jobs completed on the work-queue (it's not in the Run Pool)
+ * - Case e: it was scheduled out after the workqueue was flushed, but
+ * before we re-obtained the jsctx_mutex. The jobs have already been
+ * cancelled (but the cancel may not have completed yet) and the PM has
+ * already been idled
+ */
+
+ KBASE_TRACE_ADD( kbdev, JM_ZAP_NON_SCHEDULED, kctx, NULL, 0u, js_kctx_info->ctx.is_scheduled );
+
+ OSK_PRINT_INFO(OSK_BASE_JM, "Zap: Ctx %p evict_success=%d, scheduled=%d", kctx, evict_success, js_kctx_info->ctx.is_scheduled );
+
+ if ( evict_success != MALI_FALSE )
+ {
+ /* Only cancel jobs and pm-idle when we evicted from the policy queue.
+ *
+ * Having is_dying set ensures that this kills, and doesn't requeue
+ *
+ * In addition, is_dying set ensure that this calls kbase_pm_context_idle().
+ * This is safe because the context is guaranteed to not be in the
+ * runpool, by virtue of it being evicted from the policy queue */
+ kbasep_js_runpool_requeue_or_kill_ctx( kbdev, kctx );
+ }
+ mutex_unlock( &js_kctx_info->ctx.jsctx_mutex );
+ }
+ else
+ {
+ unsigned long flags;
+ mali_bool was_retained;
+ /* Didn't evict, but it is scheduled - it's in the Run Pool:
+ * Cases d and b(i) */
+ KBASE_TRACE_ADD( kbdev, JM_ZAP_SCHEDULED, kctx, NULL, 0u, js_kctx_info->ctx.is_scheduled );
+ OSK_PRINT_INFO(OSK_BASE_JM, "Zap: Ctx %p is in RunPool", kctx );
+
+ /* Disable the ctx from submitting any more jobs */
+ spin_lock_irqsave(&js_devdata->runpool_irq.lock, flags);
+ kbasep_js_clear_submit_allowed( js_devdata, kctx );
+
+ /* Retain and (later) release the context whilst it is is now disallowed from submitting
+ * jobs - ensures that someone somewhere will be removing the context later on */
+ was_retained = kbasep_js_runpool_retain_ctx_nolock( kbdev, kctx );
+
+ /* Since it's scheduled and we have the jsctx_mutex, it must be retained successfully */
+ OSK_ASSERT( was_retained != MALI_FALSE );
+
+ OSK_PRINT_INFO(OSK_BASE_JM, "Zap: Ctx %p Kill Any Running jobs", kctx );
+ /* Cancel any remaining running jobs for this kctx - if any. Submit is disallowed
+ * which takes effect immediately, so no more new jobs will appear after we do this. */
+ for (i = 0; i < kbdev->gpu_props.num_job_slots; i++)
+ {
+ kbase_job_slot_hardstop(kctx, i, NULL);
+ }
+ spin_unlock_irqrestore(&js_devdata->runpool_irq.lock, flags);
+ mutex_unlock( &js_kctx_info->ctx.jsctx_mutex );
+
+ OSK_PRINT_INFO(OSK_BASE_JM, "Zap: Ctx %p Release (may or may not schedule out immediately)", kctx );
+ kbasep_js_runpool_release_ctx( kbdev, kctx );
+ }
+ KBASE_TRACE_ADD( kbdev, JM_ZAP_DONE, kctx, NULL, 0u, 0u );
+
+ /* After this, you must wait on both the kbase_jd_context::zero_jobs_wait
+ * and the kbasep_js_kctx_info::ctx::is_scheduled_waitq - to wait for the
+ * jobs to be destroyed, and the context to be de-scheduled (if it was on
+ * the runpool).
+ *
+ * kbase_jd_zap_context() will do this. */
+}
+KBASE_EXPORT_TEST_API(kbase_job_zap_context)
+
+mali_error kbase_job_slot_init(kbase_device *kbdev)
+{
+ int i;
+ OSK_ASSERT(kbdev);
+
+ for (i = 0; i < kbdev->gpu_props.num_job_slots; i++)
+ {
+ kbasep_jm_init_submit_slot( &kbdev->jm_slots[i] );
+ }
+ return MALI_ERROR_NONE;
+}
+KBASE_EXPORT_TEST_API(kbase_job_slot_init)
+
+void kbase_job_slot_halt(kbase_device *kbdev)
+{
+ CSTD_UNUSED(kbdev);
+}
+
+void kbase_job_slot_term(kbase_device *kbdev)
+{
+ OSK_ASSERT(kbdev);
+}
+KBASE_EXPORT_TEST_API(kbase_job_slot_term)
+
+
+/**
+ * Soft-stop the specified job slot
+ *
+ * The job slot lock must be held when calling this function.
+ * The job slot must not already be in the process of being soft-stopped.
+ *
+ * Where possible any job in the next register is evicted before the soft-stop.
+ *
+ * @param kbdev The kbase device
+ * @param js The job slot to soft-stop
+ * @param target_katom The job that should be soft-stopped (or NULL for any job)
+ */
+void kbase_job_slot_softstop(kbase_device *kbdev, int js, kbase_jd_atom *target_katom)
+{
+ kbasep_job_slot_soft_or_hard_stop(kbdev, NULL, js, target_katom, JSn_COMMAND_SOFT_STOP);
+}
+
+/**
+ * Hard-stop the specified job slot
+ *
+ * The job slot lock must be held when calling this function.
+ *
+ * @param kctx The kbase context that contains the job(s) that should be hard-stopped
+ * @param js The job slot to hard-stop
+ * @param target_katom The job that should be hard-stopped (or NULL for all jobs from the context)
+ */
+void kbase_job_slot_hardstop(kbase_context *kctx, int js, kbase_jd_atom *target_katom)
+{
+ kbase_device *kbdev = kctx->kbdev;
+ kbasep_job_slot_soft_or_hard_stop(kbdev, kctx, js, target_katom, JSn_COMMAND_HARD_STOP);
+
+ if (kbase_hw_has_issue(kctx->kbdev, BASE_HW_ISSUE_8401) ||
+ kbase_hw_has_issue(kctx->kbdev, BASE_HW_ISSUE_9510))
+ {
+ /* The workaround for HW issue 8401 has an issue, so instead of hard-stopping
+ * just reset the GPU. This will ensure that the jobs leave the GPU.
+ */
+ if (kbase_prepare_to_reset_gpu_locked(kbdev))
+ {
+ OSK_PRINT_WARN(OSK_BASE_JD, "NOTE: GPU will now be reset as a workaround for a hardware issue");
+ kbase_reset_gpu_locked(kbdev);
+ }
+ }
+}
+
+void kbasep_reset_timeout_worker(struct work_struct *data)
+{
+ unsigned long flags;
+ kbase_device *kbdev;
+ int i;
+ ktime_t end_timestamp = ktime_get();
+ kbasep_js_device_data *js_devdata;
+ kbase_uk_hwcnt_setup hwcnt_setup = {{0}};
+ kbase_instr_state bckp_state;
+
+ OSK_ASSERT(data);
+
+ kbdev = container_of(data, kbase_device, reset_work);
+
+ OSK_ASSERT(kbdev);
+ KBASE_TRACE_ADD( kbdev, JM_BEGIN_RESET_WORKER, NULL, NULL, 0u, 0 );
+
+ kbase_pm_context_active(kbdev);
+
+ js_devdata = &kbdev->js_data;
+
+ /* All slot have been soft-stopped and we've waited SOFT_STOP_RESET_TIMEOUT for the slots to clear, at this point
+ * we assume that anything that is still left on the GPU is stuck there and we'll kill it when we reset the GPU */
+
+ OSK_PRINT_ERROR(OSK_BASE_JD, "Resetting GPU");
+
+ /* Make sure the timer has completed - this cannot be done from interrupt context,
+ * so this cannot be done within kbasep_try_reset_gpu_early. */
+ hrtimer_cancel(&kbdev->reset_timer);
+
+ spin_lock_irqsave(&kbdev->hwcnt.lock, flags);
+
+ if (kbdev->hwcnt.state == KBASE_INSTR_STATE_RESETTING)
+ { /*the same interrupt handler preempted itself*/
+ /* GPU is being reset*/
+ spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags);
+ wait_event(kbdev->hwcnt.wait, kbdev->hwcnt.triggered != 0);
+ spin_lock_irqsave(&kbdev->hwcnt.lock, flags);
+ }
+ /* Save the HW counters setup */
+ if (kbdev->hwcnt.kctx != NULL)
+ {
+ kbase_context *kctx = kbdev->hwcnt.kctx;
+ hwcnt_setup.dump_buffer = kbase_reg_read(kbdev, GPU_CONTROL_REG(PRFCNT_BASE_LO), kctx) & 0xffffffff;
+ hwcnt_setup.dump_buffer |= (mali_addr64)kbase_reg_read(kbdev, GPU_CONTROL_REG(PRFCNT_BASE_HI), kctx) << 32;
+ hwcnt_setup.jm_bm = kbase_reg_read(kbdev, GPU_CONTROL_REG(PRFCNT_JM_EN), kctx);
+ hwcnt_setup.shader_bm = kbase_reg_read(kbdev, GPU_CONTROL_REG(PRFCNT_SHADER_EN), kctx);
+ hwcnt_setup.tiler_bm = kbase_reg_read(kbdev, GPU_CONTROL_REG(PRFCNT_TILER_EN), kctx);
+ hwcnt_setup.l3_cache_bm = kbase_reg_read(kbdev, GPU_CONTROL_REG(PRFCNT_L3_CACHE_EN), kctx);
+ hwcnt_setup.mmu_l2_bm = kbase_reg_read(kbdev, GPU_CONTROL_REG(PRFCNT_MMU_L2_EN), kctx);
+ }
+ bckp_state = kbdev->hwcnt.state;
+ kbdev->hwcnt.state = KBASE_INSTR_STATE_RESETTING;
+ kbdev->hwcnt.triggered = 0;
+ /* Disable IRQ to avoid IRQ handlers to kick in after releaseing the spinlock;
+ * this also clears any outstanding interrupts */
+ kbase_pm_disable_interrupts(kbdev);
+ /* Ensure that any IRQ handlers have finished */
+ kbase_synchronize_irqs(kbdev);
+ spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags);
+
+ /* Reset the GPU */
+ kbase_pm_power_transitioning(kbdev);
+ kbase_pm_init_hw(kbdev);
+ /* IRQs were re-enabled by kbase_pm_init_hw */
+
+ kbase_pm_power_transitioning(kbdev);
+
+ spin_lock_irqsave(&kbdev->hwcnt.lock, flags);
+ /* Restore the HW counters setup */
+ if (kbdev->hwcnt.kctx != NULL)
+ {
+ kbase_context *kctx = kbdev->hwcnt.kctx;
+ kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_BASE_LO), hwcnt_setup.dump_buffer & 0xFFFFFFFF, kctx);
+ kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_BASE_HI), hwcnt_setup.dump_buffer >> 32, kctx);
+ kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_JM_EN), hwcnt_setup.jm_bm, kctx);
+ kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_SHADER_EN), hwcnt_setup.shader_bm, kctx);
+ kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_L3_CACHE_EN), hwcnt_setup.l3_cache_bm, kctx);
+ kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_MMU_L2_EN), hwcnt_setup.mmu_l2_bm, kctx);
+
+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8186))
+ {
+ /* Issue 8186 requires TILER_EN to be disabled before updating PRFCNT_CONFIG. We then restore the register contents */
+ kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_TILER_EN), 0, kctx);
+ }
+
+ kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_CONFIG), (kctx->as_nr << PRFCNT_CONFIG_AS_SHIFT) | PRFCNT_CONFIG_MODE_MANUAL, kctx);
+ kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_TILER_EN), hwcnt_setup.tiler_bm, kctx);
+ }
+ kbdev->hwcnt.triggered = 1;
+ wake_up(&kbdev->hwcnt.wait);
+ kbdev->hwcnt.state = bckp_state;
+ spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags);
+
+ /* Re-init the power policy. Note that this does not re-enable interrupts,
+ * because the call to kbase_pm_clock_on() will do nothing (due to
+ * pm.gpu_powered == MALI_TRUE by this point) */
+ kbase_pm_send_event(kbdev, KBASE_PM_EVENT_POLICY_INIT);
+
+ /* Wait for the policy to power up the GPU */
+ kbase_pm_wait_for_power_up(kbdev);
+
+ /* Complete any jobs that were still on the GPU */
+ spin_lock_irqsave(&js_devdata->runpool_irq.lock, flags);
+ for (i = 0; i < kbdev->gpu_props.num_job_slots; i++)
+ {
+ int nr_done;
+ kbase_jm_slot *slot = &kbdev->jm_slots[i];
+
+ nr_done = kbasep_jm_nr_jobs_submitted( slot );
+ while (nr_done) {
+ OSK_PRINT_ERROR(OSK_BASE_JD, "Job stuck in slot %d on the GPU was cancelled", i);
+ kbase_job_done_slot(kbdev, i, BASE_JD_EVENT_JOB_CANCELLED, 0, &end_timestamp);
+ nr_done--;
+ }
+ }
+ spin_unlock_irqrestore(&js_devdata->runpool_irq.lock, flags);
+
+ mutex_lock( &js_devdata->runpool_mutex );
+
+ /* Reprogram the GPU's MMU */
+ for(i = 0; i < BASE_MAX_NR_AS; i++)
+ {
+ if (js_devdata->runpool_irq.per_as_data[i].kctx) {
+ kbase_as *as = &kbdev->as[i];
+ mutex_lock(&as->transaction_mutex);
+ kbase_mmu_update(js_devdata->runpool_irq.per_as_data[i].kctx);
+ mutex_unlock(&as->transaction_mutex);
+ }
+ }
+
+ atomic_set(&kbdev->reset_gpu, KBASE_RESET_GPU_NOT_PENDING);
+ wake_up(&kbdev->reset_wait);
+ OSK_PRINT_ERROR(OSK_BASE_JD, "Reset complete");
+
+ /* Try submitting some jobs to restart processing */
+ if (js_devdata->nr_user_contexts_running > 0)
+ {
+ KBASE_TRACE_ADD( kbdev, JM_SUBMIT_AFTER_RESET, NULL, NULL, 0u, 0 );
+
+ spin_lock_irqsave(&js_devdata->runpool_irq.lock, flags);
+ kbasep_js_try_run_next_job_nolock(kbdev);
+ spin_unlock_irqrestore(&js_devdata->runpool_irq.lock, flags);
+ }
+ mutex_unlock( &js_devdata->runpool_mutex );
+
+ kbase_pm_context_idle(kbdev);
+ KBASE_TRACE_ADD( kbdev, JM_END_RESET_WORKER, NULL, NULL, 0u, 0 );
+}
+
+enum hrtimer_restart kbasep_reset_timer_callback(struct hrtimer * timer)
+{
+ kbase_device *kbdev = container_of(timer, kbase_device, reset_timer);
+
+ OSK_ASSERT(kbdev);
+
+ /* Reset still pending? */
+ if (atomic_cmpxchg(&kbdev->reset_gpu, KBASE_RESET_GPU_COMMITTED, KBASE_RESET_GPU_HAPPENING) ==
+ KBASE_RESET_GPU_COMMITTED)
+ {
+ queue_work(kbdev->reset_workq, &kbdev->reset_work);
+ }
+
+ return HRTIMER_NORESTART;
+}
+
+/*
+ * If all jobs are evicted from the GPU then we can reset the GPU
+ * immediately instead of waiting for the timeout to elapse
+ */
+
+static void kbasep_try_reset_gpu_early_locked(kbase_device *kbdev)
+{
+ int i;
+ int pending_jobs = 0;
+
+ OSK_ASSERT(kbdev);
+
+ /* Count the number of jobs */
+ for (i = 0; i < kbdev->gpu_props.num_job_slots; i++)
+ {
+ kbase_jm_slot *slot = &kbdev->jm_slots[i];
+ pending_jobs += kbasep_jm_nr_jobs_submitted(slot);
+ }
+
+ if (pending_jobs > 0)
+ {
+ /* There are still jobs on the GPU - wait */
+ return;
+ }
+
+ /* Check that the reset has been committed to (i.e. kbase_reset_gpu has been called), and that no other
+ * thread beat this thread to starting the reset */
+ if (atomic_cmpxchg(&kbdev->reset_gpu, KBASE_RESET_GPU_COMMITTED, KBASE_RESET_GPU_HAPPENING) !=
+ KBASE_RESET_GPU_COMMITTED)
+ {
+ /* Reset has already occurred */
+ return;
+ }
+ queue_work(kbdev->reset_workq, &kbdev->reset_work);
+}
+
+static void kbasep_try_reset_gpu_early(kbase_device *kbdev)
+{
+ unsigned long flags;
+ kbasep_js_device_data *js_devdata;
+
+ js_devdata = &kbdev->js_data;
+ spin_lock_irqsave(&js_devdata->runpool_irq.lock, flags);
+ kbasep_try_reset_gpu_early_locked(kbdev);
+ spin_unlock_irqrestore(&js_devdata->runpool_irq.lock, flags);
+}
+
+/*
+ * Prepare for resetting the GPU.
+ * This function just soft-stops all the slots to ensure that as many jobs as possible are saved.
+ *
+ * The function returns a boolean which should be interpreted as follows:
+ * - MALI_TRUE - Prepared for reset, kbase_reset_gpu should be called.
+ * - MALI_FALSE - Another thread is performing a reset, kbase_reset_gpu should not be called.
+ *
+ * @return See description
+ */
+mali_bool kbase_prepare_to_reset_gpu_locked(kbase_device *kbdev)
+{
+ int i;
+
+ OSK_ASSERT(kbdev);
+
+ if (atomic_cmpxchg(&kbdev->reset_gpu, KBASE_RESET_GPU_NOT_PENDING, KBASE_RESET_GPU_PREPARED) !=
+ KBASE_RESET_GPU_NOT_PENDING)
+ {
+ /* Some other thread is already resetting the GPU */
+ return MALI_FALSE;
+ }
+
+ OSK_PRINT_ERROR(OSK_BASE_JD, "Preparing to soft-reset GPU: Soft-stopping all jobs");
+
+ for (i = 0; i < kbdev->gpu_props.num_job_slots; i++)
+ {
+ kbase_job_slot_softstop(kbdev, i, NULL);
+ }
+
+ return MALI_TRUE;
+
+}
+
+mali_bool kbase_prepare_to_reset_gpu(kbase_device *kbdev)
+{
+ unsigned long flags;
+ mali_bool ret;
+ kbasep_js_device_data *js_devdata;
+
+ js_devdata = &kbdev->js_data;
+ spin_lock_irqsave(&js_devdata->runpool_irq.lock, flags);
+ ret = kbase_prepare_to_reset_gpu_locked(kbdev);
+ spin_unlock_irqrestore(&js_devdata->runpool_irq.lock, flags);
+
+ return ret;
+}
+KBASE_EXPORT_TEST_API(kbase_prepare_to_reset_gpu)
+
+
+
+/*
+ * This function should be called after kbase_prepare_to_reset_gpu iff it returns MALI_TRUE.
+ * It should never be called without a corresponding call to kbase_prepare_to_reset_gpu.
+ *
+ * After this function is called (or not called if kbase_prepare_to_reset_gpu returned MALI_FALSE),
+ * the caller should wait for kbdev->reset_waitq to be signalled to know when the reset has completed.
+ */
+void kbase_reset_gpu(kbase_device *kbdev)
+{
+ u32 timeout_ms;
+
+ OSK_ASSERT(kbdev);
+
+ /* Note this is an assert/atomic_set because it is a software issue for a race to be occuring here */
+ OSK_ASSERT(atomic_read(&kbdev->reset_gpu) == KBASE_RESET_GPU_PREPARED);
+ atomic_set(&kbdev->reset_gpu, KBASE_RESET_GPU_COMMITTED);
+
+ timeout_ms = kbasep_get_config_value(kbdev, kbdev->config_attributes, KBASE_CONFIG_ATTR_JS_RESET_TIMEOUT_MS);
+ hrtimer_start(&kbdev->reset_timer, HR_TIMER_DELAY_MSEC(timeout_ms), HRTIMER_MODE_REL);
+
+ /* Try resetting early */
+ kbasep_try_reset_gpu_early(kbdev);
+}
+KBASE_EXPORT_TEST_API(kbase_reset_gpu)
+
+void kbase_reset_gpu_locked(kbase_device *kbdev)
+{
+ u32 timeout_ms;
+
+ OSK_ASSERT(kbdev);
+
+ /* Note this is an assert/atomic_set because it is a software issue for a race to be occuring here */
+ OSK_ASSERT(atomic_read(&kbdev->reset_gpu) == KBASE_RESET_GPU_PREPARED);
+ atomic_set(&kbdev->reset_gpu, KBASE_RESET_GPU_COMMITTED);
+
+ timeout_ms = kbasep_get_config_value(kbdev, kbdev->config_attributes, KBASE_CONFIG_ATTR_JS_RESET_TIMEOUT_MS);
+ hrtimer_start(&kbdev->reset_timer, HR_TIMER_DELAY_MSEC(timeout_ms), HRTIMER_MODE_REL);
+
+ /* Try resetting early */
+ kbasep_try_reset_gpu_early_locked(kbdev);
+}
diff --git a/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_jm.h b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_jm.h
new file mode 100644
index 0000000..2f6d9b6
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_jm.h
@@ -0,0 +1,207 @@
+/*
+ *
+ * (C) COPYRIGHT 2011-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_kbase_jm.h
+ * Job Manager Low-level APIs.
+ */
+
+#ifndef _KBASE_JM_H_
+#define _KBASE_JM_H_
+
+#include <kbase/src/common/mali_kbase_8401_workaround.h>
+#include <kbase/src/common/mali_kbase_hw.h>
+#include <asm/atomic.h>
+
+
+/**
+ * @addtogroup base_api
+ * @{
+ */
+
+/**
+ * @addtogroup base_kbase_api
+ * @{
+ */
+
+
+/**
+ * @addtogroup kbase_jm Job Manager Low-level APIs
+ * @{
+ *
+ */
+
+static INLINE int kbasep_jm_is_js_free(kbase_device *kbdev, int js, kbase_context *kctx)
+{
+ OSK_ASSERT( kbdev != NULL );
+ OSK_ASSERT( 0 <= js && js < kbdev->gpu_props.num_job_slots );
+
+ return !kbase_reg_read(kbdev, JOB_SLOT_REG(js, JSn_COMMAND_NEXT), kctx);
+}
+
+/**
+ * This checks that:
+ * - there is enough space in the GPU's buffers (JSn_NEXT and JSn_HEAD registers) to accomodate the job.
+ * - there is enough space to track the job in a our Submit Slots. Note that we have to maintain space to
+ * requeue one job in case the next registers on the hardware need to be cleared.
+ */
+static INLINE mali_bool kbasep_jm_is_submit_slots_free(kbase_device *kbdev, int js, kbase_context *kctx)
+{
+ OSK_ASSERT( kbdev != NULL );
+ OSK_ASSERT( 0 <= js && js < kbdev->gpu_props.num_job_slots );
+
+ if (atomic_read(&kbdev->reset_gpu) != KBASE_RESET_GPU_NOT_PENDING)
+ {
+ /* The GPU is being reset - so prevent submission */
+ return MALI_FALSE;
+ }
+
+ return (mali_bool)( kbasep_jm_is_js_free(kbdev, js, kctx)
+ && kbdev->jm_slots[js].submitted_nr < (BASE_JM_SUBMIT_SLOTS-2) );
+}
+
+/**
+ * Initialize a submit slot
+ */
+static INLINE void kbasep_jm_init_submit_slot( kbase_jm_slot *slot )
+{
+ slot->submitted_nr = 0;
+ slot->submitted_head = 0;
+}
+
+/**
+ * Find the atom at the idx'th element in the queue without removing it, starting at the head with idx==0.
+ */
+static INLINE kbase_jd_atom* kbasep_jm_peek_idx_submit_slot( kbase_jm_slot *slot, u8 idx )
+{
+ u8 pos;
+ kbase_jd_atom *katom;
+
+ OSK_ASSERT( idx < BASE_JM_SUBMIT_SLOTS );
+
+ pos = (slot->submitted_head + idx) & BASE_JM_SUBMIT_SLOTS_MASK;
+ katom = slot->submitted[pos];
+
+ return katom;
+}
+
+/**
+ * Pop front of the submitted
+ */
+static INLINE kbase_jd_atom* kbasep_jm_dequeue_submit_slot( kbase_jm_slot *slot )
+{
+ u8 pos;
+ kbase_jd_atom *katom;
+
+ pos = slot->submitted_head & BASE_JM_SUBMIT_SLOTS_MASK;
+ katom = slot->submitted[pos];
+ slot->submitted[pos] = NULL; /* Just to catch bugs... */
+ OSK_ASSERT(katom);
+
+ /* rotate the buffers */
+ slot->submitted_head = (slot->submitted_head + 1) & BASE_JM_SUBMIT_SLOTS_MASK;
+ slot->submitted_nr--;
+
+ OSK_PRINT_INFO( OSK_BASE_JM, "katom %p new head %u",
+ (void *)katom, (unsigned int)slot->submitted_head);
+
+ return katom;
+}
+
+/* Pop back of the submitted queue (unsubmit a job)
+ */
+static INLINE kbase_jd_atom *kbasep_jm_dequeue_tail_submit_slot( kbase_jm_slot *slot )
+{
+ u8 pos;
+
+ slot->submitted_nr--;
+
+ pos = (slot->submitted_head + slot->submitted_nr) & BASE_JM_SUBMIT_SLOTS_MASK;
+
+ return slot->submitted[pos];
+}
+
+static INLINE u8 kbasep_jm_nr_jobs_submitted( kbase_jm_slot *slot )
+{
+ return slot->submitted_nr;
+}
+
+
+/**
+ * Push back of the submitted
+ */
+static INLINE void kbasep_jm_enqueue_submit_slot( kbase_jm_slot *slot, kbase_jd_atom *katom )
+{
+ u8 nr;
+ u8 pos;
+ nr = slot->submitted_nr++;
+ OSK_ASSERT(nr < BASE_JM_SUBMIT_SLOTS);
+
+ pos = (slot->submitted_head + nr) & BASE_JM_SUBMIT_SLOTS_MASK;
+ slot->submitted[pos] = katom;
+}
+
+/**
+ * @brief Query whether a job peeked/dequeued from the submit slots is a
+ * 'dummy' job that is used for hardware workaround purposes.
+ *
+ * Any time a job is peeked/dequeued from the submit slots, this should be
+ * queried on that job.
+ *
+ * If a \a atom is indicated as being a dummy job, then you <b>must not attempt
+ * to use \a atom</b>. This is because its members will not necessarily be
+ * initialized, and so could lead to a fault if they were used.
+ *
+ * @param[in] kbdev kbase device pointer
+ * @param[in] atom The atom to query
+ *
+ * @return MALI_TRUE if \a atom is for a dummy job, in which case you must not
+ * attempt to use it.
+ * @return MALI_FALSE otherwise, and \a atom is safe to use.
+ */
+static INLINE mali_bool kbasep_jm_is_dummy_workaround_job( kbase_device *kbdev, kbase_jd_atom *atom )
+{
+ /* Query the set of workaround jobs here */
+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8401))
+ {
+ if ( kbasep_8401_is_workaround_job( atom ) != MALI_FALSE )
+ {
+ return MALI_TRUE;
+ }
+ }
+
+ /* This job is not a workaround job, so it will be processed as normal */
+ return MALI_FALSE;
+}
+
+/**
+ * @brief Submit a job to a certain job-slot
+ *
+ * The caller must check kbasep_jm_is_submit_slots_free() != MALI_FALSE before calling this.
+ *
+ * The following locking conditions are made on the caller:
+ * - it must hold the kbasep_js_device_data::runpoool_irq::lock
+ */
+void kbase_job_submit_nolock(kbase_device *kbdev, kbase_jd_atom *katom, int js);
+
+/**
+ * @brief Complete the head job on a particular job-slot
+ */
+void kbase_job_done_slot(kbase_device *kbdev, int s, u32 completion_code, u64 job_tail, ktime_t *end_timestamp);
+
+/** @} */ /* end group kbase_jm */
+/** @} */ /* end group base_kbase_api */
+/** @} */ /* end group base_api */
+
+#endif /* _KBASE_JM_H_ */
diff --git a/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_js.c b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_js.c
new file mode 100644
index 0000000..f0833f3
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_js.c
@@ -0,0 +1,2110 @@
+/*
+ *
+ * (C) COPYRIGHT 2011-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/*
+ * Job Scheduler Implementation
+ */
+#include <kbase/src/common/mali_kbase.h>
+#include <kbase/src/common/mali_kbase_js.h>
+#include <kbase/src/common/mali_kbase_js_affinity.h>
+#include <kbase/src/common/mali_kbase_gator.h>
+#include <kbase/src/common/mali_kbase_hw.h>
+
+#include "mali_kbase_jm.h"
+#include <kbase/src/common/mali_kbase_defs.h>
+
+/*
+ * Private types
+ */
+
+/** Bitpattern indicating the result of releasing a context */
+enum
+{
+ /** The context was descheduled - caller should try scheduling in a new one
+ * to keep the runpool full */
+ KBASEP_JS_RELEASE_RESULT_WAS_DESCHEDULED = (1u << 0),
+};
+
+typedef u32 kbasep_js_release_result;
+
+/*
+ * Private function prototypes
+ */
+STATIC INLINE void kbasep_js_deref_permon_check_and_disable_cycle_counter( kbase_device *kbdev,
+ kbase_jd_atom * katom );
+
+STATIC INLINE void kbasep_js_ref_permon_check_and_enable_cycle_counter( kbase_device *kbdev,
+ kbase_jd_atom * katom );
+
+STATIC kbasep_js_release_result kbasep_js_runpool_release_ctx_internal(
+ kbase_device *kbdev,
+ kbase_context *kctx,
+ kbasep_js_atom_retained_state *katom_retained_state );
+
+/** Helper for trace subcodes */
+#if KBASE_TRACE_ENABLE != 0
+STATIC int kbasep_js_trace_get_refcnt( kbase_device *kbdev, kbase_context *kctx )
+{
+ unsigned long flags;
+ kbasep_js_device_data *js_devdata;
+ int as_nr;
+ int refcnt = 0;
+
+ js_devdata = &kbdev->js_data;
+
+ spin_lock_irqsave( &js_devdata->runpool_irq.lock, flags);
+ as_nr = kctx->as_nr;
+ if ( as_nr != KBASEP_AS_NR_INVALID )
+ {
+ kbasep_js_per_as_data *js_per_as_data;
+ js_per_as_data = &js_devdata->runpool_irq.per_as_data[as_nr];
+
+ refcnt = js_per_as_data->as_busy_refcount;
+ }
+ spin_unlock_irqrestore( &js_devdata->runpool_irq.lock, flags);
+
+ return refcnt;
+}
+#else /* KBASE_TRACE_ENABLE != 0 */
+STATIC int kbasep_js_trace_get_refcnt( kbase_device *kbdev, kbase_context *kctx )
+{
+ CSTD_UNUSED( kbdev );
+ CSTD_UNUSED( kctx );
+ return 0;
+}
+#endif /* KBASE_TRACE_ENABLE != 0 */
+
+
+
+/*
+ * Private types
+ */
+enum
+{
+ JS_DEVDATA_INIT_NONE =0,
+ JS_DEVDATA_INIT_CONSTANTS =(1 << 0),
+ JS_DEVDATA_INIT_POLICY =(1 << 1),
+ JS_DEVDATA_INIT_ALL =((1 << 2)-1)
+};
+
+enum
+{
+ JS_KCTX_INIT_NONE =0,
+ JS_KCTX_INIT_CONSTANTS =(1 << 0),
+ JS_KCTX_INIT_POLICY =(1 << 1),
+ JS_KCTX_INIT_ALL =((1 << 2)-1)
+};
+
+/*
+ * Private functions
+ */
+
+/**
+ * Check if the job had performance monitoring enabled and decrement the count. If no jobs require
+ * performance monitoring, then the cycle counters will be disabled in the GPU.
+ *
+ * No locks need to be held - locking is handled further down
+ *
+ * This function does not sleep.
+ */
+
+STATIC INLINE void kbasep_js_deref_permon_check_and_disable_cycle_counter( kbase_device *kbdev, kbase_jd_atom * katom )
+{
+ OSK_ASSERT( kbdev != NULL );
+ OSK_ASSERT( katom != NULL );
+
+ if ( katom->core_req & BASE_JD_REQ_PERMON )
+ {
+ kbase_pm_release_gpu_cycle_counter(kbdev);
+ }
+}
+
+/**
+ * Check if the job has performance monitoring enabled and keep a count of it. If at least one
+ * job requires performance monitoring, then the cycle counters will be enabled in the GPU.
+ *
+ * No locks need to be held - locking is handled further down
+ *
+ * This function does not sleep.
+ */
+
+STATIC INLINE void kbasep_js_ref_permon_check_and_enable_cycle_counter( kbase_device *kbdev, kbase_jd_atom * katom )
+{
+ OSK_ASSERT( kbdev != NULL );
+ OSK_ASSERT( katom != NULL );
+
+ if ( katom->core_req & BASE_JD_REQ_PERMON )
+ {
+ kbase_pm_request_gpu_cycle_counter(kbdev);
+ }
+}
+
+/*
+ * The following locking conditions are made on the caller:
+ * - The caller must hold the kbasep_js_kctx_info::ctx::jsctx_mutex.
+ * - The caller must hold the kbasep_js_device_data::runpool_mutex
+ */
+STATIC INLINE void runpool_inc_context_count( kbase_device *kbdev, kbase_context *kctx )
+{
+ kbasep_js_device_data *js_devdata;
+ kbasep_js_kctx_info *js_kctx_info;
+ OSK_ASSERT( kbdev != NULL );
+ OSK_ASSERT( kctx != NULL );
+
+ js_devdata = &kbdev->js_data;
+ js_kctx_info = &kctx->jctx.sched_info;
+
+ BUG_ON(!mutex_is_locked( &js_kctx_info->ctx.jsctx_mutex ));
+ BUG_ON(!mutex_is_locked( &js_devdata->runpool_mutex ));
+
+ /* Track total contexts */
+ ++(js_devdata->nr_all_contexts_running);
+
+ if ( (js_kctx_info->ctx.flags & KBASE_CTX_FLAG_SUBMIT_DISABLED) == 0 )
+ {
+ /* Track contexts that can submit jobs */
+ ++(js_devdata->nr_user_contexts_running);
+ }
+}
+
+/*
+ * The following locking conditions are made on the caller:
+ * - The caller must hold the kbasep_js_kctx_info::ctx::jsctx_mutex.
+ * - The caller must hold the kbasep_js_device_data::runpool_mutex
+ */
+STATIC INLINE void runpool_dec_context_count( kbase_device *kbdev, kbase_context *kctx )
+{
+ kbasep_js_device_data *js_devdata;
+ kbasep_js_kctx_info *js_kctx_info;
+ OSK_ASSERT( kbdev != NULL );
+ OSK_ASSERT( kctx != NULL );
+
+ js_devdata = &kbdev->js_data;
+ js_kctx_info = &kctx->jctx.sched_info;
+
+ BUG_ON(!mutex_is_locked( &js_kctx_info->ctx.jsctx_mutex ));
+ BUG_ON(!mutex_is_locked( &js_devdata->runpool_mutex ));
+
+ /* Track total contexts */
+ --(js_devdata->nr_all_contexts_running);
+
+ if ( (js_kctx_info->ctx.flags & KBASE_CTX_FLAG_SUBMIT_DISABLED) == 0 )
+ {
+ /* Track contexts that can submit jobs */
+ --(js_devdata->nr_user_contexts_running);
+ }
+}
+
+/**
+ * @brief check whether the runpool is full for a specified context
+ *
+ * If kctx == NULL, then this makes the least restrictive check on the
+ * runpool. A specific context that is supplied immediately after could fail
+ * the check, even under the same conditions.
+ *
+ * Therefore, once a context is obtained you \b must re-check it with this
+ * function, since the return value could change to MALI_FALSE.
+ *
+ * The following locking conditions are made on the caller:
+ * - In all cases, the caller must hold kbasep_js_device_data::runpool_mutex
+ * - When kctx != NULL the caller must hold the kbasep_js_kctx_info::ctx::jsctx_mutex.
+ * - When kctx == NULL, then the caller need not hold any jsctx_mutex locks (but it doesn't do any harm to do so).
+ */
+STATIC mali_bool check_is_runpool_full( kbase_device *kbdev, kbase_context *kctx )
+{
+ kbasep_js_device_data *js_devdata;
+ mali_bool is_runpool_full;
+ OSK_ASSERT( kbdev != NULL );
+
+ js_devdata = &kbdev->js_data;
+ BUG_ON(!mutex_is_locked( &js_devdata->runpool_mutex ));
+
+ is_runpool_full = (mali_bool)(js_devdata->nr_all_contexts_running >= kbdev->nr_hw_address_spaces);
+
+ if ( kctx != NULL && (kctx->jctx.sched_info.ctx.flags & KBASE_CTX_FLAG_SUBMIT_DISABLED) == 0 )
+ {
+ BUG_ON(!mutex_is_locked( &kctx->jctx.sched_info.ctx.jsctx_mutex ));
+ /* Contexts that don't submit might use less of the address spaces available, due to HW workarounds */
+ is_runpool_full = (mali_bool)(js_devdata->nr_user_contexts_running >= kbdev->nr_user_address_spaces);
+ }
+
+ return is_runpool_full;
+}
+
+
+STATIC base_jd_core_req core_reqs_from_jsn_features( u16 features /* JS<n>_FEATURE register value */ )
+{
+ base_jd_core_req core_req = 0u;
+
+ if ( (features & JSn_FEATURE_SET_VALUE_JOB) != 0 )
+ {
+ core_req |= BASE_JD_REQ_V;
+ }
+ if ( (features & JSn_FEATURE_CACHE_FLUSH_JOB) != 0 )
+ {
+ core_req |= BASE_JD_REQ_CF;
+ }
+ if ( (features & JSn_FEATURE_COMPUTE_JOB) != 0 )
+ {
+ core_req |= BASE_JD_REQ_CS;
+ }
+ if ( (features & JSn_FEATURE_TILER_JOB) != 0 )
+ {
+ core_req |= BASE_JD_REQ_T;
+ }
+ if ( (features & JSn_FEATURE_FRAGMENT_JOB) != 0 )
+ {
+ core_req |= BASE_JD_REQ_FS;
+ }
+ return core_req;
+}
+
+/**
+ * Picks and reserves an address space.
+ *
+ * When this function returns, the address space returned is reserved and
+ * cannot be picked for another context until it is released.
+ *
+ * The caller must ensure there \b is a free address space before calling this.
+ *
+ * The following locking conditions are made on the caller:
+ * - it must hold kbasep_js_device_data::runpool_mutex
+ *
+ * @return a non-NULL pointer to a kbase_as that is not in use by any other context
+ */
+STATIC kbase_as *pick_free_addr_space( kbase_device *kbdev )
+{
+ kbasep_js_device_data *js_devdata;
+ kbase_as *current_as;
+ long ffs_result;
+ js_devdata = &kbdev->js_data;
+
+ lockdep_assert_held(&js_devdata->runpool_mutex);
+
+ /* Find the free address space */
+ ffs_result = osk_find_first_set_bit( js_devdata->as_free );
+ /* ASSERT that we should've found a free one */
+ OSK_ASSERT( 0 <= ffs_result && ffs_result < kbdev->nr_hw_address_spaces );
+ /* Ensure no-one else picks this one */
+ js_devdata->as_free &= ~((u16)(1u << ffs_result));
+
+ current_as = &kbdev->as[ffs_result];
+
+ return current_as;
+}
+
+/**
+ * Release an address space, making it available for being picked again.
+ *
+ * The following locking conditions are made on the caller:
+ * - it must hold kbasep_js_device_data::runpool_mutex
+ */
+STATIC INLINE void release_addr_space( kbase_device *kbdev, int kctx_as_nr )
+{
+ kbasep_js_device_data *js_devdata;
+ u16 as_bit = (1u << kctx_as_nr);
+
+ js_devdata = &kbdev->js_data;
+ lockdep_assert_held(&js_devdata->runpool_mutex);
+
+ /* The address space must not already be free */
+ OSK_ASSERT( !(js_devdata->as_free & as_bit) );
+
+ js_devdata->as_free |= as_bit;
+}
+
+/**
+ * Assign an Address Space (AS) to a context, and add the context to the Policy.
+ *
+ * This includes:
+ * - setting up the global runpool_irq structure and the context on the AS
+ * - Activating the MMU on the AS
+ * - Allowing jobs to be submitted on the AS
+ *
+ * Locking conditions:
+ * - Caller must hold the kbasep_js_kctx_info::jsctx_mutex
+ * - Caller must hold the kbasep_js_device_data::runpool_mutex
+ * - Caller must hold AS transaction mutex
+ * - Caller must hold Runpool IRQ lock
+ */
+STATIC void assign_and_activate_kctx_addr_space( kbase_device *kbdev, kbase_context *kctx, kbase_as *current_as )
+{
+ kbasep_js_device_data *js_devdata;
+ kbasep_js_per_as_data *js_per_as_data;
+ int as_nr;
+
+ OSK_ASSERT( kbdev != NULL );
+ OSK_ASSERT( kctx != NULL );
+ OSK_ASSERT( current_as != NULL );
+
+ js_devdata = &kbdev->js_data;
+ as_nr = current_as->number;
+
+ lockdep_assert_held(&kctx->jctx.sched_info.ctx.jsctx_mutex);
+ lockdep_assert_held(&js_devdata->runpool_mutex);
+ lockdep_assert_held(¤t_as->transaction_mutex);
+ lockdep_assert_held(&js_devdata->runpool_irq.lock);
+
+ js_per_as_data = &js_devdata->runpool_irq.per_as_data[as_nr];
+
+ /* Attribute handling */
+ kbasep_js_ctx_attr_runpool_retain_ctx( kbdev, kctx );
+
+ /* Assign addr space */
+ kctx->as_nr = as_nr;
+#ifdef CONFIG_MALI_GATOR_SUPPORT
+ kbase_trace_mali_mmu_as_in_use(kctx->as_nr);
+#endif /* CONFIG_MALI_GATOR_SUPPORT */
+ /* Activate this address space on the MMU */
+ kbase_mmu_update( kctx );
+
+ /* Allow it to run jobs */
+ kbasep_js_set_submit_allowed( js_devdata, kctx );
+
+ /* Book-keeping */
+ js_per_as_data->kctx = kctx;
+ js_per_as_data->as_busy_refcount = 0;
+
+ /* Lastly, add the context to the policy's runpool - this really allows it to run jobs */
+ kbasep_js_policy_runpool_add_ctx( &js_devdata->policy, kctx );
+
+}
+
+void kbasep_js_try_run_next_job_nolock( kbase_device *kbdev )
+{
+ kbasep_js_device_data *js_devdata;
+ int js;
+
+ OSK_ASSERT( kbdev != NULL );
+ js_devdata = &kbdev->js_data;
+ lockdep_assert_held(&js_devdata->runpool_mutex);
+ lockdep_assert_held(&js_devdata->runpool_irq.lock);
+
+ /* It's cheap and simple to retest this here - otherwise we burden the
+ * caller with it. In some cases, we do this higher up to optimize out the
+ * spinlock. */
+ if ( js_devdata->nr_user_contexts_running == 0 )
+ {
+ /* No contexts present - the GPU might be powered off, so just return */
+ return;
+ }
+
+ for ( js = 0; js < kbdev->gpu_props.num_job_slots ; ++js )
+ {
+ kbasep_js_try_run_next_job_on_slot_nolock( kbdev, js );
+ }
+}
+
+/** Hold the kbasep_js_device_data::runpool_irq::lock for this */
+mali_bool kbasep_js_runpool_retain_ctx_nolock( kbase_device *kbdev, kbase_context *kctx )
+{
+ kbasep_js_device_data *js_devdata;
+ kbasep_js_per_as_data *js_per_as_data;
+ mali_bool result = MALI_FALSE;
+ int as_nr;
+ OSK_ASSERT( kbdev != NULL );
+ OSK_ASSERT( kctx != NULL );
+ js_devdata = &kbdev->js_data;
+
+ as_nr = kctx->as_nr;
+ if ( as_nr != KBASEP_AS_NR_INVALID )
+ {
+ int new_refcnt;
+
+ OSK_ASSERT( as_nr >= 0 );
+ js_per_as_data = &js_devdata->runpool_irq.per_as_data[as_nr];
+
+ OSK_ASSERT( js_per_as_data->kctx != NULL );
+
+ new_refcnt = ++(js_per_as_data->as_busy_refcount);
+ KBASE_TRACE_ADD_REFCOUNT( kbdev, JS_RETAIN_CTX_NOLOCK, kctx, NULL, 0u,
+ new_refcnt );
+ result = MALI_TRUE;
+ }
+
+ return result;
+}
+
+/*
+ * Functions private to KBase ('Protected' functions)
+ */
+void kbase_js_try_run_jobs( kbase_device *kbdev )
+{
+ kbasep_js_device_data *js_devdata;
+ unsigned long flags;
+
+ OSK_ASSERT( kbdev != NULL );
+ js_devdata = &kbdev->js_data;
+
+ mutex_lock( &js_devdata->runpool_mutex );
+ if (js_devdata->nr_user_contexts_running != 0)
+ {
+ /* Only try running jobs when we have contexts present, otherwise the GPU might be powered off. */
+ spin_lock_irqsave( &js_devdata->runpool_irq.lock, flags);
+
+ kbasep_js_try_run_next_job_nolock( kbdev );
+
+ spin_unlock_irqrestore( &js_devdata->runpool_irq.lock, flags);
+ }
+ mutex_unlock( &js_devdata->runpool_mutex );
+}
+
+
+void kbase_js_try_run_jobs_on_slot( kbase_device *kbdev, int js )
+{
+ unsigned long flags;
+ kbasep_js_device_data *js_devdata;
+
+ OSK_ASSERT( kbdev != NULL );
+ js_devdata = &kbdev->js_data;
+
+ mutex_lock( &js_devdata->runpool_mutex );
+ if (js_devdata->nr_user_contexts_running != 0)
+ {
+ /* Only try running jobs when we have contexts present, otherwise the GPU might be powered off. */
+ spin_lock_irqsave(&js_devdata->runpool_irq.lock, flags);
+
+ kbasep_js_try_run_next_job_on_slot_nolock( kbdev, js );
+
+ spin_unlock_irqrestore(&js_devdata->runpool_irq.lock, flags);
+ }
+ mutex_unlock( &js_devdata->runpool_mutex );
+}
+
+
+mali_error kbasep_js_devdata_init( kbase_device *kbdev )
+{
+ kbasep_js_device_data *js_devdata;
+ mali_error err;
+ int i;
+ u16 as_present;
+
+ OSK_ASSERT( kbdev != NULL );
+
+ js_devdata = &kbdev->js_data;
+
+ OSK_ASSERT( js_devdata->init_status == JS_DEVDATA_INIT_NONE );
+
+ /* These two must be recalculated if nr_hw_address_spaces changes (e.g. for HW workarounds) */
+ as_present = (1U << kbdev->nr_hw_address_spaces) - 1;
+ kbdev->nr_user_address_spaces = kbdev->nr_hw_address_spaces;
+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8987))
+ {
+ mali_bool use_workaround_for_security;
+ use_workaround_for_security = (mali_bool)kbasep_get_config_value( kbdev, kbdev->config_attributes, KBASE_CONFIG_ATTR_SECURE_BUT_LOSS_OF_PERFORMANCE );
+ if ( use_workaround_for_security != MALI_FALSE )
+ {
+ OSK_PRINT(OSK_BASE_JM, "GPU has HW ISSUE 8987, and driver configured for security workaround: 1 address space only");
+ kbdev->nr_user_address_spaces = 1;
+ }
+ }
+#ifdef CONFIG_MALI_DEBUG
+ /* Soft-stop will be disabled on a single context by default unless softstop_always is set */
+ js_devdata->softstop_always = MALI_FALSE;
+#endif /* CONFIG_MALI_DEBUG */
+ js_devdata->nr_all_contexts_running = 0;
+ js_devdata->nr_user_contexts_running = 0;
+ js_devdata->as_free = as_present; /* All ASs initially free */
+ js_devdata->runpool_irq.submit_allowed = 0u; /* No ctx allowed to submit */
+ memset( js_devdata->runpool_irq.ctx_attr_ref_count, 0, sizeof(js_devdata->runpool_irq.ctx_attr_ref_count) );
+ memset( js_devdata->runpool_irq.slot_affinities, 0, sizeof( js_devdata->runpool_irq.slot_affinities ) );
+ js_devdata->runpool_irq.slots_blocked_on_affinity = 0u;
+ memset( js_devdata->runpool_irq.slot_affinity_refcount, 0, sizeof( js_devdata->runpool_irq.slot_affinity_refcount ) );
+
+ /* Config attributes */
+ js_devdata->scheduling_tick_ns = (u32)kbasep_get_config_value( kbdev, kbdev->config_attributes, KBASE_CONFIG_ATTR_JS_SCHEDULING_TICK_NS );
+ js_devdata->soft_stop_ticks = (u32)kbasep_get_config_value( kbdev, kbdev->config_attributes, KBASE_CONFIG_ATTR_JS_SOFT_STOP_TICKS );
+ js_devdata->hard_stop_ticks_ss = (u32)kbasep_get_config_value( kbdev, kbdev->config_attributes, KBASE_CONFIG_ATTR_JS_HARD_STOP_TICKS_SS );
+ js_devdata->hard_stop_ticks_nss = (u32)kbasep_get_config_value( kbdev, kbdev->config_attributes, KBASE_CONFIG_ATTR_JS_HARD_STOP_TICKS_NSS );
+ js_devdata->gpu_reset_ticks_ss = (u32)kbasep_get_config_value( kbdev, kbdev->config_attributes, KBASE_CONFIG_ATTR_JS_RESET_TICKS_SS );
+ js_devdata->gpu_reset_ticks_nss = (u32)kbasep_get_config_value( kbdev, kbdev->config_attributes, KBASE_CONFIG_ATTR_JS_RESET_TICKS_NSS );
+ js_devdata->ctx_timeslice_ns = (u32)kbasep_get_config_value( kbdev, kbdev->config_attributes, KBASE_CONFIG_ATTR_JS_CTX_TIMESLICE_NS );
+ js_devdata->cfs_ctx_runtime_init_slices = (u32)kbasep_get_config_value( kbdev, kbdev->config_attributes, KBASE_CONFIG_ATTR_JS_CFS_CTX_RUNTIME_INIT_SLICES );
+ js_devdata->cfs_ctx_runtime_min_slices = (u32)kbasep_get_config_value( kbdev, kbdev->config_attributes, KBASE_CONFIG_ATTR_JS_CFS_CTX_RUNTIME_MIN_SLICES );
+
+ OSK_PRINT_INFO( OSK_BASE_JM, "JS Config Attribs: " );
+ OSK_PRINT_INFO( OSK_BASE_JM, "\tjs_devdata->scheduling_tick_ns:%u", js_devdata->scheduling_tick_ns );
+ OSK_PRINT_INFO( OSK_BASE_JM, "\tjs_devdata->soft_stop_ticks:%u", js_devdata->soft_stop_ticks );
+ OSK_PRINT_INFO( OSK_BASE_JM, "\tjs_devdata->hard_stop_ticks_ss:%u", js_devdata->hard_stop_ticks_ss );
+ OSK_PRINT_INFO( OSK_BASE_JM, "\tjs_devdata->hard_stop_ticks_nss:%u", js_devdata->hard_stop_ticks_nss );
+ OSK_PRINT_INFO( OSK_BASE_JM, "\tjs_devdata->gpu_reset_ticks_ss:%u", js_devdata->gpu_reset_ticks_ss );
+ OSK_PRINT_INFO( OSK_BASE_JM, "\tjs_devdata->gpu_reset_ticks_nss:%u", js_devdata->gpu_reset_ticks_nss );
+ OSK_PRINT_INFO( OSK_BASE_JM, "\tjs_devdata->ctx_timeslice_ns:%u", js_devdata->ctx_timeslice_ns );
+ OSK_PRINT_INFO( OSK_BASE_JM, "\tjs_devdata->cfs_ctx_runtime_init_slices:%u", js_devdata->cfs_ctx_runtime_init_slices );
+ OSK_PRINT_INFO( OSK_BASE_JM, "\tjs_devdata->cfs_ctx_runtime_min_slices:%u", js_devdata->cfs_ctx_runtime_min_slices );
+
+#if KBASE_DISABLE_SCHEDULING_SOFT_STOPS != 0
+ OSK_PRINT( OSK_BASE_JM,
+ "Job Scheduling Policy Soft-stops disabled, ignoring value for soft_stop_ticks==%u at %uns per tick. Other soft-stops may still occur.",
+ js_devdata->soft_stop_ticks,
+ js_devdata->scheduling_tick_ns );
+#endif
+#if KBASE_DISABLE_SCHEDULING_HARD_STOPS != 0
+ OSK_PRINT( OSK_BASE_JM,
+ "Job Scheduling Policy Hard-stops disabled, ignoring values for hard_stop_ticks_ss==%d and hard_stop_ticks_nss==%u at %uns per tick. Other hard-stops may still occur.",
+ js_devdata->hard_stop_ticks_ss,
+ js_devdata->hard_stop_ticks_nss,
+ js_devdata->scheduling_tick_ns );
+#endif
+#if KBASE_DISABLE_SCHEDULING_SOFT_STOPS != 0 && KBASE_DISABLE_SCHEDULING_HARD_STOPS != 0
+ OSK_PRINT( OSK_BASE_JM, "Note: The JS policy's tick timer (if coded) will still be run, but do nothing." );
+#endif
+
+ /* setup the number of irq throttle cycles base on given time */
+ {
+ int irq_throttle_time_us = kbdev->gpu_props.irq_throttle_time_us;
+ int irq_throttle_cycles = kbasep_js_convert_us_to_gpu_ticks_max_freq(kbdev, irq_throttle_time_us);
+ atomic_set( &kbdev->irq_throttle_cycles, irq_throttle_cycles);
+ }
+
+ /* Clear the AS data, including setting NULL pointers */
+ memset( &js_devdata->runpool_irq.per_as_data[0], 0, sizeof(js_devdata->runpool_irq.per_as_data) );
+
+ for ( i = 0; i < kbdev->gpu_props.num_job_slots; ++i )
+ {
+ js_devdata->js_reqs[i] = core_reqs_from_jsn_features( kbdev->gpu_props.props.raw_props.js_features[i] );
+ }
+ js_devdata->init_status |= JS_DEVDATA_INIT_CONSTANTS;
+
+ /* On error, we could continue on: providing none of the below resources
+ * rely on the ones above */
+
+ mutex_init( &js_devdata->runpool_mutex);
+ mutex_init( &js_devdata->queue_mutex);
+ spin_lock_init( &js_devdata->runpool_irq.lock);
+
+ err = kbasep_js_policy_init( kbdev );
+ if ( err == MALI_ERROR_NONE)
+ {
+ js_devdata->init_status |= JS_DEVDATA_INIT_POLICY;
+ }
+
+ /* On error, do no cleanup; this will be handled by the caller(s), since
+ * we've designed this resource to be safe to terminate on init-fail */
+ if ( js_devdata->init_status != JS_DEVDATA_INIT_ALL)
+ {
+ return MALI_ERROR_FUNCTION_FAILED;
+ }
+
+ return MALI_ERROR_NONE;
+}
+
+void kbasep_js_devdata_halt( kbase_device *kbdev )
+{
+ CSTD_UNUSED(kbdev);
+}
+
+void kbasep_js_devdata_term( kbase_device *kbdev )
+{
+ kbasep_js_device_data *js_devdata;
+
+ OSK_ASSERT( kbdev != NULL );
+
+ js_devdata = &kbdev->js_data;
+
+ if ( (js_devdata->init_status & JS_DEVDATA_INIT_CONSTANTS) )
+ {
+ s8 zero_ctx_attr_ref_count[KBASEP_JS_CTX_ATTR_COUNT] = { 0, };
+ /* The caller must de-register all contexts before calling this */
+ OSK_ASSERT( js_devdata->nr_all_contexts_running == 0 );
+ OSK_ASSERT( memcmp( js_devdata->runpool_irq.ctx_attr_ref_count, zero_ctx_attr_ref_count, sizeof(js_devdata->runpool_irq.ctx_attr_ref_count)) == 0 );
+ CSTD_UNUSED( zero_ctx_attr_ref_count );
+ }
+ if ( (js_devdata->init_status & JS_DEVDATA_INIT_POLICY) )
+ {
+ kbasep_js_policy_term( &js_devdata->policy );
+ }
+ js_devdata->init_status = JS_DEVDATA_INIT_NONE;
+}
+
+
+mali_error kbasep_js_kctx_init( kbase_context *kctx )
+{
+ kbase_device *kbdev;
+ kbasep_js_kctx_info *js_kctx_info;
+ mali_error err;
+
+ OSK_ASSERT( kctx != NULL );
+
+ kbdev = kctx->kbdev;
+ OSK_ASSERT( kbdev != NULL );
+
+ js_kctx_info = &kctx->jctx.sched_info;
+ OSK_ASSERT( js_kctx_info->init_status == JS_KCTX_INIT_NONE );
+
+ js_kctx_info->ctx.nr_jobs = 0;
+ js_kctx_info->ctx.is_scheduled = MALI_FALSE;
+ js_kctx_info->ctx.is_dying = MALI_FALSE;
+ memset( js_kctx_info->ctx.ctx_attr_ref_count, 0, sizeof(js_kctx_info->ctx.ctx_attr_ref_count) );
+
+ /* Initially, the context is disabled from submission until the create flags are set */
+ js_kctx_info->ctx.flags = KBASE_CTX_FLAG_SUBMIT_DISABLED;
+
+ js_kctx_info->init_status |= JS_KCTX_INIT_CONSTANTS;
+
+ /* On error, we could continue on: providing none of the below resources
+ * rely on the ones above */
+ mutex_init( &js_kctx_info->ctx.jsctx_mutex);
+
+ init_waitqueue_head(&js_kctx_info->ctx.is_scheduled_wait);
+
+ err = kbasep_js_policy_init_ctx( kbdev, kctx );
+ if ( err == MALI_ERROR_NONE )
+ {
+ js_kctx_info->init_status |= JS_KCTX_INIT_POLICY;
+ }
+
+ /* On error, do no cleanup; this will be handled by the caller(s), since
+ * we've designed this resource to be safe to terminate on init-fail */
+ if ( js_kctx_info->init_status != JS_KCTX_INIT_ALL)
+ {
+ return MALI_ERROR_FUNCTION_FAILED;
+ }
+
+ return MALI_ERROR_NONE;
+}
+
+void kbasep_js_kctx_term( kbase_context *kctx )
+{
+ kbase_device *kbdev;
+ kbasep_js_kctx_info *js_kctx_info;
+ kbasep_js_policy *js_policy;
+
+ OSK_ASSERT( kctx != NULL );
+
+ kbdev = kctx->kbdev;
+ OSK_ASSERT( kbdev != NULL );
+
+ js_policy = &kbdev->js_data.policy;
+ js_kctx_info = &kctx->jctx.sched_info;
+
+ if ( (js_kctx_info->init_status & JS_KCTX_INIT_CONSTANTS) )
+ {
+ /* The caller must de-register all jobs before calling this */
+ OSK_ASSERT( js_kctx_info->ctx.is_scheduled == MALI_FALSE );
+ OSK_ASSERT( js_kctx_info->ctx.nr_jobs == 0 );
+ /* Only certain Ctx Attributes will be zero (others can have a non-zero value for the life of the context) */
+ OSK_ASSERT( kbasep_js_ctx_attr_count_on_runpool( kbdev, KBASEP_JS_CTX_ATTR_NSS ) == 0 );
+ }
+
+ if ( (js_kctx_info->init_status & JS_KCTX_INIT_POLICY) )
+ {
+ kbasep_js_policy_term_ctx( js_policy, kctx );
+ }
+
+ js_kctx_info->init_status = JS_KCTX_INIT_NONE;
+}
+
+/* Evict jobs from the NEXT registers
+ *
+ * The caller must hold:
+ * - kbasep_js_kctx_info::ctx::jsctx_mutex
+ * - kbasep_js_device_data::runpool_mutex
+ */
+STATIC void kbasep_js_runpool_evict_next_jobs( kbase_device *kbdev, kbase_context *kctx )
+{
+ unsigned long flags;
+ int js;
+ kbasep_js_device_data *js_devdata;
+
+ js_devdata = &kbdev->js_data;
+
+ BUG_ON(!mutex_is_locked( &kctx->jctx.sched_info.ctx.jsctx_mutex ));
+ BUG_ON(!mutex_is_locked( &js_devdata->runpool_mutex ));
+
+ /* Prevent contexts in the runpool from submitting jobs */
+ spin_lock_irqsave(&js_devdata->runpool_irq.lock, flags);
+
+ /* There's no need to prevent contexts in the runpool from submitting jobs,
+ * because we complete this operation by the time we release the
+ * runpool_irq.lock */
+
+ /* Evict jobs from the NEXT registers */
+ for (js = 0; js < kbdev->gpu_props.num_job_slots; js++)
+ {
+ kbase_jm_slot *slot;
+ kbase_jd_atom *tail;
+
+ if (!kbase_reg_read(kbdev, JOB_SLOT_REG(js, JSn_COMMAND_NEXT), NULL))
+ {
+ /* No job in the NEXT register */
+ continue;
+ }
+
+ slot = &kbdev->jm_slots[js];
+ tail = kbasep_jm_peek_idx_submit_slot(slot, slot->submitted_nr-1);
+
+ /* Clearing job from next registers */
+ kbase_reg_write(kbdev, JOB_SLOT_REG(js, JSn_COMMAND_NEXT), JSn_COMMAND_NOP, NULL);
+
+ /* Check to see if we did remove a job from the next registers */
+ if (kbase_reg_read(kbdev, JOB_SLOT_REG(js, JSn_HEAD_NEXT_LO), NULL) != 0 ||
+ kbase_reg_read(kbdev, JOB_SLOT_REG(js, JSn_HEAD_NEXT_HI), NULL) != 0)
+ {
+ /* The job was successfully cleared from the next registers, requeue it */
+ slot->submitted_nr--;
+
+ /* Set the next registers to NULL */
+ kbase_reg_write(kbdev, JOB_SLOT_REG(js, JSn_HEAD_NEXT_LO), 0, NULL);
+ kbase_reg_write(kbdev, JOB_SLOT_REG(js, JSn_HEAD_NEXT_HI), 0, NULL);
+
+ tail->event_code = BASE_JD_EVENT_REMOVED_FROM_NEXT;
+
+ /* Complete the job, indicate that it took no time, and start_new_jobs==MALI_FALSE */
+ kbase_jd_done(tail, js, NULL, MALI_FALSE);
+ }
+
+ }
+ spin_unlock_irqrestore(&js_devdata->runpool_irq.lock, flags);
+}
+
+/**
+ * Fast start a higher priority job
+ * If the runpool is full, the lower priority contexts with no running jobs
+ * will be evicted from the runpool
+ *
+ * If \a kctx_new is NULL, the first context with no running jobs will be evicted
+ *
+ * The following locking conditions are made on the caller:
+ * - The caller must \b not hold \a kctx_new's
+ * kbasep_js_kctx_info::ctx::jsctx_mutex, or that mutex of any ctx in the
+ * runpool. This is because \a kctx_new's jsctx_mutex and one of the other
+ * scheduled ctx's jsctx_mutex will be obtained internally.
+ * - it must \em not hold kbasep_js_device_data::runpool_irq::lock (as this will be
+ * obtained internally)
+ * - it must \em not hold kbasep_js_device_data::runpool_mutex (as this will be
+ * obtained internally)
+ * - it must \em not hold kbasep_jd_device_data::queue_mutex (again, it's used
+ * internally).
+ */
+STATIC void kbasep_js_runpool_attempt_fast_start_ctx( kbase_device *kbdev, kbase_context *kctx_new )
+{
+ unsigned long flags;
+ kbasep_js_device_data *js_devdata;
+ kbasep_js_kctx_info *js_kctx_new;
+ kbasep_js_policy *js_policy;
+ kbasep_js_per_as_data *js_per_as_data;
+ int evict_as_nr;
+ kbasep_js_atom_retained_state katom_retained_state;
+
+ OSK_ASSERT(kbdev != NULL);
+
+ js_devdata = &kbdev->js_data;
+ js_policy = &kbdev->js_data.policy;
+
+ if (kctx_new != NULL)
+ {
+ js_kctx_new = &kctx_new->jctx.sched_info;
+ mutex_lock( &js_kctx_new->ctx.jsctx_mutex );
+ }
+ else
+ {
+ js_kctx_new = NULL;
+ CSTD_UNUSED(js_kctx_new);
+ }
+
+ /* Setup a dummy katom_retained_state */
+ kbasep_js_atom_retained_state_init_invalid( &katom_retained_state );
+
+ mutex_lock( &js_devdata->runpool_mutex );
+
+ /* If the runpool is full, attempt to fast start our context */
+ if (check_is_runpool_full(kbdev, kctx_new) != MALI_FALSE)
+ {
+ /* No free address spaces - attempt to evict non-running lower priority context */
+ spin_lock_irqsave(&js_devdata->runpool_irq.lock, flags);
+ for(evict_as_nr = 0; evict_as_nr < kbdev->nr_hw_address_spaces; evict_as_nr++)
+ {
+ kbase_context *kctx_evict;
+ js_per_as_data = &js_devdata->runpool_irq.per_as_data[evict_as_nr];
+ kctx_evict = js_per_as_data->kctx;
+
+ /* Look for the AS which is not currently running */
+ if(0 == js_per_as_data->as_busy_refcount && kctx_evict != NULL)
+ {
+ /* Now compare the scheduled priority we are considering evicting with the new ctx priority
+ * and take into consideration if the scheduled priority is a realtime policy or not.
+ * Note that the lower the number, the higher the priority
+ */
+ if((kctx_new == NULL) || kbasep_js_policy_ctx_has_priority(js_policy, kctx_evict, kctx_new))
+ {
+ mali_bool retain_result;
+ kbasep_js_release_result release_result;
+ KBASE_TRACE_ADD( kbdev, JS_FAST_START_EVICTS_CTX, kctx_evict, NULL, 0u, (u32)kctx_new );
+
+ /* Retain the ctx to work on it - this shouldn't be able to fail */
+ retain_result = kbasep_js_runpool_retain_ctx_nolock( kbdev, kctx_evict );
+ OSK_ASSERT( retain_result != MALI_FALSE );
+ CSTD_UNUSED( retain_result );
+
+ /* This will cause the context to be scheduled out on the next runpool_release_ctx(),
+ * and also stop its refcount increasing */
+ kbasep_js_clear_submit_allowed(js_devdata, kctx_evict);
+
+ spin_unlock_irqrestore(&js_devdata->runpool_irq.lock, flags);
+ mutex_unlock(&js_devdata->runpool_mutex);
+ if (kctx_new != NULL)
+ {
+ mutex_unlock( &js_kctx_new->ctx.jsctx_mutex );
+ }
+
+ /* Stop working on the target context, start working on the kctx_evict context */
+
+ mutex_lock( &kctx_evict->jctx.sched_info.ctx.jsctx_mutex );
+ mutex_lock( &js_devdata->runpool_mutex );
+ release_result = kbasep_js_runpool_release_ctx_internal( kbdev, kctx_evict, &katom_retained_state );
+ mutex_unlock( &js_devdata->runpool_mutex );
+ /* Only requeue if actually descheduled, which is more robust in case
+ * something else retains it (e.g. two high priority contexts racing
+ * to evict the same lower priority context) */
+ if ( (release_result & KBASEP_JS_RELEASE_RESULT_WAS_DESCHEDULED) != 0u )
+ {
+ kbasep_js_runpool_requeue_or_kill_ctx( kbdev, kctx_evict );
+ }
+ mutex_unlock( &kctx_evict->jctx.sched_info.ctx.jsctx_mutex );
+
+ /* release_result isn't propogated further:
+ * - the caller will be scheduling in a context anyway
+ * - which will also cause new jobs to run */
+
+ /* ctx fast start has taken place */
+ return;
+ }
+ }
+ }
+ spin_unlock_irqrestore(&js_devdata->runpool_irq.lock, flags);
+ }
+
+ /* ctx fast start has not taken place */
+ mutex_unlock( &js_devdata->runpool_mutex );
+ if (kctx_new != NULL)
+ {
+ mutex_unlock( &js_kctx_new->ctx.jsctx_mutex );
+ }
+}
+
+mali_bool kbasep_js_add_job( kbase_context *kctx, kbase_jd_atom *atom )
+{
+ unsigned long flags;
+ kbasep_js_kctx_info *js_kctx_info;
+ kbase_device *kbdev;
+ kbasep_js_device_data *js_devdata;
+ kbasep_js_policy *js_policy;
+
+ mali_bool policy_queue_updated = MALI_FALSE;
+
+ OSK_ASSERT( kctx != NULL );
+ OSK_ASSERT( atom != NULL );
+
+ kbdev = kctx->kbdev;
+ js_devdata = &kbdev->js_data;
+ js_policy = &kbdev->js_data.policy;
+ js_kctx_info = &kctx->jctx.sched_info;
+
+ mutex_lock( &js_kctx_info->ctx.jsctx_mutex );
+ /* Policy-specific initialization of atoms (which cannot fail). Anything that
+ * could've failed must've been done at kbasep_jd_policy_init_job() time. */
+ kbasep_js_policy_register_job( js_policy, kctx, atom );
+
+ /*
+ * Begin Runpool transaction
+ */
+ mutex_lock( &js_devdata->runpool_mutex );
+ {
+ KBASE_TRACE_ADD_REFCOUNT( kbdev, JS_ADD_JOB, kctx, atom, atom->jc,
+ kbasep_js_trace_get_refcnt(kbdev, kctx));
+ }
+
+ /* Refcount ctx.nr_jobs */
+ OSK_ASSERT( js_kctx_info->ctx.nr_jobs < U32_MAX );
+ ++(js_kctx_info->ctx.nr_jobs);
+
+ /* Setup any scheduling information */
+ kbasep_js_clear_job_retry_submit( atom );
+
+ /* Lock for state available during IRQ */
+ spin_lock_irqsave( &js_devdata->runpool_irq.lock, flags);
+
+ /* Context Attribute Refcounting */
+ kbasep_js_ctx_attr_ctx_retain_atom( kbdev, kctx, atom );
+
+ /* Enqueue the job in the policy, causing it to be scheduled if the
+ * parent context gets scheduled */
+ kbasep_js_policy_enqueue_job( js_policy, atom );
+
+ if ( js_kctx_info->ctx.is_scheduled != MALI_FALSE )
+ {
+ /* Handle an already running context - try to run the new job, in case it
+ * matches requirements that aren't matched by any other job in the Run
+ * Pool */
+ kbasep_js_try_run_next_job_nolock( kbdev );
+ }
+ spin_unlock_irqrestore( &js_devdata->runpool_irq.lock, flags);
+ mutex_unlock( &js_devdata->runpool_mutex );
+ /* End runpool transaction */
+
+ if ( js_kctx_info->ctx.is_scheduled == MALI_FALSE && js_kctx_info->ctx.nr_jobs == 1 )
+ {
+ /* Handle Refcount going from 0 to 1: schedule the context on the Policy Queue */
+ OSK_ASSERT( js_kctx_info->ctx.is_scheduled == MALI_FALSE );
+
+ OSK_PRINT_INFO(OSK_BASE_JM, "JS: Enqueue Context %p", kctx );
+
+ /* This context is becoming active */
+ kbase_pm_context_active(kctx->kbdev);
+
+ mutex_lock( &js_devdata->queue_mutex );
+ kbasep_js_policy_enqueue_ctx( js_policy, kctx );
+ mutex_unlock( &js_devdata->queue_mutex );
+ /* If the runpool is full and this job has a higher priority than the non-running
+ * job in the runpool - evict it so this higher priority job starts faster */
+ mutex_unlock( &js_kctx_info->ctx.jsctx_mutex );
+
+ /* Fast-starting requires the jsctx_mutex to be dropped, because it works on multiple ctxs */
+ kbasep_js_runpool_attempt_fast_start_ctx( kbdev, kctx );
+
+ /* NOTE: Potentially, we can make the scheduling of the head context
+ * happen in a work-queue if we need to wait for the PM to power
+ * up. Also need logic to submit nothing until PM really has completed
+ * powering up. */
+
+ /* Policy Queue was updated - caller must try to schedule the head context */
+ policy_queue_updated = MALI_TRUE;
+ }
+ else
+ {
+ mutex_unlock( &js_kctx_info->ctx.jsctx_mutex );
+ }
+
+ return policy_queue_updated;
+}
+
+void kbasep_js_remove_job( kbase_device *kbdev, kbase_context *kctx, kbase_jd_atom *atom )
+{
+ kbasep_js_kctx_info *js_kctx_info;
+ kbasep_js_device_data *js_devdata;
+ kbasep_js_policy *js_policy;
+
+ OSK_ASSERT( kbdev != NULL );
+ OSK_ASSERT( kctx != NULL );
+ OSK_ASSERT( atom != NULL );
+
+ js_devdata = &kbdev->js_data;
+ js_policy = &kbdev->js_data.policy;
+ js_kctx_info = &kctx->jctx.sched_info;
+
+ KBASE_TRACE_ADD_REFCOUNT( kbdev, JS_REMOVE_JOB, kctx, atom, atom->jc,
+ kbasep_js_trace_get_refcnt(kbdev, kctx));
+
+ /* De-refcount ctx.nr_jobs */
+ OSK_ASSERT( js_kctx_info->ctx.nr_jobs > 0 );
+ --(js_kctx_info->ctx.nr_jobs);
+
+ /* De-register the job from the system */
+ kbasep_js_policy_deregister_job( js_policy, kctx, atom );
+}
+
+void kbasep_js_remove_cancelled_job( kbase_device *kbdev, kbase_context *kctx, kbase_jd_atom *katom )
+{
+ unsigned long flags;
+ kbasep_js_atom_retained_state katom_retained_state;
+ kbasep_js_device_data *js_devdata;
+ mali_bool attr_state_changed;
+
+ OSK_ASSERT( kbdev != NULL );
+ OSK_ASSERT( kctx != NULL );
+ OSK_ASSERT( katom != NULL );
+
+ js_devdata = &kbdev->js_data;
+
+ kbasep_js_atom_retained_state_copy( &katom_retained_state, katom );
+ kbasep_js_remove_job( kbdev, kctx, katom );
+
+ spin_lock_irqsave( &js_devdata->runpool_irq.lock, flags);
+
+ /* The atom has 'finished' (will not be re-run), so no need to call
+ * kbasep_js_has_atom_finished().
+ *
+ * This is because it returns MALI_FALSE for soft-stopped atoms, but we
+ * want to override that, because we're cancelling an atom regardless of
+ * whether it was soft-stopped or not */
+ attr_state_changed = kbasep_js_ctx_attr_ctx_release_atom( kbdev, kctx, &katom_retained_state );
+
+ spin_unlock_irqrestore( &js_devdata->runpool_irq.lock, flags);
+
+ if ( attr_state_changed != MALI_FALSE )
+ {
+ /* A change in runpool ctx attributes might mean we can run more jobs
+ * than before. */
+ kbase_js_try_run_jobs( kbdev );
+ }
+}
+
+mali_bool kbasep_js_runpool_retain_ctx( kbase_device *kbdev, kbase_context *kctx )
+{
+ unsigned long flags;
+ kbasep_js_device_data *js_devdata;
+ mali_bool result;
+ OSK_ASSERT( kbdev != NULL );
+ js_devdata = &kbdev->js_data;
+
+ /* KBASE_TRACE_ADD_REFCOUNT( kbdev, JS_RETAIN_CTX, kctx, NULL, 0,
+ kbasep_js_trace_get_refcnt(kbdev, kctx)); */
+ spin_lock_irqsave( &js_devdata->runpool_irq.lock, flags);
+ result = kbasep_js_runpool_retain_ctx_nolock( kbdev, kctx );
+ spin_unlock_irqrestore( &js_devdata->runpool_irq.lock, flags);
+
+ return result;
+}
+
+
+kbase_context* kbasep_js_runpool_lookup_ctx( kbase_device *kbdev, int as_nr )
+{
+ unsigned long flags;
+ kbasep_js_device_data *js_devdata;
+ kbase_context *found_kctx = NULL;
+ kbasep_js_per_as_data *js_per_as_data;
+
+ OSK_ASSERT( kbdev != NULL );
+ OSK_ASSERT( 0 <= as_nr && as_nr < BASE_MAX_NR_AS );
+ js_devdata = &kbdev->js_data;
+ js_per_as_data = &js_devdata->runpool_irq.per_as_data[as_nr];
+
+ spin_lock_irqsave( &js_devdata->runpool_irq.lock, flags);
+
+ found_kctx = js_per_as_data->kctx;
+
+ if ( found_kctx != NULL )
+ {
+ ++(js_per_as_data->as_busy_refcount);
+ }
+
+ spin_unlock_irqrestore( &js_devdata->runpool_irq.lock, flags);
+
+ return found_kctx;
+}
+
+/**
+ * @brief Try running more jobs after releasing a context and/or atom
+ *
+ * This collates a set of actions that must happen whilst
+ * kbasep_js_device_data::runpool_irq::lock is held.
+ *
+ * This includes running more jobs when:
+ * - The previously released kctx caused a ctx attribute change
+ * - The released atom caused a ctx attribute change
+ * - Slots were previously blocked due to affinity restrictions
+ * - Submission during IRQ handling failed
+ */
+STATIC void kbasep_js_run_jobs_after_ctx_and_atom_release( kbase_device *kbdev,
+ kbase_context *kctx,
+ kbasep_js_atom_retained_state *katom_retained_state,
+ mali_bool runpool_ctx_attr_change )
+{
+ kbasep_js_device_data *js_devdata;
+
+ OSK_ASSERT( kbdev != NULL );
+ OSK_ASSERT( kctx != NULL );
+ OSK_ASSERT( katom_retained_state != NULL );
+ js_devdata = &kbdev->js_data;
+
+ lockdep_assert_held(&kctx->jctx.sched_info.ctx.jsctx_mutex);
+ lockdep_assert_held(&js_devdata->runpool_mutex);
+ lockdep_assert_held(&js_devdata->runpool_irq.lock);
+
+ if (js_devdata->nr_user_contexts_running != 0)
+ {
+ mali_bool retry_submit;
+ int retry_jobslot;
+
+ retry_submit = kbasep_js_get_atom_retry_submit_slot( katom_retained_state, &retry_jobslot );
+
+ if ( runpool_ctx_attr_change != MALI_FALSE )
+ {
+ /* A change in runpool ctx attributes might mean we can run more jobs
+ * than before */
+ kbasep_js_try_run_next_job_nolock( kbdev );
+
+ /* A retry submit on all slots has now happened, so don't need to do it again */
+ retry_submit = MALI_FALSE;
+ }
+
+ /* Submit on any slots that might've had atoms blocked by the affinity of
+ * a completed atom.
+ *
+ * If no atom has recently completed, then this is harmelss */
+ kbase_js_affinity_submit_to_blocked_slots( kbdev );
+
+ /* If the IRQ handler failed to get a job from the policy, try again from
+ * outside the IRQ handler
+ * NOTE: We may've already cleared retry_submit from submitting above */
+ if ( retry_submit != MALI_FALSE )
+ {
+ KBASE_TRACE_ADD_SLOT( kbdev, JD_DONE_TRY_RUN_NEXT_JOB, kctx, NULL, 0u, retry_jobslot );
+ kbasep_js_try_run_next_job_on_slot_nolock( kbdev, retry_jobslot );
+ }
+ }
+}
+
+/**
+ * Internal function to release the reference on a ctx and an atom's "retained
+ * state", only taking the runpool and as transaction mutexes
+ *
+ * This also starts more jobs running in the case of an ctx-attribute state change
+ *
+ * This does none of the followup actions for scheduling:
+ * - It does not schedule in a new context
+ * - It does not requeue or handle dying contexts
+ *
+ * For those tasks, just call kbasep_js_runpool_release_ctx() instead
+ *
+ * Requires:
+ * - Context is scheduled in, and kctx->as_nr matches kctx_as_nr
+ * - Context has a non-zero refcount
+ * - Caller holds js_kctx_info->ctx.jsctx_mutex
+ * - Caller holds js_devdata->runpool_mutex
+ */
+STATIC kbasep_js_release_result kbasep_js_runpool_release_ctx_internal(
+ kbase_device *kbdev,
+ kbase_context *kctx,
+ kbasep_js_atom_retained_state *katom_retained_state )
+{
+ unsigned long flags;
+ kbasep_js_device_data *js_devdata;
+ kbasep_js_kctx_info *js_kctx_info;
+ kbasep_js_policy *js_policy;
+ kbasep_js_per_as_data *js_per_as_data;
+
+ kbasep_js_release_result release_result = 0u;
+ mali_bool runpool_ctx_attr_change = MALI_FALSE;
+ int kctx_as_nr;
+ kbase_as *current_as;
+ int new_ref_count;
+
+ OSK_ASSERT( kbdev != NULL );
+ OSK_ASSERT( kctx != NULL );
+ js_kctx_info = &kctx->jctx.sched_info;
+ js_devdata = &kbdev->js_data;
+ js_policy = &kbdev->js_data.policy;
+
+ /* Ensure context really is scheduled in */
+ OSK_ASSERT( js_kctx_info->ctx.is_scheduled != MALI_FALSE );
+
+ /* kctx->as_nr and js_per_as_data are only read from here. The caller's
+ * js_ctx_mutex provides a barrier that ensures they are up-to-date.
+ *
+ * They will not change whilst we're reading them, because the refcount
+ * is non-zero (and we ASSERT on that last fact).
+ */
+ kctx_as_nr = kctx->as_nr;
+ OSK_ASSERT( kctx_as_nr != KBASEP_AS_NR_INVALID );
+ js_per_as_data = &js_devdata->runpool_irq.per_as_data[kctx_as_nr];
+ OSK_ASSERT( js_per_as_data->as_busy_refcount > 0 );
+
+ /*
+ * Transaction begins on AS and runpool_irq
+ *
+ * Assert about out calling contract
+ */
+ current_as = &kbdev->as[kctx_as_nr];
+ mutex_lock( ¤t_as->transaction_mutex );
+ spin_lock_irqsave( &js_devdata->runpool_irq.lock, flags);
+ OSK_ASSERT( kctx_as_nr == kctx->as_nr );
+ OSK_ASSERT( js_per_as_data->as_busy_refcount > 0 );
+
+ /* Update refcount */
+ new_ref_count = --(js_per_as_data->as_busy_refcount);
+
+ /* Release the atom if it finished (i.e. wasn't soft-stopped) */
+ if ( kbasep_js_has_atom_finished( katom_retained_state ) != MALI_FALSE )
+ {
+ runpool_ctx_attr_change |= kbasep_js_ctx_attr_ctx_release_atom( kbdev, kctx, katom_retained_state );
+ }
+
+ KBASE_TRACE_ADD_REFCOUNT( kbdev, JS_RELEASE_CTX, kctx, NULL, 0u,
+ new_ref_count);
+
+ if ( new_ref_count == 1 && kctx->jctx.sched_info.ctx.flags & KBASE_CTX_FLAG_PRIVILEGED )
+ {
+ /* Context is kept scheduled into an address space even when there are no jobs, in this case we have
+ * to handle the situation where all jobs have been evicted from the GPU and submission is disabled.
+ *
+ * At this point we re-enable submission to allow further jobs to be executed
+ */
+ kbasep_js_set_submit_allowed( js_devdata, kctx );
+ }
+
+ /* Make a set of checks to see if the context should be scheduled out */
+ if ( new_ref_count == 0
+ && ( kctx->jctx.sched_info.ctx.nr_jobs == 0
+ || kbasep_js_is_submit_allowed( js_devdata, kctx ) == MALI_FALSE ) )
+ {
+ /* Last reference, and we've been told to remove this context from the Run Pool */
+ OSK_PRINT_INFO(OSK_BASE_JM, "JS: RunPool Remove Context %p because as_busy_refcount=%d, jobs=%d, allowed=%d",
+ kctx,
+ new_ref_count,
+ js_kctx_info->ctx.nr_jobs,
+ kbasep_js_is_submit_allowed( js_devdata, kctx ) );
+
+ kbasep_js_policy_runpool_remove_ctx( js_policy, kctx );
+
+ /* Stop any more refcounts occuring on the context */
+ js_per_as_data->kctx = NULL;
+
+ /* Ensure we prevent the context from submitting any new jobs
+ * e.g. from kbasep_js_try_run_next_job_on_slot_irq_nolock() */
+ kbasep_js_clear_submit_allowed( js_devdata, kctx );
+
+ /* Disable the MMU on the affected address space, and indicate it's invalid */
+ kbase_mmu_disable( kctx );
+
+#ifdef CONFIG_MALI_GATOR_SUPPORT
+ kbase_trace_mali_mmu_as_released(kctx->as_nr);
+#endif /* CONFIG_MALI_GATOR_SUPPORT */
+
+ kctx->as_nr = KBASEP_AS_NR_INVALID;
+
+ /* Ctx Attribute handling
+ *
+ * Releasing atoms attributes must either happen before this, or after
+ * 'is_scheduled' is changed, otherwise we double-decount the attributes*/
+ runpool_ctx_attr_change |= kbasep_js_ctx_attr_runpool_release_ctx( kbdev, kctx );
+
+ /* Early update of context count, to optimize the
+ * kbasep_js_run_jobs_after_ctx_and_atom_release() call */
+ runpool_dec_context_count( kbdev, kctx );
+
+ /* Releasing the context and katom retained state can allow more jobs to run */
+ kbasep_js_run_jobs_after_ctx_and_atom_release( kbdev, kctx, katom_retained_state, runpool_ctx_attr_change );
+
+ /*
+ * Transaction ends on AS and runpool_irq:
+ *
+ * By this point, the AS-related data is now clear and ready for re-use.
+ *
+ * Since releases only occur once for each previous successful retain, and no more
+ * retains are allowed on this context, no other thread will be operating in this
+ * code whilst we are
+ */
+ spin_unlock_irqrestore( &js_devdata->runpool_irq.lock, flags);
+ mutex_unlock( ¤t_as->transaction_mutex );
+
+ /* Free up the address space */
+ release_addr_space( kbdev, kctx_as_nr );
+ /* Note: Don't reuse kctx_as_nr now */
+
+ /* update book-keeping info */
+ js_kctx_info->ctx.is_scheduled = MALI_FALSE;
+ /* Signal any waiter that the context is not scheduled, so is safe for
+ * termination - once the jsctx_mutex is also dropped, and jobs have
+ * finished. */
+ wake_up(&js_kctx_info->ctx.is_scheduled_wait);
+
+ /* Queue an action to occur after we've dropped the lock */
+ release_result |= KBASEP_JS_RELEASE_RESULT_WAS_DESCHEDULED;
+
+ }
+ else
+ {
+ kbasep_js_run_jobs_after_ctx_and_atom_release( kbdev, kctx, katom_retained_state, runpool_ctx_attr_change );
+
+ spin_unlock_irqrestore( &js_devdata->runpool_irq.lock, flags);
+ mutex_unlock( ¤t_as->transaction_mutex );
+ }
+
+ return release_result;
+}
+
+void kbasep_js_runpool_requeue_or_kill_ctx( kbase_device *kbdev, kbase_context *kctx )
+{
+ kbasep_js_device_data *js_devdata;
+ kbasep_js_policy *js_policy;
+ kbasep_js_kctx_info *js_kctx_info;
+
+ OSK_ASSERT( kbdev != NULL );
+ OSK_ASSERT( kctx != NULL );
+ js_kctx_info = &kctx->jctx.sched_info;
+ js_policy = &kbdev->js_data.policy;
+ js_devdata = &kbdev->js_data;
+
+ /* This is called if and only if you've you've detached the context from
+ * the Runpool or the Policy Queue, and not added it back to the Runpool */
+ OSK_ASSERT( js_kctx_info->ctx.is_scheduled == MALI_FALSE );
+
+ if ( js_kctx_info->ctx.is_dying != MALI_FALSE )
+ {
+ /* Dying: kill and idle the context */
+
+ /* Notify PM that a context has gone idle */
+ OSK_PRINT_INFO(OSK_BASE_JM, "JS: Idling Context %p (not requeued)", kctx );
+ kbase_pm_context_idle(kbdev);
+
+ /* The killing happens asynchronously */
+ OSK_PRINT_INFO(OSK_BASE_JM, "JS: ** Killing Context %p on RunPool Remove **", kctx );
+ kbasep_js_policy_kill_all_ctx_jobs( js_policy, kctx );
+ }
+ else if ( js_kctx_info->ctx.nr_jobs > 0 )
+ {
+ /* Not dying, has jobs: add back to the queue */
+ OSK_PRINT_INFO(OSK_BASE_JM, "JS: Requeue Context %p", kctx );
+ mutex_lock( &js_devdata->queue_mutex );
+ kbasep_js_policy_enqueue_ctx( js_policy, kctx );
+ mutex_unlock( &js_devdata->queue_mutex );
+ }
+ else
+ {
+ /* Not dying, no jobs: PM-idle the context, don't add back to the queue */
+ OSK_PRINT_INFO(OSK_BASE_JM, "JS: Idling Context %p (not requeued)", kctx );
+ kbase_pm_context_idle(kbdev);
+ }
+}
+
+void kbasep_js_runpool_release_ctx_and_katom_retained_state( kbase_device *kbdev,
+ kbase_context *kctx,
+ kbasep_js_atom_retained_state *katom_retained_state )
+{
+ kbasep_js_device_data *js_devdata;
+ kbasep_js_kctx_info *js_kctx_info;
+ kbasep_js_release_result release_result;
+
+ OSK_ASSERT( kbdev != NULL );
+ OSK_ASSERT( kctx != NULL );
+ js_kctx_info = &kctx->jctx.sched_info;
+ js_devdata = &kbdev->js_data;
+
+ mutex_lock( &js_kctx_info->ctx.jsctx_mutex );
+ mutex_lock( &js_devdata->runpool_mutex );
+ release_result = kbasep_js_runpool_release_ctx_internal( kbdev, kctx, katom_retained_state );
+
+ /* Drop the runpool mutex to allow requeing kctx */
+ mutex_unlock( &js_devdata->runpool_mutex );
+ if ( (release_result & KBASEP_JS_RELEASE_RESULT_WAS_DESCHEDULED) != 0u )
+ {
+ kbasep_js_runpool_requeue_or_kill_ctx( kbdev, kctx ) ;
+ }
+
+ /* Drop the jsctx_mutex to allow scheduling in a new context */
+ mutex_unlock( &js_kctx_info->ctx.jsctx_mutex );
+ if ( (release_result & KBASEP_JS_RELEASE_RESULT_WAS_DESCHEDULED) != 0u )
+ {
+ /* We've freed up an address space, so let's try to schedule in another
+ * context
+ *
+ * Note: if there's a context to schedule in, then it also tries to run
+ * another job, in case the new context has jobs satisfying requirements
+ * that no other context/job in the runpool does */
+ kbasep_js_try_schedule_head_ctx( kbdev );
+ }
+}
+
+void kbasep_js_runpool_release_ctx( kbase_device *kbdev, kbase_context *kctx )
+{
+ kbasep_js_atom_retained_state katom_retained_state;
+
+ kbasep_js_atom_retained_state_init_invalid( &katom_retained_state );
+
+ kbasep_js_runpool_release_ctx_and_katom_retained_state( kbdev, kctx, &katom_retained_state );
+}
+
+/**
+ * @brief Handle retaining cores for power management and affinity management,
+ * ensuring that cores are powered up and won't violate affinity restrictions.
+ *
+ * This function enters at the following @ref kbase_atom_coreref_state states:
+ *
+ * - NO_CORES_REQUESTED,
+ * - WAITING_FOR_REQUESTED_CORES,
+ * - RECHECK_AFFINITY,
+ *
+ * The transitions are as folows:
+ * - NO_CORES_REQUESTED -> WAITING_FOR_REQUESTED_CORES
+ * - WAITING_FOR_REQUESTED_CORES -> ( WAITING_FOR_REQUESTED_CORES or RECHECK_AFFINITY )
+ * - RECHECK_AFFINITY -> ( WAITING_FOR_REQUESTED_CORES or CHECK_AFFINITY_VIOLATIONS )
+ * - CHECK_AFFINITY_VIOLATIONS -> ( RECHECK_AFFINITY or READY )
+ *
+ * The caller must hold:
+ * - kbasep_js_device_data::runpool_irq::lock
+ *
+ * @return MALI_FALSE when the function makes a transition to the same or lower state, indicating
+ * that the cores are not ready.
+ * @return MALI_TRUE once READY state is reached, indicating that the cores are 'ready' and won't
+ * violate affinity restrictions.
+ *
+ */
+STATIC mali_bool kbasep_js_job_check_ref_cores(kbase_device *kbdev, int js, kbase_jd_atom *katom)
+{
+ u64 tiler_affinity = 0;
+ /* The most recently checked affinity. Having this at this scope allows us
+ * to guarantee that we've checked the affinity in this function call. */
+ u64 recently_chosen_affinity = 0;
+
+ if (katom->core_req & BASE_JD_REQ_T)
+ {
+ tiler_affinity = kbdev->tiler_present_bitmap;
+ }
+
+ /* NOTE: The following uses a number of FALLTHROUGHs to optimize the
+ * calls to this function. Ending of the function is indicated by BREAK OUT */
+ switch ( katom->coreref_state )
+ {
+ /* State when job is first attempted to be run */
+ case KBASE_ATOM_COREREF_STATE_NO_CORES_REQUESTED:
+ OSK_ASSERT( katom->affinity == 0 );
+ /* Compute affinity */
+ kbase_js_choose_affinity( &recently_chosen_affinity, kbdev, katom, js );
+
+ /* Request the cores */
+ if (MALI_ERROR_NONE != kbase_pm_request_cores( kbdev, recently_chosen_affinity, tiler_affinity ))
+ {
+ /* Failed to request cores, don't set the affinity so we try again and return */
+ KBASE_TRACE_ADD_SLOT_INFO( kbdev, JS_CORE_REF_REQUEST_CORES_FAILED, katom->kctx, katom,
+ katom->jc, js, (u32)recently_chosen_affinity );
+ /* *** BREAK OUT: No state transition *** */
+ break;
+ }
+
+ katom->affinity = recently_chosen_affinity;
+ /* Proceed to next state */
+ katom->coreref_state = KBASE_ATOM_COREREF_STATE_WAITING_FOR_REQUESTED_CORES;
+
+ /* ***FALLTHROUGH: TRANSITION TO HIGHER STATE*** */
+
+ case KBASE_ATOM_COREREF_STATE_WAITING_FOR_REQUESTED_CORES:
+ {
+ mali_bool cores_ready;
+ OSK_ASSERT( katom->affinity != 0 );
+
+ cores_ready = kbase_pm_register_inuse_cores( kbdev, katom->affinity, tiler_affinity );
+ if ( !cores_ready )
+ {
+ /* Stay in this state and return, to retry at this state later */
+ KBASE_TRACE_ADD_SLOT_INFO( kbdev, JS_CORE_REF_REGISTER_INUSE_FAILED, katom->kctx, katom,
+ katom->jc, js, (u32)katom->affinity );
+ /* *** BREAK OUT: No state transition *** */
+ break;
+ }
+ /* Proceed to next state */
+ katom->coreref_state = KBASE_ATOM_COREREF_STATE_RECHECK_AFFINITY;
+ }
+
+ /* ***FALLTHROUGH: TRANSITION TO HIGHER STATE*** */
+
+ case KBASE_ATOM_COREREF_STATE_RECHECK_AFFINITY:
+ OSK_ASSERT( katom->affinity != 0 );
+
+ /* Optimize out choosing the affinity twice in the same function call */
+ if ( recently_chosen_affinity == 0 )
+ {
+ /* See if the affinity changed since a previous call. */
+ kbase_js_choose_affinity( &recently_chosen_affinity, kbdev, katom, js );
+ }
+
+ /* Now see if this requires a different set of cores */
+ if ( recently_chosen_affinity != katom->affinity )
+ {
+ if (MALI_ERROR_NONE != kbase_pm_request_cores( kbdev, recently_chosen_affinity, tiler_affinity ))
+ {
+ /* Failed to request cores, rollback the previous gained set
+ * That also resets the state to NO_CORES_REQUESTED */
+ kbasep_js_job_check_deref_cores( kbdev, katom );
+ KBASE_TRACE_ADD_SLOT_INFO( kbdev, JS_CORE_REF_REQUEST_ON_RECHECK_FAILED, katom->kctx, katom,
+ katom->jc, js, (u32)recently_chosen_affinity );
+ /* *** BREAK OUT: Transition to lower state *** */
+ break;
+ }
+ else
+ {
+ mali_bool cores_ready;
+ /* Register new cores whislt we still hold the old ones, to minimize power transitions */
+ cores_ready = kbase_pm_register_inuse_cores( kbdev, recently_chosen_affinity, tiler_affinity );
+ kbasep_js_job_check_deref_cores( kbdev, katom );
+
+ /* Fixup the state that was reduced by deref_cores: */
+ katom->coreref_state = KBASE_ATOM_COREREF_STATE_RECHECK_AFFINITY;
+ katom->affinity = recently_chosen_affinity;
+ /* Now might be waiting for powerup again, with a new affinity */
+ if ( !cores_ready )
+ {
+ /* Return to previous state */
+ katom->coreref_state = KBASE_ATOM_COREREF_STATE_WAITING_FOR_REQUESTED_CORES;
+ KBASE_TRACE_ADD_SLOT_INFO( kbdev, JS_CORE_REF_REGISTER_ON_RECHECK_FAILED, katom->kctx, katom,
+ katom->jc, js, (u32)katom->affinity );
+ /* *** BREAK OUT: Transition to lower state *** */
+ break;
+ }
+ }
+ }
+ /* Proceed to next state */
+ katom->coreref_state = KBASE_ATOM_COREREF_STATE_CHECK_AFFINITY_VIOLATIONS;
+
+ /* ***FALLTHROUGH: TRANSITION TO HIGHER STATE*** */
+ case KBASE_ATOM_COREREF_STATE_CHECK_AFFINITY_VIOLATIONS:
+ OSK_ASSERT( katom->affinity != 0 );
+ OSK_ASSERT( katom->affinity == recently_chosen_affinity );
+
+ /* Note: this is where the caller must've taken the runpool_irq.lock */
+
+ /* Check for affinity violations - if there are any, then we just ask
+ * the caller to requeue and try again later */
+ if ( kbase_js_affinity_would_violate( kbdev, js, katom->affinity ) != MALI_FALSE )
+ {
+ /* Cause a re-attempt to submit from this slot on the next job complete */
+ kbase_js_affinity_slot_blocked_an_atom( kbdev, js );
+ /* Return to previous state */
+ katom->coreref_state = KBASE_ATOM_COREREF_STATE_RECHECK_AFFINITY;
+ /* *** BREAK OUT: Transition to lower state *** */
+ KBASE_TRACE_ADD_SLOT_INFO( kbdev, JS_CORE_REF_AFFINITY_WOULD_VIOLATE, katom->kctx, katom,
+ katom->jc, js, (u32)katom->affinity );
+ break;
+ }
+
+ /* No affinity violations would result, so the cores are ready */
+ katom->coreref_state = KBASE_ATOM_COREREF_STATE_READY;
+ /* *** BREAK OUT: Cores Ready *** */
+ break;
+
+ default:
+ OSK_ASSERT_MSG( MALI_FALSE, "Unhandled kbase_atom_coreref_state %d", katom->coreref_state );
+ break;
+ }
+
+ return (katom->coreref_state == KBASE_ATOM_COREREF_STATE_READY);
+}
+
+void kbasep_js_job_check_deref_cores(kbase_device *kbdev, struct kbase_jd_atom *katom)
+{
+ u64 tiler_affinity = 0;
+
+ OSK_ASSERT( kbdev != NULL );
+ OSK_ASSERT( katom != NULL );
+
+ if (katom->core_req & BASE_JD_REQ_T)
+ {
+ tiler_affinity = kbdev->tiler_present_bitmap;
+ }
+
+ switch ( katom->coreref_state )
+ {
+ case KBASE_ATOM_COREREF_STATE_READY:
+ /* State where atom was submitted to the HW - just proceed to power-down */
+ OSK_ASSERT( katom->affinity != 0 );
+
+ /* *** FALLTHROUGH *** */
+
+ case KBASE_ATOM_COREREF_STATE_RECHECK_AFFINITY:
+ /* State where cores were registered */
+ OSK_ASSERT( katom->affinity != 0 );
+ kbase_pm_release_cores(kbdev, katom->affinity, tiler_affinity);
+
+ /* Note: We do not clear the state for kbase_js_affinity_slot_blocked_an_atom().
+ * That is handled after finishing the job. This might be slightly
+ * suboptimal for some corner cases, but is otherwise not a problem
+ * (and resolves itself after the next job completes). */
+
+ break;
+
+ case KBASE_ATOM_COREREF_STATE_WAITING_FOR_REQUESTED_CORES:
+ /* State where cores were requested, but not registered */
+ OSK_ASSERT( katom->affinity != 0 );
+ kbase_pm_unrequest_cores(kbdev, katom->affinity, tiler_affinity);
+ break;
+
+ case KBASE_ATOM_COREREF_STATE_NO_CORES_REQUESTED:
+ /* Initial state - nothing required */
+ OSK_ASSERT( katom->affinity == 0 );
+ break;
+
+ default:
+ OSK_ASSERT_MSG( MALI_FALSE, "Unhandled coreref_state: %d", katom->coreref_state );
+ break;
+ }
+
+ katom->affinity = 0;
+ katom->coreref_state = KBASE_ATOM_COREREF_STATE_NO_CORES_REQUESTED;
+}
+
+
+
+/*
+ * Note: this function is quite similar to kbasep_js_try_run_next_job_on_slot()
+ */
+mali_bool kbasep_js_try_run_next_job_on_slot_irq_nolock( kbase_device *kbdev, int js, s8 *submit_count )
+{
+ kbasep_js_device_data *js_devdata;
+ mali_bool tried_to_dequeue_jobs_but_failed = MALI_FALSE;
+ mali_bool cores_ready;
+
+ OSK_ASSERT( kbdev != NULL );
+
+ js_devdata = &kbdev->js_data;
+
+ /* The caller of this function may not be aware of Ctx Attribute state changes so we
+ * must recheck if the given slot is still valid. Otherwise do not try to run.
+ */
+ if (kbase_js_can_run_job_on_slot_no_lock( kbdev, js))
+ {
+ /* Keep submitting while there's space to run a job on this job-slot,
+ * and there are jobs to get that match its requirements (see 'break'
+ * statement below) */
+ while ( *submit_count < KBASE_JS_MAX_JOB_SUBMIT_PER_SLOT_PER_IRQ
+ && kbasep_jm_is_submit_slots_free( kbdev, js, NULL ) != MALI_FALSE )
+ {
+ kbase_jd_atom *dequeued_atom;
+ mali_bool has_job = MALI_FALSE;
+
+ /* Dequeue a job that matches the requirements */
+ has_job = kbasep_js_policy_dequeue_job_irq( kbdev, js, &dequeued_atom );
+
+ if ( has_job != MALI_FALSE )
+ {
+ /* NOTE: since the runpool_irq lock is currently held and acts across
+ * all address spaces, any context whose busy refcount has reached
+ * zero won't yet be scheduled out whilst we're trying to run jobs
+ * from it */
+ kbase_context *parent_ctx = dequeued_atom->kctx;
+ mali_bool retain_success;
+
+ /* Retain/power up the cores it needs, check if cores are ready */
+ cores_ready = kbasep_js_job_check_ref_cores( kbdev, js, dequeued_atom );
+
+ if ( cores_ready != MALI_TRUE )
+ {
+ /* The job can't be submitted until the cores are ready, requeue the job */
+ kbasep_js_policy_enqueue_job( &kbdev->js_data.policy, dequeued_atom );
+ break;
+ }
+
+ /* ASSERT that the Policy picked a job from an allowed context */
+ OSK_ASSERT( kbasep_js_is_submit_allowed( js_devdata, parent_ctx) );
+
+ /* Retain the context to stop it from being scheduled out
+ * This is released when the job finishes */
+ retain_success = kbasep_js_runpool_retain_ctx_nolock( kbdev, parent_ctx );
+ OSK_ASSERT( retain_success != MALI_FALSE );
+ CSTD_UNUSED( retain_success );
+
+ /* Retain the affinity on the slot */
+ kbase_js_affinity_retain_slot_cores( kbdev, js, dequeued_atom->affinity );
+
+ /* Check if this job needs the cycle counter enabled before submission */
+ kbasep_js_ref_permon_check_and_enable_cycle_counter( kbdev, dequeued_atom );
+
+ /* Submit the job */
+ kbase_job_submit_nolock( kbdev, dequeued_atom, js );
+
+ ++(*submit_count);
+ }
+ else
+ {
+ tried_to_dequeue_jobs_but_failed = MALI_TRUE;
+ /* No more jobs - stop submitting for this slot */
+ break;
+ }
+ }
+ }
+
+ /* Indicate whether a retry in submission should be tried on a different
+ * dequeue function. These are the reasons why it *must* happen:
+ *
+ * - kbasep_js_policy_dequeue_job_irq() couldn't get any jobs. In this case,
+ * kbasep_js_policy_dequeue_job() might be able to get jobs (must be done
+ * outside of IRQ)
+ * - kbasep_js_policy_dequeue_job_irq() got some jobs, but failed to get a
+ * job in the last call to it. Again, kbasep_js_policy_dequeue_job()
+ * might be able to get jobs.
+ * - the KBASE_JS_MAX_JOB_SUBMIT_PER_SLOT_PER_IRQ threshold was reached
+ * and new scheduling must be performed outside of IRQ mode.
+ *
+ * Failure to indicate this correctly could stop further jobs being processed.
+ *
+ * However, we do not _need_ to indicate a retry for the following:
+ * - kbasep_jm_is_submit_slots_free() was MALI_FALSE, indicating jobs were
+ * already running. When those jobs complete, that will still cause events
+ * that cause us to resume job submission.
+ * - kbase_js_can_run_job_on_slot_no_lock() was MALI_FALSE - this is for
+ * Ctx Attribute handling. That _can_ change outside of IRQ context, but
+ * is handled explicitly by kbasep_js_runpool_release_ctx_and_katom_retained_state().
+ */
+ return (mali_bool)(tried_to_dequeue_jobs_but_failed || *submit_count >= KBASE_JS_MAX_JOB_SUBMIT_PER_SLOT_PER_IRQ);
+}
+
+void kbasep_js_try_run_next_job_on_slot_nolock( kbase_device *kbdev, int js )
+{
+ kbasep_js_device_data *js_devdata;
+ mali_bool has_job;
+ mali_bool cores_ready;
+
+ OSK_ASSERT( kbdev != NULL );
+
+ js_devdata = &kbdev->js_data;
+
+ OSK_ASSERT( js_devdata->nr_user_contexts_running > 0 );
+
+ /* Keep submitting while there's space to run a job on this job-slot,
+ * and there are jobs to get that match its requirements (see 'break'
+ * statement below) */
+ if ( kbasep_jm_is_submit_slots_free( kbdev, js, NULL ) != MALI_FALSE )
+ {
+ /* The caller of this function may not be aware of Ctx Attribute state changes so we
+ * must recheck if the given slot is still valid. Otherwise do not try to run.
+ */
+ if (kbase_js_can_run_job_on_slot_no_lock( kbdev, js))
+ {
+ do {
+ kbase_jd_atom *dequeued_atom;
+
+ /* Dequeue a job that matches the requirements */
+ has_job = kbasep_js_policy_dequeue_job( kbdev, js, &dequeued_atom );
+
+ if ( has_job != MALI_FALSE )
+ {
+ /* NOTE: since the runpool_irq lock is currently held and acts across
+ * all address spaces, any context whose busy refcount has reached
+ * zero won't yet be scheduled out whilst we're trying to run jobs
+ * from it */
+ kbase_context *parent_ctx = dequeued_atom->kctx;
+ mali_bool retain_success;
+
+ /* Retain/power up the cores it needs, check if cores are ready */
+ cores_ready = kbasep_js_job_check_ref_cores( kbdev, js, dequeued_atom );
+
+ if ( cores_ready != MALI_TRUE )
+ {
+ /* The job can't be submitted until the cores are ready, requeue the job */
+ kbasep_js_policy_enqueue_job( &kbdev->js_data.policy, dequeued_atom );
+ break;
+ }
+ /* ASSERT that the Policy picked a job from an allowed context */
+ OSK_ASSERT( kbasep_js_is_submit_allowed( js_devdata, parent_ctx) );
+
+ /* Retain the context to stop it from being scheduled out
+ * This is released when the job finishes */
+ retain_success = kbasep_js_runpool_retain_ctx_nolock( kbdev, parent_ctx );
+ OSK_ASSERT( retain_success != MALI_FALSE );
+ CSTD_UNUSED( retain_success );
+
+ /* Retain the affinity on the slot */
+ kbase_js_affinity_retain_slot_cores( kbdev, js, dequeued_atom->affinity );
+
+ /* Check if this job needs the cycle counter enabled before submission */
+ kbasep_js_ref_permon_check_and_enable_cycle_counter( kbdev, dequeued_atom );
+
+ /* Submit the job */
+ kbase_job_submit_nolock( kbdev, dequeued_atom, js );
+ }
+
+ } while ( kbasep_jm_is_submit_slots_free( kbdev, js, NULL ) != MALI_FALSE
+ && has_job != MALI_FALSE );
+ }
+ }
+}
+
+void kbasep_js_try_schedule_head_ctx( kbase_device *kbdev )
+{
+ kbasep_js_device_data *js_devdata;
+ mali_bool has_kctx;
+ kbase_context *head_kctx;
+ kbasep_js_kctx_info *js_kctx_info;
+ mali_bool is_runpool_full;
+ kbase_as *new_address_space;
+ unsigned long flags;
+
+ OSK_ASSERT( kbdev != NULL );
+
+ js_devdata = &kbdev->js_data;
+
+ /* We *don't* make a speculative check on whether we can fit a context in the
+ * runpool, because most of our use-cases assume 2 or fewer contexts, and
+ * so we will usually have enough address spaces free.
+ *
+ * In any case, the check will be done later on once we have a context */
+
+ /* Grab the context off head of queue - if there is one */
+ mutex_lock( &js_devdata->queue_mutex );
+ has_kctx = kbasep_js_policy_dequeue_head_ctx( &js_devdata->policy, &head_kctx );
+ mutex_unlock( &js_devdata->queue_mutex );
+
+ if ( has_kctx == MALI_FALSE )
+ {
+ /* No ctxs to run - nothing to do */
+ return;
+ }
+ js_kctx_info = &head_kctx->jctx.sched_info;
+
+ OSK_PRINT_INFO(OSK_BASE_JM, "JS: Dequeue Context %p", head_kctx );
+
+ /*
+ * Atomic transaction on the Context and Run Pool begins
+ */
+ mutex_lock( &js_kctx_info->ctx.jsctx_mutex );
+ mutex_lock( &js_devdata->runpool_mutex );
+
+ /* Check to see if the Run Pool is full against a specific context
+ * (some contexts are allowed in whereas others may not, due to HW workarounds) */
+ is_runpool_full = check_is_runpool_full(kbdev, head_kctx);
+ if ( is_runpool_full != MALI_FALSE )
+ {
+ /* No free address spaces - roll back the transaction so far and return */
+ mutex_unlock( &js_devdata->runpool_mutex );
+
+ kbasep_js_runpool_requeue_or_kill_ctx( kbdev, head_kctx );
+
+ mutex_unlock( &js_kctx_info->ctx.jsctx_mutex );
+ return;
+ }
+
+ KBASE_TRACE_ADD_REFCOUNT( kbdev, JS_TRY_SCHEDULE_HEAD_CTX, head_kctx, NULL, 0u,
+ kbasep_js_trace_get_refcnt(kbdev, head_kctx));
+
+
+
+#if MALI_CUSTOMER_RELEASE == 0
+ if ( js_devdata->nr_user_contexts_running == 0 )
+ {
+ /* Only when there are no other contexts submitting jobs:
+ * Latch in run-time job scheduler timeouts that were set through js_timeouts sysfs file */
+ if (kbdev->js_soft_stop_ticks != 0)
+ {
+ js_devdata->soft_stop_ticks = kbdev->js_soft_stop_ticks;
+ }
+ if (kbdev->js_hard_stop_ticks_ss != 0)
+ {
+ js_devdata->hard_stop_ticks_ss = kbdev->js_hard_stop_ticks_ss;
+ }
+ if (kbdev->js_hard_stop_ticks_nss != 0)
+ {
+ js_devdata->hard_stop_ticks_nss = kbdev->js_hard_stop_ticks_nss;
+ }
+ if (kbdev->js_reset_ticks_ss != 0)
+ {
+ js_devdata->gpu_reset_ticks_ss = kbdev->js_reset_ticks_ss;
+ }
+ if (kbdev->js_reset_ticks_nss != 0)
+ {
+ js_devdata->gpu_reset_ticks_nss = kbdev->js_reset_ticks_nss;
+ }
+ }
+#endif
+
+ runpool_inc_context_count( kbdev, head_kctx );
+ /* Cause any future waiter-on-termination to wait until the context is
+ * descheduled */
+ js_kctx_info->ctx.is_scheduled = MALI_TRUE;
+ wake_up(&js_kctx_info->ctx.is_scheduled_wait);
+
+ /* Pick the free address space (guaranteed free by check_is_runpool_full() ) */
+ new_address_space = pick_free_addr_space( kbdev );
+
+ /* Lock the address space whilst working on it */
+ mutex_lock( &new_address_space->transaction_mutex );
+ spin_lock_irqsave( &js_devdata->runpool_irq.lock, flags);
+
+ /* Do all the necessaries to assign the address space (inc. update book-keeping info)
+ * Add the context to the Run Pool, and allow it to run jobs */
+ assign_and_activate_kctx_addr_space( kbdev, head_kctx, new_address_space );
+
+ /* NOTE: If Linux allows, then we can drop the new_address_space->transaction mutex here */
+
+ if ( (js_kctx_info->ctx.flags & KBASE_CTX_FLAG_PRIVILEGED) != 0 )
+ {
+ /* We need to retain it to keep the corresponding address space */
+ kbasep_js_runpool_retain_ctx_nolock(kbdev, head_kctx);
+ }
+
+ /* Try to run the next job, in case this context has jobs that match the
+ * job slot requirements, but none of the other currently running contexts
+ * do */
+ kbasep_js_try_run_next_job_nolock( kbdev );
+
+ /* Transaction complete */
+ spin_unlock_irqrestore( &js_devdata->runpool_irq.lock, flags);
+ mutex_unlock( &new_address_space->transaction_mutex );
+ mutex_unlock( &js_devdata->runpool_mutex );
+ mutex_unlock( &js_kctx_info->ctx.jsctx_mutex );
+ /* Note: after this point, the context could potentially get scheduled out immediately */
+}
+
+void kbasep_js_schedule_privileged_ctx( kbase_device *kbdev, kbase_context *kctx )
+{
+ kbasep_js_kctx_info *js_kctx_info;
+ kbasep_js_device_data *js_devdata;
+ mali_bool is_scheduled;
+
+ OSK_ASSERT( kbdev != NULL );
+ OSK_ASSERT( kctx != NULL );
+
+ js_devdata = &kbdev->js_data;
+ js_kctx_info = &kctx->jctx.sched_info;
+
+ kbase_pm_request_l2_caches(kbdev);
+
+ mutex_lock( &js_kctx_info->ctx.jsctx_mutex );
+ /* Mark the context as privileged */
+ js_kctx_info->ctx.flags |= KBASE_CTX_FLAG_PRIVILEGED;
+
+ is_scheduled = js_kctx_info->ctx.is_scheduled;
+ if ( is_scheduled == MALI_FALSE )
+ {
+ mali_bool is_runpool_full;
+
+ /* Add the context to the runpool */
+ mutex_lock( &js_devdata->queue_mutex );
+ kbasep_js_policy_enqueue_ctx( &js_devdata->policy, kctx );
+ mutex_unlock( &js_devdata->queue_mutex );
+
+ mutex_lock( &js_devdata->runpool_mutex );
+ {
+ is_runpool_full = check_is_runpool_full( kbdev, kctx);
+ if ( is_runpool_full != MALI_FALSE )
+ {
+ /* Evict jobs from the NEXT registers to free an AS asap */
+ kbasep_js_runpool_evict_next_jobs( kbdev, kctx );
+ }
+ }
+ mutex_unlock( &js_devdata->runpool_mutex );
+ mutex_unlock( &js_kctx_info->ctx.jsctx_mutex );
+ /* Fast-starting requires the jsctx_mutex to be dropped, because it works on multiple ctxs */
+
+ if ( is_runpool_full != MALI_FALSE )
+ {
+ /* Evict non-running contexts from the runpool */
+ kbasep_js_runpool_attempt_fast_start_ctx( kbdev, NULL );
+ }
+ /* Try to schedule the context in */
+ kbasep_js_try_schedule_head_ctx( kbdev );
+
+ /* Wait for the context to be scheduled in */
+ wait_event(kctx->jctx.sched_info.ctx.is_scheduled_wait, kctx->jctx.sched_info.ctx.is_scheduled == MALI_TRUE);
+ }
+ else
+ {
+ /* Already scheduled in - We need to retain it to keep the corresponding address space */
+ kbasep_js_runpool_retain_ctx(kbdev, kctx);
+ mutex_unlock( &js_kctx_info->ctx.jsctx_mutex );
+
+ }
+}
+
+void kbasep_js_release_privileged_ctx( kbase_device *kbdev, kbase_context *kctx )
+{
+ kbasep_js_kctx_info *js_kctx_info;
+ OSK_ASSERT( kctx != NULL );
+ js_kctx_info = &kctx->jctx.sched_info;
+
+ /* We don't need to use the address space anymore */
+ mutex_lock( &js_kctx_info->ctx.jsctx_mutex );
+ js_kctx_info->ctx.flags &= (~KBASE_CTX_FLAG_PRIVILEGED);
+ mutex_unlock( &js_kctx_info->ctx.jsctx_mutex );
+
+ kbase_pm_release_l2_caches( kbdev );
+
+ /* Release the context - it will be scheduled out if there is no pending job */
+ kbasep_js_runpool_release_ctx(kbdev, kctx);
+}
+
+
+void kbasep_js_job_done_slot_irq( kbase_jd_atom *katom, int slot_nr, ktime_t *end_timestamp, mali_bool start_new_jobs )
+{
+ kbase_device *kbdev;
+ kbasep_js_policy *js_policy;
+ kbasep_js_device_data *js_devdata;
+ mali_bool submit_retry_needed = MALI_TRUE; /* If we don't start jobs here, start them from the workqueue */
+ ktime_t tick_diff;
+ u64 microseconds_spent = 0u;
+ kbase_context *parent_ctx;
+
+ OSK_ASSERT(katom);
+ parent_ctx = katom->kctx;
+ OSK_ASSERT(parent_ctx);
+ kbdev = parent_ctx->kbdev;
+ OSK_ASSERT(kbdev);
+
+ js_devdata = &kbdev->js_data;
+ js_policy = &kbdev->js_data.policy;
+
+ lockdep_assert_held(&js_devdata->runpool_irq.lock);
+
+ /*
+ * Release resources before submitting new jobs (bounds the refcount of
+ * the resource to BASE_JM_SUBMIT_SLOTS)
+ */
+#ifdef CONFIG_MALI_GATOR_SUPPORT
+ kbase_trace_mali_job_slots_event(GATOR_MAKE_EVENT(GATOR_JOB_SLOT_STOP, slot_nr), NULL);
+#endif /* CONFIG_MALI_GATOR_SUPPORT */
+
+ if (katom->poking && kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8316))
+ {
+ OSK_ASSERT(parent_ctx->as_nr != KBASEP_AS_NR_INVALID);
+ kbase_as_poking_timer_release(&kbdev->as[parent_ctx->as_nr]);
+ katom->poking = 0;
+ }
+
+ /* Check if submitted jobs no longer require the cycle counter to be enabled */
+ kbasep_js_deref_permon_check_and_disable_cycle_counter( kbdev, katom );
+
+ /* Release the affinity from the slot - must happen before next submission to this slot */
+ kbase_js_affinity_release_slot_cores( kbdev, slot_nr, katom->affinity );
+ kbase_js_debug_log_current_affinities( kbdev );
+ /* Calculate the job's time used */
+ if ( end_timestamp != NULL )
+ {
+ /* Only calculating it for jobs that really run on the HW (e.g. removed
+ * from next jobs never actually ran, so really did take zero time) */
+ tick_diff = ktime_sub( *end_timestamp, katom->start_timestamp );
+
+ microseconds_spent = ktime_to_ns( tick_diff );
+ osk_divmod6432( µseconds_spent, 1000 );
+
+ /* Round up time spent to the minimum timer resolution */
+ if (microseconds_spent < KBASEP_JS_TICK_RESOLUTION_US)
+ {
+ microseconds_spent = KBASEP_JS_TICK_RESOLUTION_US;
+ }
+ }
+
+ /* Log the result of the job (completion status, and time spent). */
+ kbasep_js_policy_log_job_result( js_policy, katom, microseconds_spent );
+ /* Determine whether the parent context's timeslice is up */
+ if ( kbasep_js_policy_should_remove_ctx( js_policy, parent_ctx ) != MALI_FALSE )
+ {
+ kbasep_js_clear_submit_allowed( js_devdata, parent_ctx );
+ }
+
+ if ( start_new_jobs != MALI_FALSE )
+ {
+ /* Submit a new job (if there is one) to help keep the GPU's HEAD and NEXT registers full */
+ KBASE_TRACE_ADD_SLOT( kbdev, JS_JOB_DONE_TRY_RUN_NEXT_JOB, parent_ctx, katom, katom->jc, slot_nr);
+
+ submit_retry_needed = kbasep_js_try_run_next_job_on_slot_irq_nolock(kbdev,
+ slot_nr,
+ &kbdev->slot_submit_count_irq[slot_nr] );
+ }
+
+ if ( submit_retry_needed != MALI_FALSE || katom->event_code == BASE_JD_EVENT_STOPPED )
+ {
+ /* The extra condition on STOPPED jobs is needed because they may be
+ * the only job present, but they won't get re-run until the JD work
+ * queue activates. Crucially, work queues can run items out of order
+ * e.g. on different CPUs, so being able to submit from the IRQ handler
+ * is not a good indication that we don't need to run jobs; the
+ * submitted job could be processed on the work-queue *before* the
+ * stopped job, even though it was submitted after.
+ *
+ * Therefore, we must try to run it, otherwise it might not get run at
+ * all after this. */
+
+ KBASE_TRACE_ADD_SLOT( kbdev, JS_JOB_DONE_RETRY_NEEDED, parent_ctx, katom, katom->jc, slot_nr);
+ kbasep_js_set_job_retry_submit_slot( katom, slot_nr );
+ }
+}
diff --git a/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_js.h b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_js.h
new file mode 100644
index 0000000..82652fb
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_js.h
@@ -0,0 +1,862 @@
+/*
+ *
+ * (C) COPYRIGHT 2011-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_kbase_js.h
+ * Job Scheduler APIs.
+ */
+
+#ifndef _KBASE_JS_H_
+#define _KBASE_JS_H_
+
+#include <malisw/mali_malisw.h>
+#include <osk/mali_osk.h>
+
+#include "mali_kbase_js_defs.h"
+#include "mali_kbase_js_policy.h"
+#include "mali_kbase_defs.h"
+
+#include "mali_kbase_js_ctx_attr.h"
+
+/**
+ * @addtogroup base_api
+ * @{
+ */
+
+/**
+ * @addtogroup base_kbase_api
+ * @{
+ */
+
+/**
+ * @addtogroup kbase_js Job Scheduler Internal APIs
+ * @{
+ *
+ * These APIs are Internal to KBase and are available for use by the
+ * @ref kbase_js_policy "Job Scheduler Policy APIs"
+ */
+
+/**
+ * @brief Initialize the Job Scheduler
+ *
+ * The kbasep_js_device_data sub-structure of \a kbdev must be zero
+ * initialized before passing to the kbasep_js_devdata_init() function. This is
+ * to give efficient error path code.
+ */
+mali_error kbasep_js_devdata_init( kbase_device *kbdev );
+
+/**
+ * @brief Halt the Job Scheduler.
+ *
+ * It is safe to call this on \a kbdev even if it the kbasep_js_device_data
+ * sub-structure was never initialized/failed initialization, to give efficient
+ * error-path code.
+ *
+ * For this to work, the kbasep_js_device_data sub-structure of \a kbdev must
+ * be zero initialized before passing to the kbasep_js_devdata_init()
+ * function. This is to give efficient error path code.
+ *
+ * It is a Programming Error to call this whilst there are still kbase_context
+ * structures registered with this scheduler.
+ *
+ */
+void kbasep_js_devdata_halt( kbase_device * kbdev);
+
+/**
+ * @brief Terminate the Job Scheduler
+ *
+ * It is safe to call this on \a kbdev even if it the kbasep_js_device_data
+ * sub-structure was never initialized/failed initialization, to give efficient
+ * error-path code.
+ *
+ * For this to work, the kbasep_js_device_data sub-structure of \a kbdev must
+ * be zero initialized before passing to the kbasep_js_devdata_init()
+ * function. This is to give efficient error path code.
+ *
+ * It is a Programming Error to call this whilst there are still kbase_context
+ * structures registered with this scheduler.
+ */
+void kbasep_js_devdata_term( kbase_device *kbdev );
+
+
+/**
+ * @brief Initialize the Scheduling Component of a kbase_context on the Job Scheduler.
+ *
+ * This effectively registers a kbase_context with a Job Scheduler.
+ *
+ * It does not register any jobs owned by the kbase_context with the scheduler.
+ * Those must be separately registered by kbasep_js_add_job().
+ *
+ * The kbase_context must be zero intitialized before passing to the
+ * kbase_js_init() function. This is to give efficient error path code.
+ */
+mali_error kbasep_js_kctx_init( kbase_context *kctx );
+
+/**
+ * @brief Terminate the Scheduling Component of a kbase_context on the Job Scheduler
+ *
+ * This effectively de-registers a kbase_context from its Job Scheduler
+ *
+ * It is safe to call this on a kbase_context that has never had or failed
+ * initialization of its jctx.sched_info member, to give efficient error-path
+ * code.
+ *
+ * For this to work, the kbase_context must be zero intitialized before passing
+ * to the kbase_js_init() function.
+ *
+ * It is a Programming Error to call this whilst there are still jobs
+ * registered with this context.
+ */
+void kbasep_js_kctx_term( kbase_context *kctx );
+
+/**
+ * @brief Add a job chain to the Job Scheduler, and take necessary actions to
+ * schedule the context/run the job.
+ *
+ * This atomically does the following:
+ * - Update the numbers of jobs information (including NSS state changes)
+ * - Add the job to the run pool if necessary (part of init_job)
+ *
+ * Once this is done, then an appropriate action is taken:
+ * - If the ctx is scheduled, it attempts to start the next job (which might be
+ * this added job)
+ * - Otherwise, and if this is the first job on the context, it enqueues it on
+ * the Policy Queue
+ *
+ * The Policy's Queue can be updated by this in the following ways:
+ * - In the above case that this is the first job on the context
+ * - If the job is high priority and the context is not scheduled, then it
+ * could cause the Policy to schedule out a low-priority context, allowing
+ * this context to be scheduled in.
+ *
+ * If the context is already scheduled on the RunPool, then adding a job to it
+ * is guarenteed not to update the Policy Queue. And so, the caller is
+ * guarenteed to not need to try scheduling a context from the Run Pool - it
+ * can safely assert that the result is MALI_FALSE.
+ *
+ * It is a programming error to have more than U32_MAX jobs in flight at a time.
+ *
+ * The following locking conditions are made on the caller:
+ * - it must \em not hold kbasep_js_kctx_info::ctx::jsctx_mutex.
+ * - it must \em not hold kbasep_js_device_data::runpool_irq::lock (as this will be
+ * obtained internally)
+ * - it must \em not hold kbasep_js_device_data::runpool_mutex (as this will be
+ * obtained internally)
+ * - it must \em not hold kbasep_jd_device_data::queue_mutex (again, it's used internally).
+ *
+ * @return MALI_TRUE indicates that the Policy Queue was updated, and so the
+ * caller will need to try scheduling a context onto the Run Pool.
+ * @return MALI_FALSE indicates that no updates were made to the Policy Queue,
+ * so no further action is required from the caller. This is \b always returned
+ * when the context is currently scheduled.
+ */
+mali_bool kbasep_js_add_job( kbase_context *kctx, kbase_jd_atom *atom );
+
+/**
+ * @brief Remove a job chain from the Job Scheduler, except for its 'retained state'.
+ *
+ * Completely removing a job requires several calls:
+ * - kbasep_js_copy_atom_retained_state(), to capture the 'retained state' of
+ * the atom
+ * - kbasep_js_remove_job(), to partially remove the atom from the Job Scheduler
+ * - kbasep_js_runpool_release_ctx_and_katom_retained_state(), to release the
+ * remaining state held as part of the job having been run.
+ *
+ * In the common case of atoms completing normally, this set of actions is more optimal for spinlock purposes than having kbasep_js_remove_job() handle all of the actions.
+ *
+ * In the case of cancelling atoms, it is easier to call kbasep_js_remove_cancelled_job(), which handles all the necessary actions.
+ *
+ * It is a programming error to call this when:
+ * - \a atom is not a job belonging to kctx.
+ * - \a atom has already been removed from the Job Scheduler.
+ * - \a atom is still in the runpool:
+ * - it has not been killed with kbasep_js_policy_kill_all_ctx_jobs()
+ * - or, it has not been removed with kbasep_js_policy_dequeue_job()
+ * - or, it has not been removed with kbasep_js_policy_dequeue_job_irq()
+ *
+ * The following locking conditions are made on the caller:
+ * - it must hold kbasep_js_kctx_info::ctx::jsctx_mutex.
+ *
+ */
+void kbasep_js_remove_job( kbase_device *kbdev, kbase_context *kctx, kbase_jd_atom *atom );
+
+/**
+ * @brief Completely remove a job chain from the Job Scheduler, in the case
+ * where the job chain was cancelled.
+ *
+ * This is a variant of kbasep_js_remove_job() that takes care of removing all
+ * of the retained state too. This is generally useful for cancelled atoms,
+ * which need not be handled in an optimal way.
+ *
+ * As such, this can cause an NSS/SS state transition. In this case, slots that
+ * previously could not have jobs submitted to might now be submittable to. For
+ * this reason, and NSS/SS state transition will cause the Scheduler to try to
+ * submit new jobs on the jm_slots.
+ *
+ * It is a programming error to call this when:
+ * - \a atom is not a job belonging to kctx.
+ * - \a atom has already been removed from the Job Scheduler.
+ * - \a atom is still in the runpool:
+ * - it has not been killed with kbasep_js_policy_kill_all_ctx_jobs()
+ * - or, it has not been removed with kbasep_js_policy_dequeue_job()
+ * - or, it has not been removed with kbasep_js_policy_dequeue_job_irq()
+ *
+ * The following locking conditions are made on the caller:
+ * - it must hold kbasep_js_kctx_info::ctx::jsctx_mutex.
+ * - it must \em not hold the kbasep_js_device_data::runpool_irq::lock, (as this will be
+ * obtained internally)
+ * - it must \em not hold kbasep_js_device_data::runpool_mutex (as this could be
+ * obtained internally)
+ */
+void kbasep_js_remove_cancelled_job( kbase_device *kbdev, kbase_context *kctx, kbase_jd_atom *katom );
+
+/**
+ * @brief Refcount a context as being busy, preventing it from being scheduled
+ * out.
+ *
+ * @note This function can safely be called from IRQ context.
+ *
+ * The following locking conditions are made on the caller:
+ * - it must \em not hold the kbasep_js_device_data::runpool_irq::lock, because
+ * it will be used internally.
+ *
+ * @return value != MALI_FALSE if the retain succeeded, and the context will not be scheduled out.
+ * @return MALI_FALSE if the retain failed (because the context is being/has been scheduled out).
+ */
+mali_bool kbasep_js_runpool_retain_ctx( kbase_device *kbdev, kbase_context *kctx );
+
+/**
+ * @brief Refcount a context as being busy, preventing it from being scheduled
+ * out.
+ *
+ * @note This function can safely be called from IRQ context.
+ *
+ * The following locks must be held by the caller:
+ * - kbasep_js_device_data::runpool_irq::lock
+ *
+ * @return value != MALI_FALSE if the retain succeeded, and the context will not be scheduled out.
+ * @return MALI_FALSE if the retain failed (because the context is being/has been scheduled out).
+ */
+mali_bool kbasep_js_runpool_retain_ctx_nolock( kbase_device *kbdev, kbase_context *kctx );
+
+/**
+ * @brief Lookup a context in the Run Pool based upon its current address space
+ * and ensure that is stays scheduled in.
+ *
+ * The context is refcounted as being busy to prevent it from scheduling
+ * out. It must be released with kbasep_js_runpool_release_ctx() when it is no
+ * longer required to stay scheduled in.
+ *
+ * @note This function can safely be called from IRQ context.
+ *
+ * The following locking conditions are made on the caller:
+ * - it must \em not hold the kbasep_js_device_data::runpoool_irq::lock, because
+ * it will be used internally.
+ *
+ * @return a valid kbase_context on success, which has been refcounted as being busy.
+ * @return NULL on failure, indicating that no context was found in \a as_nr
+ */
+kbase_context* kbasep_js_runpool_lookup_ctx( kbase_device *kbdev, int as_nr );
+
+/**
+ * @brief Handling the requeuing/killing of a context that was evicted from the
+ * policy queue or runpool.
+ *
+ * This should be used whenever handing off a context that has been evicted
+ * from the policy queue or the runpool:
+ * - If the context is not dying and has jobs, it gets re-added to the policy
+ * queue
+ * - Otherwise, it is not added (but PM is informed that it is idle)
+ *
+ * In addition, if the context is dying the jobs are killed asynchronously.
+ *
+ * The following locking conditions are made on the caller:
+ * - it must hold kbasep_js_kctx_info::ctx::jsctx_mutex.
+ * - it must \em not hold kbasep_jd_device_data::queue_mutex (as this will be
+ * obtained internally)
+ */
+void kbasep_js_runpool_requeue_or_kill_ctx( kbase_device *kbdev, kbase_context *kctx );
+
+/**
+ * @brief Release a refcount of a context being busy, allowing it to be
+ * scheduled out.
+ *
+ * When the refcount reaches zero and the context \em might be scheduled out
+ * (depending on whether the Scheudling Policy has deemed it so, or if it has run
+ * out of jobs).
+ *
+ * If the context does get scheduled out, then The following actions will be
+ * taken as part of deschduling a context:
+ * - For the context being descheduled:
+ * - If the context is in the processing of dying (all the jobs are being
+ * removed from it), then descheduling also kills off any jobs remaining in the
+ * context.
+ * - If the context is not dying, and any jobs remain after descheduling the
+ * context then it is re-enqueued to the Policy's Queue.
+ * - Otherwise, the context is still known to the scheduler, but remains absent
+ * from the Policy Queue until a job is next added to it.
+ *
+ * Whilst the context is being descheduled, this also handles actions that
+ * cause more atoms to be run:
+ * - Attempt submitting atoms when the Context Attributes on the Runpool have
+ * changed. This is because the context being scheduled out could mean that
+ * there are more opportunities to run atoms.
+ * - Attempt submitting to a slot that was previously blocked due to affinity
+ * restrictions. This is usually only necessary when releasing a context
+ * happens as part of completing a previous job, but is harmless nonetheless.
+ * - Attempt scheduling in a new context (if one is available), and if necessary,
+ * running a job from that new context.
+ *
+ * Unlike retaining a context in the runpool, this function \b cannot be called
+ * from IRQ context.
+ *
+ * It is a programming error to call this on a \a kctx that is not currently
+ * scheduled, or that already has a zero refcount.
+ *
+ * The following locking conditions are made on the caller:
+ * - it must \em not hold the kbasep_js_device_data::runpool_irq::lock, because
+ * it will be used internally.
+ * - it must \em not hold kbasep_js_kctx_info::ctx::jsctx_mutex.
+ * - it must \em not hold kbasep_js_device_data::runpool_mutex (as this will be
+ * obtained internally)
+ * - it must \em not hold the kbase_device::as[n].transaction_mutex (as this will be obtained internally)
+ * - it must \em not hold kbasep_jd_device_data::queue_mutex (as this will be
+ * obtained internally)
+ *
+ */
+void kbasep_js_runpool_release_ctx( kbase_device *kbdev, kbase_context *kctx );
+
+/**
+ * @brief Variant of kbasep_js_runpool_release_ctx() that handles additional
+ * actions from completing an atom.
+ *
+ * This is usually called as part of completing an atom and releasing the
+ * refcount on the context held by the atom.
+ *
+ * Therefore, the extra actions carried out are part of handling actions queued
+ * on a completed atom, namely:
+ * - Releasing the atom's context attributes
+ * - Retrying the submission on a particular slot, because we couldn't submit
+ * on that slot from an IRQ handler.
+ *
+ * The locking conditions of this function are the same as those for
+ * kbasep_js_runpool_release_ctx()
+ */
+void kbasep_js_runpool_release_ctx_and_katom_retained_state( kbase_device *kbdev,
+ kbase_context *kctx,
+ kbasep_js_atom_retained_state *katom_retained_state );
+
+/**
+ * @brief Try to submit the next job on a \b particular slot whilst in IRQ
+ * context, and whilst the caller already holds the runpool IRQ spinlock.
+ *
+ * \a *submit_count will be checked against
+ * KBASE_JS_MAX_JOB_SUBMIT_PER_SLOT_PER_IRQ to see whether too many jobs have
+ * been submitted. This is to prevent the IRQ handler looping over lots of GPU
+ * NULL jobs, which may complete whilst the IRQ handler is still processing. \a
+ * submit_count itself should point to kbase_device::slot_submit_count_irq[ \a js ],
+ * which is initialized to zero on entry to the IRQ handler.
+ *
+ * The following locks must be held by the caller:
+ * - kbasep_js_device_data::runpool_irq::lock
+ *
+ * @return truthful (i.e. != MALI_FALSE) if there was space to submit in the
+ * GPU, but we couldn't get a job from the Run Pool. This may be because the
+ * Run Pool needs maintenence outside of IRQ context. Therefore, this indicates
+ * that submission should be retried from a work-queue, by using
+ * kbasep_js_try_run_next_job_on_slot_nolock()/kbase_js_try_run_jobs_on_slot().
+ * @return MALI_FALSE if submission had no problems: the GPU is either already
+ * full of jobs in the HEAD and NEXT registers, or we were able to get enough
+ * jobs from the Run Pool to fill the GPU's HEAD and NEXT registers.
+ */
+mali_bool kbasep_js_try_run_next_job_on_slot_irq_nolock( kbase_device *kbdev, int js, s8 *submit_count );
+
+/**
+ * @brief Try to submit the next job on a particular slot, outside of IRQ context
+ *
+ * This obtains the Job Slot lock for the duration of the call only.
+ *
+ * Unlike kbasep_js_try_run_next_job_on_slot_irq_nolock(), there is no limit on
+ * submission, because eventually IRQ_THROTTLE will kick in to prevent us
+ * getting stuck in a loop of submitting GPU NULL jobs. This is because the IRQ
+ * handler will be delayed, and so this function will eventually fill up the
+ * space in our software 'submitted' slot (kbase_jm_slot::submitted).
+ *
+ * In addition, there's no return value - we'll run the maintenence functions
+ * on the Policy's Run Pool, but if there's nothing there after that, then the
+ * Run Pool is truely empty, and so no more action need be taken.
+ *
+ * The following locking conditions are made on the caller:
+ * - it must hold kbasep_js_device_data::runpool_mutex
+ * - it must hold kbasep_js_device_data::runpool_irq::lock
+ *
+ * This must only be called whilst the GPU is powered - for example, when
+ * kbdev->jsdata.nr_user_contexts_running > 0.
+ *
+ * @note The caller \em might be holding one of the
+ * kbasep_js_kctx_info::ctx::jsctx_mutex locks.
+ *
+ */
+void kbasep_js_try_run_next_job_on_slot_nolock( kbase_device *kbdev, int js );
+
+/**
+ * @brief Try to submit the next job for each slot in the system, outside of IRQ context
+ *
+ * This will internally call kbasep_js_try_run_next_job_on_slot_nolock(), so similar
+ * locking conditions on the caller are required.
+ *
+ * The following locking conditions are made on the caller:
+ * - it must hold kbasep_js_device_data::runpool_mutex
+ * - it must hold kbasep_js_device_data::runpool_irq::lock
+ *
+ * @note The caller \em might be holding one of the
+ * kbasep_js_kctx_info::ctx::jsctx_mutex locks.
+ *
+ */
+void kbasep_js_try_run_next_job_nolock( kbase_device *kbdev );
+
+/**
+ * @brief Try to schedule the next context onto the Run Pool
+ *
+ * This checks whether there's space in the Run Pool to accommodate a new
+ * context. If so, it attempts to dequeue a context from the Policy Queue, and
+ * submit this to the Run Pool.
+ *
+ * If the scheduling succeeds, then it also makes a call to
+ * kbasep_js_try_run_next_job_nolock(), in case the new context has jobs matching the
+ * job slot requirements, but no other currently scheduled context has such
+ * jobs.
+ *
+ * If any of these actions fail (Run Pool Full, Policy Queue empty, etc) then
+ * the function just returns normally.
+ *
+ * The following locking conditions are made on the caller:
+ * - it must \em not hold the kbasep_js_device_data::runpool_irq::lock, because
+ * it will be used internally.
+ * - it must \em not hold kbasep_js_device_data::runpool_mutex (as this will be
+ * obtained internally)
+ * - it must \em not hold the kbase_device::as[n].transaction_mutex (as this will be obtained internally)
+ * - it must \em not hold kbasep_jd_device_data::queue_mutex (again, it's used internally).
+ * - it must \em not hold kbasep_js_kctx_info::ctx::jsctx_mutex, because it will
+ * be used internally.
+ *
+ */
+void kbasep_js_try_schedule_head_ctx( kbase_device *kbdev );
+
+/**
+ * @brief Schedule in a privileged context
+ *
+ * This schedules a context in regardless of the context priority.
+ * If the runpool is full, a context will be forced out of the runpool and the function will wait
+ * for the new context to be scheduled in.
+ * The context will be kept scheduled in (and the corresponding address space reserved) until
+ * kbasep_js_release_privileged_ctx is called).
+ *
+ * The following locking conditions are made on the caller:
+ * - it must \em not hold the kbasep_js_device_data::runpool_irq::lock, because
+ * it will be used internally.
+ * - it must \em not hold kbasep_js_device_data::runpool_mutex (as this will be
+ * obtained internally)
+ * - it must \em not hold the kbase_device::as[n].transaction_mutex (as this will be obtained internally)
+ * - it must \em not hold kbasep_jd_device_data::queue_mutex (again, it's used internally).
+ * - it must \em not hold kbasep_js_kctx_info::ctx::jsctx_mutex, because it will
+ * be used internally.
+ *
+ */
+void kbasep_js_schedule_privileged_ctx( kbase_device *kbdev, kbase_context *kctx );
+
+/**
+ * @brief Release a privileged context, allowing it to be scheduled out.
+ *
+ * See kbasep_js_runpool_release_ctx for potential side effects.
+ *
+ * The following locking conditions are made on the caller:
+ * - it must \em not hold the kbasep_js_device_data::runpool_irq::lock, because
+ * it will be used internally.
+ * - it must \em not hold kbasep_js_kctx_info::ctx::jsctx_mutex.
+ * - it must \em not hold kbasep_js_device_data::runpool_mutex (as this will be
+ * obtained internally)
+ * - it must \em not hold the kbase_device::as[n].transaction_mutex (as this will be obtained internally)
+ *
+ */
+void kbasep_js_release_privileged_ctx( kbase_device *kbdev, kbase_context *kctx );
+
+/**
+ * @brief Handle the Job Scheduler component for the IRQ of a job finishing
+ *
+ * This does the following:
+ * -# Releases resources held by the atom
+ * -# if \a end_timestamp != NULL, updates the runpool's notion of time spent by a running ctx
+ * -# determines whether a context should be marked for scheduling out
+ * -# if start_new_jobs is true, tries to submit the next job on the slot
+ * (picking from all ctxs in the runpool)
+ *
+ * In addition, if submission didn't happen (the submit-from-IRQ function
+ * failed or start_new_jobs == MALI_FALSE), then this sets a message on katom
+ * that submission needs to be retried from the worker thread.
+ *
+ * Normally, the time calculated from end_timestamp is rounded up to the
+ * minimum time precision. Therefore, to ensure the job is recorded as not
+ * spending any time, then set end_timestamp to NULL. For example, this is necessary when
+ * evicting jobs from JSn_HEAD_NEXT (because they didn't actually run).
+ *
+ * NOTE: It's possible to move the steps (2) and (3) (inc calculating job's time
+ * used) into the worker (outside of IRQ context), but this may allow a context
+ * to use up to twice as much timeslice as is allowed by the policy. For
+ * policies that order by time spent, this is not a problem for overall
+ * 'fairness', but can still increase latency between contexts.
+ *
+ * The following locking conditions are made on the caller:
+ * - it must hold kbasep_js_device_data::runpoool_irq::lock
+ */
+void kbasep_js_job_done_slot_irq( kbase_jd_atom *katom, int slot_nr, ktime_t *end_timestamp, mali_bool start_new_jobs );
+
+/**
+ * @brief Try to submit the next job on each slot
+ *
+ * The following locks may be used:
+ * - kbasep_js_device_data::runpool_mutex
+ * - kbasep_js_device_data::runpool_irq::lock
+ */
+void kbase_js_try_run_jobs( kbase_device *kbdev );
+
+/**
+ * @brief Try to submit the next job on a specfic slot
+ *
+ * The following locking conditions are made on the caller:
+ *
+ * - it must \em not hold kbasep_js_device_data::runpool_mutex (as this will be
+ * obtained internally)
+ * - it must \em not hold kbasep_js_device_data::runpool_irq::lock (as this
+ * will be obtained internally)
+ *
+ */
+void kbase_js_try_run_jobs_on_slot( kbase_device *kbdev, int js );
+
+/**
+ * @brief Handle releasing cores for power management and affinity management,
+ * ensuring that cores are powered down and affinity tracking is updated.
+ *
+ * This must only be called on an atom that is not currently running, and has
+ * not been re-queued onto the context (and so does not need locking)
+ *
+ * This function enters at the following @ref kbase_atom_coreref_state states:
+ * - NO_CORES_REQUESTED
+ * - WAITING_FOR_REQUESTED_CORES
+ * - RECHECK_AFFINITY
+ * - READY
+ *
+ * It transitions the above states back to NO_CORES_REQUESTED by the end of the
+ * function call (possibly via intermediate states).
+ *
+ * No locks need be held by the caller, since this takes the necessary Power
+ * Management locks itself. The runpool_irq.lock is not taken (the work that
+ * requires it is handled by kbase_js_affinity_submit_to_blocked_slots() ).
+ *
+ * @note The corresponding kbasep_js_job_check_ref_cores() is private to the
+ * Job Scheduler, and is called automatically when running the next job.
+ */
+void kbasep_js_job_check_deref_cores(kbase_device *kbdev, struct kbase_jd_atom *katom);
+
+/*
+ * Helpers follow
+ */
+
+/**
+ * @brief Check that a context is allowed to submit jobs on this policy
+ *
+ * The purpose of this abstraction is to hide the underlying data size, and wrap up
+ * the long repeated line of code.
+ *
+ * As with any mali_bool, never test the return value with MALI_TRUE.
+ *
+ * The caller must hold kbasep_js_device_data::runpool_irq::lock.
+ */
+static INLINE mali_bool kbasep_js_is_submit_allowed( kbasep_js_device_data *js_devdata, kbase_context *kctx )
+{
+ u16 test_bit;
+
+ /* Ensure context really is scheduled in */
+ OSK_ASSERT( kctx->as_nr != KBASEP_AS_NR_INVALID );
+ OSK_ASSERT( kctx->jctx.sched_info.ctx.is_scheduled != MALI_FALSE );
+
+ test_bit = (u16)(1u << kctx->as_nr);
+
+ return (mali_bool)(js_devdata->runpool_irq.submit_allowed & test_bit);
+}
+
+/**
+ * @brief Allow a context to submit jobs on this policy
+ *
+ * The purpose of this abstraction is to hide the underlying data size, and wrap up
+ * the long repeated line of code.
+ *
+ * The caller must hold kbasep_js_device_data::runpool_irq::lock.
+ */
+static INLINE void kbasep_js_set_submit_allowed( kbasep_js_device_data *js_devdata, kbase_context *kctx )
+{
+ u16 set_bit;
+
+ /* Ensure context really is scheduled in */
+ OSK_ASSERT( kctx->as_nr != KBASEP_AS_NR_INVALID );
+ OSK_ASSERT( kctx->jctx.sched_info.ctx.is_scheduled != MALI_FALSE );
+
+ set_bit = (u16)(1u << kctx->as_nr);
+
+ OSK_PRINT_INFO(OSK_BASE_JM, "JS: Setting Submit Allowed on %p (as=%d)", kctx, kctx->as_nr );
+
+ js_devdata->runpool_irq.submit_allowed |= set_bit;
+}
+
+/**
+ * @brief Prevent a context from submitting more jobs on this policy
+ *
+ * The purpose of this abstraction is to hide the underlying data size, and wrap up
+ * the long repeated line of code.
+ *
+ * The caller must hold kbasep_js_device_data::runpool_irq::lock.
+ */
+static INLINE void kbasep_js_clear_submit_allowed( kbasep_js_device_data *js_devdata, kbase_context *kctx )
+{
+ u16 clear_bit;
+ u16 clear_mask;
+
+ /* Ensure context really is scheduled in */
+ OSK_ASSERT( kctx->as_nr != KBASEP_AS_NR_INVALID );
+ OSK_ASSERT( kctx->jctx.sched_info.ctx.is_scheduled != MALI_FALSE );
+
+ clear_bit = (u16)(1u << kctx->as_nr);
+ clear_mask = ~clear_bit;
+
+ OSK_PRINT_INFO(OSK_BASE_JM, "JS: Clearing Submit Allowed on %p (as=%d)", kctx, kctx->as_nr );
+
+ js_devdata->runpool_irq.submit_allowed &= clear_mask;
+}
+
+/**
+ * @brief Manage the 'retry_submit_on_slot' part of a kbase_jd_atom
+ */
+static INLINE void kbasep_js_clear_job_retry_submit( kbase_jd_atom *atom )
+{
+ atom->retry_submit_on_slot = KBASEP_JS_RETRY_SUBMIT_SLOT_INVALID;
+}
+
+static INLINE void kbasep_js_set_job_retry_submit_slot( kbase_jd_atom *atom, int js )
+{
+ OSK_ASSERT( 0 <= js && js <= BASE_JM_MAX_NR_SLOTS );
+
+ atom->retry_submit_on_slot = js;
+}
+
+/**
+ * Create an initial 'invalid' atom retained state, that requires no
+ * atom-related work to be done on releasing with
+ * kbasep_js_runpool_release_ctx_and_katom_retained_state()
+ */
+static INLINE void kbasep_js_atom_retained_state_init_invalid( kbasep_js_atom_retained_state *retained_state )
+{
+ retained_state->event_code = BASE_JD_EVENT_NOT_STARTED;
+ retained_state->core_req = KBASEP_JS_ATOM_RETAINED_STATE_CORE_REQ_INVALID;
+ retained_state->retry_submit_on_slot = KBASEP_JS_RETRY_SUBMIT_SLOT_INVALID;
+}
+
+
+/**
+ * Copy atom state that can be made available after jd_done_nolock() is called
+ * on that atom.
+ */
+static INLINE void kbasep_js_atom_retained_state_copy( kbasep_js_atom_retained_state *retained_state,
+ const kbase_jd_atom *katom )
+{
+ retained_state->event_code = katom->event_code;
+ retained_state->core_req = katom->core_req;
+ retained_state->retry_submit_on_slot = katom->retry_submit_on_slot;
+}
+
+/**
+ * @brief Determine whether an atom has finished (given its retained state),
+ * and so should be given back to userspace/removed from the system.
+ *
+ * Reasons for an atom not finishing include:
+ * - Being soft-stopped (and so, the atom should be resubmitted sometime later)
+ *
+ * @param[in] katom_retained_state the retained state of the atom to check
+ * @return MALI_FALSE if the atom has not finished
+ * @return !=MALI_FALSE if the atom has finished
+ */
+static INLINE mali_bool kbasep_js_has_atom_finished( const kbasep_js_atom_retained_state *katom_retained_state )
+{
+ return (mali_bool)(katom_retained_state->event_code != BASE_JD_EVENT_STOPPED
+ && katom_retained_state->event_code != BASE_JD_EVENT_REMOVED_FROM_NEXT );
+}
+
+/**
+ * @brief Determine whether a kbasep_js_atom_retained_state is valid
+ *
+ * An invalid kbasep_js_atom_retained_state is allowed, and indicates that the
+ * code should just ignore it.
+ *
+ * @param[in] katom_retained_state the atom's retained state to check
+ * @return MALI_FALSE if the retained state is invalid, and can be ignored
+ * @return !=MALI_FALSE if the retained state is valid
+ */
+static INLINE mali_bool kbasep_js_atom_retained_state_is_valid( const kbasep_js_atom_retained_state *katom_retained_state )
+{
+ return (mali_bool)(katom_retained_state->core_req != KBASEP_JS_ATOM_RETAINED_STATE_CORE_REQ_INVALID);
+}
+
+
+static INLINE mali_bool kbasep_js_get_atom_retry_submit_slot( const kbasep_js_atom_retained_state *katom_retained_state, int *res )
+{
+ int js = katom_retained_state->retry_submit_on_slot;
+ *res = js;
+ return (mali_bool)( js >= 0 );
+}
+
+#if OSK_DISABLE_ASSERTS == 0
+/**
+ * Debug Check the refcount of a context. Only use within ASSERTs
+ *
+ * Obtains kbasep_js_device_data::runpool_irq::lock
+ *
+ * @return negative value if the context is not scheduled in
+ * @return current refcount of the context if it is scheduled in. The refcount
+ * is not guarenteed to be kept constant.
+ */
+static INLINE int kbasep_js_debug_check_ctx_refcount( kbase_device *kbdev, kbase_context *kctx )
+{
+ unsigned long flags;
+ kbasep_js_device_data *js_devdata;
+ int result = -1;
+ int as_nr;
+
+ OSK_ASSERT( kbdev != NULL );
+ OSK_ASSERT( kctx != NULL );
+ js_devdata = &kbdev->js_data;
+
+ spin_lock_irqsave( &js_devdata->runpool_irq.lock, flags);
+ as_nr = kctx->as_nr;
+ if ( as_nr != KBASEP_AS_NR_INVALID )
+ {
+ result = js_devdata->runpool_irq.per_as_data[as_nr].as_busy_refcount;
+ }
+ spin_unlock_irqrestore( &js_devdata->runpool_irq.lock, flags);
+
+ return result;
+}
+#endif /* OSK_DISABLE_ASSERTS == 0 */
+
+/**
+ * @brief Variant of kbasep_js_runpool_lookup_ctx() that can be used when the
+ * context is guarenteed to be already previously retained.
+ *
+ * It is a programming error to supply the \a as_nr of a context that has not
+ * been previously retained/has a busy refcount of zero. The only exception is
+ * when there is no ctx in \a as_nr (NULL returned).
+ *
+ * The following locking conditions are made on the caller:
+ * - it must \em not hold the kbasep_js_device_data::runpoool_irq::lock, because
+ * it will be used internally.
+ *
+ * @return a valid kbase_context on success, with a refcount that is guarenteed
+ * to be non-zero and unmodified by this function.
+ * @return NULL on failure, indicating that no context was found in \a as_nr
+ */
+static INLINE kbase_context* kbasep_js_runpool_lookup_ctx_noretain( kbase_device *kbdev, int as_nr )
+{
+ unsigned long flags;
+ kbasep_js_device_data *js_devdata;
+ kbase_context *found_kctx;
+ kbasep_js_per_as_data *js_per_as_data;
+
+ OSK_ASSERT( kbdev != NULL );
+ OSK_ASSERT( 0 <= as_nr && as_nr < BASE_MAX_NR_AS );
+ js_devdata = &kbdev->js_data;
+ js_per_as_data = &js_devdata->runpool_irq.per_as_data[as_nr];
+
+ spin_lock_irqsave( &js_devdata->runpool_irq.lock, flags);
+
+ found_kctx = js_per_as_data->kctx;
+ OSK_ASSERT( found_kctx == NULL || js_per_as_data->as_busy_refcount > 0 );
+
+ spin_unlock_irqrestore( &js_devdata->runpool_irq.lock, flags);
+
+ return found_kctx;
+}
+
+/**
+ * This will provide a conversion from time (us) to ticks of the gpu clock
+ * based on the minimum available gpu frequency.
+ * This is usually good to compute best/worst case (where the use of current
+ * frequency is not valid due to DVFS).
+ * e.g.: when you need the number of cycles to guarantee you won't wait for
+ * longer than 'us' time (you might have a shorter wait).
+ */
+static INLINE u32 kbasep_js_convert_us_to_gpu_ticks_min_freq( kbase_device *kbdev, u32 us )
+{
+ u32 gpu_freq = kbdev->gpu_props.props.core_props.gpu_freq_khz_min;
+ OSK_ASSERT( 0!= gpu_freq );
+ return (us * (gpu_freq / 1000));
+}
+
+/**
+ * This will provide a conversion from time (us) to ticks of the gpu clock
+ * based on the maximum available gpu frequency.
+ * This is usually good to compute best/worst case (where the use of current
+ * frequency is not valid due to DVFS).
+ * e.g.: When you need the number of cycles to guarantee you'll wait at least
+ * 'us' amount of time (but you might wait longer).
+ */
+static INLINE u32 kbasep_js_convert_us_to_gpu_ticks_max_freq( kbase_device *kbdev, u32 us )
+{
+ u32 gpu_freq = kbdev->gpu_props.props.core_props.gpu_freq_khz_max;
+ OSK_ASSERT( 0!= gpu_freq );
+ return (us * (u32)(gpu_freq / 1000));
+}
+
+/**
+ * This will provide a conversion from ticks of the gpu clock to time (us)
+ * based on the minimum available gpu frequency.
+ * This is usually good to compute best/worst case (where the use of current
+ * frequency is not valid due to DVFS).
+ * e.g.: When you need to know the worst-case wait that 'ticks' cycles will
+ * take (you guarantee that you won't wait any longer than this, but it may
+ * be shorter).
+ */
+static INLINE u32 kbasep_js_convert_gpu_ticks_to_us_min_freq( kbase_device *kbdev, u32 ticks )
+{
+ u32 gpu_freq = kbdev->gpu_props.props.core_props.gpu_freq_khz_min;
+ OSK_ASSERT( 0!= gpu_freq );
+ return (ticks / gpu_freq * 1000);
+}
+
+/**
+ * This will provide a conversion from ticks of the gpu clock to time (us)
+ * based on the maximum available gpu frequency.
+ * This is usually good to compute best/worst case (where the use of current
+ * frequency is not valid due to DVFS).
+ * e.g.: When you need to know the best-case wait for 'tick' cycles (you
+ * guarantee to be waiting for at least this long, but it may be longer).
+ */
+static INLINE u32 kbasep_js_convert_gpu_ticks_to_us_max_freq( kbase_device *kbdev, u32 ticks )
+{
+ u32 gpu_freq = kbdev->gpu_props.props.core_props.gpu_freq_khz_max;
+ OSK_ASSERT( 0!= gpu_freq );
+ return (ticks / gpu_freq * 1000);
+}
+/** @} */ /* end group kbase_js */
+/** @} */ /* end group base_kbase_api */
+/** @} */ /* end group base_api */
+
+#endif /* _KBASE_JS_H_ */
diff --git a/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_js_affinity.c b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_js_affinity.c
new file mode 100644
index 0000000..a171ad1
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_js_affinity.c
@@ -0,0 +1,463 @@
+/*
+ *
+ * (C) COPYRIGHT 2010-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_kbase_js_affinity.c
+ * Base kernel affinity manager APIs
+ */
+
+#include <kbase/src/common/mali_kbase.h>
+#include "mali_kbase_js_affinity.h"
+
+#if defined(CONFIG_MALI_DEBUG) && 0 /* disabled to avoid compilation warnings */
+
+STATIC void debug_get_binary_string(const u64 n, char *buff, const int size)
+{
+ unsigned int i;
+ for (i = 0; i < size; i++)
+ {
+ buff[i] = ((n >> i) & 1) ? '*' : '-';
+ }
+ buff[size] = '\0';
+}
+
+#define N_CORES 8
+STATIC void debug_print_affinity_info(const kbase_device *kbdev, const kbase_jd_atom *katom, int js, u64 affinity)
+{
+ char buff[N_CORES +1];
+ char buff2[N_CORES +1];
+ base_jd_core_req core_req = katom->atom->core_req;
+ u8 nr_nss_ctxs_running = kbdev->js_data.runpool_irq.ctx_attr_ref_count[KBASEP_JS_CTX_ATTR_NSS];
+ u64 shader_present_bitmap = kbdev->shader_present_bitmap;
+
+ debug_get_binary_string(shader_present_bitmap, buff, N_CORES);
+ debug_get_binary_string(affinity, buff2, N_CORES);
+
+ OSK_PRINT_INFO(OSK_BASE_JM, "Job: NSS COH FS CS T CF V JS | NSS_ctx | GPU:12345678 | AFF:12345678");
+ OSK_PRINT_INFO(OSK_BASE_JM, " %s %s %s %s %s %s %s %u | %u | %s | %s",
+ core_req & BASE_JD_REQ_NSS ? "*" : "-",
+ core_req & BASE_JD_REQ_COHERENT_GROUP ? "*" : "-",
+ core_req & BASE_JD_REQ_FS ? "*" : "-",
+ core_req & BASE_JD_REQ_CS ? "*" : "-",
+ core_req & BASE_JD_REQ_T ? "*" : "-",
+ core_req & BASE_JD_REQ_CF ? "*" : "-",
+ core_req & BASE_JD_REQ_V ? "*" : "-",
+ js, nr_nss_ctxs_running, buff, buff2);
+}
+
+#endif /* CONFIG_MALI_DEBUG */
+
+OSK_STATIC_INLINE mali_bool affinity_job_uses_high_cores( kbase_device *kbdev, kbase_jd_atom *katom )
+{
+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8987))
+ {
+ kbase_context *kctx;
+ kbase_context_flags ctx_flags;
+
+ kctx = katom->kctx;
+ ctx_flags = kctx->jctx.sched_info.ctx.flags;
+
+ /* In this HW Workaround, compute-only jobs/contexts use the high cores
+ * during a core-split, all other contexts use the low cores. */
+ return (mali_bool)((katom->core_req & BASE_JD_REQ_ONLY_COMPUTE) != 0
+ || (ctx_flags & KBASE_CTX_FLAG_HINT_ONLY_COMPUTE) != 0);
+ }
+ else
+ {
+ base_jd_core_req core_req = katom->core_req;
+ /* NSS-ness determines whether the high cores in a core split are used */
+ return (mali_bool)(core_req & BASE_JD_REQ_NSS);
+ }
+}
+
+
+/**
+ * @brief Decide whether a split in core affinity is required across job slots
+ *
+ * The following locking conditions are made on the caller:
+ * - it must hold kbasep_js_device_data::runpool_irq::lock
+ *
+ * @param kbdev The kbase device structure of the device
+ * @return MALI_FALSE if a core split is not required
+ * @return != MALI_FALSE if a core split is required.
+ */
+OSK_STATIC_INLINE mali_bool kbase_affinity_requires_split(kbase_device *kbdev)
+{
+ OSK_ASSERT( kbdev != NULL );
+ lockdep_assert_held(&kbdev->js_data.runpool_irq.lock);
+
+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8987))
+ {
+ s8 nr_compute_ctxs = kbasep_js_ctx_attr_count_on_runpool( kbdev, KBASEP_JS_CTX_ATTR_COMPUTE );
+ s8 nr_noncompute_ctxs = kbasep_js_ctx_attr_count_on_runpool( kbdev, KBASEP_JS_CTX_ATTR_NON_COMPUTE );
+
+ /* In this case, a mix of Compute+Non-Compute determines whether a
+ * core-split is required, to ensure jobs with different numbers of RMUs
+ * don't use the same cores.
+ *
+ * When it's entirely compute, or entirely non-compute, then no split is
+ * required.
+ *
+ * A context can be both Compute and Non-compute, in which case this will
+ * correctly decide that a core-split is required. */
+
+ return (mali_bool)( nr_compute_ctxs > 0 && nr_noncompute_ctxs > 0 );
+ }
+ else
+ {
+ /* NSS/SS state determines whether a core-split is required */
+ return kbasep_js_ctx_attr_is_attr_on_runpool( kbdev, KBASEP_JS_CTX_ATTR_NSS );
+ }
+}
+
+
+
+
+mali_bool kbase_js_can_run_job_on_slot_no_lock( kbase_device *kbdev, int js )
+{
+ /*
+ * Here are the reasons for using job slot 2:
+ * - BASE_HW_ISSUE_8987 (which is entirely used for that purpose)
+ * - NSS atoms (in NSS state, this is entirely used for that)
+ * - In absence of the above two, then:
+ * - Atoms with BASE_JD_REQ_COHERENT_GROUP
+ * - But, only when there aren't contexts with
+ * KBASEP_JS_CTX_ATTR_COMPUTE_ALL_CORES, because the atoms that run on
+ * all cores on slot 1 could be blocked by those using a coherent group
+ * on slot 2
+ * - And, only when you actually have 2 or more coregroups - if you only
+ * have 1 coregroup, then having jobs for slot 2 implies they'd also be
+ * for slot 1, meaning you'll get interference from them. Jobs able to
+ * run on slot 2 could also block jobs that can only run on slot 1
+ * (tiler jobs)
+ */
+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8987))
+ {
+ return MALI_TRUE;
+ }
+
+ if ( js != 2 )
+ {
+ return MALI_TRUE;
+ }
+
+ /* Only deal with js==2 now: */
+ if ( kbasep_js_ctx_attr_is_attr_on_runpool( kbdev, KBASEP_JS_CTX_ATTR_NSS ) != MALI_FALSE )
+ {
+ /* In NSS state, slot 2 is used, and exclusively for NSS jobs (which cause a coresplit) */
+ return MALI_TRUE;
+ }
+
+ if ( kbdev->gpu_props.num_core_groups > 1 )
+ {
+ /* Otherwise, only use slot 2 in the 2+ coregroup case */
+ if ( kbasep_js_ctx_attr_is_attr_on_runpool( kbdev, KBASEP_JS_CTX_ATTR_COMPUTE_ALL_CORES ) == MALI_FALSE )
+ {
+ /* ...But only when we *don't* have atoms that run on all cores */
+
+ /* No specific check for BASE_JD_REQ_COHERENT_GROUP atoms - the policy will sort that out */
+ return MALI_TRUE;
+ }
+ }
+
+ /* Above checks failed mean we shouldn't use slot 2 */
+ return MALI_FALSE;
+}
+
+/*
+ * As long as it has been decided to have a deeper modification of
+ * what job scheduler, power manager and affinity manager will
+ * implement, this function is just an intermediate step that
+ * assumes:
+ * - all working cores will be powered on when this is called.
+ * - largest current configuration is a T658 (2x4 cores).
+ * - It has been decided not to have hardcoded values so the low
+ * and high cores in a core split will be evently distributed.
+ * - Odd combinations of core requirements have been filtered out
+ * and do not get to this function (e.g. CS+T+NSS is not
+ * supported here).
+ * - This function is frequently called and can be optimized,
+ * (see notes in loops), but as the functionallity will likely
+ * be modified, optimization has not been addressed.
+*/
+void kbase_js_choose_affinity(u64 *affinity, kbase_device *kbdev, kbase_jd_atom *katom, int js)
+{
+ base_jd_core_req core_req = katom->core_req;
+ u64 shader_present_bitmap = kbdev->shader_present_bitmap;
+ unsigned int num_core_groups = kbdev->gpu_props.num_core_groups;
+
+ OSK_ASSERT(0 != shader_present_bitmap);
+ OSK_ASSERT( js >= 0 );
+
+ if (1 == kbdev->gpu_props.num_cores)
+ {
+ /* trivial case only one core, nothing to do */
+ *affinity = shader_present_bitmap;
+ }
+ else if ( kbase_affinity_requires_split( kbdev ) == MALI_FALSE )
+ {
+ if ( (core_req & (BASE_JD_REQ_COHERENT_GROUP | BASE_JD_REQ_SPECIFIC_COHERENT_GROUP)) )
+ {
+ if ( js == 0 || num_core_groups == 1 )
+ {
+ /* js[0] and single-core-group systems just get the first core group */
+ *affinity = kbdev->gpu_props.props.coherency_info.group[0].core_mask;
+ }
+ else
+ {
+ /* js[1], js[2] use core groups 0, 1 for dual-core-group systems */
+ u32 core_group_idx = ((u32)js) - 1;
+ OSK_ASSERT( core_group_idx < num_core_groups );
+ *affinity = kbdev->gpu_props.props.coherency_info.group[core_group_idx].core_mask;
+ }
+ }
+ else
+ {
+ /* All cores are available when no core split is required */
+ *affinity = shader_present_bitmap;
+ }
+ }
+ else
+ {
+ /* Core split required - divide cores in two non-overlapping groups */
+ u64 low_bitmap, high_bitmap;
+ int n_high_cores = kbdev->gpu_props.num_cores >> 1;
+ OSK_ASSERT(0 != n_high_cores);
+
+ /* compute the reserved high cores bitmap */
+ high_bitmap = ~0;
+ /* note: this can take a while, optimization desirable */
+ while (n_high_cores != osk_count_set_bits(high_bitmap & shader_present_bitmap))
+ {
+ high_bitmap = high_bitmap << 1;
+ }
+ high_bitmap &= shader_present_bitmap;
+
+ /* now decide 4 different situations depending on the low or high
+ * set of cores and requiring coherent group or not */
+ if (affinity_job_uses_high_cores( kbdev, katom ))
+ {
+ OSK_ASSERT(0 != num_core_groups);
+
+ if ( (core_req & (BASE_JD_REQ_COHERENT_GROUP | BASE_JD_REQ_SPECIFIC_COHERENT_GROUP))
+ && (1 != num_core_groups))
+ {
+ /* high set of cores requiring coherency and coherency matters
+ * because we got more than one core group */
+ u64 group1_mask = kbdev->gpu_props.props.coherency_info.group[1].core_mask;
+ *affinity = high_bitmap & group1_mask;
+ }
+ else
+ {
+ /* high set of cores not requiring coherency or coherency is
+ assured as we only have one core_group */
+ *affinity = high_bitmap;
+ }
+ }
+ else
+ {
+ low_bitmap = shader_present_bitmap ^ high_bitmap;
+
+ if ( core_req & (BASE_JD_REQ_COHERENT_GROUP | BASE_JD_REQ_SPECIFIC_COHERENT_GROUP))
+ {
+ /* low set of cores and req coherent group */
+ u64 group0_mask = kbdev->gpu_props.props.coherency_info.group[0].core_mask;
+ u64 low_coh_bitmap = low_bitmap & group0_mask;
+ *affinity = low_coh_bitmap;
+ }
+ else
+ {
+ /* low set of cores and does not req coherent group */
+ *affinity = low_bitmap;
+ }
+ }
+ }
+
+ OSK_ASSERT(*affinity != 0);
+}
+
+OSK_STATIC_INLINE mali_bool kbase_js_affinity_is_violating( kbase_device *kbdev, u64 *affinities )
+{
+ /* This implementation checks whether:
+ * - the two slots involved in Generic thread creation have intersecting affinity
+ * - Cores for the fragment slot (slot 0) would compete with cores for slot 2 when NSS atoms are in use.
+ * - This is due to micro-architectural issues where a job in slot A targetting
+ * cores used by slot B could prevent the job in slot B from making progress
+ * until the job in slot A has completed.
+ * - In our case, when slot 2 is used for batch/NSS atoms, the affinity
+ * intersecting with slot 0 would cause fragment atoms to be delayed by the batch/NSS
+ * atoms.
+ *
+ * @note It just so happens that these restrictions also allow
+ * BASE_HW_ISSUE_8987 to be worked around by placing on job slot 2 the
+ * atoms from ctxs with KBASE_CTX_FLAG_HINT_ONLY_COMPUTE flag set
+ */
+ u64 affinity_set_left;
+ u64 affinity_set_right;
+ u64 intersection;
+ OSK_ASSERT( affinities != NULL );
+
+ affinity_set_left = affinities[1];
+
+ if ( kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8987)
+ || kbasep_js_ctx_attr_is_attr_on_runpool(kbdev, KBASEP_JS_CTX_ATTR_NSS) != MALI_FALSE )
+ {
+ /* The left set also includes those on the Fragment slot when:
+ * - We are using the HW workaround for BASE_HW_ISSUE_8987
+ * - We're in NSS state - to prevent NSS atoms using the same cores as Fragment atoms */
+ affinity_set_left |= affinities[0];
+ }
+
+ affinity_set_right = affinities[2];
+
+ /* A violation occurs when any bit in the left_set is also in the right_set */
+ intersection = affinity_set_left & affinity_set_right;
+
+ return (mali_bool)( intersection != (u64)0u );
+}
+
+mali_bool kbase_js_affinity_would_violate( kbase_device *kbdev, int js, u64 affinity )
+{
+ kbasep_js_device_data *js_devdata;
+ u64 new_affinities[BASE_JM_MAX_NR_SLOTS];
+
+ OSK_ASSERT( kbdev != NULL );
+ OSK_ASSERT( js < BASE_JM_MAX_NR_SLOTS );
+ js_devdata = &kbdev->js_data;
+
+ memcpy( new_affinities, js_devdata->runpool_irq.slot_affinities, sizeof(js_devdata->runpool_irq.slot_affinities) );
+
+ new_affinities[ js ] |= affinity;
+
+ return kbase_js_affinity_is_violating( kbdev, new_affinities );
+}
+
+void kbase_js_affinity_retain_slot_cores( kbase_device *kbdev, int js, u64 affinity )
+{
+ kbasep_js_device_data *js_devdata;
+ u64 cores;
+
+ OSK_ASSERT( kbdev != NULL );
+ OSK_ASSERT( js < BASE_JM_MAX_NR_SLOTS );
+ js_devdata = &kbdev->js_data;
+
+ OSK_ASSERT( kbase_js_affinity_would_violate( kbdev, js, affinity ) == MALI_FALSE );
+
+ cores = affinity;
+ while (cores)
+ {
+ int bitnum = 63 - osk_clz_64(cores);
+ u64 bit = 1ULL << bitnum;
+ s8 cnt;
+
+ OSK_ASSERT( js_devdata->runpool_irq.slot_affinity_refcount[ js ][bitnum] < BASE_JM_SUBMIT_SLOTS );
+
+ cnt = ++(js_devdata->runpool_irq.slot_affinity_refcount[ js ][bitnum]);
+
+ if ( cnt == 1 )
+ {
+ js_devdata->runpool_irq.slot_affinities[js] |= bit;
+ }
+
+ cores &= ~bit;
+ }
+
+}
+
+void kbase_js_affinity_release_slot_cores( kbase_device *kbdev, int js, u64 affinity )
+{
+ kbasep_js_device_data *js_devdata;
+ u64 cores;
+
+ OSK_ASSERT( kbdev != NULL );
+ OSK_ASSERT( js < BASE_JM_MAX_NR_SLOTS );
+ js_devdata = &kbdev->js_data;
+
+ cores = affinity;
+ while (cores)
+ {
+ int bitnum = 63 - osk_clz_64(cores);
+ u64 bit = 1ULL << bitnum;
+ s8 cnt;
+
+ OSK_ASSERT( js_devdata->runpool_irq.slot_affinity_refcount[ js ][bitnum] > 0 );
+
+ cnt = --(js_devdata->runpool_irq.slot_affinity_refcount[ js ][bitnum]);
+
+ if (0 == cnt)
+ {
+ js_devdata->runpool_irq.slot_affinities[js] &= ~bit;
+ }
+
+ cores &= ~bit;
+ }
+
+}
+
+void kbase_js_affinity_slot_blocked_an_atom( kbase_device *kbdev, int js )
+{
+ kbasep_js_device_data *js_devdata;
+
+ OSK_ASSERT( kbdev != NULL );
+ OSK_ASSERT( js < BASE_JM_MAX_NR_SLOTS );
+ js_devdata = &kbdev->js_data;
+
+ js_devdata->runpool_irq.slots_blocked_on_affinity |= 1u << js;
+}
+
+void kbase_js_affinity_submit_to_blocked_slots( kbase_device *kbdev )
+{
+ kbasep_js_device_data *js_devdata;
+ u16 slots;
+
+ OSK_ASSERT( kbdev != NULL );
+ js_devdata = &kbdev->js_data;
+
+ OSK_ASSERT( js_devdata->nr_user_contexts_running != 0 );
+
+ /* Must take a copy because submitting jobs will update this member. */
+ slots = js_devdata->runpool_irq.slots_blocked_on_affinity;
+
+ while (slots)
+ {
+ int bitnum = 31 - osk_clz(slots);
+ u16 bit = 1u << bitnum;
+ slots &= ~bit;
+
+ KBASE_TRACE_ADD_SLOT( kbdev, JS_AFFINITY_SUBMIT_TO_BLOCKED, NULL, NULL, 0u, bitnum);
+
+ /* must update this before we submit, incase it's set again */
+ js_devdata->runpool_irq.slots_blocked_on_affinity &= ~bit;
+
+ kbasep_js_try_run_next_job_on_slot_nolock( kbdev, bitnum );
+
+ /* Don't re-read slots_blocked_on_affinity after this - it could loop for a long time */
+ }
+}
+
+#if defined(CONFIG_MALI_DEBUG) || (KBASE_TRACE_ENABLE != 0)
+void kbase_js_debug_log_current_affinities( kbase_device *kbdev )
+{
+ kbasep_js_device_data *js_devdata;
+ int slot_nr;
+
+ OSK_ASSERT( kbdev != NULL );
+ js_devdata = &kbdev->js_data;
+
+ for ( slot_nr = 0; slot_nr < 3 ; ++slot_nr )
+ {
+ KBASE_TRACE_ADD_SLOT_INFO( kbdev, JS_AFFINITY_CURRENT, NULL, NULL, 0u, slot_nr, (u32)js_devdata->runpool_irq.slot_affinities[slot_nr] );
+ }
+}
+#endif /* defined(CONFIG_MALI_DEBUG) || (KBASE_TRACE_ENABLE != 0) */
diff --git a/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_js_affinity.h b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_js_affinity.h
new file mode 100644
index 0000000..a11abea
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_js_affinity.h
@@ -0,0 +1,163 @@
+/*
+ *
+ * (C) COPYRIGHT 2011-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_kbase_js_affinity.h
+ * Affinity Manager internal APIs.
+ */
+
+#ifndef _KBASE_JS_AFFINITY_H_
+#define _KBASE_JS_AFFINITY_H_
+
+
+
+/**
+ * @addtogroup base_api
+ * @{
+ */
+
+/**
+ * @addtogroup base_kbase_api
+ * @{
+ */
+
+
+/**
+ * @addtogroup kbase_js_affinity Affinity Manager internal APIs.
+ * @{
+ *
+ */
+
+
+/**
+ * @brief Decide whether it is possible to submit a job to a particular job slot in the current status
+ *
+ * Will check if submitting to the given job slot is allowed in the current
+ * status. For example using job slot 2 while in soft-stoppable state and only
+ * having 1 coregroup is not allowed by the policy. This function should be
+ * called prior to submitting a job to a slot to make sure policy rules are not
+ * violated.
+ *
+ * The following locking conditions are made on the caller:
+ * - it must hold kbasep_js_device_data::runpool_irq::lock
+ *
+ * @param kbdev The kbase device structure of the device
+ * @param js Job slot number to check for allowance
+ */
+mali_bool kbase_js_can_run_job_on_slot_no_lock( kbase_device *kbdev, int js );
+
+/**
+ * @brief Compute affinity for a given job.
+ *
+ * Currently assumes an all-on/all-off power management policy.
+ * Also assumes there is at least one core with tiler available.
+ * Will try to produce an even distribution of cores for SS and
+ * NSS jobs. SS jobs will be given cores starting from core-group
+ * 0 forward to n. NSS jobs will be given cores from core-group n
+ * backwards to 0. This way for example in a T658 SS jobs will
+ * tend to run on cores from core-group 0 and NSS jobs will tend
+ * to run on cores from core-group 1.
+ * An assertion will be raised if computed affinity is 0
+ *
+ * @param[out] affinity Affinity bitmap computed
+ * @param kbdev The kbase device structure of the device
+ * @param katom Job chain of which affinity is going to be found
+ * @param js Slot the job chain is being submitted
+
+ */
+void kbase_js_choose_affinity( u64 *affinity, kbase_device *kbdev, kbase_jd_atom *katom, int js );
+
+/**
+ * @brief Determine whether a proposed \a affinity on job slot \a js would
+ * cause a violation of affinity restrictions.
+ *
+ * The following locks must be held by the caller:
+ * - kbasep_js_device_data::runpool_irq::lock
+ */
+mali_bool kbase_js_affinity_would_violate( kbase_device *kbdev, int js, u64 affinity );
+
+/**
+ * @brief Affinity tracking: retain cores used by a slot
+ *
+ * The following locks must be held by the caller:
+ * - kbasep_js_device_data::runpool_irq::lock
+ */
+void kbase_js_affinity_retain_slot_cores( kbase_device *kbdev, int js, u64 affinity );
+
+/**
+ * @brief Affinity tracking: release cores used by a slot
+ *
+ * Cores \b must be released as soon as a job is dequeued from a slot's 'submit
+ * slots', and before another job is submitted to those slots. Otherwise, the
+ * refcount could exceed the maximum number submittable to a slot,
+ * BASE_JM_SUBMIT_SLOTS.
+ *
+ * The following locks must be held by the caller:
+ * - kbasep_js_device_data::runpool_irq::lock
+ */
+void kbase_js_affinity_release_slot_cores( kbase_device *kbdev, int js, u64 affinity );
+
+/**
+ * @brief Register a slot as blocking atoms due to affinity violations
+ *
+ * Once a slot has been registered, we must check after every atom completion
+ * (including those on different slots) to see if the slot can be
+ * unblocked. This is done by calling
+ * kbase_js_affinity_submit_to_blocked_slots(), which will also deregister the
+ * slot if it no long blocks atoms due to affinity violations.
+ *
+ * The following locks must be held by the caller:
+ * - kbasep_js_device_data::runpool_irq::lock
+ */
+void kbase_js_affinity_slot_blocked_an_atom( kbase_device *kbdev, int js );
+
+/**
+ * @brief Submit to job slots that have registered that an atom was blocked on
+ * the slot previously due to affinity violations.
+ *
+ * This submits to all slots registered by
+ * kbase_js_affinity_slot_blocked_an_atom(). If submission succeeded, then the
+ * slot is deregistered as having blocked atoms due to affinity
+ * violations. Otherwise it stays registered, and the next atom to complete
+ * must attempt to submit to the blocked slots again.
+ *
+ * This must only be called whilst the GPU is powered - for example, when
+ * kbdev->jsdata.nr_user_contexts_running > 0.
+ *
+ * The following locking conditions are made on the caller:
+ * - it must hold kbasep_js_device_data::runpool_mutex
+ * - it must hold kbasep_js_device_data::runpool_irq::lock
+ */
+void kbase_js_affinity_submit_to_blocked_slots( kbase_device *kbdev );
+
+/**
+ * @brief Output to the Trace log the current tracked affinities on all slots
+ */
+#if defined(CONFIG_MALI_DEBUG) || (KBASE_TRACE_ENABLE != 0)
+void kbase_js_debug_log_current_affinities( kbase_device *kbdev );
+#else /* defined(CONFIG_MALI_DEBUG) || (KBASE_TRACE_ENABLE != 0) */
+OSK_STATIC_INLINE void kbase_js_debug_log_current_affinities( kbase_device *kbdev )
+{
+}
+#endif /* defined(CONFIG_MALI_DEBUG) || (KBASE_TRACE_ENABLE != 0) */
+
+/** @} */ /* end group kbase_js_affinity */
+/** @} */ /* end group base_kbase_api */
+/** @} */ /* end group base_api */
+
+
+
+
+
+#endif /* _KBASE_JS_AFFINITY_H_ */
diff --git a/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_js_ctx_attr.c b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_js_ctx_attr.c
new file mode 100644
index 0000000..943ec00
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_js_ctx_attr.c
@@ -0,0 +1,359 @@
+/*
+ *
+ * (C) COPYRIGHT 2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+#include <kbase/src/common/mali_kbase.h>
+
+/*
+ * Private functions follow
+ */
+
+/**
+ * @brief Check whether a ctx has a certain attribute, and if so, retain that
+ * attribute on the runpool.
+ *
+ * Requires:
+ * - jsctx mutex
+ * - runpool_irq spinlock
+ * - ctx is scheduled on the runpool
+ *
+ * @return MALI_TRUE indicates a change in ctx attributes state of the runpool.
+ * In this state, the scheduler might be able to submit more jobs than
+ * previously, and so the caller should ensure kbasep_js_try_run_next_job_nolock()
+ * or similar is called sometime later.
+ * @return MALI_FALSE indicates no change in ctx attributes state of the runpool.
+ */
+STATIC mali_bool kbasep_js_ctx_attr_runpool_retain_attr( kbase_device *kbdev,
+ kbase_context *kctx,
+ kbasep_js_ctx_attr attribute )
+{
+ kbasep_js_device_data *js_devdata;
+ kbasep_js_kctx_info *js_kctx_info;
+ mali_bool runpool_state_changed = MALI_FALSE;
+
+ OSK_ASSERT( kbdev != NULL );
+ OSK_ASSERT( kctx != NULL );
+ OSK_ASSERT( attribute < KBASEP_JS_CTX_ATTR_COUNT );
+ js_devdata = &kbdev->js_data;
+ js_kctx_info = &kctx->jctx.sched_info;
+
+ BUG_ON(!mutex_is_locked( &js_kctx_info->ctx.jsctx_mutex ));
+ lockdep_assert_held( &kbdev->js_data.runpool_irq.lock );
+
+ OSK_ASSERT( js_kctx_info->ctx.is_scheduled != MALI_FALSE );
+
+ if ( kbasep_js_ctx_attr_is_attr_on_ctx( kctx, attribute ) != MALI_FALSE )
+ {
+ OSK_ASSERT( js_devdata->runpool_irq.ctx_attr_ref_count[attribute] < S8_MAX );
+ ++(js_devdata->runpool_irq.ctx_attr_ref_count[attribute]);
+
+ if ( js_devdata->runpool_irq.ctx_attr_ref_count[attribute] == 1 )
+ {
+ /* First refcount indicates a state change */
+ runpool_state_changed = MALI_TRUE;
+ KBASE_TRACE_ADD( kbdev, JS_CTX_ATTR_NOW_ON_RUNPOOL, kctx, NULL, 0u, attribute );
+ }
+ }
+
+ return runpool_state_changed;
+}
+
+/**
+ * @brief Check whether a ctx has a certain attribute, and if so, release that
+ * attribute on the runpool.
+ *
+ * Requires:
+ * - jsctx mutex
+ * - runpool_irq spinlock
+ * - ctx is scheduled on the runpool
+ *
+ * @return MALI_TRUE indicates a change in ctx attributes state of the runpool.
+ * In this state, the scheduler might be able to submit more jobs than
+ * previously, and so the caller should ensure kbasep_js_try_run_next_job_nolock()
+ * or similar is called sometime later.
+ * @return MALI_FALSE indicates no change in ctx attributes state of the runpool.
+ */
+STATIC mali_bool kbasep_js_ctx_attr_runpool_release_attr( kbase_device *kbdev,
+ kbase_context *kctx,
+ kbasep_js_ctx_attr attribute )
+{
+ kbasep_js_device_data *js_devdata;
+ kbasep_js_kctx_info *js_kctx_info;
+ mali_bool runpool_state_changed = MALI_FALSE;
+
+ OSK_ASSERT( kbdev != NULL );
+ OSK_ASSERT( kctx != NULL );
+ OSK_ASSERT( attribute < KBASEP_JS_CTX_ATTR_COUNT );
+ js_devdata = &kbdev->js_data;
+ js_kctx_info = &kctx->jctx.sched_info;
+
+ BUG_ON(!mutex_is_locked( &js_kctx_info->ctx.jsctx_mutex ));
+ lockdep_assert_held( &kbdev->js_data.runpool_irq.lock );
+ OSK_ASSERT( js_kctx_info->ctx.is_scheduled != MALI_FALSE );
+
+ if ( kbasep_js_ctx_attr_is_attr_on_ctx( kctx, attribute ) != MALI_FALSE )
+ {
+ OSK_ASSERT( js_devdata->runpool_irq.ctx_attr_ref_count[attribute] > 0 );
+ --(js_devdata->runpool_irq.ctx_attr_ref_count[attribute]);
+
+ if ( js_devdata->runpool_irq.ctx_attr_ref_count[attribute] == 0 )
+ {
+ /* Last de-refcount indicates a state change */
+ runpool_state_changed = MALI_TRUE;
+ KBASE_TRACE_ADD( kbdev, JS_CTX_ATTR_NOW_OFF_RUNPOOL, kctx, NULL, 0u, attribute );
+ }
+ }
+
+ return runpool_state_changed;
+}
+
+/**
+ * @brief Retain a certain attribute on a ctx, also retaining it on the runpool
+ * if the context is scheduled.
+ *
+ * Requires:
+ * - jsctx mutex
+ * - If the context is scheduled, then runpool_irq spinlock must also be held
+ *
+ * @return MALI_TRUE indicates a change in ctx attributes state of the runpool.
+ * This may allow the scheduler to submit more jobs than previously.
+ * @return MALI_FALSE indicates no change in ctx attributes state of the runpool.
+ */
+STATIC mali_bool kbasep_js_ctx_attr_ctx_retain_attr( kbase_device *kbdev,
+ kbase_context *kctx,
+ kbasep_js_ctx_attr attribute )
+{
+ kbasep_js_kctx_info *js_kctx_info;
+ mali_bool runpool_state_changed = MALI_FALSE;
+
+ OSK_ASSERT( kbdev != NULL );
+ OSK_ASSERT( kctx != NULL );
+ OSK_ASSERT( attribute < KBASEP_JS_CTX_ATTR_COUNT );
+ js_kctx_info = &kctx->jctx.sched_info;
+
+ BUG_ON(!mutex_is_locked( &js_kctx_info->ctx.jsctx_mutex ));
+ OSK_ASSERT( js_kctx_info->ctx.ctx_attr_ref_count[ attribute ] < U32_MAX );
+
+ ++(js_kctx_info->ctx.ctx_attr_ref_count[ attribute ]);
+
+ if ( js_kctx_info->ctx.is_scheduled != MALI_FALSE
+ && js_kctx_info->ctx.ctx_attr_ref_count[ attribute ] == 1 )
+ {
+ lockdep_assert_held( &kbdev->js_data.runpool_irq.lock );
+ /* Only ref-count the attribute on the runpool for the first time this contexts sees this attribute */
+ KBASE_TRACE_ADD( kbdev, JS_CTX_ATTR_NOW_ON_CTX, kctx, NULL, 0u, attribute );
+ runpool_state_changed = kbasep_js_ctx_attr_runpool_retain_attr( kbdev, kctx, attribute );
+ }
+
+ return runpool_state_changed;
+}
+
+/**
+ * @brief Release a certain attribute on a ctx, also releasign it from the runpool
+ * if the context is scheduled.
+ *
+ * Requires:
+ * - jsctx mutex
+ * - If the context is scheduled, then runpool_irq spinlock must also be held
+ *
+ * @return MALI_TRUE indicates a change in ctx attributes state of the runpool.
+ * This may allow the scheduler to submit more jobs than previously.
+ * @return MALI_FALSE indicates no change in ctx attributes state of the runpool.
+ */
+STATIC mali_bool kbasep_js_ctx_attr_ctx_release_attr( kbase_device *kbdev,
+ kbase_context *kctx,
+ kbasep_js_ctx_attr attribute )
+{
+ kbasep_js_kctx_info *js_kctx_info;
+ mali_bool runpool_state_changed = MALI_FALSE;
+
+ OSK_ASSERT( kbdev != NULL );
+ OSK_ASSERT( kctx != NULL );
+ OSK_ASSERT( attribute < KBASEP_JS_CTX_ATTR_COUNT );
+ js_kctx_info = &kctx->jctx.sched_info;
+
+ BUG_ON(!mutex_is_locked( &js_kctx_info->ctx.jsctx_mutex ));
+ OSK_ASSERT( js_kctx_info->ctx.ctx_attr_ref_count[ attribute ] > 0 );
+
+ if ( js_kctx_info->ctx.is_scheduled != MALI_FALSE
+ && js_kctx_info->ctx.ctx_attr_ref_count[ attribute ] == 1 )
+ {
+ lockdep_assert_held( &kbdev->js_data.runpool_irq.lock );
+ /* Only de-ref-count the attribute on the runpool when this is the last ctx-reference to it */
+ runpool_state_changed = kbasep_js_ctx_attr_runpool_release_attr( kbdev, kctx, attribute );
+ KBASE_TRACE_ADD( kbdev, JS_CTX_ATTR_NOW_OFF_CTX, kctx, NULL, 0u, attribute );
+ }
+
+ /* De-ref must happen afterwards, because kbasep_js_ctx_attr_runpool_release() needs to check it too */
+ --(js_kctx_info->ctx.ctx_attr_ref_count[ attribute ]);
+
+ return runpool_state_changed;
+}
+
+
+/*
+ * More commonly used public functions
+ */
+
+void kbasep_js_ctx_attr_set_initial_attrs( kbase_device *kbdev,
+ kbase_context *kctx )
+{
+ kbasep_js_kctx_info *js_kctx_info;
+ mali_bool runpool_state_changed = MALI_FALSE;
+
+ OSK_ASSERT( kbdev != NULL );
+ OSK_ASSERT( kctx != NULL );
+ js_kctx_info = &kctx->jctx.sched_info;
+
+ if ( (js_kctx_info->ctx.flags & KBASE_CTX_FLAG_SUBMIT_DISABLED) != MALI_FALSE )
+ {
+ /* This context never submits, so don't track any scheduling attributes */
+ return;
+ }
+
+ /* Transfer attributes held in the context flags for contexts that have submit enabled */
+
+ if ( (js_kctx_info->ctx.flags & KBASE_CTX_FLAG_HINT_ONLY_COMPUTE) != MALI_FALSE )
+ {
+ /* Compute context */
+ runpool_state_changed |= kbasep_js_ctx_attr_ctx_retain_attr( kbdev, kctx, KBASEP_JS_CTX_ATTR_COMPUTE );
+ }
+ /* NOTE: Whether this is a non-compute context depends on the jobs being
+ * run, e.g. it might be submitting jobs with BASE_JD_REQ_ONLY_COMPUTE */
+
+ /* ... More attributes can be added here ... */
+
+ /* The context should not have been scheduled yet, so ASSERT if this caused
+ * runpool state changes (note that other threads *can't* affect the value
+ * of runpool_state_changed, due to how it's calculated) */
+ OSK_ASSERT( runpool_state_changed == MALI_FALSE );
+ CSTD_UNUSED( runpool_state_changed );
+}
+
+void kbasep_js_ctx_attr_runpool_retain_ctx( kbase_device *kbdev,
+ kbase_context *kctx )
+{
+ mali_bool runpool_state_changed;
+ int i;
+
+ /* Retain any existing attributes */
+ for ( i = 0 ; i < KBASEP_JS_CTX_ATTR_COUNT; ++i )
+ {
+ if ( kbasep_js_ctx_attr_is_attr_on_ctx( kctx, (kbasep_js_ctx_attr)i ) != MALI_FALSE )
+ {
+ /* The context is being scheduled in, so update the runpool with the new attributes */
+ runpool_state_changed = kbasep_js_ctx_attr_runpool_retain_attr( kbdev, kctx, (kbasep_js_ctx_attr)i );
+
+ /* We don't need to know about state changed, because retaining a
+ * context occurs on scheduling it, and that itself will also try
+ * to run new atoms */
+ CSTD_UNUSED( runpool_state_changed );
+ }
+ }
+}
+
+mali_bool kbasep_js_ctx_attr_runpool_release_ctx( kbase_device *kbdev,
+ kbase_context *kctx )
+{
+ mali_bool runpool_state_changed = MALI_FALSE;
+ int i;
+
+ /* Release any existing attributes */
+ for ( i = 0 ; i < KBASEP_JS_CTX_ATTR_COUNT; ++i )
+ {
+ if ( kbasep_js_ctx_attr_is_attr_on_ctx( kctx, (kbasep_js_ctx_attr)i ) != MALI_FALSE )
+ {
+ /* The context is being scheduled out, so update the runpool on the removed attributes */
+ runpool_state_changed |= kbasep_js_ctx_attr_runpool_release_attr( kbdev, kctx, (kbasep_js_ctx_attr)i );
+ }
+ }
+
+ return runpool_state_changed;
+}
+
+void kbasep_js_ctx_attr_ctx_retain_atom( kbase_device *kbdev,
+ kbase_context *kctx,
+ kbase_jd_atom *katom )
+{
+ mali_bool runpool_state_changed = MALI_FALSE;
+ base_jd_core_req core_req;
+
+ OSK_ASSERT( katom );
+ core_req = katom->core_req;
+
+ if ( core_req & BASE_JD_REQ_NSS )
+ {
+ runpool_state_changed |= kbasep_js_ctx_attr_ctx_retain_attr( kbdev, kctx, KBASEP_JS_CTX_ATTR_NSS );
+ }
+
+ if ( core_req & BASE_JD_REQ_ONLY_COMPUTE )
+ {
+ runpool_state_changed |= kbasep_js_ctx_attr_ctx_retain_attr( kbdev, kctx, KBASEP_JS_CTX_ATTR_COMPUTE );
+ }
+ else
+ {
+ runpool_state_changed |= kbasep_js_ctx_attr_ctx_retain_attr( kbdev, kctx, KBASEP_JS_CTX_ATTR_NON_COMPUTE );
+ }
+
+ if ( (core_req & ( BASE_JD_REQ_CS | BASE_JD_REQ_ONLY_COMPUTE | BASE_JD_REQ_T)) != 0
+ && (core_req & ( BASE_JD_REQ_COHERENT_GROUP | BASE_JD_REQ_SPECIFIC_COHERENT_GROUP )) == 0 )
+ {
+ /* Atom that can run on slot1 or slot2, and can use all cores */
+ runpool_state_changed |= kbasep_js_ctx_attr_ctx_retain_attr( kbdev, kctx, KBASEP_JS_CTX_ATTR_COMPUTE_ALL_CORES );
+ }
+
+ /* We don't need to know about state changed, because retaining an
+ * atom occurs on adding it, and that itself will also try to run
+ * new atoms */
+ CSTD_UNUSED( runpool_state_changed );
+}
+
+mali_bool kbasep_js_ctx_attr_ctx_release_atom( kbase_device *kbdev,
+ kbase_context *kctx,
+ kbasep_js_atom_retained_state *katom_retained_state )
+{
+ mali_bool runpool_state_changed = MALI_FALSE;
+ base_jd_core_req core_req;
+
+ OSK_ASSERT( katom_retained_state );
+ core_req = katom_retained_state->core_req;
+
+ /* No-op for invalid atoms */
+ if ( kbasep_js_atom_retained_state_is_valid( katom_retained_state ) == MALI_FALSE )
+ {
+ return MALI_FALSE;
+ }
+
+ if ( core_req & BASE_JD_REQ_NSS )
+ {
+ runpool_state_changed |= kbasep_js_ctx_attr_ctx_release_attr( kbdev, kctx, KBASEP_JS_CTX_ATTR_NSS );
+ }
+
+ if ( core_req & BASE_JD_REQ_ONLY_COMPUTE )
+ {
+ runpool_state_changed |= kbasep_js_ctx_attr_ctx_release_attr( kbdev, kctx, KBASEP_JS_CTX_ATTR_COMPUTE );
+ }
+ else
+ {
+ runpool_state_changed |= kbasep_js_ctx_attr_ctx_release_attr( kbdev, kctx, KBASEP_JS_CTX_ATTR_NON_COMPUTE );
+ }
+
+ if ( (core_req & ( BASE_JD_REQ_CS | BASE_JD_REQ_ONLY_COMPUTE | BASE_JD_REQ_T )) != 0
+ && (core_req & ( BASE_JD_REQ_COHERENT_GROUP | BASE_JD_REQ_SPECIFIC_COHERENT_GROUP )) == 0 )
+ {
+ /* Atom that can run on slot1 or slot2, and can use all cores */
+ runpool_state_changed |= kbasep_js_ctx_attr_ctx_release_attr( kbdev, kctx, KBASEP_JS_CTX_ATTR_COMPUTE_ALL_CORES );
+ }
+
+
+ return runpool_state_changed;
+}
diff --git a/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_js_ctx_attr.h b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_js_ctx_attr.h
new file mode 100644
index 0000000..5ac9483
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_js_ctx_attr.h
@@ -0,0 +1,162 @@
+/*
+ *
+ * (C) COPYRIGHT 2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_kbase_js_ctx_attr.h
+ * Job Scheduler Context Attribute APIs
+ */
+
+
+#ifndef _KBASE_JS_CTX_ATTR_H_
+#define _KBASE_JS_CTX_ATTR_H_
+
+/**
+ * @addtogroup base_api
+ * @{
+ */
+
+/**
+ * @addtogroup base_kbase_api
+ * @{
+ */
+
+/**
+ * @addtogroup kbase_js
+ * @{
+ */
+
+/**
+ * Set the initial attributes of a context (when context create flags are set)
+ *
+ * Requires:
+ * - Hold the jsctx_mutex
+ */
+void kbasep_js_ctx_attr_set_initial_attrs( kbase_device *kbdev,
+ kbase_context *kctx );
+
+/**
+ * Retain all attributes of a context
+ *
+ * This occurs on scheduling in the context on the runpool (but after
+ * is_scheduled is set)
+ *
+ * Requires:
+ * - jsctx mutex
+ * - runpool_irq spinlock
+ * - ctx->is_scheduled is true
+ */
+void kbasep_js_ctx_attr_runpool_retain_ctx( kbase_device *kbdev,
+ kbase_context *kctx );
+
+/**
+ * Release all attributes of a context
+ *
+ * This occurs on scheduling out the context from the runpool (but before
+ * is_scheduled is cleared)
+ *
+ * Requires:
+ * - jsctx mutex
+ * - runpool_irq spinlock
+ * - ctx->is_scheduled is true
+ *
+ * @return MALI_TRUE indicates a change in ctx attributes state of the runpool.
+ * In this state, the scheduler might be able to submit more jobs than
+ * previously, and so the caller should ensure kbasep_js_try_run_next_job_nolock()
+ * or similar is called sometime later.
+ * @return MALI_FALSE indicates no change in ctx attributes state of the runpool.
+ */
+mali_bool kbasep_js_ctx_attr_runpool_release_ctx( kbase_device *kbdev,
+ kbase_context *kctx );
+
+/**
+ * Retain all attributes of an atom
+ *
+ * This occurs on adding an atom to a context
+ *
+ * Requires:
+ * - jsctx mutex
+ * - If the context is scheduled, then runpool_irq spinlock must also be held
+ */
+void kbasep_js_ctx_attr_ctx_retain_atom( kbase_device *kbdev,
+ kbase_context *kctx,
+ kbase_jd_atom *katom );
+
+/**
+ * Release all attributes of an atom, given its retained state.
+ *
+ * This occurs after (permanently) removing an atom from a context
+ *
+ * Requires:
+ * - jsctx mutex
+ * - If the context is scheduled, then runpool_irq spinlock must also be held
+ *
+ * This is a no-op when \a katom_retained_state is invalid.
+ *
+ * @return MALI_TRUE indicates a change in ctx attributes state of the runpool.
+ * In this state, the scheduler might be able to submit more jobs than
+ * previously, and so the caller should ensure kbasep_js_try_run_next_job_nolock()
+ * or similar is called sometime later.
+ * @return MALI_FALSE indicates no change in ctx attributes state of the runpool.
+ */
+mali_bool kbasep_js_ctx_attr_ctx_release_atom( kbase_device *kbdev,
+ kbase_context *kctx,
+ kbasep_js_atom_retained_state *katom_retained_state );
+
+/**
+ * Requires:
+ * - runpool_irq spinlock
+ */
+OSK_STATIC_INLINE s8 kbasep_js_ctx_attr_count_on_runpool( kbase_device *kbdev, kbasep_js_ctx_attr attribute )
+{
+ kbasep_js_device_data *js_devdata;
+
+ OSK_ASSERT( kbdev != NULL );
+ OSK_ASSERT( attribute < KBASEP_JS_CTX_ATTR_COUNT );
+ js_devdata = &kbdev->js_data;
+
+ return js_devdata->runpool_irq.ctx_attr_ref_count[attribute];
+}
+
+
+/**
+ * Requires:
+ * - runpool_irq spinlock
+ */
+OSK_STATIC_INLINE mali_bool kbasep_js_ctx_attr_is_attr_on_runpool( kbase_device *kbdev, kbasep_js_ctx_attr attribute )
+{
+ /* In general, attributes are 'on' when they have a non-zero refcount (note: the refcount will never be < 0) */
+ return (mali_bool)kbasep_js_ctx_attr_count_on_runpool( kbdev, attribute );
+}
+
+/**
+ * Requires:
+ * - jsctx mutex
+ */
+OSK_STATIC_INLINE mali_bool kbasep_js_ctx_attr_is_attr_on_ctx( kbase_context *kctx, kbasep_js_ctx_attr attribute )
+{
+ kbasep_js_kctx_info *js_kctx_info;
+
+ OSK_ASSERT( kctx != NULL );
+ OSK_ASSERT( attribute < KBASEP_JS_CTX_ATTR_COUNT );
+ js_kctx_info = &kctx->jctx.sched_info;
+
+ /* In general, attributes are 'on' when they have a refcount (which should never be < 0) */
+ return (mali_bool)(js_kctx_info->ctx.ctx_attr_ref_count[ attribute ]);
+}
+
+/** @} */ /* end group kbase_js */
+/** @} */ /* end group base_kbase_api */
+/** @} */ /* end group base_api */
+
+#endif /* _KBASE_JS_DEFS_H_ */
diff --git a/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_js_defs.h b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_js_defs.h
new file mode 100644
index 0000000..f397034
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_js_defs.h
@@ -0,0 +1,471 @@
+/*
+ *
+ * (C) COPYRIGHT 2011-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_kbase_js.h
+ * Job Scheduler Type Definitions
+ */
+
+
+#ifndef _KBASE_JS_DEFS_H_
+#define _KBASE_JS_DEFS_H_
+
+/**
+ * @addtogroup base_api
+ * @{
+ */
+
+/**
+ * @addtogroup base_kbase_api
+ * @{
+ */
+
+/**
+ * @addtogroup kbase_js
+ * @{
+ */
+
+/* Types used by the policies must go here */
+enum
+{
+ /** Context will not submit any jobs */
+ KBASE_CTX_FLAG_SUBMIT_DISABLED = (1u << 0),
+
+ /** Set if the context uses an address space and should be kept scheduled in */
+ KBASE_CTX_FLAG_PRIVILEGED = (1u << 1),
+
+ /** Kernel-side equivalent of BASE_CONTEXT_HINT_ONLY_COMPUTE. Non-mutable after creation flags set */
+ KBASE_CTX_FLAG_HINT_ONLY_COMPUTE= (1u << 2)
+
+ /* NOTE: Add flags for other things, such as 'is scheduled', and 'is dying' */
+};
+
+typedef u32 kbase_context_flags;
+
+typedef struct kbasep_atom_req
+{
+ base_jd_core_req core_req;
+ kbase_context_flags ctx_req;
+ u32 device_nr;
+} kbasep_atom_req;
+
+#include "mali_kbase_js_policy_cfs.h"
+
+
+/* Wrapper Interface - doxygen is elsewhere */
+typedef union kbasep_js_policy
+{
+#ifdef KBASE_JS_POLICY_AVAILABLE_FCFS
+ kbasep_js_policy_fcfs fcfs;
+#endif
+#ifdef KBASE_JS_POLICY_AVAILABLE_CFS
+ kbasep_js_policy_cfs cfs;
+#endif
+} kbasep_js_policy;
+
+/* Wrapper Interface - doxygen is elsewhere */
+typedef union kbasep_js_policy_ctx_info
+{
+#ifdef KBASE_JS_POLICY_AVAILABLE_FCFS
+ kbasep_js_policy_fcfs_ctx fcfs;
+#endif
+#ifdef KBASE_JS_POLICY_AVAILABLE_CFS
+ kbasep_js_policy_cfs_ctx cfs;
+#endif
+} kbasep_js_policy_ctx_info;
+
+/* Wrapper Interface - doxygen is elsewhere */
+typedef union kbasep_js_policy_job_info
+{
+#ifdef KBASE_JS_POLICY_AVAILABLE_FCFS
+ kbasep_js_policy_fcfs_job fcfs;
+#endif
+#ifdef KBASE_JS_POLICY_AVAILABLE_CFS
+ kbasep_js_policy_cfs_job cfs;
+#endif
+} kbasep_js_policy_job_info;
+
+/**
+ * @brief Maximum number of jobs that can be submitted to a job slot whilst
+ * inside the IRQ handler.
+ *
+ * This is important because GPU NULL jobs can complete whilst the IRQ handler
+ * is running. Otherwise, it potentially allows an unlimited number of GPU NULL
+ * jobs to be submitted inside the IRQ handler, which increases IRQ latency.
+ */
+#define KBASE_JS_MAX_JOB_SUBMIT_PER_SLOT_PER_IRQ 2
+
+/**
+ * @brief the IRQ_THROTTLE time in microseconds
+ *
+ * This will be converted via the GPU's clock frequency into a cycle-count.
+ *
+ * @note we can make an estimate of the GPU's frequency by periodically
+ * sampling its CYCLE_COUNT register
+ */
+#define KBASE_JS_IRQ_THROTTLE_TIME_US 20
+
+/**
+ * @brief Context attributes
+ *
+ * Each context attribute can be thought of as a boolean value that caches some
+ * state information about either the runpool, or the context:
+ * - In the case of the runpool, it is a cache of "Do any contexts owned by
+ * the runpool have attribute X?"
+ * - In the case of a context, it is a cache of "Do any atoms owned by the
+ * context have attribute X?"
+ *
+ * The boolean value of the context attributes often affect scheduling
+ * decisions, such as affinities to use and job slots to use.
+ *
+ * To accomodate changes of state in the context, each attribute is refcounted
+ * in the context, and in the runpool for all running contexts. Specifically:
+ * - The runpool holds a refcount of how many contexts in the runpool have this
+ * attribute.
+ * - The context holds a refcount of how many atoms have this attribute.
+ *
+ * Examples of use:
+ * - Finding out when NSS jobs are in the runpool
+ * - Finding out when there are a mix of @ref BASE_CONTEXT_HINT_ONLY_COMPUTE
+ * and ! @ref BASE_CONTEXT_HINT_ONLY_COMPUTE contexts in the runpool
+ */
+typedef enum
+{
+ /** Attribute indicating an NSS context */
+ KBASEP_JS_CTX_ATTR_NSS,
+
+ /** Attribute indicating a context that contains Compute jobs. That is,
+ * @ref BASE_CONTEXT_HINT_ONLY_COMPUTE is \b set and/or the context has jobs of type
+ * @ref BASE_JD_REQ_ONLY_COMPUTE
+ *
+ * @note A context can be both 'Compute' and 'Non Compute' if it contains
+ * both types of jobs.
+ */
+ KBASEP_JS_CTX_ATTR_COMPUTE,
+
+ /** Attribute indicating a context that contains Non-Compute jobs. That is,
+ * the context has some jobs that are \b not of type @ref
+ * BASE_JD_REQ_ONLY_COMPUTE. The context usually has
+ * BASE_CONTEXT_HINT_COMPUTE \b clear, but this depends on the HW
+ * workarounds in use in the Job Scheduling Policy.
+ *
+ * @note A context can be both 'Compute' and 'Non Compute' if it contains
+ * both types of jobs.
+ */
+ KBASEP_JS_CTX_ATTR_NON_COMPUTE,
+
+ /** Attribute indicating that a context contains compute-job atoms that
+ * aren't restricted to a coherent group, and can run on all cores.
+ *
+ * Specifically, this is when the atom's \a core_req satisfy:
+ * - (\a core_req & (BASE_JD_REQ_CS | BASE_JD_REQ_ONLY_COMPUTE | BASE_JD_REQ_T) // uses slot 1 or slot 2
+ * - && !(\a core_req & BASE_JD_REQ_COHERENT_GROUP) // not restricted to coherent groups
+ *
+ * Such atoms could be blocked from running if one of the coherent groups
+ * is being used by another job slot, so tracking this context attribute
+ * allows us to prevent such situations.
+ *
+ * @note This doesn't take into account the 1-coregroup case, where all
+ * compute atoms would effectively be able to run on 'all cores', but
+ * contexts will still not always get marked with this attribute. Instead,
+ * it is the caller's responsibility to take into account the number of
+ * coregroups when interpreting this attribute.
+ *
+ * @note Whilst Tiler atoms are normally combined with
+ * BASE_JD_REQ_COHERENT_GROUP, it is possible to send such atoms without
+ * BASE_JD_REQ_COHERENT_GROUP set. This is an unlikely case, but it's easy
+ * enough to handle anyway.
+ */
+ KBASEP_JS_CTX_ATTR_COMPUTE_ALL_CORES,
+
+ /** Must be the last in the enum */
+ KBASEP_JS_CTX_ATTR_COUNT
+} kbasep_js_ctx_attr;
+
+
+/**
+ * Data used by the scheduler that is unique for each Address Space.
+ *
+ * This is used in IRQ context and kbasep_js_device_data::runpoool_irq::lock
+ * must be held whilst accessing this data (inculding reads and atomic
+ * decisions based on the read).
+ */
+typedef struct kbasep_js_per_as_data
+{
+ /**
+ * Ref count of whether this AS is busy, and must not be scheduled out
+ *
+ * When jobs are running this is always positive. However, it can still be
+ * positive when no jobs are running. If all you need is a heuristic to
+ * tell you whether jobs might be running, this should be sufficient.
+ */
+ int as_busy_refcount;
+
+ /** Pointer to the current context on this address space, or NULL for no context */
+ kbase_context *kctx;
+} kbasep_js_per_as_data;
+
+/**
+ * @brief KBase Device Data Job Scheduler sub-structure
+ *
+ * This encapsulates the current context of the Job Scheduler on a particular
+ * device. This context is global to the device, and is not tied to any
+ * particular kbase_context running on the device.
+ *
+ * nr_contexts_running, nr_nss_ctxs_running and as_free are
+ * optimized for packing together (by making them smaller types than u32). The
+ * operations on them should rarely involve masking. The use of signed types for
+ * arithmetic indicates to the compiler that the value will not rollover (which
+ * would be undefined behavior), and so under the Total License model, it is free
+ * to make optimizations based on that (i.e. to remove masking).
+ */
+typedef struct kbasep_js_device_data
+{
+ /** Sub-structure to collect together Job Scheduling data used in IRQ context */
+ struct runpool_irq
+ {
+ /**
+ * Lock for accessing Job Scheduling data used in IRQ context
+ *
+ * This lock must be held whenever this data is accessed (read, or
+ * write). Even for read-only access, memory barriers would be needed.
+ * In any case, it is likely that decisions based on only reading must
+ * also be atomic with respect to data held here and elsewhere in the
+ * Job Scheduler.
+ *
+ * This lock must also be held for accessing:
+ * - kbase_context::as_nr
+ * - kbase_device::jm_slots
+ * - Parts of the kbasep_js_policy, dependent on the policy (refer to
+ * the policy in question for more information)
+ * - Parts of kbasep_js_policy_ctx_info, dependent on the policy (refer to
+ * the policy in question for more information)
+ */
+ spinlock_t lock;
+
+ /** Bitvector indicating whether a currently scheduled context is allowed to submit jobs.
+ * When bit 'N' is set in this, it indicates whether the context bound to address space
+ * 'N' (per_as_data[N].kctx) is allowed to submit jobs.
+ *
+ * It is placed here because it's much more memory efficient than having a mali_bool8 in
+ * kbasep_js_per_as_data to store this flag */
+ u16 submit_allowed;
+
+ /** Context Attributes:
+ * Each is large enough to hold a refcount of the number of contexts
+ * that can fit into the runpool. This is currently BASE_MAX_NR_AS
+ *
+ * Note that when BASE_MAX_NR_AS==16 we need 5 bits (not 4) to store
+ * the refcount. Hence, it's not worthwhile reducing this to
+ * bit-manipulation on u32s to save space (where in contrast, 4 bit
+ * sub-fields would be easy to do and would save space).
+ *
+ * Whilst this must not become negative, the sign bit is used for:
+ * - error detection in debug builds
+ * - Optimization: it is undefined for a signed int to overflow, and so
+ * the compiler can optimize for that never happening (thus, no masking
+ * is required on updating the variable) */
+ s8 ctx_attr_ref_count[KBASEP_JS_CTX_ATTR_COUNT];
+
+ /** Data that is unique for each AS */
+ kbasep_js_per_as_data per_as_data[BASE_MAX_NR_AS];
+
+ /*
+ * Affinity management and tracking
+ */
+ /** Bitvector to aid affinity checking. Element 'n' bit 'i' indicates
+ * that slot 'n' is using core i (i.e. slot_affinity_refcount[n][i] > 0) */
+ u64 slot_affinities[BASE_JM_MAX_NR_SLOTS];
+ /** Bitvector indicating which slots \em might have atoms blocked on
+ * them because otherwise they'd violate affinity restrictions */
+ u16 slots_blocked_on_affinity;
+ /** Refcount for each core owned by each slot. Used to generate the
+ * slot_affinities array of bitvectors
+ *
+ * The value of the refcount will not exceed BASE_JM_SUBMIT_SLOTS,
+ * because it is refcounted only when a job is definitely about to be
+ * submitted to a slot, and is de-refcounted immediately after a job
+ * finishes */
+ s8 slot_affinity_refcount[BASE_JM_MAX_NR_SLOTS][64];
+
+ } runpool_irq;
+
+ /**
+ * Run Pool mutex, for managing contexts within the runpool.
+ * You must hold this lock whilst accessing any members that follow
+ *
+ * In addition, this is used to access:
+ * - the kbasep_js_kctx_info::runpool substructure
+ */
+ struct mutex runpool_mutex;
+
+ /**
+ * Queue Lock, used to access the Policy's queue of contexts independently
+ * of the Run Pool.
+ *
+ * Of course, you don't need the Run Pool lock to access this.
+ */
+ struct mutex queue_mutex;
+
+ u16 as_free; /**< Bitpattern of free Address Spaces */
+
+ /** Number of currently scheduled user contexts (excluding ones that are not submitting jobs) */
+ s8 nr_user_contexts_running;
+ /** Number of currently scheduled contexts (including ones that are not submitting jobs) */
+ s8 nr_all_contexts_running;
+
+ /**
+ * Policy-specific information.
+ *
+ * Refer to the structure defined by the current policy to determine which
+ * locks must be held when accessing this.
+ */
+ kbasep_js_policy policy;
+
+ /** Core Requirements to match up with base_js_atom's core_req memeber
+ * @note This is a write-once member, and so no locking is required to read */
+ base_jd_core_req js_reqs[BASE_JM_MAX_NR_SLOTS];
+
+ u32 scheduling_tick_ns; /**< Value for KBASE_CONFIG_ATTR_JS_SCHEDULING_TICK_NS */
+ u32 soft_stop_ticks; /**< Value for KBASE_CONFIG_ATTR_JS_SOFT_STOP_TICKS */
+ u32 hard_stop_ticks_ss; /**< Value for KBASE_CONFIG_ATTR_JS_HARD_STOP_TICKS_SS */
+ u32 hard_stop_ticks_nss; /**< Value for KBASE_CONFIG_ATTR_JS_HARD_STOP_TICKS_NSS */
+ u32 gpu_reset_ticks_ss; /**< Value for KBASE_CONFIG_ATTR_JS_RESET_TICKS_SS */
+ u32 gpu_reset_ticks_nss; /**< Value for KBASE_CONFIG_ATTR_JS_RESET_TICKS_NSS */
+ u32 ctx_timeslice_ns; /**< Value for KBASE_CONFIG_ATTR_JS_CTX_TIMESLICE_NS */
+ u32 cfs_ctx_runtime_init_slices; /**< Value for KBASE_CONFIG_ATTR_JS_CFS_CTX_RUNTIME_INIT_SLICES */
+ u32 cfs_ctx_runtime_min_slices; /**< Value for KBASE_CONFIG_ATTR_JS_CFS_CTX_RUNTIME_MIN_SLICES */
+#ifdef CONFIG_MALI_DEBUG
+ /* Support soft-stop on a single context */
+ mali_bool softstop_always;
+#endif /* CONFIG_MALI_DEBUG */
+ /** The initalized-flag is placed at the end, to avoid cache-pollution (we should
+ * only be using this during init/term paths).
+ * @note This is a write-once member, and so no locking is required to read */
+ int init_status;
+} kbasep_js_device_data;
+
+
+/**
+ * @brief KBase Context Job Scheduling information structure
+ *
+ * This is a substructure in the kbase_context that encapsulates all the
+ * scheduling information.
+ */
+typedef struct kbasep_js_kctx_info
+{
+ /**
+ * Runpool substructure. This must only be accessed whilst the Run Pool
+ * mutex ( kbasep_js_device_data::runpool_mutex ) is held.
+ *
+ * In addition, the kbasep_js_device_data::runpool_irq::lock may need to be
+ * held for certain sub-members.
+ *
+ * @note some of the members could be moved into kbasep_js_device_data for
+ * improved d-cache/tlb efficiency.
+ */
+ struct
+ {
+ kbasep_js_policy_ctx_info policy_ctx; /**< Policy-specific context */
+ } runpool;
+
+ /**
+ * Job Scheduler Context information sub-structure. These members are
+ * accessed regardless of whether the context is:
+ * - In the Policy's Run Pool
+ * - In the Policy's Queue
+ * - Not queued nor in the Run Pool.
+ *
+ * You must obtain the jsctx_mutex before accessing any other members of
+ * this substructure.
+ *
+ * You may not access any of these members from IRQ context.
+ */
+ struct
+ {
+ struct mutex jsctx_mutex; /**< Job Scheduler Context lock */
+
+ /** Number of jobs <b>ready to run</b> - does \em not include the jobs waiting in
+ * the dispatcher, and dependency-only jobs. See kbase_jd_context::job_nr
+ * for such jobs*/
+ u32 nr_jobs;
+
+ /** Context Attributes:
+ * Each is large enough to hold a refcount of the number of atoms on
+ * the context. **/
+ u32 ctx_attr_ref_count[KBASEP_JS_CTX_ATTR_COUNT];
+
+ kbase_context_flags flags;
+ /* NOTE: Unify the following flags into kbase_context_flags */
+ /**
+ * Is the context scheduled on the Run Pool?
+ *
+ * This is only ever updated whilst the jsctx_mutex is held.
+ */
+ mali_bool is_scheduled;
+ /**
+ * Wait queue to wait for is_scheduled state changes.
+ * */
+ wait_queue_head_t is_scheduled_wait;
+
+ mali_bool is_dying; /**< Is the context in the process of being evicted? */
+ } ctx;
+
+ /* The initalized-flag is placed at the end, to avoid cache-pollution (we should
+ * only be using this during init/term paths) */
+ int init_status;
+} kbasep_js_kctx_info;
+
+/** Subset of atom state that can be available after jd_done_nolock() is called
+ * on that atom. A copy must be taken via kbasep_js_atom_retained_state_copy(),
+ * because the original atom could disappear. */
+typedef struct kbasep_js_atom_retained_state
+{
+ /** Event code - to determine whether the atom has finished */
+ base_jd_event_code event_code;
+ /** core requirements */
+ base_jd_core_req core_req;
+ /** Job Slot to retry submitting to if submission from IRQ handler failed */
+ int retry_submit_on_slot;
+
+} kbasep_js_atom_retained_state;
+
+/**
+ * Value signifying 'no retry on a slot required' for:
+ * - kbase_js_atom_retained_state::retry_submit_on_slot
+ * - kbase_jd_atom::retry_submit_on_slot
+ */
+#define KBASEP_JS_RETRY_SUBMIT_SLOT_INVALID (-1)
+
+/**
+ * base_jd_core_req value signifying 'invalid' for a kbase_jd_atom_retained_state.
+ *
+ * @see kbase_atom_retained_state_is_valid()
+ */
+#define KBASEP_JS_ATOM_RETAINED_STATE_CORE_REQ_INVALID BASE_JD_REQ_DEP
+
+/**
+ * @brief The JS timer resolution, in microseconds
+ *
+ * Any non-zero difference in time will be at least this size.
+ */
+#define KBASEP_JS_TICK_RESOLUTION_US 1
+
+
+#endif /* _KBASE_JS_DEFS_H_ */
+
+
+/** @} */ /* end group kbase_js */
+/** @} */ /* end group base_kbase_api */
+/** @} */ /* end group base_api */
diff --git a/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_js_policy.h b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_js_policy.h
new file mode 100644
index 0000000..5bf540b
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_js_policy.h
@@ -0,0 +1,818 @@
+/*
+ *
+ * (C) COPYRIGHT 2011-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_kbase_js_policy.h
+ * Job Scheduler Policy APIs.
+ */
+
+#ifndef _KBASE_JS_POLICY_H_
+#define _KBASE_JS_POLICY_H_
+
+/**
+ * @page page_kbase_js_policy Job Scheduling Policies
+ * The Job Scheduling system is described in the following:
+ * - @subpage page_kbase_js_policy_overview
+ * - @subpage page_kbase_js_policy_operation
+ *
+ * The API details are as follows:
+ * - @ref kbase_jm
+ * - @ref kbase_js
+ * - @ref kbase_js_policy
+ */
+
+/**
+ * @page page_kbase_js_policy_overview Overview of the Policy System
+ *
+ * The Job Scheduler Policy manages:
+ * - The assigning of KBase Contexts to GPU Address Spaces (\em ASs)
+ * - The choosing of Job Chains (\em Jobs) from a KBase context, to run on the
+ * GPU's Job Slots (\em JSs).
+ * - The amount of \em time a context is assigned to (<em>scheduled on</em>) an
+ * Address Space
+ * - The amount of \em time a Job spends running on the GPU
+ *
+ * The Policy implements this management via 2 components:
+ * - A Policy Queue, which manages a set of contexts that are ready to run,
+ * but not currently running.
+ * - A Policy Run Pool, which manages the currently running contexts (one per Address
+ * Space) and the jobs to run on the Job Slots.
+ *
+ * Each Graphics Process in the system has at least one KBase Context. Therefore,
+ * the Policy Queue can be seen as a queue of Processes waiting to run Jobs on
+ * the GPU.
+ *
+ * <!-- The following needs to be all on one line, due to doxygen's parser -->
+ * @dotfile policy_overview.dot "Diagram showing a very simplified overview of the Policy System. IRQ handling, soft/hard-stopping, contexts re-entering the system and Policy details are omitted"
+ *
+ * The main operations on the queue are:
+ * - Enqueuing a Context to it
+ * - Dequeuing a Context from it, to run it.
+ * - Note: requeuing a context is much the same as enqueuing a context, but
+ * occurs when a context is scheduled out of the system to allow other contexts
+ * to run.
+ *
+ * These operations have much the same meaning for the Run Pool - Jobs are
+ * dequeued to run on a Jobslot, and requeued when they are scheduled out of
+ * the GPU.
+ *
+ * @note This is an over-simplification of the Policy APIs - there are more
+ * operations than 'Enqueue'/'Dequeue', and a Dequeue from the Policy Queue
+ * takes at least two function calls: one to Dequeue from the Queue, one to add
+ * to the Run Pool.
+ *
+ * As indicated on the diagram, Jobs permanently leave the scheduling system
+ * when they are completed, otherwise they get dequeued/requeued until this
+ * happens. Similarly, Contexts leave the scheduling system when their jobs
+ * have all completed. However, Contexts may later return to the scheduling
+ * system (not shown on the diagram) if more Bags of Jobs are submitted to
+ * them.
+ */
+
+/**
+ * @page page_kbase_js_policy_operation Policy Operation
+ *
+ * We describe the actions that the Job Scheduler Core takes on the Policy in
+ * the following cases:
+ * - The IRQ Path
+ * - The Job Submission Path
+ * - The High Priority Job Submission Path
+ *
+ * This shows how the Policy APIs will be used by the Job Scheduler core.
+ *
+ * The following diagram shows an example Policy that contains a Low Priority
+ * queue, and a Real-time (High Priority) Queue. The RT queue is examined
+ * before the LowP one on dequeuing from the head. The Low Priority Queue is
+ * ordered by time, and the RT queue is ordered by RT-priority, and then by
+ * time. In addition, it shows that the Job Scheduler Core will start a
+ * Soft-Stop Timer (SS-Timer) when it dequeue's and submits a job. The
+ * Soft-Stop time is set by a global configuration value, and must be a value
+ * appropriate for the policy. For example, this could include "don't run a
+ * soft-stop timer" for a First-Come-First-Served (FCFS) policy.
+ *
+ * <!-- The following needs to be all on one line, due to doxygen's parser -->
+ * @dotfile policy_operation_diagram.dot "Diagram showing the objects managed by an Example Policy, and the operations made upon these objects by the Job Scheduler Core."
+ *
+ * @section sec_kbase_js_policy_operation_prio Dealing with Priority
+ *
+ * Priority applies both to a context as a whole, and to the jobs within a
+ * context. The jobs specify a priority in the base_jd_atom::prio member, which
+ * is relative to that of the context. A positive setting indicates a reduction
+ * in priority, whereas a negative setting indicates a boost in priority. Of
+ * course, the boost in priority should only be honoured when the originating
+ * process has sufficient priviledges, and should be ignored for unpriviledged
+ * processes. The meaning of the combined priority value is up to the policy
+ * itself, and could be a logarithmic scale instead of a linear scale (e.g. the
+ * policy could implement an increase/decrease in priority by 1 results in an
+ * increase/decrease in \em proportion of time spent scheduled in by 25%, an
+ * effective change in timeslice by 11%).
+ *
+ * It is up to the policy whether a boost in priority boosts the priority of
+ * the entire context (e.g. to such an extent where it may pre-empt other
+ * running contexts). If it chooses to do this, the Policy must make sure that
+ * only the high-priority jobs are run, and that the context is scheduled out
+ * once only low priority jobs remain. This ensures that the low priority jobs
+ * within the context do not gain from the priority boost, yet they still get
+ * scheduled correctly with respect to other low priority contexts.
+ *
+ *
+ * @section sec_kbase_js_policy_operation_irq IRQ Path
+ *
+ * The following happens on the IRQ path from the Job Scheduler Core:
+ * - Note the slot that completed (for later)
+ * - Log the time spent by the job (and implicitly, the time spent by the
+ * context)
+ * - call kbasep_js_policy_log_job_result() <em>in the context of the irq
+ * handler.</em>
+ * - This must happen regardless of whether the job completed successfully or
+ * not (otherwise the context gets away with DoS'ing the system with faulty jobs)
+ * - What was the result of the job?
+ * - If Completed: job is just removed from the system
+ * - If Hard-stop or failure: job is removed from the system
+ * - If Soft-stop: queue the book-keeping work onto a work-queue: have a
+ * work-queue call kbasep_js_policy_enqueue_job()
+ * - Check the timeslice used by the owning context
+ * - call kbasep_js_policy_should_remove_ctx() <em>in the context of the irq
+ * handler.</em>
+ * - If this returns true, clear the "allowed" flag.
+ * - Check the ctx's flags for "allowed", "has jobs to run" and "is running
+ * jobs"
+ * - And so, should the context stay scheduled in?
+ * - If No, push onto a work-queue the work of scheduling out the old context,
+ * and getting a new one. That is:
+ * - kbasep_js_policy_runpool_remove_ctx() on old_ctx
+ * - kbasep_js_policy_enqueue_ctx() on old_ctx
+ * - kbasep_js_policy_dequeue_head_ctx() to get new_ctx
+ * - kbasep_js_policy_runpool_add_ctx() on new_ctx
+ * - (all of this work is deferred on a work-queue to keep the IRQ handler quick)
+ * - If there is space in the completed job slots' HEAD/NEXT registers, run the next job:
+ * - kbasep_js_policy_dequeue_job_irq() <em>in the context of the irq
+ * handler</em> with core_req set to that of the completing slot
+ * - if this returned MALI_TRUE, submit the job to the completed slot.
+ * - This is repeated until kbasep_js_policy_dequeue_job_irq() returns
+ * MALI_FALSE, or the job slot has a job queued on both the HEAD and NEXT registers.
+ * - If kbasep_js_policy_dequeue_job_irq() returned false, submit some work to
+ * the work-queue to retry from outside of IRQ context (calling
+ * kbasep_js_policy_dequeue_job() from a work-queue).
+ *
+ * Since the IRQ handler submits new jobs \em and re-checks the IRQ_RAWSTAT,
+ * this sequence could loop a large number of times: this could happen if
+ * the jobs submitted completed on the GPU very quickly (in a few cycles), such
+ * as GPU NULL jobs. Then, the HEAD/NEXT registers will always be free to take
+ * more jobs, causing us to loop until we run out of jobs.
+ *
+ * To mitigate this, we must limit the number of jobs submitted per slot during
+ * the IRQ handler - for example, no more than 2 jobs per slot per IRQ should
+ * be sufficient (to fill up the HEAD + NEXT registers in normal cases). For
+ * Mali-T600 with 3 job slots, this means that up to 6 jobs could be submitted per
+ * slot. Note that IRQ Throttling can make this situation commonplace: 6 jobs
+ * could complete but the IRQ for each of them is delayed by the throttling. By
+ * the time you get the IRQ, all 6 jobs could've completed, meaning you can
+ * submit jobs to fill all 6 HEAD+NEXT registers again.
+ *
+ * @note As much work is deferred as possible, which includes the scheduling
+ * out of a context and scheduling in a new context. However, we can still make
+ * starting a single high-priorty context quick despite this:
+ * - On Mali-T600 family, there is one more AS than JSs.
+ * - This means we can very quickly schedule out one AS, no matter what the
+ * situation (because there will always be one AS that's not currently running
+ * on the job slot - it can only have a job in the NEXT register).
+ * - Even with this scheduling out, fair-share can still be guaranteed e.g. by
+ * a timeline-based Completely Fair Scheduler.
+ * - When our high-priority context comes in, we can do this quick-scheduling
+ * out immediately, and then schedule in the high-priority context without having to block.
+ * - This all assumes that the context to schedule out is of lower
+ * priority. Otherwise, we will have to block waiting for some other low
+ * priority context to finish its jobs. Note that it's likely (but not
+ * impossible) that the high-priority context \b is running jobs, by virtue of
+ * it being high priority.
+ * - Therefore, we can give a high liklihood that on Mali-T600 at least one
+ * high-priority context can be started very quickly. For the general case, we
+ * can guarantee starting (no. ASs) - (no. JSs) high priority contexts
+ * quickly. In any case, there is a high likelihood that we're able to start
+ * more than one high priority context quickly.
+ *
+ * In terms of the functions used in the IRQ handler directly, these are the
+ * perfomance considerations:
+ * - kbase_js_policy_log_job_result():
+ * - This is just adding to a 64-bit value (possibly even a 32-bit value if we
+ * only store the time the job's recently spent - see below on 'priority weighting')
+ * - For priority weighting, a divide operation ('div') could happen, but
+ * this can happen in a deferred context (outside of IRQ) when scheduling out
+ * the ctx; as per our Engineering Specification, the contexts of different
+ * priority still stay scheduled in for the same timeslice, but higher priority
+ * ones scheduled back in more often.
+ * - That is, the weighted and unweighted times must be stored separately, and
+ * the weighted time is only updated \em outside of IRQ context.
+ * - Of course, this divide is more likely to be a 'multiply by inverse of the
+ * weight', assuming that the weight (priority) doesn't change.
+ * - kbasep_js_policy_should_remove_ctx():
+ * - This is usually just a comparison of the stored time value against some
+ * maximum value.
+ * - kbasep_js_policy_dequeue_job_irq():
+ * - For very fast operation, it can keep a very small buffer of 1 element per
+ * job-slot that allows the job at the head of the runpool for each job-slot
+ * to be retreived very quickly (O(1) time). This is complicated by high
+ * priority jobs that may 'jump' the queue, but could be eased by having a
+ * second buffer for high priority jobs. This assumes the requirement is only to
+ * run any high priority job quickly, not to run the highest high priority job
+ * quickly.
+ * - Of course, if a job slot completes two jobs in quick succession, then
+ * kbasep_js_policy_dequeue_job_irq() can return MALI_FALSE on the second call
+ * (because the small quick-access buffer is already exhausted)
+ * - The quick-access buffer must be refilled by the other Policy Job
+ * Management APIs that are called ourside of IRQ context.
+ * - This scheme guarantees that we keep every jobslot busy with at least one
+ * job - good utilization.
+ * - As a side effect, processes that try to submit too many quick-running
+ * jobs (to increase IRQ rate to cause a DoS attack ) will be limited to the
+ * rate at which the kernel work-queue can be serivced. This can be seen as a
+ * benefit.
+ *
+ * @note all deferred work can be wrapped up into one call - we usually need to
+ * indicate that a job/bag is done outside of IRQ context anyway.
+ *
+ *
+ *
+ * @section sec_kbase_js_policy_operation_submit Submission path
+ *
+ * Start with a Context with no jobs present, and assume equal priority of all
+ * contexts in the system. The following work all happens outside of IRQ
+ * Context :
+ * - As soon as job is made 'ready to 'run', then is must be registerd with the Job
+ * Scheduler Policy:
+ * - 'Ready to run' means they've satisified their dependencies in the
+ * Kernel-side Job Dispatch system.
+ * - Call kbasep_js_policy_enqueue_job()
+ * - This indicates that the job should be scheduled (it is ready to run).
+ * - As soon as a ctx changes from having 0 jobs 'ready to run' to >0 jobs
+ * 'ready to run', we enqueue the context on the policy queue:
+ * - Call kbasep_js_policy_enqueue_ctx()
+ * - This indicates that the \em ctx should be scheduled (it is ready to run)
+ *
+ * Next, we need to handle adding a context to the Run Pool - if it's sensible
+ * to do so. This can happen due to two reasons:
+ * -# A context is enqueued as above, and there are ASs free for it to run on
+ * (e.g. it is the first context to be run, in which case it can be added to
+ * the Run Pool immediately after enqueuing on the Policy Queue)
+ * -# A previous IRQ caused another ctx to be scheduled out, requiring that the
+ * context at the head of the queue be scheduled in. Such steps would happen in
+ * a work queue (work deferred from the IRQ context).
+ *
+ * In both cases, we'd handle it as follows:
+ * - Get the context at the Head of the Policy Queue:
+ * - Call kbasep_js_policy_dequeue_head_ctx()
+ * - Assign the Context an Address Space (Assert that there will be one free,
+ * given the above two reasons)
+ * - Add this context to the Run Pool:
+ * - Call kbasep_js_policy_runpool_add_ctx()
+ * - Now see if a job should be run:
+ * - Mostly, this will be done in the IRQ handler at the completion of a
+ * previous job.
+ * - However, there are two cases where this cannot be done: a) The first job
+ * enqueued to the system (there is no previous IRQ to act upon) b) When jobs
+ * are submitted at a low enough rate to not fill up all Job Slots (or, not to
+ * fill both the 'HEAD' and 'NEXT' registers in the job-slots)
+ * - Hence, on each ctx <b>and job</b> submission we should try to see if we
+ * can run a job:
+ * - For each job slot that has free space (in NEXT or HEAD+NEXT registers):
+ * - Call kbasep_js_policy_dequeue_job() with core_req set to that of the
+ * slot
+ * - if we got one, submit it to the job slot.
+ * - This is repeated until kbasep_js_policy_dequeue_job() returns
+ * MALI_FALSE, or the job slot has a job queued on both the HEAD and NEXT registers.
+ *
+ * The above case shows that we should attempt to run jobs in cases where a) a ctx
+ * has been added to the Run Pool, and b) new jobs have been added to a context
+ * in the Run Pool:
+ * - In the latter case, the context is in the runpool because it's got a job
+ * ready to run, or is already running a job
+ * - We could just wait until the IRQ handler fires, but for certain types of
+ * jobs this can take comparatively a long time to complete, e.g. GLES FS jobs
+ * generally take much longer to run that GLES CS jobs, which are vertex shader
+ * jobs. Even worse are NSS jobs, which may run for seconds/minutes.
+ * - Therefore, when a new job appears in the ctx, we must check the job-slots
+ * to see if they're free, and run the jobs as before.
+ *
+ *
+ *
+ * @section sec_kbase_js_policy_operation_submit_hipri Submission path for High Priority Contexts
+ *
+ * For High Priority Contexts on Mali-T600, we can make sure that at least 1 of
+ * them can be scheduled in immediately to start high prioriy jobs. In general,
+ * (no. ASs) - (no JSs) high priority contexts may be started immediately. The
+ * following describes how this happens:
+ *
+ * Similar to the previous section, consider what happens with a high-priority
+ * context (a context with a priority higher than that of any in the Run Pool)
+ * that starts out with no jobs:
+ * - A job becomes ready to run on the context, and so we enqueue the context
+ * on the Policy's Queue.
+ * - However, we'd like to schedule in this context immediately, instead of
+ * waiting for one of the Run Pool contexts' timeslice to expire
+ * - The policy's Enqueue function must detect this (because it is the policy
+ * that embodies the concept of priority), and take appropriate action
+ * - That is, kbasep_js_policy_enqueue_ctx() should check the Policy's Run
+ * Pool to see if a lower priority context should be scheduled out, and then
+ * schedule in the High Priority context.
+ * - For Mali-T600, we can always pick a context to schedule out immediately
+ * (because there are more ASs than JSs), and so scheduling out a victim context
+ * and scheduling in the high priority context can happen immediately.
+ * - If a policy implements fair-sharing, then this can still ensure the
+ * victim later on gets a fair share of the GPU.
+ * - As a note, consider whether the victim can be of equal/higher priority
+ * than the incoming context:
+ * - Usually, higher priority contexts will be the ones currently running
+ * jobs, and so the context with the lowest priority is usually not running
+ * jobs.
+ * - This makes it likely that the victim context is low priority, but
+ * it's not impossible for it to be a high priority one:
+ * - Suppose 3 high priority contexts are submitting only FS jobs, and one low
+ * priority context submitting CS jobs. Then, the context not running jobs will
+ * be one of the hi priority contexts (because only 2 FS jobs can be
+ * queued/running on the GPU HW for Mali-T600).
+ * - The problem can be mitigated by extra action, but it's questionable
+ * whether we need to: we already have a high likelihood that there's at least
+ * one high priority context - that should be good enough.
+ * - And so, this method makes sure that at least one high priority context
+ * can be started very quickly, but more than one high priority contexts could be
+ * delayed (up to one timeslice).
+ * - To improve this, use a GPU with a higher number of Address Spaces vs Job
+ * Slots.
+ * - At this point, let's assume this high priority context has been scheduled
+ * in immediately. The next step is to ensure it can start some jobs quickly.
+ * - It must do this by Soft-Stopping jobs on any of the Job Slots that it can
+ * submit to.
+ * - The rest of the logic for starting the jobs is taken care of by the IRQ
+ * handler. All the policy needs to do is ensure that
+ * kbasep_js_policy_dequeue_job() will return the jobs from the high priority
+ * context.
+ *
+ * @note in SS state, we currently only use 2 job-slots (even for T608, but
+ * this might change in future). In this case, it's always possible to schedule
+ * out 2 ASs quickly (their jobs won't be in the HEAD registers). At the same
+ * time, this maximizes usage of the job-slots (only 2 are in use), because you
+ * can guarantee starting of the jobs from the High Priority contexts immediately too.
+ *
+ *
+ *
+ * @section sec_kbase_js_policy_operation_notes Notes
+ *
+ * - In this design, a separate 'init' is needed from dequeue/requeue, so that
+ * information can be retained between the dequeue/requeue calls. For example,
+ * the total time spent for a context/job could be logged between
+ * dequeue/requeuing, to implement Fair Sharing. In this case, 'init' just
+ * initializes that information to some known state.
+ *
+ *
+ *
+ */
+
+/**
+ * @addtogroup base_api
+ * @{
+ */
+
+/**
+ * @addtogroup base_kbase_api
+ * @{
+ */
+
+/**
+ * @addtogroup kbase_js_policy Job Scheduler Policy APIs
+ * @{
+ *
+ * <b>Refer to @ref page_kbase_js_policy for an overview and detailed operation of
+ * the Job Scheduler Policy and its use from the Job Scheduler Core.</b>
+ */
+
+/**
+ * @brief Job Scheduler Policy structure
+ */
+union kbasep_js_policy;
+
+/**
+ * @brief Initialize the Job Scheduler Policy
+ */
+mali_error kbasep_js_policy_init( kbase_device *kbdev );
+
+/**
+ * @brief Terminate the Job Scheduler Policy
+ */
+void kbasep_js_policy_term( kbasep_js_policy *js_policy );
+
+
+
+/**
+ * @addtogroup kbase_js_policy_ctx Job Scheduler Policy, Context Management API
+ * @{
+ *
+ * <b>Refer to @ref page_kbase_js_policy for an overview and detailed operation of
+ * the Job Scheduler Policy and its use from the Job Scheduler Core.</b>
+ */
+
+
+/**
+ * @brief Job Scheduler Policy Ctx Info structure
+ *
+ * This structure is embedded in the kbase_context structure. It is used to:
+ * - track information needed for the policy to schedule the context (e.g. time
+ * used, OS priority etc.)
+ * - link together kbase_contexts into a queue, so that a kbase_context can be
+ * obtained as the container of the policy ctx info. This allows the API to
+ * return what "the next context" should be.
+ * - obtain other information already stored in the kbase_context for
+ * scheduling purposes (e.g process ID to get the priority of the originating
+ * process)
+ */
+union kbasep_js_policy_ctx_info;
+
+/**
+ * @brief Initialize a ctx for use with the Job Scheduler Policy
+ *
+ * This effectively initializes the kbasep_js_policy_ctx_info structure within
+ * the kbase_context (itself located within the kctx->jctx.sched_info structure).
+ */
+mali_error kbasep_js_policy_init_ctx( kbase_device *kbdev, kbase_context *kctx );
+
+/**
+ * @brief Terminate resources associated with using a ctx in the Job Scheduler
+ * Policy.
+ */
+void kbasep_js_policy_term_ctx( kbasep_js_policy *js_policy, kbase_context *kctx );
+
+/**
+ * @brief Enqueue a context onto the Job Scheduler Policy Queue
+ *
+ * If the context enqueued has a priority higher than any in the Run Pool, then
+ * it is the Policy's responsibility to decide whether to schedule out a low
+ * priority context from the Run Pool to allow the high priority context to be
+ * scheduled in.
+ *
+ * If the context has the privileged flag set, it will always be kept at the
+ * head of the queue.
+ *
+ * The caller will be holding kbasep_js_kctx_info::ctx::jsctx_mutex.
+ * The caller will be holding kbasep_js_device_data::queue_mutex.
+ */
+void kbasep_js_policy_enqueue_ctx( kbasep_js_policy *js_policy, kbase_context *kctx );
+
+/**
+ * @brief Dequeue a context from the Head of the Job Scheduler Policy Queue
+ *
+ * The caller will be holding kbasep_js_device_data::queue_mutex.
+ *
+ * @return MALI_TRUE if a context was available, and *kctx_ptr points to
+ * the kctx dequeued.
+ * @return MALI_FALSE if no contexts were available.
+ */
+mali_bool kbasep_js_policy_dequeue_head_ctx( kbasep_js_policy *js_policy, kbase_context **kctx_ptr );
+
+/**
+ * @brief Evict a context from the Job Scheduler Policy Queue
+ *
+ * This is only called as part of destroying a kbase_context.
+ *
+ * There are many reasons why this might fail during the lifetime of a
+ * context. For example, the context is in the process of being scheduled. In
+ * that case a thread doing the scheduling might have a pointer to it, but the
+ * context is neither in the Policy Queue, nor is it in the Run
+ * Pool. Crucially, neither the Policy Queue, Run Pool, or the Context itself
+ * are locked.
+ *
+ * Hence to find out where in the system the context is, it is important to do
+ * more than just check the kbasep_js_kctx_info::ctx::is_scheduled member.
+ *
+ * The caller will be holding kbasep_js_device_data::queue_mutex.
+ *
+ * @return MALI_TRUE if the context was evicted from the Policy Queue
+ * @return MALI_FALSE if the context was not found in the Policy Queue
+ */
+mali_bool kbasep_js_policy_try_evict_ctx( kbasep_js_policy *js_policy, kbase_context *kctx );
+
+/**
+ * @brief Remove all jobs belonging to a non-queued, non-running context.
+ *
+ * This must call kbase_jd_cancel() on each job belonging to the context, which
+ * causes all necessary job cleanup actions to occur on a workqueue.
+ *
+ * At the time of the call, the context is guarenteed to be not-currently
+ * scheduled on the Run Pool (is_scheduled == MALI_FALSE), and not present in
+ * the Policy Queue. This is because one of the following functions was used
+ * recently on the context:
+ * - kbasep_js_policy_evict_ctx()
+ * - kbasep_js_policy_runpool_remove_ctx()
+ *
+ * In both cases, no subsequent call was made on the context to any of:
+ * - kbasep_js_policy_runpool_add_ctx()
+ * - kbasep_js_policy_enqueue_ctx()
+ *
+ * This is only called as part of destroying a kbase_context.
+ *
+ * The locking conditions on the caller are as follows:
+ * - it will be holding kbasep_js_kctx_info::ctx::jsctx_mutex.
+ */
+void kbasep_js_policy_kill_all_ctx_jobs( kbasep_js_policy *js_policy, kbase_context *kctx );
+
+/**
+ * @brief Add a context to the Job Scheduler Policy's Run Pool
+ *
+ * If the context enqueued has a priority higher than any in the Run Pool, then
+ * it is the Policy's responsibility to decide whether to schedule out low
+ * priority jobs that are currently running on the GPU.
+ *
+ * The number of contexts present in the Run Pool will never be more than the
+ * number of Address Spaces.
+ *
+ * The following guarentees are made about the state of the system when this
+ * is called:
+ * - kctx->as_nr member is valid
+ * - the context has its submit_allowed flag set
+ * - kbasep_js_device_data::runpool_irq::per_as_data[kctx->as_nr] is valid
+ * - The refcount of the context is guarenteed to be zero.
+ * - kbasep_js_kctx_info::ctx::is_scheduled will be MALI_TRUE.
+ *
+ * The locking conditions on the caller are as follows:
+ * - it will be holding kbasep_js_kctx_info::ctx::jsctx_mutex.
+ * - it will be holding kbasep_js_device_data::runpool_mutex.
+ * - it will be holding kbasep_js_device_data::runpool_irq::lock (a spinlock)
+ *
+ * Due to a spinlock being held, this function must not call any APIs that sleep.
+ */
+void kbasep_js_policy_runpool_add_ctx( kbasep_js_policy *js_policy, kbase_context *kctx );
+
+/**
+ * @brief Remove a context from the Job Scheduler Policy's Run Pool
+ *
+ * The kctx->as_nr member is valid and the context has its submit_allowed flag
+ * set when this is called. The state of
+ * kbasep_js_device_data::runpool_irq::per_as_data[kctx->as_nr] is also
+ * valid. The refcount of the context is guarenteed to be zero.
+ *
+ * The locking conditions on the caller are as follows:
+ * - it will be holding kbasep_js_kctx_info::ctx::jsctx_mutex.
+ * - it will be holding kbasep_js_device_data::runpool_mutex.
+ * - it will be holding kbasep_js_device_data::runpool_irq::lock (a spinlock)
+ *
+ * Due to a spinlock being held, this function must not call any APIs that sleep.
+ */
+void kbasep_js_policy_runpool_remove_ctx( kbasep_js_policy *js_policy, kbase_context *kctx );
+
+/**
+ * @brief Indicate whether a context should be removed from the Run Pool
+ * (should be scheduled out).
+ *
+ * The kbasep_js_device_data::runpool_irq::lock will be held by the caller.
+ *
+ * @note This API is called from IRQ context.
+ */
+mali_bool kbasep_js_policy_should_remove_ctx( kbasep_js_policy *js_policy, kbase_context *kctx );
+
+/**
+ * @brief Indicate whether a new context has an higher priority than the current context.
+ *
+ *
+ * The caller has the following conditions on locking:
+ * - kbasep_js_kctx_info::ctx::jsctx_mutex will be held for \a new_ctx
+ *
+ * This function must not sleep, because an IRQ spinlock might be held whilst
+ * this is called.
+ *
+ * @note There is nothing to stop the priority of \a current_ctx changing
+ * during or immediately after this function is called (because its jsctx_mutex
+ * cannot be held). Therefore, this function should only be seen as a heuristic
+ * guide as to whether \a new_ctx is higher priority than \a current_ctx
+ */
+mali_bool kbasep_js_policy_ctx_has_priority( kbasep_js_policy *js_policy, kbase_context *current_ctx, kbase_context *new_ctx );
+
+
+/** @} */ /* end group kbase_js_policy_ctx */
+
+/**
+ * @addtogroup kbase_js_policy_job Job Scheduler Policy, Job Chain Management API
+ * @{
+ *
+ * <b>Refer to @ref page_kbase_js_policy for an overview and detailed operation of
+ * the Job Scheduler Policy and its use from the Job Scheduler Core.</b>
+ */
+
+
+
+/**
+ * @brief Job Scheduler Policy Job Info structure
+ *
+ * This structure is embedded in the kbase_jd_atom structure. It is used to:
+ * - track information needed for the policy to schedule the job (e.g. time
+ * used, OS priority etc.)
+ * - link together jobs into a queue/buffer, so that a kbase_jd_atom can be
+ * obtained as the container of the policy job info. This allows the API to
+ * return what "the next job" should be.
+ * - obtain other information already stored in the kbase_context for
+ * scheduling purposes (e.g user-side relative priority)
+ */
+union kbasep_js_policy_job_info;
+
+/**
+ * @brief Initialize a job for use with the Job Scheduler Policy
+ *
+ * This function initializes the kbasep_js_policy_job_info structure within the
+ * kbase_jd_atom. It will only initialize/allocate resources that are specific
+ * to the job.
+ *
+ * That is, this function makes \b no attempt to:
+ * - initialize any context/policy-wide information
+ * - enqueue the job on the policy.
+ *
+ * At some later point, the following functions must be called on the job, in this order:
+ * - kbasep_js_policy_register_job() to register the job and initialize policy/context wide data.
+ * - kbasep_js_policy_enqueue_job() to enqueue the job
+ *
+ * A job must only ever be initialized on the Policy once, and must be
+ * terminated on the Policy before the job is freed.
+ *
+ * The caller will not be holding any locks, and so this function will not
+ * modify any information in \a kctx or \a js_policy.
+ *
+ * @return MALI_ERROR_NONE if initialization was correct.
+ */
+mali_error kbasep_js_policy_init_job( const kbasep_js_policy *js_policy, const kbase_context *kctx, kbase_jd_atom *katom );
+
+/**
+ * @brief Register context/policy-wide information for a job on the Job Scheduler Policy.
+ *
+ * Registers the job with the policy. This is used to track the job before it
+ * has been enqueued/requeued by kbasep_js_policy_enqueue_job(). Specifically,
+ * it is used to update information under a lock that could not be updated at
+ * kbasep_js_policy_init_job() time (such as context/policy-wide data).
+ *
+ * @note This function will not fail, and hence does not allocate any
+ * resources. Any failures that could occur on registration will be caught
+ * during kbasep_js_policy_init_job() instead.
+ *
+ * A job must only ever be registerd on the Policy once, and must be
+ * deregistered on the Policy on completion (whether or not that completion was
+ * success/failure).
+ *
+ * The caller has the following conditions on locking:
+ * - kbasep_js_kctx_info::ctx::jsctx_mutex will be held.
+ */
+void kbasep_js_policy_register_job( kbasep_js_policy *js_policy, kbase_context *kctx, kbase_jd_atom *katom );
+
+/**
+ * @brief De-register context/policy-wide information for a on the Job Scheduler Policy.
+ *
+ * This must be used before terminating the resources associated with using a
+ * job in the Job Scheduler Policy. This function does not itself terminate any
+ * resources, at most it just updates information in the policy and context.
+ *
+ * The caller has the following conditions on locking:
+ * - kbasep_js_kctx_info::ctx::jsctx_mutex will be held.
+ */
+void kbasep_js_policy_deregister_job( kbasep_js_policy *js_policy, kbase_context *kctx, kbase_jd_atom *katom );
+
+
+/**
+ * @brief Dequeue a Job for a job slot from the Job Scheduler Policy Run Pool
+ *
+ * The job returned by the policy will match at least one of the bits in the
+ * job slot's core requirements (but it may match more than one, or all @ref
+ * base_jd_core_req bits supported by the job slot).
+ *
+ * In addition, the requirements of the job returned will be a subset of those
+ * requested - the job returned will not have requirements that \a job_slot_idx
+ * cannot satisfy.
+ *
+ * The caller will submit the job to the GPU as soon as the GPU's NEXT register
+ * for the corresponding slot is empty. Of course, the GPU will then only run
+ * this new job when the currently executing job (in the jobslot's HEAD
+ * register) has completed.
+ *
+ * @return MALI_TRUE if a job was available, and *kctx_ptr points to
+ * the kctx dequeued.
+ * @return MALI_FALSE if no jobs were available among all ctxs in the Run Pool.
+ *
+ * @note base_jd_core_req is currently a u8 - beware of type conversion.
+ *
+ * @note This API is not called from IRQ context outside of the policy
+ * itself, and so need not operate in O(1) time. Refer to
+ * kbasep_js_policy_dequeue_job_irq() for dequeuing from IRQ context.
+ *
+ * As a result of kbasep_js_policy_dequeue_job_irq(), this function might need to
+ * carry out work to maintain its internal queues both before and after a job
+ * is dequeued.
+ *
+ * The caller has the following conditions on locking:
+ * - kbasep_js_device_data::runpool_lock::irq will be held.
+ * - kbasep_js_device_data::runpool_mutex will be held.
+ * - kbasep_js_kctx_info::ctx::jsctx_mutex. will be held
+ */
+mali_bool kbasep_js_policy_dequeue_job( kbase_device *kbdev,
+ int job_slot_idx,
+ kbase_jd_atom **katom_ptr );
+
+/**
+ * @brief IRQ Context Fast equivalent of kbasep_js_policy_dequeue_job()
+ *
+ * This is a 'fast' variant of kbasep_js_policy_dequeue_job() that will be
+ * called from IRQ context.
+ *
+ * It is recommended that this is coded to be O(1) and must be capable of
+ * returning at least one job per job-slot to IRQ context. If IRQs occur in
+ * quick succession without any work done in non-irq context, then this
+ * function is allowed to return MALI_FALSE even if there are jobs available
+ * that satisfy the requirements.
+ *
+ * This relaxation of correct dequeuing allows O(1) execution with bounded
+ * memory requirements. For example, in addition to the ctxs' job queues the run
+ * pool can have a buffer that can contain a single job for 'quick access' per job
+ * slot, but this buffer is only refilled from the job queue outside of IRQ
+ * context.
+ *
+ * Therefore, all other Job Scheduled Policy Job Management APIs can be
+ * implemented to refill this buffer/maintain the Run Pool's job queues outside
+ * of IRQ context.
+ *
+ * The caller has the following conditions on locking:
+ * - kbasep_js_device_data::runpool_irq::lock will be held.
+ *
+ * @note The caller \em might be holding one of the
+ * kbasep_js_kctx_info::ctx::jsctx_mutex locks, if this code is called from
+ * outside of IRQ context.
+ */
+mali_bool kbasep_js_policy_dequeue_job_irq( kbase_device *kbdev,
+ int job_slot_idx,
+ kbase_jd_atom **katom_ptr );
+
+
+/**
+ * @brief Requeue a Job back into the the Job Scheduler Policy Run Pool
+ *
+ * This will be used to enqueue a job after its creation and also to requeue
+ * a job into the Run Pool that was previously dequeued (running). It notifies
+ * the policy that the job should be run again at some point later.
+ *
+ * As a result of kbasep_js_policy_dequeue_job_irq(), this function might need to
+ * carry out work to maintain its internal queues both before and after a job
+ * is requeued.
+ *
+ * The caller has the following conditions on locking:
+ * - kbasep_js_device_data::runpool_irq::lock (a spinlock) will be held.
+ * - kbasep_js_device_data::runpool_mutex will be held.
+ * - kbasep_js_kctx_info::ctx::jsctx_mutex will be held.
+ */
+void kbasep_js_policy_enqueue_job( kbasep_js_policy *js_policy, kbase_jd_atom *katom );
+
+
+/**
+ * @brief Log the result of a job: the time spent on a job/context, and whether
+ * the job failed or not.
+ *
+ * Since a kbase_jd_atom contains a pointer to the kbase_context owning it,
+ * then this can also be used to log time on either/both the job and the
+ * containing context.
+ *
+ * The completion state of the job can be found by examining \a katom->event.event_code
+ *
+ * If the Job failed and the policy is implementing fair-sharing, then the
+ * policy must penalize the failing job/context:
+ * - At the very least, it should penalize the time taken by the amount of
+ * time spent processing the IRQ in SW. This because a job in the NEXT slot
+ * waiting to run will be delayed until the failing job has had the IRQ
+ * cleared.
+ * - \b Optionally, the policy could apply other penalties. For example, based
+ * on a threshold of a number of failing jobs, after which a large penalty is
+ * applied.
+ *
+ * The kbasep_js_device_data::runpool_mutex will be held by the caller.
+ *
+ * @note This API is called from IRQ context.
+ *
+ * The caller has the following conditions on locking:
+ * - kbasep_js_device_data::runpool_irq::lock will be held.
+ *
+ * @param js_policy job scheduler policy
+ * @param katom job dispatch atom
+ * @param time_spent_us the time spent by the job, in microseconds (10^-6 seconds).
+ */
+void kbasep_js_policy_log_job_result( kbasep_js_policy *js_policy, kbase_jd_atom *katom, u64 time_spent_us );
+
+/** @} */ /* end group kbase_js_policy_job */
+
+
+
+/** @} */ /* end group kbase_js_policy */
+/** @} */ /* end group base_kbase_api */
+/** @} */ /* end group base_api */
+
+#endif /* _KBASE_JS_POLICY_H_ */
diff --git a/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_js_policy_cfs.c b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_js_policy_cfs.c
new file mode 100644
index 0000000..6ab0428
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_js_policy_cfs.c
@@ -0,0 +1,1643 @@
+/*
+ *
+ * (C) COPYRIGHT 2011-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/*
+ * Job Scheduler: Completely Fair Policy Implementation
+ */
+
+#include <kbase/src/common/mali_kbase.h>
+#include <kbase/src/common/mali_kbase_jm.h>
+#include <kbase/src/common/mali_kbase_js.h>
+#include <kbase/src/common/mali_kbase_js_policy_cfs.h>
+
+/**
+ * Define for when dumping is enabled.
+ * This should not be based on the instrumentation level as whether dumping is enabled for a particular level is down to the integrator.
+ * However this is being used for now as otherwise the cinstr headers would be needed.
+ */
+#define CINSTR_DUMPING_ENABLED ( 2 == MALI_INSTRUMENTATION_LEVEL )
+
+/** Fixed point constants used for runtime weight calculations */
+#define WEIGHT_FIXEDPOINT_SHIFT 10
+#define WEIGHT_TABLE_SIZE 40
+#define WEIGHT_0_NICE (WEIGHT_TABLE_SIZE/2)
+#define WEIGHT_0_VAL (1 << WEIGHT_FIXEDPOINT_SHIFT)
+
+#define LOOKUP_VARIANT_MASK ((1u<<KBASEP_JS_MAX_NR_CORE_REQ_VARIANTS) - 1u)
+
+/** Core requirements that all the variants support */
+#define JS_CORE_REQ_ALL_OTHERS \
+ ( BASE_JD_REQ_CF | BASE_JD_REQ_V | BASE_JD_REQ_PERMON | BASE_JD_REQ_EXTERNAL_RESOURCES )
+
+/** Context requirements the all the variants support */
+
+/* In HW issue 8987 workaround, restrict Compute-only contexts and Compute jobs onto job slot[2],
+ * which will ensure their affinity does not intersect GLES jobs */
+#define JS_CTX_REQ_ALL_OTHERS_8987 \
+ ( KBASE_CTX_FLAG_PRIVILEGED )
+#define JS_CORE_REQ_COMPUTE_SLOT_8987 \
+ ( BASE_JD_REQ_CS )
+#define JS_CORE_REQ_ONLY_COMPUTE_SLOT_8987 \
+ ( BASE_JD_REQ_ONLY_COMPUTE )
+
+/* Otherwise, compute-only contexts/compute jobs can use any job slot */
+#define JS_CTX_REQ_ALL_OTHERS \
+ ( KBASE_CTX_FLAG_PRIVILEGED | KBASE_CTX_FLAG_HINT_ONLY_COMPUTE)
+#define JS_CORE_REQ_COMPUTE_SLOT \
+ ( BASE_JD_REQ_CS | BASE_JD_REQ_ONLY_COMPUTE )
+
+/* core_req variants are ordered by least restrictive first, so that our
+ * algorithm in cached_variant_idx_init picks the least restrictive variant for
+ * each job . Note that coherent_group requirement is added to all CS variants as the
+ * selection of job-slot does not depend on the coherency requirement. */
+static const kbasep_atom_req core_req_variants[] ={
+ {
+ /* 0: Fragment variant */
+ (JS_CORE_REQ_ALL_OTHERS | BASE_JD_REQ_FS | BASE_JD_REQ_COHERENT_GROUP),
+ (JS_CTX_REQ_ALL_OTHERS),
+ 0
+ },
+ {
+ /* 1: Compute variant, can use all coregroups */
+ (JS_CORE_REQ_ALL_OTHERS | JS_CORE_REQ_COMPUTE_SLOT),
+ (JS_CTX_REQ_ALL_OTHERS),
+ 0
+ },
+ {
+ /* 2: Compute variant, uses only coherent coregroups */
+ (JS_CORE_REQ_ALL_OTHERS | JS_CORE_REQ_COMPUTE_SLOT | BASE_JD_REQ_COHERENT_GROUP ),
+ (JS_CTX_REQ_ALL_OTHERS),
+ 0
+ },
+ {
+ /* 3: Compute variant, might only use coherent coregroup, and must use tiling */
+ (JS_CORE_REQ_ALL_OTHERS | JS_CORE_REQ_COMPUTE_SLOT | BASE_JD_REQ_COHERENT_GROUP | BASE_JD_REQ_T),
+ (JS_CTX_REQ_ALL_OTHERS),
+ 0
+ },
+
+ {
+ /* 4: Variant guarenteed to support NSS atoms.
+ *
+ * In the case of a context that's specified as 'Only Compute', it'll
+ * not allow Tiler or Fragment atoms, and so those get rejected */
+ (JS_CORE_REQ_ALL_OTHERS | JS_CORE_REQ_COMPUTE_SLOT | BASE_JD_REQ_COHERENT_GROUP | BASE_JD_REQ_NSS ),
+ (JS_CTX_REQ_ALL_OTHERS),
+ 0
+ },
+
+ {
+ /* 5: Compute variant for specific-coherent-group targetting CoreGroup 0 */
+ (JS_CORE_REQ_ALL_OTHERS | JS_CORE_REQ_COMPUTE_SLOT | BASE_JD_REQ_COHERENT_GROUP | BASE_JD_REQ_SPECIFIC_COHERENT_GROUP ),
+ (JS_CTX_REQ_ALL_OTHERS),
+ 0 /* device_nr */
+ },
+ {
+ /* 6: Compute variant for specific-coherent-group targetting CoreGroup 1 */
+ (JS_CORE_REQ_ALL_OTHERS | JS_CORE_REQ_COMPUTE_SLOT | BASE_JD_REQ_COHERENT_GROUP | BASE_JD_REQ_SPECIFIC_COHERENT_GROUP ),
+ (JS_CTX_REQ_ALL_OTHERS),
+ 1 /* device_nr */
+ },
+
+ /* Unused core_req variants, to bring the total up to a power of 2 */
+ {
+ /* 7 */
+ 0,
+ 0,
+ 0
+ },
+};
+
+static const kbasep_atom_req core_req_variants_8987[] ={
+ {
+ /* 0: Fragment variant */
+ (JS_CORE_REQ_ALL_OTHERS | BASE_JD_REQ_FS | BASE_JD_REQ_COHERENT_GROUP),
+ (JS_CTX_REQ_ALL_OTHERS_8987),
+ 0
+ },
+ {
+ /* 1: Compute variant, can use all coregroups */
+ (JS_CORE_REQ_ALL_OTHERS | JS_CORE_REQ_COMPUTE_SLOT_8987),
+ (JS_CTX_REQ_ALL_OTHERS_8987),
+ 0
+ },
+ {
+ /* 2: Compute variant, uses only coherent coregroups */
+ (JS_CORE_REQ_ALL_OTHERS | JS_CORE_REQ_COMPUTE_SLOT_8987 | BASE_JD_REQ_COHERENT_GROUP ),
+ (JS_CTX_REQ_ALL_OTHERS_8987),
+ 0
+ },
+ {
+ /* 3: Compute variant, might only use coherent coregroup, and must use tiling */
+ (JS_CORE_REQ_ALL_OTHERS | JS_CORE_REQ_COMPUTE_SLOT_8987 | BASE_JD_REQ_COHERENT_GROUP | BASE_JD_REQ_T),
+ (JS_CTX_REQ_ALL_OTHERS_8987),
+ 0
+ },
+
+ {
+ /* 4: Variant guarenteed to support Compute contexts/atoms
+ *
+ * In the case of a context that's specified as 'Only Compute', it'll
+ * not allow Tiler or Fragment atoms, and so those get rejected
+ *
+ * NOTE: NSS flag cannot be supported, so its flag is cleared on bag
+ * submit */
+ (JS_CORE_REQ_ALL_OTHERS | JS_CORE_REQ_ONLY_COMPUTE_SLOT_8987 | BASE_JD_REQ_COHERENT_GROUP ),
+ (JS_CTX_REQ_ALL_OTHERS_8987 | KBASE_CTX_FLAG_HINT_ONLY_COMPUTE),
+ 0
+ },
+
+ {
+ /* 5: Compute variant for specific-coherent-group targetting CoreGroup 0
+ * Specifically, this only allows 'Only Compute' contexts/atoms */
+ (JS_CORE_REQ_ALL_OTHERS | JS_CORE_REQ_ONLY_COMPUTE_SLOT_8987 | BASE_JD_REQ_COHERENT_GROUP | BASE_JD_REQ_SPECIFIC_COHERENT_GROUP ),
+ (JS_CTX_REQ_ALL_OTHERS_8987 | KBASE_CTX_FLAG_HINT_ONLY_COMPUTE),
+ 0 /* device_nr */
+ },
+ {
+ /* 6: Compute variant for specific-coherent-group targetting CoreGroup 1
+ * Specifically, this only allows 'Only Compute' contexts/atoms */
+ (JS_CORE_REQ_ALL_OTHERS | JS_CORE_REQ_ONLY_COMPUTE_SLOT_8987 | BASE_JD_REQ_COHERENT_GROUP | BASE_JD_REQ_SPECIFIC_COHERENT_GROUP ),
+ (JS_CTX_REQ_ALL_OTHERS_8987 | KBASE_CTX_FLAG_HINT_ONLY_COMPUTE),
+ 1 /* device_nr */
+ },
+ /* Unused core_req variants, to bring the total up to a power of 2 */
+ {
+ /* 7 */
+ 0,
+ 0,
+ 0
+ },
+};
+
+#define CORE_REQ_VARIANT_FRAGMENT 0
+#define CORE_REQ_VARIANT_COMPUTE_ALL_CORES 1
+#define CORE_REQ_VARIANT_COMPUTE_ONLY_COHERENT_GROUP 2
+#define CORE_REQ_VARIANT_COMPUTE_OR_TILING 3
+#define CORE_REQ_VARIANT_COMPUTE_NSS 4
+#define CORE_REQ_VARIANT_COMPUTE_SPECIFIC_COHERENT_0 5
+#define CORE_REQ_VARIANT_COMPUTE_SPECIFIC_COHERENT_1 6
+
+#define CORE_REQ_VARIANT_ONLY_COMPUTE_8987 4
+#define CORE_REQ_VARIANT_ONLY_COMPUTE_8987_SPECIFIC_COHERENT_0 5
+#define CORE_REQ_VARIANT_ONLY_COMPUTE_8987_SPECIFIC_COHERENT_1 6
+
+
+#define NUM_CORE_REQ_VARIANTS NELEMS(core_req_variants)
+#define NUM_CORE_REQ_VARIANTS_8987 NELEMS(core_req_variants_8987)
+
+/** Mappings between job slot and variant lists for Soft-Stoppable State */
+static const u32 variants_supported_ss_state[] =
+{
+ /* js[0] uses Fragment only */
+ (1u << CORE_REQ_VARIANT_FRAGMENT),
+
+ /* js[1] uses: Compute-all-cores, Compute-only-coherent, Compute-or-Tiling,
+ * compute-specific-coregroup-0 */
+ (1u << CORE_REQ_VARIANT_COMPUTE_ALL_CORES)
+ | (1u << CORE_REQ_VARIANT_COMPUTE_ONLY_COHERENT_GROUP)
+ | (1u << CORE_REQ_VARIANT_COMPUTE_OR_TILING)
+ | (1u << CORE_REQ_VARIANT_COMPUTE_SPECIFIC_COHERENT_0),
+
+ /* js[2] uses: Compute-only-coherent, compute-specific-coregroup-1 */
+ (1u << CORE_REQ_VARIANT_COMPUTE_ONLY_COHERENT_GROUP)
+ | (1u << CORE_REQ_VARIANT_COMPUTE_SPECIFIC_COHERENT_1)
+};
+
+/** Mappings between job slot and variant lists for Soft-Stoppable State, when
+ * we have atoms that can use all the cores (KBASEP_JS_CTX_ATTR_COMPUTE_ALL_CORES)
+ * and there's more than one coregroup */
+static const u32 variants_supported_ss_allcore_state[] =
+{
+ /* js[0] uses Fragment only */
+ (1u << CORE_REQ_VARIANT_FRAGMENT),
+
+ /* js[1] uses: Compute-all-cores, Compute-only-coherent, Compute-or-Tiling,
+ * compute-specific-coregroup-0, compute-specific-coregroup-1 */
+ (1u << CORE_REQ_VARIANT_COMPUTE_ALL_CORES)
+ | (1u << CORE_REQ_VARIANT_COMPUTE_ONLY_COHERENT_GROUP)
+ | (1u << CORE_REQ_VARIANT_COMPUTE_OR_TILING)
+ | (1u << CORE_REQ_VARIANT_COMPUTE_SPECIFIC_COHERENT_0)
+ | (1u << CORE_REQ_VARIANT_COMPUTE_SPECIFIC_COHERENT_1),
+
+ /* js[2] not used */
+ 0
+};
+
+/** Mappings between job slot and variant lists for Soft-Stoppable State for
+ * BASE_HW_ISSUE_8987
+ *
+ * @note There is no 'allcores' variant of this, because this HW issue forces all
+ * atoms with BASE_JD_CORE_REQ_SPECIFIC_COHERENT_GROUP to use slot 2 anyway -
+ * hence regardless of whether a specific coregroup is targetted, those atoms
+ * still make progress. */
+static const u32 variants_supported_ss_state_8987[] =
+{
+ /* js[0] uses Fragment only */
+ (1u << CORE_REQ_VARIANT_FRAGMENT),
+
+ /* js[1] uses: Compute-all-cores, Compute-only-coherent, Compute-or-Tiling*/
+ (1u << CORE_REQ_VARIANT_COMPUTE_ALL_CORES)
+ | (1u << CORE_REQ_VARIANT_COMPUTE_ONLY_COHERENT_GROUP)
+ | (1u << CORE_REQ_VARIANT_COMPUTE_OR_TILING),
+
+ /* js[2] uses: All Only-compute atoms (including those targetting a
+ * specific coregroup), and nothing else. This is because their affinity
+ * must not intersect with non-only-compute atoms.
+ *
+ * As a side effect, this causes the 'device_nr' for atoms targetting a
+ * specific coregroup to be ignored */
+ (1u << CORE_REQ_VARIANT_ONLY_COMPUTE_8987)
+ | (1u << CORE_REQ_VARIANT_ONLY_COMPUTE_8987_SPECIFIC_COHERENT_0)
+ | (1u << CORE_REQ_VARIANT_ONLY_COMPUTE_8987_SPECIFIC_COHERENT_1)
+};
+
+/** Mappings between job slot and variant lists for Non-Soft-Stoppable State
+ *
+ * @note There is no 'allcores' variant of this, because NSS state forces all
+ * atoms with BASE_JD_CORE_REQ_SPECIFIC_COHERENT_GROUP to use slot 1 anyway -
+ * hence regardless of whether a specific coregroup is targetted, those atoms
+ * still make progress.
+ *
+ * @note This is effectively not used during BASE_HW_ISSUE_8987, because the
+ * NSS flag is cleared from all atoms */
+static const u32 variants_supported_nss_state[] =
+{
+ /* js[0] uses Fragment only */
+ (1u << CORE_REQ_VARIANT_FRAGMENT),
+
+ /* js[1] uses: Compute-all-cores, Compute-only-coherent, Compute-or-Tiling,
+ * Compute-targetting-specific-coregroup
+ *
+ * Due to NSS atoms, this causes the 'device_nr' for atoms targetting a
+ * specific coregroup to be ignored (otherwise the Non-NSS atoms targetting
+ * a coregroup would be unreasonably delayed) */
+ (1u << CORE_REQ_VARIANT_COMPUTE_ALL_CORES)
+ | (1u << CORE_REQ_VARIANT_COMPUTE_ONLY_COHERENT_GROUP)
+ | (1u << CORE_REQ_VARIANT_COMPUTE_OR_TILING)
+ | (1u << CORE_REQ_VARIANT_COMPUTE_SPECIFIC_COHERENT_0)
+ | (1u << CORE_REQ_VARIANT_COMPUTE_SPECIFIC_COHERENT_1),
+
+ /* js[2] uses: NSS only */
+ (1u << CORE_REQ_VARIANT_COMPUTE_NSS)
+};
+
+/* Defines for easy asserts 'is scheduled'/'is queued'/'is neither queued norscheduled' */
+#define KBASEP_JS_CHECKFLAG_QUEUED (1u << 0) /**< Check the queued state */
+#define KBASEP_JS_CHECKFLAG_SCHEDULED (1u << 1) /**< Check the scheduled state */
+#define KBASEP_JS_CHECKFLAG_IS_QUEUED (1u << 2) /**< Expect queued state to be set */
+#define KBASEP_JS_CHECKFLAG_IS_SCHEDULED (1u << 3) /**< Expect scheduled state to be set */
+
+enum
+{
+ KBASEP_JS_CHECK_NOTQUEUED = KBASEP_JS_CHECKFLAG_QUEUED,
+ KBASEP_JS_CHECK_NOTSCHEDULED = KBASEP_JS_CHECKFLAG_SCHEDULED,
+ KBASEP_JS_CHECK_QUEUED = KBASEP_JS_CHECKFLAG_QUEUED | KBASEP_JS_CHECKFLAG_IS_QUEUED,
+ KBASEP_JS_CHECK_SCHEDULED = KBASEP_JS_CHECKFLAG_SCHEDULED | KBASEP_JS_CHECKFLAG_IS_SCHEDULED
+};
+
+typedef u32 kbasep_js_check;
+
+/*
+ * Private Functions
+ */
+
+/* Table autogenerated using util built from: kbase/scripts/gen_cfs_weight_of_prio.c */
+
+/* weight = 1.25 */
+static const int weight_of_priority[] =
+{
+ /* -20 */ 11, 14, 18, 23,
+ /* -16 */ 29, 36, 45, 56,
+ /* -12 */ 70, 88, 110, 137,
+ /* -8 */ 171, 214, 268, 335,
+ /* -4 */ 419, 524, 655, 819,
+ /* 0 */ 1024, 1280, 1600, 2000,
+ /* 4 */ 2500, 3125, 3906, 4883,
+ /* 8 */ 6104, 7630, 9538, 11923,
+ /* 12 */ 14904, 18630, 23288, 29110,
+ /* 16 */ 36388, 45485, 56856, 71070
+};
+
+/**
+ * @note There is nothing to stop the priority of the ctx containing \a
+ * ctx_info changing during or immediately after this function is called
+ * (because its jsctx_mutex cannot be held during IRQ). Therefore, this
+ * function should only be seen as a heuristic guide as to the priority weight
+ * of the context.
+ */
+STATIC u64 priority_weight(kbasep_js_policy_cfs_ctx *ctx_info, u64 time_us)
+{
+ u64 time_delta_us;
+ int priority;
+ priority = ctx_info->process_priority + ctx_info->bag_priority;
+
+ /* Adjust runtime_us using priority weight if required */
+ if(priority != 0 && time_us != 0)
+ {
+ int clamped_priority;
+
+ /* Clamp values to min..max weights */
+ if(priority > OSK_PROCESS_PRIORITY_MAX)
+ {
+ clamped_priority = OSK_PROCESS_PRIORITY_MAX;
+ }
+ else if(priority < OSK_PROCESS_PRIORITY_MIN)
+ {
+ clamped_priority = OSK_PROCESS_PRIORITY_MIN;
+ }
+ else
+ {
+ clamped_priority = priority;
+ }
+
+ /* Fixed point multiplication */
+ time_delta_us = (time_us * weight_of_priority[WEIGHT_0_NICE + clamped_priority]);
+ /* Remove fraction */
+ time_delta_us = time_delta_us >> WEIGHT_FIXEDPOINT_SHIFT;
+ /* Make sure the time always increases */
+ if(0 == time_delta_us)
+ {
+ time_delta_us++;
+ }
+ }
+ else
+ {
+ time_delta_us = time_us;
+ }
+
+ return time_delta_us;
+}
+
+#if KBASE_TRACE_ENABLE != 0
+STATIC int kbasep_js_policy_trace_get_refcnt_nolock( kbase_device *kbdev, kbase_context *kctx )
+{
+ kbasep_js_device_data *js_devdata;
+ int as_nr;
+ int refcnt = 0;
+
+ js_devdata = &kbdev->js_data;
+
+ as_nr = kctx->as_nr;
+ if ( as_nr != KBASEP_AS_NR_INVALID )
+ {
+ kbasep_js_per_as_data *js_per_as_data;
+ js_per_as_data = &js_devdata->runpool_irq.per_as_data[as_nr];
+
+ refcnt = js_per_as_data->as_busy_refcount;
+ }
+
+ return refcnt;
+}
+
+STATIC INLINE int kbasep_js_policy_trace_get_refcnt( kbase_device *kbdev, kbase_context *kctx )
+{
+ unsigned long flags;
+ kbasep_js_device_data *js_devdata;
+ int refcnt = 0;
+
+ js_devdata = &kbdev->js_data;
+
+ spin_lock_irqsave( &js_devdata->runpool_irq.lock, flags);
+ refcnt = kbasep_js_policy_trace_get_refcnt_nolock( kbdev, kctx );
+ spin_unlock_irqrestore( &js_devdata->runpool_irq.lock, flags);
+
+ return refcnt;
+}
+#else /* KBASE_TRACE_ENABLE != 0 */
+STATIC int kbasep_js_policy_trace_get_refcnt_nolock( kbase_device *kbdev, kbase_context *kctx )
+{
+ CSTD_UNUSED( kbdev );
+ CSTD_UNUSED( kctx );
+ return 0;
+}
+
+STATIC INLINE int kbasep_js_policy_trace_get_refcnt( kbase_device *kbdev, kbase_context *kctx )
+{
+ CSTD_UNUSED( kbdev );
+ CSTD_UNUSED( kctx );
+ return 0;
+}
+#endif /* KBASE_TRACE_ENABLE != 0 */
+
+
+#ifdef CONFIG_MALI_DEBUG
+STATIC void kbasep_js_debug_check( kbasep_js_policy_cfs *policy_info, kbase_context *kctx, kbasep_js_check check_flag )
+{
+ /* This function uses the ternary operator and non-explicit comparisons,
+ * because it makes for much shorter, easier to read code */
+
+ if ( check_flag & KBASEP_JS_CHECKFLAG_QUEUED )
+ {
+ mali_bool is_queued;
+ mali_bool expect_queued;
+ is_queued = ( OSK_DLIST_MEMBER_OF( &policy_info->ctx_queue_head,
+ kctx,
+ jctx.sched_info.runpool.policy_ctx.cfs.list ) )? MALI_TRUE: MALI_FALSE;
+
+ if(!is_queued)
+ {
+ is_queued = ( OSK_DLIST_MEMBER_OF( &policy_info->ctx_rt_queue_head,
+ kctx,
+ jctx.sched_info.runpool.policy_ctx.cfs.list ) )? MALI_TRUE: MALI_FALSE;
+ }
+
+ expect_queued = ( check_flag & KBASEP_JS_CHECKFLAG_IS_QUEUED ) ? MALI_TRUE : MALI_FALSE;
+
+ OSK_ASSERT_MSG( expect_queued == is_queued,
+ "Expected context %p to be %s but it was %s\n",
+ kctx,
+ (expect_queued) ?"queued":"not queued",
+ (is_queued) ?"queued":"not queued" );
+
+ }
+
+ if ( check_flag & KBASEP_JS_CHECKFLAG_SCHEDULED )
+ {
+ mali_bool is_scheduled;
+ mali_bool expect_scheduled;
+ is_scheduled = ( OSK_DLIST_MEMBER_OF( &policy_info->scheduled_ctxs_head,
+ kctx,
+ jctx.sched_info.runpool.policy_ctx.cfs.list ) )? MALI_TRUE: MALI_FALSE;
+
+ expect_scheduled = ( check_flag & KBASEP_JS_CHECKFLAG_IS_SCHEDULED ) ? MALI_TRUE : MALI_FALSE;
+ OSK_ASSERT_MSG( expect_scheduled == is_scheduled,
+ "Expected context %p to be %s but it was %s\n",
+ kctx,
+ (expect_scheduled)?"scheduled":"not scheduled",
+ (is_scheduled) ?"scheduled":"not scheduled" );
+
+ }
+
+}
+#else /* CONFIG_MALI_DEBUG */
+STATIC void kbasep_js_debug_check( kbasep_js_policy_cfs *policy_info, kbase_context *kctx, kbasep_js_check check_flag )
+{
+ CSTD_UNUSED( policy_info );
+ CSTD_UNUSED( kctx );
+ CSTD_UNUSED( check_flag );
+ return;
+}
+#endif /* CONFIG_MALI_DEBUG */
+
+STATIC INLINE void set_slot_to_variant_lookup( u32 *bit_array, u32 slot_idx, u32 variants_supported )
+{
+ u32 overall_bit_idx = slot_idx * KBASEP_JS_MAX_NR_CORE_REQ_VARIANTS;
+ u32 word_idx = overall_bit_idx / 32;
+ u32 bit_idx = overall_bit_idx % 32;
+
+ OSK_ASSERT( slot_idx < BASE_JM_MAX_NR_SLOTS );
+ OSK_ASSERT( (variants_supported & ~LOOKUP_VARIANT_MASK) == 0 );
+
+ bit_array[word_idx] |= variants_supported << bit_idx;
+}
+
+
+STATIC INLINE u32 get_slot_to_variant_lookup( u32 *bit_array, u32 slot_idx )
+{
+ u32 overall_bit_idx = slot_idx * KBASEP_JS_MAX_NR_CORE_REQ_VARIANTS;
+ u32 word_idx = overall_bit_idx / 32;
+ u32 bit_idx = overall_bit_idx % 32;
+
+ u32 res;
+
+ OSK_ASSERT( slot_idx < BASE_JM_MAX_NR_SLOTS );
+
+ res = bit_array[word_idx] >> bit_idx;
+ res &= LOOKUP_VARIANT_MASK;
+
+ return res;
+}
+
+/* Check the core_req_variants: make sure that every job slot is satisifed by
+ * one of the variants. This checks that cached_variant_idx_init will produce a
+ * valid result for jobs that make maximum use of the job slots.
+ *
+ * @note The checks are limited to the job slots - this does not check that
+ * every context requirement is covered (because some are intentionally not
+ * supported, such as KBASE_CTX_FLAG_SUBMIT_DISABLED) */
+#ifdef CONFIG_MALI_DEBUG
+STATIC void debug_check_core_req_variants( kbase_device *kbdev, kbasep_js_policy_cfs *policy_info )
+{
+ kbasep_js_device_data *js_devdata;
+ u32 i;
+ int j;
+
+ js_devdata = &kbdev->js_data;
+
+ for ( j = 0 ; j < kbdev->gpu_props.num_job_slots ; ++j )
+ {
+ base_jd_core_req job_core_req;
+ mali_bool found = MALI_FALSE;
+
+ job_core_req = js_devdata->js_reqs[j];
+ for ( i = 0; i < policy_info->num_core_req_variants ; ++i )
+ {
+ base_jd_core_req var_core_req;
+ var_core_req = policy_info->core_req_variants[i].core_req;
+
+ if ( (var_core_req & job_core_req) == job_core_req )
+ {
+ found = MALI_TRUE;
+ break;
+ }
+ }
+
+ /* Early-out on any failure */
+ OSK_ASSERT_MSG( found != MALI_FALSE,
+ "Job slot %d features 0x%x not matched by core_req_variants. "
+ "Rework core_req_variants and vairants_supported_<...>_state[] to match\n",
+ j,
+ job_core_req );
+ }
+}
+#endif
+
+STATIC void build_core_req_variants( kbase_device *kbdev, kbasep_js_policy_cfs *policy_info )
+{
+ OSK_ASSERT( kbdev != NULL );
+ OSK_ASSERT( policy_info != NULL );
+ CSTD_UNUSED( kbdev );
+
+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8987))
+ {
+ OSK_ASSERT( NUM_CORE_REQ_VARIANTS_8987 <= KBASEP_JS_MAX_NR_CORE_REQ_VARIANTS );
+
+ /* Assume a static set of variants */
+ memcpy( policy_info->core_req_variants, core_req_variants_8987, sizeof(core_req_variants_8987) );
+
+ policy_info->num_core_req_variants = NUM_CORE_REQ_VARIANTS_8987;
+ }
+ else
+ {
+ OSK_ASSERT( NUM_CORE_REQ_VARIANTS <= KBASEP_JS_MAX_NR_CORE_REQ_VARIANTS );
+
+ /* Assume a static set of variants */
+ memcpy( policy_info->core_req_variants, core_req_variants, sizeof(core_req_variants) );
+
+ policy_info->num_core_req_variants = NUM_CORE_REQ_VARIANTS;
+ }
+
+ OSK_DEBUG_CODE( debug_check_core_req_variants( kbdev, policy_info ) );
+}
+
+
+STATIC void build_slot_lookups( kbase_device *kbdev, kbasep_js_policy_cfs *policy_info )
+{
+ u8 i;
+ const u32 *variants_supported_ss_for_this_hw = variants_supported_ss_state;
+
+ OSK_ASSERT( kbdev != NULL );
+ OSK_ASSERT( policy_info != NULL );
+
+ OSK_ASSERT( kbdev->gpu_props.num_job_slots <= NELEMS(variants_supported_ss_state) );
+ OSK_ASSERT( kbdev->gpu_props.num_job_slots <= NELEMS(variants_supported_ss_allcore_state) );
+ OSK_ASSERT( kbdev->gpu_props.num_job_slots <= NELEMS(variants_supported_ss_state_8987) );
+ OSK_ASSERT( kbdev->gpu_props.num_job_slots <= NELEMS(variants_supported_nss_state) );
+
+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8987))
+ {
+ variants_supported_ss_for_this_hw = variants_supported_ss_state_8987;
+ }
+
+ /* Given the static set of variants, provide a static set of lookups */
+ for ( i = 0; i < kbdev->gpu_props.num_job_slots; ++i )
+ {
+ set_slot_to_variant_lookup( policy_info->slot_to_variant_lookup_ss_state,
+ i,
+ variants_supported_ss_for_this_hw[i] );
+
+ set_slot_to_variant_lookup( policy_info->slot_to_variant_lookup_ss_allcore_state,
+ i,
+ variants_supported_ss_allcore_state[i] );
+
+ set_slot_to_variant_lookup( policy_info->slot_to_variant_lookup_nss_state,
+ i,
+ variants_supported_nss_state[i] );
+ }
+
+}
+
+STATIC mali_error cached_variant_idx_init( const kbasep_js_policy_cfs *policy_info, const kbase_context *kctx, kbase_jd_atom *atom )
+{
+ kbasep_js_policy_cfs_job *job_info;
+ u32 i;
+ base_jd_core_req job_core_req;
+ u32 job_device_nr;
+ kbase_context_flags ctx_flags;
+ const kbasep_js_kctx_info *js_kctx_info;
+ const kbase_device *kbdev;
+
+ OSK_ASSERT( policy_info != NULL );
+ OSK_ASSERT( kctx != NULL );
+ OSK_ASSERT( atom != NULL );
+
+ kbdev = container_of(policy_info, const kbase_device, js_data.policy.cfs);
+ job_info = &atom->sched_info.cfs;
+ job_core_req = atom->core_req;
+ job_device_nr = atom->device_nr;
+ js_kctx_info = &kctx->jctx.sched_info;
+ ctx_flags = js_kctx_info->ctx.flags;
+
+ /* Initial check for atoms targetting a specific coregroup */
+ if ( (job_core_req & BASE_JD_REQ_SPECIFIC_COHERENT_GROUP) != MALI_FALSE
+ && job_device_nr >= kbdev->gpu_props.num_core_groups )
+ {
+ /* device_nr exceeds the number of coregroups - not allowed by
+ * @ref base_jd_atom API contract */
+ return MALI_ERROR_FUNCTION_FAILED;
+ }
+
+ /* Pick a core_req variant that matches us. Since they're ordered by least
+ * restrictive first, it picks the least restrictive variant */
+ for ( i = 0; i < policy_info->num_core_req_variants ; ++i )
+ {
+ base_jd_core_req var_core_req;
+ kbase_context_flags var_ctx_req;
+ u32 var_device_nr;
+ var_core_req = policy_info->core_req_variants[i].core_req;
+ var_ctx_req = policy_info->core_req_variants[i].ctx_req;
+ var_device_nr = policy_info->core_req_variants[i].device_nr;
+
+ if ( (var_core_req & job_core_req) == job_core_req
+ && (var_ctx_req & ctx_flags) == ctx_flags
+ && ((var_core_req & BASE_JD_REQ_SPECIFIC_COHERENT_GROUP)==MALI_FALSE || var_device_nr == job_device_nr ) )
+ {
+ job_info->cached_variant_idx = i;
+ return MALI_ERROR_NONE;
+ }
+ }
+
+ /* Could not find a matching requirement, this should only be caused by an
+ * attempt to attack the driver. */
+ return MALI_ERROR_FUNCTION_FAILED;
+}
+
+STATIC mali_bool dequeue_job( kbase_device *kbdev,
+ kbase_context *kctx,
+ u32 variants_supported,
+ kbase_jd_atom **katom_ptr,
+ int job_slot_idx)
+{
+ kbasep_js_device_data *js_devdata;
+ kbasep_js_policy_cfs *policy_info;
+ kbasep_js_policy_cfs_ctx *ctx_info;
+
+ OSK_ASSERT( kbdev != NULL );
+ OSK_ASSERT( katom_ptr != NULL );
+ OSK_ASSERT( kctx != NULL );
+
+ js_devdata = &kbdev->js_data;
+ policy_info = &js_devdata->policy.cfs;
+ ctx_info = &kctx->jctx.sched_info.runpool.policy_ctx.cfs;
+
+ /* Only submit jobs from contexts that are allowed */
+ if ( kbasep_js_is_submit_allowed( js_devdata, kctx ) != MALI_FALSE )
+ {
+ /* Check each variant in turn */
+ while ( variants_supported != 0 )
+ {
+ long variant_idx;
+ osk_dlist *job_list;
+ variant_idx = osk_find_first_set_bit( variants_supported );
+ job_list = &ctx_info->job_list_head[variant_idx];
+
+ if ( OSK_DLIST_IS_EMPTY( job_list ) == MALI_FALSE )
+ {
+ int err;
+
+ /* Found a context with a matching job */
+ {
+ kbase_jd_atom *front_atom = OSK_DLIST_FRONT( job_list, kbase_jd_atom, sched_info.cfs.list );
+ KBASE_TRACE_ADD_SLOT( kbdev, JS_POLICY_DEQUEUE_JOB, front_atom->kctx, front_atom,
+ front_atom->jc, job_slot_idx );
+ }
+ *katom_ptr = OSK_DLIST_POP_FRONT( job_list, kbase_jd_atom, sched_info.cfs.list, err);
+
+ (*katom_ptr)->sched_info.cfs.ticks = 0;
+
+ /* Put this context at the back of the Run Pool */
+ OSK_DLIST_REMOVE( &policy_info->scheduled_ctxs_head,
+ kctx,
+ jctx.sched_info.runpool.policy_ctx.cfs.list, err);
+ OSK_DLIST_PUSH_BACK( &policy_info->scheduled_ctxs_head,
+ kctx,
+ kbase_context,
+ jctx.sched_info.runpool.policy_ctx.cfs.list );
+
+ return MALI_TRUE;
+ }
+
+ variants_supported &= ~(1u << variant_idx);
+ }
+ /* All variants checked by here */
+ }
+
+ /* The context does not have a matching job */
+
+ return MALI_FALSE;
+}
+
+/**
+ * Hold the runpool_irq spinlock for this
+ */
+OSK_STATIC_INLINE mali_bool timer_callback_should_run( kbase_device *kbdev )
+{
+ kbasep_js_device_data *js_devdata;
+ s8 nr_running_ctxs;
+
+ OSK_ASSERT(kbdev != NULL);
+ js_devdata = &kbdev->js_data;
+
+ /* nr_user_contexts_running is updated with the runpool_mutex. However, the
+ * locking in the caller gives us a barrier that ensures nr_user_contexts is
+ * up-to-date for reading */
+ nr_running_ctxs = js_devdata->nr_user_contexts_running;
+
+#ifdef CONFIG_MALI_DEBUG
+ if(js_devdata->softstop_always)
+ {
+ /* Debug support for allowing soft-stop on a single context */
+ return MALI_TRUE;
+ }
+#endif /* CONFIG_MALI_DEBUG */
+
+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_9435))
+ {
+ /* Timeouts would have to be 4x longer (due to micro-architectural design)
+ * to support OpenCL conformance tests, so only run the timer when there's:
+ * - 2 or more CL contexts
+ * - 1 or more GLES contexts
+ *
+ * NOTE: We will treat a context that has both Compute and Non-Compute jobs
+ * will be treated as an OpenCL context (hence, we don't check
+ * KBASEP_JS_CTX_ATTR_NON_COMPUTE).
+ */
+ {
+ s8 nr_compute_ctxs = kbasep_js_ctx_attr_count_on_runpool( kbdev, KBASEP_JS_CTX_ATTR_COMPUTE );
+ s8 nr_noncompute_ctxs = nr_running_ctxs - nr_compute_ctxs;
+
+ return (mali_bool)( nr_compute_ctxs >= 2 || nr_noncompute_ctxs > 0 );
+ }
+ }
+ else
+ {
+ /* Run the timer callback whenever you have at least 1 context */
+ return (mali_bool)(nr_running_ctxs > 0);
+ }
+}
+
+static enum hrtimer_restart timer_callback( struct hrtimer * timer )
+{
+ unsigned long flags;
+ kbase_device *kbdev;
+ kbasep_js_device_data *js_devdata;
+ kbasep_js_policy_cfs *policy_info;
+ int s;
+ mali_bool reset_needed = MALI_FALSE;
+
+ OSK_ASSERT(timer != NULL);
+
+ policy_info = container_of( timer, kbasep_js_policy_cfs, scheduling_timer );
+
+ kbdev = policy_info->kbdev;
+ js_devdata = &kbdev->js_data;
+
+ /* Loop through the slots */
+ spin_lock_irqsave(&js_devdata->runpool_irq.lock, flags);
+ for(s=0; s<kbdev->gpu_props.num_job_slots; s++)
+ {
+ kbase_jm_slot *slot = &kbdev->jm_slots[s];
+ kbase_jd_atom *atom = NULL;
+
+ if (kbasep_jm_nr_jobs_submitted(slot) > 0)
+ {
+ atom = kbasep_jm_peek_idx_submit_slot(slot, 0);
+ OSK_ASSERT( atom != NULL );
+
+ if ( kbasep_jm_is_dummy_workaround_job( kbdev, atom ) != MALI_FALSE )
+ {
+ /* Prevent further use of the atom - never cause a soft-stop, hard-stop, or a GPU reset due to it. */
+ atom = NULL;
+ }
+ }
+
+ if ( atom != NULL )
+ {
+ /* The current version of the model doesn't support Soft-Stop */
+ if (!kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_5736))
+ {
+ u32 ticks = atom->sched_info.cfs.ticks ++;
+
+#if !CINSTR_DUMPING_ENABLED
+ if ( (atom->core_req & BASE_JD_REQ_NSS) == 0 )
+ {
+ /* Job is Soft-Stoppable */
+ if (ticks == js_devdata->soft_stop_ticks)
+ {
+ /* Job has been scheduled for at least js_devdata->soft_stop_ticks ticks.
+ * Soft stop the slot so we can run other jobs.
+ */
+ OSK_PRINT_INFO( OSK_BASE_JM, "Soft-stop" );
+
+#if KBASE_DISABLE_SCHEDULING_SOFT_STOPS == 0
+ kbase_job_slot_softstop(kbdev, s, atom);
+#endif
+ }
+ else if (ticks == js_devdata->hard_stop_ticks_ss)
+ {
+ /* Job has been scheduled for at least js_devdata->hard_stop_ticks_ss ticks.
+ * It should have been soft-stopped by now. Hard stop the slot.
+ */
+#if KBASE_DISABLE_SCHEDULING_HARD_STOPS == 0
+ OSK_PRINT_WARN(OSK_BASE_JM, "JS: Job Hard-Stopped (took more than %lu ticks at %lu ms/tick)", ticks, js_devdata->scheduling_tick_ns/1000000u );
+ kbase_job_slot_hardstop(atom->kctx, s, atom);
+#endif
+ }
+ else if (ticks == js_devdata->gpu_reset_ticks_ss)
+ {
+ /* Job has been scheduled for at least js_devdata->gpu_reset_ticks_ss ticks.
+ * It should have left the GPU by now. Signal that the GPU needs to be reset.
+ */
+ reset_needed = MALI_TRUE;
+ }
+ }
+ else
+#endif /* !CINSTR_DUMPING_ENABLED */
+ /* NOTE: During CINSTR_DUMPING_ENABLED, we use the NSS-timeouts for *all* atoms,
+ * which makes the hard-stop and GPU reset timeout much longer. We also ensure
+ * that we don't soft-stop at all.
+ *
+ * Otherwise, this next block is only used for NSS-atoms */
+ {
+ /* Job is Non Soft-Stoppable */
+ if (ticks == js_devdata->soft_stop_ticks)
+ {
+ /* Job has been scheduled for at least js_devdata->soft_stop_ticks.
+ * Let's try to soft-stop it even if it's supposed to be NSS.
+ */
+ OSK_PRINT_INFO( OSK_BASE_JM, "Soft-stop" );
+
+#if (KBASE_DISABLE_SCHEDULING_SOFT_STOPS == 0) && (CINSTR_DUMPING_ENABLED == 0)
+ kbase_job_slot_softstop(kbdev, s, atom);
+#endif
+ }
+ else if (ticks == js_devdata->hard_stop_ticks_nss)
+ {
+ /* Job has been scheduled for at least js_devdata->hard_stop_ticks_nss ticks.
+ * Hard stop the slot.
+ */
+#if KBASE_DISABLE_SCHEDULING_HARD_STOPS == 0
+ OSK_PRINT_WARN(OSK_BASE_JM, "JS: Job Hard-Stopped (took more than %lu ticks at %lu ms/tick)", ticks, js_devdata->scheduling_tick_ns/1000000u );
+ kbase_job_slot_hardstop(atom->kctx, s, atom);
+#endif
+ }
+ else if (ticks == js_devdata->gpu_reset_ticks_nss)
+ {
+ /* Job has been scheduled for at least js_devdata->gpu_reset_ticks_nss ticks.
+ * It should have left the GPU by now. Signal that the GPU needs to be reset.
+ */
+ reset_needed = MALI_TRUE;
+ }
+ }
+ }
+ }
+ }
+
+ if (reset_needed)
+ {
+ OSK_PRINT_WARN(OSK_BASE_JM, "JS: Job has been on the GPU for too long");
+ if (kbase_prepare_to_reset_gpu_locked(kbdev))
+ {
+ kbase_reset_gpu_locked(kbdev);
+ }
+ }
+
+ /* the timer is re-issued if there is contexts in the run-pool */
+
+ if (timer_callback_should_run(kbdev) != MALI_FALSE)
+ {
+ hrtimer_start( &policy_info->scheduling_timer,
+ HR_TIMER_DELAY_NSEC( js_devdata->scheduling_tick_ns ),
+ HRTIMER_MODE_REL );
+ }
+ else
+ {
+ KBASE_TRACE_ADD( kbdev, JS_POLICY_TIMER_END, NULL, NULL, 0u, 0u );
+ policy_info->timer_running = MALI_FALSE;
+ }
+
+ spin_unlock_irqrestore(&js_devdata->runpool_irq.lock, flags);
+
+ return HRTIMER_NORESTART;
+}
+
+/*
+ * Non-private functions
+ */
+
+mali_error kbasep_js_policy_init( kbase_device *kbdev )
+{
+ kbasep_js_device_data *js_devdata;
+ kbasep_js_policy_cfs *policy_info;
+
+ OSK_ASSERT( kbdev != NULL );
+ js_devdata = &kbdev->js_data;
+ policy_info = &js_devdata->policy.cfs;
+
+ OSK_DLIST_INIT( &policy_info->ctx_queue_head );
+ OSK_DLIST_INIT( &policy_info->scheduled_ctxs_head );
+ OSK_DLIST_INIT( &policy_info->ctx_rt_queue_head );
+
+ hrtimer_init(&policy_info->scheduling_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL );
+ policy_info->scheduling_timer.function = timer_callback;
+
+ policy_info->timer_running = MALI_FALSE;
+ policy_info->kbdev = kbdev;
+ policy_info->head_runtime_us = 0;
+
+ /* Build up the core_req variants */
+ build_core_req_variants( kbdev, policy_info );
+ /* Build the slot to variant lookups */
+ build_slot_lookups(kbdev, policy_info );
+
+ return MALI_ERROR_NONE;
+}
+
+void kbasep_js_policy_term( kbasep_js_policy *js_policy )
+{
+ kbasep_js_policy_cfs *policy_info;
+ OSK_ASSERT( js_policy != NULL );
+ policy_info = &js_policy->cfs;
+
+ /* ASSERT that there are no contexts queued */
+ OSK_ASSERT( OSK_DLIST_IS_EMPTY( &policy_info->ctx_queue_head ) != MALI_FALSE );
+ /* ASSERT that there are no contexts scheduled */
+ OSK_ASSERT( OSK_DLIST_IS_EMPTY( &policy_info->scheduled_ctxs_head ) != MALI_FALSE );
+
+ /* ASSERT that there are no contexts queued */
+ OSK_ASSERT( OSK_DLIST_IS_EMPTY( &policy_info->ctx_rt_queue_head ) != MALI_FALSE );
+
+ hrtimer_cancel(&policy_info->scheduling_timer);
+}
+
+mali_error kbasep_js_policy_init_ctx( kbase_device *kbdev, kbase_context *kctx )
+{
+ kbasep_js_device_data *js_devdata;
+ kbasep_js_policy_cfs_ctx *ctx_info;
+ kbasep_js_policy_cfs *policy_info;
+ osk_process_priority prio;
+ u32 i;
+
+ OSK_ASSERT( kbdev != NULL );
+ OSK_ASSERT( kctx != NULL );
+
+ js_devdata = &kbdev->js_data;
+ policy_info = &kbdev->js_data.policy.cfs;
+ ctx_info = &kctx->jctx.sched_info.runpool.policy_ctx.cfs;
+
+ KBASE_TRACE_ADD_REFCOUNT( kbdev, JS_POLICY_INIT_CTX, kctx, NULL, 0u,
+ kbasep_js_policy_trace_get_refcnt( kbdev, kctx ));
+
+ for ( i = 0 ; i < policy_info->num_core_req_variants ; ++i )
+ {
+ OSK_DLIST_INIT( &ctx_info->job_list_head[i] );
+ }
+
+ osk_get_process_priority(&prio);
+ ctx_info->process_rt_policy = prio.is_realtime;
+ ctx_info->process_priority = prio.priority;
+ ctx_info->bag_total_priority = 0;
+ ctx_info->bag_total_nr_atoms = 0;
+
+ /* Initial runtime (relative to least-run context runtime)
+ *
+ * This uses the Policy Queue's most up-to-date head_runtime_us by using the
+ * queue mutex to issue memory barriers - also ensure future updates to
+ * head_runtime_us occur strictly after this context is initialized */
+ mutex_lock( &js_devdata->queue_mutex );
+
+ /* No need to hold the the runpool_irq.lock here, because we're initializing
+ * the value, and the context is definitely not being updated in the
+ * runpool at this point. The queue_mutex ensures the memory barrier. */
+ ctx_info->runtime_us = policy_info->head_runtime_us +
+ priority_weight(ctx_info,
+ (u64)js_devdata->cfs_ctx_runtime_init_slices * (u64)(js_devdata->ctx_timeslice_ns/1000u));
+
+ mutex_unlock( &js_devdata->queue_mutex );
+
+ return MALI_ERROR_NONE;
+}
+
+void kbasep_js_policy_term_ctx( kbasep_js_policy *js_policy, kbase_context *kctx )
+{
+ kbasep_js_policy_cfs_ctx *ctx_info;
+ kbasep_js_policy_cfs *policy_info;
+ u32 i;
+
+ OSK_ASSERT( js_policy != NULL );
+ OSK_ASSERT( kctx != NULL );
+
+ policy_info = &js_policy->cfs;
+ ctx_info = &kctx->jctx.sched_info.runpool.policy_ctx.cfs;
+
+ {
+ kbase_device *kbdev = container_of( js_policy, kbase_device, js_data.policy );
+ KBASE_TRACE_ADD_REFCOUNT( kbdev, JS_POLICY_TERM_CTX, kctx, NULL, 0u,
+ kbasep_js_policy_trace_get_refcnt( kbdev, kctx ));
+ }
+
+ /* ASSERT that no jobs are present */
+ for ( i = 0 ; i < policy_info->num_core_req_variants ; ++i )
+ {
+ OSK_ASSERT( OSK_DLIST_IS_EMPTY( &ctx_info->job_list_head[i] ) != MALI_FALSE );
+ }
+
+ /* No work to do */
+}
+
+
+/*
+ * Context Management
+ */
+
+void kbasep_js_policy_enqueue_ctx( kbasep_js_policy *js_policy, kbase_context *kctx )
+{
+ kbasep_js_policy_cfs *policy_info;
+ kbasep_js_policy_cfs_ctx *ctx_info;
+ kbase_context *list_kctx = NULL;
+ kbasep_js_device_data *js_devdata;
+ osk_dlist *queue_head;
+
+ OSK_ASSERT( js_policy != NULL );
+ OSK_ASSERT( kctx != NULL );
+
+ policy_info = &js_policy->cfs;
+ ctx_info = &kctx->jctx.sched_info.runpool.policy_ctx.cfs;
+ js_devdata = container_of( js_policy, kbasep_js_device_data, policy );
+
+ {
+ kbase_device *kbdev = container_of( js_policy, kbase_device, js_data.policy );
+ KBASE_TRACE_ADD_REFCOUNT( kbdev, JS_POLICY_ENQUEUE_CTX, kctx, NULL, 0u,
+ kbasep_js_policy_trace_get_refcnt( kbdev, kctx ));
+ }
+
+ /* ASSERT about scheduled-ness/queued-ness */
+ kbasep_js_debug_check( policy_info, kctx, KBASEP_JS_CHECK_NOTQUEUED );
+
+ /* Clamp the runtime to prevent DoS attacks through "stored-up" runtime */
+ if (policy_info->head_runtime_us > ctx_info->runtime_us
+ + (u64)js_devdata->cfs_ctx_runtime_min_slices * (u64)(js_devdata->ctx_timeslice_ns/1000u))
+ {
+ /* No need to hold the the runpool_irq.lock here, because we're essentially
+ * initializing the value, and the context is definitely not being updated in the
+ * runpool at this point. The queue_mutex held by the caller ensures the memory
+ * barrier. */
+ ctx_info->runtime_us = policy_info->head_runtime_us
+ - (u64)js_devdata->cfs_ctx_runtime_min_slices * (u64)(js_devdata->ctx_timeslice_ns/1000u);
+ }
+
+ /* Find the position where the context should be enqueued */
+ if(ctx_info->process_rt_policy)
+ {
+ queue_head = &policy_info->ctx_rt_queue_head;
+ }
+ else
+ {
+ queue_head = &policy_info->ctx_queue_head;
+ }
+
+ OSK_DLIST_FOREACH( queue_head,
+ kbase_context,
+ jctx.sched_info.runpool.policy_ctx.cfs.list,
+ list_kctx )
+ {
+ kbasep_js_policy_cfs_ctx *list_ctx_info;
+ list_ctx_info = &list_kctx->jctx.sched_info.runpool.policy_ctx.cfs;
+
+ if ( (kctx->jctx.sched_info.ctx.flags & KBASE_CTX_FLAG_PRIVILEGED) != 0 )
+ {
+ break;
+ }
+
+ if ( (list_ctx_info->runtime_us > ctx_info->runtime_us) &&
+ ((list_kctx->jctx.sched_info.ctx.flags & KBASE_CTX_FLAG_PRIVILEGED) == 0) )
+ {
+ break;
+ }
+ }
+
+ /* Add the context to the queue */
+ if (OSK_DLIST_IS_VALID( list_kctx, jctx.sched_info.runpool.policy_ctx.cfs.list ) == MALI_TRUE)
+ {
+ OSK_DLIST_INSERT_BEFORE( queue_head,
+ kctx,
+ list_kctx,
+ kbase_context,
+ jctx.sched_info.runpool.policy_ctx.cfs.list );
+ }
+ else
+ {
+ OSK_DLIST_PUSH_BACK( queue_head,
+ kctx,
+ kbase_context,
+ jctx.sched_info.runpool.policy_ctx.cfs.list );
+ }
+}
+
+mali_bool kbasep_js_policy_dequeue_head_ctx( kbasep_js_policy *js_policy, kbase_context **kctx_ptr )
+{
+ kbasep_js_policy_cfs *policy_info;
+ kbase_context *head_ctx;
+ osk_dlist *queue_head;
+ int err;
+
+ OSK_ASSERT( js_policy != NULL );
+ OSK_ASSERT( kctx_ptr != NULL );
+
+ policy_info = &js_policy->cfs;
+
+ /* attempt to dequeue from the 'realttime' queue first */
+ if ( OSK_DLIST_IS_EMPTY( &policy_info->ctx_rt_queue_head ) != MALI_FALSE )
+ {
+ if ( OSK_DLIST_IS_EMPTY( &policy_info->ctx_queue_head ) != MALI_FALSE )
+ {
+ /* Nothing to dequeue */
+ return MALI_FALSE;
+ }
+ else
+ {
+ queue_head = &policy_info->ctx_queue_head;
+ }
+ }
+ else
+ {
+ queue_head = &policy_info->ctx_rt_queue_head;
+ }
+
+ /* Contexts are dequeued from the front of the queue */
+ *kctx_ptr = OSK_DLIST_POP_FRONT( queue_head,
+ kbase_context,
+ jctx.sched_info.runpool.policy_ctx.cfs.list, err );
+
+ {
+ kbase_device *kbdev = container_of( js_policy, kbase_device, js_data.policy );
+ kbase_context *kctx = *kctx_ptr;
+ KBASE_TRACE_ADD_REFCOUNT( kbdev, JS_POLICY_DEQUEUE_HEAD_CTX, kctx, NULL, 0u,
+ kbasep_js_policy_trace_get_refcnt( kbdev, kctx ));
+ }
+
+
+ /* Update the head runtime */
+ head_ctx = OSK_DLIST_FRONT( queue_head,
+ kbase_context,
+ jctx.sched_info.runpool.policy_ctx.cfs.list );
+ if (OSK_DLIST_IS_VALID( head_ctx, jctx.sched_info.runpool.policy_ctx.cfs.list ) == MALI_TRUE)
+ {
+ /* No need to hold the the runpool_irq.lock here for reading - the
+ * context is definitely not being updated in the runpool at this
+ * point. The queue_mutex held by the caller ensures the memory barrier. */
+ u64 head_runtime = head_ctx->jctx.sched_info.runpool.policy_ctx.cfs.runtime_us;
+
+ if (head_runtime > policy_info->head_runtime_us)
+ {
+ policy_info->head_runtime_us = head_runtime;
+ }
+ }
+
+ return MALI_TRUE;
+}
+
+mali_bool kbasep_js_policy_try_evict_ctx( kbasep_js_policy *js_policy, kbase_context *kctx )
+{
+ kbasep_js_policy_cfs_ctx *ctx_info;
+ kbasep_js_policy_cfs *policy_info;
+ mali_bool is_present;
+ osk_dlist *queue_head;
+ osk_dlist *qhead;
+
+ OSK_ASSERT( js_policy != NULL );
+ OSK_ASSERT( kctx != NULL );
+
+ policy_info = &js_policy->cfs;
+ ctx_info = &kctx->jctx.sched_info.runpool.policy_ctx.cfs;
+
+ if(ctx_info->process_rt_policy)
+ {
+ queue_head = &policy_info->ctx_rt_queue_head;
+ }
+ else
+ {
+ queue_head = &policy_info->ctx_queue_head;
+ }
+ qhead = queue_head;
+
+ is_present = OSK_DLIST_MEMBER_OF( qhead,
+ kctx,
+ jctx.sched_info.runpool.policy_ctx.cfs.list );
+
+ {
+ kbase_device *kbdev = container_of( js_policy, kbase_device, js_data.policy );
+ KBASE_TRACE_ADD_REFCOUNT_INFO( kbdev, JS_POLICY_TRY_EVICT_CTX, kctx, NULL, 0u,
+ kbasep_js_policy_trace_get_refcnt( kbdev, kctx ), is_present);
+ }
+
+ if ( is_present != MALI_FALSE )
+ {
+ int err;
+ kbase_context *head_ctx;
+ qhead = queue_head;
+ /* Remove the context */
+ OSK_DLIST_REMOVE( qhead,
+ kctx,
+ jctx.sched_info.runpool.policy_ctx.cfs.list, err );
+
+ qhead = queue_head;
+ /* Update the head runtime */
+ head_ctx = OSK_DLIST_FRONT( qhead,
+ kbase_context,
+ jctx.sched_info.runpool.policy_ctx.cfs.list );
+ if (OSK_DLIST_IS_VALID( head_ctx, jctx.sched_info.runpool.policy_ctx.cfs.list ) == MALI_TRUE)
+ {
+ /* No need to hold the the runpool_irq.lock here for reading - the
+ * context is definitely not being updated in the runpool at this
+ * point. The queue_mutex held by the caller ensures the memory barrier. */
+ u64 head_runtime = head_ctx->jctx.sched_info.runpool.policy_ctx.cfs.runtime_us;
+
+ if (head_runtime > policy_info->head_runtime_us)
+ {
+ policy_info->head_runtime_us = head_runtime;
+ }
+ }
+ }
+
+ return is_present;
+}
+
+void kbasep_js_policy_kill_all_ctx_jobs( kbasep_js_policy *js_policy, kbase_context *kctx )
+{
+ kbasep_js_policy_cfs *policy_info;
+ kbasep_js_policy_cfs_ctx *ctx_info;
+ u32 i;
+
+ OSK_ASSERT( js_policy != NULL );
+ OSK_ASSERT( kctx != NULL );
+
+ policy_info = &js_policy->cfs;
+ ctx_info = &kctx->jctx.sched_info.runpool.policy_ctx.cfs;
+
+ {
+ kbase_device *kbdev = container_of( js_policy, kbase_device, js_data.policy );
+ KBASE_TRACE_ADD_REFCOUNT( kbdev, JS_POLICY_KILL_ALL_CTX_JOBS, kctx, NULL, 0u,
+ kbasep_js_policy_trace_get_refcnt( kbdev, kctx ));
+ }
+
+ /* Kill jobs on each variant in turn */
+ for ( i = 0; i < policy_info->num_core_req_variants; ++i )
+ {
+ osk_dlist *job_list;
+ job_list = &ctx_info->job_list_head[i];
+
+ /* Call kbase_jd_cancel() on all kbase_jd_atoms in this list, whilst removing them from the list */
+ OSK_DLIST_EMPTY_LIST( job_list, kbase_jd_atom, sched_info.cfs.list, kbase_jd_cancel );
+ }
+
+}
+
+void kbasep_js_policy_runpool_add_ctx( kbasep_js_policy *js_policy, kbase_context *kctx )
+{
+ kbasep_js_policy_cfs *policy_info;
+ kbasep_js_device_data *js_devdata;
+ kbase_device *kbdev;
+
+ OSK_ASSERT( js_policy != NULL );
+ OSK_ASSERT( kctx != NULL );
+
+ policy_info = &js_policy->cfs;
+ js_devdata = container_of( js_policy, kbasep_js_device_data, policy );
+
+ kbdev = kctx->kbdev;
+
+ {
+ KBASE_TRACE_ADD_REFCOUNT( kbdev, JS_POLICY_RUNPOOL_ADD_CTX, kctx, NULL, 0u,
+ kbasep_js_policy_trace_get_refcnt_nolock( kbdev, kctx ));
+ }
+
+ /* ASSERT about scheduled-ness/queued-ness */
+ kbasep_js_debug_check( policy_info, kctx, KBASEP_JS_CHECK_NOTSCHEDULED );
+
+ /* All enqueued contexts go to the back of the runpool */
+ OSK_DLIST_PUSH_BACK( &policy_info->scheduled_ctxs_head,
+ kctx,
+ kbase_context,
+ jctx.sched_info.runpool.policy_ctx.cfs.list );
+
+ if ( timer_callback_should_run(kbdev) != MALI_FALSE
+ && policy_info->timer_running == MALI_FALSE )
+ {
+ hrtimer_start( &policy_info->scheduling_timer,
+ HR_TIMER_DELAY_NSEC( js_devdata->scheduling_tick_ns ),
+ HRTIMER_MODE_REL );
+
+ KBASE_TRACE_ADD( kbdev, JS_POLICY_TIMER_START, NULL, NULL, 0u, 0u );
+ policy_info->timer_running = MALI_TRUE;
+ }
+}
+
+void kbasep_js_policy_runpool_remove_ctx( kbasep_js_policy *js_policy, kbase_context *kctx )
+{
+ kbasep_js_policy_cfs *policy_info;
+
+ int err;
+
+ OSK_ASSERT( js_policy != NULL );
+ OSK_ASSERT( kctx != NULL );
+
+ policy_info = &js_policy->cfs;
+
+ {
+ kbase_device *kbdev = container_of( js_policy, kbase_device, js_data.policy );
+ KBASE_TRACE_ADD_REFCOUNT( kbdev, JS_POLICY_RUNPOOL_REMOVE_CTX, kctx, NULL, 0u,
+ kbasep_js_policy_trace_get_refcnt_nolock( kbdev, kctx ));
+ }
+
+ /* ASSERT about scheduled-ness/queued-ness */
+ kbasep_js_debug_check( policy_info, kctx, KBASEP_JS_CHECK_SCHEDULED );
+
+ /* No searching or significant list maintenance required to remove this context */
+ OSK_DLIST_REMOVE( &policy_info->scheduled_ctxs_head,
+ kctx,
+ jctx.sched_info.runpool.policy_ctx.cfs.list, err);
+}
+
+mali_bool kbasep_js_policy_should_remove_ctx( kbasep_js_policy *js_policy, kbase_context *kctx )
+{
+ kbasep_js_policy_cfs_ctx *ctx_info;
+ kbasep_js_policy_cfs *policy_info;
+ kbase_context *head_ctx;
+ kbasep_js_device_data *js_devdata;
+ osk_dlist *queue_head;
+
+ OSK_ASSERT( js_policy != NULL );
+ OSK_ASSERT( kctx != NULL );
+
+ policy_info = &js_policy->cfs;
+ ctx_info = &kctx->jctx.sched_info.runpool.policy_ctx.cfs;
+ js_devdata = container_of( js_policy, kbasep_js_device_data, policy );
+
+ if(ctx_info->process_rt_policy)
+ {
+ queue_head = &policy_info->ctx_rt_queue_head;
+ }
+ else
+ {
+ queue_head = &policy_info->ctx_queue_head;
+ }
+
+ head_ctx = OSK_DLIST_FRONT( queue_head,
+ kbase_context,
+ jctx.sched_info.runpool.policy_ctx.cfs.list );
+ if (OSK_DLIST_IS_VALID( head_ctx, jctx.sched_info.runpool.policy_ctx.cfs.list ) == MALI_TRUE)
+ {
+ u64 head_runtime_us = head_ctx->jctx.sched_info.runpool.policy_ctx.cfs.runtime_us;
+
+ if ((head_runtime_us + priority_weight(ctx_info, (u64)(js_devdata->ctx_timeslice_ns/1000u)))
+ < ctx_info->runtime_us)
+ {
+ /* The context is scheduled out if it's not the least-run context anymore.
+ * The "real" head runtime is used instead of the cached runtime so the current
+ * context is not scheduled out when there is less contexts than address spaces.
+ */
+ return MALI_TRUE;
+ }
+ }
+
+ return MALI_FALSE;
+}
+
+/*
+ * Job Chain Management
+ */
+
+mali_error kbasep_js_policy_init_job( const kbasep_js_policy *js_policy, const kbase_context *kctx, kbase_jd_atom *katom )
+{
+ const kbasep_js_policy_cfs *policy_info;
+
+ OSK_ASSERT( js_policy != NULL );
+ OSK_ASSERT( katom != NULL );
+ OSK_ASSERT( kctx != NULL );
+
+ policy_info = &js_policy->cfs;
+
+ /* Determine the job's index into the job list head, will return error if the
+ * atom is malformed and so is reported. */
+ return cached_variant_idx_init( policy_info, kctx, katom );
+}
+
+void kbasep_js_policy_register_job( kbasep_js_policy *js_policy, kbase_context *kctx, kbase_jd_atom *katom )
+{
+ kbasep_js_policy_cfs_ctx *ctx_info;
+
+ OSK_ASSERT( js_policy != NULL );
+ OSK_ASSERT( katom != NULL );
+ OSK_ASSERT( kctx != NULL );
+
+ ctx_info = &kctx->jctx.sched_info.runpool.policy_ctx.cfs;
+
+ /* Adjust context priority to include the new job */
+ ctx_info->bag_total_nr_atoms++;
+ ctx_info->bag_total_priority += katom->nice_prio;
+
+ /* Get average priority and convert to NICE range -20..19 */
+ if(ctx_info->bag_total_nr_atoms)
+ {
+ ctx_info->bag_priority = (ctx_info->bag_total_priority / ctx_info->bag_total_nr_atoms) - 20;
+ }
+}
+
+void kbasep_js_policy_deregister_job( kbasep_js_policy *js_policy, kbase_context *kctx, kbase_jd_atom *katom )
+{
+ kbasep_js_policy_cfs_ctx *ctx_info;
+
+ OSK_ASSERT( js_policy != NULL );
+ CSTD_UNUSED(js_policy);
+ OSK_ASSERT( katom != NULL );
+ OSK_ASSERT( kctx != NULL );
+
+ ctx_info = &kctx->jctx.sched_info.runpool.policy_ctx.cfs;
+
+ /* Adjust context priority to no longer include removed job */
+ OSK_ASSERT(ctx_info->bag_total_nr_atoms > 0);
+ ctx_info->bag_total_nr_atoms--;
+ ctx_info->bag_total_priority -= katom->nice_prio;
+ OSK_ASSERT(ctx_info->bag_total_priority >= 0);
+
+ /* Get average priority and convert to NICE range -20..19 */
+ if(ctx_info->bag_total_nr_atoms)
+ {
+ ctx_info->bag_priority = (ctx_info->bag_total_priority / ctx_info->bag_total_nr_atoms) - 20;
+ }
+}
+KBASE_EXPORT_TEST_API(kbasep_js_policy_deregister_job)
+
+mali_bool kbasep_js_policy_dequeue_job( kbase_device *kbdev,
+ int job_slot_idx,
+ kbase_jd_atom **katom_ptr )
+{
+ kbasep_js_device_data *js_devdata;
+ kbasep_js_policy_cfs *policy_info;
+ kbase_context *kctx;
+ u32 variants_supported;
+
+ OSK_ASSERT( kbdev != NULL );
+ OSK_ASSERT( katom_ptr != NULL );
+ OSK_ASSERT( job_slot_idx < BASE_JM_MAX_NR_SLOTS );
+
+ js_devdata = &kbdev->js_data;
+ policy_info = &js_devdata->policy.cfs;
+
+ /* Get the variants for this slot */
+ if ( kbasep_js_ctx_attr_is_attr_on_runpool( kbdev, KBASEP_JS_CTX_ATTR_NSS ) != MALI_FALSE )
+ {
+ /* NSS-state */
+ variants_supported = get_slot_to_variant_lookup( policy_info->slot_to_variant_lookup_nss_state, job_slot_idx );
+ }
+ else if ( kbdev->gpu_props.num_core_groups > 1
+ && kbasep_js_ctx_attr_is_attr_on_runpool( kbdev, KBASEP_JS_CTX_ATTR_COMPUTE_ALL_CORES ) != MALI_FALSE )
+ {
+ /* SS-allcore state, and there's more than one coregroup */
+ variants_supported = get_slot_to_variant_lookup( policy_info->slot_to_variant_lookup_ss_allcore_state, job_slot_idx );
+ }
+ else
+ {
+ /* SS-state */
+ variants_supported = get_slot_to_variant_lookup( policy_info->slot_to_variant_lookup_ss_state, job_slot_idx );
+ }
+
+ /* First pass through the runpool we consider the realtime priority jobs */
+ OSK_DLIST_FOREACH( &policy_info->scheduled_ctxs_head,
+ kbase_context,
+ jctx.sched_info.runpool.policy_ctx.cfs.list,
+ kctx )
+ {
+ if(kctx->jctx.sched_info.runpool.policy_ctx.cfs.process_rt_policy)
+ {
+ if(dequeue_job(kbdev, kctx, variants_supported, katom_ptr, job_slot_idx))
+ {
+ /* Realtime policy job matched */
+ return MALI_TRUE;
+ }
+ }
+ }
+
+ /* Second pass through the runpool we consider the non-realtime priority jobs */
+ OSK_DLIST_FOREACH( &policy_info->scheduled_ctxs_head,
+ kbase_context,
+ jctx.sched_info.runpool.policy_ctx.cfs.list,
+ kctx )
+ {
+ if(kctx->jctx.sched_info.runpool.policy_ctx.cfs.process_rt_policy == MALI_FALSE)
+ {
+ if(dequeue_job(kbdev, kctx, variants_supported, katom_ptr, job_slot_idx))
+ {
+ /* Non-realtime policy job matched */
+ return MALI_TRUE;
+ }
+ }
+ }
+
+ /* By this point, no contexts had a matching job */
+ return MALI_FALSE;
+}
+
+mali_bool kbasep_js_policy_dequeue_job_irq( kbase_device *kbdev,
+ int job_slot_idx,
+ kbase_jd_atom **katom_ptr )
+{
+ /* IRQ and non-IRQ variants of this are the same (though, the IRQ variant could be made faster) */
+
+ /* KBASE_TRACE_ADD_SLOT( kbdev, JS_POLICY_DEQUEUE_JOB_IRQ, NULL, NULL, 0u,
+ job_slot_idx); */
+ return kbasep_js_policy_dequeue_job( kbdev, job_slot_idx, katom_ptr );
+}
+
+
+void kbasep_js_policy_enqueue_job( kbasep_js_policy *js_policy, kbase_jd_atom *katom )
+{
+ kbasep_js_policy_cfs_job *job_info;
+ kbasep_js_policy_cfs_ctx *ctx_info;
+ kbase_context *parent_ctx;
+
+ OSK_ASSERT( js_policy != NULL );
+ OSK_ASSERT( katom != NULL );
+ parent_ctx = katom->kctx;
+ OSK_ASSERT( parent_ctx != NULL );
+
+ job_info = &katom->sched_info.cfs;
+ ctx_info = &parent_ctx->jctx.sched_info.runpool.policy_ctx.cfs;
+
+ {
+ kbase_device *kbdev = container_of( js_policy, kbase_device, js_data.policy );
+ KBASE_TRACE_ADD( kbdev, JS_POLICY_ENQUEUE_JOB, katom->kctx, katom, katom->jc,
+ 0 );
+ }
+
+ OSK_DLIST_PUSH_BACK( &ctx_info->job_list_head[job_info->cached_variant_idx],
+ katom,
+ kbase_jd_atom,
+ sched_info.cfs.list );
+}
+
+void kbasep_js_policy_log_job_result( kbasep_js_policy *js_policy, kbase_jd_atom *katom, u64 time_spent_us )
+{
+ kbasep_js_policy_cfs_ctx *ctx_info;
+ kbase_context *parent_ctx;
+ OSK_ASSERT( js_policy != NULL );
+ OSK_ASSERT( katom != NULL );
+ CSTD_UNUSED( js_policy );
+
+ parent_ctx = katom->kctx;
+ OSK_ASSERT( parent_ctx != NULL );
+
+ ctx_info = &parent_ctx->jctx.sched_info.runpool.policy_ctx.cfs;
+
+ ctx_info->runtime_us += priority_weight(ctx_info, time_spent_us);
+}
+
+mali_bool kbasep_js_policy_ctx_has_priority( kbasep_js_policy *js_policy, kbase_context *current_ctx, kbase_context *new_ctx )
+{
+ kbasep_js_policy_cfs_ctx *current_ctx_info;
+ kbasep_js_policy_cfs_ctx *new_ctx_info;
+
+ OSK_ASSERT( current_ctx != NULL );
+ OSK_ASSERT( new_ctx != NULL );
+ CSTD_UNUSED(js_policy);
+
+ current_ctx_info = ¤t_ctx->jctx.sched_info.runpool.policy_ctx.cfs;
+ new_ctx_info = &new_ctx->jctx.sched_info.runpool.policy_ctx.cfs;
+
+ if((current_ctx_info->process_rt_policy == MALI_FALSE) &&
+ (new_ctx_info->process_rt_policy == MALI_TRUE))
+ {
+ return MALI_TRUE;
+ }
+
+ if((current_ctx_info->process_rt_policy == new_ctx_info->process_rt_policy) &&
+ (current_ctx_info->bag_priority > new_ctx_info->bag_priority))
+ {
+ return MALI_TRUE;
+ }
+
+ return MALI_FALSE;
+}
diff --git a/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_js_policy_cfs.h b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_js_policy_cfs.h
new file mode 100644
index 0000000..92ebca4
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_js_policy_cfs.h
@@ -0,0 +1,162 @@
+/*
+ *
+ * (C) COPYRIGHT 2011-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_kbase_js_policy_cfs.h
+ * Completely Fair Job Scheduler Policy structure definitions
+ */
+
+#ifndef _KBASE_JS_POLICY_CFS_H_
+#define _KBASE_JS_POLICY_CFS_H_
+
+#define KBASE_JS_POLICY_AVAILABLE_CFS
+
+/** @addtogroup base_api
+ * @{ */
+/** @addtogroup base_kbase_api
+ * @{ */
+/** @addtogroup kbase_js_policy
+ * @{ */
+
+/**
+ * Internally, this policy keeps a few internal queues for different variants
+ * of core requirements, which are used to decide how to schedule onto the
+ * different job slots.
+ *
+ * Currently, one extra variant is supported: an NSS variant.
+ *
+ * Must be a power of 2 to keep the lookup math simple
+ */
+#define KBASEP_JS_MAX_NR_CORE_REQ_VARIANTS_LOG2 3
+#define KBASEP_JS_MAX_NR_CORE_REQ_VARIANTS (1u << KBASEP_JS_MAX_NR_CORE_REQ_VARIANTS_LOG2 )
+
+/** Bits needed in the lookup to support all slots */
+#define KBASEP_JS_VARIANT_LOOKUP_BITS_NEEDED (BASE_JM_MAX_NR_SLOTS * KBASEP_JS_MAX_NR_CORE_REQ_VARIANTS)
+/** Number of u32s needed in the lookup array to support all slots */
+#define KBASEP_JS_VARIANT_LOOKUP_WORDS_NEEDED ((KBASEP_JS_VARIANT_LOOKUP_BITS_NEEDED + 31) / 32)
+
+typedef struct kbasep_js_policy_cfs
+{
+ /** List of all contexts in the context queue. Hold
+ * kbasep_js_device_data::queue_mutex whilst accessing. */
+ osk_dlist ctx_queue_head;
+
+ /** List of all contexts in the realtime (priority) context queue */
+ osk_dlist ctx_rt_queue_head;
+
+ /** List of scheduled contexts. Hold kbasep_jd_device_data::runpool_irq::lock
+ * whilst accessing, which is a spinlock */
+ osk_dlist scheduled_ctxs_head;
+
+ /** Number of valid elements in the core_req_variants member, and the
+ * kbasep_js_policy_rr_ctx::job_list_head array */
+ u32 num_core_req_variants;
+
+ /** Variants of the core requirements */
+ kbasep_atom_req core_req_variants[KBASEP_JS_MAX_NR_CORE_REQ_VARIANTS];
+
+ /* Lookups per job slot against which core_req_variants match it */
+ u32 slot_to_variant_lookup_ss_state[KBASEP_JS_VARIANT_LOOKUP_WORDS_NEEDED];
+ u32 slot_to_variant_lookup_ss_allcore_state[KBASEP_JS_VARIANT_LOOKUP_WORDS_NEEDED];
+ u32 slot_to_variant_lookup_nss_state[KBASEP_JS_VARIANT_LOOKUP_WORDS_NEEDED];
+
+ /* The timer tick used for rescheduling jobs */
+ struct hrtimer scheduling_timer;
+
+ /* Is the timer running?
+ *
+ * The kbasep_js_device_data::runpool_irq::lock (a spinlock) must be held
+ * whilst accessing this */
+ mali_bool timer_running;
+
+ /* Number of us the least-run context has been running for
+ *
+ * The kbasep_js_device_data::queue_mutex must be held whilst updating this
+ * Reads are possible without this mutex, but an older value might be read
+ * if no memory barriers are issued beforehand. */
+ u64 head_runtime_us;
+ /* Pointer to the kbase_device structure, for convenience to avoid deeply nested container_of
+ * statements. */
+ kbase_device * kbdev;
+} kbasep_js_policy_cfs;
+
+/**
+ * This policy contains a single linked list of all contexts.
+ */
+typedef struct kbasep_js_policy_cfs_ctx
+{
+ /** Link implementing the Policy's Queue, and Currently Scheduled list */
+ osk_dlist_item list;
+
+ /** Job lists for use when in the Run Pool - only using
+ * kbasep_js_policy_fcfs::num_unique_slots of them. We still need to track
+ * the jobs when we're not in the runpool, so this member is accessed from
+ * outside the policy queue (for the first job), inside the policy queue,
+ * and inside the runpool.
+ *
+ * If the context is in the runpool, then this must only be accessed with
+ * kbasep_js_device_data::runpool_irq::lock held
+ *
+ * Jobs are still added to this list even when the context is not in the
+ * runpool. In that case, the kbasep_js_kctx_info::ctx::jsctx_mutex must be
+ * held before accessing this. */
+ osk_dlist job_list_head[KBASEP_JS_MAX_NR_CORE_REQ_VARIANTS];
+
+ /** Number of us this context has been running for
+ *
+ * The kbasep_js_device_data::runpool_irq::lock (a spinlock) must be held
+ * whilst updating this. Initializing will occur on context init and
+ * context enqueue (which can only occur in one thread at a time), but
+ * multi-thread access only occurs while the context is in the runpool.
+ *
+ * Reads are possible without this spinlock, but an older value might be read
+ * if no memory barriers are issued beforehand */
+ u64 runtime_us;
+
+ /* Calling process policy scheme is a realtime scheduler and will use the priority queue
+ * Non-mutable after ctx init */
+ mali_bool process_rt_policy;
+ /* Calling process NICE priority */
+ int process_priority;
+ /* Average NICE priority of all atoms in bag:
+ * Hold the kbasep_js_kctx_info::ctx::jsctx_mutex when accessing */
+ int bag_priority;
+ /* Total NICE priority of all atoms in bag
+ * Hold the kbasep_js_kctx_info::ctx::jsctx_mutex when accessing */
+ int bag_total_priority;
+ /* Total number of atoms in the bag
+ * Hold the kbasep_js_kctx_info::ctx::jsctx_mutex when accessing */
+ int bag_total_nr_atoms;
+
+} kbasep_js_policy_cfs_ctx;
+
+/**
+ * In this policy, each Job is part of at most one of the per_corereq lists
+ */
+typedef struct kbasep_js_policy_cfs_job
+{
+ osk_dlist_item list; /**< Link implementing the Run Pool list/Jobs owned by the ctx */
+ u32 cached_variant_idx; /**< Cached index of the list this should be entered into on re-queue */
+
+ /** Number of ticks that this job has been executing for
+ *
+ * To access this, the kbasep_js_device_data::runpool_irq::lock must be held */
+ u32 ticks;
+} kbasep_js_policy_cfs_job;
+
+/** @} */ /* end group kbase_js_policy */
+/** @} */ /* end group base_kbase_api */
+/** @} */ /* end group base_api */
+
+#endif
diff --git a/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_mem.c b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_mem.c
new file mode 100644
index 0000000..dfdbc72
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_mem.c
@@ -0,0 +1,2608 @@
+/*
+ *
+ * (C) COPYRIGHT 2010-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_kbase_mem.c
+ * Base kernel memory APIs
+ */
+#ifdef CONFIG_DMA_SHARED_BUFFER
+#include <linux/dma-buf.h>
+#endif /* CONFIG_DMA_SHARED_BUFFER */
+
+#include <osk/mali_osk.h>
+
+#include <kbase/mali_kbase_config.h>
+#include <kbase/src/common/mali_kbase.h>
+#include <kbase/src/common/mali_midg_regmap.h>
+#include <kbase/src/common/mali_kbase_cache_policy.h>
+#include <kbase/src/common/mali_kbase_hw.h>
+#include <kbase/src/common/mali_kbase_gator.h>
+
+#include <asm/atomic.h>
+#include <linux/debugfs.h>
+#include <linux/highmem.h>
+#include <linux/memblock.h>
+#include <linux/mm.h>
+#include <linux/seq_file.h>
+
+static unsigned long kbase_carveout_start_pfn = ~0UL;
+static unsigned long kbase_carveout_end_pfn;
+static LIST_HEAD(kbase_carveout_free_list);
+static DEFINE_MUTEX(kbase_carveout_free_list_lock);
+static unsigned int kbase_carveout_pages;
+static atomic_t kbase_carveout_used_pages;
+static atomic_t kbase_carveout_system_pages;
+
+static struct page *kbase_carveout_get_page(void)
+{
+ struct page *p = NULL;
+
+ mutex_lock(&kbase_carveout_free_list_lock);
+ if (!list_empty(&kbase_carveout_free_list)) {
+ p = list_first_entry(&kbase_carveout_free_list, struct page, lru);
+ list_del(&p->lru);
+ atomic_inc(&kbase_carveout_used_pages);
+ }
+ mutex_unlock(&kbase_carveout_free_list_lock);
+
+ if (!p) {
+ p = alloc_page(GFP_HIGHUSER);
+ if (p) {
+ atomic_inc(&kbase_carveout_system_pages);
+ }
+ }
+
+ return p;
+}
+
+static void kbase_carveout_put_page(struct page *p)
+{
+ if (page_to_pfn(p) >= kbase_carveout_start_pfn &&
+ page_to_pfn(p) <= kbase_carveout_end_pfn) {
+ mutex_lock(&kbase_carveout_free_list_lock);
+ list_add(&p->lru, &kbase_carveout_free_list);
+ atomic_dec(&kbase_carveout_used_pages);
+ mutex_unlock(&kbase_carveout_free_list_lock);
+ } else {
+ __free_page(p);
+ atomic_dec(&kbase_carveout_system_pages);
+ }
+}
+
+static int kbase_carveout_seq_show(struct seq_file *s, void *data)
+{
+ seq_printf(s, "carveout pages: %u\n", kbase_carveout_pages);
+ seq_printf(s, "used carveout pages: %u\n",
+ atomic_read(&kbase_carveout_used_pages));
+ seq_printf(s, "used system pages: %u\n",
+ atomic_read(&kbase_carveout_system_pages));
+ return 0;
+}
+
+static int kbasep_carveout_debugfs_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, kbase_carveout_seq_show, NULL);
+}
+
+static const struct file_operations kbase_carveout_debugfs_fops = {
+ .open = kbasep_carveout_debugfs_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release_private,
+};
+
+static int kbase_carveout_init(void)
+{
+ unsigned long pfn;
+
+ mutex_lock(&kbase_carveout_free_list_lock);
+
+ for (pfn = kbase_carveout_start_pfn; pfn <= kbase_carveout_end_pfn; pfn++) {
+ struct page *p = pfn_to_page(pfn);
+ list_add_tail(&p->lru, &kbase_carveout_free_list);
+ }
+
+ mutex_unlock(&kbase_carveout_free_list_lock);
+
+ debugfs_create_file("kbase_carveout", S_IRUGO, NULL, NULL,
+ &kbase_carveout_debugfs_fops);
+
+ return 0;
+}
+subsys_initcall(kbase_carveout_init);
+
+int __init kbase_carveout_mem_reserve(phys_addr_t size)
+{
+ phys_addr_t mem;
+
+ mem = memblock_alloc_base(size, PAGE_SIZE, MEMBLOCK_ALLOC_ANYWHERE);
+ if (mem == 0) {
+ pr_warning("%s: Failed to allocate %d for kbase carveout\n",
+ __func__, size);
+ return -ENOMEM;
+ }
+
+ kbase_carveout_start_pfn = page_to_pfn(phys_to_page(mem));
+ kbase_carveout_end_pfn = page_to_pfn(phys_to_page(mem + size - 1));
+ kbase_carveout_pages = kbase_carveout_end_pfn - kbase_carveout_start_pfn + 1;
+
+ return 0;
+}
+
+STATIC int kbase_mem_allocator_shrink(struct shrinker *s, struct shrink_control *sc)
+{
+ kbase_mem_allocator * allocator;
+ int i;
+ int freed;
+
+ allocator = container_of(s, kbase_mem_allocator, free_list_reclaimer);
+
+ if (sc->nr_to_scan == 0)
+ return atomic_read(&allocator->free_list_size);
+
+ might_sleep();
+
+ mutex_lock(&allocator->free_list_lock);
+
+ i = MIN(atomic_read(&allocator->free_list_size), sc->nr_to_scan);
+ freed = i;
+
+ atomic_sub(i, &allocator->free_list_size);
+
+ while (i--)
+ {
+ struct page * p;
+ BUG_ON(list_empty(&allocator->free_list_head));
+ p = list_first_entry(&allocator->free_list_head, struct page, lru);
+ list_del(&p->lru);
+ kbase_carveout_put_page(p);
+ }
+
+ mutex_unlock(&allocator->free_list_lock);
+
+ return atomic_read(&allocator->free_list_size);
+}
+
+mali_error kbase_mem_allocator_init(kbase_mem_allocator * const allocator, unsigned int max_size)
+{
+ OSK_ASSERT(NULL != allocator);
+
+ INIT_LIST_HEAD(&allocator->free_list_head);
+ mutex_init(&allocator->free_list_lock);
+ atomic_set(&allocator->free_list_size, 0);
+
+ allocator->free_list_max_size = max_size;
+
+ allocator->free_list_reclaimer.shrink = kbase_mem_allocator_shrink;
+ allocator->free_list_reclaimer.seeks = DEFAULT_SEEKS;
+ allocator->free_list_reclaimer.batch = 0;
+
+ register_shrinker(&allocator->free_list_reclaimer);
+
+ return MALI_ERROR_NONE;
+}
+
+void kbase_mem_allocator_term(kbase_mem_allocator *allocator)
+{
+ OSK_ASSERT(NULL != allocator);
+
+ unregister_shrinker(&allocator->free_list_reclaimer);
+
+ while (!list_empty(&allocator->free_list_head))
+ {
+ struct page * p;
+ p = list_first_entry(&allocator->free_list_head, struct page, lru);
+ list_del(&p->lru);
+ kbase_carveout_put_page(p);
+ }
+
+}
+
+mali_error kbase_mem_allocator_alloc(kbase_mem_allocator *allocator, u32 nr_pages, osk_phy_addr *pages, int flags)
+{
+ struct page * p;
+ struct page * tmp;
+ void * mp;
+ int i;
+ int num_from_free_list;
+ struct list_head from_free_list = LIST_HEAD_INIT(from_free_list);
+
+ might_sleep();
+
+ OSK_ASSERT(NULL != allocator);
+
+ /* take from the free list first */
+ mutex_lock(&allocator->free_list_lock);
+
+ num_from_free_list = MIN(nr_pages, atomic_read(&allocator->free_list_size));
+ atomic_sub(num_from_free_list, &allocator->free_list_size);
+
+ for (i = 0; i < num_from_free_list; i++)
+ {
+ BUG_ON(list_empty(&allocator->free_list_head));
+ p = list_first_entry(&allocator->free_list_head, struct page, lru);
+ list_move(&p->lru, &from_free_list);
+ }
+ mutex_unlock(&allocator->free_list_lock);
+
+ i = 0;
+ list_for_each_entry_safe(p, tmp, &from_free_list, lru)
+ {
+ if (flags & KBASE_REG_MUST_ZERO)
+ {
+ mp = kmap(p);
+ if (NULL == mp)
+ {
+ /* free the current page */
+ kbase_carveout_put_page(p);
+ /* put the rest back on the free list */
+ mutex_lock(&allocator->free_list_lock);
+ list_splice(&from_free_list, &allocator->free_list_head);
+ atomic_add(num_from_free_list - i - 1, &allocator->free_list_size);
+ mutex_unlock(&allocator->free_list_lock);
+ /* drop down to the normal Linux alloc */
+ break;
+ }
+ memset(mp, 0x00, PAGE_SIZE);
+ osk_sync_to_memory(PFN_PHYS(page_to_pfn(p)), mp, PAGE_SIZE);
+ kunmap(p);
+ }
+
+ pages[i] = PFN_PHYS(page_to_pfn(p));
+ i++;
+ }
+
+ if (i == nr_pages)
+ return MALI_ERROR_NONE;
+
+ for (; i < nr_pages; i++)
+ {
+ p = kbase_carveout_get_page();
+ if (NULL == p)
+ {
+ goto err_out_roll_back;
+ }
+
+ mp = kmap(p);
+ if (NULL == mp)
+ {
+ kbase_carveout_put_page(p);
+ goto err_out_roll_back;
+ }
+ memset(mp, 0x00, PAGE_SIZE); /* instead of __GFP_ZERO, so we can do cache maintenance */
+ osk_sync_to_memory(PFN_PHYS(page_to_pfn(p)), mp, PAGE_SIZE);
+ kunmap(p);
+ pages[i] = PFN_PHYS(page_to_pfn(p));
+ }
+
+ return MALI_ERROR_NONE;
+
+err_out_roll_back:
+ while (i--)
+ {
+ struct page * p;
+ p = pfn_to_page(PFN_DOWN(pages[i]));
+ pages[i] = (osk_phy_addr)0;
+ kbase_carveout_put_page(p);
+ }
+ return MALI_ERROR_OUT_OF_MEMORY;
+}
+
+void kbase_mem_allocator_free(kbase_mem_allocator *allocator, u32 nr_pages, osk_phy_addr *pages)
+{
+ int i = 0;
+ int page_count = 0;
+ int tofree;
+ LIST_HEAD(new_free_list_items);
+
+ OSK_ASSERT(NULL != allocator);
+
+ might_sleep();
+
+ /* Starting by just freeing the overspill.
+ * As we do this outside of the lock we might spill too many pages
+ * or get too many on the free list, but the max_size is just a ballpark so it is ok
+ */
+ tofree = atomic_read(&allocator->free_list_size) + nr_pages - allocator->free_list_max_size;
+ /* if tofree became negative this first for loop will be ignored */
+ for (; i < tofree; i++)
+ {
+ if (likely(0 != pages[i]))
+ {
+ struct page * p;
+ p = pfn_to_page(PFN_DOWN(pages[i]));
+ pages[i] = (osk_phy_addr)0;
+ kbase_carveout_put_page(p);
+ }
+ }
+
+ for (; i < nr_pages; i++)
+ {
+ if (likely(0 != pages[i]))
+ {
+ struct page * p;
+
+ p = pfn_to_page(PFN_DOWN(pages[i]));
+ pages[i] = (osk_phy_addr)0;
+ list_add(&p->lru, &new_free_list_items);
+ page_count++;
+ }
+ }
+
+ mutex_lock(&allocator->free_list_lock);
+ list_splice(&new_free_list_items, &allocator->free_list_head);
+ atomic_add(page_count, &allocator->free_list_size);
+ mutex_unlock(&allocator->free_list_lock);
+}
+
+/**
+ * @brief Check the zone compatibility of two regions.
+ */
+STATIC int kbase_region_tracker_match_zone(struct kbase_va_region *reg1, struct kbase_va_region *reg2)
+{
+ if (OSK_SIMULATE_FAILURE(OSK_BASE_MEM))
+ {
+ return MALI_FALSE;
+ }
+
+ return ((reg1->flags & KBASE_REG_ZONE_MASK) == (reg2->flags & KBASE_REG_ZONE_MASK));
+}
+KBASE_EXPORT_TEST_API(kbase_region_tracker_match_zone)
+
+/* This function inserts a region into the tree. */
+static void kbase_region_tracker_insert(
+ kbase_context *kctx,
+ struct kbase_va_region *new_reg )
+{
+ u64 start_pfn = new_reg->start_pfn;
+ struct rb_node **link = &(kctx->reg_rbtree.rb_node);
+ struct rb_node *parent = NULL;
+
+ /* Find the right place in the tree using tree search */
+ while (*link)
+ {
+ struct kbase_va_region * old_reg;
+
+ parent = *link;
+ old_reg = rb_entry(parent, struct kbase_va_region, rblink);
+
+ /* RBTree requires no duplicate entries. */
+ OSK_ASSERT( old_reg->start_pfn != start_pfn );
+
+ if (old_reg->start_pfn > start_pfn)
+ {
+ link = &(*link)->rb_left;
+ }
+ else
+ {
+ link = &(*link)->rb_right;
+ }
+ }
+
+ /* Put the new node there, and rebalance tree */
+ rb_link_node(&(new_reg->rblink), parent, link);
+ rb_insert_color( &(new_reg->rblink), &(kctx->reg_rbtree));
+}
+
+/* Find allocated region enclosing range. */
+struct kbase_va_region * kbase_region_tracker_find_region_enclosing_range(
+ kbase_context *kctx,
+ u64 start_pfn,
+ u32 nr_pages )
+{
+ struct rb_node * rbnode;
+ struct kbase_va_region *reg;
+ u64 end_pfn = start_pfn + nr_pages;
+
+ if (OSK_SIMULATE_FAILURE(OSK_BASE_MEM))
+ {
+ return NULL;
+ }
+
+ rbnode = kctx->reg_rbtree.rb_node;
+ while( rbnode )
+ {
+ u64 tmp_start_pfn, tmp_end_pfn;
+ reg = rb_entry( rbnode, struct kbase_va_region, rblink );
+ tmp_start_pfn = reg->start_pfn;
+ tmp_end_pfn = reg->start_pfn + reg->nr_alloc_pages;
+
+
+ /* If start is lower than this, go left. */
+ if (start_pfn < tmp_start_pfn )
+ {
+ rbnode = rbnode->rb_left;
+ }
+ /* If end is higher than this, then go right. */
+ else if ( end_pfn > tmp_end_pfn )
+ {
+ rbnode = rbnode->rb_right;
+ }
+ else /* Enclosing */
+ {
+ return reg;
+ }
+ }
+
+ return NULL;
+}
+
+/* Find allocated region enclosing free range. */
+struct kbase_va_region * kbase_region_tracker_find_region_enclosing_range_free(
+ kbase_context *kctx,
+ u64 start_pfn,
+ u32 nr_pages )
+{
+ struct rb_node * rbnode;
+ struct kbase_va_region *reg;
+ u64 end_pfn = start_pfn + nr_pages;
+
+ if (OSK_SIMULATE_FAILURE(OSK_BASE_MEM))
+ {
+ return NULL;
+ }
+
+ rbnode = kctx->reg_rbtree.rb_node;
+ while( rbnode )
+ {
+ u64 tmp_start_pfn, tmp_end_pfn;
+ reg = rb_entry( rbnode, struct kbase_va_region, rblink );
+ tmp_start_pfn = reg->start_pfn;
+ tmp_end_pfn = reg->start_pfn + reg->nr_pages;
+
+ /* If start is lower than this, go left. */
+ if (start_pfn < tmp_start_pfn )
+ {
+ rbnode = rbnode->rb_left;
+ }
+ /* If end is higher than this, then go right. */
+ else if ( end_pfn > tmp_end_pfn )
+ {
+ rbnode = rbnode->rb_right;
+ }
+ else /* Enclosing */
+ {
+ return reg;
+ }
+ }
+
+ return NULL;
+}
+
+/* Find region enclosing given address. */
+kbase_va_region *kbase_region_tracker_find_region_enclosing_address(
+ kbase_context *kctx,
+ mali_addr64 gpu_addr)
+{
+ struct rb_node * rbnode;
+ struct kbase_va_region *reg;
+ u64 gpu_pfn = gpu_addr >> PAGE_SHIFT;
+
+ OSK_ASSERT(NULL != kctx);
+
+ if (OSK_SIMULATE_FAILURE(OSK_BASE_MEM))
+ {
+ return NULL;
+ }
+
+ rbnode = kctx->reg_rbtree.rb_node;
+ while( rbnode )
+ {
+ u64 tmp_start_pfn, tmp_end_pfn;
+ reg = rb_entry( rbnode, struct kbase_va_region, rblink );
+ tmp_start_pfn = reg->start_pfn;
+ tmp_end_pfn = reg->start_pfn + reg->nr_pages;
+
+
+ /* If start is lower than this, go left. */
+ if (gpu_pfn < tmp_start_pfn )
+ {
+ rbnode = rbnode->rb_left;
+ }
+ /* If end is higher than this, then go right. */
+ else if ( gpu_pfn >= tmp_end_pfn )
+ {
+ rbnode = rbnode->rb_right;
+ }
+ else /* Enclosing */
+ {
+ return reg;
+ }
+ }
+
+ return NULL;
+}
+KBASE_EXPORT_TEST_API(kbase_region_tracker_find_region_enclosing_address)
+
+/* Find region with given base address */
+kbase_va_region *kbase_region_tracker_find_region_base_address(
+ kbase_context *kctx,
+ mali_addr64 gpu_addr)
+{
+ u64 gpu_pfn = gpu_addr >> PAGE_SHIFT;
+ struct rb_node * rbnode;
+ struct kbase_va_region *reg;
+
+ OSK_ASSERT(NULL != kctx);
+
+ if (OSK_SIMULATE_FAILURE(OSK_BASE_MEM))
+ {
+ return NULL;
+ }
+
+ rbnode = kctx->reg_rbtree.rb_node;
+ while(rbnode)
+ {
+ reg = rb_entry( rbnode, struct kbase_va_region, rblink );
+ if (reg->start_pfn > gpu_pfn )
+ {
+ rbnode = rbnode->rb_left;
+ }
+ else if (reg->start_pfn < gpu_pfn )
+ {
+ rbnode = rbnode->rb_right;
+ }
+ else if ( gpu_pfn == reg->start_pfn )
+ {
+ return reg;
+ }
+ else
+ {
+ rbnode = NULL;
+ }
+ }
+
+ return NULL;
+}
+KBASE_EXPORT_TEST_API(kbase_region_tracker_find_region_base_address)
+
+/* Find region meeting given requirements */
+static struct kbase_va_region * kbase_region_tracker_find_region_meeting_reqs(
+ kbase_context *kctx,
+ struct kbase_va_region *reg_reqs,
+ u32 nr_pages,
+ u32 align )
+{
+ struct rb_node * rbnode;
+ struct kbase_va_region *reg;
+
+ if (OSK_SIMULATE_FAILURE(OSK_BASE_MEM))
+ {
+ return NULL;
+ }
+
+ /* Note that this search is a linear search, as we do not have a target
+ address in mind, so does not benefit from the rbtree search */
+ rbnode = rb_first( &(kctx->reg_rbtree) );
+ while(rbnode)
+ {
+ reg = rb_entry( rbnode, struct kbase_va_region, rblink );
+ if( (reg->nr_pages >= nr_pages) &&
+ (reg->flags & KBASE_REG_FREE) &&
+ kbase_region_tracker_match_zone(reg, reg_reqs) )
+ {
+
+ /* Check alignment */
+ u64 start_pfn = (reg->start_pfn + align - 1) & ~(align - 1);
+ if( (start_pfn >= reg->start_pfn) &&
+ (start_pfn <= (reg->start_pfn + reg->nr_pages - 1) ) &&
+ ((start_pfn + nr_pages - 1) <= (reg->start_pfn + reg->nr_pages -1)) )
+ {
+ return reg;
+ }
+ }
+ rbnode = rb_next( rbnode );
+ }
+
+ return NULL;
+}
+
+/**
+ * @brief Remove a region object from the global list.
+ *
+ * The region reg is removed, possibly by merging with other free and
+ * compatible adjacent regions. It must be called with the context
+ * region lock held. The associated memory is not released (see
+ * kbase_free_alloced_region). Internal use only.
+ */
+STATIC mali_error kbase_remove_va_region(
+ kbase_context *kctx,
+ struct kbase_va_region *reg )
+{
+ struct rb_node *rbprev;
+ struct kbase_va_region *prev = NULL;
+ struct rb_node *rbnext;
+ struct kbase_va_region *next = NULL;
+
+ int merged_front = 0;
+ int merged_back = 0;
+ mali_error err = MALI_ERROR_NONE;
+
+ /* Try to merge with the previous block first */
+ rbprev = rb_prev( &(reg->rblink) );
+ if( rbprev )
+ {
+ prev = rb_entry( rbprev, struct kbase_va_region, rblink );
+ if ( (prev->flags & KBASE_REG_FREE) && kbase_region_tracker_match_zone(prev, reg) )
+ {
+ /* We're compatible with the previous VMA, merge with it */
+ prev->nr_pages += reg->nr_pages;
+ rb_erase(&(reg->rblink), &kctx->reg_rbtree);
+ reg = prev;
+ merged_front = 1;
+ }
+ }
+
+ /* Try to merge with the next block second */
+ /* Note we do the lookup here as the tree may have been rebalanced. */
+ rbnext = rb_next( &(reg->rblink) );
+ if( rbnext )
+ {
+ /* We're compatible with the next VMA, merge with it */
+ next = rb_entry( rbnext, struct kbase_va_region, rblink );
+ if ( (next->flags & KBASE_REG_FREE) && kbase_region_tracker_match_zone(next, reg) )
+ {
+ next->start_pfn = reg->start_pfn;
+ next->nr_pages += reg->nr_pages;
+ rb_erase(&(reg->rblink), &kctx->reg_rbtree);
+ merged_back = 1;
+ if (merged_front)
+ {
+ /* We already merged with prev, free it */
+ kbase_free_alloced_region( reg );
+ }
+ }
+ }
+
+ /* If we failed to merge then we need to add a new block */
+ if (!(merged_front || merged_back))
+ {
+ /*
+ * We didn't merge anything. Add a new free
+ * placeholder and remove the original one.
+ */
+ struct kbase_va_region *free_reg;
+
+ free_reg = kbase_alloc_free_region(kctx, reg->start_pfn, reg->nr_pages, reg->flags & KBASE_REG_ZONE_MASK);
+ if (!free_reg)
+ {
+ err = MALI_ERROR_OUT_OF_MEMORY;
+ goto out;
+ }
+
+ rb_replace_node( &(reg->rblink), &(free_reg->rblink), &(kctx->reg_rbtree) );
+ }
+
+out:
+ return err;
+}
+KBASE_EXPORT_TEST_API(kbase_remove_va_region)
+
+/**
+ * @brief Insert a VA region to the list, replacing the current at_reg.
+ */
+static mali_error kbase_insert_va_region_nolock(
+ kbase_context *kctx,
+ struct kbase_va_region *new_reg,
+ struct kbase_va_region *at_reg,
+ u64 start_pfn,
+ u32 nr_pages )
+{
+ mali_error err = MALI_ERROR_NONE;
+
+ /* Must be a free region */
+ OSK_ASSERT((at_reg->flags & KBASE_REG_FREE) != 0);
+ /* start_pfn should be contained within at_reg */
+ OSK_ASSERT((start_pfn >= at_reg->start_pfn) && (start_pfn < at_reg->start_pfn + at_reg->nr_pages));
+ /* at least nr_pages from start_pfn should be contained within at_reg */
+ OSK_ASSERT(start_pfn + nr_pages <= at_reg->start_pfn + at_reg->nr_pages );
+
+ new_reg->start_pfn = start_pfn;
+ new_reg->nr_pages = nr_pages;
+
+ /* Regions are a whole use, so swap and delete old one. */
+ if (at_reg->start_pfn == start_pfn && at_reg->nr_pages == nr_pages)
+ {
+ rb_replace_node( &(at_reg->rblink), &(new_reg->rblink), &(kctx->reg_rbtree) );
+ kbase_free_alloced_region(at_reg);
+ }
+ /* New region replaces the start of the old one, so insert before. */
+ else if (at_reg->start_pfn == start_pfn)
+ {
+ at_reg->start_pfn += nr_pages;
+ OSK_ASSERT(at_reg->nr_pages >= nr_pages);
+ at_reg->nr_pages -= nr_pages;
+
+ kbase_region_tracker_insert( kctx, new_reg );
+ }
+ /* New region replaces the end of the old one, so insert after. */
+ else if ((at_reg->start_pfn + at_reg->nr_pages) == (start_pfn + nr_pages))
+ {
+ at_reg->nr_pages -= nr_pages;
+
+ kbase_region_tracker_insert( kctx, new_reg );
+ }
+ /* New region splits the old one, so insert and create new */
+ else
+ {
+ struct kbase_va_region * new_front_reg = kbase_alloc_free_region(
+ kctx, at_reg->start_pfn, start_pfn - at_reg->start_pfn, at_reg->flags & KBASE_REG_ZONE_MASK );
+ if (new_front_reg)
+ {
+ at_reg->nr_pages -= nr_pages + new_front_reg->nr_pages;
+ at_reg->start_pfn = start_pfn + nr_pages;
+
+ kbase_region_tracker_insert( kctx, new_front_reg );
+ kbase_region_tracker_insert( kctx, new_reg );
+ }
+ else
+ {
+ err = MALI_ERROR_OUT_OF_MEMORY;
+ }
+ }
+
+ return err;
+}
+
+/**
+ * @brief Add a VA region to the list.
+ */
+mali_error kbase_add_va_region(
+ kbase_context *kctx,
+ struct kbase_va_region *reg,
+ mali_addr64 addr,
+ u32 nr_pages,
+ u32 align)
+{
+ struct kbase_va_region *tmp;
+ u64 gpu_pfn = addr >> PAGE_SHIFT;
+ mali_error err = MALI_ERROR_NONE;
+
+ OSK_ASSERT(NULL != kctx);
+ OSK_ASSERT(NULL != reg);
+
+ if (!align)
+ {
+ align = 1;
+ }
+
+ /* must be a power of 2 */
+ OSK_ASSERT((align & (align - 1)) == 0);
+ OSK_ASSERT( nr_pages > 0 );
+
+ /* Path 1: Map a specific address. Find the enclosing region, which *must* be free. */
+ if (gpu_pfn)
+ {
+ OSK_ASSERT(!(gpu_pfn & (align - 1)));
+
+ tmp = kbase_region_tracker_find_region_enclosing_range_free( kctx, gpu_pfn, nr_pages );
+ if( !tmp )
+ {
+ OSK_PRINT_WARN(OSK_BASE_MEM, "Enclosing region not found: %08x gpu_pfn, %u nr_pages", gpu_pfn, nr_pages );
+ err = MALI_ERROR_OUT_OF_GPU_MEMORY;
+ goto exit;
+ }
+
+ if(
+ (!kbase_region_tracker_match_zone(tmp, reg)) ||
+ (!(tmp->flags & KBASE_REG_FREE)) )
+ {
+ OSK_PRINT_WARN(OSK_BASE_MEM, "Zone mismatch: %d != %d", tmp->flags & KBASE_REG_ZONE_MASK, reg->flags & KBASE_REG_ZONE_MASK);
+ OSK_PRINT_WARN(OSK_BASE_MEM, "!(tmp->flags & KBASE_REG_FREE): tmp->start_pfn=0x%llx tmp->flags=0x%x tmp->nr_pages=0x%x gpu_pfn=0x%llx nr_pages=0x%x\n",
+ tmp->start_pfn, tmp->flags, tmp->nr_pages, gpu_pfn, nr_pages);
+ OSK_PRINT_WARN(OSK_BASE_MEM, "in function %s (%p, %p, 0x%llx, 0x%x, 0x%x)\n", __func__,
+ kctx,reg,addr, nr_pages, align);
+ err = MALI_ERROR_OUT_OF_GPU_MEMORY;
+ goto exit;
+ }
+
+ err = kbase_insert_va_region_nolock(kctx, reg, tmp, gpu_pfn, nr_pages);
+ if (err)
+ {
+ OSK_PRINT_WARN(OSK_BASE_MEM, "Failed to insert va region");
+ err = MALI_ERROR_OUT_OF_GPU_MEMORY;
+ goto exit;
+ }
+
+ goto exit;
+ }
+
+ /* Path 2: Map any free address which meets the requirements. */
+ {
+ u64 start_pfn;
+ tmp = kbase_region_tracker_find_region_meeting_reqs( kctx, reg, nr_pages, align );
+ if( !tmp )
+ {
+ err = MALI_ERROR_OUT_OF_GPU_MEMORY;
+ goto exit;
+ }
+ start_pfn = (tmp->start_pfn + align - 1) & ~(align - 1);
+ err = kbase_insert_va_region_nolock(kctx, reg, tmp, start_pfn, nr_pages);
+ }
+
+exit:
+ return err;
+}
+KBASE_EXPORT_TEST_API(kbase_add_va_region)
+
+/**
+ * @brief Initialize the internal region tracker data structure.
+ */
+static void kbase_region_tracker_ds_init(
+ kbase_context *kctx,
+ struct kbase_va_region *pmem_reg,
+ struct kbase_va_region *exec_reg,
+ struct kbase_va_region *tmem_reg )
+{
+ kctx->reg_rbtree = RB_ROOT;
+ kbase_region_tracker_insert( kctx, pmem_reg );
+ kbase_region_tracker_insert( kctx, exec_reg );
+ kbase_region_tracker_insert( kctx, tmem_reg );
+}
+
+void kbase_region_tracker_term(kbase_context *kctx)
+{
+ struct rb_node * rbnode;
+ struct kbase_va_region * reg;
+ do
+ {
+ rbnode = rb_first( &(kctx->reg_rbtree) );
+ if( rbnode )
+ {
+ rb_erase( rbnode, &(kctx->reg_rbtree) );
+ reg = rb_entry( rbnode, struct kbase_va_region, rblink );
+ kbase_free_alloced_region( reg );
+ }
+ } while( rbnode );
+}
+
+/**
+ * Initialize the region tracker data structure.
+ */
+mali_error kbase_region_tracker_init(kbase_context *kctx)
+{
+ struct kbase_va_region *pmem_reg;
+ struct kbase_va_region *exec_reg;
+ struct kbase_va_region *tmem_reg;
+
+ /* Make sure page 0 is not used... */
+ pmem_reg = kbase_alloc_free_region(
+ kctx, 1, KBASE_REG_ZONE_EXEC_BASE - 1, KBASE_REG_ZONE_PMEM);
+ if(!pmem_reg)
+ {
+ return MALI_ERROR_OUT_OF_MEMORY;
+ }
+
+ exec_reg = kbase_alloc_free_region(
+ kctx, KBASE_REG_ZONE_EXEC_BASE, KBASE_REG_ZONE_EXEC_SIZE, KBASE_REG_ZONE_EXEC);
+ if(!exec_reg)
+ {
+ kbase_free_alloced_region(pmem_reg);
+ return MALI_ERROR_OUT_OF_MEMORY;
+ }
+
+ tmem_reg = kbase_alloc_free_region(
+ kctx, KBASE_REG_ZONE_TMEM_BASE, KBASE_REG_ZONE_TMEM_SIZE, KBASE_REG_ZONE_TMEM);
+ if(!tmem_reg)
+ {
+ kbase_free_alloced_region(pmem_reg);
+ kbase_free_alloced_region(exec_reg);
+ return MALI_ERROR_OUT_OF_MEMORY;
+ }
+
+ kbase_region_tracker_ds_init(kctx, pmem_reg, exec_reg, tmem_reg);
+
+ return MALI_ERROR_NONE;
+}
+
+mali_error kbase_mem_init(kbase_device * kbdev)
+{
+ CSTD_UNUSED(kbdev);
+
+ if (OSK_SIMULATE_FAILURE(OSK_BASE_MEM))
+ {
+ return MALI_ERROR_OUT_OF_MEMORY;
+ }
+
+ /* nothing to do, zero-inited when kbase_device was created */
+ return MALI_ERROR_NONE;
+}
+
+void kbase_mem_halt(kbase_device * kbdev)
+{
+ CSTD_UNUSED(kbdev);
+}
+
+void kbase_mem_term(kbase_device * kbdev)
+{
+ kbasep_mem_device * memdev;
+ OSK_ASSERT(kbdev);
+
+ memdev = &kbdev->memdev;
+
+ kbase_mem_usage_term(&memdev->usage);
+}
+KBASE_EXPORT_TEST_API(kbase_mem_term)
+
+mali_error kbase_mem_usage_init(kbasep_mem_usage * usage, u32 max_pages)
+{
+ OSK_ASSERT(usage);
+
+ if (OSK_SIMULATE_FAILURE(OSK_BASE_MEM))
+ {
+ return MALI_ERROR_OUT_OF_MEMORY;
+ }
+
+ atomic_set(&usage->cur_pages, 0);
+ /* query the max page count */
+ usage->max_pages = max_pages;
+
+ return MALI_ERROR_NONE;
+}
+
+void kbase_mem_usage_term(kbasep_mem_usage * usage)
+{
+ OSK_ASSERT(usage);
+ /* No memory should be in use now */
+ OSK_ASSERT(0 == atomic_read(&usage->cur_pages));
+ /* So any new alloc requests will fail */
+ usage->max_pages = 0;
+ /* So we assert on double term */
+ atomic_set(&usage->cur_pages, INT_MAX);
+}
+
+mali_error kbase_mem_usage_request_pages(kbasep_mem_usage *usage, u32 nr_pages)
+{
+ int cur_pages;
+ int old_cur_pages;
+
+ OSK_ASSERT(usage);
+ OSK_ASSERT(nr_pages); /* 0 pages would be an error in the calling code */
+
+ if (OSK_SIMULATE_FAILURE(OSK_BASE_MEM))
+ {
+ return MALI_ERROR_OUT_OF_MEMORY;
+ }
+
+ /*
+ * Fetch the initial cur_pages value
+ * each loop iteration below fetches
+ * it as part of the store attempt
+ */
+ cur_pages = atomic_read(&usage->cur_pages);
+
+ /* this check allows the simple if test in the loop below */
+ if (usage->max_pages < nr_pages)
+ {
+ goto usage_cap_exceeded;
+ }
+
+ do
+ {
+ u32 new_cur_pages;
+
+ /* enough pages to fullfill the request? */
+ if (usage->max_pages - nr_pages < cur_pages)
+ {
+usage_cap_exceeded:
+ OSK_PRINT_WARN( OSK_BASE_MEM,
+ "Memory usage cap has been reached:\n"
+ "\t%lu pages currently used\n"
+ "\t%lu pages usage cap\n"
+ "\t%lu new pages requested\n"
+ "\twould result in %lu pages over the cap\n",
+ cur_pages,
+ usage->max_pages,
+ nr_pages,
+ cur_pages + nr_pages - usage->max_pages
+ );
+ return MALI_ERROR_OUT_OF_MEMORY;
+ }
+
+ /* try to atomically commit the new count */
+ old_cur_pages = cur_pages;
+ new_cur_pages = cur_pages + nr_pages;
+ cur_pages = atomic_cmpxchg(&usage->cur_pages, old_cur_pages, new_cur_pages);
+ /* cur_pages will be like old_cur_pages if there was no race */
+ } while (cur_pages != old_cur_pages);
+
+#ifdef CONFIG_MALI_GATOR_SUPPORT
+ kbase_trace_mali_total_alloc_pages_change((long long int)cur_pages);
+#endif /* CONFIG_MALI_GATOR_SUPPORT */
+
+ return MALI_ERROR_NONE;
+}
+KBASE_EXPORT_TEST_API(kbase_mem_usage_request_pages)
+
+void kbase_mem_usage_release_pages(kbasep_mem_usage * usage, u32 nr_pages)
+{
+ OSK_ASSERT(usage);
+ OSK_ASSERT(nr_pages <= atomic_read(&usage->cur_pages));
+
+ atomic_sub(nr_pages, &usage->cur_pages);
+#ifdef CONFIG_MALI_GATOR_SUPPORT
+ kbase_trace_mali_total_alloc_pages_change((long long int)atomic_read(&usage->cur_pages));
+#endif /* CONFIG_MALI_GATOR_SUPPORT */
+}
+KBASE_EXPORT_TEST_API(kbase_mem_usage_release_pages)
+
+/**
+ * @brief Wait for GPU write flush - only in use for BASE_HW_ISSUE_6367
+ *
+ * Wait 1000 GPU clock cycles. This delay is known to give the GPU time to flush its write buffer.
+ * @note If GPU resets occur then the counters are reset to zero, the delay may not be as expected.
+ */
+#ifdef CONFIG_MALI_NO_MALI
+static void kbase_wait_write_flush(kbase_context *kctx) { }
+#else /* CONFIG_MALI_NO_MALI */
+static void kbase_wait_write_flush(kbase_context *kctx)
+{
+ u32 base_count = 0;
+ kbase_pm_context_active(kctx->kbdev);
+ kbase_pm_request_gpu_cycle_counter(kctx->kbdev);
+ while( MALI_TRUE )
+ {
+ u32 new_count;
+ new_count = kbase_reg_read(kctx->kbdev, GPU_CONTROL_REG(CYCLE_COUNT_LO), NULL);
+ /* First time around, just store the count. */
+ if( base_count == 0 )
+ {
+ base_count = new_count;
+ continue;
+ }
+
+ /* No need to handle wrapping, unsigned maths works for this. */
+ if( (new_count - base_count) > 1000 )
+ {
+ break;
+ }
+ }
+ kbase_pm_release_gpu_cycle_counter(kctx->kbdev);
+ kbase_pm_context_idle(kctx->kbdev);
+}
+#endif /* CONFIG_MALI_NO_MALI */
+
+/**
+ * @brief Allocate a free region object.
+ *
+ * The allocated object is not part of any list yet, and is flagged as
+ * KBASE_REG_FREE. No mapping is allocated yet.
+ *
+ * zone is KBASE_REG_ZONE_TMEM, KBASE_REG_ZONE_PMEM, or KBASE_REG_ZONE_EXEC
+ *
+ */
+struct kbase_va_region *kbase_alloc_free_region(kbase_context *kctx, u64 start_pfn, u32 nr_pages, u32 zone)
+{
+ struct kbase_va_region *new_reg;
+
+ OSK_ASSERT(kctx != NULL);
+
+ /* zone argument should only contain zone related region flags */
+ OSK_ASSERT((zone & ~KBASE_REG_ZONE_MASK) == 0);
+ OSK_ASSERT(nr_pages > 0);
+ OSK_ASSERT( start_pfn + nr_pages <= (UINT64_MAX / PAGE_SIZE) ); /* 64-bit address range is the max */
+
+ if(OSK_SIMULATE_FAILURE(OSK_OSK))
+ {
+ new_reg = NULL;
+ }
+ else
+ {
+ new_reg = kzalloc(sizeof(*new_reg), GFP_KERNEL);
+ }
+
+ if (!new_reg)
+ {
+ OSK_PRINT_WARN(OSK_BASE_MEM, "kzalloc failed");
+ return NULL;
+ }
+
+ new_reg->kctx = kctx;
+ new_reg->flags = zone | KBASE_REG_FREE;
+
+ if ( KBASE_REG_ZONE_TMEM == zone || KBASE_REG_ZONE_EXEC == zone )
+ {
+ new_reg->flags |= KBASE_REG_GROWABLE;
+ }
+
+ /* not imported by default */
+ new_reg->imported_type = BASE_TMEM_IMPORT_TYPE_INVALID;
+
+ new_reg->start_pfn = start_pfn;
+ new_reg->nr_pages = nr_pages;
+ new_reg->nr_alloc_pages = 0;
+ OSK_DLIST_INIT(&new_reg->map_list);
+
+ return new_reg;
+}
+KBASE_EXPORT_TEST_API(kbase_alloc_free_region)
+
+/**
+ * @brief Free a region object.
+ *
+ * The described region must be freed of any mapping.
+ *
+ * If the region is not flagged as KBASE_REG_FREE, the destructor
+ * kbase_free_phy_pages() will be called.
+ */
+void kbase_free_alloced_region(struct kbase_va_region *reg)
+{
+ OSK_ASSERT(NULL != reg);
+ OSK_ASSERT(OSK_DLIST_IS_EMPTY(®->map_list));
+ if (!(reg->flags & KBASE_REG_FREE))
+ {
+ kbase_free_phy_pages(reg);
+ OSK_DEBUG_CODE(
+ /* To detect use-after-free in debug builds */
+ reg->flags |= KBASE_REG_FREE
+ );
+ }
+ kfree(reg);
+}
+KBASE_EXPORT_TEST_API(kbase_free_alloced_region)
+
+void kbase_mmu_update(kbase_context *kctx)
+{
+ /* Use GPU implementation-defined caching policy. */
+ u32 memattr = ASn_MEMATTR_IMPL_DEF_CACHE_POLICY;
+ u32 pgd_high;
+
+ OSK_ASSERT(NULL != kctx);
+ /* ASSERT that the context has a valid as_nr, which is only the case
+ * when it's scheduled in.
+ *
+ * as_nr won't change because the caller has the runpool_irq lock */
+ OSK_ASSERT( kctx->as_nr != KBASEP_AS_NR_INVALID );
+
+ pgd_high = sizeof(kctx->pgd)>4?(kctx->pgd >> 32):0;
+
+ kbase_reg_write(kctx->kbdev,
+ MMU_AS_REG(kctx->as_nr, ASn_TRANSTAB_LO),
+ (kctx->pgd & ASn_TRANSTAB_ADDR_SPACE_MASK) | ASn_TRANSTAB_READ_INNER
+ | ASn_TRANSTAB_ADRMODE_TABLE, kctx);
+
+ /* Need to use a conditional expression to avoid "right shift count >= width of type"
+ * error when using an if statement - although the size_of condition is evaluated at compile
+ * time the unused branch is not removed until after it is type-checked and the error
+ * produced.
+ */
+ pgd_high = sizeof(kctx->pgd)>4?(kctx->pgd >> 32):0;
+
+ kbase_reg_write(kctx->kbdev,
+ MMU_AS_REG(kctx->as_nr, ASn_TRANSTAB_HI),
+ pgd_high, kctx);
+
+ kbase_reg_write(kctx->kbdev,
+ MMU_AS_REG(kctx->as_nr, ASn_MEMATTR_LO),
+ memattr, kctx);
+ kbase_reg_write(kctx->kbdev,
+ MMU_AS_REG(kctx->as_nr, ASn_MEMATTR_HI),
+ memattr, kctx);
+ kbase_reg_write(kctx->kbdev,
+ MMU_AS_REG(kctx->as_nr, ASn_COMMAND),
+ ASn_COMMAND_UPDATE, kctx);
+}
+KBASE_EXPORT_TEST_API(kbase_mmu_update)
+
+void kbase_mmu_disable (kbase_context *kctx)
+{
+ OSK_ASSERT(NULL != kctx);
+ /* ASSERT that the context has a valid as_nr, which is only the case
+ * when it's scheduled in.
+ *
+ * as_nr won't change because the caller has the runpool_irq lock */
+ OSK_ASSERT( kctx->as_nr != KBASEP_AS_NR_INVALID );
+
+ kbase_reg_write(kctx->kbdev,
+ MMU_AS_REG(kctx->as_nr, ASn_TRANSTAB_LO),
+ 0, kctx);
+ kbase_reg_write(kctx->kbdev,
+ MMU_AS_REG(kctx->as_nr, ASn_TRANSTAB_HI),
+ 0, kctx);
+ kbase_reg_write(kctx->kbdev,
+ MMU_AS_REG(kctx->as_nr, ASn_COMMAND),
+ ASn_COMMAND_UPDATE, kctx);
+}
+KBASE_EXPORT_TEST_API(kbase_mmu_disable)
+
+mali_error kbase_gpu_mmap(kbase_context *kctx,
+ struct kbase_va_region *reg,
+ mali_addr64 addr, u32 nr_pages,
+ u32 align)
+{
+ mali_error err;
+ OSK_ASSERT(NULL != kctx);
+ OSK_ASSERT(NULL != reg);
+
+ err = kbase_add_va_region(kctx, reg, addr, nr_pages, align);
+ if (MALI_ERROR_NONE != err)
+ {
+ return err;
+ }
+
+ err = kbase_mmu_insert_pages(kctx, reg->start_pfn,
+ kbase_get_phy_pages(reg),
+ reg->nr_alloc_pages, reg->flags & ((1 << KBASE_REG_FLAGS_NR_BITS)-1));
+ if(MALI_ERROR_NONE != err)
+ {
+ kbase_remove_va_region(kctx, reg);
+ }
+
+ return err;
+}
+KBASE_EXPORT_TEST_API(kbase_gpu_mmap)
+
+mali_error kbase_gpu_munmap(kbase_context *kctx, struct kbase_va_region *reg)
+{
+ mali_error err;
+
+ if(reg->start_pfn == 0 )
+ {
+ return MALI_ERROR_NONE;
+ }
+ err = kbase_mmu_teardown_pages(kctx, reg->start_pfn, reg->nr_alloc_pages);
+ if(MALI_ERROR_NONE != err)
+ {
+ return err;
+ }
+
+ err = kbase_remove_va_region(kctx, reg);
+ return err;
+}
+
+/**
+ * @brief Find a mapping keyed with ptr in region reg
+ */
+STATIC struct kbase_cpu_mapping *kbase_find_cpu_mapping(struct kbase_va_region *reg,
+ const void *ptr)
+{
+ struct kbase_cpu_mapping *map;
+ OSK_ASSERT(NULL != reg);
+
+ if (OSK_SIMULATE_FAILURE(OSK_BASE_MEM))
+ {
+ return NULL;
+ }
+
+ OSK_DLIST_FOREACH(®->map_list, struct kbase_cpu_mapping, link, map)
+ {
+ if (map->private == ptr)
+ {
+ return map;
+ }
+ }
+
+ return NULL;
+}
+KBASE_EXPORT_TEST_API(kbase_find_cpu_mapping)
+
+STATIC struct kbase_cpu_mapping *kbasep_find_enclosing_cpu_mapping_of_region(
+ const struct kbase_va_region *reg,
+ osk_virt_addr uaddr,
+ size_t size)
+{
+ struct kbase_cpu_mapping *map;
+
+ OSK_ASSERT(NULL != reg);
+
+ if (OSK_SIMULATE_FAILURE(OSK_BASE_MEM))
+ {
+ return NULL;
+ }
+
+ if ((uintptr_t)uaddr + size < (uintptr_t)uaddr) /* overflow check */
+ {
+ return NULL;
+ }
+
+ OSK_DLIST_FOREACH(®->map_list, struct kbase_cpu_mapping, link, map)
+ {
+ if (map->uaddr <= uaddr && ((uintptr_t)map->uaddr + (map->nr_pages << PAGE_SHIFT)) >= ((uintptr_t)uaddr + size))
+ {
+ return map;
+ }
+ }
+
+ return NULL;
+}
+KBASE_EXPORT_TEST_API(kbasep_find_enclosing_cpu_mapping_of_region)
+
+static void kbase_dump_mappings(struct kbase_va_region *reg)
+{
+ struct kbase_cpu_mapping *map;
+
+ OSK_ASSERT(NULL != reg);
+
+ OSK_DLIST_FOREACH(®->map_list, struct kbase_cpu_mapping, link, map)
+ {
+ OSK_PRINT_WARN(OSK_BASE_MEM, "uaddr %p nr_pages %d page_off %016llx vma %p\n",
+ map->uaddr, map->nr_pages,
+ map->page_off, map->private);
+ }
+}
+
+/**
+ * @brief Delete a mapping keyed with ptr in region reg
+ */
+mali_error kbase_cpu_free_mapping(struct kbase_va_region *reg, const void *ptr)
+{
+ struct kbase_cpu_mapping *map;
+ mali_error err = MALI_ERROR_NONE;
+ int err_dummy;
+ OSK_ASSERT(NULL != reg);
+ map = kbase_find_cpu_mapping(reg, ptr);
+ if (!map)
+ {
+ OSK_PRINT_WARN(OSK_BASE_MEM, "Freeing unknown mapping %p in region %p\n", ptr, (void*)reg);
+ kbase_dump_mappings(reg);
+ err = MALI_ERROR_FUNCTION_FAILED;
+ goto out;
+ }
+
+ /* As the tmem is being unmapped we need to update the pages used by the process */
+ if ( (reg->flags & KBASE_REG_ZONE_MASK) == KBASE_REG_ZONE_TMEM )
+ {
+ kbase_process_page_usage_inc(reg->kctx, map->nr_pages);
+ }
+
+ OSK_DLIST_REMOVE(®->map_list, map, link, err_dummy);
+ kfree(map);
+
+ if ((reg->flags & KBASE_REG_DELAYED_FREE) && OSK_DLIST_IS_EMPTY(®->map_list))
+ {
+ err = kbase_mem_free_region(reg->kctx, reg);
+ }
+
+out:
+ return err;
+}
+KBASE_EXPORT_TEST_API(kbase_cpu_free_mapping)
+
+struct kbase_cpu_mapping *kbasep_find_enclosing_cpu_mapping(
+ kbase_context *kctx,
+ mali_addr64 gpu_addr,
+ osk_virt_addr uaddr,
+ size_t size )
+{
+ struct kbase_cpu_mapping *map = NULL;
+ const struct kbase_va_region *reg;
+
+ OSKP_ASSERT( kctx != NULL );
+
+ kbase_gpu_vm_lock(kctx);
+
+ reg = kbase_region_tracker_find_region_enclosing_address( kctx, gpu_addr );
+ if ( NULL != reg )
+ {
+ map = kbasep_find_enclosing_cpu_mapping_of_region( reg, uaddr, size );
+ }
+ kbase_gpu_vm_unlock(kctx);
+
+ return map;
+}
+KBASE_EXPORT_TEST_API(kbasep_find_enclosing_cpu_mapping)
+
+static mali_error kbase_do_syncset(kbase_context *kctx, base_syncset *set,
+ osk_sync_kmem_fn sync_fn)
+{
+ mali_error err = MALI_ERROR_NONE;
+ struct basep_syncset *sset = &set->basep_sset;
+ struct kbase_va_region *reg;
+ struct kbase_cpu_mapping *map;
+ osk_phy_addr *pa;
+ u64 page_off, page_count;
+ osk_virt_addr start;
+ size_t size;
+ u64 i;
+ u32 offset_within_page;
+ osk_phy_addr base_phy_addr = 0;
+ osk_virt_addr base_virt_addr = 0;
+ size_t area_size = 0;
+
+ kbase_os_mem_map_lock(kctx);
+
+ kbase_gpu_vm_lock(kctx);
+
+ /* find the region where the virtual address is contained */
+ reg = kbase_region_tracker_find_region_enclosing_address(kctx, sset->mem_handle);
+ if (!reg)
+ {
+ err = MALI_ERROR_FUNCTION_FAILED;
+ goto out_unlock;
+ }
+
+ if (!(reg->flags & KBASE_REG_CPU_CACHED))
+ {
+ goto out_unlock;
+ }
+
+ start = (osk_virt_addr)(uintptr_t)sset->user_addr;
+ size = sset->size;
+
+ map = kbasep_find_enclosing_cpu_mapping_of_region(reg, start, size);
+ if (!map)
+ {
+ err = MALI_ERROR_FUNCTION_FAILED;
+ goto out_unlock;
+ }
+
+ offset_within_page = (uintptr_t)start & (PAGE_SIZE - 1);
+ page_off = map->page_off + (((uintptr_t)start - (uintptr_t)map->uaddr) >> PAGE_SHIFT);
+ page_count = ((size + offset_within_page + (PAGE_SIZE - 1)) & PAGE_MASK) >> PAGE_SHIFT;
+ pa = kbase_get_phy_pages(reg);
+
+ for (i = 0; i < page_count; i++)
+ {
+ u32 offset = (uintptr_t)start & (PAGE_SIZE - 1);
+ osk_phy_addr paddr = pa[page_off + i] + offset;
+ size_t sz = OSK_MIN(((size_t)PAGE_SIZE - offset), size);
+
+ if (paddr == base_phy_addr + area_size &&
+ start == (osk_virt_addr)((uintptr_t)base_virt_addr + area_size))
+ {
+ area_size += sz;
+ }
+ else if (area_size > 0)
+ {
+ sync_fn(base_phy_addr, base_virt_addr, area_size);
+ area_size = 0;
+ }
+
+ if (area_size == 0)
+ {
+ base_phy_addr = paddr;
+ base_virt_addr = start;
+ area_size = sz;
+ }
+
+ start = (osk_virt_addr)((uintptr_t)start + sz);
+ size -= sz;
+ }
+
+ if (area_size > 0)
+ {
+ sync_fn(base_phy_addr, base_virt_addr, area_size);
+ }
+
+ OSK_ASSERT(size == 0);
+
+out_unlock:
+ kbase_gpu_vm_unlock(kctx);
+ kbase_os_mem_map_unlock(kctx);
+ return err;
+}
+
+static mali_error kbase_sync_to_memory(kbase_context *kctx, base_syncset *syncset)
+{
+ return kbase_do_syncset(kctx, syncset, osk_sync_to_memory);
+}
+
+static mali_error kbase_sync_to_cpu(kbase_context *kctx, base_syncset *syncset)
+{
+ return kbase_do_syncset(kctx, syncset, osk_sync_to_cpu);
+}
+
+mali_error kbase_sync_now(kbase_context *kctx, base_syncset *syncset)
+{
+ mali_error err = MALI_ERROR_FUNCTION_FAILED;
+ struct basep_syncset *sset;
+
+ OSK_ASSERT( NULL != kctx );
+ OSK_ASSERT( NULL != syncset );
+
+ sset = &syncset->basep_sset;
+
+ switch(sset->type)
+ {
+ case BASE_SYNCSET_OP_MSYNC:
+ err = kbase_sync_to_memory(kctx, syncset);
+ break;
+
+ case BASE_SYNCSET_OP_CSYNC:
+ err = kbase_sync_to_cpu(kctx, syncset);
+ break;
+
+ default:
+ OSK_PRINT_WARN(OSK_BASE_MEM, "Unknown msync op %d\n", sset->type);
+ break;
+ }
+
+ return err;
+}
+KBASE_EXPORT_TEST_API(kbase_sync_now)
+
+#ifdef CONFIG_DMA_SHARED_BUFFER
+static mali_bool is_actively_imported_umm(kbase_va_region *reg)
+{
+ if (reg->imported_type == BASE_TMEM_IMPORT_TYPE_UMM)
+ {
+ if (reg->imported_metadata.umm.current_mapping_usage_count > 0)
+ {
+ return MALI_TRUE;
+ }
+ }
+ return MALI_FALSE;
+}
+#else
+static mali_bool is_actively_imported_umm(kbase_va_region *reg)
+{
+ return MALI_FALSE;
+}
+#endif /* CONFIG_DMA_SHARED_BUFFER */
+
+/* vm lock must be held */
+mali_error kbase_mem_free_region(kbase_context *kctx,
+ kbase_va_region *reg)
+{
+ mali_error err;
+ OSK_ASSERT(NULL != kctx);
+ OSK_ASSERT(NULL != reg);
+ BUG_ON(!mutex_is_locked(&kctx->reg_lock));
+
+ if (!OSK_DLIST_IS_EMPTY(®->map_list) || is_actively_imported_umm(reg))
+ {
+ /*
+ * We still have mappings, can't free memory. This also handles the race condition with the unmap code
+ * (see kbase_cpu_vm_close()).
+ */
+ err = MALI_ERROR_NONE;
+ reg->flags |= KBASE_REG_DELAYED_FREE;
+ goto out;
+ }
+
+ err = kbase_gpu_munmap(kctx, reg);
+ if (err)
+ {
+ OSK_PRINT_WARN(OSK_BASE_MEM, "Could not unmap from the GPU...\n");
+ goto out;
+ }
+
+ if (kbase_hw_has_issue(kctx->kbdev, BASE_HW_ISSUE_6367))
+ {
+ /* Wait for GPU to flush write buffer before freeing physical pages */
+ kbase_wait_write_flush(kctx);
+ }
+
+ /* This will also free the physical pages */
+ kbase_free_alloced_region(reg);
+
+out:
+ return err;
+}
+KBASE_EXPORT_TEST_API(kbase_mem_free_region)
+
+/**
+ * @brief Free the region from the GPU and unregister it.
+ *
+ * This function implements the free operation on a memory segment.
+ * It will loudly fail if called with outstanding mappings.
+ */
+mali_error kbase_mem_free(kbase_context *kctx, mali_addr64 gpu_addr)
+{
+ mali_error err = MALI_ERROR_NONE;
+ struct kbase_va_region *reg;
+
+ OSK_ASSERT(kctx != NULL);
+
+ if (0 == gpu_addr)
+ {
+ OSK_PRINT_WARN(OSK_BASE_MEM, "gpu_addr 0 is reserved for the ringbuffer and it's an error to try to free it using kbase_mem_free\n");
+ return MALI_ERROR_FUNCTION_FAILED;
+ }
+ kbase_gpu_vm_lock(kctx);
+
+ if (gpu_addr < PAGE_SIZE)
+ {
+ /* an OS specific cookie, ask the OS specific code to validate it */
+ reg = kbase_lookup_cookie(kctx, gpu_addr);
+ if (!reg)
+ {
+ err = MALI_ERROR_FUNCTION_FAILED;
+ goto out_unlock;
+ }
+
+ /* ask to unlink the cookie as we'll free it */
+ kbase_unlink_cookie(kctx, gpu_addr, reg);
+
+ kbase_free_alloced_region(reg);
+ }
+ else
+ {
+ /* A real GPU va */
+
+ /* Validate the region */
+ reg = kbase_region_tracker_find_region_base_address(kctx, gpu_addr);
+ if (!reg)
+ {
+ OSK_ASSERT_MSG(0, "Trying to free nonexistent region\n 0x%llX", gpu_addr);
+ err = MALI_ERROR_FUNCTION_FAILED;
+ goto out_unlock;
+ }
+
+ err = kbase_mem_free_region(kctx, reg);
+ }
+
+out_unlock:
+ kbase_gpu_vm_unlock(kctx);
+ return err;
+}
+KBASE_EXPORT_TEST_API(kbase_mem_free)
+
+void kbase_update_region_flags(struct kbase_va_region *reg, u32 flags, mali_bool is_growable)
+{
+ OSK_ASSERT(NULL != reg);
+ OSK_ASSERT((flags & ~((1 << BASE_MEM_FLAGS_NR_BITS) - 1)) == 0);
+
+ reg->flags |= kbase_cache_enabled(flags, reg->nr_pages);
+
+ if ((flags & BASE_MEM_GROW_ON_GPF) || is_growable)
+ {
+ reg->flags |= KBASE_REG_GROWABLE;
+
+ if (flags & BASE_MEM_GROW_ON_GPF)
+ {
+ reg->flags |= KBASE_REG_PF_GROW;
+ }
+ }
+ else
+ {
+ /* As this region is not growable but the default is growable, we
+ explicitly clear the growable flag. */
+ reg->flags &= ~KBASE_REG_GROWABLE;
+ }
+
+ if (flags & BASE_MEM_PROT_CPU_WR)
+ {
+ reg->flags |= KBASE_REG_CPU_WR;
+ }
+
+ if (flags & BASE_MEM_PROT_CPU_RD)
+ {
+ reg->flags |= KBASE_REG_CPU_RD;
+ }
+
+ if (flags & BASE_MEM_PROT_GPU_WR)
+ {
+ reg->flags |= KBASE_REG_GPU_WR;
+ }
+
+ if (flags & BASE_MEM_PROT_GPU_RD)
+ {
+ reg->flags |= KBASE_REG_GPU_RD;
+ }
+
+ if (0 == (flags & BASE_MEM_PROT_GPU_EX))
+ {
+ reg->flags |= KBASE_REG_GPU_NX;
+ }
+
+ if (flags & BASE_MEM_COHERENT_LOCAL)
+ {
+ reg->flags |= KBASE_REG_SHARE_IN;
+ }
+ else if (flags & BASE_MEM_COHERENT_SYSTEM)
+ {
+ reg->flags |= KBASE_REG_SHARE_BOTH;
+ }
+
+ if (!(flags & BASE_MEM_DONT_ZERO_INIT))
+ {
+ reg->flags |= KBASE_REG_MUST_ZERO;
+ }
+}
+
+mali_error kbase_alloc_phy_pages_helper(struct kbase_va_region *reg, u32 nr_pages_requested)
+{
+ kbase_context * kctx;
+ osk_phy_addr * page_array;
+
+ OSK_ASSERT(reg);
+ /* Can't call this on TB buffers */
+ OSK_ASSERT(0 == (reg->flags & KBASE_REG_IS_TB));
+ /* can't be called on imported types */
+ OSK_ASSERT(BASE_TMEM_IMPORT_TYPE_INVALID == reg->imported_type);
+ /* Growth of too many pages attempted! (written this way to catch overflow)) */
+ OSK_ASSERT(reg->nr_pages - reg->nr_alloc_pages >= nr_pages_requested);
+ /* A complete commit is required if not marked as growable */
+ OSK_ASSERT((reg->flags & KBASE_REG_GROWABLE) || (reg->nr_pages == nr_pages_requested));
+
+ /* early out if nothing to do */
+ if (0 == nr_pages_requested)
+ return MALI_ERROR_NONE;
+
+ kctx = reg->kctx;
+ OSK_ASSERT(kctx);
+
+ if (MALI_ERROR_NONE != kbase_mem_usage_request_pages(&kctx->usage, nr_pages_requested))
+ {
+ return MALI_ERROR_OUT_OF_MEMORY;
+ }
+
+ page_array = kbase_get_phy_pages(reg);
+
+ if (MALI_ERROR_NONE != kbase_mem_allocator_alloc(&kctx->osalloc, nr_pages_requested, page_array + reg->nr_alloc_pages, reg->flags))
+ {
+ kbase_mem_usage_release_pages(&kctx->usage, nr_pages_requested);
+ return MALI_ERROR_OUT_OF_MEMORY;
+ }
+
+ reg->nr_alloc_pages += nr_pages_requested;
+
+ if ( (reg->flags & KBASE_REG_ZONE_MASK) == KBASE_REG_ZONE_TMEM)
+ {
+ kbase_process_page_usage_inc(kctx, nr_pages_requested);
+ }
+
+ return MALI_ERROR_NONE;
+}
+
+void kbase_free_phy_pages_helper(struct kbase_va_region * reg, u32 nr_pages_to_free)
+{
+ kbase_context * kctx;
+ osk_phy_addr * page_array;
+
+ OSK_ASSERT(reg);
+ /* Can't call this on TB buffers */
+ OSK_ASSERT(0 == (reg->flags & KBASE_REG_IS_TB));
+ /* can't be called on imported types */
+ OSK_ASSERT(BASE_TMEM_IMPORT_TYPE_INVALID == reg->imported_type);
+ /* Free of too many pages attempted! */
+ OSK_ASSERT(reg->nr_alloc_pages >= nr_pages_to_free);
+ /* A complete free is required if not marked as growable */
+ OSK_ASSERT((reg->flags & KBASE_REG_GROWABLE) || (reg->nr_alloc_pages == nr_pages_to_free));
+
+ /* early out if nothing to do */
+ if (0 == nr_pages_to_free)
+ return;
+
+ kctx = reg->kctx;
+ OSK_ASSERT(kctx);
+
+ page_array = kbase_get_phy_pages(reg);
+
+ kbase_mem_allocator_free(&kctx->osalloc, nr_pages_to_free, page_array + reg->nr_alloc_pages - nr_pages_to_free);
+
+ reg->nr_alloc_pages -= nr_pages_to_free;
+
+ if ( (reg->flags & KBASE_REG_ZONE_MASK) == KBASE_REG_ZONE_TMEM )
+ {
+ kbase_process_page_usage_dec(reg->kctx, nr_pages_to_free);
+ }
+ kbase_mem_usage_release_pages(®->kctx->usage, nr_pages_to_free);
+}
+
+KBASE_EXPORT_TEST_API(kbase_update_region_flags)
+
+/* Frees all allocated pages of a region */
+void kbase_free_phy_pages(struct kbase_va_region *reg)
+{
+ osk_phy_addr *page_array;
+ OSK_ASSERT(NULL != reg);
+
+ page_array = kbase_get_phy_pages(reg);
+
+ if (reg->imported_type != BASE_TMEM_IMPORT_TYPE_INVALID)
+ {
+ switch (reg->imported_type)
+ {
+#ifdef CONFIG_UMP
+ case BASE_TMEM_IMPORT_TYPE_UMP:
+ {
+ ump_dd_handle umph;
+ umph = (ump_dd_handle)reg->imported_metadata.ump_handle;
+ ump_dd_release(umph);
+ break;
+ }
+#endif /* CONFIG_UMP */
+#ifdef CONFIG_DMA_SHARED_BUFFER
+ case BASE_TMEM_IMPORT_TYPE_UMM:
+ {
+ dma_buf_detach(reg->imported_metadata.umm.dma_buf, reg->imported_metadata.umm.dma_attachment);
+ dma_buf_put(reg->imported_metadata.umm.dma_buf);
+ break;
+ }
+#endif /* CONFIG_DMA_SHARED_BUFFER */
+ default:
+ /* unsupported types should never reach this point */
+ OSK_ASSERT(0);
+ break;
+ }
+ reg->imported_type = BASE_TMEM_IMPORT_TYPE_INVALID;
+ }
+ else
+ {
+ if (reg->flags & KBASE_REG_IS_TB)
+ {
+ /* trace buffer being freed. Disconnect, then use vfree */
+ /* save tb so we can free it after the disconnect call */
+ void * tb;
+ tb = reg->kctx->jctx.tb;
+ kbase_device_trace_buffer_uninstall(reg->kctx);
+ vfree(tb);
+ }
+ else if (reg->flags & (KBASE_REG_IS_RB | KBASE_REG_IS_MMU_DUMP))
+ {
+ /* nothing to do */
+ }
+ else
+ {
+ kbase_free_phy_pages_helper(reg, reg->nr_alloc_pages);
+ }
+ }
+
+ kbase_set_phy_pages(reg, NULL);
+ vfree(page_array);
+}
+KBASE_EXPORT_TEST_API(kbase_free_phy_pages)
+
+int kbase_alloc_phy_pages(struct kbase_va_region *reg, u32 vsize, u32 size)
+{
+ osk_phy_addr *page_array;
+
+ OSK_ASSERT( NULL != reg );
+ OSK_ASSERT( vsize > 0 );
+
+ /* validate user provided arguments */
+ if (size > vsize || vsize > reg->nr_pages)
+ {
+ goto out_term;
+ }
+
+ /* Prevent vsize*sizeof from wrapping around.
+ * For instance, if vsize is 2**29+1, we'll allocate 1 byte and the alloc won't fail.
+ */
+ if ((size_t)vsize > ((size_t)-1 / sizeof(*page_array)))
+ {
+ goto out_term;
+ }
+
+ if(OSK_SIMULATE_FAILURE(OSK_OSK))
+ {
+ page_array = NULL;
+ }
+ else
+ {
+ OSK_ASSERT(0 != vsize);
+ page_array = vmalloc_user(vsize * sizeof(*page_array));
+ }
+
+ if (!page_array)
+ {
+ goto out_term;
+ }
+
+ kbase_set_phy_pages(reg, page_array);
+ reg->nr_alloc_pages = 0;
+
+ if (MALI_ERROR_NONE != kbase_alloc_phy_pages_helper(reg, size))
+ {
+ goto out_free;
+ }
+
+ return 0;
+
+out_free:
+ vfree(page_array);
+out_term:
+ return -1;
+}
+KBASE_EXPORT_TEST_API(kbase_alloc_phy_pages)
+
+/** @brief Round to +inf a tmem growable delta in pages */
+STATIC mali_bool kbasep_tmem_growable_round_delta( kbase_device *kbdev, s32 *delta_ptr )
+{
+ s32 delta;
+
+ OSK_ASSERT( delta_ptr != NULL );
+
+ if (OSK_SIMULATE_FAILURE(OSK_BASE_MEM))
+ {
+ return MALI_FALSE;
+ }
+
+ delta = *delta_ptr;
+
+ if (delta >= 0)
+ {
+ u32 new_delta_unsigned = kbasep_tmem_growable_round_size( kbdev, (u32)delta );
+ if ( new_delta_unsigned > S32_MAX )
+ {
+ /* Can't support a delta of this size */
+ return MALI_FALSE;
+ }
+
+ *delta_ptr = (s32)new_delta_unsigned;
+ }
+ else
+ {
+ u32 new_delta_unsigned = (u32)-delta;
+ /* Round down */
+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_9630))
+ {
+ new_delta_unsigned = new_delta_unsigned & ~(KBASEP_TMEM_GROWABLE_BLOCKSIZE_PAGES_HW_ISSUE_9630-1);
+ }
+ else if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8316))
+ {
+ new_delta_unsigned = new_delta_unsigned & ~(KBASEP_TMEM_GROWABLE_BLOCKSIZE_PAGES_HW_ISSUE_8316-1);
+ }
+ else
+ {
+ new_delta_unsigned = new_delta_unsigned & ~(KBASEP_TMEM_GROWABLE_BLOCKSIZE_PAGES-1);
+ }
+
+ *delta_ptr = (s32)-new_delta_unsigned;
+ }
+
+ return MALI_TRUE;
+}
+
+mali_bool kbase_check_alloc_flags(u32 flags)
+{
+ if (OSK_SIMULATE_FAILURE(OSK_BASE_MEM))
+ {
+ return MALI_FALSE;
+ }
+
+ /* Only known flags should be set. */
+ if (flags & ~((1 << BASE_MEM_FLAGS_NR_BITS) - 1))
+ {
+ return MALI_FALSE;
+ }
+ /* At least one flag should be set */
+ if (flags == 0)
+ {
+ return MALI_FALSE;
+ }
+ /* Either the GPU or CPU must be reading from the allocated memory */
+ if ((flags & (BASE_MEM_PROT_CPU_RD | BASE_MEM_PROT_GPU_RD)) == 0)
+ {
+ return MALI_FALSE;
+ }
+ /* Either the GPU or CPU must be writing to the allocated memory */
+ if ((flags & (BASE_MEM_PROT_CPU_WR | BASE_MEM_PROT_GPU_WR)) == 0)
+ {
+ return MALI_FALSE;
+ }
+ /* GPU cannot be writing to GPU executable memory and cannot grow the memory on page fault. */
+ if ((flags & BASE_MEM_PROT_GPU_EX) && (flags & (BASE_MEM_PROT_GPU_WR | BASE_MEM_GROW_ON_GPF)))
+ {
+ return MALI_FALSE;
+ }
+ /* GPU should have at least read or write access otherwise there is no
+ reason for allocating pmem/tmem. */
+ if ((flags & (BASE_MEM_PROT_GPU_RD | BASE_MEM_PROT_GPU_WR)) == 0)
+ {
+ return MALI_FALSE;
+ }
+
+ return MALI_TRUE;
+}
+
+struct kbase_va_region *kbase_tmem_alloc(kbase_context *kctx,
+ u32 vsize, u32 psize,
+ u32 extent, u32 flags, mali_bool is_growable)
+{
+ struct kbase_va_region *reg;
+ mali_error err;
+ u32 align = 1;
+ u32 vsize_rounded = vsize;
+ u32 psize_rounded = psize;
+ u32 extent_rounded = extent;
+ u32 zone = KBASE_REG_ZONE_TMEM;
+
+ if ( 0 == vsize )
+ {
+ goto out1;
+ }
+
+ OSK_ASSERT(NULL != kctx);
+
+ if (!kbase_check_alloc_flags(flags))
+ {
+ goto out1;
+ }
+
+ if ((flags & BASE_MEM_GROW_ON_GPF) != MALI_FALSE)
+ {
+ /* Round up the sizes for growable on GPU page fault memory */
+ vsize_rounded = kbasep_tmem_growable_round_size( kctx->kbdev, vsize );
+ psize_rounded = kbasep_tmem_growable_round_size( kctx->kbdev, psize );
+ extent_rounded = kbasep_tmem_growable_round_size( kctx->kbdev, extent );
+
+ if ( vsize_rounded < vsize || psize_rounded < psize || extent_rounded < extent )
+ {
+ /* values too large to round */
+ return NULL;
+ }
+ }
+
+ if (flags & BASE_MEM_PROT_GPU_EX)
+ {
+ zone = KBASE_REG_ZONE_EXEC;
+ }
+
+ if ( extent > 0 && !(flags & BASE_MEM_GROW_ON_GPF))
+ {
+ OSK_PRINT_WARN(OSK_BASE_MEM, "BASE_MEM_GROW_ON_GPF flag not set when extent is greater than 0");
+ goto out1;
+ }
+
+ reg = kbase_alloc_free_region(kctx, 0, vsize_rounded, zone);
+ if (!reg)
+ {
+ goto out1;
+ }
+
+ reg->flags &= ~KBASE_REG_FREE;
+
+ kbase_update_region_flags(reg, flags, is_growable);
+
+ if (kbase_alloc_phy_pages(reg, vsize_rounded, psize_rounded))
+ {
+ goto out2;
+ }
+
+ reg->nr_alloc_pages = psize_rounded;
+ reg->extent = extent_rounded;
+
+ kbase_gpu_vm_lock(kctx);
+ err = kbase_gpu_mmap(kctx, reg, 0, vsize_rounded, align);
+ kbase_gpu_vm_unlock(kctx);
+
+ if (err)
+ {
+ OSK_PRINT_WARN(OSK_BASE_MEM, "kbase_gpu_mmap failed\n");
+ goto out3;
+ }
+
+ return reg;
+
+out3:
+ kbase_free_phy_pages(reg);
+out2:
+ kfree(reg);
+out1:
+ return NULL;
+}
+KBASE_EXPORT_TEST_API(kbase_tmem_alloc)
+
+mali_error kbase_tmem_resize(kbase_context *kctx, mali_addr64 gpu_addr, s32 delta, u32 *size, base_backing_threshold_status * failure_reason)
+{
+ kbase_va_region *reg;
+ mali_error ret = MALI_ERROR_FUNCTION_FAILED;
+ osk_phy_addr *phy_pages;
+
+ OSK_ASSERT(NULL != kctx);
+ OSK_ASSERT(size);
+ OSK_ASSERT(failure_reason);
+ OSK_ASSERT(gpu_addr != 0);
+
+ kbase_gpu_vm_lock(kctx);
+
+ /* Validate the region */
+ reg = kbase_region_tracker_find_region_base_address(kctx, gpu_addr);
+ if (!reg || (reg->flags & KBASE_REG_FREE) )
+ {
+ /* not a valid region or is free memory*/
+ *failure_reason = BASE_BACKING_THRESHOLD_ERROR_INVALID_ARGUMENTS;
+ goto out_unlock;
+ }
+
+ if (!( (KBASE_REG_ZONE_MASK & reg->flags) == KBASE_REG_ZONE_TMEM ||
+ (KBASE_REG_ZONE_MASK & reg->flags) == KBASE_REG_ZONE_EXEC ) )
+ {
+ /* not a valid region - not tmem or exec region */
+ *failure_reason = BASE_BACKING_THRESHOLD_ERROR_INVALID_ARGUMENTS;
+ goto out_unlock;
+ }
+ if (0 == (reg->flags & KBASE_REG_GROWABLE))
+ {
+ /* not growable */
+ *failure_reason = BASE_BACKING_THRESHOLD_ERROR_NOT_GROWABLE;
+ goto out_unlock;
+ }
+
+ if ( (delta != 0) && !OSK_DLIST_IS_EMPTY(®->map_list))
+ {
+ /* We still have mappings */
+ *failure_reason = BASE_BACKING_THRESHOLD_ERROR_MAPPED;
+ goto out_unlock;
+ }
+
+ if ( reg->flags & KBASE_REG_PF_GROW )
+ {
+ /* Apply rounding to +inf on the delta, which may cause a negative delta to become zero */
+ if ( kbasep_tmem_growable_round_delta( kctx->kbdev, &delta ) == MALI_FALSE )
+ {
+ /* Can't round this big a delta */
+ *failure_reason = BASE_BACKING_THRESHOLD_ERROR_INVALID_ARGUMENTS;
+ goto out_unlock;
+ }
+ }
+
+ if (delta < 0 && (u32)-delta > reg->nr_alloc_pages)
+ {
+ /* Underflow */
+ *failure_reason = BASE_BACKING_THRESHOLD_ERROR_INVALID_ARGUMENTS;
+ goto out_unlock;
+ }
+ if (reg->nr_alloc_pages + delta > reg->nr_pages)
+ {
+ /* Would overflow the VA region */
+ *failure_reason = BASE_BACKING_THRESHOLD_ERROR_INVALID_ARGUMENTS;
+ goto out_unlock;
+ }
+
+ phy_pages = kbase_get_phy_pages(reg);
+
+ if (delta > 0)
+ {
+ mali_error err;
+
+ /* Allocate some more pages */
+ if (MALI_ERROR_NONE != kbase_alloc_phy_pages_helper(reg, delta))
+ {
+ *failure_reason = BASE_BACKING_THRESHOLD_ERROR_OOM;
+ goto out_unlock;
+ }
+ err = kbase_mmu_insert_pages(kctx, reg->start_pfn + reg->nr_alloc_pages - delta,
+ phy_pages + reg->nr_alloc_pages - delta,
+ delta, reg->flags);
+ if(MALI_ERROR_NONE != err)
+ {
+ kbase_free_phy_pages_helper(reg, delta);
+ *failure_reason = BASE_BACKING_THRESHOLD_ERROR_OOM;
+ goto out_unlock;
+ }
+ }
+ else if (delta < 0)
+ {
+ mali_error err;
+ /* Free some pages */
+
+ /* Get the absolute value of delta. Note that we have to add one before and after the negation to avoid
+ * overflowing when delta is INT_MIN */
+ u32 num_pages = (u32)(-(delta+1))+1;
+
+ err = kbase_mmu_teardown_pages(kctx, reg->start_pfn + reg->nr_alloc_pages - num_pages, num_pages);
+ if(MALI_ERROR_NONE != err)
+ {
+ *failure_reason = BASE_BACKING_THRESHOLD_ERROR_OOM;
+ goto out_unlock;
+ }
+
+ if (kbase_hw_has_issue(kctx->kbdev, BASE_HW_ISSUE_6367))
+ {
+ /* Wait for GPU to flush write buffer before freeing physical pages */
+ kbase_wait_write_flush(kctx);
+ }
+
+ kbase_free_phy_pages_helper(reg, num_pages);
+ }
+ /* else just a size query */
+
+ *size = reg->nr_alloc_pages;
+
+ ret = MALI_ERROR_NONE;
+
+out_unlock:
+ kbase_gpu_vm_unlock(kctx);
+ return ret;
+}
+KBASE_EXPORT_TEST_API(kbase_tmem_resize)
+
+
+mali_error kbase_tmem_set_size(kbase_context *kctx, mali_addr64 gpu_addr, u32 size, u32 *actual_size, base_backing_threshold_status * failure_reason)
+{
+ u32 delta = 0;
+ kbase_va_region *reg;
+ mali_error ret = MALI_ERROR_FUNCTION_FAILED;
+ osk_phy_addr *phy_pages;
+
+ OSK_ASSERT(NULL != kctx);
+ OSK_ASSERT(NULL != actual_size);
+ OSK_ASSERT(failure_reason);
+ OSK_ASSERT(gpu_addr != 0);
+
+ kbase_gpu_vm_lock(kctx);
+
+ /* Validate the region */
+ reg = kbase_region_tracker_find_region_base_address(kctx, gpu_addr);
+ if (!reg || (reg->flags & KBASE_REG_FREE) )
+ {
+ *failure_reason = BASE_BACKING_THRESHOLD_ERROR_INVALID_ARGUMENTS;
+ goto out_unlock;
+ }
+
+ if (!( (KBASE_REG_ZONE_MASK & reg->flags) == KBASE_REG_ZONE_TMEM ||
+ (KBASE_REG_ZONE_MASK & reg->flags) == KBASE_REG_ZONE_EXEC ) )
+ {
+ /* not a valid region - not tmem or exec region */
+ *failure_reason = BASE_BACKING_THRESHOLD_ERROR_INVALID_ARGUMENTS;
+ goto out_unlock;
+ }
+ if (0 == (reg->flags & KBASE_REG_GROWABLE))
+ {
+ *actual_size = reg->nr_alloc_pages;
+ *failure_reason = BASE_BACKING_THRESHOLD_ERROR_NOT_GROWABLE;
+ goto out_unlock;
+ }
+
+ if ( !OSK_DLIST_IS_EMPTY(®->map_list) )
+ {
+ /* We still have mappings */
+ *failure_reason = BASE_BACKING_THRESHOLD_ERROR_MAPPED;
+ goto out_unlock;
+ }
+
+ if ( size && reg->flags & KBASE_REG_PF_GROW )
+ {
+ size = kbasep_tmem_growable_round_size( kctx->kbdev, size );
+ /* check for rounding overflow */
+ if ( !size )
+ {
+ *failure_reason = BASE_BACKING_THRESHOLD_ERROR_INVALID_ARGUMENTS;
+ goto out_unlock;
+ }
+ }
+
+ if ( size > reg->nr_pages )
+ {
+ /* Would overflow the VA region */
+ *failure_reason = BASE_BACKING_THRESHOLD_ERROR_INVALID_ARGUMENTS;
+ goto out_unlock;
+ }
+
+ phy_pages = kbase_get_phy_pages(reg);
+
+ if ( size > reg->nr_alloc_pages )
+ {
+ mali_error err;
+ delta = size-reg->nr_alloc_pages;
+ /* Allocate some more pages */
+
+ if (MALI_ERROR_NONE != kbase_alloc_phy_pages_helper(reg, delta))
+ {
+ *failure_reason = BASE_BACKING_THRESHOLD_ERROR_OOM;
+ goto out_unlock;
+ }
+ err = kbase_mmu_insert_pages(kctx, reg->start_pfn + reg->nr_alloc_pages - delta,
+ phy_pages + reg->nr_alloc_pages - delta,
+ delta, reg->flags);
+ if(MALI_ERROR_NONE != err)
+ {
+ kbase_free_phy_pages_helper(reg, delta);
+ *failure_reason = BASE_BACKING_THRESHOLD_ERROR_OOM;
+ goto out_unlock;
+ }
+ }
+ else if (size < reg->nr_alloc_pages )
+ {
+ mali_error err;
+ delta = reg->nr_alloc_pages-size;
+
+ /* Free some pages */
+ err = kbase_mmu_teardown_pages(kctx, reg->start_pfn + reg->nr_alloc_pages - delta, delta);
+ if(MALI_ERROR_NONE != err)
+ {
+ *failure_reason = BASE_BACKING_THRESHOLD_ERROR_OOM;
+ goto out_unlock;
+ }
+
+ if (kbase_hw_has_issue(kctx->kbdev, BASE_HW_ISSUE_6367))
+ {
+ /* Wait for GPU to flush write buffer before freeing physical pages */
+ kbase_wait_write_flush(kctx);
+ }
+
+ kbase_free_phy_pages_helper(reg, delta);
+ }
+
+ *actual_size = reg->nr_alloc_pages;
+
+ ret = MALI_ERROR_NONE;
+
+out_unlock:
+ kbase_gpu_vm_unlock(kctx);
+
+ return ret;
+}
+KBASE_EXPORT_TEST_API(kbase_tmem_set_size)
+
+mali_error kbase_tmem_get_size(kbase_context *kctx, mali_addr64 gpu_addr, u32 *actual_size )
+{
+ kbase_va_region *reg;
+ mali_error ret = MALI_ERROR_FUNCTION_FAILED;
+
+ OSK_ASSERT(NULL != kctx);
+ OSK_ASSERT(NULL != actual_size);
+ OSK_ASSERT(gpu_addr != 0);
+
+ kbase_gpu_vm_lock(kctx);
+
+ /* Validate the region */
+ reg = kbase_region_tracker_find_region_base_address(kctx, gpu_addr);
+ if (!reg || (reg->flags & KBASE_REG_FREE) )
+ {
+ goto out_unlock;
+ }
+
+ *actual_size = reg->nr_alloc_pages;
+
+ ret = MALI_ERROR_NONE;
+
+out_unlock:
+ kbase_gpu_vm_unlock(kctx);
+ return ret;
+}
+KBASE_EXPORT_TEST_API(kbase_tmem_get_size)
+
+#ifdef CONFIG_UMP
+
+static struct kbase_va_region *kbase_tmem_from_ump(kbase_context *kctx, ump_secure_id id, u64 * const pages)
+{
+ struct kbase_va_region *reg;
+ mali_error err;
+ ump_dd_handle umph;
+ u64 vsize;
+ u64 block_count;
+ const ump_dd_physical_block_64 * block_array;
+ osk_phy_addr *page_array;
+ u64 i, j;
+ int page = 0;
+ ump_alloc_flags ump_flags;
+ ump_alloc_flags cpu_flags;
+ ump_alloc_flags gpu_flags;
+
+ OSK_ASSERT(NULL != pages);
+
+ umph = ump_dd_from_secure_id(id);
+ if (UMP_DD_INVALID_MEMORY_HANDLE == umph)
+ {
+ return NULL;
+ }
+
+ ump_flags = ump_dd_allocation_flags_get(umph);
+ cpu_flags = (ump_flags >> UMP_DEVICE_CPU_SHIFT) & UMP_DEVICE_MASK;
+ gpu_flags = (ump_flags >> kctx->kbdev->memdev.ump_device_id) & UMP_DEVICE_MASK;
+
+ vsize = ump_dd_size_get_64(umph);
+ vsize >>= PAGE_SHIFT;
+
+ reg = kbase_alloc_free_region(kctx, 0, vsize, KBASE_REG_ZONE_TMEM);
+ if (!reg)
+ {
+ goto out1;
+ }
+
+ reg->flags &= ~KBASE_REG_FREE;
+ reg->flags |= KBASE_REG_GPU_NX; /* UMP is always No eXecute */
+ reg->flags &= ~KBASE_REG_GROWABLE; /* UMP cannot be grown */
+
+ reg->imported_type = BASE_TMEM_IMPORT_TYPE_UMP;
+
+ reg->imported_metadata.ump_handle = umph;
+
+ if ((cpu_flags & (UMP_HINT_DEVICE_RD|UMP_HINT_DEVICE_WR)) == (UMP_HINT_DEVICE_RD|UMP_HINT_DEVICE_WR))
+ {
+ reg->flags |= KBASE_REG_CPU_CACHED;
+ }
+
+ if (cpu_flags & UMP_PROT_DEVICE_WR)
+ {
+ reg->flags |= KBASE_REG_CPU_WR;
+ }
+
+ if (cpu_flags & UMP_PROT_DEVICE_RD)
+ {
+ reg->flags |= KBASE_REG_CPU_RD;
+ }
+
+
+ if ((gpu_flags & (UMP_HINT_DEVICE_RD|UMP_HINT_DEVICE_WR)) == (UMP_HINT_DEVICE_RD|UMP_HINT_DEVICE_WR))
+ {
+ reg->flags |= KBASE_REG_GPU_CACHED;
+ }
+
+ if (gpu_flags & UMP_PROT_DEVICE_WR)
+ {
+ reg->flags |= KBASE_REG_GPU_WR;
+ }
+
+ if (gpu_flags & UMP_PROT_DEVICE_RD)
+ {
+ reg->flags |= KBASE_REG_GPU_RD;
+ }
+
+ /* ump phys block query */
+ ump_dd_phys_blocks_get_64(umph, &block_count, &block_array);
+
+ if(OSK_SIMULATE_FAILURE(OSK_OSK))
+ {
+ page_array = NULL;
+ }
+ else
+ {
+ OSK_ASSERT(0 != vsize);
+ page_array = vmalloc_user(vsize * sizeof(*page_array));
+ }
+
+ if (!page_array)
+ {
+ goto out2;
+ }
+
+ for (i = 0; i < block_count; i++)
+ {
+ for (j = 0; j < (block_array[i].size >> PAGE_SHIFT); j++)
+ {
+ page_array[page] = block_array[i].addr + (j << PAGE_SHIFT);
+ page++;
+ }
+ }
+
+ kbase_set_phy_pages(reg, page_array);
+
+ reg->nr_alloc_pages = vsize;
+ reg->extent = vsize;
+
+ kbase_gpu_vm_lock(kctx);
+ err = kbase_gpu_mmap(kctx, reg, 0, vsize, 1/* no alignment */);
+ kbase_gpu_vm_unlock(kctx);
+
+ if (err)
+ {
+ OSK_PRINT_WARN(OSK_BASE_MEM, "kbase_gpu_mmap failed\n");
+ goto out3;
+ }
+
+ *pages = vsize;
+
+ return reg;
+
+out3:
+ vfree(page_array);
+out2:
+ kfree(reg);
+out1:
+ ump_dd_release(umph);
+ return NULL;
+
+
+}
+
+#endif /* CONFIG_UMP */
+
+#ifdef CONFIG_DMA_SHARED_BUFFER
+static struct kbase_va_region *kbase_tmem_from_umm(kbase_context *kctx, int fd, u64 * const pages)
+{
+ struct kbase_va_region *reg;
+ struct dma_buf * dma_buf;
+ struct dma_buf_attachment * dma_attachment;
+ osk_phy_addr *page_array;
+ unsigned long nr_pages;
+ mali_error err;
+
+ dma_buf = dma_buf_get(fd);
+ if (IS_ERR_OR_NULL(dma_buf))
+ goto no_buf;
+
+ dma_attachment = dma_buf_attach(dma_buf, kctx->kbdev->osdev.dev);
+ if (!dma_attachment)
+ goto no_attachment;
+
+ nr_pages = (dma_buf->size + PAGE_SIZE - 1) >> PAGE_SHIFT;
+
+ reg = kbase_alloc_free_region(kctx, 0, nr_pages , KBASE_REG_ZONE_TMEM);
+ if (!reg)
+ goto no_region;
+
+ reg->flags &= ~KBASE_REG_FREE;
+ reg->flags |= KBASE_REG_GPU_NX; /* UMM is always No eXecute */
+ reg->flags &= ~KBASE_REG_GROWABLE; /* UMM cannot be grown */
+ reg->flags |= KBASE_REG_GPU_CACHED;
+
+ /* no read or write permission given on import, only on run do we give the right permissions */
+
+ reg->imported_type = BASE_TMEM_IMPORT_TYPE_UMM;
+
+ reg->imported_metadata.umm.st = NULL;
+ reg->imported_metadata.umm.dma_buf = dma_buf;
+ reg->imported_metadata.umm.dma_attachment = dma_attachment;
+ reg->imported_metadata.umm.current_mapping_usage_count = 0;
+
+ if(OSK_SIMULATE_FAILURE(OSK_OSK))
+ {
+ page_array = NULL;
+ }
+ else
+ {
+ OSK_ASSERT(0 != nr_pages);
+ page_array = vmalloc_user(nr_pages * sizeof(*page_array));
+ }
+
+ if (!page_array)
+ goto no_page_array;
+
+ memset(page_array, 0, nr_pages * sizeof(*page_array));
+
+ kbase_set_phy_pages(reg, page_array);
+
+ reg->nr_alloc_pages = nr_pages;
+ reg->extent = nr_pages;
+
+ kbase_gpu_vm_lock(kctx);
+ err = kbase_add_va_region(kctx, reg, 0, nr_pages, 1);
+ kbase_gpu_vm_unlock(kctx);
+ if (err != MALI_ERROR_NONE)
+ goto no_addr_reserve;
+
+ *pages = nr_pages;
+
+ return reg;
+
+no_addr_reserve:
+ vfree(page_array);
+no_page_array:
+ kfree(reg);
+no_region:
+ dma_buf_detach(dma_buf, dma_attachment);
+no_attachment:
+ dma_buf_put(dma_buf);
+no_buf:
+ return NULL;
+}
+#endif /* CONFIG_DMA_SHARED_BUFFER */
+
+struct kbase_va_region *kbase_tmem_import(kbase_context *kctx, base_tmem_import_type type, int handle, u64 * const pages)
+{
+ switch (type)
+ {
+#ifdef CONFIG_UMP
+ case BASE_TMEM_IMPORT_TYPE_UMP:
+ {
+ ump_secure_id id;
+ id = (ump_secure_id)handle;
+ return kbase_tmem_from_ump(kctx, id, pages);
+ }
+#endif /* CONFIG_UMP */
+#ifdef CONFIG_DMA_SHARED_BUFFER
+ case BASE_TMEM_IMPORT_TYPE_UMM:
+ return kbase_tmem_from_umm(kctx, handle, pages);
+#endif /* CONFIG_DMA_SHARED_BUFFER */
+ default:
+ return NULL;
+ }
+}
+
+/**
+ * @brief Acquire the per-context region list lock
+ */
+void kbase_gpu_vm_lock(kbase_context *kctx)
+{
+ OSK_ASSERT(kctx != NULL);
+ mutex_lock(&kctx->reg_lock);
+}
+KBASE_EXPORT_TEST_API(kbase_gpu_vm_lock)
+
+/**
+ * @brief Release the per-context region list lock
+ */
+void kbase_gpu_vm_unlock(kbase_context *kctx)
+{
+ OSK_ASSERT(kctx != NULL);
+ mutex_unlock(&kctx->reg_lock);
+}
+KBASE_EXPORT_TEST_API(kbase_gpu_vm_unlock)
+
diff --git a/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_mem.h b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_mem.h
new file mode 100644
index 0000000..471c685
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_mem.h
@@ -0,0 +1,582 @@
+/*
+ *
+ * (C) COPYRIGHT 2010-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_kbase_mem.h
+ * Base kernel memory APIs
+ */
+
+#ifndef _KBASE_MEM_H_
+#define _KBASE_MEM_H_
+
+#ifndef _KBASE_H_
+#error "Don't include this file directly, use mali_kbase.h instead"
+#endif
+
+#include <malisw/mali_malisw.h>
+#include <osk/mali_osk.h>
+#ifdef CONFIG_UMP
+#include <linux/ump.h>
+#endif /* CONFIG_UMP */
+#include <kbase/mali_base_kernel.h>
+#include <kbase/src/common/mali_kbase_hw.h>
+#include "mali_kbase_pm.h"
+#include "mali_kbase_defs.h"
+
+/* Part of the workaround for uTLB invalid pages is to ensure we grow/shrink tmem by 4 pages at a time */
+#define KBASEP_TMEM_GROWABLE_BLOCKSIZE_PAGES_LOG2_HW_ISSUE_8316 (2) /* round to 4 pages */
+
+/* Part of the workaround for PRLAM-9630 requires us to grow/shrink memory by 8 pages.
+The MMU reads in 8 page table entries from memory at a time, if we have more than one page fault within the same 8 pages and
+page tables are updated accordingly, the MMU does not re-read the page table entries from memory for the subsequent page table
+updates and generates duplicate page faults as the page table information used by the MMU is not valid. */
+#define KBASEP_TMEM_GROWABLE_BLOCKSIZE_PAGES_LOG2_HW_ISSUE_9630 (3) /* round to 8 pages */
+
+#define KBASEP_TMEM_GROWABLE_BLOCKSIZE_PAGES_LOG2 (0) /* round to 1 page */
+
+/* This must always be a power of 2 */
+#define KBASEP_TMEM_GROWABLE_BLOCKSIZE_PAGES (1u << KBASEP_TMEM_GROWABLE_BLOCKSIZE_PAGES_LOG2)
+#define KBASEP_TMEM_GROWABLE_BLOCKSIZE_PAGES_HW_ISSUE_8316 (1u << KBASEP_TMEM_GROWABLE_BLOCKSIZE_PAGES_LOG2_HW_ISSUE_8316)
+#define KBASEP_TMEM_GROWABLE_BLOCKSIZE_PAGES_HW_ISSUE_9630 (1u << KBASEP_TMEM_GROWABLE_BLOCKSIZE_PAGES_LOG2_HW_ISSUE_9630)
+
+/**
+ * A CPU mapping
+ */
+typedef struct kbase_cpu_mapping
+{
+ osk_dlist_item link;
+ osk_virt_addr uaddr;
+ u32 nr_pages;
+ mali_size64 page_off;
+ void *private; /* Use for VMA */
+} kbase_cpu_mapping;
+
+/**
+ * A GPU memory region, and attributes for CPU mappings.
+ */
+typedef struct kbase_va_region
+{
+ struct rb_node rblink;
+ osk_dlist_item link;
+
+ kbase_context *kctx; /* Backlink to base context */
+
+ u64 start_pfn; /* The PFN in GPU space */
+ u32 nr_pages; /* VA size */
+
+#define KBASE_REG_FREE (1ul << 0) /* Free region */
+#define KBASE_REG_CPU_WR (1ul << 1) /* CPU write access */
+#define KBASE_REG_GPU_WR (1ul << 2) /* GPU write access */
+#define KBASE_REG_GPU_NX (1ul << 3) /* No eXectue flag */
+#define KBASE_REG_CPU_CACHED (1ul << 4) /* Is CPU cached? */
+#define KBASE_REG_GPU_CACHED (1ul << 5) /* Is GPU cached? */
+
+#define KBASE_REG_GROWABLE (1ul << 6) /* Is growable? */
+#define KBASE_REG_PF_GROW (1ul << 7) /* Can grow on pf? */
+
+#define KBASE_REG_IS_RB (1ul << 8) /* Is ringbuffer? */
+#define KBASE_REG_IS_MMU_DUMP (1ul << 9) /* Is an MMU dump */
+#define KBASE_REG_IS_TB (1ul << 10) /* Is register trace buffer? */
+
+#define KBASE_REG_SHARE_IN (1ul << 11) /* inner shareable coherency */
+#define KBASE_REG_SHARE_BOTH (1ul << 12) /* inner & outer shareable coherency */
+
+#define KBASE_REG_DELAYED_FREE (1ul << 13) /* kbase_mem_free_region called but mappings still exist */
+
+#define KBASE_REG_ZONE_MASK (3ul << 14) /* Space for 4 different zones */
+#define KBASE_REG_ZONE(x) (((x) & 3) << 14)
+
+#define KBASE_REG_GPU_RD (1ul<<16) /* GPU write access */
+#define KBASE_REG_CPU_RD (1ul<<17) /* CPU read access */
+
+#define KBASE_REG_MUST_ZERO (1ul<<18) /* No zeroing needed */
+
+#define KBASE_REG_FLAGS_NR_BITS 19 /* Number of bits used by kbase_va_region flags */
+
+#define KBASE_REG_ZONE_PMEM KBASE_REG_ZONE(0)
+
+#ifndef KBASE_REG_ZONE_TMEM /* To become 0 on a 64bit platform */
+/*
+ * On a 32bit platform, TMEM should be wired from 4GB to the VA limit
+ * of the GPU, which is currently hardcoded at 48 bits. Unfortunately,
+ * the Linux mmap() interface limits us to 2^32 pages (2^44 bytes, see
+ * mmap64 man page for reference).
+ */
+#define KBASE_REG_ZONE_EXEC KBASE_REG_ZONE(1) /* Dedicated 4GB region for shader code */
+#define KBASE_REG_ZONE_EXEC_BASE ((1ULL << 32) >> OSK_PAGE_SHIFT)
+#define KBASE_REG_ZONE_EXEC_SIZE (((1ULL << 33) >> OSK_PAGE_SHIFT) - \
+ KBASE_REG_ZONE_EXEC_BASE)
+
+#define KBASE_REG_ZONE_TMEM KBASE_REG_ZONE(2)
+#define KBASE_REG_ZONE_TMEM_BASE ((1ULL << 33) >> OSK_PAGE_SHIFT) /* Starting after KBASE_REG_ZONE_EXEC */
+#define KBASE_REG_ZONE_TMEM_SIZE (((1ULL << 44) >> OSK_PAGE_SHIFT) - \
+ KBASE_REG_ZONE_TMEM_BASE)
+#endif
+
+#define KBASE_REG_COOKIE_MASK (~((1ul << KBASE_REG_FLAGS_NR_BITS)-1))
+#define KBASE_REG_COOKIE(x) ((x << KBASE_REG_FLAGS_NR_BITS) & KBASE_REG_COOKIE_MASK)
+
+/* The reserved cookie values */
+#define KBASE_REG_COOKIE_RB 0
+#define KBASE_REG_COOKIE_MMU_DUMP 1
+#define KBASE_REG_COOKIE_TB 2
+#define KBASE_REG_COOKIE_MTP 3
+#define KBASE_REG_COOKIE_FIRST_FREE 4
+
+/* Bit mask of cookies that not used for PMEM but reserved for other uses */
+#define KBASE_REG_RESERVED_COOKIES ((1ULL << (KBASE_REG_COOKIE_FIRST_FREE))-1)
+
+ u32 flags;
+
+ u32 nr_alloc_pages; /* nr of pages allocated */
+ u32 extent; /* nr of pages alloc'd on PF */
+
+ osk_phy_addr *phy_pages;
+
+ osk_dlist map_list;
+
+ /* non-NULL if this memory object is a kds_resource */
+ struct kds_resource * kds_res;
+
+ base_tmem_import_type imported_type;
+
+ /* member in union valid based on imported_type */
+ union
+ {
+#ifdef CONFIG_UMP
+ ump_dd_handle ump_handle;
+#endif /* CONFIG_UMP */
+#if defined(CONFIG_DMA_SHARED_BUFFER)
+ struct
+ {
+ struct dma_buf * dma_buf;
+ struct dma_buf_attachment * dma_attachment;
+ unsigned int current_mapping_usage_count;
+ struct sg_table * st;
+ } umm;
+#endif /* defined(CONFIG_DMA_SHARED_BUFFER) */
+ } imported_metadata;
+
+} kbase_va_region;
+
+/* Common functions */
+static INLINE osk_phy_addr *kbase_get_phy_pages(struct kbase_va_region *reg)
+{
+ OSK_ASSERT(reg);
+
+ return reg->phy_pages;
+}
+
+static INLINE void kbase_set_phy_pages(struct kbase_va_region *reg, osk_phy_addr *phy_pages)
+{
+ OSK_ASSERT(reg);
+
+ reg->phy_pages = phy_pages;
+}
+
+mali_error kbase_mem_init(kbase_device * kbdev);
+void kbase_mem_halt(kbase_device * kbdev);
+void kbase_mem_term(kbase_device * kbdev);
+
+/**
+ * @brief Initialize an OS based memory allocator.
+ *
+ * Initializes a allocator.
+ * Must be called before any allocation is attempted.
+ * \a kbase_mem_allocator_alloc and \a kbase_mem_allocator_free is used
+ * to allocate and free memory.
+ * \a kbase_mem_allocator_term must be called to clean up the allocator.
+ * All memory obtained via \a kbase_mem_allocator_alloc must have been
+ * \a kbase_mem_allocator_free before \a kbase_mem_allocator_term is called.
+ *
+ * @param allocator Allocator object to initialize
+ * @param max_size Maximum number of pages to keep on the freelist.
+ * @return MALI_ERROR_NONE on success, an error code indicating what failed on error.
+ */
+mali_error kbase_mem_allocator_init(kbase_mem_allocator * allocator, unsigned int max_size);
+/**
+ * @brief Allocate memory via an OS based memory allocator.
+ *
+ * @param[in] allocator Allocator to obtain the memory from
+ * @param nr_pages Number of pages to allocate
+ * @param[out] pages Pointer to an array where the physical address of the allocated pages will be stored
+ * @param flags Allocation flag, 0 or KBASE_REG_MUST_ZERO supported.
+ * @return MALI_ERROR_NONE if the pages were allocated, an error code indicating what failed on error
+ */
+mali_error kbase_mem_allocator_alloc(kbase_mem_allocator * allocator, u32 nr_pages, osk_phy_addr *pages, int flags);
+/**
+ * @brief Free memory obtained for an OS based memory allocator.
+ *
+ * @param[in] allocator Allocator to free the memory back to
+ * @param nr_pages Number of pages to free
+ * @param[in] pages Pointer to an array holding the physical address of the paghes to free.
+ */
+void kbase_mem_allocator_free(kbase_mem_allocator * allocator, u32 nr_pages, osk_phy_addr *pages);
+/**
+ * @brief Terminate an OS based memory allocator.
+ *
+ * Frees all cached allocations and clean up internal state.
+ * All allocate pages must have been \a kbase_mem_allocator_free before
+ * this function is called.
+ *
+ * @param[in] allocator Allocator to terminate
+ */
+void kbase_mem_allocator_term(kbase_mem_allocator * allocator);
+
+/**
+ * @brief Initializes memory context which tracks memory usage.
+ *
+ * Function initializes memory context with given max_pages value.
+ *
+ * @param[in] usage usage tracker
+ * @param[in] max_pages maximum pages allowed to be allocated within this memory context
+ *
+ * @return MALI_ERROR_NONE in case of error. Error code otherwise.
+ */
+mali_error kbase_mem_usage_init(kbasep_mem_usage * usage, u32 max_pages);
+
+/*
+ * @brief Terminates given memory context
+ *
+ * @param[in] usage usage tracker
+ *
+ * @return MALI_ERROR_NONE in case of error. Error code otherwise.
+ */
+void kbase_mem_usage_term(kbasep_mem_usage *usage);
+
+/*
+ * @brief Requests a number of pages from the given context.
+ *
+ * Function requests a number of pages from the given context. Context is updated only if it contains enough number of
+ * free pages. Otherwise function returns error and no pages are claimed.
+ *
+ * @param[in] usage usage tracker
+ * @param[in] nr_pages number of pages requested
+ *
+ * @return MALI_ERROR_NONE when context page request succeeded. Error code otherwise.
+ */
+mali_error kbase_mem_usage_request_pages(kbasep_mem_usage *usage, u32 nr_pages);
+
+/*
+ * @brief Release a number of pages from the given context.
+ *
+ * @param[in] usage usage tracker
+ * @param[in] nr_pages number of pages to be released
+ */
+void kbase_mem_usage_release_pages(kbasep_mem_usage *usage, u32 nr_pages);
+
+
+mali_error kbase_region_tracker_init(kbase_context *kctx);
+void kbase_region_tracker_term(kbase_context *kctx);
+
+struct kbase_va_region * kbase_region_tracker_find_region_enclosing_range(
+ kbase_context *kctx, u64 start_pgoff, u32 nr_pages );
+
+struct kbase_va_region * kbase_region_tracker_find_region_enclosing_address(
+ kbase_context *kctx, mali_addr64 gpu_addr );
+
+/**
+ * @brief Check that a pointer is actually a valid region.
+ *
+ * Must be called with context lock held.
+ */
+struct kbase_va_region * kbase_region_tracker_find_region_base_address(
+ kbase_context *kctx, mali_addr64 gpu_addr );
+
+
+struct kbase_va_region *kbase_alloc_free_region(kbase_context *kctx, u64 start_pfn, u32 nr_pages, u32 zone);
+void kbase_free_alloced_region(struct kbase_va_region *reg);
+mali_error kbase_add_va_region(kbase_context *kctx,
+ struct kbase_va_region *reg,
+ mali_addr64 addr, u32 nr_pages,
+ u32 align);
+
+mali_error kbase_gpu_mmap(kbase_context *kctx,
+ struct kbase_va_region *reg,
+ mali_addr64 addr, u32 nr_pages,
+ u32 align);
+mali_bool kbase_check_alloc_flags(u32 flags);
+void kbase_update_region_flags(struct kbase_va_region *reg, u32 flags, mali_bool is_growable);
+
+void kbase_gpu_vm_lock(kbase_context *kctx);
+void kbase_gpu_vm_unlock(kbase_context *kctx);
+
+void kbase_free_phy_pages(struct kbase_va_region *reg);
+int kbase_alloc_phy_pages(struct kbase_va_region *reg, u32 vsize, u32 size);
+
+mali_error kbase_cpu_free_mapping(struct kbase_va_region *reg, const void *ptr);
+
+mali_error kbase_mmu_init(kbase_context *kctx);
+void kbase_mmu_term(kbase_context *kctx);
+
+osk_phy_addr kbase_mmu_alloc_pgd(kbase_context *kctx);
+void kbase_mmu_free_pgd(kbase_context *kctx);
+mali_error kbase_mmu_insert_pages(kbase_context *kctx, u64 vpfn,
+ osk_phy_addr *phys, u32 nr, u32 flags);
+mali_error kbase_mmu_teardown_pages(kbase_context *kctx, u64 vpfn, u32 nr);
+
+/**
+ * @brief Register region and map it on the GPU.
+ *
+ * Call kbase_add_va_region() and map the region on the GPU.
+ */
+mali_error kbase_gpu_mmap(kbase_context *kctx,
+ struct kbase_va_region *reg,
+ mali_addr64 addr, u32 nr_pages,
+ u32 align);
+
+/**
+ * @brief Remove the region from the GPU and unregister it.
+ *
+ * Must be called with context lock held.
+ */
+mali_error kbase_gpu_munmap(kbase_context *kctx, struct kbase_va_region *reg);
+
+/**
+ * The caller has the following locking conditions:
+ * - It must hold kbase_as::transaction_mutex on kctx's address space
+ * - It must hold the kbasep_js_device_data::runpool_irq::lock
+ */
+void kbase_mmu_update(kbase_context *kctx);
+
+/**
+ * The caller has the following locking conditions:
+ * - It must hold kbase_as::transaction_mutex on kctx's address space
+ * - It must hold the kbasep_js_device_data::runpool_irq::lock
+ */
+void kbase_mmu_disable (kbase_context *kctx);
+
+void kbase_mmu_interrupt(kbase_device * kbdev, u32 irq_stat);
+
+/** Dump the MMU tables to a buffer
+ *
+ * This function allocates a buffer (of @c nr_pages pages) to hold a dump of the MMU tables and fills it. If the
+ * buffer is too small then the return value will be NULL.
+ *
+ * The GPU vm lock must be held when calling this function.
+ *
+ * The buffer returned should be freed with @ref vfree when it is no longer required.
+ *
+ * @param[in] kctx The kbase context to dump
+ * @param[in] nr_pages The number of pages to allocate for the buffer.
+ *
+ * @return The address of the buffer containing the MMU dump or NULL on error (including if the @c nr_pages is too
+ * small)
+ */
+void *kbase_mmu_dump(kbase_context *kctx,int nr_pages);
+
+mali_error kbase_sync_now(kbase_context *kctx, base_syncset *syncset);
+void kbase_pre_job_sync(kbase_context *kctx, base_syncset *syncsets, u32 nr);
+void kbase_post_job_sync(kbase_context *kctx, base_syncset *syncsets, u32 nr);
+
+struct kbase_va_region *kbase_tmem_alloc(kbase_context *kctx,
+ u32 vsize, u32 psize,
+ u32 extent, u32 flags, mali_bool is_growable);
+
+/** Resize a tmem region
+ *
+ * This function changes the number of physical pages committed to a tmem region.
+ *
+ * @param[in] kctx The kbase context which the tmem belongs to
+ * @param[in] gpu_addr The base address of the tmem region
+ * @param[in] delta The number of pages to grow or shrink by
+ * @param[out] size The number of pages of memory committed after growing/shrinking
+ * @param[out] failure_reason Error code describing reason of failure.
+ *
+ * @return MALI_ERROR_NONE on success
+ */
+
+mali_error kbase_tmem_resize(kbase_context *kctx, mali_addr64 gpu_addr, s32 delta, u32 *size, base_backing_threshold_status * failure_reason);
+
+/** Set the size of a tmem region
+ *
+ * This function sets the number of physical pages committed to a tmem region upto max region size.
+ *
+ * @param[in] kctx The kbase context which the tmem belongs to
+ * @param[in] gpu_addr The base address of the tmem region
+ * @param[in] size The number of pages desired
+ * @param[out] actual_size The actual number of pages of memory committed to this tmem
+ * @param[out] failure_reason Error code describing reason of failure.
+ *
+ * @return MALI_ERROR_NONE on success
+ */
+
+mali_error kbase_tmem_set_size(kbase_context *kctx, mali_addr64 gpu_addr, u32 size, u32 *actual_size, base_backing_threshold_status * failure_reason);
+
+/** Get a tmem region size
+ *
+ * This function obtains the number of physical pages committed to a tmem region.
+ *
+ * @param[in] kctx The kbase context which the tmem belongs to
+ * @param[in] gpu_addr The base address of the tmem region
+ * @param[out] actual_size The actual number of pages of memory committed to this tmem
+ *
+ * @return MALI_ERROR_NONE on success
+ */
+
+mali_error kbase_tmem_get_size(kbase_context *kctx, mali_addr64 gpu_addr, u32 *actual_size );
+
+/**
+ * Import external memory.
+ *
+ * This function supports importing external memory.
+ * If imported a kbase_va_region is created of the tmem type.
+ * The region might not be mappable on the CPU depending on the imported type.
+ * If not mappable the KBASE_REG_NO_CPU_MAP bit will be set.
+ *
+ * Import will fail if (but not limited to):
+ * @li Unsupported import type
+ * @li Handle not valid for the type
+ * @li Access to a handle was not valid
+ * @li The underlying memory can't be accessed by the GPU
+ * @li No VA space found to map the memory
+ * @li Resources to track the region was not available
+ *
+ * @param[in] kctx The kbase context which the tmem will be created in
+ * @param type The type of memory to import
+ * @param handle Handle to the memory to import
+ * @param[out] pages Where to store the number of pages imported
+ * @return A region pointer on success, NULL on failure
+ */
+struct kbase_va_region *kbase_tmem_import(kbase_context *kctx, base_tmem_import_type type, int handle, u64 * const pages);
+
+
+/* OS specific functions */
+struct kbase_va_region * kbase_lookup_cookie(kbase_context * kctx, mali_addr64 cookie);
+void kbase_unlink_cookie(kbase_context * kctx, mali_addr64 cookie, struct kbase_va_region * reg);
+mali_error kbase_mem_free(kbase_context *kctx, mali_addr64 gpu_addr);
+mali_error kbase_mem_free_region(kbase_context *kctx,
+ struct kbase_va_region *reg);
+void kbase_os_mem_map_lock(kbase_context * kctx);
+void kbase_os_mem_map_unlock(kbase_context * kctx);
+
+/**
+ * @brief Update the memory allocation counters for the current process
+ *
+ * OS specific call to updates the current memory allocation counters for the current process with
+ * the supplied delta.
+ *
+ * @param[in] pages The desired delta to apply to the memory usage counters.
+ */
+
+void kbasep_os_process_page_usage_update( struct kbase_context * kctx, int pages );
+
+/**
+ * @brief Add to the memory allocation counters for the current process
+ *
+ * OS specific call to add to the current memory allocation counters for the current process by
+ * the supplied amount.
+ *
+ * @param[in] kctx The kernel base context used for the allocation.
+ * @param[in] pages The desired delta to apply to the memory usage counters.
+ */
+
+static INLINE void kbase_process_page_usage_inc( struct kbase_context *kctx, int pages )
+{
+ kbasep_os_process_page_usage_update( kctx, pages );
+}
+
+/**
+ * @brief Subtract from the memory allocation counters for the current process
+ *
+ * OS specific call to subtract from the current memory allocation counters for the current process by
+ * the supplied amount.
+ *
+ * @param[in] kctx The kernel base context used for the allocation.
+ * @param[in] pages The desired delta to apply to the memory usage counters.
+ */
+
+static INLINE void kbase_process_page_usage_dec( struct kbase_context *kctx, int pages )
+{
+ kbasep_os_process_page_usage_update( kctx, 0 - pages );
+}
+
+/**
+ * @brief Find a CPU mapping of a memory allocation containing a given address range
+ *
+ * Searches for a CPU mapping of any part of the region starting at @p gpu_addr that
+ * fully encloses the CPU virtual address range specified by @p uaddr and @p size.
+ * Returns a failure indication if only part of the address range lies within a
+ * CPU mapping, or the address range lies within a CPU mapping of a different region.
+ *
+ * @param[in,out] kctx The kernel base context used for the allocation.
+ * @param[in] gpu_addr GPU address of the start of the allocated region
+ * within which to search.
+ * @param[in] uaddr Start of the CPU virtual address range.
+ * @param[in] size Size of the CPU virtual address range (in bytes).
+ *
+ * @return A pointer to a descriptor of the CPU mapping that fully encloses
+ * the specified address range, or NULL if none was found.
+ */
+struct kbase_cpu_mapping *kbasep_find_enclosing_cpu_mapping(
+ kbase_context *kctx,
+ mali_addr64 gpu_addr,
+ osk_virt_addr uaddr,
+ size_t size );
+
+/**
+ * @brief Round TMem Growable no. pages to allow for HW workarounds/block allocators
+ *
+ * For success, the caller should check that the unsigned return value is
+ * higher than the \a nr_pages parameter.
+ *
+ * @param[in] kbdev The kernel base context used for the allocation
+ * @param[in] nr_pages Size value (in pages) to round
+ *
+ * @return the rounded-up number of pages (which may have wraped around to zero)
+ */
+static INLINE u32 kbasep_tmem_growable_round_size( kbase_device *kbdev, u32 nr_pages )
+{
+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_9630))
+ {
+ return (nr_pages + KBASEP_TMEM_GROWABLE_BLOCKSIZE_PAGES_HW_ISSUE_9630 - 1) & ~(KBASEP_TMEM_GROWABLE_BLOCKSIZE_PAGES_HW_ISSUE_9630 - 1);
+ }
+ else if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8316))
+ {
+ return (nr_pages + KBASEP_TMEM_GROWABLE_BLOCKSIZE_PAGES_HW_ISSUE_8316 - 1) & ~(KBASEP_TMEM_GROWABLE_BLOCKSIZE_PAGES_HW_ISSUE_8316 - 1);
+ }
+ else
+ {
+ return (nr_pages + KBASEP_TMEM_GROWABLE_BLOCKSIZE_PAGES - 1) & ~(KBASEP_TMEM_GROWABLE_BLOCKSIZE_PAGES-1);
+ }
+}
+
+enum hrtimer_restart kbasep_as_poke_timer_callback(struct hrtimer * timer);
+void kbase_as_poking_timer_retain(kbase_as * as);
+void kbase_as_poking_timer_release(kbase_as * as);
+
+/**
+ * @brief Allocates physical pages.
+ *
+ * Allocates \a nr_pages_requested and updates the region object.
+ *
+ * @param[in] reg memory region in which physical pages are supposed to be allocated
+ * @param[in] nr_pages number of physical pages to allocate
+ *
+ * @return MALI_ERROR_NONE if all pages have been successfully allocated. Error code otherwise
+ */
+mali_error kbase_alloc_phy_pages_helper(struct kbase_va_region *reg, u32 nr_pages_requested);
+
+/**
+ * @brief Free physical pages.
+ *
+ * Frees \a nr_pages and updates the region object.
+ *
+ * @param[in] reg memory region in which physical pages are supposed to be allocated
+ * @param[in] nr_pages number of physical pages to free
+ */
+void kbase_free_phy_pages_helper(struct kbase_va_region * reg, u32 nr_pages);
+
+
+#endif /* _KBASE_MEM_H_ */
diff --git a/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_mmu.c b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_mmu.c
new file mode 100644
index 0000000..9798a700
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_mmu.c
@@ -0,0 +1,1354 @@
+/*
+ *
+ * (C) COPYRIGHT 2010-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_kbase_mmu.c
+ * Base kernel MMU management.
+ */
+
+/* #define DEBUG 1 */
+#include <osk/mali_osk.h>
+#include <kbase/src/common/mali_kbase.h>
+#include <kbase/src/common/mali_midg_regmap.h>
+#include <kbase/src/common/mali_kbase_gator.h>
+
+#define beenthere(f, a...) OSK_PRINT_INFO(OSK_BASE_MMU, "%s:" f, __func__, ##a)
+
+#include <kbase/src/common/mali_kbase_defs.h>
+#include <kbase/src/common/mali_kbase_hw.h>
+
+#define KBASE_MMU_PAGE_ENTRIES 512
+
+/*
+ * Definitions:
+ * - PGD: Page Directory.
+ * - PTE: Page Table Entry. A 64bit value pointing to the next
+ * level of translation
+ * - ATE: Address Transation Entry. A 64bit value pointing to
+ * a 4kB physical page.
+ */
+
+static void kbase_mmu_report_fault_and_kill(kbase_context *kctx, kbase_as * as, mali_addr64 fault_addr);
+static u64 lock_region(kbase_device * kbdev, u64 pfn, u32 num_pages);
+
+static void ksync_kern_vrange_gpu(osk_phy_addr paddr, osk_virt_addr vaddr, size_t size)
+{
+ osk_sync_to_memory(paddr, vaddr, size);
+}
+
+static u32 make_multiple(u32 minimum, u32 multiple)
+{
+ u32 remainder = minimum % multiple;
+ if (remainder == 0)
+ {
+ return minimum;
+ }
+ else
+ {
+ return minimum + multiple - remainder;
+ }
+}
+
+static void mmu_mask_reenable(kbase_device * kbdev, kbase_context *kctx, kbase_as * as)
+{
+ unsigned long flags;
+ u32 mask;
+ spin_lock_irqsave(&kbdev->mmu_mask_change, flags);
+ mask = kbase_reg_read(kbdev, MMU_REG(MMU_IRQ_MASK), kctx);
+ mask |= ((1UL << as->number) | (1UL << (MMU_REGS_BUS_ERROR_FLAG(as->number))));
+ kbase_reg_write(kbdev, MMU_REG(MMU_IRQ_MASK), mask, kctx);
+ spin_unlock_irqrestore(&kbdev->mmu_mask_change, flags);
+}
+
+static void page_fault_worker(struct work_struct *data)
+{
+ u64 fault_pfn;
+ u32 new_pages;
+ u32 fault_rel_pfn;
+ kbase_as * faulting_as;
+ int as_no;
+ kbase_context * kctx;
+ kbase_device * kbdev;
+ kbase_va_region *region;
+ mali_error err;
+
+ u32 fault_status;
+
+ faulting_as = container_of(data, kbase_as, work_pagefault);
+ fault_pfn = faulting_as->fault_addr >> PAGE_SHIFT;
+ as_no = faulting_as->number;
+
+ kbdev = container_of( faulting_as, kbase_device, as[as_no] );
+
+ /* Grab the context that was already refcounted in kbase_mmu_interrupt().
+ * Therefore, it cannot be scheduled out of this AS until we explicitly release it
+ *
+ * NOTE: NULL can be returned here if we're gracefully handling a spurious interrupt */
+ kctx = kbasep_js_runpool_lookup_ctx_noretain( kbdev, as_no );
+
+ if ( kctx == NULL )
+ {
+ /* Address space has no context, terminate the work */
+ u32 reg;
+ /* AS transaction begin */
+ mutex_lock(&faulting_as->transaction_mutex);
+ reg = kbase_reg_read(kbdev, MMU_AS_REG(as_no, ASn_TRANSTAB_LO), NULL);
+ reg = (reg & (~(u32)MMU_TRANSTAB_ADRMODE_MASK)) | ASn_TRANSTAB_ADRMODE_UNMAPPED;
+ kbase_reg_write(kbdev, MMU_AS_REG(as_no, ASn_TRANSTAB_LO), reg, NULL);
+ kbase_reg_write(kbdev, MMU_AS_REG(as_no, ASn_COMMAND), ASn_COMMAND_UPDATE, NULL);
+ kbase_reg_write(kbdev, MMU_REG(MMU_IRQ_CLEAR), (1UL << as_no), NULL);
+ mutex_unlock(&faulting_as->transaction_mutex);
+ /* AS transaction end */
+
+ mmu_mask_reenable(kbdev, NULL, faulting_as);
+ return;
+ }
+
+ fault_status = kbase_reg_read(kbdev, MMU_AS_REG(as_no, ASn_FAULTSTATUS), NULL);
+
+ OSK_ASSERT( kctx->kbdev == kbdev );
+
+ kbase_gpu_vm_lock(kctx);
+
+ /* find the region object for this VA */
+ region = kbase_region_tracker_find_region_enclosing_address(kctx, faulting_as->fault_addr);
+ if (NULL == region || (GROWABLE_FLAGS_REQUIRED != (region->flags & GROWABLE_FLAGS_MASK)))
+ {
+ kbase_gpu_vm_unlock(kctx);
+ /* failed to find the region or mismatch of the flags */
+ kbase_mmu_report_fault_and_kill(kctx, faulting_as, faulting_as->fault_addr);
+ goto fault_done;
+ }
+
+ if ((((fault_status & ASn_FAULTSTATUS_ACCESS_TYPE_MASK) == ASn_FAULTSTATUS_ACCESS_TYPE_READ) &&
+ !(region->flags & KBASE_REG_GPU_RD)) ||
+ (((fault_status & ASn_FAULTSTATUS_ACCESS_TYPE_MASK) == ASn_FAULTSTATUS_ACCESS_TYPE_WRITE) &&
+ !(region->flags & KBASE_REG_GPU_WR)) ||
+ (((fault_status & ASn_FAULTSTATUS_ACCESS_TYPE_MASK) == ASn_FAULTSTATUS_ACCESS_TYPE_EX) &&
+ (region->flags & KBASE_REG_GPU_NX)))
+ {
+ OSK_PRINT_WARN(OSK_BASE_MMU, "Access permissions don't match: region->flags=0x%x", region->flags);
+ kbase_gpu_vm_unlock(kctx);
+ kbase_mmu_report_fault_and_kill(kctx, faulting_as, faulting_as->fault_addr);
+ goto fault_done;
+ }
+
+ /* find the size we need to grow it by */
+ /* we know the result fit in a u32 due to kbase_region_tracker_find_region_enclosing_address
+ * validating the fault_adress to be within a u32 from the start_pfn */
+ fault_rel_pfn = fault_pfn - region->start_pfn;
+
+ if (fault_rel_pfn < region->nr_alloc_pages)
+ {
+ OSK_PRINT_WARN(OSK_BASE_MMU, "Fault in allocated region of growable TMEM: Ignoring");
+ kbase_reg_write(kbdev, MMU_REG(MMU_IRQ_CLEAR), (1UL << as_no), NULL);
+ mmu_mask_reenable(kbdev, kctx, faulting_as);
+ kbase_gpu_vm_unlock(kctx);
+ goto fault_done;
+ }
+
+ new_pages = make_multiple(fault_rel_pfn - region->nr_alloc_pages + 1, region->extent);
+ if (new_pages + region->nr_alloc_pages > region->nr_pages)
+ {
+ /* cap to max vsize */
+ new_pages = region->nr_pages - region->nr_alloc_pages;
+ }
+
+ if (0 == new_pages)
+ {
+ /* Duplicate of a fault we've already handled, nothing to do */
+ kbase_reg_write(kbdev, MMU_REG(MMU_IRQ_CLEAR), (1UL << as_no), NULL);
+ mmu_mask_reenable(kbdev, kctx, faulting_as);
+ kbase_gpu_vm_unlock(kctx);
+ goto fault_done;
+ }
+
+ if (MALI_ERROR_NONE == kbase_alloc_phy_pages_helper(region, new_pages))
+ {
+ /* alloc success */
+ mali_addr64 lock_addr;
+ OSK_ASSERT(region->nr_alloc_pages <= region->nr_pages);
+
+ /* AS transaction begin */
+ mutex_lock(&faulting_as->transaction_mutex);
+
+ /* Lock the VA region we're about to update */
+ lock_addr = lock_region(kbdev, faulting_as->fault_addr >> PAGE_SHIFT, new_pages);
+ kbase_reg_write(kbdev, MMU_AS_REG(as_no, ASn_LOCKADDR_LO), lock_addr & 0xFFFFFFFFUL, kctx);
+ kbase_reg_write(kbdev, MMU_AS_REG(as_no, ASn_LOCKADDR_HI), lock_addr >> 32, kctx);
+ kbase_reg_write(kbdev, MMU_AS_REG(as_no, ASn_COMMAND), ASn_COMMAND_LOCK, kctx);
+
+ /* set up the new pages */
+ err = kbase_mmu_insert_pages(kctx, region->start_pfn + region->nr_alloc_pages - new_pages,
+ ®ion->phy_pages[region->nr_alloc_pages - new_pages],
+ new_pages, region->flags);
+ if(MALI_ERROR_NONE != err)
+ {
+ /* failed to insert pages, handle as a normal PF */
+ mutex_unlock(&faulting_as->transaction_mutex);
+ kbase_gpu_vm_unlock(kctx);
+ /* The locked VA region will be unlocked and the cache invalidated in here */
+ kbase_mmu_report_fault_and_kill(kctx, faulting_as, faulting_as->fault_addr);
+ goto fault_done;
+ }
+
+#ifdef CONFIG_MALI_GATOR_SUPPORT
+ kbase_trace_mali_page_fault_insert_pages(as_no, new_pages);
+#endif /* CONFIG_MALI_GATOR_SUPPORT */
+ /* clear the irq */
+ /* MUST BE BEFORE THE FLUSH/UNLOCK */
+ kbase_reg_write(kbdev, MMU_REG(MMU_IRQ_CLEAR), (1UL << as_no), NULL);
+
+ /* flush L2 and unlock the VA (resumes the MMU) */
+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_6367))
+ {
+ kbase_reg_write(kbdev, MMU_AS_REG(as_no, ASn_COMMAND), ASn_COMMAND_FLUSH, kctx);
+ }
+ else
+ {
+ kbase_reg_write(kbdev, MMU_AS_REG(as_no, ASn_COMMAND), ASn_COMMAND_FLUSH_PT, kctx);
+ }
+
+ /* wait for the flush to complete */
+ while (kbase_reg_read(kbdev, MMU_AS_REG(as_no, ASn_STATUS), kctx) & 1);
+
+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_9630))
+ {
+ /* Issue an UNLOCK command to ensure that valid page tables are re-read by the GPU after an update.
+ Note that, the FLUSH command should perform all the actions necessary, however the bus logs show
+ that if multiple page faults occur within an 8 page region the MMU does not always re-read the
+ updated page table entries for later faults or is only partially read, it subsequently raises the
+ page fault IRQ for the same addresses, the unlock ensures that the MMU cache is flushed, so updates
+ can be re-read. As the region is now unlocked we need to issue 2 UNLOCK commands in order to flush the
+ MMU/uTLB, see PRLAM-8812.
+ */
+ kbase_reg_write(kctx->kbdev, MMU_AS_REG(kctx->as_nr, ASn_COMMAND), ASn_COMMAND_UNLOCK, kctx);
+ kbase_reg_write(kctx->kbdev, MMU_AS_REG(kctx->as_nr, ASn_COMMAND), ASn_COMMAND_UNLOCK, kctx);
+ }
+
+ mutex_unlock(&faulting_as->transaction_mutex);
+ /* AS transaction end */
+
+ /* reenable this in the mask */
+ mmu_mask_reenable(kbdev, kctx, faulting_as);
+ kbase_gpu_vm_unlock(kctx);
+ }
+ else
+ {
+ /* failed to extend, handle as a normal PF */
+ kbase_gpu_vm_unlock(kctx);
+ kbase_mmu_report_fault_and_kill(kctx, faulting_as, faulting_as->fault_addr);
+ }
+
+
+fault_done:
+ /* By this point, the fault was handled in some way, so release the ctx refcount */
+ kbasep_js_runpool_release_ctx( kbdev, kctx );
+}
+
+osk_phy_addr kbase_mmu_alloc_pgd(kbase_context *kctx)
+{
+ osk_phy_addr pgd;
+ u64 *page;
+ int i;
+ OSK_ASSERT( NULL != kctx);
+ if (MALI_ERROR_NONE != kbase_mem_usage_request_pages(&kctx->usage, 1))
+ {
+ return 0;
+ }
+ if (MALI_ERROR_NONE != kbase_mem_allocator_alloc(kctx->pgd_allocator, 1, &pgd, 0))
+ {
+ kbase_mem_usage_release_pages(&kctx->usage, 1);
+ return 0;
+ }
+
+ page = osk_kmap(pgd);
+ if(NULL == page)
+ {
+ kbase_mem_allocator_free(kctx->pgd_allocator, 1, &pgd);
+ kbase_mem_usage_release_pages(&kctx->usage, 1);
+ return 0;
+ }
+
+ kbase_process_page_usage_inc(kctx, 1);
+
+ for (i = 0; i < KBASE_MMU_PAGE_ENTRIES; i++)
+ page[i] = ENTRY_IS_INVAL;
+
+ /* Clean the full page */
+ ksync_kern_vrange_gpu(pgd, page, KBASE_MMU_PAGE_ENTRIES * sizeof(u64));
+ osk_kunmap(pgd, page);
+ return pgd;
+}
+KBASE_EXPORT_TEST_API(kbase_mmu_alloc_pgd)
+
+static osk_phy_addr mmu_pte_to_phy_addr(u64 entry)
+{
+ if (!(entry & 1))
+ return 0;
+
+ return entry & ~0xFFF;
+}
+
+static u64 mmu_phyaddr_to_pte(osk_phy_addr phy)
+{
+ return (phy & ~0xFFF) | ENTRY_IS_PTE;
+}
+
+static u64 mmu_phyaddr_to_ate(osk_phy_addr phy, u64 flags)
+{
+ return (phy & ~0xFFF) | (flags & ENTRY_FLAGS_MASK) | ENTRY_IS_ATE;
+}
+
+/* Given PGD PFN for level N, return PGD PFN for level N+1 */
+static osk_phy_addr mmu_get_next_pgd(kbase_context *kctx,
+ osk_phy_addr pgd, u64 vpfn, int level)
+{
+ u64 *page;
+ osk_phy_addr target_pgd;
+
+ OSK_ASSERT(pgd);
+
+ /*
+ * Architecture spec defines level-0 as being the top-most.
+ * This is a bit unfortunate here, but we keep the same convention.
+ */
+ vpfn >>= (3 - level) * 9;
+ vpfn &= 0x1FF;
+
+ page = osk_kmap(pgd);
+ if(NULL == page)
+ {
+ OSK_PRINT_WARN(OSK_BASE_MMU, "mmu_get_next_pgd: kmap failure\n");
+ return 0;
+ }
+
+ target_pgd = mmu_pte_to_phy_addr(page[vpfn]);
+
+ if (!target_pgd) {
+ target_pgd = kbase_mmu_alloc_pgd(kctx);
+ if(!target_pgd)
+ {
+ OSK_PRINT_WARN(OSK_BASE_MMU, "mmu_get_next_pgd: kbase_mmu_alloc_pgd failure\n");
+ osk_kunmap(pgd, page);
+ return 0;
+ }
+
+ page[vpfn] = mmu_phyaddr_to_pte(target_pgd);
+ ksync_kern_vrange_gpu(pgd + (vpfn * sizeof(u64)), page + vpfn, sizeof(u64));
+ /* Rely on the caller to update the address space flags. */
+ }
+
+ osk_kunmap(pgd, page);
+ return target_pgd;
+}
+
+static osk_phy_addr mmu_get_bottom_pgd(kbase_context *kctx, u64 vpfn)
+{
+ osk_phy_addr pgd;
+ int l;
+
+ pgd = kctx->pgd;
+
+ for (l = MIDGARD_MMU_TOPLEVEL; l < 3; l++) {
+ pgd = mmu_get_next_pgd(kctx, pgd, vpfn, l);
+ /* Handle failure condition */
+ if(!pgd)
+ {
+ OSK_PRINT_WARN(OSK_BASE_MMU, "mmu_get_bottom_pgd: mmu_get_next_pgd failure\n");
+ return 0;
+ }
+ }
+
+ return pgd;
+}
+
+static osk_phy_addr mmu_insert_pages_recover_get_next_pgd(kbase_context *kctx,
+ osk_phy_addr pgd, u64 vpfn, int level)
+{
+ u64 *page;
+ osk_phy_addr target_pgd;
+
+ OSK_ASSERT(pgd);
+ CSTD_UNUSED(kctx);
+
+ /*
+ * Architecture spec defines level-0 as being the top-most.
+ * This is a bit unfortunate here, but we keep the same convention.
+ */
+ vpfn >>= (3 - level) * 9;
+ vpfn &= 0x1FF;
+
+ page = osk_kmap_atomic(pgd);
+ /* osk_kmap_atomic should NEVER fail */
+ OSK_ASSERT(NULL != page);
+
+ target_pgd = mmu_pte_to_phy_addr(page[vpfn]);
+ /* As we are recovering from what has already been set up, we should have a target_pgd */
+ OSK_ASSERT(0 != target_pgd);
+
+ osk_kunmap_atomic(pgd, page);
+ return target_pgd;
+}
+
+static osk_phy_addr mmu_insert_pages_recover_get_bottom_pgd(kbase_context *kctx, u64 vpfn)
+{
+ osk_phy_addr pgd;
+ int l;
+
+ pgd = kctx->pgd;
+
+ for (l = MIDGARD_MMU_TOPLEVEL; l < 3; l++) {
+ pgd = mmu_insert_pages_recover_get_next_pgd(kctx, pgd, vpfn, l);
+ /* Should never fail */
+ OSK_ASSERT(0 != pgd);
+ }
+
+ return pgd;
+}
+
+static void mmu_insert_pages_failure_recovery(kbase_context *kctx, u64 vpfn,
+ osk_phy_addr *phys, u32 nr)
+{
+ osk_phy_addr pgd;
+ u64 *pgd_page;
+
+ OSK_ASSERT( NULL != kctx );
+ OSK_ASSERT( 0 != vpfn );
+ OSK_ASSERT( vpfn <= (UINT64_MAX / PAGE_SIZE) ); /* 64-bit address range is the max */
+
+ while (nr) {
+ u32 i;
+ u32 index = vpfn & 0x1FF;
+ u32 count = KBASE_MMU_PAGE_ENTRIES - index;
+
+ if (count > nr)
+ {
+ count = nr;
+ }
+
+ pgd = mmu_insert_pages_recover_get_bottom_pgd(kctx, vpfn);
+ OSK_ASSERT(0 != pgd);
+
+ pgd_page = osk_kmap_atomic(pgd);
+ OSK_ASSERT(NULL != pgd_page);
+
+ /* Invalidate the entries we added */
+ for (i = 0; i < count; i++) {
+ pgd_page[index + i] = ENTRY_IS_INVAL;
+ }
+
+ phys += count;
+ vpfn += count;
+ nr -= count;
+
+ ksync_kern_vrange_gpu(pgd + (index * sizeof(u64)), pgd_page + index, count * sizeof(u64));
+
+ osk_kunmap_atomic(pgd, pgd_page);
+ }
+}
+
+/*
+ * Map 'nr' pages pointed to by 'phys' at GPU PFN 'vpfn'
+ */
+mali_error kbase_mmu_insert_pages(kbase_context *kctx, u64 vpfn,
+ osk_phy_addr *phys, u32 nr, u32 flags)
+{
+ osk_phy_addr pgd;
+ u64 *pgd_page;
+ u64 mmu_flags = 0;
+ /* In case the insert_pages only partially completes we need to be able to recover */
+ mali_bool recover_required = MALI_FALSE;
+ u64 recover_vpfn = vpfn;
+ osk_phy_addr *recover_phys = phys;
+ u32 recover_count = 0;
+
+ OSK_ASSERT( NULL != kctx );
+ OSK_ASSERT( 0 != vpfn );
+ OSK_ASSERT( (flags & ~((1 << KBASE_REG_FLAGS_NR_BITS) - 1)) == 0 );
+ OSK_ASSERT( vpfn <= (UINT64_MAX / PAGE_SIZE) ); /* 64-bit address range is the max */
+
+ mmu_flags |= (flags & KBASE_REG_GPU_WR) ? ENTRY_WR_BIT : 0; /* write perm if requested */
+ mmu_flags |= (flags & KBASE_REG_GPU_RD) ? ENTRY_RD_BIT : 0; /* read perm if requested */
+ mmu_flags |= (flags & KBASE_REG_GPU_NX) ? ENTRY_NX_BIT : 0; /* nx if requested */
+
+ if (flags & KBASE_REG_SHARE_BOTH)
+ {
+ /* inner and outer shareable */
+ mmu_flags |= SHARE_BOTH_BITS;
+ }
+ else if (flags & KBASE_REG_SHARE_IN)
+ {
+ /* inner shareable coherency */
+ mmu_flags |= SHARE_INNER_BITS;
+ }
+
+ while (nr) {
+ u32 i;
+ u32 index = vpfn & 0x1FF;
+ u32 count = KBASE_MMU_PAGE_ENTRIES - index;
+
+ if (count > nr)
+ count = nr;
+
+ /*
+ * Repeatedly calling mmu_get_bottom_pte() is clearly
+ * suboptimal. We don't have to re-parse the whole tree
+ * each time (just cache the l0-l2 sequence).
+ * On the other hand, it's only a gain when we map more than
+ * 256 pages at once (on average). Do we really care?
+ */
+ pgd = mmu_get_bottom_pgd(kctx, vpfn);
+ if(!pgd)
+ {
+ OSK_PRINT_WARN(OSK_BASE_MMU, "kbase_mmu_insert_pages: mmu_get_bottom_pgd failure\n");
+ if(recover_required)
+ {
+ /* Invalidate the pages we have partially completed */
+ mmu_insert_pages_failure_recovery(kctx, recover_vpfn, recover_phys, recover_count);
+ }
+ return MALI_ERROR_FUNCTION_FAILED;
+ }
+
+ pgd_page = osk_kmap(pgd);
+ if(!pgd_page)
+ {
+ OSK_PRINT_WARN(OSK_BASE_MMU, "kbase_mmu_insert_pages: kmap failure\n");
+ if(recover_required)
+ {
+ /* Invalidate the pages we have partially completed */
+ mmu_insert_pages_failure_recovery(kctx, recover_vpfn, recover_phys, recover_count);
+ }
+ return MALI_ERROR_OUT_OF_MEMORY;
+ }
+
+ for (i = 0; i < count; i++) {
+ OSK_ASSERT(0 == (pgd_page[index + i] & 1UL));
+ pgd_page[index + i] = mmu_phyaddr_to_ate(phys[i], mmu_flags);
+ }
+
+ phys += count;
+ vpfn += count;
+ nr -= count;
+
+ ksync_kern_vrange_gpu(pgd + (index * sizeof(u64)), pgd_page + index, count * sizeof(u64));
+
+ osk_kunmap(pgd, pgd_page);
+ /* We have started modifying the page table. If further pages need inserting and fail we need to
+ * undo what has already taken place */
+ recover_required = MALI_TRUE;
+ recover_count+= count;
+ }
+ return MALI_ERROR_NONE;
+}
+KBASE_EXPORT_TEST_API(kbase_mmu_insert_pages)
+
+/*
+ * We actually only discard the ATE, and not the page table
+ * pages. There is a potential DoS here, as we'll leak memory by
+ * having PTEs that are potentially unused. Will require physical
+ * page accounting, so MMU pages are part of the process allocation.
+ *
+ * IMPORTANT: This uses kbasep_js_runpool_release_ctx() when the context is
+ * currently scheduled into the runpool, and so potentially uses a lot of locks.
+ * These locks must be taken in the correct order with respect to others
+ * already held by the caller. Refer to kbasep_js_runpool_release_ctx() for more
+ * information.
+ */
+ mali_error kbase_mmu_teardown_pages(kbase_context *kctx, u64 vpfn, u32 nr)
+{
+ osk_phy_addr pgd;
+ u64 *pgd_page;
+ kbase_device *kbdev;
+ mali_bool ctx_is_in_runpool;
+ u32 requested_nr = nr;
+
+ beenthere("kctx %p vpfn %lx nr %d", (void *)kctx, (unsigned long)vpfn, nr);
+
+ OSK_ASSERT(NULL != kctx);
+
+ if (0 == nr)
+ {
+ /* early out if nothing to do */
+ return MALI_ERROR_NONE;
+ }
+
+ kbdev = kctx->kbdev;
+
+ while (nr)
+ {
+ u32 i;
+ u32 index = vpfn & 0x1FF;
+ u32 count = KBASE_MMU_PAGE_ENTRIES - index;
+ if (count > nr)
+ count = nr;
+
+ pgd = mmu_get_bottom_pgd(kctx, vpfn);
+ if(!pgd)
+ {
+ OSK_PRINT_WARN(OSK_BASE_MMU, "kbase_mmu_teardown_pages: mmu_get_bottom_pgd failure\n");
+ return MALI_ERROR_FUNCTION_FAILED;
+ }
+
+ pgd_page = osk_kmap(pgd);
+ if(!pgd_page)
+ {
+ OSK_PRINT_WARN(OSK_BASE_MMU, "kbase_mmu_teardown_pages: kmap failure\n");
+ return MALI_ERROR_OUT_OF_MEMORY;
+ }
+
+ for (i = 0; i < count; i++) {
+ /*
+ * Possible micro-optimisation: only write to the
+ * low 32bits. That's enough to invalidate the mapping.
+ */
+ pgd_page[index + i] = ENTRY_IS_INVAL;
+ }
+
+ vpfn += count;
+ nr -= count;
+
+ ksync_kern_vrange_gpu(pgd + (index * sizeof(u64)), pgd_page + index, count * sizeof(u64));
+
+ osk_kunmap(pgd, pgd_page);
+ }
+
+ /* We must flush if we're currently running jobs. At the very least, we need to retain the
+ * context to ensure it doesn't schedule out whilst we're trying to flush it */
+ ctx_is_in_runpool = kbasep_js_runpool_retain_ctx( kbdev, kctx );
+
+ if ( ctx_is_in_runpool )
+ {
+ OSK_ASSERT( kctx->as_nr != KBASEP_AS_NR_INVALID );
+
+ /* Second level check is to try to only do this when jobs are running. The refcount is
+ * a heuristic for this. */
+ if ( kbdev->js_data.runpool_irq.per_as_data[kctx->as_nr].as_busy_refcount >= 2 )
+ {
+ /* Lock the VA region we're about to update */
+ u64 lock_addr = lock_region(kbdev, vpfn, requested_nr);
+ u32 max_loops = KBASE_AS_FLUSH_MAX_LOOPS;
+
+ /* AS transaction begin */
+ mutex_lock(&kbdev->as[kctx->as_nr].transaction_mutex);
+ kbase_reg_write(kctx->kbdev, MMU_AS_REG(kctx->as_nr, ASn_LOCKADDR_LO), lock_addr & 0xFFFFFFFFUL, kctx);
+ kbase_reg_write(kctx->kbdev, MMU_AS_REG(kctx->as_nr, ASn_LOCKADDR_HI), lock_addr >> 32, kctx);
+ kbase_reg_write(kctx->kbdev, MMU_AS_REG(kctx->as_nr, ASn_COMMAND), ASn_COMMAND_LOCK, kctx);
+
+ /* flush L2 and unlock the VA */
+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_6367))
+ {
+ kbase_reg_write(kctx->kbdev, MMU_AS_REG(kctx->as_nr, ASn_COMMAND), ASn_COMMAND_FLUSH, kctx);
+ }
+ else
+ {
+ kbase_reg_write(kctx->kbdev, MMU_AS_REG(kctx->as_nr, ASn_COMMAND), ASn_COMMAND_FLUSH_MEM, kctx);
+ }
+
+ /* wait for the flush to complete */
+ while (--max_loops &&
+ kbase_reg_read(kctx->kbdev, MMU_AS_REG(kctx->as_nr, ASn_STATUS), kctx) & ASn_STATUS_FLUSH_ACTIVE)
+ {
+ }
+
+ if (!max_loops)
+ {
+ /* Flush failed to complete, assume the GPU has hung and perform a reset to recover */
+ OSK_PRINT_ERROR(OSK_BASE_MMU, "ASn_STATUS_FLUSH_ACTIVE stuck set. Resetting to recover\n");
+ if (kbase_prepare_to_reset_gpu(kbdev))
+ {
+ kbase_reset_gpu(kbdev);
+ }
+ }
+
+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_9630))
+ {
+ /* Issue an UNLOCK command to ensure that valid page tables are re-read by the GPU after an update.
+ Note that, the FLUSH command should perform all the actions necessary, however the bus logs show
+ that if multiple page faults occur within an 8 page region the MMU does not always re-read the
+ updated page table entries for later faults or is only partially read, it subsequently raises the
+ page fault IRQ for the same addresses, the unlock ensures that the MMU cache is flushed, so updates
+ can be re-read. As the region is now unlocked we need to issue 2 UNLOCK commands in order to flush the
+ MMU/uTLB, see PRLAM-8812.
+ */
+ kbase_reg_write(kctx->kbdev, MMU_AS_REG(kctx->as_nr, ASn_COMMAND), ASn_COMMAND_UNLOCK, kctx);
+ kbase_reg_write(kctx->kbdev, MMU_AS_REG(kctx->as_nr, ASn_COMMAND), ASn_COMMAND_UNLOCK, kctx);
+ }
+
+ mutex_unlock(&kbdev->as[kctx->as_nr].transaction_mutex);
+ /* AS transaction end */
+ }
+ kbasep_js_runpool_release_ctx( kbdev, kctx );
+ }
+ return MALI_ERROR_NONE;
+}
+KBASE_EXPORT_TEST_API(kbase_mmu_teardown_pages)
+
+static int mmu_pte_is_valid(u64 pte)
+{
+ return ((pte & 3) == ENTRY_IS_ATE);
+}
+
+/* This is a debug feature only */
+static void mmu_check_unused(kbase_context *kctx, osk_phy_addr pgd)
+{
+ u64 *page;
+ int i;
+ CSTD_UNUSED(kctx);
+
+ page = osk_kmap_atomic(pgd);
+ /* kmap_atomic should NEVER fail. */
+ OSK_ASSERT(NULL != page);
+
+ for (i = 0; i < KBASE_MMU_PAGE_ENTRIES; i++)
+ {
+ if (mmu_pte_is_valid(page[i]))
+ {
+ beenthere("live pte %016lx", (unsigned long)page[i]);
+ }
+ }
+ osk_kunmap_atomic(pgd, page);
+}
+
+static void mmu_teardown_level(kbase_context *kctx, osk_phy_addr pgd, int level, int zap, u64 *pgd_page_buffer)
+{
+ osk_phy_addr target_pgd;
+ u64 *pgd_page;
+ int i;
+
+ pgd_page = osk_kmap_atomic(pgd);
+ /* kmap_atomic should NEVER fail. */
+ OSK_ASSERT(NULL != pgd_page);
+ /* Copy the page to our preallocated buffer so that we can minimize kmap_atomic usage */
+ memcpy(pgd_page_buffer, pgd_page, PAGE_SIZE);
+ osk_kunmap_atomic(pgd, pgd_page);
+ pgd_page = pgd_page_buffer;
+
+ for (i = 0; i < KBASE_MMU_PAGE_ENTRIES; i++) {
+ target_pgd = mmu_pte_to_phy_addr(pgd_page[i]);
+
+ if (target_pgd) {
+ if (level < 2)
+ {
+ mmu_teardown_level(kctx, target_pgd, level + 1, zap, pgd_page_buffer+(PAGE_SIZE/sizeof(u64)));
+ }
+ else {
+ /*
+ * So target_pte is a level-3 page.
+ * As a leaf, it is safe to free it.
+ * Unless we have live pages attached to it!
+ */
+ mmu_check_unused(kctx, target_pgd);
+ }
+
+ beenthere("pte %lx level %d", (unsigned long)target_pgd, level + 1);
+ if (zap)
+ {
+ kbase_mem_allocator_free(kctx->pgd_allocator, 1, &target_pgd);
+ kbase_process_page_usage_dec(kctx, 1);
+ kbase_mem_usage_release_pages(&kctx->usage, 1);
+ }
+ }
+ }
+}
+
+mali_error kbase_mmu_init(kbase_context *kctx)
+{
+ OSK_ASSERT(NULL != kctx);
+ OSK_ASSERT(NULL == kctx->mmu_teardown_pages);
+
+ /* Preallocate MMU depth of four pages for mmu_teardown_level to use */
+ if(OSK_SIMULATE_FAILURE(OSK_OSK))
+ {
+ kctx->mmu_teardown_pages = NULL;
+ }
+ else
+ {
+ kctx->mmu_teardown_pages = kmalloc(PAGE_SIZE*4, GFP_KERNEL);
+ }
+
+ if(NULL == kctx->mmu_teardown_pages)
+ {
+ return MALI_ERROR_OUT_OF_MEMORY;
+ }
+ return MALI_ERROR_NONE;
+}
+
+void kbase_mmu_term(kbase_context *kctx)
+{
+ OSK_ASSERT(NULL != kctx);
+ OSK_ASSERT(NULL != kctx->mmu_teardown_pages);
+
+ kfree(kctx->mmu_teardown_pages);
+ kctx->mmu_teardown_pages = NULL;
+}
+
+void kbase_mmu_free_pgd(kbase_context *kctx)
+{
+ OSK_ASSERT(NULL != kctx);
+ OSK_ASSERT(NULL != kctx->mmu_teardown_pages);
+
+ mmu_teardown_level(kctx, kctx->pgd, MIDGARD_MMU_TOPLEVEL, 1, kctx->mmu_teardown_pages);
+
+ beenthere("pgd %lx", (unsigned long)kctx->pgd);
+ kbase_mem_allocator_free(kctx->pgd_allocator, 1, &kctx->pgd);
+ kbase_process_page_usage_dec(kctx, 1 );
+ kbase_mem_usage_release_pages(&kctx->usage, 1);
+}
+KBASE_EXPORT_TEST_API(kbase_mmu_free_pgd)
+
+static size_t kbasep_mmu_dump_level(kbase_context *kctx, osk_phy_addr pgd, int level, char **buffer, size_t *size_left)
+{
+ osk_phy_addr target_pgd;
+ u64 *pgd_page;
+ int i;
+ size_t size = KBASE_MMU_PAGE_ENTRIES*sizeof(u64)+sizeof(u64);
+ size_t dump_size;
+
+ pgd_page = osk_kmap(pgd);
+ if(!pgd_page)
+ {
+ OSK_PRINT_WARN(OSK_BASE_MMU, "kbasep_mmu_dump_level: kmap failure\n");
+ return 0;
+ }
+
+ if (*size_left >= size)
+ {
+ /* A modified physical address that contains the page table level */
+ u64 m_pgd = pgd | level;
+
+ /* Put the modified physical address in the output buffer */
+ memcpy(*buffer, &m_pgd, sizeof(m_pgd));
+ *buffer += sizeof(m_pgd);
+
+ /* Followed by the page table itself */
+ memcpy(*buffer, pgd_page, sizeof(u64)*KBASE_MMU_PAGE_ENTRIES);
+ *buffer += sizeof(u64)*KBASE_MMU_PAGE_ENTRIES;
+
+ *size_left -= size;
+ }
+
+ for (i = 0; i < KBASE_MMU_PAGE_ENTRIES; i++) {
+ if ((pgd_page[i] & ENTRY_IS_PTE) == ENTRY_IS_PTE) {
+ target_pgd = mmu_pte_to_phy_addr(pgd_page[i]);
+
+ dump_size = kbasep_mmu_dump_level(kctx, target_pgd, level + 1, buffer, size_left);
+ if(!dump_size)
+ {
+ osk_kunmap(pgd, pgd_page);
+ return 0;
+ }
+ size += dump_size;
+ }
+ }
+
+ osk_kunmap(pgd, pgd_page);
+
+ return size;
+}
+
+void *kbase_mmu_dump(kbase_context *kctx,int nr_pages)
+{
+ void *kaddr;
+ size_t size_left;
+
+ OSK_ASSERT(kctx);
+
+ if (0 == nr_pages)
+ {
+ /* can't find in a 0 sized buffer, early out */
+ return NULL;
+ }
+
+ size_left = nr_pages * PAGE_SIZE;
+
+ if(OSK_SIMULATE_FAILURE(OSK_OSK))
+ {
+ kaddr = NULL;
+ }
+ else
+ {
+ OSK_ASSERT(0 != size_left);
+ kaddr = vmalloc_user(size_left);
+ }
+
+ if (kaddr)
+ {
+ u64 end_marker = 0xFFULL;
+ char *buffer = (char*)kaddr;
+
+ size_t size = kbasep_mmu_dump_level(kctx, kctx->pgd, MIDGARD_MMU_TOPLEVEL, &buffer, &size_left);
+ if(!size)
+ {
+ vfree(kaddr);
+ return NULL;
+ }
+
+ /* Add on the size for the end marker */
+ size += sizeof(u64);
+
+ if (size > nr_pages * PAGE_SIZE || size_left < sizeof(u64)) {
+ /* The buffer isn't big enough - free the memory and return failure */
+ vfree(kaddr);
+ return NULL;
+ }
+
+ /* Add the end marker */
+ memcpy(buffer, &end_marker, sizeof(u64));
+ }
+
+ return kaddr;
+}
+KBASE_EXPORT_TEST_API(kbase_mmu_dump)
+
+static u64 lock_region(kbase_device *kbdev, u64 pfn, u32 num_pages)
+{
+ u64 region;
+
+ /* can't lock a zero sized range */
+ OSK_ASSERT(num_pages);
+
+ region = pfn << PAGE_SHIFT;
+ /*
+ * osk_clz returns (given the ASSERT above):
+ * 32-bit: 0 .. 31
+ * 64-bit: 0 .. 63
+ *
+ * 32-bit: 32 + 10 - osk_clz(num_pages)
+ * results in the range (11 .. 42)
+ * 64-bit: 64 + 10 - osk_clz(num_pages)
+ * results in the range (11 .. 42)
+ */
+
+ /* gracefully handle num_pages being zero */
+ if (0 == num_pages)
+ {
+ region |= 11;
+ }
+ else
+ {
+ u8 region_width;
+ region_width = ( OSK_BITS_PER_LONG + 10 - osk_clz(num_pages) );
+ if (num_pages != (1ul << (region_width - 11)))
+ {
+ /* not pow2, so must go up to the next pow2 */
+ region_width += 1;
+ }
+ OSK_ASSERT(region_width <= KBASE_LOCK_REGION_MAX_SIZE);
+ OSK_ASSERT(region_width >= KBASE_LOCK_REGION_MIN_SIZE);
+ region |= region_width;
+ }
+
+ return region;
+}
+
+static void bus_fault_worker(struct work_struct *data)
+{
+ const int num_as = 16;
+ kbase_as * faulting_as;
+ int as_no;
+ kbase_context * kctx;
+ kbase_device * kbdev;
+ u32 reg;
+ mali_bool reset_status= MALI_FALSE;
+
+ faulting_as = container_of(data, kbase_as, work_busfault);
+ as_no = faulting_as->number;
+
+ kbdev = container_of( faulting_as, kbase_device, as[as_no] );
+
+ /* Grab the context that was already refcounted in kbase_mmu_interrupt().
+ * Therefore, it cannot be scheduled out of this AS until we explicitly release it
+ *
+ * NOTE: NULL can be returned here if we're gracefully handling a spurious interrupt */
+ kctx = kbasep_js_runpool_lookup_ctx_noretain( kbdev, as_no );
+
+ /* switch to UNMAPPED mode, will abort all jobs and stop any hw counter dumping */
+ /* AS transaction begin */
+ mutex_lock(&kbdev->as[as_no].transaction_mutex);
+
+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8245))
+ {
+ /* Due to H/W issue 8245 we need to reset the GPU after using UNMAPPED mode.
+ * We start the reset before switching to UNMAPPED to ensure that unrelated jobs
+ * are evicted from the GPU before the switch.
+ */
+ OSK_PRINT_WARN(OSK_BASE_MMU, "NOTE: GPU will now be reset as a workaround for a hardware issue*");
+ reset_status = kbase_prepare_to_reset_gpu(kbdev);
+ }
+
+ reg = kbase_reg_read(kbdev, MMU_AS_REG(as_no, ASn_TRANSTAB_LO), kctx);
+ reg &= ~3;
+ kbase_reg_write(kbdev, MMU_AS_REG(as_no, ASn_TRANSTAB_LO), reg, kctx);
+ kbase_reg_write(kbdev, MMU_AS_REG(as_no, ASn_COMMAND), ASn_COMMAND_UPDATE, kctx);
+
+ kbase_reg_write(kbdev, MMU_REG(MMU_IRQ_CLEAR), (1UL << as_no) | (1UL << (as_no + num_as)) , NULL);
+ mutex_unlock(&kbdev->as[as_no].transaction_mutex);
+ /* AS transaction end */
+
+ mmu_mask_reenable( kbdev, kctx, faulting_as );
+
+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8245) && reset_status)
+ {
+ kbase_reset_gpu(kbdev);
+ }
+
+ /* By this point, the fault was handled in some way, so release the ctx refcount */
+ if ( kctx != NULL )
+ {
+ kbasep_js_runpool_release_ctx( kbdev, kctx );
+ }
+}
+
+void kbase_mmu_interrupt(kbase_device * kbdev, u32 irq_stat)
+{
+ unsigned long flags;
+ const int num_as = 16;
+ kbasep_js_device_data *js_devdata;
+ const int busfault_shift = 16;
+ const int pf_shift = 0;
+ const unsigned long mask = (1UL << num_as) - 1;
+
+ u64 fault_addr;
+ u32 new_mask;
+ u32 tmp;
+
+ u32 bf_bits = (irq_stat >> busfault_shift) & mask; /* bus faults */
+ /* Ignore ASes with both pf and bf */
+ u32 pf_bits = ((irq_stat >> pf_shift) & mask) & ~bf_bits; /* page faults */
+
+ OSK_ASSERT( NULL != kbdev);
+
+ js_devdata = &kbdev->js_data;
+
+ /* remember current mask */
+ spin_lock_irqsave(&kbdev->mmu_mask_change, flags);
+ new_mask = kbase_reg_read(kbdev, MMU_REG(MMU_IRQ_MASK), NULL);
+ /* mask interrupts for now */
+ kbase_reg_write(kbdev, MMU_REG(MMU_IRQ_MASK), 0, NULL);
+ spin_unlock_irqrestore(&kbdev->mmu_mask_change, flags);
+
+ while (bf_bits)
+ {
+ kbase_as * as;
+ int as_no;
+ kbase_context * kctx;
+
+ /* the while logic ensures we have a bit set, no need to check for not-found here */
+ as_no = osk_find_first_set_bit(bf_bits);
+
+ /* Refcount the kctx ASAP - it shouldn't disappear anyway, since Bus/Page faults
+ * _should_ only occur whilst jobs are running, and a job causing the Bus/Page fault
+ * shouldn't complete until the MMU is updated */
+ kctx = kbasep_js_runpool_lookup_ctx( kbdev, as_no );
+
+ /* mark as handled */
+ bf_bits &= ~(1UL << as_no);
+
+ /* find faulting address */
+ fault_addr = kbase_reg_read(kbdev, MMU_AS_REG(as_no, ASn_FAULTADDRESS_HI), kctx);
+ fault_addr <<= 32;
+ fault_addr |= kbase_reg_read(kbdev, MMU_AS_REG(as_no, ASn_FAULTADDRESS_LO), kctx);
+
+ if (kctx)
+ {
+ /* hw counters dumping in progress, signal the other thread that it failed */
+ if ((kbdev->hwcnt.kctx == kctx) && (kbdev->hwcnt.state == KBASE_INSTR_STATE_DUMPING))
+ {
+ kbdev->hwcnt.state = KBASE_INSTR_STATE_FAULT;
+ }
+
+ /* Stop the kctx from submitting more jobs and cause it to be scheduled
+ * out/rescheduled when all references to it are released */
+ spin_lock_irqsave( &js_devdata->runpool_irq.lock, flags);
+ kbasep_js_clear_submit_allowed( js_devdata, kctx );
+ spin_unlock_irqrestore( &js_devdata->runpool_irq.lock, flags);
+
+ OSK_PRINT_WARN(OSK_BASE_MMU, "Bus error in AS%d at 0x%016llx\n", as_no, fault_addr);
+ }
+ else
+ {
+ OSK_PRINT_WARN(OSK_BASE_MMU,
+ "Bus error in AS%d at 0x%016llx with no context present! "
+ "Suprious IRQ or SW Design Error?\n",
+ as_no, fault_addr);
+ }
+
+ as = &kbdev->as[as_no];
+
+ /* remove the queued BFs from the mask */
+ new_mask &= ~(1UL << (as_no + num_as));
+
+ /* We need to switch to UNMAPPED mode - but we do this in a worker so that we can sleep */
+ OSK_ASSERT(0 == object_is_on_stack(&as->work_busfault));
+ INIT_WORK(&as->work_busfault, bus_fault_worker);
+ queue_work(as->pf_wq, &as->work_busfault);
+ }
+
+ /*
+ * pf_bits is non-zero if we have at least one AS with a page fault and no bus fault.
+ * Handle the PFs in our worker thread.
+ */
+ while (pf_bits)
+ {
+ kbase_as * as;
+ /* the while logic ensures we have a bit set, no need to check for not-found here */
+ int as_no = osk_find_first_set_bit(pf_bits);
+ kbase_context * kctx;
+
+ /* Refcount the kctx ASAP - it shouldn't disappear anyway, since Bus/Page faults
+ * _should_ only occur whilst jobs are running, and a job causing the Bus/Page fault
+ * shouldn't complete until the MMU is updated */
+ kctx = kbasep_js_runpool_lookup_ctx( kbdev, as_no );
+
+ /* mark as handled */
+ pf_bits &= ~(1UL << as_no);
+
+ /* find faulting address */
+ fault_addr = kbase_reg_read(kbdev, MMU_AS_REG(as_no, ASn_FAULTADDRESS_HI), kctx);
+ fault_addr <<= 32;
+ fault_addr |= kbase_reg_read(kbdev, MMU_AS_REG(as_no, ASn_FAULTADDRESS_LO), kctx);
+
+ if ( kctx == NULL )
+ {
+ OSK_PRINT_WARN(OSK_BASE_MMU,
+ "Page fault in AS%d at 0x%016llx with no context present! "
+ "Suprious IRQ or SW Design Error?\n",
+ as_no, fault_addr);
+ }
+
+ as = &kbdev->as[as_no];
+
+ /* remove the queued PFs from the mask */
+ new_mask &= ~((1UL << as_no) | (1UL << (as_no + num_as)));
+
+ /* queue work pending for this AS */
+ as->fault_addr = fault_addr;
+
+ OSK_ASSERT(0 == object_is_on_stack(&as->work_pagefault));
+ INIT_WORK(&as->work_pagefault, page_fault_worker);
+ queue_work(as->pf_wq, &as->work_pagefault);
+ }
+
+ /* reenable interrupts */
+ spin_lock_irqsave(&kbdev->mmu_mask_change, flags);
+ tmp = kbase_reg_read(kbdev, MMU_REG(MMU_IRQ_MASK), NULL);
+ new_mask |= tmp;
+ kbase_reg_write(kbdev, MMU_REG(MMU_IRQ_MASK), new_mask, NULL);
+ spin_unlock_irqrestore(&kbdev->mmu_mask_change, flags);
+}
+KBASE_EXPORT_TEST_API(kbase_mmu_interrupt)
+
+const char *kbase_exception_name(u32 exception_code)
+{
+ const char *e;
+
+ switch(exception_code)
+ {
+ /* Non-Fault Status code */
+ case 0x00: e = "NOT_STARTED/IDLE/OK"; break;
+ case 0x01: e = "DONE"; break;
+ case 0x02: e = "INTERRUPTED"; break;
+ case 0x03: e = "STOPPED"; break;
+ case 0x04: e = "TERMINATED"; break;
+ case 0x08: e = "ACTIVE"; break;
+ /* Job exceptions */
+ case 0x40: e = "JOB_CONFIG_FAULT"; break;
+ case 0x41: e = "JOB_POWER_FAULT"; break;
+ case 0x42: e = "JOB_READ_FAULT"; break;
+ case 0x43: e = "JOB_WRITE_FAULT"; break;
+ case 0x44: e = "JOB_AFFINITY_FAULT"; break;
+ case 0x48: e = "JOB_BUS_FAULT"; break;
+ case 0x50: e = "INSTR_INVALID_PC"; break;
+ case 0x51: e = "INSTR_INVALID_ENC"; break;
+ case 0x52: e = "INSTR_TYPE_MISMATCH"; break;
+ case 0x53: e = "INSTR_OPERAND_FAULT"; break;
+ case 0x54: e = "INSTR_TLS_FAULT"; break;
+ case 0x55: e = "INSTR_BARRIER_FAULT"; break;
+ case 0x56: e = "INSTR_ALIGN_FAULT"; break;
+ case 0x58: e = "DATA_INVALID_FAULT"; break;
+ case 0x59: e = "TILE_RANGE_FAULT"; break;
+ case 0x5A: e = "ADDR_RANGE_FAULT"; break;
+ case 0x60: e = "OUT_OF_MEMORY"; break;
+ /* GPU exceptions */
+ case 0x80: e = "DELAYED_BUS_FAULT"; break;
+ case 0x81: e = "SHAREABILITY_FAULT"; break;
+ /* MMU exceptions */
+ case 0xC0: case 0xC1: case 0xC2: case 0xC3:
+ case 0xC4: case 0xC5: case 0xC6: case 0xC7:
+ e = "TRANSLATION_FAULT"; break;
+ case 0xC8: e = "PERMISSION_FAULT"; break;
+ case 0xD0: case 0xD1: case 0xD2: case 0xD3:
+ case 0xD4: case 0xD5: case 0xD6: case 0xD7:
+ e = "TRANSTAB_BUS_FAULT"; break;
+ case 0xD8: e = "ACCESS_FLAG"; break;
+ default:
+ e = "UNKNOWN"; break;
+ };
+
+ return e;
+}
+
+/**
+ * The caller must ensure it's retained the ctx to prevent it from being scheduled out whilst it's being worked on.
+ */
+static void kbase_mmu_report_fault_and_kill(kbase_context *kctx, kbase_as * as, mali_addr64 fault_addr)
+{
+ unsigned long flags;
+ u32 fault_status;
+ u32 reg;
+ int exception_type;
+ int access_type;
+ int source_id;
+ int as_no;
+ kbase_device * kbdev;
+ kbasep_js_device_data *js_devdata;
+ mali_bool reset_status = MALI_FALSE;
+#ifdef CONFIG_MALI_DEBUG
+ static const char *access_type_names[] = { "RESERVED", "EXECUTE", "READ", "WRITE" };
+#endif /* CONFIG_MALI_DEBUG */
+
+ OSK_ASSERT(as);
+ OSK_ASSERT(kctx);
+ CSTD_UNUSED(fault_addr);
+
+ as_no = as->number;
+ kbdev = kctx->kbdev;
+ js_devdata = &kbdev->js_data;
+
+ /* ASSERT that the context won't leave the runpool */
+ OSK_ASSERT( kbasep_js_debug_check_ctx_refcount( kbdev, kctx ) > 0 );
+
+ fault_status = kbase_reg_read(kbdev, MMU_AS_REG(as_no, ASn_FAULTSTATUS), kctx);
+
+ /* decode the fault status */
+ exception_type = fault_status & 0xFF;
+ access_type = (fault_status >> 8) & 0x3;
+ source_id = (fault_status >> 16);
+
+ /* terminal fault, print info about the fault */
+ OSK_PRINT_WARN(OSK_BASE_MMU, "Fault in AS%d at VA 0x%016llX", as_no, fault_addr);
+ OSK_PRINT_WARN(OSK_BASE_MMU, "raw fault status 0x%X", fault_status);
+ OSK_PRINT_WARN(OSK_BASE_MMU, "decoded fault status (%s):", (fault_status & (1 << 10) ? "DECODER FAULT" : "SLAVE FAULT"));
+ OSK_PRINT_WARN(OSK_BASE_MMU, "exception type 0x%X: %s", exception_type, kbase_exception_name(exception_type));
+ OSK_PRINT_WARN(OSK_BASE_MMU, "access type 0x%X: %s", access_type, access_type_names[access_type]);
+ OSK_PRINT_WARN(OSK_BASE_MMU, "source id 0x%X", source_id);
+
+ /* hardware counters dump fault handling */
+ if ((kbdev->hwcnt.kctx) &&
+ (kbdev->hwcnt.kctx->as_nr == as_no) &&
+ (kbdev->hwcnt.state == KBASE_INSTR_STATE_DUMPING))
+ {
+ u32 num_core_groups = kbdev->gpu_props.num_core_groups;
+ if ((fault_addr >= kbdev->hwcnt.addr) && (fault_addr < (kbdev->hwcnt.addr + (num_core_groups * 2048))))
+ {
+ kbdev->hwcnt.state = KBASE_INSTR_STATE_FAULT;
+ }
+ }
+
+ /* Stop the kctx from submitting more jobs and cause it to be scheduled
+ * out/rescheduled - this will occur on releasing the context's refcount */
+ spin_lock_irqsave( &js_devdata->runpool_irq.lock, flags);
+ kbasep_js_clear_submit_allowed( js_devdata, kctx );
+ spin_unlock_irqrestore( &js_devdata->runpool_irq.lock, flags);
+
+ /* Kill any running jobs from the context. Submit is disallowed, so no more jobs from this
+ * context can appear in the job slots from this point on */
+ kbase_job_kill_jobs_from_context(kctx);
+ /* AS transaction begin */
+ mutex_lock(&as->transaction_mutex);
+
+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8245))
+ {
+ /* Due to H/W issue 8245 we need to reset the GPU after using UNMAPPED mode.
+ * We start the reset before switching to UNMAPPED to ensure that unrelated jobs
+ * are evicted from the GPU before the switch.
+ */
+ OSK_PRINT_WARN(OSK_BASE_MMU, "NOTE: GPU will now be reset as a workaround for a hardware issue**");
+ reset_status = kbase_prepare_to_reset_gpu(kbdev);
+ }
+
+ /* switch to UNMAPPED mode, will abort all jobs and stop any hw counter dumping */
+ reg = kbase_reg_read(kbdev, MMU_AS_REG(as_no, ASn_TRANSTAB_LO), kctx);
+ reg &= ~3;
+ kbase_reg_write(kbdev, MMU_AS_REG(as_no, ASn_TRANSTAB_LO), reg, kctx);
+ kbase_reg_write(kbdev, MMU_AS_REG(as_no, ASn_COMMAND), ASn_COMMAND_UPDATE, kctx);
+
+ kbase_reg_write(kbdev, MMU_REG(MMU_IRQ_CLEAR), (1UL << as_no), NULL);
+
+ mutex_unlock(&as->transaction_mutex);
+ /* AS transaction end */
+ mmu_mask_reenable(kbdev, kctx, as);
+
+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8245) && reset_status)
+ {
+ kbase_reset_gpu(kbdev);
+ }
+}
+
+void kbasep_as_do_poke(struct work_struct *work)
+{
+ kbase_as * as;
+ kbase_device * kbdev;
+
+ OSK_ASSERT(work);
+ as = container_of(work, kbase_as, poke_work);
+ kbdev = container_of(as, kbase_device, as[as->number]);
+
+ kbase_pm_context_active(kbdev);
+
+ /* AS transaction begin */
+ mutex_lock(&as->transaction_mutex);
+ /* Force a uTLB invalidate */
+ kbase_reg_write(kbdev, MMU_AS_REG(as->number, ASn_COMMAND), ASn_COMMAND_UNLOCK, NULL);
+ mutex_unlock(&as->transaction_mutex);
+ /* AS transaction end */
+
+ kbase_pm_context_idle(kbdev);
+
+ if (atomic_read(&as->poke_refcount))
+ {
+ /* still someone depending on the UNLOCK, schedule a run */
+ hrtimer_start(&as->poke_timer, HR_TIMER_DELAY_MSEC(5), HRTIMER_MODE_REL );
+ }
+}
+
+enum hrtimer_restart kbasep_as_poke_timer_callback(struct hrtimer * timer)
+{
+ kbase_as * as = container_of(timer, kbase_as, poke_timer);
+
+ OSK_ASSERT(NULL != as);
+
+ queue_work(as->poke_wq, &as->poke_work);
+
+ return HRTIMER_NORESTART;
+}
+
+void kbase_as_poking_timer_retain(kbase_as * as)
+{
+ OSK_ASSERT(as);
+
+ if (1 == atomic_inc_return(&as->poke_refcount))
+ {
+ /* need to start poking */
+ queue_work(as->poke_wq, &as->poke_work);
+ }
+}
+
+void kbase_as_poking_timer_release(kbase_as * as)
+{
+ OSK_ASSERT(as);
+ atomic_dec(&as->poke_refcount);
+}
+
diff --git a/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_pm.c b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_pm.c
new file mode 100644
index 0000000..124955d
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_pm.c
@@ -0,0 +1,585 @@
+/*
+ *
+ * (C) COPYRIGHT 2010-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_kbase_pm.c
+ * Base kernel power management APIs
+ */
+
+#include <osk/mali_osk.h>
+#include <kbase/src/common/mali_kbase.h>
+#include <kbase/src/common/mali_midg_regmap.h>
+
+#include <kbase/src/common/mali_kbase_pm.h>
+
+/* Policy operation structures */
+extern const kbase_pm_policy kbase_pm_always_on_policy_ops;
+extern const kbase_pm_policy kbase_pm_demand_policy_ops;
+extern const kbase_pm_policy kbase_pm_coarse_demand_policy_ops;
+
+/** A list of the power policies available in the system */
+static const kbase_pm_policy * const policy_list[] =
+{
+#ifdef CONFIG_MALI_NO_MALI
+ &kbase_pm_always_on_policy_ops,
+ &kbase_pm_coarse_demand_policy_ops,
+ &kbase_pm_demand_policy_ops
+#else /* CONFIG_MALI_NO_MALI */
+ &kbase_pm_demand_policy_ops,
+ &kbase_pm_coarse_demand_policy_ops,
+ &kbase_pm_always_on_policy_ops
+#endif /* CONFIG_MALI_NO_MALI */
+};
+
+/** The number of policies available in the system.
+ * This is derived from the number of functions listed in policy_get_functions.
+ */
+#define POLICY_COUNT (sizeof(policy_list)/sizeof(*policy_list))
+
+void kbase_pm_register_access_enable(kbase_device *kbdev)
+{
+ kbase_pm_callback_conf *callbacks;
+
+ callbacks = (kbase_pm_callback_conf*) kbasep_get_config_value(kbdev, kbdev->config_attributes,
+ KBASE_CONFIG_ATTR_POWER_MANAGEMENT_CALLBACKS);
+
+ if (callbacks)
+ {
+ callbacks->power_on_callback(kbdev);
+ }
+}
+
+void kbase_pm_register_access_disable(kbase_device *kbdev)
+{
+ kbase_pm_callback_conf *callbacks;
+
+ callbacks = (kbase_pm_callback_conf*) kbasep_get_config_value(kbdev, kbdev->config_attributes,
+ KBASE_CONFIG_ATTR_POWER_MANAGEMENT_CALLBACKS);
+
+ if (callbacks)
+ {
+ callbacks->power_off_callback(kbdev);
+ }
+}
+
+mali_error kbase_pm_init(kbase_device *kbdev)
+{
+ mali_error ret = MALI_ERROR_NONE;
+ kbase_pm_callback_conf *callbacks;
+
+ OSK_ASSERT(kbdev != NULL);
+
+ kbdev->pm.gpu_powered = MALI_FALSE;
+ atomic_set(&kbdev->pm.gpu_in_desired_state, MALI_TRUE);
+
+ callbacks = (kbase_pm_callback_conf*) kbasep_get_config_value(kbdev, kbdev->config_attributes,
+ KBASE_CONFIG_ATTR_POWER_MANAGEMENT_CALLBACKS);
+ if (callbacks)
+ {
+ kbdev->pm.callback_power_on = callbacks->power_on_callback;
+ kbdev->pm.callback_power_off = callbacks->power_off_callback;
+ kbdev->pm.callback_power_runtime_init = callbacks->power_runtime_init_callback;
+ kbdev->pm.callback_power_runtime_term = callbacks->power_runtime_term_callback;
+ kbdev->pm.callback_power_runtime_on = callbacks->power_runtime_on_callback;
+ kbdev->pm.callback_power_runtime_off = callbacks->power_runtime_off_callback;
+ }
+ else
+ {
+ kbdev->pm.callback_power_on = NULL;
+ kbdev->pm.callback_power_off = NULL;
+ kbdev->pm.callback_power_runtime_init = NULL;
+ kbdev->pm.callback_power_runtime_term = NULL;
+ kbdev->pm.callback_power_runtime_on = NULL;
+ kbdev->pm.callback_power_runtime_off = NULL;
+ }
+
+ /* Initialise the metrics subsystem */
+ ret = kbasep_pm_metrics_init(kbdev);
+ if (MALI_ERROR_NONE != ret)
+ {
+ return ret;
+ }
+ init_waitqueue_head(&kbdev->pm.l2_powered_wait);
+ kbdev->pm.l2_powered = 0;
+
+ init_waitqueue_head(&kbdev->pm.power_state_wait);
+ kbdev->pm.power_state = PM_POWER_STATE_TRANS;
+
+ init_waitqueue_head(&kbdev->pm.no_outstanding_event_wait);
+ kbdev->pm.no_outstanding_event = 1;
+
+ /* Simulate failure to create the workqueue */
+ if(OSK_SIMULATE_FAILURE(OSK_BASE_PM))
+ {
+ kbdev->pm.workqueue = NULL;
+ goto workq_fail;
+ }
+
+ kbdev->pm.workqueue = alloc_workqueue("kbase_pm", WQ_NON_REENTRANT | WQ_HIGHPRI | WQ_MEM_RECLAIM, 1);
+ if (NULL == kbdev->pm.workqueue)
+ {
+ goto workq_fail;
+ }
+
+ spin_lock_init(&kbdev->pm.power_change_lock);
+ spin_lock_init(&kbdev->pm.active_count_lock);
+ spin_lock_init(&kbdev->pm.gpu_cycle_counter_requests_lock);
+ spin_lock_init(&kbdev->pm.gpu_powered_lock);
+ return MALI_ERROR_NONE;
+
+workq_fail:
+ kbasep_pm_metrics_term(kbdev);
+ return MALI_ERROR_FUNCTION_FAILED;
+}
+KBASE_EXPORT_TEST_API(kbase_pm_init)
+
+mali_error kbase_pm_powerup(kbase_device *kbdev)
+{
+ unsigned long flags;
+ mali_error ret;
+
+ OSK_ASSERT(kbdev != NULL);
+
+ ret = kbase_pm_init_hw(kbdev);
+ if (ret != MALI_ERROR_NONE)
+ {
+ return ret;
+ }
+
+ kbase_pm_power_transitioning(kbdev);
+
+ kbasep_pm_read_present_cores(kbdev);
+
+ /* Pretend the GPU is active to prevent a power policy turning the GPU cores off */
+ spin_lock_irqsave(&kbdev->pm.active_count_lock, flags);
+ kbdev->pm.active_count = 1;
+ spin_unlock_irqrestore(&kbdev->pm.active_count_lock, flags);
+
+ spin_lock_irqsave(&kbdev->pm.gpu_cycle_counter_requests_lock, flags);
+ /* Ensure cycle counter is off */
+ kbdev->pm.gpu_cycle_counter_requests = 0;
+ kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_COMMAND), GPU_COMMAND_CYCLE_COUNT_STOP, NULL);
+ spin_unlock_irqrestore(&kbdev->pm.gpu_cycle_counter_requests_lock, flags);
+
+ atomic_set(&kbdev->pm.pending_events, 0);
+
+ atomic_set(&kbdev->pm.work_active, KBASE_PM_WORK_ACTIVE_STATE_INACTIVE);
+
+ kbdev->pm.new_policy = NULL;
+ kbdev->pm.current_policy = policy_list[0];
+ KBASE_TRACE_ADD( kbdev, PM_CURRENT_POLICY_INIT, NULL, NULL, 0u, kbdev->pm.current_policy->id );
+ kbdev->pm.current_policy->init(kbdev);
+
+ kbase_pm_send_event(kbdev, KBASE_PM_EVENT_POLICY_INIT);
+
+ /* Idle the GPU */
+ kbase_pm_context_idle(kbdev);
+
+ return MALI_ERROR_NONE;
+}
+KBASE_EXPORT_TEST_API(kbase_pm_powerup)
+
+void kbase_pm_power_transitioning(kbase_device *kbdev)
+{
+ OSK_ASSERT(kbdev != NULL);
+ kbdev->pm.power_state = PM_POWER_STATE_TRANS;
+ wake_up(&kbdev->pm.power_state_wait);
+}
+
+KBASE_EXPORT_TEST_API(kbase_pm_power_transitioning)
+
+void kbase_pm_power_up_done(kbase_device *kbdev)
+{
+ OSK_ASSERT(kbdev != NULL);
+ kbdev->pm.power_state = PM_POWER_STATE_ON;
+ wake_up(&kbdev->pm.power_state_wait);
+}
+KBASE_EXPORT_TEST_API(kbase_pm_power_up_done)
+
+void kbase_pm_reset_done(kbase_device *kbdev)
+{
+ OSK_ASSERT(kbdev != NULL);
+ kbdev->pm.power_state = PM_POWER_STATE_ON;
+ wake_up(&kbdev->pm.power_state_wait);
+}
+KBASE_EXPORT_TEST_API(kbase_pm_reset_done)
+
+void kbase_pm_power_down_done(kbase_device *kbdev)
+{
+ OSK_ASSERT(kbdev != NULL);
+ kbdev->pm.power_state = PM_POWER_STATE_OFF;
+ wake_up(&kbdev->pm.power_state_wait);
+}
+KBASE_EXPORT_TEST_API(kbase_pm_power_down_done)
+
+static void kbase_pm_wait_for_no_outstanding_events(kbase_device *kbdev)
+{
+ wait_event(kbdev->pm.no_outstanding_event_wait, kbdev->pm.no_outstanding_event == 1);
+}
+
+void kbase_pm_context_active(kbase_device *kbdev)
+{
+ unsigned long flags;
+ int c;
+
+ OSK_ASSERT(kbdev != NULL);
+
+ spin_lock_irqsave(&kbdev->pm.active_count_lock, flags);
+ c = ++kbdev->pm.active_count;
+ spin_unlock_irqrestore(&kbdev->pm.active_count_lock, flags);
+
+ KBASE_TRACE_ADD_REFCOUNT( kbdev, PM_CONTEXT_ACTIVE, NULL, NULL, 0u, c );
+
+ if (c == 1)
+ {
+ /* First context active */
+ kbase_pm_send_event(kbdev, KBASE_PM_EVENT_GPU_ACTIVE);
+
+ kbasep_pm_record_gpu_active(kbdev);
+ }
+ /* Synchronise with the power policy to ensure that the event has been noticed */
+ kbase_pm_wait_for_no_outstanding_events(kbdev);
+
+ kbase_pm_wait_for_power_up(kbdev);
+}
+KBASE_EXPORT_TEST_API(kbase_pm_context_active)
+
+void kbase_pm_context_idle(kbase_device *kbdev)
+{
+ unsigned long flags;
+ int c;
+
+ OSK_ASSERT(kbdev != NULL);
+
+ spin_lock_irqsave(&kbdev->pm.active_count_lock, flags);
+
+ c = --kbdev->pm.active_count;
+
+ KBASE_TRACE_ADD_REFCOUNT( kbdev, PM_CONTEXT_IDLE, NULL, NULL, 0u, c );
+
+ OSK_ASSERT(c >= 0);
+
+ if (c == 0)
+ {
+ /* Last context has gone idle */
+ kbase_pm_send_event(kbdev, KBASE_PM_EVENT_GPU_IDLE);
+
+ kbasep_pm_record_gpu_idle(kbdev);
+ }
+
+ /* We must wait for the above functions to finish (in the case c==0) before releasing the lock otherwise there is
+ * a race with another thread calling kbase_pm_context_active - in this case the IDLE message could be sent
+ * *after* the ACTIVE message causing the policy and metrics systems to become confused
+ */
+ spin_unlock_irqrestore(&kbdev->pm.active_count_lock, flags);
+}
+KBASE_EXPORT_TEST_API(kbase_pm_context_idle)
+
+void kbase_pm_halt(kbase_device *kbdev)
+{
+ OSK_ASSERT(kbdev != NULL);
+
+ if (kbdev->pm.current_policy != NULL)
+ {
+ /* Turn the GPU off */
+ kbase_pm_send_event(kbdev, KBASE_PM_EVENT_SYSTEM_SUSPEND);
+ /* Wait for the policy to acknowledge */
+ kbase_pm_wait_for_power_down(kbdev);
+ }
+}
+KBASE_EXPORT_TEST_API(kbase_pm_halt)
+
+void kbase_pm_term(kbase_device *kbdev)
+{
+ unsigned long flags;
+ OSK_ASSERT(kbdev != NULL);
+ OSK_ASSERT(kbdev->pm.active_count == 0);
+ OSK_ASSERT(kbdev->pm.gpu_cycle_counter_requests == 0);
+
+ /* Destroy the workqueue - this ensures that all messages have been processed */
+ destroy_workqueue(kbdev->pm.workqueue);
+
+ if (kbdev->pm.current_policy != NULL)
+ {
+ /* Free any resources the policy allocated */
+ KBASE_TRACE_ADD( kbdev, PM_CURRENT_POLICY_TERM, NULL, NULL, 0u, kbdev->pm.current_policy->id );
+ kbdev->pm.current_policy->term(kbdev);
+ }
+ /* Synchronise with other threads */
+ spin_lock_irqsave(&kbdev->pm.power_change_lock, flags);
+ spin_unlock_irqrestore(&kbdev->pm.power_change_lock, flags);
+
+ /* Shut down the metrics subsystem */
+ kbasep_pm_metrics_term(kbdev);
+}
+KBASE_EXPORT_TEST_API(kbase_pm_term)
+
+void kbase_pm_wait_for_power_up(kbase_device *kbdev)
+{
+ OSK_ASSERT(kbdev != NULL);
+
+ wait_event(kbdev->pm.power_state_wait, kbdev->pm.power_state == PM_POWER_STATE_ON);
+}
+KBASE_EXPORT_TEST_API(kbase_pm_wait_for_power_up)
+
+void kbase_pm_wait_for_power_down(kbase_device *kbdev)
+{
+ OSK_ASSERT(kbdev != NULL);
+
+ wait_event(kbdev->pm.power_state_wait, kbdev->pm.power_state == PM_POWER_STATE_OFF);
+}
+KBASE_EXPORT_TEST_API(kbase_pm_wait_for_power_down)
+
+int kbase_pm_list_policies(const kbase_pm_policy * const **list)
+{
+ if (!list)
+ return POLICY_COUNT;
+
+ *list = policy_list;
+
+ return POLICY_COUNT;
+}
+KBASE_EXPORT_TEST_API(kbase_pm_list_policies)
+
+const kbase_pm_policy *kbase_pm_get_policy(kbase_device *kbdev)
+{
+ OSK_ASSERT(kbdev != NULL);
+
+ return kbdev->pm.current_policy;
+}
+KBASE_EXPORT_TEST_API(kbase_pm_get_policy)
+
+void kbase_pm_set_policy(kbase_device *kbdev, const kbase_pm_policy *new_policy)
+{
+ OSK_ASSERT(kbdev != NULL);
+ OSK_ASSERT(new_policy != NULL);
+
+ if (kbdev->pm.new_policy) {
+ /* A policy change is already outstanding */
+ KBASE_TRACE_ADD( kbdev, PM_SET_POLICY, NULL, NULL, 0u, -1 );
+ return;
+ }
+ KBASE_TRACE_ADD( kbdev, PM_SET_POLICY, NULL, NULL, 0u, new_policy->id );
+ /* During a policy change we pretend the GPU is active */
+ kbase_pm_context_active(kbdev);
+
+ kbdev->pm.new_policy = new_policy;
+ kbase_pm_send_event(kbdev, KBASE_PM_EVENT_POLICY_CHANGE);
+}
+KBASE_EXPORT_TEST_API(kbase_pm_set_policy)
+
+void kbase_pm_change_policy(kbase_device *kbdev)
+{
+ OSK_ASSERT(kbdev != NULL);
+
+ KBASE_TRACE_ADD( kbdev, PM_CHANGE_POLICY, NULL, NULL, 0u,
+ kbdev->pm.current_policy->id | (kbdev->pm.new_policy->id<<16) );
+
+ KBASE_TRACE_ADD( kbdev, PM_CURRENT_POLICY_TERM, NULL, NULL, 0u, kbdev->pm.current_policy->id );
+ kbdev->pm.current_policy->term(kbdev);
+ kbdev->pm.current_policy = kbdev->pm.new_policy;
+ KBASE_TRACE_ADD( kbdev, PM_CURRENT_POLICY_INIT, NULL, NULL, 0u, kbdev->pm.current_policy->id );
+ kbdev->pm.current_policy->init(kbdev);
+
+ kbase_pm_send_event(kbdev, KBASE_PM_EVENT_POLICY_INIT);
+
+ /* Changing policy might have occurred during an update to the core desired
+ * states, but the KBASE_PM_EVENT_CHANGE_GPU_STATE event could've been
+ * optimized out if the previous policy had
+ * KBASE_PM_POLICY_FLAG_NO_CORE_TRANSITIONS set.
+ *
+ * In any case, we issue a KBASE_PM_EVENT_CHANGE_GPU_STATE just in case. */
+ kbase_pm_send_event(kbdev, KBASE_PM_EVENT_CHANGE_GPU_STATE);
+
+ /* Now the policy change is finished, we release our fake context active reference */
+ kbase_pm_context_idle(kbdev);
+
+ kbdev->pm.new_policy = NULL;
+}
+KBASE_EXPORT_TEST_API(kbase_pm_change_policy)
+
+/** Callback for the power management work queue.
+ *
+ * This function is called on the power management work queue and is responsible for delivering events to the active
+ * power policy. It manipulates the @ref kbase_pm_device_data.work_active field of @ref kbase_pm_device_data to track
+ * whether all events have been consumed.
+ *
+ * @param data A pointer to the @c pm.work field of the @ref kbase_device struct
+ */
+
+STATIC void kbase_pm_worker(struct work_struct *data)
+{
+ kbase_device *kbdev = container_of(data, kbase_device, pm.work);
+ int pending_events;
+ int old_value;
+ int i;
+
+ do
+ {
+ atomic_set(&kbdev->pm.work_active, KBASE_PM_WORK_ACTIVE_STATE_PROCESSING);
+
+ /* Atomically read and clear the bit mask */
+ pending_events = atomic_read(&kbdev->pm.pending_events);
+
+ do
+ {
+ old_value = pending_events;
+ pending_events = atomic_cmpxchg(&kbdev->pm.pending_events, old_value, 0);
+ } while (old_value != pending_events);
+
+ for(i = 0; pending_events; i++)
+ {
+ if (pending_events & (1 << i))
+ {
+ KBASE_TRACE_ADD( kbdev, PM_HANDLE_EVENT, NULL, NULL, 0u, i );
+ kbdev->pm.current_policy->event(kbdev, (kbase_pm_event)i);
+
+ pending_events &= ~(1 << i);
+ }
+ }
+ i = atomic_cmpxchg(&kbdev->pm.work_active,
+ KBASE_PM_WORK_ACTIVE_STATE_PROCESSING,
+ KBASE_PM_WORK_ACTIVE_STATE_INACTIVE);
+ } while (i == KBASE_PM_WORK_ACTIVE_STATE_PENDING_EVT);
+ kbdev->pm.no_outstanding_event = 1;
+ wake_up(&kbdev->pm.no_outstanding_event_wait);
+}
+KBASE_EXPORT_TEST_API(kbase_pm_worker)
+
+/** Merge an event into the list of events to deliver.
+ *
+ * This ensures that if, for example, a GPU_IDLE is immediately followed by a GPU_ACTIVE then instead of delivering
+ * both messages to the policy the GPU_IDLE is simply discarded.
+ *
+ * In particular in the sequence GPU_IDLE, GPU_ACTIVE, GPU_IDLE the resultant message is GPU_IDLE and not (GPU_IDLE
+ * and GPU_ACTIVE).
+ *
+ * @param old_events The bit mask of events that were previously pending
+ * @param new_event The event that should be merged into old_events
+ *
+ * @return The combination of old_events and the new event
+ */
+STATIC int kbasep_pm_merge_event(int old_events, kbase_pm_event new_event)
+{
+ switch(new_event) {
+ case KBASE_PM_EVENT_POLICY_INIT:
+ /* On policy initialisation, ignore any pending old_events. */
+ return ( 1 << KBASE_PM_EVENT_POLICY_INIT);
+
+ case KBASE_PM_EVENT_GPU_STATE_CHANGED:
+ case KBASE_PM_EVENT_POLICY_CHANGE:
+ case KBASE_PM_EVENT_CHANGE_GPU_STATE:
+ /* Just merge these events into the list */
+ return old_events | (1 << new_event);
+ case KBASE_PM_EVENT_SYSTEM_SUSPEND:
+ if (old_events & (1 << KBASE_PM_EVENT_SYSTEM_RESUME))
+ {
+ return old_events & ~(1 << KBASE_PM_EVENT_SYSTEM_RESUME);
+ }
+ return old_events | (1 << new_event);
+ case KBASE_PM_EVENT_SYSTEM_RESUME:
+ if (old_events & (1 << KBASE_PM_EVENT_SYSTEM_SUSPEND))
+ {
+ return old_events & ~(1 << KBASE_PM_EVENT_SYSTEM_SUSPEND);
+ }
+ return old_events | (1 << new_event);
+ case KBASE_PM_EVENT_GPU_ACTIVE:
+ if (old_events & (1 << KBASE_PM_EVENT_GPU_IDLE))
+ {
+ return old_events & ~(1 << KBASE_PM_EVENT_GPU_IDLE);
+ }
+ return old_events | (1 << new_event);
+ case KBASE_PM_EVENT_GPU_IDLE:
+ if (old_events & (1 << KBASE_PM_EVENT_GPU_ACTIVE))
+ {
+ return old_events & ~(1 << KBASE_PM_EVENT_GPU_ACTIVE);
+ }
+ return old_events | (1 << new_event);
+ default:
+ /* Unrecognised event - this should never happen */
+ OSK_ASSERT(0);
+ return old_events | (1 << new_event);
+ }
+}
+KBASE_EXPORT_TEST_API(kbasep_pm_merge_event)
+
+void kbase_pm_send_event(kbase_device *kbdev, kbase_pm_event event)
+{
+ int pending_events;
+ int work_active;
+ int old_value, new_value;
+
+ OSK_ASSERT(kbdev != NULL);
+
+ if ( (kbdev->pm.current_policy->flags & KBASE_PM_POLICY_FLAG_NO_CORE_TRANSITIONS)
+ && event == KBASE_PM_EVENT_CHANGE_GPU_STATE )
+ {
+ /* Optimize out event sending when the policy doesn't transition individual cores */
+ return;
+ }
+
+ KBASE_TRACE_ADD( kbdev, PM_SEND_EVENT, NULL, NULL, 0u, event );
+
+ pending_events = atomic_read(&kbdev->pm.pending_events);
+
+ /* Atomically OR the new event into the pending_events bit mask */
+ do
+ {
+ old_value = pending_events;
+ new_value = kbasep_pm_merge_event(pending_events, event);
+ if (old_value == new_value)
+ {
+ /* Event already pending */
+ return;
+ }
+ pending_events = atomic_cmpxchg(&kbdev->pm.pending_events, old_value, new_value);
+ } while (old_value != pending_events);
+
+ work_active = atomic_read(&kbdev->pm.work_active);
+ do
+ {
+ old_value = work_active;
+ switch(old_value)
+ {
+ case KBASE_PM_WORK_ACTIVE_STATE_INACTIVE:
+ /* Need to enqueue an event */
+ new_value = KBASE_PM_WORK_ACTIVE_STATE_ENQUEUED;
+ break;
+ case KBASE_PM_WORK_ACTIVE_STATE_ENQUEUED:
+ /* Event already queued */
+ return;
+ case KBASE_PM_WORK_ACTIVE_STATE_PROCESSING:
+ /* Event being processed, we need to ensure it checks for another event */
+ new_value = KBASE_PM_WORK_ACTIVE_STATE_PENDING_EVT;
+ break;
+ case KBASE_PM_WORK_ACTIVE_STATE_PENDING_EVT:
+ /* Event being processed, but another check for events is going to happen */
+ return;
+ default:
+ OSK_ASSERT(0);
+ }
+ work_active = atomic_cmpxchg(&kbdev->pm.work_active, old_value, new_value);
+ } while (old_value != work_active);
+
+ if (old_value == KBASE_PM_WORK_ACTIVE_STATE_INACTIVE)
+ {
+ KBASE_TRACE_ADD( kbdev, PM_ACTIVATE_WORKER, NULL, NULL, 0u, 0u );
+ kbdev->pm.no_outstanding_event = 0;
+ OSK_ASSERT(0 == object_is_on_stack(&kbdev->pm.work));
+ INIT_WORK(&kbdev->pm.work, kbase_pm_worker);
+ queue_work(kbdev->pm.workqueue, &kbdev->pm.work);
+ }
+}
+
+KBASE_EXPORT_TEST_API(kbase_pm_send_event)
diff --git a/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_pm.h b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_pm.h
new file mode 100644
index 0000000..d051359
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_pm.h
@@ -0,0 +1,932 @@
+/*
+ *
+ * (C) COPYRIGHT 2010-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_kbase_pm.h
+ * Power management API definitions
+ */
+
+#ifndef _KBASE_PM_H_
+#define _KBASE_PM_H_
+
+#include <kbase/src/common/mali_midg_regmap.h>
+#include <asm/atomic.h>
+
+#include "mali_kbase_pm_always_on.h"
+#include "mali_kbase_pm_demand.h"
+#include "mali_kbase_pm_coarse_demand.h"
+
+/* Forward definition - see mali_kbase.h */
+struct kbase_device;
+
+/** List of policy IDs */
+typedef enum kbase_pm_policy_id
+{
+ KBASE_PM_POLICY_ID_DEMAND = 1,
+ KBASE_PM_POLICY_ID_ALWAYS_ON,
+ KBASE_PM_POLICY_ID_COARSE_DEMAND
+} kbase_pm_policy_id;
+
+/** The types of core in a GPU.
+ *
+ * These enumerated values are used in calls to @ref kbase_pm_invoke_power_up, @ref kbase_pm_invoke_power_down, @ref
+ * kbase_pm_get_present_cores, @ref kbase_pm_get_active_cores, @ref kbase_pm_get_trans_cores, @ref
+ * kbase_pm_get_ready_cores. The specify which type of core should be acted on.
+ * These values are set in a manner that allows @ref core_type_to_reg function to be simpler and more efficient.
+ */
+typedef enum kbase_pm_core_type
+{
+ KBASE_PM_CORE_L3 = L3_PRESENT_LO, /**< The L3 cache */
+ KBASE_PM_CORE_L2 = L2_PRESENT_LO, /**< The L2 cache */
+ KBASE_PM_CORE_SHADER = SHADER_PRESENT_LO, /**< Shader cores */
+ KBASE_PM_CORE_TILER = TILER_PRESENT_LO /**< Tiler cores */
+} kbase_pm_core_type;
+
+/** Initialize the power management framework.
+ *
+ * Must be called before any other power management function
+ *
+ * @param kbdev The kbase device structure for the device (must be a valid pointer)
+ *
+ * @return MALI_ERROR_NONE if the power management framework was successfully initialized.
+ */
+mali_error kbase_pm_init(struct kbase_device *kbdev);
+
+/** Power up GPU after all modules have been initialized and interrupt handlers installed.
+ *
+ * @param kbdev The kbase device structure for the device (must be a valid pointer)
+ *
+ * @return MALI_ERROR_NONE if powerup was successful.
+ */
+mali_error kbase_pm_powerup(struct kbase_device *kbdev);
+
+/**
+ * Halt the power management framework.
+ * Should ensure that no new interrupts are generated,
+ * but allow any currently running interrupt handlers to complete successfully.
+ * No event can make the pm system turn on the GPU after this function returns.
+ * The active policy is sent @ref KBASE_PM_EVENT_SYSTEM_SUSPEND.
+ *
+ * @param kbdev The kbase device structure for the device (must be a valid pointer)
+ */
+void kbase_pm_halt(struct kbase_device *kbdev);
+
+/** Terminate the power management framework.
+ *
+ * No power management functions may be called after this
+ * (except @ref kbase_pm_init)
+ *
+ * @param kbdev The kbase device structure for the device (must be a valid pointer)
+ */
+void kbase_pm_term(struct kbase_device *kbdev);
+
+/** Events that can be sent to a power policy.
+ *
+ * Power policies are expected to handle all these events, although they may choose to take no action.
+ */
+typedef enum kbase_pm_event
+{
+ /* helper for tests */
+ KBASEP_PM_EVENT_FIRST,
+
+ /** Initialize the power policy.
+ *
+ * This event is sent immediately after the @ref kbase_pm_policy.init function of the policy returns.
+ *
+ * The policy may decide to transition the cores to its 'normal' state (e.g. an always on policy would turn all
+ * the cores on). The policy should assume that the GPU is in active use (i.e. as if the @ref
+ * KBASE_PM_EVENT_GPU_ACTIVE event had been received), if this is not the case then @ref KBASE_PM_EVENT_GPU_IDLE
+ * will be called after this event has been handled.
+ */
+ KBASE_PM_EVENT_POLICY_INIT = KBASEP_PM_EVENT_FIRST,
+ /** The power state of the device has changed.
+ *
+ * This event is sent when the GPU raises an interrupt to announce that a power transition has finished. Because
+ * there may be multiple power transitions the power policy must interrogate the state of the GPU to check whether
+ * all expected transitions have finished. If the GPU has just turned on or off then the policy must call @ref
+ * kbase_pm_power_up_done or @ref kbase_pm_power_down_done as appropriate.
+ */
+ KBASE_PM_EVENT_GPU_STATE_CHANGED,
+ /** The GPU is becoming active.
+ *
+ * This event is sent when the first context is about to use the GPU.
+ *
+ * If the core is turned off then this event must cause the core to turn on. This is done asynchronously and the
+ * policy must call the function kbase_pm_power_up_done to signal that the core is turned on sufficiently to allow
+ * register access.
+ */
+ KBASE_PM_EVENT_GPU_ACTIVE,
+ /** The GPU is becoming idle.
+ *
+ * This event is sent when the last context has finished using the GPU.
+ *
+ * The power policy may turn the GPU off entirely (e.g. turn the clocks or power off).
+ */
+ KBASE_PM_EVENT_GPU_IDLE,
+ /** The system has requested a change of power policy.
+ *
+ * The current policy receives this message when a request to change policy occurs. It must ensure that all active
+ * power transitions are completed and then call the @ref kbase_pm_change_policy function.
+ *
+ * This event is only delivered when the policy has been informed that the GPU is 'active' (the power management
+ * code internally increments the context active counter during a policy change).
+ */
+ KBASE_PM_EVENT_POLICY_CHANGE,
+ /** The system is requesting to suspend the GPU.
+ *
+ * The power policy should ensure that the GPU is shut down sufficiently for the system to suspend the device.
+ * Once the GPU is ready the policy should call @ref kbase_pm_power_down_done.
+ */
+ KBASE_PM_EVENT_SYSTEM_SUSPEND,
+ /** The system is requesting to resume the GPU.
+ *
+ * The power policy should restore the GPU to the state it was before the previous
+ * @ref KBASE_PM_EVENT_SYSTEM_SUSPEND event. If the GPU is being powered up then it should call
+ * @ref kbase_pm_power_transitioning before changing the state and @ref kbase_pm_power_up_done when
+ * the transition is complete.
+ */
+ KBASE_PM_EVENT_SYSTEM_RESUME,
+ /** The job scheduler is requesting to power up/down cores.
+ *
+ * This event is sent when:
+ * - powered down cores are needed to complete a job
+ * - powered up cores are not needed anymore
+ */
+ KBASE_PM_EVENT_CHANGE_GPU_STATE,
+
+ /* helpers for tests */
+ KBASEP_PM_EVENT_LAST = KBASE_PM_EVENT_CHANGE_GPU_STATE,
+ KBASEP_PM_EVENT_INVALID
+} kbase_pm_event;
+
+/** Flags that give information about Power Policies */
+enum
+{
+ /** This policy does not power up/down cores and L2/L3 caches individually,
+ * outside of KBASE_PM_EVENT_GPU_IDLE and KBASE_PM_EVENT_GPU_ACTIVE events.
+ * That is, the policy guarantees all cores/L2/L3 caches will be powered
+ * after a KBASE_PM_EVENT_GPU_ACTIVE event.
+ *
+ * Hence, it does not need to be sent KBASE_PM_EVENT_CHANGE_GPU_STATE
+ * events. */
+ KBASE_PM_POLICY_FLAG_NO_CORE_TRANSITIONS = (1u << 0)
+};
+
+typedef u32 kbase_pm_policy_flags;
+
+
+typedef union kbase_pm_policy_data
+{
+ kbasep_pm_policy_always_on always_on;
+ kbasep_pm_policy_demand demand;
+ kbasep_pm_policy_coarse_demand coarse_demand;
+} kbase_pm_policy_data;
+
+/** Power policy structure.
+ *
+ * Each power management policy exposes a (static) instance of this structure which contains function pointers to the
+ * policy's methods.
+ */
+typedef struct kbase_pm_policy
+{
+ /** The name of this policy */
+ char *name;
+
+ /** Function called when the policy is selected
+ *
+ * This should initialize the kbdev->pm.policy_data pointer to the policy's data structure. It should not attempt
+ * to make any changes to hardware state.
+ *
+ * It is undefined what state the cores are in when the function is called, however no power transitions should be
+ * occurring.
+ *
+ * @param kbdev The kbase device structure for the device (must be a valid pointer)
+ */
+ void (*init)(struct kbase_device *kbdev);
+ /** Function called when the policy is unselected.
+ *
+ * This should free any data allocated with \c init
+ *
+ * @param kbdev The kbase device structure for the device (must be a valid pointer)
+ */
+ void (*term)(struct kbase_device *kbdev);
+ /** Function called when there is an event to process
+ *
+ * @param kbdev The kbase device structure for the device (must be a valid pointer)
+ * @param event The event to process
+ */
+ void (*event)(struct kbase_device *kbdev, kbase_pm_event event);
+ /** Field indicating flags for this policy */
+ kbase_pm_policy_flags flags;
+ /** Field indicating an ID for this policy. This is not necessarily the
+ * same as its index in the list returned by kbase_pm_list_policies().
+ * It is used purely for debugging. */
+ kbase_pm_policy_id id;
+} kbase_pm_policy;
+
+/** Metrics data collected for use by the power management framework.
+ *
+ */
+typedef struct kbasep_pm_metrics_data
+{
+ int vsync_hit;
+ int utilisation;
+
+ ktime_t time_period_start;
+ u32 time_busy;
+ u32 time_idle;
+ mali_bool gpu_active;
+
+ spinlock_t lock;
+
+ struct hrtimer timer;
+ mali_bool timer_active;
+
+ void * platform_data;
+ struct kbase_device * kbdev;
+} kbasep_pm_metrics_data;
+
+/** Actions for DVFS.
+ *
+ * kbase_pm_get_dvfs_action will return one of these enumerated values to
+ * describe the action that the DVFS system should take.
+ */
+typedef enum kbase_pm_dvfs_action
+{
+ KBASE_PM_DVFS_NOP, /**< No change in clock frequency is requested */
+ KBASE_PM_DVFS_CLOCK_UP, /**< The clock frequency should be increased if possible */
+ KBASE_PM_DVFS_CLOCK_DOWN /**< The clock frequency should be decreased if possible */
+} kbase_pm_dvfs_action;
+
+/** A value for an atomic @ref kbase_pm_device_data::work_active,
+ * which tracks whether the work unit has been enqueued.
+ */
+typedef enum kbase_pm_work_active_state
+{
+ KBASE_PM_WORK_ACTIVE_STATE_INACTIVE = 0x00u, /**< There are no work units enqueued and @ref kbase_pm_worker is not running. */
+ KBASE_PM_WORK_ACTIVE_STATE_ENQUEUED = 0x01u, /**< There is a work unit enqueued, but @ref kbase_pm_worker is not running. */
+ KBASE_PM_WORK_ACTIVE_STATE_PROCESSING = 0x02u, /**< @ref kbase_pm_worker is running. */
+ KBASE_PM_WORK_ACTIVE_STATE_PENDING_EVT = 0x03u /**< Processing and there's an event outstanding.
+ @ref kbase_pm_worker is running, but @ref kbase_pm_device_data::pending_events
+ has been updated since it started so
+ it should recheck the list of pending events before exiting. */
+} kbase_pm_work_active_state;
+
+/** Data stored per device for power management.
+ *
+ * This structure contains data for the power management framework. There is one instance of this structure per device
+ * in the system.
+ */
+typedef struct kbase_pm_device_data
+{
+ /** The policy that is currently actively controlling the power state. */
+ const kbase_pm_policy *current_policy;
+ /** The policy that the system is transitioning to. */
+ const kbase_pm_policy *new_policy;
+ /** The data needed for the current policy. This is considered private to the policy. */
+ kbase_pm_policy_data policy_data;
+ /** The workqueue that the policy callbacks are executed on. */
+ struct workqueue_struct *workqueue;
+ /** A bit mask of events that are waiting to be delivered to the active policy. */
+ atomic_t pending_events;
+ /** The work unit that is enqueued onto the workqueue. */
+ struct work_struct work;
+ /** An atomic which tracks whether the work unit has been enqueued.
+ * For list of possible values please refer to @ref kbase_pm_work_active_state.
+ */
+ atomic_t work_active;
+
+ /** Power state and a queue to wait for changes */
+ #define PM_POWER_STATE_OFF 1
+ #define PM_POWER_STATE_TRANS 2
+ #define PM_POWER_STATE_ON 3
+ int power_state;
+ wait_queue_head_t power_state_wait;
+
+ /** Wait queue for whether the l2 cache has been powered as requested */
+ wait_queue_head_t l2_powered_wait;
+ /** State indicating whether all the l2 caches are powered.
+ * Non-zero indicates they're *all* powered
+ * Zero indicates that some (or all) are not powered */
+ int l2_powered;
+
+ int no_outstanding_event;
+ wait_queue_head_t no_outstanding_event_wait;
+
+ /** The reference count of active contexts on this device. */
+ int active_count;
+ /** Lock to protect active_count */
+ spinlock_t active_count_lock;
+ /** The reference count of active gpu cycle counter users */
+ int gpu_cycle_counter_requests;
+ /** Lock to protect gpu_cycle_counter_requests */
+ spinlock_t gpu_cycle_counter_requests_lock;
+ /** A bit mask identifying the shader cores that the power policy would like to be on.
+ * The current state of the cores may be different, but there should be transitions in progress that will
+ * eventually achieve this state (assuming that the policy doesn't change its mind in the mean time.
+ */
+ u64 desired_shader_state;
+ /** bit mask indicating which shader cores are currently in a power-on transition */
+ u64 powering_on_shader_state;
+ /** A bit mask identifying the tiler cores that the power policy would like to be on.
+ * @see kbase_pm_device_data:desired_shader_state */
+ u64 desired_tiler_state;
+ /** bit mask indicating which tiler core are currently in a power-on transition */
+ u64 powering_on_tiler_state;
+
+ /** bit mask indicating which l2-caches are currently in a power-on transition */
+ u64 powering_on_l2_state;
+ /** bit mask indicating which l3-caches are currently in a power-on transition */
+ u64 powering_on_l3_state;
+
+ /** Lock protecting the power state of the device.
+ *
+ * This lock must be held when accessing the shader_available_bitmap, tiler_available_bitmap, shader_inuse_bitmap
+ * and tiler_inuse_bitmap fields of kbase_device. It is also held when the hardware power registers are being
+ * written to, to ensure that two threads do not conflict over the power transitions that the hardware should
+ * make.
+ */
+ spinlock_t power_change_lock;
+
+ /** This flag is set iff the GPU is powered as requested by the desired_xxx_state variables */
+ atomic_t gpu_in_desired_state;
+
+ /** Set to true when the GPU is powered and register accesses are possible, false otherwise */
+ mali_bool gpu_powered;
+ /** Spinlock that must be held when writing gpu_powered */
+ spinlock_t gpu_powered_lock;
+
+ /** Structure to hold metrics for the GPU */
+ kbasep_pm_metrics_data metrics;
+
+ /** Callback when the GPU needs to be turned on. See @ref kbase_pm_callback_conf
+ *
+ * @param kbdev The kbase device
+ *
+ * @return 1 if GPU state was lost, 0 otherwise
+ */
+ int (*callback_power_on)(struct kbase_device *kbdev);
+
+ /** Callback when the GPU may be turned off. See @ref kbase_pm_callback_conf
+ *
+ * @param kbdev The kbase device
+ */
+ void (*callback_power_off)(struct kbase_device *kbdev);
+
+ /** Callback for initializing the runtime power management.
+ *
+ * @param kbdev The kbase device
+ *
+ * @return MALI_ERROR_NONE on success, else error code
+ */
+ mali_error (*callback_power_runtime_init)(struct kbase_device *kbdev);
+
+ /** Callback for terminating the runtime power management.
+ *
+ * @param kbdev The kbase device
+ */
+ void (*callback_power_runtime_term)(struct kbase_device *kbdev);
+
+ /** Callback when the GPU needs to be turned on. See @ref kbase_pm_callback_conf
+ *
+ * @param kbdev The kbase device
+ *
+ * @return 1 if GPU state was lost, 0 otherwise
+ */
+ int (*callback_power_runtime_on)(struct kbase_device *kbdev);
+
+ /** Callback when the GPU may be turned off. See @ref kbase_pm_callback_conf
+ *
+ * @param kbdev The kbase device
+ */
+ void (*callback_power_runtime_off)(struct kbase_device *kbdev);
+
+} kbase_pm_device_data;
+
+/** Get the current policy.
+ * Returns the policy that is currently active.
+ *
+ * @param kbdev The kbase device structure for the device (must be a valid pointer)
+ *
+ * @return The current policy
+ */
+const kbase_pm_policy *kbase_pm_get_policy(struct kbase_device *kbdev);
+
+/** Change the policy to the one specified.
+ *
+ * @param kbdev The kbase device structure for the device (must be a valid pointer)
+ * @param policy The policy to change to (valid pointer returned from @ref kbase_pm_list_policies)
+ */
+void kbase_pm_set_policy(struct kbase_device *kbdev, const kbase_pm_policy *policy);
+
+/** Retrieve a static list of the available policies.
+ * @param[out] policies An array pointer to take the list of policies. This may be NULL.
+ * The contents of this array must not be modified.
+ *
+ * @return The number of policies
+ */
+int kbase_pm_list_policies(const kbase_pm_policy * const **policies);
+
+/** The current policy is ready to change to the new policy
+ *
+ * The current policy must ensure that all cores have finished transitioning before calling this function.
+ * The new policy is sent an @ref KBASE_PM_EVENT_POLICY_INIT event.
+ *
+ * @param kbdev The kbase device structure for the device (must be a valid pointer)
+ */
+void kbase_pm_change_policy(struct kbase_device *kbdev);
+
+/** The GPU is idle.
+ *
+ * The OS may choose to turn off idle devices
+ *
+ * @param kbdev The kbase device structure for the device (must be a valid pointer)
+ */
+void kbase_pm_dev_idle(struct kbase_device *kbdev);
+
+/** The GPU is active.
+ *
+ * The OS should avoid opportunistically turning off the GPU while it is active
+ *
+ * @param kbdev The kbase device structure for the device (must be a valid pointer)
+ */
+void kbase_pm_dev_activate(struct kbase_device *kbdev);
+
+/** Send an event to the active power policy.
+ *
+ * The event is queued for sending to the active power policy. The event is merged with the current queue by the @ref
+ * kbasep_pm_merge_event function which may decide to drop events.
+ *
+ * Note that this function may be called in an atomic context on Linux which implies that it must not sleep.
+ *
+ * @param kbdev The kbase device structure for the device (must be a valid pointer)
+ * @param event The event that should be queued
+ */
+void kbase_pm_send_event(struct kbase_device *kbdev, kbase_pm_event event);
+
+/** Turn one or more cores on.
+ *
+ * This function is called by the active power policy to turn one or more cores on.
+ *
+ * @param kbdev The kbase device structure for the device (must be a valid pointer)
+ * @param type The type of core (see the @ref kbase_pm_core_type enumeration)
+ * @param cores A bitmask of cores to turn on
+ */
+void kbase_pm_invoke_power_up(struct kbase_device *kbdev, kbase_pm_core_type type, u64 cores);
+
+/** Turn one or more cores off.
+ *
+ * This function is called by the active power policy to turn one or more core off.
+ *
+ * @param kbdev The kbase device structure for the device (must be a valid pointer)
+ * @param type The type of core (see the @ref kbase_pm_core_type enumeration)
+ * @param cores A bitmask of cores to turn off
+ */
+void kbase_pm_invoke_power_down(struct kbase_device *kbdev, kbase_pm_core_type type, u64 cores);
+
+/** Get details of the cores that are present in the device.
+ *
+ * This function can be called by the active power policy to return a bitmask of the cores (of a specified type)
+ * present in the GPU device and also a count of the number of cores.
+ *
+ * @param kbdev The kbase device structure for the device (must be a valid pointer)
+ * @param type The type of core (see the @ref kbase_pm_core_type enumeration)
+ *
+ * @return The bit mask of cores present
+ */
+u64 kbase_pm_get_present_cores(struct kbase_device *kbdev, kbase_pm_core_type type);
+
+/** Get details of the cores that are currently active in the device.
+ *
+ * This function can be called by the active power policy to return a bitmask of the cores (of a specified type) that
+ * are actively processing work (i.e. turned on *and* busy).
+ *
+ * @param kbdev The kbase device structure for the device (must be a valid pointer)
+ * @param type The type of core (see the @ref kbase_pm_core_type enumeration)
+ *
+ * @return The bit mask of active cores
+ */
+u64 kbase_pm_get_active_cores(struct kbase_device *kbdev, kbase_pm_core_type type);
+
+/** Get details of the cores that are currently transitioning between power states.
+ *
+ * This function can be called by the active power policy to return a bitmask of the cores (of a specified type) that
+ * are currently transitioning between power states.
+ *
+ * @param kbdev The kbase device structure for the device (must be a valid pointer)
+ * @param type The type of core (see the @ref kbase_pm_core_type enumeration)
+ *
+ * @return The bit mask of transitioning cores
+ */
+u64 kbase_pm_get_trans_cores(struct kbase_device *kbdev, kbase_pm_core_type type);
+
+/** Get details of the cores that are currently powered and ready for jobs.
+ *
+ * This function can be called by the active power policy to return a bitmask of the cores (of a specified type) that
+ * are powered and ready for jobs (they may or may not be currently executing jobs).
+ *
+ * @param kbdev The kbase device structure for the device (must be a valid pointer)
+ * @param type The type of core (see the @ref kbase_pm_core_type enumeration)
+ *
+ * @return The bit mask of ready cores
+ */
+u64 kbase_pm_get_ready_cores(struct kbase_device *kbdev, kbase_pm_core_type type);
+
+/** Return whether the power manager is active
+ *
+ * This function will return true when there are cores (of any time) that are currently transitioning between power
+ * states.
+ *
+ * It can be used on receipt of the @ref KBASE_PM_EVENT_GPU_STATE_CHANGED message to determine whether the requested power
+ * transitions have completely finished or not.
+ *
+ * @param kbdev The kbase device structure for the device (must be a valid pointer)
+ *
+ * @return true when there are cores transitioning between power states, false otherwise
+ */
+mali_bool kbase_pm_get_pwr_active(struct kbase_device *kbdev);
+
+/** Turn the clock for the device on, and enable device interrupts.
+ *
+ * This function can be used by a power policy to turn the clock for the GPU on. It should be modified during
+ * integration to perform the necessary actions to ensure that the GPU is fully powered and clocked.
+ *
+ * @param kbdev The kbase device structure for the device (must be a valid pointer)
+ */
+void kbase_pm_clock_on(struct kbase_device *kbdev);
+
+/** Disable device interrupts, and turn the clock for the device off.
+ *
+ * This function can be used by a power policy to turn the clock for the GPU off. It should be modified during
+ * integration to perform the necessary actions to turn the clock off (if this is possible in the integration).
+ *
+ * @param kbdev The kbase device structure for the device (must be a valid pointer)
+ */
+void kbase_pm_clock_off(struct kbase_device *kbdev);
+
+/** Enable interrupts on the device.
+ *
+ * Interrupts are also enabled after a call to kbase_pm_clock_on().
+ *
+ * @param kbdev The kbase device structure for the device (must be a valid pointer)
+ */
+void kbase_pm_enable_interrupts(struct kbase_device *kbdev);
+
+/** Disable interrupts on the device.
+ *
+ * This prevents interrupt delivery to the CPU so no further @ref KBASE_PM_EVENT_GPU_STATE_CHANGED messages will be
+ * received until @ref kbase_pm_enable_interrupts or kbase_pm_clock_on() is called.
+ *
+ * Interrupts are also disabled after a call to kbase_pm_clock_off().
+ *
+ * @param kbdev The kbase device structure for the device (must be a valid pointer)
+ */
+void kbase_pm_disable_interrupts(struct kbase_device *kbdev);
+
+/** Initialize the hardware
+ *
+ * This function checks the GPU ID register to ensure that the GPU is supported by the driver and performs a reset on
+ * the device so that it is in a known state before the device is used.
+ *
+ * @param kbdev The kbase device structure for the device (must be a valid pointer)
+ *
+ * @return MALI_ERROR_NONE if the device is supported and successfully reset.
+ */
+mali_error kbase_pm_init_hw(struct kbase_device *kbdev);
+
+/** Inform the power management system that the power state of the device is transitioning.
+ *
+ * This function must be called by the active power policy before transitioning the core between an 'off state' and an
+ * 'on state'. It resets the wait queues that are waited on by @ref kbase_pm_wait_for_power_up and @ref
+ * kbase_pm_wait_for_power_down.
+ *
+ * @param kbdev The kbase device structure for the device (must be a valid pointer)
+ */
+void kbase_pm_power_transitioning(struct kbase_device *kbdev);
+
+/** The GPU has been powered up successfully.
+ *
+ * This function must be called by the active power policy when the GPU has been powered up successfully. It signals
+ * to the rest of the system that jobs can start being submitted to the device.
+ *
+ * @param kbdev The kbase device structure for the device (must be a valid pointer)
+ */
+void kbase_pm_power_up_done(struct kbase_device *kbdev);
+
+/** The GPU has been reset successfully.
+ *
+ * This function must be called by the GPU interrupt handler when the RESET_COMPLETED bit is set. It signals to the
+ * power management initialization code that the GPU has been successfully reset.
+ *
+ * @param kbdev The kbase device structure for the device (must be a valid pointer)
+ */
+void kbase_pm_reset_done(struct kbase_device *kbdev);
+
+/** The GPU has been powered down successfully.
+ *
+ * This function must be called by the active power policy when the GPU has been powered down successfully. It signals
+ * to the rest of the system that a system suspend can now take place.
+ *
+ * @param kbdev The kbase device structure for the device (must be a valid pointer)
+ */
+void kbase_pm_power_down_done(struct kbase_device *kbdev);
+
+/** Wait for the power policy to signal power up.
+ *
+ * This function waits for the power policy to signal power up by calling @ref kbase_pm_power_up_done. After the power
+ * policy has signalled this the function will return immediately until the power policy calls @ref
+ * kbase_pm_power_transitioning.
+ *
+ * @param kbdev The kbase device structure for the device (must be a valid pointer)
+ */
+void kbase_pm_wait_for_power_up(struct kbase_device *kbdev);
+
+/** Wait for the power policy to signal power down.
+ *
+ * This function waits for the power policy to signal power down by calling @ref kbase_pm_power_down_done. After the
+ * power policy has signalled this the function will return immediately until the power policy calls @ref
+ * kbase_pm_power_transitioning.
+ *
+ * @param kbdev The kbase device structure for the device (must be a valid pointer)
+ */
+void kbase_pm_wait_for_power_down(struct kbase_device *kbdev);
+
+/** Increment the count of active contexts.
+ *
+ * This function should be called when a context is about to submit a job. It informs the active power policy that the
+ * GPU is going to be in use shortly and the policy is expected to start turning on the GPU.
+ *
+ * This function will block until the GPU is available.
+ *
+ * @param kbdev The kbase device structure for the device (must be a valid pointer)
+ */
+void kbase_pm_context_active(struct kbase_device *kbdev);
+
+/** Decrement the reference count of active contexts.
+ *
+ * This function should be called when a context becomes idle. After this call the GPU may be turned off by the power
+ * policy so the calling code should ensure that it does not access the GPU's registers.
+ *
+ * @param kbdev The kbase device structure for the device (must be a valid pointer)
+ */
+void kbase_pm_context_idle(struct kbase_device *kbdev);
+
+/** Check if there are any power transitions to make, and if so start them.
+ *
+ * This function will check the desired_xx_state members of kbase_pm_device_data and the actual status of the
+ * hardware to see if any power transitions can be made at this time to make the hardware state closer to the state
+ * desired by the power policy.
+ *
+ * @param kbdev The kbase device structure for the device (must be a valid pointer)
+ */
+void kbase_pm_check_transitions(struct kbase_device *kbdev);
+
+/** Read the bitmasks of present cores.
+ *
+ * This information is cached to avoid having to perform register reads whenever the information is required.
+ *
+ * @param kbdev The kbase device structure for the device (must be a valid pointer)
+ */
+void kbasep_pm_read_present_cores(struct kbase_device *kbdev);
+
+/** Mark one or more cores as being required for jobs to be submitted.
+ *
+ * This function is called by the job scheduler to mark one or both cores
+ * as being required to submit jobs that are ready to run.
+ *
+ * The cores requested are reference counted and a subsequent call to @ref kbase_pm_register_inuse_cores or
+ * @ref kbase_pm_unrequest_cores should be made to dereference the cores as being 'needed'.
+ *
+ * The current running policy is sent an @ref KBASE_PM_EVENT_CHANGE_GPU_STATE if power up of requested core is
+ * required.
+
+ * The policy is expected to make these cores available at some point in the future,
+ * but may take an arbitrary length of time to reach this state.
+ *
+ * @param kbdev The kbase device structure for the device
+ * @param shader_cores A bitmask of shader cores which are necessary for the job
+ * @param tiler_cores A bitmask of tiler cores which are necessary for the job
+ *
+ * @return MALI_ERROR_NONE if the cores were successfully requested.
+ */
+mali_error kbase_pm_request_cores(struct kbase_device *kbdev, u64 shader_cores, u64 tiler_cores);
+
+/** Unmark one or more cores as being required for jobs to be submitted.
+ *
+ * This function undoes the effect of @ref kbase_pm_request_cores. It should be used when a job is not
+ * going to be submitted to the hardware (e.g. the job is cancelled before it is enqueued).
+ *
+ * The current running policy is sent an @ref KBASE_PM_EVENT_CHANGE_GPU_STATE if power down of requested core
+ * is required.
+ *
+ * The policy may use this as an indication that it can power down cores.
+ *
+ * @param kbdev The kbase device structure for the device
+ * @param shader_cores A bitmask of shader cores (as given to @ref kbase_pm_request_cores)
+ * @param tiler_cores A bitmask of tiler cores (as given to @ref kbase_pm_request_cores)
+ */
+void kbase_pm_unrequest_cores(struct kbase_device *kbdev, u64 shader_cores, u64 tiler_cores);
+
+/** Register a set of cores as in use by a job.
+ *
+ * This function should be called after @ref kbase_pm_request_cores when the job is about to be submitted to
+ * the hardware. It will check that the necessary cores are available and if so update the 'needed' and 'inuse'
+ * bitmasks to reflect that the job is now committed to being run.
+ *
+ * If the necessary cores are not currently available then the function will return MALI_FALSE and have no effect.
+ *
+ * @param kbdev The kbase device structure for the device
+ * @param shader_cores A bitmask of shader cores (as given to @ref kbase_pm_request_cores)
+ * @param tiler_cores A bitmask of tiler cores (as given to @ref kbase_pm_request_cores)
+ *
+ * @return MALI_TRUE if the job can be submitted to the hardware or MALI_FALSE if the job is not ready to run.
+ */
+mali_bool kbase_pm_register_inuse_cores(struct kbase_device *kbdev, u64 shader_cores, u64 tiler_cores);
+
+/** Release cores after a job has run.
+ *
+ * This function should be called when a job has finished running on the hardware. A call to @ref
+ * kbase_pm_register_inuse_cores must have previously occurred. The reference counts of the specified cores will be
+ * decremented which may cause the bitmask of 'inuse' cores to be reduced. The power policy may then turn off any
+ * cores which are no longer 'inuse'.
+ *
+ * @param kbdev The kbase device structure for the device
+ * @param shader_cores A bitmask of shader cores (as given to @ref kbase_pm_register_inuse_cores)
+ * @param tiler_cores A bitmask of tiler cores (as given to @ref kbase_pm_register_inuse_cores)
+ */
+void kbase_pm_release_cores(struct kbase_device *kbdev, u64 shader_cores, u64 tiler_cores);
+
+/** Initialize the metrics gathering framework.
+ *
+ * This must be called before other metric gathering APIs are called.
+ *
+ * @param kbdev The kbase device structure for the device (must be a valid pointer)
+ *
+ * @return MALI_ERROR_NONE on success, MALI_ERROR_FUNCTION_FAILED on error
+ */
+mali_error kbasep_pm_metrics_init(struct kbase_device *kbdev);
+
+/** Terminate the metrics gathering framework.
+ *
+ * This must be called when metric gathering is no longer required. It is an error to call any metrics gathering
+ * function (other than kbasep_pm_metrics_init) after calling this function.
+ *
+ * @param kbdev The kbase device structure for the device (must be a valid pointer)
+ */
+void kbasep_pm_metrics_term(struct kbase_device *kbdev);
+
+/** Record that the GPU is active.
+ *
+ * This records that the GPU is now active. The previous GPU state must have been idle, the function will assert if
+ * this is not true in a debug build.
+ *
+ * @param kbdev The kbase device structure for the device (must be a valid pointer)
+ */
+void kbasep_pm_record_gpu_active(struct kbase_device *kbdev);
+
+/** Record that the GPU is idle.
+ *
+ * This records that the GPU is now idle. The previous GPU state must have been active, the function will assert if
+ * this is not true in a debug build.
+ *
+ * @param kbdev The kbase device structure for the device (must be a valid pointer)
+ */
+void kbasep_pm_record_gpu_idle(struct kbase_device *kbdev);
+
+/** Function to be called by the frame buffer driver to update the vsync metric.
+ *
+ * This function should be called by the frame buffer driver to update whether the system is hitting the vsync target
+ * or not. buffer_updated should be true if the vsync corresponded with a new frame being displayed, otherwise it
+ * should be false. This function does not need to be called every vsync, but only when the value of buffer_updated
+ * differs from a previous call.
+ *
+ * @param kbdev The kbase device structure for the device (must be a valid pointer)
+ * @param buffer_updated True if the buffer has been updated on this VSync, false otherwise
+ */
+void kbase_pm_report_vsync(struct kbase_device *kbdev, int buffer_updated);
+
+/** Configure the frame buffer device to set the vsync callback.
+ *
+ * This function should do whatever is necessary for this integration to ensure that kbase_pm_report_vsync is
+ * called appropriately.
+ *
+ * This function will need porting as part of the integration for a device.
+ *
+ * @param kbdev The kbase device structure for the device (must be a valid pointer)
+ */
+void kbase_pm_register_vsync_callback(struct kbase_device *kbdev);
+
+/** Free any resources that kbase_pm_register_vsync_callback allocated.
+ *
+ * This function should perform any cleanup required from the call to kbase_pm_register_vsync_callback.
+ * No call backs should occur after this function has returned.
+ *
+ * This function will need porting as part of the integration for a device.
+ *
+ * @param kbdev The kbase device structure for the device (must be a valid pointer)
+ */
+void kbase_pm_unregister_vsync_callback(struct kbase_device *kbdev);
+
+/** Determine whether the DVFS system should change the clock speed of the GPU.
+ *
+ * This function should be called regularly by the DVFS system to check whether the clock speed of the GPU needs
+ * updating. It will return one of three enumerated values of kbase_pm_dvfs_action:
+ *
+ * @param kbdev The kbase device structure for the device (must be a valid pointer)
+ * @retval KBASE_PM_DVFS_NOP The clock does not need changing
+ * @retval KBASE_PM_DVFS_CLOCK_UP, The clock frequency should be increased if possible.
+ * @retval KBASE_PM_DVFS_CLOCK_DOWN The clock frequency should be decreased if possible.
+ */
+kbase_pm_dvfs_action kbase_pm_get_dvfs_action(struct kbase_device *kbdev);
+
+/** Mark that the GPU cycle counter is needed, if the caller is the first caller
+ * then the GPU cycle counters will be enabled.
+ *
+ * The GPU must be powered when calling this function (i.e. @ref kbase_pm_context_active must have been called).
+ *
+ * @param kbdev The kbase device structure for the device (must be a valid pointer)
+ */
+
+void kbase_pm_request_gpu_cycle_counter(struct kbase_device *kbdev);
+
+/** Mark that the GPU cycle counter is no longer in use, if the caller is the last
+ * caller then the GPU cycle counters will be disabled. A request must have been made
+ * before a call to this.
+ *
+ * @param kbdev The kbase device structure for the device (must be a valid pointer)
+ */
+
+void kbase_pm_release_gpu_cycle_counter(struct kbase_device *kbdev);
+
+/** Enables access to the GPU registers before power management has powered up the GPU
+ * with kbase_pm_powerup().
+ *
+ * Access to registers should be done using kbase_os_reg_read/write() at this stage,
+ * not kbase_reg_read/write().
+ *
+ * This results in the power management callbacks provided in the driver configuration
+ * to get called to turn on power and/or clocks to the GPU.
+ * See @ref kbase_pm_callback_conf.
+ *
+ * This should only be used before power management is powered up with kbase_pm_powerup()
+ *
+ * @param kbdev The kbase device structure for the device (must be a valid pointer)
+ */
+void kbase_pm_register_access_enable(struct kbase_device *kbdev);
+
+/** Disables access to the GPU registers enabled earlier by a call to
+ * kbase_pm_register_access_enable().
+ *
+ * This results in the power management callbacks provided in the driver configuration
+ * to get called to turn off power and/or clocks to the GPU.
+ * See @ref kbase_pm_callback_conf
+ *
+ * This should only be used before power management is powered up with kbase_pm_powerup()
+ *
+ * @param kbdev The kbase device structure for the device (must be a valid pointer)
+ */
+void kbase_pm_register_access_disable(struct kbase_device *kbdev);
+
+/** Request the use of l2 caches for all core groups, power up, wait and prevent the power manager from
+ * powering down the l2 caches.
+ *
+ * This tells the power management that the caches should be powered up, and they
+ * should remain powered, irrespective of the usage of tiler and shader cores. This does not
+ * return until the l2 caches are powered up.
+ *
+ * The caller must call @ref kbase_pm_release_l2_caches when they are finished to
+ * allow normal power management of the l2 caches to resume.
+ *
+ * This should only be used when power management is active.
+ *
+ * @param kbdev The kbase device structure for the device (must be a valid pointer)
+ */
+
+void kbase_pm_request_l2_caches(struct kbase_device *kbdev);
+
+/** Release the use of l2 caches for all core groups and allow the power manager to
+ * power them down when necessary.
+ *
+ * This tells the power management that the caches can be powered down if necessary, with respect
+ * to the usage of tiler and shader cores.
+ *
+ * The caller must have called @ref kbase_pm_request_l2_caches prior to a call to this.
+ *
+ * This should only be used when power management is active.
+ *
+ * @param kbdev The kbase device structure for the device (must be a valid pointer)
+ */
+void kbase_pm_release_l2_caches(struct kbase_device *kbdev);
+
+#endif /* _KBASE_PM_H_ */
diff --git a/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_pm_always_on.c b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_pm_always_on.c
new file mode 100644
index 0000000..d050e02
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_pm_always_on.c
@@ -0,0 +1,230 @@
+/*
+ *
+ * (C) COPYRIGHT 2010-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_kbase_pm_always_on.c
+ * "Always on" power management policy
+ */
+
+#include <osk/mali_osk.h>
+#include <kbase/src/common/mali_kbase.h>
+#include <kbase/src/common/mali_kbase_pm.h>
+
+
+/** Function to handle a GPU state change for the always_on power policy.
+ *
+ * This function is called whenever the GPU has transitioned to another state. It first checks that the transition is
+ * complete and then moves the state machine to the next state.
+ *
+ * @param kbdev The kbase device structure for the device
+ */
+static void always_on_state_changed(kbase_device *kbdev)
+{
+ kbasep_pm_policy_always_on *data = &kbdev->pm.policy_data.always_on;
+
+ switch(data->state)
+ {
+ case KBASEP_PM_ALWAYS_ON_STATE_POWERING_UP:
+ if (kbase_pm_get_pwr_active(kbdev))
+ {
+ /* Cores still transitioning */
+ return;
+ }
+ /* All cores have transitioned, inform the OS */
+ kbase_pm_power_up_done(kbdev);
+ data->state = KBASEP_PM_ALWAYS_ON_STATE_POWERED_UP;
+
+ break;
+ case KBASEP_PM_ALWAYS_ON_STATE_POWERING_DOWN:
+ if (kbase_pm_get_pwr_active(kbdev))
+ {
+ /* Cores still transitioning */
+ return;
+ }
+ /* All cores have transitioned, turn the clock and interrupts off */
+ kbase_pm_clock_off(kbdev);
+
+ /* Inform the OS */
+ kbase_pm_power_down_done(kbdev);
+
+ data->state = KBASEP_PM_ALWAYS_ON_STATE_POWERED_DOWN;
+
+ break;
+ case KBASEP_PM_ALWAYS_ON_STATE_CHANGING_POLICY:
+ if (kbase_pm_get_pwr_active(kbdev))
+ {
+ /* Cores still transitioning */
+ return;
+ }
+ /* All cores have transitioned, inform the system we can change policy*/
+ kbase_pm_change_policy(kbdev);
+
+ break;
+ default:
+ break;
+ }
+}
+
+/** Function to handle the @ref KBASE_PM_EVENT_SYSTEM_SUSPEND message for the always_on power policy.
+ *
+ * This function is called when a @ref KBASE_PM_EVENT_SYSTEM_SUSPEND message is received. It instructs the GPU to turn off
+ * all cores.
+ *
+ * @param kbdev The kbase device structure for the device
+ */
+static void always_on_suspend(kbase_device *kbdev)
+{
+ u64 cores;
+
+ /* Inform the system that the transition has started */
+ kbase_pm_power_transitioning(kbdev);
+
+ /* Turn the cores off */
+ cores = kbase_pm_get_present_cores(kbdev, KBASE_PM_CORE_SHADER);
+ kbase_pm_invoke_power_down(kbdev, KBASE_PM_CORE_SHADER, cores);
+
+ cores = kbase_pm_get_present_cores(kbdev, KBASE_PM_CORE_TILER);
+ kbase_pm_invoke_power_down(kbdev, KBASE_PM_CORE_TILER, cores);
+
+ kbase_pm_check_transitions(kbdev);
+
+ kbdev->pm.policy_data.always_on.state = KBASEP_PM_ALWAYS_ON_STATE_POWERING_DOWN;
+
+ /* Ensure that the OS is informed even if we didn't do anything */
+ always_on_state_changed(kbdev);
+}
+
+/** Function to handle the @ref KBASE_PM_EVENT_SYSTEM_RESUME message for the always_on power policy.
+ *
+ * This function is called when a @ref KBASE_PM_EVENT_SYSTEM_RESUME message is received. It instructs the GPU to turn on all
+ * the cores.
+ *
+ * @param kbdev The kbase device structure for the device
+ */
+static void always_on_resume(kbase_device *kbdev)
+{
+ u64 cores;
+
+ /* Inform the system that the transition has started */
+ kbase_pm_power_transitioning(kbdev);
+
+ /* Turn the clock on and enable interrupts */
+ kbase_pm_clock_on(kbdev);
+
+ /* Turn the cores on */
+ cores = kbase_pm_get_present_cores(kbdev, KBASE_PM_CORE_SHADER);
+ kbase_pm_invoke_power_up(kbdev, KBASE_PM_CORE_SHADER, cores);
+
+ cores = kbase_pm_get_present_cores(kbdev, KBASE_PM_CORE_TILER);
+ kbase_pm_invoke_power_up(kbdev, KBASE_PM_CORE_TILER, cores);
+
+ kbase_pm_check_transitions(kbdev);
+
+ kbdev->pm.policy_data.always_on.state = KBASEP_PM_ALWAYS_ON_STATE_POWERING_UP;
+
+ /* Ensure that the OS is informed even if we didn't do anything */
+ always_on_state_changed(kbdev);
+}
+
+/** The event callback function for the always_on power policy.
+ *
+ * This function is called to handle the events for the power policy. It calls the relevant handler function depending
+ * on the type of the event.
+ *
+ * @param kbdev The kbase device structure for the device
+ * @param event The event that should be processed
+ */
+static void always_on_event(kbase_device *kbdev, kbase_pm_event event)
+{
+ kbasep_pm_policy_always_on *data = &kbdev->pm.policy_data.always_on;
+
+ switch(event)
+ {
+ case KBASE_PM_EVENT_SYSTEM_SUSPEND:
+ always_on_suspend(kbdev);
+ break;
+ case KBASE_PM_EVENT_POLICY_INIT: /* Init is the same as resume for this policy */
+ case KBASE_PM_EVENT_SYSTEM_RESUME:
+ always_on_resume(kbdev);
+ break;
+ case KBASE_PM_EVENT_GPU_STATE_CHANGED:
+ always_on_state_changed(kbdev);
+ break;
+ case KBASE_PM_EVENT_POLICY_CHANGE:
+ if (data->state == KBASEP_PM_ALWAYS_ON_STATE_POWERED_UP ||
+ data->state == KBASEP_PM_ALWAYS_ON_STATE_POWERED_DOWN)
+ {
+ kbase_pm_change_policy(kbdev);
+ }
+ else
+ {
+ data->state = KBASEP_PM_ALWAYS_ON_STATE_CHANGING_POLICY;
+ }
+ break;
+ case KBASE_PM_EVENT_GPU_ACTIVE:
+ case KBASE_PM_EVENT_GPU_IDLE:
+ break;
+ case KBASE_PM_EVENT_CHANGE_GPU_STATE:
+ /*
+ * Note that the GPU is always kept on, however we still may
+ * be required to update anyone waiting for power up events.
+ */
+ kbase_pm_check_transitions(kbdev);
+ break;
+ default:
+ /* Unrecognised event - this should never happen */
+ OSK_ASSERT(0);
+ }
+}
+
+/** Initialize the always_on power policy
+ *
+ * This sets up the private @ref kbase_pm_device_data.policy_data field of the device for use with the always_on power
+ * policy.
+ *
+ * @param kbdev The kbase device structure for the device
+ */
+static void always_on_init(kbase_device *kbdev)
+{
+ kbasep_pm_policy_always_on *data = &kbdev->pm.policy_data.always_on;
+
+ data->state = KBASEP_PM_ALWAYS_ON_STATE_POWERING_UP;
+}
+
+/** Terminate the always_on power policy
+ *
+ * This frees the resources that were allocated by @ref always_on_init.
+ *
+ * @param kbdev The kbase device structure for the device
+ */
+static void always_on_term(kbase_device *kbdev)
+{
+ CSTD_UNUSED(kbdev);
+}
+
+/** The @ref kbase_pm_policy structure for the always_on power policy
+ *
+ * This is the extern structure that defines the always_on power policy's callback and name.
+ */
+const kbase_pm_policy kbase_pm_always_on_policy_ops =
+{
+ "always_on", /* name */
+ always_on_init, /* init */
+ always_on_term, /* term */
+ always_on_event, /* event */
+ KBASE_PM_POLICY_FLAG_NO_CORE_TRANSITIONS, /* flags */
+ KBASE_PM_POLICY_ID_ALWAYS_ON, /* id */
+};
+
+KBASE_EXPORT_TEST_API(kbase_pm_always_on_policy_ops)
diff --git a/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_pm_always_on.h b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_pm_always_on.h
new file mode 100644
index 0000000..f5efc1e
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_pm_always_on.h
@@ -0,0 +1,82 @@
+/*
+ *
+ * (C) COPYRIGHT 2011-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_kbase_pm_always_on.h
+ * "Always on" power management policy
+ */
+
+#ifndef MALI_KBASE_PM_ALWAYS_ON_H
+#define MALI_KBASE_PM_ALWAYS_ON_H
+
+/** The states that the always_on policy can enter.
+ *
+ * The diagram below should the states that the always_on policy can enter and the transitions that can occur between
+ * the states:
+ *
+ * @dot
+ * digraph always_on_states {
+ * node [fontsize=10];
+ * edge [fontsize=10];
+ *
+ * POWERING_UP [label="STATE_POWERING_UP"
+ * URL="\ref kbasep_pm_always_on_state.KBASEP_PM_ALWAYS_ON_STATE_POWERING_UP"];
+ * POWERING_DOWN [label="STATE_POWERING_DOWN"
+ * URL="\ref kbasep_pm_always_on_state.KBASEP_PM_ALWAYS_ON_STATE_POWERING_DOWN"];
+ * POWERED_UP [label="STATE_POWERED_UP"
+ * URL="\ref kbasep_pm_always_on_state.KBASEP_PM_ALWAYS_ON_STATE_POWERED_UP"];
+ * POWERED_DOWN [label="STATE_POWERED_DOWN"
+ * URL="\ref kbasep_pm_always_on_state.KBASEP_PM_ALWAYS_ON_STATE_POWERED_DOWN"];
+ * CHANGING_POLICY [label="STATE_CHANGING_POLICY"
+ * URL="\ref kbasep_pm_always_on_state.KBASEP_PM_ALWAYS_ON_STATE_CHANGING_POLICY"];
+ *
+ * init [label="init" URL="\ref KBASE_PM_EVENT_INIT"];
+ * change_policy [label="change_policy" URL="\ref kbase_pm_change_policy"];
+ *
+ * init -> POWERING_UP [ label = "Policy init" ];
+ *
+ * POWERING_UP -> POWERED_UP [label = "Power state change" URL="\ref KBASE_PM_EVENT_STATE_CHANGED"];
+ * POWERING_DOWN -> POWERED_DOWN [label = "Power state change" URL="\ref KBASE_PM_EVENT_STATE_CHANGED"];
+ * CHANGING_POLICY -> change_policy [label = "Power state change" URL="\ref KBASE_PM_EVENT_STATE_CHANGED"];
+ *
+ * POWERED_UP -> POWERING_DOWN [label = "Suspend" URL="\ref KBASE_PM_EVENT_SUSPEND"];
+ *
+ * POWERED_DOWN -> POWERING_UP [label = "Resume" URL="\ref KBASE_PM_EVENT_RESUME"];
+ *
+ * POWERING_UP -> CHANGING_POLICY [label = "Change policy" URL="\ref KBASE_PM_EVENT_CHANGE_POLICY"];
+ * POWERING_DOWN -> CHANGING_POLICY [label = "Change policy" URL="\ref KBASE_PM_EVENT_CHANGE_POLICY"];
+ * POWERED_UP -> change_policy [label = "Change policy" URL="\ref KBASE_PM_EVENT_CHANGE_POLICY"];
+ * POWERED_DOWN -> change_policy [label = "Change policy" URL="\ref KBASE_PM_EVENT_CHANGE_POLICY"];
+ * }
+ * @enddot
+ */
+typedef enum kbasep_pm_always_on_state
+{
+ KBASEP_PM_ALWAYS_ON_STATE_POWERING_UP, /**< The GPU is powering up */
+ KBASEP_PM_ALWAYS_ON_STATE_POWERING_DOWN, /**< The GPU is powering down */
+ KBASEP_PM_ALWAYS_ON_STATE_POWERED_UP, /**< The GPU is powered up and jobs can execute */
+ KBASEP_PM_ALWAYS_ON_STATE_POWERED_DOWN, /**< The GPU is powered down and the system can suspend */
+ KBASEP_PM_ALWAYS_ON_STATE_CHANGING_POLICY /**< The power policy is about to change */
+} kbasep_pm_always_on_state;
+
+/** Private structure for policy instance data.
+ *
+ * This contains data that is private to the particular power policy that is active.
+ */
+typedef struct kbasep_pm_policy_always_on
+{
+ kbasep_pm_always_on_state state; /**< The current state of the policy */
+} kbasep_pm_policy_always_on;
+
+#endif
diff --git a/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_pm_coarse_demand.c b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_pm_coarse_demand.c
new file mode 100644
index 0000000..1e2859a
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_pm_coarse_demand.c
@@ -0,0 +1,281 @@
+/*
+ *
+ * (C) COPYRIGHT 2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_kbase_pm_coarse_demand.c
+ * "Coarse Demand" power management policy
+ */
+
+#include <osk/mali_osk.h>
+#include <kbase/src/common/mali_kbase.h>
+#include <kbase/src/common/mali_kbase_pm.h>
+
+
+/** Function to handle a GPU state change for the coarse_demand power policy.
+ *
+ * This function is called whenever the GPU has transitioned to another state. It first checks that the transition is
+ * complete and then moves the state machine to the next state.
+ *
+ * @param kbdev The kbase device structure for the device
+ */
+static void coarse_demand_state_changed(kbase_device *kbdev)
+{
+ kbasep_pm_policy_coarse_demand *data = &kbdev->pm.policy_data.coarse_demand;
+
+ /* No need to early-out if cores transitioning during the POWERING_UP state */
+ if (data->state != KBASEP_PM_COARSE_DEMAND_STATE_POWERING_UP
+ && kbase_pm_get_pwr_active(kbdev)) {
+ /* Cores are still transitioning - ignore the event */
+ return;
+ }
+
+ switch(data->state)
+ {
+ case KBASEP_PM_COARSE_DEMAND_STATE_POWERING_UP:
+ /* All cores are ready, inform the OS */
+ data->state = KBASEP_PM_COARSE_DEMAND_STATE_POWERED_UP;
+ kbase_pm_power_up_done(kbdev);
+ /*
+ * No need to submit jobs:
+ * - All cores will be powered on
+ * - Cores are made available even while they're transitioning to 'powered on'
+ * - We signal power_up_done after calling kbase_pm_check_transitions(), which makes the cores available.
+ * Hence, the submission of jobs will already be handled by the call-path that invoked kbase_pm_context_active()
+ */
+
+ break;
+ case KBASEP_PM_COARSE_DEMAND_STATE_POWERING_DOWN:
+ data->state = KBASEP_PM_COARSE_DEMAND_STATE_POWERED_DOWN;
+ /* All cores have transitioned, turn the clock and interrupts off */
+ kbase_pm_clock_off(kbdev);
+
+ /* Inform the OS */
+ kbase_pm_power_down_done(kbdev);
+
+ break;
+ case KBASEP_PM_COARSE_DEMAND_STATE_CHANGING_POLICY:
+ /* Signal power events before switching the policy */
+ kbase_pm_power_up_done(kbdev);
+ kbase_pm_power_down_done(kbdev);
+ kbase_pm_change_policy(kbdev);
+
+ break;
+ default:
+ break;
+ }
+}
+
+/** Turn the GPU off.
+ *
+ * Turns the GPU off - assuming that no Job Chains are currently running on the GPU.
+ */
+static void coarse_demand_power_down(kbase_device *kbdev)
+{
+ u64 cores;
+
+ /* Inform the system that the transition has started */
+ kbase_pm_power_transitioning(kbdev);
+
+ cores = kbase_pm_get_present_cores(kbdev, KBASE_PM_CORE_SHADER);
+ kbase_pm_invoke_power_down(kbdev, KBASE_PM_CORE_SHADER, cores);
+
+ cores = kbase_pm_get_present_cores(kbdev, KBASE_PM_CORE_TILER);
+ kbase_pm_invoke_power_down(kbdev, KBASE_PM_CORE_TILER, cores);
+
+ /* Note we don't call kbase_pm_check_transitions because we don't want to wait
+ * for the above transitions to take place before turning the GPU power domain off */
+
+ kbdev->pm.policy_data.coarse_demand.state = KBASEP_PM_COARSE_DEMAND_STATE_POWERING_DOWN;
+
+ /* Ensure that the OS is informed even if we didn't do anything */
+ coarse_demand_state_changed(kbdev);
+}
+
+/** Turn the GPU off, safe against jobs that are currently running.
+ *
+ * Turns the GPU off in a way that will wait for jobs to finish first.
+ */
+static void coarse_demand_suspend(kbase_device *kbdev)
+{
+ u64 cores;
+
+ /* Inform the system that the transition has started */
+ kbase_pm_power_transitioning(kbdev);
+
+ /* Turn the cores off */
+ cores = kbase_pm_get_present_cores(kbdev, KBASE_PM_CORE_SHADER);
+ kbase_pm_invoke_power_down(kbdev, KBASE_PM_CORE_SHADER, cores);
+
+ cores = kbase_pm_get_present_cores(kbdev, KBASE_PM_CORE_TILER);
+ kbase_pm_invoke_power_down(kbdev, KBASE_PM_CORE_TILER, cores);
+
+ kbdev->pm.policy_data.coarse_demand.state = KBASEP_PM_COARSE_DEMAND_STATE_POWERING_DOWN;
+
+ kbase_pm_check_transitions(kbdev);
+}
+
+
+/** Turns the cores on.
+ *
+ * This function turns all the cores of the GPU on.
+ */
+static void coarse_demand_power_up(kbase_device *kbdev)
+{
+ u64 cores;
+
+ /* Inform the system that the transition has started */
+ kbase_pm_power_transitioning(kbdev);
+
+ /* Turn the clock on and enable interrupts */
+ kbase_pm_clock_on(kbdev);
+
+ /* Turn the cores on */
+ cores = kbase_pm_get_present_cores(kbdev, KBASE_PM_CORE_SHADER);
+ kbase_pm_invoke_power_up(kbdev, KBASE_PM_CORE_SHADER, cores);
+
+ cores = kbase_pm_get_present_cores(kbdev, KBASE_PM_CORE_TILER);
+ kbase_pm_invoke_power_up(kbdev, KBASE_PM_CORE_TILER, cores);
+
+ kbase_pm_check_transitions(kbdev);
+
+ kbdev->pm.policy_data.coarse_demand.state = KBASEP_PM_COARSE_DEMAND_STATE_POWERING_UP;
+
+ /* Ensure that the OS is informed even if we didn't do anything */
+ coarse_demand_state_changed(kbdev);
+}
+
+/** The event callback function for the coarse_demand power policy.
+ *
+ * This function is called to handle the events for the power policy. It calls the relevant handler function depending
+ * on the type of the event.
+ *
+ * @param kbdev The kbase device structure for the device
+ * @param event The event that should be processed
+ */
+static void coarse_demand_event(kbase_device *kbdev, kbase_pm_event event)
+{
+ kbasep_pm_policy_coarse_demand *data = &kbdev->pm.policy_data.coarse_demand;
+
+ switch(event)
+ {
+ case KBASE_PM_EVENT_POLICY_INIT:
+ coarse_demand_power_up(kbdev);
+ break;
+ case KBASE_PM_EVENT_SYSTEM_SUSPEND:
+ switch (data->state)
+ {
+ case KBASEP_PM_COARSE_DEMAND_STATE_POWERING_DOWN:
+ break;
+ case KBASEP_PM_COARSE_DEMAND_STATE_POWERED_DOWN:
+ kbase_pm_power_down_done(kbdev);
+ break;
+ default:
+ coarse_demand_suspend(kbdev);
+ }
+ break;
+ case KBASE_PM_EVENT_GPU_IDLE:
+ switch (data->state)
+ {
+ case KBASEP_PM_COARSE_DEMAND_STATE_POWERING_DOWN:
+ break;
+ case KBASEP_PM_COARSE_DEMAND_STATE_POWERED_DOWN:
+ kbase_pm_power_down_done(kbdev);
+ break;
+ default:
+ coarse_demand_power_down(kbdev);
+ }
+ break;
+ case KBASE_PM_EVENT_GPU_ACTIVE:
+ case KBASE_PM_EVENT_SYSTEM_RESUME:
+ switch (data->state)
+ {
+ case KBASEP_PM_COARSE_DEMAND_STATE_POWERING_UP:
+ break;
+ case KBASEP_PM_COARSE_DEMAND_STATE_POWERED_UP:
+ kbase_pm_power_up_done(kbdev);
+ break;
+ default:
+ coarse_demand_power_up(kbdev);
+ }
+ break;
+ case KBASE_PM_EVENT_GPU_STATE_CHANGED:
+ coarse_demand_state_changed(kbdev);
+ break;
+ case KBASE_PM_EVENT_POLICY_CHANGE:
+ if (data->state == KBASEP_PM_COARSE_DEMAND_STATE_POWERED_UP ||
+ data->state == KBASEP_PM_COARSE_DEMAND_STATE_POWERED_DOWN)
+ {
+ kbase_pm_change_policy(kbdev);
+ }
+ else
+ {
+ data->state = KBASEP_PM_COARSE_DEMAND_STATE_CHANGING_POLICY;
+ }
+ break;
+ case KBASE_PM_EVENT_CHANGE_GPU_STATE:
+ if (data->state != KBASEP_PM_COARSE_DEMAND_STATE_POWERED_DOWN &&
+ data->state != KBASEP_PM_COARSE_DEMAND_STATE_POWERING_DOWN)
+ {
+ /*
+ * Update anyone waiting for power up events.
+ */
+ kbase_pm_check_transitions(kbdev);
+ }
+ break;
+ default:
+ /* Unrecognised event - this should never happen */
+ OSK_ASSERT(0);
+ }
+}
+
+/** Initialize the coarse_demand power policy
+ *
+ * This sets up the private @ref kbase_pm_device_data.policy_data field of the device for use with the coarse_demand power
+ * policy.
+ *
+ * @param kbdev The kbase device structure for the device
+ */
+static void coarse_demand_init(kbase_device *kbdev)
+{
+ kbasep_pm_policy_coarse_demand *data = &kbdev->pm.policy_data.coarse_demand;
+
+ data->state = KBASEP_PM_COARSE_DEMAND_STATE_POWERED_UP;
+}
+
+/** Terminate the coarse_demand power policy
+ *
+ * This frees the resources that were allocated by @ref coarse_demand_init.
+ *
+ * @param kbdev The kbase device structure for the device
+ */
+static void coarse_demand_term(kbase_device *kbdev)
+{
+ CSTD_UNUSED(kbdev);
+}
+
+/** The @ref kbase_pm_policy structure for the coarse_demand power policy
+ *
+ * This is the extern structure that defines the coarse_demand power policy's callback and name.
+ */
+const kbase_pm_policy kbase_pm_coarse_demand_policy_ops =
+{
+ "coarse_demand", /* name */
+ coarse_demand_init, /* init */
+ coarse_demand_term, /* term */
+ coarse_demand_event, /* event */
+ KBASE_PM_POLICY_FLAG_NO_CORE_TRANSITIONS, /* flags */
+ KBASE_PM_POLICY_ID_COARSE_DEMAND, /* id */
+};
+
+KBASE_EXPORT_TEST_API(kbase_pm_coarse_demand_policy_ops)
diff --git a/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_pm_coarse_demand.h b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_pm_coarse_demand.h
new file mode 100644
index 0000000..f19a02c
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_pm_coarse_demand.h
@@ -0,0 +1,84 @@
+/*
+ *
+ * (C) COPYRIGHT 2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_kbase_pm_coarse_demand.h
+ * "Coarse" power management policy
+ */
+
+#ifndef MALI_KBASE_PM_COARSE_DEMAND_H
+#define MALI_KBASE_PM_COARSE_DEMAND_H
+
+/** The states that the coarse_demand policy can enter.
+ *
+ * The diagram below should the states that the coarse_demand policy can enter and the transitions that can occur between
+ * the states:
+ *
+ * @dot
+ * digraph coarse_demand_states {
+ * node [fontsize=10];
+ * edge [fontsize=10];
+ *
+ * POWERING_UP [label="STATE_POWERING_UP"
+ * URL="\ref kbasep_pm_coarse_demand_state.KBASEP_PM_COARSE_DEMAND_STATE_POWERING_UP"];
+ * POWERING_DOWN [label="STATE_POWERING_DOWN"
+ * URL="\ref kbasep_pm_coarse_demand_state.KBASEP_PM_COARSE_DEMAND_STATE_POWERING_DOWN"];
+ * POWERED_UP [label="STATE_POWERED_UP"
+ * URL="\ref kbasep_pm_coarse_demand_state.KBASEP_PM_COARSE_DEMAND_STATE_POWERED_UP"];
+ * POWERED_DOWN [label="STATE_POWERED_DOWN"
+ * URL="\ref kbasep_pm_coarse_demand_state.KBASEP_PM_COARSE_DEMAND_STATE_POWERED_DOWN"];
+ * CHANGING_POLICY [label="STATE_CHANGING_POLICY"
+ * URL="\ref kbasep_pm_coarse_demand_state.KBASEP_PM_COARSE_DEMAND_STATE_CHANGING_POLICY"];
+ *
+ * init [label="init" URL="\ref KBASE_PM_EVENT_INIT"];
+ * change_policy [label="change_policy" URL="\ref kbase_pm_change_policy"];
+ *
+ * init -> POWERING_UP [ label = "Policy init" ];
+ *
+ * POWERING_UP -> POWERED_UP [label = "Power state change" URL="\ref KBASE_PM_EVENT_STATE_CHANGED"];
+ * POWERING_DOWN -> POWERED_DOWN [label = "Power state change" URL="\ref KBASE_PM_EVENT_STATE_CHANGED"];
+ * CHANGING_POLICY -> change_policy [label = "Power state change" URL="\ref KBASE_PM_EVENT_STATE_CHANGED"];
+ *
+ * POWERED_UP -> POWERING_DOWN [label = "GPU Idle" URL="\ref KBASE_PM_EVENT_GPU_IDLE"];
+ * POWERING_UP -> POWERING_DOWN [label = "GPU Idle" URL="\ref KBASE_PM_EVENT_GPU_IDLE"];
+ *
+ * POWERED_DOWN -> POWERING_UP [label = "GPU Active" URL="\ref KBASE_PM_EVENT_GPU_ACTIVE"];
+ * POWERING_DOWN -> POWERING_UP [label = "GPU Active" URL="\ref KBASE_PM_EVENT_GPU_ACTIVE"];
+ *
+ * POWERING_UP -> CHANGING_POLICY [label = "Change policy" URL="\ref KBASE_PM_EVENT_CHANGE_POLICY"];
+ * POWERING_DOWN -> CHANGING_POLICY [label = "Change policy" URL="\ref KBASE_PM_EVENT_CHANGE_POLICY"];
+ * POWERED_UP -> change_policy [label = "Change policy" URL="\ref KBASE_PM_EVENT_CHANGE_POLICY"];
+ * POWERED_DOWN -> change_policy [label = "Change policy" URL="\ref KBASE_PM_EVENT_CHANGE_POLICY"];
+ * }
+ * @enddot
+ */
+typedef enum kbasep_pm_coarse_demand_state
+{
+ KBASEP_PM_COARSE_DEMAND_STATE_POWERING_UP, /**< The GPU is powering up */
+ KBASEP_PM_COARSE_DEMAND_STATE_POWERING_DOWN, /**< The GPU is powering down */
+ KBASEP_PM_COARSE_DEMAND_STATE_POWERED_UP, /**< The GPU is powered up and jobs can execute */
+ KBASEP_PM_COARSE_DEMAND_STATE_POWERED_DOWN, /**< The GPU is powered down and the system can suspend */
+ KBASEP_PM_COARSE_DEMAND_STATE_CHANGING_POLICY /**< The power policy is about to change */
+} kbasep_pm_coarse_demand_state;
+
+/** Private structure for policy instance data.
+ *
+ * This contains data that is private to the particular power policy that is active.
+ */
+typedef struct kbasep_pm_policy_coarse_demand
+{
+ kbasep_pm_coarse_demand_state state; /**< The current state of the policy */
+} kbasep_pm_policy_coarse_demand;
+
+#endif
diff --git a/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_pm_demand.c b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_pm_demand.c
new file mode 100644
index 0000000..a00259e
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_pm_demand.c
@@ -0,0 +1,242 @@
+/*
+ *
+ * (C) COPYRIGHT 2010-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_kbase_pm_demand.c
+ * A simple demand based power management policy
+ */
+
+#include <osk/mali_osk.h>
+#include <kbase/src/common/mali_kbase.h>
+#include <kbase/src/common/mali_kbase_pm.h>
+
+/* Forward declaration for state change function, as it is required by
+ * the power up and down functions */
+static void demand_state_changed(kbase_device *kbdev);
+
+/** Turns the cores on.
+ *
+ * This function turns all the cores of the GPU on.
+ */
+static void demand_power_up(kbase_device *kbdev)
+{
+ /* Inform the system that the transition has started */
+ kbase_pm_power_transitioning(kbdev);
+
+ /* Turn clocks and interrupts on */
+ kbase_pm_clock_on(kbdev);
+
+ kbase_pm_check_transitions(kbdev);
+
+ kbdev->pm.policy_data.demand.state = KBASEP_PM_DEMAND_STATE_POWERING_UP;
+}
+
+/** Turn the cores off.
+ *
+ * This function turns all the cores of the GPU off.
+ */
+static void demand_power_down(kbase_device *kbdev)
+{
+ u64 cores;
+
+ /* Inform the system that the transition has started */
+ kbase_pm_power_transitioning(kbdev);
+
+ /* Turn the cores off */
+ cores = kbase_pm_get_present_cores(kbdev, KBASE_PM_CORE_SHADER);
+ kbase_pm_invoke_power_down(kbdev, KBASE_PM_CORE_SHADER, cores);
+
+ cores = kbase_pm_get_present_cores(kbdev, KBASE_PM_CORE_TILER);
+ kbase_pm_invoke_power_down(kbdev, KBASE_PM_CORE_TILER, cores);
+
+ kbdev->pm.policy_data.demand.state = KBASEP_PM_DEMAND_STATE_POWERING_DOWN;
+
+ kbase_pm_check_transitions(kbdev);
+}
+
+/** Turn some cores on/off.
+ *
+ * This function turns on/off the cores needed by the scheduler.
+ */
+static void demand_change_gpu_state(kbase_device *kbdev)
+{
+ /* Update the bitmap of the cores we need */
+ u64 new_shader_desired = kbdev->shader_needed_bitmap | kbdev->shader_inuse_bitmap;
+ u64 new_tiler_desired = kbdev->tiler_needed_bitmap | kbdev->tiler_inuse_bitmap;
+
+ if ( kbdev->pm.desired_shader_state != new_shader_desired )
+ {
+ KBASE_TRACE_ADD( kbdev, PM_CORES_CHANGE_DESIRED, NULL, NULL, 0u, (u32)new_shader_desired );
+ }
+
+ kbdev->pm.desired_shader_state = new_shader_desired;
+ kbdev->pm.desired_tiler_state = new_tiler_desired;
+
+ kbase_pm_check_transitions(kbdev);
+}
+
+/** Function to handle a GPU state change for the demand power policy
+ *
+ * This function is called whenever the GPU has transitioned to another state. It first checks that the transition is
+ * complete and then moves the state machine to the next state.
+ */
+static void demand_state_changed(kbase_device *kbdev)
+{
+ kbasep_pm_policy_demand *data = &kbdev->pm.policy_data.demand;
+
+ if (kbase_pm_get_pwr_active(kbdev)) {
+ /* Cores are still transitioning - ignore the event */
+ return;
+ }
+
+ switch(data->state)
+ {
+ case KBASEP_PM_DEMAND_STATE_CHANGING_POLICY:
+ /* Signal power events before switching the policy */
+ kbase_pm_power_up_done(kbdev);
+ kbase_pm_power_down_done(kbdev);
+ kbase_pm_change_policy(kbdev);
+ break;
+ case KBASEP_PM_DEMAND_STATE_POWERING_UP:
+ data->state = KBASEP_PM_DEMAND_STATE_POWERED_UP;
+ kbase_pm_power_up_done(kbdev);
+ /* State changed, try to run jobs */
+ KBASE_TRACE_ADD( kbdev, PM_JOB_SUBMIT_AFTER_POWERING_UP, NULL, NULL, 0u, 0 );
+ kbase_js_try_run_jobs(kbdev);
+ break;
+ case KBASEP_PM_DEMAND_STATE_POWERING_DOWN:
+ data->state = KBASEP_PM_DEMAND_STATE_POWERED_DOWN;
+ /* Disable interrupts and turn the clock off */
+ kbase_pm_clock_off(kbdev);
+ kbase_pm_power_down_done(kbdev);
+ break;
+ case KBASEP_PM_DEMAND_STATE_POWERED_UP:
+ /* Core states may have been changed, try to run jobs */
+ KBASE_TRACE_ADD( kbdev, PM_JOB_SUBMIT_AFTER_POWERED_UP, NULL, NULL, 0u, 0 );
+ kbase_js_try_run_jobs(kbdev);
+ break;
+ default:
+ break;
+ }
+}
+
+/** The event callback function for the demand power policy.
+ *
+ * This function is called to handle the events for the power policy. It calls the relevant handler function depending
+ * on the type of the event.
+ *
+ * @param kbdev The kbase device structure for the device
+ * @param event The event that should be processed
+ */
+static void demand_event(kbase_device *kbdev, kbase_pm_event event)
+{
+ kbasep_pm_policy_demand *data = &kbdev->pm.policy_data.demand;
+
+ switch(event)
+ {
+ case KBASE_PM_EVENT_POLICY_INIT:
+ demand_power_up(kbdev);
+ break;
+ case KBASE_PM_EVENT_POLICY_CHANGE:
+ if (data->state == KBASEP_PM_DEMAND_STATE_POWERED_UP ||
+ data->state == KBASEP_PM_DEMAND_STATE_POWERED_DOWN)
+ {
+ kbase_pm_change_policy(kbdev);
+ }
+ else
+ {
+ data->state = KBASEP_PM_DEMAND_STATE_CHANGING_POLICY;
+ }
+ break;
+ case KBASE_PM_EVENT_SYSTEM_RESUME:
+ case KBASE_PM_EVENT_GPU_ACTIVE:
+ switch (data->state)
+ {
+ case KBASEP_PM_DEMAND_STATE_POWERING_UP:
+ break;
+ case KBASEP_PM_DEMAND_STATE_POWERED_UP:
+ kbase_pm_power_up_done(kbdev);
+ break;
+ default:
+ demand_power_up(kbdev);
+ }
+ break;
+ case KBASE_PM_EVENT_SYSTEM_SUSPEND:
+ case KBASE_PM_EVENT_GPU_IDLE:
+ switch (data->state)
+ {
+ case KBASEP_PM_DEMAND_STATE_POWERING_DOWN:
+ break;
+ case KBASEP_PM_DEMAND_STATE_POWERED_DOWN:
+ kbase_pm_power_down_done(kbdev);
+ break;
+ default:
+ demand_power_down(kbdev);
+ }
+ break;
+ case KBASE_PM_EVENT_CHANGE_GPU_STATE:
+ if (data->state != KBASEP_PM_DEMAND_STATE_POWERED_DOWN &&
+ data->state != KBASEP_PM_DEMAND_STATE_POWERING_DOWN)
+ {
+ demand_change_gpu_state(kbdev);
+ }
+ break;
+ case KBASE_PM_EVENT_GPU_STATE_CHANGED:
+ demand_state_changed(kbdev);
+ break;
+ default:
+ /* unrecognized event, should never happen */
+ OSK_ASSERT(0);
+ }
+}
+
+/** Initialize the demand power policy.
+ *
+ * This sets up the private @ref kbase_pm_device_data.policy_data field of the device for use with the demand power
+ * policy.
+ *
+ * @param kbdev The kbase device structure for the device
+ */
+static void demand_init(kbase_device *kbdev)
+{
+ kbdev->pm.policy_data.demand.state = KBASEP_PM_DEMAND_STATE_POWERED_UP;
+}
+
+/** Terminate the demand power policy.
+ *
+ * This frees the resources that were allocated by @ref demand_init.
+ *
+ * @param kbdev The kbase device structure for the device
+ */
+static void demand_term(kbase_device *kbdev)
+{
+ CSTD_UNUSED(kbdev);
+}
+
+/** The @ref kbase_pm_policy structure for the demand power policy.
+ *
+ * This is the static structure that defines the demand power policy's callback and name.
+ */
+const kbase_pm_policy kbase_pm_demand_policy_ops =
+{
+ "demand", /* name */
+ demand_init, /* init */
+ demand_term, /* term */
+ demand_event, /* event */
+ 0u, /* flags */
+ KBASE_PM_POLICY_ID_DEMAND, /* id */
+};
+
+
+KBASE_EXPORT_TEST_API(kbase_pm_demand_policy_ops)
diff --git a/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_pm_demand.h b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_pm_demand.h
new file mode 100644
index 0000000..28e9cba
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_pm_demand.h
@@ -0,0 +1,84 @@
+/*
+ *
+ * (C) COPYRIGHT 2011-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_kbase_pm_demand.h
+ * A simple demand based power management policy
+ */
+
+#ifndef MALI_KBASE_PM_DEMAND_H
+#define MALI_KBASE_PM_DEMAND_H
+
+/** The states that the demand policy can enter.
+ *
+ * The diagram below should the states that the demand policy can enter and the transitions that can occur between the
+ * states:
+ *
+ * @dot
+ * digraph demand_states {
+ * node [fontsize=10];
+ * edge [fontsize=10];
+ *
+ * POWERING_UP [label="STATE_POWERING_UP"
+ * URL="\ref kbasep_pm_demand_state.KBASEP_PM_DEMAND_STATE_POWERING_UP"];
+ * POWERING_DOWN [label="STATE_POWERING_DOWN"
+ * URL="\ref kbasep_pm_demand_state.KBASEP_PM_DEMAND_STATE_POWERING_DOWN"];
+ * POWERED_UP [label="STATE_POWERED_UP"
+ * URL="\ref kbasep_pm_demand_state.KBASEP_PM_DEMAND_STATE_POWERED_UP"];
+ * POWERED_DOWN [label="STATE_POWERED_DOWN"
+ * URL="\ref kbasep_pm_demand_state.KBASEP_PM_DEMAND_STATE_POWERED_DOWN"];
+ * CHANGING_POLICY [label="STATE_CHANGING_POLICY"
+ * URL="\ref kbasep_pm_demand_state.KBASEP_PM_DEMAND_STATE_CHANGING_POLICY"];
+ *
+ * init [label="init" URL="\ref KBASE_PM_EVENT_INIT"];
+ * change_policy [label="change_policy" URL="\ref kbase_pm_change_policy"];
+ *
+ * init -> POWERING_UP [ label = "Policy init" ];
+ *
+ * POWERING_UP -> POWERED_UP [label = "Power state change" URL="\ref KBASE_PM_EVENT_STATE_CHANGED"];
+ * POWERING_DOWN -> POWERED_DOWN [label = "Power state change" URL="\ref KBASE_PM_EVENT_STATE_CHANGED"];
+ * CHANGING_POLICY -> change_policy [label = "Power state change" URL="\ref KBASE_PM_EVENT_STATE_CHANGED"];
+ *
+ * POWERED_UP -> POWERING_DOWN [label = "GPU Idle" URL="\ref KBASE_PM_EVENT_GPU_IDLE"];
+ * POWERING_UP -> POWERING_DOWN [label = "GPU Idle" URL="\ref KBASE_PM_EVENT_GPU_IDLE"];
+ *
+ * POWERED_DOWN -> POWERING_UP [label = "GPU Active" URL="\ref KBASE_PM_EVENT_GPU_ACTIVE"];
+ * POWERING_DOWN -> POWERING_UP [label = "GPU Active" URL="\ref KBASE_PM_EVENT_GPU_ACTIVE"];
+
+ * POWERING_UP -> CHANGING_POLICY [label = "Change policy" URL="\ref KBASE_PM_EVENT_CHANGE_POLICY"];
+ * POWERING_DOWN -> CHANGING_POLICY [label = "Change policy" URL="\ref KBASE_PM_EVENT_CHANGE_POLICY"];
+ * POWERED_UP -> change_policy [label = "Change policy" URL="\ref KBASE_PM_EVENT_CHANGE_POLICY"];
+ * POWERED_DOWN -> change_policy [label = "Change policy" URL="\ref KBASE_PM_EVENT_CHANGE_POLICY"];
+ * }
+ * @enddot
+ */
+typedef enum kbasep_pm_demand_state
+{
+ KBASEP_PM_DEMAND_STATE_POWERING_UP, /**< The GPU is powering up */
+ KBASEP_PM_DEMAND_STATE_POWERED_UP, /**< The GPU is powered up and jobs can execute */
+ KBASEP_PM_DEMAND_STATE_POWERING_DOWN, /**< The GPU is powering down */
+ KBASEP_PM_DEMAND_STATE_POWERED_DOWN, /**< The GPU is powered down */
+ KBASEP_PM_DEMAND_STATE_CHANGING_POLICY /**< The power policy is about to change */
+} kbasep_pm_demand_state;
+
+/** Private structure for policy instance data.
+ *
+ * This contains data that is private to the particular power policy that is active.
+ */
+typedef struct kbasep_pm_policy_demand
+{
+ kbasep_pm_demand_state state; /**< The current state of the policy */
+} kbasep_pm_policy_demand;
+
+#endif
diff --git a/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_pm_driver.c b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_pm_driver.c
new file mode 100644
index 0000000..c2485d5
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_pm_driver.c
@@ -0,0 +1,1133 @@
+/*
+ *
+ * (C) COPYRIGHT 2010-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_kbase_pm_driver.c
+ * Base kernel Power Management hardware control
+ */
+
+#include <osk/mali_osk.h>
+#include <kbase/src/common/mali_kbase.h>
+#include <kbase/src/common/mali_midg_regmap.h>
+#include <kbase/src/common/mali_kbase_gator.h>
+#include <kbase/src/common/mali_kbase_pm.h>
+
+#if MALI_MOCK_TEST
+#define MOCKABLE(function) function##_original
+#else
+#define MOCKABLE(function) function
+#endif /* MALI_MOCK_TEST */
+
+/** Number of milliseconds before we time out on a reset */
+#define RESET_TIMEOUT 500
+
+/** Actions that can be performed on a core.
+ *
+ * This enumeration is private to the file. Its values are set to allow @ref core_type_to_reg function,
+ * which decodes this enumeration, to be simpler and more efficient.
+ */
+typedef enum kbasep_pm_action
+{
+ ACTION_PRESENT = 0,
+ ACTION_READY = (SHADER_READY_LO - SHADER_PRESENT_LO),
+ ACTION_PWRON = (SHADER_PWRON_LO - SHADER_PRESENT_LO),
+ ACTION_PWROFF = (SHADER_PWROFF_LO - SHADER_PRESENT_LO),
+ ACTION_PWRTRANS = (SHADER_PWRTRANS_LO - SHADER_PRESENT_LO),
+ ACTION_PWRACTIVE = (SHADER_PWRACTIVE_LO - SHADER_PRESENT_LO)
+} kbasep_pm_action;
+
+/** Decode a core type and action to a register.
+ *
+ * Given a core type (defined by @ref kbase_pm_core_type) and an action (defined by @ref kbasep_pm_action) this
+ * function will return the register offset that will perform the action on the core type. The register returned is
+ * the \c _LO register and an offset must be applied to use the \c _HI register.
+ *
+ * @param core_type The type of core
+ * @param action The type of action
+ *
+ * @return The register offset of the \c _LO register that performs an action of type \c action on a core of type \c
+ * core_type.
+ */
+static u32 core_type_to_reg(kbase_pm_core_type core_type, kbasep_pm_action action)
+{
+ return core_type + action;
+}
+
+/** Invokes an action on a core set
+ *
+ * This function performs the action given by \c action on a set of cores of a type given by \c core_type. It is a
+ * static function used by @ref kbase_pm_transition_core_type
+ *
+ * @param kbdev The kbase device structure of the device
+ * @param core_type The type of core that the action should be performed on
+ * @param cores A bit mask of cores to perform the action on (low 32 bits)
+ * @param action The action to perform on the cores
+ */
+STATIC void kbase_pm_invoke(kbase_device *kbdev, kbase_pm_core_type core_type, u64 cores, kbasep_pm_action action)
+{
+ u32 reg;
+ u32 lo = cores & 0xFFFFFFFF;
+ u32 hi = (cores >> 32) & 0xFFFFFFFF;
+
+ reg = core_type_to_reg(core_type, action);
+
+ OSK_ASSERT(reg);
+#ifdef CONFIG_MALI_GATOR_SUPPORT
+ if (cores)
+ {
+ if (action == ACTION_PWRON )
+ {
+ kbase_trace_mali_pm_power_on(core_type, cores);
+ }
+ else if ( action == ACTION_PWROFF )
+ {
+ kbase_trace_mali_pm_power_off(core_type, cores);
+ }
+ }
+#endif /* CONFIG_MALI_GATOR_SUPPORT */
+ /* Tracing */
+ if ( cores != 0 && core_type == KBASE_PM_CORE_SHADER )
+ {
+ if (action == ACTION_PWRON )
+ {
+ KBASE_TRACE_ADD( kbdev, PM_PWRON, NULL, NULL, 0u, lo );
+ }
+ else if ( action == ACTION_PWROFF )
+ {
+ KBASE_TRACE_ADD( kbdev, PM_PWROFF, NULL, NULL, 0u, lo );
+ }
+ }
+
+ if (lo != 0)
+ {
+ kbase_reg_write(kbdev, GPU_CONTROL_REG(reg), lo, NULL);
+ }
+ if (hi != 0)
+ {
+ kbase_reg_write(kbdev, GPU_CONTROL_REG(reg+4), hi, NULL);
+ }
+}
+
+void kbase_pm_invoke_power_up(kbase_device *kbdev, kbase_pm_core_type type, u64 cores)
+{
+ OSK_ASSERT( kbdev != NULL );
+
+ switch(type)
+ {
+ case KBASE_PM_CORE_SHADER:
+ {
+ u64 prev_desired_shader = kbdev->pm.desired_shader_state;
+ kbdev->pm.desired_shader_state |= cores;
+ if ( prev_desired_shader != kbdev->pm.desired_shader_state )
+ {
+ KBASE_TRACE_ADD( kbdev, PM_CORES_CHANGE_DESIRED_ON_POWERUP, NULL, NULL, 0u, (u32)kbdev->pm.desired_shader_state );
+ }
+ }
+ break;
+ case KBASE_PM_CORE_TILER:
+ kbdev->pm.desired_tiler_state |= cores;
+ break;
+ default:
+ OSK_ASSERT(0);
+ }
+}
+KBASE_EXPORT_TEST_API(kbase_pm_invoke_power_up)
+
+void kbase_pm_invoke_power_down(kbase_device *kbdev, kbase_pm_core_type type, u64 cores)
+{
+ OSK_ASSERT( kbdev != NULL );
+
+ switch(type)
+ {
+ case KBASE_PM_CORE_SHADER:
+ {
+ u64 prev_desired_shader = kbdev->pm.desired_shader_state;
+ kbdev->pm.desired_shader_state &= ~cores;
+ if ( prev_desired_shader != kbdev->pm.desired_shader_state )
+ {
+ KBASE_TRACE_ADD( kbdev, PM_CORES_CHANGE_DESIRED_ON_POWERDOWN, NULL, NULL, 0u, (u32)kbdev->pm.desired_shader_state );
+ }
+ /* Also remove the cores from the available set to prevent job submission to
+ * these cores before the next call to kbase_pm_check_transitions */
+ kbdev->shader_available_bitmap &= ~cores;
+ }
+ break;
+ case KBASE_PM_CORE_TILER:
+ kbdev->pm.desired_tiler_state &= ~cores;
+ kbdev->tiler_available_bitmap &= ~cores;
+ break;
+ default:
+ OSK_ASSERT(0);
+ }
+}
+KBASE_EXPORT_TEST_API(kbase_pm_invoke_power_down)
+/** Get information about a core set
+ *
+ * This function gets information (chosen by \c action) about a set of cores of a type given by \c core_type. It is a
+ * static function used by @ref kbase_pm_get_present_cores, @ref kbase_pm_get_active_cores, @ref
+ * kbase_pm_get_trans_cores and @ref kbase_pm_get_ready_cores.
+ *
+ * @param kbdev The kbase device structure of the device
+ * @param core_type The type of core that the should be queried
+ * @param action The property of the cores to query
+ *
+ * @return A bit mask specifying the state of the cores
+ */
+static u64 kbase_pm_get_state(kbase_device *kbdev, kbase_pm_core_type core_type, kbasep_pm_action action)
+{
+ u32 reg;
+ u32 lo, hi;
+
+ reg = core_type_to_reg(core_type, action);
+
+ OSK_ASSERT(reg);
+
+ lo = kbase_reg_read(kbdev, GPU_CONTROL_REG(reg), NULL);
+ hi = kbase_reg_read(kbdev, GPU_CONTROL_REG(reg+4), NULL);
+
+ return (((u64)hi) << 32) | ((u64)lo);
+}
+
+void kbasep_pm_read_present_cores(kbase_device *kbdev)
+{
+ kbdev->shader_present_bitmap = kbase_pm_get_state(kbdev, KBASE_PM_CORE_SHADER, ACTION_PRESENT);
+ kbdev->tiler_present_bitmap = kbase_pm_get_state(kbdev, KBASE_PM_CORE_TILER, ACTION_PRESENT);
+ kbdev->l2_present_bitmap = kbase_pm_get_state(kbdev, KBASE_PM_CORE_L2, ACTION_PRESENT);
+ kbdev->l3_present_bitmap = kbase_pm_get_state(kbdev, KBASE_PM_CORE_L3, ACTION_PRESENT);
+
+ kbdev->shader_inuse_bitmap = 0;
+ kbdev->tiler_inuse_bitmap = 0;
+ kbdev->shader_needed_bitmap = 0;
+ kbdev->tiler_needed_bitmap = 0;
+ kbdev->shader_available_bitmap = 0;
+ kbdev->tiler_available_bitmap = 0;
+ kbdev->l2_users_count = 0;
+
+ memset(kbdev->shader_needed_cnt, 0, sizeof(kbdev->shader_needed_cnt));
+ memset(kbdev->tiler_needed_cnt, 0, sizeof(kbdev->tiler_needed_cnt));
+}
+KBASE_EXPORT_TEST_API(kbasep_pm_read_present_cores)
+
+/** Get the cores that are present
+ */
+u64 kbase_pm_get_present_cores(kbase_device *kbdev, kbase_pm_core_type type)
+{
+ OSK_ASSERT( kbdev != NULL );
+
+ switch(type) {
+ case KBASE_PM_CORE_L3:
+ return kbdev->l3_present_bitmap;
+ break;
+ case KBASE_PM_CORE_L2:
+ return kbdev->l2_present_bitmap;
+ break;
+ case KBASE_PM_CORE_SHADER:
+ return kbdev->shader_present_bitmap;
+ break;
+ case KBASE_PM_CORE_TILER:
+ return kbdev->tiler_present_bitmap;
+ break;
+ }
+ OSK_ASSERT(0);
+ return 0;
+}
+KBASE_EXPORT_TEST_API(kbase_pm_get_present_cores)
+
+/** Get the cores that are "active" (busy processing work)
+ */
+u64 kbase_pm_get_active_cores(kbase_device *kbdev, kbase_pm_core_type type)
+{
+ return kbase_pm_get_state(kbdev, type, ACTION_PWRACTIVE);
+}
+KBASE_EXPORT_TEST_API(kbase_pm_get_active_cores)
+
+/** Get the cores that are transitioning between power states
+ */
+u64 MOCKABLE(kbase_pm_get_trans_cores)(kbase_device *kbdev, kbase_pm_core_type type)
+{
+ return kbase_pm_get_state(kbdev, type, ACTION_PWRTRANS);
+}
+KBASE_EXPORT_TEST_API(kbase_pm_get_trans_cores)
+/** Get the cores that are powered on
+ */
+u64 kbase_pm_get_ready_cores(kbase_device *kbdev, kbase_pm_core_type type)
+{
+ u64 result;
+ result = kbase_pm_get_state(kbdev, type, ACTION_READY);
+
+ if ( type == KBASE_PM_CORE_SHADER )
+ {
+ KBASE_TRACE_ADD( kbdev, PM_CORES_POWERED, NULL, NULL, 0u, (u32)result);
+ }
+ return result;
+}
+KBASE_EXPORT_TEST_API(kbase_pm_get_ready_cores)
+
+/** Is there an active power transition?
+ *
+ * Returns true if there is a power transition in progress, otherwise false.
+ */
+mali_bool MOCKABLE(kbase_pm_get_pwr_active)(kbase_device *kbdev)
+{
+ mali_bool state = atomic_read(&kbdev->pm.gpu_in_desired_state);
+ return !state;
+}
+KBASE_EXPORT_TEST_API(kbase_pm_get_pwr_active)
+
+/** Perform power transitions for a particular core type.
+ *
+ * This function will perform any available power transitions to make the actual hardware state closer to the desired
+ * state. If a core is currently transitioning then changes to the power state of that call cannot be made until the
+ * transition has finished. Cores which are not present in the hardware are ignored if they are specified in the
+ * desired_state bitmask, however the return value will always be 0 in this case.
+ *
+ * @param kbdev The kbase device
+ * @param type The core type to perform transitions for
+ * @param desired_state A bit mask of the desired state of the cores
+ * @param in_use A bit mask of the cores that are currently running jobs.
+ * These cores have to be kept powered up because there are jobs
+ * running (or about to run) on them.
+ * @param[out] available Receives a bit mask of the cores that the job scheduler can use to submit jobs to.
+ * May be NULL if this is not needed.
+ * @param[in,out] powering_on Bit mask to update with cores that are transitioning to a power-on state.
+ *
+ * @return MALI_TRUE if the desired state has been reached, MALI_FALSE otherwise
+ */
+
+STATIC mali_bool kbase_pm_transition_core_type(kbase_device *kbdev, kbase_pm_core_type type, u64 desired_state,
+ u64 in_use, u64 *available, u64 *powering_on)
+{
+ u64 present;
+ u64 ready;
+ u64 trans;
+ u64 powerup;
+ u64 powerdown;
+ u64 powering_on_trans;
+
+ /* Get current state */
+ present = kbase_pm_get_present_cores(kbdev, type);
+ trans = kbase_pm_get_trans_cores(kbdev, type);
+ ready = kbase_pm_get_ready_cores(kbdev, type);
+
+ powering_on_trans = trans & *powering_on;
+ *powering_on = powering_on_trans;
+ if (available != NULL)
+ {
+ *available = (ready | powering_on_trans) & desired_state;
+ }
+
+ /* Update desired state to include the in-use cores. These have to be kept powered up because there are jobs
+ * running or about to run on these cores
+ */
+ desired_state |= in_use;
+
+ /* Update state of whether l2 caches are powered */
+ if ( type == KBASE_PM_CORE_L2 )
+ {
+ if ( (ready == present) && (desired_state == ready) && (trans == 0) )
+ {
+ /* All are ready, none will be turned off, and none are transitioning */
+ kbdev->pm.l2_powered = 1;
+ if ( kbdev->l2_users_count > 0 )
+ {
+ /* Notify any registered l2 cache users (optimized out when no users waiting) */
+ wake_up(&kbdev->pm.l2_powered_wait);
+ }
+ }
+ else
+ {
+ kbdev->pm.l2_powered = 0;
+ }
+ }
+
+ if (desired_state == ready && (trans == 0))
+ {
+ return MALI_TRUE;
+ }
+
+ /* Restrict the cores to those that are actually present */
+ powerup = desired_state & present;
+ powerdown = (~desired_state) & present;
+
+ /* Restrict to cores that are not already in the desired state */
+ powerup &= ~ready;
+ powerdown &= ready;
+
+ /* Don't transition any cores that are already transitioning */
+ powerup &= ~trans;
+ powerdown &= ~trans;
+
+ /* Perform transitions if any */
+ kbase_pm_invoke(kbdev, type, powerup, ACTION_PWRON);
+ kbase_pm_invoke(kbdev, type, powerdown, ACTION_PWROFF);
+
+ /* Recalculate cores transitioning on, and re-evaluate our state */
+ powering_on_trans |= powerup;
+ *powering_on = powering_on_trans;
+ if (available != NULL)
+ {
+ *available = (ready | powering_on_trans) & desired_state;
+ }
+
+ return MALI_FALSE;
+}
+KBASE_EXPORT_TEST_API(kbase_pm_transition_core_type)
+
+/** Determine which caches should be on for a particular core state.
+ *
+ * This function takes a bit mask of the present caches and the cores (or caches) that are attached to the caches that
+ * will be powered. It then computes which caches should be turned on to allow the cores requested to be powered up.
+ *
+ * @param present The bit mask of present caches
+ * @param cores_powered A bit mask of cores (or L2 caches) that are desired to be powered
+ *
+ * @return A bit mask of the caches that should be turned on
+ */
+STATIC u64 get_desired_cache_status(u64 present, u64 cores_powered)
+{
+ u64 desired = 0;
+
+ while (present)
+ {
+ /* Find out which is the highest set bit */
+ u64 bit = 63-osk_clz_64(present);
+ u64 bit_mask = 1ull << bit;
+ /* Create a mask which has all bits from 'bit' upwards set */
+
+ u64 mask = ~(bit_mask-1);
+
+ /* If there are any cores powered at this bit or above (that haven't previously been processed) then we need
+ * this core on */
+ if (cores_powered & mask)
+ {
+ desired |= bit_mask;
+ }
+
+ /* Remove bits from cores_powered and present */
+ cores_powered &= ~mask;
+ present &= ~bit_mask;
+ }
+
+ return desired;
+}
+KBASE_EXPORT_TEST_API(get_desired_cache_status)
+static mali_bool kbasep_pm_unrequest_cores_nolock(kbase_device *kbdev, u64 shader_cores, u64 tiler_cores)
+{
+ mali_bool change_gpu_state = MALI_FALSE;
+
+
+ OSK_ASSERT( kbdev != NULL );
+
+ while (shader_cores)
+ {
+ int bitnum = 63 - osk_clz_64(shader_cores);
+ u64 bit = 1ULL << bitnum;
+ int cnt;
+
+ OSK_ASSERT(kbdev->shader_needed_cnt[bitnum] > 0);
+
+ cnt = --kbdev->shader_needed_cnt[bitnum];
+
+ if (0 == cnt)
+ {
+ kbdev->shader_needed_bitmap &= ~bit;
+ change_gpu_state = MALI_TRUE;
+ }
+
+ shader_cores &= ~bit;
+ }
+
+ if ( change_gpu_state )
+ {
+ KBASE_TRACE_ADD( kbdev, PM_UNREQUEST_CHANGE_SHADER_NEEDED, NULL, NULL, 0u, (u32)kbdev->shader_needed_bitmap );
+ }
+
+ while (tiler_cores)
+ {
+ int bitnum = 63 - osk_clz_64(tiler_cores);
+ u64 bit = 1ULL << bitnum;
+ int cnt;
+
+ OSK_ASSERT(kbdev->tiler_needed_cnt[bitnum] > 0);
+
+ cnt = --kbdev->tiler_needed_cnt[bitnum];
+
+ if (0 == cnt)
+ {
+ kbdev->tiler_needed_bitmap &= ~bit;
+ change_gpu_state = MALI_TRUE;
+ }
+
+ tiler_cores &= ~bit;
+ }
+
+ return change_gpu_state;
+}
+
+mali_error kbase_pm_request_cores(kbase_device *kbdev, u64 shader_cores, u64 tiler_cores)
+{
+ unsigned long flags;
+ u64 cores;
+
+ mali_bool change_gpu_state = MALI_FALSE;
+
+ OSK_ASSERT( kbdev != NULL );
+
+ spin_lock_irqsave(&kbdev->pm.power_change_lock, flags);
+
+ cores = shader_cores;
+ while (cores)
+ {
+ int bitnum = 63 - osk_clz_64(cores);
+ u64 bit = 1ULL << bitnum;
+
+ int cnt = ++kbdev->shader_needed_cnt[bitnum];
+
+ if (0 == cnt)
+ {
+ /* Wrapped, undo everything we've done so far */
+
+ kbdev->shader_needed_cnt[bitnum]--;
+ kbasep_pm_unrequest_cores_nolock(kbdev, cores ^ shader_cores, 0);
+
+ spin_unlock_irqrestore(&kbdev->pm.power_change_lock, flags);
+ return MALI_ERROR_FUNCTION_FAILED;
+ }
+
+ if (1 == cnt)
+ {
+ kbdev->shader_needed_bitmap |= bit;
+ change_gpu_state = MALI_TRUE;
+ }
+
+ cores &= ~bit;
+ }
+
+
+ if ( change_gpu_state )
+ {
+ KBASE_TRACE_ADD( kbdev, PM_REQUEST_CHANGE_SHADER_NEEDED, NULL, NULL, 0u, (u32)kbdev->shader_needed_bitmap );
+ }
+
+ cores = tiler_cores;
+ while (cores)
+ {
+ int bitnum = 63 - osk_clz_64(cores);
+ u64 bit = 1ULL << bitnum;
+
+ int cnt = ++kbdev->tiler_needed_cnt[bitnum];
+
+ if (0 == cnt)
+ {
+ /* Wrapped, undo everything we've done so far */
+
+ kbdev->tiler_needed_cnt[bitnum]--;
+ kbasep_pm_unrequest_cores_nolock(kbdev, shader_cores, cores ^ tiler_cores);
+
+ spin_unlock_irqrestore(&kbdev->pm.power_change_lock, flags);
+ return MALI_ERROR_FUNCTION_FAILED;
+ }
+
+ if (1 == cnt)
+ {
+ kbdev->tiler_needed_bitmap |= bit;
+ change_gpu_state = MALI_TRUE;
+ }
+
+ cores &= ~bit;
+ }
+
+ if (change_gpu_state)
+ {
+ kbase_pm_send_event(kbdev, KBASE_PM_EVENT_CHANGE_GPU_STATE);
+ }
+
+ spin_unlock_irqrestore(&kbdev->pm.power_change_lock, flags);
+
+ return MALI_ERROR_NONE;
+}
+KBASE_EXPORT_TEST_API(kbase_pm_request_cores)
+
+void kbase_pm_unrequest_cores(kbase_device *kbdev, u64 shader_cores, u64 tiler_cores)
+{
+ unsigned long flags;
+ mali_bool change_gpu_state = MALI_FALSE;
+
+
+ OSK_ASSERT( kbdev != NULL );
+
+ spin_lock_irqsave(&kbdev->pm.power_change_lock, flags);
+
+ change_gpu_state = kbasep_pm_unrequest_cores_nolock(kbdev, shader_cores, tiler_cores);
+
+ if (change_gpu_state)
+ {
+ kbase_pm_send_event(kbdev, KBASE_PM_EVENT_CHANGE_GPU_STATE);
+ }
+
+ spin_unlock_irqrestore(&kbdev->pm.power_change_lock, flags);
+}
+KBASE_EXPORT_TEST_API(kbase_pm_unrequest_cores)
+
+mali_bool kbase_pm_register_inuse_cores(kbase_device *kbdev, u64 shader_cores, u64 tiler_cores)
+{
+ unsigned long flags;
+ u64 prev_shader_needed; /* Just for tracing */
+ u64 prev_shader_inuse; /* Just for tracing */
+
+ spin_lock_irqsave(&kbdev->pm.power_change_lock, flags);
+
+ prev_shader_needed = kbdev->shader_needed_bitmap;
+ prev_shader_inuse = kbdev->shader_inuse_bitmap;
+
+ if ((kbdev->shader_available_bitmap & shader_cores) != shader_cores ||
+ (kbdev->tiler_available_bitmap & tiler_cores) != tiler_cores)
+ {
+ spin_unlock_irqrestore(&kbdev->pm.power_change_lock, flags);
+ return MALI_FALSE;
+ }
+
+ while (shader_cores)
+ {
+ int bitnum = 63 - osk_clz_64(shader_cores);
+ u64 bit = 1ULL << bitnum;
+ int cnt;
+
+ OSK_ASSERT(kbdev->shader_needed_cnt[bitnum] > 0);
+
+ cnt = --kbdev->shader_needed_cnt[bitnum];
+
+ if (0 == cnt)
+ {
+ kbdev->shader_needed_bitmap &= ~bit;
+ }
+
+ /* shader_inuse_cnt should not overflow because there can only be a
+ * very limited number of jobs on the h/w at one time */
+
+ kbdev->shader_inuse_cnt[bitnum]++;
+ kbdev->shader_inuse_bitmap |= bit;
+
+ shader_cores &= ~bit;
+ }
+
+ if ( prev_shader_needed != kbdev->shader_needed_bitmap )
+ {
+ KBASE_TRACE_ADD( kbdev, PM_REGISTER_CHANGE_SHADER_NEEDED, NULL, NULL, 0u, (u32)kbdev->shader_needed_bitmap );
+ }
+ if ( prev_shader_inuse != kbdev->shader_inuse_bitmap )
+ {
+ KBASE_TRACE_ADD( kbdev, PM_REGISTER_CHANGE_SHADER_INUSE, NULL, NULL, 0u, (u32)kbdev->shader_inuse_bitmap );
+ }
+
+ while (tiler_cores)
+ {
+ int bitnum = 63 - osk_clz_64(tiler_cores);
+ u64 bit = 1ULL << bitnum;
+ int cnt;
+
+ OSK_ASSERT(kbdev->tiler_needed_cnt[bitnum] > 0);
+
+ cnt = --kbdev->tiler_needed_cnt[bitnum];
+
+ if (0 == cnt)
+ {
+ kbdev->tiler_needed_bitmap &= ~bit;
+ }
+
+ /* tiler_inuse_cnt should not overflow because there can only be a
+ * very limited number of jobs on the h/w at one time */
+
+ kbdev->tiler_inuse_cnt[bitnum]++;
+ kbdev->tiler_inuse_bitmap |= bit;
+
+ tiler_cores &= ~bit;
+ }
+
+ spin_unlock_irqrestore(&kbdev->pm.power_change_lock, flags);
+
+ return MALI_TRUE;
+}
+KBASE_EXPORT_TEST_API(kbase_pm_register_inuse_cores)
+
+void kbase_pm_request_l2_caches( kbase_device *kbdev )
+{
+ unsigned long flags;
+ u32 prior_l2_users_count;
+ spin_lock_irqsave(&kbdev->pm.power_change_lock, flags);
+
+ prior_l2_users_count = kbdev->l2_users_count++;
+
+ OSK_ASSERT( kbdev->l2_users_count != 0 );
+
+ if ( !prior_l2_users_count )
+ {
+ kbase_pm_send_event(kbdev, KBASE_PM_EVENT_CHANGE_GPU_STATE);
+ }
+ spin_unlock_irqrestore(&kbdev->pm.power_change_lock, flags);
+ wait_event(kbdev->pm.l2_powered_wait, kbdev->pm.l2_powered == 1);
+}
+KBASE_EXPORT_TEST_API(kbase_pm_request_l2_caches)
+
+void kbase_pm_release_l2_caches(kbase_device *kbdev )
+{
+ unsigned long flags;
+ spin_lock_irqsave(&kbdev->pm.power_change_lock, flags);
+
+ OSK_ASSERT( kbdev->l2_users_count > 0 );
+
+ --kbdev->l2_users_count;
+
+ if ( !kbdev->l2_users_count )
+ {
+ kbase_pm_send_event(kbdev, KBASE_PM_EVENT_CHANGE_GPU_STATE);
+ }
+ spin_unlock_irqrestore(&kbdev->pm.power_change_lock, flags);
+}
+KBASE_EXPORT_TEST_API(kbase_pm_release_l2_caches)
+
+
+void kbase_pm_release_cores(kbase_device *kbdev, u64 shader_cores, u64 tiler_cores)
+{
+ unsigned long flags;
+ mali_bool change_gpu_state = MALI_FALSE;
+
+ OSK_ASSERT( kbdev != NULL );
+
+ spin_lock_irqsave(&kbdev->pm.power_change_lock, flags);
+
+ while (shader_cores)
+ {
+ int bitnum = 63 - osk_clz_64(shader_cores);
+ u64 bit = 1ULL << bitnum;
+ int cnt;
+
+ OSK_ASSERT(kbdev->shader_inuse_cnt[bitnum] > 0);
+
+ cnt = --kbdev->shader_inuse_cnt[bitnum];
+
+ if (0 == cnt)
+ {
+ kbdev->shader_inuse_bitmap &= ~bit;
+ change_gpu_state = MALI_TRUE;
+ }
+
+ shader_cores &= ~bit;
+ }
+
+ if ( change_gpu_state )
+ {
+ KBASE_TRACE_ADD( kbdev, PM_RELEASE_CHANGE_SHADER_INUSE, NULL, NULL, 0u, (u32)kbdev->shader_inuse_bitmap );
+ }
+
+ while (tiler_cores)
+ {
+ int bitnum = 63 - osk_clz_64(tiler_cores);
+ u64 bit = 1ULL << bitnum;
+ int cnt;
+
+ OSK_ASSERT(kbdev->tiler_inuse_cnt[bitnum] > 0);
+
+ cnt = --kbdev->tiler_inuse_cnt[bitnum];
+
+ if (0 == cnt)
+ {
+ kbdev->tiler_inuse_bitmap &= ~bit;
+ change_gpu_state = MALI_TRUE;
+ }
+
+ tiler_cores &= ~bit;
+ }
+
+ if (change_gpu_state)
+ {
+ kbase_pm_send_event(kbdev, KBASE_PM_EVENT_CHANGE_GPU_STATE);
+ }
+
+ spin_unlock_irqrestore(&kbdev->pm.power_change_lock, flags);
+}
+KBASE_EXPORT_TEST_API(kbase_pm_release_cores)
+
+void MOCKABLE(kbase_pm_check_transitions)(kbase_device *kbdev)
+{
+ unsigned long flags;
+ mali_bool in_desired_state = MALI_TRUE;
+ u64 desired_l2_state;
+ u64 desired_l3_state;
+ u64 cores_powered;
+ u64 tiler_available_bitmap;
+ u64 shader_available_bitmap;
+
+ OSK_ASSERT( NULL != kbdev );
+
+ spin_lock_irqsave(&kbdev->pm.power_change_lock, flags);
+
+ /* If any cores are already powered then, we must keep the caches on */
+ cores_powered = kbase_pm_get_ready_cores(kbdev, KBASE_PM_CORE_TILER);
+ cores_powered |= kbase_pm_get_ready_cores(kbdev, KBASE_PM_CORE_SHADER);
+
+ cores_powered |= (kbdev->pm.desired_shader_state | kbdev->pm.desired_tiler_state);
+
+ /* If there are l2 cache users registered, keep all l2s powered even if all other cores are off.*/
+ if ( kbdev->l2_users_count > 0 )
+ {
+ cores_powered |= kbdev->l2_present_bitmap;
+ }
+
+ desired_l2_state = get_desired_cache_status(kbdev->l2_present_bitmap, cores_powered);
+ desired_l3_state = get_desired_cache_status(kbdev->l3_present_bitmap, desired_l2_state);
+
+ in_desired_state &= kbase_pm_transition_core_type(kbdev, KBASE_PM_CORE_L3, desired_l3_state, 0, NULL, &kbdev->pm.powering_on_l3_state);
+ in_desired_state &= kbase_pm_transition_core_type(kbdev, KBASE_PM_CORE_L2, desired_l2_state, 0, NULL, &kbdev->pm.powering_on_l2_state);
+
+ if (in_desired_state)
+ {
+ in_desired_state &= kbase_pm_transition_core_type(kbdev, KBASE_PM_CORE_TILER,
+ kbdev->pm.desired_tiler_state, kbdev->tiler_inuse_bitmap,
+ &tiler_available_bitmap,
+ &kbdev->pm.powering_on_tiler_state);
+ in_desired_state &= kbase_pm_transition_core_type(kbdev, KBASE_PM_CORE_SHADER,
+ kbdev->pm.desired_shader_state, kbdev->shader_inuse_bitmap,
+ &shader_available_bitmap,
+ &kbdev->pm.powering_on_shader_state);
+
+ if ( kbdev->shader_available_bitmap != shader_available_bitmap )
+ {
+ KBASE_TRACE_ADD( kbdev, PM_CORES_CHANGE_AVAILABLE, NULL, NULL, 0u, (u32)shader_available_bitmap );
+ }
+ kbdev->shader_available_bitmap = shader_available_bitmap;
+ kbdev->tiler_available_bitmap = tiler_available_bitmap;
+ }
+
+ atomic_set(&kbdev->pm.gpu_in_desired_state, in_desired_state);
+
+ if (in_desired_state)
+ {
+#ifdef CONFIG_MALI_GATOR_SUPPORT
+ kbase_trace_mali_pm_status(KBASE_PM_CORE_L3, kbase_pm_get_ready_cores(kbdev, KBASE_PM_CORE_L3));
+ kbase_trace_mali_pm_status(KBASE_PM_CORE_L2, kbase_pm_get_ready_cores(kbdev, KBASE_PM_CORE_L2));
+ kbase_trace_mali_pm_status(KBASE_PM_CORE_SHADER, kbase_pm_get_ready_cores(kbdev, KBASE_PM_CORE_SHADER));
+ kbase_trace_mali_pm_status(KBASE_PM_CORE_TILER, kbase_pm_get_ready_cores(kbdev, KBASE_PM_CORE_TILER));
+#endif /* CONFIG_MALI_GATOR_SUPPORT */
+ kbase_pm_send_event(kbdev, KBASE_PM_EVENT_GPU_STATE_CHANGED);
+ }
+
+ spin_unlock_irqrestore(&kbdev->pm.power_change_lock, flags);
+}
+KBASE_EXPORT_TEST_API(kbase_pm_check_transitions)
+
+void MOCKABLE(kbase_pm_enable_interrupts)(kbase_device *kbdev)
+{
+
+ OSK_ASSERT( NULL != kbdev );
+ /*
+ * Clear all interrupts,
+ * and unmask them all.
+ */
+ kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_IRQ_CLEAR), GPU_IRQ_REG_ALL, NULL);
+ kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_IRQ_MASK), GPU_IRQ_REG_ALL, NULL);
+
+ kbase_reg_write(kbdev, JOB_CONTROL_REG(JOB_IRQ_CLEAR), 0xFFFFFFFF, NULL);
+ kbase_reg_write(kbdev, JOB_CONTROL_REG(JOB_IRQ_MASK), 0xFFFFFFFF, NULL);
+
+ kbase_reg_write(kbdev, MMU_REG(MMU_IRQ_CLEAR), 0xFFFFFFFF, NULL);
+ kbase_reg_write(kbdev, MMU_REG(MMU_IRQ_MASK), 0xFFFFFFFF, NULL);
+}
+KBASE_EXPORT_TEST_API(kbase_pm_enable_interrupts)
+
+void MOCKABLE(kbase_pm_disable_interrupts)(kbase_device *kbdev)
+{
+
+ OSK_ASSERT( NULL != kbdev );
+ /*
+ * Mask all interrupts,
+ * and clear them all.
+ */
+ kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_IRQ_MASK), 0, NULL);
+ kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_IRQ_CLEAR), GPU_IRQ_REG_ALL, NULL);
+
+ kbase_reg_write(kbdev, JOB_CONTROL_REG(JOB_IRQ_MASK), 0, NULL);
+ kbase_reg_write(kbdev, JOB_CONTROL_REG(JOB_IRQ_CLEAR), 0xFFFFFFFF, NULL);
+
+ kbase_reg_write(kbdev, MMU_REG(MMU_IRQ_MASK), 0, NULL);
+ kbase_reg_write(kbdev, MMU_REG(MMU_IRQ_CLEAR), 0xFFFFFFFF, NULL);
+}
+KBASE_EXPORT_TEST_API(kbase_pm_disable_interrupts)
+
+/*
+ * pmu layout:
+ * 0x0000: PMU TAG (RO) (0xCAFECAFE)
+ * 0x0004: PMU VERSION ID (RO) (0x00000000)
+ * 0x0008: CLOCK ENABLE (RW) (31:1 SBZ, 0 CLOCK STATE)
+ */
+void kbase_pm_clock_on(kbase_device *kbdev)
+{
+ unsigned long flags;
+ OSK_ASSERT( NULL != kbdev );
+
+ if (kbdev->pm.gpu_powered)
+ {
+ /* Already turned on */
+ return;
+ }
+
+ KBASE_TRACE_ADD( kbdev, PM_GPU_ON, NULL, NULL, 0u, 0u );
+
+ /* The GPU is going to transition, so unset the wait queues until the policy
+ * informs us that the transition is complete */
+ kbdev->pm.power_state = PM_POWER_STATE_TRANS;
+ wake_up(&kbdev->pm.power_state_wait);
+
+ if (kbdev->pm.callback_power_on && kbdev->pm.callback_power_on(kbdev))
+ {
+ /* GPU state was lost, reset GPU to ensure it is in a consistent state */
+ kbase_pm_init_hw(kbdev);
+ }
+
+ spin_lock_irqsave(&kbdev->pm.gpu_powered_lock, flags);
+ kbdev->pm.gpu_powered = MALI_TRUE;
+ spin_unlock_irqrestore(&kbdev->pm.gpu_powered_lock, flags);
+
+ /* Lastly, enable the interrupts */
+ kbase_pm_enable_interrupts(kbdev);
+}
+KBASE_EXPORT_TEST_API(kbase_pm_clock_on)
+
+void kbase_pm_clock_off(kbase_device *kbdev)
+{
+ unsigned long flags;
+ OSK_ASSERT( NULL != kbdev );
+
+ if (!kbdev->pm.gpu_powered)
+ {
+ /* Already turned off */
+ return;
+ }
+
+ KBASE_TRACE_ADD( kbdev, PM_GPU_OFF, NULL, NULL, 0u, 0u );
+
+ /* Disable interrupts. This also clears any outstanding interrupts */
+ kbase_pm_disable_interrupts(kbdev);
+ /* Ensure that any IRQ handlers have finished */
+ kbase_synchronize_irqs(kbdev);
+
+ /* The GPU power may be turned off from this point */
+ spin_lock_irqsave(&kbdev->pm.gpu_powered_lock, flags);
+ kbdev->pm.gpu_powered = MALI_FALSE;
+ spin_unlock_irqrestore(&kbdev->pm.gpu_powered_lock, flags);
+
+ if (kbdev->pm.callback_power_off)
+ {
+ kbdev->pm.callback_power_off(kbdev);
+ }
+}
+KBASE_EXPORT_TEST_API(kbase_pm_clock_off)
+
+struct kbasep_reset_timeout_data
+{
+ struct hrtimer timer;
+ mali_bool timed_out;
+ kbase_device *kbdev;
+};
+
+static enum hrtimer_restart kbasep_reset_timeout(struct hrtimer * timer)
+{
+ struct kbasep_reset_timeout_data *rtdata = container_of( timer, struct kbasep_reset_timeout_data, timer );
+
+ rtdata->timed_out = 1;
+
+ /* Set the wait queue to wake up kbase_pm_init_hw even though the reset hasn't completed */
+ kbase_pm_reset_done(rtdata->kbdev);
+
+ return HRTIMER_NORESTART;
+}
+
+static void kbase_pm_hw_issues(kbase_device *kbdev)
+{
+ u32 value = 0;
+
+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8443))
+ {
+ /* Needed due to MIDBASE-1494: LS_PAUSEBUFFER_DISABLE. See PRLAM-8443. */
+ value |= (1 << 16);
+ }
+
+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_10327))
+ {
+ /* Needed due to MIDBASE-2054: SDC_DISABLE_OQ_DISCARD. See PRLAM-10327. */
+ value |= (1 << 6);
+ }
+
+ if (value != 0)
+ {
+ kbase_reg_write(kbdev, GPU_CONTROL_REG(SHADER_CONFIG), value, NULL);
+ }
+}
+
+mali_error kbase_pm_init_hw(kbase_device *kbdev)
+{
+ unsigned long flags;
+ struct kbasep_reset_timeout_data rtdata;
+
+ OSK_ASSERT( NULL != kbdev );
+
+ /* Ensure the clock is on before attempting to access the hardware */
+ if (!kbdev->pm.gpu_powered)
+ {
+ /* The GPU is going to transition, so set the state to transitioning until the policy
+ * informs us that the transition is complete */
+ kbdev->pm.power_state = PM_POWER_STATE_TRANS;
+ wake_up(&kbdev->pm.power_state_wait);
+
+ if (kbdev->pm.callback_power_on)
+ kbdev->pm.callback_power_on(kbdev);
+
+ spin_lock_irqsave(&kbdev->pm.gpu_powered_lock, flags);
+ kbdev->pm.gpu_powered = MALI_TRUE;
+ spin_unlock_irqrestore(&kbdev->pm.gpu_powered_lock, flags);
+ }
+
+ /* Ensure interrupts are off to begin with, this also clears any outstanding interrupts */
+ kbase_pm_disable_interrupts(kbdev);
+
+ /* Soft reset the GPU */
+ KBASE_TRACE_ADD( kbdev, CORE_GPU_SOFT_RESET, NULL, NULL, 0u, 0 );
+ kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_COMMAND), GPU_COMMAND_SOFT_RESET, NULL);
+
+ /* Unmask the reset complete interrupt only */
+ kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_IRQ_MASK), RESET_COMPLETED, NULL);
+
+ /* Initialize a structure for tracking the status of the reset */
+ rtdata.kbdev = kbdev;
+ rtdata.timed_out = 0;
+
+ /* Create a timer to use as a timeout on the reset */
+ hrtimer_init_on_stack(&rtdata.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL );
+ rtdata.timer.function = kbasep_reset_timeout;
+
+ hrtimer_start(&rtdata.timer, HR_TIMER_DELAY_MSEC(RESET_TIMEOUT), HRTIMER_MODE_REL );
+
+ /* Wait for the RESET_COMPLETED interrupt to be raised,
+ * we use the PM_STATE_ON since it isn't in use yet */
+ wait_event(kbdev->pm.power_state_wait, kbdev->pm.power_state == PM_POWER_STATE_ON);
+
+ if (rtdata.timed_out == 0)
+ {
+ /* GPU has been reset */
+ hrtimer_cancel(&rtdata.timer);
+ destroy_hrtimer_on_stack(&rtdata.timer);
+ goto out;
+ }
+
+ /* No interrupt has been received - check if the RAWSTAT register says the reset has completed */
+ if (kbase_reg_read(kbdev, GPU_CONTROL_REG(GPU_IRQ_RAWSTAT), NULL) & RESET_COMPLETED)
+ {
+ /* The interrupt is set in the RAWSTAT; this suggests that the interrupts are not getting to the CPU */
+ OSK_PRINT_WARN(OSK_BASE_PM, "Reset interrupt didn't reach CPU. Check interrupt assignments.\n");
+ /* If interrupts aren't working we can't continue. */
+ destroy_hrtimer_on_stack(&rtdata.timer);
+ goto out;
+ }
+
+ /* The GPU doesn't seem to be responding to the reset so try a hard reset */
+ OSK_PRINT_WARN(OSK_BASE_PM, "Failed to soft reset GPU, attempting a hard reset\n");
+ KBASE_TRACE_ADD( kbdev, CORE_GPU_HARD_RESET, NULL, NULL, 0u, 0 );
+ kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_COMMAND), GPU_COMMAND_HARD_RESET, NULL);
+
+ /* Restart the timer to wait for the hard reset to complete */
+ rtdata.timed_out = 0;
+
+ hrtimer_start(&rtdata.timer,
+ HR_TIMER_DELAY_MSEC(RESET_TIMEOUT),
+ HRTIMER_MODE_REL );
+
+ /* Wait for the RESET_COMPLETED interrupt to be raised,
+ * we use the PM_STATE_ON since it isn't in use yet */
+ wait_event(kbdev->pm.power_state_wait, kbdev->pm.power_state == PM_POWER_STATE_ON);
+
+ if (rtdata.timed_out == 0)
+ {
+ /* GPU has been reset */
+ hrtimer_cancel(&rtdata.timer);
+ destroy_hrtimer_on_stack(&rtdata.timer);
+ goto out;
+ }
+
+ destroy_hrtimer_on_stack(&rtdata.timer);
+
+ OSK_PRINT_ERROR(OSK_BASE_PM, "Failed to reset the GPU\n");
+
+ /* The GPU still hasn't reset, give up */
+ return MALI_ERROR_FUNCTION_FAILED;
+
+out:
+ /* Re-enable interrupts */
+ kbase_pm_enable_interrupts(kbdev);
+
+ /* If cycle counter was in use-re enable it */
+ spin_lock_irqsave( &kbdev->pm.gpu_cycle_counter_requests_lock, flags);
+
+ if ( kbdev->pm.gpu_cycle_counter_requests )
+ {
+ kbase_reg_write( kbdev, GPU_CONTROL_REG(GPU_COMMAND), GPU_COMMAND_CYCLE_COUNT_START, NULL );
+ }
+
+ spin_unlock_irqrestore( &kbdev->pm.gpu_cycle_counter_requests_lock, flags);
+
+ kbase_pm_hw_issues(kbdev);
+
+ return MALI_ERROR_NONE;
+}
+KBASE_EXPORT_TEST_API(kbase_pm_init_hw)
+
+void kbase_pm_request_gpu_cycle_counter( kbase_device *kbdev )
+{
+ unsigned long flags;
+ OSK_ASSERT( kbdev != NULL );
+
+ OSK_ASSERT( kbdev->pm.gpu_powered );
+
+ spin_lock_irqsave( &kbdev->pm.gpu_cycle_counter_requests_lock, flags);
+
+ OSK_ASSERT( kbdev->pm.gpu_cycle_counter_requests < INT_MAX );
+
+ ++kbdev->pm.gpu_cycle_counter_requests;
+
+ if ( 1 == kbdev->pm.gpu_cycle_counter_requests )
+ {
+ kbase_reg_write( kbdev, GPU_CONTROL_REG(GPU_COMMAND), GPU_COMMAND_CYCLE_COUNT_START, NULL );
+ }
+ spin_unlock_irqrestore( &kbdev->pm.gpu_cycle_counter_requests_lock, flags);
+}
+KBASE_EXPORT_TEST_API(kbase_pm_request_gpu_cycle_counter)
+
+void kbase_pm_release_gpu_cycle_counter( kbase_device *kbdev )
+{
+ unsigned long flags;
+ OSK_ASSERT( kbdev != NULL );
+
+ spin_lock_irqsave( &kbdev->pm.gpu_cycle_counter_requests_lock, flags);
+
+ OSK_ASSERT( kbdev->pm.gpu_cycle_counter_requests > 0 );
+
+ --kbdev->pm.gpu_cycle_counter_requests;
+
+ if ( 0 == kbdev->pm.gpu_cycle_counter_requests )
+ {
+ kbase_reg_write( kbdev, GPU_CONTROL_REG(GPU_COMMAND), GPU_COMMAND_CYCLE_COUNT_STOP, NULL );
+ }
+ spin_unlock_irqrestore( &kbdev->pm.gpu_cycle_counter_requests_lock, flags);
+}
+KBASE_EXPORT_TEST_API(kbase_pm_release_gpu_cycle_counter)
+
diff --git a/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_pm_metrics.c b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_pm_metrics.c
new file mode 100644
index 0000000..1586ef5
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_pm_metrics.c
@@ -0,0 +1,245 @@
+/*
+ *
+ * (C) COPYRIGHT 2011-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/**
+ * @file mali_kbase_pm_metrics.c
+ * Metrics for power management
+ */
+
+#include <osk/mali_osk.h>
+
+#include <kbase/src/common/mali_kbase.h>
+#include <kbase/src/common/mali_kbase_pm.h>
+#ifdef CONFIG_MALI_T6XX_DVFS
+#include <kbase/src/platform/mali_kbase_dvfs.h>
+#endif
+
+/* When VSync is being hit aim for utilisation between 70-90% */
+#define KBASE_PM_VSYNC_MIN_UTILISATION 70
+#define KBASE_PM_VSYNC_MAX_UTILISATION 90
+/* Otherwise aim for 10-40% */
+#define KBASE_PM_NO_VSYNC_MIN_UTILISATION 10
+#define KBASE_PM_NO_VSYNC_MAX_UTILISATION 40
+
+#ifndef CONFIG_MALI_T6XX_DVFS
+/* Frequency that DVFS clock frequency decisions should be made */
+#define KBASE_PM_DVFS_FREQUENCY 500
+#endif
+
+/* Shift used for kbasep_pm_metrics_data.time_busy/idle - units of (1 << 8) ns
+ This gives a maximum period between samples of 2^(32+8)/100 ns = slightly under 11s.
+ Exceeding this will cause overflow */
+#define KBASE_PM_TIME_SHIFT 8
+
+static enum hrtimer_restart dvfs_callback(struct hrtimer *timer)
+{
+ unsigned long flags;
+ kbase_pm_dvfs_action action;
+ kbasep_pm_metrics_data * metrics;
+
+ OSK_ASSERT(timer != NULL);
+
+ metrics = container_of(timer, kbasep_pm_metrics_data, timer );
+ action = kbase_pm_get_dvfs_action(metrics->kbdev);
+ spin_lock_irqsave(&metrics->lock, flags);
+ if (metrics->timer_active)
+ {
+ hrtimer_start(timer,
+ HR_TIMER_DELAY_MSEC(KBASE_PM_DVFS_FREQUENCY),
+ HRTIMER_MODE_REL);
+ }
+ spin_unlock_irqrestore(&metrics->lock, flags);
+
+ return HRTIMER_NORESTART;
+}
+
+mali_error kbasep_pm_metrics_init(kbase_device *kbdev)
+{
+ OSK_ASSERT(kbdev != NULL);
+
+ kbdev->pm.metrics.kbdev = kbdev;
+ kbdev->pm.metrics.vsync_hit = 0;
+ kbdev->pm.metrics.utilisation = 0;
+
+ kbdev->pm.metrics.time_period_start = ktime_get();
+ kbdev->pm.metrics.time_busy = 0;
+ kbdev->pm.metrics.time_idle = 0;
+ kbdev->pm.metrics.gpu_active = MALI_TRUE;
+ kbdev->pm.metrics.timer_active = MALI_TRUE;
+
+ spin_lock_init(&kbdev->pm.metrics.lock);
+
+ hrtimer_init(&kbdev->pm.metrics.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ kbdev->pm.metrics.timer.function = dvfs_callback;
+
+ hrtimer_start(&kbdev->pm.metrics.timer,
+ HR_TIMER_DELAY_MSEC(KBASE_PM_DVFS_FREQUENCY),
+ HRTIMER_MODE_REL);
+
+ kbase_pm_register_vsync_callback(kbdev);
+
+ return MALI_ERROR_NONE;
+}
+KBASE_EXPORT_TEST_API(kbasep_pm_metrics_init)
+
+void kbasep_pm_metrics_term(kbase_device *kbdev)
+{
+ unsigned long flags;
+ OSK_ASSERT(kbdev != NULL);
+
+ spin_lock_irqsave(&kbdev->pm.metrics.lock, flags);
+ kbdev->pm.metrics.timer_active = MALI_FALSE;
+ spin_unlock_irqrestore(&kbdev->pm.metrics.lock, flags);
+
+ hrtimer_cancel(&kbdev->pm.metrics.timer);
+
+ kbase_pm_unregister_vsync_callback(kbdev);
+}
+KBASE_EXPORT_TEST_API(kbasep_pm_metrics_term)
+
+void kbasep_pm_record_gpu_idle(kbase_device *kbdev)
+{
+ unsigned long flags;
+ ktime_t now = ktime_get();
+ ktime_t diff;
+
+ OSK_ASSERT(kbdev != NULL);
+
+ spin_lock_irqsave(&kbdev->pm.metrics.lock, flags);
+
+ OSK_ASSERT(kbdev->pm.metrics.gpu_active == MALI_TRUE);
+
+ kbdev->pm.metrics.gpu_active = MALI_FALSE;
+
+ diff = ktime_sub( now, kbdev->pm.metrics.time_period_start );
+
+ kbdev->pm.metrics.time_busy += (u32)(ktime_to_ns( diff ) >> KBASE_PM_TIME_SHIFT);
+ kbdev->pm.metrics.time_period_start = now;
+
+ spin_unlock_irqrestore(&kbdev->pm.metrics.lock, flags);
+}
+KBASE_EXPORT_TEST_API(kbasep_pm_record_gpu_idle)
+
+void kbasep_pm_record_gpu_active(kbase_device *kbdev)
+{
+ unsigned long flags;
+ ktime_t now = ktime_get();
+ ktime_t diff;
+
+ OSK_ASSERT(kbdev != NULL);
+
+ spin_lock_irqsave(&kbdev->pm.metrics.lock, flags);
+
+ OSK_ASSERT(kbdev->pm.metrics.gpu_active == MALI_FALSE);
+
+ kbdev->pm.metrics.gpu_active = MALI_TRUE;
+
+ diff = ktime_sub( now, kbdev->pm.metrics.time_period_start );
+
+ kbdev->pm.metrics.time_idle += (u32)(ktime_to_ns( diff ) >> KBASE_PM_TIME_SHIFT);
+ kbdev->pm.metrics.time_period_start = now;
+
+ spin_unlock_irqrestore(&kbdev->pm.metrics.lock, flags);
+}
+KBASE_EXPORT_TEST_API(kbasep_pm_record_gpu_active)
+
+void kbase_pm_report_vsync(kbase_device *kbdev, int buffer_updated)
+{
+ unsigned long flags;
+ OSK_ASSERT(kbdev != NULL);
+
+ spin_lock_irqsave(&kbdev->pm.metrics.lock, flags);
+ kbdev->pm.metrics.vsync_hit = buffer_updated;
+ spin_unlock_irqrestore(&kbdev->pm.metrics.lock, flags);
+}
+KBASE_EXPORT_TEST_API(kbase_pm_report_vsync)
+
+kbase_pm_dvfs_action kbase_pm_get_dvfs_action(kbase_device *kbdev)
+{
+ unsigned long flags;
+ int utilisation = 0;
+ kbase_pm_dvfs_action action;
+ ktime_t now = ktime_get();
+ ktime_t diff;
+
+ OSK_ASSERT(kbdev != NULL);
+
+ spin_lock_irqsave(&kbdev->pm.metrics.lock, flags);
+
+
+ diff = ktime_sub( now, kbdev->pm.metrics.time_period_start );
+
+ if (kbdev->pm.metrics.gpu_active)
+ {
+ kbdev->pm.metrics.time_busy += (u32)(ktime_to_ns( diff ) >> KBASE_PM_TIME_SHIFT);
+ kbdev->pm.metrics.time_period_start = now;
+ }
+ else
+ {
+ kbdev->pm.metrics.time_idle += (u32)(ktime_to_ns( diff ) >> KBASE_PM_TIME_SHIFT);
+ kbdev->pm.metrics.time_period_start = now;
+ }
+
+ if (kbdev->pm.metrics.time_idle + kbdev->pm.metrics.time_busy == 0)
+ {
+ /* No data - so we return NOP */
+ action = KBASE_PM_DVFS_NOP;
+ goto out;
+ }
+
+ utilisation = (100*kbdev->pm.metrics.time_busy) / (kbdev->pm.metrics.time_idle + kbdev->pm.metrics.time_busy);
+
+ if (kbdev->pm.metrics.vsync_hit)
+ {
+ /* VSync is being met */
+ if (utilisation < KBASE_PM_VSYNC_MIN_UTILISATION)
+ {
+ action = KBASE_PM_DVFS_CLOCK_DOWN;
+ }
+ else if (utilisation > KBASE_PM_VSYNC_MAX_UTILISATION)
+ {
+ action = KBASE_PM_DVFS_CLOCK_UP;
+ }
+ else
+ {
+ action = KBASE_PM_DVFS_NOP;
+ }
+ }
+ else
+ {
+ /* VSync is being missed */
+ if (utilisation < KBASE_PM_NO_VSYNC_MIN_UTILISATION)
+ {
+ action = KBASE_PM_DVFS_CLOCK_DOWN;
+ }
+ else if (utilisation > KBASE_PM_NO_VSYNC_MAX_UTILISATION)
+ {
+ action = KBASE_PM_DVFS_CLOCK_UP;
+ }
+ else
+ {
+ action = KBASE_PM_DVFS_NOP;
+ }
+ }
+
+ kbdev->pm.metrics.utilisation = utilisation;
+out:
+#ifdef CONFIG_MALI_T6XX_DVFS
+ kbase_platform_dvfs_event(kbdev, utilisation);
+#endif /*CONFIG_MALI_T6XX_DVFS*/
+ kbdev->pm.metrics.time_idle = 0;
+ kbdev->pm.metrics.time_busy = 0;
+ spin_unlock_irqrestore(&kbdev->pm.metrics.lock, flags);
+
+ return action;
+}
+KBASE_EXPORT_TEST_API(kbase_pm_get_dvfs_action)
diff --git a/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_pm_metrics_dummy.c b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_pm_metrics_dummy.c
new file mode 100644
index 0000000..5ac782d
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_pm_metrics_dummy.c
@@ -0,0 +1,34 @@
+/*
+ *
+ * (C) COPYRIGHT 2011 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_kbase_pm_metrics_dummy.c
+ * Dummy Metrics for power management.
+ */
+
+#include <kbase/src/common/mali_kbase.h>
+#include <kbase/src/common/mali_kbase_pm.h>
+
+void kbase_pm_register_vsync_callback(kbase_device *kbdev)
+{
+ OSK_ASSERT(kbdev != NULL);
+
+ /* no VSync metrics will be available */
+ kbdev->pm.metrics.platform_data = NULL;
+}
+
+void kbase_pm_unregister_vsync_callback(kbase_device *kbdev)
+{
+ OSK_ASSERT(kbdev != NULL);
+}
diff --git a/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_security.c b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_security.c
new file mode 100644
index 0000000..889ebdd
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_security.c
@@ -0,0 +1,76 @@
+/*
+ *
+ * (C) COPYRIGHT 2011-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_kbase_security.c
+ * Base kernel security capability API
+ */
+
+#include <osk/mali_osk.h>
+#include <kbase/src/common/mali_kbase.h>
+
+/**
+ * kbase_security_has_capability - see mali_kbase_caps.h for description.
+ */
+
+mali_bool kbase_security_has_capability(kbase_context *kctx, kbase_security_capability cap, u32 flags)
+{
+ /* Assume failure */
+ mali_bool access_allowed = MALI_FALSE;
+ mali_bool audit = (KBASE_SEC_FLAG_AUDIT & flags)? MALI_TRUE : MALI_FALSE;
+
+ OSK_ASSERT(NULL != kctx);
+ CSTD_UNUSED(kctx);
+
+ /* Detect unsupported flags */
+ OSK_ASSERT(((~KBASE_SEC_FLAG_MASK) & flags) == 0);
+
+ /* Determine if access is allowed for the given cap */
+ switch(cap)
+ {
+ case KBASE_SEC_MODIFY_PRIORITY:
+#if KBASE_HWCNT_DUMP_BYPASS_ROOT
+ access_allowed = TRUE;
+#else
+ if (osk_is_privileged() == MALI_TRUE)
+ {
+ access_allowed = TRUE;
+ }
+#endif
+ break;
+ case KBASE_SEC_INSTR_HW_COUNTERS_COLLECT:
+ /* Access is granted only if the caller is privileged */
+#if KBASE_HWCNT_DUMP_BYPASS_ROOT
+ access_allowed = TRUE;
+#else
+ if (osk_is_privileged() == MALI_TRUE)
+ {
+ access_allowed = TRUE;
+ }
+#endif
+ break;
+ }
+
+ /* Report problem if requested */
+ if(MALI_FALSE == access_allowed)
+ {
+ if(MALI_FALSE != audit)
+ {
+ OSK_PRINT_WARN(OSK_BASE_CORE, "Security capability failure: %d, %p", cap, (void *)kctx);
+ }
+ }
+
+ return access_allowed;
+}
+KBASE_EXPORT_TEST_API(kbase_security_has_capability)
diff --git a/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_security.h b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_security.h
new file mode 100644
index 0000000..e1d1aa5
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_security.h
@@ -0,0 +1,49 @@
+/*
+ *
+ * (C) COPYRIGHT 2011 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_kbase_security.h
+ * Base kernel security capability APIs
+ */
+
+#ifndef _KBASE_SECURITY_H_
+#define _KBASE_SECURITY_H_
+
+/* Security flags */
+#define KBASE_SEC_FLAG_NOAUDIT (0u << 0) /* Silently handle privilege failure */
+#define KBASE_SEC_FLAG_AUDIT (1u << 0) /* Write audit message on privilege failure */
+#define KBASE_SEC_FLAG_MASK (KBASE_SEC_FLAG_AUDIT) /* Mask of all valid flag bits */
+
+/* List of unique capabilities that have security access privileges */
+typedef enum {
+ /* Instrumentation Counters access privilege */
+ KBASE_SEC_INSTR_HW_COUNTERS_COLLECT = 1,
+ KBASE_SEC_MODIFY_PRIORITY
+ /* Add additional access privileges here */
+} kbase_security_capability;
+
+
+/**
+ * kbase_security_has_capability - determine whether a task has a particular effective capability
+ * @param[in] kctx The task context.
+ * @param[in] cap The capability to check for.
+ * @param[in] flags Additional configuration information
+ * Such as whether to write an audit message or not.
+ * @return MALI_TRUE if success (capability is allowed), MALI_FALSE otherwise.
+ */
+
+mali_bool kbase_security_has_capability(kbase_context *kctx, kbase_security_capability cap, u32 flags);
+
+#endif /* _KBASE_SECURITY_H_ */
+
diff --git a/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_softjobs.c b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_softjobs.c
new file mode 100644
index 0000000..9098747
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_softjobs.c
@@ -0,0 +1,390 @@
+/*
+ *
+ * (C) COPYRIGHT 2011-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+#include <kbase/src/common/mali_kbase.h>
+
+#ifdef CONFIG_SYNC
+#include <linux/sync.h>
+#include <linux/syscalls.h>
+#include "../linux/mali_kbase_sync.h"
+#endif
+
+/**
+ * @file mali_kbase_softjobs.c
+ *
+ * This file implements the logic behind software only jobs that are
+ * executed within the driver rather than being handed over to the GPU.
+ */
+
+static base_jd_event_code kbase_dump_cpu_gpu_time(kbase_jd_atom *katom)
+{
+ kbase_va_region *reg;
+ osk_phy_addr addr;
+ u64 pfn;
+ u32 offset;
+ char *page;
+ struct timespec ts;
+ base_dump_cpu_gpu_counters data;
+ u64 system_time;
+ u64 cycle_counter;
+ mali_addr64 jc = katom->jc;
+ kbase_context *kctx = katom->kctx;
+
+ u32 hi1, hi2;
+
+ memset(&data, 0, sizeof(data));
+
+ kbase_pm_context_active(kctx->kbdev);
+
+ /* Read hi, lo, hi to ensure that overflow from lo to hi is handled correctly */
+ do {
+ hi1 = kbase_reg_read(kctx->kbdev, GPU_CONTROL_REG(CYCLE_COUNT_HI), NULL);
+ cycle_counter = kbase_reg_read(kctx->kbdev, GPU_CONTROL_REG(CYCLE_COUNT_LO), NULL);
+ hi2 = kbase_reg_read(kctx->kbdev, GPU_CONTROL_REG(CYCLE_COUNT_HI), NULL);
+ cycle_counter |= (((u64)hi1) << 32);
+ } while (hi1 != hi2);
+
+ /* Read hi, lo, hi to ensure that overflow from lo to hi is handled correctly */
+ do {
+ hi1 = kbase_reg_read(kctx->kbdev, GPU_CONTROL_REG(TIMESTAMP_HI), NULL);
+ system_time = kbase_reg_read(kctx->kbdev, GPU_CONTROL_REG(TIMESTAMP_LO), NULL);
+ hi2 = kbase_reg_read(kctx->kbdev, GPU_CONTROL_REG(TIMESTAMP_HI), NULL);
+ system_time |= (((u64)hi1) << 32);
+ } while (hi1 != hi2);
+
+ /* Record the CPU's idea of current time */
+ getnstimeofday(&ts);
+
+ kbase_pm_context_idle(kctx->kbdev);
+
+ data.sec = ts.tv_sec;
+ data.usec = ts.tv_nsec / 1000;
+ data.system_time = system_time;
+ data.cycle_counter = cycle_counter;
+
+ pfn = jc >> 12;
+ offset = jc & 0xFFF;
+
+ if (offset > 0x1000-sizeof(data))
+ {
+ /* Wouldn't fit in the page */
+ return BASE_JD_EVENT_JOB_CANCELLED;
+ }
+
+ reg = kbase_region_tracker_find_region_enclosing_address(kctx, jc);
+ if (!reg)
+ {
+ return BASE_JD_EVENT_JOB_CANCELLED;
+ }
+
+ if (! (reg->flags & KBASE_REG_GPU_WR) )
+ {
+ /* Region is not writable by GPU so we won't write to it either */
+ return BASE_JD_EVENT_JOB_CANCELLED;
+ }
+
+ if (!reg->phy_pages)
+ {
+ return BASE_JD_EVENT_JOB_CANCELLED;
+ }
+
+ addr = reg->phy_pages[pfn - reg->start_pfn];
+ if (!addr)
+ {
+ return BASE_JD_EVENT_JOB_CANCELLED;
+ }
+
+ page = osk_kmap(addr);
+ if (!page)
+ {
+ return BASE_JD_EVENT_JOB_CANCELLED;
+ }
+ memcpy(page+offset, &data, sizeof(data));
+ osk_sync_to_cpu(addr+offset, page+offset, sizeof(data));
+ osk_kunmap(addr, page);
+
+ return BASE_JD_EVENT_DONE;
+}
+
+#ifdef CONFIG_SYNC
+
+/* Complete an atom that has returned '1' from kbase_process_soft_job (i.e. has waited)
+ *
+ * @param katom The atom to complete
+ */
+static void complete_soft_job(kbase_jd_atom *katom)
+{
+ int err;
+ kbase_context *kctx = katom->kctx;
+
+ kbasep_list_trace_add(15, kctx->kbdev, katom, &kctx->waiting_soft_jobs, KBASE_TRACE_LIST_DEL, KBASE_TRACE_LIST_WAITING_SOFT_JOBS);
+ mutex_lock(&kctx->jctx.lock);
+ OSK_DLIST_REMOVE(&kctx->waiting_soft_jobs, katom, dep_item[0], err);
+ if (err) {
+ kbasep_list_trace_dump(kctx->kbdev);
+ BUG();
+ }
+ kbase_finish_soft_job(katom);
+ if (jd_done_nolock(katom))
+ {
+ kbasep_js_try_schedule_head_ctx( kctx->kbdev );
+ }
+ mutex_unlock(&kctx->jctx.lock);
+}
+
+
+static base_jd_event_code kbase_fence_trigger(kbase_jd_atom *katom, int result)
+{
+ struct sync_pt *pt;
+ struct sync_timeline *timeline;
+
+ if (!list_is_singular(&katom->fence->pt_list_head))
+ {
+ /* Not exactly one item in the list - so it didn't (directly) come from us */
+ return BASE_JD_EVENT_JOB_CANCELLED;
+ }
+
+ pt = list_first_entry(&katom->fence->pt_list_head, struct sync_pt, pt_list);
+ timeline = pt->parent;
+
+ if (!kbase_sync_timeline_is_ours(timeline))
+ {
+ /* Fence has a sync_pt which isn't ours! */
+ return BASE_JD_EVENT_JOB_CANCELLED;
+ }
+
+ kbase_sync_signal_pt(pt, result);
+
+ sync_timeline_signal(timeline);
+
+ return (result < 0) ? BASE_JD_EVENT_JOB_CANCELLED : BASE_JD_EVENT_DONE;
+}
+
+static void kbase_fence_wait_worker(struct work_struct *data)
+{
+ kbase_jd_atom *katom;
+ kbase_context *kctx;
+
+ katom = container_of(data, kbase_jd_atom, work);
+ kctx = katom->kctx;
+
+ complete_soft_job(katom);
+}
+
+static void kbase_fence_wait_callback(struct sync_fence *fence, struct sync_fence_waiter *waiter)
+{
+ kbase_jd_atom *katom = container_of(waiter, kbase_jd_atom, sync_waiter);
+ kbase_context *kctx;
+
+ OSK_ASSERT(NULL != katom);
+
+ kctx = katom->kctx;
+
+ OSK_ASSERT(NULL != kctx);
+
+ /* Propagate the fence status to the atom.
+ * If negative then cancel this atom and its dependencies.
+ */
+ if (fence->status < 0)
+ {
+ katom->event_code = BASE_JD_EVENT_JOB_CANCELLED;
+ }
+
+ /* To prevent a potential deadlock we schedule the work onto the job_done_wq workqueue
+ *
+ * The issue is that we may signal the timeline while holding kctx->jctx.lock and
+ * the callbacks are run synchronously from sync_timeline_signal. So we simply defer the work.
+ */
+
+ OSK_ASSERT(0 == object_is_on_stack(&katom->work));
+ INIT_WORK(&katom->work, kbase_fence_wait_worker);
+ queue_work(kctx->jctx.job_done_wq, &katom->work);
+}
+
+static int kbase_fence_wait(kbase_jd_atom *katom)
+{
+ int ret;
+
+ OSK_ASSERT(NULL != katom);
+ OSK_ASSERT(NULL != katom->kctx);
+
+ sync_fence_waiter_init(&katom->sync_waiter, kbase_fence_wait_callback);
+
+ ret = sync_fence_wait_async(katom->fence, &katom->sync_waiter);
+
+ if (ret == 1)
+ {
+ /* Already signalled */
+ return 0;
+ }
+ else if (ret < 0)
+ {
+ goto cancel_atom;
+ }
+ return 1;
+
+cancel_atom:
+ katom->event_code = BASE_JD_EVENT_JOB_CANCELLED;
+ /* We should cause the dependant jobs in the bag to be failed,
+ * to do this we schedule the work queue to complete this job */
+ OSK_ASSERT(0 == object_is_on_stack(&katom->work));
+ INIT_WORK(&katom->work, kbase_fence_wait_worker);
+ queue_work(katom->kctx->jctx.job_done_wq, &katom->work);
+ return 1;
+}
+
+static void kbase_fence_cancel_wait(kbase_jd_atom *katom)
+{
+ if (sync_fence_cancel_async(katom->fence, &katom->sync_waiter) != 0)
+ {
+ /* The wait wasn't cancelled - leave the cleanup for kbase_fence_wait_callback */
+ return;
+ }
+
+ /* Wait was cancelled - zap the atoms */
+ katom->event_code = BASE_JD_EVENT_JOB_CANCELLED;
+
+ kbase_finish_soft_job(katom);
+
+ if (jd_done_nolock(katom))
+ {
+ kbasep_js_try_schedule_head_ctx( katom->kctx->kbdev );
+ }
+}
+
+#endif
+
+int kbase_process_soft_job(kbase_jd_atom *katom )
+{
+ switch(katom->core_req)
+ {
+ case BASE_JD_REQ_SOFT_DUMP_CPU_GPU_TIME:
+ katom->event_code = kbase_dump_cpu_gpu_time(katom);
+ break;
+#ifdef CONFIG_SYNC
+ case BASE_JD_REQ_SOFT_FENCE_TRIGGER:
+ OSK_ASSERT(katom->fence != NULL);
+ katom->event_code = kbase_fence_trigger(katom, katom->event_code == BASE_JD_EVENT_DONE ? 0 : -EFAULT);
+ /* Release the reference as we don't need it any more */
+ sync_fence_put(katom->fence);
+ katom->fence = NULL;
+ break;
+ case BASE_JD_REQ_SOFT_FENCE_WAIT:
+ return kbase_fence_wait(katom);
+#endif /* CONFIG_SYNC */
+ }
+
+ /* Atom is complete */
+ return 0;
+}
+
+void kbase_cancel_soft_job(kbase_jd_atom *katom)
+{
+ switch(katom->core_req)
+ {
+#ifdef CONFIG_SYNC
+ case BASE_JD_REQ_SOFT_FENCE_WAIT:
+ kbase_fence_cancel_wait(katom);
+ break;
+#endif
+ default:
+ /* This soft-job doesn't support cancellation! */
+ OSK_ASSERT(0);
+ }
+}
+
+mali_error kbase_prepare_soft_job(kbase_jd_atom *katom )
+{
+ switch(katom->core_req) {
+ case BASE_JD_REQ_SOFT_DUMP_CPU_GPU_TIME:
+ /* Nothing to do */
+ break;
+#ifdef CONFIG_SYNC
+ case BASE_JD_REQ_SOFT_FENCE_TRIGGER:
+ {
+ base_fence fence;
+ int fd;
+ if (MALI_ERROR_NONE != ukk_copy_from_user(sizeof(fence), &fence, (__user void*)(uintptr_t)katom->jc))
+ {
+ return MALI_ERROR_FUNCTION_FAILED;
+ }
+ fd = kbase_stream_create_fence(fence.basep.stream_fd);
+ if (fd < 0)
+ {
+ return MALI_ERROR_FUNCTION_FAILED;
+ }
+ katom->fence = sync_fence_fdget(fd);
+
+ if (katom->fence == NULL)
+ {
+ /* The only way the fence can be NULL is if userspace closed it for us.
+ * So we don't need to clear it up */
+ return MALI_ERROR_FUNCTION_FAILED;
+ }
+ fence.basep.fd = fd;
+ if (MALI_ERROR_NONE != ukk_copy_to_user(sizeof(fence), (__user void*)(uintptr_t)katom->jc, &fence))
+ {
+ katom->fence = NULL;
+ sys_close(fd);
+ return MALI_ERROR_FUNCTION_FAILED;
+ }
+ }
+ break;
+ case BASE_JD_REQ_SOFT_FENCE_WAIT:
+ {
+ base_fence fence;
+ if (MALI_ERROR_NONE != ukk_copy_from_user(sizeof(fence), &fence, (__user void*)(uintptr_t)katom->jc))
+ {
+ return MALI_ERROR_FUNCTION_FAILED;
+ }
+
+ /* Get a reference to the fence object */
+ katom->fence = sync_fence_fdget(fence.basep.fd);
+ if (katom->fence == NULL)
+ {
+ return MALI_ERROR_FUNCTION_FAILED;
+ }
+ }
+ break;
+#endif /* CONFIG_SYNC */
+ default:
+ /* Unsupported soft-job */
+ return MALI_ERROR_FUNCTION_FAILED;
+ }
+ return MALI_ERROR_NONE;
+}
+
+void kbase_finish_soft_job(kbase_jd_atom *katom )
+{
+ switch(katom->core_req) {
+ case BASE_JD_REQ_SOFT_DUMP_CPU_GPU_TIME:
+ /* Nothing to do */
+ break;
+#ifdef CONFIG_SYNC
+ case BASE_JD_REQ_SOFT_FENCE_TRIGGER:
+ if (katom->fence) {
+ /* The fence has not yet been signalled, so we do it now */
+ kbase_fence_trigger(katom, katom->event_code == BASE_JD_EVENT_DONE ? 0 : -EFAULT);
+ sync_fence_put(katom->fence);
+ katom->fence = NULL;
+ }
+ break;
+ case BASE_JD_REQ_SOFT_FENCE_WAIT:
+ /* Release the reference to the fence object */
+ sync_fence_put(katom->fence);
+ katom->fence = NULL;
+ break;
+#endif /* CONFIG_SYNC */
+ }
+}
diff --git a/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_trace_defs.h b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_trace_defs.h
new file mode 100644
index 0000000..3dc85f8
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_trace_defs.h
@@ -0,0 +1,201 @@
+/*
+ *
+ * (C) COPYRIGHT 2011-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+
+/* ***** IMPORTANT: THIS IS NOT A NORMAL HEADER FILE *****
+ * ***** DO NOT INCLUDE DIRECTLY *****
+ * ***** THE LACK OF HEADER GUARDS IS INTENTIONAL ***** */
+
+/*
+ * The purpose of this header file is just to contain a list of trace code idenitifers
+ *
+ * Each identifier is wrapped in a macro, so that its string form and enum form can be created
+ *
+ * Each macro is separated with a comma, to allow insertion into an array initializer or enum definition block.
+ *
+ * This allows automatic creation of an enum and a corresponding array of strings
+ *
+ * Before #including, the includer MUST #define KBASE_TRACE_CODE_MAKE_CODE.
+ * After #including, the includer MUST #under KBASE_TRACE_CODE_MAKE_CODE.
+ *
+ * e.g.:
+ * #define KBASE_TRACE_CODE( X ) KBASE_TRACE_CODE_ ## X
+ * typedef enum
+ * {
+ * #define KBASE_TRACE_CODE_MAKE_CODE( X ) KBASE_TRACE_CODE( X )
+ * #include "mali_kbase_trace_defs.h"
+ * #undef KBASE_TRACE_CODE_MAKE_CODE
+ * } kbase_trace_code;
+ *
+ * IMPORTANT: THIS FILE MUST NOT BE USED FOR ANY OTHER PURPOSE OTHER THAN THE ABOVE
+ *
+ *
+ * The use of the macro here is:
+ * - KBASE_TRACE_CODE_MAKE_CODE( X )
+ *
+ * Which produces:
+ * - For an enum, KBASE_TRACE_CODE_X
+ * - For a string, "X"
+ *
+ *
+ * For example:
+ * - KBASE_TRACE_CODE_MAKE_CODE( JM_JOB_COMPLETE ) expands to:
+ * - KBASE_TRACE_CODE_JM_JOB_COMPLETE for the enum
+ * - "JM_JOB_COMPLETE" for the string
+ * - To use it to trace an event, do:
+ * - KBASE_TRACE_ADD( kbdev, JM_JOB_COMPLETE, subcode, kctx, uatom, val );
+ */
+
+/*
+ * Core events
+ */
+KBASE_TRACE_CODE_MAKE_CODE( CORE_CTX_DESTROY ), /* no info_val, no gpu_addr, no atom */
+KBASE_TRACE_CODE_MAKE_CODE( CORE_CTX_HWINSTR_TERM ), /* no info_val, no gpu_addr, no atom */
+KBASE_TRACE_CODE_MAKE_CODE( CORE_GPU_IRQ ), /* info_val == GPU_IRQ_STATUS register */
+KBASE_TRACE_CODE_MAKE_CODE( CORE_GPU_SOFT_RESET ),
+KBASE_TRACE_CODE_MAKE_CODE( CORE_GPU_HARD_RESET ),
+
+/*
+ * Job Slot management events
+ */
+
+KBASE_TRACE_CODE_MAKE_CODE( JM_IRQ ), /* info_val==irq rawstat at start */
+KBASE_TRACE_CODE_MAKE_CODE( JM_IRQ_END ), /* info_val==jobs processed */
+/* In the following:
+ *
+ * - ctx is set if a corresponding job found (NULL otherwise, e.g. some soft-stop cases)
+ * - uatom==kernel-side mapped uatom address (for correlation with user-side)
+ */
+KBASE_TRACE_CODE_MAKE_CODE( JM_JOB_DONE ), /* info_val==exit code; gpu_addr==chain gpuaddr */
+KBASE_TRACE_CODE_MAKE_CODE( JM_SUBMIT ), /* gpu_addr==JSn_HEAD_NEXT written, info_val==lower 32 bits of affinity */
+
+/* gpu_addr is as follows:
+ * - If JSn_STATUS active after soft-stop, val==gpu addr written to JSn_HEAD on submit
+ * - otherwise gpu_addr==0 */
+KBASE_TRACE_CODE_MAKE_CODE( JM_SOFTSTOP ),
+KBASE_TRACE_CODE_MAKE_CODE( JM_HARDSTOP ), /* gpu_addr==JSn_HEAD read */
+
+KBASE_TRACE_CODE_MAKE_CODE( JM_UPDATE_HEAD ), /* gpu_addr==JSn_TAIL read */
+/* gpu_addr is as follows:
+ * - If JSn_STATUS active before soft-stop, val==JSn_HEAD
+ * - otherwise gpu_addr==0 */
+KBASE_TRACE_CODE_MAKE_CODE( JM_CHECK_HEAD ), /* gpu_addr==JSn_HEAD read */
+
+KBASE_TRACE_CODE_MAKE_CODE( JM_FLUSH_WORKQS ),
+KBASE_TRACE_CODE_MAKE_CODE( JM_FLUSH_WORKQS_DONE ),
+
+KBASE_TRACE_CODE_MAKE_CODE( JM_ZAP_NON_SCHEDULED ), /* info_val == is_scheduled */
+KBASE_TRACE_CODE_MAKE_CODE( JM_ZAP_SCHEDULED ), /* info_val == is_scheduled */
+KBASE_TRACE_CODE_MAKE_CODE( JM_ZAP_DONE ),
+
+KBASE_TRACE_CODE_MAKE_CODE( JM_SLOT_SOFT_OR_HARD_STOP ), /* info_val == nr jobs submitted */
+KBASE_TRACE_CODE_MAKE_CODE( JM_SLOT_EVICT ), /* gpu_addr==JSn_HEAD_NEXT last written */
+KBASE_TRACE_CODE_MAKE_CODE( JM_SUBMIT_AFTER_RESET ),
+KBASE_TRACE_CODE_MAKE_CODE( JM_BEGIN_RESET_WORKER ),
+KBASE_TRACE_CODE_MAKE_CODE( JM_END_RESET_WORKER ),
+
+
+/*
+ * Job dispatch events
+ */
+KBASE_TRACE_CODE_MAKE_CODE( JD_DONE ), /* gpu_addr==value to write into JSn_HEAD */
+KBASE_TRACE_CODE_MAKE_CODE( JD_DONE_WORKER ), /* gpu_addr==value to write into JSn_HEAD */
+KBASE_TRACE_CODE_MAKE_CODE( JD_DONE_WORKER_END ), /* gpu_addr==value to write into JSn_HEAD */
+KBASE_TRACE_CODE_MAKE_CODE( JD_DONE_TRY_RUN_NEXT_JOB ), /* gpu_addr==value to write into JSn_HEAD */
+
+KBASE_TRACE_CODE_MAKE_CODE( JD_ZAP_CONTEXT ), /* gpu_addr==0, info_val==0, uatom==0 */
+KBASE_TRACE_CODE_MAKE_CODE( JD_CANCEL ), /* gpu_addr==value to write into JSn_HEAD */
+KBASE_TRACE_CODE_MAKE_CODE( JD_CANCEL_WORKER ), /* gpu_addr==value to write into JSn_HEAD */
+
+/*
+ * Scheduler Core events
+ */
+
+KBASE_TRACE_CODE_MAKE_CODE( JS_RETAIN_CTX_NOLOCK ),
+KBASE_TRACE_CODE_MAKE_CODE( JS_ADD_JOB ), /* gpu_addr==value to write into JSn_HEAD */
+KBASE_TRACE_CODE_MAKE_CODE( JS_REMOVE_JOB ), /* gpu_addr==last value written/would be written to JSn_HEAD */
+KBASE_TRACE_CODE_MAKE_CODE( JS_RETAIN_CTX ),
+KBASE_TRACE_CODE_MAKE_CODE( JS_RELEASE_CTX ),
+KBASE_TRACE_CODE_MAKE_CODE( JS_TRY_SCHEDULE_HEAD_CTX ),
+KBASE_TRACE_CODE_MAKE_CODE( JS_JOB_DONE_TRY_RUN_NEXT_JOB ), /* gpu_addr==value to write into JSn_HEAD */
+KBASE_TRACE_CODE_MAKE_CODE( JS_JOB_DONE_RETRY_NEEDED ), /* gpu_addr==value to write into JSn_HEAD */
+KBASE_TRACE_CODE_MAKE_CODE( JS_FAST_START_EVICTS_CTX ), /* kctx is the one being evicted, info_val == kctx to put in */
+KBASE_TRACE_CODE_MAKE_CODE( JS_AFFINITY_SUBMIT_TO_BLOCKED ),
+KBASE_TRACE_CODE_MAKE_CODE( JS_AFFINITY_CURRENT ), /* info_val == lower 32 bits of affinity */
+KBASE_TRACE_CODE_MAKE_CODE( JS_CORE_REF_REQUEST_CORES_FAILED ), /* info_val == lower 32 bits of affinity */
+KBASE_TRACE_CODE_MAKE_CODE( JS_CORE_REF_REGISTER_INUSE_FAILED ), /* info_val == lower 32 bits of affinity */
+KBASE_TRACE_CODE_MAKE_CODE( JS_CORE_REF_REQUEST_ON_RECHECK_FAILED ), /* info_val == lower 32 bits of rechecked affinity */
+KBASE_TRACE_CODE_MAKE_CODE( JS_CORE_REF_REGISTER_ON_RECHECK_FAILED ), /* info_val == lower 32 bits of rechecked affinity */
+KBASE_TRACE_CODE_MAKE_CODE( JS_CORE_REF_AFFINITY_WOULD_VIOLATE ), /* info_val == lower 32 bits of affinity */
+KBASE_TRACE_CODE_MAKE_CODE( JS_CTX_ATTR_NOW_ON_CTX ), /* info_val == the ctx attribute now on ctx */
+KBASE_TRACE_CODE_MAKE_CODE( JS_CTX_ATTR_NOW_ON_RUNPOOL ), /* info_val == the ctx attribute now on runpool */
+KBASE_TRACE_CODE_MAKE_CODE( JS_CTX_ATTR_NOW_OFF_CTX ), /* info_val == the ctx attribute now off ctx */
+KBASE_TRACE_CODE_MAKE_CODE( JS_CTX_ATTR_NOW_OFF_RUNPOOL ), /* info_val == the ctx attribute now off runpool */
+
+
+/*
+ * Scheduler Policy events
+ */
+
+KBASE_TRACE_CODE_MAKE_CODE( JS_POLICY_INIT_CTX ),
+KBASE_TRACE_CODE_MAKE_CODE( JS_POLICY_TERM_CTX ),
+KBASE_TRACE_CODE_MAKE_CODE( JS_POLICY_TRY_EVICT_CTX ), /* info_val == whether it was evicted */
+KBASE_TRACE_CODE_MAKE_CODE( JS_POLICY_KILL_ALL_CTX_JOBS ),
+KBASE_TRACE_CODE_MAKE_CODE( JS_POLICY_ENQUEUE_CTX ),
+KBASE_TRACE_CODE_MAKE_CODE( JS_POLICY_DEQUEUE_HEAD_CTX ),
+KBASE_TRACE_CODE_MAKE_CODE( JS_POLICY_RUNPOOL_ADD_CTX ),
+KBASE_TRACE_CODE_MAKE_CODE( JS_POLICY_RUNPOOL_REMOVE_CTX ),
+
+KBASE_TRACE_CODE_MAKE_CODE( JS_POLICY_DEQUEUE_JOB ),
+KBASE_TRACE_CODE_MAKE_CODE( JS_POLICY_DEQUEUE_JOB_IRQ ),
+KBASE_TRACE_CODE_MAKE_CODE( JS_POLICY_ENQUEUE_JOB ), /* gpu_addr==JSn_HEAD to write if the job were run */
+KBASE_TRACE_CODE_MAKE_CODE( JS_POLICY_TIMER_START ),
+KBASE_TRACE_CODE_MAKE_CODE( JS_POLICY_TIMER_END ),
+
+
+/*
+ * Power Management Events
+ */
+KBASE_TRACE_CODE_MAKE_CODE( PM_JOB_SUBMIT_AFTER_POWERING_UP ),
+KBASE_TRACE_CODE_MAKE_CODE( PM_JOB_SUBMIT_AFTER_POWERED_UP ),
+KBASE_TRACE_CODE_MAKE_CODE( PM_PWRON ),
+KBASE_TRACE_CODE_MAKE_CODE( PM_PWROFF ),
+KBASE_TRACE_CODE_MAKE_CODE( PM_CORES_POWERED ),
+KBASE_TRACE_CODE_MAKE_CODE( PM_CORES_CHANGE_DESIRED_ON_POWERUP ),
+KBASE_TRACE_CODE_MAKE_CODE( PM_CORES_CHANGE_DESIRED_ON_POWERDOWN ),
+KBASE_TRACE_CODE_MAKE_CODE( PM_CORES_CHANGE_DESIRED ),
+KBASE_TRACE_CODE_MAKE_CODE( PM_CORES_CHANGE_AVAILABLE ),
+KBASE_TRACE_CODE_MAKE_CODE( PM_REGISTER_CHANGE_SHADER_INUSE ),
+KBASE_TRACE_CODE_MAKE_CODE( PM_REGISTER_CHANGE_SHADER_NEEDED ),
+KBASE_TRACE_CODE_MAKE_CODE( PM_RELEASE_CHANGE_SHADER_INUSE ),
+KBASE_TRACE_CODE_MAKE_CODE( PM_UNREQUEST_CHANGE_SHADER_NEEDED ),
+KBASE_TRACE_CODE_MAKE_CODE( PM_REQUEST_CHANGE_SHADER_NEEDED ),
+KBASE_TRACE_CODE_MAKE_CODE( PM_CONTEXT_ACTIVE ),
+KBASE_TRACE_CODE_MAKE_CODE( PM_CONTEXT_IDLE ),
+KBASE_TRACE_CODE_MAKE_CODE( PM_GPU_ON ),
+KBASE_TRACE_CODE_MAKE_CODE( PM_GPU_OFF ),
+KBASE_TRACE_CODE_MAKE_CODE( PM_SEND_EVENT ), /* info_val == event code */
+KBASE_TRACE_CODE_MAKE_CODE( PM_HANDLE_EVENT ), /* info_val == event code */
+KBASE_TRACE_CODE_MAKE_CODE( PM_ACTIVATE_WORKER ),
+KBASE_TRACE_CODE_MAKE_CODE( PM_SET_POLICY ), /* info_val == policy number, or -1 for "Already changing" */
+KBASE_TRACE_CODE_MAKE_CODE( PM_CHANGE_POLICY ), /* info_val bit0:15 == old policy, bit16:31 == new policy */
+KBASE_TRACE_CODE_MAKE_CODE( PM_CURRENT_POLICY_INIT ), /* info_val == policy number */
+KBASE_TRACE_CODE_MAKE_CODE( PM_CURRENT_POLICY_TERM ), /* info_val == policy number */
+
+
+/* Unused code just to make it easier to not have a comma at the end.
+ * All other codes MUST come before this */
+KBASE_TRACE_CODE_MAKE_CODE( DUMMY )
+
+/* ***** THE LACK OF HEADER GUARDS IS INTENTIONAL ***** */
diff --git a/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_ukk.c b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_ukk.c
new file mode 100644
index 0000000..ca927c7
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_ukk.c
@@ -0,0 +1,82 @@
+/*
+ *
+ * (C) COPYRIGHT 2010, 2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+#include <osk/mali_osk.h>
+#include <kbase/mali_ukk.h>
+#include <mali_ukk_os.h>
+
+void ukk_call_prepare(ukk_call_context * const ukk_ctx, ukk_session * const session)
+{
+ OSK_ASSERT(NULL != ukk_ctx);
+ OSK_ASSERT(NULL != session);
+
+ ukk_ctx->ukk_session = session;
+}
+
+void *ukk_session_get(ukk_call_context * const ukk_ctx)
+{
+ OSK_ASSERT(NULL != ukk_ctx);
+ return ukk_ctx->ukk_session;
+}
+
+static mali_error ukkp_dispatch_call(ukk_call_context *ukk_ctx, void *args, u32 args_size)
+{
+ uk_header *header = (uk_header *)args;
+ mali_error ret = MALI_ERROR_NONE;
+
+ if(UKP_FUNC_ID_CHECK_VERSION == header->id)
+ {
+ if (args_size == sizeof(uku_version_check_args))
+ {
+ ukk_session *ukk_session = ukk_session_get(ukk_ctx);
+ uku_version_check_args *version_check = (uku_version_check_args *)args;
+
+ version_check->major = ukk_session->version_major;
+ version_check->minor = ukk_session->version_minor;
+ header->ret = MALI_ERROR_NONE;
+ }
+ else
+ {
+ header->ret = MALI_ERROR_FUNCTION_FAILED;
+ }
+ }
+ else
+ {
+ ret = MALI_ERROR_FUNCTION_FAILED; /* not handled */
+ }
+ return ret;
+}
+
+mali_error ukk_dispatch(ukk_call_context * const ukk_ctx, void * const args, u32 args_size)
+{
+ mali_error ret;
+ uk_header *header = (uk_header *)args;
+
+ OSK_ASSERT(NULL != ukk_ctx);
+ OSK_ASSERT(NULL != args);
+
+ /* Verify args_size both in debug and release builds */
+ OSK_ASSERT(args_size >= sizeof(uk_header));
+ if (args_size < sizeof(uk_header)) return MALI_ERROR_FUNCTION_FAILED;
+
+ if (header->id >= UK_FUNC_ID)
+ {
+ ret = ukk_ctx->ukk_session->dispatch(ukk_ctx, args, args_size);
+ }
+ else
+ {
+ ret = ukkp_dispatch_call(ukk_ctx, args, args_size);
+ }
+ return ret;
+}
diff --git a/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_uku.h b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_uku.h
new file mode 100644
index 0000000..0e25fe9
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_uku.h
@@ -0,0 +1,312 @@
+/*
+ *
+ * (C) COPYRIGHT 2008-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+#ifndef _KBASE_UKU_H_
+#define _KBASE_UKU_H_
+
+#include <kbase/mali_uk.h>
+#include <malisw/mali_malisw.h>
+#include <kbase/mali_base_kernel.h>
+#if defined(CONFIG_MALI_ERROR_INJECT) || defined(CONFIG_MALI_NO_MALI)
+#include <kbase/src/common/mali_kbase_model_dummy.h>
+#endif
+
+#include "mali_kbase_gpuprops_types.h"
+
+#define BASE_UK_VERSION_MAJOR 1
+#define BASE_UK_VERSION_MINOR 1
+
+typedef struct kbase_uk_tmem_alloc
+{
+ uk_header header;
+ /* IN */
+ u32 vsize;
+ u32 psize;
+ u32 extent;
+ u32 flags;
+ mali_bool is_growable;
+ /* OUT */
+ mali_addr64 gpu_addr;
+} kbase_uk_tmem_alloc;
+
+typedef struct kbase_uk_tmem_import
+{
+ uk_header header;
+ /* IN */
+ kbase_pointer phandle;
+ base_tmem_import_type type;
+ u32 padding;
+ /* OUT */
+ mali_addr64 gpu_addr;
+ u64 pages;
+} kbase_uk_tmem_import;
+
+typedef struct kbase_uk_pmem_alloc
+{
+ uk_header header;
+ /* IN */
+ u32 vsize;
+ u32 flags;
+ /* OUT */
+ u16 cookie;
+} kbase_uk_pmem_alloc;
+
+typedef struct kbase_uk_mem_free
+{
+ uk_header header;
+ /* IN */
+ mali_addr64 gpu_addr;
+ /* OUT */
+} kbase_uk_mem_free;
+
+typedef struct kbase_uk_job_submit
+{
+ uk_header header;
+ /* IN */
+ kbase_pointer addr;
+ u32 nr_atoms;
+ u32 stride; /* bytes between atoms, i.e. sizeof(base_jd_atom_v2) */
+ /* OUT */
+} kbase_uk_job_submit;
+
+typedef struct kbase_uk_post_term
+{
+ uk_header header;
+} kbase_uk_post_term;
+
+typedef struct kbase_uk_sync_now
+{
+ uk_header header;
+
+ /* IN */
+ base_syncset sset;
+
+ /* OUT */
+} kbase_uk_sync_now;
+
+typedef struct kbase_uk_hwcnt_setup
+{
+ uk_header header;
+
+ /* IN */
+ mali_addr64 dump_buffer;
+ u32 jm_bm;
+ u32 shader_bm;
+ u32 tiler_bm;
+ u32 l3_cache_bm;
+ u32 mmu_l2_bm;
+ /* OUT */
+} kbase_uk_hwcnt_setup;
+
+typedef struct kbase_uk_hwcnt_dump
+{
+ uk_header header;
+} kbase_uk_hwcnt_dump;
+
+typedef struct kbase_uk_hwcnt_clear
+{
+ uk_header header;
+} kbase_uk_hwcnt_clear;
+
+typedef struct kbase_uk_fence_validate
+{
+ uk_header header;
+ /* IN */
+ int fd;
+ /* OUT */
+} kbase_uk_fence_validate;
+
+typedef struct kbase_uk_stream_create
+{
+ uk_header header;
+ /* IN */
+ char name[32];
+ /* OUT */
+ int fd;
+} kbase_uk_stream_create;
+
+typedef struct kbase_uk_cpuprops
+{
+ uk_header header;
+
+ /* IN */
+ struct base_cpu_props props;
+ /* OUT */
+}kbase_uk_cpuprops;
+
+typedef struct kbase_uk_gpuprops
+{
+ uk_header header;
+
+ /* IN */
+ struct mali_base_gpu_props props;
+ /* OUT */
+}kbase_uk_gpuprops;
+
+typedef struct kbase_uk_tmem_get_size
+{
+ uk_header header;
+ /* IN */
+ mali_addr64 gpu_addr;
+ /* OUT */
+ u32 actual_size;
+} kbase_uk_tmem_get_size;
+
+typedef struct kbase_uk_tmem_set_size
+{
+ uk_header header;
+ /* IN */
+ mali_addr64 gpu_addr;
+ u32 size;
+ /* OUT */
+ u32 actual_size;
+ base_backing_threshold_status result_subcode;
+} kbase_uk_tmem_set_size;
+
+typedef struct kbase_uk_tmem_resize
+{
+ uk_header header;
+ /* IN */
+ mali_addr64 gpu_addr;
+ s32 delta;
+ /* OUT */
+ u32 actual_size;
+ base_backing_threshold_status result_subcode;
+} kbase_uk_tmem_resize;
+
+typedef struct kbase_uk_find_cpu_mapping
+{
+ uk_header header;
+ /* IN */
+ mali_addr64 gpu_addr;
+ u64 cpu_addr;
+ u64 size;
+ /* OUT */
+ u64 uaddr;
+ u32 nr_pages;
+ mali_size64 page_off;
+} kbase_uk_find_cpu_mapping;
+
+#define KBASE_GET_VERSION_BUFFER_SIZE 64
+typedef struct kbase_uk_get_ddk_version
+{
+ uk_header header;
+ /* OUT */
+ char version_buffer[KBASE_GET_VERSION_BUFFER_SIZE];
+ u32 version_string_size;
+} kbase_uk_get_ddk_version;
+
+typedef struct kbase_uk_set_flags
+{
+ uk_header header;
+ /* IN */
+ u32 create_flags;
+} kbase_uk_set_flags;
+
+#if MALI_UNIT_TEST
+#define TEST_ADDR_COUNT 4
+#define KBASE_TEST_BUFFER_SIZE 128
+typedef struct kbase_exported_test_data
+{
+ mali_addr64 test_addr[TEST_ADDR_COUNT]; /**< memory address */
+ u32 test_addr_pages[TEST_ADDR_COUNT]; /**< memory size in pages */
+ struct kbase_context *kctx; /**< base context created by process */
+ void *mm; /**< pointer to process address space */
+ u8 buffer1[KBASE_TEST_BUFFER_SIZE]; /**< unit test defined parameter */
+ u8 buffer2[KBASE_TEST_BUFFER_SIZE]; /**< unit test defined parameter */
+} kbase_exported_test_data;
+
+typedef struct kbase_uk_set_test_data
+{
+ uk_header header;
+ /* IN */
+ kbase_exported_test_data test_data;
+} kbase_uk_set_test_data;
+
+#endif /* MALI_UNIT_TEST */
+#ifdef CONFIG_MALI_ERROR_INJECT
+typedef struct kbase_uk_error_params
+{
+ uk_header header;
+ /* IN */
+ kbase_error_params params;
+} kbase_uk_error_params;
+#endif /* CONFIG_MALI_ERROR_INJECT */
+
+#ifdef CONFIG_MALI_NO_MALI
+typedef struct kbase_uk_model_control_params
+{
+ uk_header header;
+ /* IN */
+ kbase_model_control_params params;
+} kbase_uk_model_control_params;
+#endif /* CONFIG_MALI_NO_MALI */
+
+#define KBASE_MAXIMUM_EXT_RESOURCES 255
+
+typedef struct kbase_uk_ext_buff_kds_data
+{
+ uk_header header;
+ kbase_pointer external_resource;
+ int num_res; /* limited to KBASE_MAXIMUM_EXT_RESOURCES */
+ kbase_pointer file_descriptor;
+} kbase_uk_ext_buff_kds_data;
+
+typedef struct kbase_uk_keep_gpu_powered
+{
+ uk_header header;
+ mali_bool enabled;
+} kbase_uk_keep_gpu_powered;
+
+typedef enum kbase_uk_function_id
+{
+ KBASE_FUNC_TMEM_ALLOC = (UK_FUNC_ID + 0),
+ KBASE_FUNC_TMEM_IMPORT,
+ KBASE_FUNC_PMEM_ALLOC,
+ KBASE_FUNC_MEM_FREE,
+
+ KBASE_FUNC_JOB_SUBMIT,
+
+ KBASE_FUNC_SYNC,
+
+ KBASE_FUNC_POST_TERM,
+
+ KBASE_FUNC_HWCNT_SETUP,
+ KBASE_FUNC_HWCNT_DUMP,
+ KBASE_FUNC_HWCNT_CLEAR,
+
+ KBASE_FUNC_CPU_PROPS_REG_DUMP,
+ KBASE_FUNC_GPU_PROPS_REG_DUMP,
+
+ KBASE_FUNC_TMEM_RESIZE,
+
+ KBASE_FUNC_FIND_CPU_MAPPING,
+
+ KBASE_FUNC_GET_VERSION,
+ KBASE_FUNC_EXT_BUFFER_LOCK,
+ KBASE_FUNC_SET_FLAGS,
+
+ KBASE_FUNC_SET_TEST_DATA,
+ KBASE_FUNC_INJECT_ERROR,
+ KBASE_FUNC_MODEL_CONTROL,
+
+ KBASE_FUNC_KEEP_GPU_POWERED,
+
+ KBASE_FUNC_FENCE_VALIDATE,
+ KBASE_FUNC_STREAM_CREATE,
+ KBASE_FUNC_TMEM_SETSIZE,
+ KBASE_FUNC_TMEM_GETSIZE
+} kbase_uk_function_id;
+
+#endif /* _KBASE_UKU_H_ */
diff --git a/drivers/gpu/arm/t6xx/kbase/src/common/mali_midg_regmap.h b/drivers/gpu/arm/t6xx/kbase/src/common/mali_midg_regmap.h
new file mode 100644
index 0000000..8c7931f
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/common/mali_midg_regmap.h
@@ -0,0 +1,450 @@
+/*
+ *
+ * (C) COPYRIGHT 2010-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+#ifndef _MIDGARD_REGMAP_H_
+#define _MIDGARD_REGMAP_H_
+
+/*
+ * Begin Register Offsets
+ */
+
+#define GPU_CONTROL_BASE 0x0000
+#define GPU_CONTROL_REG(r) (GPU_CONTROL_BASE + (r))
+#define GPU_ID 0x000 /* (RO) GPU and revision identifier */
+#define L2_FEATURES 0x004 /* (RO) Level 2 cache features */
+#define L3_FEATURES 0x008 /* (RO) Level 3 cache features */
+#define TILER_FEATURES 0x00C /* (RO) Tiler Features */
+#define MEM_FEATURES 0x010 /* (RO) Memory system features */
+#define MMU_FEATURES 0x014 /* (RO) MMU features */
+#define AS_PRESENT 0x018 /* (RO) Address space slots present */
+#define JS_PRESENT 0x01C /* (RO) Job slots present */
+#define GPU_IRQ_RAWSTAT 0x020 /* (RW) */
+#define GPU_IRQ_CLEAR 0x024 /* (WO) */
+#define GPU_IRQ_MASK 0x028 /* (RW) */
+#define GPU_IRQ_STATUS 0x02C /* (RO) */
+
+/* IRQ flags */
+#define GPU_FAULT (1 << 0) /* A GPU Fault has occurred */
+#define MULTIPLE_GPU_FAULTS (1 << 7) /* More than one GPU Fault occurred. */
+#define RESET_COMPLETED (1 << 8) /* Set when a reset has completed. Intended to use with SOFT_RESET
+ commands which may take time.*/
+#define POWER_CHANGED_SINGLE (1 << 9) /* Set when a single core has finished powering up or down. */
+#define POWER_CHANGED_ALL (1 << 10) /* Set when all cores have finished powering up or down
+ and the power manager is idle. */
+
+#define PRFCNT_SAMPLE_COMPLETED (1 << 16) /* Set when a performance count sample has completed. */
+#define CLEAN_CACHES_COMPLETED (1 << 17) /* Set when a cache clean operation has completed. */
+
+#define GPU_IRQ_REG_ALL (GPU_FAULT | MULTIPLE_GPU_FAULTS | RESET_COMPLETED \
+ | POWER_CHANGED_ALL | PRFCNT_SAMPLE_COMPLETED \
+ | CLEAN_CACHES_COMPLETED)
+
+#define GPU_COMMAND 0x030 /* (WO) */
+#define GPU_STATUS 0x034 /* (RO) */
+
+#define GROUPS_L2_COHERENT (1 << 0) /* Cores groups are l2 coherent */
+#define GROUPS_L3_COHERENT (1 << 1) /* Cores groups are l3 coherent */
+
+#define GPU_FAULTSTATUS 0x03C /* (RO) GPU exception type and fault status */
+#define GPU_FAULTADDRESS_LO 0x040 /* (RO) GPU exception fault address, low word */
+#define GPU_FAULTADDRESS_HI 0x044 /* (RO) GPU exception fault address, high word */
+
+#define PWR_KEY 0x050 /* (WO) Power manager key register */
+#define PWR_OVERRIDE0 0x054 /* (RW) Power manager override settings */
+#define PWR_OVERRIDE1 0x058 /* (RW) Power manager override settings */
+
+#define PRFCNT_BASE_LO 0x060 /* (RW) Performance counter memory region base address, low word */
+#define PRFCNT_BASE_HI 0x064 /* (RW) Performance counter memory region base address, high word */
+#define PRFCNT_CONFIG 0x068 /* (RW) Performance counter configuration */
+#define PRFCNT_JM_EN 0x06C /* (RW) Performance counter enable flags for Job Manager */
+#define PRFCNT_SHADER_EN 0x070 /* (RW) Performance counter enable flags for shader cores */
+#define PRFCNT_TILER_EN 0x074 /* (RW) Performance counter enable flags for tiler */
+#define PRFCNT_L3_CACHE_EN 0x078 /* (RW) Performance counter enable flags for L3 cache */
+#define PRFCNT_MMU_L2_EN 0x07C /* (RW) Performance counter enable flags for MMU/L2 cache */
+
+#define CYCLE_COUNT_LO 0x090 /* (RO) Cycle counter, low word */
+#define CYCLE_COUNT_HI 0x094 /* (RO) Cycle counter, high word */
+#define TIMESTAMP_LO 0x098 /* (RO) Global time stamp counter, low word */
+#define TIMESTAMP_HI 0x09C /* (RO) Global time stamp counter, high word */
+
+#define TEXTURE_FEATURES_0 0x0B0 /* (RO) Support flags for indexed texture formats 0..31 */
+#define TEXTURE_FEATURES_1 0x0B4 /* (RO) Support flags for indexed texture formats 32..63 */
+#define TEXTURE_FEATURES_2 0x0B8 /* (RO) Support flags for indexed texture formats 64..95 */
+
+#define TEXTURE_FEATURES_REG(n) GPU_CONTROL_REG(TEXTURE_FEATURES_0 + ((n) << 2))
+
+#define JS0_FEATURES 0x0C0 /* (RO) Features of job slot 0 */
+#define JS1_FEATURES 0x0C4 /* (RO) Features of job slot 1 */
+#define JS2_FEATURES 0x0C8 /* (RO) Features of job slot 2 */
+#define JS3_FEATURES 0x0CC /* (RO) Features of job slot 3 */
+#define JS4_FEATURES 0x0D0 /* (RO) Features of job slot 4 */
+#define JS5_FEATURES 0x0D4 /* (RO) Features of job slot 5 */
+#define JS6_FEATURES 0x0D8 /* (RO) Features of job slot 6 */
+#define JS7_FEATURES 0x0DC /* (RO) Features of job slot 7 */
+#define JS8_FEATURES 0x0E0 /* (RO) Features of job slot 8 */
+#define JS9_FEATURES 0x0E4 /* (RO) Features of job slot 9 */
+#define JS10_FEATURES 0x0E8 /* (RO) Features of job slot 10 */
+#define JS11_FEATURES 0x0EC /* (RO) Features of job slot 11 */
+#define JS12_FEATURES 0x0F0 /* (RO) Features of job slot 12 */
+#define JS13_FEATURES 0x0F4 /* (RO) Features of job slot 13 */
+#define JS14_FEATURES 0x0F8 /* (RO) Features of job slot 14 */
+#define JS15_FEATURES 0x0FC /* (RO) Features of job slot 15 */
+
+#define JS_FEATURES_REG(n) GPU_CONTROL_REG(JS0_FEATURES + ((n) << 2))
+
+#define SHADER_PRESENT_LO 0x100 /* (RO) Shader core present bitmap, low word */
+#define SHADER_PRESENT_HI 0x104 /* (RO) Shader core present bitmap, high word */
+
+#define TILER_PRESENT_LO 0x110 /* (RO) Tiler core present bitmap, low word */
+#define TILER_PRESENT_HI 0x114 /* (RO) Tiler core present bitmap, high word */
+
+#define L2_PRESENT_LO 0x120 /* (RO) Level 2 cache present bitmap, low word */
+#define L2_PRESENT_HI 0x124 /* (RO) Level 2 cache present bitmap, high word */
+
+#define L3_PRESENT_LO 0x130 /* (RO) Level 3 cache present bitmap, low word */
+#define L3_PRESENT_HI 0x134 /* (RO) Level 3 cache present bitmap, high word */
+
+#define SHADER_READY_LO 0x140 /* (RO) Shader core ready bitmap, low word */
+#define SHADER_READY_HI 0x144 /* (RO) Shader core ready bitmap, high word */
+
+#define TILER_READY_LO 0x150 /* (RO) Tiler core ready bitmap, low word */
+#define TILER_READY_HI 0x154 /* (RO) Tiler core ready bitmap, high word */
+
+#define L2_READY_LO 0x160 /* (RO) Level 2 cache ready bitmap, low word */
+#define L2_READY_HI 0x164 /* (RO) Level 2 cache ready bitmap, high word */
+
+#define L3_READY_LO 0x170 /* (RO) Level 3 cache ready bitmap, low word */
+#define L3_READY_HI 0x174 /* (RO) Level 3 cache ready bitmap, high word */
+
+#define SHADER_PWRON_LO 0x180 /* (WO) Shader core power on bitmap, low word */
+#define SHADER_PWRON_HI 0x184 /* (WO) Shader core power on bitmap, high word */
+
+#define TILER_PWRON_LO 0x190 /* (WO) Tiler core power on bitmap, low word */
+#define TILER_PWRON_HI 0x194 /* (WO) Tiler core power on bitmap, high word */
+
+#define L2_PWRON_LO 0x1A0 /* (WO) Level 2 cache power on bitmap, low word */
+#define L2_PWRON_HI 0x1A4 /* (WO) Level 2 cache power on bitmap, high word */
+
+#define L3_PWRON_LO 0x1B0 /* (WO) Level 3 cache power on bitmap, low word */
+#define L3_PWRON_HI 0x1B4 /* (WO) Level 3 cache power on bitmap, high word */
+
+#define SHADER_PWROFF_LO 0x1C0 /* (WO) Shader core power off bitmap, low word */
+#define SHADER_PWROFF_HI 0x1C4 /* (WO) Shader core power off bitmap, high word */
+
+#define TILER_PWROFF_LO 0x1D0 /* (WO) Tiler core power off bitmap, low word */
+#define TILER_PWROFF_HI 0x1D4 /* (WO) Tiler core power off bitmap, high word */
+
+#define L2_PWROFF_LO 0x1E0 /* (WO) Level 2 cache power off bitmap, low word */
+#define L2_PWROFF_HI 0x1E4 /* (WO) Level 2 cache power off bitmap, high word */
+
+#define L3_PWROFF_LO 0x1F0 /* (WO) Level 3 cache power off bitmap, low word */
+#define L3_PWROFF_HI 0x1F4 /* (WO) Level 3 cache power off bitmap, high word */
+
+#define SHADER_PWRTRANS_LO 0x200 /* (RO) Shader core power transition bitmap, low word */
+#define SHADER_PWRTRANS_HI 0x204 /* (RO) Shader core power transition bitmap, high word */
+
+#define TILER_PWRTRANS_LO 0x210 /* (RO) Tiler core power transition bitmap, low word */
+#define TILER_PWRTRANS_HI 0x214 /* (RO) Tiler core power transition bitmap, high word */
+
+#define L2_PWRTRANS_LO 0x220 /* (RO) Level 2 cache power transition bitmap, low word */
+#define L2_PWRTRANS_HI 0x224 /* (RO) Level 2 cache power transition bitmap, high word */
+
+#define L3_PWRTRANS_LO 0x230 /* (RO) Level 3 cache power transition bitmap, low word */
+#define L3_PWRTRANS_HI 0x234 /* (RO) Level 3 cache power transition bitmap, high word */
+
+#define SHADER_PWRACTIVE_LO 0x240 /* (RO) Shader core active bitmap, low word */
+#define SHADER_PWRACTIVE_HI 0x244 /* (RO) Shader core active bitmap, high word */
+
+#define TILER_PWRACTIVE_LO 0x250 /* (RO) Tiler core active bitmap, low word */
+#define TILER_PWRACTIVE_HI 0x254 /* (RO) Tiler core active bitmap, high word */
+
+#define L2_PWRACTIVE_LO 0x260 /* (RO) Level 2 cache active bitmap, low word */
+#define L2_PWRACTIVE_HI 0x264 /* (RO) Level 2 cache active bitmap, high word */
+
+#define L3_PWRACTIVE_LO 0x270 /* (RO) Level 3 cache active bitmap, low word */
+#define L3_PWRACTIVE_HI 0x274 /* (RO) Level 3 cache active bitmap, high word */
+
+
+#define SHADER_CONFIG 0xF04 /* (RW) Shader core configuration settings (Mali-T60x additional register) */
+#define L2_MMU_CONFIG 0xF0C /* (RW) Configuration of the L2 cache and MMU (Mali-T60x additional register) */
+
+
+#define JOB_CONTROL_BASE 0x1000
+
+#define JOB_CONTROL_REG(r) (JOB_CONTROL_BASE + (r))
+
+#define JOB_IRQ_RAWSTAT 0x000 /* Raw interrupt status register */
+#define JOB_IRQ_CLEAR 0x004 /* Interrupt clear register */
+#define JOB_IRQ_MASK 0x008 /* Interrupt mask register */
+#define JOB_IRQ_STATUS 0x00C /* Interrupt status register */
+#define JOB_IRQ_JS_STATE 0x010 /* status==active and _next == busy snapshot from last JOB_IRQ_CLEAR */
+#define JOB_IRQ_THROTTLE 0x014 /* cycles to delay delivering an interrupt externally. The JOB_IRQ_STATUS is NOT affected by this, just the delivery of the interrupt. */
+
+#define JOB_SLOT0 0x800 /* Configuration registers for job slot 0 */
+#define JOB_SLOT1 0x880 /* Configuration registers for job slot 1 */
+#define JOB_SLOT2 0x900 /* Configuration registers for job slot 2 */
+#define JOB_SLOT3 0x980 /* Configuration registers for job slot 3 */
+#define JOB_SLOT4 0xA00 /* Configuration registers for job slot 4 */
+#define JOB_SLOT5 0xA80 /* Configuration registers for job slot 5 */
+#define JOB_SLOT6 0xB00 /* Configuration registers for job slot 6 */
+#define JOB_SLOT7 0xB80 /* Configuration registers for job slot 7 */
+#define JOB_SLOT8 0xC00 /* Configuration registers for job slot 8 */
+#define JOB_SLOT9 0xC80 /* Configuration registers for job slot 9 */
+#define JOB_SLOT10 0xD00 /* Configuration registers for job slot 10 */
+#define JOB_SLOT11 0xD80 /* Configuration registers for job slot 11 */
+#define JOB_SLOT12 0xE00 /* Configuration registers for job slot 12 */
+#define JOB_SLOT13 0xE80 /* Configuration registers for job slot 13 */
+#define JOB_SLOT14 0xF00 /* Configuration registers for job slot 14 */
+#define JOB_SLOT15 0xF80 /* Configuration registers for job slot 15 */
+
+#define JOB_SLOT_REG(n,r) (JOB_CONTROL_REG(JOB_SLOT0 + ((n) << 7)) + (r))
+
+#define JSn_HEAD_LO 0x00 /* (RO) Job queue head pointer for job slot n, low word */
+#define JSn_HEAD_HI 0x04 /* (RO) Job queue head pointer for job slot n, high word */
+#define JSn_TAIL_LO 0x08 /* (RO) Job queue tail pointer for job slot n, low word */
+#define JSn_TAIL_HI 0x0C /* (RO) Job queue tail pointer for job slot n, high word */
+#define JSn_AFFINITY_LO 0x10 /* (RO) Core affinity mask for job slot n, low word */
+#define JSn_AFFINITY_HI 0x14 /* (RO) Core affinity mask for job slot n, high word */
+#define JSn_CONFIG 0x18 /* (RO) Configuration settings for job slot n */
+
+#define JSn_COMMAND 0x20 /* (WO) Command register for job slot n */
+#define JSn_STATUS 0x24 /* (RO) Status register for job slot n */
+
+#define JSn_HEAD_NEXT_LO 0x40 /* (RW) Next job queue head pointer for job slot n, low word */
+#define JSn_HEAD_NEXT_HI 0x44 /* (RW) Next job queue head pointer for job slot n, high word */
+
+#define JSn_AFFINITY_NEXT_LO 0x50 /* (RW) Next core affinity mask for job slot n, low word */
+#define JSn_AFFINITY_NEXT_HI 0x54 /* (RW) Next core affinity mask for job slot n, high word */
+#define JSn_CONFIG_NEXT 0x58 /* (RW) Next configuration settings for job slot n */
+
+#define JSn_COMMAND_NEXT 0x60 /* (RW) Next command register for job slot n */
+
+
+#define MEMORY_MANAGEMENT_BASE 0x2000
+#define MMU_REG(r) (MEMORY_MANAGEMENT_BASE + (r))
+
+#define MMU_IRQ_RAWSTAT 0x000 /* (RW) Raw interrupt status register */
+#define MMU_IRQ_CLEAR 0x004 /* (WO) Interrupt clear register */
+#define MMU_IRQ_MASK 0x008 /* (RW) Interrupt mask register */
+#define MMU_IRQ_STATUS 0x00C /* (RO) Interrupt status register */
+
+#define MMU_AS0 0x400 /* Configuration registers for address space 0 */
+#define MMU_AS1 0x440 /* Configuration registers for address space 1 */
+#define MMU_AS2 0x480 /* Configuration registers for address space 2 */
+#define MMU_AS3 0x4C0 /* Configuration registers for address space 3 */
+#define MMU_AS4 0x500 /* Configuration registers for address space 4 */
+#define MMU_AS5 0x540 /* Configuration registers for address space 5 */
+#define MMU_AS6 0x580 /* Configuration registers for address space 6 */
+#define MMU_AS7 0x5C0 /* Configuration registers for address space 7 */
+#define MMU_AS8 0x600 /* Configuration registers for address space 8 */
+#define MMU_AS9 0x640 /* Configuration registers for address space 9 */
+#define MMU_AS10 0x680 /* Configuration registers for address space 10 */
+#define MMU_AS11 0x6C0 /* Configuration registers for address space 11 */
+#define MMU_AS12 0x700 /* Configuration registers for address space 12 */
+#define MMU_AS13 0x740 /* Configuration registers for address space 13 */
+#define MMU_AS14 0x780 /* Configuration registers for address space 14 */
+#define MMU_AS15 0x7C0 /* Configuration registers for address space 15 */
+
+#define MMU_AS_REG(n,r) (MMU_REG(MMU_AS0 + ((n) << 6)) + (r))
+
+#define ASn_TRANSTAB_LO 0x00 /* (RW) Translation Table Base Address for address space n, low word */
+#define ASn_TRANSTAB_HI 0x04 /* (RW) Translation Table Base Address for address space n, high word */
+#define ASn_MEMATTR_LO 0x08 /* (RW) Memory attributes for address space n, low word. */
+#define ASn_MEMATTR_HI 0x0C /* (RW) Memory attributes for address space n, high word. */
+#define ASn_LOCKADDR_LO 0x10 /* (RW) Lock region address for address space n, low word */
+#define ASn_LOCKADDR_HI 0x14 /* (RW) Lock region address for address space n, high word */
+#define ASn_COMMAND 0x18 /* (WO) MMU command register for address space n */
+#define ASn_FAULTSTATUS 0x1C /* (RO) MMU fault status register for address space n */
+#define ASn_FAULTADDRESS_LO 0x20 /* (RO) Fault Address for address space n, low word */
+#define ASn_FAULTADDRESS_HI 0x24 /* (RO) Fault Address for address space n, high word */
+#define ASn_STATUS 0x28 /* (RO) Status flags for address space n */
+
+/* End Register Offsets */
+
+/*
+ * MMU_IRQ_RAWSTAT register values. Values are valid also for
+ MMU_IRQ_CLEAR, MMU_IRQ_MASK, MMU_IRQ_STATUS registers.
+ */
+
+#define MMU_REGS_PAGE_FAULT_FLAGS 16
+
+/* Macros return bit number to retrvie page fault or bus eror flag from MMU registers */
+#define MMU_REGS_PAGE_FAULT_FLAG(n) (n)
+#define MMU_REGS_BUS_ERROR_FLAG(n) (n + MMU_REGS_PAGE_FAULT_FLAGS)
+
+/*
+ * Begin MMU TRANSTAB register values
+ */
+#define ASn_TRANSTAB_ADDR_SPACE_MASK 0xfffff000
+#define ASn_TRANSTAB_ADRMODE_UNMAPPED (0u << 0)
+#define ASn_TRANSTAB_ADRMODE_IDENTITY (1u << 1)
+#define ASn_TRANSTAB_ADRMODE_TABLE (3u << 0)
+#define ASn_TRANSTAB_READ_INNER (1u << 2)
+#define ASn_TRANSTAB_SHARE_OUTER (1u << 4)
+
+#define MMU_TRANSTAB_ADRMODE_MASK 0x00000003
+
+/*
+ * Begin MMU STATUS register values
+ */
+#define ASn_STATUS_FLUSH_ACTIVE 0x01
+
+#define ASn_FAULTSTATUS_ACCESS_TYPE_MASK (0x3<<8)
+#define ASn_FAULTSTATUS_ACCESS_TYPE_EX (0x1<<8)
+#define ASn_FAULTSTATUS_ACCESS_TYPE_READ (0x2<<8)
+#define ASn_FAULTSTATUS_ACCESS_TYPE_WRITE (0x3<<8)
+
+/*
+ * Begin Command Values
+ */
+
+/* JSn_COMMAND register commands */
+#define JSn_COMMAND_NOP 0x00 /* NOP Operation. Writing this value is ignored */
+#define JSn_COMMAND_START 0x01 /* Start processing a job chain. Writing this value is ignored */
+#define JSn_COMMAND_SOFT_STOP 0x02 /* Gently stop processing a job chain */
+#define JSn_COMMAND_HARD_STOP 0x03 /* Rudely stop processing a job chain */
+
+/* ASn_COMMAND register commands */
+#define ASn_COMMAND_NOP 0x00 /* NOP Operation */
+#define ASn_COMMAND_UPDATE 0x01 /* Broadcasts the values in ASn_TRANSTAB and ASn_MEMATTR to all MMUs */
+#define ASn_COMMAND_LOCK 0x02 /* Issue a lock region command to all MMUs */
+#define ASn_COMMAND_UNLOCK 0x03 /* Issue a flush region command to all MMUs */
+#define ASn_COMMAND_FLUSH 0x04 /* Flush all L2 caches then issue a flush region command to all MMUs
+ (deprecated - only for use with T60x/T65x) */
+#define ASn_COMMAND_FLUSH_PT 0x04 /* Flush all L2 caches then issue a flush region command to all MMUs */
+#define ASn_COMMAND_FLUSH_MEM 0x05 /* Wait for memory accesses to complete, flush all the L1s cache then
+ flush all L2 caches then issue a flush region command to all MMUs */
+
+/* Possible values of JSn_CONFIG and JSn_CONFIG_NEXT registers */
+#define JSn_CONFIG_START_FLUSH_NO_ACTION (0u << 0)
+#define JSn_CONFIG_START_FLUSH_CLEAN (1u << 8)
+#define JSn_CONFIG_START_FLUSH_CLEAN_INVALIDATE (3u << 8)
+#define JSn_CONFIG_START_MMU (1u << 10)
+#define JSn_CONFIG_END_FLUSH_NO_ACTION JSn_CONFIG_START_FLUSH_NO_ACTION
+#define JSn_CONFIG_END_FLUSH_CLEAN (1u << 12)
+#define JSn_CONFIG_END_FLUSH_CLEAN_INVALIDATE (3u << 12)
+#define JSn_CONFIG_THREAD_PRI(n) ((n) << 16)
+
+/* JSn_STATUS register values */
+
+/* NOTE: Please keep this values in sync with enum base_jd_event_code in mali_base_kernel.h.
+ * The values are separated to avoid dependency of userspace and kernel code.
+ */
+
+/* Group of values representing the job status insead a particular fault */
+#define JSn_STATUS_NO_EXCEPTION_BASE 0x00
+#define JSn_STATUS_INTERRUPTED (JSn_STATUS_NO_EXCEPTION_BASE + 0x02) /* 0x02 means INTERRUPTED */
+#define JSn_STATUS_STOPPED (JSn_STATUS_NO_EXCEPTION_BASE + 0x03) /* 0x03 means STOPPED */
+#define JSn_STATUS_TERMINATED (JSn_STATUS_NO_EXCEPTION_BASE + 0x04) /* 0x04 means TERMINATED */
+
+/* General fault values */
+#define JSn_STATUS_FAULT_BASE 0x40
+#define JSn_STATUS_CONFIG_FAULT (JSn_STATUS_FAULT_BASE) /* 0x40 means CONFIG FAULT */
+#define JSn_STATUS_POWER_FAULT (JSn_STATUS_FAULT_BASE + 0x01) /* 0x41 means POWER FAULT */
+#define JSn_STATUS_READ_FAULT (JSn_STATUS_FAULT_BASE + 0x02) /* 0x42 means READ FAULT */
+#define JSn_STATUS_WRITE_FAULT (JSn_STATUS_FAULT_BASE + 0x03) /* 0x43 means WRITE FAULT */
+#define JSn_STATUS_AFFINITY_FAULT (JSn_STATUS_FAULT_BASE + 0x04) /* 0x44 means AFFINITY FAULT */
+#define JSn_STATUS_BUS_FAULT (JSn_STATUS_FAULT_BASE + 0x08) /* 0x48 means BUS FAULT */
+
+/* Instruction or data faults */
+#define JSn_STATUS_INSTRUCTION_FAULT_BASE 0x50
+#define JSn_STATUS_INSTR_INVALID_PC (JSn_STATUS_INSTRUCTION_FAULT_BASE) /* 0x50 means INSTR INVALID PC */
+#define JSn_STATUS_INSTR_INVALID_ENC (JSn_STATUS_INSTRUCTION_FAULT_BASE + 0x01) /* 0x51 means INSTR INVALID ENC */
+#define JSn_STATUS_INSTR_TYPE_MISMATCH (JSn_STATUS_INSTRUCTION_FAULT_BASE + 0x02) /* 0x52 means INSTR TYPE MISMATCH */
+#define JSn_STATUS_INSTR_OPERAND_FAULT (JSn_STATUS_INSTRUCTION_FAULT_BASE + 0x03) /* 0x53 means INSTR OPERAND FAULT */
+#define JSn_STATUS_INSTR_TLS_FAULT (JSn_STATUS_INSTRUCTION_FAULT_BASE + 0x04) /* 0x54 means INSTR TLS FAULT */
+#define JSn_STATUS_INSTR_BARRIER_FAULT (JSn_STATUS_INSTRUCTION_FAULT_BASE + 0x05) /* 0x55 means INSTR BARRIER FAULT */
+#define JSn_STATUS_INSTR_ALIGN_FAULT (JSn_STATUS_INSTRUCTION_FAULT_BASE + 0x06) /* 0x56 means INSTR ALIGN FAULT */
+/* NOTE: No fault with 0x57 code defined in spec. */
+#define JSn_STATUS_DATA_INVALID_FAULT (JSn_STATUS_INSTRUCTION_FAULT_BASE + 0x08) /* 0x58 means DATA INVALID FAULT */
+#define JSn_STATUS_TILE_RANGE_FAULT (JSn_STATUS_INSTRUCTION_FAULT_BASE + 0x09) /* 0x59 means TILE RANGE FAULT */
+#define JSn_STATUS_ADDRESS_RANGE_FAULT (JSn_STATUS_INSTRUCTION_FAULT_BASE + 0x0A) /* 0x5A means ADDRESS RANGE FAULT */
+
+/* Other faults */
+#define JSn_STATUS_MEMORY_FAULT_BASE 0x60
+#define JSn_STATUS_OUT_OF_MEMORY (JSn_STATUS_MEMORY_FAULT_BASE) /* 0x60 means OUT OF MEMORY */
+#define JSn_STATUS_UNKNOWN 0x7F /* 0x7F means UNKNOWN */
+
+
+/* GPU_COMMAND values */
+#define GPU_COMMAND_NOP 0x00 /* No operation, nothing happens */
+#define GPU_COMMAND_SOFT_RESET 0x01 /* Stop all external bus interfaces, and then reset the entire GPU. */
+#define GPU_COMMAND_HARD_RESET 0x02 /* Immediately reset the entire GPU. */
+#define GPU_COMMAND_PRFCNT_CLEAR 0x03 /* Clear all performance counters, setting them all to zero. */
+#define GPU_COMMAND_PRFCNT_SAMPLE 0x04 /* Sample all performance counters, writing them out to memory */
+#define GPU_COMMAND_CYCLE_COUNT_START 0x05 /* Starts the cycle counter, and system timestamp propagation */
+#define GPU_COMMAND_CYCLE_COUNT_STOP 0x06 /* Stops the cycle counter, and system timestamp propagation */
+#define GPU_COMMAND_CLEAN_CACHES 0x07 /* Clean all caches */
+#define GPU_COMMAND_CLEAN_INV_CACHES 0x08 /* Clean and invalidate all caches */
+
+/* End Command Values */
+
+/* GPU_STATUS values */
+#define GPU_STATUS_PRFCNT_ACTIVE (1 << 2) /* Set if the performance counters are active. */
+
+/* PRFCNT_CONFIG register values */
+#define PRFCNT_CONFIG_AS_SHIFT 4 /* address space bitmap starts from bit 4 of the register */
+#define PRFCNT_CONFIG_MODE_OFF 0 /* The performance counters are disabled. */
+#define PRFCNT_CONFIG_MODE_MANUAL 1 /* The performance counters are enabled, but are only written out when a PRFCNT_SAMPLE command is issued using the GPU_COMMAND register. */
+#define PRFCNT_CONFIG_MODE_TILE 2 /* The performance counters are enabled, and are written out each time a tile finishes rendering. */
+
+/* AS<n>_MEMATTR values */
+#define ASn_MEMATTR_IMPL_DEF_CACHE_POLICY 0x48484848 /* Use GPU implementation-defined caching policy. */
+#define ASn_MEMATTR_FORCE_TO_CACHE_ALL 0x4F4F4F4F /* The attribute set to force all resources to be cached. */
+
+/* GPU_ID register */
+#define GPU_ID_VERSION_STATUS_SHIFT 0
+#define GPU_ID_VERSION_MINOR_SHIFT 4
+#define GPU_ID_VERSION_MAJOR_SHIFT 12
+#define GPU_ID_VERSION_PRODUCT_ID_SHIFT 16
+#define GPU_ID_VERSION_STATUS (0xF << GPU_ID_VERSION_STATUS_SHIFT)
+#define GPU_ID_VERSION_MINOR (0xFF << GPU_ID_VERSION_MINOR_SHIFT)
+#define GPU_ID_VERSION_MAJOR (0xF << GPU_ID_VERSION_MAJOR_SHIFT)
+#define GPU_ID_VERSION_PRODUCT_ID (0xFFFF << GPU_ID_VERSION_PRODUCT_ID_SHIFT)
+
+/* Values for GPU_ID_VERSION_PRODUCT_ID bitfield */
+#define GPU_ID_PI_T60X 0x6956
+#define GPU_ID_PI_T65X 0x3456
+#define GPU_ID_PI_T62X 0x0620
+#define GPU_ID_PI_T67X 0x0670
+
+/* Values for GPU_ID_VERSION_STATUS field for PRODUCT_ID GPU_ID_PI_T60X and GPU_ID_PI_T65X */
+#define GPU_ID_S_15DEV0 0x1
+#define GPU_ID_S_EAC 0x2
+
+/* Helper macro to create a GPU_ID assuming valid values for id, major, minor, status */
+#define GPU_ID_MAKE(id, major, minor, status) \
+ (((id) << GPU_ID_VERSION_PRODUCT_ID_SHIFT) | \
+ ((major) << GPU_ID_VERSION_MAJOR_SHIFT) | \
+ ((minor) << GPU_ID_VERSION_MINOR_SHIFT) | \
+ ((status) << GPU_ID_VERSION_STATUS_SHIFT))
+
+/* End GPU_ID register */
+
+/* JS<n>_FEATURES register */
+
+#define JSn_FEATURE_NULL_JOB (1u << 1)
+#define JSn_FEATURE_SET_VALUE_JOB (1u << 2)
+#define JSn_FEATURE_CACHE_FLUSH_JOB (1u << 3)
+#define JSn_FEATURE_COMPUTE_JOB (1u << 4)
+#define JSn_FEATURE_VERTEX_JOB (1u << 5)
+#define JSn_FEATURE_GEOMETRY_JOB (1u << 6)
+#define JSn_FEATURE_TILER_JOB (1u << 7)
+#define JSn_FEATURE_FUSED_JOB (1u << 8)
+#define JSn_FEATURE_FRAGMENT_JOB (1u << 9)
+
+/* End JS<n>_FEATURES register */
+
+#endif /* _MIDGARD_REGMAP_H_ */
+
diff --git a/drivers/gpu/arm/t6xx/kbase/src/linux/config/mali_kbase_config_vexpress.c b/drivers/gpu/arm/t6xx/kbase/src/linux/config/mali_kbase_config_vexpress.c
new file mode 100644
index 0000000..b0c9b2d
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/linux/config/mali_kbase_config_vexpress.c
@@ -0,0 +1,443 @@
+/*
+ *
+ * (C) COPYRIGHT 2011-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+#include <linux/ioport.h>
+#include <kbase/src/common/mali_kbase.h>
+#include <kbase/src/common/mali_kbase_defs.h>
+#include <kbase/src/linux/mali_kbase_config_linux.h>
+#ifdef CONFIG_UMP
+#include <linux/ump-common.h>
+#endif /* CONFIG_UMP */
+
+#include "mali_kbase_cpu_vexpress.h"
+
+/* Versatile Express (VE) configuration defaults shared between config_attributes[]
+ * and config_attributes_hw_issue_8408[]. Settings are not shared for
+ * JS_HARD_STOP_TICKS_SS and JS_RESET_TICKS_SS.
+ */
+#define KBASE_VE_MEMORY_PER_PROCESS_LIMIT 512 * 1024 * 1024UL /* 512MB */
+#define KBASE_VE_MEMORY_OS_SHARED_MAX 768 * 1024 * 1024UL /* 768MB */
+#define KBASE_VE_MEMORY_OS_SHARED_PERF_GPU KBASE_MEM_PERF_SLOW
+#define KBASE_VE_GPU_FREQ_KHZ_MAX 5000
+#define KBASE_VE_GPU_FREQ_KHZ_MIN 5000
+#ifdef CONFIG_UMP
+#define KBASE_VE_UMP_DEVICE UMP_DEVICE_Z_SHIFT
+#endif /* CONFIG_UMP */
+
+#define KBASE_VE_JS_SCHEDULING_TICK_NS_DEBUG 15000000u /* 15ms, an agressive tick for testing purposes. This will reduce performance significantly */
+#define KBASE_VE_JS_SOFT_STOP_TICKS_DEBUG 1 /* between 15ms and 30ms before soft-stop a job */
+#define KBASE_VE_JS_HARD_STOP_TICKS_SS_DEBUG 333 /* 5s before hard-stop */
+#define KBASE_VE_JS_HARD_STOP_TICKS_SS_8401_DEBUG 2000 /* 30s before hard-stop, for a certain GLES2 test at 128x128 (bound by combined vertex+tiler job) - for issue 8401 */
+#define KBASE_VE_JS_HARD_STOP_TICKS_NSS_DEBUG 100000 /* 1500s (25mins) before NSS hard-stop */
+#define KBASE_VE_JS_RESET_TICKS_SS_DEBUG 500 /* 45s before resetting GPU, for a certain GLES2 test at 128x128 (bound by combined vertex+tiler job) */
+#define KBASE_VE_JS_RESET_TICKS_SS_8401_DEBUG 3000 /* 7.5s before resetting GPU - for issue 8401 */
+#define KBASE_VE_JS_RESET_TICKS_NSS_DEBUG 100166 /* 1502s before resetting GPU */
+
+#define KBASE_VE_JS_SCHEDULING_TICK_NS 2500000000u /* 2.5s */
+#define KBASE_VE_JS_SOFT_STOP_TICKS 1 /* 2.5s before soft-stop a job */
+#define KBASE_VE_JS_HARD_STOP_TICKS_SS 2 /* 5s before hard-stop */
+#define KBASE_VE_JS_HARD_STOP_TICKS_SS_8401 12 /* 30s before hard-stop, for a certain GLES2 test at 128x128 (bound by combined vertex+tiler job) - for issue 8401 */
+#define KBASE_VE_JS_HARD_STOP_TICKS_NSS 600 /* 1500s before NSS hard-stop */
+#define KBASE_VE_JS_RESET_TICKS_SS 3 /* 7.5s before resetting GPU */
+#define KBASE_VE_JS_RESET_TICKS_SS_8401 18 /* 45s before resetting GPU, for a certain GLES2 test at 128x128 (bound by combined vertex+tiler job) - for issue 8401 */
+#define KBASE_VE_JS_RESET_TICKS_NSS 601 /* 1502s before resetting GPU */
+
+#define KBASE_VE_JS_RESET_TIMEOUT_MS 3000 /* 3s before cancelling stuck jobs */
+#define KBASE_VE_JS_CTX_TIMESLICE_NS 1000000 /* 1ms - an agressive timeslice for testing purposes (causes lots of scheduling out for >4 ctxs) */
+#define KBASE_VE_SECURE_BUT_LOSS_OF_PERFORMANCE (uintptr_t)MALI_FALSE /* By default we prefer performance over security on r0p0-15dev0 and KBASE_CONFIG_ATTR_ earlier */
+#define KBASE_VE_POWER_MANAGEMENT_CALLBACKS (uintptr_t)&pm_callbacks
+#define KBASE_VE_MEMORY_RESOURCE_ZBT (uintptr_t)<_zbt
+#define KBASE_VE_MEMORY_RESOURCE_DDR (uintptr_t)<_ddr
+#define KBASE_VE_CPU_SPEED_FUNC (uintptr_t)&kbase_get_vexpress_cpu_clock_speed
+
+/* Set this to 1 to enable dedicated memory banks */
+#define T6F1_ZBT_DDR_ENABLED 0
+#define HARD_RESET_AT_POWER_OFF 0
+
+static kbase_io_resources io_resources =
+{
+ .job_irq_number = 68,
+ .mmu_irq_number = 69,
+ .gpu_irq_number = 70,
+ .io_memory_region =
+ {
+ .start = 0xFC010000,
+ .end = 0xFC010000 + (4096 * 5) - 1
+ }
+};
+
+#if T6F1_ZBT_DDR_ENABLED
+
+static kbase_attribute lt_zbt_attrs[] =
+{
+ {
+ KBASE_MEM_ATTR_PERF_CPU,
+ KBASE_MEM_PERF_SLOW
+ },
+ {
+ KBASE_MEM_ATTR_END,
+ 0
+ }
+};
+
+static kbase_memory_resource lt_zbt =
+{
+ .base = 0xFD000000,
+ .size = 16 * 1024 * 1024UL /* 16MB */,
+ .attributes = lt_zbt_attrs,
+ .name = "T604 ZBT memory"
+};
+
+
+static kbase_attribute lt_ddr_attrs[] =
+{
+ {
+ KBASE_MEM_ATTR_PERF_CPU,
+ KBASE_MEM_PERF_SLOW
+ },
+ {
+ KBASE_MEM_ATTR_END,
+ 0
+ }
+};
+
+static kbase_memory_resource lt_ddr =
+{
+ .base = 0xE0000000,
+ .size = 256 * 1024 * 1024UL /* 256MB */,
+ .attributes = lt_ddr_attrs,
+ .name = "T604 DDR memory"
+};
+
+#endif /* T6F1_ZBT_DDR_ENABLED */
+
+static int pm_callback_power_on(kbase_device *kbdev)
+{
+ /* Nothing is needed on VExpress, but we may have destroyed GPU state (if the below HARD_RESET code is active) */
+ return 1;
+}
+
+static void pm_callback_power_off(kbase_device *kbdev)
+{
+#if HARD_RESET_AT_POWER_OFF
+ /* Cause a GPU hard reset to test whether we have actually idled the GPU
+ * and that we properly reconfigure the GPU on power up.
+ * Usually this would be dangerous, but if the GPU is working correctly it should
+ * be completely safe as the GPU should not be active at this point.
+ * However this is disabled normally because it will most likely interfere with
+ * bus logging etc.
+ */
+ KBASE_TRACE_ADD( kbdev, CORE_GPU_HARD_RESET, NULL, NULL, 0u, 0 );
+ kbase_os_reg_write(kbdev, GPU_CONTROL_REG(GPU_COMMAND), GPU_COMMAND_HARD_RESET);
+#endif
+}
+
+static kbase_pm_callback_conf pm_callbacks =
+{
+ .power_on_callback = pm_callback_power_on,
+ .power_off_callback = pm_callback_power_off
+};
+
+/* Please keep table config_attributes in sync with config_attributes_hw_issue_8408 */
+static kbase_attribute config_attributes[] =
+{
+ {
+ KBASE_CONFIG_ATTR_MEMORY_PER_PROCESS_LIMIT,
+ KBASE_VE_MEMORY_PER_PROCESS_LIMIT
+ },
+#ifdef CONFIG_UMP
+ {
+ KBASE_CONFIG_ATTR_UMP_DEVICE,
+ KBASE_VE_UMP_DEVICE
+ },
+#endif /* CONFIG_UMP */
+ {
+ KBASE_CONFIG_ATTR_MEMORY_OS_SHARED_MAX,
+ KBASE_VE_MEMORY_OS_SHARED_MAX
+ },
+
+ {
+ KBASE_CONFIG_ATTR_MEMORY_OS_SHARED_PERF_GPU,
+ KBASE_VE_MEMORY_OS_SHARED_PERF_GPU
+ },
+
+#if T6F1_ZBT_DDR_ENABLED
+ {
+ KBASE_CONFIG_ATTR_MEMORY_RESOURCE,
+ KBASE_VE_MEMORY_RESOURCE_ZBT
+ },
+
+ {
+ KBASE_CONFIG_ATTR_MEMORY_RESOURCE,
+ KBASE_VE_MEMORY_RESOURCE_DDR
+ },
+#endif /* T6F1_ZBT_DDR_ENABLED */
+
+ {
+ KBASE_CONFIG_ATTR_GPU_FREQ_KHZ_MAX,
+ KBASE_VE_GPU_FREQ_KHZ_MAX
+ },
+
+ {
+ KBASE_CONFIG_ATTR_GPU_FREQ_KHZ_MIN,
+ KBASE_VE_GPU_FREQ_KHZ_MIN
+ },
+
+#ifdef CONFIG_MALI_DEBUG
+/* Use more aggressive scheduling timeouts in debug builds for testing purposes */
+ {
+ KBASE_CONFIG_ATTR_JS_SCHEDULING_TICK_NS,
+ KBASE_VE_JS_SCHEDULING_TICK_NS_DEBUG
+ },
+
+ {
+ KBASE_CONFIG_ATTR_JS_SOFT_STOP_TICKS,
+ KBASE_VE_JS_SOFT_STOP_TICKS_DEBUG
+ },
+
+ {
+ KBASE_CONFIG_ATTR_JS_HARD_STOP_TICKS_SS,
+ KBASE_VE_JS_HARD_STOP_TICKS_SS_DEBUG
+ },
+
+ {
+ KBASE_CONFIG_ATTR_JS_HARD_STOP_TICKS_NSS,
+ KBASE_VE_JS_HARD_STOP_TICKS_NSS_DEBUG
+ },
+
+ {
+ KBASE_CONFIG_ATTR_JS_RESET_TICKS_SS,
+ KBASE_VE_JS_RESET_TICKS_SS_DEBUG
+ },
+
+ {
+ KBASE_CONFIG_ATTR_JS_RESET_TICKS_NSS,
+ KBASE_VE_JS_RESET_TICKS_NSS_DEBUG
+ },
+#else /* CONFIG_MALI_DEBUG */
+/* In release builds same as the defaults but scaled for 5MHz FPGA */
+ {
+ KBASE_CONFIG_ATTR_JS_SCHEDULING_TICK_NS,
+ KBASE_VE_JS_SCHEDULING_TICK_NS
+ },
+
+ {
+ KBASE_CONFIG_ATTR_JS_SOFT_STOP_TICKS,
+ KBASE_VE_JS_SOFT_STOP_TICKS
+ },
+
+ {
+ KBASE_CONFIG_ATTR_JS_HARD_STOP_TICKS_SS,
+ KBASE_VE_JS_HARD_STOP_TICKS_SS
+ },
+
+ {
+ KBASE_CONFIG_ATTR_JS_HARD_STOP_TICKS_NSS,
+ KBASE_VE_JS_HARD_STOP_TICKS_NSS
+ },
+
+ {
+ KBASE_CONFIG_ATTR_JS_RESET_TICKS_SS,
+ KBASE_VE_JS_RESET_TICKS_SS
+ },
+
+ {
+ KBASE_CONFIG_ATTR_JS_RESET_TICKS_NSS,
+ KBASE_VE_JS_RESET_TICKS_NSS
+ },
+#endif /* CONFIG_MALI_DEBUG */
+ {
+ KBASE_CONFIG_ATTR_JS_RESET_TIMEOUT_MS,
+ KBASE_VE_JS_RESET_TIMEOUT_MS
+ },
+
+ {
+ KBASE_CONFIG_ATTR_JS_CTX_TIMESLICE_NS,
+ KBASE_VE_JS_CTX_TIMESLICE_NS
+ },
+
+ {
+ KBASE_CONFIG_ATTR_POWER_MANAGEMENT_CALLBACKS,
+ KBASE_VE_POWER_MANAGEMENT_CALLBACKS
+ },
+
+ {
+ KBASE_CONFIG_ATTR_CPU_SPEED_FUNC,
+ KBASE_VE_CPU_SPEED_FUNC
+ },
+
+ {
+ KBASE_CONFIG_ATTR_SECURE_BUT_LOSS_OF_PERFORMANCE,
+ KBASE_VE_SECURE_BUT_LOSS_OF_PERFORMANCE
+ },
+
+ {
+ KBASE_CONFIG_ATTR_GPU_IRQ_THROTTLE_TIME_US,
+ 20
+ },
+
+ {
+ KBASE_CONFIG_ATTR_END,
+ 0
+ }
+};
+
+/* as config_attributes array above except with different settings for
+ * JS_HARD_STOP_TICKS_SS, JS_RESET_TICKS_SS that
+ * are needed for BASE_HW_ISSUE_8408.
+ */
+kbase_attribute config_attributes_hw_issue_8408[] =
+{
+ {
+ KBASE_CONFIG_ATTR_MEMORY_PER_PROCESS_LIMIT,
+ KBASE_VE_MEMORY_PER_PROCESS_LIMIT
+ },
+#ifdef CONFIG_UMP
+ {
+ KBASE_CONFIG_ATTR_UMP_DEVICE,
+ KBASE_VE_UMP_DEVICE
+ },
+#endif /* CONFIG_UMP */
+ {
+ KBASE_CONFIG_ATTR_MEMORY_OS_SHARED_MAX,
+ KBASE_VE_MEMORY_OS_SHARED_MAX
+ },
+
+ {
+ KBASE_CONFIG_ATTR_MEMORY_OS_SHARED_PERF_GPU,
+ KBASE_VE_MEMORY_OS_SHARED_PERF_GPU
+ },
+
+#if T6F1_ZBT_DDR_ENABLED
+ {
+ KBASE_CONFIG_ATTR_MEMORY_RESOURCE,
+ KBASE_VE_MEMORY_RESOURCE_ZBT
+ },
+
+ {
+ KBASE_CONFIG_ATTR_MEMORY_RESOURCE,
+ KBASE_VE_MEMORY_RESOURCE_DDR
+ },
+#endif /* T6F1_ZBT_DDR_ENABLED */
+
+ {
+ KBASE_CONFIG_ATTR_GPU_FREQ_KHZ_MAX,
+ KBASE_VE_GPU_FREQ_KHZ_MAX
+ },
+
+ {
+ KBASE_CONFIG_ATTR_GPU_FREQ_KHZ_MIN,
+ KBASE_VE_GPU_FREQ_KHZ_MIN
+ },
+
+#ifdef CONFIG_MALI_DEBUG
+/* Use more aggressive scheduling timeouts in debug builds for testing purposes */
+ {
+ KBASE_CONFIG_ATTR_JS_SCHEDULING_TICK_NS,
+ KBASE_VE_JS_SCHEDULING_TICK_NS_DEBUG
+ },
+
+ {
+ KBASE_CONFIG_ATTR_JS_SOFT_STOP_TICKS,
+ KBASE_VE_JS_SOFT_STOP_TICKS_DEBUG
+ },
+
+ {
+ KBASE_CONFIG_ATTR_JS_HARD_STOP_TICKS_SS,
+ KBASE_VE_JS_HARD_STOP_TICKS_SS_8401_DEBUG
+ },
+
+ {
+ KBASE_CONFIG_ATTR_JS_HARD_STOP_TICKS_NSS,
+ KBASE_VE_JS_HARD_STOP_TICKS_NSS_DEBUG
+ },
+
+ {
+ KBASE_CONFIG_ATTR_JS_RESET_TICKS_SS,
+ KBASE_VE_JS_RESET_TICKS_SS_8401_DEBUG
+ },
+
+ {
+ KBASE_CONFIG_ATTR_JS_RESET_TICKS_NSS,
+ KBASE_VE_JS_RESET_TICKS_NSS_DEBUG
+ },
+#else /* CONFIG_MALI_DEBUG */
+/* In release builds same as the defaults but scaled for 5MHz FPGA */
+ {
+ KBASE_CONFIG_ATTR_JS_SCHEDULING_TICK_NS,
+ KBASE_VE_JS_SCHEDULING_TICK_NS
+ },
+
+ {
+ KBASE_CONFIG_ATTR_JS_SOFT_STOP_TICKS,
+ KBASE_VE_JS_SOFT_STOP_TICKS
+ },
+
+ {
+ KBASE_CONFIG_ATTR_JS_HARD_STOP_TICKS_SS,
+ KBASE_VE_JS_HARD_STOP_TICKS_SS_8401
+ },
+
+ {
+ KBASE_CONFIG_ATTR_JS_HARD_STOP_TICKS_NSS,
+ KBASE_VE_JS_HARD_STOP_TICKS_NSS
+ },
+
+ {
+ KBASE_CONFIG_ATTR_JS_RESET_TICKS_SS,
+ KBASE_VE_JS_RESET_TICKS_SS_8401
+ },
+
+ {
+ KBASE_CONFIG_ATTR_JS_RESET_TICKS_NSS,
+ KBASE_VE_JS_RESET_TICKS_NSS
+ },
+#endif /* CONFIG_MALI_DEBUG */
+ {
+ KBASE_CONFIG_ATTR_JS_RESET_TIMEOUT_MS,
+ KBASE_VE_JS_RESET_TIMEOUT_MS
+ },
+
+ {
+ KBASE_CONFIG_ATTR_JS_CTX_TIMESLICE_NS,
+ KBASE_VE_JS_CTX_TIMESLICE_NS
+ },
+
+ {
+ KBASE_CONFIG_ATTR_POWER_MANAGEMENT_CALLBACKS,
+ KBASE_VE_POWER_MANAGEMENT_CALLBACKS
+ },
+
+ {
+ KBASE_CONFIG_ATTR_CPU_SPEED_FUNC,
+ KBASE_VE_CPU_SPEED_FUNC
+ },
+
+ {
+ KBASE_CONFIG_ATTR_SECURE_BUT_LOSS_OF_PERFORMANCE,
+ KBASE_VE_SECURE_BUT_LOSS_OF_PERFORMANCE
+ },
+
+ {
+ KBASE_CONFIG_ATTR_END,
+ 0
+ }
+};
+
+kbase_platform_config platform_config =
+{
+ .attributes = config_attributes,
+ .io_resources = &io_resources
+};
+
diff --git a/drivers/gpu/arm/t6xx/kbase/src/linux/config/mali_kbase_cpu_vexpress.c b/drivers/gpu/arm/t6xx/kbase/src/linux/config/mali_kbase_cpu_vexpress.c
new file mode 100644
index 0000000..660877e
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/linux/config/mali_kbase_cpu_vexpress.c
@@ -0,0 +1,174 @@
+/*
+ *
+ * (C) COPYRIGHT 2011-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+#include <linux/io.h>
+#include <kbase/src/common/mali_kbase.h>
+#include "mali_kbase_cpu_vexpress.h"
+
+#define HZ_IN_MHZ (1000000)
+
+#define CORETILE_EXPRESS_A9X4_SCC_START (0x100E2000)
+#define MOTHERBOARD_SYS_CFG_START (0x10000000)
+#define SYS_CFGDATA_OFFSET (0x000000A0)
+#define SYS_CFGCTRL_OFFSET (0x000000A4)
+#define SYS_CFGSTAT_OFFSET (0x000000A8)
+
+#define SYS_CFGCTRL_START_BIT_VALUE (1 << 31)
+#define READ_REG_BIT_VALUE (0 << 30)
+#define DCC_DEFAULT_BIT_VALUE (0 << 26)
+#define SYS_CFG_OSC_FUNC_BIT_VALUE (1 << 20)
+#define SITE_DEFAULT_BIT_VALUE (1 << 16)
+#define BOARD_STACK_POS_DEFAULT_BIT_VALUE (0 << 12)
+#define DEVICE_DEFAULT_BIT_VALUE (2 << 0)
+#define SYS_CFG_COMPLETE_BIT_VALUE (1 << 0)
+#define SYS_CFG_ERROR_BIT_VALUE (1 << 1)
+
+#define FEED_REG_BIT_MASK (0x0F)
+#define FCLK_PA_DIVIDE_BIT_SHIFT (0x03)
+#define FCLK_PB_DIVIDE_BIT_SHIFT (0x07)
+#define FCLK_PC_DIVIDE_BIT_SHIFT (0x0B)
+#define AXICLK_PA_DIVIDE_BIT_SHIFT (0x0F)
+#define AXICLK_PB_DIVIDE_BIT_SHIFT (0x13)
+
+#define IS_SINGLE_BIT_SET(val,pos) (val&(1<<pos))
+
+/**
+ * kbase_get_vendor_specific_cpu_clock_speed
+ * @brief Retrieves the CPU clock speed.
+ * The implementation is platform specific.
+ * @param[in/out] u32* cpu_clock - the value of CPU clock speed in MHz
+ * @return 0 on success, 1 otherwise
+*/
+int kbase_get_vexpress_cpu_clock_speed(u32* cpu_clock)
+{
+ int result = 0;
+ u32 reg_val = 0;
+ u32 osc2_value = 0;
+ u32 pa_divide = 0;
+ u32 pb_divide = 0;
+ u32 pc_divide = 0;
+ void* volatile pSysCfgReg = 0;
+ void* volatile pSCCReg = 0;
+
+ /* Init the value case something goes wrong */
+ *cpu_clock = 0;
+
+ /* Map CPU register into virtual memory */
+ pSysCfgReg = ioremap(MOTHERBOARD_SYS_CFG_START, 0x1000);
+ if (pSysCfgReg == NULL)
+ {
+ result = 1;
+
+ goto pSysCfgReg_map_failed;
+ }
+
+ pSCCReg = ioremap(CORETILE_EXPRESS_A9X4_SCC_START, 0x1000);
+ if (pSCCReg == NULL)
+ {
+ result = 1;
+
+ goto pSCCReg_map_failed;
+ }
+
+ /*Read SYS regs - OSC2*/
+ reg_val = readl(pSysCfgReg + SYS_CFGCTRL_OFFSET);
+
+ /*Verify if there is no other undergoing request*/
+ if(!(reg_val&SYS_CFGCTRL_START_BIT_VALUE ))
+ {
+ /*Reset the CGFGSTAT reg*/
+ writel(0,(pSysCfgReg + SYS_CFGSTAT_OFFSET));
+
+ writel( SYS_CFGCTRL_START_BIT_VALUE | READ_REG_BIT_VALUE | DCC_DEFAULT_BIT_VALUE |
+ SYS_CFG_OSC_FUNC_BIT_VALUE | SITE_DEFAULT_BIT_VALUE |
+ BOARD_STACK_POS_DEFAULT_BIT_VALUE | DEVICE_DEFAULT_BIT_VALUE,
+ (pSysCfgReg + SYS_CFGCTRL_OFFSET));
+ /* Wait for the transaction to complete */
+ while( !(readl(pSysCfgReg + SYS_CFGSTAT_OFFSET)&SYS_CFG_COMPLETE_BIT_VALUE));
+ /* Read SYS_CFGSTAT Register to get the status of submitted transaction*/
+ reg_val = readl(pSysCfgReg + SYS_CFGSTAT_OFFSET);
+
+ /*------------------------------------------------------------------------------------------*/
+ /* Check for possible errors*/
+ if(reg_val & SYS_CFG_ERROR_BIT_VALUE)
+ {
+ /* Error while setting register*/
+ result = 1;
+ }
+ else
+ {
+ osc2_value = readl(pSysCfgReg + SYS_CFGDATA_OFFSET );
+ /* Read the SCC CFGRW0 register*/
+ reg_val = readl(pSCCReg);
+
+ /*
+ Select the appropriate feed:
+ CFGRW0[0] - CLKOB
+ CFGRW0[1] - CLKOC
+ CFGRW0[2] - FACLK (CLK)B FROM AXICLK PLL)
+ */
+ /* Calculate the FCLK*/
+ if(IS_SINGLE_BIT_SET(reg_val,0)) /*CFGRW0[0] - CLKOB*/
+ {
+ /* CFGRW0[6:3]*/
+ pa_divide =((reg_val&(FEED_REG_BIT_MASK<<FCLK_PA_DIVIDE_BIT_SHIFT))>>FCLK_PA_DIVIDE_BIT_SHIFT);
+ /* CFGRW0[10:7]*/
+ pb_divide =((reg_val&(FEED_REG_BIT_MASK<<FCLK_PB_DIVIDE_BIT_SHIFT))>>FCLK_PB_DIVIDE_BIT_SHIFT);
+ *cpu_clock = osc2_value * (pa_divide + 1) / (pb_divide +1);
+ }
+ else
+ {
+ if(IS_SINGLE_BIT_SET(reg_val,1))/*CFGRW0[1] - CLKOC*/
+ {
+ /* CFGRW0[6:3]*/
+ pa_divide = ((reg_val&(FEED_REG_BIT_MASK<<FCLK_PA_DIVIDE_BIT_SHIFT))>>FCLK_PA_DIVIDE_BIT_SHIFT);
+ /* CFGRW0[14:11]*/
+ pc_divide = ((reg_val&(FEED_REG_BIT_MASK<<FCLK_PC_DIVIDE_BIT_SHIFT)) >> FCLK_PC_DIVIDE_BIT_SHIFT);
+ *cpu_clock = osc2_value * (pa_divide + 1) / (pc_divide + 1);
+ }
+ else
+ if(IS_SINGLE_BIT_SET(reg_val,2))/*CFGRW0[2] - FACLK*/
+ {
+ /* CFGRW0[18:15]*/
+ pa_divide = ((reg_val&(FEED_REG_BIT_MASK<<AXICLK_PA_DIVIDE_BIT_SHIFT)) >>AXICLK_PA_DIVIDE_BIT_SHIFT);
+ /* CFGRW0[22:19]*/
+ pb_divide = ((reg_val&(FEED_REG_BIT_MASK<<AXICLK_PB_DIVIDE_BIT_SHIFT))>>AXICLK_PB_DIVIDE_BIT_SHIFT);
+ *cpu_clock = osc2_value * (pa_divide + 1) / (pb_divide +1);
+ }
+ else
+ {
+ result = 1;
+ }
+ }
+ }
+ }
+ else
+ {
+ result = 1;
+ }
+
+ /* Convert result expressed in Hz to Mhz units.*/
+ *cpu_clock /= HZ_IN_MHZ;
+
+ /* Unmap memory*/
+ iounmap(pSCCReg);
+
+pSCCReg_map_failed:
+ iounmap(pSysCfgReg);
+
+pSysCfgReg_map_failed:
+ return result;
+}
+
+
diff --git a/drivers/gpu/arm/t6xx/kbase/src/linux/config/mali_kbase_cpu_vexpress.h b/drivers/gpu/arm/t6xx/kbase/src/linux/config/mali_kbase_cpu_vexpress.h
new file mode 100644
index 0000000..95aff02
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/linux/config/mali_kbase_cpu_vexpress.h
@@ -0,0 +1,24 @@
+/*
+ *
+ * (C) COPYRIGHT 2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+#ifndef _KBASE_CPU_VEXPRESS_H_
+#define _KBASE_CPU_VEXPRESS_H_
+
+/**
+ * Versatile Express implementation of @ref kbase_cpuprops_clock_speed_function.
+ */
+int kbase_get_vexpress_cpu_clock_speed(u32* cpu_clock);
+
+#endif /* _KBASE_CPU_VEXPRESS_H_ */
+
diff --git a/drivers/gpu/arm/t6xx/kbase/src/linux/config/tpip/mali_kbase_config_exynos5.c b/drivers/gpu/arm/t6xx/kbase/src/linux/config/tpip/mali_kbase_config_exynos5.c
new file mode 100644
index 0000000..2a773f1
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/linux/config/tpip/mali_kbase_config_exynos5.c
@@ -0,0 +1,251 @@
+/*
+ *
+ * (C) COPYRIGHT 2011 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <linux/ioport.h>
+#include <linux/clk.h>
+#include <kbase/src/common/mali_kbase.h>
+#include <kbase/src/common/mali_kbase_defs.h>
+#include <kbase/src/linux/mali_kbase_config_linux.h>
+#include <mach/map.h>
+#include <plat/devs.h>
+#include <linux/pm_runtime.h>
+#include <kbase/src/platform/mali_kbase_platform.h>
+#include <linux/suspend.h>
+#include <kbase/src/platform/mali_kbase_dvfs.h>
+
+#define HZ_IN_MHZ (1000000)
+#ifdef CONFIG_MALI_T6XX_RT_PM
+#define RUNTIME_PM_DELAY_TIME 100
+#endif
+
+static int mali_pm_notifier(struct notifier_block *nb,unsigned long event,void* cmd);
+static struct notifier_block mali_pm_nb = {
+ .notifier_call = mali_pm_notifier
+};
+
+static kbase_io_resources io_resources =
+{
+ .job_irq_number = JOB_IRQ_NUMBER,
+ .mmu_irq_number = MMU_IRQ_NUMBER,
+ .gpu_irq_number = GPU_IRQ_NUMBER,
+ .io_memory_region =
+ {
+ .start = EXYNOS5_PA_G3D,
+ .end = EXYNOS5_PA_G3D+ (4096 * 5) - 1
+ }
+};
+
+int get_cpu_clock_speed(u32* cpu_clock)
+{
+ struct clk * cpu_clk;
+ u32 freq=0;
+ cpu_clk = clk_get(NULL, "armclk");
+ if (IS_ERR(cpu_clk))
+ return 1;
+ freq = clk_get_rate(cpu_clk);
+ *cpu_clock = (freq/HZ_IN_MHZ);
+ return 0;
+}
+
+static int mali_pm_notifier(struct notifier_block *nb,unsigned long event,void* cmd)
+{
+ int err = NOTIFY_OK;
+ switch (event) {
+ case PM_SUSPEND_PREPARE:
+#ifdef CONFIG_MALI_T6XX_DVFS
+ if (kbase_platform_dvfs_enable(false, MALI_DVFS_BL_CONFIG_FREQ)!= MALI_TRUE)
+ err = NOTIFY_BAD;
+#endif
+ break;
+ case PM_POST_SUSPEND:
+#ifdef CONFIG_MALI_T6XX_DVFS
+ if (kbase_platform_dvfs_enable(true, MALI_DVFS_START_FREQ)!= MALI_TRUE)
+ err = NOTIFY_BAD;
+#endif
+ break;
+ default:
+ break;
+ }
+ return err;
+}
+
+/**
+ * * Exynos5 hardware specific initialization
+ * */
+mali_bool kbase_platform_exynos5_init(kbase_device *kbdev)
+{
+ if(MALI_ERROR_NONE == kbase_platform_init(kbdev))
+ {
+ if (register_pm_notifier(&mali_pm_nb)) {
+ return MALI_FALSE;
+ }
+ return MALI_TRUE;
+ }
+
+ return MALI_FALSE;
+}
+
+/**
+ * * Exynos5 hardware specific termination
+ * */
+void kbase_platform_exynos5_term(kbase_device *kbdev)
+{
+ unregister_pm_notifier(&mali_pm_nb);
+#ifdef CONFIG_MALI_T6XX_DEBUG_SYS
+ kbase_platform_remove_sysfs_file(kbdev->osdev.dev);
+#endif /* CONFIG_MALI_T6XX_DEBUG_SYS */
+ kbase_platform_term(kbdev);
+}
+kbase_platform_funcs_conf platform_funcs =
+{
+ .platform_init_func = &kbase_platform_exynos5_init,
+ .platform_term_func = &kbase_platform_exynos5_term,
+};
+
+#ifdef CONFIG_MALI_T6XX_RT_PM
+static int pm_callback_power_on(kbase_device *kbdev)
+{
+ int result;
+ int ret_val;
+ struct kbase_os_device *osdev = &kbdev->osdev;
+ struct exynos_context *platform;
+
+ platform = (struct exynos_context *) kbdev->platform_context;
+
+ if (pm_runtime_status_suspended(osdev->dev))
+ ret_val = 1;
+ else
+ ret_val = 0;
+
+ if(osdev->dev->power.disable_depth > 0) {
+ if(platform->cmu_pmu_status == 0)
+ kbase_platform_cmu_pmu_control(kbdev, 1);
+ return ret_val;
+ }
+ result = pm_runtime_resume(osdev->dev);
+
+ if(result < 0 && result == -EAGAIN)
+ kbase_platform_cmu_pmu_control(kbdev, 1);
+ else if(result < 0)
+ OSK_PRINT_ERROR(OSK_BASE_PM, "pm_runtime_get_sync failed (%d)\n", result);
+
+ return ret_val;
+}
+
+static void pm_callback_power_off(kbase_device *kbdev)
+{
+ struct kbase_os_device *osdev = &kbdev->osdev;
+ pm_schedule_suspend(osdev->dev, RUNTIME_PM_DELAY_TIME);
+}
+
+mali_error kbase_device_runtime_init(struct kbase_device *kbdev)
+{
+ pm_suspend_ignore_children(kbdev->osdev.dev, true);
+ pm_runtime_enable(kbdev->osdev.dev);
+#ifdef CONFIG_MALI_T6XX_DEBUG_SYS
+ if(kbase_platform_create_sysfs_file(kbdev->osdev.dev)) {
+ return MALI_ERROR_FUNCTION_FAILED;
+ }
+#endif /* CONFIG_MALI_T6XX_DEBUG_SYS */
+ return MALI_ERROR_NONE;
+}
+
+void kbase_device_runtime_disable(struct kbase_device *kbdev)
+{
+ pm_runtime_disable(kbdev->osdev.dev);
+}
+
+static int pm_callback_runtime_on(kbase_device *kbdev)
+{
+ kbase_platform_clock_on(kbdev);
+#ifdef CONFIG_MALI_T6XX_DVFS
+ if (kbase_platform_dvfs_enable(true, MALI_DVFS_START_FREQ)!= MALI_TRUE)
+ return -EPERM;
+#endif
+ return 0;
+}
+
+static void pm_callback_runtime_off(kbase_device *kbdev)
+{
+ kbase_platform_clock_off(kbdev);
+#ifdef CONFIG_MALI_T6XX_DVFS
+ if (kbase_platform_dvfs_enable(false, MALI_DVFS_CURRENT_FREQ)!= MALI_TRUE)
+ printk("[err] disabling dvfs is faled\n");
+#endif
+}
+
+static kbase_pm_callback_conf pm_callbacks =
+{
+ .power_on_callback = pm_callback_power_on,
+ .power_off_callback = pm_callback_power_off,
+#ifdef CONFIG_PM_RUNTIME
+ .power_runtime_init_callback = kbase_device_runtime_init,
+ .power_runtime_term_callback = kbase_device_runtime_disable,
+ .power_runtime_on_callback = pm_callback_runtime_on,
+ .power_runtime_off_callback = pm_callback_runtime_off,
+#else /* CONFIG_PM_RUNTIME */
+ .power_runtime_init_callback = NULL,
+ .power_runtime_term_callback = NULL,
+ .power_runtime_on_callback = NULL,
+ .power_runtime_off_callback = NULL,
+#endif /* CONFIG_PM_RUNTIME */
+};
+#endif
+
+static kbase_attribute config_attributes[] = {
+ {
+ KBASE_CONFIG_ATTR_MEMORY_OS_SHARED_MAX,
+ 2048 * 1024 * 1024UL /* 2048MB */
+ },
+ {
+ KBASE_CONFIG_ATTR_MEMORY_OS_SHARED_PERF_GPU,
+ KBASE_MEM_PERF_FAST
+ },
+#ifdef CONFIG_MALI_T6XX_RT_PM
+ {
+ KBASE_CONFIG_ATTR_POWER_MANAGEMENT_CALLBACKS,
+ (uintptr_t)&pm_callbacks
+ },
+#endif
+ {
+ KBASE_CONFIG_ATTR_PLATFORM_FUNCS,
+ (uintptr_t)&platform_funcs
+ },
+ {
+ KBASE_CONFIG_ATTR_GPU_FREQ_KHZ_MAX,
+ 533000
+ },
+
+ {
+ KBASE_CONFIG_ATTR_GPU_FREQ_KHZ_MIN,
+ 100000
+ },
+ {
+ KBASE_CONFIG_ATTR_JS_RESET_TIMEOUT_MS,
+ 500 /* 500ms before cancelling stuck jobs */
+ },
+ {
+ KBASE_CONFIG_ATTR_CPU_SPEED_FUNC,
+ (uintptr_t)&get_cpu_clock_speed
+ },
+ {
+ KBASE_CONFIG_ATTR_END,
+ 0
+ }
+};
+
+kbase_platform_config platform_config =
+{
+ .attributes = config_attributes,
+ .io_resources = &io_resources,
+ .midgard_type = KBASE_MALI_T604
+};
diff --git a/drivers/gpu/arm/t6xx/kbase/src/linux/mali_kbase_config_linux.c b/drivers/gpu/arm/t6xx/kbase/src/linux/mali_kbase_config_linux.c
new file mode 100644
index 0000000..29b5d334
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/linux/mali_kbase_config_linux.c
@@ -0,0 +1,40 @@
+/*
+ *
+ * (C) COPYRIGHT 2011-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+#include <kbase/src/linux/mali_kbase_config_linux.h>
+#include <osk/mali_osk.h>
+
+#ifdef CONFIG_MALI_PLATFORM_FAKE
+
+void kbasep_config_parse_io_resources(const kbase_io_resources *io_resources, struct resource *linux_resources)
+{
+ OSK_ASSERT(io_resources != NULL);
+ OSK_ASSERT(linux_resources != NULL);
+
+ memset(linux_resources, 0, PLATFORM_CONFIG_RESOURCE_COUNT * sizeof(struct resource));
+
+ linux_resources[0].start = io_resources->io_memory_region.start;
+ linux_resources[0].end = io_resources->io_memory_region.end;
+ linux_resources[0].flags = IORESOURCE_MEM;
+
+ linux_resources[1].start = linux_resources[1].end = io_resources->job_irq_number;
+ linux_resources[1].flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL;
+
+ linux_resources[2].start = linux_resources[2].end = io_resources->mmu_irq_number;
+ linux_resources[2].flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL;
+
+ linux_resources[3].start = linux_resources[3].end = io_resources->gpu_irq_number;
+ linux_resources[3].flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL;
+}
+
+#endif /* CONFIG_MALI_PLATFORM_FAKE */
diff --git a/drivers/gpu/arm/t6xx/kbase/src/linux/mali_kbase_config_linux.h b/drivers/gpu/arm/t6xx/kbase/src/linux/mali_kbase_config_linux.h
new file mode 100644
index 0000000..00a5efd
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/linux/mali_kbase_config_linux.h
@@ -0,0 +1,39 @@
+/*
+ *
+ * (C) COPYRIGHT 2011-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+#ifndef _KBASE_CONFIG_LINUX_H_
+#define _KBASE_CONFIG_LINUX_H_
+
+#include <kbase/mali_kbase_config.h>
+#include <linux/ioport.h>
+
+#define PLATFORM_CONFIG_RESOURCE_COUNT 4
+#define PLATFORM_CONFIG_IRQ_RES_COUNT 3
+
+#ifdef CONFIG_MALI_PLATFORM_FAKE
+/**
+ * @brief Convert data in kbase_io_resources struct to Linux-specific resources
+ *
+ * Function converts data in kbase_io_resources struct to an array of Linux resource structures. Note that function
+ * assumes that size of linux_resource array is at least PLATFORM_CONFIG_RESOURCE_COUNT.
+ * Resources are put in fixed order: I/O memory region, job IRQ, MMU IRQ, GPU IRQ.
+ *
+ * @param[in] io_resource Input IO resource data
+ * @param[out] linux_resources Pointer to output array of Linux resource structures
+ */
+void kbasep_config_parse_io_resources(const kbase_io_resources *io_resource, struct resource *linux_resources);
+#endif /* CONFIG_MALI_PLATFORM_FAKE */
+
+
+#endif /* _KBASE_CONFIG_LINUX_H_ */
diff --git a/drivers/gpu/arm/t6xx/kbase/src/linux/mali_kbase_core_linux.c b/drivers/gpu/arm/t6xx/kbase/src/linux/mali_kbase_core_linux.c
new file mode 100644
index 0000000..0b207f9
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/linux/mali_kbase_core_linux.c
@@ -0,0 +1,2751 @@
+/*
+ *
+ * (C) COPYRIGHT 2010-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_kbase_core_linux.c
+ * Base kernel driver init.
+ */
+
+#include <osk/mali_osk.h>
+#include <kbase/src/common/mali_kbase.h>
+#include <kbase/src/common/mali_kbase_uku.h>
+#include <kbase/src/common/mali_midg_regmap.h>
+#include <kbase/src/linux/mali_kbase_mem_linux.h>
+#include <kbase/src/linux/mali_kbase_config_linux.h>
+#include <kbase/mali_ukk.h>
+#ifdef CONFIG_MALI_NO_MALI
+#include "mali_kbase_model_linux.h"
+#endif /* CONFIG_MALI_NO_MALI */
+
+#ifdef CONFIG_KDS
+#include <linux/kds.h>
+#include <linux/anon_inodes.h>
+#include <linux/syscalls.h>
+#endif /* CONFIG_KDS */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/miscdevice.h>
+#include <linux/list.h>
+#include <linux/semaphore.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/compat.h> /* is_compat_task */
+#include <kbase/src/common/mali_kbase_8401_workaround.h>
+#include <kbase/src/common/mali_kbase_hw.h>
+#ifdef CONFIG_SYNC
+#include <kbase/src/linux/mali_kbase_sync.h>
+#endif /* CONFIG_SYNC */
+
+#ifdef CONFIG_MALI_PLATFORM_THIRDPARTY
+#include <plat/devs.h>
+#endif
+
+#define JOB_IRQ_TAG 0
+#define MMU_IRQ_TAG 1
+#define GPU_IRQ_TAG 2
+
+struct kbase_irq_table
+{
+ u32 tag;
+ irq_handler_t handler;
+};
+#if MALI_UNIT_TEST
+kbase_exported_test_data shared_kernel_test_data;
+EXPORT_SYMBOL(shared_kernel_test_data);
+#endif /* MALI_UNIT_TEST */
+
+#define KBASE_DRV_NAME "mali"
+
+static const char kbase_drv_name[] = KBASE_DRV_NAME;
+
+static int kbase_dev_nr;
+
+static DEFINE_SEMAPHORE(kbase_dev_list_lock);
+static LIST_HEAD(kbase_dev_list);
+
+KBASE_EXPORT_TEST_API(kbase_dev_list_lock)
+KBASE_EXPORT_TEST_API(kbase_dev_list)
+
+#define KERNEL_SIDE_DDK_VERSION_STRING "K:" MALI_RELEASE_NAME "(GPL)"
+
+static INLINE void __compile_time_asserts( void )
+{
+ CSTD_COMPILE_TIME_ASSERT( sizeof(KERNEL_SIDE_DDK_VERSION_STRING) <= KBASE_GET_VERSION_BUFFER_SIZE);
+}
+
+#ifdef CONFIG_KDS
+
+typedef struct kbasep_kds_resource_set_file_data
+{
+ struct kds_resource_set * lock;
+}kbasep_kds_resource_set_file_data;
+
+static int kds_resource_release(struct inode *inode, struct file *file);
+
+static const struct file_operations kds_resource_fops =
+{
+ .release = kds_resource_release
+};
+
+typedef struct kbase_kds_resource_list_data
+{
+ struct kds_resource ** kds_resources;
+ unsigned long * kds_access_bitmap;
+ int num_elems;
+}kbase_kds_resource_list_data;
+
+
+static int kds_resource_release(struct inode *inode, struct file *file)
+{
+ struct kbasep_kds_resource_set_file_data *data;
+
+ data = (struct kbasep_kds_resource_set_file_data *)file->private_data;
+ if ( NULL != data )
+ {
+ if ( NULL != data->lock )
+ {
+ kds_resource_set_release( &data->lock );
+ }
+ kfree( data );
+ }
+ return 0;
+}
+
+mali_error kbasep_kds_allocate_resource_list_data( kbase_context * kctx,
+ base_external_resource *ext_res,
+ int num_elems,
+ kbase_kds_resource_list_data * resources_list )
+{
+ base_external_resource *res = ext_res;
+ int res_id;
+
+ /* assume we have to wait for all */
+
+ if(OSK_SIMULATE_FAILURE(OSK_OSK))
+ {
+ resources_list->kds_resources = NULL;
+ }
+ else
+ {
+ OSK_ASSERT(0 != num_elems);
+ resources_list->kds_resources = kmalloc(sizeof(struct kds_resource *) * num_elems, GFP_KERNEL);
+ }
+
+ if ( NULL == resources_list->kds_resources )
+ {
+ return MALI_ERROR_OUT_OF_MEMORY;
+ }
+
+ if(OSK_SIMULATE_FAILURE(OSK_OSK))
+ {
+ resources_list->kds_access_bitmap = NULL;
+ }
+ else
+ {
+ OSK_ASSERT(0 != num_elems);
+ resources_list->kds_access_bitmap = kzalloc(sizeof(unsigned long) * ((num_elems + OSK_BITS_PER_LONG - 1) / OSK_BITS_PER_LONG), GFP_KERNEL);
+ }
+
+ if (NULL == resources_list->kds_access_bitmap)
+ {
+ kfree(resources_list->kds_access_bitmap);
+ return MALI_ERROR_OUT_OF_MEMORY;
+ }
+
+ for (res_id = 0; res_id < num_elems; res_id++, res++ )
+ {
+ int exclusive;
+ kbase_va_region * reg;
+ struct kds_resource * kds_res = NULL;
+
+ exclusive = res->ext_resource & BASE_EXT_RES_ACCESS_EXCLUSIVE;
+ reg = kbase_region_tracker_find_region_enclosing_address(kctx, res->ext_resource & ~BASE_EXT_RES_ACCESS_EXCLUSIVE);
+
+ /* did we find a matching region object? */
+ if (NULL == reg)
+ {
+ break;
+ }
+
+ switch (reg->imported_type)
+ {
+#if defined(CONFIG_UMP) && defined(CONFIG_KDS)
+ case BASE_TMEM_IMPORT_TYPE_UMP:
+ kds_res = ump_dd_kds_resource_get(reg->imported_metadata.ump_handle);
+ break;
+#endif /* defined(CONFIG_UMP) && defined(CONFIG_KDS) */
+ default:
+ break;
+ }
+
+ /* no kds resource for the region ? */
+ if (!kds_res)
+ {
+ break;
+ }
+
+ resources_list->kds_resources[res_id] = kds_res;
+
+ if (exclusive)
+ {
+ osk_bitarray_set_bit(res_id, resources_list->kds_access_bitmap);
+ }
+ }
+
+ /* did the loop run to completion? */
+ if (res_id == num_elems)
+ {
+ return MALI_ERROR_NONE;
+ }
+
+ /* Clean up as the resource list is not valid. */
+ kfree( resources_list->kds_resources );
+ kfree( resources_list->kds_access_bitmap );
+
+ return MALI_ERROR_FUNCTION_FAILED;
+}
+
+mali_bool kbasep_validate_kbase_pointer( kbase_pointer * p )
+{
+#ifdef CONFIG_COMPAT
+ if (is_compat_task())
+ {
+ if ( p->compat_value == 0 )
+ {
+ return MALI_FALSE;
+ }
+ }
+ else
+ {
+#endif /* CONFIG_COMPAT */
+ if ( NULL == p->value )
+ {
+ return MALI_FALSE;
+ }
+#ifdef CONFIG_COMPAT
+ }
+#endif /* CONFIG_COMPAT */
+ return MALI_TRUE;
+}
+
+mali_error kbase_external_buffer_lock(kbase_context * kctx, ukk_call_context *ukk_ctx, kbase_uk_ext_buff_kds_data *args, u32 args_size)
+{
+ base_external_resource *ext_res_copy;
+ size_t ext_resource_size;
+ mali_error return_error = MALI_ERROR_FUNCTION_FAILED;
+ int fd;
+
+ if (args_size != sizeof(kbase_uk_ext_buff_kds_data))
+ {
+ return MALI_ERROR_FUNCTION_FAILED;
+ }
+
+ /* Check user space has provided valid data */
+ if ( !kbasep_validate_kbase_pointer(&args->external_resource) ||
+ !kbasep_validate_kbase_pointer(&args->file_descriptor) ||
+ (0 == args->num_res) || (args->num_res > KBASE_MAXIMUM_EXT_RESOURCES) )
+ {
+ return MALI_ERROR_FUNCTION_FAILED;
+ }
+
+ ext_resource_size = sizeof( base_external_resource ) * args->num_res;
+
+ if(OSK_SIMULATE_FAILURE(OSK_OSK))
+ {
+ ext_res_copy = NULL;
+ }
+ else
+ {
+ OSK_ASSERT(0 != ext_resource_size);
+ ext_res_copy = (base_external_resource *)kmalloc( ext_resource_size, GFP_KERNEL );
+ }
+
+ if ( NULL != ext_res_copy )
+ {
+ base_external_resource * __user ext_res_user;
+ int * __user file_descriptor_user;
+#ifdef CONFIG_COMPAT
+ if (is_compat_task())
+ {
+ ext_res_user = args->external_resource.compat_value;
+ file_descriptor_user = args->file_descriptor.compat_value;
+ }
+ else
+ {
+#endif /* CONFIG_COMPAT */
+ ext_res_user = args->external_resource.value;
+ file_descriptor_user = args->file_descriptor.value;
+#ifdef CONFIG_COMPAT
+ }
+#endif /* CONFIG_COMPAT */
+
+ /* Copy the external resources to lock from user space */
+ if ( MALI_ERROR_NONE == ukk_copy_from_user( ext_resource_size, ext_res_copy, ext_res_user ) )
+ {
+ kbasep_kds_resource_set_file_data * fdata;
+
+ /* Allocate data to be stored in the file */
+ if(OSK_SIMULATE_FAILURE(OSK_OSK))
+ {
+ fdata = NULL;
+ }
+ else
+ {
+ fdata = kmalloc( sizeof( kbasep_kds_resource_set_file_data), GFP_KERNEL);
+ }
+
+ if ( NULL != fdata )
+ {
+ kbase_kds_resource_list_data resource_list_data;
+ /* Parse given elements and create resource and access lists */
+ return_error = kbasep_kds_allocate_resource_list_data( kctx, ext_res_copy, args->num_res, &resource_list_data );
+ if ( MALI_ERROR_NONE == return_error )
+ {
+ fdata->lock = NULL;
+
+ fd = anon_inode_getfd( "kds_ext", &kds_resource_fops, fdata, 0 );
+
+ return_error = ukk_copy_to_user( sizeof( fd ), file_descriptor_user, &fd );
+
+ /* If the file descriptor was valid and we successfully copied it to user space, then we
+ * can try and lock the requested kds resources.
+ */
+ if ( ( fd >= 0 ) && ( MALI_ERROR_NONE == return_error ) )
+ {
+ struct kds_resource_set * lock;
+
+ lock = kds_waitall(args->num_res,
+ resource_list_data.kds_access_bitmap,
+ resource_list_data.kds_resources, KDS_WAIT_BLOCKING );
+
+ if (IS_ERR_OR_NULL(lock))
+ {
+ return_error = MALI_ERROR_FUNCTION_FAILED;
+ }
+ else
+ {
+ return_error = MALI_ERROR_NONE;
+ fdata->lock = lock;
+ }
+ }
+ else
+ {
+ return_error = MALI_ERROR_FUNCTION_FAILED;
+ }
+
+ kfree( resource_list_data.kds_resources );
+ kfree( resource_list_data.kds_access_bitmap );
+ }
+
+ if ( MALI_ERROR_NONE != return_error )
+ {
+ /* If the file was opened successfully then close it which will clean up
+ * the file data, otherwise we clean up the file data ourself. */
+ if ( fd >= 0 )
+ {
+ sys_close(fd);
+ }
+ else
+ {
+ kfree( fdata );
+ }
+ }
+ }
+ else
+ {
+ return_error = MALI_ERROR_OUT_OF_MEMORY;
+ }
+ }
+ kfree( ext_res_copy );
+ }
+ return return_error;
+}
+#endif /* CONFIG_KDS */
+
+static mali_error kbase_dispatch(ukk_call_context * const ukk_ctx, void * const args, u32 args_size)
+{
+ kbase_context *kctx;
+ struct kbase_device *kbdev;
+ uk_header *ukh = args;
+ u32 id;
+
+ OSKP_ASSERT( ukh != NULL );
+
+ kctx = container_of(ukk_session_get(ukk_ctx), kbase_context, ukk_session);
+ kbdev = kctx->kbdev;
+ id = ukh->id;
+ ukh->ret = MALI_ERROR_NONE; /* Be optimistic */
+
+ if (!atomic_read(&kctx->setup_complete))
+ {
+ /* setup pending, try to signal that we'll do the setup */
+ if (atomic_cmpxchg(&kctx->setup_in_progress, 0, 1))
+ {
+ /* setup was already in progress, err this call */
+ return MALI_ERROR_FUNCTION_FAILED;
+ }
+
+ /* we're the one doing setup */
+
+ /* is it the only call we accept? */
+ if (id == KBASE_FUNC_SET_FLAGS)
+ {
+ kbase_uk_set_flags *kbase_set_flags = (kbase_uk_set_flags *)args;
+
+ if (sizeof(*kbase_set_flags) != args_size)
+ {
+ /* not matching the expected call, stay stuck in setup mode */
+ goto bad_size;
+ }
+
+ if (MALI_ERROR_NONE != kbase_context_set_create_flags(kctx, kbase_set_flags->create_flags))
+ {
+ ukh->ret = MALI_ERROR_FUNCTION_FAILED;
+ /* bad flags, will stay stuck in setup mode */
+ return MALI_ERROR_NONE;
+ }
+ else
+ {
+ /* we've done the setup, all OK */
+ atomic_set(&kctx->setup_complete, 1);
+ return MALI_ERROR_NONE;
+ }
+ }
+ else
+ {
+ /* unexpected call, will stay stuck in setup mode */
+ return MALI_ERROR_FUNCTION_FAILED;
+ }
+ }
+
+ /* setup complete, perform normal operation */
+ switch(id)
+ {
+ case KBASE_FUNC_TMEM_ALLOC:
+ {
+ kbase_uk_tmem_alloc *tmem = args;
+ struct kbase_va_region *reg;
+
+ if (sizeof(*tmem) != args_size)
+ {
+ goto bad_size;
+ }
+
+ reg = kbase_tmem_alloc(kctx, tmem->vsize, tmem->psize,
+ tmem->extent, tmem->flags, tmem->is_growable);
+ if (reg)
+ {
+ tmem->gpu_addr = reg->start_pfn << PAGE_SHIFT;
+ }
+ else
+ {
+ ukh->ret = MALI_ERROR_FUNCTION_FAILED;
+ }
+ break;
+ }
+
+ case KBASE_FUNC_TMEM_IMPORT:
+ {
+ kbase_uk_tmem_import * tmem_import = args;
+ struct kbase_va_region *reg;
+ int * __user phandle;
+ int handle;
+
+ if (sizeof(*tmem_import) != args_size)
+ {
+ goto bad_size;
+ }
+#ifdef CONFIG_COMPAT
+ if (is_compat_task())
+ {
+ phandle = tmem_import->phandle.compat_value;
+ }
+ else
+ {
+#endif /* CONFIG_COMPAT */
+ phandle = tmem_import->phandle.value;
+#ifdef CONFIG_COMPAT
+ }
+#endif /* CONFIG_COMPAT */
+
+ /* code should be in kbase_tmem_import and its helpers, but uk dropped its get_user abstraction */
+ switch (tmem_import->type)
+ {
+#ifdef CONFIG_UMP
+ case BASE_TMEM_IMPORT_TYPE_UMP:
+ get_user(handle, phandle);
+ break;
+#endif /* CONFIG_UMP */
+ case BASE_TMEM_IMPORT_TYPE_UMM:
+ get_user(handle, phandle);
+ break;
+ default:
+ goto bad_type;
+ break;
+ }
+
+ reg = kbase_tmem_import(kctx, tmem_import->type, handle, &tmem_import->pages);
+
+ if (reg)
+ {
+ tmem_import->gpu_addr = reg->start_pfn << PAGE_SHIFT;
+ }
+ else
+ {
+bad_type:
+ ukh->ret = MALI_ERROR_FUNCTION_FAILED;
+ }
+ break;
+ }
+ case KBASE_FUNC_PMEM_ALLOC:
+ {
+ kbase_uk_pmem_alloc *pmem = args;
+ struct kbase_va_region *reg;
+
+ if (sizeof(*pmem) != args_size)
+ {
+ goto bad_size;
+ }
+
+ reg = kbase_pmem_alloc(kctx, pmem->vsize, pmem->flags,
+ &pmem->cookie);
+ if (!reg)
+ {
+ ukh->ret = MALI_ERROR_FUNCTION_FAILED;
+ }
+ break;
+ }
+
+ case KBASE_FUNC_MEM_FREE:
+ {
+ kbase_uk_mem_free *mem = args;
+
+ if (sizeof(*mem) != args_size)
+ {
+ goto bad_size;
+ }
+
+ if ((mem->gpu_addr & BASE_MEM_TAGS_MASK)&&(mem->gpu_addr >= PAGE_SIZE))
+ {
+ OSK_PRINT_WARN(OSK_BASE_MEM, "kbase_dispatch case KBASE_FUNC_MEM_FREE: mem->gpu_addr: passed parameter is invalid");
+ ukh->ret = MALI_ERROR_FUNCTION_FAILED;
+ break;
+ }
+
+ if (kbase_mem_free(kctx, mem->gpu_addr))
+ {
+ ukh->ret = MALI_ERROR_FUNCTION_FAILED;
+ }
+ break;
+ }
+
+ case KBASE_FUNC_JOB_SUBMIT:
+ {
+ kbase_uk_job_submit * job = args;
+
+ if (sizeof(*job) != args_size)
+ {
+ goto bad_size;
+ }
+
+ if (MALI_ERROR_NONE != kbase_jd_submit(kctx, job))
+ {
+ ukh->ret = MALI_ERROR_FUNCTION_FAILED;
+ }
+ break;
+ }
+
+ case KBASE_FUNC_SYNC:
+ {
+ kbase_uk_sync_now *sn = args;
+
+ if (sizeof(*sn) != args_size)
+ {
+ goto bad_size;
+ }
+
+ if (sn->sset.basep_sset.mem_handle & BASE_MEM_TAGS_MASK)
+ {
+ OSK_PRINT_WARN(OSK_BASE_MEM, "kbase_dispatch case KBASE_FUNC_SYNC: sn->sset.basep_sset.mem_handle: passed parameter is invalid");
+ ukh->ret = MALI_ERROR_FUNCTION_FAILED;
+ break;
+ }
+
+ if (MALI_ERROR_NONE != kbase_sync_now(kctx, &sn->sset))
+ {
+ ukh->ret = MALI_ERROR_FUNCTION_FAILED;
+ }
+ break;
+ }
+
+ case KBASE_FUNC_POST_TERM:
+ {
+ kbase_event_close(kctx);
+ break;
+ }
+
+ case KBASE_FUNC_HWCNT_SETUP:
+ {
+ kbase_uk_hwcnt_setup * setup = args;
+
+ if (sizeof(*setup) != args_size)
+ {
+ goto bad_size;
+ }
+ if (MALI_ERROR_NONE != kbase_instr_hwcnt_setup(kctx, setup))
+ {
+ ukh->ret = MALI_ERROR_FUNCTION_FAILED;
+ }
+ break;
+ }
+
+ case KBASE_FUNC_HWCNT_DUMP:
+ {
+ /* args ignored */
+ if (MALI_ERROR_NONE != kbase_instr_hwcnt_dump(kctx))
+ {
+ ukh->ret = MALI_ERROR_FUNCTION_FAILED;
+ }
+ break;
+ }
+
+ case KBASE_FUNC_HWCNT_CLEAR:
+ {
+ /* args ignored */
+ if (MALI_ERROR_NONE != kbase_instr_hwcnt_clear(kctx))
+ {
+ ukh->ret = MALI_ERROR_FUNCTION_FAILED;
+ }
+ break;
+ }
+
+ case KBASE_FUNC_CPU_PROPS_REG_DUMP:
+ {
+ kbase_uk_cpuprops * setup = args;
+
+ if (sizeof(*setup) != args_size)
+ {
+ goto bad_size;
+ }
+
+ if (MALI_ERROR_NONE != kbase_cpuprops_uk_get_props(kctx,setup))
+ {
+ ukh->ret = MALI_ERROR_FUNCTION_FAILED;
+ }
+ break;
+ }
+
+ case KBASE_FUNC_GPU_PROPS_REG_DUMP:
+ {
+ kbase_uk_gpuprops * setup = args;
+
+ if (sizeof(*setup) != args_size)
+ {
+ goto bad_size;
+ }
+
+ if (MALI_ERROR_NONE != kbase_gpuprops_uk_get_props(kctx, setup))
+ {
+ ukh->ret = MALI_ERROR_FUNCTION_FAILED;
+ }
+ break;
+ }
+
+ case KBASE_FUNC_TMEM_GETSIZE:
+ {
+ kbase_uk_tmem_get_size *getsize = args;
+ if (sizeof(*getsize) != args_size)
+ {
+ goto bad_size;
+ }
+
+ if (getsize->gpu_addr & BASE_MEM_TAGS_MASK)
+ {
+ OSK_PRINT_WARN(OSK_BASE_MEM, "kbase_dispatch case KBASE_FUNC_TMEM_GETSIZE: getsize->gpu_addr: passed parameter is invalid");
+ ukh->ret = MALI_ERROR_FUNCTION_FAILED;
+ break;
+ }
+
+ ukh->ret = kbase_tmem_get_size(kctx, getsize->gpu_addr, &getsize->actual_size);
+ break;
+ }
+ break;
+
+ case KBASE_FUNC_TMEM_SETSIZE:
+ {
+ kbase_uk_tmem_set_size *set_size = args;
+
+ if (sizeof(*set_size) != args_size)
+ {
+ goto bad_size;
+ }
+
+ if (set_size->gpu_addr & BASE_MEM_TAGS_MASK)
+ {
+ OSK_PRINT_WARN(OSK_BASE_MEM, "kbase_dispatch case KBASE_FUNC_TMEM_SETSIZE: set_size->gpu_addr: passed parameter is invalid");
+ ukh->ret = MALI_ERROR_FUNCTION_FAILED;
+ break;
+ }
+
+ ukh->ret = kbase_tmem_set_size(kctx, set_size->gpu_addr, set_size->size, &set_size->actual_size, &set_size->result_subcode);
+ break;
+ }
+
+ case KBASE_FUNC_TMEM_RESIZE:
+ {
+ kbase_uk_tmem_resize *resize = args;
+ if (sizeof(*resize) != args_size)
+ {
+ goto bad_size;
+ }
+
+ if (resize->gpu_addr & BASE_MEM_TAGS_MASK)
+ {
+ OSK_PRINT_WARN(OSK_BASE_MEM, "kbase_dispatch case KBASE_FUNC_TMEM_RESIZE: resize->gpu_addr: passed parameter is invalid");
+ ukh->ret = MALI_ERROR_FUNCTION_FAILED;
+ break;
+ }
+
+ ukh->ret = kbase_tmem_resize(kctx, resize->gpu_addr, resize->delta, &resize->actual_size, &resize->result_subcode);
+ break;
+ }
+
+ case KBASE_FUNC_FIND_CPU_MAPPING:
+ {
+ kbase_uk_find_cpu_mapping *find = args;
+ struct kbase_cpu_mapping *map;
+
+ if (sizeof(*find) != args_size)
+ {
+ goto bad_size;
+ }
+ if (find->gpu_addr & BASE_MEM_TAGS_MASK)
+ {
+ OSK_PRINT_WARN(OSK_BASE_MEM, "kbase_dispatch case KBASE_FUNC_FIND_CPU_MAPPING: find->gpu_addr: passed parameter is invalid");
+ goto out_bad;
+ }
+
+ OSKP_ASSERT( find != NULL );
+ if ( find->size > SIZE_MAX || find->cpu_addr > ULONG_MAX )
+ {
+ map = NULL;
+ }
+ else
+ {
+ map = kbasep_find_enclosing_cpu_mapping( kctx,
+ find->gpu_addr,
+ (osk_virt_addr)(uintptr_t)find->cpu_addr,
+ (size_t)find->size );
+ }
+
+ if ( NULL != map )
+ {
+ find->uaddr = PTR_TO_U64( map->uaddr );
+ find->nr_pages = map->nr_pages;
+ find->page_off = map->page_off;
+ }
+ else
+ {
+ ukh->ret = MALI_ERROR_FUNCTION_FAILED;
+ }
+ break;
+ }
+ case KBASE_FUNC_GET_VERSION:
+ {
+ kbase_uk_get_ddk_version *get_version = (kbase_uk_get_ddk_version *)args;
+
+ if (sizeof(*get_version) != args_size)
+ {
+ goto bad_size;
+ }
+
+ /* version buffer size check is made in compile time assert */
+ memcpy(get_version->version_buffer, KERNEL_SIDE_DDK_VERSION_STRING,
+ sizeof(KERNEL_SIDE_DDK_VERSION_STRING));
+ get_version->version_string_size = sizeof(KERNEL_SIDE_DDK_VERSION_STRING);
+ break;
+ }
+#ifdef CONFIG_SYNC
+ case KBASE_FUNC_STREAM_CREATE:
+ {
+ kbase_uk_stream_create * screate = (kbase_uk_stream_create*)args;
+
+ if (sizeof(*screate) != args_size)
+ {
+ goto bad_size;
+ }
+
+ if (strnlen(screate->name, sizeof(screate->name)) >= sizeof(screate->name))
+ {
+ /* not NULL terminated */
+ ukh->ret = MALI_ERROR_FUNCTION_FAILED;
+ break;
+ }
+
+ ukh->ret = kbase_stream_create(screate->name, &screate->fd);
+ break;
+ }
+ case KBASE_FUNC_FENCE_VALIDATE:
+ {
+ kbase_uk_fence_validate * fence_validate = (kbase_uk_fence_validate*)args;
+ if (sizeof(*fence_validate) != args_size)
+ {
+ goto bad_size;
+ }
+ ukh->ret = kbase_fence_validate(fence_validate->fd);
+ break;
+ }
+#endif /* CONFIG_SYNC */
+#ifdef CONFIG_KDS
+ case KBASE_FUNC_EXT_BUFFER_LOCK:
+ {
+ ukh->ret = kbase_external_buffer_lock( kctx, ukk_ctx,(kbase_uk_ext_buff_kds_data *)args, args_size );
+ break;
+ }
+#endif /* CONFIG_KDS */
+#if MALI_UNIT_TEST
+ case KBASE_FUNC_SET_TEST_DATA:
+ {
+ kbase_uk_set_test_data *set_data = args;
+
+ shared_kernel_test_data = set_data->test_data;
+ shared_kernel_test_data.kctx = kctx;
+ shared_kernel_test_data.mm = (void*)current->mm;
+ ukh->ret = MALI_ERROR_NONE;
+ break;
+ }
+#endif /* MALI_UNIT_TEST */
+#ifdef CONFIG_MALI_ERROR_INJECT
+ case KBASE_FUNC_INJECT_ERROR:
+ {
+ unsigned long flags;
+ kbase_error_params params = ((kbase_uk_error_params*)args)->params;
+ /*mutex lock*/
+ spin_lock_irqsave(&kbdev->osdev.reg_op_lock, flags);
+ ukh->ret = job_atom_inject_error(¶ms);
+ spin_unlock_irqrestore(&kbdev->osdev.reg_op_lock, flags);
+ /*mutex unlock*/
+
+ break;
+ }
+#endif /* CONFIG_MALI_ERROR_INJECT */
+#ifdef CONFIG_MALI_NO_MALI
+ case KBASE_FUNC_MODEL_CONTROL:
+ {
+ unsigned long flags;
+ kbase_model_control_params params = ((kbase_uk_model_control_params*)args)->params;
+ /*mutex lock*/
+ spin_lock_irqsave(&kbdev->osdev.reg_op_lock, flags);
+ ukh->ret = midg_model_control(kbdev->osdev.model, ¶ms);
+ spin_unlock_irqrestore(&kbdev->osdev.reg_op_lock, flags);
+ /*mutex unlock*/
+ break;
+ }
+#endif /* CONFIG_MALI_NO_MALI */
+ case KBASE_FUNC_KEEP_GPU_POWERED:
+ {
+ kbase_uk_keep_gpu_powered *kgp = (kbase_uk_keep_gpu_powered*)args;
+
+ if (kgp->enabled && !kctx->keep_gpu_powered)
+ {
+ kbase_pm_context_active(kbdev);
+ kctx->keep_gpu_powered = MALI_TRUE;
+ }
+ else if (!kgp->enabled && kctx->keep_gpu_powered)
+ {
+ kbase_pm_context_idle(kbdev);
+ kctx->keep_gpu_powered = MALI_FALSE;
+ }
+
+ break;
+ }
+ default:
+ dev_err(kbdev->osdev.dev, "unknown ioctl %u", id);
+ goto out_bad;
+ }
+
+ return MALI_ERROR_NONE;
+
+bad_size:
+ dev_err(kbdev->osdev.dev, "Wrong syscall size (%d) for %08x\n", args_size, id);
+out_bad:
+ return MALI_ERROR_FUNCTION_FAILED;
+}
+
+static struct kbase_device *to_kbase_device(struct device *dev)
+{
+ return dev_get_drvdata(dev);
+}
+
+/* Find a particular kbase device (as specified by minor number), or find the "first" device if -1 is specified */
+struct kbase_device *kbase_find_device(int minor)
+{
+ struct kbase_device *kbdev = NULL;
+ struct list_head *entry;
+
+ down(&kbase_dev_list_lock);
+ list_for_each(entry, &kbase_dev_list)
+ {
+ struct kbase_device *tmp;
+
+ tmp = list_entry(entry, struct kbase_device, osdev.entry);
+ if (tmp->osdev.mdev.minor == minor || minor == -1)
+ {
+ kbdev = tmp;
+ get_device(kbdev->osdev.dev);
+ break;
+ }
+ }
+ up(&kbase_dev_list_lock);
+
+ return kbdev;
+}
+
+EXPORT_SYMBOL(kbase_find_device);
+
+
+
+
+
+void kbase_release_device(struct kbase_device *kbdev)
+{
+ put_device(kbdev->osdev.dev);
+}
+
+EXPORT_SYMBOL(kbase_release_device);
+
+static int kbase_open(struct inode *inode, struct file *filp)
+{
+ struct kbase_device *kbdev = NULL;
+ kbase_context *kctx;
+ int ret = 0;
+
+ /* Enforce that the driver is opened with O_CLOEXEC so that execve() automatically
+ * closes the file descriptor in a child process.
+ */
+ if (0 == (filp->f_flags & O_CLOEXEC))
+ {
+ printk(KERN_ERR KBASE_DRV_NAME " error: O_CLOEXEC flag not set\n");
+ /*return -EINVAL;*/
+ }
+
+ kbdev = kbase_find_device(iminor(inode));
+
+ if (!kbdev)
+ return -ENODEV;
+
+ kctx = kbase_create_context(kbdev);
+ if (!kctx)
+ {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ if (MALI_ERROR_NONE != ukk_session_init(&kctx->ukk_session, kbase_dispatch, BASE_UK_VERSION_MAJOR, BASE_UK_VERSION_MINOR))
+ {
+ kbase_destroy_context(kctx);
+ ret = -EFAULT;
+ goto out;
+ }
+
+ init_waitqueue_head(&kctx->osctx.event_queue);
+ filp->private_data = kctx;
+
+ dev_dbg(kbdev->osdev.dev, "created base context\n");
+ return 0;
+
+out:
+ kbase_release_device(kbdev);
+ return ret;
+}
+
+static int kbase_release(struct inode *inode, struct file *filp)
+{
+ kbase_context *kctx = filp->private_data;
+ struct kbase_device *kbdev = kctx->kbdev;
+
+ ukk_session_term(&kctx->ukk_session);
+ filp->private_data = NULL;
+ kbase_destroy_context(kctx);
+
+ dev_dbg(kbdev->osdev.dev, "deleted base context\n");
+ kbase_release_device(kbdev);
+ return 0;
+}
+
+static long kbase_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ u64 msg[(UKK_CALL_MAX_SIZE+7)>>3] = {0xdeadbeefdeadbeefull}; /* alignment fixup */
+ u32 size = _IOC_SIZE(cmd);
+ ukk_call_context ukk_ctx;
+ kbase_context *kctx = filp->private_data;
+
+ if (size > UKK_CALL_MAX_SIZE) return -ENOTTY;
+
+ if (0 != copy_from_user(&msg, (void *)arg, size))
+ {
+ pr_err("failed to copy ioctl argument into kernel space\n");
+ return -EFAULT;
+ }
+
+ ukk_call_prepare(&ukk_ctx, &kctx->ukk_session);
+
+ if (MALI_ERROR_NONE != ukk_dispatch(&ukk_ctx, &msg, size))
+ {
+ return -EFAULT;
+ }
+
+ if (0 != copy_to_user((void *)arg, &msg, size))
+ {
+ pr_err("failed to copy results of UK call back to user space\n");
+ return -EFAULT;
+ }
+ return 0;
+}
+
+static ssize_t kbase_read(struct file *filp, char __user *buf,
+ size_t count, loff_t *f_pos)
+{
+ kbase_context *kctx = filp->private_data;
+ base_jd_event_v2 uevent;
+ int out_count = 0;
+
+ if (count < sizeof(uevent))
+ {
+ return -ENOBUFS;
+ }
+
+ do
+ {
+ while (kbase_event_dequeue(kctx, &uevent))
+ {
+ if (out_count > 0)
+ {
+ goto out;
+ }
+ if (filp->f_flags & O_NONBLOCK)
+ {
+ return -EAGAIN;
+ }
+
+ if (wait_event_interruptible(kctx->osctx.event_queue,
+ kbase_event_pending(kctx)))
+ {
+ return -ERESTARTSYS;
+ }
+ }
+ if (uevent.event_code == BASE_JD_EVENT_DRV_TERMINATED)
+ {
+ if (out_count == 0)
+ {
+ return -EPIPE;
+ }
+ goto out;
+ }
+
+ if (copy_to_user(buf, &uevent, sizeof(uevent)))
+ {
+ return -EFAULT;
+ }
+ buf += sizeof(uevent);
+ out_count++;
+ count -= sizeof(uevent);
+ } while (count >= sizeof(uevent));
+
+out:
+ return out_count*sizeof(uevent);
+}
+
+static unsigned int kbase_poll(struct file *filp, poll_table *wait)
+{
+ kbase_context *kctx = filp->private_data;
+
+ poll_wait(filp, &kctx->osctx.event_queue, wait);
+ if (kbase_event_pending(kctx))
+ {
+ return POLLIN | POLLRDNORM;
+ }
+
+ return 0;
+}
+
+void kbase_event_wakeup(kbase_context *kctx)
+{
+ OSK_ASSERT(kctx);
+
+ wake_up_interruptible(&kctx->osctx.event_queue);
+}
+KBASE_EXPORT_TEST_API(kbase_event_wakeup)
+
+int kbase_check_flags(int flags)
+{
+ /* Enforce that the driver keeps the O_CLOEXEC flag so that execve() always
+ * closes the file descriptor in a child process.
+ */
+ if (0 == (flags & O_CLOEXEC))
+ {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct file_operations kbase_fops =
+{
+ .owner = THIS_MODULE,
+ .open = kbase_open,
+ .release = kbase_release,
+ .read = kbase_read,
+ .poll = kbase_poll,
+ .unlocked_ioctl = kbase_ioctl,
+ .mmap = kbase_mmap,
+ .check_flags = kbase_check_flags,
+};
+
+#ifndef CONFIG_MALI_NO_MALI
+void kbase_os_reg_write(kbase_device *kbdev, u16 offset, u32 value)
+{
+ writel(value, kbdev->osdev.reg + offset);
+}
+
+u32 kbase_os_reg_read(kbase_device *kbdev, u16 offset)
+{
+ return readl(kbdev->osdev.reg + offset);
+}
+
+static void *kbase_tag(void *ptr, u32 tag)
+{
+ return (void *)(((uintptr_t) ptr) | tag);
+}
+
+static void *kbase_untag(void *ptr)
+{
+ return (void *)(((uintptr_t) ptr) & ~3);
+}
+
+static irqreturn_t kbase_job_irq_handler(int irq, void *data)
+{
+ unsigned long flags;
+ struct kbase_device *kbdev = kbase_untag(data);
+ u32 val;
+
+ spin_lock_irqsave(&kbdev->pm.gpu_powered_lock, flags);
+
+ if (!kbdev->pm.gpu_powered)
+ {
+ /* GPU is turned off - IRQ is not for us */
+ spin_unlock_irqrestore(&kbdev->pm.gpu_powered_lock, flags);
+ return IRQ_NONE;
+ }
+
+ val = kbase_reg_read(kbdev, JOB_CONTROL_REG(JOB_IRQ_STATUS), NULL);
+
+ spin_unlock_irqrestore(&kbdev->pm.gpu_powered_lock, flags);
+
+ if (!val)
+ {
+ return IRQ_NONE;
+ }
+
+ dev_dbg(kbdev->osdev.dev, "%s: irq %d irqstatus 0x%x\n", __func__, irq, val);
+
+ kbase_job_done(kbdev, val);
+
+ return IRQ_HANDLED;
+}
+KBASE_EXPORT_TEST_API(kbase_job_irq_handler);
+
+static irqreturn_t kbase_mmu_irq_handler(int irq, void *data)
+{
+ unsigned long flags;
+ struct kbase_device *kbdev = kbase_untag(data);
+ u32 val;
+
+ spin_lock_irqsave(&kbdev->pm.gpu_powered_lock, flags);
+
+ if (!kbdev->pm.gpu_powered)
+ {
+ /* GPU is turned off - IRQ is not for us */
+ spin_unlock_irqrestore(&kbdev->pm.gpu_powered_lock, flags);
+ return IRQ_NONE;
+ }
+
+ val = kbase_reg_read(kbdev, MMU_REG(MMU_IRQ_STATUS), NULL);
+
+ spin_unlock_irqrestore(&kbdev->pm.gpu_powered_lock, flags);
+
+ if (!val)
+ {
+ return IRQ_NONE;
+ }
+
+ dev_dbg(kbdev->osdev.dev, "%s: irq %d irqstatus 0x%x\n", __func__, irq, val);
+
+ kbase_mmu_interrupt(kbdev, val);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t kbase_gpu_irq_handler(int irq, void *data)
+{
+ unsigned long flags;
+ struct kbase_device *kbdev = kbase_untag(data);
+ u32 val;
+
+ spin_lock_irqsave(&kbdev->pm.gpu_powered_lock, flags);
+
+ if (!kbdev->pm.gpu_powered)
+ {
+ /* GPU is turned off - IRQ is not for us */
+ spin_unlock_irqrestore(&kbdev->pm.gpu_powered_lock, flags);
+ return IRQ_NONE;
+ }
+
+ val = kbase_reg_read(kbdev, GPU_CONTROL_REG(GPU_IRQ_STATUS), NULL);
+
+ spin_unlock_irqrestore(&kbdev->pm.gpu_powered_lock, flags);
+
+ if (!val)
+ {
+ return IRQ_NONE;
+ }
+
+ dev_dbg(kbdev->osdev.dev, "%s: irq %d irqstatus 0x%x\n", __func__, irq, val);
+
+ kbase_gpu_interrupt(kbdev, val);
+
+ return IRQ_HANDLED;
+}
+
+static irq_handler_t kbase_handler_table[] = {
+ [JOB_IRQ_TAG] = kbase_job_irq_handler,
+ [MMU_IRQ_TAG] = kbase_mmu_irq_handler,
+ [GPU_IRQ_TAG] = kbase_gpu_irq_handler,
+};
+
+#ifdef CONFIG_MALI_DEBUG
+#define JOB_IRQ_HANDLER JOB_IRQ_TAG
+#define MMU_IRQ_HANDLER MMU_IRQ_TAG
+#define GPU_IRQ_HANDLER GPU_IRQ_TAG
+
+/**
+ * @brief Registers given interrupt handler for requested interrupt type
+ * Case irq handler is not specified default handler shall be registered
+ *
+ * @param[in] kbdev - Device for which the handler is to be registered
+ * @param[in] custom_handler - Handler to be registered
+ * @param[in] irq_type - Interrupt type
+ * @return MALI_ERROR_NONE case success, MALI_ERROR_FUNCTION_FAILED otherwise
+ */
+static mali_error kbase_set_custom_irq_handler(kbase_device *kbdev, irq_handler_t custom_handler, int irq_type)
+{
+ struct kbase_os_device * osdev = &kbdev->osdev;
+ mali_error result = MALI_ERROR_NONE;
+ irq_handler_t requested_irq_handler = NULL;
+ OSK_ASSERT((JOB_IRQ_HANDLER <= irq_type) && (GPU_IRQ_HANDLER >= irq_type));
+
+ /* Release previous handler */
+ if(osdev->irqs[irq_type].irq)
+ {
+ free_irq(osdev->irqs[irq_type].irq, kbase_tag(kbdev, irq_type));
+ }
+
+ requested_irq_handler = (NULL != custom_handler) ? custom_handler : kbase_handler_table[irq_type];
+
+ if ( 0 != request_irq(osdev->irqs[irq_type].irq,
+ requested_irq_handler,
+ osdev->irqs[irq_type].flags | IRQF_SHARED,
+ dev_name(osdev->dev),
+ kbase_tag(kbdev, irq_type)))
+ {
+ result = MALI_ERROR_FUNCTION_FAILED;
+ dev_err(osdev->dev, "Can't request interrupt %d (index %d)\n", osdev->irqs[irq_type].irq, irq_type);
+ }
+
+ return result;
+}
+KBASE_EXPORT_TEST_API(kbase_set_custom_irq_handler)
+
+/* test correct interrupt assigment and reception by cpu */
+typedef struct kbasep_irq_test
+{
+ struct hrtimer timer;
+ wait_queue_head_t wait;
+ int triggered;
+ u32 timeout;
+}kbasep_irq_test;
+
+static kbasep_irq_test kbasep_irq_test_data;
+
+#define IRQ_TEST_TIMEOUT 500
+
+static irqreturn_t kbase_job_irq_test_handler(int irq, void *data)
+{
+ unsigned long flags;
+ struct kbase_device *kbdev = kbase_untag(data);
+ u32 val;
+
+ spin_lock_irqsave(&kbdev->pm.gpu_powered_lock, flags);
+
+ if (!kbdev->pm.gpu_powered)
+ {
+ /* GPU is turned off - IRQ is not for us */
+ spin_unlock_irqrestore(&kbdev->pm.gpu_powered_lock, flags);
+ return IRQ_NONE;
+ }
+
+ val = kbase_reg_read(kbdev, JOB_CONTROL_REG(JOB_IRQ_STATUS), NULL);
+
+ spin_unlock_irqrestore(&kbdev->pm.gpu_powered_lock, flags);
+
+ if (!val)
+ {
+ return IRQ_NONE;
+ }
+
+ dev_dbg(kbdev->osdev.dev, "%s: irq %d irqstatus 0x%x\n", __func__, irq, val);
+
+ kbasep_irq_test_data.triggered = 1;
+ wake_up(&kbasep_irq_test_data.wait);
+
+ kbase_reg_write(kbdev, JOB_CONTROL_REG(JOB_IRQ_CLEAR), val, NULL);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t kbase_mmu_irq_test_handler(int irq, void *data)
+{
+ unsigned long flags;
+ struct kbase_device *kbdev = kbase_untag(data);
+ u32 val;
+
+ spin_lock_irqsave(&kbdev->pm.gpu_powered_lock, flags);
+
+ if (!kbdev->pm.gpu_powered)
+ {
+ /* GPU is turned off - IRQ is not for us */
+ spin_unlock_irqrestore(&kbdev->pm.gpu_powered_lock, flags);
+ return IRQ_NONE;
+ }
+
+ val = kbase_reg_read(kbdev, MMU_REG(MMU_IRQ_STATUS), NULL);
+
+ spin_unlock_irqrestore(&kbdev->pm.gpu_powered_lock, flags);
+
+ if (!val)
+ {
+ return IRQ_NONE;
+ }
+
+ dev_dbg(kbdev->osdev.dev, "%s: irq %d irqstatus 0x%x\n", __func__, irq, val);
+
+ kbasep_irq_test_data.triggered = 1;
+ wake_up(&kbasep_irq_test_data.wait);
+
+ kbase_reg_write(kbdev, MMU_REG(MMU_IRQ_CLEAR), val, NULL);
+
+ return IRQ_HANDLED;
+}
+
+static enum hrtimer_restart kbasep_test_interrupt_timeout(struct hrtimer * timer)
+{
+ kbasep_irq_test *test_data = container_of( timer, kbasep_irq_test, timer );
+
+ test_data->timeout = 1;
+ test_data->triggered = 1;
+ wake_up(&test_data->wait);
+ return HRTIMER_NORESTART;
+}
+
+static mali_error kbasep_common_test_interrupt(kbase_device * const kbdev, u32 tag )
+{
+ struct kbase_os_device *osdev = &kbdev->osdev;
+ osk_error err = MALI_ERROR_NONE;
+ irq_handler_t test_handler;
+
+ u32 old_mask_val;
+ u16 mask_offset;
+ u16 rawstat_offset;
+
+ switch(tag)
+ {
+ case JOB_IRQ_TAG:
+ test_handler = kbase_job_irq_test_handler;
+ rawstat_offset = JOB_CONTROL_REG(JOB_IRQ_RAWSTAT);
+ mask_offset = JOB_CONTROL_REG(JOB_IRQ_MASK);
+ break;
+ case MMU_IRQ_TAG:
+ test_handler = kbase_mmu_irq_test_handler;
+ rawstat_offset = MMU_REG(MMU_IRQ_RAWSTAT);
+ mask_offset = MMU_REG(MMU_IRQ_MASK);
+ break;
+ case GPU_IRQ_TAG:
+ /* already tested by pm_driver - bail out */
+ default:
+ return MALI_ERROR_NONE;
+ }
+
+ /* store old mask */
+ old_mask_val = kbase_reg_read(kbdev, mask_offset, NULL);
+ /* mask interrupts */
+ kbase_reg_write(kbdev, mask_offset, 0x0, NULL);
+
+ if (osdev->irqs[tag].irq)
+ {
+ /* release original handler and install test handler */
+ if(MALI_ERROR_NONE != kbase_set_custom_irq_handler(kbdev, test_handler,tag ))
+ {
+ err = MALI_ERROR_FUNCTION_FAILED;
+ }
+ else
+ {
+ kbasep_irq_test_data.timeout = 0;
+ hrtimer_init(&kbasep_irq_test_data.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL );
+ kbasep_irq_test_data.timer.function = kbasep_test_interrupt_timeout;
+
+ /* trigger interrupt */
+ kbase_reg_write(kbdev, mask_offset, 0x1, NULL);
+ kbase_reg_write(kbdev, rawstat_offset, 0x1, NULL);
+
+ hrtimer_start( &kbasep_irq_test_data.timer,
+ HR_TIMER_DELAY_MSEC(IRQ_TEST_TIMEOUT),
+ HRTIMER_MODE_REL );
+
+ wait_event(kbasep_irq_test_data.wait, kbasep_irq_test_data.triggered != 0);
+
+ if(kbasep_irq_test_data.timeout != 0)
+ {
+ dev_err(osdev->dev, "Interrupt %d (index %d) didn't reach CPU.\n", osdev->irqs[tag].irq, tag);
+ err = MALI_ERROR_FUNCTION_FAILED;
+ }
+ else
+ {
+ dev_dbg(osdev->dev, "Interrupt %d (index %d) reached CPU.\n", osdev->irqs[tag].irq, tag);
+ }
+
+ hrtimer_cancel(&kbasep_irq_test_data.timer);
+ kbasep_irq_test_data.triggered = 0;
+
+ /* mask interrupts */
+ kbase_reg_write(kbdev, mask_offset, 0x0, NULL);
+
+ /* release test handler */
+ free_irq(osdev->irqs[tag].irq, kbase_tag(kbdev, tag));
+ }
+
+ /* restore original interrupt */
+ if (request_irq(osdev->irqs[tag].irq,
+ kbase_handler_table[tag],
+ osdev->irqs[tag].flags | IRQF_SHARED,
+ dev_name(osdev->dev),
+ kbase_tag(kbdev, tag)))
+ {
+ dev_err(osdev->dev, "Can't restore original interrupt %d (index %d)\n", osdev->irqs[tag].irq, tag);
+ err = MALI_ERROR_FUNCTION_FAILED;
+ }
+ }
+ /* restore old mask */
+ kbase_reg_write(kbdev, mask_offset, old_mask_val, NULL);
+
+ return err;
+}
+
+static mali_error kbasep_common_test_interrupt_handlers(kbase_device * const kbdev)
+{
+ struct kbase_os_device *osdev = &kbdev->osdev;
+ mali_error err;
+
+ init_waitqueue_head(&kbasep_irq_test_data.wait);
+ kbasep_irq_test_data.triggered = 0;
+
+ kbase_pm_context_active(kbdev);
+
+ err = kbasep_common_test_interrupt(kbdev, JOB_IRQ_TAG);
+ if (MALI_ERROR_NONE != err)
+ {
+ dev_err(osdev->dev, "Interrupt JOB_IRQ didn't reach CPU. Check interrupt assignments.\n");
+ goto out;
+ }
+
+ err = kbasep_common_test_interrupt(kbdev, MMU_IRQ_TAG);
+ if (MALI_ERROR_NONE != err)
+ {
+ dev_err(osdev->dev, "Interrupt MMU_IRQ didn't reach CPU. Check interrupt assignments.\n");
+ goto out;
+ }
+
+ dev_err(osdev->dev, "Interrupts are correctly assigned.\n");
+
+out:
+ kbase_pm_context_idle(kbdev);
+
+ return err;
+
+}
+#endif /* CONFIG_MALI_DEBUG */
+
+static int kbase_install_interrupts(kbase_device *kbdev)
+{
+ struct kbase_os_device *osdev = &kbdev->osdev;
+ u32 nr = ARRAY_SIZE(kbase_handler_table);
+ int err;
+ u32 i;
+
+ BUG_ON(nr > PLATFORM_CONFIG_IRQ_RES_COUNT); /* Only 3 interrupts! */
+
+ for (i = 0; i < nr; i++)
+ {
+ err = request_irq(osdev->irqs[i].irq,
+ kbase_handler_table[i],
+ osdev->irqs[i].flags | IRQF_SHARED,
+ dev_name(osdev->dev),
+ kbase_tag(kbdev, i));
+ if (err)
+ {
+ dev_err(osdev->dev, "Can't request interrupt %d (index %d)\n", osdev->irqs[i].irq, i);
+ goto release;
+ }
+ }
+
+ return 0;
+
+release:
+ while (i-- > 0)
+ {
+ free_irq(osdev->irqs[i].irq, kbase_tag(kbdev, i));
+ }
+
+ return err;
+}
+
+static void kbase_release_interrupts(kbase_device *kbdev)
+{
+ struct kbase_os_device *osdev = &kbdev->osdev;
+ u32 nr = ARRAY_SIZE(kbase_handler_table);
+ u32 i;
+
+ for (i = 0; i < nr; i++)
+ {
+ if (osdev->irqs[i].irq)
+ {
+ free_irq(osdev->irqs[i].irq, kbase_tag(kbdev, i));
+ }
+ }
+}
+
+void kbase_synchronize_irqs(kbase_device *kbdev)
+{
+ struct kbase_os_device *osdev = &kbdev->osdev;
+ u32 nr = ARRAY_SIZE(kbase_handler_table);
+ u32 i;
+
+ for (i = 0; i < nr; i++)
+ {
+ if (osdev->irqs[i].irq)
+ {
+ synchronize_irq(osdev->irqs[i].irq);
+ }
+ }
+}
+
+#endif /* CONFIG_MALI_NO_MALI */
+
+/** Show callback for the @c power_policy sysfs file.
+ *
+ * This function is called to get the contents of the @c power_policy sysfs
+ * file. This is a list of the available policies with the currently active one
+ * surrounded by square brackets.
+ *
+ * @param dev The device this sysfs file is for
+ * @param attr The attributes of the sysfs file
+ * @param buf The output buffer for the sysfs file contents
+ *
+ * @return The number of bytes output to @c buf.
+ */
+static ssize_t show_policy(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct kbase_device *kbdev;
+ const struct kbase_pm_policy *current_policy;
+ const struct kbase_pm_policy * const *policy_list;
+ int policy_count;
+ int i;
+ ssize_t ret = 0;
+
+ kbdev = to_kbase_device(dev);
+
+ if (!kbdev)
+ {
+ return -ENODEV;
+ }
+
+ current_policy = kbase_pm_get_policy(kbdev);
+
+ policy_count = kbase_pm_list_policies(&policy_list);
+
+ for(i=0; i<policy_count && ret<PAGE_SIZE; i++)
+ {
+ if (policy_list[i] == current_policy)
+ {
+ ret += scnprintf(buf+ret, PAGE_SIZE - ret, "[%s] ", policy_list[i]->name);
+ }
+ else
+ {
+ ret += scnprintf(buf+ret, PAGE_SIZE - ret, "%s ", policy_list[i]->name);
+ }
+ }
+
+ if (ret < PAGE_SIZE - 1)
+ {
+ ret += scnprintf(buf+ret, PAGE_SIZE-ret, "\n");
+ }
+ else
+ {
+ buf[PAGE_SIZE-2] = '\n';
+ buf[PAGE_SIZE-1] = '\0';
+ ret = PAGE_SIZE-1;
+ }
+
+ return ret;
+}
+
+/** Store callback for the @c power_policy sysfs file.
+ *
+ * This function is called when the @c power_policy sysfs file is written to.
+ * It matches the requested policy against the available policies and if a
+ * matching policy is found calls @ref kbase_pm_set_policy to change the
+ * policy.
+ *
+ * @param dev The device with sysfs file is for
+ * @param attr The attributes of the sysfs file
+ * @param buf The value written to the sysfs file
+ * @param count The number of bytes written to the sysfs file
+ *
+ * @return @c count if the function succeeded. An error code on failure.
+ */
+static ssize_t set_policy(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct kbase_device *kbdev;
+ const struct kbase_pm_policy *new_policy = NULL;
+ const struct kbase_pm_policy * const *policy_list;
+ int policy_count;
+ int i;
+
+ kbdev = to_kbase_device(dev);
+
+ if (!kbdev)
+ {
+ return -ENODEV;
+ }
+
+ policy_count = kbase_pm_list_policies(&policy_list);
+
+ for(i=0; i<policy_count; i++)
+ {
+ if (sysfs_streq(policy_list[i]->name, buf))
+ {
+ new_policy = policy_list[i];
+ break;
+ }
+ }
+
+ if (!new_policy)
+ {
+ dev_err(dev, "power_policy: policy not found\n");
+ return -EINVAL;
+ }
+
+ kbase_pm_set_policy(kbdev, new_policy);
+ return count;
+}
+
+/** The sysfs file @c power_policy.
+ *
+ * This is used for obtaining information about the available policies,
+ * determining which policy is currently active, and changing the active
+ * policy.
+ */
+DEVICE_ATTR(power_policy, S_IRUGO|S_IWUSR, show_policy, set_policy);
+
+#if MALI_CUSTOMER_RELEASE == 0
+/** Store callback for the @c js_timeouts sysfs file.
+ *
+ * This function is called to get the contents of the @c js_timeouts sysfs
+ * file. This file contains five values separated by whitespace. The values
+ * are basically the same as KBASE_CONFIG_ATTR_JS_SOFT_STOP_TICKS,
+ * KBASE_CONFIG_ATTR_JS_HARD_STOP_TICKS_SS, KBASE_CONFIG_ATTR_JS_HARD_STOP_TICKS_NSS,
+ * KBASE_CONFIG_ATTR_JS_RESET_TICKS_SS, BASE_CONFIG_ATTR_JS_RESET_TICKS_NSS
+ * configuration values (in that order), with the difference that the js_timeout
+ * valus are expressed in MILLISECONDS.
+ *
+ * The js_timeouts sysfile file allows the current values in
+ * use by the job scheduler to get override. Note that a value needs to
+ * be other than 0 for it to override the current job scheduler value.
+ *
+ * @param dev The device with sysfs file is for
+ * @param attr The attributes of the sysfs file
+ * @param buf The value written to the sysfs file
+ * @param count The number of bytes written to the sysfs file
+ *
+ * @return @c count if the function succeeded. An error code on failure.
+ */
+static ssize_t set_js_timeouts(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct kbase_device *kbdev;
+ int items;
+ unsigned long js_soft_stop_ms;
+ unsigned long js_hard_stop_ms_ss;
+ unsigned long js_hard_stop_ms_nss;
+ unsigned long js_reset_ms_ss;
+ unsigned long js_reset_ms_nss;
+
+ kbdev = to_kbase_device(dev);
+ if (!kbdev)
+ {
+ return -ENODEV;
+ }
+
+ items = sscanf(buf, "%lu %lu %lu %lu %lu", &js_soft_stop_ms, &js_hard_stop_ms_ss, &js_hard_stop_ms_nss, &js_reset_ms_ss, &js_reset_ms_nss);
+ if (items == 5)
+ {
+ u64 ticks;
+
+ ticks = js_soft_stop_ms * 1000000ULL;
+ osk_divmod6432(&ticks, kbdev->js_data.scheduling_tick_ns);
+ kbdev->js_soft_stop_ticks = ticks;
+
+ ticks = js_hard_stop_ms_ss * 1000000ULL;
+ osk_divmod6432(&ticks, kbdev->js_data.scheduling_tick_ns);
+ kbdev->js_hard_stop_ticks_ss = ticks;
+
+ ticks = js_hard_stop_ms_nss * 1000000ULL;
+ osk_divmod6432(&ticks, kbdev->js_data.scheduling_tick_ns);
+ kbdev->js_hard_stop_ticks_nss = ticks;
+
+ ticks = js_reset_ms_ss * 1000000ULL;
+ osk_divmod6432(&ticks, kbdev->js_data.scheduling_tick_ns);
+ kbdev->js_reset_ticks_ss = ticks;
+
+ ticks = js_reset_ms_nss * 1000000ULL;
+ osk_divmod6432(&ticks, kbdev->js_data.scheduling_tick_ns);
+ kbdev->js_reset_ticks_nss = ticks;
+
+ dev_info(kbdev->osdev.dev, "Overriding KBASE_CONFIG_ATTR_JS_SOFT_STOP_TICKS with %lu ticks (%lu ms)\n", (unsigned long)kbdev->js_soft_stop_ticks, js_soft_stop_ms);
+ dev_info(kbdev->osdev.dev, "Overriding KBASE_CONFIG_ATTR_JS_HARD_STOP_TICKS_SS with %lu ticks (%lu ms)\n", (unsigned long)kbdev->js_hard_stop_ticks_ss, js_hard_stop_ms_ss);
+ dev_info(kbdev->osdev.dev, "Overriding KBASE_CONFIG_ATTR_JS_HARD_STOP_TICKS_NSS with %lu ticks (%lu ms)\n", (unsigned long)kbdev->js_hard_stop_ticks_nss, js_hard_stop_ms_nss);
+ dev_info(kbdev->osdev.dev, "Overriding KBASE_CONFIG_ATTR_JS_RESET_TICKS_SS with %lu ticks (%lu ms)\n", (unsigned long)kbdev->js_reset_ticks_ss, js_reset_ms_ss);
+ dev_info(kbdev->osdev.dev, "Overriding KBASE_CONFIG_ATTR_JS_RESET_TICKS_NSS with %lu ticks (%lu ms)\n", (unsigned long)kbdev->js_reset_ticks_nss, js_reset_ms_nss);
+
+ return count;
+ }
+ else
+ {
+ dev_err(kbdev->osdev.dev, "Couldn't process js_timeouts write operation.\nUse format "
+ "<soft_stop_ms> <hard_stop_ms_ss> <hard_stop_ms_nss> <reset_ms_ss> <reset_ms_nss>\n");
+ return -EINVAL;
+ }
+}
+
+/** Show callback for the @c js_timeouts sysfs file.
+ *
+ * This function is called to get the contents of the @c js_timeouts sysfs
+ * file. It returns the last set values written to the js_timeouts sysfs file.
+ * If the file didn't get written yet, the values will be 0.
+ *
+ * @param dev The device this sysfs file is for
+ * @param attr The attributes of the sysfs file
+ * @param buf The output buffer for the sysfs file contents
+ *
+ * @return The number of bytes output to @c buf.
+ */
+static ssize_t show_js_timeouts(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct kbase_device *kbdev;
+ ssize_t ret;
+ u64 ms;
+ unsigned long js_soft_stop_ms;
+ unsigned long js_hard_stop_ms_ss;
+ unsigned long js_hard_stop_ms_nss;
+ unsigned long js_reset_ms_ss;
+ unsigned long js_reset_ms_nss;
+
+ kbdev = to_kbase_device(dev);
+ if (!kbdev)
+ {
+ return -ENODEV;
+ }
+
+ ms = (u64)kbdev->js_soft_stop_ticks * kbdev->js_data.scheduling_tick_ns;
+ osk_divmod6432(&ms, 1000000UL);
+ js_soft_stop_ms = (unsigned long)ms;
+
+ ms = (u64)kbdev->js_hard_stop_ticks_ss * kbdev->js_data.scheduling_tick_ns;
+ osk_divmod6432(&ms, 1000000UL);
+ js_hard_stop_ms_ss = (unsigned long)ms;
+
+ ms = (u64)kbdev->js_hard_stop_ticks_nss * kbdev->js_data.scheduling_tick_ns;
+ osk_divmod6432(&ms, 1000000UL);
+ js_hard_stop_ms_nss = (unsigned long)ms;
+
+ ms = (u64)kbdev->js_reset_ticks_ss * kbdev->js_data.scheduling_tick_ns;
+ osk_divmod6432(&ms, 1000000UL);
+ js_reset_ms_ss = (unsigned long)ms;
+
+ ms = (u64)kbdev->js_reset_ticks_nss * kbdev->js_data.scheduling_tick_ns;
+ osk_divmod6432(&ms, 1000000UL);
+ js_reset_ms_nss = (unsigned long)ms;
+
+ ret = scnprintf(buf, PAGE_SIZE, "%lu %lu %lu %lu %lu\n", js_soft_stop_ms, js_hard_stop_ms_ss, js_hard_stop_ms_nss, js_reset_ms_ss, js_reset_ms_nss);
+
+ if (ret >= PAGE_SIZE )
+ {
+ buf[PAGE_SIZE-2] = '\n';
+ buf[PAGE_SIZE-1] = '\0';
+ ret = PAGE_SIZE-1;
+ }
+
+ return ret;
+}
+/** The sysfs file @c js_timeouts.
+ *
+ * This is used to override the current job scheduler values for
+ * KBASE_CONFIG_ATTR_JS_STOP_STOP_TICKS_SS
+ * KBASE_CONFIG_ATTR_JS_HARD_STOP_TICKS_SS
+ * KBASE_CONFIG_ATTR_JS_HARD_STOP_TICKS_NSS
+ * KBASE_CONFIG_ATTR_JS_RESET_TICKS_SS
+ * KBASE_CONFIG_ATTR_JS_RESET_TICKS_NSS.
+ */
+DEVICE_ATTR(js_timeouts, S_IRUGO|S_IWUSR, show_js_timeouts, set_js_timeouts);
+#endif /* MALI_CUSTOMER_RELEASE == 0 */
+
+#ifdef CONFIG_MALI_DEBUG
+static ssize_t set_js_softstop_always(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct kbase_device *kbdev;
+ int items;
+ int softstop_always;
+
+ kbdev = to_kbase_device(dev);
+ if (!kbdev)
+ {
+ return -ENODEV;
+ }
+
+ items = sscanf(buf, "%d", &softstop_always);
+ if ((items == 1) && ((softstop_always == 0) || (softstop_always == 1)))
+ {
+ kbdev->js_data.softstop_always = (mali_bool) softstop_always;
+
+ dev_info(kbdev->osdev.dev, "Support for softstop on a single context: %s\n", (kbdev->js_data.softstop_always == MALI_FALSE)? "Disabled" : "Enabled");
+ return count;
+ }
+ else
+ {
+ dev_err(kbdev->osdev.dev, "Couldn't process js_softstop_always write operation.\nUse format "
+ "<soft_stop_always>\n");
+ return -EINVAL;
+ }
+}
+
+static ssize_t show_js_softstop_always(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct kbase_device *kbdev;
+ ssize_t ret;
+
+ kbdev = to_kbase_device(dev);
+ if (!kbdev)
+ {
+ return -ENODEV;
+ }
+
+ ret = scnprintf(buf, PAGE_SIZE, "%d\n", kbdev->js_data.softstop_always);
+
+ if (ret >= PAGE_SIZE )
+ {
+ buf[PAGE_SIZE-2] = '\n';
+ buf[PAGE_SIZE-1] = '\0';
+ ret = PAGE_SIZE-1;
+ }
+
+ return ret;
+}
+/**
+ * By default, soft-stops are disabled when only a single context is present. The ability to
+ * enable soft-stop when only a single context is present can be used for debug and unit-testing purposes.
+ * (see CL t6xx_stress_1 unit-test as an example whereby this feature is used.)
+ */
+DEVICE_ATTR(js_softstop_always, S_IRUGO|S_IWUSR, show_js_softstop_always, set_js_softstop_always);
+#endif /* CONFIG_MALI_DEBUG */
+
+#ifdef CONFIG_MALI_DEBUG
+typedef void (kbasep_debug_command_func)( kbase_device * );
+
+typedef enum
+{
+ KBASEP_DEBUG_COMMAND_DUMPTRACE,
+
+ /* This must be the last enum */
+ KBASEP_DEBUG_COMMAND_COUNT
+} kbasep_debug_command_code;
+
+typedef struct kbasep_debug_command
+{
+ char *str;
+ kbasep_debug_command_func *func;
+} kbasep_debug_command;
+
+/** Debug commands supported by the driver */
+static const kbasep_debug_command debug_commands[] =
+{
+ {
+ .str = "dumptrace",
+ .func = &kbasep_trace_dump,
+ }
+};
+
+/** Show callback for the @c debug_command sysfs file.
+ *
+ * This function is called to get the contents of the @c debug_command sysfs
+ * file. This is a list of the available debug commands, separated by newlines.
+ *
+ * @param dev The device this sysfs file is for
+ * @param attr The attributes of the sysfs file
+ * @param buf The output buffer for the sysfs file contents
+ *
+ * @return The number of bytes output to @c buf.
+ */
+static ssize_t show_debug(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct kbase_device *kbdev;
+ int i;
+ ssize_t ret = 0;
+
+ kbdev = to_kbase_device(dev);
+
+ if (!kbdev)
+ {
+ return -ENODEV;
+ }
+
+ for(i=0; i<KBASEP_DEBUG_COMMAND_COUNT && ret<PAGE_SIZE; i++)
+ {
+ ret += scnprintf(buf+ret, PAGE_SIZE - ret, "%s\n", debug_commands[i].str);
+ }
+
+ if (ret >= PAGE_SIZE )
+ {
+ buf[PAGE_SIZE-2] = '\n';
+ buf[PAGE_SIZE-1] = '\0';
+ ret = PAGE_SIZE-1;
+ }
+
+ return ret;
+}
+
+/** Store callback for the @c debug_command sysfs file.
+ *
+ * This function is called when the @c debug_command sysfs file is written to.
+ * It matches the requested command against the available commands, and if
+ * a matching command is found calls the associated function from
+ * @ref debug_commands to issue the command.
+ *
+ * @param dev The device with sysfs file is for
+ * @param attr The attributes of the sysfs file
+ * @param buf The value written to the sysfs file
+ * @param count The number of bytes written to the sysfs file
+ *
+ * @return @c count if the function succeeded. An error code on failure.
+ */
+static ssize_t issue_debug(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct kbase_device *kbdev;
+ int i;
+
+ kbdev = to_kbase_device(dev);
+
+ if (!kbdev)
+ {
+ return -ENODEV;
+ }
+
+ for(i=0; i<KBASEP_DEBUG_COMMAND_COUNT; i++)
+ {
+ if (sysfs_streq(debug_commands[i].str, buf))
+ {
+ debug_commands[i].func( kbdev );
+ return count;
+ }
+ }
+
+ /* Debug Command not found */
+ dev_err(dev, "debug_command: command not known\n");
+ return -EINVAL;
+}
+
+/** The sysfs file @c debug_command.
+ *
+ * This is used to issue general debug commands to the device driver.
+ * Reading it will produce a list of debug commands, separated by newlines.
+ * Writing to it with one of those commands will issue said command.
+ */
+DEVICE_ATTR(debug_command, S_IRUGO|S_IWUSR, show_debug, issue_debug);
+#endif /* CONFIG_MALI_DEBUG*/
+
+static int kbase_common_reg_map(kbase_device *kbdev)
+{
+ struct kbase_os_device *osdev = &kbdev->osdev;
+ int err = -ENOMEM;
+
+ osdev->reg_res = request_mem_region(osdev->reg_start,
+ osdev->reg_size,
+ dev_name(osdev->dev)
+ );
+ if (!osdev->reg_res)
+ {
+ dev_err(osdev->dev, "Register window unavailable\n");
+ err = -EIO;
+ goto out_region;
+ }
+
+ osdev->reg = ioremap(osdev->reg_start, osdev->reg_size);
+ if (!osdev->reg)
+ {
+ dev_err(osdev->dev, "Can't remap register window\n");
+ err = -EINVAL;
+ goto out_ioremap;
+ }
+
+ return 0;
+
+out_ioremap:
+ release_resource(osdev->reg_res);
+ kfree(osdev->reg_res);
+out_region:
+ return err;
+}
+
+static void kbase_common_reg_unmap(kbase_device *kbdev)
+{
+ struct kbase_os_device *osdev = &kbdev->osdev;
+
+ iounmap(osdev->reg);
+ release_resource(osdev->reg_res);
+ kfree(osdev->reg_res);
+}
+
+static int kbase_common_device_init(kbase_device *kbdev)
+{
+ struct kbase_os_device *osdev = &kbdev->osdev;
+ int err = -ENOMEM;
+ mali_error mali_err;
+ enum
+ {
+ inited_mem = (1u << 0),
+ inited_job_slot = (1u << 1),
+ inited_pm = (1u << 2),
+ inited_js = (1u << 3),
+ inited_irqs = (1u << 4)
+ ,inited_debug = (1u << 5)
+ ,inited_js_softstop = (1u << 6)
+#if MALI_CUSTOMER_RELEASE == 0
+ ,inited_js_timeouts = (1u << 7)
+#endif
+ /* BASE_HW_ISSUE_8401 */
+ ,inited_workaround = (1u << 8)
+ ,inited_pm_runtime_init = (1u << 9)
+ };
+
+ int inited = 0;
+
+ dev_set_drvdata(osdev->dev, kbdev);
+
+ osdev->mdev.minor = MISC_DYNAMIC_MINOR;
+ osdev->mdev.name = osdev->devname;
+ osdev->mdev.fops = &kbase_fops;
+ osdev->mdev.parent = get_device(osdev->dev);
+
+ scnprintf(osdev->devname, DEVNAME_SIZE, "%s%d", kbase_drv_name, kbase_dev_nr++);
+
+ if (misc_register(&osdev->mdev))
+ {
+ dev_err(osdev->dev, "Couldn't register misc dev %s\n", osdev->devname);
+ err = -EINVAL;
+ goto out_misc;
+ }
+
+ if (device_create_file(osdev->dev, &dev_attr_power_policy))
+ {
+ dev_err(osdev->dev, "Couldn't create power_policy sysfs file\n");
+ goto out_file;
+ }
+
+ down(&kbase_dev_list_lock);
+ list_add(&osdev->entry, &kbase_dev_list);
+ up(&kbase_dev_list_lock);
+ dev_info(osdev->dev, "Probed as %s\n", dev_name(osdev->mdev.this_device));
+
+ mali_err = kbase_pm_init(kbdev);
+ if (MALI_ERROR_NONE != mali_err)
+ {
+ goto out_partial;
+ }
+ inited |= inited_pm;
+
+ if(kbdev->pm.callback_power_runtime_init)
+ {
+ mali_err = kbdev->pm.callback_power_runtime_init(kbdev);
+ if (MALI_ERROR_NONE != mali_err)
+ {
+ goto out_partial;
+ }
+ inited |= inited_pm_runtime_init;
+ }
+
+ mali_err = kbase_mem_init(kbdev);
+ if (MALI_ERROR_NONE != mali_err)
+ {
+ goto out_partial;
+ }
+ inited |= inited_mem;
+
+ mali_err = kbase_job_slot_init(kbdev);
+ if (MALI_ERROR_NONE != mali_err)
+ {
+ goto out_partial;
+ }
+ inited |= inited_job_slot;
+
+ mali_err = kbasep_js_devdata_init(kbdev);
+ if (MALI_ERROR_NONE != mali_err)
+ {
+ goto out_partial;
+ }
+ inited |= inited_js;
+
+ err = kbase_install_interrupts(kbdev);
+ if (err)
+ {
+ goto out_partial;
+ }
+ inited |= inited_irqs;
+
+#ifdef CONFIG_MALI_DEBUG
+ if (device_create_file(osdev->dev, &dev_attr_debug_command))
+ {
+ dev_err(osdev->dev, "Couldn't create debug_command sysfs file\n");
+ goto out_partial;
+ }
+ inited |= inited_debug;
+
+ if (device_create_file(osdev->dev, &dev_attr_js_softstop_always))
+ {
+ dev_err(osdev->dev, "Couldn't create js_softstop_always sysfs file\n");
+ goto out_partial;
+ }
+ inited |= inited_js_softstop;
+#endif /* CONFIG_MALI_DEBUG */
+#if MALI_CUSTOMER_RELEASE == 0
+ if (device_create_file(osdev->dev, &dev_attr_js_timeouts))
+ {
+ dev_err(osdev->dev, "Couldn't create js_timeouts sysfs file\n");
+ goto out_partial;
+ }
+ inited |= inited_js_timeouts;
+#endif /* MALI_CUSTOMER_RELEASE */
+
+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8401))
+ {
+ if (MALI_ERROR_NONE != kbasep_8401_workaround_init(kbdev))
+ {
+ goto out_partial;
+ }
+ inited |= inited_workaround;
+ }
+
+ mali_err = kbase_pm_powerup(kbdev);
+ if (MALI_ERROR_NONE == mali_err)
+ {
+#ifdef CONFIG_MALI_DEBUG
+#ifndef CONFIG_MALI_NO_MALI
+ if(MALI_ERROR_NONE != kbasep_common_test_interrupt_handlers(kbdev))
+ {
+ dev_err(osdev->dev, "Interrupt assigment check failed.\n");
+ err = -EINVAL;
+ goto out_partial;
+ }
+#endif /* CONFIG_MALI_NO_MALI */
+#endif /* CONFIG_MALI_DEBUG */
+ return 0;
+ }
+
+out_partial:
+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8401))
+ {
+ if (inited & inited_workaround)
+ {
+ kbasep_8401_workaround_term(kbdev);
+ }
+ }
+
+#if MALI_CUSTOMER_RELEASE == 0
+ if (inited & inited_js_timeouts)
+ {
+ device_remove_file(kbdev->osdev.dev, &dev_attr_js_timeouts);
+ }
+#endif
+#ifdef CONFIG_MALI_DEBUG
+ if (inited & inited_js_softstop)
+ {
+ device_remove_file(kbdev->osdev.dev, &dev_attr_js_softstop_always);
+ }
+
+ if (inited & inited_debug)
+ {
+ device_remove_file(kbdev->osdev.dev, &dev_attr_debug_command);
+ }
+#endif /* CONFIG_MALI_DEBUG */
+
+ if (inited & inited_js)
+ {
+ kbasep_js_devdata_halt(kbdev);
+ }
+ if (inited & inited_job_slot)
+ {
+ kbase_job_slot_halt(kbdev);
+ }
+ if (inited & inited_mem)
+ {
+ kbase_mem_halt(kbdev);
+ }
+ if (inited & inited_pm)
+ {
+ kbase_pm_halt(kbdev);
+ }
+
+ if (inited & inited_irqs)
+ {
+ kbase_release_interrupts(kbdev);
+ }
+
+ if (inited & inited_js)
+ {
+ kbasep_js_devdata_term(kbdev);
+ }
+ if (inited & inited_job_slot)
+ {
+ kbase_job_slot_term(kbdev);
+ }
+ if (inited & inited_mem)
+ {
+ kbase_mem_term(kbdev);
+ }
+
+ if (inited & inited_pm_runtime_init)
+ {
+ if(kbdev->pm.callback_power_runtime_term)
+ {
+ kbdev->pm.callback_power_runtime_term(kbdev);
+ }
+ }
+
+ if (inited & inited_pm)
+ {
+ kbase_pm_term(kbdev);
+ }
+
+ down(&kbase_dev_list_lock);
+ list_del(&osdev->entry);
+ up(&kbase_dev_list_lock);
+
+ device_remove_file(kbdev->osdev.dev, &dev_attr_power_policy);
+out_file:
+ misc_deregister(&kbdev->osdev.mdev);
+out_misc:
+ put_device(osdev->dev);
+ return err;
+}
+
+static int kbase_platform_device_probe(struct platform_device *pdev)
+{
+ struct kbase_device *kbdev;
+ struct kbase_os_device *osdev;
+ struct resource *reg_res;
+ kbase_attribute *platform_data;
+ int err;
+ int i;
+ struct mali_base_gpu_core_props *core_props;
+#ifdef CONFIG_MALI_NO_MALI
+ mali_error mali_err;
+#endif /* CONFIG_MALI_NO_MALI */
+
+ kbdev = kbase_device_alloc();
+ if (!kbdev)
+ {
+ dev_err(&pdev->dev, "Can't allocate device\n");
+ err = -ENOMEM;
+ goto out;
+ }
+
+#ifdef CONFIG_MALI_NO_MALI
+ mali_err = midg_device_create(kbdev);
+ if (MALI_ERROR_NONE != mali_err)
+ {
+ dev_err(&pdev->dev, "Can't initialize dummy model\n");
+ err = -ENOMEM;
+ goto out_midg;
+ }
+#endif /* CONFIG_MALI_NO_MALI */
+
+ osdev = &kbdev->osdev;
+ osdev->dev = &pdev->dev;
+ platform_data = (kbase_attribute *)osdev->dev->platform_data;
+
+ if (NULL == platform_data)
+ {
+ dev_err(osdev->dev, "Platform data not specified\n");
+ err = -ENOENT;
+ goto out_free_dev;
+ }
+
+ if (MALI_TRUE != kbasep_validate_configuration_attributes(kbdev, platform_data))
+ {
+ dev_err(osdev->dev, "Configuration attributes failed to validate\n");
+ err = -EINVAL;
+ goto out_free_dev;
+ }
+ kbdev->config_attributes = platform_data;
+
+ /* 3 IRQ resources */
+ for (i = 0; i < 3; i++)
+ {
+ struct resource *irq_res;
+
+ irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, i);
+ if (!irq_res)
+ {
+ dev_err(osdev->dev, "No IRQ resource at index %d\n", i);
+ err = -ENOENT;
+ goto out_free_dev;
+ }
+
+ osdev->irqs[i].irq = irq_res->start;
+ osdev->irqs[i].flags = (irq_res->flags & IRQF_TRIGGER_MASK);
+ }
+
+ /* the first memory resource is the physical address of the GPU registers */
+ reg_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!reg_res)
+ {
+ dev_err(&pdev->dev, "Invalid register resource\n");
+ err = -ENOENT;
+ goto out_free_dev;
+ }
+
+ osdev->reg_start = reg_res->start;
+ osdev->reg_size = resource_size(reg_res);
+
+ err = kbase_common_reg_map(kbdev);
+ if (err)
+ {
+ goto out_free_dev;
+ }
+
+ if (MALI_ERROR_NONE != kbase_device_init(kbdev))
+ {
+ dev_err(&pdev->dev, "Can't initialize device\n");
+ err = -ENOMEM;
+ goto out_reg_unmap;
+ }
+
+#ifdef CONFIG_UMP
+ kbdev->memdev.ump_device_id = kbasep_get_config_value(kbdev, platform_data,
+ KBASE_CONFIG_ATTR_UMP_DEVICE);
+#endif /* CONFIG_UMP */
+
+ kbdev->memdev.per_process_memory_limit = kbasep_get_config_value(kbdev, platform_data,
+ KBASE_CONFIG_ATTR_MEMORY_PER_PROCESS_LIMIT);
+
+ /* obtain min/max configured gpu frequencies */
+ core_props = &(kbdev->gpu_props.props.core_props);
+ core_props->gpu_freq_khz_min = kbasep_get_config_value(kbdev, platform_data,
+ KBASE_CONFIG_ATTR_GPU_FREQ_KHZ_MIN);
+ core_props->gpu_freq_khz_max = kbasep_get_config_value(kbdev, platform_data,
+ KBASE_CONFIG_ATTR_GPU_FREQ_KHZ_MAX);
+ kbdev->gpu_props.irq_throttle_time_us = kbasep_get_config_value(kbdev, platform_data,
+ KBASE_CONFIG_ATTR_GPU_IRQ_THROTTLE_TIME_US);
+
+ err = kbase_common_device_init(kbdev);
+ if (err)
+ {
+ dev_err(osdev->dev, "Failed kbase_common_device_init\n");
+ goto out_term_dev;
+ }
+ return 0;
+
+out_term_dev:
+ kbase_device_term(kbdev);
+out_reg_unmap:
+ kbase_common_reg_unmap(kbdev);
+out_free_dev:
+#ifdef CONFIG_MALI_NO_MALI
+ midg_device_destroy(kbdev);
+out_midg:
+#endif /* CONFIG_MALI_NO_MALI */
+ kbase_device_free(kbdev);
+out:
+ return err;
+}
+
+static int kbase_common_device_remove(struct kbase_device *kbdev)
+{
+ if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8401))
+ {
+ kbasep_8401_workaround_term(kbdev);
+ }
+
+ if(kbdev->pm.callback_power_runtime_term)
+ {
+ kbdev->pm.callback_power_runtime_term(kbdev);
+ }
+
+ /* Remove the sys power policy file */
+ device_remove_file(kbdev->osdev.dev, &dev_attr_power_policy);
+#ifdef CONFIG_MALI_DEBUG
+ device_remove_file(kbdev->osdev.dev, &dev_attr_js_softstop_always);
+ device_remove_file(kbdev->osdev.dev, &dev_attr_debug_command);
+#endif /* CONFIG_MALI_DEBUG */
+
+ kbasep_js_devdata_halt(kbdev);
+ kbase_job_slot_halt(kbdev);
+ kbase_mem_halt(kbdev);
+ kbase_pm_halt(kbdev);
+
+ kbase_release_interrupts(kbdev);
+
+ kbasep_js_devdata_term(kbdev);
+ kbase_job_slot_term(kbdev);
+ kbase_mem_term(kbdev);
+ kbase_pm_term(kbdev);
+
+ down(&kbase_dev_list_lock);
+ list_del(&kbdev->osdev.entry);
+ up(&kbase_dev_list_lock);
+ misc_deregister(&kbdev->osdev.mdev);
+ put_device(kbdev->osdev.dev);
+ kbase_common_reg_unmap(kbdev);
+ kbase_device_term(kbdev);
+#ifdef CONFIG_MALI_NO_MALI
+ midg_device_destroy(kbdev);
+#endif /* CONFIG_MALI_NO_MALI */
+ kbase_device_free(kbdev);
+
+ return 0;
+}
+
+
+static int kbase_platform_device_remove(struct platform_device *pdev)
+{
+ struct kbase_device *kbdev = to_kbase_device(&pdev->dev);
+
+ if (!kbdev)
+ {
+ return -ENODEV;
+ }
+
+ return kbase_common_device_remove(kbdev);
+}
+
+/** Suspend callback from the OS.
+ *
+ * This is called by Linux when the device should suspend.
+ *
+ * @param dev The device to suspend
+ *
+ * @return A standard Linux error code
+ */
+static int kbase_device_suspend(struct device *dev)
+{
+ struct kbase_device *kbdev = to_kbase_device(dev);
+
+ if (!kbdev)
+ {
+ return -ENODEV;
+ }
+
+ /* Send the event to the power policy */
+ kbase_pm_send_event(kbdev, KBASE_PM_EVENT_SYSTEM_SUSPEND);
+
+ /* Wait for the policy to suspend the device */
+ kbase_pm_wait_for_power_down(kbdev);
+
+ return 0;
+}
+
+/** Resume callback from the OS.
+ *
+ * This is called by Linux when the device should resume from suspension.
+ *
+ * @param dev The device to resume
+ *
+ * @return A standard Linux error code
+ */
+static int kbase_device_resume(struct device *dev)
+{
+ struct kbase_device *kbdev = to_kbase_device(dev);
+
+ if (!kbdev)
+ {
+ return -ENODEV;
+ }
+
+ /* Send the event to the power policy */
+ kbase_pm_send_event(kbdev, KBASE_PM_EVENT_SYSTEM_RESUME);
+
+ /* Wait for the policy to resume the device */
+ kbase_pm_wait_for_power_up(kbdev);
+
+ return 0;
+}
+
+/** Runtime suspend callback from the OS.
+ *
+ * This is called by Linux when the device should prepare for a condition in which it will
+ * not be able to communicate with the CPU(s) and RAM due to power management.
+ *
+ * @param dev The device to suspend
+ *
+ * @return A standard Linux error code
+ */
+#ifdef CONFIG_PM_RUNTIME
+static int kbase_device_runtime_suspend(struct device *dev)
+{
+ struct kbase_device *kbdev = to_kbase_device(dev);
+
+ if (!kbdev)
+ {
+ return -ENODEV;
+ }
+
+ if(kbdev->pm.callback_power_runtime_off)
+ {
+ kbdev->pm.callback_power_runtime_off(kbdev);
+ OSK_PRINT_INFO(OSK_BASE_PM,"runtime suspend\n");
+ }
+ return 0;
+}
+#endif /* CONFIG_PM_RUNTIME */
+
+/** Runtime resume callback from the OS.
+ *
+ * This is called by Linux when the device should go into a fully active state.
+ *
+ * @param dev The device to suspend
+ *
+ * @return A standard Linux error code
+ */
+
+#ifdef CONFIG_PM_RUNTIME
+int kbase_device_runtime_resume(struct device *dev)
+{
+ int ret = 0;
+ struct kbase_device *kbdev = to_kbase_device(dev);
+
+ if (!kbdev)
+ {
+ return -ENODEV;
+ }
+
+ if(kbdev->pm.callback_power_runtime_on)
+ {
+ ret = kbdev->pm.callback_power_runtime_on(kbdev);
+ OSK_PRINT_INFO(OSK_BASE_PM,"runtime resume\n");
+ }
+ return ret;
+}
+#endif /* CONFIG_PM_RUNTIME */
+
+/** Runtime idle callback from the OS.
+ *
+ * This is called by Linux when the device appears to be inactive and it might be
+ * placed into a low power state
+ *
+ * @param dev The device to suspend
+ *
+ * @return A standard Linux error code
+ */
+
+#ifdef CONFIG_PM_RUNTIME
+static int kbase_device_runtime_idle(struct device *dev)
+{
+ /* Avoid pm_runtime_suspend being called */
+ return 1;
+}
+#endif /* CONFIG_PM_RUNTIME */
+
+/** The power management operations for the platform driver.
+ */
+static struct dev_pm_ops kbase_pm_ops =
+{
+ .suspend = kbase_device_suspend,
+ .resume = kbase_device_resume,
+#ifdef CONFIG_PM_RUNTIME
+ .runtime_suspend = kbase_device_runtime_suspend,
+ .runtime_resume = kbase_device_runtime_resume,
+ .runtime_idle = kbase_device_runtime_idle,
+#endif /* CONFIG_PM_RUNTIME */
+};
+
+static struct platform_driver kbase_platform_driver =
+{
+ .probe = kbase_platform_device_probe,
+ .remove = kbase_platform_device_remove,
+ .driver =
+ {
+ .name = kbase_drv_name,
+ .owner = THIS_MODULE,
+ .pm = &kbase_pm_ops,
+ },
+};
+
+#ifdef CONFIG_MALI_PLATFORM_FAKE
+static struct platform_device *mali_device;
+#endif /* CONFIG_MALI_PLATFORM_FAKE */
+
+static int __init kbase_driver_init(void)
+{
+ int err;
+#ifdef CONFIG_MALI_PLATFORM_FAKE
+ kbase_platform_config *config;
+ int attribute_count;
+ struct resource resources[PLATFORM_CONFIG_RESOURCE_COUNT];
+
+ config = kbasep_get_platform_config();
+ attribute_count = kbasep_get_config_attribute_count(config->attributes);
+#ifdef CONFIG_MALI_PLATFORM_THIRDPARTY
+ err = platform_device_add_data(&exynos5_device_g3d, config->attributes, attribute_count * sizeof(config->attributes[0]));
+ if (err)
+ {
+ return err;
+ }
+#else
+
+ mali_device = platform_device_alloc( kbase_drv_name, 0);
+ if (mali_device == NULL)
+ {
+ return -ENOMEM;
+ }
+
+ kbasep_config_parse_io_resources(config->io_resources, resources);
+ err = platform_device_add_resources(mali_device, resources, PLATFORM_CONFIG_RESOURCE_COUNT);
+ if (err)
+ {
+ platform_device_put(mali_device);
+ mali_device = NULL;
+ return err;
+ }
+
+ err = platform_device_add_data(mali_device, config->attributes, attribute_count * sizeof(config->attributes[0]));
+ if (err)
+ {
+ platform_device_unregister(mali_device);
+ mali_device = NULL;
+ return err;
+ }
+
+ err = platform_device_add(mali_device);
+ if (err)
+ {
+ platform_device_unregister(mali_device);
+ mali_device = NULL;
+ return err;
+ }
+
+#endif /* CONFIG_MALI_PLATFORM_THIRDPARTY */
+#endif /* CONFIG_MALI_PLATFORM_FAKE */
+ err = platform_driver_register(&kbase_platform_driver);
+ if (err)
+ {
+ return err;
+ }
+
+ return 0;
+}
+
+static void __exit kbase_driver_exit(void)
+{
+ platform_driver_unregister(&kbase_platform_driver);
+#ifdef CONFIG_MALI_PLATFORM_FAKE
+ if (mali_device)
+ {
+ platform_device_unregister(mali_device);
+ }
+#endif /* CONFIG_MALI_PLATFORM_FAKE */
+}
+
+module_init(kbase_driver_init);
+module_exit(kbase_driver_exit);
+
+MODULE_LICENSE("GPL");
+
+#ifdef CONFIG_MALI_GATOR_SUPPORT
+/* Create the trace points (otherwise we just get code to call a tracepoint) */
+#define CREATE_TRACE_POINTS
+#include "mali_linux_trace.h"
+
+void kbase_trace_mali_pm_status(u32 event, u64 value)
+{
+ trace_mali_pm_status(event, value);
+}
+
+void kbase_trace_mali_pm_power_off(u32 event, u64 value)
+{
+ trace_mali_pm_power_off(event, value);
+}
+
+void kbase_trace_mali_pm_power_on(u32 event, u64 value)
+{
+ trace_mali_pm_power_on(event, value);
+}
+
+void kbase_trace_mali_job_slots_event(u32 event, const kbase_context * kctx)
+{
+ trace_mali_job_slots_event(event, (kctx != NULL ? kctx->osctx.tgid : 0), 0);
+}
+
+void kbase_trace_mali_page_fault_insert_pages(int event, u32 value)
+{
+ trace_mali_page_fault_insert_pages(event, value);
+}
+
+void kbase_trace_mali_mmu_as_in_use(int event)
+{
+ trace_mali_mmu_as_in_use(event);
+}
+void kbase_trace_mali_mmu_as_released(int event)
+{
+ trace_mali_mmu_as_released(event);
+}
+void kbase_trace_mali_total_alloc_pages_change(long long int event)
+{
+ trace_mali_total_alloc_pages_change(event);
+}
+#endif /* CONFIG_MALI_GATOR_SUPPORT */
+
+
diff --git a/drivers/gpu/arm/t6xx/kbase/src/linux/mali_kbase_linux.h b/drivers/gpu/arm/t6xx/kbase/src/linux/mali_kbase_linux.h
new file mode 100644
index 0000000..613a084
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/linux/mali_kbase_linux.h
@@ -0,0 +1,79 @@
+/*
+ *
+ * (C) COPYRIGHT 2010-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_kbase_linux.h
+ * Base kernel APIs, Linux implementation.
+ */
+
+#ifndef _KBASE_LINUX_H_
+#define _KBASE_LINUX_H_
+
+/* All things that are needed for the Linux port. */
+#include <linux/platform_device.h>
+#include <linux/miscdevice.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <asm/atomic.h>
+
+typedef struct kbase_os_context
+{
+ u64 cookies;
+ osk_dlist reg_pending;
+ wait_queue_head_t event_queue;
+ pid_t tgid;
+} kbase_os_context;
+
+
+#define DEVNAME_SIZE 16
+
+typedef struct kbase_os_device
+{
+ struct list_head entry;
+ struct device *dev;
+ struct miscdevice mdev;
+ u64 reg_start;
+ size_t reg_size;
+ void __iomem *reg;
+ struct resource *reg_res;
+ struct {
+ int irq;
+ int flags;
+ } irqs[3];
+ char devname[DEVNAME_SIZE];
+
+#ifdef CONFIG_MALI_NO_MALI
+ void *model;
+ struct kmem_cache *irq_slab;
+ struct workqueue_struct *irq_workq;
+ atomic_t serving_job_irq;
+ atomic_t serving_gpu_irq;
+ atomic_t serving_mmu_irq;
+ spinlock_t reg_op_lock;
+#endif /* CONFIG_MALI_NO_MALI */
+} kbase_os_device;
+
+#if defined(MALI_KERNEL_TEST_API)
+#if (1 == MALI_KERNEL_TEST_API)
+#define KBASE_EXPORT_TEST_API(func) EXPORT_SYMBOL(func);
+#else
+#define KBASE_EXPORT_TEST_API(func)
+#endif
+#else
+#define KBASE_EXPORT_TEST_API(func)
+#endif
+
+#define KBASE_EXPORT_SYMBOL(func) EXPORT_SYMBOL(func);
+
+#endif /* _KBASE_LINUX_H_ */
diff --git a/drivers/gpu/arm/t6xx/kbase/src/linux/mali_kbase_mem_linux.c b/drivers/gpu/arm/t6xx/kbase/src/linux/mali_kbase_mem_linux.c
new file mode 100644
index 0000000..b15e862
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/linux/mali_kbase_mem_linux.c
@@ -0,0 +1,793 @@
+/*
+ *
+ * (C) COPYRIGHT 2010-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_kbase_mem_linux.c
+ * Base kernel memory APIs, Linux implementation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bug.h>
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/dma-mapping.h>
+#ifdef CONFIG_DMA_SHARED_BUFFER
+#include <linux/dma-buf.h>
+#endif /* defined(CONFIG_DMA_SHARED_BUFFER) */
+
+#include <kbase/src/common/mali_kbase.h>
+#include <kbase/src/linux/mali_kbase_mem_linux.h>
+
+static int kbase_tracking_page_setup(struct kbase_context * kctx, struct vm_area_struct * vma);
+
+struct kbase_va_region *kbase_pmem_alloc(kbase_context *kctx, u32 size,
+ u32 flags, u16 *pmem_cookie)
+{
+ struct kbase_va_region *reg;
+ u16 cookie;
+
+ OSK_ASSERT(kctx != NULL);
+ OSK_ASSERT(pmem_cookie != NULL);
+
+ if ( 0 == size )
+ {
+ goto out1;
+ }
+
+ if (!kbase_check_alloc_flags(flags))
+ {
+ goto out1;
+ }
+
+ reg = kbase_alloc_free_region(kctx, 0, size, KBASE_REG_ZONE_PMEM);
+ if (!reg)
+ goto out1;
+
+ reg->flags &= ~KBASE_REG_FREE;
+
+ kbase_update_region_flags(reg, flags, MALI_FALSE);
+
+ if (kbase_alloc_phy_pages(reg, size, size))
+ goto out2;
+
+ reg->nr_alloc_pages = size;
+ reg->extent = 0;
+
+ kbase_gpu_vm_lock(kctx);
+ if (!kctx->osctx.cookies)
+ goto out3;
+
+ cookie = __ffs(kctx->osctx.cookies);
+ kctx->osctx.cookies &= ~(1UL << cookie);
+ reg->flags &= ~KBASE_REG_COOKIE_MASK;
+ reg->flags |= KBASE_REG_COOKIE(cookie);
+
+ OSK_DLIST_PUSH_FRONT(&kctx->osctx.reg_pending, reg,
+ struct kbase_va_region, link);
+
+ *pmem_cookie = cookie;
+ kbase_gpu_vm_unlock(kctx);
+
+ return reg;
+
+out3:
+ kbase_gpu_vm_unlock(kctx);
+ kbase_free_phy_pages(reg);
+out2:
+ kfree(reg);
+out1:
+ return NULL;
+
+}
+KBASE_EXPORT_TEST_API(kbase_pmem_alloc)
+
+/*
+ * Callback for munmap(). PMEM receives a special treatment, as it
+ * frees the memory at the same time it gets unmapped. This avoids the
+ * map/unmap race where map reuses a memory range that has been
+ * unmapped from CPU, but still mapped on GPU.
+ */
+STATIC void kbase_cpu_vm_close(struct vm_area_struct *vma)
+{
+ struct kbase_va_region *reg = vma->vm_private_data;
+ kbase_context *kctx = reg->kctx;
+ mali_error err;
+
+ kbase_gpu_vm_lock(kctx);
+
+ err = kbase_cpu_free_mapping(reg, vma);
+ if (!err &&
+ (reg->flags & KBASE_REG_ZONE_MASK) == KBASE_REG_ZONE_PMEM)
+ {
+ kbase_mem_free_region(kctx, reg);
+ }
+
+ kbase_gpu_vm_unlock(kctx);
+}
+KBASE_EXPORT_TEST_API(kbase_cpu_vm_close)
+
+static const struct vm_operations_struct kbase_vm_ops = {
+ .close = kbase_cpu_vm_close,
+};
+
+static int kbase_cpu_mmap(struct kbase_va_region *reg, struct vm_area_struct *vma, void *kaddr, u32 nr_pages)
+{
+ struct kbase_cpu_mapping *map;
+ u64 start_off = vma->vm_pgoff - reg->start_pfn;
+ osk_phy_addr *page_array;
+ int err = 0;
+ int i;
+
+ if(OSK_SIMULATE_FAILURE(OSK_OSK))
+ {
+ map = NULL;
+ }
+ else
+ {
+ map = kzalloc(sizeof(*map), GFP_KERNEL);
+ }
+
+ if (!map)
+ {
+ WARN_ON(1);
+ err = -ENOMEM;
+ goto out;
+ }
+
+ /*
+ * VM_DONTCOPY - don't make this mapping available in fork'ed processes
+ * VM_DONTEXPAND - disable mremap on this region
+ * VM_RESERVED & VM_IO - disables paging
+ * VM_MIXEDMAP - Support mixing struct page*s and raw pfns.
+ * This is needed to support using the dedicated and
+ * the OS based memory backends together.
+ */
+ /*
+ * This will need updating to propagate coherency flags
+ * See MIDBASE-1057
+ */
+ vma->vm_flags |= VM_DONTCOPY | VM_DONTEXPAND | VM_RESERVED | VM_IO | VM_MIXEDMAP;
+ vma->vm_ops = &kbase_vm_ops;
+ vma->vm_private_data = reg;
+
+ page_array = kbase_get_phy_pages(reg);
+
+ if (!(reg->flags & KBASE_REG_CPU_CACHED))
+ {
+ /* We can't map vmalloc'd memory uncached.
+ * Other memory will have been returned from
+ * osk_phy_pages_alloc which should have done the cache
+ * maintenance necessary to support an uncached mapping
+ */
+ BUG_ON(kaddr);
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+ }
+
+ if (!kaddr)
+ {
+ for (i = 0; i < nr_pages; i++)
+ {
+ err = vm_insert_mixed(vma, vma->vm_start + (i << PAGE_SHIFT), page_array[i + start_off] >> PAGE_SHIFT);
+ WARN_ON(err);
+ if (err)
+ break;
+ }
+ }
+ else
+ {
+ /* vmalloc remaping is easy... */
+ err = remap_vmalloc_range(vma, kaddr, 0);
+ WARN_ON(err);
+ }
+
+ if (err)
+ {
+ kfree(map);
+ goto out;
+ }
+
+ map->uaddr = (osk_virt_addr)vma->vm_start;
+ map->nr_pages = nr_pages;
+ map->page_off = start_off;
+ map->private = vma;
+
+ if ( (reg->flags & KBASE_REG_ZONE_MASK) == KBASE_REG_ZONE_TMEM)
+ {
+ kbase_process_page_usage_dec(reg->kctx, nr_pages);
+ }
+
+ OSK_DLIST_PUSH_FRONT(®->map_list, map,
+ struct kbase_cpu_mapping, link);
+
+out:
+ return err;
+}
+
+static int kbase_trace_buffer_mmap(kbase_context * kctx, struct vm_area_struct * vma, struct kbase_va_region **reg, void **kaddr)
+{
+ struct kbase_va_region *new_reg;
+ u32 nr_pages;
+ size_t size;
+ int err = 0;
+ u32 * tb;
+
+ pr_debug("in %s\n", __func__);
+ size = (vma->vm_end - vma->vm_start);
+ nr_pages = size >> PAGE_SHIFT;
+
+ if (!kctx->jctx.tb)
+ {
+ if(OSK_SIMULATE_FAILURE(OSK_OSK))
+ {
+ tb = NULL;
+ }
+ else
+ {
+ OSK_ASSERT(0 != size);
+ tb = vmalloc_user(size);
+ }
+
+ if (NULL == tb)
+ {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ kbase_device_trace_buffer_install(kctx, tb, size);
+ }
+ else
+ {
+ err = -EINVAL;
+ goto out;
+ }
+
+ *kaddr = kctx->jctx.tb;
+
+ new_reg = kbase_alloc_free_region(kctx, 0, nr_pages, KBASE_REG_ZONE_PMEM);
+ if (!new_reg)
+ {
+ err = -ENOMEM;
+ WARN_ON(1);
+ goto out_disconnect;
+ }
+
+ new_reg->flags &= ~KBASE_REG_FREE;
+ new_reg->flags |= KBASE_REG_IS_TB | KBASE_REG_CPU_CACHED;
+ new_reg->nr_alloc_pages = nr_pages;
+
+ if (MALI_ERROR_NONE != kbase_add_va_region(kctx, new_reg, vma->vm_start, nr_pages, 1))
+ {
+ err = -ENOMEM;
+ WARN_ON(1);
+ goto out_va_region;
+ }
+
+ *reg = new_reg;
+
+ /* map read only, noexec */
+ vma->vm_flags &= ~(VM_WRITE|VM_EXEC);
+ /* the rest of the flags is added by the cpu_mmap handler */
+
+ pr_debug("%s done\n", __func__);
+ return 0;
+
+out_va_region:
+ kbase_free_alloced_region(new_reg);
+out_disconnect:
+ kbase_device_trace_buffer_uninstall(kctx);
+ vfree(tb);
+out:
+ return err;
+
+}
+
+static int kbase_mmu_dump_mmap( kbase_context *kctx,
+ struct vm_area_struct *vma,
+ struct kbase_va_region **reg,
+ void **kmap_addr )
+{
+ struct kbase_va_region *new_reg;
+ void *kaddr;
+ u32 nr_pages;
+ size_t size;
+ int err = 0;
+
+ pr_debug("in kbase_mmu_dump_mmap\n");
+ size = (vma->vm_end - vma->vm_start);
+ nr_pages = size >> PAGE_SHIFT;
+
+ kaddr = kbase_mmu_dump(kctx, nr_pages);
+
+ if (!kaddr)
+ {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ new_reg = kbase_alloc_free_region(kctx, 0, nr_pages, KBASE_REG_ZONE_PMEM);
+ if (!new_reg)
+ {
+ err = -ENOMEM;
+ WARN_ON(1);
+ goto out;
+ }
+
+ new_reg->flags &= ~KBASE_REG_FREE;
+ new_reg->flags |= KBASE_REG_IS_MMU_DUMP | KBASE_REG_CPU_CACHED;
+ new_reg->nr_alloc_pages = nr_pages;
+
+ if (MALI_ERROR_NONE != kbase_add_va_region(kctx, new_reg, vma->vm_start, nr_pages, 1))
+ {
+ err = -ENOMEM;
+ WARN_ON(1);
+ goto out_va_region;
+ }
+
+ *kmap_addr = kaddr;
+ *reg = new_reg;
+
+ pr_debug("kbase_mmu_dump_mmap done\n");
+ return 0;
+
+out_va_region:
+ kbase_free_alloced_region(new_reg);
+out:
+ return err;
+}
+
+/* must be called with the gpu vm lock held */
+
+struct kbase_va_region * kbase_lookup_cookie(kbase_context * kctx, mali_addr64 cookie)
+{
+ struct kbase_va_region * reg;
+ mali_addr64 test_cookie;
+
+ OSK_ASSERT(kctx != NULL);
+ BUG_ON(!mutex_is_locked(&kctx->reg_lock));
+
+ test_cookie = KBASE_REG_COOKIE(cookie);
+
+ OSK_DLIST_FOREACH(&kctx->osctx.reg_pending, struct kbase_va_region, link, reg)
+ {
+ if ((reg->flags & KBASE_REG_COOKIE_MASK) == test_cookie)
+ {
+ return reg;
+ }
+ }
+
+ return NULL; /* not found */
+}
+KBASE_EXPORT_TEST_API(kbase_lookup_cookie)
+
+void kbase_unlink_cookie(kbase_context * kctx, mali_addr64 cookie, struct kbase_va_region * reg)
+{
+ int err;
+ OSKP_ASSERT(kctx != NULL);
+ OSKP_ASSERT(reg != NULL);
+ OSKP_ASSERT(MALI_TRUE == OSK_DLIST_MEMBER_OF(&kctx->osctx.reg_pending, reg, link));
+ OSKP_ASSERT(KBASE_REG_COOKIE(cookie) == (reg->flags & KBASE_REG_COOKIE_MASK));
+ OSKP_ASSERT((kctx->osctx.cookies & (1UL << cookie)) == 0);
+
+ OSK_DLIST_REMOVE(&kctx->osctx.reg_pending, reg, link, err);
+ kctx->osctx.cookies |= (1UL << cookie); /* mark as resolved */
+}
+
+KBASE_EXPORT_TEST_API(kbase_unlink_cookie)
+
+void kbase_os_mem_map_lock(kbase_context * kctx)
+{
+ struct mm_struct * mm = current->mm;
+ (void)kctx;
+ down_read(&mm->mmap_sem);
+}
+
+void kbase_os_mem_map_unlock(kbase_context * kctx)
+{
+ struct mm_struct * mm = current->mm;
+ (void)kctx;
+ up_read(&mm->mmap_sem);
+}
+
+int kbase_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ kbase_context *kctx = file->private_data;
+ struct kbase_va_region *reg;
+ void *kaddr = NULL;
+ u32 nr_pages;
+ int err = 0;
+
+ pr_debug("kbase_mmap\n");
+ nr_pages = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+
+ if ( 0 == nr_pages )
+ {
+ err = -EINVAL;
+ goto out;
+ }
+
+ kbase_gpu_vm_lock(kctx);
+
+ if (vma->vm_pgoff == KBASE_REG_COOKIE_MTP)
+ {
+ /* The non-mapped tracking helper page */
+ err = kbase_tracking_page_setup(kctx, vma);
+ goto out_unlock;
+ }
+
+ /* if not the MTP, verify that the MTP has been mapped */
+ rcu_read_lock();
+ /* catches both when the special page isn't present or when we've forked */
+ if (rcu_dereference(kctx->process_mm) != current->mm)
+ {
+ err = -EINVAL;
+ rcu_read_unlock();
+ goto out_unlock;
+ }
+ rcu_read_unlock();
+
+
+ if (vma->vm_pgoff == KBASE_REG_COOKIE_RB)
+ {
+ /* Ring buffer doesn't exist any more */
+ err = -EINVAL;
+ goto out_unlock;
+ }
+ else if (vma->vm_pgoff == KBASE_REG_COOKIE_TB)
+ {
+ err = kbase_trace_buffer_mmap(kctx, vma, ®, &kaddr);
+ if (0 != err)
+ goto out_unlock;
+ pr_debug("kbase_trace_buffer_mmap ok\n");
+ goto map;
+ }
+ else if (vma->vm_pgoff == KBASE_REG_COOKIE_MMU_DUMP)
+ {
+ /* MMU dump */
+ if ((err = kbase_mmu_dump_mmap(kctx, vma, ®, &kaddr)))
+ goto out_unlock;
+
+ goto map;
+ }
+
+ if (vma->vm_pgoff < PAGE_SIZE) /* first page is reserved for cookie resolution */
+ {
+ /* PMEM stuff, fetch the right region */
+ reg = kbase_lookup_cookie(kctx, vma->vm_pgoff);
+
+ if (NULL != reg)
+ {
+ if (reg->nr_pages != nr_pages)
+ {
+ /* incorrect mmap size */
+ /* leave the cookie for a potential later mapping, or to be reclaimed later when the context is freed */
+ err = -ENOMEM;
+ goto out_unlock;
+ }
+
+ kbase_unlink_cookie(kctx, vma->vm_pgoff, reg);
+
+ if (MALI_ERROR_NONE != kbase_gpu_mmap(kctx, reg, vma->vm_start, nr_pages, 1))
+ {
+ /* Unable to map in GPU space. Recover from kbase_unlink_cookie */
+ OSK_DLIST_PUSH_FRONT(&kctx->osctx.reg_pending, reg, struct kbase_va_region, link);
+ kctx->osctx.cookies &= ~(1UL << vma->vm_pgoff);
+ WARN_ON(1);
+ err = -ENOMEM;
+ goto out_unlock;
+ }
+
+ /*
+ * Overwrite the offset with the
+ * region start_pfn, so we effectively
+ * map from offset 0 in the region.
+ */
+ vma->vm_pgoff = reg->start_pfn;
+ goto map;
+ }
+
+ err = -ENOMEM;
+ goto out_unlock;
+ }
+ else if (vma->vm_pgoff < KBASE_REG_ZONE_EXEC_BASE)
+ {
+ /* invalid offset as it identifies an already mapped pmem */
+ err = -ENOMEM;
+ goto out_unlock;
+ }
+ else
+ {
+ u32 zone;
+
+ /* TMEM case or EXEC case */
+ if (vma->vm_pgoff < KBASE_REG_ZONE_TMEM_BASE)
+ {
+ zone = KBASE_REG_ZONE_EXEC;
+ }
+ else
+ {
+ zone = KBASE_REG_ZONE_TMEM;
+ }
+
+ reg = kbase_region_tracker_find_region_enclosing_range( kctx, vma->vm_pgoff, nr_pages );
+ if( reg &&
+ (reg->flags & (KBASE_REG_ZONE_MASK | KBASE_REG_FREE )) == zone )
+ {
+#ifdef CONFIG_DMA_SHARED_BUFFER
+ if (reg->imported_type == BASE_TMEM_IMPORT_TYPE_UMM)
+ {
+ goto dma_map;
+ }
+#endif /* CONFIG_DMA_SHARED_BUFFER */
+ goto map;
+ }
+
+ err = -ENOMEM;
+ goto out_unlock;
+ }
+map:
+ err = kbase_cpu_mmap(reg, vma, kaddr, nr_pages);
+
+ if (vma->vm_pgoff == KBASE_REG_COOKIE_MMU_DUMP) {
+ /* MMU dump - userspace should now have a reference on
+ * the pages, so we can now free the kernel mapping */
+ vfree(kaddr);
+ }
+ goto out_unlock;
+
+#ifdef CONFIG_DMA_SHARED_BUFFER
+dma_map:
+ err = dma_buf_mmap(reg->imported_metadata.umm.dma_buf, vma, vma->vm_pgoff - reg->start_pfn);
+#endif /* CONFIG_DMA_SHARED_BUFFER */
+out_unlock:
+ kbase_gpu_vm_unlock(kctx);
+out:
+ if (err)
+ {
+ pr_err("mmap failed %d\n", err);
+ }
+ return err;
+}
+KBASE_EXPORT_TEST_API(kbase_mmap)
+
+mali_error kbase_create_os_context(kbase_os_context *osctx)
+{
+ OSK_ASSERT(osctx != NULL);
+
+ OSK_DLIST_INIT(&osctx->reg_pending);
+ osctx->cookies = ~KBASE_REG_RESERVED_COOKIES;
+ osctx->tgid = current->tgid;
+ init_waitqueue_head(&osctx->event_queue);
+
+ return MALI_ERROR_NONE;
+}
+KBASE_EXPORT_TEST_API(kbase_create_os_context)
+
+static void kbase_reg_pending_dtor(struct kbase_va_region *reg)
+{
+ kbase_free_phy_pages(reg);
+ pr_info("Freeing pending unmapped region\n");
+ kfree(reg);
+}
+
+void kbase_destroy_os_context(kbase_os_context *osctx)
+{
+ OSK_ASSERT(osctx != NULL);
+
+ OSK_DLIST_EMPTY_LIST(&osctx->reg_pending, struct kbase_va_region,
+ link, kbase_reg_pending_dtor);
+}
+KBASE_EXPORT_TEST_API(kbase_destroy_os_context)
+
+void *kbase_va_alloc(kbase_context *kctx, u32 size)
+{
+ void *va;
+ u32 pages = ((size-1) >> PAGE_SHIFT) + 1;
+ struct kbase_va_region *reg;
+ osk_phy_addr *page_array;
+ u32 flags = BASE_MEM_PROT_CPU_RD | BASE_MEM_PROT_CPU_WR |
+ BASE_MEM_PROT_GPU_RD | BASE_MEM_PROT_GPU_WR;
+ int i;
+
+ OSK_ASSERT(kctx != NULL);
+
+ if (size == 0)
+ {
+ goto err;
+ }
+
+ if(OSK_SIMULATE_FAILURE(OSK_OSK))
+ {
+ va = NULL;
+ }
+ else
+ {
+ OSK_ASSERT(0 != size);
+ va = vmalloc_user(size);
+ }
+
+ if (!va)
+ {
+ goto err;
+ }
+
+ kbase_gpu_vm_lock(kctx);
+
+ reg = kbase_alloc_free_region(kctx, 0, pages, KBASE_REG_ZONE_PMEM);
+ if (!reg)
+ {
+ goto vm_unlock;
+ }
+
+ reg->flags &= ~KBASE_REG_FREE;
+ kbase_update_region_flags(reg, flags, MALI_FALSE);
+
+ reg->nr_alloc_pages = pages;
+ reg->extent = 0;
+
+ if(OSK_SIMULATE_FAILURE(OSK_OSK))
+ {
+ page_array = NULL;
+ }
+ else
+ {
+ OSK_ASSERT(0 != pages);
+ page_array = vmalloc_user(pages * sizeof(*page_array));
+ }
+
+ if (!page_array)
+ {
+ goto free_reg;
+ }
+
+ for (i = 0; i < pages; i++)
+ {
+ uintptr_t addr;
+ struct page *page;
+ addr = (uintptr_t)va + (i << PAGE_SHIFT);
+ page = vmalloc_to_page((void *)addr);
+ page_array[i] = PFN_PHYS(page_to_pfn(page));
+ }
+
+ kbase_set_phy_pages(reg, page_array);
+
+ if (kbase_gpu_mmap(kctx, reg, (uintptr_t)va, pages, 1))
+ {
+ goto free_array;
+ }
+
+ kbase_gpu_vm_unlock(kctx);
+
+ return va;
+
+free_array:
+ vfree(page_array);
+free_reg:
+ kfree(reg);
+vm_unlock:
+ kbase_gpu_vm_unlock(kctx);
+ vfree(va);
+err:
+ return NULL;
+}
+KBASE_EXPORT_SYMBOL(kbase_va_alloc)
+
+void kbasep_os_process_page_usage_update( kbase_context *kctx, int pages )
+{
+ struct mm_struct *mm;
+
+ rcu_read_lock();
+ mm = rcu_dereference(kctx->process_mm);
+ if (mm)
+ {
+ atomic_add(pages, &kctx->nonmapped_pages);
+#ifdef SPLIT_RSS_COUNTING
+ add_mm_counter(mm, MM_FILEPAGES, pages);
+#else
+ spin_lock(&mm->page_table_lock);
+ add_mm_counter(mm, MM_FILEPAGES, pages);
+ spin_unlock(&mm->page_table_lock);
+#endif
+ }
+ rcu_read_unlock();
+}
+
+static void kbasep_os_process_page_usage_drain(kbase_context * kctx)
+{
+ int pages;
+ struct mm_struct * mm;
+
+ spin_lock(&kctx->mm_update_lock);
+ mm = rcu_dereference_protected(kctx->process_mm, lockdep_is_held(&kctx->mm_update_lock));
+ if (!mm)
+ {
+ spin_unlock(&kctx->mm_update_lock);
+ return;
+ }
+
+ rcu_assign_pointer(kctx->process_mm, NULL);
+ spin_unlock(&kctx->mm_update_lock);
+ synchronize_rcu();
+
+ pages = atomic_xchg(&kctx->nonmapped_pages, 0);
+#ifdef SPLIT_RSS_COUNTING
+ add_mm_counter(mm, MM_FILEPAGES, -pages);
+#else
+ spin_lock(&mm->page_table_lock);
+ add_mm_counter(mm, MM_FILEPAGES, -pages);
+ spin_unlock(&mm->page_table_lock);
+#endif
+}
+
+static void kbase_special_vm_close(struct vm_area_struct *vma)
+{
+ kbase_context * kctx;
+ kctx = vma->vm_private_data;
+ kbasep_os_process_page_usage_drain(kctx);
+}
+
+static const struct vm_operations_struct kbase_vm_special_ops = {
+ .close = kbase_special_vm_close,
+};
+
+static int kbase_tracking_page_setup(struct kbase_context * kctx, struct vm_area_struct * vma)
+{
+ /* check that this is the only tracking page */
+ spin_lock(&kctx->mm_update_lock);
+ if (rcu_dereference_protected(kctx->process_mm, lockdep_is_held(&kctx->mm_update_lock)))
+ {
+ spin_unlock(&kctx->mm_update_lock);
+ return -EFAULT;
+ }
+
+ rcu_assign_pointer(kctx->process_mm, current->mm);
+
+ spin_unlock(&kctx->mm_update_lock);
+
+ /* no real access */
+ vma->vm_flags &= ~(VM_READ | VM_WRITE | VM_EXEC);
+ vma->vm_flags |= VM_DONTCOPY | VM_DONTEXPAND | VM_RESERVED | VM_IO;
+ vma->vm_ops = &kbase_vm_special_ops;
+ vma->vm_private_data = kctx;
+
+ return 0;
+}
+
+void kbase_va_free(kbase_context *kctx, void *va)
+{
+ struct kbase_va_region *reg;
+ osk_phy_addr *page_array;
+ mali_error err;
+
+ OSK_ASSERT(kctx != NULL);
+ OSK_ASSERT(va != NULL);
+
+ kbase_gpu_vm_lock(kctx);
+
+ reg = kbase_region_tracker_find_region_base_address(kctx, (uintptr_t)va);
+ OSK_ASSERT(reg);
+
+ err = kbase_gpu_munmap(kctx, reg);
+ OSK_ASSERT(err == MALI_ERROR_NONE);
+
+ page_array = kbase_get_phy_pages(reg);
+ vfree(page_array);
+
+ kfree(reg);
+
+ kbase_gpu_vm_unlock(kctx);
+
+ vfree(va);
+}
+KBASE_EXPORT_SYMBOL(kbase_va_free)
+
diff --git a/drivers/gpu/arm/t6xx/kbase/src/linux/mali_kbase_mem_linux.h b/drivers/gpu/arm/t6xx/kbase/src/linux/mali_kbase_mem_linux.h
new file mode 100644
index 0000000..a4af8c0
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/linux/mali_kbase_mem_linux.h
@@ -0,0 +1,42 @@
+/*
+ *
+ * (C) COPYRIGHT 2010, 2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_kbase_mem_linux.h
+ * Base kernel memory APIs, Linux implementation.
+ */
+
+#ifndef _KBASE_MEM_LINUX_H_
+#define _KBASE_MEM_LINUX_H_
+
+struct kbase_va_region *kbase_pmem_alloc(kbase_context *kctx, u32 size,
+ u32 flags, u16 *pmem_cookie);
+int kbase_mmap(struct file *file, struct vm_area_struct *vma);
+
+/* @brief Allocate memory from kernel space and map it onto the GPU
+ *
+ * @param kctx The context used for the allocation/mapping
+ * @param size The size of the allocation in bytes
+ * @return the VA for kernel space and GPU MMU
+ */
+void *kbase_va_alloc(kbase_context *kctx, u32 size);
+
+/* @brief Free/unmap memory allocated by kbase_va_alloc
+ *
+ * @param kctx The context used for the allocation/mapping
+ * @param va The VA returned by kbase_va_alloc
+ */
+void kbase_va_free(kbase_context *kctx, void *va);
+
+#endif /* _KBASE_MEM_LINUX_H_ */
diff --git a/drivers/gpu/arm/t6xx/kbase/src/linux/mali_kbase_sync.c b/drivers/gpu/arm/t6xx/kbase/src/linux/mali_kbase_sync.c
new file mode 100644
index 0000000..388770f
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/linux/mali_kbase_sync.c
@@ -0,0 +1,203 @@
+/*
+ *
+ * (C) COPYRIGHT 2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_kbase_sync.c
+ *
+ */
+
+#ifdef CONFIG_SYNC
+
+#include <linux/sync.h>
+#include <kbase/src/common/mali_kbase.h>
+
+struct mali_sync_timeline
+{
+ struct sync_timeline timeline;
+ atomic_t counter;
+ atomic_t signalled;
+};
+
+struct mali_sync_pt
+{
+ struct sync_pt pt;
+ u32 order;
+ int result;
+};
+
+static struct mali_sync_timeline *to_mali_sync_timeline(struct sync_timeline *timeline)
+{
+ return container_of(timeline, struct mali_sync_timeline, timeline);
+}
+
+static struct mali_sync_pt *to_mali_sync_pt(struct sync_pt *pt)
+{
+ return container_of(pt, struct mali_sync_pt, pt);
+}
+
+static struct sync_pt *timeline_dup(struct sync_pt *pt)
+{
+ struct mali_sync_pt *mpt = to_mali_sync_pt(pt);
+ struct mali_sync_pt *new_mpt;
+ struct sync_pt *new_pt = sync_pt_create(pt->parent, sizeof(struct mali_sync_pt));
+
+ if (!new_pt)
+ {
+ return NULL;
+ }
+
+ new_mpt = to_mali_sync_pt(new_pt);
+ new_mpt->order = mpt->order;
+ new_mpt->result = mpt->result;
+
+ return new_pt;
+
+}
+
+static int timeline_has_signaled(struct sync_pt *pt)
+{
+ struct mali_sync_pt *mpt = to_mali_sync_pt(pt);
+ struct mali_sync_timeline *mtl = to_mali_sync_timeline(pt->parent);
+ int result = mpt->result;
+
+ long diff = atomic_read(&mtl->signalled) - mpt->order;
+
+ if (diff >= 0)
+ {
+ return result < 0 ? result : 1;
+ }
+ else
+ return 0;
+}
+
+static int timeline_compare(struct sync_pt *a, struct sync_pt *b)
+{
+ struct mali_sync_pt *ma = container_of(a, struct mali_sync_pt, pt);
+ struct mali_sync_pt *mb = container_of(b, struct mali_sync_pt, pt);
+
+ long diff = ma->order - mb->order;
+
+ if (diff < 0)
+ {
+ return -1;
+ }
+ else if (diff == 0)
+ {
+ return 0;
+ }
+ else
+ {
+ return 1;
+ }
+}
+
+static void timeline_value_str(struct sync_timeline *timeline, char * str,
+ int size)
+{
+ struct mali_sync_timeline *mtl = to_mali_sync_timeline(timeline);
+ snprintf(str, size, "%d", mtl->signalled);
+}
+
+static void pt_value_str(struct sync_pt *pt, char *str, int size)
+{
+ struct mali_sync_pt *mpt = to_mali_sync_pt(pt);
+ snprintf(str, size, "%d(%d)", mpt->order, mpt->result);
+}
+
+static struct sync_timeline_ops mali_timeline_ops = {
+ .driver_name = "Mali",
+ .dup = timeline_dup,
+ .has_signaled = timeline_has_signaled,
+ .compare = timeline_compare,
+ .timeline_value_str = timeline_value_str,
+ .pt_value_str = pt_value_str,
+#if 0
+ .free_pt = timeline_free_pt,
+ .release_obj = timeline_release_obj
+#endif
+};
+
+int kbase_sync_timeline_is_ours(struct sync_timeline *timeline)
+{
+ return (timeline->ops == &mali_timeline_ops);
+}
+
+struct sync_timeline *kbase_sync_timeline_alloc(const char * name)
+{
+ struct sync_timeline *tl;
+ struct mali_sync_timeline *mtl;
+
+ tl = sync_timeline_create(&mali_timeline_ops,
+ sizeof(struct mali_sync_timeline), name);
+ if (!tl)
+ {
+ return NULL;
+ }
+
+ /* Set the counter in our private struct */
+ mtl = to_mali_sync_timeline(tl);
+ atomic_set(&mtl->counter, 0);
+ atomic_set(&mtl->signalled, 0);
+
+ return tl;
+}
+
+struct sync_pt *kbase_sync_pt_alloc(struct sync_timeline *parent)
+{
+ struct sync_pt *pt = sync_pt_create(parent, sizeof(struct mali_sync_pt));
+ struct mali_sync_timeline *mtl = to_mali_sync_timeline(parent);
+ struct mali_sync_pt *mpt;
+
+ if (!pt)
+ {
+ return NULL;
+ }
+
+ mpt = to_mali_sync_pt(pt);
+ mpt->order = atomic_inc_return(&mtl->counter);
+ mpt->result = 0;
+
+ return pt;
+}
+
+void kbase_sync_signal_pt(struct sync_pt *pt, int result)
+{
+ struct mali_sync_pt *mpt = to_mali_sync_pt(pt);
+ struct mali_sync_timeline *mtl = to_mali_sync_timeline(pt->parent);
+ int signalled;
+ long diff;
+
+ mpt->result = result;
+
+ do {
+
+ signalled = atomic_read(&mtl->signalled);
+
+ diff = signalled - mpt->order;
+
+ if (diff > 0)
+ {
+ /* The timeline is already at or ahead of this point. This should not happen unless userspace
+ * has been signalling fences out of order, so warn but don't violate the sync_pt API.
+ * The warning is only in release builds to prevent a malicious user being able to spam dmesg.
+ */
+#ifdef CONFIG_MALI_DEBUG
+ OSK_PRINT_ERROR(OSK_BASE_JD, "Fence's were triggered in a different order to allocation!");
+#endif /* CONFIG_MALI_DEBUG */
+ return;
+ }
+ } while (atomic_cmpxchg(&mtl->signalled, signalled, mpt->order) != signalled);
+}
+
+#endif /* CONFIG_SYNC */
diff --git a/drivers/gpu/arm/t6xx/kbase/src/linux/mali_kbase_sync.h b/drivers/gpu/arm/t6xx/kbase/src/linux/mali_kbase_sync.h
new file mode 100644
index 0000000..6e4130e
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/linux/mali_kbase_sync.h
@@ -0,0 +1,79 @@
+/*
+ *
+ * (C) COPYRIGHT 2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_kbase_sync.h
+ *
+ */
+
+#ifndef MALI_KBASE_SYNC_H
+#define MALI_KBASE_SYNC_H
+
+#include <linux/sync.h>
+#include <malisw/mali_malisw.h>
+
+/*
+ * Create a stream object.
+ * Built on top of timeline object.
+ * Exposed as a file descriptor.
+ * Life-time controlled via the file descriptor:
+ * - dup to add a ref
+ * - close to remove a ref
+ */
+mali_error kbase_stream_create(const char * name, int * out_fd);
+
+/*
+ * Create a fence in a stream object
+ */
+int kbase_stream_create_fence(int tl_fd);
+
+/*
+ * Validate a fd to be a valid fence
+ * No reference is taken.
+ *
+ * This function is only usable to catch unintentional user errors early,
+ * it does not stop malicious code changing the fd after this function returns.
+ */
+mali_error kbase_fence_validate(int fd);
+
+
+/* Returns true if the specified timeline is allocated by Mali */
+int kbase_sync_timeline_is_ours(struct sync_timeline *timeline);
+
+/* Allocates a timeline for Mali
+ *
+ * One timeline should be allocated per API context.
+ */
+struct sync_timeline *kbase_sync_timeline_alloc(const char * name);
+
+/* Allocates a sync point within the timeline.
+ *
+ * The timeline must be the one allocated by kbase_sync_timeline_alloc
+ *
+ * Sync points must be triggered in *exactly* the same order as they are allocated.
+ */
+struct sync_pt *kbase_sync_pt_alloc(struct sync_timeline *parent);
+
+/* Signals a particular sync point
+ *
+ * Sync points must be triggered in *exactly* the same order as they are allocated.
+ *
+ * If they are signalled in the wrong order then a message will be printed in debug
+ * builds and otherwise attempts to signal order sync_pts will be ignored.
+ *
+ * result can be negative to indicate error, any other value is interpreted as success.
+ */
+void kbase_sync_signal_pt(struct sync_pt *pt, int result);
+
+#endif
diff --git a/drivers/gpu/arm/t6xx/kbase/src/linux/mali_kbase_sync_user.c b/drivers/gpu/arm/t6xx/kbase/src/linux/mali_kbase_sync_user.c
new file mode 100644
index 0000000..8e6c1816
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/linux/mali_kbase_sync_user.c
@@ -0,0 +1,153 @@
+/*
+ *
+ * (C) COPYRIGHT 2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+/**
+ * @file mali_kbase_sync_user.c
+ *
+ */
+
+#ifdef CONFIG_SYNC
+
+#include <linux/sched.h>
+#include <linux/fdtable.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/anon_inodes.h>
+#include <linux/version.h>
+#include <asm/uaccess.h>
+#include <kbase/src/linux/mali_kbase_sync.h>
+#include <kbase/mali_base_kernel_sync.h>
+
+static int kbase_stream_close(struct inode * inode, struct file * file)
+{
+ struct sync_timeline * tl;
+ tl = (struct sync_timeline*)file->private_data;
+ BUG_ON(!tl);
+ sync_timeline_destroy(tl);
+ return 0;
+}
+
+static struct file_operations stream_fops =
+{
+ .owner = THIS_MODULE,
+ .release = kbase_stream_close,
+};
+
+mali_error kbase_stream_create(const char * name, int * out_fd)
+{
+ struct sync_timeline * tl;
+ BUG_ON(!out_fd);
+
+ tl = kbase_sync_timeline_alloc(name);
+ if (!tl)
+ {
+ return MALI_ERROR_FUNCTION_FAILED;
+ }
+
+ *out_fd = anon_inode_getfd(name, &stream_fops, tl, O_RDONLY | O_CLOEXEC);
+
+ if (*out_fd < 0)
+ {
+ sync_timeline_destroy(tl);
+ return MALI_ERROR_FUNCTION_FAILED;
+ }
+ else
+ {
+ return MALI_ERROR_NONE;
+ }
+}
+
+int kbase_stream_create_fence(int tl_fd)
+{
+ struct sync_timeline *tl;
+ struct sync_pt * pt;
+ struct sync_fence * fence;
+ struct files_struct * files;
+ struct fdtable * fdt;
+ int fd;
+ struct file *tl_file;
+
+ tl_file = fget(tl_fd);
+ if (tl_file == NULL)
+ return -EBADF;
+
+ if (tl_file->f_op != &stream_fops)
+ {
+ fd = -EBADF;
+ goto out;
+ }
+
+ tl = tl_file->private_data;
+
+ pt = kbase_sync_pt_alloc(tl);
+ if (!pt)
+ {
+ fd = -EFAULT;
+ goto out;
+ }
+
+ fence = sync_fence_create("mali_fence", pt);
+ if (!fence)
+ {
+ sync_pt_free(pt);
+ fd = -EFAULT;
+ goto out;
+ }
+
+ /* from here the fence owns the sync_pt */
+
+ /* create a fd representing the fence */
+ fd = get_unused_fd();
+ if (fd < 0)
+ {
+ sync_fence_put(fence);
+ goto out;
+ }
+
+ files = current->files;
+ spin_lock(&files->file_lock);
+ fdt = files_fdtable(files);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,0)
+ __set_close_on_exec(fd, fdt);
+#else
+ FD_SET(fd, fdt->close_on_exec);
+#endif
+ spin_unlock(&files->file_lock);
+
+ /* bind fence to the new fd */
+ sync_fence_install(fence, fd);
+
+out:
+ fput(tl_file);
+
+ return fd;
+}
+
+mali_error kbase_fence_validate(int fd)
+{
+ struct sync_fence * fence;
+ fence = sync_fence_fdget(fd);
+ if (NULL != fence)
+ {
+ sync_fence_put(fence);
+ return MALI_ERROR_NONE;
+ }
+ else
+ {
+ return MALI_ERROR_FUNCTION_FAILED;
+ }
+}
+
+#endif /* CONFIG_SYNC */
diff --git a/drivers/gpu/arm/t6xx/kbase/src/linux/mali_kbase_ukk_os.c b/drivers/gpu/arm/t6xx/kbase/src/linux/mali_kbase_ukk_os.c
new file mode 100644
index 0000000..65c1671
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/linux/mali_kbase_ukk_os.c
@@ -0,0 +1,58 @@
+/*
+ *
+ * (C) COPYRIGHT 2010, 2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+#include <linux/kernel.h> /* Needed for KERN_INFO */
+#include <linux/init.h> /* Needed for the macros */
+
+#include <osk/mali_osk.h>
+#include <kbase/mali_ukk.h>
+
+mali_error ukk_session_init(ukk_session *ukk_session, ukk_dispatch_function dispatch, u16 version_major, u16 version_minor)
+{
+ OSK_ASSERT(NULL != ukk_session);
+ OSK_ASSERT(NULL != dispatch);
+
+ /* OS independent initialization of UKK context */
+ ukk_session->dispatch = dispatch;
+ ukk_session->version_major = version_major;
+ ukk_session->version_minor = version_minor;
+
+ /* OS specific initialization of UKK context */
+ ukk_session->internal_session.dummy = 0;
+ return MALI_ERROR_NONE;
+}
+
+void ukk_session_term(ukk_session *ukk_session)
+{
+ OSK_ASSERT(NULL != ukk_session);
+}
+
+mali_error ukk_copy_from_user( size_t bytes, void * kernel_buffer, const void * const user_buffer )
+{
+ if ( copy_from_user( kernel_buffer, user_buffer, bytes ) )
+ {
+ return MALI_ERROR_FUNCTION_FAILED;
+ }
+ return MALI_ERROR_NONE;
+}
+
+mali_error ukk_copy_to_user( size_t bytes, void * user_buffer, const void * const kernel_buffer )
+{
+ if ( copy_to_user( user_buffer, kernel_buffer, bytes ) )
+ {
+ return MALI_ERROR_FUNCTION_FAILED;
+ }
+ return MALI_ERROR_NONE;
+}
+
diff --git a/drivers/gpu/arm/t6xx/kbase/src/linux/mali_linux_trace.h b/drivers/gpu/arm/t6xx/kbase/src/linux/mali_linux_trace.h
new file mode 100644
index 0000000..703fa54
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/linux/mali_linux_trace.h
@@ -0,0 +1,240 @@
+/*
+ *
+ * (C) COPYRIGHT 2011-2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+#if !defined(_TRACE_MALI_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_MALI_H
+
+#include <linux/stringify.h>
+#include <linux/tracepoint.h>
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM mali
+#define TRACE_SYSTEM_STRING __stringify(TRACE_SYSTEM)
+#define TRACE_INCLUDE_FILE mali_linux_trace
+
+/**
+ * mali_job_slots_event - called from mali_kbase_core_linux.c
+ * @event_id: ORed together bitfields representing a type of event, made with the GATOR_MAKE_EVENT() macro.
+ */
+TRACE_EVENT(mali_job_slots_event,
+
+ TP_PROTO(unsigned int event_id, unsigned int tgid, unsigned int pid),
+
+ TP_ARGS(event_id, tgid, pid),
+
+ TP_STRUCT__entry(
+ __field( unsigned int, event_id )
+ __field( unsigned int, tgid )
+ __field( unsigned int, pid )
+ ),
+
+ TP_fast_assign(
+ __entry->event_id = event_id;
+ __entry->tgid = tgid;
+ __entry->pid = pid;
+ ),
+
+ TP_printk("event=%u tgid=%u pid=%u", __entry->event_id, __entry->tgid, __entry->pid)
+);
+
+/**
+ * mali_pm_status - Called by mali_kbase_pm_driver.c
+ * @event_id: core type (shader, tiler, l2 cache, l3 cache)
+ * @value: 64bits bitmask reporting either power status of the cores (1-ON, 0-OFF)
+ */
+TRACE_EVENT(mali_pm_status,
+
+ TP_PROTO(unsigned int event_id, unsigned long long value),
+
+ TP_ARGS(event_id, value),
+
+ TP_STRUCT__entry(
+ __field( unsigned int, event_id )
+ __field( unsigned long long, value )
+ ),
+
+ TP_fast_assign(
+ __entry->event_id = event_id;
+ ),
+
+ TP_printk("event %u = %llu", __entry->event_id, __entry->value)
+);
+
+/**
+ * mali_pm_power_on - Called by mali_kbase_pm_driver.c
+ * @event_id: core type (shader, tiler, l2 cache, l3 cache)
+ * @value: 64bits bitmask reporting the cores to power up
+ */
+TRACE_EVENT(mali_pm_power_on,
+
+ TP_PROTO(unsigned int event_id, unsigned long long value),
+
+ TP_ARGS(event_id, value),
+
+ TP_STRUCT__entry(
+ __field( unsigned int, event_id )
+ __field( unsigned long long, value )
+ ),
+
+ TP_fast_assign(
+ __entry->event_id = event_id;
+ ),
+
+ TP_printk("event %u = %llu", __entry->event_id, __entry->value)
+);
+
+/**
+ * mali_pm_power_off - Called by mali_kbase_pm_driver.c
+ * @event_id: core type (shader, tiler, l2 cache, l3 cache)
+ * @value: 64bits bitmask reporting the cores to power down
+ */
+TRACE_EVENT(mali_pm_power_off,
+
+ TP_PROTO(unsigned int event_id, unsigned long long value),
+
+ TP_ARGS(event_id, value),
+
+ TP_STRUCT__entry(
+ __field( unsigned int, event_id )
+ __field( unsigned long long, value )
+ ),
+
+ TP_fast_assign(
+ __entry->event_id = event_id;
+ ),
+
+ TP_printk("event %u = %llu", __entry->event_id, __entry->value)
+);
+
+/**
+ * mali_page_fault_insert_pages - Called by page_fault_worker()
+ * it reports an MMU page fault resulting in new pages being mapped.
+ * @event_id: MMU address space number.
+ * @value: number of newly allocated pages
+ */
+TRACE_EVENT(mali_page_fault_insert_pages,
+
+ TP_PROTO(int event_id, unsigned long value),
+
+ TP_ARGS(event_id, value),
+
+ TP_STRUCT__entry(
+ __field( int, event_id )
+ __field( unsigned long, value )
+ ),
+
+ TP_fast_assign(
+ __entry->event_id = event_id;
+ ),
+
+ TP_printk("event %d = %lu", __entry->event_id, __entry->value)
+);
+
+/**
+ * mali_mmu_as_in_use - Called by assign_and_activate_kctx_addr_space()
+ * it reports that a certain MMU address space is in use now.
+ * @event_id: MMU address space number.
+ */
+TRACE_EVENT(mali_mmu_as_in_use,
+
+ TP_PROTO(int event_id),
+
+ TP_ARGS(event_id),
+
+ TP_STRUCT__entry(
+ __field( int, event_id )
+ ),
+
+ TP_fast_assign(
+ __entry->event_id = event_id;
+ ),
+
+ TP_printk("event=%d", __entry->event_id)
+);
+
+/**
+ * mali_mmu_as_released - Called by kbasep_js_runpool_release_ctx_internal()
+ * it reports that a certain MMU address space has been released now.
+ * @event_id: MMU address space number.
+ */
+TRACE_EVENT(mali_mmu_as_released,
+
+ TP_PROTO(int event_id),
+
+ TP_ARGS(event_id),
+
+ TP_STRUCT__entry(
+ __field( int, event_id )
+ ),
+
+ TP_fast_assign(
+ __entry->event_id = event_id;
+ ),
+
+ TP_printk("event=%d", __entry->event_id)
+);
+
+/**
+ * mali_total_alloc_pages_change - Called by kbase_mem_usage_request_pages()
+ * and by kbase_mem_usage_release_pages
+ * it reports that the total number of allocated pages is changed.
+ * @event_id: number of pages to be added or subtracted (according to the sign).
+ */
+TRACE_EVENT(mali_total_alloc_pages_change,
+
+ TP_PROTO(long long int event_id),
+
+ TP_ARGS(event_id),
+
+ TP_STRUCT__entry(
+ __field( long long int, event_id )
+ ),
+
+ TP_fast_assign(
+ __entry->event_id = event_id;
+ ),
+
+ TP_printk("event=%lld", __entry->event_id)
+);
+
+/**
+ * mali_sw_counter - not currently used
+ * @event_id: counter id
+ */
+TRACE_EVENT(mali_sw_counter,
+
+ TP_PROTO(unsigned int event_id, signed long long value),
+
+ TP_ARGS(event_id, value),
+
+ TP_STRUCT__entry(
+ __field( int, event_id )
+ __field( long long, value )
+ ),
+
+ TP_fast_assign(
+ __entry->event_id = event_id;
+ ),
+
+ TP_printk("event %d = %lld", __entry->event_id, __entry->value)
+);
+
+#endif /* _TRACE_MALI_H */
+
+#undef TRACE_INCLUDE_PATH
+#undef linux
+#define TRACE_INCLUDE_PATH MALI_KBASE_SRC_LINUX_PATH
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/drivers/gpu/arm/t6xx/kbase/src/mali_base_mem_priv.h b/drivers/gpu/arm/t6xx/kbase/src/mali_base_mem_priv.h
new file mode 100644
index 0000000..5bc55c7
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/mali_base_mem_priv.h
@@ -0,0 +1,47 @@
+/*
+ *
+ * (C) COPYRIGHT 2010-2011 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+
+#ifndef _BASE_MEM_PRIV_H_
+#define _BASE_MEM_PRIV_H_
+
+#define BASE_SYNCSET_OP_MSYNC (1U << 0)
+#define BASE_SYNCSET_OP_CSYNC (1U << 1)
+
+/*
+ * This structure describe a basic memory coherency operation.
+ * It can either be:
+ * @li a sync from CPU to Memory:
+ * - type = ::BASE_SYNCSET_OP_MSYNC
+ * - mem_handle = a handle to the memory object on which the operation
+ * is taking place
+ * - user_addr = the address of the range to be synced
+ * - size = the amount of data to be synced, in bytes
+ * - offset is ignored.
+ * @li a sync from Memory to CPU:
+ * - type = ::BASE_SYNCSET_OP_CSYNC
+ * - mem_handle = a handle to the memory object on which the operation
+ * is taking place
+ * - user_addr = the address of the range to be synced
+ * - size = the amount of data to be synced, in bytes.
+ * - offset is ignored.
+ */
+typedef struct basep_syncset
+{
+ mali_addr64 mem_handle;
+ u64 user_addr;
+ u32 size;
+ u8 type;
+} basep_syncset;
+
+#endif
diff --git a/drivers/gpu/arm/t6xx/kbase/src/mali_base_vendor_specific_func.h b/drivers/gpu/arm/t6xx/kbase/src/mali_base_vendor_specific_func.h
new file mode 100644
index 0000000..6324ed9
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/mali_base_vendor_specific_func.h
@@ -0,0 +1,21 @@
+/*
+ *
+ * (C) COPYRIGHT 2010, 2012 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+#ifndef _BASE_VENDOR_SPEC_FUNC_H_
+#define _BASE_VENDOR_SPEC_FUNC_H_
+
+#include <malisw/mali_stdtypes.h>
+
+mali_error kbase_get_vendor_specific_cpu_clock_speed(u32*);
+
+#endif /*_BASE_VENDOR_SPEC_FUNC_H_*/
diff --git a/drivers/gpu/arm/t6xx/kbase/src/platform/mali_kbase_dvfs.c b/drivers/gpu/arm/t6xx/kbase/src/platform/mali_kbase_dvfs.c
new file mode 100644
index 0000000..51b286e
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/platform/mali_kbase_dvfs.c
@@ -0,0 +1,800 @@
+/* drivers/gpu/t6xx/kbase/src/platform/mali_kbase_dvfs.c
+ *
+ * Copyright 2011 by S.LSI. Samsung Electronics Inc.
+ * San#24, Nongseo-Dong, Giheung-Gu, Yongin, Korea
+ *
+ * Samsung SoC Mali-T604 DVFS driver
+ *
+ * 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.
+ */
+
+/**
+ * @file mali_kbase_dvfs.c
+ * DVFS
+ */
+
+#include <osk/mali_osk.h>
+#include <kbase/src/common/mali_kbase.h>
+#include <kbase/src/common/mali_kbase_uku.h>
+#include <kbase/src/common/mali_kbase_mem.h>
+#include <kbase/src/common/mali_midg_regmap.h>
+#include <kbase/src/linux/mali_kbase_mem_linux.h>
+#include <kbase/mali_ukk.h>
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/pci.h>
+#include <linux/miscdevice.h>
+#include <linux/list.h>
+#include <linux/semaphore.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+
+#include <mach/map.h>
+#include <linux/fb.h>
+#include <linux/clk.h>
+#include <mach/regs-clock.h>
+#include <asm/delay.h>
+#include <linux/regulator/consumer.h>
+#include <linux/regulator/driver.h>
+#include <kbase/src/platform/mali_kbase_platform.h>
+#include <kbase/src/platform/mali_kbase_dvfs.h>
+#include <kbase/src/common/mali_kbase_gator.h>
+#ifdef CONFIG_EXYNOS5_CPUFREQ
+#include <mach/cpufreq.h>
+#endif
+#include <mach/exynos5_bus.h>
+
+#ifdef MALI_DVFS_ASV_ENABLE
+#include <mach/asv-exynos.h>
+#define ASV_STATUS_INIT 1
+#define ASV_STATUS_NOT_INIT 0
+#define ASV_STATUS_DISABLE_REQ 2
+
+#define ASV_CMD_DISABLE -1
+#define ASV_CMD_ENABLE 0
+#endif
+
+#ifdef CONFIG_REGULATOR
+static struct regulator *g3d_regulator=NULL;
+#endif
+
+static struct exynos5_bus_mif_handle *mem_freq_req;
+
+/***********************************************************/
+/* This table and variable are using the check time share of GPU Clock */
+/***********************************************************/
+
+typedef struct _mali_dvfs_info{
+ unsigned int voltage;
+ unsigned int clock;
+ int min_threshold;
+ int max_threshold;
+ unsigned long long time;
+ int mem_freq;
+}mali_dvfs_info;
+
+static mali_dvfs_info mali_dvfs_infotbl[] = {
+ {925000, 100, 0, 70, 0, 100000},
+ {925000, 160, 50, 65, 0, 160000},
+ {1025000, 266, 60, 78, 0, 400000},
+ {1075000, 350, 70, 80, 0, 400000},
+ {1125000, 400, 70, 80, 0, 800000},
+ {1150000, 450, 76, 99, 0, 800000},
+ {1200000, 533, 99, 100, 0, 800000},
+};
+
+#define MALI_DVFS_STEP ARRAY_SIZE(mali_dvfs_infotbl)
+
+#ifdef CONFIG_MALI_T6XX_DVFS
+typedef struct _mali_dvfs_status_type{
+ kbase_device *kbdev;
+ int step;
+ int utilisation;
+#ifdef CONFIG_MALI_T6XX_FREQ_LOCK
+ int upper_lock;
+ int under_lock;
+#endif
+#ifdef MALI_DVFS_ASV_ENABLE
+ int asv_status;
+#endif
+}mali_dvfs_status;
+
+static struct workqueue_struct *mali_dvfs_wq = 0;
+spinlock_t mali_dvfs_spinlock;
+struct mutex mali_set_clock_lock;
+struct mutex mali_enable_clock_lock;
+static int kbase_platform_dvfs_get_bw(int level);
+#ifdef CONFIG_MALI_T6XX_DEBUG_SYS
+static void update_time_in_state(int level);
+#endif
+
+/*dvfs status*/
+static mali_dvfs_status mali_dvfs_status_current;
+#ifdef MALI_DVFS_ASV_ENABLE
+static const unsigned int mali_dvfs_vol_default[]=
+ { 925000, 925000, 1025000, 1075000, 1125000, 1150000, 1200000};
+
+
+static int mali_dvfs_update_asv(int cmd)
+{
+ int i;
+ int voltage = 0;
+
+ if (cmd == ASV_CMD_DISABLE) {
+ for (i=0; i<MALI_DVFS_STEP; i++)
+ {
+ mali_dvfs_infotbl[i].voltage = mali_dvfs_vol_default[i];
+ }
+ printk("mali_dvfs_update_asv use default table\n");
+ return ASV_STATUS_INIT;
+ }
+ for (i=0; i<MALI_DVFS_STEP; i++) {
+ voltage = asv_get_volt(ID_G3D, mali_dvfs_infotbl[i].clock*1000);
+ if (voltage == 0) {
+ return ASV_STATUS_NOT_INIT;
+ }
+ mali_dvfs_infotbl[i].voltage = voltage;
+ }
+
+ return ASV_STATUS_INIT;
+}
+#endif
+
+static void mali_dvfs_event_proc(struct work_struct *w)
+{
+ unsigned long flags;
+ mali_dvfs_status *dvfs_status;
+ struct exynos_context *platform;
+
+ mutex_lock(&mali_enable_clock_lock);
+ dvfs_status = &mali_dvfs_status_current;
+
+ if (!kbase_platform_dvfs_get_enable_status()) {
+ mutex_unlock(&mali_enable_clock_lock);
+ return;
+ }
+
+ platform = (struct exynos_context *)dvfs_status->kbdev->platform_context;
+#ifdef MALI_DVFS_ASV_ENABLE
+ if (dvfs_status->asv_status==ASV_STATUS_DISABLE_REQ) {
+ dvfs_status->asv_status=mali_dvfs_update_asv(ASV_CMD_DISABLE);
+ } else if (dvfs_status->asv_status==ASV_STATUS_NOT_INIT) {
+ dvfs_status->asv_status=mali_dvfs_update_asv(ASV_CMD_ENABLE);
+ }
+#endif
+ spin_lock_irqsave(&mali_dvfs_spinlock, flags);
+ if (dvfs_status->utilisation > mali_dvfs_infotbl[dvfs_status->step].max_threshold) {
+ if (dvfs_status->step==kbase_platform_dvfs_get_level(450)) {
+ if (platform->utilisation > mali_dvfs_infotbl[dvfs_status->step].max_threshold)
+ dvfs_status->step++;
+ OSK_ASSERT(dvfs_status->step < MALI_DVFS_STEP);
+ } else {
+ dvfs_status->step++;
+ OSK_ASSERT(dvfs_status->step < MALI_DVFS_STEP);
+ }
+ }else if ((dvfs_status->step>0) &&
+ (platform->time_tick == MALI_DVFS_TIME_INTERVAL) &&
+ (platform->utilisation < mali_dvfs_infotbl[dvfs_status->step].min_threshold)) {
+ OSK_ASSERT(dvfs_status->step > 0);
+ dvfs_status->step--;
+ }
+#ifdef CONFIG_MALI_T6XX_FREQ_LOCK
+ if ((dvfs_status->upper_lock >= 0)&&(dvfs_status->step > dvfs_status->upper_lock)) {
+ dvfs_status->step = dvfs_status->upper_lock;
+ }
+ if (dvfs_status->under_lock > 0) {
+ if (dvfs_status->step < dvfs_status->under_lock)
+ dvfs_status->step = dvfs_status->under_lock;
+ }
+#endif
+ spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
+
+ kbase_platform_dvfs_set_level(dvfs_status->kbdev, dvfs_status->step);
+
+ mutex_unlock(&mali_enable_clock_lock);
+}
+
+static DECLARE_WORK(mali_dvfs_work, mali_dvfs_event_proc);
+
+int kbase_platform_dvfs_event(struct kbase_device *kbdev, u32 utilisation)
+{
+ unsigned long flags;
+ struct exynos_context *platform;
+
+ OSK_ASSERT(kbdev != NULL);
+ platform = (struct exynos_context *) kbdev->platform_context;
+
+ spin_lock_irqsave(&mali_dvfs_spinlock, flags);
+ if (platform->time_tick < MALI_DVFS_TIME_INTERVAL) {
+ platform->time_tick++;
+ platform->time_busy += kbdev->pm.metrics.time_busy;
+ platform->time_idle += kbdev->pm.metrics.time_idle;
+ } else {
+ platform->time_busy = kbdev->pm.metrics.time_busy;
+ platform->time_idle = kbdev->pm.metrics.time_idle;
+ platform->time_tick = 0;
+ }
+
+ if ((platform->time_tick == MALI_DVFS_TIME_INTERVAL) &&
+ (platform->time_idle + platform->time_busy > 0))
+ platform->utilisation = (100*platform->time_busy) / (platform->time_idle + platform->time_busy);
+
+ mali_dvfs_status_current.utilisation = utilisation;
+ spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
+
+ queue_work_on(0, mali_dvfs_wq, &mali_dvfs_work);
+ /*add error handle here*/
+ return MALI_TRUE;
+}
+
+int kbase_platform_dvfs_get_utilisation(void)
+{
+ unsigned long flags;
+ int utilisation = 0;
+
+ spin_lock_irqsave(&mali_dvfs_spinlock, flags);
+ utilisation = mali_dvfs_status_current.utilisation;
+ spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
+
+ return utilisation;
+}
+
+int kbase_platform_dvfs_get_enable_status(void)
+{
+ struct kbase_device *kbdev;
+ unsigned long flags;
+ int enable;
+
+ kbdev = mali_dvfs_status_current.kbdev;
+ spin_lock_irqsave(&kbdev->pm.metrics.lock, flags);
+ enable = kbdev->pm.metrics.timer_active;
+ spin_unlock_irqrestore(&kbdev->pm.metrics.lock, flags);
+
+ return enable;
+}
+
+int kbase_platform_dvfs_enable(bool enable, int freq)
+{
+ mali_dvfs_status *dvfs_status;
+ struct kbase_device *kbdev;
+ unsigned long flags;
+ struct exynos_context *platform;
+ int f;
+
+ dvfs_status = &mali_dvfs_status_current;
+ kbdev = mali_dvfs_status_current.kbdev;
+
+ OSK_ASSERT(kbdev != NULL);
+ platform = (struct exynos_context *)kbdev->platform_context;
+
+ mutex_lock(&mali_enable_clock_lock);
+
+ if (freq != MALI_DVFS_CURRENT_FREQ) {
+ spin_lock_irqsave(&mali_dvfs_spinlock, flags);
+ platform->time_tick = 0;
+ platform->time_busy = 0;
+ platform->time_idle = 0;
+ platform->utilisation = 0;
+ dvfs_status->step = kbase_platform_dvfs_get_level(freq);
+ spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
+
+ kbase_platform_dvfs_set_level(dvfs_status->kbdev, dvfs_status->step);
+ }
+
+ if (enable != kbdev->pm.metrics.timer_active) {
+ if (enable) {
+ spin_lock_irqsave(&kbdev->pm.metrics.lock, flags);
+ kbdev->pm.metrics.timer_active = MALI_TRUE;
+ spin_unlock_irqrestore(&kbdev->pm.metrics.lock, flags);
+ hrtimer_start(&kbdev->pm.metrics.timer,
+ HR_TIMER_DELAY_MSEC(KBASE_PM_DVFS_FREQUENCY),
+ HRTIMER_MODE_REL);
+ f = mali_dvfs_infotbl[dvfs_status->step].mem_freq;
+ exynos5_bus_mif_update(mem_freq_req, f);
+ } else {
+ spin_lock_irqsave(&kbdev->pm.metrics.lock, flags);
+ kbdev->pm.metrics.timer_active = MALI_FALSE;
+ spin_unlock_irqrestore(&kbdev->pm.metrics.lock, flags);
+ hrtimer_cancel(&kbdev->pm.metrics.timer);
+ exynos5_bus_mif_update(mem_freq_req, 0);
+ }
+ }
+ mutex_unlock(&mali_enable_clock_lock);
+
+ return MALI_TRUE;
+}
+
+int kbase_platform_dvfs_init(struct kbase_device *kbdev)
+{
+ unsigned long flags;
+ /*default status
+ add here with the right function to get initilization value.
+ */
+ if (!mali_dvfs_wq)
+ mali_dvfs_wq = create_singlethread_workqueue("mali_dvfs");
+
+ spin_lock_init(&mali_dvfs_spinlock);
+ mutex_init(&mali_set_clock_lock);
+ mutex_init(&mali_enable_clock_lock);
+
+ mem_freq_req = exynos5_bus_mif_min(0);
+
+ /*add a error handling here*/
+ spin_lock_irqsave(&mali_dvfs_spinlock, flags);
+ mali_dvfs_status_current.kbdev = kbdev;
+ mali_dvfs_status_current.utilisation = 100;
+ mali_dvfs_status_current.step = MALI_DVFS_STEP-1;
+#ifdef CONFIG_MALI_T6XX_FREQ_LOCK
+ mali_dvfs_status_current.upper_lock = -1;
+ mali_dvfs_status_current.under_lock = -1;
+#endif
+#ifdef MALI_DVFS_ASV_ENABLE
+ mali_dvfs_status_current.asv_status=ASV_STATUS_NOT_INIT;
+#endif
+ spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
+
+ return MALI_TRUE;
+}
+
+void kbase_platform_dvfs_term(void)
+{
+ if (mali_dvfs_wq)
+ destroy_workqueue(mali_dvfs_wq);
+
+ mali_dvfs_wq = NULL;
+}
+#endif /*CONFIG_MALI_T6XX_DVFS*/
+
+static int kbase_platform_dvfs_get_bw(int level)
+{
+ int bw;
+
+ if (level == 0)
+ return -1;
+
+ bw = mali_dvfs_infotbl[level].clock * 16;
+ return clamp(bw, 0, 6400);
+}
+
+int mali_get_dvfs_upper_locked_freq(void)
+{
+ unsigned long flags;
+ unsigned int locked_level = -1;
+
+#ifdef CONFIG_MALI_T6XX_FREQ_LOCK
+ spin_lock_irqsave(&mali_dvfs_spinlock, flags);
+ locked_level = mali_dvfs_infotbl[mali_dvfs_status_current.upper_lock].clock;
+ spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
+#endif
+ return locked_level;
+}
+
+int mali_get_dvfs_under_locked_freq(void)
+{
+ unsigned long flags;
+ unsigned int locked_level = -1;
+
+#ifdef CONFIG_MALI_T6XX_FREQ_LOCK
+ spin_lock_irqsave(&mali_dvfs_spinlock, flags);
+ locked_level = mali_dvfs_infotbl[mali_dvfs_status_current.under_lock].clock;
+ spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
+#endif
+ return locked_level;
+}
+
+int mali_get_dvfs_current_level(void)
+{
+ unsigned long flags;
+ unsigned int current_level = -1;
+
+#ifdef CONFIG_MALI_T6XX_FREQ_LOCK
+ spin_lock_irqsave(&mali_dvfs_spinlock, flags);
+ current_level = mali_dvfs_status_current.step;
+ spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
+#endif
+ return current_level;
+}
+
+int mali_dvfs_freq_lock(int level)
+{
+ unsigned long flags;
+#ifdef CONFIG_MALI_T6XX_FREQ_LOCK
+ spin_lock_irqsave(&mali_dvfs_spinlock, flags);
+ if (mali_dvfs_status_current.under_lock >= 0) {
+ printk( KERN_ERR "[G3D] Upper lock Error : Under lock is already set\n");
+ spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
+ return -1;
+ }
+ mali_dvfs_status_current.upper_lock = level;
+ spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
+
+ printk( "[G3D] Upper Lock Set : %d\n", level );
+#endif
+ return 0;
+}
+void mali_dvfs_freq_unlock(void)
+{
+ unsigned long flags;
+#ifdef CONFIG_MALI_T6XX_FREQ_LOCK
+ spin_lock_irqsave(&mali_dvfs_spinlock, flags);
+ mali_dvfs_status_current.upper_lock = -1;
+ spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
+#endif
+
+ printk("[G3D] Upper Lock Unset\n");
+}
+
+int mali_dvfs_freq_under_lock(int level)
+{
+ unsigned long flags;
+#ifdef CONFIG_MALI_T6XX_FREQ_LOCK
+ spin_lock_irqsave(&mali_dvfs_spinlock, flags);
+ if (mali_dvfs_status_current.upper_lock >= 0) {
+ printk( KERN_ERR "[G3D] Under lock Error : Upper lock is already set\n");
+ spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
+ return -1;
+ }
+ mali_dvfs_status_current.under_lock = level;
+ spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
+
+ printk( "[G3D] Under Lock Set : %d\n", level );
+#endif
+ return 0;
+}
+void mali_dvfs_freq_under_unlock(void)
+{
+ unsigned long flags;
+#ifdef CONFIG_MALI_T6XX_FREQ_LOCK
+ spin_lock_irqsave(&mali_dvfs_spinlock, flags);
+ mali_dvfs_status_current.under_lock = -1;
+ spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
+#endif
+ printk("[G3D] Under Lock Unset\n");
+}
+
+int kbase_platform_regulator_init(void)
+{
+
+#ifdef CONFIG_REGULATOR
+ int mali_gpu_vol = 0;
+ g3d_regulator = regulator_get(NULL, "vdd_g3d");
+ if (IS_ERR(g3d_regulator)) {
+ printk("[kbase_platform_regulator_init] failed to get mali t6xx regulator\n");
+ return -1;
+ }
+
+ if (regulator_enable(g3d_regulator) != 0) {
+ printk("[kbase_platform_regulator_init] failed to enable mali t6xx regulator\n");
+ return -1;
+ }
+#ifdef MALI_DVFS_ASV_ENABLE
+ mali_gpu_vol = asv_get_volt(ID_G3D, MALI_DVFS_BL_CONFIG_FREQ*1000);
+#endif
+ if (mali_gpu_vol == 0)
+ mali_gpu_vol = mali_dvfs_infotbl[ARRAY_SIZE(mali_dvfs_infotbl)-1].voltage;
+
+ if (regulator_set_voltage(g3d_regulator, mali_gpu_vol, mali_gpu_vol) != 0) {
+ printk("[kbase_platform_regulator_init] failed to set mali t6xx operating voltage [%d]\n", mali_gpu_vol);
+ return -1;
+ }
+#endif
+ return 0;
+}
+
+int kbase_platform_regulator_disable(void)
+{
+#ifdef CONFIG_REGULATOR
+ if (!g3d_regulator) {
+ printk("[kbase_platform_regulator_disable] g3d_regulator is not initialized\n");
+ return -1;
+ }
+
+ if (regulator_disable(g3d_regulator) != 0) {
+ printk("[kbase_platform_regulator_disable] failed to disable g3d regulator\n");
+ return -1;
+ }
+#endif
+ return 0;
+}
+
+int kbase_platform_regulator_enable(void)
+{
+#ifdef CONFIG_REGULATOR
+ if (!g3d_regulator) {
+ printk("[kbase_platform_regulator_enable] g3d_regulator is not initialized\n");
+ return -1;
+ }
+
+ if (regulator_enable(g3d_regulator) != 0) {
+ printk("[kbase_platform_regulator_enable] failed to enable g3d regulator\n");
+ return -1;
+ }
+#endif
+ return 0;
+}
+
+int kbase_platform_get_voltage(struct device *dev, int *vol)
+{
+#ifdef CONFIG_REGULATOR
+ if (!g3d_regulator) {
+ printk("[kbase_platform_get_voltage] g3d_regulator is not initialized\n");
+ return -1;
+ }
+
+ *vol = regulator_get_voltage(g3d_regulator);
+#else
+ *vol = 0;
+#endif
+ return 0;
+}
+
+int kbase_platform_set_voltage(struct device *dev, int vol)
+{
+#ifdef CONFIG_REGULATOR
+ if (!g3d_regulator) {
+ printk("[kbase_platform_set_voltage] g3d_regulator is not initialized\n");
+ return -1;
+ }
+
+ if (regulator_set_voltage(g3d_regulator, vol, vol) != 0)
+ {
+ printk("[kbase_platform_set_voltage] failed to set voltage\n");
+ return -1;
+ }
+#endif
+ return 0;
+}
+
+void kbase_platform_dvfs_set_clock(kbase_device *kbdev, int freq)
+{
+ static struct clk * mout_gpll = NULL;
+ static struct clk * fin_gpll = NULL;
+ static struct clk * fout_gpll = NULL;
+ static int _freq = -1;
+ static unsigned long gpll_rate_prev = 0;
+ unsigned long gpll_rate = 0, aclk_400_rate = 0;
+ unsigned long tmp = 0;
+ struct exynos_context *platform;
+
+ if (!kbdev)
+ panic("oops");
+
+ platform = (struct exynos_context *) kbdev->platform_context;
+ if (NULL == platform)
+ {
+ panic("oops");
+ }
+
+ if (mout_gpll==NULL) {
+ mout_gpll = clk_get(kbdev->osdev.dev, "mout_gpll");
+ fin_gpll = clk_get(kbdev->osdev.dev, "ext_xtal");
+ fout_gpll = clk_get(kbdev->osdev.dev, "fout_gpll");
+ if (IS_ERR(mout_gpll) || IS_ERR(fin_gpll) || IS_ERR(fout_gpll))
+ panic("clk_get ERROR");
+ }
+
+ if (platform->sclk_g3d == 0)
+ return;
+
+ if (freq == _freq)
+ return;
+
+ switch(freq) {
+ case 533:
+ gpll_rate = 533000000;
+ aclk_400_rate = 533000000;
+ break;
+ case 450:
+ gpll_rate = 450000000;
+ aclk_400_rate = 450000000;
+ break;
+ case 400:
+ gpll_rate = 800000000;
+ aclk_400_rate = 400000000;
+ break;
+ case 350:
+ gpll_rate = 1400000000;
+ aclk_400_rate = 350000000;
+ break;
+ case 266:
+ gpll_rate = 800000000;
+ aclk_400_rate = 267000000;
+ break;
+ case 160:
+ gpll_rate = 800000000;
+ aclk_400_rate = 160000000;
+ break;
+ case 100:
+ gpll_rate = 800000000;
+ aclk_400_rate = 100000000;
+ break;
+ default:
+ return;
+ }
+
+ /* if changed the GPLL rate, set rate for GPLL and wait for lock time */
+ if (gpll_rate != gpll_rate_prev) {
+ /*for stable clock input.*/
+ clk_set_rate(platform->sclk_g3d, 100000000);
+ clk_set_parent(mout_gpll, fin_gpll);
+
+ /*change gpll*/
+ clk_set_rate( fout_gpll, gpll_rate );
+
+ /*restore parent*/
+ clk_set_parent(mout_gpll, fout_gpll);
+ gpll_rate_prev = gpll_rate;
+ }
+
+ _freq = freq;
+ clk_set_rate(platform->sclk_g3d, aclk_400_rate);
+
+ /* Waiting for clock is stable */
+ do {
+ tmp = __raw_readl(EXYNOS5_CLKDIV_STAT_TOP0);
+ } while (tmp & 0x1000000);
+
+ return;
+}
+
+static void kbase_platform_dvfs_set_vol(unsigned int vol)
+{
+ static int _vol = -1;
+
+ if (_vol == vol)
+ return;
+
+ kbase_platform_set_voltage(NULL, vol);
+ _vol = vol;
+
+ return;
+}
+
+int kbase_platform_dvfs_get_level(int freq)
+{
+ int i;
+ for (i=0; i < MALI_DVFS_STEP; i++) {
+ if (mali_dvfs_infotbl[i].clock == freq)
+ return i;
+ }
+
+ return -1;
+}
+
+void kbase_platform_dvfs_set_level(kbase_device *kbdev, int level)
+{
+ static int prev_level = -1;
+ int f;
+
+ if (level == prev_level)
+ return;
+
+ if (WARN_ON((level >= MALI_DVFS_STEP)||(level < 0)))
+ panic("invalid level");
+
+#ifdef CONFIG_MALI_T6XX_DVFS
+ mutex_lock(&mali_set_clock_lock);
+#endif
+
+ f = mali_dvfs_infotbl[level].mem_freq;
+
+ if (level > prev_level) {
+ exynos5_bus_mif_update(mem_freq_req, f);
+ kbase_platform_dvfs_set_vol(mali_dvfs_infotbl[level].voltage);
+ kbase_platform_dvfs_set_clock(kbdev, mali_dvfs_infotbl[level].clock);
+ } else {
+ kbase_platform_dvfs_set_clock(kbdev, mali_dvfs_infotbl[level].clock);
+ kbase_platform_dvfs_set_vol(mali_dvfs_infotbl[level].voltage);
+ exynos5_bus_mif_update(mem_freq_req, f);
+ }
+#if defined(CONFIG_MALI_T6XX_DEBUG_SYS) && defined(CONFIG_MALI_T6XX_DVFS)
+ update_time_in_state(prev_level);
+#endif
+ prev_level = level;
+#ifdef CONFIG_MALI_T6XX_DVFS
+ mutex_unlock(&mali_set_clock_lock);
+#endif
+}
+
+int kbase_platform_dvfs_sprint_avs_table(char *buf)
+{
+#ifdef MALI_DVFS_ASV_ENABLE
+ int i, cnt=0;
+ if (buf==NULL)
+ return 0;
+
+ for (i=MALI_DVFS_STEP-1; i >= 0; i--) {
+ cnt+=sprintf(buf+cnt,"%dMhz:%d\n",
+ mali_dvfs_infotbl[i].clock, mali_dvfs_infotbl[i].voltage);
+ }
+ return cnt;
+#else
+ return 0;
+#endif
+}
+
+int kbase_platform_dvfs_set(int enable)
+{
+ unsigned long flags;
+#ifdef MALI_DVFS_ASV_ENABLE
+ spin_lock_irqsave(&mali_dvfs_spinlock, flags);
+ if (enable) {
+ mali_dvfs_status_current.asv_status=ASV_STATUS_NOT_INIT;
+ } else {
+ mali_dvfs_status_current.asv_status=ASV_STATUS_DISABLE_REQ;
+ }
+ spin_unlock_irqrestore(&mali_dvfs_spinlock, flags);
+#endif
+ return 0;
+}
+
+#ifdef CONFIG_MALI_T6XX_DEBUG_SYS
+#ifdef CONFIG_MALI_T6XX_DVFS
+static void update_time_in_state(int level)
+{
+ u64 current_time;
+ static u64 prev_time=0;
+
+ if (!kbase_platform_dvfs_get_enable_status())
+ return;
+
+ if (prev_time ==0)
+ prev_time=get_jiffies_64();
+
+ current_time = get_jiffies_64();
+ mali_dvfs_infotbl[level].time += current_time-prev_time;
+ prev_time = current_time;
+}
+#endif
+
+ssize_t show_time_in_state(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct kbase_device *kbdev;
+ ssize_t ret = 0;
+ int i;
+
+ kbdev = dev_get_drvdata(dev);
+
+#ifdef CONFIG_MALI_T6XX_DVFS
+ update_time_in_state(mali_dvfs_status_current.step);
+#endif
+ if (!kbdev)
+ return -ENODEV;
+
+ for (i = 0; i < MALI_DVFS_STEP; i++) {
+ ret += snprintf(buf+ret, PAGE_SIZE-ret, "%d %llu\n",
+ mali_dvfs_infotbl[i].clock,
+ mali_dvfs_infotbl[i].time);
+ }
+
+ if (ret < PAGE_SIZE - 1) {
+ ret += snprintf(buf+ret, PAGE_SIZE-ret, "\n");
+ } else {
+ buf[PAGE_SIZE-2] = '\n';
+ buf[PAGE_SIZE-1] = '\0';
+ ret = PAGE_SIZE-1;
+ }
+
+ return ret;
+}
+
+ssize_t set_time_in_state(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ int i;
+
+ for (i = 0; i < MALI_DVFS_STEP; i++) {
+ mali_dvfs_infotbl[i].time = 0;
+ }
+
+ return count;
+}
+#endif
diff --git a/drivers/gpu/arm/t6xx/kbase/src/platform/mali_kbase_dvfs.h b/drivers/gpu/arm/t6xx/kbase/src/platform/mali_kbase_dvfs.h
new file mode 100644
index 0000000..075eb52
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/platform/mali_kbase_dvfs.h
@@ -0,0 +1,70 @@
+/* drivers/gpu/t6xx/kbase/src/platform/mali_kbase_dvfs.h
+ *
+ * Copyright 2011 by S.LSI. Samsung Electronics Inc.
+ * San#24, Nongseo-Dong, Giheung-Gu, Yongin, Korea
+ *
+ * Samsung SoC Mali-T604 DVFS driver
+ *
+ * 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.
+ */
+
+/**
+ * @file mali_kbase_dvfs.h
+ * DVFS
+ */
+
+#ifndef _KBASE_DVFS_H_
+#define _KBASE_DVFS_H_
+
+/* Frequency that DVFS clock frequency decisions should be made */
+#define KBASE_PM_DVFS_FREQUENCY 100
+
+#define MALI_DVFS_KEEP_STAY_CNT 10
+#define MALI_DVFS_TIME_INTERVAL 5
+
+#define MALI_DVFS_CURRENT_FREQ 0
+#define MALI_DVFS_BL_CONFIG_FREQ 533
+#define MALI_DVFS_START_FREQ 450
+
+#ifdef CONFIG_MALI_T6XX_DVFS
+#define CONFIG_MALI_T6XX_FREQ_LOCK
+#ifdef CONFIG_CPU_FREQ
+#define MALI_DVFS_ASV_ENABLE
+#endif
+#endif
+
+struct regulator *kbase_platform_get_regulator(void);
+int kbase_platform_regulator_init(void);
+int kbase_platform_regulator_disable(void);
+int kbase_platform_regulator_enable(void);
+int kbase_platform_get_voltage(struct device *dev, int *vol);
+int kbase_platform_set_voltage(struct device *dev, int vol);
+void kbase_platform_dvfs_set_clock(kbase_device *kbdev, int freq);
+int kbase_platform_dvfs_sprint_avs_table(char *buf);
+int kbase_platform_dvfs_set(int enable);
+void kbase_platform_dvfs_set_level(struct kbase_device *kbdev, int level);
+int kbase_platform_dvfs_get_level(int freq);
+
+#ifdef CONFIG_MALI_T6XX_DVFS
+int kbase_platform_dvfs_init(struct kbase_device *dev);
+void kbase_platform_dvfs_term(void);
+int kbase_platform_dvfs_event(struct kbase_device *kbdev, u32 utilisation);
+int kbase_platform_dvfs_get_enable_status(void);
+int kbase_platform_dvfs_enable(bool enable, int freq);
+int kbase_platform_dvfs_get_utilisation(void);
+#endif
+
+int mali_get_dvfs_current_level(void);
+int mali_get_dvfs_upper_locked_freq(void);
+int mali_get_dvfs_under_locked_freq(void);
+int mali_dvfs_freq_lock(int level);
+void mali_dvfs_freq_unlock(void);
+int mali_dvfs_freq_under_lock(int level);
+void mali_dvfs_freq_under_unlock(void);
+
+ssize_t show_time_in_state(struct device *dev, struct device_attribute *attr, char *buf);
+ssize_t set_time_in_state(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
+
+#endif /* _KBASE_DVFS_H_ */
diff --git a/drivers/gpu/arm/t6xx/kbase/src/platform/mali_kbase_platform.c b/drivers/gpu/arm/t6xx/kbase/src/platform/mali_kbase_platform.c
new file mode 100644
index 0000000..a9c0c55
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/platform/mali_kbase_platform.c
@@ -0,0 +1,1050 @@
+/* drivers/gpu/t6xx/kbase/src/platform/mali_kbase_platform.c
+ *
+ * Copyright 2011 by S.LSI. Samsung Electronics Inc.
+ * San#24, Nongseo-Dong, Giheung-Gu, Yongin, Korea
+ *
+ * Samsung SoC Mali-T604 platform-dependent codes
+ *
+ * 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.
+ */
+
+/**
+ * @file mali_kbase_platform.c
+ * Platform-dependent init.
+ */
+#include <osk/mali_osk.h>
+#include <kbase/src/common/mali_kbase.h>
+#include <kbase/src/common/mali_kbase_pm.h>
+#include <kbase/src/common/mali_kbase_uku.h>
+#include <kbase/src/common/mali_kbase_mem.h>
+#include <kbase/src/common/mali_midg_regmap.h>
+#include <kbase/src/linux/mali_kbase_mem_linux.h>
+#include <kbase/mali_ukk.h>
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/pci.h>
+#include <linux/miscdevice.h>
+#include <linux/list.h>
+#include <linux/semaphore.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+
+#include <mach/map.h>
+#include <linux/fb.h>
+#include <linux/clk.h>
+#include <mach/regs-clock.h>
+#include <mach/pmu.h>
+#include <mach/regs-pmu.h>
+#include <asm/delay.h>
+#include <kbase/src/platform/mali_kbase_platform.h>
+#include <kbase/src/platform/mali_kbase_dvfs.h>
+
+#include <kbase/src/common/mali_kbase_gator.h>
+
+#define MALI_T6XX_DEFAULT_CLOCK 533000000
+
+static struct clk *clk_g3d = NULL;
+static int clk_g3d_status = 0;
+
+static int kbase_platform_power_clock_init(kbase_device *kbdev)
+{
+ struct device *dev = kbdev->osdev.dev;
+ int timeout;
+ struct exynos_context *platform;
+
+ platform = (struct exynos_context *) kbdev->platform_context;
+ if (NULL == platform) {
+ panic("oops");
+ }
+
+ /* Turn on G3D power */
+ __raw_writel(0x7, EXYNOS5_G3D_CONFIGURATION);
+
+ /* Wait for G3D power stability for 1ms */
+ timeout = 10;
+ while((__raw_readl(EXYNOS5_G3D_STATUS) & 0x7) != 0x7) {
+ if(timeout == 0) {
+ /* need to call panic */
+ panic("failed to turn on g3d power\n");
+ goto out;
+ }
+ timeout--;
+ udelay(100);
+ }
+ /* Turn on G3D clock */
+ clk_g3d = clk_get(dev, "g3d");
+ if (IS_ERR(clk_g3d)) {
+ clk_g3d = NULL;
+ OSK_PRINT_ERROR(OSK_BASE_PM, "failed to clk_get [clk_g3d]\n");
+ } else {
+ clk_enable(clk_g3d);
+ clk_g3d_status = 1;
+ }
+
+ platform->sclk_g3d = clk_get(dev, "aclk_400_g3d");
+ if (IS_ERR(platform->sclk_g3d)) {
+ OSK_PRINT_ERROR(OSK_BASE_PM, "failed to clk_get [sclk_g3d]\n");
+ goto out;
+ }
+
+ clk_set_rate(platform->sclk_g3d, MALI_T6XX_DEFAULT_CLOCK);
+ if (IS_ERR(platform->sclk_g3d)) {
+ OSK_PRINT_ERROR(OSK_BASE_PM, "failed to clk_set_rate [sclk_g3d] = %d\n", MALI_T6XX_DEFAULT_CLOCK);
+ goto out;
+ }
+ (void) clk_enable(platform->sclk_g3d);
+
+ return 0;
+out:
+ return -EPERM;
+}
+
+int kbase_platform_clock_on(struct kbase_device *kbdev)
+{
+ struct exynos_context *platform;
+ if (!kbdev)
+ return -ENODEV;
+
+ platform = (struct exynos_context *) kbdev->platform_context;
+ if (!platform)
+ return -ENODEV;
+
+ if (clk_g3d_status == 1)
+ return 0;
+
+ if(clk_g3d) {
+ (void) clk_enable(clk_g3d);
+ } else {
+ (void) clk_enable(platform->sclk_g3d);
+ }
+ clk_g3d_status = 1;
+
+ return 0;
+}
+
+int kbase_platform_clock_off(struct kbase_device *kbdev)
+{
+ struct exynos_context *platform;
+ if (!kbdev)
+ return -ENODEV;
+
+ platform = (struct exynos_context *) kbdev->platform_context;
+ if (!platform)
+ return -ENODEV;
+
+ if (clk_g3d_status == 0)
+ return 0;
+
+ if(clk_g3d) {
+ (void)clk_disable(clk_g3d);
+ } else {
+ (void)clk_disable(platform->sclk_g3d);
+ }
+ clk_g3d_status = 0;
+
+ return 0;
+}
+
+int kbase_platform_is_power_on(void)
+{
+ return ((__raw_readl(EXYNOS5_G3D_STATUS) & 0x7) == 0x7) ? 1 : 0;
+}
+
+static int kbase_platform_power_on(void)
+{
+ int timeout;
+
+ /* Turn on G3D */
+ __raw_writel(0x7, EXYNOS5_G3D_CONFIGURATION);
+
+ /* Wait for G3D power stability */
+ timeout = 1000;
+
+ while((__raw_readl(EXYNOS5_G3D_STATUS) & 0x7) != 0x7) {
+ if(timeout == 0) {
+ /* need to call panic */
+ panic("failed to turn on g3d via g3d_configuration\n");
+ return -ETIMEDOUT;
+ }
+ timeout--;
+ udelay(10);
+ }
+
+ return 0;
+}
+
+static int kbase_platform_power_off(void)
+{
+ int timeout;
+
+ /* Turn off G3D */
+ __raw_writel(0x0, EXYNOS5_G3D_CONFIGURATION);
+
+ /* Wait for G3D power stability */
+ timeout = 1000;
+
+ while(__raw_readl(EXYNOS5_G3D_STATUS) & 0x7) {
+ if(timeout == 0) {
+ /* need to call panic */
+ panic( "failed to turn off g3d via g3d_configuration\n");
+ return -ETIMEDOUT;
+ }
+ timeout--;
+ udelay(10);
+ }
+
+ return 0;
+}
+
+int kbase_platform_cmu_pmu_control(struct kbase_device *kbdev, int control)
+{
+ unsigned long flags;
+ struct exynos_context *platform;
+ if (!kbdev) {
+ return -ENODEV;
+ }
+
+ platform = (struct exynos_context *) kbdev->platform_context;
+ if (!platform) {
+ return -ENODEV;
+ }
+
+ spin_lock_irqsave(&platform->cmu_pmu_lock, flags);
+
+ /* off */
+ if(control == 0) {
+ if(platform->cmu_pmu_status == 0) {
+ spin_unlock_irqrestore(&platform->cmu_pmu_lock, flags);
+ return 0;
+ }
+ if(kbase_platform_power_off())
+ panic("failed to turn off g3d power\n");
+ if(kbase_platform_clock_off(kbdev))
+ panic("failed to turn off sclk_g3d\n");
+ platform->cmu_pmu_status = 0;
+ } else {
+ /* on */
+ if(platform->cmu_pmu_status == 1) {
+ spin_unlock_irqrestore(&platform->cmu_pmu_lock, flags);
+ return 0;
+ }
+ if(kbase_platform_clock_on(kbdev))
+ panic("failed to turn on sclk_g3d\n");
+ if(kbase_platform_power_on())
+ panic("failed to turn on g3d power\n");
+ platform->cmu_pmu_status = 1;
+ }
+ spin_unlock_irqrestore(&platform->cmu_pmu_lock, flags);
+
+ return 0;
+}
+
+#ifdef CONFIG_MALI_T6XX_DEBUG_SYS
+static ssize_t show_clock(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct kbase_device *kbdev;
+ struct exynos_context *platform;
+ ssize_t ret = 0;
+ unsigned int clkrate;
+
+ kbdev = dev_get_drvdata(dev);
+
+ if (!kbdev)
+ return -ENODEV;
+
+ platform = (struct exynos_context *) kbdev->platform_context;
+ if (!platform)
+ return -ENODEV;
+
+ if (!platform->sclk_g3d)
+ return -ENODEV;
+
+ clkrate = clk_get_rate(platform->sclk_g3d);
+ ret += snprintf(buf+ret, PAGE_SIZE-ret, "Current sclk_g3d[G3D_BLK] = %dMhz", clkrate/1000000);
+
+ /* To be revised */
+ ret += snprintf(buf+ret, PAGE_SIZE-ret, "\nPossible settings : 533, 450, 400, 350, 266, 160, 100Mhz");
+
+ if (ret < PAGE_SIZE - 1) {
+ ret += snprintf(buf+ret, PAGE_SIZE-ret, "\n");
+ } else {
+ buf[PAGE_SIZE-2] = '\n';
+ buf[PAGE_SIZE-1] = '\0';
+ ret = PAGE_SIZE-1;
+ }
+
+ return ret;
+}
+
+static ssize_t set_clock(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct kbase_device *kbdev;
+ struct exynos_context *platform;
+ unsigned int tmp = 0, freq = 0;
+ kbdev = dev_get_drvdata(dev);
+
+ if (!kbdev)
+ return -ENODEV;
+
+ platform = (struct exynos_context *) kbdev->platform_context;
+ if(!platform)
+ return -ENODEV;
+
+ if(!platform->sclk_g3d)
+ return -ENODEV;
+
+ if (sysfs_streq("533", buf)) {
+ freq=533;
+ } else if (sysfs_streq("450", buf)) {
+ freq=450;
+ } else if (sysfs_streq("400", buf)) {
+ freq=400;
+ } else if (sysfs_streq("350", buf)) {
+ freq=350;
+ } else if (sysfs_streq("266", buf)) {
+ freq=266;
+ } else if (sysfs_streq("160", buf)) {
+ freq=160;
+ } else if (sysfs_streq("100", buf)) {
+ freq=100;
+ } else {
+ dev_err(dev, "set_clock: invalid value\n");
+ return -ENOENT;
+ }
+
+ kbase_platform_dvfs_set_level(kbdev, kbase_platform_dvfs_get_level(freq));
+ /* Waiting for clock is stable */
+ do {
+ tmp = __raw_readl(EXYNOS5_CLKDIV_STAT_TOP0);
+ } while (tmp & 0x1000000);
+
+ return count;
+}
+
+static ssize_t show_fbdev(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct kbase_device *kbdev;
+ ssize_t ret = 0;
+ int i;
+
+ kbdev = dev_get_drvdata(dev);
+
+ if (!kbdev)
+ return -ENODEV;
+
+ for(i = 0 ; i < num_registered_fb ; i++) {
+ ret += snprintf(buf+ret, PAGE_SIZE-ret, "fb[%d] xres=%d, yres=%d, addr=0x%lx\n", i, registered_fb[i]->var.xres, registered_fb[i]->var.yres, registered_fb[i]->fix.smem_start);
+ }
+
+ if (ret < PAGE_SIZE - 1) {
+ ret += snprintf(buf+ret, PAGE_SIZE-ret, "\n");
+ } else {
+ buf[PAGE_SIZE-2] = '\n';
+ buf[PAGE_SIZE-1] = '\0';
+ ret = PAGE_SIZE-1;
+ }
+
+ return ret;
+}
+
+typedef enum {
+ L1_I_tag_RAM = 0x00,
+ L1_I_data_RAM = 0x01,
+ L1_I_BTB_RAM = 0x02,
+ L1_I_GHB_RAM = 0x03,
+ L1_I_TLB_RAM = 0x04,
+ L1_I_indirect_predictor_RAM = 0x05,
+ L1_D_tag_RAM = 0x08,
+ L1_D_data_RAM = 0x09,
+ L1_D_load_TLB_array = 0x0A,
+ L1_D_store_TLB_array = 0x0B,
+ L2_tag_RAM = 0x10,
+ L2_data_RAM = 0x11,
+ L2_snoop_tag_RAM = 0x12,
+ L2_data_ECC_RAM = 0x13,
+ L2_dirty_RAM = 0x14,
+ L2_TLB_RAM = 0x18
+} RAMID_type;
+
+static inline void asm_ramindex_mrc(u32 *DL1Data0, u32 *DL1Data1, u32 *DL1Data2, u32 *DL1Data3)
+{
+ u32 val;
+
+ if(DL1Data0) {
+ asm volatile("mrc p15, 0, %0, c15, c1, 0" : "=r" (val));
+ *DL1Data0 = val;
+ }
+ if(DL1Data1) {
+ asm volatile("mrc p15, 0, %0, c15, c1, 1" : "=r" (val));
+ *DL1Data1 = val;
+ }
+ if(DL1Data2) {
+ asm volatile("mrc p15, 0, %0, c15, c1, 2" : "=r" (val));
+ *DL1Data2 = val;
+ }
+ if(DL1Data3) {
+ asm volatile("mrc p15, 0, %0, c15, c1, 3" : "=r" (val));
+ *DL1Data3 = val;
+ }
+}
+
+static inline void asm_ramindex_mcr(u32 val)
+{
+ asm volatile("mcr p15, 0, %0, c15, c4, 0" : : "r" (val));
+ asm volatile("dsb");
+ asm volatile("isb");
+}
+
+static void get_tlb_array(u32 val, u32 *DL1Data0, u32 *DL1Data1, u32 *DL1Data2, u32 *DL1Data3)
+{
+ asm_ramindex_mcr(val);
+ asm_ramindex_mrc(DL1Data0, DL1Data1, DL1Data2, DL1Data3);
+}
+
+static RAMID_type ramindex = L1_D_load_TLB_array;
+static ssize_t show_dtlb(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct kbase_device *kbdev;
+ ssize_t ret = 0;
+ int entries, ways;
+ u32 DL1Data0 = 0, DL1Data1 = 0, DL1Data2 = 0, DL1Data3 = 0;
+
+ kbdev = dev_get_drvdata(dev);
+
+ if (!kbdev)
+ return -ENODEV;
+
+ /* L1-I tag RAM */
+ if(ramindex == L1_I_tag_RAM) {
+ printk("Not implemented yet\n");
+ } /* L1-I data RAM */
+ else if(ramindex == L1_I_data_RAM) {
+ printk("Not implemented yet\n");
+ } /* L1-I BTB RAM */
+ else if(ramindex == L1_I_BTB_RAM) {
+ printk("Not implemented yet\n");
+ } /* L1-I GHB RAM */
+ else if(ramindex == L1_I_GHB_RAM) {
+ printk("Not implemented yet\n");
+ } /* L1-I TLB RAM */
+ else if(ramindex == L1_I_TLB_RAM) {
+ printk("L1-I TLB RAM\n");
+ for(entries = 0 ; entries < 32 ; entries++) {
+ get_tlb_array((((u8)ramindex) << 24) + entries, &DL1Data0, &DL1Data1, &DL1Data2, NULL);
+ printk("entries[%d], DL1Data0=%08x, DL1Data1=%08x DL1Data2=%08x\n", entries, DL1Data0, DL1Data1 & 0xffff, 0x0);
+ }
+ } /* L1-I indirect predictor RAM */
+ else if(ramindex == L1_I_indirect_predictor_RAM) {
+ printk("Not implemented yet\n");
+ }
+ /* L1-D tag RAM */
+ else if(ramindex == L1_D_tag_RAM) {
+ printk("Not implemented yet\n");
+ }
+ /* L1-D data RAM */
+ else if(ramindex == L1_D_data_RAM) {
+ printk("Not implemented yet\n");
+ }
+ /* L1-D load TLB array */
+ else if(ramindex == L1_D_load_TLB_array) {
+ printk("L1-D load TLB array\n");
+ for(entries = 0 ; entries < 32 ; entries++)
+ {
+ get_tlb_array((((u8)ramindex) << 24) + entries, &DL1Data0, &DL1Data1, &DL1Data2, &DL1Data3);
+ printk("entries[%d], DL1Data0=%08x, DL1Data1=%08x, DL1Data2=%08x, DL1Data3=%08x\n", entries, DL1Data0, DL1Data1, DL1Data2, DL1Data3 & 0x3f);
+ }
+ }
+ /* L1-D store TLB array */
+ else if(ramindex == L1_D_store_TLB_array) {
+ printk("\nL1-D store TLB array\n");
+ for(entries = 0; entries < 32; entries++) {
+ get_tlb_array((((u8)ramindex) << 24) + entries, &DL1Data0, &DL1Data1, &DL1Data2, &DL1Data3);
+ printk("entries[%d], DL1Data0=%08x, DL1Data1=%08x, DL1Data2=%08x, DL1Data3=%08x\n", entries, DL1Data0, DL1Data1, DL1Data2, DL1Data3 & 0x3f);
+ }
+ }
+ /* L2 tag RAM */
+ else if(ramindex == L2_tag_RAM) {
+ printk("Not implemented yet\n");
+ }
+ /* L2 data RAM */
+ else if(ramindex == L2_data_RAM) {
+ printk("Not implemented yet\n");
+ }
+ /* L2 snoop tag RAM */
+ else if(ramindex == L2_snoop_tag_RAM) {
+ printk("Not implemented yet\n");
+ }
+ /* L2 data ECC RAM */
+ else if(ramindex == L2_data_ECC_RAM) {
+ printk("Not implemented yet\n");
+ }
+ /* L2 dirty RAM */
+ else if(ramindex == L2_dirty_RAM) {
+ printk("Not implemented yet\n");
+ }
+ /* L2 TLB array */
+ else if(ramindex == L2_TLB_RAM) {
+ printk("\nL2 TLB array\n");
+ for(ways = 0 ; ways < 4 ; ways++) {
+ for(entries = 0 ; entries < 512 ; entries++) {
+ get_tlb_array((ramindex << 24) + (ways << 18) + entries, &DL1Data0, &DL1Data1, &DL1Data2, &DL1Data3);
+ printk("ways[%d]:entries[%d], DL1Data0=%08x, DL1Data1=%08x, DL1Data2=%08x, DL1Data3=%08x\n", ways, entries, DL1Data0, DL1Data1, DL1Data2, DL1Data3);
+ }
+ }
+ }
+ else {
+ }
+
+ ret += snprintf(buf+ret, PAGE_SIZE-ret, "Succeeded...\n");
+
+ if (ret < PAGE_SIZE - 1) {
+ ret += snprintf(buf+ret, PAGE_SIZE-ret, "\n");
+ } else {
+ buf[PAGE_SIZE-2] = '\n';
+ buf[PAGE_SIZE-1] = '\0';
+ ret = PAGE_SIZE-1;
+ }
+ return ret;
+}
+
+static ssize_t set_dtlb(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct kbase_device *kbdev;
+ kbdev = dev_get_drvdata(dev);
+
+ if (!kbdev)
+ return -ENODEV;
+
+ if (sysfs_streq("L1_I_tag_RAM", buf)) {
+ ramindex = L1_I_tag_RAM;
+ } else if (sysfs_streq("L1_I_data_RAM", buf)) {
+ ramindex = L1_I_data_RAM;
+ } else if (sysfs_streq("L1_I_BTB_RAM", buf)) {
+ ramindex = L1_I_BTB_RAM;
+ } else if (sysfs_streq("L1_I_GHB_RAM", buf)) {
+ ramindex = L1_I_GHB_RAM;
+ } else if (sysfs_streq("L1_I_TLB_RAM", buf)) {
+ ramindex = L1_I_TLB_RAM;
+ } else if (sysfs_streq("L1_I_indirect_predictor_RAM", buf)) {
+ ramindex = L1_I_indirect_predictor_RAM;
+ } else if (sysfs_streq("L1_D_tag_RAM", buf)) {
+ ramindex = L1_D_tag_RAM;
+ } else if (sysfs_streq("L1_D_data_RAM", buf)) {
+ ramindex = L1_D_data_RAM;
+ } else if (sysfs_streq("L1_D_load_TLB_array", buf)) {
+ ramindex = L1_D_load_TLB_array;
+ } else if (sysfs_streq("L1_D_store_TLB_array", buf)) {
+ ramindex = L1_D_store_TLB_array;
+ } else if (sysfs_streq("L2_tag_RAM", buf)) {
+ ramindex = L2_tag_RAM;
+ } else if (sysfs_streq("L2_data_RAM", buf)) {
+ ramindex = L2_data_RAM;
+ } else if (sysfs_streq("L2_snoop_tag_RAM", buf)) {
+ ramindex = L2_snoop_tag_RAM;
+ } else if (sysfs_streq("L2_data_ECC_RAM", buf)) {
+ ramindex = L2_data_ECC_RAM;
+ } else if (sysfs_streq("L2_dirty_RAM", buf)) {
+ ramindex = L2_dirty_RAM;
+ } else if (sysfs_streq("L2_TLB_RAM", buf)) {
+ ramindex = L2_TLB_RAM;
+ } else {
+ printk("Invalid value....\n\n");
+ printk("Available options are one of below\n");
+ printk("L1_I_tag_RAM, L1_I_data_RAM, L1_I_BTB_RAM\n");
+ printk("L1_I_GHB_RAM, L1_I_TLB_RAM, L1_I_indirect_predictor_RAM\n");
+ printk("L1_D_tag_RAM, L1_D_data_RAM, L1_D_load_TLB_array, L1_D_store_TLB_array\n");
+ printk("L2_tag_RAM, L2_data_RAM, L2_snoop_tag_RAM, L2_data_ECC_RAM\n");
+ printk("L2_dirty_RAM, L2_TLB_RAM\n");
+ }
+
+ return count;
+}
+
+static ssize_t show_vol(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct kbase_device *kbdev;
+ ssize_t ret = 0;
+ int vol;
+
+ kbdev = dev_get_drvdata(dev);
+
+ if (!kbdev)
+ return -ENODEV;
+
+ kbase_platform_get_voltage(dev, &vol);
+ ret += snprintf(buf+ret, PAGE_SIZE-ret, "Current operating voltage for mali t6xx = %d, 0x%x", vol, __raw_readl(EXYNOS5_G3D_STATUS));
+
+ if (ret < PAGE_SIZE - 1) {
+ ret += snprintf(buf+ret, PAGE_SIZE-ret, "\n");
+ } else {
+ buf[PAGE_SIZE-2] = '\n';
+ buf[PAGE_SIZE-1] = '\0';
+ ret = PAGE_SIZE-1;
+ }
+
+ return ret;
+}
+
+static int get_clkout_cmu_top(int *val)
+{
+ *val = __raw_readl(EXYNOS5_CLKOUT_CMU_TOP);
+ if((*val & 0x1f) == 0xB) /* CLKOUT is ACLK_400 in CLKOUT_CMU_TOP */
+ return 1;
+ else
+ return 0;
+}
+
+static void set_clkout_for_3d(void)
+{
+#ifdef PMU_XCLKOUT_SET
+ int tmp;
+
+ tmp = 0x0;
+ tmp |= 0x1000B; // ACLK_400 selected
+ tmp |= 9 << 8; // divided by (9 + 1)
+ __raw_writel(tmp, EXYNOS5_CLKOUT_CMU_TOP);
+
+ tmp = 0x0;
+ tmp |= 7 << 8; // CLKOUT_CMU_TOP selected
+ __raw_writel(tmp, S5P_PMU_DEBUG);
+#endif
+}
+
+static ssize_t show_clkout(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct kbase_device *kbdev;
+ ssize_t ret = 0;
+ int val;
+
+ kbdev = dev_get_drvdata(dev);
+
+ if (!kbdev)
+ return -ENODEV;
+
+ if(get_clkout_cmu_top(&val))
+ ret += snprintf(buf+ret, PAGE_SIZE-ret, "Current CLKOUT is g3d divided by 10, CLKOUT_CMU_TOP=0x%x", val);
+ else
+ ret += snprintf(buf+ret, PAGE_SIZE-ret, "Current CLKOUT is not g3d, CLKOUT_CMU_TOP=0x%x", val);
+
+ if (ret < PAGE_SIZE - 1) {
+ ret += snprintf(buf+ret, PAGE_SIZE-ret, "\n");
+ } else {
+ buf[PAGE_SIZE-2] = '\n';
+ buf[PAGE_SIZE-1] = '\0';
+ ret = PAGE_SIZE-1;
+ }
+
+ return ret;
+}
+
+static ssize_t set_clkout(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct kbase_device *kbdev;
+ kbdev = dev_get_drvdata(dev);
+
+ if (!kbdev)
+ return -ENODEV;
+
+ if (sysfs_streq("3d", buf)) {
+ set_clkout_for_3d();
+ } else {
+ printk("invalid val (only 3d is accepted\n");
+ }
+
+ return count;
+}
+
+static ssize_t show_dvfs(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct kbase_device *kbdev;
+ ssize_t ret = 0;
+
+ kbdev = dev_get_drvdata(dev);
+
+ if (!kbdev)
+ return -ENODEV;
+
+#ifdef CONFIG_MALI_T6XX_DVFS
+ if(kbase_platform_dvfs_get_enable_status())
+ ret += snprintf(buf+ret, PAGE_SIZE-ret, "G3D DVFS is on\nutilisation:%d",kbase_platform_dvfs_get_utilisation());
+ else
+ ret += snprintf(buf+ret, PAGE_SIZE-ret, "G3D DVFS is off");
+#else
+ ret += snprintf(buf+ret, PAGE_SIZE-ret, "G3D DVFS is disabled");
+#endif
+
+ if (ret < PAGE_SIZE - 1) {
+ ret += snprintf(buf+ret, PAGE_SIZE-ret, "\n");
+ } else {
+ buf[PAGE_SIZE-2] = '\n';
+ buf[PAGE_SIZE-1] = '\0';
+ ret = PAGE_SIZE-1;
+ }
+
+ return ret;
+}
+
+static ssize_t set_dvfs(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct kbase_device *kbdev;
+ kbdev = dev_get_drvdata(dev);
+
+ if (!kbdev)
+ return -ENODEV;
+
+#ifdef CONFIG_MALI_T6XX_DVFS
+ if (sysfs_streq("off", buf)) {
+ kbase_platform_dvfs_enable(false, MALI_DVFS_BL_CONFIG_FREQ);
+ } else if (sysfs_streq("on", buf)) {
+ kbase_platform_dvfs_enable(true, MALI_DVFS_START_FREQ);
+ } else {
+ printk("invalid val -only [on, off] is accepted\n");
+ }
+#else
+ printk("G3D DVFS is disabled\n");
+#endif
+ return count;
+}
+
+static ssize_t show_upper_lock_dvfs(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct kbase_device *kbdev;
+ ssize_t ret = 0;
+#ifdef CONFIG_MALI_T6XX_DVFS
+ unsigned int locked_level = -1;
+#endif
+
+ kbdev = dev_get_drvdata(dev);
+
+ if (!kbdev)
+ return -ENODEV;
+
+#ifdef CONFIG_MALI_T6XX_DVFS
+ locked_level = mali_get_dvfs_upper_locked_freq();
+ if( locked_level > 0 )
+ ret += snprintf(buf+ret, PAGE_SIZE-ret, "Current Upper Lock Level = %dMhz", locked_level );
+ else
+ ret += snprintf(buf+ret, PAGE_SIZE-ret, "Unset the Upper Lock Level");
+ ret += snprintf(buf+ret, PAGE_SIZE-ret, "\nPossible settings : 450, 400, 266, 160, 100, If you want to unlock : 533 or off");
+
+#else
+ ret += snprintf(buf+ret, PAGE_SIZE-ret, "G3D DVFS is disabled. You can not set");
+#endif
+
+ if (ret < PAGE_SIZE - 1) {
+ ret += snprintf(buf+ret, PAGE_SIZE-ret, "\n");
+ } else {
+ buf[PAGE_SIZE-2] = '\n';
+ buf[PAGE_SIZE-1] = '\0';
+ ret = PAGE_SIZE-1;
+ }
+
+ return ret;
+}
+
+static ssize_t set_upper_lock_dvfs(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct kbase_device *kbdev;
+ kbdev = dev_get_drvdata(dev);
+
+ if (!kbdev)
+ return -ENODEV;
+
+#ifdef CONFIG_MALI_T6XX_DVFS
+ if (sysfs_streq("off", buf)) {
+ mali_dvfs_freq_unlock();
+ } else if (sysfs_streq("533", buf)) {
+ mali_dvfs_freq_unlock();
+ } else if (sysfs_streq("450", buf)) {
+ mali_dvfs_freq_lock(5);
+ } else if (sysfs_streq("400", buf)) {
+ mali_dvfs_freq_lock(4);
+ } else if (sysfs_streq("350", buf)) {
+ mali_dvfs_freq_lock(3);
+ } else if (sysfs_streq("266", buf)) {
+ mali_dvfs_freq_lock(2);
+ } else if (sysfs_streq("160", buf)) {
+ mali_dvfs_freq_lock(1);
+ } else if (sysfs_streq("100", buf)) {
+ mali_dvfs_freq_lock(0);
+ } else {
+ dev_err(dev, "set_clock: invalid value\n");
+ dev_err(dev, "Possible settings : 450, 400, 266, 160, 100, If you want to unlock : 533\n");
+ return -ENOENT;
+ }
+#else /* CONFIG_MALI_T6XX_DVFS */
+ printk("G3D DVFS is disabled. You can not set\n");
+#endif
+
+ return count;
+}
+
+static ssize_t show_under_lock_dvfs(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct kbase_device *kbdev;
+ ssize_t ret = 0;
+#ifdef CONFIG_MALI_T6XX_DVFS
+ unsigned int locked_level = -1;
+#endif
+
+ kbdev = dev_get_drvdata(dev);
+
+ if (!kbdev)
+ return -ENODEV;
+
+#ifdef CONFIG_MALI_T6XX_DVFS
+ locked_level = mali_get_dvfs_under_locked_freq();
+ if( locked_level > 0 )
+ ret += snprintf(buf+ret, PAGE_SIZE-ret, "Current Under Lock Level = %dMhz", locked_level );
+ else
+ ret += snprintf(buf+ret, PAGE_SIZE-ret, "Unset the Under Lock Level");
+ ret += snprintf(buf+ret, PAGE_SIZE-ret, "\nPossible settings : 533, 450, 400, 266, 160, If you want to unlock : 100 or off");
+
+#else
+ ret += snprintf(buf+ret, PAGE_SIZE-ret, "G3D DVFS is disabled. You can not set");
+#endif
+
+ if (ret < PAGE_SIZE - 1) {
+ ret += snprintf(buf+ret, PAGE_SIZE-ret, "\n");
+ } else {
+ buf[PAGE_SIZE-2] = '\n';
+ buf[PAGE_SIZE-1] = '\0';
+ ret = PAGE_SIZE-1;
+ }
+
+ return ret;
+}
+
+static ssize_t set_under_lock_dvfs(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct kbase_device *kbdev;
+ kbdev = dev_get_drvdata(dev);
+
+ if (!kbdev)
+ return -ENODEV;
+
+#ifdef CONFIG_MALI_T6XX_DVFS
+ if (sysfs_streq("off", buf)) {
+ mali_dvfs_freq_under_unlock();
+ } else if (sysfs_streq("533", buf)) {
+ mali_dvfs_freq_under_lock(6);
+ } else if (sysfs_streq("450", buf)) {
+ mali_dvfs_freq_under_lock(5);
+ } else if (sysfs_streq("400", buf)) {
+ mali_dvfs_freq_under_lock(4);
+ } else if (sysfs_streq("350", buf)) {
+ mali_dvfs_freq_under_lock(3);
+ } else if (sysfs_streq("266", buf)) {
+ mali_dvfs_freq_under_lock(2);
+ } else if (sysfs_streq("160", buf)) {
+ mali_dvfs_freq_under_lock(1);
+ } else if (sysfs_streq("100", buf)) {
+ mali_dvfs_freq_under_unlock();
+ } else {
+ dev_err(dev, "set_clock: invalid value\n");
+ dev_err(dev, "Possible settings : 533, 450, 400, 266, 160, If you want to unlock : 100 or off\n");
+ return -ENOENT;
+ }
+#else // CONFIG_MALI_T6XX_DVFS
+ printk("G3D DVFS is disabled. You can not set\n");
+#endif
+
+ return count;
+}
+
+static ssize_t show_asv(struct device *dev, struct device_attribute *attr, char *buf)
+{
+
+ struct kbase_device *kbdev;
+ ssize_t ret = 0;
+
+ kbdev = dev_get_drvdata(dev);
+
+ if (!kbdev)
+ return -ENODEV;
+
+ ret=kbase_platform_dvfs_sprint_avs_table(buf);
+
+ return ret;
+}
+static ssize_t set_asv(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ if (sysfs_streq("off", buf)) {
+ kbase_platform_dvfs_set(0);
+ } else if (sysfs_streq("on", buf)) {
+ kbase_platform_dvfs_set(1);
+ } else {
+ printk("invalid val -only [on, off] is accepted\n");
+ }
+ return count;
+}
+
+
+/** The sysfs file @c clock, fbdev.
+ *
+ * This is used for obtaining information about the mali t6xx operating clock & framebuffer address,
+ */
+DEVICE_ATTR(clock, S_IRUGO|S_IWUSR, show_clock, set_clock);
+DEVICE_ATTR(fbdev, S_IRUGO, show_fbdev, NULL);
+DEVICE_ATTR(dtlb, S_IRUGO|S_IWUSR, show_dtlb, set_dtlb);
+DEVICE_ATTR(vol, S_IRUGO|S_IWUSR, show_vol, NULL);
+DEVICE_ATTR(clkout, S_IRUGO|S_IWUSR, show_clkout, set_clkout);
+DEVICE_ATTR(dvfs, S_IRUGO|S_IWUSR, show_dvfs, set_dvfs);
+DEVICE_ATTR(dvfs_upper_lock, S_IRUGO|S_IWUSR, show_upper_lock_dvfs, set_upper_lock_dvfs);
+DEVICE_ATTR(dvfs_under_lock, S_IRUGO|S_IWUSR, show_under_lock_dvfs, set_under_lock_dvfs);
+DEVICE_ATTR(asv, S_IRUGO|S_IWUSR, show_asv, set_asv);
+DEVICE_ATTR(time_in_state, S_IRUGO|S_IWUSR, show_time_in_state, set_time_in_state);
+
+int kbase_platform_create_sysfs_file(struct device *dev)
+{
+ if (device_create_file(dev, &dev_attr_clock)) {
+ dev_err(dev, "Couldn't create sysfs file [clock]\n");
+ goto out;
+ }
+
+ if (device_create_file(dev, &dev_attr_fbdev)) {
+ dev_err(dev, "Couldn't create sysfs file [fbdev]\n");
+ goto out;
+ }
+
+ if (device_create_file(dev, &dev_attr_dtlb)) {
+ dev_err(dev, "Couldn't create sysfs file [dtlb]\n");
+ goto out;
+ }
+
+ if (device_create_file(dev, &dev_attr_vol)) {
+ dev_err(dev, "Couldn't create sysfs file [vol]\n");
+ goto out;
+ }
+
+ if (device_create_file(dev, &dev_attr_clkout)) {
+ dev_err(dev, "Couldn't create sysfs file [clkout]\n");
+ goto out;
+ }
+
+ if (device_create_file(dev, &dev_attr_dvfs)) {
+ dev_err(dev, "Couldn't create sysfs file [dvfs]\n");
+ goto out;
+ }
+
+ if (device_create_file(dev, &dev_attr_dvfs_upper_lock)) {
+ dev_err(dev, "Couldn't create sysfs file [dvfs_upper_lock]\n");
+ goto out;
+ }
+
+ if (device_create_file(dev, &dev_attr_dvfs_under_lock)) {
+ dev_err(dev, "Couldn't create sysfs file [dvfs_under_lock]\n");
+ goto out;
+ }
+
+ if (device_create_file(dev, &dev_attr_asv)) {
+ dev_err(dev, "Couldn't create sysfs file [asv]\n");
+ goto out;
+ }
+
+ if (device_create_file(dev, &dev_attr_time_in_state)) {
+ dev_err(dev, "Couldn't create sysfs file [time_in_state]\n");
+ goto out;
+ }
+
+ return 0;
+out:
+ return -ENOENT;
+}
+
+void kbase_platform_remove_sysfs_file(struct device *dev)
+{
+ device_remove_file(dev, &dev_attr_clock);
+ device_remove_file(dev, &dev_attr_fbdev);
+ device_remove_file(dev, &dev_attr_dtlb);
+ device_remove_file(dev, &dev_attr_vol);
+ device_remove_file(dev, &dev_attr_clkout);
+ device_remove_file(dev, &dev_attr_dvfs);
+ device_remove_file(dev, &dev_attr_dvfs_upper_lock);
+ device_remove_file(dev, &dev_attr_dvfs_under_lock);
+ device_remove_file(dev, &dev_attr_asv);
+ device_remove_file(dev, &dev_attr_time_in_state);
+}
+#endif /* CONFIG_MALI_T6XX_DEBUG_SYS */
+
+mali_error kbase_platform_init(struct kbase_device *kbdev)
+{
+ struct exynos_context *platform;
+
+ platform = osk_malloc(sizeof(struct exynos_context));
+
+ if (NULL == platform) {
+ return MALI_ERROR_OUT_OF_MEMORY;
+ }
+
+ kbdev->platform_context = (void *) platform;
+
+ platform->cmu_pmu_status = 0;
+#ifdef CONFIG_MALI_T6XX_DVFS
+ platform->utilisation = 0;
+ platform->time_busy = 0;
+ platform->time_idle = 0;
+ platform->time_tick = 0;
+#endif
+
+ spin_lock_init(&platform->cmu_pmu_lock);
+
+ if (kbase_platform_power_clock_init(kbdev)) {
+ goto clock_init_fail;
+ }
+
+#ifdef CONFIG_REGULATOR
+ if (kbase_platform_regulator_init()) {
+ goto regulator_init_fail;
+ }
+#endif /* CONFIG_REGULATOR */
+
+
+#ifdef CONFIG_MALI_T6XX_DVFS
+ kbase_platform_dvfs_init(kbdev);
+#endif /* CONFIG_MALI_T6XX_DVFS */
+
+ /* Enable power */
+ kbase_platform_cmu_pmu_control(kbdev, 1);
+
+ return MALI_ERROR_NONE;
+
+regulator_init_fail:
+clock_init_fail:
+#ifdef CONFIG_REGULATOR
+ kbase_platform_regulator_disable();
+#endif /* CONFIG_REGULATOR */
+ osk_free(platform);
+
+ return MALI_ERROR_FUNCTION_FAILED;
+}
+
+void kbase_platform_term(kbase_device *kbdev)
+{
+ struct exynos_context *platform;
+
+ platform = (struct exynos_context *) kbdev->platform_context;
+
+#ifdef CONFIG_MALI_T6XX_DVFS
+ kbase_platform_dvfs_term();
+#endif /* CONFIG_MALI_T6XX_DVFS */
+ /* Disable power */
+ kbase_platform_cmu_pmu_control(kbdev, 0);
+#ifdef CONFIG_REGULATOR
+ kbase_platform_regulator_disable();
+#endif /* CONFIG_REGULATOR */
+ osk_free(kbdev->platform_context);
+ kbdev->platform_context = 0;
+
+ return;
+}
+
diff --git a/drivers/gpu/arm/t6xx/kbase/src/platform/mali_kbase_platform.h b/drivers/gpu/arm/t6xx/kbase/src/platform/mali_kbase_platform.h
new file mode 100644
index 0000000..de986ff
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/kbase/src/platform/mali_kbase_platform.h
@@ -0,0 +1,48 @@
+/* drivers/gpu/t6xx/kbase/src/platform/mali_kbase_platform.h
+ *
+ * Copyright 2011 by S.LSI. Samsung Electronics Inc.
+ * San#24, Nongseo-Dong, Giheung-Gu, Yongin, Korea
+ *
+ * Samsung SoC Mali-T604 platform-dependent codes
+ *
+ * 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.
+ */
+
+/**
+ * @file mali_kbase_platform.h
+ * Platform-dependent init
+ */
+
+#ifndef _KBASE_PLATFORM_H_
+#define _KBASE_PLATFORM_H_
+
+struct exynos_context
+{
+ /** Indicator if system clock to mail-t604 is active */
+ int cmu_pmu_status;
+ /** cmd & pmu lock */
+ spinlock_t cmu_pmu_lock;
+ struct clk *sclk_g3d;
+#ifdef CONFIG_MALI_T6XX_DVFS
+ /*To calculate utilization for x sec*/
+ int time_tick;
+ int utilisation;
+ u32 time_busy;
+ u32 time_idle;
+#endif
+};
+
+/* All things that are needed for the Linux port. */
+int kbase_platform_cmu_pmu_control(struct kbase_device *kbdev, int control);
+int kbase_platform_create_sysfs_file(struct device *dev);
+void kbase_platform_remove_sysfs_file(struct device *dev);
+int kbase_platform_is_power_on(void);
+mali_error kbase_platform_init(struct kbase_device *kbdev);
+void kbase_platform_term(kbase_device *kbdev);
+
+int kbase_platform_clock_on(struct kbase_device *kbdev);
+int kbase_platform_clock_off(struct kbase_device *kbdev);
+
+#endif /* _KBASE_PLATFORM_H_ */
diff --git a/drivers/gpu/arm/t6xx/license.txt b/drivers/gpu/arm/t6xx/license.txt
new file mode 100755
index 0000000..77c14bd
--- /dev/null
+++ b/drivers/gpu/arm/t6xx/license.txt
@@ -0,0 +1,198 @@
+GPLV2 LICENCE AGREEMENT FOR MALI GPUS LINUX KERNEL DEVICE DRIVERS SOURCE CODE
+
+THE USE OF THE SOFTWARE ACCOMPANYING THIS DOCUMENT IS EXPRESSLY SUBJECT TO THE TERMS OF THE GNU GENERAL PUBLIC LICENSE VERSION 2 AS PUBLISHED BY THE FREE SOFTWARE FOUNDATION AND SET OUT BELOW FOR REFERENCE (?GPL LICENCE?). ARM IS ONLY WILLING TO DISTRIBUTE THE SOFTWARE TO YOU ON CONDITION THAT YOU ACCEPT ALL OF THE TERMS IN THE GPL LICENCE PRIOR TO MODIFYING OR DISTRIBUTING THE SOFTWARE.
+
+
+
+Further for the period of three (3) years, ARM hereby offers to make available the source code of any part of the software program that is supplied as object code or in executable form.
+
+
+
+GPL Licence
+
+
+
+GNU GENERAL PUBLIC LICENSE
+
+Version 2, June 1991
+
+
+
+Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
+
+
+
+Preamble
+
+
+
+The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too.
+
+
+
+When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things.
+
+
+
+To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it.
+
+
+
+For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.
+
+
+
+We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software.
+
+
+
+Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations.
+
+
+
+Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all.
+
+
+
+The precise terms and conditions for copying, distribution and modification follow.
+
+
+
+GNU GENERAL PUBLIC LICENSE
+
+TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+
+
+0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you".
+
+
+
+Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program).
+
+Whether that is true depends on what the Program does.
+
+
+
+1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty;
+
+and give any other recipients of the Program a copy of this License along with the Program.
+
+
+
+You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.
+
+
+
+2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:
+
+
+
+a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.
+
+
+
+b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License.
+
+
+
+c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.)
+
+
+
+These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.
+
+
+
+Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program.
+
+
+
+In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.
+
+
+
+3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following:
+
+
+
+a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
+
+
+
+b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
+
+
+
+c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.)
+
+
+
+The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.
+
+
+
+If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code.
+
+
+
+4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.
+
+
+
+5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the
+
+Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it.
+
+
+
+6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein.
+
+You are not responsible for enforcing compliance by third parties to this License.
+
+
+
+7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program.
+
+
+
+If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances.
+
+
+
+It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.
+
+
+
+This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.
+
+
+
+8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.
+
+
+
+9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.
+
+
+
+Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation.
+
+
+
+10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.
+
+
+
+NO WARRANTY
+
+
+
+11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+
+
+12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+/end
+
diff --git a/drivers/gpu/ion/Kconfig b/drivers/gpu/ion/Kconfig
index b5bfdb4..442f697 100644
--- a/drivers/gpu/ion/Kconfig
+++ b/drivers/gpu/ion/Kconfig
@@ -11,3 +11,49 @@
help
Choose this option if you wish to use ion on an nVidia Tegra.
+config ION_EXYNOS
+ tristate "Ion for Exynos"
+ depends on ARCH_EXYNOS && ION
+ select CMA
+ help
+ Choose this option if you wish to use ion on a Samsung Exynos.
+
+config ION_EXYNOS_CONTIGHEAP_SIZE
+ int "Size in Kilobytes of memory pool of EXYNOS_CONTIG_HEAP"
+ depends on ION_EXYNOS && CMA
+ default 45056
+
+config ION_EXYNOS_DRM_MFC_SH
+ bool "ION Heap for drm mfc sh"
+ depends on EXYNOS_CONTENT_PATH_PROTECTION
+ default y
+
+config ION_EXYNOS_DRM_MSGBOX_SH
+ bool "ION Heap for drm msgbox sh"
+ depends on EXYNOS_CONTENT_PATH_PROTECTION
+ default y
+
+config ION_EXYNOS_DRM_MFC_FW
+ bool "ION Heap for drm fw"
+ depends on EXYNOS_CONTENT_PATH_PROTECTION
+ default y
+
+config ION_EXYNOS_DRM_SECTBL
+ bool "ION Heap for drm sectbl"
+ depends on EXYNOS_CONTENT_PATH_PROTECTION
+ default y
+
+config ION_EXYNOS_DRM_MEMSIZE_FIMD_VIDEO
+ int "Reserved memsize in kilobytes for FIMD VIDEO"
+ depends on EXYNOS_CONTENT_PATH_PROTECTION
+ default 98304
+
+config ION_EXYNOS_DRM_MEMSIZE_MFC_OUTPUT
+ int "Reserved memsize in kilobytes for MFC OUTPUT"
+ depends on EXYNOS_CONTENT_PATH_PROTECTION
+ default 40960
+
+config ION_EXYNOS_DRM_MEMSIZE_MFC_INPUT
+ int "Reserved memsize in kilobytes for MFC INPUT"
+ depends on EXYNOS_CONTENT_PATH_PROTECTION
+ default 16384
diff --git a/drivers/gpu/ion/Makefile b/drivers/gpu/ion/Makefile
index 306fff9..ddfb805 100644
--- a/drivers/gpu/ion/Makefile
+++ b/drivers/gpu/ion/Makefile
@@ -1,3 +1,4 @@
obj-$(CONFIG_ION) += ion.o ion_heap.o ion_page_pool.o ion_system_heap.o \
ion_carveout_heap.o ion_chunk_heap.o
obj-$(CONFIG_ION_TEGRA) += tegra/
+obj-$(CONFIG_ION_EXYNOS) += exynos/
diff --git a/drivers/gpu/ion/exynos/Makefile b/drivers/gpu/ion/exynos/Makefile
new file mode 100644
index 0000000..9b6de53
--- /dev/null
+++ b/drivers/gpu/ion/exynos/Makefile
@@ -0,0 +1 @@
+obj-y += exynos_ion.o
diff --git a/drivers/gpu/ion/exynos/exynos_ion.c b/drivers/gpu/ion/exynos/exynos_ion.c
new file mode 100644
index 0000000..0d6a7a8
--- /dev/null
+++ b/drivers/gpu/ion/exynos/exynos_ion.c
@@ -0,0 +1,1022 @@
+/*
+ * drivers/gpu/exynos/exynos_ion.c
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 <linux/err.h>
+#include <linux/ion.h>
+#include <linux/exynos_ion.h>
+#include <linux/platform_device.h>
+#include <linux/mm.h>
+#include <linux/cma.h>
+#include <linux/scatterlist.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/bitops.h>
+#include <linux/pagemap.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/pgtable.h>
+
+#include "../ion_priv.h"
+
+struct ion_device *ion_exynos;
+
+static int num_heaps;
+static struct ion_heap **heaps;
+static struct device *exynos_ion_dev;
+
+/* IMBUFS stands for "InterMediate BUFfer Storage" */
+#define IMBUFS_SHIFT 4
+#define IMBUFS_ENTRIES (1 << IMBUFS_SHIFT)
+#define IMBUFS_MASK (IMBUFS_ENTRIES - 1) /* masking lower bits */
+#define MAX_LV0IMBUFS IMBUFS_ENTRIES
+#define MAX_LV1IMBUFS (IMBUFS_ENTRIES + IMBUFS_ENTRIES * IMBUFS_ENTRIES)
+#define MAX_IMBUFS (MAX_LV1IMBUFS + (IMBUFS_ENTRIES << (IMBUFS_SHIFT * 2)))
+
+#define LV1IDX(lv1base) ((lv1base) >> IMBUFS_SHIFT)
+#define LV2IDX1(lv2base) ((lv2base) >> (IMBUFS_SHIFT * 2))
+#define LV2IDX2(lv2base) (((lv2base) >> (IMBUFS_SHIFT)) & IMBUFS_MASK)
+
+static int orders[] = {PAGE_SHIFT + 8, PAGE_SHIFT + 4, PAGE_SHIFT, 0};
+
+static inline phys_addr_t *get_imbufs_and_free(int idx,
+ phys_addr_t *lv0imbufs, phys_addr_t **lv1pimbufs,
+ phys_addr_t ***lv2ppimbufs)
+{
+ if (idx < MAX_LV0IMBUFS) {
+ return lv0imbufs;
+ } else if (idx < MAX_LV1IMBUFS) {
+ phys_addr_t *imbufs;
+ idx -= MAX_LV0IMBUFS;
+ imbufs = lv1pimbufs[LV1IDX(idx)];
+ if ((LV1IDX(idx) == (IMBUFS_ENTRIES - 1)) ||
+ (lv1pimbufs[LV1IDX(idx) + 1] == NULL))
+ kfree(lv1pimbufs);
+ return imbufs;
+ } else if (idx < MAX_IMBUFS) {
+ int baseidx;
+ phys_addr_t *imbufs;
+ baseidx = idx - MAX_LV1IMBUFS;
+ imbufs = lv2ppimbufs[LV2IDX1(baseidx)][LV2IDX2(baseidx)];
+ if ((LV2IDX2(baseidx) == (IMBUFS_ENTRIES - 1)) ||
+ (lv2ppimbufs[LV2IDX1(baseidx)][LV2IDX2(baseidx) + 1]
+ == NULL)) {
+ kfree(lv2ppimbufs[LV2IDX1(baseidx)]);
+ if ((LV2IDX1(baseidx) == (IMBUFS_ENTRIES - 1)) ||
+ (lv2ppimbufs[LV2IDX1(baseidx) + 1] == NULL))
+ kfree(lv2ppimbufs);
+ }
+ return imbufs;
+
+ }
+ return NULL;
+}
+
+static int ion_exynos_heap_allocate(struct ion_heap *heap,
+ struct ion_buffer *buffer,
+ unsigned long size, unsigned long align,
+ unsigned long flags)
+{
+ int *cur_order = orders;
+ int alloc_chunks = 0;
+ int ret = 0;
+ phys_addr_t *im_phys_bufs = NULL;
+ phys_addr_t **pim_phys_bufs = NULL;
+ phys_addr_t ***ppim_phys_bufs = NULL;
+ phys_addr_t *cur_bufs = NULL;
+ int copied = 0;
+ struct scatterlist *sgl;
+ struct sg_table *sgtable;
+
+ while (size && *cur_order) {
+ struct page *page;
+
+ if (size < (1 << *cur_order)) {
+ cur_order++;
+ continue;
+ }
+
+ page = alloc_pages(GFP_HIGHUSER | __GFP_COMP |
+ __GFP_NOWARN | __GFP_NORETRY,
+ *cur_order - PAGE_SHIFT);
+ if (!page) {
+ cur_order++;
+ continue;
+ }
+
+ if (alloc_chunks & IMBUFS_MASK) {
+ cur_bufs++;
+ } else if (alloc_chunks < MAX_LV0IMBUFS) {
+ if (!im_phys_bufs)
+ im_phys_bufs = kzalloc(
+ sizeof(*im_phys_bufs) * IMBUFS_ENTRIES,
+ GFP_KERNEL);
+ if (!im_phys_bufs)
+ break;
+
+ cur_bufs = im_phys_bufs;
+ } else if (alloc_chunks < MAX_LV1IMBUFS) {
+ int lv1idx = LV1IDX(alloc_chunks - MAX_LV0IMBUFS);
+
+ if (!pim_phys_bufs) {
+ pim_phys_bufs = kzalloc(
+ sizeof(*pim_phys_bufs) * IMBUFS_ENTRIES,
+ GFP_KERNEL);
+ if (!pim_phys_bufs)
+ break;
+ }
+
+ if (!pim_phys_bufs[lv1idx]) {
+ pim_phys_bufs[lv1idx] = kzalloc(
+ sizeof(*cur_bufs) * IMBUFS_ENTRIES,
+ GFP_KERNEL);
+ if (!pim_phys_bufs[lv1idx])
+ break;
+ }
+
+ cur_bufs = pim_phys_bufs[lv1idx];
+ } else if (alloc_chunks < MAX_IMBUFS) {
+ phys_addr_t **pcur_bufs;
+ int lv2base = alloc_chunks - MAX_LV1IMBUFS;
+
+ if (!ppim_phys_bufs) {
+ ppim_phys_bufs = kzalloc(
+ sizeof(*ppim_phys_bufs) * IMBUFS_ENTRIES
+ , GFP_KERNEL);
+ if (!ppim_phys_bufs)
+ break;
+ }
+
+ if (!ppim_phys_bufs[LV2IDX1(lv2base)]) {
+ ppim_phys_bufs[LV2IDX1(lv2base)] = kzalloc(
+ sizeof(*pcur_bufs) * IMBUFS_ENTRIES,
+ GFP_KERNEL);
+ if (!ppim_phys_bufs[LV2IDX1(lv2base)])
+ break;
+ }
+ pcur_bufs = ppim_phys_bufs[LV2IDX1(lv2base)];
+
+ if (!pcur_bufs[LV2IDX2(lv2base)]) {
+ pcur_bufs[LV2IDX2(lv2base)] = kzalloc(
+ sizeof(*cur_bufs) * IMBUFS_ENTRIES,
+ GFP_KERNEL);
+ if (!pcur_bufs[LV2IDX2(lv2base)])
+ break;
+ }
+ cur_bufs = pcur_bufs[LV2IDX2(lv2base)];
+ } else {
+ break;
+ }
+
+ *cur_bufs = page_to_phys(page) | *cur_order;
+
+ size = size - (1 << *cur_order);
+ alloc_chunks++;
+ }
+
+ if (size) {
+ ret = -ENOMEM;
+ goto alloc_error;
+ }
+
+ sgtable = kmalloc(sizeof(*sgtable), GFP_KERNEL);
+ if (!sgtable) {
+ ret = -ENOMEM;
+ goto alloc_error;
+ }
+
+ if (sg_alloc_table(sgtable, alloc_chunks, GFP_KERNEL)) {
+ ret = -ENOMEM;
+ kfree(sgtable);
+ goto alloc_error;
+ }
+
+ sgl = sgtable->sgl;
+ while (copied < alloc_chunks) {
+ int i;
+ cur_bufs = get_imbufs_and_free(copied, im_phys_bufs,
+ pim_phys_bufs, ppim_phys_bufs);
+ BUG_ON(!cur_bufs);
+ for (i = 0; (i < IMBUFS_ENTRIES) && cur_bufs[i]; i++) {
+ phys_addr_t phys;
+ int order;
+
+ phys = cur_bufs[i];
+ order = phys & ~PAGE_MASK;
+ sg_set_page(sgl, phys_to_page(phys), 1 << order, 0);
+ sgl = sg_next(sgl);
+ copied++;
+ }
+
+ kfree(cur_bufs);
+ }
+
+ buffer->priv_virt = sgtable;
+ buffer->flags = flags;
+
+ return 0;
+alloc_error:
+ copied = 0;
+ while (copied < alloc_chunks) {
+ int i;
+ cur_bufs = get_imbufs_and_free(copied, im_phys_bufs,
+ pim_phys_bufs, ppim_phys_bufs);
+ for (i = 0; (i < IMBUFS_ENTRIES) && cur_bufs[i]; i++) {
+ phys_addr_t phys;
+ int gfp_order;
+
+ phys = cur_bufs[i];
+ gfp_order = (phys & ~PAGE_MASK) - PAGE_SHIFT;
+ phys = phys & PAGE_MASK;
+ __free_pages(phys_to_page(phys), gfp_order);
+ }
+
+ kfree(cur_bufs);
+ copied += IMBUFS_ENTRIES;
+ }
+
+ return ret;
+}
+
+static void ion_exynos_heap_free(struct ion_buffer *buffer)
+{
+ struct scatterlist *sg;
+ int i;
+ struct sg_table *sgtable = buffer->priv_virt;
+
+ for_each_sg(sgtable->sgl, sg, sgtable->orig_nents, i)
+ __free_pages(sg_page(sg), __ffs(sg_dma_len(sg)) - PAGE_SHIFT);
+
+ sg_free_table(sgtable);
+ kfree(sgtable);
+}
+
+static struct sg_table *ion_exynos_heap_map_dma(struct ion_heap *heap,
+ struct ion_buffer *buffer)
+{
+ return buffer->priv_virt;
+}
+
+static void ion_exynos_heap_unmap_dma(struct ion_heap *heap,
+ struct ion_buffer *buffer)
+{
+}
+
+static void *ion_exynos_heap_map_kernel(struct ion_heap *heap,
+ struct ion_buffer *buffer)
+{
+ struct page **pages, **tmp_pages;
+ struct sg_table *sgt;
+ struct scatterlist *sgl;
+ int num_pages, i;
+ void *vaddr;
+
+ sgt = buffer->priv_virt;
+ num_pages = PAGE_ALIGN(offset_in_page(sg_phys(sgt->sgl)) + buffer->size)
+ >> PAGE_SHIFT;
+
+ pages = vmalloc(sizeof(*pages) * num_pages);
+ if (!pages)
+ return NULL;
+
+ tmp_pages = pages;
+ for_each_sg(sgt->sgl, sgl, sgt->orig_nents, i) {
+ struct page *page = sg_page(sgl);
+ unsigned int n =
+ PAGE_ALIGN(sgl->offset + sg_dma_len(sgl)) >> PAGE_SHIFT;
+
+ for (; n > 0; n--)
+ *(tmp_pages++) = page++;
+ }
+
+ vaddr = vmap(pages, num_pages, VM_USERMAP | VM_MAP, PAGE_KERNEL);
+
+ vfree(pages);
+
+ return vaddr + offset_in_page(sg_phys(sgt->sgl));
+}
+
+static void ion_exynos_heap_unmap_kernel(struct ion_heap *heap,
+ struct ion_buffer *buffer)
+{
+ struct sg_table *sgt = buffer->priv_virt;
+
+ vunmap(buffer->vaddr - offset_in_page(sg_phys(sgt->sgl)));
+}
+
+static int ion_exynos_heap_map_user(struct ion_heap *heap,
+ struct ion_buffer *buffer, struct vm_area_struct *vma)
+{
+ struct sg_table *sgt = buffer->priv_virt;
+ struct scatterlist *sgl;
+ unsigned long pgoff;
+ int i;
+ unsigned long start;
+ int map_pages;
+
+ if (buffer->kmap_cnt)
+ return remap_vmalloc_range(vma, buffer->vaddr, vma->vm_pgoff);
+
+ pgoff = vma->vm_pgoff;
+ start = vma->vm_start;
+ map_pages = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+ vma->vm_flags |= VM_RESERVED;
+
+ for_each_sg(sgt->sgl, sgl, sgt->orig_nents, i) {
+ unsigned long sg_pgnum = sg_dma_len(sgl) >> PAGE_SHIFT;
+
+ if (sg_pgnum <= pgoff) {
+ pgoff -= sg_pgnum;
+ } else {
+ struct page *page = sg_page(sgl) + pgoff;
+ int i;
+
+ sg_pgnum -= pgoff;
+
+ for (i = 0; (map_pages > 0) && (i < sg_pgnum); i++) {
+ int ret;
+ ret = vm_insert_page(vma, start, page);
+ if (ret)
+ return ret;
+ start += PAGE_SIZE;
+ page++;
+ map_pages--;
+ }
+
+ pgoff = 0;
+
+ if (map_pages == 0)
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static struct ion_heap_ops vmheap_ops = {
+ .allocate = ion_exynos_heap_allocate,
+ .free = ion_exynos_heap_free,
+ .map_dma = ion_exynos_heap_map_dma,
+ .unmap_dma = ion_exynos_heap_unmap_dma,
+ .map_kernel = ion_exynos_heap_map_kernel,
+ .unmap_kernel = ion_exynos_heap_unmap_kernel,
+ .map_user = ion_exynos_heap_map_user,
+};
+
+static struct ion_heap *ion_exynos_heap_create(struct ion_platform_heap *unused)
+{
+ struct ion_heap *heap;
+
+ heap = kzalloc(sizeof(struct ion_heap), GFP_KERNEL);
+ if (!heap)
+ return ERR_PTR(-ENOMEM);
+ heap->ops = &vmheap_ops;
+ heap->type = ION_HEAP_TYPE_EXYNOS;
+ return heap;
+}
+
+static void ion_exynos_heap_destroy(struct ion_heap *heap)
+{
+ kfree(heap);
+}
+
+static int ion_exynos_contig_heap_allocate(struct ion_heap *heap,
+ struct ion_buffer *buffer,
+ unsigned long len,
+ unsigned long align,
+ unsigned long flags)
+{
+ char *type = NULL;
+
+ if (flags & ION_EXYNOS_MFC_SH_MASK)
+ type = "mfc_sh";
+ else if (flags & ION_EXYNOS_MSGBOX_SH_MASK)
+ type = "msgbox_sh";
+ else if (flags & ION_EXYNOS_FIMD_VIDEO_MASK)
+ type = "fimd_video";
+ else if (flags & ION_EXYNOS_MFC_OUTPUT_MASK)
+ type = "mfc_output";
+ else if (flags & ION_EXYNOS_MFC_INPUT_MASK)
+ type = "mfc_input";
+ else if (flags & ION_EXYNOS_MFC_FW_MASK)
+ type = "mfc_fw";
+ else if (flags & ION_EXYNOS_SECTBL_MASK)
+ type = "sectbl";
+
+ buffer->priv_phys = cma_alloc(exynos_ion_dev, type, len, align);
+ if (IS_ERR_VALUE(buffer->priv_phys))
+ return (int)buffer->priv_phys;
+
+ buffer->flags = flags;
+
+ return 0;
+}
+
+static void ion_exynos_contig_heap_free(struct ion_buffer *buffer)
+{
+ cma_free(buffer->priv_phys);
+}
+
+static int ion_exynos_contig_heap_phys(struct ion_heap *heap,
+ struct ion_buffer *buffer,
+ ion_phys_addr_t *addr, size_t *len)
+{
+ *addr = buffer->priv_phys;
+ *len = buffer->size;
+ return 0;
+}
+
+static struct sg_table *ion_exynos_contig_heap_map_dma(struct ion_heap *heap,
+ struct ion_buffer *buffer)
+{
+ struct sg_table *table;
+ int ret;
+
+ table = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
+ if (!table)
+ return ERR_PTR(-ENOMEM);
+ ret = sg_alloc_table(table, 1, GFP_KERNEL);
+ if (ret)
+ return ERR_PTR(ret);
+ sg_set_page(table->sgl, phys_to_page(buffer->priv_phys), buffer->size,
+ offset_in_page(buffer->priv_phys));
+ return table;
+}
+
+static void ion_exynos_contig_heap_unmap_dma(struct ion_heap *heap,
+ struct ion_buffer *buffer)
+{
+ if (buffer->sg_table)
+ sg_free_table(buffer->sg_table);
+}
+
+static int ion_exynos_contig_heap_map_user(struct ion_heap *heap,
+ struct ion_buffer *buffer,
+ struct vm_area_struct *vma)
+{
+ unsigned long pfn = __phys_to_pfn(buffer->priv_phys);
+
+ return remap_pfn_range(vma, vma->vm_start, pfn + vma->vm_pgoff,
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot);
+
+}
+
+static void *ion_exynos_contig_heap_map_kernel(struct ion_heap *heap,
+ struct ion_buffer *buffer)
+{
+ int npages = PAGE_ALIGN(buffer->size) / PAGE_SIZE;
+ struct page **pages = vmalloc(sizeof(struct page *) * npages);
+ int i;
+
+ if (!pages)
+ return 0;
+
+ for (i = 0; i < npages; i++)
+ pages[i] = phys_to_page(buffer->priv_phys + i * PAGE_SIZE);
+ buffer->vaddr = vmap(pages, npages, VM_MAP, PAGE_KERNEL);
+ vfree(pages);
+
+ return buffer->vaddr;
+}
+
+static void ion_exynos_contig_heap_unmap_kernel(struct ion_heap *heap,
+ struct ion_buffer *buffer)
+{
+ vunmap(buffer->vaddr);
+}
+
+static struct ion_heap_ops contig_heap_ops = {
+ .allocate = ion_exynos_contig_heap_allocate,
+ .free = ion_exynos_contig_heap_free,
+ .phys = ion_exynos_contig_heap_phys,
+ .map_dma = ion_exynos_contig_heap_map_dma,
+ .unmap_dma = ion_exynos_contig_heap_unmap_dma,
+ .map_kernel = ion_exynos_contig_heap_map_kernel,
+ .unmap_kernel = ion_exynos_contig_heap_unmap_kernel,
+ .map_user = ion_exynos_contig_heap_map_user,
+};
+
+static struct ion_heap *ion_exynos_contig_heap_create(
+ struct ion_platform_heap *unused)
+{
+ struct ion_heap *heap;
+
+ heap = kzalloc(sizeof(struct ion_heap), GFP_KERNEL);
+ if (!heap)
+ return ERR_PTR(-ENOMEM);
+ heap->ops = &contig_heap_ops;
+ heap->type = ION_HEAP_TYPE_EXYNOS_CONTIG;
+ return heap;
+}
+
+static void ion_exynos_contig_heap_destroy(struct ion_heap *heap)
+{
+ kfree(heap);
+}
+
+struct exynos_user_heap_data {
+ struct sg_table sgt;
+ bool is_pfnmap; /* The region has VM_PFNMAP property */
+};
+
+static int pfnmap_digger(struct sg_table *sgt, unsigned long addr, int nr_pages)
+{
+ /* If the given user address is not normal mapping,
+ It must be contiguous physical mapping */
+ struct vm_area_struct *vma;
+ unsigned long *pfns;
+ int i, ipfn, pi, ret;
+ struct scatterlist *sg;
+ unsigned int contigs;
+ unsigned long pfn;
+
+
+ down_read(¤t->mm->mmap_sem);
+ vma = find_vma(current->mm, addr);
+ up_read(¤t->mm->mmap_sem);
+
+ if ((vma == NULL) || (vma->vm_end < (addr + (nr_pages << PAGE_SHIFT))))
+ return -EINVAL;
+
+ pfns = kmalloc(sizeof(*pfns) * nr_pages, GFP_KERNEL);
+ if (!pfns)
+ return -ENOMEM;
+
+ ret = follow_pfn(vma, addr, &pfns[0]); /* no side effect */
+ if (ret)
+ goto err_follow_pfn;
+
+ if (!pfn_valid(pfns[0])) {
+ ret = -EINVAL;
+ goto err_follow_pfn;
+ }
+
+ addr += PAGE_SIZE;
+
+ /* An element of pfns consists of
+ * - higher 20 bits: page frame number (pfn)
+ * - lower 12 bits: number of contiguous pages from the pfn
+ * Maximum size of a contiguous chunk: 16MB (4096 pages)
+ * contigs = 0 indicates no adjacent page is found yet.
+ * Thus, contigs = x means (x + 1) pages are contiguous.
+ */
+ for (i = 1, pi = 0, ipfn = 0, contigs = 0; i < nr_pages; i++) {
+ ret = follow_pfn(vma, addr, &pfn);
+ if (ret)
+ break;
+
+ if (pfns[ipfn] == (pfn - (i - pi))) {
+ contigs++;
+ } else {
+ if (contigs & PAGE_MASK) {
+ ret = -EOVERFLOW;
+ break;
+ }
+
+ pfns[ipfn] <<= PAGE_SHIFT;
+ pfns[ipfn] |= contigs;
+ ipfn++;
+ pi = i;
+ contigs = 0;
+ pfns[ipfn] = pfn;
+ }
+
+ addr += PAGE_SIZE;
+ }
+
+ if (i == nr_pages) {
+ if (contigs & PAGE_MASK) {
+ ret = -EOVERFLOW;
+ goto err_follow_pfn;
+ }
+
+ pfns[ipfn] <<= PAGE_SHIFT;
+ pfns[ipfn] |= contigs;
+
+ nr_pages = ipfn + 1;
+ } else {
+ goto err_follow_pfn;
+ }
+
+ ret = sg_alloc_table(sgt, nr_pages, GFP_KERNEL);
+ if (ret)
+ goto err_follow_pfn;
+
+ for_each_sg(sgt->sgl, sg, nr_pages, i)
+ sg_set_page(sg, phys_to_page(pfns[i]),
+ ((pfns[i] & ~PAGE_MASK) + 1) << PAGE_SHIFT, 0);
+err_follow_pfn:
+ kfree(pfns);
+ return ret;
+}
+
+static int ion_exynos_user_heap_allocate(struct ion_heap *heap,
+ struct ion_buffer *buffer,
+ unsigned long len,
+ unsigned long align,
+ unsigned long flags)
+{
+ unsigned long start = align;
+ size_t last_size = 0;
+ struct page **pages;
+ int nr_pages;
+ int ret = 0, i;
+ off_t start_off;
+ struct exynos_user_heap_data *privdata = NULL;
+ struct scatterlist *sgl;
+
+ last_size = (start + len) & ~PAGE_MASK;
+ if (last_size == 0)
+ last_size = PAGE_SIZE;
+
+ start_off = offset_in_page(start);
+
+ start = round_down(start, PAGE_SIZE);
+
+ nr_pages = PFN_DOWN(PAGE_ALIGN(len + start_off));
+
+ pages = kzalloc(nr_pages * sizeof(*pages), GFP_KERNEL);
+ if (!pages)
+ return -ENOMEM;
+
+ privdata = kmalloc(sizeof(*privdata), GFP_KERNEL);
+ if (!privdata) {
+ ret = -ENOMEM;
+ goto finish;
+ }
+
+ buffer->priv_virt = privdata;
+ buffer->flags = flags;
+
+ ret = get_user_pages_fast(start, nr_pages,
+ flags & ION_EXYNOS_WRITE_MASK, pages);
+
+ if (ret < 0) {
+ ret = pfnmap_digger(&privdata->sgt, start, nr_pages);
+ if (ret)
+ goto err_pfnmap;
+
+ privdata->is_pfnmap = true;
+
+ goto finish;
+ }
+
+ if (ret != nr_pages) {
+ nr_pages = ret;
+ ret = -EFAULT;
+ goto err_alloc_sg;
+ }
+
+ ret = sg_alloc_table(&privdata->sgt, nr_pages, GFP_KERNEL);
+ if (ret)
+ goto err_alloc_sg;
+
+ sgl = privdata->sgt.sgl;
+
+ sg_set_page(sgl, pages[0],
+ (nr_pages == 1) ? len : PAGE_SIZE - start_off,
+ start_off);
+
+ sgl = sg_next(sgl);
+
+ /* nr_pages == 1 if sgl == NULL here */
+ for (i = 1; i < (nr_pages - 1); i++) {
+ sg_set_page(sgl, pages[i], PAGE_SIZE, 0);
+ sgl = sg_next(sgl);
+ }
+
+ if (sgl)
+ sg_set_page(sgl, pages[i], last_size, 0);
+
+ privdata->is_pfnmap = false;
+
+ kfree(pages);
+
+ return 0;
+err_alloc_sg:
+ for (i = 0; i < nr_pages; i++)
+ put_page(pages[i]);
+err_pfnmap:
+ kfree(privdata);
+finish:
+ kfree(pages);
+ return ret;
+}
+
+static void ion_exynos_user_heap_free(struct ion_buffer *buffer)
+{
+ struct scatterlist *sg;
+ int i;
+ struct exynos_user_heap_data *privdata = buffer->priv_virt;
+
+ if (!privdata->is_pfnmap) {
+ if (buffer->flags & ION_EXYNOS_WRITE_MASK) {
+ for_each_sg(privdata->sgt.sgl, sg,
+ privdata->sgt.orig_nents, i) {
+ set_page_dirty_lock(sg_page(sg));
+ put_page(sg_page(sg));
+ }
+ } else {
+ for_each_sg(privdata->sgt.sgl, sg,
+ privdata->sgt.orig_nents, i)
+ put_page(sg_page(sg));
+ }
+ }
+
+ sg_free_table(&privdata->sgt);
+ kfree(privdata);
+}
+
+static int ion_exynos_user_heap_phys(struct ion_heap *heap,
+ struct ion_buffer *buffer,
+ ion_phys_addr_t *addr, size_t *len)
+{
+ struct exynos_user_heap_data *privdata = buffer->priv_virt;
+
+ if (privdata->sgt.orig_nents != 1)
+ return -EINVAL;
+
+ if (addr)
+ *addr = sg_phys(privdata->sgt.sgl);
+
+ if (len)
+ *len = sg_dma_len(privdata->sgt.sgl);
+
+ return 0;
+}
+
+static struct ion_heap_ops user_heap_ops = {
+ .allocate = ion_exynos_user_heap_allocate,
+ .free = ion_exynos_user_heap_free,
+ .phys = ion_exynos_user_heap_phys,
+ .map_dma = ion_exynos_heap_map_dma,
+ .unmap_dma = ion_exynos_heap_unmap_dma,
+ .map_kernel = ion_exynos_heap_map_kernel,
+ .unmap_kernel = ion_exynos_heap_unmap_kernel,
+};
+
+static struct ion_heap *ion_exynos_user_heap_create(
+ struct ion_platform_heap *unused)
+{
+ struct ion_heap *heap;
+
+ heap = kzalloc(sizeof(struct ion_heap), GFP_KERNEL);
+ if (!heap)
+ return ERR_PTR(-ENOMEM);
+ heap->ops = &user_heap_ops;
+ heap->type = ION_HEAP_TYPE_EXYNOS_USER;
+ return heap;
+}
+
+static void ion_exynos_user_heap_destroy(struct ion_heap *heap)
+{
+ kfree(heap);
+}
+
+#if 0
+enum ION_MSYNC_TYPE {
+ IMSYNC_DEV_TO_READ = 0,
+ IMSYNC_DEV_TO_WRITE = 1,
+ IMSYNC_DEV_TO_RW = 2,
+ IMSYNC_BUF_TYPES_MASK = 3,
+ IMSYNC_BUF_TYPES_NUM = 4,
+ IMSYNC_SYNC_FOR_DEV = 0x10000,
+ IMSYNC_SYNC_FOR_CPU = 0x20000,
+};
+
+static enum dma_data_direction ion_msync_dir_table[IMSYNC_BUF_TYPES_NUM] = {
+ DMA_TO_DEVICE,
+ DMA_FROM_DEVICE,
+ DMA_BIDIRECTIONAL,
+};
+
+static long ion_exynos_heap_msync(struct ion_client *client,
+ struct ion_handle *handle, off_t offset, size_t size, long dir)
+{
+ struct ion_buffer *buffer;
+ struct scatterlist *sg, *tsg;
+ int nents = 0;
+ int ret = 0;
+
+ buffer = ion_share(client, handle);
+ if (IS_ERR(buffer))
+ return PTR_ERR(buffer);
+
+ if ((offset + size) > buffer->size)
+ return -EINVAL;
+
+ sg = ion_map_dma(client, handle);
+ if (IS_ERR(sg))
+ return PTR_ERR(sg);
+
+ while (sg && (offset >= sg_dma_len(sg))) {
+ offset -= sg_dma_len(sg);
+ sg = sg_next(sg);
+ }
+
+ size += offset;
+
+ if (!sg)
+ goto err_buf_sync;
+
+ tsg = sg;
+ while (tsg && (size > sg_dma_len(tsg))) {
+ size -= sg_dma_len(tsg);
+ nents++;
+ tsg = sg_next(tsg);
+ }
+
+ if (tsg && size)
+ nents++;
+
+ /* TODO: exclude offset in the first entry and remainder of the
+ last entry. */
+ if (dir & IMSYNC_SYNC_FOR_CPU)
+ dma_sync_sg_for_cpu(NULL, sg, nents,
+ ion_msync_dir_table[dir & IMSYNC_BUF_TYPES_MASK]);
+ else if (dir & IMSYNC_SYNC_FOR_DEV)
+ dma_sync_sg_for_device(NULL, sg, nents,
+ ion_msync_dir_table[dir & IMSYNC_BUF_TYPES_MASK]);
+
+err_buf_sync:
+ ion_unmap_dma(client, handle);
+ return ret;
+}
+
+struct ion_msync_data {
+ enum ION_MSYNC_TYPE dir;
+ int fd_buffer;
+ size_t size;
+ off_t offset;
+};
+
+enum ION_EXYNOS_CUSTOM_CMD {
+ ION_EXYNOS_CUSTOM_MSYNC
+};
+
+static long exynos_heap_ioctl(struct ion_client *client, unsigned int cmd,
+ unsigned long arg)
+{
+ int ret = 0;
+
+ switch (cmd) {
+ case ION_EXYNOS_CUSTOM_MSYNC:
+ {
+ struct ion_msync_data data;
+ struct ion_handle *handle;
+
+ if (copy_from_user(&data, (void __user *)arg, sizeof(data)))
+ return -EFAULT;
+
+ if ((data.offset + data.size) < data.offset)
+ return -EINVAL;
+
+ handle = ion_import_fd(client, data.fd_buffer);
+ if (IS_ERR(handle))
+ return PTR_ERR(handle);
+
+ ret = ion_exynos_heap_msync(client, handle, data.offset,
+ data.size, data.dir);
+ ion_free(client, handle);
+ break;
+ }
+ default:
+ return -ENOTTY;
+ }
+
+ return ret;
+}
+#endif
+
+static struct ion_heap *__ion_heap_create(struct ion_platform_heap *heap_data)
+{
+ struct ion_heap *heap = NULL;
+
+ switch (heap_data->type) {
+ case ION_HEAP_TYPE_EXYNOS:
+ heap = ion_exynos_heap_create(heap_data);
+ break;
+ case ION_HEAP_TYPE_EXYNOS_CONTIG:
+ heap = ion_exynos_contig_heap_create(heap_data);
+ break;
+ case ION_HEAP_TYPE_EXYNOS_USER:
+ heap = ion_exynos_user_heap_create(heap_data);
+ break;
+ default:
+ return ion_heap_create(heap_data);
+ }
+
+ if (IS_ERR_OR_NULL(heap)) {
+ pr_err("%s: error creating heap %s type %d base %lu size %u\n",
+ __func__, heap_data->name, heap_data->type,
+ heap_data->base, heap_data->size);
+ return ERR_PTR(-EINVAL);
+ }
+
+ heap->name = heap_data->name;
+ heap->id = heap_data->id;
+
+ return heap;
+}
+
+void __ion_heap_destroy(struct ion_heap *heap)
+{
+ if (!heap)
+ return;
+
+ switch (heap->type) {
+ case ION_HEAP_TYPE_EXYNOS:
+ ion_exynos_heap_destroy(heap);
+ break;
+ case ION_HEAP_TYPE_EXYNOS_CONTIG:
+ ion_exynos_contig_heap_destroy(heap);
+ break;
+ case ION_HEAP_TYPE_EXYNOS_USER:
+ ion_exynos_user_heap_destroy(heap);
+ break;
+ default:
+ ion_heap_destroy(heap);
+ }
+}
+
+static int exynos_ion_probe(struct platform_device *pdev)
+{
+ struct ion_platform_data *pdata = pdev->dev.platform_data;
+ int err;
+ int i;
+
+ num_heaps = pdata->nr;
+
+ heaps = kzalloc(sizeof(struct ion_heap *) * pdata->nr, GFP_KERNEL);
+ if (!heaps)
+ return -ENOMEM;
+
+ ion_exynos = ion_device_create(NULL);
+ if (IS_ERR_OR_NULL(ion_exynos)) {
+ kfree(heaps);
+ return PTR_ERR(ion_exynos);
+ }
+
+ /* create the heaps as specified in the board file */
+ for (i = 0; i < num_heaps; i++) {
+ struct ion_platform_heap *heap_data = &pdata->heaps[i];
+
+ heaps[i] = __ion_heap_create(heap_data);
+ if (IS_ERR_OR_NULL(heaps[i])) {
+ err = PTR_ERR(heaps[i]);
+ goto err;
+ }
+ ion_device_add_heap(ion_exynos, heaps[i]);
+ }
+ platform_set_drvdata(pdev, ion_exynos);
+
+ exynos_ion_dev = &pdev->dev;
+
+ return 0;
+err:
+ for (i = 0; i < num_heaps; i++) {
+ if (heaps[i])
+ ion_heap_destroy(heaps[i]);
+ }
+ kfree(heaps);
+ return err;
+}
+
+static int exynos_ion_remove(struct platform_device *pdev)
+{
+ struct ion_device *idev = platform_get_drvdata(pdev);
+ int i;
+
+ ion_device_destroy(idev);
+ for (i = 0; i < num_heaps; i++)
+ __ion_heap_destroy(heaps[i]);
+ kfree(heaps);
+ return 0;
+}
+
+static struct platform_driver ion_driver = {
+ .probe = exynos_ion_probe,
+ .remove = exynos_ion_remove,
+ .driver = { .name = "ion-exynos" }
+};
+
+static int __init ion_init(void)
+{
+ return platform_driver_register(&ion_driver);
+}
+
+subsys_initcall(ion_init);
diff --git a/drivers/gud/Kconfig b/drivers/gud/Kconfig
new file mode 100644
index 0000000..f843d86
--- /dev/null
+++ b/drivers/gud/Kconfig
@@ -0,0 +1,52 @@
+#
+# MobiCore configuration
+#
+
+menu "MobiCore secure driver"
+
+config MOBICORE_DRIVER
+ tristate "MobiCore support"
+ depends on ARM_TRUSTZONE
+ ---help---
+ Enable Linux Kernel MobiCore Support
+
+config MOBICORE_DEBUG
+ bool "MobiCore Module debug mode"
+ depends on MOBICORE_DRIVER
+ ---help---
+ Enable Debug mode in the MobiCore Driver.
+ It enables printing information about mobicore operations
+
+config MOBICORE_VERBOSE
+ bool "MobiCore Module verbose debug mode"
+ depends on MOBICORE_DEBUG
+ ---help---
+ Enable Verbose Debug mode in the MobiCore Driver.
+ It enables printing extra information about mobicore operations
+ Beware: this is only useful for debuging deep in the driver because
+ it prints too much logs
+
+config MOBICORE_API
+ tristate "MobiCore Kernel API"
+ depends on MOBICORE_DRIVER
+ ---help---
+ Enable Linux Kernel MobiCore API
+
+if MOBICORE_DRIVER
+
+choice
+ prompt "MobiCore platform"
+ default MOBICORE_PLATFORM_EXYNOS5 if ARCH_EXYNOS5
+
+ config MOBICORE_PLATFORM_EXYNOS5
+ bool "MobiCore for Exynos5" if ARCH_EXYNOS5
+
+endchoice
+
+config MOBICORE_PLATFORM
+ string
+ default "EXYNOS_5250_STD" if MOBICORE_PLATFORM_EXYNOS5
+
+endif
+
+endmenu
diff --git a/drivers/gud/Makefile b/drivers/gud/Makefile
new file mode 100644
index 0000000..e68bd5a
--- /dev/null
+++ b/drivers/gud/Makefile
@@ -0,0 +1,34 @@
+#
+# Makefile for the kernel mobicore drivers
+#
+GUD_ROOT_FOLDER := drivers/gud/
+# add our modules to kernel.
+obj-$(CONFIG_MOBICORE_API) += mcKernelApi.o
+obj-$(CONFIG_MOBICORE_DRIVER) += mcDrvModule.o
+mcDrvModule-objs := MobiCoreDriver/logging.o \
+ MobiCoreDriver/ops.o \
+ MobiCoreDriver/mem.o \
+ MobiCoreDriver/api.o \
+ MobiCoreDriver/pm.o \
+ MobiCoreDriver/main.o
+
+mcKernelApi-objs := MobiCoreKernelApi/main.o \
+ MobiCoreKernelApi/clientlib.o \
+ MobiCoreKernelApi/device.o \
+ MobiCoreKernelApi/session.o \
+ MobiCoreKernelApi/connection.o
+
+# Release mode by default
+ccflags-y := -DNDEBUG -include $(GUD_ROOT_FOLDER)/build_tag.h
+ccflags-y += -Wno-declaration-after-statement
+
+ccflags-$(CONFIG_MOBICORE_DEBUG) += -DDEBUG
+ccflags-$(CONFIG_MOBICORE_VERBOSE) += -DDEBUG_VERBOSE
+
+# Use the selected platform folder
+ccflags-y += -I$(GUD_ROOT_FOLDER)/MobiCoreDriver/platforms/$(CONFIG_MOBICORE_PLATFORM)
+# MobiCore Driver includes
+ccflags-y += -I$(GUD_ROOT_FOLDER)/MobiCoreDriver/public
+# MobiCore KernelApi required incldes
+ccflags-y += -I$(GUD_ROOT_FOLDER)/MobiCoreKernelApi/include \
+ -I$(GUD_ROOT_FOLDER)/MobiCoreKernelApi/public
\ No newline at end of file
diff --git a/drivers/gud/MobiCoreDriver/Makefile b/drivers/gud/MobiCoreDriver/Makefile
new file mode 100644
index 0000000..17410b4
--- /dev/null
+++ b/drivers/gud/MobiCoreDriver/Makefile
@@ -0,0 +1,26 @@
+#
+# this makefile is called from the kernel make system. Thus we basiclly
+# add things to "obj-m" here.
+
+ifeq ($(MODE),release)
+ ccflags-y = -O2 -DNDEBUG
+else
+ ccflags-y = -DDEBUG
+endif # DEBUG/RELEASE
+
+# CFLAGS from the build script
+ifdef MOBICORE_CFLAGS
+ ccflags-y += $(MOBICORE_CFLAGS)
+endif
+#EXTRA_CFLAGS+=-DDEBUG_VERBOSE
+
+ccflags-y += -include $(M)/build_tag.h -Wall
+# add our module to kernel.
+obj-m += mcDrvModule.o
+
+mcDrvModule-objs :=logging.o ops.o mem.o api.o pm.o main.o
+
+clean:
+ rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions \
+ Module.markers Module.symvers modules.order
+
diff --git a/drivers/gud/MobiCoreDriver/android.h b/drivers/gud/MobiCoreDriver/android.h
new file mode 100644
index 0000000..5a36200
--- /dev/null
+++ b/drivers/gud/MobiCoreDriver/android.h
@@ -0,0 +1,40 @@
+/**
+ * Header file of MobiCore Driver Kernel Module.
+ *
+ * @addtogroup MobiCore_Driver_Kernel_Module
+ * @{
+ * Android specific defines
+ * @file
+ *
+ * Android specific defines
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ *
+ * 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.
+ */
+
+#ifndef _MC_ANDROID_H_
+#define _MC_ANDROID_H_
+
+#ifdef CONFIG_ANDROID
+/* Defines needed to identify the Daemon in Android systems
+ * For the full list see:
+ * platform_system_core/include/private/android_filesystem_config.h in the
+ * Android source tree
+ */
+/* traditional unix root user */
+#define AID_ROOT 0
+/* system server */
+#define AID_SYSTEM 1000
+/* access to misc storage */
+#define AID_MISC 9998
+#define AID_NOBODY 9999
+/* first app user */
+#define AID_APP 10000
+
+#endif /* CONFIG_ANDROID */
+
+#endif /* _MC_ANDROID_H_ */
+/** @} */
diff --git a/drivers/gud/MobiCoreDriver/api.c b/drivers/gud/MobiCoreDriver/api.c
new file mode 100644
index 0000000..75cc271
--- /dev/null
+++ b/drivers/gud/MobiCoreDriver/api.c
@@ -0,0 +1,118 @@
+/** MobiCore driver module.(interface to the secure world SWD)
+ * @addtogroup MCD_MCDIMPL_KMOD_IMPL
+ * @{
+ * @file
+ * MobiCore Driver Kernel Module.
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ *
+ * 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.
+ */
+#include <linux/module.h>
+
+#include "main.h"
+#include "mem.h"
+#include "debug.h"
+
+
+/**
+ * Map a virtual memory buffer structure to Mobicore
+ * @param instance
+ * @param addr address of the buffer(NB it must be kernel virtual!)
+ * @param len buffer length
+ * @param handle pointer to handle
+ * @param phys_wsm_l2_table pointer to physical L2 table(?)
+ *
+ * @return 0 if no error
+ *
+ */
+int mobicore_map_vmem(struct mc_instance *instance, void *addr,
+ uint32_t len, uint32_t *handle, uint32_t *phys)
+{
+ return mc_register_wsm_l2(instance, (uint32_t)addr, len,
+ handle, phys);
+}
+EXPORT_SYMBOL(mobicore_map_vmem);
+
+/**
+ * Unmap a virtual memory buffer from mobicore
+ * @param instance
+ * @param handle
+ *
+ * @return 0 if no error
+ *
+ */
+int mobicore_unmap_vmem(struct mc_instance *instance, uint32_t handle)
+{
+ return mc_unregister_wsm_l2(instance, handle);
+}
+EXPORT_SYMBOL(mobicore_unmap_vmem);
+
+/**
+ * Free a WSM buffer allocated with mobicore_allocate_wsm
+ * @param instance
+ * @param handle handle of the buffer
+ *
+ * @return 0 if no error
+ *
+ */
+int mobicore_free_wsm(struct mc_instance *instance, uint32_t handle)
+{
+ return mc_free_buffer(instance, handle);
+}
+EXPORT_SYMBOL(mobicore_free_wsm);
+
+
+/**
+ * Allocate WSM for given instance
+ *
+ * @param instance instance
+ * @param requested_size size of the WSM
+ * @param handle pointer where the handle will be saved
+ * @param virt_kernel_addr pointer for the kernel virtual address
+ * @param phys_addr pointer for the physical address
+ *
+ * @return error code or 0 for success
+ */
+int mobicore_allocate_wsm(struct mc_instance *instance,
+ unsigned long requested_size, uint32_t *handle, void **virt_kernel_addr,
+ void **phys_addr)
+{
+ struct mc_buffer *buffer = NULL;
+
+ /* Setup the WSM buffer structure! */
+ if (mc_get_buffer(instance, &buffer, requested_size))
+ return -EFAULT;
+
+ *handle = buffer->handle;
+ *phys_addr = buffer->phys;
+ *virt_kernel_addr = buffer->addr;
+ return 0;
+}
+EXPORT_SYMBOL(mobicore_allocate_wsm);
+
+/**
+ * Initialize a new mobicore API instance object
+ *
+ * @return Instance or NULL if no allocation was possible.
+ */
+struct mc_instance *mobicore_open(void)
+{
+ return mc_alloc_instance();
+}
+EXPORT_SYMBOL(mobicore_open);
+
+/**
+ * Release a mobicore instance object and all objects related to it
+ * @param instance instance
+ * @return 0 if Ok or -E ERROR
+ */
+int mobicore_release(struct mc_instance *instance)
+{
+ return mc_release_instance(instance);
+}
+EXPORT_SYMBOL(mobicore_release);
+
+/** @} */
diff --git a/drivers/gud/MobiCoreDriver/arm.h b/drivers/gud/MobiCoreDriver/arm.h
new file mode 100644
index 0000000..59122c4
--- /dev/null
+++ b/drivers/gud/MobiCoreDriver/arm.h
@@ -0,0 +1,64 @@
+/** MobiCore driver module.(interface to the secure world SWD)
+ * <!-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ *
+ * 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.
+ */
+
+#ifndef __MC_ARM_H
+#define __MC_ARM_H
+
+#include "debug.h"
+
+/** ARM Trustzone specific masks and modes
+ * Vanilla Linux is unaware of TrustZone extension.
+ * I.e. arch/arm/include/asm/ptrace.h does not define monitor mode.
+ * Also TZ bits in cpuid are not defined, ARM port uses magic numbers,
+ * see arch/arm/kernel/setup.c */
+#define ARM_MONITOR_MODE (0b10110)
+#define ARM_SECURITY_EXTENSION_MASK (0x30)
+
+/* check if CPU supports the ARM TrustZone Security Extensions */
+inline int has_security_extensions(void)
+{
+ u32 fea = 0;
+ asm volatile(
+ "mrc p15, 0, %[fea], cr0, cr1, 0" :
+ [fea]"=r" (fea));
+
+ MCDRV_DBG_VERBOSE("CPU Features: 0x%X", fea);
+
+ /* If the CPU features ID has 0 for security features then the CPU
+ * doesn't support TrustZone at all!
+ */
+ if ((fea & ARM_SECURITY_EXTENSION_MASK) == 0)
+ return 0;
+
+ return 1;
+}
+
+/* check if running in secure mode */
+inline int is_secure_mode(void)
+{
+ u32 cpsr = 0, nsacr = 0;
+ asm volatile(
+ "mrc p15, 0, %[nsacr], cr1, cr1, 2\n"
+ "mrs %[cpsr], cpsr\n" :
+ [nsacr]"=r" (nsacr),
+ [cpsr]"=r"(cpsr));
+
+ MCDRV_DBG_VERBOSE("CPRS.M = set to 0x%X\n", cpsr & MODE_MASK);
+ MCDRV_DBG_VERBOSE("SCR.NS = set to 0x%X\n", nsacr);
+
+ /* If the NSACR contains the reset value(=0) then most likely we are
+ * running in Secure MODE.
+ * If the cpsr mode is set to monitor mode then we cannot load!
+ */
+ if (nsacr == 0 || ((cpsr & MODE_MASK) == ARM_MONITOR_MODE))
+ return 1;
+
+ return 0;
+}
+
+#endif /* __MC_ARM_H */
diff --git a/drivers/gud/MobiCoreDriver/build_tag.h b/drivers/gud/MobiCoreDriver/build_tag.h
new file mode 100644
index 0000000..e2a9029
--- /dev/null
+++ b/drivers/gud/MobiCoreDriver/build_tag.h
@@ -0,0 +1 @@
+#define MOBICORE_COMPONENT_BUILD_TAG "*** SAMSUNG Exynos 5250 MC1.2 V005 release ###"
diff --git a/drivers/gud/MobiCoreDriver/debug.h b/drivers/gud/MobiCoreDriver/debug.h
new file mode 100644
index 0000000..fe13b84
--- /dev/null
+++ b/drivers/gud/MobiCoreDriver/debug.h
@@ -0,0 +1,61 @@
+/** MobiCore driver module.(interface to the secure world SWD)
+ * <!-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ *
+ * 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.
+ */
+
+#ifndef __MC_DEBUG_H
+#define __MC_DEBUG_H
+
+#define MCDRV_DBG_ERROR(txt, ...) \
+ printk(KERN_ERR "MobiCore [%d] %s() ### ERROR: " txt, \
+ task_pid_vnr(current), \
+ __func__, \
+ ##__VA_ARGS__)
+
+/* dummy function helper macro. */
+#define DUMMY_FUNCTION() do {} while (0)
+
+#if defined(DEBUG)
+
+/* #define DEBUG_VERBOSE */
+#if defined(DEBUG_VERBOSE)
+#define MCDRV_DBG_VERBOSE MCDRV_DBG
+#else
+#define MCDRV_DBG_VERBOSE(...) DUMMY_FUNCTION()
+#endif
+
+#define MCDRV_DBG(txt, ...) \
+ printk(KERN_INFO "MobiCore [%d on CPU%d] %s(): " txt, \
+ task_pid_vnr(current), \
+ raw_smp_processor_id(), \
+ __func__, \
+ ##__VA_ARGS__)
+
+#define MCDRV_DBG_WARN(txt, ...) \
+ printk(KERN_WARNING "MobiCore [%d] %s() WARNING: " txt, \
+ task_pid_vnr(current), \
+ __func__, \
+ ##__VA_ARGS__)
+
+#define MCDRV_ASSERT(cond) \
+ do { \
+ if (unlikely(!(cond))) { \
+ panic("MobiCore Assertion failed: %s:%d\n", \
+ __FILE__, __LINE__); \
+ } \
+ } while (0)
+
+#else
+
+#define MCDRV_DBG_VERBOSE(...) DUMMY_FUNCTION()
+#define MCDRV_DBG(...) DUMMY_FUNCTION()
+#define MCDRV_DBG_WARN(...) DUMMY_FUNCTION()
+
+#define MCDRV_ASSERT(...) DUMMY_FUNCTION()
+
+#endif /* [not] defined(DEBUG) */
+
+#endif /* __MC_DEBUG_H */
diff --git a/drivers/gud/MobiCoreDriver/fastcall.h b/drivers/gud/MobiCoreDriver/fastcall.h
new file mode 100644
index 0000000..2fea065
--- /dev/null
+++ b/drivers/gud/MobiCoreDriver/fastcall.h
@@ -0,0 +1,180 @@
+/**
+ * Header file of MobiCore Driver Kernel Module.
+ *
+ * @addtogroup MobiCore_Driver_Kernel_Module
+ * @{
+ * Internal structures of the McDrvModule
+ * @file
+ *
+ * MobiCore Fast Call interface
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ *
+ * 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.
+ */
+
+#ifndef _MC_FASTCALL_H_
+#define _MC_FASTCALL_H_
+
+#include "debug.h"
+
+/**
+ * MobiCore SMCs
+ */
+#define MC_SMC_N_YIELD 0x3 /**< Yield to switch from NWd to SWd. */
+#define MC_SMC_N_SIQ 0x4 /**< SIQ to switch from NWd to SWd. */
+
+/**
+ * MobiCore fast calls. See MCI documentation
+ */
+#define MC_FC_INIT -1
+#define MC_FC_INFO -2
+#define MC_FC_POWER -3
+#define MC_FC_DUMP -4
+#define MC_FC_NWD_TRACE -31 /**< Mem trace setup fastcall */
+
+
+/**
+ * return code for fast calls
+ */
+#define MC_FC_RET_OK 0
+#define MC_FC_RET_ERR_INVALID 1
+#define MC_FC_RET_ERR_ALREADY_INITIALIZED 5
+
+
+/* structure wrappers for specific fastcalls */
+
+/** generic fast call parameters */
+union fc_generic {
+ struct {
+ uint32_t cmd;
+ uint32_t param[3];
+ } as_in;
+ struct {
+ uint32_t resp;
+ uint32_t ret;
+ uint32_t param[2];
+ } as_out;
+};
+
+
+/** fast call init */
+union mc_fc_init {
+ union fc_generic as_generic;
+ struct {
+ uint32_t cmd;
+ uint32_t base;
+ uint32_t nq_info;
+ uint32_t mcp_info;
+ } as_in;
+ struct {
+ uint32_t resp;
+ uint32_t ret;
+ uint32_t rfu[2];
+ } as_out;
+};
+
+
+/** fast call info parameters */
+union mc_fc_info {
+ union fc_generic as_generic;
+ struct {
+ uint32_t cmd;
+ uint32_t ext_info_id;
+ uint32_t rfu[2];
+ } as_in;
+ struct {
+ uint32_t resp;
+ uint32_t ret;
+ uint32_t state;
+ uint32_t ext_info;
+ } as_out;
+};
+
+/**
+ * fast call to MobiCore
+ *
+ * @param fc_generic pointer to fast call data
+ */
+static inline long _smc(void *data)
+{
+ union fc_generic *fc_generic = data;
+ MCDRV_ASSERT(fc_generic != NULL);
+ /* We only expect to make smc calls on CPU0 otherwise something wrong
+ * will happen */
+ MCDRV_ASSERT(raw_smp_processor_id() == 0);
+#ifdef MC_SMC_FASTCALL
+ {
+ int ret = 0;
+ ret = smc_fastcall((void *)fc_generic, sizeof(*fc_generic));
+ }
+#else
+ {
+ /* SVC expect values in r0-r3 */
+ register u32 reg0 __asm__("r0") = fc_generic->as_in.cmd;
+ register u32 reg1 __asm__("r1") = fc_generic->as_in.param[0];
+ register u32 reg2 __asm__("r2") = fc_generic->as_in.param[1];
+ register u32 reg3 __asm__("r3") = fc_generic->as_in.param[2];
+
+ /* one of the famous preprocessor hacks to stringify things.*/
+#define __STR2(x) #x
+#define __STR(x) __STR2(x)
+
+ /* compiler does not support certain instructions
+ * "SMC": secure monitor call.*/
+#define ASM_ARM_SMC 0xE1600070
+ /* "BPKT": debugging breakpoint.
+ * We keep this, as is comes quite handy for debugging. */
+#define ASM_ARM_BPKT 0xE1200070
+#define ASM_THUMB_BPKT 0xBE00
+
+
+ __asm__ volatile (
+#ifdef CONFIG_ARM_ERRATA_766421
+ "dmb\n"
+#endif
+ ".word " __STR(ASM_ARM_SMC) "\n"
+#ifdef CONFIG_ARM_ERRATA_766421
+ "dmb\n"
+#endif
+ : "+r"(reg0), "+r"(reg1), "+r"(reg2), "+r"(reg3)
+ );
+
+ /* set response */
+ fc_generic->as_out.resp = reg0;
+ fc_generic->as_out.ret = reg1;
+ fc_generic->as_out.param[0] = reg2;
+ fc_generic->as_out.param[1] = reg3;
+ }
+#endif
+ return 0;
+}
+
+/**
+ * convert fast call return code to linux driver module error code
+ *
+ */
+static inline int convert_fc_ret(uint32_t sret)
+{
+ int ret = -EFAULT;
+
+ switch (sret) {
+ case MC_FC_RET_OK:
+ ret = 0;
+ break;
+
+ case MC_FC_RET_ERR_INVALID:
+ ret = -EINVAL;
+ break;
+
+ case MC_FC_RET_ERR_ALREADY_INITIALIZED:
+ ret = -EBUSY;
+ break;
+ }
+ return ret;
+}
+
+#endif /* _MC_FASTCALL_H_ */
+/** @} */
diff --git a/drivers/gud/MobiCoreDriver/logging.c b/drivers/gud/MobiCoreDriver/logging.c
new file mode 100644
index 0000000..24e858a
--- /dev/null
+++ b/drivers/gud/MobiCoreDriver/logging.c
@@ -0,0 +1,343 @@
+/** MobiCore driver module.(interface to the secure world SWD)
+ * @addtogroup MCD_MCDIMPL_KMOD_LOGGING MobiCore Driver Logging Subsystem.
+ * @ingroup MCD_MCDIMPL_KMOD
+ * @{
+ * @file
+ * MobiCore Driver Logging Subsystem.
+ * The logging subsytem provides the interface between the Mobicore trace
+ * buffer and the Linux log
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ *
+ * 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.
+ */
+#include <linux/miscdevice.h>
+#include <linux/moduleparam.h>
+#include <linux/kthread.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+
+#include "main.h"
+#include "debug.h"
+#include "ops.h"
+#include "logging.h"
+
+/* Default len of the log ring buffer 256KB*/
+#define LOG_BUF_SIZE (64 * PAGE_SIZE)
+
+/* Max Len of a log line for printing */
+#define LOG_LINE_SIZE 256
+
+static uint32_t log_size = LOG_BUF_SIZE;
+module_param(log_size, uint, 0);
+MODULE_PARM_DESC(log_size, " Size of the MobiCore log ringbuffer "
+ "(or 256KB default).");
+
+/* Definitions for log version 2 */
+#define LOG_TYPE_MASK (0x0007)
+#define LOG_TYPE_CHAR 0
+#define LOG_TYPE_INTEGER 1
+/* Field length */
+#define LOG_LENGTH_MASK (0x00F8)
+#define LOG_LENGTH_SHIFT 3
+/* Extra attributes */
+#define LOG_EOL (0x0100)
+#define LOG_INTEGER_DECIMAL (0x0200)
+#define LOG_INTEGER_SIGNED (0x0400)
+
+struct logmsg_struct {
+ /* Type and format of data */
+ uint16_t ctrl;
+ /* Unique value for each event source */
+ uint16_t source;
+ /* Value, if any */
+ uint32_t log_data;
+};
+
+/** MobiCore log previous position */
+static uint32_t log_pos;
+/** MobiCore log buffer structure */
+static struct mc_trace_buf *log_buf;
+/** Log Thread task structure */
+struct task_struct *log_thread;
+/** Log Line buffer */
+static char *log_line;
+/** Log Line buffer current len */
+static uint32_t log_line_len;
+
+static void log_eol(void)
+{
+ if (!strnlen(log_line, LOG_LINE_SIZE))
+ return;
+ printk(KERN_INFO "%s\n", log_line);
+ log_line_len = 0;
+ log_line[0] = 0;
+}
+/**
+ * Put a char to the log line if there is enough space if not then also
+ * output the line. Assume nobody else is updating the line! */
+static void log_char(char ch)
+{
+ if (ch == '\n' || ch == '\r') {
+ log_eol();
+ return;
+ }
+
+ if (log_line_len >= LOG_LINE_SIZE - 1) {
+ printk(KERN_INFO "%s\n", log_line);
+ log_line_len = 0;
+ log_line[0] = 0;
+ }
+
+ log_line[log_line_len] = ch;
+ log_line[log_line_len + 1] = 0;
+ log_line_len++;
+}
+
+/**
+ * Put a string to the log line if there is enough space if not then also
+ * output the line. Assume nobody else is updating the line! */
+static void log_str(const char *s)
+{
+ int i;
+ for (i = 0; i < strnlen(s, LOG_LINE_SIZE); i++)
+ log_char(s[i]);
+}
+
+static uint32_t process_v1log(void)
+{
+ char *last_char = log_buf->buff + log_buf->write_pos;
+ char *buff = log_buf->buff + log_pos;
+ while (buff != last_char) {
+ log_char(*(buff++));
+ /* Wrap around */
+ if (buff - (char *)log_buf >= log_size)
+ buff = log_buf->buff;
+ }
+ return buff - log_buf->buff;
+}
+
+static const uint8_t HEX2ASCII[16] = { '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+
+static void dbg_raw_nro(uint32_t format, uint32_t value)
+{
+ int digits = 1;
+ uint32_t base = (format & LOG_INTEGER_DECIMAL) ? 10 : 16;
+ int width = (format & LOG_LENGTH_MASK) >> LOG_LENGTH_SHIFT;
+ int negative = 0;
+ uint32_t digit_base = 1;
+
+ if ((format & LOG_INTEGER_SIGNED) != 0 && ((signed int)value) < 0) {
+ negative = 1;
+ value = (uint32_t)(-(signed int)value);
+ width--;
+ }
+
+ /* Find length and divider to get largest digit */
+ while (value / digit_base >= base) {
+ digit_base *= base;
+ digits++;
+ }
+
+ if (width > digits) {
+ char ch = (base == 10) ? ' ' : '0';
+ while (width > digits) {
+ log_char(ch);
+ width--;
+ }
+ }
+
+ if (negative)
+ log_char('-');
+
+ while (digits-- > 0) {
+ uint32_t d = value / digit_base;
+ log_char(HEX2ASCII[d]);
+ value = value - d * digit_base;
+ digit_base /= base;
+ }
+}
+
+static void log_msg(struct logmsg_struct *msg)
+{
+ unsigned char msgtxt[5];
+ int mpos = 0;
+ switch (msg->ctrl & LOG_TYPE_MASK) {
+ case LOG_TYPE_CHAR: {
+ uint32_t ch;
+ ch = msg->log_data;
+ while (ch != 0) {
+ msgtxt[mpos++] = ch&0xFF;
+ ch >>= 8;
+ }
+ msgtxt[mpos] = 0;
+ log_str(msgtxt);
+ break;
+ }
+ case LOG_TYPE_INTEGER: {
+ dbg_raw_nro(msg->ctrl, msg->log_data);
+ break;
+ }
+ default:
+ break;
+ }
+ if (msg->ctrl & LOG_EOL)
+ log_eol();
+}
+
+static uint32_t process_v2log(void)
+{
+ char *last_msg = log_buf->buff + log_buf->write_pos;
+ char *buff = log_buf->buff + log_pos;
+ while (buff != last_msg) {
+ log_msg((struct logmsg_struct *)buff);
+ buff += sizeof(struct logmsg_struct);
+ /* Wrap around */
+ if (buff + sizeof(struct logmsg_struct) >
+ (char *)log_buf + log_size)
+ buff = log_buf->buff;
+ }
+ return buff - log_buf->buff;
+}
+
+static int log_worker(void *p)
+{
+ /* The thread should have never started */
+ if (log_buf == NULL)
+ return -EFAULT;
+
+ while (!kthread_should_stop()) {
+ if (log_buf->write_pos == log_pos)
+ schedule_timeout_interruptible(MAX_SCHEDULE_TIMEOUT);
+
+ switch (log_buf->version) {
+ case 1:
+ log_pos = process_v1log();
+ break;
+ case 2:
+ log_pos = process_v2log();
+ break;
+ default:
+ MCDRV_DBG_ERROR("Unknown Mobicore log data "
+ "version %d logging disabled.",
+ log_buf->version);
+ log_pos = log_buf->write_pos;
+ /* Stop the thread as we have no idea what
+ * happens next */
+ return -EFAULT;
+ }
+ }
+ MCDRV_DBG("Logging thread stopped!");
+ return 0;
+}
+
+/**
+ * Wakeup the log reader thread
+ * This should be called from the places where calls into MobiCore have
+ * generated some logs(eg, yield, SIQ...)
+ */
+void mobicore_log_read(void)
+{
+ if (log_thread == NULL || IS_ERR(log_thread))
+ return;
+
+ wake_up_process(log_thread);
+}
+
+/**
+ * Setup mobicore kernel log. It assumes it's running on CORE 0!
+ * The fastcall will complain is that is not the case!
+ */
+long mobicore_log_setup(void)
+{
+ unsigned long phys_log_buf;
+ union fc_generic fc_log;
+ struct sched_param param = { .sched_priority = 1 };
+
+ long ret;
+ log_pos = 0;
+ log_buf = NULL;
+ log_thread = NULL;
+ log_line = NULL;
+ log_line_len = 0;
+
+ /* Sanity check for the log size */
+ if (log_size < PAGE_SIZE)
+ return -EFAULT;
+ else
+ log_size = PAGE_ALIGN(log_size);
+
+ log_line = kzalloc(LOG_LINE_SIZE, GFP_KERNEL);
+ if (IS_ERR(log_line)) {
+ MCDRV_DBG_ERROR("failed to allocate log line!");
+ return -ENOMEM;
+ }
+
+ log_thread = kthread_create(log_worker, NULL, "mobicore_log");
+ if (IS_ERR(log_thread)) {
+ MCDRV_DBG_ERROR("mobicore log thread creation failed!");
+ ret = -EFAULT;
+ goto mobicore_log_setup_log_line;
+ }
+
+ sched_setscheduler(log_thread, SCHED_IDLE, ¶m);
+
+ /* We are going to map this buffer into virtual address space in SWd.
+ * To reduce complexity there, we use a contiguous buffer. */
+ log_buf = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
+ get_order(log_size));
+ if (!log_buf) {
+ MCDRV_DBG_ERROR("Failed to get page for logger!");
+ ret = -ENOMEM;
+ goto mobicore_log_setup_kthread;
+ }
+ phys_log_buf = virt_to_phys(log_buf);
+
+ memset(&fc_log, 0, sizeof(fc_log));
+ fc_log.as_in.cmd = MC_FC_NWD_TRACE;
+ fc_log.as_in.param[0] = phys_log_buf;
+ fc_log.as_in.param[1] = log_size;
+
+ MCDRV_DBG("fc_log virt=%p phys=%p ", log_buf, (void *)phys_log_buf);
+ mc_fastcall(&fc_log);
+ MCDRV_DBG("fc_log out ret=0x%08x", fc_log.as_out.ret);
+ /* If the setup failed we must free the memory allocated */
+ if (fc_log.as_out.ret) {
+ MCDRV_DBG_ERROR("MobiCore shared traces setup failed!");
+ free_pages((unsigned long)log_buf, get_order(log_size));
+ log_buf = NULL;
+ ret = -EIO;
+ goto mobicore_log_setup_kthread;
+ }
+
+ wake_up_process(log_thread);
+
+ MCDRV_DBG("fc_log Logger version %u\n", log_buf->version);
+ return 0;
+
+mobicore_log_setup_kthread:
+ kthread_stop(log_thread);
+ log_thread = NULL;
+mobicore_log_setup_log_line:
+ kfree(log_line);
+ log_line = NULL;
+ return ret;
+}
+
+/**
+ * Free kernel log componenets.
+ * ATTN: We can't free the log buffer because it's also in use by MobiCore and
+ * even if the module is unloaded MobiCore is still running.
+ */
+void mobicore_log_free(void)
+{
+ if (log_thread && !IS_ERR(log_thread)) {
+ /* We don't really care what the thread returns for exit */
+ kthread_stop(log_thread);
+ }
+
+ kfree(log_line);
+}
diff --git a/drivers/gud/MobiCoreDriver/logging.h b/drivers/gud/MobiCoreDriver/logging.h
new file mode 100644
index 0000000..27a5ef3
--- /dev/null
+++ b/drivers/gud/MobiCoreDriver/logging.h
@@ -0,0 +1,25 @@
+/** MobiCore driver module.(interface to the secure world SWD)
+ * <!-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ *
+ * 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.
+ */
+
+#ifndef __MC_LOGGING_H
+#define __MC_LOGGING_H
+
+/** MobiCore internal trace buffer structure. */
+struct mc_trace_buf {
+ uint32_t version; /**< version of trace buffer */
+ uint32_t length; /**< length of allocated buffer(includes header) */
+ uint32_t write_pos; /**< last write position */
+ char buff[1]; /**< start of the log buffer */
+};
+
+/*** MobiCore internal trace log setup. */
+void mobicore_log_read(void);
+long mobicore_log_setup(void);
+void mobicore_log_free(void);
+
+#endif /* __MC_LOGGING_H */
diff --git a/drivers/gud/MobiCoreDriver/main.c b/drivers/gud/MobiCoreDriver/main.c
new file mode 100644
index 0000000..458a782
--- /dev/null
+++ b/drivers/gud/MobiCoreDriver/main.c
@@ -0,0 +1,1155 @@
+/**
+ * <!-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ *
+ * 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.
+ *
+ * MobiCore driver module.(interface to the secure world SWD)
+ * @addtogroup MCD_MCDIMPL_KMOD_IMPL
+ * @{
+ * @file
+ * MobiCore Driver Kernel Module.
+ * This driver represents the command proxy on the lowest layer, from the
+ * secure world to the non secure world, and vice versa.
+
+ * This driver offers IOCTL commands, for access to the secure world, and has
+ * the interface from the secure world to the normal world.
+ * The access to the driver is possible with a file descriptor,
+ * which has to be created by the fd = open(/dev/mobicore) command or
+ * fd = open(/dev/mobicore-user)
+ */
+#include <linux/miscdevice.h>
+#include <linux/interrupt.h>
+#include <linux/highmem.h>
+#include <linux/slab.h>
+#include <linux/kthread.h>
+#include <linux/module.h>
+#include <linux/ioctl.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/completion.h>
+
+#include "main.h"
+#include "android.h"
+#include "fastcall.h"
+
+#include "arm.h"
+#include "mem.h"
+#include "ops.h"
+#include "pm.h"
+#include "debug.h"
+#include "logging.h"
+
+/** MobiCore interrupt context data */
+struct mc_context ctx;
+
+/* Get process context from file pointer */
+static struct mc_instance *get_instance(struct file *file)
+{
+ if (!file)
+ return NULL;
+
+ return (struct mc_instance *)(file->private_data);
+}
+
+/* Get a unique ID */
+unsigned int get_unique_id(void)
+{
+ return (unsigned int)atomic_inc_return(&ctx.unique_counter);
+}
+
+/* Clears the reserved bit of each page and frees the pages */
+static inline void free_continguous_pages(void *addr, unsigned int order)
+{
+ int i;
+ struct page *page = virt_to_page(addr);
+ for (i = 0; i < (1<<order); i++) {
+ MCDRV_DBG_VERBOSE("free page at 0x%p\n", page);
+ ClearPageReserved(page);
+ page++;
+ }
+
+ MCDRV_DBG_VERBOSE("freeing addr:%p, order:%x\n", addr, order);
+ free_pages((unsigned long)addr, order);
+}
+
+/* Frees the memory associated with a bufer */
+static int free_buffer(struct mc_buffer *buffer)
+{
+ if (buffer->handle == 0)
+ return -EINVAL;
+
+ if (buffer->addr == 0)
+ return -EINVAL;
+
+ if (!atomic_dec_and_test(&buffer->usage)) {
+
+ MCDRV_DBG_VERBOSE("Could not free buffer h=%u", buffer->handle);
+ return 0;
+ }
+
+ MCDRV_DBG("phys_addr=0x%p, virt_addr=0x%p\n",
+ buffer->phys,
+ buffer->addr);
+
+ list_del(&buffer->list);
+
+ free_continguous_pages(buffer->addr, buffer->order);
+ kfree(buffer);
+ return 0;
+}
+
+static uint32_t mc_find_cont_wsm(struct mc_instance *instance, uint32_t handle,
+ uint32_t *phys, uint32_t *len)
+{
+ int ret = 0;
+ struct mc_buffer *buffer;
+
+ if (WARN(!instance, "No instance data available"))
+ return -EFAULT;
+
+ if (WARN_ON(!is_daemon(instance))) {
+ MCDRV_DBG_ERROR("caller not MobiCore Daemon\n");
+ return -EPERM;
+ }
+
+ mutex_lock(&instance->lock);
+
+ mutex_lock(&ctx.bufs_lock);
+
+ /* search for the given handle in the buffers list */
+ list_for_each_entry(buffer, &ctx.cont_bufs, list) {
+ if (buffer->handle == handle) {
+ *phys = (uint32_t)buffer->phys;
+ *len = buffer->len;
+ goto found;
+ }
+ }
+
+ /* Coundn't find the buffer */
+ ret = -EINVAL;
+
+found:
+ mutex_unlock(&ctx.bufs_lock);
+ mutex_unlock(&instance->lock);
+
+ return ret;
+}
+
+/**
+ * Free a WSM buffer allocated with mobicore_allocate_wsm
+ * @param instance
+ * @param handle handle of the buffer
+ *
+ * @return 0 if no error
+ *
+ */
+static int __free_buffer(struct mc_instance *instance, uint32_t handle)
+{
+ int ret = 0;
+ struct mc_buffer *buffer;
+
+ if (WARN(!instance, "No instance data available"))
+ return -EFAULT;
+
+ mutex_lock(&ctx.bufs_lock);
+ /* search for the given handle in the buffers list */
+ list_for_each_entry(buffer, &ctx.cont_bufs, list) {
+ if (buffer->handle == handle)
+ goto del_buffer;
+ }
+ ret = -EINVAL;
+ goto err;
+
+del_buffer:
+ ret = free_buffer(buffer);
+err:
+ mutex_unlock(&ctx.bufs_lock);
+ return ret;
+}
+
+int mc_free_buffer(struct mc_instance *instance, uint32_t handle)
+{
+ int ret = 0;
+
+ if (WARN(!instance, "No instance data available"))
+ return -EFAULT;
+
+ mutex_lock(&instance->lock);
+
+ ret = __free_buffer(instance, handle);
+ mutex_unlock(&instance->lock);
+ return ret;
+}
+
+
+int mc_get_buffer(struct mc_instance *instance,
+ struct mc_buffer **buffer, unsigned long len)
+{
+ struct mc_buffer *cbuffer = NULL;
+ void *addr = 0;
+ void *phys = 0;
+ unsigned int order;
+ unsigned long allocated_size;
+ int ret = 0;
+
+ if (WARN(!instance, "No instance data available"))
+ return -EFAULT;
+
+ if (len == 0) {
+ MCDRV_DBG_WARN("cannot allocate size 0\n");
+ return -ENOMEM;
+ }
+
+ order = get_order(len);
+ if (order > MAX_ORDER) {
+ MCDRV_DBG_WARN("Buffer size too large\n");
+ return -ENOMEM;
+ }
+ allocated_size = (1 << order) * PAGE_SIZE;
+
+ if (mutex_lock_interruptible(&instance->lock))
+ return -ERESTARTSYS;
+
+ /* allocate a new buffer. */
+ cbuffer = kzalloc(sizeof(struct mc_buffer), GFP_KERNEL);
+
+ if (cbuffer == NULL) {
+ MCDRV_DBG_WARN("MMAP_WSM request: could not allocate buffer\n");
+ return -ENOMEM;
+ }
+ mutex_lock(&ctx.bufs_lock);
+
+ MCDRV_DBG_VERBOSE("size %ld -> order %d --> %ld (2^n pages)\n",
+ len, order, allocated_size);
+
+ addr = (void *)__get_free_pages(GFP_USER | __GFP_ZERO, order);
+
+ if (addr == NULL) {
+ MCDRV_DBG_WARN("get_free_pages failed, "
+ "no contiguous region available.\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+ phys = (void *)virt_to_phys(addr);
+ cbuffer->handle = get_unique_id();
+ cbuffer->phys = phys;
+ cbuffer->addr = addr;
+ cbuffer->order = order;
+ cbuffer->len = len;
+ cbuffer->instance = instance;
+ /* Refcount +1 because the TLC is requesting it */
+ atomic_set(&cbuffer->usage, 1);
+
+ INIT_LIST_HEAD(&cbuffer->list);
+ list_add(&cbuffer->list, &ctx.cont_bufs);
+
+ MCDRV_DBG("allocated phys=0x%p - 0x%p, "
+ "size=%ld, kernel_virt=0x%p, handle=%d\n",
+ phys, (void *)((unsigned int)phys+allocated_size),
+ allocated_size, addr, cbuffer->handle);
+ *buffer = cbuffer;
+ goto unlock;
+
+err:
+ kfree(cbuffer);
+unlock:
+ mutex_unlock(&ctx.bufs_lock);
+ mutex_unlock(&instance->lock);
+ return ret;
+}
+
+/* Locks a contiguous buffer - +1 refcount. Assumes the instance lock is
+ * already taken! */
+static int __lock_buffer(struct mc_instance *instance, uint32_t handle)
+{
+ int ret = 0;
+ struct mc_buffer *buffer;
+
+ if (WARN(!instance, "No instance data available"))
+ return -EFAULT;
+
+ if (WARN_ON(!is_daemon(instance))) {
+ MCDRV_DBG_ERROR("caller not MobiCore Daemon\n");
+ return -EPERM;
+ }
+
+ mutex_lock(&ctx.bufs_lock);
+ /* search for the given handle in the buffers list */
+ list_for_each_entry(buffer, &ctx.cont_bufs, list) {
+ if (buffer->handle == handle) {
+ atomic_inc(&buffer->usage);
+ goto unlock;
+ }
+ }
+ ret = -EINVAL;
+
+unlock:
+ mutex_unlock(&ctx.bufs_lock);
+ return ret;
+}
+
+void *get_mci_base_phys(unsigned int len)
+{
+ if (ctx.mci_base.phys)
+ return ctx.mci_base.phys;
+ else {
+ unsigned int order = get_order(len);
+ ctx.mcp = NULL;
+ ctx.mci_base.order = order;
+ ctx.mci_base.addr =
+ (void *)__get_free_pages(GFP_USER | __GFP_ZERO, order);
+ if (ctx.mci_base.addr == NULL) {
+ MCDRV_DBG_WARN("get_free_pages failed, "
+ "no contiguous region available.\n");
+ memset(&ctx.mci_base, 0, sizeof(ctx.mci_base));
+ return NULL;
+ }
+ ctx.mci_base.phys = (void *)virt_to_phys(ctx.mci_base.addr);
+ return ctx.mci_base.phys;
+ }
+}
+
+/* Create a l2 table from a virtual memory buffer which can be vmalloc
+ * or user space virtual memory */
+int mc_register_wsm_l2(struct mc_instance *instance,
+ uint32_t buffer, uint32_t len,
+ uint32_t *handle, uint32_t *phys)
+{
+ int ret = 0;
+ struct mc_l2_table *table = NULL;
+ struct task_struct *task = current;
+
+ if (WARN(!instance, "No instance data available"))
+ return -EFAULT;
+
+ if (len == 0) {
+ MCDRV_DBG_ERROR("len=0 is not supported!\n");
+ return -EINVAL;
+ }
+
+ table = mc_alloc_l2_table(instance, task, (void *)buffer, len);
+
+ if (IS_ERR(table)) {
+ MCDRV_DBG_ERROR("new_used_l2_table() failed\n");
+ return -EINVAL;
+ }
+
+ /* set response */
+ *handle = table->handle;
+ /* WARNING: daemon shouldn't know this either, but live with it */
+ if (is_daemon(instance))
+ *phys = (uint32_t)table->phys;
+ else
+ *phys = 0;
+
+ MCDRV_DBG_VERBOSE("handle: %d, phys=%p\n", *handle, (void *)*phys);
+
+ MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
+
+ return ret;
+}
+
+/**
+ *
+ * @param instance
+ * @param arg
+ *
+ * @return 0 if no error
+ *
+ */
+int mc_unregister_wsm_l2(struct mc_instance *instance, uint32_t handle)
+{
+ int ret = 0;
+
+ if (WARN(!instance, "No instance data available"))
+ return -EFAULT;
+
+ /* free table (if no further locks exist) */
+ mc_free_l2_table(instance, handle);
+
+ return ret;
+}
+/* Lock the object from handle, it could be a WSM l2 table or a cont buffer! */
+static int mc_lock_handle(struct mc_instance *instance, uint32_t handle)
+{
+ int ret = 0;
+
+ if (WARN(!instance, "No instance data available"))
+ return -EFAULT;
+
+ if (WARN_ON(!is_daemon(instance))) {
+ MCDRV_DBG_ERROR("caller not MobiCore Daemon\n");
+ return -EPERM;
+ }
+
+ mutex_lock(&instance->lock);
+ ret = mc_lock_l2_table(instance, handle);
+
+ /* Handle was not a l2 table but a cont buffer */
+ if (ret == -EINVAL) {
+ /* Call the non locking variant! */
+ ret = __lock_buffer(instance, handle);
+ }
+
+ mutex_unlock(&instance->lock);
+
+ return ret;
+}
+
+static int mc_unlock_handle(struct mc_instance *instance, uint32_t handle)
+{
+ int ret = 0;
+
+ if (WARN(!instance, "No instance data available"))
+ return -EFAULT;
+
+ if (WARN_ON(!is_daemon(instance))) {
+ MCDRV_DBG_ERROR("caller not MobiCore Daemon\n");
+ return -EPERM;
+ }
+
+ mutex_lock(&instance->lock);
+ ret = mc_free_l2_table(instance, handle);
+
+ /* Not a l2 table, then it must be a buffer */
+ if (ret == -EINVAL) {
+ /* Call the non locking variant! */
+ ret = __free_buffer(instance, handle);
+ }
+ mutex_unlock(&instance->lock);
+
+ return ret;
+}
+
+static uint32_t mc_find_wsm_l2(struct mc_instance *instance, uint32_t handle)
+{
+ uint32_t ret = 0;
+
+ if (WARN(!instance, "No instance data available"))
+ return 0;
+
+ if (WARN_ON(!is_daemon(instance))) {
+ MCDRV_DBG_ERROR("caller not MobiCore Daemon\n");
+ return 0;
+ }
+
+ mutex_lock(&instance->lock);
+ ret = mc_find_l2_table(instance, handle);
+ mutex_unlock(&instance->lock);
+
+ return ret;
+}
+
+static int mc_clean_wsm_l2(struct mc_instance *instance)
+{
+ if (WARN(!instance, "No instance data available"))
+ return -EFAULT;
+
+ if (WARN_ON(!is_daemon(instance))) {
+ MCDRV_DBG_ERROR("caller not MobiCore Daemon\n");
+ return -EPERM;
+ }
+
+ mc_clean_l2_tables();
+
+ return 0;
+}
+
+static int mc_fd_mmap(struct file *file, struct vm_area_struct *vmarea)
+{
+ struct mc_instance *instance = get_instance(file);
+ unsigned long len = vmarea->vm_end - vmarea->vm_start;
+ void *paddr = (void *)(vmarea->vm_pgoff << PAGE_SHIFT);
+ unsigned int pfn;
+ struct mc_buffer *buffer = 0;
+ int ret = 0;
+
+ MCDRV_DBG("enter (vma start=0x%p, size=%ld, mci=%p)\n",
+ (void *)vmarea->vm_start, len, ctx.mci_base.phys);
+
+ if (WARN(!instance, "No instance data available"))
+ return -EFAULT;
+
+ if (len == 0) {
+ MCDRV_DBG_ERROR("cannot allocate size 0\n");
+ return -ENOMEM;
+ }
+ if (paddr) {
+ mutex_lock(&ctx.bufs_lock);
+
+ /* search for the buffer list. */
+ list_for_each_entry(buffer, &ctx.cont_bufs, list) {
+ if (buffer->phys == paddr)
+ goto found;
+ else
+ break;
+ }
+ /* Nothing found return */
+ mutex_unlock(&ctx.bufs_lock);
+ return -EINVAL;
+
+found:
+ vmarea->vm_flags |= VM_RESERVED;
+ /* Convert kernel address to user address. Kernel address begins
+ * at PAGE_OFFSET, user address range is below PAGE_OFFSET.
+ * Remapping the area is always done, so multiple mappings
+ * of one region are possible. Now remap kernel address
+ * space into user space */
+ pfn = (unsigned int)paddr >> PAGE_SHIFT;
+ ret = (int)remap_pfn_range(vmarea, vmarea->vm_start, pfn,
+ buffer->len, vmarea->vm_page_prot);
+ mutex_unlock(&ctx.bufs_lock);
+ } else {
+ if (!is_daemon(instance))
+ return -EPERM;
+
+ paddr = get_mci_base_phys(len);
+ if (!paddr)
+ return -EFAULT;
+
+ vmarea->vm_flags |= VM_RESERVED;
+ /* Convert kernel address to user address. Kernel address begins
+ * at PAGE_OFFSET, user address range is below PAGE_OFFSET.
+ * Remapping the area is always done, so multiple mappings
+ * of one region are possible. Now remap kernel address
+ * space into user space */
+ pfn = (unsigned int)paddr >> PAGE_SHIFT;
+ ret = (int)remap_pfn_range(vmarea, vmarea->vm_start, pfn, len,
+ vmarea->vm_page_prot);
+ }
+
+ MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
+
+ return ret;
+}
+
+/*
+#############################################################################
+##
+## IoCtl handlers
+##
+#############################################################################*/
+static inline int ioctl_check_pointer(unsigned int cmd, int __user *uarg)
+{
+ int err = 0;
+ if (_IOC_DIR(cmd) & _IOC_READ)
+ err = !access_ok(VERIFY_WRITE, uarg, _IOC_SIZE(cmd));
+ else if (_IOC_DIR(cmd) & _IOC_WRITE)
+ err = !access_ok(VERIFY_READ, uarg, _IOC_SIZE(cmd));
+ if (err)
+ return -EFAULT;
+
+ return 0;
+}
+
+/**
+ * This function will be called from user space as ioctl(...).
+ * @param file pointer to file
+ * @param cmd command
+ * @param arg arguments
+ *
+ * @return int 0 for OK and an errno in case of error
+ */
+static long mc_fd_user_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct mc_instance *instance = get_instance(file);
+ int __user *uarg = (int __user *)arg;
+ int ret = -EINVAL;
+
+ if (WARN(!instance, "No instance data available"))
+ return -EFAULT;
+
+ if (ioctl_check_pointer(cmd, uarg))
+ return -EFAULT;
+
+ switch (cmd) {
+ case MC_IO_FREE:
+ ret = mc_free_buffer(instance, (uint32_t)arg);
+ break;
+
+ case MC_IO_REG_WSM:{
+ struct mc_ioctl_reg_wsm reg;
+ if (copy_from_user(®, uarg, sizeof(reg)))
+ return -EFAULT;
+
+ ret = mc_register_wsm_l2(instance, reg.buffer,
+ reg.len, ®.handle, ®.table_phys);
+ if (!ret) {
+ if (copy_to_user(uarg, ®, sizeof(reg))) {
+ ret = -EFAULT;
+ mc_unregister_wsm_l2(instance, reg.handle);
+ }
+ }
+ break;
+ }
+ case MC_IO_UNREG_WSM:
+ ret = mc_unregister_wsm_l2(instance, (uint32_t)arg);
+ break;
+
+ case MC_IO_VERSION:
+ ret = put_user(mc_get_version(), uarg);
+ if (ret)
+ MCDRV_DBG_ERROR("IOCTL_GET_VERSION failed to put data");
+ break;
+
+ case MC_IO_MAP_WSM:{
+ struct mc_ioctl_map map;
+ struct mc_buffer *buffer = 0;
+ if (copy_from_user(&map, uarg, sizeof(map)))
+ return -EFAULT;
+
+ /* Setup the WSM buffer structure! */
+ if (mc_get_buffer(instance, &buffer, map.len))
+ return -EFAULT;
+
+ map.handle = buffer->handle;
+ map.phys_addr = (unsigned long)buffer->phys;
+ map.reused = 0;
+ if (copy_to_user(uarg, &map, sizeof(map)))
+ ret = -EFAULT;
+
+ ret = 0;
+ break;
+ }
+ default:
+ MCDRV_DBG_ERROR("unsupported cmd=%d\n", cmd);
+ ret = -ENOIOCTLCMD;
+ break;
+
+ } /* end switch(cmd) */
+
+#ifdef MC_MEM_TRACES
+ mobicore_log_read();
+#endif
+
+ return (int)ret;
+}
+
+static long mc_fd_admin_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct mc_instance *instance = get_instance(file);
+ int __user *uarg = (int __user *)arg;
+ int ret = -EINVAL;
+
+ if (WARN(!instance, "No instance data available"))
+ return -EFAULT;
+
+ if (WARN_ON(!is_daemon(instance))) {
+ MCDRV_DBG_ERROR("caller not MobiCore Daemon\n");
+ return -EPERM;
+ }
+
+ if (ioctl_check_pointer(cmd, uarg))
+ return -EFAULT;
+
+ switch (cmd) {
+ case MC_IO_INIT: {
+ struct mc_ioctl_init init;
+ ctx.mcp = NULL;
+ if (!ctx.mci_base.phys) {
+ MCDRV_DBG_ERROR("Cannot init MobiCore without MCI!");
+ return -EINVAL;
+ }
+ if (copy_from_user(&init, uarg, sizeof(init)))
+ return -EFAULT;
+
+ ctx.mcp = ctx.mci_base.addr + init.mcp_offset;
+ ret = mc_init((uint32_t)ctx.mci_base.phys, init.nq_offset,
+ init.nq_length, init.mcp_offset, init.mcp_length);
+ break;
+ }
+ case MC_IO_INFO: {
+ struct mc_ioctl_info info;
+ if (copy_from_user(&info, uarg, sizeof(info)))
+ return -EFAULT;
+
+ ret = mc_info(info.ext_info_id, &info.state,
+ &info.ext_info);
+
+ if (!ret) {
+ if (copy_to_user(uarg, &info, sizeof(info)))
+ ret = -EFAULT;
+ }
+ break;
+ }
+ case MC_IO_YIELD:
+ ret = mc_yield();
+ break;
+
+ case MC_IO_NSIQ:
+ ret = mc_nsiq();
+ break;
+
+ case MC_IO_LOCK_WSM: {
+ ret = mc_lock_handle(instance, (uint32_t)arg);
+ break;
+ }
+ case MC_IO_UNLOCK_WSM:
+ ret = mc_unlock_handle(instance, (uint32_t)arg);
+ break;
+ case MC_IO_CLEAN_WSM:
+ ret = mc_clean_wsm_l2(instance);
+ break;
+ case MC_IO_RESOLVE_WSM: {
+ uint32_t handle, phys;
+ if (get_user(handle, uarg))
+ return -EFAULT;
+ phys = mc_find_wsm_l2(instance, handle);
+ if (!phys)
+ return -EFAULT;
+ ret = put_user(phys, uarg);
+ break;
+ }
+ case MC_IO_RESOLVE_CONT_WSM: {
+ struct mc_ioctl_resolv_cont_wsm cont_wsm;
+ uint32_t phys = 0, len = 0;
+ if (copy_from_user(&cont_wsm, uarg, sizeof(cont_wsm)))
+ return -EFAULT;
+ ret = mc_find_cont_wsm(instance, cont_wsm.handle, &phys, &len);
+ if (!ret) {
+ cont_wsm.phys = phys;
+ cont_wsm.length = len;
+ if (copy_to_user(uarg, &cont_wsm, sizeof(cont_wsm)))
+ ret = -EFAULT;
+ }
+ break;
+ }
+ case MC_IO_MAP_MCI:{
+ struct mc_ioctl_map map;
+ if (copy_from_user(&map, uarg, sizeof(map)))
+ return -EFAULT;
+
+ map.reused = (ctx.mci_base.phys != 0);
+ map.phys_addr = (unsigned long)get_mci_base_phys(map.len);
+ if (!map.phys_addr) {
+ MCDRV_DBG_ERROR("Failed to setup MCI buffer!");
+ return -EFAULT;
+ }
+
+ if (copy_to_user(uarg, &map, sizeof(map)))
+ ret = -EFAULT;
+ ret = 0;
+ break;
+ }
+ case MC_IO_MAP_PWSM:{
+ break;
+ }
+
+ /* The rest is handled commonly by user IOCTL */
+ default:
+ ret = mc_fd_user_ioctl(file, cmd, arg);
+ } /* end switch(cmd) */
+
+#ifdef MC_MEM_TRACES
+ mobicore_log_read();
+#endif
+
+ return (int)ret;
+}
+
+/**
+ * This function will be called from user space as read(...).
+ * The read function is blocking until a interrupt occurs. In that case the
+ * event counter is copied into user space and the function is finished.
+ * @param *file
+ * @param *buffer buffer where to copy to(userspace)
+ * @param buffer_len number of requested data
+ * @param *pos not used
+ * @return ssize_t ok case: number of copied data
+ * error case: return errno
+ */
+static ssize_t mc_fd_read(struct file *file, char *buffer, size_t buffer_len,
+ loff_t *pos)
+{
+ int ret = 0, ssiq_counter;
+ struct mc_instance *instance = get_instance(file);
+
+ if (WARN(!instance, "No instance data available"))
+ return -EFAULT;
+
+ /* avoid debug output on non-error, because this is call quite often */
+ MCDRV_DBG_VERBOSE("enter\n");
+
+ /* only the MobiCore Daemon is allowed to call this function */
+ if (WARN_ON(!is_daemon(instance))) {
+ MCDRV_DBG_ERROR("caller not MobiCore Daemon\n");
+ return -EPERM;
+ }
+
+ if (buffer_len < sizeof(unsigned int)) {
+ MCDRV_DBG_ERROR("invalid length\n");
+ return -EINVAL;
+ }
+
+ for (;;) {
+ if (wait_for_completion_interruptible(&ctx.isr_comp)) {
+ MCDRV_DBG_VERBOSE("read interrupted\n");
+ return -ERESTARTSYS;
+ }
+
+ ssiq_counter = atomic_read(&ctx.isr_counter);
+ MCDRV_DBG_VERBOSE("ssiq_counter=%i, ctx.counter=%i\n",
+ ssiq_counter, ctx.evt_counter);
+
+ if (ssiq_counter != ctx.evt_counter) {
+ /* read data and exit loop without error */
+ ctx.evt_counter = ssiq_counter;
+ ret = 0;
+ break;
+ }
+
+ /* end loop if non-blocking */
+ if (file->f_flags & O_NONBLOCK) {
+ MCDRV_DBG_ERROR("non-blocking read\n");
+ return -EAGAIN;
+ }
+
+ if (signal_pending(current)) {
+ MCDRV_DBG_VERBOSE("received signal.\n");
+ return -ERESTARTSYS;
+ }
+ }
+
+ /* read data and exit loop */
+ ret = copy_to_user(buffer, &ctx.evt_counter, sizeof(unsigned int));
+
+ if (ret != 0) {
+ MCDRV_DBG_ERROR("copy_to_user failed\n");
+ return -EFAULT;
+ }
+
+ ret = sizeof(unsigned int);
+
+ return (ssize_t)ret;
+}
+
+/**
+ * Initialize a new mobicore API instance object
+ *
+ * @return Instance or NULL if no allocation was possible.
+ */
+struct mc_instance *mc_alloc_instance(void)
+{
+ struct mc_instance *instance;
+
+ instance = kzalloc(sizeof(*instance), GFP_KERNEL);
+ if (instance == NULL)
+ return NULL;
+
+ /* get a unique ID for this instance (PIDs are not unique) */
+ instance->handle = get_unique_id();
+
+ mutex_init(&instance->lock);
+
+ return instance;
+}
+
+/**
+ * Release a mobicore instance object and all objects related to it
+ * @param instance instance
+ * @return 0 if Ok or -E ERROR
+ */
+int mc_release_instance(struct mc_instance *instance)
+{
+ struct mc_buffer *buffer, *tmp;
+
+ if (WARN(!instance, "No instance data available"))
+ return -EFAULT;
+
+ mutex_lock(&instance->lock);
+ mc_clear_l2_tables(instance);
+
+ mutex_lock(&ctx.bufs_lock);
+ /* release all mapped data */
+
+ /* Check if some buffers are orphaned. */
+ list_for_each_entry_safe(buffer, tmp, &ctx.cont_bufs, list) {
+ if (buffer->instance == instance) {
+ buffer->instance = NULL;
+ free_buffer(buffer);
+ }
+ }
+ mutex_unlock(&ctx.bufs_lock);
+
+ mutex_unlock(&instance->lock);
+
+ /* release instance context */
+ kfree(instance);
+
+ return 0;
+}
+
+/**
+ * This function will be called from user space as fd = open(...).
+ * A set of internal instance data are created and initialized.
+ *
+ * @param inode
+ * @param file
+ * @return 0 if OK or -ENOMEM if no allocation was possible.
+ */
+static int mc_fd_user_open(struct inode *inode, struct file *file)
+{
+ struct mc_instance *instance;
+
+ MCDRV_DBG_VERBOSE("enter\n");
+
+ instance = mc_alloc_instance();
+ if (instance == NULL)
+ return -ENOMEM;
+
+ /* store instance data reference */
+ file->private_data = instance;
+
+ return 0;
+}
+
+static int mc_fd_admin_open(struct inode *inode, struct file *file)
+{
+ struct mc_instance *instance;
+
+ /* The daemon is already set so we can't allow anybody else to open
+ * the admin interface. */
+ if (ctx.daemon_inst) {
+ MCDRV_DBG_ERROR("Daemon is already connected");
+ return -EPERM;
+ }
+ /* Setup the usual variables */
+ mc_fd_user_open(inode, file);
+ instance = get_instance(file);
+
+ MCDRV_DBG("accept this as MobiCore Daemon\n");
+
+ /* Set the caller's CPU mask to CPU0*/
+ /*if (goto_cpu0() != 0) {
+ mc_release_instance(instance);
+ file->private_data = NULL;
+ MCDRV_DBG("changing core failed!\n");
+ return -EFAULT;
+ }*/
+
+ ctx.daemon_inst = instance;
+ instance->admin = true;
+ init_completion(&ctx.isr_comp);
+ /* init ssiq event counter */
+ ctx.evt_counter = atomic_read(&(ctx.isr_counter));
+
+ return 0;
+}
+
+/**
+ * This function will be called from user space as close(...).
+ * The instance data are freed and the associated memory pages are unreserved.
+ *
+ * @param inode
+ * @param file
+ *
+ * @return 0
+ */
+static int mc_fd_release(struct inode *inode, struct file *file)
+{
+ int ret = 0;
+ struct mc_instance *instance = get_instance(file);
+
+ if (WARN(!instance, "No instance data available"))
+ return -EFAULT;
+
+ /* check if daemon closes us. */
+ if (is_daemon(instance)) {
+ /* TODO: cleanup? ctx.mc_l2_tables remains */
+ MCDRV_DBG_WARN("WARNING: MobiCore Daemon died\n");
+ ctx.daemon_inst = NULL;
+ }
+
+ ret = mc_release_instance(instance);
+
+ /* ret is quite irrelevant here as most apps don't care about the
+ * return value from close() and it's quite difficult to recover */
+ MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
+
+ return (int)ret;
+}
+
+/*
+ * This function represents the interrupt function of the mcDrvModule.
+ * It signals by incrementing of an event counter and the start of the read
+ * waiting queue, the read function a interrupt has occurred.
+ */
+static irqreturn_t mc_ssiq_isr(int intr, void *context)
+{
+ /* increment interrupt event counter */
+ atomic_inc(&(ctx.isr_counter));
+
+ /* signal the daemon */
+ complete(&ctx.isr_comp);
+
+ return IRQ_HANDLED;
+}
+
+/* function table structure of this device driver. */
+static const struct file_operations mc_admin_fops = {
+ .owner = THIS_MODULE,
+ .open = mc_fd_admin_open,
+ .release = mc_fd_release,
+ .unlocked_ioctl = mc_fd_admin_ioctl,
+ .mmap = mc_fd_mmap,
+ .read = mc_fd_read,
+};
+
+static struct miscdevice mc_admin_device = {
+ .name = MC_ADMIN_DEVNODE,
+ .mode = (S_IRWXU),
+ .minor = MISC_DYNAMIC_MINOR,
+ .fops = &mc_admin_fops,
+};
+
+/* function table structure of this device driver. */
+static const struct file_operations mc_user_fops = {
+ .owner = THIS_MODULE,
+ .open = mc_fd_user_open,
+ .release = mc_fd_release,
+ .unlocked_ioctl = mc_fd_user_ioctl,
+ .mmap = mc_fd_mmap,
+};
+
+static struct miscdevice mc_user_device = {
+ .name = MC_USER_DEVNODE,
+ .mode = (S_IRWXU | S_IRWXG | S_IRWXO),
+ .minor = MISC_DYNAMIC_MINOR,
+ .fops = &mc_user_fops,
+};
+
+/**
+ * This function is called the kernel during startup or by a insmod command.
+ * This device is installed and registered as miscdevice, then interrupt and
+ * queue handling is set up
+ */
+static int __init mobicore_init(void)
+{
+ int ret = 0;
+
+ MCDRV_DBG("enter (Build " __TIMESTAMP__ ")\n");
+ MCDRV_DBG("mcDrvModuleApi version is %i.%i\n",
+ MCDRVMODULEAPI_VERSION_MAJOR,
+ MCDRVMODULEAPI_VERSION_MINOR);
+#ifdef MOBICORE_COMPONENT_BUILD_TAG
+ MCDRV_DBG("%s\n", MOBICORE_COMPONENT_BUILD_TAG);
+#endif
+ /* Hardware does not support ARM TrustZone -> Cannot continue! */
+ if (!has_security_extensions()) {
+ MCDRV_DBG_ERROR(
+ "Hardware does't support ARM TrustZone!\n");
+ return -ENODEV;
+ }
+
+ /* Running in secure mode -> Cannot load the driver! */
+ if (is_secure_mode()) {
+ MCDRV_DBG_ERROR("Running in secure MODE!\n");
+ return -ENODEV;
+ }
+
+ ret = mc_fastcall_init();
+ if (ret)
+ goto error;
+
+ init_completion(&ctx.isr_comp);
+ /* set up S-SIQ interrupt handler */
+ ret = request_irq(MC_INTR_SSIQ, mc_ssiq_isr, IRQF_TRIGGER_RISING,
+ MC_ADMIN_DEVNODE, &ctx);
+ if (ret != 0) {
+ MCDRV_DBG_ERROR("interrupt request failed\n");
+ goto err_req_irq;
+ }
+
+#ifdef MC_PM_RUNTIME
+ ret = mc_pm_initialize(&ctx);
+ if (ret != 0) {
+ MCDRV_DBG_ERROR("Power Management init failed!\n");
+ goto free_isr;
+ }
+#endif
+
+ ret = misc_register(&mc_admin_device);
+ if (ret != 0) {
+ MCDRV_DBG_ERROR("admin device register failed\n");
+ goto free_isr;
+ }
+
+ ret = misc_register(&mc_user_device);
+ if (ret != 0) {
+ MCDRV_DBG_ERROR("user device register failed\n");
+ goto free_admin;
+ }
+
+#ifdef MC_MEM_TRACES
+ mobicore_log_setup();
+#endif
+
+ /* initialize event counter for signaling of an IRQ to zero */
+ atomic_set(&ctx.isr_counter, 0);
+
+ ret = mc_init_l2_tables();
+
+ /* initialize unique number counter which we can use for
+ * handles. It is limited to 2^32, but this should be
+ * enough to be roll-over safe for us. We start with 1
+ * instead of 0. */
+ atomic_set(&ctx.unique_counter, 1);
+
+ /* init list for contiguous buffers */
+ INIT_LIST_HEAD(&ctx.cont_bufs);
+
+ /* init lock for the buffers list */
+ mutex_init(&ctx.bufs_lock);
+
+ memset(&ctx.mci_base, 0, sizeof(ctx.mci_base));
+ MCDRV_DBG("initialized\n");
+ return 0;
+
+free_admin:
+ misc_deregister(&mc_admin_device);
+free_isr:
+ free_irq(MC_INTR_SSIQ, &ctx);
+err_req_irq:
+ mc_fastcall_destroy();
+error:
+ return ret;
+}
+
+/**
+ * This function removes this device driver from the Linux device manager .
+ */
+static void __exit mobicore_exit(void)
+{
+ MCDRV_DBG_VERBOSE("enter\n");
+#ifdef MC_MEM_TRACES
+ mobicore_log_free();
+#endif
+
+ mc_release_l2_tables();
+
+#ifdef MC_PM_RUNTIME
+ mc_pm_free();
+#endif
+
+ free_irq(MC_INTR_SSIQ, &ctx);
+
+ misc_deregister(&mc_admin_device);
+ misc_deregister(&mc_user_device);
+
+ mc_fastcall_destroy();
+
+ MCDRV_DBG_VERBOSE("exit");
+}
+
+/* Linux Driver Module Macros */
+module_init(mobicore_init);
+module_exit(mobicore_exit);
+MODULE_AUTHOR("Giesecke & Devrient GmbH");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MobiCore driver");
+
+/** @} */
diff --git a/drivers/gud/MobiCoreDriver/main.h b/drivers/gud/MobiCoreDriver/main.h
new file mode 100644
index 0000000..8a08df8
--- /dev/null
+++ b/drivers/gud/MobiCoreDriver/main.h
@@ -0,0 +1,148 @@
+/**
+ * Header file of MobiCore Driver Kernel Module.
+ *
+ * @addtogroup MCD_MCDIMPL_KMOD_IMPL
+ * @{
+ * Internal structures of the McDrvModule
+ * @file
+ *
+ * Header file the MobiCore Driver Kernel Module,
+ * its internal structures and defines.
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ *
+ * 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.
+ */
+
+#ifndef _MC_DRV_KMOD_H_
+#define _MC_DRV_KMOD_H_
+
+#include <asm/pgtable.h>
+#include <linux/semaphore.h>
+#include <linux/completion.h>
+#include <linux/mutex.h>
+
+#include "public/mc_linux.h"
+/** Platform specific settings */
+#include "platform.h"
+
+#define MC_VERSION(major, minor) \
+ (((major & 0x0000ffff) << 16) | (minor & 0x0000ffff))
+
+/** Maximum number of contiguous buffer allocations that one process can get via
+ * mmap. */
+#define MC_DRV_KMOD_MAX_CONTG_BUFFERS 16
+
+/** Instance data for MobiCore Daemon and TLCs. */
+struct mc_instance {
+ struct mutex lock;
+ /** unique handle */
+ unsigned int handle;
+ bool admin;
+};
+
+/**
+ * Contiguous buffer allocated to TLCs.
+ * These buffers are uses as world shared memory (wsm) and shared with
+ * secure world.
+ * The virtual kernel address is added for a simpler search algorithm.
+ */
+struct mc_buffer {
+ struct list_head list;
+ /**< unique handle */
+ unsigned int handle;
+ /** Number of references kept to this buffer */
+ atomic_t usage;
+ /**< virtual Kernel start address */
+ void *addr;
+ /**< physical start address */
+ void *phys;
+ /**< order of number of pages */
+ unsigned int order;
+ uint32_t len;
+ struct mc_instance *instance;
+};
+
+/** MobiCore Driver Kernel Module context data. */
+struct mc_context {
+ /** MobiCore MCI information */
+ struct mc_buffer mci_base;
+ /** MobiCore MCP buffer */
+ struct mc_mcp_buffer *mcp;
+ /** event completion */
+ struct completion isr_comp;
+ /** isr event counter */
+ unsigned int evt_counter;
+ atomic_t isr_counter;
+ /** ever incrementing counter */
+ atomic_t unique_counter;
+ /** pointer to instance of daemon */
+ struct mc_instance *daemon_inst;
+ /** General list of contigous buffers allocated by the kernel */
+ struct list_head cont_bufs;
+ /** Lock for the list of contiguous buffers */
+ struct mutex bufs_lock;
+};
+
+struct mc_sleep_mode {
+ uint16_t SleepReq;
+ uint16_t ReadyToSleep;
+};
+
+/**< MobiCore is idle. No scheduling required. */
+#define SCHEDULE_IDLE 0
+/**< MobiCore is non idle, scheduling is required. */
+#define SCHEDULE_NON_IDLE 1
+
+/** MobiCore status flags */
+struct mc_flags {
+ /**< Scheduling hint: if <> SCHEDULE_IDLE, MobiCore should
+ * be scheduled by the NWd */
+ uint32_t schedule;
+ /**< */
+ struct mc_sleep_mode sleep_mode;
+ /**< Reserved for future use: Must not be interpreted */
+ uint32_t rfu[2];
+};
+
+/** MCP buffer structure */
+struct mc_mcp_buffer {
+ /**< MobiCore Flags */
+ struct mc_flags flags;
+ uint32_t rfu; /**< MCP message buffer - ignore */
+} ;
+
+unsigned int get_unique_id(void);
+
+/** check if caller is MobiCore Daemon */
+static inline bool is_daemon(struct mc_instance *instance)
+{
+ if (!instance)
+ return false;
+ return instance->admin;
+}
+
+
+/* Initialize a new mobicore API instance object */
+struct mc_instance *mc_alloc_instance(void);
+/* Release a mobicore instance object and all objects related to it */
+int mc_release_instance(struct mc_instance *instance);
+
+/* Create a l2 table from a virtual memory buffer which can be vmalloc
+ * or user space virtual memory */
+int mc_register_wsm_l2(struct mc_instance *instance,
+ uint32_t buffer, uint32_t len,
+ uint32_t *handle, uint32_t *phys);
+/* Unregister the buffer mapped above */
+int mc_unregister_wsm_l2(struct mc_instance *instance, uint32_t handle);
+
+/* Allocate one mc_buffer of contigous space */
+int mc_get_buffer(struct mc_instance *instance,
+ struct mc_buffer **buffer, unsigned long len);
+/* Free the buffer allocated above */
+int mc_free_buffer(struct mc_instance *instance, uint32_t handle);
+
+#endif /* _MC_DRV_KMOD_H_ */
+/** @} */
diff --git a/drivers/gud/MobiCoreDriver/mem.c b/drivers/gud/MobiCoreDriver/mem.c
new file mode 100644
index 0000000..cb223b3
--- /dev/null
+++ b/drivers/gud/MobiCoreDriver/mem.c
@@ -0,0 +1,670 @@
+/** MobiCore driver module.(interface to the secure world SWD)
+ * @addtogroup MCD_MCDIMPL_KMOD_IMPL
+ * @{
+ * @file
+ * MobiCore Driver Kernel Module.
+ * This module is written as a Linux device driver.
+ * This driver represents the command proxy on the lowest layer, from the
+ * secure world to the non secure world, and vice versa.
+ * This driver is located in the non secure world (Linux).
+ * This driver offers IOCTL commands, for access to the secure world, and has
+ * the interface from the secure world to the normal world.
+ * The access to the driver is possible with a file descriptor,
+ * which has to be created by the fd = open(/dev/mobicore) command.
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ *
+ * 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.
+ */
+#include "main.h"
+#include "debug.h"
+#include "mem.h"
+
+#include <linux/highmem.h>
+#include <linux/slab.h>
+#include <linux/kthread.h>
+#include <linux/pagemap.h>
+
+
+/** MobiCore memory context data */
+struct mc_mem_context mem_ctx;
+
+/* convert L2 PTE to page pointer */
+static inline struct page *l2_pte_to_page(pte_t pte)
+{
+ unsigned long phys_page_addr = ((unsigned long)pte & PAGE_MASK);
+ unsigned int pfn = phys_page_addr >> PAGE_SHIFT;
+ struct page *page = pfn_to_page(pfn);
+ return page;
+}
+
+/* convert page pointer to L2 PTE */
+static inline pte_t page_to_l2_pte(struct page *page)
+{
+ unsigned long pfn = page_to_pfn(page);
+ unsigned long phys_addr = (pfn << PAGE_SHIFT);
+ pte_t pte = (pte_t)(phys_addr & PAGE_MASK);
+ return pte;
+}
+
+static inline void release_page(struct page *page)
+{
+ SetPageDirty(page);
+
+ page_cache_release(page);
+}
+
+static int lock_pages(struct task_struct *task, void *virt_start_page_addr,
+ int pages_no, struct page **pages)
+{
+ int locked_pages;
+
+ /* lock user pages, must hold the mmap_sem to do this. */
+ down_read(&(task->mm->mmap_sem));
+ locked_pages = get_user_pages(
+ task,
+ task->mm,
+ (unsigned long)virt_start_page_addr,
+ pages_no,
+ 1, /* write access */
+ 0,
+ pages,
+ NULL); /* we don't need the VMAs */
+ up_read(&(task->mm->mmap_sem));
+
+ /* could as lock all pages? */
+ if (locked_pages != pages_no) {
+ MCDRV_DBG_ERROR("get_user_pages() failed, locked_pages=%d",
+ locked_pages);
+ if (locked_pages > 0) {
+ /* release all locked pages. */
+ release_pages(pages, locked_pages, 0);
+ }
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+/* Get kernel pointer to shared L2 table given a per-process reference */
+struct l2table *get_l2_table_kernel_virt(struct mc_l2_table *table)
+{
+ if (WARN(!table, "Invalid L2 table"))
+ return NULL;
+
+ if (WARN(!table->set, "Invalid L2 table set"))
+ return NULL;
+
+ if (WARN(!table->set->kernel_virt, "Invalid L2 pointer"))
+ return NULL;
+
+ return &(table->set->kernel_virt->table[table->idx]);
+}
+
+/* Get physical address of a shared L2 table given a per-process reference */
+struct l2table *get_l2_table_phys(struct mc_l2_table *table)
+{
+ if (WARN(!table, "Invalid L2 table"))
+ return NULL;
+ if (WARN(!table->set, "Invalid L2 table set"))
+ return NULL;
+ if (WARN(!table->set->kernel_virt, "Invalid L2 phys pointer"))
+ return NULL;
+
+ return &(table->set->phys->table[table->idx]);
+}
+
+static inline int in_use(struct mc_l2_table *table)
+{
+ return atomic_read(&table->usage) > 0;
+}
+
+/* Search the list of used l2 tables and return the one with the handle.
+ * Assumes the table_lock is taken */
+struct mc_l2_table *find_l2_table(unsigned int handle)
+{
+ struct mc_l2_table *table;
+
+ list_for_each_entry(table, &mem_ctx.l2_tables, list) {
+ if (table->handle == handle)
+ return table;
+ }
+ return NULL;
+}
+
+/* Allocate a new l2 table store plus L2_TABLES_PER_PAGE in the l2 free tables
+ * list. Assumes the table_lock is already taken by the caller above */
+static int alloc_table_store(void)
+{
+ unsigned long store;
+ struct mc_l2_tables_set *l2table_set;
+ struct mc_l2_table *l2table;
+ struct page *page;
+ int ret = 0, i;
+ /* temp list for holding the l2 tables */
+ LIST_HEAD(temp);
+
+ store = get_zeroed_page(GFP_KERNEL);
+ if (!store)
+ return -ENOMEM;
+
+ /* Actually, locking is not necessary, because kernel
+ * memory is not supposed to get swapped out. But we
+ * play safe.... */
+ page = virt_to_page(store);
+ SetPageReserved(page);
+
+ /* add all the descriptors to the free descriptors list */
+ l2table_set = kmalloc(sizeof(*l2table_set), GFP_KERNEL | __GFP_ZERO);
+ if (l2table_set == NULL) {
+ ret = -ENOMEM;
+ goto free_store;
+ }
+ /* initialize */
+ l2table_set->kernel_virt = (void *)store;
+ l2table_set->page = page;
+ l2table_set->phys = (void *)virt_to_phys((void *)store);
+ /* the set is not yet used */
+ atomic_set(&l2table_set->used_tables, 0);
+
+ /* init add to list. */
+ INIT_LIST_HEAD(&(l2table_set->list));
+ list_add(&l2table_set->list, &mem_ctx.l2_tables_sets);
+
+ for (i = 0; i < L2_TABLES_PER_PAGE; i++) {
+ /* allocate a WSM L2 descriptor */
+ l2table = kmalloc(sizeof(*l2table), GFP_KERNEL | __GFP_ZERO);
+ /* If one of the allocations fails what then? */
+ if (l2table == NULL) {
+ ret = -ENOMEM;
+ MCDRV_DBG_ERROR("out of memory\n");
+ /* Free the full temp list and the store in this case */
+ goto free_temp_list;
+ }
+
+ /* set set reference */
+ l2table->set = l2table_set;
+ l2table->idx = i;
+ l2table->virt = get_l2_table_kernel_virt(l2table);
+ l2table->phys = (unsigned long)get_l2_table_phys(l2table);
+ atomic_set(&l2table->usage, 0);
+
+ /* add to temp list. */
+ INIT_LIST_HEAD(&l2table->list);
+ list_add_tail(&l2table->list, &temp);
+ }
+
+ /* If everything went ok then merge the temp list with the global
+ * free list */
+ list_splice_tail(&temp, &mem_ctx.free_l2_tables);
+ return 0;
+free_temp_list:
+ list_for_each_entry(l2table, &temp, list) {
+ kfree(l2table);
+ }
+
+ list_del(&l2table_set->list);
+
+free_store:
+ free_page(store);
+ return ret;
+
+}
+/* Get a l2 table from the free tables list or alocate a new one and
+ * initialize it. Assumes the table_lock is already taken. */
+static struct mc_l2_table *alloc_l2_table(struct mc_instance *instance)
+{
+ int ret = 0;
+ struct mc_l2_table *table = NULL;
+
+ if (list_empty(&mem_ctx.free_l2_tables)) {
+ ret = alloc_table_store();
+ if (ret) {
+ MCDRV_DBG_ERROR("Failed to allocate new store!");
+ return ERR_PTR(-ENOMEM);
+ }
+ /* if it's still empty something wrong has happened */
+ if (list_empty(&mem_ctx.free_l2_tables)) {
+ MCDRV_DBG_ERROR("Free list not updated correctly!");
+ return ERR_PTR(-EFAULT);
+ }
+ }
+
+ /* get a WSM L2 descriptor */
+ table = list_first_entry(&mem_ctx.free_l2_tables,
+ struct mc_l2_table, list);
+ if (table == NULL) {
+ MCDRV_DBG_ERROR("out of memory\n");
+ return ERR_PTR(-ENOMEM);
+ }
+ /* Move it to the used l2 tables list */
+ list_move_tail(&table->list, &mem_ctx.l2_tables);
+
+ table->handle = get_unique_id();
+ table->owner = instance;
+
+ atomic_inc(&table->set->used_tables);
+ atomic_inc(&table->usage);
+
+ MCDRV_DBG_VERBOSE("chunkPhys=%p,idx=%d", table->set->phys, table->idx);
+
+ return table;
+}
+
+/* Frees the object associated with a l2 table. Initially the object is moved
+ * to the free tables list, but if all the 4 lists of the store are free
+ * then the store is also released.
+ * Assumes the table_lock is already taken.*/
+static void free_l2_table(struct mc_l2_table *table)
+{
+ struct mc_l2_tables_set *l2table_set;
+
+ if (WARN(!table, "Invalid table"))
+ return;
+
+ l2table_set = table->set;
+ if (WARN(!l2table_set, "Invalid table set"))
+ return;
+
+ list_move_tail(&table->list, &mem_ctx.free_l2_tables);
+
+ /* if nobody uses this set, we can release it. */
+ if (atomic_dec_and_test(&l2table_set->used_tables)) {
+ struct mc_l2_table *tmp;
+
+ /* remove from list */
+ list_del(&l2table_set->list);
+ /* All the l2 tables are in the free list for this set
+ * so we can just remove them from there */
+ list_for_each_entry_safe(table, tmp, &mem_ctx.free_l2_tables,
+ list) {
+ if (table->set == l2table_set) {
+ list_del(&table->list);
+ kfree(table);
+ }
+ } /* end while */
+
+ /* We shouldn't recover from this since it was some data
+ * corruption before */
+ BUG_ON(!l2table_set->page);
+ ClearPageReserved(l2table_set->page);
+
+ BUG_ON(!l2table_set->kernel_virt);
+ free_page((unsigned long)l2table_set->kernel_virt);
+
+ kfree(l2table_set);
+ }
+}
+
+/* Create a L2 table in a WSM container that has been allocates previously.
+ * Assumes the table lock is already taken or there is no need to take like
+ * when first creating the l2 table the full list is locked.
+ *
+ * @param task pointer to task owning WSM
+ * @param wsm_buffer user space WSM start
+ * @param wsm_len WSM length
+ * @param used_l2table Pointer to L2 table details
+ */
+static int map_buffer(struct task_struct *task, void *wsm_buffer,
+ unsigned int wsm_len, struct mc_l2_table *table)
+{
+ int ret = 0;
+ unsigned int i, nr_of_pages;
+ /* start address of the 4 KiB page of wsm_buffer */
+ void *virt_addr_page;
+ struct page *page;
+ struct l2table *l2table;
+ struct page **l2table_as_array_of_pointers_to_page;
+ /* page offset in wsm buffer */
+ unsigned int offset;
+
+ if (WARN(!wsm_buffer, "Invalid WSM buffer pointer"))
+ return -EINVAL;
+
+ if (WARN(wsm_len == 0, "Invalid WSM buffer length"))
+ return -EINVAL;
+
+ if (WARN(!table, "Invalid mapping table for WSM"))
+ return -EINVAL;
+
+ /* no size > 1Mib supported */
+ if (wsm_len > SZ_1M) {
+ MCDRV_DBG_ERROR("size > 1 MiB\n");
+ return -EINVAL;
+ }
+
+ MCDRV_DBG_VERBOSE("WSM addr=0x%p, len=0x%08x\n", wsm_buffer, wsm_len);
+
+ /* Check if called from kernel space wsm_buffer is actually
+ * vmalloced or not */
+ if (task == NULL && !is_vmalloc_addr(wsm_buffer)) {
+ MCDRV_DBG_ERROR("WSM addr is not a vmalloc address");
+ return -EINVAL;
+ }
+
+ /* calculate page usage */
+ virt_addr_page = (void *)(((unsigned long)(wsm_buffer)) & PAGE_MASK);
+ offset = (unsigned int) (((unsigned long)(wsm_buffer)) & (~PAGE_MASK));
+ nr_of_pages = PAGE_ALIGN(offset + wsm_len) / PAGE_SIZE;
+
+ MCDRV_DBG_VERBOSE("virt addr page start=0x%p, pages=%d\n",
+ virt_addr_page, nr_of_pages);
+
+ /* L2 table can hold max 1MiB in 256 pages. */
+ if ((nr_of_pages * PAGE_SIZE) > SZ_1M) {
+ MCDRV_DBG_ERROR("WSM paged exceed 1 MiB\n");
+ return -EINVAL;
+ }
+
+ l2table = table->virt;
+ /* We use the memory for the L2 table to hold the pointer
+ * and convert them later. This works, as everything comes
+ * down to a 32 bit value. */
+ l2table_as_array_of_pointers_to_page = (struct page **)l2table;
+
+ /* Request comes from user space */
+ if (task != NULL && !is_vmalloc_addr(wsm_buffer)) {
+ /* lock user page in memory, so they do not get swapped
+ * out.
+ * REV axh: Kernel 2.6.27 added a new get_user_pages_fast()
+ * function, maybe it is called fast_gup() in some
+ * versions.
+ * handle user process doing a fork().
+ * Child should not get things.
+ * http://osdir.com/ml/linux-media/2009-07/msg00813.html
+ * http://lwn.net/Articles/275808/ */
+ ret = lock_pages(task, virt_addr_page, nr_of_pages,
+ l2table_as_array_of_pointers_to_page);
+ if (ret != 0) {
+ MCDRV_DBG_ERROR("lock_user_pages() failed\n");
+ return ret;
+ }
+ }
+ /* Request comes from kernel space(vmalloc buffer) */
+ else {
+ void *uaddr = wsm_buffer;
+ for (i = 0; i < nr_of_pages; i++) {
+ page = vmalloc_to_page(uaddr);
+ if (!page) {
+ MCDRV_DBG_ERROR("vmalloc_to_Page()"
+ " failed to map address\n");
+ return -EINVAL;
+ }
+ get_page(page);
+ l2table_as_array_of_pointers_to_page[i] = page;
+ uaddr += PAGE_SIZE;
+ }
+ }
+
+ table->pages = nr_of_pages;
+
+ /* create L2 Table entries.
+ * used_l2table->table contains a list of page pointers here.
+ * For a proper cleanup we have to ensure that the following
+ * code either works and used_l2table contains a valid L2 table
+ * - or fails and used_l2table->table contains the list of page
+ * pointers.
+ * Any mixed contents will make cleanup difficult.*/
+ for (i = 0; i < nr_of_pages; i++) {
+ pte_t pte;
+ page = l2table_as_array_of_pointers_to_page[i];
+
+ /* create L2 table entry, see ARM MMU docu for details
+ * about flags stored in the lowest 12 bits.
+ * As a side reference, the Article
+ * "ARM's multiply-mapped memory mess"
+ * found in the collection at
+ * http://lwn.net/Articles/409032/
+ * is also worth reading.*/
+ pte = page_to_l2_pte(page)
+ | PTE_EXT_AP1 | PTE_EXT_AP0
+ | PTE_CACHEABLE | PTE_BUFFERABLE
+ | PTE_TYPE_SMALL | PTE_TYPE_EXT | PTE_EXT_NG;
+ /* Linux uses different mappings for SMP systems(the
+ * sharing flag is set for the pte. In order not to
+ * confuse things too much in Mobicore make sure the
+ * shared buffers have the same flags.
+ * This should also be done in SWD side
+ */
+#ifdef CONFIG_SMP
+ pte |= PTE_EXT_SHARED | PTE_EXT_TEX(1);
+#endif
+
+ l2table->table_entries[i] = pte;
+ MCDRV_DBG_VERBOSE("L2 entry %d: 0x%08x\n", i,
+ (unsigned int)(pte));
+ }
+
+ /* ensure rest of table is empty */
+ while (i < 255)
+ l2table->table_entries[i++] = (pte_t)0;
+
+
+ return ret;
+
+}
+
+/* Remove a L2 table in a WSM container. Afterwards the container may be
+ * released. Assumes the table_lock and the lock is taken. */
+static void unmap_buffers(struct mc_l2_table *table)
+{
+ struct l2table *l2table;
+ int i;
+
+ if (WARN_ON(!table))
+ return;
+
+ /* found the table, now release the resources. */
+ MCDRV_DBG_VERBOSE("clear L2 table, phys_base=%lx, nr_of_pages=%d\n",
+ table->phys, table->pages);
+
+ l2table = table->virt;
+
+ /* release all locked user space pages */
+ for (i = 0; i < table->pages; i++) {
+ /* convert physical entries from L2 table to page pointers */
+ pte_t pte = l2table->table_entries[i];
+ struct page *page = l2_pte_to_page(pte);
+ release_page(page);
+ }
+
+ /* remember that all pages have been freed */
+ table->pages = 0;
+}
+
+/** Delete a used l2 table. Assumes the table_lock and the lock is taken */
+static void unmap_l2_table(struct mc_l2_table *table)
+{
+ /* Check if it's not locked by other processes too! */
+ if (!atomic_dec_and_test(&table->usage))
+ return;
+
+ /* release if Nwd and Swd/MC do no longer use it. */
+ unmap_buffers(table);
+ free_l2_table(table);
+}
+
+int mc_free_l2_table(struct mc_instance *instance, uint32_t handle)
+{
+ struct mc_l2_table *table;
+ int ret = 0;
+
+ if (WARN(!instance, "No instance data available"))
+ return -EFAULT;
+
+ mutex_lock(&mem_ctx.table_lock);
+ table = find_l2_table(handle);
+
+ if (table == NULL) {
+ MCDRV_DBG_VERBOSE("entry not found");
+ ret = -EINVAL;
+ goto err_unlock;
+ }
+ /* TODO: Lock the table! */
+ if (instance != table->owner && !is_daemon(instance)) {
+ MCDRV_DBG_ERROR("instance does no own it");
+ ret = -EPERM;
+ goto err_unlock;
+ }
+ /* free table (if no further locks exist) */
+ unmap_l2_table(table);
+err_unlock:
+ mutex_unlock(&mem_ctx.table_lock);
+
+ return ret;
+}
+
+int mc_lock_l2_table(struct mc_instance *instance, uint32_t handle)
+{
+ int ret = 0;
+ struct mc_l2_table *table = NULL;
+
+ if (WARN(!instance, "No instance data available"))
+ return -EFAULT;
+
+ mutex_lock(&mem_ctx.table_lock);
+ table = find_l2_table(handle);
+
+ if (table == NULL) {
+ MCDRV_DBG_VERBOSE("entry not found %u\n", handle);
+ ret = -EINVAL;
+ goto table_err;
+ }
+ /* TODO: Lock the table! */
+ if (instance != table->owner && !is_daemon(instance)) {
+ MCDRV_DBG_ERROR("instance does no own it\n");
+ ret = -EPERM;
+ goto table_err;
+ }
+
+ /* lock entry */
+ atomic_inc(&table->usage);
+table_err:
+ mutex_unlock(&mem_ctx.table_lock);
+ return ret;
+}
+/** Allocate L2 table and map buffer into it.
+ * That is, create respective table entries.
+ * Must hold Semaphore mem_ctx.wsm_l2_sem */
+struct mc_l2_table *mc_alloc_l2_table(struct mc_instance *instance,
+ struct task_struct *task, void *wsm_buffer, unsigned int wsm_len)
+{
+ int ret = 0;
+ struct mc_l2_table *table;
+
+ if (WARN(!instance, "No instance data available"))
+ return ERR_PTR(-EFAULT);
+
+ mutex_lock(&mem_ctx.table_lock);
+ table = alloc_l2_table(instance);
+ if (IS_ERR(table)) {
+ MCDRV_DBG_ERROR("allocate_used_l2_table() failed\n");
+ ret = -ENOMEM;
+ goto err_no_mem;
+ }
+
+ /* create the L2 page for the WSM */
+ ret = map_buffer(task, wsm_buffer, wsm_len, table);
+
+ if (ret != 0) {
+ MCDRV_DBG_ERROR("map_buffer_into_used_l2_table() failed\n");
+ unmap_l2_table(table);
+ goto err_no_mem;
+ }
+ MCDRV_DBG("mapped buffer %p to table with handle %d @ %lx", wsm_buffer,
+ table->handle, table->phys);
+
+ mutex_unlock(&mem_ctx.table_lock);
+ return table;
+err_no_mem:
+ mutex_unlock(&mem_ctx.table_lock);
+ return ERR_PTR(ret);
+}
+
+uint32_t mc_find_l2_table(struct mc_instance *instance, uint32_t handle)
+{
+ uint32_t ret = 0;
+ struct mc_l2_table *table = NULL;
+
+ if (WARN(!instance, "No instance data available"))
+ return 0;
+
+ mutex_lock(&mem_ctx.table_lock);
+ table = find_l2_table(handle);
+
+ if (table == NULL) {
+ MCDRV_DBG_ERROR("entry not found %u\n", handle);
+ ret = 0;
+ goto table_err;
+ }
+
+ ret = table->phys;
+table_err:
+ mutex_unlock(&mem_ctx.table_lock);
+ return ret;
+}
+
+void mc_clean_l2_tables(void)
+{
+ struct mc_l2_table *table, *tmp;
+
+ mutex_lock(&mem_ctx.table_lock);
+ /* Check if some WSM is orphaned. */
+ list_for_each_entry_safe(table, tmp, &mem_ctx.l2_tables, list) {
+ if (table->owner == NULL) {
+ MCDRV_DBG("clearing orphaned WSM L2: "
+ "physBase=%lx ,nr_of_pages=%d\n",
+ table->phys, table->pages);
+ unmap_l2_table(table);
+ }
+ }
+ mutex_unlock(&mem_ctx.table_lock);
+}
+
+void mc_clear_l2_tables(struct mc_instance *instance)
+{
+ struct mc_l2_table *table, *tmp;
+
+ mutex_lock(&mem_ctx.table_lock);
+ /* Check if some WSM is still in use. */
+ list_for_each_entry_safe(table, tmp, &mem_ctx.l2_tables, list) {
+ if (table->owner == instance) {
+ MCDRV_DBG("trying to release WSM L2: "
+ "physBase=%lx ,nr_of_pages=%d\n",
+ table->phys, table->pages);
+ /* unlock app usage and free or mark it as orphan */
+ table->owner = NULL;
+ unmap_l2_table(table);
+ }
+ }
+ mutex_unlock(&mem_ctx.table_lock);
+}
+
+int mc_init_l2_tables(void)
+{
+ /* init list for WSM L2 chunks. */
+ INIT_LIST_HEAD(&mem_ctx.l2_tables_sets);
+
+ /* L2 table descriptor list. */
+ INIT_LIST_HEAD(&mem_ctx.l2_tables);
+
+ /* L2 table descriptor list. */
+ INIT_LIST_HEAD(&mem_ctx.free_l2_tables);
+
+ mutex_init(&mem_ctx.table_lock);
+
+ return 0;
+}
+
+void mc_release_l2_tables()
+{
+ struct mc_l2_table *table;
+ /* Check if some WSM is still in use. */
+ list_for_each_entry(table, &mem_ctx.l2_tables, list) {
+ WARN(1, "WSM L2 still in use: physBase=%lx ,nr_of_pages=%d\n",
+ table->phys,
+ table->pages);
+ }
+}
diff --git a/drivers/gud/MobiCoreDriver/mem.h b/drivers/gud/MobiCoreDriver/mem.h
new file mode 100644
index 0000000..41bc7fc7
--- /dev/null
+++ b/drivers/gud/MobiCoreDriver/mem.h
@@ -0,0 +1,120 @@
+/** MobiCore driver module.(interface to the secure world SWD)
+ * <!-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ *
+ * 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.
+ */
+
+#ifndef __MC_MEM_H
+#define __MC_MEM_H
+
+#define FREE_FROM_SWD 1
+#define FREE_FROM_NWD 0
+
+#define LOCKED_BY_APP (1U << 0)
+#define LOCKED_BY_MC (1U << 1)
+
+/** MobiCore specific page tables for world shared memory.
+ * Linux uses shadow page tables, see arch/arm/include/asm/pgtable-2level.
+ * MobiCore uses the default ARM format.
+ *
+ * Number of page table entries in one L2 table. This is ARM specific, an
+ * L2 table covers 1 MiB by using 256 entry referring to 4KiB pages each.
+ */
+#define MC_ARM_L2_TABLE_ENTRIES 256
+
+/** ARM level 2 (L2) table with 256 entries. Size: 1k */
+struct l2table {
+ pte_t table_entries[MC_ARM_L2_TABLE_ENTRIES];
+};
+
+/** Number of pages for L2 tables. There are 4 table in each page. */
+#define L2_TABLES_PER_PAGE 4
+
+/** Store for four L2 tables in one 4kb page*/
+struct mc_l2_table_store {
+ struct l2table table[L2_TABLES_PER_PAGE];
+};
+
+/** Usage and maintenance information about mc_l2_table_store */
+struct mc_l2_tables_set {
+ struct list_head list;
+ /**< kernel virtual address */
+ struct mc_l2_table_store *kernel_virt;
+ /**< physical address */
+ struct mc_l2_table_store *phys;
+ /**< pointer to page struct */
+ struct page *page;
+ /**< How many pages from this set are used */
+ atomic_t used_tables;
+};
+
+/**
+ * L2 table allocated to the Daemon or a TLC describing a world shared buffer.
+ * When users map a malloc()ed area into SWd, a L2 table is allocated.
+ * In addition, the area of maximum 1MB virtual address space is mapped into
+ * the L2 table and a handle for this table is returned to the user.
+ */
+struct mc_l2_table {
+ struct list_head list;
+ /** Table lock */
+ struct mutex lock;
+ /** handle as communicated to user mode */
+ unsigned int handle;
+ /** Number of references kept to this l2 table */
+ atomic_t usage;
+ /** owner of this L2 table */
+ struct mc_instance *owner;
+ /** set describing where our L2 table is stored */
+ struct mc_l2_tables_set *set;
+ /** index into L2 table set */
+ unsigned int idx;
+ /** size of buffer */
+ unsigned int pages;
+ /** virtual address*/
+ void *virt;
+ unsigned long phys;
+};
+
+/** MobiCore Driver Memory context data. */
+struct mc_mem_context {
+ struct mc_instance *daemon_inst;
+ /** Backing store for L2 tables */
+ struct list_head l2_tables_sets;
+ /** Bookkeeping for used L2 tables */
+ struct list_head l2_tables;
+ /** Bookkeeping for free L2 tables */
+ struct list_head free_l2_tables;
+ /** semaphore to synchronize access to above lists */
+ struct mutex table_lock;
+};
+
+/* Allocate L2 table and map buffer into it.
+ * That is, create respective table entries. */
+struct mc_l2_table *mc_alloc_l2_table(struct mc_instance *instance,
+ struct task_struct *task, void *wsm_buffer, unsigned int wsm_len);
+
+/* Delete all the l2 tables associated with an instance */
+void mc_clear_l2_tables(struct mc_instance *instance);
+
+/* Release all orphaned L2 tables */
+void mc_clean_l2_tables(void);
+
+/* Delete a used l2 table. */
+int mc_free_l2_table(struct mc_instance *instance, uint32_t handle);
+
+/* Lock a l2 table - the daemon adds +1 to refcount of the L2 table
+ * marking it in use by SWD so it doesn't get released when the TLC dies. */
+int mc_lock_l2_table(struct mc_instance *instance, uint32_t handle);
+/* Unlock l2 table. */
+int mc_unlock_l2_table(struct mc_instance *instance, uint32_t handle);
+/* Return the phys address of l2 table. */
+uint32_t mc_find_l2_table(struct mc_instance *instance, uint32_t handle);
+/* Release all used l2 tables to Linux memory space */
+void mc_release_l2_tables(void);
+
+/* Initialize all l2 tables structure */
+int mc_init_l2_tables(void);
+
+#endif /* __MC_MEM_H */
diff --git a/drivers/gud/MobiCoreDriver/ops.c b/drivers/gud/MobiCoreDriver/ops.c
new file mode 100644
index 0000000..011f565
--- /dev/null
+++ b/drivers/gud/MobiCoreDriver/ops.c
@@ -0,0 +1,206 @@
+/** MobiCore driver module.(interface to the secure world SWD)
+ * @addtogroup MCD_MCDIMPL_KMOD_IMPL
+ * @{
+ * @file
+ * MobiCore Driver Kernel Module.
+ * This module is written as a Linux device driver.
+ * This driver represents the command proxy on the lowest layer, from the
+ * secure world to the non secure world, and vice versa.
+ * This driver is located in the non secure world (Linux).
+ * This driver offers IOCTL commands, for access to the secure world, and has
+ * the interface from the secure world to the normal world.
+ * The access to the driver is possible with a file descriptor,
+ * which has to be created by the fd = open(/dev/mobicore) command.
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ *
+ * 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.
+ */
+
+#include <linux/kthread.h>
+#include <linux/module.h>
+
+#include "main.h"
+#include "fastcall.h"
+#include "ops.h"
+#include "mem.h"
+#include "debug.h"
+
+#define MC_STATUS_HALT 3
+#define SYS_STATE_HALT (4 << 8)
+
+static struct task_struct *fastcall_thread;
+static DEFINE_KTHREAD_WORKER(fastcall_worker);
+
+struct fastcall_work {
+ struct kthread_work work;
+ void *data;
+};
+
+static void fastcall_work_func(struct kthread_work *work)
+{
+ struct fastcall_work *fc_work =
+ container_of(work, struct fastcall_work, work);
+ _smc(fc_work->data);
+}
+
+void mc_fastcall(void *data)
+{
+ struct fastcall_work fc_work = {
+ KTHREAD_WORK_INIT(fc_work.work, fastcall_work_func),
+ .data = data,
+ };
+
+ queue_kthread_work(&fastcall_worker, &fc_work.work);
+ flush_kthread_work(&fc_work.work);
+}
+
+int mc_fastcall_init(void)
+{
+ int ret = 0;
+
+ fastcall_thread = kthread_create(kthread_worker_fn, &fastcall_worker,
+ "mc_fastcall");
+ if (IS_ERR(fastcall_thread)) {
+ ret = PTR_ERR(fastcall_thread);
+ fastcall_thread = NULL;
+ MCDRV_DBG_ERROR("cannot create fastcall wq (%d)\n", ret);
+ return ret;
+ }
+
+ /* this thread MUST run on CPU 0 */
+ kthread_bind(fastcall_thread, 0);
+ wake_up_process(fastcall_thread);
+
+ return 0;
+}
+
+void mc_fastcall_destroy(void)
+{
+ if (!IS_ERR_OR_NULL(fastcall_thread)) {
+ kthread_stop(fastcall_thread);
+ fastcall_thread = NULL;
+ }
+}
+
+int mc_info(uint32_t ext_info_id, uint32_t *state, uint32_t *ext_info)
+{
+ int ret = 0;
+ union mc_fc_info fc_info;
+
+ MCDRV_DBG_VERBOSE("enter\n");
+
+ memset(&fc_info, 0, sizeof(fc_info));
+ fc_info.as_in.cmd = MC_FC_INFO;
+ fc_info.as_in.ext_info_id = ext_info_id;
+
+ MCDRV_DBG("fc_info in cmd=0x%08x, ext_info_id=0x%08x\n",
+ fc_info.as_in.cmd, fc_info.as_in.ext_info_id);
+
+ mc_fastcall(&(fc_info.as_generic));
+
+ MCDRV_DBG("fc_info out resp=0x%08x, ret=0x%08x "
+ "state=0x%08x, ext_info=0x%08x\n",
+ fc_info.as_out.resp,
+ fc_info.as_out.ret,
+ fc_info.as_out.state,
+ fc_info.as_out.ext_info);
+
+ ret = convert_fc_ret(fc_info.as_out.ret);
+
+ *state = fc_info.as_out.state;
+ *ext_info = fc_info.as_out.ext_info;
+
+ if (*state == MC_STATUS_HALT ||
+ (ext_info_id == 1 && (*ext_info & SYS_STATE_HALT))) {
+ MCDRV_DBG_ERROR("MobiCore halt is detected.\n");
+ panic("MobiCore Halt\n");
+ }
+
+ MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
+
+ return ret;
+}
+
+/* Yield to MobiCore */
+int mc_yield(void)
+{
+ int ret = 0;
+ union fc_generic yield;
+
+ MCDRV_DBG_VERBOSE("enter\n");
+
+ memset(&yield, 0, sizeof(yield));
+ yield.as_in.cmd = MC_SMC_N_YIELD;
+ mc_fastcall(&yield);
+ ret = convert_fc_ret(yield.as_out.ret);
+
+ return ret;
+}
+
+/* call common notify */
+int mc_nsiq(void)
+{
+ int ret = 0;
+ union fc_generic nsiq;
+ MCDRV_DBG_VERBOSE("enter\n");
+
+ memset(&nsiq, 0, sizeof(nsiq));
+ nsiq.as_in.cmd = MC_SMC_N_SIQ;
+ mc_fastcall(&nsiq);
+ ret = convert_fc_ret(nsiq.as_out.ret);
+
+ return ret;
+}
+
+/* Call the INIT fastcall to setup MobiCore initialization */
+int mc_init(uint32_t base, uint32_t nq_offset, uint32_t nq_length,
+ uint32_t mcp_offset, uint32_t mcp_length)
+{
+ int ret = 0;
+ union mc_fc_init fc_init;
+
+ MCDRV_DBG_VERBOSE("enter\n");
+
+ memset(&fc_init, 0, sizeof(fc_init));
+
+ fc_init.as_in.cmd = MC_FC_INIT;
+ /* base address of mci buffer 4KB aligned */
+ fc_init.as_in.base = base;
+ /* notification buffer start/length [16:16] [start, length] */
+ fc_init.as_in.nq_info = (nq_offset << 16) | (nq_length & 0xFFFF);
+ /* mcp buffer start/length [16:16] [start, length] */
+ fc_init.as_in.mcp_info = (mcp_offset << 16) | (mcp_length & 0xFFFF);
+
+ /* Set KMOD notification queue to start of MCI
+ * mciInfo was already set up in mmap */
+ MCDRV_DBG("cmd=0x%08x, base=0x%08x,nq_info=0x%08x, mcp_info=0x%08x\n",
+ fc_init.as_in.cmd, fc_init.as_in.base, fc_init.as_in.nq_info,
+ fc_init.as_in.mcp_info);
+
+ mc_fastcall(&fc_init.as_generic);
+
+ MCDRV_DBG("out cmd=0x%08x, ret=0x%08x\n",
+ fc_init.as_out.resp,
+ fc_init.as_out.ret);
+
+ ret = convert_fc_ret(fc_init.as_out.ret);
+
+ MCDRV_DBG_VERBOSE("exit with %d/0x%08X\n", ret, ret);
+
+ return ret;
+}
+
+/* Return MobiCore driver version */
+uint32_t mc_get_version(void)
+{
+ MCDRV_DBG("MobiCore driver version is %i.%i\n",
+ MCDRVMODULEAPI_VERSION_MAJOR,
+ MCDRVMODULEAPI_VERSION_MINOR);
+
+ return MC_VERSION(MCDRVMODULEAPI_VERSION_MAJOR,
+ MCDRVMODULEAPI_VERSION_MINOR);
+}
+/** @} */
diff --git a/drivers/gud/MobiCoreDriver/ops.h b/drivers/gud/MobiCoreDriver/ops.h
new file mode 100644
index 0000000..7633f8d
--- /dev/null
+++ b/drivers/gud/MobiCoreDriver/ops.h
@@ -0,0 +1,27 @@
+/** MobiCore driver module.(interface to the secure world SWD)
+ * <!-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ *
+ * 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.
+ */
+
+#ifndef __MC_OPS_H
+#define __MC_OPS_H
+
+#include <linux/workqueue.h>
+#include "fastcall.h"
+
+int mc_yield(void);
+int mc_nsiq(void);
+uint32_t mc_get_version(void);
+
+int mc_info(uint32_t ext_info_id, uint32_t *state, uint32_t *ext_info);
+int mc_init(uint32_t base, uint32_t nq_offset, uint32_t nq_length,
+ uint32_t mcp_offset, uint32_t mcp_length);
+
+void mc_fastcall(void *data);
+int mc_fastcall_init(void);
+void mc_fastcall_destroy(void);
+
+#endif /* __MC_OPS_H */
diff --git a/drivers/gud/MobiCoreDriver/platforms/EXYNOS_5250_STD/platform.h b/drivers/gud/MobiCoreDriver/platforms/EXYNOS_5250_STD/platform.h
new file mode 100644
index 0000000..bf77050
--- /dev/null
+++ b/drivers/gud/MobiCoreDriver/platforms/EXYNOS_5250_STD/platform.h
@@ -0,0 +1,33 @@
+/**
+ * Header file of MobiCore Driver Kernel Module Platform
+ * specific structures
+ *
+ * @addtogroup MobiCore_Driver_Kernel_Module
+ * @{
+ * Internal structures of the McDrvModule
+ * @file
+ *
+ * Header file the MobiCore Driver Kernel Module,
+ * its internal structures and defines.
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ */
+
+#ifndef _MC_DRV_PLATFORM_H_
+#define _MC_DRV_PLATFORM_H_
+
+#include <mach/irqs.h>
+
+/** MobiCore Interrupt. */
+#define MC_INTR_SSIQ IRQ_SPI(122)
+
+/** Enable mobicore mem traces */
+#define MC_MEM_TRACES
+
+/** Enable Runtime Power Management */
+#ifdef CONFIG_PM_RUNTIME
+ #define MC_PM_RUNTIME
+#endif
+
+#endif /* _MC_DRV_PLATFORM_H_ */
+/** @} */
diff --git a/drivers/gud/MobiCoreDriver/pm.c b/drivers/gud/MobiCoreDriver/pm.c
new file mode 100644
index 0000000..102743b
--- /dev/null
+++ b/drivers/gud/MobiCoreDriver/pm.c
@@ -0,0 +1,127 @@
+/** MobiCore driver module.(interface to the secure world SWD)
+ * @addtogroup MCD_MCDIMPL_KMOD_IMPL
+ * @{
+ * @file
+ * MobiCore Driver Kernel Module.
+ * This module is written as a Linux device driver.
+ * This driver represents the command proxy on the lowest layer, from the
+ * secure world to the non secure world, and vice versa.
+ * This driver is located in the non secure world (Linux).
+ * This driver offers IOCTL commands, for access to the secure world, and has
+ * the interface from the secure world to the normal world.
+ * The access to the driver is possible with a file descriptor,
+ * which has to be created by the fd = open(/dev/mobicore) command.
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ *
+ * 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.
+ */
+#include <linux/module.h>
+#include <linux/timer.h>
+#include <linux/suspend.h>
+
+
+#include "pm.h"
+#include "main.h"
+#include "fastcall.h"
+#include "ops.h"
+#include "logging.h"
+#include "debug.h"
+
+#ifdef MC_PM_RUNTIME
+
+static struct mc_context *ctx;
+
+static struct timer_list resume_timer;
+
+static void mc_resume_handler(unsigned long data)
+{
+ if (!ctx->mcp)
+ return;
+
+ ctx->mcp->flags.sleep_mode.SleepReq = 0;
+}
+
+static void mc_suspend_handler(struct work_struct *work)
+{
+ if (!ctx->mcp)
+ return;
+ ctx->mcp->flags.sleep_mode.SleepReq = REQ_TO_SLEEP;
+ mc_nsiq();
+}
+DECLARE_WORK(suspend_work, mc_suspend_handler);
+
+static inline void dump_sleep_params(struct mc_flags *flags)
+{
+ MCDRV_DBG("MobiCore IDLE=%d!", flags->schedule);
+ MCDRV_DBG("MobiCore Request Sleep=%d!", flags->sleep_mode.SleepReq);
+ MCDRV_DBG("MobiCore Sleep Ready=%d!", flags->sleep_mode.ReadyToSleep);
+}
+
+static int mc_suspend_notifier(struct notifier_block *nb,
+ unsigned long event, void *dummy)
+{
+ struct mc_mcp_buffer *mcp = ctx->mcp;
+ /* We have noting to say if MobiCore is not initialized */
+ if (!mcp)
+ return 0;
+
+#ifdef MC_MEM_TRACES
+ mobicore_log_read();
+#endif
+
+ switch (event) {
+ case PM_SUSPEND_PREPARE:
+ /* Make sure we have finished all the work otherwise
+ * we end up in a race condition */
+ mod_timer(&resume_timer, 0);
+ cancel_work_sync(&suspend_work);
+ /* We can't go to sleep if MobiCore is not IDLE
+ * or not Ready to sleep */
+ dump_sleep_params(&mcp->flags);
+ if (!(mcp->flags.sleep_mode.ReadyToSleep & READY_TO_SLEEP)) {
+ schedule_work_on(0, &suspend_work);
+ dump_sleep_params(&mcp->flags);
+ MCDRV_DBG_ERROR("MobiCore can't SLEEP yet!");
+ return NOTIFY_BAD;
+ }
+ break;
+ case PM_POST_SUSPEND:
+ MCDRV_DBG("Resume MobiCore system!");
+ mod_timer(&resume_timer, jiffies +
+ msecs_to_jiffies(DAEMON_BACKOFF_TIME));
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static struct notifier_block mc_notif_block = {
+ .notifier_call = mc_suspend_notifier,
+};
+
+int mc_pm_initialize(struct mc_context *context)
+{
+ int ret = 0;
+
+ ctx = context;
+ setup_timer(&resume_timer, mc_resume_handler, 0);
+ ret = register_pm_notifier(&mc_notif_block);
+ if (ret)
+ MCDRV_DBG_ERROR("device pm register failed\n");
+ return ret;
+}
+
+int mc_pm_free(void)
+{
+ int ret = unregister_pm_notifier(&mc_notif_block);
+ if (ret)
+ MCDRV_DBG_ERROR("device pm unregister failed\n");
+ del_timer(&resume_timer);
+ return ret;
+}
+
+#endif /* MC_PM_RUNTIME */
diff --git a/drivers/gud/MobiCoreDriver/pm.h b/drivers/gud/MobiCoreDriver/pm.h
new file mode 100644
index 0000000..3fc5f7b
--- /dev/null
+++ b/drivers/gud/MobiCoreDriver/pm.h
@@ -0,0 +1,39 @@
+/**
+ * Header file of MobiCore Driver Kernel Module.
+ *
+ * @addtogroup MCD_MCDIMPL_KMOD_IMPL
+ * @{
+ * Internal structures of the McDrvModule
+ * @file
+ *
+ * Header file the MobiCore Driver Kernel Module,
+ * its internal structures and defines.
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ *
+ * 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.
+ */
+
+#ifndef _MC_PM_H_
+#define _MC_PM_H_
+
+#include "main.h"
+
+#define NO_SLEEP_REQ 0
+#define REQ_TO_SLEEP 1
+
+#define NORMAL_EXECUTION 0
+#define READY_TO_SLEEP 1
+
+/* How much time after resume the daemon should backoff */
+#define DAEMON_BACKOFF_TIME 1000
+
+/* Initialize Power Management */
+int mc_pm_initialize(struct mc_context *context);
+/* Free all Power Management resources*/
+int mc_pm_free(void);
+
+#endif /* _MC_PM_H_ */
+/** @} */
diff --git a/drivers/gud/MobiCoreDriver/public/mc_kernel_api.h b/drivers/gud/MobiCoreDriver/public/mc_kernel_api.h
new file mode 100644
index 0000000..03e6062
--- /dev/null
+++ b/drivers/gud/MobiCoreDriver/public/mc_kernel_api.h
@@ -0,0 +1,81 @@
+/** @addtogroup MCD_MCDIMPL_KMOD_KAPI Mobicore Driver Module API inside Kernel.
+ * @ingroup MCD_MCDIMPL_KMOD
+ * @{
+ * Interface to Mobicore Driver Kernel Module inside Kernel.
+ * @file
+ *
+ * Interface to be used by module MobiCoreKernelAPI.
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2010-2012 -->
+ *
+ * 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.
+ */
+
+#ifndef _MOBICORE_KERNELMODULE_API_H_
+#define _MOBICORE_KERNELMODULE_API_H_
+
+struct mc_instance;
+
+/**
+ * Initialize a new mobicore API instance object
+ *
+ * @return Instance or NULL if no allocation was possible.
+ */
+struct mc_instance *mobicore_open(void);
+
+/**
+ * Release a mobicore instance object and all objects related to it
+ * @param instance instance
+ * @return 0 if Ok or -E ERROR
+ */
+int mobicore_release(struct mc_instance *instance);
+
+/**
+ * Free a WSM buffer allocated with mobicore_allocate_wsm
+ * @param instance
+ * @param handle handle of the buffer
+ *
+ * @return 0 if no error
+ *
+ */
+int mobicore_allocate_wsm(struct mc_instance *instance,
+ unsigned long requested_size, uint32_t *handle, void **virt_kernel_addr,
+ void **phys_addr);
+
+/**
+ * Free a WSM buffer allocated with mobicore_allocate_wsm
+ * @param instance
+ * @param handle handle of the buffer
+ *
+ * @return 0 if no error
+ *
+ */
+int mobicore_free_wsm(struct mc_instance *instance, uint32_t handle);
+
+/**
+ * Map a virtual memory buffer structure to Mobicore
+ * @param instance
+ * @param addr address of the buffer(NB it must be kernel virtual!)
+ * @param len buffer length
+ * @param handle pointer to handle
+ * @param phys pointer to physical L2 table(?)
+ *
+ * @return 0 if no error
+ *
+ */
+int mobicore_map_vmem(struct mc_instance *instance, void *addr,
+ uint32_t len, uint32_t *handle, uint32_t *phys);
+
+/**
+ * Unmap a virtual memory buffer from mobicore
+ * @param instance
+ * @param handle
+ *
+ * @return 0 if no error
+ *
+ */
+int mobicore_unmap_vmem(struct mc_instance *instance, uint32_t handle);
+#endif /* _MOBICORE_KERNELMODULE_API_H_ */
+/** @} */
diff --git a/drivers/gud/MobiCoreDriver/public/mc_linux.h b/drivers/gud/MobiCoreDriver/public/mc_linux.h
new file mode 100644
index 0000000..a8df4ce
--- /dev/null
+++ b/drivers/gud/MobiCoreDriver/public/mc_linux.h
@@ -0,0 +1,227 @@
+/** @addtogroup MCD_MCDIMPL_KMOD_API Mobicore Driver Module API
+ * @ingroup MCD_MCDIMPL_KMOD
+ * @{
+ * Interface to Mobicore Driver Kernel Module.
+ * @file
+ *
+ * <h2>Introduction</h2>
+ * The MobiCore Driver Kernel Module is a Linux device driver, which represents
+ * the command proxy on the lowest layer to the secure world (Swd). Additional
+ * services like memory allocation via mmap and generation of a L2 tables for
+ * given virtual memory are also supported. IRQ functionallity receives
+ * information from the SWd in the non secure world (NWd).
+ * As customary the driver is handled as linux device driver with "open",
+ * "close" and "ioctl" commands. Access to the driver is possible after the
+ * device "/dev/mobicore" has been opened.
+ * The MobiCore Driver Kernel Module must be installed via
+ * "insmod mcDrvModule.ko".
+ *
+ *
+ * <h2>Version history</h2>
+ * <table class="customtab">
+ * <tr><td width="100px"><b>Date</b></td><td width="80px"><b>Version</b></td>
+ * <td><b>Changes</b></td></tr>
+ * <tr><td>2010-05-25</td><td>0.1</td><td>Initial Release</td></tr>
+ * </table>
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2010-2012 -->
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _MC_LINUX_H_
+#define _MC_LINUX_H_
+
+#include "version.h"
+
+#define MC_ADMIN_DEVNODE "mobicore"
+#define MC_USER_DEVNODE "mobicore-user"
+
+/**
+ * Data exchange structure of the MC_DRV_MODULE_INIT ioctl command.
+ * INIT request data to SWD
+ */
+struct mc_ioctl_init {
+ /** notification buffer start/length [16:16] [start, length] */
+ uint32_t nq_offset;
+ /** length of notification queue */
+ uint32_t nq_length;
+ /** mcp buffer start/length [16:16] [start, length] */
+ uint32_t mcp_offset;
+ /** length of mcp buffer */
+ uint32_t mcp_length;
+};
+
+
+/**
+ * Data exchange structure of the MC_DRV_MODULE_INFO ioctl command.
+ * INFO request data to the SWD
+ */
+struct mc_ioctl_info {
+ uint32_t ext_info_id; /**< extended info ID */
+ uint32_t state; /**< state */
+ uint32_t ext_info; /**< extended info */
+};
+
+/**
+ * Mmap allocates and maps contiguous memory into a process.
+ * We use the third parameter, void *offset, to distinguish between some cases
+ * offset = MC_DRV_KMOD_MMAP_WSM usual operation, pages are registered in
+ * device structure and freed later.
+ * offset = MC_DRV_KMOD_MMAP_MCI get Instance of MCI, allocates or mmaps
+ * the MCI to daemon
+ *
+ * In mmap(), the offset specifies which of several device I/O pages is
+ * requested. Linux only transfers the page number, i.e. the upper 20 bits to
+ * kernel module. Therefore we define our special offsets as multiples of page
+ * size.
+ */
+struct mc_ioctl_map {
+ size_t len; /**< Buffer length */
+ uint32_t handle; /**< WSM handle */
+ unsigned long addr; /**< Virtual address */
+ unsigned long phys_addr; /**< physical address of WSM (or NULL) */
+ bool reused; /**< if WSM memory was reused, or new allocated */
+};
+
+/**
+ * Data exchange structure of the MC_IO_REG_WSM command.
+ *
+ * Allocates a physical L2 table and maps the buffer into this page.
+ * Returns the physical address of the L2 table.
+ * The page alignment will be created and the appropriated pSize and pOffsetL2
+ * will be modified to the used values.
+ */
+struct mc_ioctl_reg_wsm {
+ uint32_t buffer; /**< base address of the virtual address */
+ uint32_t len; /**< size of the virtual address space */
+ uint32_t pid; /**< process id */
+ uint32_t handle; /**< driver handle for locked memory */
+ uint32_t table_phys; /**< physical address of the L2 table */
+};
+
+
+/**
+ * Data exchange structure of the MC_DRV_MODULE_FC_EXECUTE ioctl command.
+ * internal, unsupported
+ */
+struct mc_ioctl_execute {
+ /**< base address of mobicore binary */
+ uint32_t phys_start_addr;
+ /**< length of DDR area */
+ uint32_t length;
+};
+
+/**
+ * Data exchange structure of the MC_IO_RESOLVE_CONT_WSM ioctl command.
+ */
+struct mc_ioctl_resolv_cont_wsm {
+ /**< driver handle for buffer */
+ uint32_t handle;
+ /**< base address of memory */
+ uint32_t phys;
+ /**< length memory */
+ uint32_t length;
+};
+
+
+/* @defgroup Mobicore_Driver_Kernel_Module_Interface IOCTL */
+
+
+/**
+ * defines for the ioctl mobicore driver module function call from user space.
+ */
+/* MobiCore IOCTL magic number */
+#define MC_IOC_MAGIC 'M'
+
+#define MC_IO_INIT _IOWR(MC_IOC_MAGIC, 0, struct mc_ioctl_init)
+#define MC_IO_INFO _IOWR(MC_IOC_MAGIC, 1, struct mc_ioctl_info)
+#define MC_IO_VERSION _IOR(MC_IOC_MAGIC, 2, uint32_t)
+/**
+ * ioctl parameter to send the YIELD command to the SWD.
+ * Only possible in Privileged Mode.
+ * ioctl(fd, MC_DRV_MODULE_YIELD)
+ */
+#define MC_IO_YIELD _IO(MC_IOC_MAGIC, 3)
+/**
+ * ioctl parameter to send the NSIQ signal to the SWD.
+ * Only possible in Privileged Mode
+ * ioctl(fd, MC_DRV_MODULE_NSIQ)
+ */
+#define MC_IO_NSIQ _IO(MC_IOC_MAGIC, 4)
+/**
+ * Free's memory which is formerly allocated by the driver's mmap
+ * command. The parameter must be this mmaped address.
+ * The internal instance data regarding to this address are deleted as
+ * well as each according memory page and its appropriated reserved bit
+ * is cleared (ClearPageReserved).
+ * Usage: ioctl(fd, MC_DRV_MODULE_FREE, &address) with address beeing of
+ * type long address
+ */
+#define MC_IO_FREE _IO(MC_IOC_MAGIC, 5)
+/**
+ * Creates a L2 Table of the given base address and the size of the
+ * data.
+ * Parameter: mc_ioctl_app_reg_wsm_l2_params
+ */
+#define MC_IO_REG_WSM _IOWR(MC_IOC_MAGIC, 6, struct mc_ioctl_reg_wsm)
+#define MC_IO_UNREG_WSM _IO(MC_IOC_MAGIC, 7)
+#define MC_IO_LOCK_WSM _IO(MC_IOC_MAGIC, 8)
+#define MC_IO_UNLOCK_WSM _IO(MC_IOC_MAGIC, 9)
+#define MC_IO_EXECUTE _IOWR(MC_IOC_MAGIC, 10, struct mc_ioctl_execute)
+
+/**
+ * Mmap allocates and maps contiguous memory into a process.
+ * MC_DRV_KMOD_MMAP_WSM usual operation, pages are registered in
+ * device structure and freed later.
+ * MC_DRV_KMOD_MMAP_MCI get Instance of MCI, allocates or mmaps
+ * the MCI to daemon
+ * MC_DRV_KMOD_MMAP_PERSISTENTWSM special operation, without
+ * registration of pages
+ */
+#define MC_IO_MAP_WSM _IOWR(MC_IOC_MAGIC, 11, struct mc_ioctl_map)
+#define MC_IO_MAP_MCI _IOWR(MC_IOC_MAGIC, 12, struct mc_ioctl_map)
+#define MC_IO_MAP_PWSM _IOWR(MC_IOC_MAGIC, 13, struct mc_ioctl_map)
+
+/**
+ * Clean orphaned WSM buffers. Only available to the daemon and should
+ * only be carried out if the TLC crashes or otherwise calls exit() in
+ * an unexpected manner.
+ * The clean is needed toghether with the lock/unlock mechanism so the daemon
+ * has clear control of the mapped buffers so it can close a truslet before
+ * release all the WSM buffers, otherwise the trustlet would be able to write
+ * to possibly kernel memory areas */
+#define MC_IO_CLEAN_WSM _IO(MC_IOC_MAGIC, 14)
+
+/** Get L2 phys address of a buffer handle allocated to the user. Only
+ * available to the daemon */
+#define MC_IO_RESOLVE_WSM _IOWR(MC_IOC_MAGIC, 15, uint32_t)
+
+/** Get the phys address & len of a allocated contiguous buffer. Only available
+ * to the daemon */
+#define MC_IO_RESOLVE_CONT_WSM _IOWR(MC_IOC_MAGIC, 16, struct mc_ioctl_execute)
+
+#endif /* _MC_LINUX_H_ */
+/** @} */
diff --git a/drivers/gud/MobiCoreDriver/public/version.h b/drivers/gud/MobiCoreDriver/public/version.h
new file mode 100644
index 0000000..d01e991
--- /dev/null
+++ b/drivers/gud/MobiCoreDriver/public/version.h
@@ -0,0 +1,36 @@
+/** @addtogroup MCD_MCDIMPL_KMOD
+ * @{
+ * <!-- Copyright Giesecke & Devrient GmbH 2010-2012 -->
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _MC_DRV_VERSION_H_
+#define _MC_DRV_VERSION_H_
+
+#define MCDRVMODULEAPI_VERSION_MAJOR 1
+#define MCDRVMODULEAPI_VERSION_MINOR 1
+
+#endif /* _MC_DRV_VERSION_H_ */
diff --git a/drivers/gud/MobiCoreKernelApi/Makefile b/drivers/gud/MobiCoreKernelApi/Makefile
new file mode 100644
index 0000000..774a599
--- /dev/null
+++ b/drivers/gud/MobiCoreKernelApi/Makefile
@@ -0,0 +1,35 @@
+#
+# this makefile is called from the kernel make syste
+ifeq ($(MODE),release)
+ EXTRA_CFLAGS+=-O2 -DNDEBUG
+else # DEBUG
+ # "-O" is needed to expand inlines
+ EXTRA_CFLAGS+=-O -g3 -DDEBUG
+endif # DEBUG/RELEASE
+
+ifdef MOBICORE_CFLAGS
+ EXTRA_CFLAGS+=$(MOBICORE_CFLAGS)
+endif
+
+#Set the extra symbols
+ifdef MCDRV_SYMBOLS_FILE
+ KBUILD_EXTRA_SYMBOLS=$(MCDRV_SYMBOLS_FILE)
+endif
+
+#EXTRA_CFLAGS += -DDEBUG -DDEBUG_VERBOSE
+EXTRA_CFLAGS += -Wno-declaration-after-statement
+# add our module to kernel.
+obj-m += mcKernelApi.o
+
+mcKernelApi-objs := main.o clientlib.o device.o session.o connection.o
+
+clean:
+ rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions \
+ Module.markers Module.symvers modules.order
+
+depend .depend dep:
+ $(CC) $(CFLAGS) -M *.c > .depend
+
+ifeq (.depend,$(wildcard .depend))
+ include .depend
+endif
diff --git a/drivers/gud/MobiCoreKernelApi/clientlib.c b/drivers/gud/MobiCoreKernelApi/clientlib.c
new file mode 100644
index 0000000..0b727dc
--- /dev/null
+++ b/drivers/gud/MobiCoreKernelApi/clientlib.c
@@ -0,0 +1,1085 @@
+/**
+ * MobiCore KernelApi module
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ *
+ * 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.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/netlink.h>
+#include <net/sock.h>
+#include <net/net_namespace.h>
+#include <linux/list.h>
+
+#include "public/mobicore_driver_api.h"
+#include "public/mobicore_driver_cmd.h"
+#include "include/mcinq.h"
+#include "device.h"
+#include "session.h"
+
+/* device list */
+LIST_HEAD(devices);
+
+static struct mcore_device_t *resolve_device_id(
+ uint32_t device_id
+) {
+ struct mcore_device_t *tmp;
+ struct list_head *pos;
+
+ /* Get mcore_device_t for device_id */
+ list_for_each(pos, &devices) {
+ tmp = list_entry(pos, struct mcore_device_t, list);
+ if (tmp->device_id == device_id)
+ return tmp;
+ }
+ return NULL;
+}
+
+static void add_device(
+ struct mcore_device_t *device
+) {
+ list_add_tail(&(device->list), &devices);
+}
+
+static bool remove_device(
+ uint32_t device_id
+) {
+ struct mcore_device_t *tmp;
+ struct list_head *pos, *q;
+
+ list_for_each_safe(pos, q, &devices) {
+ tmp = list_entry(pos, struct mcore_device_t, list);
+ if (tmp->device_id == device_id) {
+ list_del(pos);
+ mcore_device_cleanup(tmp);
+ return true;
+ }
+ }
+ return false;
+}
+
+enum mc_result mc_open_device(
+ uint32_t device_id
+) {
+ enum mc_result mc_result = MC_DRV_OK;
+ struct connection *dev_con = NULL;
+
+ MCDRV_DBG_VERBOSE("===%s()===", __func__);
+
+ /* Enter critical section */
+
+ do {
+ struct mcore_device_t *device = resolve_device_id(device_id);
+ if (device != NULL) {
+ MCDRV_DBG_ERROR("Device %d already opened", device_id);
+ mc_result = MC_DRV_ERR_INVALID_OPERATION;
+ break;
+ }
+
+ /* Open new connection to device */
+ dev_con = connection_new();
+ if (!connection_connect(dev_con, MC_DAEMON_PID)) {
+ MCDRV_DBG_ERROR(
+ "Could not setup netlink connection to PID %u",
+ MC_DAEMON_PID);
+ mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
+ break;
+ }
+
+ /* Forward device open to the daemon and read result */
+ struct mc_drv_cmd_open_device_t mc_drv_cmd_open_device = {
+ /* C++ does not support C99 designated initializers */
+ /* .header = */ {
+ /* .command_id = */ MC_DRV_CMD_OPEN_DEVICE
+ },
+ /* .payload = */ {
+ /* .device_id = */ device_id
+ }
+ };
+
+ int len = connection_write_data(
+ dev_con,
+ &mc_drv_cmd_open_device,
+ sizeof(struct mc_drv_cmd_open_device_t));
+ if (len < 0) {
+ MCDRV_DBG_ERROR("CMD_OPEN_DEVICE writeCmd failed "
+ "ret=%d", len);
+ mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
+ break;
+ }
+
+ struct mc_drv_response_header_t rsp_header;
+ len = connection_read_datablock(
+ dev_con,
+ &rsp_header,
+ sizeof(rsp_header));
+ if (len != sizeof(rsp_header)) {
+ MCDRV_DBG_ERROR("CMD_OPEN_DEVICE readRsp failed "
+ "ret=%d", len);
+ mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
+ break;
+ }
+ if (rsp_header.response_id != MC_DRV_RSP_OK) {
+ MCDRV_DBG_ERROR("CMD_OPEN_DEVICE failed, respId=%d",
+ rsp_header.response_id);
+ switch (rsp_header.response_id) {
+ case MC_DRV_RSP_PAYLOAD_LENGTH_ERROR:
+ mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
+ break;
+ case MC_DRV_INVALID_DEVICE_NAME:
+ mc_result = MC_DRV_ERR_UNKNOWN_DEVICE;
+ break;
+ case MC_DRV_RSP_DEVICE_ALREADY_OPENED:
+ default:
+ mc_result = MC_DRV_ERR_INVALID_OPERATION;
+ break;
+ }
+ break;
+ }
+
+ /* there is no payload to read */
+
+ device = mcore_device_create(device_id, dev_con);
+ if (!mcore_device_open(device, MC_DRV_MOD_DEVNODE_FULLPATH)) {
+ mcore_device_cleanup(device);
+ MCDRV_DBG_ERROR("could not open device file: %s",
+ MC_DRV_MOD_DEVNODE_FULLPATH);
+ mc_result = MC_DRV_ERR_INVALID_DEVICE_FILE;
+ break;
+ }
+
+ add_device(device);
+
+ } while (false);
+
+ if (mc_result != MC_DRV_OK)
+ connection_cleanup(dev_con);
+
+ /* Exit critical section */
+
+ return mc_result;
+}
+EXPORT_SYMBOL(mc_open_device);
+
+enum mc_result mc_close_device(
+ uint32_t device_id
+) {
+ enum mc_result mc_result = MC_DRV_OK;
+
+ MCDRV_DBG_VERBOSE("===%s()===", __func__);
+
+ /* Enter critical section */
+ do {
+ struct mcore_device_t *device = resolve_device_id(device_id);
+ if (device == NULL) {
+ MCDRV_DBG_ERROR("Device not found");
+ mc_result = MC_DRV_ERR_UNKNOWN_DEVICE;
+ break;
+ }
+ struct connection *dev_con = device->connection;
+
+ /* Return if not all sessions have been closed */
+ if (mcore_device_has_sessions(device)) {
+ MCDRV_DBG_ERROR("cannot close with sessions pending");
+ mc_result = MC_DRV_ERR_SESSION_PENDING;
+ break;
+ }
+
+ struct mc_drv_cmd_close_device_t mc_drv_cmd_close_device = {
+ /* C++ does not support C99 designated initializers */
+ /* .header = */ {
+ /* .command_id = */ MC_DRV_CMD_CLOSE_DEVICE
+ }
+ };
+ int len = connection_write_data(
+ dev_con,
+ &mc_drv_cmd_close_device,
+ sizeof(struct mc_drv_cmd_close_device_t));
+ /* ignore error, but log details */
+ if (len < 0) {
+ MCDRV_DBG_ERROR("CMD_CLOSE_DEVICE writeCmd failed "
+ "ret=%d", len);
+ mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
+ }
+
+ struct mc_drv_response_header_t rsp_header;
+ len = connection_read_datablock(
+ dev_con,
+ &rsp_header,
+ sizeof(rsp_header));
+ if (len != sizeof(rsp_header)) {
+ MCDRV_DBG_ERROR("CMD_CLOSE_DEVICE readResp failed "
+ " ret=%d", len);
+ mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
+ break;
+ }
+
+ if (rsp_header.response_id != MC_DRV_RSP_OK) {
+ MCDRV_DBG_ERROR("CMD_CLOSE_DEVICE failed, respId=%d",
+ rsp_header.response_id);
+ mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
+ break;
+ }
+
+ remove_device(device_id);
+
+ } while (false);
+
+ /* Exit critical section */
+
+ return mc_result;
+}
+EXPORT_SYMBOL(mc_close_device);
+
+enum mc_result mc_open_session(
+ struct mc_session_handle *session,
+ const struct mc_uuid_t *uuid,
+ uint8_t *tci,
+ uint32_t len
+) {
+ enum mc_result mc_result = MC_DRV_OK;
+
+ MCDRV_DBG_VERBOSE("===%s()===", __func__);
+
+ /* Enter critical section */
+
+ do {
+ if (session == NULL) {
+ MCDRV_DBG_ERROR("Session is null");
+ mc_result = MC_DRV_ERR_INVALID_PARAMETER;
+ break;
+ }
+ if (uuid == NULL) {
+ MCDRV_DBG_ERROR("UUID is null");
+ mc_result = MC_DRV_ERR_INVALID_PARAMETER;
+ break;
+ }
+ if (tci == NULL) {
+ MCDRV_DBG_ERROR("TCI is null");
+ mc_result = MC_DRV_ERR_INVALID_PARAMETER;
+ break;
+ }
+ if (len > MC_MAX_TCI_LEN) {
+ MCDRV_DBG_ERROR("TCI length is longer than %d",
+ MC_MAX_TCI_LEN);
+ mc_result = MC_DRV_ERR_INVALID_PARAMETER;
+ break;
+ }
+
+ /* Get the device associated with the given session */
+ struct mcore_device_t *device =
+ resolve_device_id(session->device_id);
+ if (device == NULL) {
+ MCDRV_DBG_ERROR("Device not found");
+ mc_result = MC_DRV_ERR_UNKNOWN_DEVICE;
+ break;
+ }
+ struct connection *dev_con = device->connection;
+
+ /* Get the physical address of the given TCI */
+ struct wsm *wsm =
+ mcore_device_find_contiguous_wsm(device, tci);
+ if (wsm == NULL) {
+ MCDRV_DBG_ERROR("Could not resolve TCI phy address ");
+ mc_result = MC_DRV_ERR_INVALID_PARAMETER;
+ break;
+ }
+
+ if (wsm->len < len) {
+ MCDRV_DBG_ERROR("length is more than allocated TCI");
+ mc_result = MC_DRV_ERR_INVALID_PARAMETER;
+ break;
+ }
+
+ /* Prepare open session command */
+ struct mc_drv_cmd_open_session_t cmdOpenSession = {
+ /* C++ does not support C99 designated initializers */
+ /* .header = */ {
+ /* .command_id = */ MC_DRV_CMD_OPEN_SESSION
+ },
+ /* .payload = */ {
+ /* .device_id = */ session->device_id,
+ /* .uuid = */ *uuid,
+ /* .tci = */ (uint32_t)wsm->phys_addr,
+ /* .len = */ len
+ }
+ };
+
+ /* Transmit command data */
+
+ int len = connection_write_data(
+ dev_con,
+ &cmdOpenSession,
+ sizeof(cmdOpenSession));
+ if (len != sizeof(cmdOpenSession)) {
+ MCDRV_DBG_ERROR("CMD_OPEN_SESSION writeData failed "
+ "ret=%d", len);
+ mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
+ break;
+ }
+
+ /* Read command response */
+
+ /* read header first */
+ struct mc_drv_response_header_t rsp_header;
+ len = connection_read_datablock(
+ dev_con,
+ &rsp_header,
+ sizeof(rsp_header));
+ if (len != sizeof(rsp_header)) {
+ MCDRV_DBG_ERROR("CMD_OPEN_SESSION readResp failed "
+ " ret=%d", len);
+ mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
+ break;
+ }
+
+ if (rsp_header.response_id != MC_DRV_RSP_OK) {
+ MCDRV_DBG_ERROR("CMD_OPEN_SESSION failed, respId=%d",
+ rsp_header.response_id);
+ switch (rsp_header.response_id) {
+ case MC_DRV_RSP_TRUSTLET_NOT_FOUND:
+ mc_result = MC_DRV_ERR_INVALID_DEVICE_FILE;
+ break;
+ case MC_DRV_RSP_PAYLOAD_LENGTH_ERROR:
+ case MC_DRV_RSP_DEVICE_NOT_OPENED:
+ case MC_DRV_RSP_FAILED:
+ default:
+ mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
+ break;
+ }
+ break;
+ }
+
+ /* read payload */
+ struct mc_drv_rsp_open_session_payload_t
+ rsp_open_session_payload;
+ len = connection_read_datablock(
+ dev_con,
+ &rsp_open_session_payload,
+ sizeof(rsp_open_session_payload));
+ if (len != sizeof(rsp_open_session_payload)) {
+ MCDRV_DBG_ERROR("CMD_OPEN_SESSION readPayload failed "
+ "ret=%d", len);
+ mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
+ break;
+ }
+
+ /* Register session with handle */
+ session->session_id = rsp_open_session_payload.session_id;
+
+ /* Set up second channel for notifications */
+ struct connection *session_connection = connection_new();
+ /*TODO: no real need to connect here? */
+ if (!connection_connect(session_connection, MC_DAEMON_PID)) {
+ MCDRV_DBG_ERROR(
+ "Could not setup netlink connection to PID %u",
+ MC_DAEMON_PID);
+ connection_cleanup(session_connection);
+ mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
+ break;
+ }
+
+ /*TODO CONTINOUE HERE !!!! FIX RW RETURN HANDLING!!!! */
+
+ /* Write command to use channel for notifications */
+ struct mc_drv_cmd_nqconnect_t cmd_nqconnect = {
+ /* C++ does not support C99 designated initializers */
+ /* .header = */ {
+ /* .command_id = */ MC_DRV_CMD_NQ_CONNECT
+ },
+ /* .payload = */ {
+ /* .device_id = */ session->device_id,
+ /* .session_id = */ session->session_id,
+ /* .device_session_id = */
+ rsp_open_session_payload.device_session_id,
+ /* .session_magic = */
+ rsp_open_session_payload.session_magic
+ }
+ };
+ connection_write_data(session_connection,
+ &cmd_nqconnect,
+ sizeof(cmd_nqconnect));
+
+ /* Read command response, header first */
+ len = connection_read_datablock(
+ session_connection,
+ &rsp_header,
+ sizeof(rsp_header));
+ if (len != sizeof(rsp_header)) {
+ MCDRV_DBG_ERROR("CMD_NQ_CONNECT readRsp failed "
+ "ret=%d", len);
+ connection_cleanup(session_connection);
+ mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
+ break;
+ }
+
+ if (rsp_header.response_id != MC_DRV_RSP_OK) {
+ MCDRV_DBG_ERROR("CMD_NQ_CONNECT failed, respId=%d",
+ rsp_header.response_id);
+ connection_cleanup(session_connection);
+ mc_result = MC_DRV_ERR_NQ_FAILED;
+ break;
+ }
+
+ /* there is no payload. */
+
+ /* Session established, new session object must be created */
+ mcore_device_create_new_session(
+ device,
+ session->session_id,
+ session_connection);
+
+ } while (false);
+
+ /* Exit critical section */
+
+ return mc_result;
+}
+EXPORT_SYMBOL(mc_open_session);
+
+enum mc_result mc_close_session(
+ struct mc_session_handle *session
+) {
+ enum mc_result mc_result = MC_DRV_OK;
+
+ MCDRV_DBG_VERBOSE("===%s()===", __func__);
+
+ /* Enter critical section */
+
+ do {
+ if (session == NULL) {
+ MCDRV_DBG_ERROR("Session is null");
+ mc_result = MC_DRV_ERR_INVALID_PARAMETER;
+ break;
+ }
+
+ struct mcore_device_t *device =
+ resolve_device_id(session->device_id);
+ if (device == NULL) {
+ MCDRV_DBG_ERROR("Device not found");
+ mc_result = MC_DRV_ERR_UNKNOWN_DEVICE;
+ break;
+ }
+ struct connection *dev_con = device->connection;
+
+ struct session *nq_session =
+ mcore_device_resolve_session_id(device, session->session_id);
+ if (nq_session == NULL) {
+ MCDRV_DBG_ERROR("Session not found");
+ mc_result = MC_DRV_ERR_UNKNOWN_SESSION;
+ break;
+ }
+
+ /* Write close session command */
+ struct mc_drv_cmd_close_session_t cmd_close_session = {
+ /* C++ does not support C99 designated initializers */
+ /* .header = */ {
+ /* .command_id = */ MC_DRV_CMD_CLOSE_SESSION
+ },
+ /* .payload = */ {
+ /* .session_id = */ session->session_id,
+ }
+ };
+ connection_write_data(
+ dev_con,
+ &cmd_close_session,
+ sizeof(cmd_close_session));
+
+ /* Read command response */
+ struct mc_drv_response_header_t rsp_header;
+ int len = connection_read_datablock(
+ dev_con,
+ &rsp_header,
+ sizeof(rsp_header));
+ if (len != sizeof(rsp_header)) {
+ MCDRV_DBG_ERROR("CMD_CLOSE_SESSION readRsp failed "
+ "ret=%d", len);
+ mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
+ break;
+ }
+
+ if (rsp_header.response_id != MC_DRV_RSP_OK) {
+ MCDRV_DBG_ERROR("CMD_CLOSE_SESSION failed, respId=%d",
+ rsp_header.response_id);
+ mc_result = MC_DRV_ERR_UNKNOWN_DEVICE;
+ break;
+ }
+
+ mcore_device_remove_session(device, session->session_id);
+ mc_result = MC_DRV_OK;
+
+ } while (false);
+
+ /* Exit critical section */
+
+ return mc_result;
+}
+EXPORT_SYMBOL(mc_close_session);
+
+enum mc_result mc_notify(
+ struct mc_session_handle *session
+) {
+ enum mc_result mc_result = MC_DRV_OK;
+
+ MCDRV_DBG_VERBOSE("===%s()===", __func__);
+
+ do {
+ if (session == NULL) {
+ MCDRV_DBG_ERROR("Session is null");
+ mc_result = MC_DRV_ERR_INVALID_PARAMETER;
+ break;
+ }
+
+ struct mcore_device_t *device =
+ resolve_device_id(session->device_id);
+ if (device == NULL) {
+ MCDRV_DBG_ERROR("Device not found");
+ mc_result = MC_DRV_ERR_UNKNOWN_DEVICE;
+ break;
+ }
+ struct connection *dev_con = device->connection;
+
+ struct session *nqsession =
+ mcore_device_resolve_session_id(device, session->session_id);
+ if (nqsession == NULL) {
+ MCDRV_DBG_ERROR("Session not found");
+ mc_result = MC_DRV_ERR_UNKNOWN_SESSION;
+ break;
+ }
+
+ struct mc_drv_cmd_notify_t cmd_notify = {
+ /* C++ does not support C99 designated initializers */
+ /* .header = */ {
+ /* .command_id = */ MC_DRV_CMD_NOTIFY
+ },
+ /* .payload = */ {
+ /* .session_id = */ session->session_id,
+ }
+ };
+
+ connection_write_data(
+ dev_con,
+ &cmd_notify,
+ sizeof(cmd_notify));
+
+ /* Daemon will not return a response */
+
+ } while (false);
+
+ return mc_result;
+}
+EXPORT_SYMBOL(mc_notify);
+
+enum mc_result mc_wait_notification(
+ struct mc_session_handle *session,
+ int32_t timeout
+) {
+ enum mc_result mc_result = MC_DRV_OK;
+
+ MCDRV_DBG_VERBOSE("===%s()===", __func__);
+
+ do {
+ if (session == NULL) {
+ mc_result = MC_DRV_ERR_INVALID_PARAMETER;
+ break;
+ }
+
+ struct mcore_device_t *device =
+ resolve_device_id(session->device_id);
+ if (device == NULL) {
+ MCDRV_DBG_ERROR("Device not found");
+ mc_result = MC_DRV_ERR_UNKNOWN_DEVICE;
+ break;
+ }
+
+ struct session *nq_session =
+ mcore_device_resolve_session_id(device, session->session_id);
+ if (nq_session == NULL) {
+ MCDRV_DBG_ERROR("Session not found");
+ mc_result = MC_DRV_ERR_UNKNOWN_SESSION;
+ break;
+ }
+
+ struct connection *nqconnection =
+ nq_session->notification_connection;
+ uint32_t count = 0;
+
+ /* Read notification queue till it's empty */
+ for (;;) {
+ struct notification notification;
+ ssize_t num_read = connection_read_data(
+ nqconnection,
+ ¬ification,
+ sizeof(notification),
+ timeout);
+ /* Exit on timeout in first run. Later runs have
+ * timeout set to 0.
+ * -2 means, there is no more data. */
+ if (count == 0 && num_read == -2) {
+ MCDRV_DBG_ERROR("read timeout");
+ mc_result = MC_DRV_ERR_TIMEOUT;
+ break;
+ }
+ /* After first notification the queue will be
+ * drained, Thus we set no timeout for the
+ * following reads */
+ timeout = 0;
+
+ if (num_read != sizeof(struct notification)) {
+ if (count == 0) {
+ /* failure in first read, notify it */
+ mc_result = MC_DRV_ERR_NOTIFICATION;
+ MCDRV_DBG_ERROR(
+ "read notification failed, "
+ "%i bytes received", (int)num_read);
+ break;
+ } else {
+ /* Read of the n-th notification
+ failed/timeout. We don't tell the
+ caller, as we got valid notifications
+ before. */
+ mc_result = MC_DRV_OK;
+ break;
+ }
+ }
+
+ count++;
+ MCDRV_DBG_VERBOSE("readNq count=%d, SessionID=%d, "
+ "Payload=%d", count,
+ notification.session_id, notification.payload);
+
+ if (notification.payload != 0) {
+ /* Session end point died -> store exit code */
+ session_set_error_info(nq_session,
+ notification.payload);
+
+ mc_result = MC_DRV_INFO_NOTIFICATION;
+ break;
+ }
+ } /* for(;;) */
+
+ } while (false);
+
+ return mc_result;
+}
+EXPORT_SYMBOL(mc_wait_notification);
+
+enum mc_result mc_malloc_wsm(
+ uint32_t device_id,
+ uint32_t align,
+ uint32_t len,
+ uint8_t **wsm,
+ uint32_t wsm_flags
+) {
+ enum mc_result mc_result = MC_DRV_ERR_UNKNOWN;
+
+ MCDRV_DBG_VERBOSE("===%s()===", __func__);
+
+ /* Enter critical section */
+
+ do {
+ struct mcore_device_t *device = resolve_device_id(device_id);
+ if (device == NULL) {
+ MCDRV_DBG_ERROR("Device not found");
+ mc_result = MC_DRV_ERR_UNKNOWN_DEVICE;
+ break;
+ }
+ if (wsm == NULL) {
+ mc_result = MC_DRV_ERR_INVALID_PARAMETER;
+ break;
+ }
+
+ struct wsm *wsm_stack =
+ mcore_device_allocate_contiguous_wsm(device, len);
+ if (wsm_stack == NULL) {
+ MCDRV_DBG_ERROR("Allocation of WSM failed");
+ mc_result = MC_DRV_ERR_NO_FREE_MEMORY;
+ break;
+ }
+
+ *wsm = (uint8_t *)wsm_stack->virt_addr;
+ mc_result = MC_DRV_OK;
+
+ } while (false);
+
+ /* Exit critical section */
+
+ return mc_result;
+}
+EXPORT_SYMBOL(mc_malloc_wsm);
+
+enum mc_result mc_free_wsm(
+ uint32_t device_id,
+ uint8_t *wsm
+) {
+ enum mc_result mc_result = MC_DRV_ERR_UNKNOWN;
+ struct mcore_device_t *device;
+
+
+ MCDRV_DBG_VERBOSE("===%s()===", __func__);
+
+ /* Enter critical section */
+
+ do {
+
+ /* Get the device associated wit the given session */
+ device = resolve_device_id(device_id);
+ if (device == NULL) {
+ MCDRV_DBG_ERROR("Device not found");
+ mc_result = MC_DRV_ERR_UNKNOWN_DEVICE;
+ break;
+ }
+
+ /* find WSM object */
+ struct wsm *wsm_stack =
+ mcore_device_find_contiguous_wsm(device, wsm);
+ if (wsm_stack == NULL) {
+ MCDRV_DBG_ERROR("unknown address");
+ mc_result = MC_DRV_ERR_INVALID_PARAMETER;
+ break;
+ }
+
+ /* Free the given virtual address */
+ if (!mcore_device_free_contiguous_wsm(device, wsm_stack)) {
+ MCDRV_DBG_ERROR("Free of virtual address failed");
+ mc_result = MC_DRV_ERR_FREE_MEMORY_FAILED;
+ break;
+ }
+ mc_result = MC_DRV_OK;
+
+ } while (false);
+
+ /* Exit critical section */
+
+ return mc_result;
+}
+EXPORT_SYMBOL(mc_free_wsm);
+
+enum mc_result mc_map(
+ struct mc_session_handle *session_handle,
+ void *buf,
+ uint32_t buf_len,
+ struct mc_bulk_map *map_info
+) {
+ enum mc_result mc_result = MC_DRV_ERR_UNKNOWN;
+
+ MCDRV_DBG_VERBOSE("===%s()===", __func__);
+
+ /* Enter critical section */
+
+ do {
+ if (session_handle == NULL) {
+ MCDRV_DBG_ERROR("session_handle is null");
+ mc_result = MC_DRV_ERR_INVALID_PARAMETER;
+ break;
+ }
+ if (map_info == NULL) {
+ MCDRV_DBG_ERROR("map_info is null");
+ mc_result = MC_DRV_ERR_INVALID_PARAMETER;
+ break;
+ }
+ if (buf == NULL) {
+ MCDRV_DBG_ERROR("buf is null");
+ mc_result = MC_DRV_ERR_INVALID_PARAMETER;
+ break;
+ }
+
+ /* Determine device the session belongs to */
+ struct mcore_device_t *device = resolve_device_id(
+ session_handle->device_id);
+ if (device == NULL) {
+ MCDRV_DBG_ERROR("Device not found");
+ mc_result = MC_DRV_ERR_UNKNOWN_DEVICE;
+ break;
+ }
+ struct connection *dev_con = device->connection;
+
+ /* Get session */
+ struct session *session =
+ mcore_device_resolve_session_id(device,
+ session_handle->session_id);
+ if (session == NULL) {
+ MCDRV_DBG_ERROR("Session not found");
+ mc_result = MC_DRV_ERR_UNKNOWN_SESSION;
+ break;
+ }
+
+ /* Register mapped bulk buffer to Kernel Module and keep mapped
+ bulk buffer in mind */
+ struct bulk_buffer_descriptor *bulk_buf = session_add_bulk_buf(
+ session, buf, buf_len);
+ if (bulk_buf == NULL) {
+ MCDRV_DBG_ERROR("Error mapping bulk buffer");
+ mc_result = MC_DRV_ERR_BULK_MAPPING;
+ break;
+ }
+
+ /* Prepare map command */
+ struct mc_drv_cmd_map_bulk_mem_t mc_drv_cmd_map_bulk_mem = {
+ /* C++ does not support C99 designated initializers */
+ /* .header = */ {
+ /* .command_id = */ MC_DRV_CMD_MAP_BULK_BUF
+ },
+ /* .payload = */ {
+ /* .session_id = */ session->session_id,
+ /* .handle = */ bulk_buf->handle,
+ /* .phys_addr_l2; = */
+ (uint32_t)bulk_buf->phys_addr_wsm_l2,
+ /* .offset_payload = */
+ (uint32_t)(bulk_buf->virt_addr) & 0xFFF,
+ /* .len_bulk_mem = */ bulk_buf->len
+ }
+ };
+
+ /* Transmit map command to MobiCore device */
+ connection_write_data(
+ dev_con,
+ &mc_drv_cmd_map_bulk_mem,
+ sizeof(mc_drv_cmd_map_bulk_mem));
+
+ /* Read command response */
+ struct mc_drv_response_header_t rsp_header;
+ int len = connection_read_datablock(
+ dev_con,
+ &rsp_header,
+ sizeof(rsp_header));
+ if (len != sizeof(rsp_header)) {
+ MCDRV_DBG_ERROR("CMD_MAP_BULK_BUF readRsp failed, "
+ "ret=%d", len);
+ mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
+ break;
+ }
+
+ if (rsp_header.response_id != MC_DRV_RSP_OK) {
+ MCDRV_DBG_ERROR("CMD_MAP_BULK_BUF failed, respId=%d",
+ rsp_header.response_id);
+ /* REV We ignore Daemon Error code because client cannot
+ handle it anyhow. */
+ mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
+
+ /* Unregister mapped bulk buffer from Kernel Module and
+ remove mapped bulk buffer from session maintenance */
+ if (!session_remove_bulk_buf(session, buf)) {
+ /* Removing of bulk buffer not possible */
+ MCDRV_DBG_ERROR("Unregistering of bulk memory"
+ "from Kernel Module failed");
+ }
+ break;
+ }
+
+ struct mc_drv_rsp_map_bulk_mem_payload_t
+ rsp_map_bulk_mem_payload;
+ connection_read_datablock(
+ dev_con,
+ &rsp_map_bulk_mem_payload,
+ sizeof(rsp_map_bulk_mem_payload));
+
+ /* Set mapping info for Trustlet */
+ map_info->secure_virt_addr =
+ (void *)(rsp_map_bulk_mem_payload.secure_virtual_adr);
+ map_info->secure_virt_len = buf_len;
+ mc_result = MC_DRV_OK;
+
+ } while (false);
+
+ /* Exit critical section */
+
+ return mc_result;
+}
+EXPORT_SYMBOL(mc_map);
+
+enum mc_result mc_unmap(
+ struct mc_session_handle *session_handle,
+ void *buf,
+ struct mc_bulk_map *map_info
+) {
+ enum mc_result mc_result = MC_DRV_ERR_UNKNOWN;
+
+ MCDRV_DBG_VERBOSE("===%s()===", __func__);
+
+ /* Enter critical section */
+
+ do {
+ if (session_handle == NULL) {
+ MCDRV_DBG_ERROR("session_handle is null");
+ mc_result = MC_DRV_ERR_INVALID_PARAMETER;
+ break;
+ }
+ if (map_info == NULL) {
+ MCDRV_DBG_ERROR("map_info is null");
+ mc_result = MC_DRV_ERR_INVALID_PARAMETER;
+ break;
+ }
+ if (buf == NULL) {
+ MCDRV_DBG_ERROR("buf is null");
+ mc_result = MC_DRV_ERR_INVALID_PARAMETER;
+ break;
+ }
+
+ /* Determine device the session belongs to */
+ struct mcore_device_t *device =
+ resolve_device_id(session_handle->device_id);
+ if (device == NULL) {
+ MCDRV_DBG_ERROR("Device not found");
+ mc_result = MC_DRV_ERR_UNKNOWN_DEVICE;
+ break;
+ }
+ struct connection *dev_con = device->connection;
+
+ /* Get session */
+ struct session *session =
+ mcore_device_resolve_session_id(device,
+ session_handle->session_id);
+ if (session == NULL) {
+ MCDRV_DBG_ERROR("Session not found");
+ mc_result = MC_DRV_ERR_UNKNOWN_SESSION;
+ break;
+ }
+
+ uint32_t handle = session_find_bulk_buf(session, buf);
+ if (handle == 0) {
+ MCDRV_DBG_ERROR("Buffer not found");
+ mc_result = MC_DRV_ERR_BULK_UNMAPPING;
+ break;
+ }
+
+
+ /* Prepare unmap command */
+ struct mc_drv_cmd_unmap_bulk_mem_t cmd_unmap_bulk_mem = {
+ /* .header = */ {
+ /* .command_id = */
+ MC_DRV_CMD_UNMAP_BULK_BUF
+ },
+ /* .payload = */ {
+ /* .session_id = */ session->session_id,
+ /* .handle = */ handle,
+ /* .secure_virtual_adr = */
+ (uint32_t)(map_info->secure_virt_addr),
+ /* .len_bulk_mem =
+ map_info->secure_virt_len*/
+ }
+ };
+
+ connection_write_data(
+ dev_con,
+ &cmd_unmap_bulk_mem,
+ sizeof(cmd_unmap_bulk_mem));
+
+ /* Read command response */
+ struct mc_drv_response_header_t rsp_header;
+ int len = connection_read_datablock(
+ dev_con,
+ &rsp_header,
+ sizeof(rsp_header));
+ if (len != sizeof(rsp_header)) {
+ MCDRV_DBG_ERROR("CMD_UNMAP_BULK_BUF readRsp failed, "
+ "ret=%d", len);
+ mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
+ break;
+ }
+
+ if (rsp_header.response_id != MC_DRV_RSP_OK) {
+ MCDRV_DBG_ERROR("CMD_UNMAP_BULK_BUF failed, respId=%d",
+ rsp_header.response_id);
+ /* REV We ignore Daemon Error code because client
+ cannot handle it anyhow. */
+ mc_result = MC_DRV_ERR_DAEMON_UNREACHABLE;
+ break;
+ }
+
+ struct mc_drv_rsp_unmap_bulk_mem_payload_t
+ rsp_unmap_bulk_mem_payload;
+ connection_read_datablock(
+ dev_con,
+ &rsp_unmap_bulk_mem_payload,
+ sizeof(rsp_unmap_bulk_mem_payload));
+
+ /* REV axh: what about check the payload? */
+
+ /* Unregister mapped bulk buffer from Kernel Module and
+ * remove mapped bulk buffer from session maintenance */
+ if (!session_remove_bulk_buf(session, buf)) {
+ /* Removing of bulk buffer not possible */
+ MCDRV_DBG_ERROR("Unregistering of bulk memory from "
+ "Kernel Module failed");
+ mc_result = MC_DRV_ERR_BULK_UNMAPPING;
+ break;
+ }
+
+ mc_result = MC_DRV_OK;
+
+ } while (false);
+
+ /* Exit critical section */
+
+ return mc_result;
+}
+EXPORT_SYMBOL(mc_unmap);
+
+enum mc_result mc_get_session_error_code(
+ struct mc_session_handle *session,
+ int32_t *last_error
+) {
+ enum mc_result mc_result = MC_DRV_OK;
+
+ MCDRV_DBG_VERBOSE("===%s()===", __func__);
+
+ do {
+ if (session == NULL || last_error == NULL) {
+ mc_result = MC_DRV_ERR_INVALID_PARAMETER;
+ break;
+ }
+
+ /* Get device */
+ struct mcore_device_t *device =
+ resolve_device_id(session->device_id);
+ if (device == NULL) {
+ MCDRV_DBG_ERROR("Device not found");
+ mc_result = MC_DRV_ERR_UNKNOWN_DEVICE;
+ break;
+ }
+
+ /* Get session */
+ struct session *nqsession =
+ mcore_device_resolve_session_id(device, session->session_id);
+ if (nqsession == NULL) {
+ MCDRV_DBG_ERROR("Session not found");
+ mc_result = MC_DRV_ERR_UNKNOWN_SESSION;
+ break;
+ }
+
+ /* get session error code from session */
+ *last_error = session_get_last_err(nqsession);
+
+ } while (false);
+
+ return mc_result;
+}
+EXPORT_SYMBOL(mc_get_session_error_code);
+
+enum mc_result mc_driver_ctrl(
+ enum mc_driver_ctrl param,
+ uint8_t *data,
+ uint32_t len
+) {
+ MCDRV_DBG_WARN("not implemented");
+ return MC_DRV_ERR_NOT_IMPLEMENTED;
+}
+EXPORT_SYMBOL(mc_driver_ctrl);
+
+enum mc_result mc_manage(
+ uint32_t device_id,
+ uint8_t *data,
+ uint32_t len
+) {
+ MCDRV_DBG_WARN("not implemented");
+ return MC_DRV_ERR_NOT_IMPLEMENTED;
+}
+EXPORT_SYMBOL(mc_manage);
+
diff --git a/drivers/gud/MobiCoreKernelApi/common.h b/drivers/gud/MobiCoreKernelApi/common.h
new file mode 100644
index 0000000..2a73474
--- /dev/null
+++ b/drivers/gud/MobiCoreKernelApi/common.h
@@ -0,0 +1,97 @@
+/**
+ *
+ * Common data types
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
+ *
+ * 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.
+ */
+#ifndef COMMON_H
+#define COMMON_H
+
+#include "connection.h"
+#include "mcinq.h"
+
+void mcapi_insert_connection(
+ struct connection *connection
+);
+
+void mcapi_remove_connection(
+ uint32_t seq
+);
+
+unsigned int mcapi_unique_id(
+ void
+);
+
+
+#define MC_DAEMON_PID 0xFFFFFFFF
+#define MC_DRV_MOD_DEVNODE_FULLPATH "/dev/mobicore"
+
+/* dummy function helper macro. */
+#define DUMMY_FUNCTION() do {} while (0)
+
+#define MCDRV_ERROR(txt, ...) \
+ printk(KERN_ERR "mcKernelApi %s() ### ERROR: " txt, \
+ __func__, \
+ ##__VA_ARGS__)
+
+#if defined(DEBUG)
+
+/* #define DEBUG_VERBOSE */
+#if defined(DEBUG_VERBOSE)
+#define MCDRV_DBG_VERBOSE MCDRV_DBG
+#else
+#define MCDRV_DBG_VERBOSE(...) DUMMY_FUNCTION()
+#endif
+
+#define MCDRV_DBG(txt, ...) \
+ printk(KERN_INFO "mcKernelApi %s(): " txt, \
+ __func__, \
+ ##__VA_ARGS__)
+
+#define MCDRV_DBG_WARN(txt, ...) \
+ printk(KERN_WARNING "mcKernelApi %s() WARNING: " txt, \
+ __func__, \
+ ##__VA_ARGS__)
+
+#define MCDRV_DBG_ERROR(txt, ...) \
+ printk(KERN_ERR "mcKernelApi %s() ### ERROR: " txt, \
+ __func__, \
+ ##__VA_ARGS__)
+
+
+#define MCDRV_ASSERT(cond) \
+ do { \
+ if (unlikely(!(cond))) { \
+ panic("mcKernelApi Assertion failed: %s:%d\n", \
+ __FILE__, __LINE__); \
+ } \
+ } while (0)
+
+#elif defined(NDEBUG)
+
+#define MCDRV_DBG_VERBOSE(...) DUMMY_FUNCTION()
+#define MCDRV_DBG(...) DUMMY_FUNCTION()
+#define MCDRV_DBG_WARN(...) DUMMY_FUNCTION()
+#define MCDRV_DBG_ERROR(...) DUMMY_FUNCTION()
+
+#define MCDRV_ASSERT(...) DUMMY_FUNCTION()
+
+#else
+#error "Define DEBUG or NDEBUG"
+#endif /* [not] defined(DEBUG_MCMODULE) */
+
+
+#define LOG_I MCDRV_DBG_VERBOSE
+#define LOG_W MCDRV_DBG_WARN
+#define LOG_E MCDRV_DBG_ERROR
+
+
+#define assert(expr) MCDRV_ASSERT(expr)
+
+#endif /* COMMON_H */
+
+/** @} */
diff --git a/drivers/gud/MobiCoreKernelApi/connection.c b/drivers/gud/MobiCoreKernelApi/connection.c
new file mode 100644
index 0000000..9048ae8
--- /dev/null
+++ b/drivers/gud/MobiCoreKernelApi/connection.c
@@ -0,0 +1,229 @@
+/** @addtogroup MCD_MCDIMPL_DAEMON_SRV
+ * @{
+ * @file
+ *
+ * Connection data.
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
+ *
+ * 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.
+ */
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/netlink.h>
+#include <linux/skbuff.h>
+#include <linux/netlink.h>
+#include <linux/semaphore.h>
+#include <linux/time.h>
+#include <net/sock.h>
+#include <net/net_namespace.h>
+
+#include "connection.h"
+#include "common.h"
+
+/* Define the initial state of the Data Available Semaphore */
+#define SEM_NO_DATA_AVAILABLE 0
+
+/*----------------------------------------------------------------------------*/
+struct connection *connection_new(
+ void
+) {
+ struct connection *conn = kzalloc(sizeof(struct connection),
+ GFP_KERNEL);
+ conn->sequence_magic = mcapi_unique_id();
+ mutex_init(&conn->data_lock);
+ /* No data available */
+ sema_init(&conn->data_available_sem, SEM_NO_DATA_AVAILABLE);
+
+ mcapi_insert_connection(conn);
+ return conn;
+}
+
+/*----------------------------------------------------------------------------*/
+struct connection *connection_create(
+ int socket_descriptor,
+ pid_t dest
+) {
+ struct connection *conn = connection_new();
+
+ conn->peer_pid = dest;
+ return conn;
+}
+
+
+/*----------------------------------------------------------------------------*/
+void connection_cleanup(
+ struct connection *conn
+) {
+ if (!conn)
+ return;
+
+ kfree_skb(conn->skb);
+
+ mcapi_remove_connection(conn->sequence_magic);
+ kfree(conn);
+}
+
+
+/*----------------------------------------------------------------------------*/
+bool connection_connect(
+ struct connection *conn,
+ pid_t dest
+) {
+ /* Nothing to connect */
+ conn->peer_pid = dest;
+ return true;
+}
+
+/*----------------------------------------------------------------------------*/
+size_t connection_readDataMsg(
+ struct connection *conn,
+ void *buffer,
+ uint32_t len
+) {
+ size_t ret = -1;
+ MCDRV_DBG_VERBOSE("reading connection data %u, connection data left %u",
+ len, conn->data_len);
+ /* trying to read more than the left data */
+ if (len > conn->data_len) {
+ ret = conn->data_len;
+ memcpy(buffer, conn->data_start, conn->data_len);
+ conn->data_len = 0;
+ } else {
+ ret = len;
+ memcpy(buffer, conn->data_start, len);
+ conn->data_len -= len;
+ conn->data_start += len;
+ }
+
+ if (conn->data_len == 0) {
+ conn->data_start = NULL;
+ kfree_skb(conn->skb);
+ conn->skb = NULL;
+ }
+ MCDRV_DBG_VERBOSE("read %u", ret);
+ return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+size_t connection_read_datablock(
+ struct connection *conn,
+ void *buffer,
+ uint32_t len
+) {
+ return connection_read_data(conn, buffer, len, -1);
+}
+
+
+/*----------------------------------------------------------------------------*/
+size_t connection_read_data(
+ struct connection *conn,
+ void *buffer,
+ uint32_t len,
+ int32_t timeout
+) {
+ size_t ret = 0;
+
+ MCDRV_ASSERT(buffer != NULL);
+ MCDRV_ASSERT(conn->socket_descriptor != NULL);
+
+ MCDRV_DBG_VERBOSE("read data len = %u for PID = %u",
+ len, conn->sequence_magic);
+ do {
+ /* Wait until data is available or timeout
+ msecs_to_jiffies(-1) -> wait forever for the sem */
+ if (down_timeout(&(conn->data_available_sem),
+ msecs_to_jiffies(timeout))) {
+ MCDRV_DBG_VERBOSE("Timeout reading the data sem");
+ ret = -2;
+ break;
+ }
+
+ if (mutex_lock_interruptible(&(conn->data_lock))) {
+ MCDRV_DBG_ERROR("interrupted reading the data sem");
+ ret = -1;
+ break;
+ }
+ /* Have data, use it */
+ if (conn->data_len > 0)
+ ret = connection_readDataMsg(conn, buffer, len);
+
+ mutex_unlock(&(conn->data_lock));
+
+ /* There is still some data left */
+ if (conn->data_len > 0)
+ up(&conn->data_available_sem);
+ } while (0);
+
+ return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+size_t connection_write_data(
+ struct connection *conn,
+ void *buffer,
+ uint32_t len
+) {
+ struct sk_buff *skb = NULL;
+ struct nlmsghdr *nlh;
+ int ret = 0;
+
+ MCDRV_DBG_VERBOSE("buffer length %u from pid %u\n",
+ len, conn->sequence_magic);
+ do {
+ skb = nlmsg_new(NLMSG_SPACE(len), GFP_KERNEL);
+ if (!skb) {
+ ret = -1;
+ break;
+ }
+
+ nlh = nlmsg_put(skb, 0, conn->sequence_magic, 2,
+ NLMSG_LENGTH(len), NLM_F_REQUEST);
+ if (!nlh) {
+ ret = -1;
+ break;
+ }
+ memcpy(NLMSG_DATA(nlh), buffer, len);
+
+ netlink_unicast(conn->socket_descriptor, skb,
+ conn->peer_pid, MSG_DONTWAIT);
+ ret = len;
+ } while (0);
+
+ if (!ret && skb != NULL)
+ kfree_skb(skb);
+
+ return ret;
+}
+
+int connection_process(
+ struct connection *conn,
+ struct sk_buff *skb
+)
+{
+ int ret = 0;
+ do {
+ if (mutex_lock_interruptible(&(conn->data_lock))) {
+ MCDRV_DBG_ERROR("Interrupted getting data semaphore!");
+ ret = -1;
+ break;
+ }
+
+ kfree_skb(conn->skb);
+
+ /* Get a reference to the incomming skb */
+ conn->skb = skb_get(skb);
+ if (conn->skb) {
+ conn->data_msg = nlmsg_hdr(conn->skb);
+ conn->data_len = NLMSG_PAYLOAD(conn->data_msg, 0);
+ conn->data_start = NLMSG_DATA(conn->data_msg);
+ up(&(conn->data_available_sem));
+ }
+ mutex_unlock(&(conn->data_lock));
+ ret = 0;
+ } while (0);
+ return ret;
+}
+/** @} */
diff --git a/drivers/gud/MobiCoreKernelApi/connection.h b/drivers/gud/MobiCoreKernelApi/connection.h
new file mode 100644
index 0000000..2a36a2d
--- /dev/null
+++ b/drivers/gud/MobiCoreKernelApi/connection.h
@@ -0,0 +1,123 @@
+/** @addtogroup MCD_MCDIMPL_DAEMON_SRV
+ * @{
+ * @file
+ *
+ * Connection data.
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
+ *
+ * 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.
+ */
+#ifndef CONNECTION_H_
+#define CONNECTION_H_
+
+#include <linux/semaphore.h>
+#include <linux/mutex.h>
+
+#include <stddef.h>
+#include <stdbool.h>
+
+#define MAX_PAYLOAD_SIZE 128
+
+struct connection {
+ struct sock *socket_descriptor; /**< Netlink socket */
+ uint32_t sequence_magic; /**< Random? magic to match requests/answers */
+
+ struct nlmsghdr *data_msg;
+ uint32_t data_len; /**< How much connection data is left */
+ void *data_start; /**< Start pointer of remaining data */
+ struct sk_buff *skb;
+
+ struct mutex data_lock; /**< Data protection lock */
+ struct semaphore data_available_sem; /**< Data protection semaphore */
+
+ pid_t self_pid; /**< PID address used for local connection */
+ pid_t peer_pid; /**< Remote PID for connection */
+
+ struct list_head list; /**< The list param for using the kernel lists*/
+};
+
+struct connection *connection_new(
+ void
+);
+
+struct connection *connection_create(
+ int socket_descriptor,
+ pid_t dest
+);
+
+void connection_cleanup(
+ struct connection *conn
+);
+
+/**
+ * Connect to destination.
+ *
+ * @param Destination pointer.
+ * @return true on success.
+ */
+bool connection_connect(
+ struct connection *conn,
+ pid_t dest
+);
+
+
+/**
+ * Read bytes from the connection.
+ *
+ * @param buffer Pointer to destination buffer.
+ * @param len Number of bytes to read.
+ * @return Number of bytes read.
+ */
+size_t connection_read_datablock(
+ struct connection *conn,
+ void *buffer,
+ uint32_t len
+);
+/**
+ * Read bytes from the connection.
+ *
+ * @param buffer Pointer to destination buffer.
+ * @param len Number of bytes to read.
+ * @param timeout Timeout in milliseconds
+ * @return Number of bytes read.
+ * @return -1 if select() failed (returned -1)
+ * @return -2 if no data available, i.e. timeout
+ */
+size_t connection_read_data(
+ struct connection *conn,
+ void *buffer,
+ uint32_t len,
+ int32_t timeout
+);
+
+/**
+ * Write bytes to the connection.
+ *
+ * @param buffer Pointer to source buffer.
+ * @param len Number of bytes to read.
+ * @return Number of bytes written.
+ */
+size_t connection_write_data(
+ struct connection *conn,
+ void *buffer,
+ uint32_t len
+);
+
+/**
+ * Write bytes to the connection.
+ *
+ * @param buffer Pointer to source buffer.
+ * @param len Number of bytes to read.
+ * @return Number of bytes written.
+ */
+int connection_process(
+ struct connection *conn,
+ struct sk_buff *skb
+);
+
+#endif /* CONNECTION_H_ */
+
+/** @} */
diff --git a/drivers/gud/MobiCoreKernelApi/device.c b/drivers/gud/MobiCoreKernelApi/device.c
new file mode 100644
index 0000000..a3e9b67
--- /dev/null
+++ b/drivers/gud/MobiCoreKernelApi/device.c
@@ -0,0 +1,257 @@
+/** @addtogroup MCD_IMPL_LIB
+ * @{
+ * @file
+ *
+ * Client library device management.
+ *
+ * Device and Trustlet Session management Funtions.
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
+ *
+ * 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.
+ */
+#include <linux/list.h>
+#include <linux/slab.h>
+#include "mc_kernel_api.h"
+#include "public/mobicore_driver_api.h"
+
+#include "device.h"
+#include "common.h"
+
+/*----------------------------------------------------------------------------*/
+struct wsm *wsm_create(
+ void *virt_addr,
+ uint32_t len,
+ uint32_t handle,
+ void *phys_addr /*= NULL this may be unknown, so is can be omitted.*/
+ )
+{
+ struct wsm *wsm = kzalloc(sizeof(struct wsm), GFP_KERNEL);
+ wsm->virt_addr = virt_addr;
+ wsm->len = len;
+ wsm->handle = handle;
+ wsm->phys_addr = phys_addr;
+ return wsm;
+}
+
+
+/*----------------------------------------------------------------------------*/
+struct mcore_device_t *mcore_device_create(
+ uint32_t device_id,
+ struct connection *connection
+) {
+ struct mcore_device_t *dev =
+ kzalloc(sizeof(struct mcore_device_t), GFP_KERNEL);
+ dev->device_id = device_id;
+ dev->connection = connection;
+
+ INIT_LIST_HEAD(&dev->session_vector);
+ INIT_LIST_HEAD(&dev->wsm_l2_vector);
+
+ return dev;
+}
+
+
+/*----------------------------------------------------------------------------*/
+void mcore_device_cleanup(
+ struct mcore_device_t *dev
+) {
+ struct session *tmp;
+ struct wsm *wsm;
+ struct list_head *pos, *q;
+
+ /* Delete all session objects. Usually this should not be needed
+ * as closeDevice()requires that all sessions have been closed before.*/
+ list_for_each_safe(pos, q, &dev->session_vector) {
+ tmp = list_entry(pos, struct session, list);
+ list_del(pos);
+ session_cleanup(tmp);
+ }
+
+ /* Free all allocated WSM descriptors */
+ list_for_each_safe(pos, q, &dev->wsm_l2_vector) {
+ wsm = list_entry(pos, struct wsm, list);
+ /* mcKMod_free(dev->instance, wsm->handle); */
+ list_del(pos);
+ kfree(wsm);
+ }
+ connection_cleanup(dev->connection);
+
+ mcore_device_close(dev);
+ kfree(dev);
+}
+
+
+/*----------------------------------------------------------------------------*/
+bool mcore_device_open(
+ struct mcore_device_t *dev,
+ const char *deviceName
+) {
+ dev->instance = mobicore_open();
+ return (dev->instance != NULL);
+}
+
+
+/*----------------------------------------------------------------------------*/
+void mcore_device_close(
+ struct mcore_device_t *dev
+) {
+ mobicore_release(dev->instance);
+}
+
+
+/*----------------------------------------------------------------------------*/
+bool mcore_device_has_sessions(
+ struct mcore_device_t *dev
+) {
+ return !list_empty(&dev->session_vector);
+}
+
+
+/*----------------------------------------------------------------------------*/
+bool mcore_device_create_new_session(
+ struct mcore_device_t *dev,
+ uint32_t session_id,
+ struct connection *connection
+) {
+ /* Check if session_id already exists */
+ if (mcore_device_resolve_session_id(dev, session_id)) {
+ MCDRV_DBG_ERROR(" session %u already exists", session_id);
+ return false;
+ }
+ struct session *session = session_create(session_id, dev->instance,
+ connection);
+ list_add_tail(&(session->list), &(dev->session_vector));
+ return true;
+}
+
+
+/*----------------------------------------------------------------------------*/
+bool mcore_device_remove_session(
+ struct mcore_device_t *dev,
+ uint32_t session_id
+) {
+ bool ret = false;
+ struct session *tmp;
+ struct list_head *pos, *q;
+
+ list_for_each_safe(pos, q, &dev->session_vector) {
+ tmp = list_entry(pos, struct session, list);
+ if (tmp->session_id == session_id) {
+ list_del(pos);
+ session_cleanup(tmp);
+ ret = true;
+ break;
+ }
+ }
+ return ret;
+}
+
+
+/*----------------------------------------------------------------------------*/
+struct session *mcore_device_resolve_session_id(
+ struct mcore_device_t *dev,
+ uint32_t session_id
+) {
+ struct session *ret = NULL;
+ struct session *tmp;
+ struct list_head *pos;
+
+
+ /* Get session for session_id */
+ list_for_each(pos, &dev->session_vector) {
+ tmp = list_entry(pos, struct session, list);
+ if (tmp->session_id == session_id) {
+ ret = tmp;
+ break;
+ }
+ }
+ return ret;
+}
+
+
+/*----------------------------------------------------------------------------*/
+struct wsm *mcore_device_allocate_contiguous_wsm(
+ struct mcore_device_t *dev,
+ uint32_t len
+) {
+ struct wsm *wsm = NULL;
+ do {
+ if (len == 0)
+ break;
+
+ /* Allocate shared memory */
+ void *virt_addr;
+ uint32_t handle;
+ void *phys_addr;
+ int ret = mobicore_allocate_wsm(dev->instance,
+ len,
+ &handle,
+ &virt_addr,
+ &phys_addr);
+ if (ret != 0)
+ break;
+
+ /* Register (vaddr,paddr) with device */
+ wsm = wsm_create(virt_addr, len, handle, phys_addr);
+
+ list_add_tail(&(wsm->list), &(dev->wsm_l2_vector));
+
+ } while (0);
+
+ /* Return pointer to the allocated memory */
+ return wsm;
+}
+
+
+/*----------------------------------------------------------------------------*/
+bool mcore_device_free_contiguous_wsm(
+ struct mcore_device_t *dev,
+ struct wsm *wsm
+) {
+ bool ret = false;
+ struct wsm *tmp;
+ struct list_head *pos;
+
+ list_for_each(pos, &dev->wsm_l2_vector) {
+ tmp = list_entry(pos, struct wsm, list);
+ if (tmp == wsm) {
+ ret = true;
+ break;
+ }
+ }
+
+ if (ret) {
+ MCDRV_DBG_VERBOSE("freeWsm virt_addr=0x%p, handle=%d",
+ wsm->virt_addr, wsm->handle);
+
+ /* ignore return code */
+ mobicore_free_wsm(dev->instance, wsm->handle);
+
+ list_del(pos);
+ kfree(wsm);
+ }
+ return ret;
+}
+
+
+/*----------------------------------------------------------------------------*/
+struct wsm *mcore_device_find_contiguous_wsm(
+ struct mcore_device_t *dev,
+ void *virt_addr
+) {
+ struct wsm *wsm;
+ struct list_head *pos;
+
+ list_for_each(pos, &dev->wsm_l2_vector) {
+ wsm = list_entry(pos, struct wsm, list);
+ if (virt_addr == wsm->virt_addr)
+ return wsm;
+ }
+
+ return NULL;
+}
+
+/** @} */
diff --git a/drivers/gud/MobiCoreKernelApi/device.h b/drivers/gud/MobiCoreKernelApi/device.h
new file mode 100644
index 0000000..f40d993
--- /dev/null
+++ b/drivers/gud/MobiCoreKernelApi/device.h
@@ -0,0 +1,139 @@
+/** @addtogroup MCD_IMPL_LIB
+ * @{
+ * @file
+ *
+ * Client library device management.
+ *
+ * Device and Trustlet Session management Functions.
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
+ *
+ * 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.
+ */
+#ifndef DEVICE_H_
+#define DEVICE_H_
+
+#include <linux/list.h>
+
+#include "connection.h"
+#include "session.h"
+#include "wsm.h"
+
+
+struct mcore_device_t {
+ struct list_head session_vector; /**< MobiCore Trustlet session
+ associated with the device */
+ struct list_head wsm_l2_vector; /**< WSM L2 Table */
+
+ uint32_t device_id; /**< Device identifier */
+ struct connection *connection; /**< The device connection */
+ struct mc_instance *instance; /**< MobiCore Driver instance */
+
+ struct list_head list; /**< The list param for using the kernel lists*/
+};
+
+struct mcore_device_t *mcore_device_create(
+ uint32_t device_id,
+ struct connection *connection
+);
+
+void mcore_device_cleanup(
+ struct mcore_device_t *dev
+);
+
+/**
+ * Open the device.
+ * @param deviceName Name of the kernel modules device file.
+ * @return true if the device has been opened successfully
+ */
+bool mcore_device_open(
+ struct mcore_device_t *dev,
+ const char *deviceName
+);
+
+/**
+ * Closes the device.
+ */
+void mcore_device_close(
+ struct mcore_device_t *dev
+);
+
+/**
+ * Check if the device has open sessions.
+ * @return true if the device has one or more open sessions.
+ */
+bool mcore_device_has_sessions(
+ struct mcore_device_t *dev
+);
+
+/**
+ * Add a session to the device.
+ * @param session_id session ID
+ * @param connection session connection
+ */
+bool mcore_device_create_new_session(
+ struct mcore_device_t *dev,
+ uint32_t session_id,
+ struct connection *connection
+);
+
+/**
+ * Remove the specified session from the device.
+ * The session object will be destroyed and all resources associated with it
+ * will be freed.
+ *
+ * @param session_id Session of the session to remove.
+ * @return true if a session has been found and removed.
+ */
+bool mcore_device_remove_session(
+ struct mcore_device_t *dev,
+ uint32_t session_id
+);
+
+/**
+ * Get as session object for a given session ID.
+ * @param session_id Identified of a previously opened session.
+ * @return Session object if available or NULL if no session has been found.
+ */
+struct session *mcore_device_resolve_session_id(
+ struct mcore_device_t *dev,
+ uint32_t session_id
+);
+
+/**
+ * Allocate a block of contiguous WSM.
+ * @param len The virtual address to be registered.
+ * @return The virtual address of the allocated memory or NULL if no memory
+ * is available.
+ */
+struct wsm *mcore_device_allocate_contiguous_wsm(
+ struct mcore_device_t *dev,
+ uint32_t len
+);
+
+/**
+ * Unregister a vaddr from a device.
+ * @param vaddr The virtual address to be registered.
+ * @param paddr The physical address to be registered.
+ */
+bool mcore_device_free_contiguous_wsm(
+ struct mcore_device_t *dev,
+ struct wsm *wsm
+);
+
+/**
+ * Get a WSM object for a given virtual address.
+ * @param vaddr The virtual address which has been allocate with mc_malloc_wsm()
+ * in advance.
+ * @return the WSM object or NULL if no address has been found.
+ */
+struct wsm *mcore_device_find_contiguous_wsm(
+ struct mcore_device_t *dev,
+ void *virt_addr
+);
+
+#endif /* DEVICE_H_ */
+
+/** @} */
diff --git a/drivers/gud/MobiCoreKernelApi/include/mcinq.h b/drivers/gud/MobiCoreKernelApi/include/mcinq.h
new file mode 100644
index 0000000..3cb82be
--- /dev/null
+++ b/drivers/gud/MobiCoreKernelApi/include/mcinq.h
@@ -0,0 +1,125 @@
+/** @addtogroup NQ
+ * @{
+ * Notifications inform the MobiCore runtime environment that information is
+ * pending in a WSM buffer.
+ * The Trustlet Connector (TLC) and the corresponding trustlet also utilize
+ * this buffer to notify each other about new data within the
+ * Trustlet Connector Interface (TCI).
+ *
+ * The buffer is set up as a queue, which means that more than one
+ * notification can be written to the buffer before the switch to the other
+ * world is performed. Each side therefore facilitates an incoming and an
+ * outgoing queue for communication with the other side.
+ *
+ * Notifications hold the session ID, which is used to reference the
+ * communication partner in the other world.
+ * So if, e.g., the TLC in the normal world wants to notify his trustlet
+ * about new data in the TLC buffer
+ *
+ * @file
+ * Notification queue declarations.
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef NQ_H_
+#define NQ_H_
+
+/** \name NQ Size Defines
+ * Minimum and maximum count of elements in the notification queue.
+ * @{ */
+#define MIN_NQ_ELEM 1 /**< Minimum notification queue elements. */
+#define MAX_NQ_ELEM 64 /**< Maximum notification queue elements. */
+/** @} */
+
+/** \name NQ Length Defines
+ * Minimum and maximum notification queue length.
+ * @{ */
+/**< Minimum notification length (in bytes). */
+#define MIN_NQ_LEN (MIN_NQ_ELEM * sizeof(notification))
+/**< Maximum notification length (in bytes). */
+#define MAX_NQ_LEN (MAX_NQ_ELEM * sizeof(notification))
+/** @} */
+
+/** \name Session ID Defines
+ * Standard Session IDs.
+ * @{ */
+/**< MCP session ID is used when directly communicating with the MobiCore
+ * (e.g. for starting and stopping of trustlets). */
+#define SID_MCP 0
+/**< Invalid session id is returned in case of an error. */
+#define SID_INVALID 0xffffffff
+/** @} */
+
+/** Notification data structure. */
+struct notification {
+ uint32_t session_id; /**< Session ID. */
+ int32_t payload; /**< Additional notification information. */
+};
+
+/** Notification payload codes.
+ * 0 indicated a plain simple notification,
+ * a positive value is a termination reason from the task,
+ * a negative value is a termination reason from MobiCore.
+ * Possible negative values are given below.
+ */
+enum notification_payload {
+ /**< task terminated, but exit code is invalid */
+ ERR_INVALID_EXIT_CODE = -1,
+ /**< task terminated due to session end, no exit code available */
+ ERR_SESSION_CLOSE = -2,
+ /**< task terminated due to invalid operation */
+ ERR_INVALID_OPERATION = -3,
+ /**< session ID is unknown */
+ ERR_INVALID_SID = -4,
+ /**< session is not active */
+ ERR_SID_NOT_ACTIVE = -5
+};
+
+/** Declaration of the notification queue header.
+ * layout as specified in the data structure specification.
+ */
+struct notification_queue_header {
+ uint32_t write_cnt; /**< Write counter. */
+ uint32_t read_cnt; /**< Read counter. */
+ uint32_t queue_size; /**< Queue size. */
+};
+
+/** Queue struct which defines a queue object.
+ * The queue struct is accessed by the queue<operation> type of
+ * function. elementCnt must be a power of two and the power needs
+ * to be smaller than power of uint32_t (obviously 32).
+ */
+struct notification_queue {
+ /**< Queue header. */
+ struct notification_queue_header hdr;
+ /**< Notification elements. */
+ struct notification notification[MIN_NQ_ELEM];
+} ;
+
+#endif /** NQ_H_ */
+
+/** @} */
diff --git a/drivers/gud/MobiCoreKernelApi/include/mcuuid.h b/drivers/gud/MobiCoreKernelApi/include/mcuuid.h
new file mode 100644
index 0000000..b72acb8
--- /dev/null
+++ b/drivers/gud/MobiCoreKernelApi/include/mcuuid.h
@@ -0,0 +1,74 @@
+/**
+ * @addtogroup MC_UUID mcUuid - Universally Unique Identifier.
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2011-2012 -->
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @ingroup MC_DATA_TYPES
+ * @{
+ */
+
+#ifndef MC_UUID_H_
+#define MC_UUID_H_
+
+#define UUID_TYPE
+
+/** Universally Unique Identifier (UUID) according to ISO/IEC 11578. */
+struct mc_uuid_t {
+ uint8_t value[16]; /**< Value of the UUID. */
+};
+
+/** UUID value used as free marker in service provider containers. */
+#define MC_UUID_FREE_DEFINE \
+ { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }
+
+static const struct mc_uuid_t MC_UUID_FREE = {
+ MC_UUID_FREE_DEFINE
+};
+
+/** Reserved UUID. */
+#define MC_UUID_RESERVED_DEFINE \
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
+
+static const struct mc_uuid_t MC_UUID_RESERVED = {
+ MC_UUID_RESERVED_DEFINE
+};
+
+/** UUID for system applications. */
+#define MC_UUID_SYSTEM_DEFINE \
+ { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE }
+
+static const struct mc_uuid_t MC_UUID_SYSTEM = {
+ MC_UUID_SYSTEM_DEFINE
+};
+
+#endif /* MC_UUID_H_ */
+
+/** @} */
+
diff --git a/drivers/gud/MobiCoreKernelApi/main.c b/drivers/gud/MobiCoreKernelApi/main.c
new file mode 100644
index 0000000..62997f72
--- /dev/null
+++ b/drivers/gud/MobiCoreKernelApi/main.c
@@ -0,0 +1,181 @@
+/**
+ * MobiCore KernelApi module
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
+ *
+ * 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.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/netlink.h>
+#include <linux/kthread.h>
+#include <net/sock.h>
+
+#include <linux/list.h>
+
+#include "connection.h"
+#include "common.h"
+
+#define MC_DAEMON_NETLINK 17
+
+struct mc_kernelapi_ctx {
+ struct sock *sk;
+ struct list_head peers;
+ atomic_t counter;
+};
+
+struct mc_kernelapi_ctx *mod_ctx; /* = NULL; */
+
+/*----------------------------------------------------------------------------*/
+/* get a unique ID */
+unsigned int mcapi_unique_id(
+ void
+)
+{
+ return (unsigned int)atomic_inc_return(
+ &(mod_ctx->counter));
+}
+
+
+/*----------------------------------------------------------------------------*/
+static struct connection *mcapi_find_connection(
+ uint32_t seq
+)
+{
+ struct connection *tmp;
+ struct list_head *pos;
+
+ /* Get session for session_id */
+ list_for_each(pos, &mod_ctx->peers) {
+ tmp = list_entry(pos, struct connection, list);
+ if (tmp->sequence_magic == seq)
+ return tmp;
+ }
+
+ return NULL;
+}
+
+/*----------------------------------------------------------------------------*/
+void mcapi_insert_connection(
+ struct connection *connection
+)
+{
+ list_add_tail(&(connection->list), &(mod_ctx->peers));
+ connection->socket_descriptor = mod_ctx->sk;
+}
+
+void mcapi_remove_connection(
+ uint32_t seq
+)
+{
+ struct connection *tmp;
+ struct list_head *pos, *q;
+
+ /* Delete all session objects. Usually this should not be needed as
+ closeDevice() requires that all sessions have been closed before.*/
+ list_for_each_safe(pos, q, &mod_ctx->peers) {
+ tmp = list_entry(pos, struct connection, list);
+ if (tmp->sequence_magic == seq) {
+ list_del(pos);
+ break;
+ }
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+static int mcapi_process(
+ struct sk_buff *skb,
+ struct nlmsghdr *nlh
+)
+{
+ struct connection *c;
+ int length;
+ int seq;
+ pid_t pid;
+ int ret;
+
+ pid = nlh->nlmsg_pid;
+ length = nlh->nlmsg_len;
+ seq = nlh->nlmsg_seq;
+ MCDRV_DBG_VERBOSE("nlmsg len %d type %d pid 0x%X seq %d\n",
+ length, nlh->nlmsg_type, pid, seq);
+ do {
+ c = mcapi_find_connection(seq);
+ if (!c) {
+ MCDRV_ERROR("Invalid incomming connection - seq=%u!",
+ seq);
+ ret = -1;
+ break;
+ }
+
+ /* Pass the buffer to the appropriate connection */
+ connection_process(c, skb);
+
+ ret = 0;
+ } while (false);
+ return ret;
+}
+
+/*----------------------------------------------------------------------------*/
+static void mcapi_callback(
+ struct sk_buff *skb
+)
+{
+ struct nlmsghdr *nlh = nlmsg_hdr(skb);
+ int len = skb->len;
+ int err = 0;
+
+ while (NLMSG_OK(nlh, len)) {
+ err = mcapi_process(skb, nlh);
+
+ /* if err or if this message says it wants a response */
+ if (err || (nlh->nlmsg_flags & NLM_F_ACK))
+ netlink_ack(skb, nlh, err);
+
+ nlh = NLMSG_NEXT(nlh, len);
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+static int __init mcapi_init(void)
+{
+ printk(KERN_INFO "Mobicore API module initialized!\n");
+
+ mod_ctx = kzalloc(sizeof(struct mc_kernelapi_ctx), GFP_KERNEL);
+
+ /* start kernel thread */
+ mod_ctx->sk = netlink_kernel_create(&init_net, MC_DAEMON_NETLINK, 0,
+ mcapi_callback, NULL, THIS_MODULE);
+
+ if (!mod_ctx->sk) {
+ MCDRV_ERROR("register of recieve handler failed");
+ return -EFAULT;
+ }
+
+ INIT_LIST_HEAD(&mod_ctx->peers);
+ return 0;
+}
+
+static void __exit mcapi_exit(void)
+{
+ printk(KERN_INFO "Unloading Mobicore API module.\n");
+
+ if (mod_ctx->sk != NULL) {
+ netlink_kernel_release(mod_ctx->sk);
+ mod_ctx->sk = NULL;
+ }
+ kfree(mod_ctx);
+ mod_ctx = NULL;
+}
+
+module_init(mcapi_init);
+module_exit(mcapi_exit);
+
+MODULE_AUTHOR("Giesecke & Devrient GmbH");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MobiCore API driver");
diff --git a/drivers/gud/MobiCoreKernelApi/public/mobicore_driver_api.h b/drivers/gud/MobiCoreKernelApi/public/mobicore_driver_api.h
new file mode 100644
index 0000000..ccfb2e5
--- /dev/null
+++ b/drivers/gud/MobiCoreKernelApi/public/mobicore_driver_api.h
@@ -0,0 +1,483 @@
+/**
+ * @defgroup MCD_API MobiCore Driver API
+ * @addtogroup MCD_API
+ * @{
+ *
+ * @if DOXYGEN_MCDRV_API
+ * @mainpage MobiCore Driver API.
+ * @endif
+ *
+ * MobiCore Driver API.
+ *
+ * The MobiCore (MC) Driver API provides access functions to the MobiCore
+ * runtime environment and the contained Trustlets.
+ *
+ * @image html DoxyOverviewDrvApi500x.png
+ * @image latex DoxyOverviewDrvApi500x.png "MobiCore Overview" width=12cm
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef MCDRIVER_H_
+#define MCDRIVER_H_
+
+#define __MC_CLIENT_LIB_API
+
+#include "mcuuid.h"
+
+/**
+ * Return values of MobiCore driver functions.
+ */
+enum mc_result {
+ /**< Function call succeeded. */
+ MC_DRV_OK = 0,
+ /**< No notification available. */
+ MC_DRV_NO_NOTIFICATION = 1,
+ /**< Error during notification on communication level. */
+ MC_DRV_ERR_NOTIFICATION = 2,
+ /**< Function not implemented. */
+ MC_DRV_ERR_NOT_IMPLEMENTED = 3,
+ /**< No more resources available. */
+ MC_DRV_ERR_OUT_OF_RESOURCES = 4,
+ /**< Driver initialization failed. */
+ MC_DRV_ERR_INIT = 5,
+ /**< Unknown error. */
+ MC_DRV_ERR_UNKNOWN = 6,
+ /**< The specified device is unknown. */
+ MC_DRV_ERR_UNKNOWN_DEVICE = 7,
+ /**< The specified session is unknown.*/
+ MC_DRV_ERR_UNKNOWN_SESSION = 8,
+ /**< The specified operation is not allowed. */
+ MC_DRV_ERR_INVALID_OPERATION = 9,
+ /**< The response header from the MC is invalid. */
+ MC_DRV_ERR_INVALID_RESPONSE = 10,
+ /**< Function call timed out. */
+ MC_DRV_ERR_TIMEOUT = 11,
+ /**< Can not allocate additional memory. */
+ MC_DRV_ERR_NO_FREE_MEMORY = 12,
+ /**< Free memory failed. */
+ MC_DRV_ERR_FREE_MEMORY_FAILED = 13,
+ /**< Still some open sessions pending. */
+ MC_DRV_ERR_SESSION_PENDING = 14,
+ /**< MC daemon not reachable */
+ MC_DRV_ERR_DAEMON_UNREACHABLE = 15,
+ /**< The device file of the kernel module could not be opened. */
+ MC_DRV_ERR_INVALID_DEVICE_FILE = 16,
+ /**< Invalid parameter. */
+ MC_DRV_ERR_INVALID_PARAMETER = 17,
+ /**< Unspecified error from Kernel Module*/
+ MC_DRV_ERR_KERNEL_MODULE = 18,
+ /**< Error during mapping of additional bulk memory to session. */
+ MC_DRV_ERR_BULK_MAPPING = 19,
+ /**< Error during unmapping of additional bulk memory to session. */
+ MC_DRV_ERR_BULK_UNMAPPING = 20,
+ /**< Notification received, exit code available. */
+ MC_DRV_INFO_NOTIFICATION = 21,
+ /**< Set up of NWd connection failed. */
+ MC_DRV_ERR_NQ_FAILED = 22
+};
+
+
+/**
+ * Driver control command.
+ */
+enum mc_driver_ctrl {
+ MC_CTRL_GET_VERSION = 1 /**< Return the driver version */
+};
+
+
+/** Structure of Session Handle, includes the Session ID and the Device ID the
+ * Session belongs to.
+ * The session handle will be used for session-based MobiCore communication.
+ * It will be passed to calls which address a communication end point in the
+ * MobiCore environment.
+ */
+struct mc_session_handle {
+ uint32_t session_id; /**< MobiCore session ID */
+ uint32_t device_id; /**< Device ID the session belongs to */
+};
+
+/** Information structure about additional mapped Bulk buffer between the
+ * Trustlet Connector (Nwd) and the Trustlet (Swd). This structure is
+ * initialized from a Trustlet Connector by calling mc_map().
+ * In order to use the memory within a Trustlet the Trustlet Connector has to
+ * inform the Trustlet with the content of this structure via the TCI.
+ */
+struct mc_bulk_map {
+ /**< The virtual address of the Bulk buffer regarding the address space
+ * of the Trustlet, already includes a possible offset! */
+ void *secure_virt_addr;
+ uint32_t secure_virt_len; /**< Length of the mapped Bulk buffer */
+};
+
+
+/**< The default device ID */
+#define MC_DEVICE_ID_DEFAULT 0
+/**< Wait infinite for a response of the MC. */
+#define MC_INFINITE_TIMEOUT ((int32_t)(-1))
+/**< Do not wait for a response of the MC. */
+#define MC_NO_TIMEOUT 0
+/**< TCI/DCI must not exceed 1MiB */
+#define MC_MAX_TCI_LEN 0x100000
+
+
+
+/** Open a new connection to a MobiCore device.
+ *
+ * mc_open_device() initializes all device specific resources required to
+ * communicate with an MobiCore instance located on the specified device in the
+ * system. If the device does not exist the function will return
+ * MC_DRV_ERR_UNKNOWN_DEVICE.
+ *
+ * @param [in] device_id Identifier for the MobiCore device to be used.
+ * MC_DEVICE_ID_DEFAULT refers to the default device.
+ *
+ * @return MC_DRV_OK if operation has been successfully completed.
+ * @return MC_DRV_ERR_INVALID_OPERATION if device already opened.
+ * @return MC_DRV_ERR_DAEMON_UNREACHABLE when problems with daemon occur.
+ * @return MC_DRV_ERR_UNKNOWN_DEVICE when device_id is unknown.
+ * @return MC_DRV_ERR_INVALID_DEVICE_FILE if kernel module under
+ * /dev/mobicore cannot be opened
+ *
+ * Uses a Mutex.
+ */
+__MC_CLIENT_LIB_API enum mc_result mc_open_device(
+ uint32_t device_id
+);
+
+/** Close the connection to a MobiCore device.
+ * When closing a device, active sessions have to be closed beforehand.
+ * Resources associated with the device will be released.
+ * The device may be opened again after it has been closed.
+ *
+ * @param [in] device_id Identifier for the MobiCore device.
+ * MC_DEVICE_ID_DEFAULT refers to the default device.
+ *
+ * @return MC_DRV_OK if operation has been successfully completed.
+ * @return MC_DRV_ERR_UNKNOWN_DEVICE when device id is invalid.
+ * @return MC_DRV_ERR_SESSION_PENDING when a session is still open.
+ * @return MC_DRV_ERR_DAEMON_UNREACHABLE when problems with daemon occur.
+ *
+ * Uses a Mutex.
+ */
+__MC_CLIENT_LIB_API enum mc_result mc_close_device(
+ uint32_t device_id
+);
+
+/** Open a new session to a Trustlet. The trustlet with the given UUID has
+ * to be available in the flash filesystem.
+ *
+ * Write MCP open message to buffer and notify MobiCore about the availability
+ * of a new command.
+ * Waits till the MobiCore responses with the new session ID (stored in the MCP
+ * buffer).
+ *
+ * @param [in,out] session On success, the session data will be returned.
+ * Note that session.device_id has to be the device id of an opened device.
+ * @param [in] uuid UUID of the Trustlet to be opened.
+ * @param [in] tci TCI buffer for communicating with the trustlet.
+ * @param [in] tci_len Length of the TCI buffer. Maximum allowed value
+ * is MC_MAX_TCI_LEN.
+ *
+ * @return MC_DRV_OK if operation has been successfully completed.
+ * @return MC_DRV_INVALID_PARAMETER if session parameter is invalid.
+ * @return MC_DRV_ERR_UNKNOWN_DEVICE when device id is invalid.
+ * @return MC_DRV_ERR_DAEMON_UNREACHABLE when problems with daemon socket occur.
+ * @return MC_DRV_ERR_UNKNOWN_DEVICE when daemon returns an error.
+ *
+ * Uses a Mutex.
+ */
+__MC_CLIENT_LIB_API enum mc_result mc_open_session(
+ struct mc_session_handle *session,
+ const struct mc_uuid_t *uuid,
+ uint8_t *tci,
+ uint32_t tci_len
+);
+
+/** Close a Trustlet session.
+ *
+ * Closes the specified MobiCore session. The call will block until the
+ * session has been closed.
+ *
+ * @pre Device device_id has to be opened in advance.
+ *
+ * @param [in] session Session to be closed.
+ *
+ * @return MC_DRV_OK if operation has been successfully completed.
+ * @return MC_DRV_INVALID_PARAMETER if session parameter is invalid.
+ * @return MC_DRV_ERR_UNKNOWN_SESSION when session id is invalid.
+ * @return MC_DRV_ERR_UNKNOWN_DEVICE when device id of session is invalid.
+ * @return MC_DRV_ERR_DAEMON_UNREACHABLE when problems with daemon occur.
+ * @return MC_DRV_ERR_INVALID_DEVICE_FILE when daemon cannot open trustlet file.
+ *
+ * Uses a Mutex.
+ */
+__MC_CLIENT_LIB_API enum mc_result mc_close_session(
+ struct mc_session_handle *session
+);
+
+/** Notify a session.
+ * Notifies the session end point about available message data.
+ * If the session parameter is correct, notify will always succeed.
+ * Corresponding errors can only be received by mc_wait_notification().
+ * @pre A session has to be opened in advance.
+ *
+ * @param session The session to be notified.
+ *
+ * @return MC_DRV_OK if operation has been successfully completed.
+ * @return MC_DRV_INVALID_PARAMETER if session parameter is invalid.
+ * @return MC_DRV_ERR_UNKNOWN_SESSION when session id is invalid.
+ * @return MC_DRV_ERR_UNKNOWN_DEVICE when device id of session is invalid.
+ */
+__MC_CLIENT_LIB_API enum mc_result mc_notify(
+ struct mc_session_handle *session
+);
+
+/** Wait for a notification.
+ *
+ * Wait for a notification issued by the MobiCore for a specific session.
+ * The timeout parameter specifies the number of milliseconds the call will wait
+ * for a notification.
+ * If the caller passes 0 as timeout value the call will immediately return.
+ * If timeout value is below 0 the call will block until a notification for the
+ session has been received.
+ *
+ * @attention if timeout is below 0, call will block:
+ * Caller has to trust the other side to send a notification to wake him up
+ * again.
+ *
+ * @param [in] session The session the notification should correspond to.
+ * @param [in] timeout Time in milliseconds to wait
+ * (MC_NO_TIMEOUT : direct return, > 0 : milliseconds,
+ * MC_INFINITE_TIMEOUT : wait infinitely)
+ *
+ * @return MC_DRV_OK if notification is available.
+ * @return MC_DRV_ERR_TIMEOUT if no notification arrived in time.
+ * @return MC_DRV_INFO_NOTIFICATION if a problem with the session was
+ * encountered. Get more details with mc_get_session_error_code().
+ * @return MC_DRV_ERR_NOTIFICATION if a problem with the socket occurred.
+ * @return MC_DRV_INVALID_PARAMETER if a parameter is invalid.
+ * @return MC_DRV_ERR_UNKNOWN_SESSION when session id is invalid.
+ * @return MC_DRV_ERR_UNKNOWN_DEVICE when device id of session is invalid.
+ */
+__MC_CLIENT_LIB_API enum mc_result mc_wait_notification(
+ struct mc_session_handle *session,
+ int32_t timeout
+);
+
+/**
+ * Allocate a block of world shared memory (WSM).
+ * The MC driver allocates a contiguous block of memory which can be used as
+ * WSM.
+ * This implicates that the allocated memory is aligned according to the
+ * alignment parameter.
+ * Always returns a buffer of size WSM_SIZE aligned to 4K.
+ *
+ * @param [in] device_id The ID of an opened device to retrieve the WSM from.
+ * @param [in] align The alignment (number of pages) of the memory block
+ * (e.g. 0x00000001 for 4kb).
+ * @param [in] len Length of the block in bytes.
+ * @param [out] wsm Virtual address of the world shared memory block.
+ * @param [in] wsm_flags Platform specific flags describing the memory to
+ * be allocated.
+ *
+ * @attention: align and wsm_flags are currently ignored
+ *
+ * @return MC_DRV_OK if operation has been successfully completed.
+ * @return MC_DRV_INVALID_PARAMETER if a parameter is invalid.
+ * @return MC_DRV_ERR_UNKNOWN_DEVICE when device id is invalid.
+ * @return MC_DRV_ERR_NO_FREE_MEMORY if no more contiguous memory is available
+ * in this size or for this process.
+ *
+ * Uses a Mutex.
+ */
+__MC_CLIENT_LIB_API enum mc_result mc_malloc_wsm(
+ uint32_t device_id,
+ uint32_t align,
+ uint32_t len,
+ uint8_t **wsm,
+ uint32_t wsm_flags
+);
+
+/**
+ * Free a block of world shared memory (WSM).
+ * The MC driver will free a block of world shared memory (WSM) previously
+ * allocated with mc_malloc_wsm(). The caller has to assure that the address
+ * handed over to the driver is a valid WSM address.
+ *
+ * @param [in] device_id The ID to which the given address belongs.
+ * @param [in] wsm Address of WSM block to be freed.
+ *
+ * @return MC_DRV_OK if operation has been successfully completed.
+ * @return MC_DRV_INVALID_PARAMETER if a parameter is invalid.
+ * @return MC_DRV_ERR_UNKNOWN_DEVICE when device id is invalid.
+ * @return MC_DRV_ERR_FREE_MEMORY_FAILED on failures.
+ *
+ * Uses a Mutex.
+ */
+__MC_CLIENT_LIB_API enum mc_result mc_free_wsm(
+ uint32_t device_id,
+ uint8_t *wsm
+);
+
+/**
+ * Map additional bulk buffer between a Trustlet Connector (TLC) and
+ * the Trustlet (TL) for a session.
+ * Memory allocated in user space of the TLC can be mapped as additional
+ * communication channel (besides TCI) to the Trustlet. Limitation of the
+ * Trustlet memory structure apply: only 6 chunks can be mapped with a maximum
+ * chunk size of 1 MiB each.
+ *
+ * @attention It is up to the application layer (TLC) to inform the Trustlet
+ * about the additional mapped bulk memory.
+ *
+ * @param [in] session Session handle with information of the device_id and
+ * the session_id. The
+ * given buffer is mapped to the session specified in the sessionHandle.
+ * @param [in] buf Virtual address of a memory portion (relative to TLC)
+ * to be shared with the Trustlet, already includes a possible offset!
+ * @param [in] len length of buffer block in bytes.
+ * @param [out] map_info Information structure about the mapped Bulk buffer
+ * between the TLC (Nwd) and
+ * the TL (Swd).
+ *
+ * @return MC_DRV_OK if operation has been successfully completed.
+ * @return MC_DRV_INVALID_PARAMETER if a parameter is invalid.
+ * @return MC_DRV_ERR_UNKNOWN_SESSION when session id is invalid.
+ * @return MC_DRV_ERR_UNKNOWN_DEVICE when device id of session is invalid.
+ * @return MC_DRV_ERR_DAEMON_UNREACHABLE when problems with daemon occur.
+ * @return MC_DRV_ERR_BULK_MAPPING when buf is already uses as bulk buffer or
+ * when registering the buffer failed.
+ *
+ * Uses a Mutex.
+ */
+__MC_CLIENT_LIB_API enum mc_result mc_map(
+ struct mc_session_handle *session,
+ void *buf,
+ uint32_t len,
+ struct mc_bulk_map *map_info
+);
+
+/**
+ * Remove additional mapped bulk buffer between Trustlet Connector (TLC)
+ * and the Trustlet (TL) for a session.
+ *
+ * @attention The bulk buffer will immediately be unmapped from the session
+ * context.
+ * @attention The application layer (TLC) must inform the TL about unmapping
+ * of the additional bulk memory before calling mc_unmap!
+ *
+ * @param [in] session Session handle with information of the device_id and
+ * the session_id. The given buffer is unmapped from the session specified
+ * in the sessionHandle.
+ * @param [in] buf Virtual address of a memory portion (relative to TLC)
+ * shared with the TL, already includes a possible offset!
+ * @param [in] map_info Information structure about the mapped Bulk buffer
+ * between the TLC (Nwd) and
+ * the TL (Swd).
+ * @attention The clientlib currently ignores the len field in map_info.
+ *
+ * @return MC_DRV_OK if operation has been successfully completed.
+ * @return MC_DRV_INVALID_PARAMETER if a parameter is invalid.
+ * @return MC_DRV_ERR_UNKNOWN_SESSION when session id is invalid.
+ * @return MC_DRV_ERR_UNKNOWN_DEVICE when device id of session is invalid.
+ * @return MC_DRV_ERR_DAEMON_UNREACHABLE when problems with daemon occur.
+ * @return MC_DRV_ERR_BULK_UNMAPPING when buf was not registered earlier
+ * or when unregistering failed.
+ *
+ * Uses a Mutex.
+ */
+__MC_CLIENT_LIB_API enum mc_result mc_unmap(
+ struct mc_session_handle *session,
+ void *buf,
+ struct mc_bulk_map *map_info
+);
+
+
+/**
+ * @attention: Not implemented.
+ * Execute driver specific command.
+ * mc_driver_ctrl() can be used to execute driver specific commands.
+ * Besides the control command MC_CTRL_GET_VERSION commands are implementation
+ * specific.
+ * Please refer to the corresponding specification of the driver manufacturer.
+ *
+ * @param [in] param Command ID of the command to be executed.
+ * @param [in, out] data Command data and response depending on command.
+ * @param [in] len Length of the data block.
+ *
+ * @return MC_DRV_ERR_NOT_IMPLEMENTED.
+ */
+__MC_CLIENT_LIB_API enum mc_result mc_driver_ctrl(
+ enum mc_driver_ctrl param,
+ uint8_t *data,
+ uint32_t len
+);
+
+/**
+ * @attention: Not implemented.
+ * Execute application management command.
+ * mc_manage() shall be used to exchange application management commands with
+ * the MobiCore.
+ * The MobiCore Application Management Protocol is described in [MCAMP].
+ *
+ * @param [in] device_id Identifier for the MobiCore device to be used.
+ * NULL refers to the default device.
+ * @param [in, out] data Command data/response data depending on command.
+ * @param [in] len Length of the data block.
+ *
+ * @return MC_DRV_ERR_NOT_IMPLEMENTED.
+ */
+__MC_CLIENT_LIB_API enum mc_result mc_manage(
+ uint32_t device_id,
+ uint8_t *data,
+ uint32_t len
+);
+
+/**
+ * Get additional error information of the last error that occured on a session.
+ * After the request the stored error code will be deleted.
+ *
+ * @param [in] session Session handle with information of the device_id and
+ * the session_id.
+ * @param [out] last_error >0 Trustlet has terminated itself with this value,
+ * <0 Trustlet is dead because of an error within the MobiCore
+ * (e.g. Kernel exception).
+ * See also MCI definition.
+ *
+ * @return MC_DRV_OK if operation has been successfully completed.
+ * @return MC_DRV_INVALID_PARAMETER if a parameter is invalid.
+ * @return MC_DRV_ERR_UNKNOWN_SESSION when session id is invalid.
+ * @return MC_DRV_ERR_UNKNOWN_DEVICE when device id of session is invalid.
+ */
+__MC_CLIENT_LIB_API enum mc_result mc_get_session_error_code(
+ struct mc_session_handle *session,
+ int32_t *last_error
+);
+
+#endif /** MCDRIVER_H_ */
+
+/** @} */
diff --git a/drivers/gud/MobiCoreKernelApi/public/mobicore_driver_cmd.h b/drivers/gud/MobiCoreKernelApi/public/mobicore_driver_cmd.h
new file mode 100644
index 0000000..812971c
--- /dev/null
+++ b/drivers/gud/MobiCoreKernelApi/public/mobicore_driver_cmd.h
@@ -0,0 +1,291 @@
+/** @addtogroup MCD_MCDIMPL_DAEMON
+ * @{
+ * @file
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef MCDAEMON_H_
+#define MCDAEMON_H_
+
+
+
+
+#include "mcuuid.h"
+
+enum mc_drv_cmd_t {
+ MC_DRV_CMD_PING = 0,
+ MC_DRV_CMD_GET_INFO = 1,
+ MC_DRV_CMD_OPEN_DEVICE = 2,
+ MC_DRV_CMD_CLOSE_DEVICE = 3,
+ MC_DRV_CMD_NQ_CONNECT = 4,
+ MC_DRV_CMD_OPEN_SESSION = 5,
+ MC_DRV_CMD_CLOSE_SESSION = 6,
+ MC_DRV_CMD_NOTIFY = 7,
+ MC_DRV_CMD_MAP_BULK_BUF = 8,
+ MC_DRV_CMD_UNMAP_BULK_BUF = 9
+};
+
+
+enum mc_drv_rsp_t {
+ MC_DRV_RSP_OK = 0,
+ MC_DRV_RSP_FAILED = 1,
+ MC_DRV_RSP_DEVICE_NOT_OPENED = 2,
+ MC_DRV_RSP_DEVICE_ALREADY_OPENED = 3,
+ MC_DRV_RSP_COMMAND_NOT_ALLOWED = 4,
+ MC_DRV_INVALID_DEVICE_NAME = 5,
+ MC_DRV_RSP_MAP_BULK_ERRO = 6,
+ MC_DRV_RSP_TRUSTLET_NOT_FOUND = 7,
+ MC_DRV_RSP_PAYLOAD_LENGTH_ERROR = 8,
+};
+
+
+struct mc_drv_command_header_t {
+ uint32_t command_id;
+};
+
+struct mc_drv_response_header_t {
+ uint32_t response_id;
+};
+
+#define MC_DEVICE_ID_DEFAULT 0 /**< The default device ID */
+
+
+/*****************************************************************************/
+struct mc_drv_cmd_open_device_payload_t {
+ uint32_t device_id;
+};
+
+struct mc_drv_cmd_open_device_t {
+ struct mc_drv_command_header_t header;
+ struct mc_drv_cmd_open_device_payload_t payload;
+};
+
+
+struct mc_drv_rsp_open_device_payload_t {
+ /* empty */
+};
+
+struct mc_drv_rsp_open_device_t {
+ struct mc_drv_response_header_t header;
+ struct mc_drv_rsp_open_device_payload_t payload;
+};
+
+
+/*****************************************************************************/
+struct mc_drv_cmd_close_device_t {
+ struct mc_drv_command_header_t header;
+ /* no payload here because close has none.
+ If we use an empty struct, C++ will count it as 4 bytes.
+ This will write too much into the socket at write(cmd,sizeof(cmd)) */
+};
+
+
+struct mc_drv_rsp_close_device_payload_t {
+ /* empty */
+};
+
+struct mc_drv_rsp_close_device_t {
+ struct mc_drv_response_header_t header;
+ struct mc_drv_rsp_close_device_payload_t payload;
+};
+
+
+/*****************************************************************************/
+struct mc_drv_cmd_open_session_payload_t {
+ uint32_t device_id;
+ struct mc_uuid_t uuid;
+ uint32_t tci;
+ uint32_t len;
+};
+
+struct mc_drv_cmd_open_session_t {
+ struct mc_drv_command_header_t header;
+ struct mc_drv_cmd_open_session_payload_t payload;
+};
+
+
+struct mc_drv_rsp_open_session_payload_t {
+ uint32_t device_id;
+ uint32_t session_id;
+ uint32_t device_session_id;
+ uint32_t mc_result;
+ uint32_t session_magic;
+};
+
+struct mc_drv_rsp_open_session_t {
+ struct mc_drv_response_header_t header;
+ struct mc_drv_rsp_open_session_payload_t payload;
+};
+
+
+/*****************************************************************************/
+struct mc_drv_cmd_close_session_payload_t {
+ uint32_t session_id;
+};
+
+struct mc_drv_cmd_close_session_t {
+ struct mc_drv_command_header_t header;
+ struct mc_drv_cmd_close_session_payload_t payload;
+};
+
+
+struct mc_drv_rsp_close_session_payload_t {
+ /* empty */
+};
+
+struct mc_drv_rsp_close_session_t {
+ struct mc_drv_response_header_t header;
+ struct mc_drv_rsp_close_session_payload_t payload;
+};
+
+
+/*****************************************************************************/
+struct mc_drv_cmd_notify_payload_t {
+ uint32_t session_id;
+};
+
+struct mc_drv_cmd_notify_t {
+ struct mc_drv_command_header_t header;
+ struct mc_drv_cmd_notify_payload_t payload;
+};
+
+
+struct mc_drv_rsp_notify_payload_t {
+ /* empty */
+};
+
+struct mc_drv_rsp_notify_t {
+ struct mc_drv_response_header_t header;
+ struct mc_drv_rsp_notify_payload_t payload;
+};
+
+
+/*****************************************************************************/
+struct mc_drv_cmd_map_bulk_mem_payload_t {
+ uint32_t session_id;
+ uint32_t handle;
+ uint32_t phys_addr_l2;
+ uint32_t offset_payload;
+ uint32_t len_bulk_mem;
+};
+
+struct mc_drv_cmd_map_bulk_mem_t {
+ struct mc_drv_command_header_t header;
+ struct mc_drv_cmd_map_bulk_mem_payload_t payload;
+};
+
+
+struct mc_drv_rsp_map_bulk_mem_payload_t {
+ uint32_t session_id;
+ uint32_t secure_virtual_adr;
+ uint32_t mc_result;
+};
+
+struct mc_drv_rsp_map_bulk_mem_t {
+ struct mc_drv_response_header_t header;
+ struct mc_drv_rsp_map_bulk_mem_payload_t payload;
+};
+
+
+/*****************************************************************************/
+struct mc_drv_cmd_unmap_bulk_mem_payload_t {
+ uint32_t session_id;
+ uint32_t handle;
+ uint32_t secure_virtual_adr;
+ uint32_t len_bulk_mem;
+};
+
+struct mc_drv_cmd_unmap_bulk_mem_t {
+ struct mc_drv_command_header_t header;
+ struct mc_drv_cmd_unmap_bulk_mem_payload_t payload;
+};
+
+
+struct mc_drv_rsp_unmap_bulk_mem_payload_t {
+ uint32_t response_id;
+ uint32_t session_id;
+ uint32_t mc_result;
+};
+
+struct mc_drv_rsp_unmap_bulk_mem_t {
+ struct mc_drv_response_header_t header;
+ struct mc_drv_rsp_unmap_bulk_mem_payload_t payload;
+};
+
+
+/*****************************************************************************/
+struct mc_drv_cmd_nqconnect_payload_t {
+ uint32_t device_id;
+ uint32_t session_id;
+ uint32_t device_session_id;
+ uint32_t session_magic; /* Random data */
+};
+
+struct mc_drv_cmd_nqconnect_t {
+ struct mc_drv_command_header_t header;
+ struct mc_drv_cmd_nqconnect_payload_t payload;
+};
+
+
+struct mc_drv_rsp_nqconnect_payload_t {
+ /* empty; */
+};
+
+struct mc_drv_rsp_nqconnect_t {
+ struct mc_drv_response_header_t header;
+ struct mc_drv_rsp_nqconnect_payload_t payload;
+};
+
+
+/*****************************************************************************/
+union mc_drv_command_t {
+ struct mc_drv_command_header_t header;
+ struct mc_drv_cmd_open_device_t mc_drv_cmd_open_device;
+ struct mc_drv_cmd_close_device_t mc_drv_cmd_close_device;
+ struct mc_drv_cmd_open_session_t mc_drv_cmd_open_session;
+ struct mc_drv_cmd_close_session_t mc_drv_cmd_close_session;
+ struct mc_drv_cmd_nqconnect_t mc_drv_cmd_nqconnect;
+ struct mc_drv_cmd_notify_t mc_drv_cmd_notify;
+ struct mc_drv_cmd_map_bulk_mem_t mc_drv_cmd_map_bulk_mem;
+ struct mc_drv_cmd_unmap_bulk_mem_t mc_drv_cmd_unmap_bulk_mem;
+};
+
+union mc_drv_response_t {
+ struct mc_drv_response_header_t header;
+ struct mc_drv_rsp_open_device_t mc_drv_rsp_open_device;
+ struct mc_drv_rsp_close_device_t mc_drv_rsp_close_device;
+ struct mc_drv_rsp_open_session_t mc_drv_rsp_open_session;
+ struct mc_drv_rsp_close_session_t mc_drv_rsp_close_session;
+ struct mc_drv_rsp_nqconnect_t mc_drv_rsp_nqconnect;
+ struct mc_drv_rsp_notify_t mc_drv_rsp_notify;
+ struct mc_drv_rsp_map_bulk_mem_t mc_drv_rsp_map_bulk_mem;
+ struct mc_drv_rsp_unmap_bulk_mem_t mc_drv_rsp_unmap_bulk_mem;
+};
+
+#endif /* MCDAEMON_H_ */
+
+/** @} */
diff --git a/drivers/gud/MobiCoreKernelApi/session.c b/drivers/gud/MobiCoreKernelApi/session.c
new file mode 100644
index 0000000..d11e870
--- /dev/null
+++ b/drivers/gud/MobiCoreKernelApi/session.c
@@ -0,0 +1,224 @@
+/** @addtogroup MCD_IMPL_LIB
+ * @{
+ * @file
+ * <!-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
+ *
+ * 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.
+ */
+#include <linux/types.h>
+#include <linux/slab.h>
+#include "mc_kernel_api.h"
+#include "public/mobicore_driver_api.h"
+
+#include "session.h"
+
+/*****************************************************************************/
+struct bulk_buffer_descriptor *bulk_buffer_descriptor_create(
+ void *virt_addr,
+ uint32_t len,
+ uint32_t handle,
+ void *phys_addr_wsm_l2
+) {
+ struct bulk_buffer_descriptor *desc =
+ kzalloc(sizeof(struct bulk_buffer_descriptor), GFP_KERNEL);
+ desc->virt_addr = virt_addr;
+ desc->len = len;
+ desc->handle = handle;
+ desc->phys_addr_wsm_l2 = phys_addr_wsm_l2;
+ return desc;
+}
+
+/*****************************************************************************/
+struct session *session_create(
+ uint32_t session_id,
+ void *instance,
+ struct connection *connection
+) {
+ struct session *session =
+ kzalloc(sizeof(struct session), GFP_KERNEL);
+ session->session_id = session_id;
+ session->instance = instance;
+ session->notification_connection = connection;
+
+ session->session_info.last_error = SESSION_ERR_NO;
+ session->session_info.state = SESSION_STATE_INITIAL;
+
+ INIT_LIST_HEAD(&(session->bulk_buffer_descriptors));
+ return session;
+}
+
+
+/*****************************************************************************/
+void session_cleanup(
+ struct session *session
+) {
+ struct bulk_buffer_descriptor *bulk_buf_descr;
+ struct list_head *pos, *q;
+
+ /* Unmap still mapped buffers */
+ list_for_each_safe(pos, q, &session->bulk_buffer_descriptors) {
+ bulk_buf_descr =
+ list_entry(pos, struct bulk_buffer_descriptor, list);
+
+ MCDRV_DBG_VERBOSE("Physical Address of L2 Table = 0x%X, "
+ "handle= %d",
+ (unsigned int)bulk_buf_descr->phys_addr_wsm_l2,
+ bulk_buf_descr->handle);
+
+ /* ignore any error, as we cannot do anything in this case. */
+ int ret = mobicore_unmap_vmem(session->instance,
+ bulk_buf_descr->handle);
+ if (ret != 0)
+ MCDRV_DBG_ERROR("mobicore_unmap_vmem failed: %d", ret);
+
+ list_del(pos);
+ kfree(bulk_buf_descr);
+ }
+
+ /* Finally delete notification connection */
+ connection_cleanup(session->notification_connection);
+ kfree(session);
+}
+
+
+/*****************************************************************************/
+void session_set_error_info(
+ struct session *session,
+ int32_t err
+) {
+ session->session_info.last_error = err;
+}
+
+
+/*****************************************************************************/
+int32_t session_get_last_err(
+ struct session *session
+) {
+ return session->session_info.last_error;
+}
+
+
+/*****************************************************************************/
+struct bulk_buffer_descriptor *session_add_bulk_buf(
+ struct session *session,
+ void *buf,
+ uint32_t len
+) {
+ struct bulk_buffer_descriptor *bulk_buf_descr = NULL;
+ struct bulk_buffer_descriptor *tmp;
+ struct list_head *pos;
+
+ /* Search bulk buffer descriptors for existing vAddr
+ At the moment a virtual address can only be added one time */
+ list_for_each(pos, &session->bulk_buffer_descriptors) {
+ tmp = list_entry(pos, struct bulk_buffer_descriptor, list);
+ if (tmp->virt_addr == buf)
+ return NULL;
+ }
+
+ do {
+ /* Prepare the interface structure for memory registration in
+ Kernel Module */
+ uint32_t l2_table_phys;
+ uint32_t handle;
+
+ int ret = mobicore_map_vmem(session->instance,
+ buf,
+ len,
+ &handle,
+ &l2_table_phys);
+
+ if (ret != 0) {
+ MCDRV_DBG_ERROR("mobicore_map_vmem failed, ret=%d",
+ ret);
+ break;
+ }
+
+ MCDRV_DBG_VERBOSE("Physical Address of L2 Table = 0x%X, "
+ "handle=%d",
+ (unsigned int)l2_table_phys,
+ handle);
+
+ /* Create new descriptor */
+ bulk_buf_descr = bulk_buffer_descriptor_create(
+ buf,
+ len,
+ handle,
+ (void*)l2_table_phys);
+
+ /* Add to vector of descriptors */
+ list_add_tail(&(bulk_buf_descr->list),
+ &(session->bulk_buffer_descriptors));
+ } while (0);
+
+ return bulk_buf_descr;
+}
+
+
+/*****************************************************************************/
+bool session_remove_bulk_buf(
+ struct session *session,
+ void *virt_addr
+) {
+ bool ret = true;
+ struct bulk_buffer_descriptor *bulk_buf_descr = NULL;
+ struct bulk_buffer_descriptor *tmp;
+ struct list_head *pos, *q;
+
+ MCDRV_DBG_VERBOSE("Virtual Address = 0x%X", (unsigned int) virt_addr);
+
+ /* Search and remove bulk buffer descriptor */
+ list_for_each_safe(pos, q, &session->bulk_buffer_descriptors) {
+ tmp = list_entry(pos, struct bulk_buffer_descriptor, list);
+ if (tmp->virt_addr == virt_addr) {
+ bulk_buf_descr = tmp;
+ list_del(pos);
+ break;
+ }
+ }
+
+ if (bulk_buf_descr == NULL) {
+ MCDRV_DBG_ERROR("Virtual Address not found");
+ ret = false;
+ } else {
+ MCDRV_DBG_VERBOSE("WsmL2 phys=0x%X, handle=%d",
+ (unsigned int)bulk_buf_descr->phys_addr_wsm_l2,
+ bulk_buf_descr->handle);
+
+ /* ignore any error, as we cannot do anything */
+ int ret = mobicore_unmap_vmem(session->instance,
+ bulk_buf_descr->handle);
+ if (ret != 0)
+ MCDRV_DBG_ERROR("mobicore_unmap_vmem failed: %d", ret);
+
+ kfree(bulk_buf_descr);
+ }
+
+ return ret;
+}
+
+/*****************************************************************************/
+uint32_t session_find_bulk_buf(
+ struct session *session,
+ void *virt_addr
+) {
+ struct bulk_buffer_descriptor *tmp;
+ struct list_head *pos, *q;
+
+ MCDRV_DBG_VERBOSE("Virtual Address = 0x%X", (unsigned int) virt_addr);
+
+ /* Search and return buffer descriptor handle */
+ list_for_each_safe(pos, q, &session->bulk_buffer_descriptors) {
+ tmp = list_entry(pos, struct bulk_buffer_descriptor, list);
+ if (tmp->virt_addr == virt_addr) {
+ return tmp->handle;
+ }
+ }
+
+
+ return 0;
+}
+
+/** @} */
diff --git a/drivers/gud/MobiCoreKernelApi/session.h b/drivers/gud/MobiCoreKernelApi/session.h
new file mode 100644
index 0000000..b2df0397
--- /dev/null
+++ b/drivers/gud/MobiCoreKernelApi/session.h
@@ -0,0 +1,149 @@
+/** @addtogroup MCD_IMPL_LIB
+ * @{
+ * @file
+ * <!-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
+ *
+ * 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.
+ */
+#ifndef SESSION_H_
+#define SESSION_H_
+
+#include "common.h"
+
+#include <linux/list.h>
+#include "connection.h"
+
+
+struct bulk_buffer_descriptor {
+ void *virt_addr;/**< The virtual address of the Bulk buffer*/
+ uint32_t len; /**< Length of the Bulk buffer*/
+ uint32_t handle;
+ void *phys_addr_wsm_l2; /**< The physical address of the
+ L2 table of the Bulk buffer*/
+ struct list_head list; /**< The list param for using the kernel lists*/
+};
+
+struct bulk_buffer_descriptor *bulk_buffer_descriptor_create(
+ void *virt_addr,
+ uint32_t len,
+ uint32_t handle,
+ void *phys_addr_wsm_l2
+);
+
+/** Session states.
+ * At the moment not used !!.
+ */
+enum session_state {
+ SESSION_STATE_INITIAL,
+ SESSION_STATE_OPEN,
+ SESSION_STATE_TRUSTLET_DEAD
+};
+
+#define SESSION_ERR_NO 0 /**< No session error */
+
+/** Session information structure.
+ * The information structure is used to hold the state of the session, which
+ * will limit further actions for the session.
+ * Also the last error code will be stored till it's read.
+ */
+struct session_information {
+ enum session_state state; /**< Session state */
+ int32_t last_error; /**< Last error of session */
+};
+
+
+struct session {
+ struct mc_instance *instance;
+ /**< Descriptors of additional bulk buffer of a session */
+ struct list_head bulk_buffer_descriptors;
+ /**< Informations about session */
+ struct session_information session_info;
+
+ uint32_t session_id;
+ struct connection *notification_connection;
+
+ /**< The list param for using the kernel lists*/
+ struct list_head list;
+};
+
+struct session *session_create(
+ uint32_t session_id,
+ void *instance,
+ struct connection *connection
+);
+
+void session_cleanup(
+ struct session *session
+);
+
+/**
+ * Add address information of additional bulk buffer memory to session and
+ * register virtual memory in kernel module.
+ *
+ * @attention The virtual address can only be added one time. If the virtual
+ * address already exist, NULL is returned.
+ *
+ * @param buf The virtual address of bulk buffer.
+ * @param len Length of bulk buffer.
+ *
+ * @return On success the actual Bulk buffer descriptor with all address
+ * information is retured, NULL if an error occurs.
+ */
+struct bulk_buffer_descriptor *session_add_bulk_buf(
+ struct session *session,
+ void *buf,
+ uint32_t len
+);
+
+/**
+ * Remove address information of additional bulk buffer memory from session and
+ * unregister virtual memory in kernel module
+ *
+ * @param buf The virtual address of the bulk buffer.
+ *
+ * @return true on success.
+ */
+bool session_remove_bulk_buf(
+ struct session *session,
+ void *buf
+);
+
+/**
+ * Find the handle of the bulk buffer for this session
+ *
+ * @param buf The virtual address of bulk buffer.
+ *
+ * @return On success the actual Bulk buffer handle is retured, 0
+ * if an error occurs.
+ */
+uint32_t session_find_bulk_buf(
+ struct session *session,
+ void *virt_addr
+);
+
+/**
+ * Set additional error information of the last error that occured.
+ *
+ * @param errorCode The actual error.
+ */
+void session_set_error_info(
+ struct session *session,
+ int32_t err
+);
+
+/**
+ * Get additional error information of the last error that occured.
+ *
+ * @attention After request the information is set to SESSION_ERR_NO.
+ *
+ * @return Last stored error code or SESSION_ERR_NO.
+ */
+int32_t session_get_last_err(
+ struct session *session
+);
+
+#endif /* SESSION_H_ */
+
+/** @} */
diff --git a/drivers/gud/MobiCoreKernelApi/wsm.h b/drivers/gud/MobiCoreKernelApi/wsm.h
new file mode 100644
index 0000000..6877c53
--- /dev/null
+++ b/drivers/gud/MobiCoreKernelApi/wsm.h
@@ -0,0 +1,35 @@
+/** @addtogroup MCD_MCDIMPL_DAEMON_SRV
+ * @{
+ * @file
+ *
+ * World shared memory definitions.
+ *
+ * <!-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
+ *
+ * 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.
+ */
+#ifndef WSM_H_
+#define WSM_H_
+
+#include "common.h"
+#include <linux/list.h>
+
+struct wsm {
+ void *virt_addr;
+ uint32_t len;
+ uint32_t handle;
+ void *phys_addr;
+ struct list_head list;
+};
+
+struct wsm *wsm_create(
+ void *virt_addr,
+ uint32_t len,
+ uint32_t handle,
+ void *phys_addr /*= NULL this may be unknown, so is can be omitted.*/
+);
+#endif /* WSM_H_ */
+
+/** @} */
diff --git a/drivers/gud/build_tag.h b/drivers/gud/build_tag.h
new file mode 100644
index 0000000..e2a9029
--- /dev/null
+++ b/drivers/gud/build_tag.h
@@ -0,0 +1 @@
+#define MOBICORE_COMPONENT_BUILD_TAG "*** SAMSUNG Exynos 5250 MC1.2 V005 release ###"
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c
index 737f721..7268f00 100644
--- a/drivers/i2c/busses/i2c-s3c2410.c
+++ b/drivers/i2c/busses/i2c-s3c2410.c
@@ -62,7 +62,7 @@
struct s3c24xx_i2c {
spinlock_t lock;
wait_queue_head_t wait;
- unsigned int suspended:1;
+ bool is_suspended;
struct i2c_msg *msg;
unsigned int msg_num;
@@ -86,10 +86,22 @@
#ifdef CONFIG_CPU_FREQ
struct notifier_block freq_transition;
#endif
+ unsigned int freq;
};
/* default platform data removed, dev should always carry data. */
+static inline void dump_i2c_register(struct s3c24xx_i2c *i2c)
+{
+ dev_dbg(i2c->dev, "Register dump(%d) : %x %x %x %x %x\n"
+ , i2c->is_suspended
+ , readl(i2c->regs + S3C2410_IICCON)
+ , readl(i2c->regs + S3C2410_IICSTAT)
+ , readl(i2c->regs + S3C2410_IICADD)
+ , readl(i2c->regs + S3C2410_IICDS)
+ , readl(i2c->regs + S3C2440_IICLC));
+}
+
/* s3c24xx_i2c_is2440()
*
* return true is this is an s3c2440
@@ -212,18 +224,29 @@
static inline void s3c24xx_i2c_stop(struct s3c24xx_i2c *i2c, int ret)
{
- unsigned long iicstat = readl(i2c->regs + S3C2410_IICSTAT);
+ unsigned long iicstat;
+ unsigned long iiccon;
dev_dbg(i2c->dev, "STOP\n");
/* stop the transfer */
+
+ /* Disable irq */
+ s3c24xx_i2c_disable_irq(i2c);
+
+ /* STOP signal generation : MTx(0xD0) */
+ iicstat = readl(i2c->regs + S3C2410_IICSTAT);
iicstat &= ~S3C2410_IICSTAT_START;
writel(iicstat, i2c->regs + S3C2410_IICSTAT);
- i2c->state = STATE_STOP;
+ /* Clear pending bit */
+ iiccon = readl(i2c->regs + S3C2410_IICCON);
+ iiccon &= ~S3C2410_IICCON_IRQPEND;
+ writel(iiccon, i2c->regs + S3C2410_IICCON);
s3c24xx_i2c_master_complete(i2c, ret);
- s3c24xx_i2c_disable_irq(i2c);
+
+ i2c->state = STATE_STOP;
}
/* helper functions to determine the current state in the set of
@@ -435,6 +458,8 @@
unsigned long status;
unsigned long tmp;
+ spin_lock(&i2c->lock);
+
status = readl(i2c->regs + S3C2410_IICSTAT);
if (status & S3C2410_IICSTAT_ARBITR) {
@@ -457,6 +482,8 @@
i2c_s3c_irq_nextbyte(i2c, status);
out:
+ spin_unlock(&i2c->lock);
+
return IRQ_HANDLED;
}
@@ -477,7 +504,7 @@
if (!(iicstat & S3C2410_IICSTAT_BUSBUSY))
return 0;
- msleep(1);
+ usleep_range(1000, 2000);
}
return -ETIMEDOUT;
@@ -495,12 +522,13 @@
int spins = 20;
int ret;
- if (i2c->suspended)
+ if (i2c->is_suspended)
return -EIO;
ret = s3c24xx_i2c_set_master(i2c);
if (ret != 0) {
dev_err(i2c->dev, "cannot get bus (error %d)\n", ret);
+ dump_i2c_register(i2c);
ret = -EAGAIN;
goto out;
}
@@ -524,10 +552,13 @@
/* having these next two as dev_err() makes life very
* noisy when doing an i2cdetect */
- if (timeout == 0)
+ if (timeout == 0) {
dev_dbg(i2c->dev, "timeout\n");
- else if (ret != num)
+ dump_i2c_register(i2c);
+ } else if (ret != num) {
dev_dbg(i2c->dev, "incomplete xfer (%d)\n", ret);
+ dump_i2c_register(i2c);
+ }
/* ensure the stop has been through the bus */
@@ -537,16 +568,32 @@
do {
cpu_relax();
iicstat = readl(i2c->regs + S3C2410_IICSTAT);
- } while ((iicstat & S3C2410_IICSTAT_START) && --spins);
+ } while ((iicstat & S3C2410_IICSTAT_BUSBUSY) && --spins);
/* if that timed out sleep */
if (!spins) {
- msleep(1);
+ usleep_range(1000, 2000);
iicstat = readl(i2c->regs + S3C2410_IICSTAT);
}
- if (iicstat & S3C2410_IICSTAT_START)
- dev_warn(i2c->dev, "timeout waiting for bus idle\n");
+ /* if still not finished, clean it up */
+ spin_lock_irq(&i2c->lock);
+ if (iicstat & S3C2410_IICSTAT_BUSBUSY) {
+ dev_dbg(i2c->dev, "timeout waiting for bus idle\n");
+ dump_i2c_register(i2c);
+
+ if (i2c->state != STATE_STOP) {
+ dev_dbg(i2c->dev,
+ "timeout : i2c interrupt hasn't occurred\n");
+ s3c24xx_i2c_stop(i2c, 0);
+ }
+
+ /* Disable Serial Out : To forcely terminate the connection */
+ iicstat = readl(i2c->regs + S3C2410_IICSTAT);
+ iicstat &= ~S3C2410_IICSTAT_TXRXEN;
+ writel(iicstat, i2c->regs + S3C2410_IICSTAT);
+ }
+ spin_unlock_irq(&i2c->lock);
out:
return ret;
@@ -565,6 +612,12 @@
int retry;
int ret;
+ if (i2c->is_suspended) {
+ dev_err(i2c->dev, "I2C is not initialzed.\n");
+ dump_i2c_register(i2c);
+ return -EIO;
+ }
+
pm_runtime_get_sync(&adap->dev);
clk_enable(i2c->clk);
@@ -638,7 +691,7 @@
* range of frequencies until something is found
*/
-static int s3c24xx_i2c_clockrate(struct s3c24xx_i2c *i2c, unsigned int *got)
+static int s3c24xx_i2c_clockrate(struct s3c24xx_i2c *i2c)
{
struct s3c2410_platform_i2c *pdata = i2c->pdata;
unsigned long clkin = clk_get_rate(i2c->clk);
@@ -665,7 +718,7 @@
return -EINVAL;
}
- *got = freq;
+ i2c->freq = freq;
iiccon = readl(i2c->regs + S3C2410_IICCON);
iiccon &= ~(S3C2410_IICCON_SCALEMASK | S3C2410_IICCON_TXDIV_512);
@@ -705,7 +758,6 @@
{
struct s3c24xx_i2c *i2c = freq_to_i2c(nb);
unsigned long flags;
- unsigned int got;
int delta_f;
int ret;
@@ -719,13 +771,13 @@
if ((val == CPUFREQ_POSTCHANGE && delta_f < 0) ||
(val == CPUFREQ_PRECHANGE && delta_f > 0)) {
spin_lock_irqsave(&i2c->lock, flags);
- ret = s3c24xx_i2c_clockrate(i2c, &got);
+ ret = s3c24xx_i2c_clockrate(i2c);
spin_unlock_irqrestore(&i2c->lock, flags);
if (ret < 0)
dev_err(i2c->dev, "cannot find frequency\n");
else
- dev_info(i2c->dev, "setting freq %d\n", got);
+ dev_info(i2c->dev, "setting freq %d\n", i2c->freq);
}
return 0;
@@ -808,7 +860,6 @@
{
unsigned long iicon = S3C2410_IICCON_IRQEN | S3C2410_IICCON_ACKEN;
struct s3c2410_platform_i2c *pdata;
- unsigned int freq;
/* get the plafrom data */
@@ -826,13 +877,11 @@
writeb(pdata->slave_addr, i2c->regs + S3C2410_IICADD);
- dev_info(i2c->dev, "slave address 0x%02x\n", pdata->slave_addr);
-
writel(iicon, i2c->regs + S3C2410_IICCON);
/* we need to work out the divisors for the clock... */
- if (s3c24xx_i2c_clockrate(i2c, &freq) != 0) {
+ if (s3c24xx_i2c_clockrate(i2c) != 0) {
writel(0, i2c->regs + S3C2410_IICCON);
dev_err(i2c->dev, "cannot meet bus frequency required\n");
return -EINVAL;
@@ -840,7 +889,6 @@
/* todo - check that the i2c lines aren't being dragged anywhere */
- dev_info(i2c->dev, "bus frequency set to %d KHz\n", freq);
dev_dbg(i2c->dev, "S3C2410_IICCON=0x%02lx\n", iicon);
return 0;
@@ -1021,6 +1069,8 @@
pm_runtime_enable(&i2c->adap.dev);
dev_info(&pdev->dev, "%s: S3C I2C adapter\n", dev_name(&i2c->adap.dev));
+ dev_info(i2c->dev, "slave address 0x%02x\n", pdata->slave_addr);
+ dev_info(i2c->dev, "bus frequency set to %d KHz\n", i2c->freq);
clk_disable(i2c->clk);
return 0;
@@ -1080,7 +1130,9 @@
struct platform_device *pdev = to_platform_device(dev);
struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev);
- i2c->suspended = 1;
+ i2c_lock_adapter(&i2c->adap);
+ i2c->is_suspended = true;
+ i2c_unlock_adapter(&i2c->adap);
return 0;
}
@@ -1089,12 +1141,25 @@
{
struct platform_device *pdev = to_platform_device(dev);
struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev);
+ int ret;
- i2c->suspended = 0;
+ i2c_lock_adapter(&i2c->adap);
+
clk_enable(i2c->clk);
- s3c24xx_i2c_init(i2c);
+
+ ret = s3c24xx_i2c_init(i2c);
+ if (ret) {
+ i2c_unlock_adapter(&i2c->adap);
+ clk_disable(i2c->clk);
+ return ret;
+ }
+
clk_disable(i2c->clk);
+ i2c->is_suspended = false;
+
+ i2c_unlock_adapter(&i2c->adap);
+
return 0;
}
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 1e7c563..7584c2b 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -220,6 +220,16 @@
To compile this driver as a module, choose M here: the
module will be called eeti_ts.
+config TOUCHSCREEN_EGALAX_I2C
+ tristate "EETI eGalax multi-touch panel support with I2C"
+ depends on I2C
+ help
+ Say Y here to enable support for I2C connected EETI
+ eGalax multi-touch panels.
+
+ To compile this driver as a module, choose M here: the
+ module will be called egalax_ts.
+
config TOUCHSCREEN_EGALAX
tristate "EETI eGalax multi-touch panel support"
depends on I2C
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 175d641..9fe9f75 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -27,6 +27,7 @@
obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o
obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o
obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o
+obj-$(CONFIG_TOUCHSCREEN_EGALAX_I2C) += egalax_i2c.o
obj-$(CONFIG_TOUCHSCREEN_EGALAX) += egalax_ts.o
obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o
obj-$(CONFIG_TOUCHSCREEN_ILI210X) += ili210x.o
diff --git a/drivers/input/touchscreen/egalax_i2c.c b/drivers/input/touchscreen/egalax_i2c.c
new file mode 100644
index 0000000..28e5669
--- /dev/null
+++ b/drivers/input/touchscreen/egalax_i2c.c
@@ -0,0 +1,945 @@
+/*
+ *
+ * Touch Screen I2C Driver for EETI Controller
+ *
+ * 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/freezer.h>
+#include <linux/proc_fs.h>
+#include <linux/clk.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/device.h>
+#include <linux/cdev.h>
+#include <linux/io.h>
+#include <asm/system.h>
+#include <linux/uaccess.h>
+#include <linux/poll.h>
+#include <linux/kfifo.h>
+#include <linux/version.h>
+#include <linux/input.h>
+#include <linux/irq.h>
+#include <linux/timer.h>
+#include <linux/proc_fs.h>
+#include <plat/gpio-cfg.h>
+#include <mach/gpio.h>
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+static struct early_suspend egalax_early_suspend;
+#endif
+
+/* Global define to enable function */
+#define _ENABLE_DBG_LEVEL
+
+static int global_major; /* dynamic major by default */
+static int global_minor;
+
+#define MAX_I2C_LEN 10
+#define FIFO_SIZE PAGE_SIZE
+#define MAX_SUPPORT_POINT 5
+#define REPORTID_MOUSE 0x01
+#define REPORTID_VENDOR 0x03
+#define REPORTID_MTOUCH 0x04
+
+/* ioctl command */
+#define EGALAX_IOC_MAGIC 0x72
+#define EGALAX_IOCWAKEUP _IO(EGALAX_IOC_MAGIC, 1)
+#define EGALAX_IOC_MAXNR 1
+
+/* running mode */
+#define MODE_STOP 0
+#define MODE_WORKING 1
+#define MODE_IDLE 2
+#define MODE_SUSPEND 3
+
+#define EGALAX_MAX 2048
+#define SCREEN_WIDTH 1280
+#define SCREEN_HIGH 800
+
+struct point_data {
+ short Status;
+ short X;
+ short Y;
+};
+
+struct _egalax_i2c {
+ struct workqueue_struct *ktouch_wq;
+ struct work_struct work_irq;
+ struct work_struct work_idle;
+ struct mutex mutex_wq;
+ struct i2c_client *client;
+ unsigned char work_state;
+ unsigned char skip_packet;
+ unsigned char downCnt;
+ struct timer_list idle_timer;
+};
+
+struct egalax_char_dev {
+ int OpenCnts;
+ struct cdev cdev;
+ struct kfifo DataKFiFo;
+ unsigned char *pFiFoBuf;
+ spinlock_t FiFoLock;
+ struct semaphore sem;
+ wait_queue_head_t fifo_inq;
+};
+
+static struct _egalax_i2c *p_egalax_i2c_dev;
+static struct egalax_char_dev *p_char_dev;
+static atomic_t egalax_char_available = ATOMIC_INIT(1);
+static atomic_t wait_command_ack = ATOMIC_INIT(0);
+static struct class *egalax_class;
+static struct input_dev *input_dev;
+static struct point_data PointBuf[MAX_SUPPORT_POINT];
+
+struct mutex i2c_lock;
+
+#define DBG_MODULE 0x00000001
+#define DBG_CDEV 0x00000002
+#define DBG_PROC 0x00000004
+#define DBG_POINT 0x00000008
+#define DBG_INT 0x00000010
+#define DBG_I2C 0x00000020
+#define DBG_SUSP 0x00000040
+#define DBG_INPUT 0x00000080
+#define DBG_CONST 0x00000100
+#define DBG_IDLE 0x00000200
+#define DBG_WAKEUP 0x00000400
+#define DBG_BUTTON 0x00000800
+static unsigned int DbgLevel; /* DBG_INT|DBG_MODULE|DBG_SUSP|DBG_WAKEUP */
+
+#ifdef _ENABLE_DBG_LEVEL
+ #define PROC_FS_NAME "egalax_dbg"
+ #define PROC_FS_MAX_LEN 8
+ static struct proc_dir_entry *dbgProcFile;
+#endif
+
+#define EGALAX_DBG(level, fmt, args...) { if ((level&DbgLevel) > 0) \
+ printk(KERN_INFO "[egalax_i2c]: " fmt, ## args); }
+#define IDLE_INTERVAL (HZ/20)
+
+static int sendLoopback(struct i2c_client *client)
+{
+ u8 cmdbuf[MAX_I2C_LEN] = {0x03, 0x03, 0x0A, 0x01, 0x41, 0, 0, 0, 0, 0};
+ int ret;
+ ret = 0;
+ mutex_lock(&i2c_lock);
+ if (i2c_master_send(client, cmdbuf, MAX_I2C_LEN) != MAX_I2C_LEN) {
+ ret = -1;
+ printk("TS-SendLoopback (I2C Write)Error\n");
+ }
+ mutex_unlock(&i2c_lock);
+ return ret;
+}
+
+static int wakeup_controller(int irq)
+{
+ int ret = 0;
+ int gpio = irq_to_gpio(p_egalax_i2c_dev->client->irq);
+
+ if (gpio_get_value(gpio)) {
+ gpio_direction_output(gpio, 0);
+ barrier();
+ mdelay(5);
+ }
+
+ gpio_direction_output(gpio, 1);
+ gpio_direction_input(gpio);
+ EGALAX_DBG(DBG_WAKEUP, " INT wakeup touch controller done\n");
+
+ return ret;
+}
+
+static int egalax_cdev_open(struct inode *inode, struct file *filp)
+{
+ struct egalax_char_dev *cdev;
+
+ cdev = container_of(inode->i_cdev, struct egalax_char_dev, cdev);
+ if (cdev == NULL) {
+ EGALAX_DBG(DBG_CDEV, "No such char device node\n");
+ return -ENODEV;
+ }
+
+ if (!atomic_dec_and_test(&egalax_char_available)) {
+ atomic_inc(&egalax_char_available);
+ return -EBUSY; /* already open */
+ }
+
+ cdev->OpenCnts++;
+ filp->private_data = cdev;/* Used by the read and write metheds */
+
+ /* check and wakeup controller if necessary */
+ del_timer_sync(&p_egalax_i2c_dev->idle_timer);
+ cancel_work_sync(&p_egalax_i2c_dev->work_idle);
+ if (p_egalax_i2c_dev->work_state == MODE_IDLE)
+ wakeup_controller(p_egalax_i2c_dev->client->irq);
+
+ EGALAX_DBG(DBG_CDEV, " CDev open done!\n");
+ try_module_get(THIS_MODULE);
+ return 0;
+}
+
+static int egalax_cdev_release(struct inode *inode, struct file *filp)
+{
+ struct egalax_char_dev *cdev;/* device information */
+
+ cdev = container_of(inode->i_cdev, struct egalax_char_dev, cdev);
+ if (cdev == NULL) {
+ EGALAX_DBG(DBG_CDEV, "No such char device node\n");
+ return -ENODEV;
+ }
+
+ atomic_inc(&egalax_char_available); /* release the device */
+
+ filp->private_data = NULL;
+ cdev->OpenCnts--;
+
+ kfifo_reset(&cdev->DataKFiFo);
+
+ mod_timer(&p_egalax_i2c_dev->idle_timer, jiffies+IDLE_INTERVAL);
+
+ EGALAX_DBG(DBG_CDEV, "CDev release done!\n");
+ module_put(THIS_MODULE);
+ return 0;
+}
+
+#define MAX_READ_BUF_LEN 50
+static char fifo_read_buf[MAX_READ_BUF_LEN];
+static ssize_t egalax_cdev_read(struct file *file, char __user *buf,
+ size_t count, loff_t *offset)
+{
+ int read_cnt, ret, fifoLen;
+ struct egalax_char_dev *cdev = file->private_data;
+
+ if (down_interruptible(&cdev->sem))
+ return -ERESTARTSYS;
+
+ fifoLen = kfifo_len(&cdev->DataKFiFo);
+
+ while (fifoLen < 1) { /* nothing to read */
+ up(&cdev->sem); /* release the lock */
+ if (file->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+
+ if (wait_event_interruptible(cdev->fifo_inq,
+ kfifo_len(&cdev->DataKFiFo) > 0)) {
+ return -ERESTARTSYS;
+ }
+
+ if (down_interruptible(&cdev->sem))
+ return -ERESTARTSYS;
+ }
+
+ if (count > MAX_READ_BUF_LEN)
+ count = MAX_READ_BUF_LEN;
+
+ EGALAX_DBG(DBG_CDEV, " \"%s\" reading fifo data\n", current->comm);
+ read_cnt = kfifo_out_locked(&cdev->DataKFiFo, fifo_read_buf,
+ count, &cdev->FiFoLock);
+
+ ret = copy_to_user(buf, fifo_read_buf, read_cnt) ? -EFAULT : read_cnt;
+
+ up(&cdev->sem);
+
+ return ret;
+}
+
+static ssize_t egalax_cdev_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *offset)
+{
+ struct egalax_char_dev *cdev = file->private_data;
+ int ret = 0;
+ char *tmp;
+
+ if (down_interruptible(&cdev->sem))
+ return -ERESTARTSYS;
+
+ if (count > MAX_I2C_LEN)
+ count = MAX_I2C_LEN;
+
+ tmp = kmalloc(count, GFP_KERNEL);
+ if (tmp == NULL) {
+ up(&cdev->sem);
+ return -ENOMEM;
+ }
+
+ if (copy_from_user(tmp, buf, count)) {
+ up(&cdev->sem);
+ kfree(tmp);
+ return -EFAULT;
+ }
+
+ ret = i2c_master_send(p_egalax_i2c_dev->client, tmp, count);
+
+ up(&cdev->sem);
+ EGALAX_DBG(DBG_CDEV, " I2C writing %zu bytes.\n", count);
+ kfree(tmp);
+
+ return ret;
+}
+
+#ifdef _ENABLE_DBG_LEVEL
+static int egalax_proc_read(char *buffer, char **buffer_location, off_t offset,
+ int buffer_length, int *eof, void *data)
+{
+ int ret;
+
+ EGALAX_DBG(DBG_PROC, " \"%s\" call proc_read\n", current->comm);
+
+ if (offset > 0) /* we have finished to read, return 0 */
+ ret = 0;
+ else
+ ret = sprintf(buffer, "Debug Level: 0x%08X\n", DbgLevel);
+
+ return ret;
+}
+
+static int egalax_proc_write(struct file *file, const char *buffer,
+ unsigned long count, void *data)
+{
+ char procfs_buffer_size = 0;
+ int i;
+ unsigned char procfs_buf[PROC_FS_MAX_LEN] = {0};
+
+ EGALAX_DBG(DBG_PROC, " \"%s\" call proc_write\n", current->comm);
+
+ procfs_buffer_size = count;
+ if (procfs_buffer_size > PROC_FS_MAX_LEN)
+ procfs_buffer_size = PROC_FS_MAX_LEN+1;
+
+ if (copy_from_user(procfs_buf, buffer, procfs_buffer_size)) {
+ EGALAX_DBG(DBG_PROC, " proc_write faied at copy_from_user\n");
+ return -EFAULT;
+ }
+
+ DbgLevel = 0;
+ for (i = 0 ; i < procfs_buffer_size-1; i++) {
+ if (procfs_buf[i] >= '0' && procfs_buf[i] <= '9')
+ DbgLevel |= (procfs_buf[i] - '0');
+ else if (procfs_buf[i] >= 'A' && procfs_buf[i] <= 'F')
+ DbgLevel |= (procfs_buf[i] - 'A' + 10);
+ else if (procfs_buf[i] >= 'a' && procfs_buf[i] <= 'f')
+ DbgLevel |= (procfs_buf[i] - 'a' + 10);
+
+ if (i != procfs_buffer_size - 2)
+ DbgLevel <<= 4;
+ }
+
+ DbgLevel = DbgLevel&0xFFFFFFFF;
+
+ EGALAX_DBG(DBG_PROC, " Switch Debug Level to 0x%08X\n", DbgLevel);
+
+ return count; /* procfs_buffer_size */
+}
+#endif /* #ifdef _ENABLE_DBG_LEVEL */
+
+static long egalax_cdev_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long args)
+{
+ int ret = 0;
+
+ if (_IOC_TYPE(cmd) != EGALAX_IOC_MAGIC)
+ return -ENOTTY;
+ if (_IOC_NR(cmd) > EGALAX_IOC_MAXNR)
+ return -ENOTTY;
+
+ if (_IOC_DIR(cmd) & _IOC_READ)
+ ret = !access_ok(VERIFY_WRITE, (void __user *)args,
+ _IOC_SIZE(cmd));
+ else if (_IOC_DIR(cmd) & _IOC_WRITE)
+ ret = !access_ok(VERIFY_READ, (void __user *)args,
+ _IOC_SIZE(cmd));
+
+ if (ret)
+ return -EFAULT;
+
+ EGALAX_DBG(DBG_CDEV, "Handle device ioctl command\n");
+ switch (cmd) {
+ case EGALAX_IOCWAKEUP:
+ ret = wakeup_controller(p_egalax_i2c_dev->client->irq);
+ break;
+ default:
+ ret = -ENOTTY;
+ break;
+ }
+
+ return ret;
+}
+
+static unsigned int egalax_cdev_poll(struct file *filp,
+ struct poll_table_struct *wait)
+{
+ struct egalax_char_dev *cdev = filp->private_data;
+ unsigned int mask = 0;
+ int fifoLen;
+
+ down(&cdev->sem);
+ poll_wait(filp, &cdev->fifo_inq, wait);
+
+ fifoLen = kfifo_len(&cdev->DataKFiFo);
+
+ if (fifoLen > 0)
+ mask |= POLLIN | POLLRDNORM; /* readable */
+ if ((FIFO_SIZE - fifoLen) > MAX_I2C_LEN)
+ mask |= POLLOUT | POLLWRNORM; /* writable */
+
+ up(&cdev->sem);
+ return mask;
+}
+
+static int LastUpdateID;
+static void ProcessReport(unsigned char *buf, struct _egalax_i2c *p_egalax_i2c)
+{
+ int i, cnt_down = 0, cnt_up = 0;
+ short X, Y, ContactID, Status;
+ bool bNeedReport = false;
+ int skip_point = 0;
+
+ Status = buf[1]&0x01;
+ ContactID = (buf[1]&0x7C)>>2;
+ X = ((buf[3]<<8) + buf[2])>>4;
+ X = X * SCREEN_WIDTH / EGALAX_MAX;
+ Y = ((buf[5]<<8) + buf[4])>>4;
+ Y = Y * SCREEN_HIGH / EGALAX_MAX;
+
+ if (!(ContactID >= 0 && ContactID < MAX_SUPPORT_POINT)) {
+ EGALAX_DBG(DBG_POINT, "Get I2C Point data error "
+ "[%02X][%02X][%02X][%02X][%02X][%02X]\n",
+ buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
+ return;
+ }
+
+#ifdef CONFIG_TC4_PORTRAIT_MODE
+ PointBuf[ContactID].X = EGALAX_MAX-Y;
+ PointBuf[ContactID].Y = X;
+#else
+ PointBuf[ContactID].X = X;
+ PointBuf[ContactID].Y = Y;
+#endif
+ if (PointBuf[ContactID].Status != Status) {
+ if (Status)
+ p_egalax_i2c->downCnt++;
+ else if (PointBuf[ContactID].Status > 0)
+ p_egalax_i2c->downCnt--;
+
+ PointBuf[ContactID].Status = Status;
+ bNeedReport = true;
+ }
+
+ /* Send point report */
+ if ((bNeedReport || (ContactID <= LastUpdateID)) && (skip_point == 0)) {
+ for (i = 0; i < MAX_SUPPORT_POINT; i++) {
+ if (PointBuf[i].Status > 0) {
+ input_report_abs(input_dev,
+ ABS_MT_TRACKING_ID, i);
+ input_report_abs(input_dev,
+ ABS_MT_TOUCH_MAJOR,
+ PointBuf[i].Status);
+ input_report_abs(input_dev,
+ ABS_MT_WIDTH_MAJOR, 0);
+ input_report_abs(input_dev,
+ ABS_MT_POSITION_X,
+ PointBuf[ContactID].X);
+ input_report_abs(input_dev,
+ ABS_MT_POSITION_Y,
+ PointBuf[ContactID].Y);
+ input_mt_sync(input_dev);
+ cnt_down++;
+ } else if (PointBuf[i].Status == 0) {
+ PointBuf[i].Status--;
+ cnt_up++;
+ input_mt_sync(input_dev);
+ }
+ }
+ input_sync(input_dev);
+ EGALAX_DBG(DBG_POINT,
+ "Input sync point data done! (Down:%d Up:%d)\n",
+ cnt_down, cnt_up);
+ }
+
+ LastUpdateID = ContactID;
+}
+
+static struct input_dev *allocate_Input_Dev(void)
+{
+ int ret;
+ struct input_dev *pInputDev;
+
+ pInputDev = input_allocate_device();
+ if (pInputDev == NULL) {
+ EGALAX_DBG(DBG_MODULE, "Failed to allocate input device\n");
+ return NULL;
+ }
+
+ pInputDev->name = "egalax_i2c";
+ pInputDev->phys = "I2C";
+ pInputDev->id.bustype = BUS_I2C;
+ pInputDev->id.vendor = 0x0EEF;
+ pInputDev->id.product = 0x0020;
+ pInputDev->id.version = 0x0001;
+
+ set_bit(EV_ABS, pInputDev->evbit);
+ input_set_abs_params(pInputDev, ABS_MT_POSITION_X,
+ 0, SCREEN_WIDTH, 0, 0);
+ input_set_abs_params(pInputDev, ABS_MT_POSITION_Y,
+ 0, SCREEN_HIGH, 0, 0);
+ input_set_abs_params(pInputDev, ABS_MT_TOUCH_MAJOR,
+ 0, 255, 0, 0);
+ input_set_abs_params(pInputDev, ABS_MT_WIDTH_MAJOR,
+ 0, 255, 0, 0);
+ input_set_abs_params(pInputDev, ABS_MT_TRACKING_ID,
+ 0, MAX_SUPPORT_POINT, 0, 0);
+
+ ret = input_register_device(pInputDev);
+ if (ret) {
+ EGALAX_DBG(DBG_MODULE, "Unable to register input device.\n");
+ input_free_device(pInputDev);
+ pInputDev = NULL;
+ }
+
+ return pInputDev;
+}
+
+static int egalax_i2c_measure(struct _egalax_i2c *egalax_i2c)
+{
+ struct i2c_client *client = egalax_i2c->client;
+ u8 x_buf[MAX_I2C_LEN];
+ int count, loop = 3;
+
+ EGALAX_DBG(DBG_INT, "egalax_i2c_measure\n");
+
+ do {
+ mutex_lock(&i2c_lock);
+ count = i2c_master_recv(client, x_buf, MAX_I2C_LEN);
+ mutex_unlock(&i2c_lock);
+ } while (count == EAGAIN && --loop);
+
+ if (count < 0 || (x_buf[0] != REPORTID_VENDOR && x_buf[0]
+ != REPORTID_MTOUCH)) {
+ EGALAX_DBG(DBG_I2C,
+ "I2C read error data with Len=%d hedaer=%d\n",
+ count, x_buf[0]);
+ return -1;
+ }
+
+ EGALAX_DBG(DBG_I2C, " I2C read data with Len=%d\n", count);
+ if (x_buf[0] == REPORTID_VENDOR) {
+ atomic_set(&wait_command_ack, 1);
+ EGALAX_DBG(DBG_I2C, " I2C get vendor command packet\n");
+ }
+
+ if (egalax_i2c->skip_packet > 0)
+ return count;
+
+ /* check buffer len & header */
+ if (count == MAX_I2C_LEN && x_buf[0] == REPORTID_MTOUCH) {
+ ProcessReport(x_buf, egalax_i2c);
+ return count;
+ }
+
+ /* If someone reading now! put the data into the buffer! */
+ if (count > 0 && p_char_dev->OpenCnts > 0) {
+ kfifo_in_locked(&p_char_dev->DataKFiFo, x_buf,
+ count, &p_char_dev->FiFoLock);
+ wake_up_interruptible(&p_char_dev->fifo_inq);
+ }
+
+ return count;
+}
+
+static void egalax_i2c_wq_irq(struct work_struct *work)
+{
+ struct _egalax_i2c *egalax_i2c =
+ container_of(work, struct _egalax_i2c, work_irq);
+ struct i2c_client *client = egalax_i2c->client;
+ int gpio = irq_to_gpio(client->irq);
+
+ EGALAX_DBG(DBG_INT, " egalax_i2c_wq run\n");
+
+ mutex_lock(&egalax_i2c->mutex_wq);
+ /*continue recv data*/
+ while (!gpio_get_value(gpio)) {
+ egalax_i2c_measure(egalax_i2c);
+ schedule();
+ }
+
+ if (egalax_i2c->skip_packet > 0)
+ egalax_i2c->skip_packet = 0;
+
+ if (p_char_dev->OpenCnts <= 0 && egalax_i2c->work_state == MODE_WORKING)
+ mod_timer(&egalax_i2c->idle_timer, jiffies+IDLE_INTERVAL);
+
+ mutex_unlock(&egalax_i2c->mutex_wq);
+
+ enable_irq(client->irq);
+
+ EGALAX_DBG(DBG_INT, " egalax_i2c_wq leave\n");
+}
+
+static irqreturn_t egalax_i2c_interrupt(int irq, void *dev_id)
+{
+ struct _egalax_i2c *egalax_i2c = (struct _egalax_i2c *)dev_id;
+
+ EGALAX_DBG(DBG_INT, " INT with irq:%d\n", irq);
+
+ del_timer(&egalax_i2c->idle_timer);
+ if (egalax_i2c->work_state == MODE_IDLE)
+ egalax_i2c->work_state = MODE_WORKING;
+
+ disable_irq_nosync(irq);
+ queue_work(egalax_i2c->ktouch_wq, &egalax_i2c->work_irq);
+
+ return IRQ_HANDLED;
+}
+
+static void egalax_i2c_wq_idle(struct work_struct *work)
+{
+ struct _egalax_i2c *egalax_i2c =
+ container_of(work, struct _egalax_i2c, work_idle);
+ unsigned char buf[] = {0x03, 0x06, 0x0A, 0x04, 0x36,
+ 0x3F, 0x01, 0x00, 0, 0};
+ int ret = 0;
+
+ if (egalax_i2c->work_state == MODE_WORKING) {
+ mutex_lock(&i2c_lock);
+ ret = i2c_master_send(egalax_i2c->client, buf, MAX_I2C_LEN);
+ mutex_unlock(&i2c_lock);
+ if (ret == MAX_I2C_LEN) {
+ egalax_i2c->work_state = MODE_IDLE;
+ EGALAX_DBG(DBG_IDLE, " Set controller to idle mode\n");
+ } else
+ EGALAX_DBG(DBG_IDLE,
+ " Try to set controller to idle failed:%d\n",
+ ret);
+ }
+}
+
+static void egalax_idle_timer_routine(unsigned long data)
+{
+ struct _egalax_i2c *egalax_i2c = (struct _egalax_i2c *)data;
+
+ queue_work(egalax_i2c->ktouch_wq, &egalax_i2c->work_idle);
+}
+
+
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void egalax_i2c_early_suspend(struct early_suspend *handler)
+{
+ mod_timer(&p_egalax_i2c_dev->idle_timer, jiffies);
+
+ return;
+}
+
+#endif /* CONFIG_HAS_EARLYSUSPEND */
+
+static int __devinit egalax_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int i, ret = 0;
+ int gpio;
+
+ EGALAX_DBG(DBG_MODULE, " Start probe\n");
+
+ p_egalax_i2c_dev = kzalloc(sizeof(struct _egalax_i2c), GFP_KERNEL);
+ if (!p_egalax_i2c_dev) {
+ EGALAX_DBG(DBG_MODULE, "Request memory failed\n");
+ ret = -ENOMEM;
+ goto fail1;
+ }
+
+ input_dev = allocate_Input_Dev();
+ if (input_dev == NULL) {
+ EGALAX_DBG(DBG_MODULE, " allocate_Input_Dev failed\n");
+ ret = -EINVAL;
+ goto fail2;
+ }
+
+ EGALAX_DBG(DBG_MODULE, " Register input device done\n");
+
+ for (i = 0; i < MAX_SUPPORT_POINT; i++) {
+ PointBuf[i].Status = -1;
+ PointBuf[i].X = PointBuf[i].Y = 0;
+ }
+
+ p_egalax_i2c_dev->client = client;
+ mutex_init(&p_egalax_i2c_dev->mutex_wq);
+ mutex_init(&i2c_lock); /* cuiwenpin:i2c read write protection */
+
+ p_egalax_i2c_dev->ktouch_wq =
+ create_singlethread_workqueue("egalax_touch_wq");
+ INIT_WORK(&p_egalax_i2c_dev->work_irq, egalax_i2c_wq_irq);
+ INIT_WORK(&p_egalax_i2c_dev->work_idle, egalax_i2c_wq_idle);
+
+ i2c_set_clientdata(client, p_egalax_i2c_dev);
+
+ sendLoopback(client);
+
+ gpio = irq_to_gpio(client->irq);
+
+ if (gpio_get_value(gpio))
+ p_egalax_i2c_dev->skip_packet = 0;
+ else
+ p_egalax_i2c_dev->skip_packet = 1;
+
+ p_egalax_i2c_dev->work_state = MODE_WORKING;
+
+ /* setup timer */
+ setup_timer(&p_egalax_i2c_dev->idle_timer, egalax_idle_timer_routine,
+ (unsigned long)p_egalax_i2c_dev);
+ mod_timer(&p_egalax_i2c_dev->idle_timer, jiffies);
+
+ ret = request_irq(client->irq, egalax_i2c_interrupt,
+ IRQF_DISABLED | IRQF_TRIGGER_FALLING,
+ client->name, p_egalax_i2c_dev);
+ if (ret) {
+ EGALAX_DBG(DBG_MODULE, "Request irq(%d) failed\n", client->irq);
+ goto fail3;
+ }
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ egalax_early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN;
+ egalax_early_suspend.suspend = egalax_i2c_early_suspend;
+ egalax_early_suspend.resume = NULL;
+ register_early_suspend(&egalax_early_suspend);
+ EGALAX_DBG(DBG_MODULE, " Register early_suspend done\n");
+#endif
+
+ EGALAX_DBG(DBG_MODULE, "Request irq(%d) gpio(%d) with result:%d\n",
+ client->irq, gpio, ret);
+
+
+ EGALAX_DBG(DBG_MODULE, " I2C probe done\n");
+ return 0;
+
+fail3:
+ i2c_set_clientdata(client, NULL);
+ destroy_workqueue(p_egalax_i2c_dev->ktouch_wq);
+ input_unregister_device(input_dev);
+ input_dev = NULL;
+fail2:
+ kfree(p_egalax_i2c_dev);
+fail1:
+ p_egalax_i2c_dev = NULL;
+
+ EGALAX_DBG(DBG_MODULE, " I2C probe failed\n");
+ return ret;
+}
+
+static int __devexit egalax_i2c_remove(struct i2c_client *client)
+{
+ struct _egalax_i2c *egalax_i2c = i2c_get_clientdata(client);
+
+ egalax_i2c->work_state = MODE_STOP;
+
+ cancel_work_sync(&egalax_i2c->work_irq);
+ del_timer_sync(&egalax_i2c->idle_timer);
+ cancel_work_sync(&egalax_i2c->work_idle);
+
+ if (client->irq) {
+ disable_irq(client->irq);
+ free_irq(client->irq, egalax_i2c);
+ }
+
+ if (egalax_i2c->ktouch_wq)
+ destroy_workqueue(egalax_i2c->ktouch_wq);
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ unregister_early_suspend(&egalax_early_suspend);
+#endif
+
+ if (input_dev) {
+ EGALAX_DBG(DBG_MODULE, " Unregister input device\n");
+ input_unregister_device(input_dev);
+ input_dev = NULL;
+ }
+
+ i2c_set_clientdata(client, NULL);
+ kfree(egalax_i2c);
+ p_egalax_i2c_dev = NULL;
+
+ return 0;
+}
+
+static const struct i2c_device_id egalax_i2c_idtable[] = {
+ { "egalax_i2c", 0 },
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, egalax_i2c_idtable);
+
+static struct i2c_driver egalax_i2c_driver = {
+ .driver = {
+ .name = "egalax_i2c",
+ },
+ .id_table = egalax_i2c_idtable,
+ .probe = egalax_i2c_probe,
+ .remove = __devexit_p(egalax_i2c_remove),
+};
+
+static const struct file_operations egalax_cdev_fops = {
+ .owner = THIS_MODULE,
+ .read = egalax_cdev_read,
+ .write = egalax_cdev_write,
+ .unlocked_ioctl = egalax_cdev_ioctl,
+ .poll = egalax_cdev_poll,
+ .open = egalax_cdev_open,
+ .release = egalax_cdev_release,
+};
+
+static void egalax_i2c_ts_exit(void)
+{
+ dev_t devno = MKDEV(global_major, global_minor);
+
+ if (p_char_dev) {
+ EGALAX_DBG(DBG_MODULE, "Unregister character device\n");
+ kfree(p_char_dev->pFiFoBuf);
+
+ cdev_del(&p_char_dev->cdev);
+ kfree(p_char_dev);
+ p_char_dev = NULL;
+ }
+
+ unregister_chrdev_region(devno, 1);
+
+ if (!IS_ERR(egalax_class)) {
+ device_destroy(egalax_class, devno);
+ class_destroy(egalax_class);
+ }
+
+ i2c_del_driver(&egalax_i2c_driver);
+
+#ifdef _ENABLE_DBG_LEVEL
+ remove_proc_entry(PROC_FS_NAME, NULL);
+#endif
+
+ EGALAX_DBG(DBG_MODULE, " Exit driver done!\n");
+}
+
+static struct egalax_char_dev *setup_chardev(dev_t dev)
+{
+ struct egalax_char_dev *pCharDev;
+ int result;
+
+ pCharDev = kmalloc(1 * sizeof(struct egalax_char_dev), GFP_KERNEL);
+ if (!pCharDev)
+ goto fail_cdev;
+
+ memset(pCharDev, 0, sizeof(struct egalax_char_dev));
+
+ spin_lock_init(&pCharDev->FiFoLock);
+ pCharDev->pFiFoBuf = kmalloc(sizeof(unsigned char)*FIFO_SIZE,
+ GFP_KERNEL);
+ if (!pCharDev->pFiFoBuf)
+ goto fail_fifobuf;
+ memset(pCharDev->pFiFoBuf, 0, sizeof(unsigned char)*FIFO_SIZE);
+
+ kfifo_init(&pCharDev->DataKFiFo, pCharDev->pFiFoBuf, FIFO_SIZE);
+ if (!kfifo_initialized(&pCharDev->DataKFiFo))
+ goto fail_kfifo;
+
+ pCharDev->OpenCnts = 0;
+ cdev_init(&pCharDev->cdev, &egalax_cdev_fops);
+ pCharDev->cdev.owner = THIS_MODULE;
+ sema_init(&pCharDev->sem, 1);
+ init_waitqueue_head(&pCharDev->fifo_inq);
+
+ result = cdev_add(&pCharDev->cdev, dev, 1);
+ if (result) {
+ EGALAX_DBG(DBG_MODULE, " Failed at cdev added\n");
+ goto fail_kfifo;
+ }
+
+ return pCharDev;
+
+fail_kfifo:
+ kfree(pCharDev->pFiFoBuf);
+fail_fifobuf:
+ kfree(pCharDev);
+fail_cdev:
+ return NULL;
+}
+
+static int egalax_i2c_ts_init(void)
+{
+ int result;
+ dev_t devno = 0;
+
+ /* Asking for a dynamic major unless directed otherwise at load time. */
+ if (global_major) {
+ devno = MKDEV(global_major, global_minor);
+ result = register_chrdev_region(devno, 1, "egalax_i2c");
+ } else {
+ result = alloc_chrdev_region(&devno, global_minor,
+ 1, "egalax_i2c");
+ global_major = MAJOR(devno);
+ }
+
+ if (result < 0) {
+ EGALAX_DBG(DBG_MODULE, " Cdev can't get major number\n");
+ return 0;
+ }
+
+ /* allocate the character device */
+ p_char_dev = setup_chardev(devno);
+ if (!p_char_dev) {
+ result = -ENOMEM;
+ goto fail;
+ }
+
+ egalax_class = class_create(THIS_MODULE, "egalax_i2c");
+ if (IS_ERR(egalax_class)) {
+ EGALAX_DBG(DBG_MODULE, " Failed in creating class.\n");
+ result = -EFAULT;
+ goto fail;
+ }
+
+ device_create(egalax_class, NULL, devno, NULL, "egalax_i2c");
+ EGALAX_DBG(DBG_MODULE, "Register egalax_i2c cdev, major: %d\n",
+ global_major);
+
+#ifdef _ENABLE_DBG_LEVEL
+ dbgProcFile = create_proc_entry(PROC_FS_NAME, 0666, NULL);
+ if (dbgProcFile == NULL) {
+ remove_proc_entry(PROC_FS_NAME, NULL);
+ EGALAX_DBG(DBG_MODULE, "Could not initialize /proc/%s\n",
+ PROC_FS_NAME);
+ } else {
+ dbgProcFile->read_proc = egalax_proc_read;
+ dbgProcFile->write_proc = egalax_proc_write;
+ EGALAX_DBG(DBG_MODULE, " /proc/%s created\n", PROC_FS_NAME);
+ }
+#endif /* #ifdef _ENABLE_DBG_LEVEL */
+
+ EGALAX_DBG(DBG_MODULE, " Driver init done!\n");
+ return i2c_add_driver(&egalax_i2c_driver);
+
+fail:
+ egalax_i2c_ts_exit();
+ return result;
+}
+
+module_init(egalax_i2c_ts_init);
+module_exit(egalax_i2c_ts_exit);
+
+MODULE_AUTHOR("EETI <touch_fae@eeti.com>");
+MODULE_DESCRIPTION("egalax touch screen i2c driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index 3bd9fff..7c3122f 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -123,6 +123,42 @@
To use x2apic mode in the CPU's which support x2APIC enhancements or
to support platforms with CPU's having > 8 bit APIC ID, say Y.
+config EXYNOS_IOMMU
+ bool "Exynos IOMMU Support"
+ depends on ARCH_EXYNOS && EXYNOS_DEV_SYSMMU
+ select IOMMU_API
+ help
+ Support for the IOMMU(System MMU) of Samsung Exynos application
+ processor family. This enables H/W multimedia accellerators to see
+ non-linear physical memory chunks as a linear memory in their
+ address spaces
+
+ If unsure, say N here.
+
+config EXYNOS_IOVMM
+ bool "IO Virtual Memory Manager for Exynos IOMMUs"
+ select GENERIC_ALLOCATOR
+ depends on EXYNOS_IOMMU
+ default y
+ help
+ Supporting the users of Exynos IOMMU for allocating and mapping
+ an IO virtual memory region with a physical memory region
+ and managing the allocated virtual memory regions.
+
+config EXYNOS_IOVMM_ALIGN64K
+ bool "Let I/O memory region 64KB aligned"
+ default y
+ depends on EXYNOS_IOVMM
+
+config EXYNOS_IOMMU_DEBUG
+ bool "Debugging log for Exynos IOMMU"
+ depends on EXYNOS_IOMMU
+ help
+ Select this to see the detailed log message that shows what
+ happens in the IOMMU driver
+
+ Say N unless you need kernel log message for IOMMU debugging
+
# OMAP IOMMU support
config OMAP_IOMMU
bool "OMAP IOMMU Support"
diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile
index 7ad7a3b..48e40f9 100644
--- a/drivers/iommu/Makefile
+++ b/drivers/iommu/Makefile
@@ -5,6 +5,8 @@
obj-$(CONFIG_DMAR_TABLE) += dmar.o
obj-$(CONFIG_INTEL_IOMMU) += iova.o intel-iommu.o
obj-$(CONFIG_IRQ_REMAP) += intr_remapping.o
+obj-$(CONFIG_EXYNOS_IOMMU) += exynos-iommu.o
+obj-$(CONFIG_EXYNOS_IOVMM) += exynos-iovmm.o
obj-$(CONFIG_OMAP_IOMMU) += omap-iommu.o
obj-$(CONFIG_OMAP_IOVMM) += omap-iovmm.o
obj-$(CONFIG_OMAP_IOMMU_DEBUG) += omap-iommu-debug.o
diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
new file mode 100644
index 0000000..127bfcea
--- /dev/null
+++ b/drivers/iommu/exynos-iommu.c
@@ -0,0 +1,1043 @@
+/* linux/drivers/iommu/exynos_iommu.c
+ *
+ * Copyright (c) 2011-2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * 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.
+ */
+
+#ifdef CONFIG_EXYNOS_IOMMU_DEBUG
+#define DEBUG
+#endif
+
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/mm.h>
+#include <linux/errno.h>
+#include <linux/memblock.h>
+#include <linux/export.h>
+
+#include <asm/cacheflush.h>
+#include <asm/pgtable.h>
+
+#include <mach/sysmmu.h>
+
+#include "exynos-iommu.h"
+
+/* We does not consider super section mapping (16MB) */
+#define SECT_ORDER 20
+#define LPAGE_ORDER 16
+#define SPAGE_ORDER 12
+
+#define SECT_SIZE (1 << SECT_ORDER)
+#define LPAGE_SIZE (1 << LPAGE_ORDER)
+#define SPAGE_SIZE (1 << SPAGE_ORDER)
+
+#define SECT_MASK (~(SECT_SIZE - 1))
+#define LPAGE_MASK (~(LPAGE_SIZE - 1))
+#define SPAGE_MASK (~(SPAGE_SIZE - 1))
+
+#define lv1ent_fault(sent) (((*(sent) & 3) == 0) || ((*(sent) & 3) == 3))
+#define lv1ent_page(sent) ((*(sent) & 3) == 1)
+#define lv1ent_section(sent) ((*(sent) & 3) == 2)
+
+#define lv2ent_fault(pent) ((*(pent) & 3) == 0)
+#define lv2ent_small(pent) ((*(pent) & 2) == 2)
+#define lv2ent_large(pent) ((*(pent) & 3) == 1)
+
+#define section_phys(sent) (*(sent) & SECT_MASK)
+#define section_offs(iova) ((iova) & 0xFFFFF)
+#define lpage_phys(pent) (*(pent) & LPAGE_MASK)
+#define lpage_offs(iova) ((iova) & 0xFFFF)
+#define spage_phys(pent) (*(pent) & SPAGE_MASK)
+#define spage_offs(iova) ((iova) & 0xFFF)
+
+#define lv1ent_offset(iova) ((iova) >> SECT_ORDER)
+#define lv2ent_offset(iova) (((iova) & 0xFF000) >> SPAGE_ORDER)
+
+#define NUM_LV1ENTRIES 4096
+#define NUM_LV2ENTRIES 256
+
+#define LV2TABLE_SIZE (NUM_LV2ENTRIES * sizeof(long))
+
+#define SPAGES_PER_LPAGE (LPAGE_SIZE / SPAGE_SIZE)
+
+#define lv2table_base(sent) (*(sent) & 0xFFFFFC00)
+
+#define mk_lv1ent_sect(pa) ((pa) | 2)
+#define mk_lv1ent_page(pa) ((pa) | 1)
+#define mk_lv2ent_lpage(pa) ((pa) | 1)
+#define mk_lv2ent_spage(pa) ((pa) | 2)
+
+#define CTRL_ENABLE 0x5
+#define CTRL_BLOCK 0x7
+#define CTRL_DISABLE 0x0
+
+#define CFG_LRU 0x1
+#define CFG_QOS(n) ((n & 0xF) << 7)
+
+#define REG_MMU_CTRL 0x000
+#define REG_MMU_CFG 0x004
+#define REG_MMU_STATUS 0x008
+#define REG_MMU_FLUSH 0x00C
+#define REG_MMU_FLUSH_ENTRY 0x010
+#define REG_PT_BASE_ADDR 0x014
+#define REG_INT_STATUS 0x018
+#define REG_INT_CLEAR 0x01C
+
+#define REG_PAGE_FAULT_ADDR 0x024
+#define REG_AW_FAULT_ADDR 0x028
+#define REG_AR_FAULT_ADDR 0x02C
+#define REG_DEFAULT_SLAVE_ADDR 0x030
+
+#define REG_MMU_VERSION 0x034
+
+#define REG_PB0_SADDR 0x04C
+#define REG_PB0_EADDR 0x050
+#define REG_PB1_SADDR 0x054
+#define REG_PB1_EADDR 0x058
+
+static struct kmem_cache *lv2table_kmem_cache;
+
+static unsigned long *section_entry(unsigned long *pgtable, unsigned long iova)
+{
+ return pgtable + lv1ent_offset(iova);
+}
+
+static unsigned long *page_entry(unsigned long *sent, unsigned long iova)
+{
+ return (unsigned long *)__va(lv2table_base(sent)) + lv2ent_offset(iova);
+}
+
+static unsigned short fault_reg_offset[SYSMMU_FAULTS_NUM] = {
+ REG_PAGE_FAULT_ADDR,
+ REG_AR_FAULT_ADDR,
+ REG_AW_FAULT_ADDR,
+ REG_DEFAULT_SLAVE_ADDR,
+ REG_AR_FAULT_ADDR,
+ REG_AR_FAULT_ADDR,
+ REG_AW_FAULT_ADDR,
+ REG_AW_FAULT_ADDR
+};
+
+static char *sysmmu_fault_name[SYSMMU_FAULTS_NUM] = {
+ "PAGE FAULT",
+ "AR MULTI-HIT FAULT",
+ "AW MULTI-HIT FAULT",
+ "BUS ERROR",
+ "AR SECURITY PROTECTION FAULT",
+ "AR ACCESS PROTECTION FAULT",
+ "AW SECURITY PROTECTION FAULT",
+ "AW ACCESS PROTECTION FAULT",
+ "UNKNOWN FAULT"
+};
+
+struct exynos_iommu_domain {
+ struct list_head clients; /* list of sysmmu_drvdata.node */
+ unsigned long *pgtable; /* lv1 page table, 16KB */
+ short *lv2entcnt; /* free lv2 entry counter for each section */
+ spinlock_t lock; /* lock for this structure */
+ spinlock_t pgtablelock; /* lock for modifying page table @ pgtable */
+};
+
+static bool set_sysmmu_active(struct sysmmu_drvdata *data)
+{
+ /* return true if the System MMU was not active previously
+ and it needs to be initialized */
+ return ++data->activations == 1;
+}
+
+static bool set_sysmmu_inactive(struct sysmmu_drvdata *data)
+{
+ /* return true if the System MMU is needed to be disabled */
+ BUG_ON(data->activations < 1);
+ return --data->activations == 0;
+}
+
+static bool is_sysmmu_active(struct sysmmu_drvdata *data)
+{
+ return data->activations > 0;
+}
+
+static void sysmmu_unblock(void __iomem *sfrbase)
+{
+ __raw_writel(CTRL_ENABLE, sfrbase + REG_MMU_CTRL);
+}
+
+static bool sysmmu_block(void __iomem *sfrbase)
+{
+ int i = 120;
+
+ __raw_writel(CTRL_BLOCK, sfrbase + REG_MMU_CTRL);
+ while ((i > 0) && !(__raw_readl(sfrbase + REG_MMU_STATUS) & 1))
+ --i;
+
+ if (!(__raw_readl(sfrbase + REG_MMU_STATUS) & 1)) {
+ sysmmu_unblock(sfrbase);
+ return false;
+ }
+
+ return true;
+}
+
+static void __sysmmu_tlb_invalidate(void __iomem *sfrbase)
+{
+ __raw_writel(0x1, sfrbase + REG_MMU_FLUSH);
+}
+
+static void __sysmmu_set_ptbase(void __iomem *sfrbase,
+ unsigned long pgd)
+{
+ __raw_writel(pgd, sfrbase + REG_PT_BASE_ADDR);
+
+ __sysmmu_tlb_invalidate(sfrbase);
+}
+
+static void __sysmmu_set_prefbuf(void __iomem *sfrbase, unsigned long base,
+ unsigned long size, int idx)
+{
+ __raw_writel(base, sfrbase + REG_PB0_SADDR + idx * 8);
+ __raw_writel(size - 1 + base, sfrbase + REG_PB0_EADDR + idx * 8);
+}
+
+void exynos_sysmmu_set_prefbuf(struct device *dev,
+ unsigned long base0, unsigned long size0,
+ unsigned long base1, unsigned long size1)
+{
+ struct sysmmu_drvdata *data = dev_get_drvdata(dev->archdata.iommu);
+ unsigned long flags;
+ int i;
+
+ BUG_ON((base0 + size0) <= base0);
+ BUG_ON((size1 > 0) && ((base1 + size1) <= base1));
+
+ read_lock_irqsave(&data->lock, flags);
+ if (!is_sysmmu_active(data))
+ goto finish;
+
+ for (i = 0; i < data->nsfrs; i++) {
+ if ((readl(data->sfrbases[i] + REG_MMU_VERSION) >> 28) == 3) {
+ if (!sysmmu_block(data->sfrbases[i]))
+ continue;
+
+ if (size1 == 0) {
+ if (size0 <= SZ_128K) {
+ base1 = base0;
+ size1 = size0;
+ } else {
+ size1 = size0 -
+ ALIGN(size0 / 2, SZ_64K);
+ size0 = size0 - size1;
+ base1 = base0 + size0;
+ }
+ }
+
+ __sysmmu_set_prefbuf(
+ data->sfrbases[i], base0, size0, 0);
+ __sysmmu_set_prefbuf(
+ data->sfrbases[i], base1, size1, 1);
+
+ sysmmu_unblock(data->sfrbases[i]);
+ }
+ }
+finish:
+ read_unlock_irqrestore(&data->lock, flags);
+}
+
+static void __set_fault_handler(struct sysmmu_drvdata *data,
+ sysmmu_fault_handler_t handler)
+{
+ unsigned long flags;
+
+ write_lock_irqsave(&data->lock, flags);
+ data->fault_handler = handler;
+ write_unlock_irqrestore(&data->lock, flags);
+}
+
+void exynos_sysmmu_set_fault_handler(struct device *dev,
+ sysmmu_fault_handler_t handler)
+{
+ struct sysmmu_drvdata *data = dev_get_drvdata(dev->archdata.iommu);
+
+ __set_fault_handler(data, handler);
+}
+
+static int default_fault_handler(struct device *dev,
+ enum exynos_sysmmu_inttype itype,
+ unsigned long pgtable_base,
+ unsigned long fault_addr)
+{
+ unsigned long *ent;
+
+ if ((itype >= SYSMMU_FAULTS_NUM) || (itype < SYSMMU_PAGEFAULT))
+ itype = SYSMMU_FAULT_UNKNOWN;
+
+ pr_err("%s occured at 0x%lx(Page table base: 0x%lx)\n",
+ sysmmu_fault_name[itype], fault_addr, pgtable_base);
+
+ if (dev)
+ pr_err("iommu %s\n", dev_name(dev));
+
+ ent = section_entry(__va(pgtable_base), fault_addr);
+ pr_err("\tLv1 entry: 0x%lx\n", *ent);
+
+ if (lv1ent_page(ent)) {
+ ent = page_entry(ent, fault_addr);
+ pr_err("\t Lv2 entry: 0x%lx\n", *ent);
+ }
+
+ pr_err("Generating Kernel OOPS... because it is unrecoverable.\n");
+
+ BUG();
+
+ return 0;
+}
+
+static irqreturn_t exynos_sysmmu_irq(int irq, void *dev_id)
+{
+ /* SYSMMU is in blocked when interrupt occurred. */
+ struct sysmmu_drvdata *data = dev_id;
+ struct resource *irqres;
+ struct platform_device *pdev;
+ enum exynos_sysmmu_inttype itype;
+ unsigned long addr = -1;
+
+ int i, ret = -ENOSYS;
+
+ read_lock(&data->lock);
+
+ WARN_ON(!is_sysmmu_active(data));
+
+ pdev = to_platform_device(data->sysmmu);
+ for (i = 0; i < pdev->num_resources / 2; i++) {
+ irqres = platform_get_resource(pdev, IORESOURCE_IRQ, i);
+ if (irqres && ((int)irqres->start == irq))
+ break;
+ }
+
+ if (i == pdev->num_resources) {
+ itype = SYSMMU_FAULT_UNKNOWN;
+ } else {
+ itype = (enum exynos_sysmmu_inttype)
+ __ffs(__raw_readl(data->sfrbases[i] + REG_INT_STATUS));
+ if (WARN_ON(!((itype >= 0) && (itype < SYSMMU_FAULT_UNKNOWN))))
+ itype = SYSMMU_FAULT_UNKNOWN;
+ else
+ addr = __raw_readl(
+ data->sfrbases[i] + fault_reg_offset[itype]);
+ }
+
+ if (data->domain)
+ ret = report_iommu_fault(data->domain, data->dev,
+ addr, itype);
+
+ if ((ret == -ENOSYS) && data->fault_handler) {
+ unsigned long base = data->pgtable;
+ if (itype != SYSMMU_FAULT_UNKNOWN)
+ base = __raw_readl(
+ data->sfrbases[i] + REG_PT_BASE_ADDR);
+ ret = data->fault_handler(data->dev, itype, base, addr);
+ }
+
+ if (!ret && (itype != SYSMMU_FAULT_UNKNOWN))
+ __raw_writel(1 << itype, data->sfrbases[i] + REG_INT_CLEAR);
+ else
+ dev_dbg(data->sysmmu, "(%s) %s is not handled.\n",
+ data->dbgname, sysmmu_fault_name[itype]);
+
+ if (itype != SYSMMU_FAULT_UNKNOWN)
+ sysmmu_unblock(data->sfrbases[i]);
+
+ read_unlock(&data->lock);
+
+ return IRQ_HANDLED;
+}
+
+static bool __exynos_sysmmu_disable(struct sysmmu_drvdata *data)
+{
+ unsigned long flags;
+ bool disabled = false;
+ int i;
+
+ write_lock_irqsave(&data->lock, flags);
+
+ if (!set_sysmmu_inactive(data))
+ goto finish;
+
+ for (i = 0; i < data->nsfrs; i++)
+ __raw_writel(CTRL_DISABLE, data->sfrbases[i] + REG_MMU_CTRL);
+
+ if (data->clk[2])
+ clk_disable(data->clk[2]);
+ if (data->clk[1])
+ clk_disable(data->clk[1]);
+ if (data->clk[0])
+ clk_disable(data->clk[0]);
+
+ disabled = true;
+ data->pgtable = 0;
+ data->domain = NULL;
+finish:
+ write_unlock_irqrestore(&data->lock, flags);
+
+ if (disabled)
+ dev_dbg(data->sysmmu, "(%s) Disabled\n", data->dbgname);
+ else
+ dev_dbg(data->sysmmu, "(%s) %d times left to be disabled\n",
+ data->dbgname, data->activations);
+
+ return disabled;
+}
+
+/* __exynos_sysmmu_enable: Enables System MMU
+ *
+ * returns -error if an error occurred and System MMU is not enabled,
+ * 0 if the System MMU has been just enabled and 1 if System MMU was already
+ * enabled before.
+ */
+static int __exynos_sysmmu_enable(struct sysmmu_drvdata *data,
+ unsigned long pgtable, struct iommu_domain *domain)
+{
+ int i, ret = 0;
+ unsigned long flags;
+
+ write_lock_irqsave(&data->lock, flags);
+
+ if (!set_sysmmu_active(data)) {
+ if (WARN_ON(pgtable != data->pgtable)) {
+ ret = -EBUSY;
+ set_sysmmu_inactive(data);
+ } else {
+ ret = 1;
+ }
+
+ dev_dbg(data->sysmmu, "(%s) Already enabled\n", data->dbgname);
+ goto finish;
+ }
+
+ if (data->clk[0])
+ clk_enable(data->clk[0]);
+ if (data->clk[1])
+ clk_enable(data->clk[1]);
+ if (data->clk[2])
+ clk_enable(data->clk[2]);
+
+ data->pgtable = pgtable;
+
+ for (i = 0; i < data->nsfrs; i++) {
+ unsigned long cfg = CFG_LRU | CFG_QOS(data->qos);
+
+ __sysmmu_set_ptbase(data->sfrbases[i], pgtable);
+
+ if ((readl(data->sfrbases[i] + REG_MMU_VERSION) >> 28) == 3) {
+ /* System MMU version is 3.x */
+ __raw_writel(cfg | (1 << 12) | (2 << 28),
+ data->sfrbases[i] + REG_MMU_CFG);
+ __sysmmu_set_prefbuf(data->sfrbases[i], 0, -1, 0);
+ __sysmmu_set_prefbuf(data->sfrbases[i], 0, -1, 1);
+ } else {
+ __raw_writel(cfg, data->sfrbases[i] + REG_MMU_CFG);
+ }
+
+ __raw_writel(CTRL_ENABLE, data->sfrbases[i] + REG_MMU_CTRL);
+ }
+
+ data->domain = domain;
+
+ dev_dbg(data->sysmmu, "(%s) Enabled\n", data->dbgname);
+finish:
+ write_unlock_irqrestore(&data->lock, flags);
+
+ return ret;
+}
+
+int exynos_sysmmu_enable(struct device *dev, unsigned long pgtable)
+{
+ struct sysmmu_drvdata *data = dev_get_drvdata(dev->archdata.iommu);
+ int ret;
+
+ BUG_ON(!memblock_is_memory(pgtable));
+
+ ret = __exynos_sysmmu_enable(data, pgtable, NULL);
+ if (WARN_ON(ret < 0)) {
+ dev_err(data->sysmmu,
+ "(%s) Already enabled with page table %#lx\n",
+ data->dbgname, data->pgtable);
+ } else {
+ data->dev = dev;
+ }
+
+ return ret;
+}
+
+bool exynos_sysmmu_disable(struct device *dev)
+{
+ struct sysmmu_drvdata *data = dev_get_drvdata(dev->archdata.iommu);
+ bool disabled;
+
+ disabled = __exynos_sysmmu_disable(data);
+
+ return disabled;
+}
+
+void exynos_sysmmu_tlb_invalidate(struct device *dev)
+{
+ unsigned long flags;
+ struct sysmmu_drvdata *data = dev_get_drvdata(dev->archdata.iommu);
+
+ read_lock_irqsave(&data->lock, flags);
+
+ if (is_sysmmu_active(data)) {
+ int i;
+ for (i = 0; i < data->nsfrs; i++) {
+ if (sysmmu_block(data->sfrbases[i])) {
+ __sysmmu_tlb_invalidate(data->sfrbases[i]);
+ sysmmu_unblock(data->sfrbases[i]);
+ }
+ }
+ } else {
+ dev_dbg(data->sysmmu,
+ "(%s) Disabled. Skipping invalidating TLB.\n",
+ data->dbgname);
+ }
+
+ read_unlock_irqrestore(&data->lock, flags);
+}
+
+static int exynos_sysmmu_probe(struct platform_device *pdev)
+{
+ int i, ret;
+ struct device *dev;
+ struct sysmmu_drvdata *data;
+
+ dev = &pdev->dev;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data) {
+ dev_dbg(dev, "Not enough memory\n");
+ ret = -ENOMEM;
+ goto err_alloc;
+ }
+
+ ret = dev_set_drvdata(dev, data);
+ if (ret) {
+ dev_dbg(dev, "Unabled to initialize driver data\n");
+ goto err_init;
+ }
+
+ data->nsfrs = pdev->num_resources / 2;
+ data->sfrbases = kmalloc(sizeof(*data->sfrbases) * data->nsfrs,
+ GFP_KERNEL);
+ if (data->sfrbases == NULL) {
+ dev_dbg(dev, "Not enough memory\n");
+ ret = -ENOMEM;
+ goto err_init;
+ }
+
+ for (i = 0; i < data->nsfrs; i++) {
+ struct resource *res;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, i);
+ if (!res) {
+ dev_dbg(dev, "Unable to find IOMEM region\n");
+ ret = -ENOENT;
+ goto err_res;
+ }
+
+ data->sfrbases[i] = ioremap(res->start, resource_size(res));
+ if (!data->sfrbases[i]) {
+ dev_dbg(dev, "Unable to map IOMEM @ PA:%#x\n",
+ res->start);
+ ret = -ENOENT;
+ goto err_res;
+ }
+ }
+
+ for (i = 0; i < data->nsfrs; i++) {
+ ret = platform_get_irq(pdev, i);
+ if (ret <= 0) {
+ dev_dbg(dev, "Unable to find IRQ resource\n");
+ goto err_irq;
+ }
+
+ ret = request_irq(ret, exynos_sysmmu_irq, 0,
+ dev_name(dev), data);
+ if (ret) {
+ dev_dbg(dev, "Unabled to register interrupt handler\n");
+ goto err_irq;
+ }
+ }
+
+ if (dev_get_platdata(dev)) {
+ char *deli, *beg;
+ struct sysmmu_platform_data *platdata = dev_get_platdata(dev);
+
+ beg = platdata->clockname;
+
+ for (deli = beg; (*deli != '\0') && (*deli != ','); deli++)
+ /* NOTHING */;
+
+ if (*deli == '\0')
+ deli = NULL;
+ else
+ *deli = '\0';
+
+ data->clk[0] = clk_get(dev, beg);
+ if (IS_ERR(data->clk[0])) {
+ data->clk[0] = NULL;
+ dev_dbg(dev, "No clock descriptor registered\n");
+ }
+
+ if (data->clk[0] && deli) {
+ *deli = ',';
+ beg = ++deli;
+ while ((*deli != '\0') && (*deli != ','))
+ ++deli;
+
+ if (*deli == '\0')
+ deli = NULL;
+ else
+ *deli = '\0';
+
+ data->clk[1] = clk_get(dev, beg);
+ if (IS_ERR(data->clk[1]))
+ data->clk[1] = NULL;
+ }
+
+ if (data->clk[1] && deli) {
+ *deli = ',';
+ beg = ++deli;
+ while ((*deli != '\0') && (*deli != ','))
+ ++deli;
+
+ if (*deli == '\0')
+ deli = NULL;
+ else
+ *deli = '\0';
+
+ data->clk[2] = clk_get(dev, beg);
+ if (IS_ERR(data->clk[2]))
+ data->clk[2] = NULL;
+ }
+
+ data->dbgname = platdata->dbgname;
+ data->qos = platdata->qos;
+ }
+
+ ret = exynos_init_iovmm(dev, &data->vmm);
+ if (ret)
+ goto err_iovmm;
+
+ data->sysmmu = dev;
+ rwlock_init(&data->lock);
+ INIT_LIST_HEAD(&data->node);
+
+ __set_fault_handler(data, &default_fault_handler);
+
+ dev_dbg(dev, "(%s) Initialized\n", data->dbgname);
+ return 0;
+err_iovmm:
+ if (data->clk[0]) {
+ clk_put(data->clk[0]);
+ if (data->clk[1]) {
+ clk_put(data->clk[1]);
+ if (data->clk[2])
+ clk_put(data->clk[2]);
+ }
+ }
+err_irq:
+ while (i-- > 0) {
+ int irq;
+
+ irq = platform_get_irq(pdev, i);
+ free_irq(irq, data);
+ }
+err_res:
+ while (data->nsfrs-- > 0)
+ iounmap(data->sfrbases[data->nsfrs]);
+ kfree(data->sfrbases);
+err_init:
+ kfree(data);
+err_alloc:
+ dev_err(dev, "Failed to initialize\n");
+ return ret;
+}
+
+static struct platform_driver exynos_sysmmu_driver = {
+ .probe = exynos_sysmmu_probe,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "exynos-sysmmu",
+ }
+};
+
+static inline void pgtable_flush(void *vastart, void *vaend)
+{
+ dmac_flush_range(vastart, vaend);
+ outer_flush_range(virt_to_phys(vastart),
+ virt_to_phys(vaend));
+}
+
+static int exynos_iommu_domain_init(struct iommu_domain *domain)
+{
+ struct exynos_iommu_domain *priv;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->pgtable = (unsigned long *)__get_free_pages(
+ GFP_KERNEL | __GFP_ZERO, 2);
+ if (!priv->pgtable)
+ goto err_pgtable;
+
+ priv->lv2entcnt = (short *)__get_free_pages(
+ GFP_KERNEL | __GFP_ZERO, 1);
+ if (!priv->lv2entcnt)
+ goto err_counter;
+
+ pgtable_flush(priv->pgtable, priv->pgtable + NUM_LV1ENTRIES);
+
+ spin_lock_init(&priv->lock);
+ spin_lock_init(&priv->pgtablelock);
+ INIT_LIST_HEAD(&priv->clients);
+
+ domain->priv = priv;
+ return 0;
+
+err_counter:
+ free_pages((unsigned long)priv->pgtable, 2);
+err_pgtable:
+ kfree(priv);
+ return -ENOMEM;
+}
+
+static void exynos_iommu_domain_destroy(struct iommu_domain *domain)
+{
+ struct exynos_iommu_domain *priv = domain->priv;
+ struct sysmmu_drvdata *data;
+ unsigned long flags;
+ int i;
+
+ WARN_ON(!list_empty(&priv->clients));
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ list_for_each_entry(data, &priv->clients, node) {
+ while (!exynos_sysmmu_disable(data->dev))
+ ; /* until System MMU is actually disabled */
+ }
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ for (i = 0; i < NUM_LV1ENTRIES; i++)
+ if (lv1ent_page(priv->pgtable + i))
+ kmem_cache_free(lv2table_kmem_cache,
+ __va(lv2table_base(priv->pgtable + i)));
+
+ free_pages((unsigned long)priv->pgtable, 2);
+ free_pages((unsigned long)priv->lv2entcnt, 1);
+ kfree(domain->priv);
+ domain->priv = NULL;
+}
+
+static int exynos_iommu_attach_device(struct iommu_domain *domain,
+ struct device *dev)
+{
+ struct sysmmu_drvdata *data = dev_get_drvdata(dev->archdata.iommu);
+ struct exynos_iommu_domain *priv = domain->priv;
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ ret = __exynos_sysmmu_enable(data, __pa(priv->pgtable), domain);
+
+ if (ret == 0) {
+ /* 'data->node' must not be appeared in priv->clients */
+ BUG_ON(!list_empty(&data->node));
+ data->dev = dev;
+ list_add_tail(&data->node, &priv->clients);
+ }
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ if (ret < 0) {
+ dev_err(dev, "%s: Failed to attach IOMMU with pgtable %#lx\n",
+ __func__, __pa(priv->pgtable));
+ } else if (ret > 0) {
+ dev_dbg(dev, "%s: IOMMU with pgtable 0x%lx already attached\n",
+ __func__, __pa(priv->pgtable));
+ } else {
+ dev_dbg(dev, "%s: Attached new IOMMU with pgtable 0x%lx\n",
+ __func__, __pa(priv->pgtable));
+ }
+
+ return ret;
+}
+
+static void exynos_iommu_detach_device(struct iommu_domain *domain,
+ struct device *dev)
+{
+ struct sysmmu_drvdata *data = dev_get_drvdata(dev->archdata.iommu);
+ struct exynos_iommu_domain *priv = domain->priv;
+ struct list_head *pos;
+ unsigned long flags;
+ bool found = false;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ list_for_each(pos, &priv->clients) {
+ if (list_entry(pos, struct sysmmu_drvdata, node) == data) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ goto finish;
+
+ if (__exynos_sysmmu_disable(data)) {
+ dev_dbg(dev, "%s: Detached IOMMU with pgtable %#lx\n",
+ __func__, __pa(priv->pgtable));
+ list_del(&data->node);
+ INIT_LIST_HEAD(&data->node);
+
+ } else {
+ dev_dbg(dev, "%s: Detaching IOMMU with pgtable %#lx delayed",
+ __func__, __pa(priv->pgtable));
+ }
+
+finish:
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static unsigned long *alloc_lv2entry(unsigned long *sent, unsigned long iova,
+ short *pgcounter)
+{
+ if (lv1ent_fault(sent)) {
+ unsigned long *pent;
+
+ pent = kmem_cache_zalloc(lv2table_kmem_cache, GFP_ATOMIC);
+ BUG_ON((unsigned long)pent & (LV2TABLE_SIZE - 1));
+ if (!pent)
+ return NULL;
+
+ *sent = mk_lv1ent_page(__pa(pent));
+ kmemleak_ignore(pent);
+ *pgcounter = NUM_LV2ENTRIES;
+ pgtable_flush(pent, pent + NUM_LV2ENTRIES);
+ pgtable_flush(sent, sent + 1);
+ }
+
+ return page_entry(sent, iova);
+}
+
+static int lv1set_section(unsigned long *sent, phys_addr_t paddr, short *pgcnt)
+{
+ if (lv1ent_section(sent))
+ return -EADDRINUSE;
+
+ if (lv1ent_page(sent)) {
+ if (*pgcnt != NUM_LV2ENTRIES)
+ return -EADDRINUSE;
+
+ kmem_cache_free(lv2table_kmem_cache, page_entry(sent, 0));
+
+ *pgcnt = 0;
+ }
+
+ *sent = mk_lv1ent_sect(paddr);
+
+ pgtable_flush(sent, sent + 1);
+
+ return 0;
+}
+
+static int lv2set_page(unsigned long *pent, phys_addr_t paddr, size_t size,
+ short *pgcnt)
+{
+ if (size == SPAGE_SIZE) {
+ if (!lv2ent_fault(pent))
+ return -EADDRINUSE;
+
+ *pent = mk_lv2ent_spage(paddr);
+ pgtable_flush(pent, pent + 1);
+ *pgcnt -= 1;
+ } else { /* size == LPAGE_SIZE */
+ int i;
+ for (i = 0; i < SPAGES_PER_LPAGE; i++, pent++) {
+ if (!lv2ent_fault(pent)) {
+ memset(pent, 0, sizeof(*pent) * i);
+ return -EADDRINUSE;
+ }
+
+ *pent = mk_lv2ent_lpage(paddr);
+ }
+ pgtable_flush(pent - SPAGES_PER_LPAGE, pent);
+ *pgcnt -= SPAGES_PER_LPAGE;
+ }
+
+ return 0;
+}
+
+static int exynos_iommu_map(struct iommu_domain *domain, unsigned long iova,
+ phys_addr_t paddr, size_t size, int prot)
+{
+ struct exynos_iommu_domain *priv = domain->priv;
+ unsigned long *entry;
+ unsigned long flags;
+ int ret = -ENOMEM;
+
+ BUG_ON(priv->pgtable == NULL);
+
+ spin_lock_irqsave(&priv->pgtablelock, flags);
+
+ entry = section_entry(priv->pgtable, iova);
+
+ if (size == SECT_SIZE) {
+ ret = lv1set_section(entry, paddr,
+ &priv->lv2entcnt[lv1ent_offset(iova)]);
+ } else {
+ unsigned long *pent;
+
+ pent = alloc_lv2entry(entry, iova,
+ &priv->lv2entcnt[lv1ent_offset(iova)]);
+
+ if (!pent)
+ ret = -ENOMEM;
+ else
+ ret = lv2set_page(pent, paddr, size,
+ &priv->lv2entcnt[lv1ent_offset(iova)]);
+ }
+
+ if (ret) {
+ pr_debug("%s: Failed to map iova 0x%lx/0x%x bytes\n",
+ __func__, iova, size);
+ }
+
+ spin_unlock_irqrestore(&priv->pgtablelock, flags);
+
+ return ret;
+}
+
+static size_t exynos_iommu_unmap(struct iommu_domain *domain,
+ unsigned long iova, size_t size)
+{
+ struct exynos_iommu_domain *priv = domain->priv;
+ unsigned long flags;
+ unsigned long *ent;
+
+ BUG_ON(priv->pgtable == NULL);
+
+ spin_lock_irqsave(&priv->pgtablelock, flags);
+
+ ent = section_entry(priv->pgtable, iova);
+
+ if (lv1ent_section(ent)) {
+ BUG_ON(size < SECT_SIZE);
+
+ *ent = 0;
+ pgtable_flush(ent, ent + 1);
+ size = SECT_SIZE;
+ goto done;
+ }
+
+ if (unlikely(lv1ent_fault(ent))) {
+ if (size > SECT_SIZE)
+ size = SECT_SIZE;
+ goto done;
+ }
+
+ /* lv1ent_page(sent) == true here */
+
+ ent = page_entry(ent, iova);
+
+ if (unlikely(lv2ent_fault(ent))) {
+ size = SPAGE_SIZE;
+ goto done;
+ }
+
+ if (lv2ent_small(ent)) {
+ *ent = 0;
+ size = SPAGE_SIZE;
+ priv->lv2entcnt[lv1ent_offset(iova)] += 1;
+ goto done;
+ }
+
+ /* lv1ent_large(ent) == true here */
+ BUG_ON(size < LPAGE_SIZE);
+
+ memset(ent, 0, sizeof(*ent) * SPAGES_PER_LPAGE);
+
+ size = LPAGE_SIZE;
+ priv->lv2entcnt[lv1ent_offset(iova)] += SPAGES_PER_LPAGE;
+done:
+ spin_unlock_irqrestore(&priv->pgtablelock, flags);
+
+ return size;
+}
+
+static phys_addr_t exynos_iommu_iova_to_phys(struct iommu_domain *domain,
+ unsigned long iova)
+{
+ struct exynos_iommu_domain *priv = domain->priv;
+ unsigned long *entry;
+ unsigned long flags;
+ phys_addr_t phys = 0;
+
+ spin_lock_irqsave(&priv->pgtablelock, flags);
+
+ entry = section_entry(priv->pgtable, iova);
+
+ if (lv1ent_section(entry)) {
+ phys = section_phys(entry) + section_offs(iova);
+ } else if (lv1ent_page(entry)) {
+ entry = page_entry(entry, iova);
+
+ if (lv2ent_large(entry))
+ phys = lpage_phys(entry) + lpage_offs(iova);
+ else if (lv2ent_small(entry))
+ phys = spage_phys(entry) + spage_offs(iova);
+ }
+
+ spin_unlock_irqrestore(&priv->pgtablelock, flags);
+
+ return phys;
+}
+
+static struct iommu_ops exynos_iommu_ops = {
+ .domain_init = &exynos_iommu_domain_init,
+ .domain_destroy = &exynos_iommu_domain_destroy,
+ .attach_dev = &exynos_iommu_attach_device,
+ .detach_dev = &exynos_iommu_detach_device,
+ .map = &exynos_iommu_map,
+ .unmap = &exynos_iommu_unmap,
+ .iova_to_phys = &exynos_iommu_iova_to_phys,
+ .pgsize_bitmap = SECT_SIZE | LPAGE_SIZE | SPAGE_SIZE,
+};
+
+static int __init exynos_iommu_init(void)
+{
+ int ret;
+
+ lv2table_kmem_cache = kmem_cache_create("exynos-iommu-lv2table",
+ LV2TABLE_SIZE, LV2TABLE_SIZE, 0, NULL);
+ if (!lv2table_kmem_cache) {
+ pr_err("%s: failed to create kmem cache\n", __func__);
+ return -ENOMEM;
+ }
+
+ ret = bus_set_iommu(&platform_bus_type, &exynos_iommu_ops);
+ if (!ret)
+ ret = platform_driver_register(&exynos_sysmmu_driver);
+
+ /* Nothing to do although platform_driver_register() fails */
+
+ return ret;
+}
+subsys_initcall(exynos_iommu_init);
diff --git a/drivers/iommu/exynos-iommu.h b/drivers/iommu/exynos-iommu.h
new file mode 100644
index 0000000..a09f9ae
--- /dev/null
+++ b/drivers/iommu/exynos-iommu.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Data structure definition for Exynos IOMMU driver
+ *
+ * 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.
+ */
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/genalloc.h>
+#include <linux/iommu.h>
+
+#include <plat/sysmmu.h>
+
+#ifdef CONFIG_EXYNOS_IOVMM
+
+#define IOVA_START 0xC0000000
+#define IOVM_SIZE (SZ_1G - SZ_4K) /* last 4K is for error values */
+
+struct exynos_vm_region {
+ struct list_head node;
+ dma_addr_t start;
+ size_t size;
+};
+
+struct exynos_iovmm {
+ struct iommu_domain *domain; /* iommu domain for this iovmm */
+ struct gen_pool *vmm_pool;
+ struct list_head regions_list; /* list of exynos_vm_region */
+ spinlock_t lock; /* lock for updating regions_list */
+};
+#endif
+
+
+struct sysmmu_drvdata {
+ struct list_head node; /* entry of exynos_iommu_domain.clients */
+ struct device *sysmmu; /* System MMU's device descriptor */
+ struct device *dev; /* Owner of system MMU */
+ char *dbgname;
+ int nsfrs;
+ void __iomem **sfrbases;
+ struct clk *clk[3];
+ int activations;
+ rwlock_t lock;
+ struct iommu_domain *domain; /* domain given to iommu_attach_device() */
+ sysmmu_fault_handler_t fault_handler;
+ unsigned long pgtable;
+#ifdef CONFIG_EXYNOS_IOVMM
+ struct exynos_iovmm vmm;
+#endif
+ unsigned int qos;
+};
+
+#ifdef CONFIG_EXYNOS_IOVMM
+static inline struct exynos_iovmm *exynos_get_iovmm(struct device *dev)
+{
+ struct sysmmu_drvdata *data = dev_get_drvdata(dev->archdata.iommu);
+
+ BUG_ON(!dev->archdata.iommu || !data);
+
+ return &data->vmm;
+}
+
+int exynos_init_iovmm(struct device *sysmmu, struct exynos_iovmm *vmm);
+#else
+#define exynos_init_iovmm(sysmmu, vmm) 0
+#endif
diff --git a/drivers/iommu/exynos-iovmm.c b/drivers/iommu/exynos-iovmm.c
new file mode 100644
index 0000000..e434ea6
--- /dev/null
+++ b/drivers/iommu/exynos-iovmm.c
@@ -0,0 +1,324 @@
+/* linux/drivers/iommu/exynos_iovmm.c
+ *
+ * Copyright (c) 2011-2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * 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.
+ */
+
+#ifdef CONFIG_EXYNOS_IOMMU_DEBUG
+#define DEBUG
+#endif
+
+#include <linux/kernel.h>
+#include <linux/hardirq.h>
+#include <linux/slab.h>
+#include <linux/scatterlist.h>
+#include <linux/err.h>
+
+#include <plat/iovmm.h>
+#include <plat/sysmmu.h>
+
+#include "exynos-iommu.h"
+
+static struct exynos_vm_region *find_region(
+ struct exynos_iovmm *vmm, dma_addr_t iova)
+{
+ struct exynos_vm_region *region;
+
+ list_for_each_entry(region, &vmm->regions_list, node)
+ if (region->start == iova)
+ return region;
+
+ return NULL;
+}
+
+int iovmm_activate(struct device *dev)
+{
+ struct exynos_iovmm *vmm = exynos_get_iovmm(dev);
+
+ return iommu_attach_device(vmm->domain, dev);
+}
+
+void iovmm_deactivate(struct device *dev)
+{
+ struct exynos_iovmm *vmm = exynos_get_iovmm(dev);
+
+ iommu_detach_device(vmm->domain, dev);
+}
+
+dma_addr_t iovmm_map(struct device *dev, struct scatterlist *sg, off_t offset,
+ size_t size)
+{
+ off_t start_off;
+ dma_addr_t addr, start = 0;
+ size_t mapped_size = 0;
+ struct exynos_vm_region *region;
+ struct exynos_iovmm *vmm = exynos_get_iovmm(dev);
+ int order;
+ int ret;
+#ifdef CONFIG_EXYNOS_IOVMM_ALIGN64K
+ size_t iova_size = 0;
+#endif
+
+ for (; sg_dma_len(sg) < offset; sg = sg_next(sg))
+ offset -= sg_dma_len(sg);
+
+ start_off = offset_in_page(sg_phys(sg) + offset);
+ size = PAGE_ALIGN(size + start_off);
+
+ order = __fls(min_t(size_t, size, SZ_1M));
+
+ region = kmalloc(sizeof(*region), GFP_KERNEL);
+ if (!region) {
+ ret = -ENOMEM;
+ goto err_map_nomem;
+ }
+
+#ifdef CONFIG_EXYNOS_IOVMM_ALIGN64K
+ iova_size = ALIGN(size, SZ_64K);
+ start = (dma_addr_t)gen_pool_alloc_aligned(vmm->vmm_pool, iova_size,
+ order);
+#else
+ start = (dma_addr_t)gen_pool_alloc_aligned(vmm->vmm_pool, size, order);
+#endif
+ if (!start) {
+ ret = -ENOMEM;
+ goto err_map_noiomem;
+ }
+
+ addr = start;
+ do {
+ phys_addr_t phys;
+ size_t len;
+
+ phys = sg_phys(sg);
+ len = sg_dma_len(sg);
+
+ /* if back to back sg entries are contiguous consolidate them */
+ while (sg_next(sg) &&
+ sg_phys(sg) + sg_dma_len(sg) == sg_phys(sg_next(sg))) {
+ len += sg_dma_len(sg_next(sg));
+ sg = sg_next(sg);
+ }
+
+ if (offset > 0) {
+ len -= offset;
+ phys += offset;
+ offset = 0;
+ }
+
+ if (offset_in_page(phys)) {
+ len += offset_in_page(phys);
+ phys = round_down(phys, PAGE_SIZE);
+ }
+
+ len = PAGE_ALIGN(len);
+
+ if (len > (size - mapped_size))
+ len = size - mapped_size;
+
+ ret = iommu_map(vmm->domain, addr, phys, len, 0);
+ if (ret)
+ break;
+
+ addr += len;
+ mapped_size += len;
+ } while ((sg = sg_next(sg)) && (mapped_size < size));
+
+ BUG_ON(mapped_size > size);
+
+ if (mapped_size < size)
+ goto err_map_map;
+
+#ifdef CONFIG_EXYNOS_IOVMM_ALIGN64K
+ if (iova_size != size) {
+ addr = start + size;
+ size = iova_size;
+
+ for (; addr < start + size; addr += PAGE_SIZE) {
+ ret = iommu_map(vmm->domain, addr,
+ page_to_phys(ZERO_PAGE(0)), PAGE_SIZE, 0);
+ if (ret)
+ goto err_map_map;
+
+ mapped_size += PAGE_SIZE;
+ }
+ }
+#endif
+
+ region->start = start + start_off;
+ region->size = size;
+
+ INIT_LIST_HEAD(®ion->node);
+
+ spin_lock(&vmm->lock);
+
+ list_add(®ion->node, &vmm->regions_list);
+
+ spin_unlock(&vmm->lock);
+
+ dev_dbg(dev, "IOVMM: Allocated VM region @ %#x/%#X bytes.\n",
+ region->start, region->size);
+
+ return region->start;
+
+err_map_map:
+ iommu_unmap(vmm->domain, start, mapped_size);
+ gen_pool_free(vmm->vmm_pool, start, size);
+err_map_noiomem:
+ kfree(region);
+err_map_nomem:
+ dev_dbg(dev, "IOVMM: Failed to allocated VM region for %#x bytes.\n",
+ size);
+ return (dma_addr_t)ret;
+}
+
+void iovmm_unmap(struct device *dev, dma_addr_t iova)
+{
+ struct exynos_vm_region *region;
+ struct exynos_iovmm *vmm = exynos_get_iovmm(dev);
+ size_t unmapped_size;
+
+ /* This function must not be called in IRQ handlers */
+ BUG_ON(in_irq());
+
+ spin_lock(&vmm->lock);
+
+ region = find_region(vmm, iova);
+ if (WARN_ON(!region)) {
+ spin_unlock(&vmm->lock);
+ return;
+ }
+
+ list_del(®ion->node);
+
+ spin_unlock(&vmm->lock);
+
+ region->start = round_down(region->start, PAGE_SIZE);
+
+ unmapped_size = iommu_unmap(vmm->domain, region->start, region->size);
+
+ exynos_sysmmu_tlb_invalidate(dev);
+
+ gen_pool_free(vmm->vmm_pool, region->start, region->size);
+
+ WARN_ON(unmapped_size != region->size);
+ dev_dbg(dev, "IOVMM: Unmapped %#x bytes from %#x.\n",
+ unmapped_size, region->start);
+
+ kfree(region);
+}
+
+int iovmm_map_oto(struct device *dev, phys_addr_t phys, size_t size)
+{
+ struct exynos_vm_region *region;
+ struct exynos_iovmm *vmm = exynos_get_iovmm(dev);
+ int ret;
+
+ if (WARN_ON((phys + size) >= IOVA_START)) {
+ dev_err(dev,
+ "Unable to create one to one mapping for %#x @ %#x\n",
+ size, phys);
+ return -EINVAL;
+ }
+
+ region = kmalloc(sizeof(*region), GFP_KERNEL);
+ if (!region)
+ return -ENOMEM;
+
+ if (WARN_ON(phys & ~PAGE_MASK))
+ phys = round_down(phys, PAGE_SIZE);
+
+
+ ret = iommu_map(vmm->domain, (dma_addr_t)phys, phys, size, 0);
+ if (ret < 0) {
+ kfree(region);
+ return ret;
+ }
+
+ region->start = (dma_addr_t)phys;
+ region->size = size;
+ INIT_LIST_HEAD(®ion->node);
+
+ spin_lock(&vmm->lock);
+
+ list_add(®ion->node, &vmm->regions_list);
+
+ spin_unlock(&vmm->lock);
+
+ return 0;
+}
+
+void iovmm_unmap_oto(struct device *dev, phys_addr_t phys)
+{
+ struct exynos_vm_region *region;
+ struct exynos_iovmm *vmm = exynos_get_iovmm(dev);
+ size_t unmapped_size;
+
+ /* This function must not be called in IRQ handlers */
+ BUG_ON(in_irq());
+
+ if (WARN_ON(phys & ~PAGE_MASK))
+ phys = round_down(phys, PAGE_SIZE);
+
+ spin_lock(&vmm->lock);
+
+ region = find_region(vmm, (dma_addr_t)phys);
+ if (WARN_ON(!region)) {
+ spin_unlock(&vmm->lock);
+ return;
+ }
+
+ list_del(®ion->node);
+
+ spin_unlock(&vmm->lock);
+
+ unmapped_size = iommu_unmap(vmm->domain, region->start, region->size);
+
+ exynos_sysmmu_tlb_invalidate(dev);
+
+ WARN_ON(unmapped_size != region->size);
+ dev_dbg(dev, "IOVMM: Unmapped %#x bytes from %#x.\n",
+ unmapped_size, region->start);
+
+ kfree(region);
+}
+
+int exynos_init_iovmm(struct device *sysmmu, struct exynos_iovmm *vmm)
+{
+ int ret = 0;
+
+ vmm->vmm_pool = gen_pool_create(PAGE_SHIFT, -1);
+ if (!vmm->vmm_pool) {
+ ret = -ENOMEM;
+ goto err_setup_genalloc;
+ }
+
+ /* (1GB - 4KB) addr space from 0xC0000000 */
+ ret = gen_pool_add(vmm->vmm_pool, IOVA_START, IOVM_SIZE, -1);
+ if (ret)
+ goto err_setup_domain;
+
+ vmm->domain = iommu_domain_alloc(&platform_bus_type);
+ if (!vmm->domain) {
+ ret = -ENOMEM;
+ goto err_setup_domain;
+ }
+
+ spin_lock_init(&vmm->lock);
+
+ INIT_LIST_HEAD(&vmm->regions_list);
+
+ dev_dbg(sysmmu, "IOVMM: Created %#x B IOVMM from %#x.\n",
+ IOVM_SIZE, IOVA_START);
+ return 0;
+err_setup_domain:
+ gen_pool_destroy(vmm->vmm_pool);
+err_setup_genalloc:
+ dev_dbg(sysmmu, "IOVMM: Failed to create IOVMM (%d)\n", ret);
+
+ return ret;
+}
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index ce1e7ba..a0ca2aa 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -66,6 +66,27 @@
select VIDEOBUF2_CORE
select VIDEOBUF2_MEMOPS
tristate
+
+choice
+prompt "Video Buffer 2 for Exynos platforms"
+default VIDEOBUF2_ION
+config VIDEOBUF2_CMA_PHYS
+ bool "CMA"
+ depends on CMA
+ select VIDEOBUF2_CORE
+ select VIDEOBUF2_MEMOPS
+ help
+ Internal memory management for Video Buffer 2 by CMA
+
+config VIDEOBUF2_ION
+ bool "Android ION"
+ depends on ION_EXYNOS
+ select VIDEOBUF2_CORE
+ select VIDEOBUF2_MEMOPS
+ help
+ Internal memory management for Video Buffer 2 by ION
+endchoice
+
#
# Multimedia Video device configuration
#
@@ -547,8 +568,141 @@
---help---
This driver supports NOON010PC30 CIF camera from Siliconfile
+config VIDEO_S5K4E5
+ tristate "S5K4E5 sensor support"
+ depends on VIDEO_V4L2 && ((VIDEO_FIMC_MIPI || VIDEO_S5P_MIPI_CSIS) && VIDEO_EXYNOS_FIMC_IS) || VIDEO_EXYNOS5_FIMC_IS || VIDEO_EXYNOS5_FIMC_IS2
+ ---help---
+ This driver supports S5K4E5 sensor.
+choice
+depends on VIDEO_S5K4E5
+prompt "MIPI Camera port for S5K4E5"
+default S5K4E5_CSI_C
+config S5K4E5_CSI_C
+ bool "CSI Camera A port"
+ depends on (VIDEO_FIMC_MIPI || VIDEO_S5P_MIPI_CSIS || VIDEO_EXYNOS5_FIMC_IS || VIDEO_EXYNOS5_FIMC_IS2)
+ help
+ This enables CSI A port for 4E5 sensor
+ CSI is camera sensor interface
+ currenly there is A and B
+ This is only for internal ISP, FIMC-IS
+
+config S5K4E5_CSI_D
+ bool "CSI Camera B port"
+ depends on (VIDEO_FIMC_MIPI || VIDEO_S5P_MIPI_CSIS || VIDEO_EXYNOS5_FIMC_IS || VIDEO_EXYNOS5_FIMC_IS2)
+ help
+ This enables CSI B port for 4E5 sensor
+ CSI is camera sensor interface
+ currenly there is A and B
+ This is only for internal ISP, FIMC-IS
+endchoice
+
+choice
+depends on (VIDEO_S5K4E5 && (VIDEO_EXYNOS5_FIMC_IS || VIDEO_EXYNOS5_FIMC_IS2))
+prompt "Camera position for S5K4E5"
+default S5K4E5_POSITION_REAR
+config S5K4E5_POSITION_FRONT
+ bool "front camera"
+ depends on VIDEO_EXYNOS5_FIMC_IS || VIDEO_EXYNOS5_FIMC_IS2
+ help
+ This set as front camera
+ This set as front camera
+ This set as front camera
+ This set as front camera
+
+config S5K4E5_POSITION_REAR
+ bool "rear camera"
+ depends on VIDEO_EXYNOS5_FIMC_IS || VIDEO_EXYNOS5_FIMC_IS2
+ help
+ This set as rear camera
+ This set as rear camera
+ This set as rear camera
+ This set as rear camera
+endchoice
+
+config VIDEO_S5K6A3
+ tristate "S5K6A3 sensor support"
+ depends on VIDEO_V4L2 && ((VIDEO_FIMC_MIPI || VIDEO_S5P_MIPI_CSIS) && VIDEO_EXYNOS_FIMC_IS) || VIDEO_EXYNOS5_FIMC_IS || VIDEO_EXYNOS5_FIMC_IS2
+ help
+ This driver supports S5K6A3 sensor.
+choice
+depends on VIDEO_S5K6A3
+prompt "MIPI Camera port for S5K6A3"
+default S5K6A3_CSI_D
+config S5K6A3_CSI_C
+ bool "CSI Camera A port"
+ depends on (VIDEO_FIMC_MIPI || VIDEO_S5P_MIPI_CSIS || VIDEO_EXYNOS5_FIMC_IS || VIDEO_EXYNOS5_FIMC_IS2)
+ help
+ This enables CSI A port for 6A3 sensor
+ CSI is camera sensor interface
+ currenly there is A and B
+ This is only for internal ISP, FIMC-IS
+config S5K6A3_CSI_D
+ bool "CSI Camera B port"
+ depends on (VIDEO_FIMC_MIPI || VIDEO_S5P_MIPI_CSIS || VIDEO_EXYNOS5_FIMC_IS || VIDEO_EXYNOS5_FIMC_IS2)
+ help
+ This enables CSI B port for 6A3 sensor
+ CSI is camera sensor interface
+ currenly there is A and B
+ This is only for internal ISP, FIMC-IS
+endchoice
+
+choice
+depends on (VIDEO_S5K4E5 && (VIDEO_EXYNOS5_FIMC_IS || VIDEO_EXYNOS5_FIMC_IS2))
+prompt "Camera position for S5K6A3"
+default S5K6A3_POSITION_FRONT
+
+config S5K6A3_POSITION_FRONT
+ bool "front camera"
+ depends on VIDEO_EXYNOS5_FIMC_IS || VIDEO_EXYNOS5_FIMC_IS2
+ help
+ This set as front camera
+ This set as front camera
+ This set as front camera
+ This set as front camera
+
+config S5K6A3_POSITION_REAR
+ bool "rear camera"
+ depends on VIDEO_EXYNOS5_FIMC_IS || VIDEO_EXYNOS5_FIMC_IS2
+ help
+ This set as rear camera
+ This set as rear camera
+ This set as rear camera
+ This set as rear camera
+
+endchoice
+
source "drivers/media/video/m5mols/Kconfig"
+choice
+depends on VIDEO_S5K4BA || VIDEO_S5K4EA || VIDEO_M5MO || VIDEO_M5MOLS
+prompt "Select ITU / MIPI Camera port"
+default ITU_A
+config ITU_A
+ bool "ITU Camera A port"
+ depends on !(VIDEO_FIMC_MIPI || VIDEO_S5P_MIPI_CSIS ||\
+ VIDEO_EXYNOS_MIPI_CSIS)
+ help
+ This enables support for ITU A port
+config ITU_B
+ bool "ITU Camera B port"
+ depends on !(VIDEO_FIMC_MIPI || VIDEO_S5P_MIPI_CSIS ||\
+ VIDEO_EXYNOS_MIPI_CSIS)
+ help
+ This enables support for ITU B port
+config CSI_C
+ bool "CSI Camera A port"
+ depends on (VIDEO_FIMC_MIPI || VIDEO_S5P_MIPI_CSIS ||\
+ VIDEO_EXYNOS_MIPI_CSIS)
+ help
+ This enables support for CSI A port
+config CSI_D
+ bool "CSI Camera B port"
+ depends on (VIDEO_FIMC_MIPI || VIDEO_S5P_MIPI_CSIS ||\
+ VIDEO_EXYNOS_MIPI_CSIS)
+ help
+ This enables support for CSI B port
+endchoice
+
config VIDEO_S5K6AA
tristate "Samsung S5K6AAFX sensor support"
depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
@@ -1161,6 +1315,9 @@
source "drivers/media/video/s5p-tv/Kconfig"
endif # V4L_PLATFORM_DRIVERS
+
+source "drivers/media/video/exynos/Kconfig"
+
endif # VIDEO_CAPTURE_DRIVERS
menuconfig V4L_MEM2MEM_DRIVERS
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index a6282a3..7295a79 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -134,6 +134,8 @@
obj-$(CONFIG_VIDEOBUF2_VMALLOC) += videobuf2-vmalloc.o
obj-$(CONFIG_VIDEOBUF2_DMA_CONTIG) += videobuf2-dma-contig.o
obj-$(CONFIG_VIDEOBUF2_DMA_SG) += videobuf2-dma-sg.o
+obj-$(CONFIG_VIDEOBUF2_CMA_PHYS) += videobuf2-cma-phys.o
+obj-$(CONFIG_VIDEOBUF2_ION) += videobuf2-ion.o
obj-$(CONFIG_V4L2_MEM2MEM_DEV) += v4l2-mem2mem.o
@@ -192,6 +194,8 @@
obj-$(CONFIG_VIDEO_SAMSUNG_S5P_G2D) += s5p-g2d/
+obj-$(CONFIG_VIDEO_EXYNOS) += exynos/
+
obj-$(CONFIG_BLACKFIN) += blackfin/
obj-$(CONFIG_ARCH_DAVINCI) += davinci/
diff --git a/drivers/media/video/exynos/Kconfig b/drivers/media/video/exynos/Kconfig
new file mode 100644
index 0000000..84acff8
--- /dev/null
+++ b/drivers/media/video/exynos/Kconfig
@@ -0,0 +1,42 @@
+#
+# Exynos multimedia device drivers
+#
+config VIDEO_EXYNOS
+ bool "Exynos Multimedia Devices"
+ depends on ARCH_EXYNOS5
+ default n
+ select VIDEO_FIXED_MINOR_RANGES
+ help
+ This is a representative exynos multimedia device.
+
+if VIDEO_EXYNOS
+ source "drivers/media/video/exynos/mdev/Kconfig"
+ source "drivers/media/video/exynos/fimc-lite/Kconfig"
+ source "drivers/media/video/exynos/mipi-csis/Kconfig"
+ source "drivers/media/video/exynos/gsc/Kconfig"
+ source "drivers/media/video/exynos/jpeg/Kconfig"
+ source "drivers/media/video/exynos/fimg2d/Kconfig"
+ source "drivers/media/video/exynos/mfc/Kconfig"
+ source "drivers/media/video/exynos/tv/Kconfig"
+ source "drivers/media/video/exynos/rotator/Kconfig"
+endif
+
+choice
+depends on VIDEO_EXYNOS
+prompt "FIMC_IS(Image Signal Process) version"
+default VIDEO_EXYNOS5_FIMC_IS
+config VIDEO_EXYNOS5_FIMC_IS
+ bool "Camera 1.0"
+ help
+ This will be use fimc_is_mc for camera 1.0
+
+config VIDEO_EXYNOS5_FIMC_IS2
+ bool "Camera 2.0"
+ help
+ This will be use fimc_is_mc2 for camera 2.0
+endchoice
+
+config MEDIA_EXYNOS
+ bool
+ help
+ Compile mdev to use exynos5 media device driver.
diff --git a/drivers/media/video/exynos/Makefile b/drivers/media/video/exynos/Makefile
new file mode 100644
index 0000000..2c16319
--- /dev/null
+++ b/drivers/media/video/exynos/Makefile
@@ -0,0 +1,13 @@
+obj-$(CONFIG_EXYNOS_MEDIA_DEVICE) += mdev/
+obj-$(CONFIG_VIDEO_EXYNOS_MIPI_CSIS) += mipi-csis/
+obj-$(CONFIG_VIDEO_EXYNOS_FIMC_LITE) += fimc-lite/
+obj-$(CONFIG_VIDEO_EXYNOS_GSCALER) += gsc/
+obj-$(CONFIG_VIDEO_EXYNOS_JPEG) += jpeg/
+obj-$(CONFIG_VIDEO_EXYNOS_FIMG2D) += fimg2d/
+obj-$(CONFIG_VIDEO_EXYNOS_MFC) += mfc/
+obj-$(CONFIG_VIDEO_EXYNOS_TV) += tv/
+obj-$(CONFIG_VIDEO_EXYNOS_ROTATOR) += rotator/
+obj-$(CONFIG_VIDEO_EXYNOS5_FIMC_IS) += fimc-is-mc/
+obj-$(CONFIG_VIDEO_EXYNOS5_FIMC_IS2) += fimc-is-mc2/
+
+EXTRA_CLAGS += -Idrivers/media/video
diff --git a/drivers/media/video/exynos/fimc-is-mc/Kconfig b/drivers/media/video/exynos/fimc-is-mc/Kconfig
new file mode 100644
index 0000000..d675d87
--- /dev/null
+++ b/drivers/media/video/exynos/fimc-is-mc/Kconfig
@@ -0,0 +1,7 @@
+config VIDEO_EXYNOS5_FIMC_IS
+ bool "Exynos FIMC-IS (Image Subsystem) driver"
+ depends on VIDEO_EXYNOS && ARCH_EXYNOS5
+ select MEDIA_EXYNOS
+ default n
+ help
+ This is a v4l2 driver for exynos FIMC-IS device.
\ No newline at end of file
diff --git a/drivers/media/video/exynos/fimc-is-mc/Makefile b/drivers/media/video/exynos/fimc-is-mc/Makefile
new file mode 100644
index 0000000..f2f135a
--- /dev/null
+++ b/drivers/media/video/exynos/fimc-is-mc/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_VIDEO_EXYNOS5_FIMC_IS) += fimc-is-core.o fimc-is-vb2.o fimc-is-helper.o fimc-is-misc.o fimc-is-video.o
diff --git a/drivers/media/video/exynos/fimc-is-mc/fimc-is-cmd.h b/drivers/media/video/exynos/fimc-is-mc/fimc-is-cmd.h
new file mode 100644
index 0000000..2119334
--- /dev/null
+++ b/drivers/media/video/exynos/fimc-is-mc/fimc-is-cmd.h
@@ -0,0 +1,171 @@
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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.
+ */
+
+#ifndef FIMC_IS_CMD_H
+#define FIMC_IS_CMD_H
+
+#define IS_COMMAND_VER 107 /* IS COMMAND VERSION 1.07 */
+
+enum is_cmd {
+ /* HOST -> IS */
+ HIC_PREVIEW_STILL = 0x1,
+ HIC_PREVIEW_VIDEO,
+ HIC_CAPTURE_STILL,
+ HIC_CAPTURE_VIDEO,
+ HIC_STREAM_ON,
+ HIC_STREAM_OFF,
+ HIC_SHOT,
+ HIC_SET_PARAMETER,
+ HIC_GET_PARAMETER,
+ HIC_SET_TUNE,
+ RESERVED1,
+ HIC_GET_STATUS,
+ /* SENSOR PART*/
+ HIC_OPEN_SENSOR,
+ HIC_CLOSE_SENSOR,
+ HIC_SIMMIAN_INIT,
+ HIC_SIMMIAN_WRITE,
+ HIC_SIMMIAN_READ,
+ HIC_POWER_DOWN,
+ HIC_GET_SET_FILE_ADDR,
+ HIC_LOAD_SET_FILE,
+ HIC_MSG_CONFIG,
+ HIC_MSG_TEST,
+ /* IS -> HOST */
+ IHC_GET_SENSOR_NUMBER = 0x1000,
+ /* Parameter1 : Address of space to copy a setfile */
+ /* Parameter2 : Space szie */
+ IHC_SET_SHOT_MARK,
+ /* PARAM1 : a frame number */
+ /* PARAM2 : confidence level(smile 0~100) */
+ /* PARMA3 : confidence level(blink 0~100) */
+ IHC_SET_FACE_MARK,
+ /* PARAM1 : coordinate count */
+ /* PARAM2 : coordinate buffer address */
+ IHC_FRAME_DONE,
+ /* PARAM1 : frame start number */
+ /* PARAM2 : frame count */
+ IHC_AA_DONE,
+ IHC_NOT_READY
+};
+
+enum is_reply {
+ ISR_DONE = 0x2000,
+ ISR_NDONE
+};
+
+enum is_scenario_id {
+ ISS_PREVIEW_STILL,
+ ISS_PREVIEW_VIDEO,
+ ISS_CAPTURE_STILL,
+ ISS_CAPTURE_VIDEO,
+ ISS_END
+};
+
+struct is_setfile_header_element {
+ u32 binary_addr;
+ u32 binary_size;
+};
+
+struct is_setfile_header {
+ struct is_setfile_header_element isp[ISS_END];
+ struct is_setfile_header_element drc[ISS_END];
+ struct is_setfile_header_element fd[ISS_END];
+};
+
+#define HOST_SET_INT_BIT 0x00000001
+#define HOST_CLR_INT_BIT 0x00000001
+#define IS_SET_INT_BIT 0x00000001
+#define IS_CLR_INT_BIT 0x00000001
+
+#define HOST_SET_INTERRUPT(base) (base->uiINTGR0 |= HOST_SET_INT_BIT)
+#define HOST_CLR_INTERRUPT(base) (base->uiINTCR0 |= HOST_CLR_INT_BIT)
+#define IS_SET_INTERRUPT(base) (base->uiINTGR1 |= IS_SET_INT_BIT)
+#define IS_CLR_INTERRUPT(base) (base->uiINTCR1 |= IS_CLR_INT_BIT)
+
+struct is_common_reg {
+ u32 hicmd;
+ u32 hic_sensorid;
+ u32 hic_param1;
+ u32 hic_param2;
+ u32 hic_param3;
+ u32 hic_param4;
+
+ u32 reserved1[4];
+
+ u32 ihcmd;
+ u32 ihc_sensorid;
+ u32 ihc_param1;
+ u32 ihc_param2;
+ u32 ihc_param3;
+ u32 ihc_param4;
+
+ u32 reserved2[4];
+
+ u32 isp_sensor_id;
+ u32 isp_param1;
+ u32 isp_param2;
+ u32 isp_param3;
+ u32 isp_param4;
+ u32 reserved3[3];
+
+ u32 scc_sensor_id;
+ u32 scc_param1;
+ u32 scc_param2;
+ u32 scc_param3;
+ u32 scc_param4;
+ u32 reserved4[3];
+
+ u32 dnr_sensor_id;
+ u32 dnr_param1;
+ u32 dnr_param2;
+ u32 dnr_param3;
+ u32 dnr_param4;
+ u32 reserved5[3];
+
+ u32 scp_sensor_id;
+ u32 scp_param1;
+ u32 scp_param2;
+ u32 scp_param3;
+ u32 scp_param4;
+ u32 reserved6[15];
+};
+
+struct is_mcuctl_reg {
+ u32 mcuctl;
+ u32 bboar;
+
+ u32 intgr0;
+ u32 intcr0;
+ u32 intmr0;
+ u32 intsr0;
+ u32 intmsr0;
+
+ u32 intgr1;
+ u32 intcr1;
+ u32 intmr1;
+ u32 intsr1;
+ u32 intmsr1;
+
+ u32 intcr2;
+ u32 intmr2;
+ u32 intsr2;
+ u32 intmsr2;
+
+ u32 gpoctrl;
+ u32 cpoenctlr;
+ u32 gpictlr;
+
+ u32 pad[0xD];
+
+ struct is_common_reg common_reg;
+};
+#endif
diff --git a/drivers/media/video/exynos/fimc-is-mc/fimc-is-core.c b/drivers/media/video/exynos/fimc-is-mc/fimc-is-core.c
new file mode 100644
index 0000000..c3f20ef
--- /dev/null
+++ b/drivers/media/video/exynos/fimc-is-mc/fimc-is-core.c
@@ -0,0 +1,1920 @@
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ * exynos5 fimc-is core functions
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <mach/videonode.h>
+#if defined(CONFIG_BUSFREQ_OPP) && defined(CONFIG_CPU_EXYNOS5250)
+#include <mach/dev.h>
+#endif
+#include <media/exynos_mc.h>
+#include <linux/cma.h>
+#include <asm/cacheflush.h>
+#include <asm/pgtable.h>
+#include <linux/firmware.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/scatterlist.h>
+#include <linux/videodev2_exynos_camera.h>
+
+#include "fimc-is-core.h"
+#include "fimc-is-helper.h"
+#include "fimc-is-param.h"
+#include "fimc-is-cmd.h"
+#include "fimc-is-regs.h"
+#include "fimc-is-err.h"
+#include "fimc-is-misc.h"
+
+#if defined(CONFIG_VIDEOBUF2_ION)
+static void *is_vb_cookie;
+void *buf_start;
+
+#endif
+
+static struct fimc_is_dev *to_fimc_is_dev_from_front_dev
+ (struct fimc_is_front_dev *front_dev)
+{
+ return container_of(front_dev, struct fimc_is_dev, front);
+}
+
+static struct fimc_is_sensor_dev *to_fimc_is_sensor_dev
+ (struct v4l2_subdev *sdev)
+{
+ return container_of(sdev, struct fimc_is_sensor_dev, sd);
+}
+
+static struct fimc_is_front_dev *to_fimc_is_front_dev(struct v4l2_subdev *sdev)
+{
+ return container_of(sdev, struct fimc_is_front_dev, sd);
+}
+
+static struct fimc_is_back_dev *to_fimc_is_back_dev(struct v4l2_subdev *sdev)
+{
+ return container_of(sdev, struct fimc_is_back_dev, sd);
+}
+
+static int fimc_is_sensor_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+#if defined(CONFIG_VIDEOBUF2_CMA_PHYS)
+void fimc_is_mem_cache_clean(const void *start_addr,
+ unsigned long size)
+{
+ unsigned long paddr;
+
+ dmac_map_area(start_addr, size, DMA_TO_DEVICE);
+ /*
+ * virtual & phsical addrees mapped directly, so we can convert
+ * the address just using offset
+ */
+ paddr = __pa((unsigned long)start_addr);
+ outer_clean_range(paddr, paddr + size);
+}
+
+void fimc_is_mem_cache_inv(const void *start_addr, unsigned long size)
+{
+ unsigned long paddr;
+ paddr = __pa((unsigned long)start_addr);
+ outer_inv_range(paddr, paddr + size);
+ dmac_unmap_area(start_addr, size, DMA_FROM_DEVICE);
+}
+
+int fimc_is_init_mem(struct fimc_is_dev *dev)
+{
+ struct cma_info mem_info;
+ char cma_name[16];
+ int err;
+
+ dbg("fimc_is_init_mem - ION\n");
+ sprintf(cma_name, "%s%d", "fimc_is", 0);
+ err = cma_info(&mem_info, &dev->pdev->dev, 0);
+ dbg("%s : [cma_info] start_addr : 0x%x, end_addr : 0x%x\n",
+ __func__, mem_info.lower_bound, mem_info.upper_bound);
+ dbg("total_size : 0x%x, free_size : 0x%x\n",
+ mem_info.total_size, mem_info.free_size);
+ if (err) {
+ dev_err(&dev->pdev->dev, "%s: get cma info failed\n", __func__);
+ return -EINVAL;
+ }
+ dev->mem.size = FIMC_IS_A5_MEM_SIZE;
+ dev->mem.base = (dma_addr_t)cma_alloc
+ (&dev->pdev->dev, cma_name, (size_t)dev->mem.size, 0);
+ dev->is_p_region =
+ (struct is_region *)(phys_to_virt(dev->mem.base +
+ FIMC_IS_A5_MEM_SIZE - FIMC_IS_REGION_SIZE));
+ memset((void *)dev->is_p_region, 0,
+ (unsigned long)sizeof(struct is_region));
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ FIMC_IS_REGION_SIZE+1);
+
+ dbg("ctrl->mem.size = 0x%x\n", dev->mem.size);
+ dbg("ctrl->mem.base = 0x%x\n", dev->mem.base);
+
+ return 0;
+}
+#elif defined(CONFIG_VIDEOBUF2_ION)
+
+void fimc_is_mem_init_mem_cleanup(void *alloc_ctxes)
+{
+ vb2_ion_destroy_context(alloc_ctxes);
+}
+
+void fimc_is_mem_resume(void *alloc_ctxes)
+{
+ vb2_ion_attach_iommu(alloc_ctxes);
+}
+
+void fimc_is_mem_suspend(void *alloc_ctxes)
+{
+ vb2_ion_detach_iommu(alloc_ctxes);
+}
+
+int fimc_is_cache_flush(struct fimc_is_dev *dev,
+ const void *start_addr, unsigned long size)
+{
+ vb2_ion_sync_for_device(dev->mem.fw_cookie,
+ (unsigned long)start_addr - (unsigned long)dev->mem.kvaddr,
+ size, DMA_BIDIRECTIONAL);
+ return 0;
+}
+
+/* Allocate firmware */
+int fimc_is_alloc_firmware(struct fimc_is_dev *dev)
+{
+ void *fimc_is_bitproc_buf;
+ int ret;
+
+ dbg("Allocating memory for FIMC-IS firmware.\n");
+
+ fimc_is_bitproc_buf = vb2_ion_private_alloc(dev->alloc_ctx,
+ FIMC_IS_A5_MEM_SIZE +
+ SIZE_ODC_INTERNAL_BUF * NUM_ODC_INTERNAL_BUF +
+ SIZE_DIS_INTERNAL_BUF * NUM_DIS_INTERNAL_BUF +
+ SIZE_3DNR_INTERNAL_BUF * NUM_3DNR_INTERNAL_BUF +
+ SIZE_ISP_INTERNAL_BUF * NUM_ISP_INTERNAL_BUF);
+ if (IS_ERR(fimc_is_bitproc_buf)) {
+ fimc_is_bitproc_buf = 0;
+ err("Allocating bitprocessor buffer failed\n");
+ return -ENOMEM;
+ }
+
+ ret = vb2_ion_dma_address(fimc_is_bitproc_buf, &dev->mem.dvaddr);
+ if ((ret < 0) || (dev->mem.dvaddr & FIMC_IS_FW_BASE_MASK)) {
+ err("The base memory is not aligned to 64MB.\n");
+ vb2_ion_private_free(fimc_is_bitproc_buf);
+ dev->mem.dvaddr = 0;
+ fimc_is_bitproc_buf = 0;
+ return -EIO;
+ }
+ dbg("Device vaddr = %08x , size = %08x\n",
+ dev->mem.dvaddr, FIMC_IS_A5_MEM_SIZE);
+
+ dev->mem.kvaddr = vb2_ion_private_vaddr(fimc_is_bitproc_buf);
+ if (IS_ERR(dev->mem.kvaddr)) {
+ err("Bitprocessor memory remap failed\n");
+ vb2_ion_private_free(fimc_is_bitproc_buf);
+ dev->mem.dvaddr = 0;
+ fimc_is_bitproc_buf = 0;
+ return -EIO;
+ }
+ dbg("Virtual address for FW: %08lx\n",
+ (long unsigned int)dev->mem.kvaddr);
+ dev->mem.bitproc_buf = fimc_is_bitproc_buf;
+ dev->mem.fw_cookie = fimc_is_bitproc_buf;
+
+ is_vb_cookie = dev->mem.fw_cookie;
+ buf_start = dev->mem.kvaddr;
+ return 0;
+}
+
+void fimc_is_mem_cache_clean(const void *start_addr,
+ unsigned long size)
+{
+ off_t offset;
+
+ if (start_addr < buf_start) {
+ err("Start address error\n");
+ return;
+ }
+ size--;
+
+ offset = start_addr - buf_start;
+
+ vb2_ion_sync_for_device(is_vb_cookie, offset, size, DMA_TO_DEVICE);
+}
+
+void fimc_is_mem_cache_inv(const void *start_addr, unsigned long size)
+{
+ off_t offset;
+
+ if (start_addr < buf_start) {
+ err("Start address error\n");
+ return;
+ }
+
+ offset = start_addr - buf_start;
+
+ vb2_ion_sync_for_device(is_vb_cookie, offset, size, DMA_FROM_DEVICE);
+}
+
+int fimc_is_init_mem(struct fimc_is_dev *dev)
+{
+ int ret;
+
+ dbg("fimc_is_init_mem - ION\n");
+ ret = fimc_is_alloc_firmware(dev);
+ if (ret) {
+ err("Couldn't alloc for FIMC-IS firmware\n");
+ return -EINVAL;
+ }
+
+ memset(dev->mem.kvaddr, 0,
+ FIMC_IS_A5_MEM_SIZE +
+ SIZE_ODC_INTERNAL_BUF * NUM_ODC_INTERNAL_BUF +
+ SIZE_DIS_INTERNAL_BUF * NUM_DIS_INTERNAL_BUF +
+ SIZE_3DNR_INTERNAL_BUF * NUM_3DNR_INTERNAL_BUF +
+ SIZE_ISP_INTERNAL_BUF * NUM_ISP_INTERNAL_BUF);
+
+ dev->is_p_region =
+ (struct is_region *)(dev->mem.kvaddr +
+ FIMC_IS_A5_MEM_SIZE - FIMC_IS_REGION_SIZE);
+
+
+ dev->is_shared_region =
+ (struct is_share_region *)(dev->mem.kvaddr +
+ FIMC_IS_SHARED_REGION_ADDR);
+
+ dev->mem.dvaddr_odc = (unsigned char *)(dev->mem.dvaddr +
+ FIMC_IS_A5_MEM_SIZE);
+ dev->mem.kvaddr_odc = dev->mem.kvaddr + FIMC_IS_A5_MEM_SIZE;
+
+ dev->mem.dvaddr_dis = (unsigned char *)
+ (dev->mem.dvaddr +
+ FIMC_IS_A5_MEM_SIZE +
+ SIZE_ODC_INTERNAL_BUF * NUM_ODC_INTERNAL_BUF);
+ dev->mem.kvaddr_dis = dev->mem.kvaddr +
+ FIMC_IS_A5_MEM_SIZE +
+ SIZE_ODC_INTERNAL_BUF * NUM_ODC_INTERNAL_BUF;
+
+ dev->mem.dvaddr_3dnr = (unsigned char *)
+ (dev->mem.dvaddr +
+ FIMC_IS_A5_MEM_SIZE +
+ SIZE_ODC_INTERNAL_BUF * NUM_ODC_INTERNAL_BUF +
+ SIZE_DIS_INTERNAL_BUF * NUM_DIS_INTERNAL_BUF);
+ dev->mem.kvaddr_3dnr = dev->mem.kvaddr +
+ FIMC_IS_A5_MEM_SIZE +
+ SIZE_ODC_INTERNAL_BUF * NUM_ODC_INTERNAL_BUF +
+ SIZE_DIS_INTERNAL_BUF * NUM_DIS_INTERNAL_BUF;
+
+ dev->mem.dvaddr_isp = (unsigned char *)
+ (dev->mem.dvaddr +
+ FIMC_IS_A5_MEM_SIZE +
+ SIZE_ODC_INTERNAL_BUF * NUM_ODC_INTERNAL_BUF +
+ SIZE_DIS_INTERNAL_BUF * NUM_DIS_INTERNAL_BUF +
+ SIZE_3DNR_INTERNAL_BUF * NUM_3DNR_INTERNAL_BUF);
+ dev->mem.kvaddr_isp = dev->mem.kvaddr +
+ FIMC_IS_A5_MEM_SIZE +
+ SIZE_ODC_INTERNAL_BUF * NUM_ODC_INTERNAL_BUF +
+ SIZE_DIS_INTERNAL_BUF * NUM_DIS_INTERNAL_BUF +
+ SIZE_3DNR_INTERNAL_BUF * NUM_3DNR_INTERNAL_BUF;
+
+ dev->mem.dvaddr_shared = (unsigned char *)dev->mem.dvaddr +
+ ((unsigned char *)&dev->is_p_region->shared[0] -
+ dev->mem.kvaddr);
+ dev->mem.kvaddr_shared = dev->mem.kvaddr +
+ ((unsigned char *)&dev->is_p_region->shared[0] -
+ dev->mem.kvaddr);
+
+ if (fimc_is_cache_flush(dev, (void *)dev->is_p_region, IS_PARAM_SIZE)) {
+ err("fimc_is_cache_flush-Err\n");
+ return -EINVAL;
+ }
+ dbg("fimc_is_init_mem3\n");
+ return 0;
+}
+#endif
+
+static int fimc_is_request_firmware(struct fimc_is_dev *dev)
+{
+ int ret;
+ struct firmware *fw_blob;
+
+ ret = request_firmware((const struct firmware **)&fw_blob,
+ FIMC_IS_FW, &dev->pdev->dev);
+ if (ret) {
+ dev_err(&dev->pdev->dev,
+ "could not load firmware (err=%d)\n", ret);
+ return -EINVAL;
+ }
+
+#if defined(CONFIG_VIDEOBUF2_CMA_PHYS)
+ memcpy((void *)phys_to_virt(dev->mem.base),
+ fw_blob->data, fw_blob->size);
+ fimc_is_mem_cache_clean((void *)phys_to_virt(dev->mem.base),
+ fw_blob->size + 1);
+#elif defined(CONFIG_VIDEOBUF2_ION)
+ if (dev->mem.bitproc_buf == 0) {
+ err("failed to load FIMC-IS F/W\n");
+ } else {
+ memcpy(dev->mem.kvaddr, fw_blob->data, fw_blob->size);
+ fimc_is_mem_cache_clean(
+ (void *)dev->mem.kvaddr, fw_blob->size + 1);
+ }
+#endif
+
+ dbg("FIMC_IS F/W loaded successfully - size:%d\n",
+ fw_blob->size);
+ release_firmware(fw_blob);
+
+ return ret;
+}
+
+int fimc_is_load_fw(struct fimc_is_dev *dev)
+{
+ int ret;
+
+ dbg("%s\n", __func__);
+ if (test_bit(IS_ST_IDLE, &dev->state)) {
+ /* 1. Load IS firmware */
+ ret = fimc_is_request_firmware(dev);
+ if (ret) {
+ err("failed to fimc_is_request_firmware (%d)\n", ret);
+ return -EINVAL;
+ }
+
+ set_bit(IS_ST_PWR_ON, &dev->state);
+
+ /* 3. A5 power on */
+ clear_bit(IS_ST_FW_DOWNLOADED, &dev->state);
+ fimc_is_hw_a5_power(dev, 1);
+ ret = wait_event_timeout(dev->irq_queue,
+ test_bit(IS_ST_FW_DOWNLOADED, &dev->state),
+ FIMC_IS_SHUTDOWN_TIMEOUT);
+ if (!ret) {
+ err("wait timeout A5 power on: %s\n", __func__);
+ return -EINVAL;
+ }
+ dbg("fimc_is_load_fw end\n");
+ } else {
+ dbg("IS FW was loaded before\n");
+ }
+ return 0;
+}
+
+static int fimc_is_load_setfile(struct fimc_is_dev *dev)
+{
+ int ret;
+ struct firmware *fw_blob;
+
+ ret = request_firmware((const struct firmware **)&fw_blob,
+ FIMC_IS_SETFILE, &dev->pdev->dev);
+ if (ret) {
+ dev_err(&dev->pdev->dev,
+ "could not load firmware (err=%d)\n", ret);
+ return -EINVAL;
+ }
+
+#if defined(CONFIG_VIDEOBUF2_CMA_PHYS)
+ memcpy((void *)phys_to_virt(dev->mem.base + dev->setfile.base),
+ fw_blob->data, fw_blob->size);
+ fimc_is_mem_cache_clean(
+ (void *)phys_to_virt(dev->mem.base + dev->setfile.base),
+ fw_blob->size + 1);
+#elif defined(CONFIG_VIDEOBUF2_ION)
+ if (dev->mem.bitproc_buf == 0) {
+ err("failed to load setfile\n");
+ } else {
+ memcpy((dev->mem.kvaddr + dev->setfile.base),
+ fw_blob->data, fw_blob->size);
+ fimc_is_mem_cache_clean(
+ (void *)(dev->mem.kvaddr + dev->setfile.base),
+ fw_blob->size + 1);
+ }
+#endif
+ dev->setfile.state = 1;
+ dbg("FIMC_IS setfile loaded successfully - size:%d\n",
+ fw_blob->size);
+ release_firmware(fw_blob);
+
+ dbg("A5 mem base = 0x%08x\n", dev->mem.base);
+ dbg("Setfile base = 0x%08x\n", dev->setfile.base);
+
+ return ret;
+}
+
+int fimc_is_init_set(struct fimc_is_dev *dev , u32 val)
+{
+ int ret;
+ struct flite_frame f_frame;
+#ifdef FIMC_IS_A5_DEBUG_ON
+ unsigned long debug_device = 0;
+#endif
+
+ fimc_is_hw_diable_wdt(dev);
+ dev->sensor.sensor_type = val;
+ dev->sensor.id_dual = 0;
+ dev->setfile.sub_index = 0;
+
+ dbg("fimc_is_init\n");
+ if (test_bit(IS_ST_FW_DOWNLOADED, &dev->state)) {
+ /* Init sequence 1: Open sensor */
+ dbg("v4l2 : open sensor : %d\n", val);
+
+ /* set mipi & fimclite */
+ f_frame.o_width =
+ dev->video[FIMC_IS_VIDEO_NUM_SCALERC].frame.width + 16;
+ f_frame.o_height =
+ dev->video[FIMC_IS_VIDEO_NUM_SCALERC].frame.height + 12;
+ f_frame.offs_h = 0;
+ f_frame.offs_v = 0;
+ f_frame.width =
+ dev->video[FIMC_IS_VIDEO_NUM_SCALERC].frame.width + 16;
+ f_frame.height =
+ dev->video[FIMC_IS_VIDEO_NUM_SCALERC].frame.height + 12;
+
+ /*start mipi & fimclite*/
+ dbg("start fimclite(pos:%d) (port:%d)\n",
+ dev->sensor.id_position,
+ dev->pdata->sensor_info[dev->sensor.id_position]->flite_id);
+
+ start_fimc_lite(dev->pdata->
+ sensor_info[dev->sensor.id_position]->
+ flite_id, &f_frame);
+ mdelay(10);
+ dbg("start mipi (pos:%d) (port:%d)\n",
+ dev->sensor.id_position,
+ dev->pdata->
+ sensor_info[dev->sensor.id_position]->csi_id);
+ start_mipi_csi(dev->pdata->
+ sensor_info[dev->sensor.id_position]->
+ csi_id, &f_frame);
+
+ clear_bit(IS_ST_OPEN_SENSOR, &dev->state);
+ fimc_is_hw_open_sensor(dev, dev->sensor.id_dual, val);
+
+ ret = wait_event_timeout(dev->irq_queue,
+ test_bit(IS_ST_OPEN_SENSOR, &dev->state),
+ FIMC_IS_SHUTDOWN_TIMEOUT);
+ if (!ret) {
+ dev_err(&dev->pdev->dev,
+ "wait timeout:%s\n", __func__);
+ return -EBUSY;
+ }
+
+ if (dev->is_p_region->shared[MAX_SHARED_COUNT-1]
+ != MAGIC_NUMBER)
+ dev_err(&dev->pdev->dev, "MAGIC NUMBER error\n");
+
+ dbg("v4l2 : setfile address\n");
+ fimc_is_hw_get_setfile_addr(dev);
+ ret = wait_event_timeout(dev->irq_queue,
+ test_bit(IS_ST_SETFILE_LOADED, &dev->state),
+ FIMC_IS_SHUTDOWN_TIMEOUT);
+ if (!ret) {
+ err("wait timeout - get setfile address\n");
+ /*fimc_is_hw_set_low_poweroff(dev, true);*/
+ return -EINVAL;
+ }
+
+ fimc_is_load_setfile(dev);
+ dbg(" fimc_is_load_setfile end\n");
+ clear_bit(IS_ST_SETFILE_LOADED, &dev->state);
+
+ fimc_is_hw_load_setfile(dev);
+
+ ret = wait_event_timeout(dev->irq_queue,
+ test_bit(IS_ST_SETFILE_LOADED, &dev->state),
+ FIMC_IS_SHUTDOWN_TIMEOUT);
+ if (!ret) {
+ err("wait timeout - get setfile address\n");
+ /*fimc_is_hw_set_low_poweroff(dev, true);*/
+ return -EINVAL;
+ }
+
+ dbg("v4l2 : Load set file end\n");
+ /* Debug only */
+ dbg("Parameter region addr = 0x%08x\n",
+ (unsigned int)(dev->is_p_region));
+ dev->frame_count = 0;
+
+ dbg("Stream Off\n");
+ clear_bit(IS_ST_STREAM_OFF, &dev->state);
+ fimc_is_hw_set_stream(dev, 0); /*stream off */
+ ret = wait_event_timeout(dev->irq_queue,
+ test_bit(IS_ST_STREAM_OFF, &dev->state),
+ FIMC_IS_SHUTDOWN_TIMEOUT);
+ if (!ret) {
+ dev_err(&dev->pdev->dev,
+ "wait timeout : %s\n", __func__);
+ return -EBUSY;
+ }
+ clear_bit(IS_ST_RUN, &dev->state);
+
+ /* 1. */
+ dbg("Default setting : preview_still\n");
+ dev->scenario_id = ISS_PREVIEW_STILL;
+ fimc_is_hw_set_init(dev);
+ fimc_is_hw_change_size(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+
+ /* 1 */
+ set_bit(IS_ST_INIT_PREVIEW_STILL, &dev->state);
+ fimc_is_hw_set_param(dev);
+
+ ret = wait_event_timeout(dev->irq_queue,
+ test_bit(IS_ST_INIT_PREVIEW_VIDEO, &dev->state),
+ FIMC_IS_SHUTDOWN_TIMEOUT);
+ if (!ret) {
+ dev_err(&dev->pdev->dev,
+ "wait timeout : %s\n", __func__);
+ return -EBUSY;
+ }
+
+#ifdef FIMC_IS_A5_DEBUG_ON
+ /*set_bit(FIMC_IS_DEBUG_MAIN, &debug_device);
+ set_bit(FIMC_IS_DEBUG_EC, &debug_device);
+ set_bit(FIMC_IS_DEBUG_SENSOR, &debug_device);
+ set_bit(FIMC_IS_DEBUG_ISP, &debug_device);
+ set_bit(FIMC_IS_DEBUG_DRC, &debug_device);
+ set_bit(FIMC_IS_DEBUG_FD, &debug_device);
+ set_bit(FIMC_IS_DEBUG_SDK, &debug_device);
+ set_bit(FIMC_IS_DEBUG_SCALERC, &debug_device);
+ set_bit(FIMC_IS_DEBUG_ODC, &debug_device);
+ set_bit(FIMC_IS_DEBUG_TDNR, &debug_device);
+ set_bit(FIMC_IS_DEBUG_SCALERP, &debug_device);
+ set_bit(FIMC_IS_DEBUG_DIS, &debug_device);
+ */
+
+
+ fimc_is_hw_set_debug_level(dev, FIMC_IS_DEBUG_UART,
+ debug_device, FIMC_IS_A5_DEBUG_LEVEL);
+#endif
+ clear_bit(IS_ST_STREAM_OFF, &dev->state);
+ set_bit(IS_ST_RUN, &dev->state);
+
+ dbg("Init sequence completed!! Ready to use\n");
+ }
+
+ return 0;
+}
+
+static int fimc_is_front_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct fimc_is_front_dev *front_dev = to_fimc_is_front_dev(sd);
+ struct fimc_is_dev *isp = to_fimc_is_dev_from_front_dev(front_dev);
+ int ret;
+
+ if (enable) {
+ printk(KERN_INFO "fimc_is_front_s_stream : ON\n");
+ } else {
+ printk(KERN_INFO "fimc_is_front_s_stream : OFF\n");
+ fimc_is_hw_subip_poweroff(isp);
+ ret = wait_event_timeout(isp->irq_queue,
+ !test_bit(FIMC_IS_PWR_ST_POWER_ON_OFF, &isp->power),
+ FIMC_IS_SHUTDOWN_TIMEOUT);
+ if (!ret) {
+ dev_err(&isp->pdev->dev,
+ "wait timeout : %s\n", __func__);
+ return -EBUSY;
+ }
+ fimc_is_hw_a5_power(isp, 0);
+ isp->state = 0;
+ isp->pipe_state = 0;
+ stop_mipi_csi(isp->pdata->sensor_info[0]->csi_id);
+ stop_mipi_csi(isp->pdata->sensor_info[1]->csi_id);
+ stop_fimc_lite(isp->pdata->sensor_info[0]->flite_id);
+ stop_fimc_lite(isp->pdata->sensor_info[1]->flite_id);
+
+ if (isp->pdata->clk_off) {
+ /* isp->pdata->clk_off(isp->pdev); */
+ } else {
+ err("#### failed to Clock On ####\n");
+ return -EINVAL;
+ }
+ set_bit(IS_ST_IDLE , &isp->state);
+ dbg("state(%d), pipe_state(%d)\n",
+ (int)isp->state, (int)isp->pipe_state);
+ }
+
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_back_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_sensor_subdev_get_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_sensor_subdev_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_sensor_subdev_get_crop(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_crop *crop)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_sensor_subdev_set_crop(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_crop *crop)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_front_subdev_get_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_front_subdev_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_front_subdev_get_crop(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_crop *crop)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_front_subdev_set_crop(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_crop *crop)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_back_subdev_get_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_back_subdev_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_back_subdev_get_crop(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_crop *crop)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_back_subdev_set_crop(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_crop *crop)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_sensor_s_ctrl(struct v4l2_subdev *sd,
+ struct v4l2_control *ctrl)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_sensor_g_ctrl(struct v4l2_subdev *sd,
+ struct v4l2_control *ctrl)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_front_s_ctrl(struct v4l2_subdev *sd,
+ struct v4l2_control *ctrl)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_front_g_ctrl(struct v4l2_subdev *sd,
+ struct v4l2_control *ctrl)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+static int fimc_is_back_s_ctrl(struct v4l2_subdev *sd,
+ struct v4l2_control *ctrl)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_back_g_ctrl(struct v4l2_subdev *sd,
+ struct v4l2_control *ctrl)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static struct v4l2_subdev_pad_ops fimc_is_sensor_pad_ops = {
+ .get_fmt = fimc_is_sensor_subdev_get_fmt,
+ .set_fmt = fimc_is_sensor_subdev_set_fmt,
+ .get_crop = fimc_is_sensor_subdev_get_crop,
+ .set_crop = fimc_is_sensor_subdev_set_crop,
+};
+
+static struct v4l2_subdev_pad_ops fimc_is_front_pad_ops = {
+ .get_fmt = fimc_is_front_subdev_get_fmt,
+ .set_fmt = fimc_is_front_subdev_set_fmt,
+ .get_crop = fimc_is_front_subdev_get_crop,
+ .set_crop = fimc_is_front_subdev_set_crop,
+};
+
+static struct v4l2_subdev_pad_ops fimc_is_back_pad_ops = {
+ .get_fmt = fimc_is_back_subdev_get_fmt,
+ .set_fmt = fimc_is_back_subdev_set_fmt,
+ .get_crop = fimc_is_back_subdev_get_crop,
+ .set_crop = fimc_is_back_subdev_set_crop,
+};
+
+static struct v4l2_subdev_video_ops fimc_is_sensor_video_ops = {
+ .s_stream = fimc_is_sensor_s_stream,
+};
+
+static struct v4l2_subdev_video_ops fimc_is_front_video_ops = {
+ .s_stream = fimc_is_front_s_stream,
+};
+
+static struct v4l2_subdev_video_ops fimc_is_back_video_ops = {
+ .s_stream = fimc_is_back_s_stream,
+};
+
+static struct v4l2_subdev_core_ops fimc_is_sensor_core_ops = {
+ .s_ctrl = fimc_is_sensor_s_ctrl,
+ .g_ctrl = fimc_is_sensor_g_ctrl,
+};
+
+static struct v4l2_subdev_core_ops fimc_is_front_core_ops = {
+ .s_ctrl = fimc_is_front_s_ctrl,
+ .g_ctrl = fimc_is_front_g_ctrl,
+};
+
+static struct v4l2_subdev_core_ops fimc_is_back_core_ops = {
+ .s_ctrl = fimc_is_back_s_ctrl,
+ .g_ctrl = fimc_is_back_g_ctrl,
+};
+
+static struct v4l2_subdev_ops fimc_is_sensor_subdev_ops = {
+ .pad = &fimc_is_sensor_pad_ops,
+ .video = &fimc_is_sensor_video_ops,
+ .core = &fimc_is_sensor_core_ops,
+};
+
+static struct v4l2_subdev_ops fimc_is_front_subdev_ops = {
+ .pad = &fimc_is_front_pad_ops,
+ .video = &fimc_is_front_video_ops,
+ .core = &fimc_is_front_core_ops,
+};
+
+static struct v4l2_subdev_ops fimc_is_back_subdev_ops = {
+ .pad = &fimc_is_back_pad_ops,
+ .video = &fimc_is_back_video_ops,
+ .core = &fimc_is_back_core_ops,
+};
+
+static int fimc_is_sensor_init_formats(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_sensor_subdev_close(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_sensor_subdev_registered(struct v4l2_subdev *sd)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static void fimc_is_sensor_subdev_unregistered(struct v4l2_subdev *sd)
+{
+ dbg("%s\n", __func__);
+}
+
+static int fimc_is_front_init_formats(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_front_subdev_close(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_front_subdev_registered(struct v4l2_subdev *sd)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static void fimc_is_front_subdev_unregistered(struct v4l2_subdev *sd)
+{
+ dbg("%s\n", __func__);
+}
+
+static int fimc_is_back_init_formats(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_back_subdev_close(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_back_subdev_registered(struct v4l2_subdev *sd)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static void fimc_is_back_subdev_unregistered(struct v4l2_subdev *sd)
+{
+ dbg("%s\n", __func__);
+}
+
+static const struct v4l2_subdev_internal_ops
+ fimc_is_sensor_v4l2_internal_ops = {
+ .open = fimc_is_sensor_init_formats,
+ .close = fimc_is_sensor_subdev_close,
+ .registered = fimc_is_sensor_subdev_registered,
+ .unregistered = fimc_is_sensor_subdev_unregistered,
+};
+
+static const struct v4l2_subdev_internal_ops fimc_is_front_v4l2_internal_ops = {
+ .open = fimc_is_front_init_formats,
+ .close = fimc_is_front_subdev_close,
+ .registered = fimc_is_front_subdev_registered,
+ .unregistered = fimc_is_front_subdev_unregistered,
+};
+
+static const struct v4l2_subdev_internal_ops fimc_is_back_v4l2_internal_ops = {
+ .open = fimc_is_back_init_formats,
+ .close = fimc_is_back_subdev_close,
+ .registered = fimc_is_back_subdev_registered,
+ .unregistered = fimc_is_back_subdev_unregistered,
+};
+
+static int fimc_is_sensor_link_setup(struct media_entity *entity,
+ const struct media_pad *local,
+ const struct media_pad *remote, u32 flags)
+{
+ struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
+ struct fimc_is_sensor_dev *fimc_is_sensor = to_fimc_is_sensor_dev(sd);
+
+ dbg("++%s\n", __func__);
+ dbg("local->index : %d\n", local->index);
+ dbg("media_entity_type(remote->entity) : %d\n",
+ media_entity_type(remote->entity));
+
+ switch (local->index | media_entity_type(remote->entity)) {
+ case FIMC_IS_SENSOR_PAD_SOURCE_FRONT | MEDIA_ENT_T_V4L2_SUBDEV:
+ if (flags & MEDIA_LNK_FL_ENABLED)
+ fimc_is_sensor->output = FIMC_IS_SENSOR_OUTPUT_FRONT;
+ else
+ fimc_is_sensor->output = FIMC_IS_SENSOR_OUTPUT_NONE;
+ break;
+
+ default:
+ v4l2_err(sd, "%s : ERR link\n", __func__);
+ return -EINVAL;
+ }
+ dbg("--%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_front_link_setup(struct media_entity *entity,
+ const struct media_pad *local,
+ const struct media_pad *remote, u32 flags)
+{
+ struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
+ struct fimc_is_front_dev *fimc_is_front = to_fimc_is_front_dev(sd);
+
+ dbg("++%s\n", __func__);
+ dbg("local->index : %d\n", local->index);
+ dbg("media_entity_type(remote->entity) : %d\n",
+ media_entity_type(remote->entity));
+
+ switch (local->index | media_entity_type(remote->entity)) {
+ case FIMC_IS_FRONT_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
+ dbg("fimc_is_front sink pad\n");
+ if (flags & MEDIA_LNK_FL_ENABLED) {
+ if (fimc_is_front->input
+ != FIMC_IS_FRONT_INPUT_NONE) {
+ dbg("BUSY\n");
+ return -EBUSY;
+ }
+ if (remote->index == FIMC_IS_SENSOR_PAD_SOURCE_FRONT)
+ fimc_is_front->input
+ = FIMC_IS_FRONT_INPUT_SENSOR;
+ } else {
+ fimc_is_front->input = FIMC_IS_FRONT_INPUT_NONE;
+ }
+ break;
+
+ case FIMC_IS_FRONT_PAD_SOURCE_BACK | MEDIA_ENT_T_V4L2_SUBDEV:
+ if (flags & MEDIA_LNK_FL_ENABLED)
+ fimc_is_front->output |= FIMC_IS_FRONT_OUTPUT_BACK;
+ else
+ fimc_is_front->output = FIMC_IS_FRONT_OUTPUT_NONE;
+ break;
+
+ case FIMC_IS_FRONT_PAD_SOURCE_BAYER | MEDIA_ENT_T_DEVNODE:
+ if (flags & MEDIA_LNK_FL_ENABLED)
+ fimc_is_front->output |= FIMC_IS_FRONT_OUTPUT_BAYER;
+ else
+ fimc_is_front->output = FIMC_IS_FRONT_OUTPUT_NONE;
+ break;
+ case FIMC_IS_FRONT_PAD_SOURCE_SCALERC | MEDIA_ENT_T_DEVNODE:
+ if (flags & MEDIA_LNK_FL_ENABLED)
+ fimc_is_front->output |= FIMC_IS_FRONT_OUTPUT_SCALERC;
+ else
+ fimc_is_front->output = FIMC_IS_FRONT_OUTPUT_NONE;
+ break;
+
+ default:
+ v4l2_err(sd, "%s : ERR link\n", __func__);
+ return -EINVAL;
+ }
+ dbg("--%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_back_link_setup(struct media_entity *entity,
+ const struct media_pad *local,
+ const struct media_pad *remote, u32 flags)
+{
+ struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
+ struct fimc_is_back_dev *fimc_is_back = to_fimc_is_back_dev(sd);
+
+ dbg("++%s\n", __func__);
+ switch (local->index | media_entity_type(remote->entity)) {
+ case FIMC_IS_BACK_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
+ dbg("fimc_is_back sink pad\n");
+ if (flags & MEDIA_LNK_FL_ENABLED) {
+ if (fimc_is_back->input != FIMC_IS_BACK_INPUT_NONE) {
+ dbg("BUSY\n");
+ return -EBUSY;
+ }
+ if (remote->index == FIMC_IS_FRONT_PAD_SOURCE_BACK)
+ fimc_is_back->input = FIMC_IS_BACK_INPUT_FRONT;
+ } else {
+ fimc_is_back->input = FIMC_IS_FRONT_INPUT_NONE;
+ }
+ break;
+ case FIMC_IS_BACK_PAD_SOURCE_3DNR | MEDIA_ENT_T_DEVNODE:
+ if (flags & MEDIA_LNK_FL_ENABLED)
+ fimc_is_back->output |= FIMC_IS_BACK_OUTPUT_3DNR;
+ else
+ fimc_is_back->output = FIMC_IS_FRONT_OUTPUT_NONE;
+ break;
+ case FIMC_IS_BACK_PAD_SOURCE_SCALERP | MEDIA_ENT_T_DEVNODE:
+ if (flags & MEDIA_LNK_FL_ENABLED)
+ fimc_is_back->output |= FIMC_IS_BACK_OUTPUT_SCALERP;
+ else
+ fimc_is_back->output = FIMC_IS_FRONT_OUTPUT_NONE;
+ break;
+ default:
+ v4l2_err(sd, "%s : ERR link\n", __func__);
+ return -EINVAL;
+ }
+ dbg("--%s\n", __func__);
+ return 0;
+}
+
+static const struct media_entity_operations fimc_is_sensor_media_ops = {
+ .link_setup = fimc_is_sensor_link_setup,
+};
+
+static const struct media_entity_operations fimc_is_front_media_ops = {
+ .link_setup = fimc_is_front_link_setup,
+};
+
+static const struct media_entity_operations fimc_is_back_media_ops = {
+ .link_setup = fimc_is_back_link_setup,
+};
+
+int fimc_is_pipeline_s_stream_preview(struct media_entity *start_entity, int on)
+{
+ struct media_pad *pad = &start_entity->pads[0];
+ struct v4l2_subdev *back_sd;
+ struct v4l2_subdev *front_sd;
+ struct v4l2_subdev *sensor_sd;
+ int ret;
+
+ dbg("--%s\n", __func__);
+
+ pad = media_entity_remote_source(pad);
+ if (media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV
+ || pad == NULL)
+ dbg("cannot find back entity\n");
+
+ back_sd = media_entity_to_v4l2_subdev(pad->entity);
+
+ pad = &pad->entity->pads[0];
+
+ pad = media_entity_remote_source(pad);
+ if (media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV
+ || pad == NULL)
+ dbg("cannot find front entity\n");
+
+ front_sd = media_entity_to_v4l2_subdev(pad->entity);
+
+ pad = &pad->entity->pads[0];
+
+ pad = media_entity_remote_source(pad);
+ if (media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV
+ || pad == NULL)
+ dbg("cannot find sensor entity\n");
+
+ sensor_sd = media_entity_to_v4l2_subdev(pad->entity);
+
+ if (on) {
+
+ ret = v4l2_subdev_call(sensor_sd, video, s_stream, 1);
+ if (ret < 0 && ret != -ENOIOCTLCMD)
+ return ret;
+
+ ret = v4l2_subdev_call(front_sd, video, s_stream, 1);
+ if (ret < 0 && ret != -ENOIOCTLCMD)
+ return ret;
+
+ ret = v4l2_subdev_call(back_sd, video, s_stream, 1);
+ if (ret < 0 && ret != -ENOIOCTLCMD)
+ return ret;
+
+ } else {
+ ret = v4l2_subdev_call(back_sd, video, s_stream, 0);
+ if (ret < 0 && ret != -ENOIOCTLCMD)
+ return ret;
+ ret = v4l2_subdev_call(front_sd, video, s_stream, 0);
+ if (ret < 0 && ret != -ENOIOCTLCMD)
+ return ret;
+ ret = v4l2_subdev_call(sensor_sd, video, s_stream, 0);
+ }
+
+ return ret == -ENOIOCTLCMD ? 0 : ret;
+}
+
+
+static int fimc_is_suspend(struct device *dev)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_resume(struct device *dev)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_runtime_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct fimc_is_dev *isp
+ = (struct fimc_is_dev *)platform_get_drvdata(pdev);
+
+ return fimc_is_hw_a5_power_off(isp);
+}
+
+static int fimc_is_runtime_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct fimc_is_dev *isp
+ = (struct fimc_is_dev *)platform_get_drvdata(pdev);
+
+ return fimc_is_hw_a5_power_on(isp);
+}
+
+static int fimc_is_get_md_callback(struct device *dev, void *p)
+{
+ struct exynos_md **md_list = p;
+ struct exynos_md *md = NULL;
+
+ md = dev_get_drvdata(dev);
+
+ if (md)
+ *(md_list + md->id) = md;
+
+ return 0; /* non-zero value stops iteration */
+}
+
+static struct exynos_md *fimc_is_get_md(enum mdev_node node)
+{
+ struct device_driver *drv;
+ struct exynos_md *md[MDEV_MAX_NUM] = {NULL,};
+ int ret;
+
+ drv = driver_find(MDEV_MODULE_NAME, &platform_bus_type);
+ if (!drv)
+ return ERR_PTR(-ENODEV);
+
+ ret = driver_for_each_device(drv, NULL, &md[0],
+ fimc_is_get_md_callback);
+
+ return ret ? NULL : md[node];
+
+}
+
+static unsigned int fimc_is_get_intr_position(unsigned int intr_status)
+{
+ int i;
+
+ for (i = 0; i < 5; i++)
+ if (intr_status & (1<<i))
+ return i;
+
+ return 0;
+}
+
+static irqreturn_t fimc_is_irq_handler(int irq, void *dev_id)
+{
+ struct fimc_is_dev *dev = dev_id;
+ int buf_index;
+ unsigned int intr_status, intr_pos;
+
+ intr_status = readl(dev->regs + INTSR1);
+ intr_pos = fimc_is_get_intr_position(intr_status);
+
+ if (intr_pos == INTR_GENERAL) {
+ dev->i2h_cmd.cmd = readl(dev->regs + ISSR10);
+
+ /* Read ISSR10 ~ ISSR15 */
+ switch (dev->i2h_cmd.cmd) {
+ case IHC_GET_SENSOR_NUMBER:
+ dbg("IHC_GET_SENSOR_NUMBER\n");
+ fimc_is_hw_get_param(dev, 1);
+ dbg("ISP - FW version - %d\n", dev->i2h_cmd.arg[0]);
+ dev->fw.ver = dev->i2h_cmd.arg[0];
+ fimc_is_hw_wait_intmsr0_intmsd0(dev);
+ fimc_is_hw_set_sensor_num(dev);
+ break;
+ case IHC_SET_SHOT_MARK:
+ fimc_is_hw_get_param(dev, 3);
+ break;
+ case IHC_SET_FACE_MARK:
+ fimc_is_hw_get_param(dev, 2);
+ break;
+ case IHC_NOT_READY:
+ break;
+ case IHC_AA_DONE:
+ fimc_is_hw_get_param(dev, 3);
+ break;
+ case ISR_DONE:
+ fimc_is_hw_get_param(dev, 3);
+ break;
+ case ISR_NDONE:
+ fimc_is_hw_get_param(dev, 4);
+
+ /* fimc_is_fw_clear_insr1(dev); */
+ break;
+ }
+ /* Just clear the interrupt pending bits. */
+ fimc_is_fw_clear_irq1(dev, intr_pos);
+
+ switch (dev->i2h_cmd.cmd) {
+ case IHC_GET_SENSOR_NUMBER:
+ fimc_is_hw_set_intgr0_gd0(dev);
+ set_bit(IS_ST_FW_DOWNLOADED, &dev->state);
+ break;
+ case IHC_SET_SHOT_MARK:
+ break;
+ case IHC_SET_FACE_MARK:
+ dbg("IHC_SET_FACE_MARK - %d, %d\n",
+ dev->i2h_cmd.arg[0],
+ dev->i2h_cmd.arg[1]);
+ dev->fd_header.count = dev->i2h_cmd.arg[0];
+ dev->fd_header.index = dev->i2h_cmd.arg[1];
+ /* Implementation of AF with face */
+ if (dev->af.mode == IS_FOCUS_MODE_CONTINUOUS &&
+ dev->af.af_state == FIMC_IS_AF_LOCK) {
+ fimc_is_af_face(dev);
+ } else if (dev->af.mode == IS_FOCUS_MODE_FACEDETECT) {
+ /* Using face information once only */
+ fimc_is_af_face(dev);
+ dev->af.mode = IS_FOCUS_MODE_IDLE;
+ }
+ break;
+ case IHC_AA_DONE:
+ switch (dev->i2h_cmd.arg[0]) {
+ /* SEARCH: Occurs when search is
+ * requested at continuous AF */
+ case 2:
+ break;
+ /* INFOCUS: Occurs when focus is found. */
+ case 3:
+ if (dev->af.af_state == FIMC_IS_AF_RUNNING)
+ dev->af.af_state = FIMC_IS_AF_LOCK;
+ dev->af.af_lock_state = 0x2;
+ break;
+ /* OUTOFFOCUS: Occurs when focus is not found. */
+ case 4:
+ if (dev->af.af_state == FIMC_IS_AF_RUNNING)
+ dev->af.af_state = FIMC_IS_AF_LOCK;
+ dev->af.af_lock_state = 0x1;
+ break;
+ }
+ break;
+ case IHC_NOT_READY:
+ err("Init Sequnce Error- IS will be turned off!!");
+ break;
+ case ISR_DONE:
+ dbg("ISR_DONE - %d\n", dev->i2h_cmd.arg[0]);
+ switch (dev->i2h_cmd.arg[0]) {
+ case HIC_PREVIEW_STILL:
+ case HIC_PREVIEW_VIDEO:
+ case HIC_CAPTURE_STILL:
+ case HIC_CAPTURE_VIDEO:
+ if (test_and_clear_bit(IS_ST_CHANGE_MODE,
+ &dev->state)) {
+ dev->sensor.offset_x
+ = dev->i2h_cmd.arg[1];
+ dev->sensor.offset_y
+ = dev->i2h_cmd.arg[2];
+ set_bit(IS_ST_CHANGE_MODE_DONE,
+ &dev->state);
+ }
+ break;
+ case HIC_STREAM_ON:
+ clear_bit(IS_ST_CHANGE_MODE_DONE, &dev->state);
+ set_bit(IS_ST_STREAM_ON, &dev->state);
+ break;
+ case HIC_STREAM_OFF:
+ set_bit(IS_ST_STREAM_OFF, &dev->state);
+ set_bit(IS_ST_RUN, &dev->state);
+ break;
+ case HIC_SET_PARAMETER:
+ dev->p_region_index1 = 0;
+ dev->p_region_index2 = 0;
+ atomic_set(&dev->p_region_num, 0);
+
+ /* FW bug - should be removed*/
+ if (dev->i2h_cmd.arg[1] == 0 &&
+ dev->i2h_cmd.arg[2] == 0)
+ break;
+
+ set_bit(IS_ST_BLOCK_CMD_CLEARED, &dev->state);
+
+ if (test_bit(PARAM_ISP_AA,
+ (void *)&dev->i2h_cmd.arg[1]) &&
+ (dev->af.af_state
+ == FIMC_IS_AF_SETCONFIG)) {
+ dev->af.af_state = FIMC_IS_AF_RUNNING;
+ } else if (test_bit(PARAM_ISP_AA,
+ (void *)&dev->i2h_cmd.arg[1]) &&
+ dev->af.af_state == FIMC_IS_AF_ABORT) {
+ dev->af.af_state = FIMC_IS_AF_IDLE;
+ }
+
+ if (test_bit(IS_ST_INIT_PREVIEW_STILL,
+ &dev->state))
+ set_bit(IS_ST_INIT_PREVIEW_VIDEO,
+ &dev->state);
+ else {
+ clear_bit(IS_ST_SET_PARAM, &dev->state);
+ set_bit(IS_ST_RUN, &dev->state);
+ }
+ break;
+
+ case HIC_GET_PARAMETER:
+ break;
+ case HIC_SET_TUNE:
+ break;
+ case HIC_GET_STATUS:
+ break;
+ case HIC_OPEN_SENSOR:
+ set_bit(IS_ST_OPEN_SENSOR, &dev->state);
+ dbg("reply HIC_OPEN_SENSOR");
+ break;
+ case HIC_CLOSE_SENSOR:
+ clear_bit(IS_ST_OPEN_SENSOR, &dev->state);
+ dev->sensor.id_dual = 0;
+ break;
+ case HIC_POWER_DOWN:
+ clear_bit(FIMC_IS_PWR_ST_POWER_ON_OFF,
+ &dev->power);
+ break;
+ case HIC_GET_SET_FILE_ADDR:
+ dev->setfile.base = dev->i2h_cmd.arg[1];
+ set_bit(IS_ST_SETFILE_LOADED, &dev->state);
+ break;
+ case HIC_LOAD_SET_FILE:
+ set_bit(IS_ST_SETFILE_LOADED, &dev->state);
+ }
+ break;
+ case ISR_NDONE:
+ err("ISR_NDONE - %d: %d\n", dev->i2h_cmd.arg[0],
+ dev->i2h_cmd.arg[1]);
+
+ switch (dev->i2h_cmd.arg[1]) {
+ case IS_ERROR_SET_PARAMETER:
+ fimc_is_mem_cache_inv((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ break;
+ }
+
+ break;
+ }
+ } else if (intr_pos == INTR_FRAME_DONE_ISP) {
+ dev->i2h_cmd.arg[0] = readl(dev->regs + ISSR20);
+ dev->i2h_cmd.arg[1] = readl(dev->regs + ISSR21);
+ dev->i2h_cmd.arg[2] = readl(dev->regs + ISSR22);
+ fimc_is_fw_clear_irq1(dev, intr_pos);
+
+ buf_index = dev->i2h_cmd.arg[2];
+ dbg("Bayer returned buf index : %d\n", buf_index);
+ vb2_buffer_done(dev->video[FIMC_IS_VIDEO_NUM_BAYER].
+ vbq.bufs[buf_index], VB2_BUF_STATE_DONE);
+ fimc_is_hw_update_bufmask(dev, FIMC_IS_VIDEO_NUM_BAYER);
+ } else if (intr_pos == INTR_FRAME_DONE_SCALERC) {
+ dev->i2h_cmd.arg[0] = readl(dev->regs + ISSR28);
+ dev->i2h_cmd.arg[1] = readl(dev->regs + ISSR29);
+ dev->i2h_cmd.arg[2] = readl(dev->regs + ISSR30);
+ fimc_is_fw_clear_irq1(dev, intr_pos);
+
+ buf_index = dev->i2h_cmd.arg[2];
+ dbg("ScalerC returned buf index : %d\n", buf_index);
+ vb2_buffer_done(dev->video[FIMC_IS_VIDEO_NUM_SCALERC].
+ vbq.bufs[buf_index], VB2_BUF_STATE_DONE);
+ fimc_is_hw_update_bufmask(dev, FIMC_IS_VIDEO_NUM_SCALERC);
+ } else if (intr_pos == INTR_FRAME_DONE_TDNR) {
+
+ dev->i2h_cmd.arg[0] = readl(dev->regs + ISSR36);
+ dev->i2h_cmd.arg[1] = readl(dev->regs + ISSR37);
+ dev->i2h_cmd.arg[2] = readl(dev->regs + ISSR38);
+ fimc_is_fw_clear_irq1(dev, intr_pos);
+
+ buf_index = dev->i2h_cmd.arg[2];
+ dbg("3DNR returned buf index : %d\n", buf_index);
+ vb2_buffer_done(dev->video[FIMC_IS_VIDEO_NUM_3DNR].
+ vbq.bufs[buf_index], VB2_BUF_STATE_DONE);
+ fimc_is_hw_update_bufmask(dev, FIMC_IS_VIDEO_NUM_3DNR);
+ } else if (intr_pos == INTR_FRAME_DONE_SCALERP) {
+ dev->i2h_cmd.arg[0] = readl(dev->regs + ISSR44);
+ dev->i2h_cmd.arg[1] = readl(dev->regs + ISSR45);
+ dev->i2h_cmd.arg[2] = readl(dev->regs + ISSR46);
+ fimc_is_fw_clear_irq1(dev, intr_pos);
+
+#ifdef DZOOM_EVT0
+ set_bit(IS_ST_SCALERP_FRAME_DONE, &dev->state);
+#endif
+ buf_index = dev->i2h_cmd.arg[2];
+ dbg("ScalerP returned buf index : %d\n", buf_index);
+ vb2_buffer_done(dev->video[FIMC_IS_VIDEO_NUM_SCALERP].
+ vbq.bufs[buf_index], VB2_BUF_STATE_DONE);
+ fimc_is_hw_update_bufmask(dev, FIMC_IS_VIDEO_NUM_SCALERP);
+ }
+ wake_up(&dev->irq_queue);
+
+ return IRQ_HANDLED;
+}
+
+static int fimc_is_probe(struct platform_device *pdev)
+{
+ struct resource *mem_res;
+ struct resource *regs_res;
+ struct fimc_is_dev *isp;
+ int ret = -ENODEV;
+ struct vb2_queue *scalerc_q;
+ struct vb2_queue *scalerp_q;
+ struct vb2_queue *dnr_q;
+ struct vb2_queue *bayer_q;
+
+ dbg("fimc_is_front_probe\n");
+
+ isp = kzalloc(sizeof(struct fimc_is_dev), GFP_KERNEL);
+ if (!isp)
+ return -ENOMEM;
+
+ isp->pdev = pdev;
+ isp->pdata = pdev->dev.platform_data;
+ isp->id = pdev->id;
+ isp->pipe_state = 0;
+
+ set_bit(FIMC_IS_STATE_IDLE, &isp->pipe_state);
+ set_bit(IS_ST_IDLE , &isp->state);
+
+ init_waitqueue_head(&isp->irq_queue);
+ spin_lock_init(&isp->slock);
+ mutex_init(&isp->vb_lock);
+ mutex_init(&isp->lock);
+
+ mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem_res) {
+ dev_err(&pdev->dev, "Failed to get io memory region\n");
+ goto p_err1;
+ }
+
+ regs_res = request_mem_region(mem_res->start, resource_size(mem_res),
+ pdev->name);
+ if (!regs_res) {
+ dev_err(&pdev->dev, "Failed to request io memory region\n");
+ goto p_err1;
+ }
+
+ isp->regs_res = regs_res;
+ isp->regs = ioremap(mem_res->start, resource_size(mem_res));
+ if (!isp->regs) {
+ dev_err(&pdev->dev, "Failed to remap io region\n");
+ goto p_err2;
+ }
+
+ isp->mdev = fimc_is_get_md(MDEV_ISP);
+ if (IS_ERR_OR_NULL(isp->mdev))
+ goto p_err3;
+
+ dbg("fimc_is_front->mdev : 0x%p\n", isp->mdev);
+
+#if defined(CONFIG_VIDEOBUF2_CMA_PHYS)
+ isp->vb2 = &fimc_is_vb2_cma;
+#elif defined(CONFIG_VIDEOBUF2_ION)
+ isp->vb2 = &fimc_is_vb2_ion;
+#endif
+
+ isp->irq = platform_get_irq(pdev, 0);
+ if (isp->irq < 0) {
+ dev_err(&pdev->dev, "Failed to get irq\n");
+ goto p_err3;
+ }
+
+ ret = request_irq(isp->irq, fimc_is_irq_handler,
+ 0, dev_name(&pdev->dev), isp);
+ if (ret) {
+ dev_err(&pdev->dev, "request_irq failed\n");
+ goto p_err3;
+ }
+
+ /*sensor entity*/
+ v4l2_subdev_init(&isp->sensor.sd, &fimc_is_sensor_subdev_ops);
+ isp->sensor.sd.owner = THIS_MODULE;
+ isp->sensor.sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
+ snprintf(isp->sensor.sd.name, sizeof(isp->sensor.sd.name), "%s\n",
+ FIMC_IS_SENSOR_ENTITY_NAME);
+
+ isp->sensor.pads.flags = MEDIA_PAD_FL_SOURCE;
+ ret = media_entity_init(&isp->sensor.sd.entity, 1,
+ &isp->sensor.pads, 0);
+ if (ret < 0)
+ goto p_err3;
+
+ fimc_is_sensor_init_formats(&isp->sensor.sd, NULL);
+
+ isp->sensor.sd.internal_ops = &fimc_is_sensor_v4l2_internal_ops;
+ isp->sensor.sd.entity.ops = &fimc_is_sensor_media_ops;
+
+ ret = v4l2_device_register_subdev(&isp->mdev->v4l2_dev,
+ &isp->sensor.sd);
+ if (ret)
+ goto p_err3;
+ /* This allows to retrieve the platform device id by the host driver */
+ v4l2_set_subdevdata(&isp->sensor.sd, pdev);
+
+
+ /*front entity*/
+ v4l2_subdev_init(&isp->front.sd, &fimc_is_front_subdev_ops);
+ isp->front.sd.owner = THIS_MODULE;
+ isp->front.sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
+ snprintf(isp->front.sd.name, sizeof(isp->front.sd.name), "%s\n",
+ FIMC_IS_FRONT_ENTITY_NAME);
+
+ isp->front.pads[FIMC_IS_FRONT_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+ isp->front.pads[FIMC_IS_FRONT_PAD_SOURCE_BACK].flags
+ = MEDIA_PAD_FL_SOURCE;
+ isp->front.pads[FIMC_IS_FRONT_PAD_SOURCE_BAYER].flags
+ = MEDIA_PAD_FL_SOURCE;
+ isp->front.pads[FIMC_IS_FRONT_PAD_SOURCE_SCALERC].flags
+ = MEDIA_PAD_FL_SOURCE;
+ ret = media_entity_init(&isp->front.sd.entity, FIMC_IS_FRONT_PADS_NUM,
+ isp->front.pads, 0);
+ if (ret < 0)
+ goto p_err3;
+
+ fimc_is_front_init_formats(&isp->front.sd, NULL);
+
+ isp->front.sd.internal_ops = &fimc_is_front_v4l2_internal_ops;
+ isp->front.sd.entity.ops = &fimc_is_front_media_ops;
+
+ ret = v4l2_device_register_subdev(&isp->mdev->v4l2_dev,
+ &isp->front.sd);
+ if (ret)
+ goto p_err3;
+ /* This allows to retrieve the platform device id by the host driver */
+ v4l2_set_subdevdata(&isp->front.sd, pdev);
+
+
+ /*back entity*/
+ v4l2_subdev_init(&isp->back.sd, &fimc_is_back_subdev_ops);
+ isp->back.sd.owner = THIS_MODULE;
+ isp->back.sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
+ snprintf(isp->back.sd.name, sizeof(isp->back.sd.name), "%s\n",
+ FIMC_IS_BACK_ENTITY_NAME);
+
+ isp->back.pads[FIMC_IS_BACK_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+ isp->back.pads[FIMC_IS_BACK_PAD_SOURCE_3DNR].flags
+ = MEDIA_PAD_FL_SOURCE;
+ isp->back.pads[FIMC_IS_BACK_PAD_SOURCE_SCALERP].flags
+ = MEDIA_PAD_FL_SOURCE;
+ ret = media_entity_init(&isp->back.sd.entity, FIMC_IS_BACK_PADS_NUM,
+ isp->back.pads, 0);
+ if (ret < 0)
+ goto p_err3;
+
+ fimc_is_front_init_formats(&isp->back.sd, NULL);
+
+ isp->back.sd.internal_ops = &fimc_is_back_v4l2_internal_ops;
+ isp->back.sd.entity.ops = &fimc_is_back_media_ops;
+
+ ret = v4l2_device_register_subdev(&isp->mdev->v4l2_dev, &isp->back.sd);
+ if (ret)
+ goto p_err3;
+
+ v4l2_set_subdevdata(&isp->back.sd, pdev);
+
+ /*front video entity - scalerC */
+ snprintf(isp->video[FIMC_IS_VIDEO_NUM_SCALERC].vd.name,
+ sizeof(isp->video[FIMC_IS_VIDEO_NUM_SCALERC].vd.name),
+ "%s", FIMC_IS_VIDEO_SCALERC_NAME);
+
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERC].vd.fops
+ = &fimc_is_scalerc_video_fops;
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERC].vd.ioctl_ops
+ = &fimc_is_scalerc_video_ioctl_ops;
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERC].vd.v4l2_dev
+ = &isp->mdev->v4l2_dev;
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERC].vd.minor = -1;
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERC].vd.release
+ = video_device_release;
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERC].vd.lock = &isp->vb_lock;
+ video_set_drvdata(&isp->video[FIMC_IS_VIDEO_NUM_SCALERC].vd, isp);
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERC].dev = isp;
+
+ scalerc_q = &isp->video[FIMC_IS_VIDEO_NUM_SCALERC].vbq;
+ memset(scalerc_q, 0, sizeof(*scalerc_q));
+ scalerc_q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ scalerc_q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
+ scalerc_q->drv_priv = &isp->video[FIMC_IS_VIDEO_NUM_SCALERC];
+ scalerc_q->ops = &fimc_is_scalerc_qops;
+ scalerc_q->mem_ops = isp->vb2->ops;
+
+ vb2_queue_init(scalerc_q);
+
+ ret = video_register_device(&isp->video[FIMC_IS_VIDEO_NUM_SCALERC].vd,
+ VFL_TYPE_GRABBER,
+ FIMC_IS_VIDEO_NUM_SCALERC+EXYNOS_VIDEONODE_FIMC_IS);
+ dbg("scalerC minor : %d\n",
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERC].vd.minor);
+ if (ret) {
+ err("Failed to register ScalerC video device\n");
+ goto p_err3;
+ }
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERC].pads.flags = MEDIA_PAD_FL_SINK;
+ ret = media_entity_init(&isp->video[FIMC_IS_VIDEO_NUM_SCALERC].
+ vd.entity, 1,
+ &isp->video[FIMC_IS_VIDEO_NUM_SCALERC].pads, 0);
+ if (ret) {
+ err("Failed to media_entity_init ScalerC video device\n");
+ goto p_err3;
+ }
+
+ /* back video entity - scalerP*/
+ snprintf(isp->video[FIMC_IS_VIDEO_NUM_SCALERP].vd.name,
+ sizeof(isp->video[FIMC_IS_VIDEO_NUM_SCALERP].vd.name),
+ "%s", FIMC_IS_VIDEO_SCALERP_NAME);
+
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERP].vd.fops
+ = &fimc_is_scalerp_video_fops;
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERP].vd.ioctl_ops
+ = &fimc_is_scalerp_video_ioctl_ops;
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERP].vd.v4l2_dev
+ = &isp->mdev->v4l2_dev;
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERP].vd.minor = -1;
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERP].vd.release = video_device_release;
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERP].vd.lock = &isp->vb_lock;
+ video_set_drvdata(&isp->video[FIMC_IS_VIDEO_NUM_SCALERP].vd, isp);
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERP].dev = isp;
+
+ scalerp_q = &isp->video[FIMC_IS_VIDEO_NUM_SCALERP].vbq;
+ memset(scalerp_q, 0, sizeof(*scalerp_q));
+ scalerp_q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ scalerp_q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
+ scalerp_q->drv_priv = &isp->video[FIMC_IS_VIDEO_NUM_SCALERP];
+ scalerp_q->ops = &fimc_is_scalerp_qops;
+ scalerp_q->mem_ops = isp->vb2->ops;
+
+ vb2_queue_init(scalerp_q);
+
+ ret = video_register_device(&isp->video[FIMC_IS_VIDEO_NUM_SCALERP].vd,
+ VFL_TYPE_GRABBER,
+ FIMC_IS_VIDEO_NUM_SCALERP
+ + EXYNOS_VIDEONODE_FIMC_IS);
+ dbg("scalerP minor : %d\n",
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERP].vd.minor);
+ if (ret) {
+ err("Failed to register ScalerP video device\n");
+ goto p_err3;
+ }
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERP].pads.flags = MEDIA_PAD_FL_SINK;
+ ret = media_entity_init(&isp->video[FIMC_IS_VIDEO_NUM_SCALERP].
+ vd.entity, 1,
+ &isp->video[FIMC_IS_VIDEO_NUM_SCALERP].pads, 0);
+ if (ret) {
+ err("Failed to media_entity_init ScalerP video device\n");
+ goto p_err3;
+ }
+
+ /*back video entity - 3DNR */
+ snprintf(isp->video[FIMC_IS_VIDEO_NUM_3DNR].vd.name,
+ sizeof(isp->video[FIMC_IS_VIDEO_NUM_3DNR].vd.name),
+ "%s", FIMC_IS_VIDEO_3DNR_NAME);
+
+ isp->video[FIMC_IS_VIDEO_NUM_3DNR].vd.fops
+ = &fimc_is_3dnr_video_fops;
+ isp->video[FIMC_IS_VIDEO_NUM_3DNR].vd.ioctl_ops
+ = &fimc_is_3dnr_video_ioctl_ops;
+ isp->video[FIMC_IS_VIDEO_NUM_3DNR].vd.v4l2_dev
+ = &isp->mdev->v4l2_dev;
+ isp->video[FIMC_IS_VIDEO_NUM_3DNR].vd.minor = -1;
+ isp->video[FIMC_IS_VIDEO_NUM_3DNR].vd.release
+ = video_device_release;
+ isp->video[FIMC_IS_VIDEO_NUM_3DNR].vd.lock = &isp->vb_lock;
+ video_set_drvdata(&isp->video[FIMC_IS_VIDEO_NUM_3DNR].vd, isp);
+ isp->video[FIMC_IS_VIDEO_NUM_3DNR].dev = isp;
+
+ dnr_q = &isp->video[FIMC_IS_VIDEO_NUM_3DNR].vbq;
+ memset(dnr_q, 0, sizeof(*dnr_q));
+ dnr_q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ dnr_q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
+ dnr_q->drv_priv = &isp->video[FIMC_IS_VIDEO_NUM_3DNR];
+ dnr_q->ops = &fimc_is_3dnr_qops;
+ dnr_q->mem_ops = isp->vb2->ops;
+
+ vb2_queue_init(dnr_q);
+
+ ret = video_register_device(&isp->video[FIMC_IS_VIDEO_NUM_3DNR].vd,
+ VFL_TYPE_GRABBER,
+ FIMC_IS_VIDEO_NUM_3DNR
+ + EXYNOS_VIDEONODE_FIMC_IS);
+ dbg("3DNR minor : %d\n", isp->video[FIMC_IS_VIDEO_NUM_3DNR].vd.minor);
+ if (ret) {
+ err("Failed to register 3DNR video device\n");
+ goto p_err3;
+ }
+ isp->video[FIMC_IS_VIDEO_NUM_3DNR].pads.flags = MEDIA_PAD_FL_SINK;
+ ret = media_entity_init(&isp->video[FIMC_IS_VIDEO_NUM_3DNR].vd.entity,
+ 1, &isp->video[FIMC_IS_VIDEO_NUM_3DNR].pads, 0);
+ if (ret) {
+ err("Failed to media_entity_init 3DNR video device\n");
+ goto p_err3;
+ }
+
+ /* back video entity - bayer*/
+ snprintf(isp->video[FIMC_IS_VIDEO_NUM_BAYER].vd.name,
+ sizeof(isp->video[FIMC_IS_VIDEO_NUM_BAYER].vd.name),
+ "%s", FIMC_IS_VIDEO_BAYER_NAME);
+
+ isp->video[FIMC_IS_VIDEO_NUM_BAYER].vd.fops
+ = &fimc_is_bayer_video_fops;
+ isp->video[FIMC_IS_VIDEO_NUM_BAYER].vd.ioctl_ops
+ = &fimc_is_bayer_video_ioctl_ops;
+ isp->video[FIMC_IS_VIDEO_NUM_BAYER].vd.v4l2_dev = &isp->mdev->v4l2_dev;
+ isp->video[FIMC_IS_VIDEO_NUM_BAYER].vd.minor = -1;
+ isp->video[FIMC_IS_VIDEO_NUM_BAYER].vd.release = video_device_release;
+ isp->video[FIMC_IS_VIDEO_NUM_BAYER].vd.lock = &isp->vb_lock;
+ video_set_drvdata(&isp->video[FIMC_IS_VIDEO_NUM_BAYER].vd, isp);
+ isp->video[FIMC_IS_VIDEO_NUM_BAYER].dev = isp;
+
+ bayer_q = &isp->video[FIMC_IS_VIDEO_NUM_BAYER].vbq;
+ memset(bayer_q, 0, sizeof(*bayer_q));
+ bayer_q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ bayer_q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
+ bayer_q->drv_priv = &isp->video[FIMC_IS_VIDEO_NUM_BAYER];
+ bayer_q->ops = &fimc_is_bayer_qops;
+ bayer_q->mem_ops = isp->vb2->ops;
+
+ vb2_queue_init(bayer_q);
+
+ ret = video_register_device(&isp->video[FIMC_IS_VIDEO_NUM_BAYER].vd,
+ VFL_TYPE_GRABBER,
+ FIMC_IS_VIDEO_NUM_BAYER
+ + EXYNOS_VIDEONODE_FIMC_IS);
+ dbg("scalerP minor : %d\n",
+ isp->video[FIMC_IS_VIDEO_NUM_BAYER].vd.minor);
+ if (ret) {
+ err("Failed to register ScalerP video device\n");
+ goto p_err3;
+ }
+ isp->video[FIMC_IS_VIDEO_NUM_BAYER].pads.flags = MEDIA_PAD_FL_SINK;
+ ret = media_entity_init(&isp->video[FIMC_IS_VIDEO_NUM_BAYER].vd.entity,
+ 1, &isp->video[FIMC_IS_VIDEO_NUM_BAYER].pads, 0);
+ if (ret) {
+ err("Failed to media_entity_init ScalerP video device\n");
+ goto p_err3;
+ }
+
+ platform_set_drvdata(pdev, isp);
+
+ /* create link */
+ ret = media_entity_create_link(
+ &isp->sensor.sd.entity, FIMC_IS_SENSOR_PAD_SOURCE_FRONT,
+ &isp->front.sd.entity, FIMC_IS_FRONT_PAD_SINK, 0);
+ if (ret < 0) {
+ err("failed link creation from sensor to front\n");
+ goto p_err3;
+ }
+
+ ret = media_entity_create_link(
+ &isp->front.sd.entity, FIMC_IS_FRONT_PAD_SOURCE_BACK,
+ &isp->back.sd.entity, FIMC_IS_BACK_PAD_SINK, 0);
+ if (ret < 0) {
+ err("failed link creation from front to back\n");
+ goto p_err3;
+ }
+
+ ret = media_entity_create_link(
+ &isp->front.sd.entity, FIMC_IS_FRONT_PAD_SOURCE_SCALERC,
+ &isp->video[FIMC_IS_VIDEO_NUM_SCALERC].vd.entity, 0, 0);
+
+ if (ret < 0) {
+ err("failed link creation from front to scalerC video\n");
+ goto p_err3;
+ }
+
+ ret = media_entity_create_link(
+ &isp->back.sd.entity, FIMC_IS_BACK_PAD_SOURCE_SCALERP,
+ &isp->video[FIMC_IS_VIDEO_NUM_SCALERP].vd.entity, 0, 0);
+
+ if (ret < 0) {
+ err("failed link creation from back to scalerP video\n");
+ goto p_err3;
+ }
+
+ ret = media_entity_create_link(
+ &isp->back.sd.entity, FIMC_IS_BACK_PAD_SOURCE_3DNR,
+ &isp->video[FIMC_IS_VIDEO_NUM_3DNR].vd.entity, 0, 0);
+
+ if (ret < 0) {
+ err("failed link creation from back to 3DNR video\n");
+ goto p_err3;
+ }
+
+ /* register subdev nodes*/
+ ret = v4l2_device_register_subdev_nodes(&isp->mdev->v4l2_dev);
+ if (ret)
+ err("v4l2_device_register_subdev_nodes failed\n");
+
+ /* init vb2*/
+ isp->alloc_ctx = isp->vb2->init(isp);
+ if (IS_ERR(isp->alloc_ctx)) {
+ ret = PTR_ERR(isp->alloc_ctx);
+ goto p_err1;
+ }
+
+ /* init memory*/
+ ret = fimc_is_init_mem(isp);
+ if (ret) {
+ dbg("failed to fimc_is_init_mem (%d)\n", ret);
+ goto p_err3;
+ }
+
+#if defined(CONFIG_BUSFREQ_OPP) && defined(CONFIG_CPU_EXYNOS5250)
+ isp->bus_dev = dev_get("exynos-busfreq");
+ mutex_init(&isp->busfreq_lock);
+ isp->busfreq_num = 0;
+#endif
+
+ /*init gpio : should be moved to stream_on */
+ if (isp->pdata->cfg_gpio) {
+ isp->pdata->cfg_gpio(isp->pdev);
+ } else {
+ dev_err(&isp->pdev->dev, "failed to init GPIO config\n");
+ goto p_err3;
+ }
+
+#if defined(CONFIG_PM_RUNTIME)
+ pm_runtime_enable(&pdev->dev);
+#endif
+
+ printk(KERN_INFO "fimc-is-mc probe success\n");
+ return 0;
+
+p_err3:
+ iounmap(isp->regs);
+p_err2:
+ release_mem_region(regs_res->start, resource_size(regs_res));
+p_err1:
+ kfree(isp);
+ return ret;
+}
+
+static int fimc_is_remove(struct platform_device *pdev)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static const struct dev_pm_ops fimc_is_pm_ops = {
+ .suspend = fimc_is_suspend,
+ .resume = fimc_is_resume,
+ .runtime_suspend = fimc_is_runtime_suspend,
+ .runtime_resume = fimc_is_runtime_resume,
+};
+
+static struct platform_driver fimc_is_driver = {
+ .probe = fimc_is_probe,
+ .remove = __devexit_p(fimc_is_remove),
+ .driver = {
+ .name = FIMC_IS_MODULE_NAME,
+ .owner = THIS_MODULE,
+ .pm = &fimc_is_pm_ops,
+ }
+};
+
+static int __init fimc_is_init(void)
+{
+ int ret = platform_driver_register(&fimc_is_driver);
+ if (ret)
+ err("platform_driver_register failed: %d\n", ret);
+ return ret;
+}
+
+static void __exit fimc_is_exit(void)
+{
+ platform_driver_unregister(&fimc_is_driver);
+}
+module_init(fimc_is_init);
+module_exit(fimc_is_exit);
+
+MODULE_AUTHOR("Jiyoung Shin<idon.shin@samsung.com>");
+MODULE_DESCRIPTION("Exynos FIMC_IS driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/exynos/fimc-is-mc/fimc-is-core.h b/drivers/media/video/exynos/fimc-is-mc/fimc-is-core.h
new file mode 100644
index 0000000..6e4e9bb
--- /dev/null
+++ b/drivers/media/video/exynos/fimc-is-mc/fimc-is-core.h
@@ -0,0 +1,519 @@
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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.
+ */
+
+#ifndef FIMC_IS_CORE_H
+#define FIMC_IS_CORE_H
+
+/*#define DEBUG 1*/
+/*#define FIMC_IS_A5_DEBUG_ON 1*/
+#define FRAME_RATE_ENABLE 1
+/*#define ODC_ENABLE 1*/
+/*#define TDNR_ENABLE 1*/
+/*#define DZOOM_ENABLE 1*/
+/*#define DIS_ENABLE 1*/
+
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/pm_runtime.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-mediabus.h>
+#include <media/exynos_fimc_is.h>
+#include <media/v4l2-ioctl.h>
+#include <media/exynos_mc.h>
+#include <media/videobuf2-core.h>
+#if defined(CONFIG_VIDEOBUF2_CMA_PHYS)
+#include <media/videobuf2-cma-phys.h>
+#elif defined(CONFIG_VIDEOBUF2_ION)
+#include <media/videobuf2-ion.h>
+#endif
+#include "fimc-is-param.h"
+
+#define FIMC_IS_MODULE_NAME "exynos5-fimc-is"
+#define FIMC_IS_SENSOR_ENTITY_NAME "exynos5-fimc-is-sensor"
+#define FIMC_IS_FRONT_ENTITY_NAME "exynos5-fimc-is-front"
+#define FIMC_IS_BACK_ENTITY_NAME "exynos5-fimc-is-back"
+#define FIMC_IS_VIDEO_BAYER_NAME "exynos5-fimc-is-bayer"
+#define FIMC_IS_VIDEO_SCALERC_NAME "exynos5-fimc-is-scalerc"
+#define FIMC_IS_VIDEO_3DNR_NAME "exynos5-fimc-is-3dnr"
+#define FIMC_IS_VIDEO_SCALERP_NAME "exynos5-fimc-is-scalerp"
+
+#define FIMC_IS_A5_DEBUG_LEVEL 3
+
+#define MAX_I2H_ARG (4)
+
+#define FIMC_IS_FW "fimc_is_fw.bin"
+#define FIMC_IS_SETFILE "setfile.bin"
+
+#define FIMC_IS_SHUTDOWN_TIMEOUT (10*HZ)
+#define FIMC_IS_SHUTDOWN_TIMEOUT_SENSOR (3*HZ)
+
+#define FIMC_IS_A5_MEM_SIZE (0x00A00000)
+#define FIMC_IS_REGION_SIZE (0x5000)
+#define FIMC_IS_SETFILE_SIZE (0xc0d8)
+#define DRC_SETFILE_SIZE (0x140)
+#define FD_SETFILE_SIZE (0x88*2)
+#define FIMC_IS_FW_BASE_MASK ((1 << 26) - 1)
+#define FIMC_IS_TDNR_MEM_SIZE (1920*1080*4)
+#define FIMC_IS_DEBUG_REGION_ADDR (0x00840000)
+#define FIMC_IS_SHARED_REGION_ADDR (0x008C0000)
+
+#define FIMC_IS_MAX_BUF_NUM (16)
+#define FIMC_IS_MAX_BUf_PLANE_NUM (3)
+
+#define FIMC_IS_SENSOR_MAX_ENTITIES (1)
+#define FIMC_IS_SENSOR_PAD_SOURCE_FRONT (0)
+#define FIMC_IS_SENSOR_PADS_NUM (1)
+
+#define FIMC_IS_FRONT_MAX_ENTITIES (1)
+#define FIMC_IS_FRONT_PAD_SINK (0)
+#define FIMC_IS_FRONT_PAD_SOURCE_BACK (1)
+#define FIMC_IS_FRONT_PAD_SOURCE_BAYER (2)
+#define FIMC_IS_FRONT_PAD_SOURCE_SCALERC (3)
+#define FIMC_IS_FRONT_PADS_NUM (4)
+
+#define FIMC_IS_BACK_MAX_ENTITIES (1)
+#define FIMC_IS_BACK_PAD_SINK (0)
+#define FIMC_IS_BACK_PAD_SOURCE_3DNR (1)
+#define FIMC_IS_BACK_PAD_SOURCE_SCALERP (2)
+#define FIMC_IS_BACK_PADS_NUM (3)
+
+#define MAX_ISP_INTERNAL_BUF_WIDTH (2560) /* 4808 in HW */
+#define MAX_ISP_INTERNAL_BUF_HEIGHT (1920) /* 3356 in HW */
+#define SIZE_ISP_INTERNAL_BUF \
+ (MAX_ISP_INTERNAL_BUF_WIDTH * MAX_ISP_INTERNAL_BUF_HEIGHT * 3)
+
+#define MAX_ODC_INTERNAL_BUF_WIDTH (2560) /* 4808 in HW */
+#define MAX_ODC_INTERNAL_BUF_HEIGHT (1920) /* 3356 in HW */
+#define SIZE_ODC_INTERNAL_BUF \
+ (MAX_ODC_INTERNAL_BUF_WIDTH * MAX_ODC_INTERNAL_BUF_HEIGHT * 3)
+
+#define MAX_DIS_INTERNAL_BUF_WIDTH (2400)
+#define MAX_DIS_INTERNAL_BUF_HEIGHT (1360)
+#define SIZE_DIS_INTERNAL_BUF \
+ (MAX_DIS_INTERNAL_BUF_WIDTH * MAX_DIS_INTERNAL_BUF_HEIGHT * 2)
+
+#define MAX_3DNR_INTERNAL_BUF_WIDTH (1920)
+#define MAX_3DNR_INTERNAL_BUF_HEIGHT (1088)
+#define SIZE_3DNR_INTERNAL_BUF \
+ (MAX_3DNR_INTERNAL_BUF_WIDTH * MAX_3DNR_INTERNAL_BUF_HEIGHT * 2)
+
+#define NUM_ISP_INTERNAL_BUF (3)
+#define NUM_ODC_INTERNAL_BUF (2)
+#define NUM_DIS_INTERNAL_BUF (3)
+#define NUM_3DNR_INTERNAL_BUF (2)
+
+#define is_af_use(dev) ((dev->af.use_af) ? 1 : 0)
+
+#if defined(CONFIG_BUSFREQ_OPP) && defined(CONFIG_CPU_EXYNOS5250)
+#define FIMC_IS_FREQ_MIF (800)
+#define FIMC_IS_FREQ_INT (267)
+#endif
+
+#define err(fmt, args...) \
+ printk(KERN_ERR "%s:%d: " fmt "\n", __func__, __LINE__, ##args)
+
+#ifdef DEBUG
+#define dbg(fmt, args...) \
+ printk(KERN_DEBUG "%s:%d: " fmt "\n", __func__, __LINE__, ##args)
+#else
+#define dbg(fmt, args...)
+#endif
+
+enum fimc_is_debug_device {
+ FIMC_IS_DEBUG_MAIN = 0,
+ FIMC_IS_DEBUG_EC,
+ FIMC_IS_DEBUG_SENSOR,
+ FIMC_IS_DEBUG_ISP,
+ FIMC_IS_DEBUG_DRC,
+ FIMC_IS_DEBUG_FD,
+ FIMC_IS_DEBUG_SDK,
+ FIMC_IS_DEBUG_SCALERC,
+ FIMC_IS_DEBUG_ODC,
+ FIMC_IS_DEBUG_DIS,
+ FIMC_IS_DEBUG_TDNR,
+ FIMC_IS_DEBUG_SCALERP
+};
+
+enum fimc_is_debug_target {
+ FIMC_IS_DEBUG_UART = 0,
+ FIMC_IS_DEBUG_MEMORY,
+ FIMC_IS_DEBUG_DCC3
+};
+
+enum fimc_is_sensor_output_entity {
+ FIMC_IS_SENSOR_OUTPUT_NONE = 0,
+ FIMC_IS_SENSOR_OUTPUT_FRONT,
+};
+
+enum fimc_is_front_input_entity {
+ FIMC_IS_FRONT_INPUT_NONE = 0,
+ FIMC_IS_FRONT_INPUT_SENSOR,
+};
+
+enum fimc_is_front_output_entity {
+ FIMC_IS_FRONT_OUTPUT_NONE = 0,
+ FIMC_IS_FRONT_OUTPUT_BACK,
+ FIMC_IS_FRONT_OUTPUT_BAYER,
+ FIMC_IS_FRONT_OUTPUT_SCALERC,
+};
+
+enum fimc_is_back_input_entity {
+ FIMC_IS_BACK_INPUT_NONE = 0,
+ FIMC_IS_BACK_INPUT_FRONT,
+};
+
+enum fimc_is_back_output_entity {
+ FIMC_IS_BACK_OUTPUT_NONE = 0,
+ FIMC_IS_BACK_OUTPUT_3DNR,
+ FIMC_IS_BACK_OUTPUT_SCALERP,
+};
+
+enum fimc_is_front_state {
+ FIMC_IS_FRONT_ST_POWERED = 0,
+ FIMC_IS_FRONT_ST_STREAMING,
+ FIMC_IS_FRONT_ST_SUSPENDED,
+};
+
+enum fimc_is_video_dev_num {
+ FIMC_IS_VIDEO_NUM_BAYER = 0,
+ FIMC_IS_VIDEO_NUM_SCALERC,
+ FIMC_IS_VIDEO_NUM_3DNR,
+ FIMC_IS_VIDEO_NUM_SCALERP,
+ FIMC_IS_VIDEO_MAX_NUM,
+};
+
+enum fimc_is_pipe_state {
+ FIMC_IS_STATE_IDLE = 0,
+ FIMC_IS_STATE_FW_DOWNLOADED,
+ FIMC_IS_STATE_SENSOR_INITIALIZED,
+ FIMC_IS_STATE_HW_STREAM_ON,
+ FIMC_IS_STATE_SCALERC_STREAM_ON,
+ FIMC_IS_STATE_SCALERP_STREAM_ON,
+ FIMC_IS_STATE_3DNR_STREAM_ON,
+ FIMC_IS_STATE_BAYER_STREAM_ON,
+ FIMC_IS_STATE_SCALERC_BUFFER_PREPARED,
+ FIMC_IS_STATE_SCALERP_BUFFER_PREPARED,
+ FIMC_IS_STATE_3DNR_BUFFER_PREPARED,
+ FIMC_IS_STATE_BAYER_BUFFER_PREPARED,
+
+};
+
+enum fimc_is_state {
+ IS_ST_IDLE = 0,
+ IS_ST_PWR_ON,
+ IS_ST_FW_DOWNLOADED,
+ IS_ST_OPEN_SENSOR,
+ IS_ST_SETFILE_LOADED,
+ IS_ST_INIT_PREVIEW_STILL,
+ IS_ST_INIT_PREVIEW_VIDEO,
+ IS_ST_INIT_CAPTURE_STILL,
+ IS_ST_INIT_CAPTURE_VIDEO,
+ IS_ST_RUN,
+ IS_ST_STREAM_ON,
+ IS_ST_STREAM_OFF,
+ IS_ST_CHANGE_MODE,
+ IS_ST_SET_PARAM,
+ IS_ST_PEND,
+ IS_ST_BLOCKED,
+ IS_ST_CHANGE_MODE_DONE,
+ IS_ST_SCALERP_FRAME_DONE,
+ IS_ST_BLOCK_CMD_CLEARED,
+ IS_ST_SCALERP_MASK_DONE,
+ IS_ST_SCALERC_MASK_DONE,
+ IS_ST_TDNR_MASK_DONE,
+ IS_ST_END,
+};
+
+enum af_state {
+ FIMC_IS_AF_IDLE = 0,
+ FIMC_IS_AF_SETCONFIG = 1,
+ FIMC_IS_AF_RUNNING = 2,
+ FIMC_IS_AF_LOCK = 3,
+ FIMC_IS_AF_ABORT = 4,
+};
+
+enum af_lock_state {
+ FIMC_IS_AF_UNLOCKED = 0,
+ FIMC_IS_AF_LOCKED = 0x02
+};
+
+enum ae_lock_state {
+ FIMC_IS_AE_UNLOCKED = 0,
+ FIMC_IS_AE_LOCKED = 1
+};
+
+enum awb_lock_state {
+ FIMC_IS_AWB_UNLOCKED = 0,
+ FIMC_IS_AWB_LOCKED = 1
+};
+
+enum sensor_list {
+ SENSOR_S5K3H2_CSI_A = 1,
+ SENSOR_S5K6A3_CSI_A = 2,
+ SENSOR_S5K4E5_CSI_A = 3,
+ SENSOR_S5K3H7_CSI_A = 4,
+ SENSOR_S5K3H2_CSI_B = 101,
+ SENSOR_S5K6A3_CSI_B = 102,
+ SENSOR_S5K4E5_CSI_B = 103,
+ SENSOR_S5K3H7_CSI_B = 104,
+};
+
+enum fimc_is_power {
+ FIMC_IS_PWR_ST_BASE = 0,
+ FIMC_IS_PWR_ST_POWER_ON_OFF,
+ FIMC_IS_PWR_ST_STREAMING,
+ FIMC_IS_PWR_ST_SUSPENDED,
+ FIMC_IS_PWR_ST_RESUMED,
+};
+
+struct fimc_is_dev;
+
+struct fimc_is_fmt {
+ enum v4l2_mbus_pixelcode mbus_code;
+ char *name;
+ u32 pixelformat;
+ u16 num_planes;
+};
+
+struct fimc_is_frame {
+ struct fimc_is_fmt format;
+ u16 width;
+ u16 height;
+};
+
+struct fimc_is_vb2 {
+ const struct vb2_mem_ops *ops;
+ void *(*init)(struct fimc_is_dev *isp);
+ void (*cleanup)(void *alloc_ctx);
+
+ unsigned long (*plane_addr)(struct vb2_buffer *vb, u32 plane_no);
+
+ int (*resume)(void *alloc_ctx);
+ void (*suspend)(void *alloc_ctx);
+
+ int (*cache_flush)(struct vb2_buffer *vb, u32 num_planes);
+ void (*set_cacheable)(void *alloc_ctx, bool cacheable);
+};
+
+struct fimc_is_sensor_dev {
+ struct v4l2_subdev sd;
+ struct media_pad pads;
+ struct v4l2_mbus_framefmt mbus_fmt;
+ enum fimc_is_sensor_output_entity output;
+ int id_dual; /* for dual camera scenario */
+ int id_position; /* 0 : rear camera, 1: front camera */
+ enum sensor_list sensor_type;
+ u32 width;
+ u32 height;
+ u32 offset_x;
+ u32 offset_y;
+ int framerate_update;
+};
+
+struct fimc_is_front_dev {
+ struct v4l2_subdev sd;
+ struct media_pad pads[FIMC_IS_FRONT_PADS_NUM];
+ struct v4l2_mbus_framefmt mbus_fmt[FIMC_IS_FRONT_PADS_NUM];
+ enum fimc_is_front_input_entity input;
+ enum fimc_is_front_output_entity output;
+ u32 width;
+ u32 height;
+
+};
+
+struct fimc_is_back_dev {
+ struct v4l2_subdev sd;
+ struct media_pad pads[FIMC_IS_BACK_PADS_NUM];
+ struct v4l2_mbus_framefmt mbus_fmt[FIMC_IS_BACK_PADS_NUM];
+ enum fimc_is_back_input_entity input;
+ enum fimc_is_back_output_entity output;
+ int dis_on;
+ int odc_on;
+ int tdnr_on;
+ u32 width;
+ u32 height;
+ u32 dis_width;
+ u32 dis_height;
+};
+
+struct fimc_is_video_dev {
+ struct video_device vd;
+ struct media_pad pads;
+ struct vb2_queue vbq;
+ struct fimc_is_dev *dev;
+ struct fimc_is_frame frame;
+ unsigned int num_buf;
+ unsigned int buf_ref_cnt;
+ unsigned int buf_mask;
+
+ dma_addr_t buf[FIMC_IS_MAX_BUF_NUM][FIMC_IS_MAX_BUf_PLANE_NUM];
+};
+
+struct is_meminfo {
+ dma_addr_t base; /* buffer base */
+ size_t size; /* total length */
+ dma_addr_t vaddr_base; /* buffer base */
+ dma_addr_t vaddr_curr; /* current addr */
+ void *bitproc_buf;
+ size_t dvaddr;
+ unsigned char *kvaddr;
+ unsigned char *dvaddr_shared;
+ unsigned char *kvaddr_shared;
+ unsigned char *dvaddr_odc;
+ unsigned char *kvaddr_odc;
+ unsigned char *dvaddr_dis;
+ unsigned char *kvaddr_dis;
+ unsigned char *dvaddr_3dnr;
+ unsigned char *kvaddr_3dnr;
+ unsigned char *dvaddr_isp;
+ unsigned char *kvaddr_isp;
+ void *fw_cookie;
+
+};
+
+struct is_fw {
+ const struct firmware *info;
+ int state;
+ int ver;
+};
+
+struct is_setfile {
+ const struct firmware *info;
+ int state;
+ u32 sub_index;
+ u32 base;
+ u32 size;
+};
+
+struct is_to_host_cmd {
+ u32 cmd;
+ u32 sensor_id;
+ u16 num_valid_args;
+ u32 arg[MAX_I2H_ARG];
+};
+
+struct is_fd_result_header {
+ u32 offset;
+ u32 count;
+ u32 index;
+ u32 target_addr;
+ s32 width;
+ s32 height;
+};
+
+struct is_af_info {
+ u16 mode;
+ u32 af_state;
+ u32 af_lock_state;
+ u32 ae_lock_state;
+ u32 awb_lock_state;
+ u16 pos_x;
+ u16 pos_y;
+ u16 prev_pos_x;
+ u16 prev_pos_y;
+ u16 use_af;
+};
+
+struct flite_frame {
+ u32 o_width;
+ u32 o_height;
+ u32 width;
+ u32 height;
+ u32 offs_h;
+ u32 offs_v;
+};
+
+struct fimc_is_dev {
+ struct platform_device *pdev;
+ struct exynos5_platform_fimc_is *pdata; /* depended on isp */
+ struct exynos_md *mdev;
+ spinlock_t slock;
+ struct mutex vb_lock;
+ struct mutex lock;
+
+ struct fimc_is_sensor_dev sensor;
+ struct fimc_is_front_dev front;
+ struct fimc_is_back_dev back;
+ /* 0-bayer, 1-scalerC, 2-3DNR, 3-scalerP */
+ struct fimc_is_video_dev video[FIMC_IS_VIDEO_MAX_NUM];
+ struct vb2_alloc_ctx *alloc_ctx;
+
+ struct resource *regs_res;
+ void __iomem *regs;
+ int irq;
+ unsigned long state;
+ unsigned long power;
+ unsigned long pipe_state;
+ wait_queue_head_t irq_queue;
+ u32 id;
+ struct is_fw fw;
+ struct is_setfile setfile;
+ struct is_meminfo mem;
+ struct is_to_host_cmd i2h_cmd;
+ struct is_fd_result_header fd_header;
+
+ /* Shared parameter region */
+#if defined(CONFIG_BUSFREQ_OPP) && defined(CONFIG_CPU_EXYNOS5250)
+ struct device *bus_dev;
+ struct mutex busfreq_lock;
+ int busfreq_num;
+#endif
+ atomic_t p_region_num;
+ unsigned long p_region_index1;
+ unsigned long p_region_index2;
+ struct is_region *is_p_region;
+ struct is_share_region *is_shared_region;
+ u32 scenario_id;
+ u32 frame_count;
+ u32 sensor_num;
+ struct is_af_info af;
+ int low_power_mode;
+
+ const struct fimc_is_vb2 *vb2;
+};
+
+extern const struct v4l2_file_operations fimc_is_bayer_video_fops;
+extern const struct v4l2_ioctl_ops fimc_is_bayer_video_ioctl_ops;
+extern const struct vb2_ops fimc_is_bayer_qops;
+
+extern const struct v4l2_file_operations fimc_is_scalerc_video_fops;
+extern const struct v4l2_ioctl_ops fimc_is_scalerc_video_ioctl_ops;
+extern const struct vb2_ops fimc_is_scalerc_qops;
+
+extern const struct v4l2_file_operations fimc_is_scalerp_video_fops;
+extern const struct v4l2_ioctl_ops fimc_is_scalerp_video_ioctl_ops;
+extern const struct vb2_ops fimc_is_scalerp_qops;
+
+extern const struct v4l2_file_operations fimc_is_3dnr_video_fops;
+extern const struct v4l2_ioctl_ops fimc_is_3dnr_video_ioctl_ops;
+extern const struct vb2_ops fimc_is_3dnr_qops;
+
+#if defined(CONFIG_VIDEOBUF2_CMA_PHYS)
+extern const struct fimc_is_vb2 fimc_is_vb2_cma;
+#elif defined(CONFIG_VIDEOBUF2_ION)
+extern const struct fimc_is_vb2 fimc_is_vb2_ion;
+#endif
+
+void fimc_is_mem_suspend(void *alloc_ctxes);
+void fimc_is_mem_resume(void *alloc_ctxes);
+void fimc_is_mem_cache_clean(const void *start_addr, unsigned long size);
+void fimc_is_mem_cache_inv(const void *start_addr, unsigned long size);
+int fimc_is_pipeline_s_stream_preview
+ (struct media_entity *start_entity, int on);
+int fimc_is_init_set(struct fimc_is_dev *dev , u32 val);
+int fimc_is_load_fw(struct fimc_is_dev *dev);
+
+#endif /* FIMC_IS_CORE_H_ */
diff --git a/drivers/media/video/exynos/fimc-is-mc/fimc-is-err.h b/drivers/media/video/exynos/fimc-is-mc/fimc-is-err.h
new file mode 100644
index 0000000..3231685
--- /dev/null
+++ b/drivers/media/video/exynos/fimc-is-mc/fimc-is-err.h
@@ -0,0 +1,214 @@
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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.
+ */
+
+#ifndef FIMC_IS_ERR_H
+#define FIMC_IS_ERR_H
+
+#define IS_ERROR_VER 007 /* IS ERROR VERSION 0.07 */
+
+#define IS_ERROR_SUCCESS 0
+/* General 1 ~ 100 */
+#define IS_ERROR_INVALID_PARAMETER (IS_ERROR_SUCCESS + 1)
+#define IS_ERROR_INVALID_COMMAND (IS_ERROR_INVALID_PARAMETER + 1)
+#define IS_ERROR_REQUEST_FAIL (IS_ERROR_INVALID_COMMAND + 1)
+#define IS_ERROR_INVALID_SCENARIO (IS_ERROR_REQUEST_FAIL + 1)
+#define IS_ERROR_INVALID_SENSORID (IS_ERROR_INVALID_SCENARIO+1)
+#define IS_ERROR_INVALID_STATE (IS_ERROR_INVALID_SENSORID+1)
+#define IS_ERROR_BUSY (IS_ERROR_INVALID_STATE + 1)
+#define IS_ERROR_SET_PARAMETER (IS_ERROR_BUSY + 1)
+#define IS_ERROR_INVALID_PATH (IS_ERROR_SET_PARAMETER + 1)
+#define IS_ERROR_TIME_OUT (IS_ERROR_INVALID_PATH + 1)
+#define IS_ERROR_OPEN_SENSOR_FAIL (IS_ERROR_TIME_OUT + 1)
+#define IS_ERROR_ENTRY_MSG_THREAD_DOWN (IS_ERROR_OPEN_SENSOR_FAIL + 1)
+#define IS_ERROR_ENTRY_MSG_IS_MISSING (IS_ERROR_ENTRY_MSG_THREAD_DOWN + 1)
+#define IS_ERROR_NO_MSG_IS_RECEIVED (IS_ERROR_ENTRY_MSG_IS_MISSING + 1)
+#define IS_ERROR_SENSOR_MSG_FAIL (IS_ERROR_NO_MSG_IS_RECEIVED + 1)
+#define IS_ERROR_ISP_MSG_FAIL (IS_ERROR_SENSOR_MSG_FAIL + 1)
+#define IS_ERROR_DRC_MSG_FAIL (IS_ERROR_ISP_MSG_FAIL + 1)
+#define IS_ERROR_LHFD_MSG_FAIL (IS_ERROR_DRC_MSG_FAIL + 1)
+#define IS_ERROR_UNKNOWN 1000
+
+/* Sensor 100 ~ 200 */
+#define IS_ERROR_SENSOR_PWRDN_FAIL 100
+
+/* ISP 200 ~ 300 */
+#define IS_ERROR_ISP_PWRDN_FAIL 200
+#define IS_ERROR_ISP_MULTIPLE_INPUT (IS_ERROR_ISP_PWRDN_FAIL+1)
+#define IS_ERROR_ISP_ABSENT_INPUT (IS_ERROR_ISP_MULTIPLE_INPUT+1)
+#define IS_ERROR_ISP_ABSENT_OUTPUT (IS_ERROR_ISP_ABSENT_INPUT+1)
+#define IS_ERROR_ISP_NONADJACENT_OUTPUT (IS_ERROR_ISP_ABSENT_OUTPUT+1)
+#define IS_ERROR_ISP_FORMAT_MISMATCH (IS_ERROR_ISP_NONADJACENT_OUTPUT+1)
+#define IS_ERROR_ISP_WIDTH_MISMATCH (IS_ERROR_ISP_FORMAT_MISMATCH+1)
+#define IS_ERROR_ISP_HEIGHT_MISMATCH (IS_ERROR_ISP_WIDTH_MISMATCH+1)
+#define IS_ERROR_ISP_BITWIDTH_MISMATCH (IS_ERROR_ISP_HEIGHT_MISMATCH+1)
+#define IS_ERROR_ISP_FRAME_END_TIME_OUT (IS_ERROR_ISP_BITWIDTH_MISMATCH+1)
+
+/* DRC 300 ~ 400 */
+#define IS_ERROR_DRC_PWRDN_FAIL 300
+#define IS_ERROR_DRC_MULTIPLE_INPUT (IS_ERROR_DRC_PWRDN_FAIL+1)
+#define IS_ERROR_DRC_ABSENT_INPUT (IS_ERROR_DRC_MULTIPLE_INPUT+1)
+#define IS_ERROR_DRC_NONADJACENT_INTPUT (IS_ERROR_DRC_ABSENT_INPUT+1)
+#define IS_ERROR_DRC_ABSENT_OUTPUT (IS_ERROR_DRC_NONADJACENT_INTPUT+1)
+#define IS_ERROR_DRC_NONADJACENT_OUTPUT (IS_ERROR_DRC_ABSENT_OUTPUT+1)
+#define IS_ERROR_DRC_FORMAT_MISMATCH (IS_ERROR_DRC_NONADJACENT_OUTPUT+1)
+#define IS_ERROR_DRC_WIDTH_MISMATCH (IS_ERROR_DRC_FORMAT_MISMATCH+1)
+#define IS_ERROR_DRC_HEIGHT_MISMATCH (IS_ERROR_DRC_WIDTH_MISMATCH+1)
+#define IS_ERROR_DRC_BITWIDTH_MISMATCH (IS_ERROR_DRC_HEIGHT_MISMATCH+1)
+#define IS_ERROR_DRC_FRAME_END_TIME_OUT (IS_ERROR_DRC_BITWIDTH_MISMATCH+1)
+
+/* FD 400 ~ 500 */
+#define IS_ERROR_FD_PWRDN_FAIL 400
+#define IS_ERROR_FD_MULTIPLE_INPUT (IS_ERROR_FD_PWRDN_FAIL+1)
+#define IS_ERROR_FD_ABSENT_INPUT (IS_ERROR_FD_MULTIPLE_INPUT+1)
+#define IS_ERROR_FD_NONADJACENT_INPUT (IS_ERROR_FD_ABSENT_INPUT+1)
+#define IS_ERROR_LHFD_FRAME_END_TIME_OUT \
+ (IS_ERROR_FD_NONADJACENT_INPUT+1)
+
+/* Set parameter error enum */
+enum error {
+ /* Common error (0~99) */
+ ERROR_COMMON_NO = 0,
+ ERROR_COMMON_CMD = 1, /* Invalid command*/
+ ERROR_COMMON_PARAMETER = 2, /* Invalid parameter*/
+ /* setfile is not loaded before adjusting */
+ ERROR_COMMON_SETFILE_LOAD = 3,
+ /* setfile is not Adjusted before runnng. */
+ ERROR_COMMON_SETFILE_ADJUST = 4,
+ /* index of setfile is not valid. */
+ ERROR_COMMON_SETFILE_INDEX = 5,
+ /* Input path can be changed in ready state(stop) */
+ ERROR_COMMON_INPUT_PATH = 6,
+ /* IP can not start if input path is not set */
+ ERROR_COMMON_INPUT_INIT = 7,
+ /* Output path can be changed in ready state(stop) */
+ ERROR_COMMON_OUTPUT_PATH = 8,
+ /* IP can not start if output path is not set */
+ ERROR_COMMON_OUTPUT_INIT = 9,
+
+ ERROR_CONTROL_NO = ERROR_COMMON_NO,
+ ERROR_CONTROL_BYPASS = 11, /* Enable or Disable */
+ ERROR_CONTROL_BUF = 12, /* invalid buffer info */
+
+ ERROR_OTF_INPUT_NO = ERROR_COMMON_NO,
+ /* invalid command */
+ ERROR_OTF_INPUT_CMD = 21,
+ /* invalid format (DRC: YUV444, FD: YUV444, 422, 420) */
+ ERROR_OTF_INPUT_FORMAT = 22,
+ /* invalid width (DRC: 128~8192, FD: 32~8190) */
+ ERROR_OTF_INPUT_WIDTH = 23,
+ /* invalid height (DRC: 64~8192, FD: 16~8190) */
+ ERROR_OTF_INPUT_HEIGHT = 24,
+ /* invalid bit-width (DRC: 8~12bits, FD: 8bit) */
+ ERROR_OTF_INPUT_BIT_WIDTH = 25,
+ /* invalid frame time for ISP */
+ ERROR_OTF_INPUT_USER_FRAMETILE = 26,
+
+ ERROR_DMA_INPUT_NO = ERROR_COMMON_NO,
+ /* invalid width (DRC: 128~8192, FD: 32~8190) */
+ ERROR_DMA_INPUT_WIDTH = 31,
+ /* invalid height (DRC: 64~8192, FD: 16~8190) */
+ ERROR_DMA_INPUT_HEIGHT = 32,
+ /* invalid format (DRC: YUV444 or YUV422, FD: YUV444, 422, 420) */
+ ERROR_DMA_INPUT_FORMAT = 33,
+ /* invalid bit-width (DRC: 8~12bit, FD: 8bit) */
+ ERROR_DMA_INPUT_BIT_WIDTH = 34,
+ /* invalid order(DRC: YYCbCrorYCbYCr, FD:NO,YYCbCr,YCbYCr,CbCr,CrCb) */
+ ERROR_DMA_INPUT_ORDER = 35,
+ /* invalid palne (DRC: 3, FD: 1, 2, 3) */
+ ERROR_DMA_INPUT_PLANE = 36,
+
+ ERROR_OTF_OUTPUT_NO = ERROR_COMMON_NO,
+ /* invalid width (DRC: 128~8192) */
+ ERROR_OTF_OUTPUT_WIDTH = 41,
+ /* invalid height (DRC: 64~8192) */
+ ERROR_OTF_OUTPUT_HEIGHT = 42,
+ /* invalid format (DRC: YUV444) */
+ ERROR_OTF_OUTPUT_FORMAT = 43,
+ /* invalid bit-width (DRC: 8~12bits) */
+ ERROR_OTF_OUTPUT_BIT_WIDTH = 44,
+
+ ERROR_DMA_OUTPUT_NO = ERROR_COMMON_NO,
+ ERROR_DMA_OUTPUT_WIDTH = 51, /* invalid width */
+ ERROR_DMA_OUTPUT_HEIGHT = 52, /* invalid height */
+ ERROR_DMA_OUTPUT_FORMAT = 53, /* invalid format */
+ ERROR_DMA_OUTPUT_BIT_WIDTH = 54, /* invalid bit-width */
+ ERROR_DMA_OUTPUT_PLANE = 55, /* invalid plane */
+ ERROR_DMA_OUTPUT_ORDER = 56, /* invalid order */
+ ERROR_DMA_OUTPUT_BUF = 57, /* invalid buffer info */
+
+ ERROR_GLOBAL_SHOTMODE_NO = ERROR_COMMON_NO,
+
+ /* SENSOR Error(100~199) */
+ ERROR_SENSOR_NO = ERROR_COMMON_NO,
+ ERROR_SENSOR_I2C_FAIL = 101,
+ ERROR_SENSOR_INVALID_FRAMERATE,
+ ERROR_SENSOR_INVALID_EXPOSURETIME,
+ ERROR_SENSOR_INVALID_SIZE,
+ ERROR_SENSOR_ACTURATOR_INIT_FAIL,
+ ERROR_SENSOR_INVALID_AF_POS,
+ ERROR_SENSOR_UNSUPPORT_FUNC,
+ ERROR_SENSOR_UNSUPPORT_PERI,
+ ERROR_SENSOR_UNSUPPORT_AF,
+ ERROR_SENSOR_STOP_FAIL,
+
+ /* ISP Error (200~299) */
+ ERROR_ISP_AF_NO = ERROR_COMMON_NO,
+ ERROR_ISP_AF_BUSY = 201,
+ ERROR_ISP_AF_INVALID_COMMAND = 202,
+ ERROR_ISP_AF_INVALID_MODE = 203,
+ ERROR_ISP_FLASH_NO = ERROR_COMMON_NO,
+ ERROR_ISP_AWB_NO = ERROR_COMMON_NO,
+ ERROR_ISP_IMAGE_EFFECT_NO = ERROR_COMMON_NO,
+ ERROR_ISP_ISO_NO = ERROR_COMMON_NO,
+ ERROR_ISP_ADJUST_NO = ERROR_COMMON_NO,
+ ERROR_ISP_METERING_NO = ERROR_COMMON_NO,
+ ERROR_ISP_AFC_NO = ERROR_COMMON_NO,
+
+ /* DRC Error (300~399) */
+
+ /* FD Error (400~499) */
+ ERROR_FD_NO = ERROR_COMMON_NO,
+ /* Invalid max number (1~16) */
+ ERROR_FD_CONFIG_MAX_NUMBER_STATE = 401,
+ ERROR_FD_CONFIG_MAX_NUMBER_INVALID = 402,
+ ERROR_FD_CONFIG_YAW_ANGLE_STATE = 403,
+ ERROR_FD_CONFIG_YAW_ANGLE_INVALID = 404,
+ ERROR_FD_CONFIG_ROLL_ANGLE_STATE = 405,
+ ERROR_FD_CONFIG_ROLL_ANGLE_INVALID = 406,
+ ERROR_FD_CONFIG_SMILE_MODE_INVALID = 407,
+ ERROR_FD_CONFIG_BLINK_MODE_INVALID = 408,
+ ERROR_FD_CONFIG_EYES_DETECT_INVALID = 409,
+ ERROR_FD_CONFIG_MOUTH_DETECT_INVALID = 410,
+ ERROR_FD_CONFIG_ORIENTATION_STATE = 411,
+ ERROR_FD_CONFIG_ORIENTATION_INVALID = 412,
+ ERROR_FD_CONFIG_ORIENTATION_VALUE_INVALID = 413,
+ /* PARAM_FdResultStr can be only applied
+ * in ready-state or stream off */
+ ERROR_FD_RESULT = 414,
+ /* PARAM_FdModeStr can be only applied
+ * in ready-state or stream off */
+ ERROR_FD_MODE = 415,
+
+ /*SCALER ERR(500~599)*/
+ ERROR_SCALER_NO = ERROR_COMMON_NO,
+ ERROR_SCALER_DMA_OUTSEL = 501,
+ ERROR_SCALER_H_RATIO = 502,
+ ERROR_SCALER_V_RATIO = 503,
+ ERROR_SCALER_FRAME_BUFFER_SEQ = 504,
+
+ ERROR_SCALER_IMAGE_EFFECT = 510,
+
+ ERROR_SCALER_ROTATE = 520,
+ ERROR_SCALER_FLIP = 521,
+
+};
+
+#endif
diff --git a/drivers/media/video/exynos/fimc-is-mc/fimc-is-helper.c b/drivers/media/video/exynos/fimc-is-mc/fimc-is-helper.c
new file mode 100644
index 0000000..8b24442
--- /dev/null
+++ b/drivers/media/video/exynos/fimc-is-mc/fimc-is-helper.c
@@ -0,0 +1,2257 @@
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ * exynos5 fimc-is helper functions
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/clk.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/memory.h>
+#include <linux/regulator/consumer.h>
+#include <linux/pm_runtime.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-subdev.h>
+#include <linux/videodev2.h>
+#include <linux/videodev2_exynos_camera.h>
+#include <linux/gpio.h>
+#include <plat/gpio-cfg.h>
+#include <media/exynos_fimc_is.h>
+
+
+#include "fimc-is-core.h"
+#include "fimc-is-regs.h"
+#include "fimc-is-cmd.h"
+#include "fimc-is-param.h"
+#include "fimc-is-err.h"
+#include "fimc-is-helper.h"
+#include "fimc-is-misc.h"
+
+
+
+/*
+Default setting values
+*/
+static const struct sensor_param init_val_sensor_preview_still = {
+ .frame_rate = {
+ .frame_rate = DEFAULT_PREVIEW_STILL_FRAMERATE,
+ },
+};
+
+static const struct isp_param init_val_isp_preview_still = {
+ .control = {
+ .cmd = CONTROL_COMMAND_START,
+ .bypass = CONTROL_BYPASS_DISABLE,
+ .err = CONTROL_ERROR_NO,
+ },
+ .otf_input = {
+ .cmd = OTF_INPUT_COMMAND_ENABLE,
+ .width = DEFAULT_CAPTURE_STILL_WIDTH,
+ .height = DEFAULT_CAPTURE_STILL_HEIGHT,
+ .format = OTF_INPUT_FORMAT_BAYER,
+ .bitwidth = OTF_INPUT_BIT_WIDTH_10BIT,
+ .order = OTF_INPUT_ORDER_BAYER_GR_BG,
+ .crop_offset_x = 0,
+ .crop_offset_y = 0,
+ .crop_width = 0,
+ .crop_height = 0,
+ .frametime_min = 0,
+ .frametime_max = 33333,
+ .err = OTF_INPUT_ERROR_NO,
+ },
+ .dma1_input = {
+ .cmd = DMA_INPUT_COMMAND_DISABLE,
+ .width = 0,
+ .height = 0,
+ .format = 0,
+ .bitwidth = 0,
+ .plane = 0,
+ .order = 0,
+ .buffer_number = 0,
+ .buffer_address = 0,
+ .err = 0,
+ },
+ .dma2_input = {
+ .cmd = DMA_INPUT_COMMAND_DISABLE,
+ .width = 0, .height = 0,
+ .format = 0, .bitwidth = 0, .plane = 0,
+ .order = 0, .buffer_number = 0, .buffer_address = 0,
+ .err = 0,
+ },
+ .aa = {
+ .cmd = ISP_AA_COMMAND_START,
+ .target = ISP_AA_TARGET_AF | ISP_AA_TARGET_AE |
+ ISP_AA_TARGET_AWB,
+ .mode = 0,
+ .scene = 0,
+ .sleep = 0,
+ .face = 0,
+ .touch_x = 0, .touch_y = 0,
+ .manual_af_setting = 0,
+ .err = ISP_AF_ERROR_NO,
+ },
+ .flash = {
+ .cmd = ISP_FLASH_COMMAND_DISABLE,
+ .redeye = ISP_FLASH_REDEYE_DISABLE,
+ .err = ISP_FLASH_ERROR_NO,
+ },
+ .awb = {
+ .cmd = ISP_AWB_COMMAND_AUTO,
+ .illumination = 0,
+ .err = ISP_AWB_ERROR_NO,
+ },
+ .effect = {
+ .cmd = ISP_IMAGE_EFFECT_DISABLE,
+ .err = ISP_IMAGE_EFFECT_ERROR_NO,
+ },
+ .iso = {
+ .cmd = ISP_ISO_COMMAND_AUTO,
+ .value = 0,
+ .err = ISP_ISO_ERROR_NO,
+ },
+ .adjust = {
+ .cmd = ISP_ADJUST_COMMAND_AUTO,
+ .contrast = 0,
+ .saturation = 0,
+ .sharpness = 0,
+ .exposure = 0,
+ .brightness = 0,
+ .hue = 0,
+ .err = ISP_ADJUST_ERROR_NO,
+ },
+ .metering = {
+ .cmd = ISP_METERING_COMMAND_CENTER,
+ .win_pos_x = 0, .win_pos_y = 0,
+ .win_width = DEFAULT_CAPTURE_STILL_WIDTH,
+ .win_height = DEFAULT_CAPTURE_STILL_HEIGHT,
+ .err = ISP_METERING_ERROR_NO,
+ },
+ .afc = {
+ .cmd = ISP_AFC_COMMAND_AUTO,
+ .manual = 0, .err = ISP_AFC_ERROR_NO,
+ },
+ .otf_output = {
+ .cmd = OTF_OUTPUT_COMMAND_ENABLE,
+ .width = DEFAULT_CAPTURE_STILL_WIDTH,
+ .height = DEFAULT_CAPTURE_STILL_HEIGHT,
+ .format = OTF_OUTPUT_FORMAT_YUV444,
+ .bitwidth = OTF_OUTPUT_BIT_WIDTH_12BIT,
+ .order = OTF_OUTPUT_ORDER_BAYER_GR_BG,
+ .err = OTF_OUTPUT_ERROR_NO,
+ },
+ .dma1_output = {
+#ifdef DZOOM_EVT0
+ .cmd = DMA_OUTPUT_COMMAND_ENABLE,
+ .dma_out_mask = 0xFFFFFFFF,
+#else
+ .cmd = DMA_OUTPUT_COMMAND_DISABLE,
+ .dma_out_mask = 0,
+#endif
+ .width = DEFAULT_CAPTURE_STILL_WIDTH,
+ .height = DEFAULT_CAPTURE_STILL_HEIGHT,
+ .format = DMA_INPUT_FORMAT_YUV444,
+ .bitwidth = DMA_INPUT_BIT_WIDTH_8BIT,
+ .plane = DMA_INPUT_PLANE_1,
+ .order = DMA_INPUT_ORDER_YCbCr,
+ .buffer_number = 0,
+ .buffer_address = 0,
+ .err = DMA_OUTPUT_ERROR_NO,
+ },
+ .dma2_output = {
+ .cmd = DMA_OUTPUT_COMMAND_DISABLE,
+ .width = DEFAULT_CAPTURE_STILL_WIDTH,
+ .height = DEFAULT_CAPTURE_STILL_HEIGHT,
+ .format = DMA_OUTPUT_FORMAT_BAYER,
+ .bitwidth = DMA_OUTPUT_BIT_WIDTH_12BIT,
+ .plane = DMA_OUTPUT_PLANE_1,
+ .order = DMA_OUTPUT_ORDER_GB_BG,
+ .buffer_number = 0,
+ .buffer_address = 0,
+ .dma_out_mask = 0xFFFFFFFF,
+ .err = DMA_OUTPUT_ERROR_NO,
+ },
+};
+
+static const struct drc_param init_val_drc_preview_still = {
+ .control = {
+ .cmd = CONTROL_COMMAND_START,
+ .bypass = CONTROL_BYPASS_DISABLE,
+ .err = CONTROL_ERROR_NO,
+ },
+ .otf_input = {
+ .cmd = OTF_INPUT_COMMAND_ENABLE,
+ .width = DEFAULT_CAPTURE_STILL_WIDTH,
+ .height = DEFAULT_CAPTURE_STILL_HEIGHT,
+ .format = OTF_INPUT_FORMAT_YUV444,
+ .bitwidth = OTF_INPUT_BIT_WIDTH_12BIT,
+ .order = OTF_INPUT_ORDER_BAYER_GR_BG,
+ .err = OTF_INPUT_ERROR_NO,
+ },
+ .dma_input = {
+ .cmd = DMA_INPUT_COMMAND_DISABLE,
+ .width = DEFAULT_CAPTURE_STILL_WIDTH,
+ .height = DEFAULT_CAPTURE_STILL_HEIGHT,
+ .format = DMA_INPUT_FORMAT_YUV444,
+ .bitwidth = DMA_INPUT_BIT_WIDTH_8BIT,
+ .plane = DMA_INPUT_PLANE_1,
+ .order = DMA_INPUT_ORDER_YCbCr,
+ .buffer_number = 0,
+ .buffer_address = 0,
+ .err = 0,
+ },
+ .otf_output = {
+ .cmd = OTF_OUTPUT_COMMAND_ENABLE,
+ .width = DEFAULT_CAPTURE_STILL_WIDTH,
+ .height = DEFAULT_CAPTURE_STILL_HEIGHT,
+ .format = OTF_OUTPUT_FORMAT_YUV444,
+ .bitwidth = OTF_INPUT_BIT_WIDTH_8BIT,
+ .order = OTF_OUTPUT_ORDER_BAYER_GR_BG,
+ .err = OTF_OUTPUT_ERROR_NO,
+ },
+};
+
+static const struct scalerc_param init_val_scalerc_preview_still = {
+ .control = {
+ .cmd = CONTROL_COMMAND_START,
+ .bypass = CONTROL_BYPASS_ENABLE,
+ .err = CONTROL_ERROR_NO,
+ },
+ .otf_input = {
+ .cmd = OTF_INPUT_COMMAND_ENABLE,
+ .width = DEFAULT_CAPTURE_STILL_WIDTH,
+ .height = DEFAULT_CAPTURE_STILL_HEIGHT,
+ .format = OTF_INPUT_FORMAT_YUV444,
+ .bitwidth = OTF_INPUT_BIT_WIDTH_12BIT,
+ .order = OTF_INPUT_ORDER_BAYER_GR_BG,
+ .crop_offset_x = 0,
+ .crop_offset_y = 0,
+ .crop_width = 0,
+ .crop_height = 0,
+ .err = OTF_INPUT_ERROR_NO,
+ },
+ .effect = {
+ .cmd = 0,
+ .err = 0,
+ },
+ .input_crop = {
+ .cmd = OTF_INPUT_COMMAND_ENABLE,
+ .pos_x = 0,
+ .pos_y = 0,
+ .crop_width = DEFAULT_CAPTURE_STILL_CROP_WIDTH,
+ .crop_height = DEFAULT_CAPTURE_STILL_CROP_HEIGHT,
+ .in_width = DEFAULT_CAPTURE_STILL_WIDTH,
+ .in_height = DEFAULT_CAPTURE_STILL_HEIGHT,
+ .out_width = DEFAULT_CAPTURE_VIDEO_WIDTH,
+ .out_height = DEFAULT_CAPTURE_VIDEO_HEIGHT,
+ .err = 0,
+ },
+ .output_crop = {
+ .cmd = OTF_INPUT_COMMAND_DISABLE,
+ .pos_x = 0,
+ .pos_y = 0,
+ .crop_width = DEFAULT_CAPTURE_STILL_WIDTH,
+ .crop_height = DEFAULT_CAPTURE_STILL_HEIGHT,
+ .format = DMA_OUTPUT_FORMAT_YUV422,
+ .err = 0,
+ },
+ .otf_output = {
+ .cmd = OTF_OUTPUT_COMMAND_ENABLE,
+ .width = DEFAULT_CAPTURE_VIDEO_WIDTH,
+ .height = DEFAULT_CAPTURE_VIDEO_HEIGHT,
+ .format = OTF_OUTPUT_FORMAT_YUV444,
+ .bitwidth = OTF_OUTPUT_BIT_WIDTH_8BIT,
+ .order = OTF_OUTPUT_ORDER_BAYER_GR_BG,
+ .err = OTF_OUTPUT_ERROR_NO,
+ },
+ .dma_output = {
+ .cmd = DMA_OUTPUT_COMMAND_DISABLE,
+ .width = DEFAULT_CAPTURE_STILL_WIDTH,
+ .height = DEFAULT_CAPTURE_STILL_HEIGHT,
+ .format = DMA_OUTPUT_FORMAT_YUV422,
+ .bitwidth = DMA_OUTPUT_BIT_WIDTH_8BIT,
+ .plane = DMA_OUTPUT_PLANE_1,
+ .order = DMA_OUTPUT_ORDER_CrYCbY,
+ .buffer_number = 0,
+ .buffer_address = 0,
+ .dma_out_mask = 0xffff,
+ .reserved[0] = 2, /* unscaled*/
+ .err = DMA_OUTPUT_ERROR_NO,
+ },
+};
+
+static const struct odc_param init_val_odc_preview_still = {
+ .control = {
+ .cmd = CONTROL_COMMAND_START,
+ .bypass = CONTROL_BYPASS_ENABLE,
+ .err = CONTROL_ERROR_NO,
+ },
+ .otf_input = {
+ .cmd = OTF_INPUT_COMMAND_ENABLE,
+ .width = DEFAULT_CAPTURE_VIDEO_WIDTH,
+ .height = DEFAULT_CAPTURE_VIDEO_HEIGHT,
+ .format = OTF_INPUT_FORMAT_YUV422,
+ .bitwidth = OTF_INPUT_BIT_WIDTH_8BIT,
+ .order = OTF_INPUT_ORDER_BAYER_GR_BG,
+ .crop_offset_x = 0,
+ .crop_offset_y = 0,
+ .crop_width = 0,
+ .crop_height = 0,
+ .err = OTF_INPUT_ERROR_NO,
+ },
+ .otf_output = {
+ .cmd = OTF_OUTPUT_COMMAND_ENABLE,
+ .width = DEFAULT_CAPTURE_VIDEO_WIDTH,
+ .height = DEFAULT_CAPTURE_VIDEO_HEIGHT,
+ .format = OTF_OUTPUT_FORMAT_YUV422,
+ .bitwidth = OTF_OUTPUT_BIT_WIDTH_8BIT,
+ .order = OTF_OUTPUT_ORDER_BAYER_GR_BG,
+ .err = OTF_OUTPUT_ERROR_NO,
+ },
+};
+
+static const struct dis_param init_val_dis_preview_still = {
+ .control = {
+ .cmd = CONTROL_COMMAND_START,
+ .bypass = CONTROL_BYPASS_ENABLE,
+ .err = CONTROL_ERROR_NO,
+ },
+ .otf_input = {
+ .cmd = OTF_INPUT_COMMAND_ENABLE,
+ .width = DEFAULT_CAPTURE_VIDEO_WIDTH,
+ .height = DEFAULT_CAPTURE_VIDEO_HEIGHT,
+ .format = OTF_INPUT_FORMAT_YUV422,
+ .bitwidth = OTF_INPUT_BIT_WIDTH_8BIT,
+ .order = OTF_INPUT_ORDER_BAYER_GR_BG,
+ .crop_offset_x = 0,
+ .crop_offset_y = 0,
+ .crop_width = 0,
+ .crop_height = 0,
+ .err = OTF_INPUT_ERROR_NO,
+ },
+ .otf_output = {
+ .cmd = OTF_OUTPUT_COMMAND_ENABLE,
+ .width = DEFAULT_CAPTURE_VIDEO_WIDTH,
+ .height = DEFAULT_CAPTURE_VIDEO_HEIGHT,
+ .format = OTF_OUTPUT_FORMAT_YUV422,
+ .bitwidth = OTF_OUTPUT_BIT_WIDTH_8BIT,
+ .order = OTF_OUTPUT_ORDER_BAYER_GR_BG,
+ .err = OTF_OUTPUT_ERROR_NO,
+ },
+};
+static const struct tdnr_param init_val_tdnr_preview_still = {
+ .control = {
+ .cmd = CONTROL_COMMAND_START,
+ .bypass = CONTROL_BYPASS_ENABLE,
+ .err = CONTROL_ERROR_NO,
+ },
+ .otf_input = {
+ .cmd = OTF_INPUT_COMMAND_ENABLE,
+ .width = DEFAULT_CAPTURE_VIDEO_WIDTH,
+ .height = DEFAULT_CAPTURE_VIDEO_HEIGHT,
+ .format = OTF_INPUT_FORMAT_YUV422,
+ .bitwidth = OTF_INPUT_BIT_WIDTH_8BIT,
+ .order = OTF_INPUT_ORDER_BAYER_GR_BG,
+ .err = OTF_INPUT_ERROR_NO,
+ },
+ .frame = {
+ .cmd = 0,
+ .err = 0,
+ },
+ .otf_output = {
+ .cmd = OTF_OUTPUT_COMMAND_ENABLE,
+ .width = DEFAULT_CAPTURE_VIDEO_WIDTH,
+ .height = DEFAULT_CAPTURE_VIDEO_HEIGHT,
+ .format = OTF_OUTPUT_FORMAT_YUV422,
+ .bitwidth = OTF_INPUT_BIT_WIDTH_8BIT,
+ .order = OTF_OUTPUT_ORDER_BAYER_GR_BG,
+ .err = OTF_OUTPUT_ERROR_NO,
+ },
+ .dma_output = {
+ .cmd = DMA_OUTPUT_COMMAND_DISABLE,
+ .width = DEFAULT_CAPTURE_VIDEO_WIDTH,
+ .height = DEFAULT_CAPTURE_VIDEO_HEIGHT,
+ .format = DMA_OUTPUT_FORMAT_YUV420,
+ .bitwidth = DMA_OUTPUT_BIT_WIDTH_8BIT,
+ .plane = DMA_OUTPUT_PLANE_2,
+ .order = DMA_OUTPUT_ORDER_CbCr,
+ .buffer_number = 0,
+ .buffer_address = 0,
+ .dma_out_mask = 0xffff,
+ .err = DMA_OUTPUT_ERROR_NO,
+ },
+};
+
+static const struct scalerp_param init_val_scalerp_preview_still = {
+ .control = {
+ .cmd = CONTROL_COMMAND_START,
+ .bypass = CONTROL_BYPASS_ENABLE,
+ .err = CONTROL_ERROR_NO,
+ },
+ .otf_input = {
+ .cmd = OTF_INPUT_COMMAND_ENABLE,
+ .width = DEFAULT_CAPTURE_VIDEO_WIDTH,
+ .height = DEFAULT_CAPTURE_VIDEO_HEIGHT,
+ .format = OTF_INPUT_FORMAT_YUV444,
+ .bitwidth = OTF_INPUT_BIT_WIDTH_8BIT,
+ .order = OTF_INPUT_ORDER_BAYER_GR_BG,
+ .crop_offset_x = 0,
+ .crop_offset_y = 0,
+ .crop_width = 0,
+ .crop_height = 0,
+ .err = OTF_INPUT_ERROR_NO,
+ },
+ .effect = {
+ .cmd = 0,
+ .err = 0,
+ },
+ .input_crop = {
+ .cmd = OTF_INPUT_COMMAND_ENABLE,
+ .pos_x = 0,
+ .pos_y = 0,
+ .crop_width = DEFAULT_CAPTURE_VIDEO_WIDTH,
+ .crop_height = DEFAULT_CAPTURE_VIDEO_HEIGHT,
+ .in_width = DEFAULT_CAPTURE_VIDEO_WIDTH,
+ .in_height = DEFAULT_CAPTURE_VIDEO_HEIGHT,
+ .out_width = DEFAULT_PREVIEW_STILL_WIDTH,
+ .out_height = DEFAULT_PREVIEW_STILL_HEIGHT,
+ .err = 0,
+ },
+ .output_crop = {
+ .cmd = OTF_INPUT_COMMAND_DISABLE,
+ .pos_x = 0,
+ .pos_y = 0,
+ .crop_width = DEFAULT_PREVIEW_STILL_WIDTH,
+ .crop_height = DEFAULT_PREVIEW_STILL_HEIGHT,
+ .format = OTF_OUTPUT_FORMAT_YUV420,
+ .err = 0,
+ },
+ .rotation = {
+ .cmd = 0,
+ .err = 0,
+ },
+ .flip = {
+ .cmd = 0,
+ .err = 0,
+ },
+ .otf_output = {
+ .cmd = OTF_OUTPUT_COMMAND_ENABLE,
+ .width = DEFAULT_PREVIEW_STILL_WIDTH,
+ .height = DEFAULT_PREVIEW_STILL_HEIGHT,
+ .format = OTF_INPUT_FORMAT_YUV444,
+ .bitwidth = OTF_INPUT_BIT_WIDTH_8BIT,
+ .order = OTF_OUTPUT_ORDER_BAYER_GR_BG,
+ .err = OTF_OUTPUT_ERROR_NO,
+ },
+ .dma_output = {
+ .cmd = DMA_OUTPUT_COMMAND_DISABLE,
+ .width = DEFAULT_PREVIEW_STILL_WIDTH,
+ .height = DEFAULT_PREVIEW_STILL_HEIGHT,
+ .format = OTF_OUTPUT_FORMAT_YUV420,
+ .bitwidth = DMA_OUTPUT_BIT_WIDTH_8BIT,
+ .plane = DMA_OUTPUT_PLANE_3,
+ .order = DMA_OUTPUT_ORDER_NO,
+ .buffer_number = 0,
+ .buffer_address = 0,
+ .dma_out_mask = 0xffff,
+ .err = DMA_OUTPUT_ERROR_NO,
+ },
+};
+
+static const struct fd_param init_val_fd_preview_still = {
+ .control = {
+ .cmd = CONTROL_COMMAND_STOP,
+ .bypass = CONTROL_BYPASS_DISABLE,
+ .err = CONTROL_ERROR_NO,
+ },
+ .otf_input = {
+ .cmd = OTF_INPUT_COMMAND_ENABLE,
+ .width = DEFAULT_PREVIEW_STILL_WIDTH,
+ .height = DEFAULT_PREVIEW_STILL_HEIGHT,
+ .format = OTF_INPUT_FORMAT_YUV444,
+ .bitwidth = OTF_INPUT_BIT_WIDTH_8BIT,
+ .order = OTF_INPUT_ORDER_BAYER_GR_BG,
+ .err = OTF_INPUT_ERROR_NO,
+ },
+ .dma_input = {
+ .cmd = DMA_INPUT_COMMAND_DISABLE,
+ .width = 0, .height = 0,
+ .format = 0, .bitwidth = 0, .plane = 0,
+ .order = 0, .buffer_number = 0, .buffer_address = 0,
+ .err = 0,
+ },
+ .config = {
+ .cmd = FD_CONFIG_COMMAND_MAXIMUM_NUMBER |
+ FD_CONFIG_COMMAND_ROLL_ANGLE |
+ FD_CONFIG_COMMAND_YAW_ANGLE |
+ FD_CONFIG_COMMAND_SMILE_MODE |
+ FD_CONFIG_COMMAND_BLINK_MODE |
+ FD_CONFIG_COMMAND_EYES_DETECT |
+ FD_CONFIG_COMMAND_MOUTH_DETECT |
+ FD_CONFIG_COMMAND_ORIENTATION |
+ FD_CONFIG_COMMAND_ORIENTATION_VALUE,
+ .max_number = 5,
+ .roll_angle = FD_CONFIG_ROLL_ANGLE_FULL,
+ .yaw_angle = FD_CONFIG_YAW_ANGLE_45_90,
+ .smile_mode = FD_CONFIG_SMILE_MODE_DISABLE,
+ .blink_mode = FD_CONFIG_BLINK_MODE_DISABLE,
+ .eye_detect = FD_CONFIG_EYES_DETECT_ENABLE,
+ .mouth_detect = FD_CONFIG_MOUTH_DETECT_DISABLE,
+ .orientation = FD_CONFIG_ORIENTATION_DISABLE,
+ .orientation_value = 0,
+ .err = ERROR_FD_NO,
+ },
+};
+
+/*
+ Group 1. Interrupt
+*/
+void fimc_is_hw_set_intgr0_gd0(struct fimc_is_dev *dev)
+{
+ writel(INTGR0_INTGD0, dev->regs + INTGR0);
+}
+
+int fimc_is_hw_wait_intsr0_intsd0(struct fimc_is_dev *dev)
+{
+ u32 cfg = readl(dev->regs + INTSR0);
+ u32 status = INTSR0_GET_INTSD0(cfg);
+ while (status) {
+ cfg = readl(dev->regs + INTSR0);
+ status = INTSR0_GET_INTSD0(cfg);
+ }
+ return 0;
+}
+
+int fimc_is_hw_wait_intmsr0_intmsd0(struct fimc_is_dev *dev)
+{
+ u32 cfg = readl(dev->regs + INTMSR0);
+ u32 status = INTMSR0_GET_INTMSD0(cfg);
+ while (status) {
+ cfg = readl(dev->regs + INTMSR0);
+ status = INTMSR0_GET_INTMSD0(cfg);
+ }
+ return 0;
+}
+
+int fimc_is_fw_clear_irq1(struct fimc_is_dev *dev, unsigned int intr_pos)
+{
+ writel((1<<intr_pos), dev->regs + INTCR1);
+ return 0;
+}
+
+int fimc_is_fw_clear_irq1_all(struct fimc_is_dev *dev)
+{
+ writel(0xFF, dev->regs + INTCR1);
+ return 0;
+}
+int fimc_is_fw_clear_irq2(struct fimc_is_dev *dev)
+{
+ u32 cfg = readl(dev->regs + INTSR2);
+
+ writel(cfg, dev->regs + INTCR2);
+ return 0;
+}
+
+int fimc_is_fw_clear_insr1(struct fimc_is_dev *dev)
+{
+
+ writel(0, dev->regs + INTGR1);
+ return 0;
+}
+
+/*
+ Group 2. Common
+*/
+int fimc_is_hw_get_sensor_type(enum exynos5_sensor_id sensor_id,
+ enum exynos5_flite_id flite_id)
+{
+ int id = sensor_id;
+
+ if (flite_id == FLITE_ID_A)
+ id = sensor_id;
+ else if (flite_id == FLITE_ID_B)
+ id = sensor_id + 100;
+
+ return id;
+}
+
+int fimc_is_hw_get_sensor_max_framerate(struct fimc_is_dev *dev)
+{
+ int max_framerate = 0;
+ switch (dev->sensor.sensor_type) {
+ case SENSOR_S5K3H2_CSI_A:
+ case SENSOR_S5K3H2_CSI_B:
+ max_framerate = 15;
+ break;
+ case SENSOR_S5K3H7_CSI_A:
+ case SENSOR_S5K3H7_CSI_B:
+ max_framerate = 30;
+ break;
+ case SENSOR_S5K6A3_CSI_A:
+ case SENSOR_S5K6A3_CSI_B:
+ max_framerate = 30;
+ break;
+ case SENSOR_S5K4E5_CSI_A:
+ case SENSOR_S5K4E5_CSI_B:
+ max_framerate = 30;
+ break;
+ default:
+ max_framerate = 15;
+ }
+ return max_framerate;
+}
+
+void fimc_is_hw_open_sensor(struct fimc_is_dev *dev, u32 id, u32 sensor_index)
+{
+ fimc_is_hw_wait_intmsr0_intmsd0(dev);
+ writel(HIC_OPEN_SENSOR, dev->regs + ISSR0);
+ writel(id, dev->regs + ISSR1);
+ switch (sensor_index) {
+ case SENSOR_S5K3H2_CSI_A:
+ dev->af.use_af = 1;
+ dev->sensor.sensor_type = SENSOR_S5K3H2_CSI_A;
+ writel(SENSOR_NAME_S5K3H2, dev->regs + ISSR2);
+ writel(SENSOR_CONTROL_I2C0, dev->regs + ISSR3);
+ break;
+ case SENSOR_S5K3H2_CSI_B:
+ dev->af.use_af = 1;
+ dev->sensor.sensor_type = SENSOR_S5K3H2_CSI_B;
+ writel(SENSOR_NAME_S5K3H2, dev->regs + ISSR2);
+ writel(SENSOR_CONTROL_I2C1, dev->regs + ISSR3);
+ break;
+ case SENSOR_S5K6A3_CSI_A:
+ dev->af.use_af = 0;
+ dev->sensor.sensor_type = SENSOR_S5K6A3_CSI_A;
+ writel(SENSOR_NAME_S5K6A3, dev->regs + ISSR2);
+ writel(SENSOR_CONTROL_I2C0, dev->regs + ISSR3);
+ break;
+ case SENSOR_S5K6A3_CSI_B:
+ dev->af.use_af = 0;
+ dev->sensor.sensor_type = SENSOR_S5K6A3_CSI_B;
+ writel(SENSOR_NAME_S5K6A3, dev->regs + ISSR2);
+ writel(SENSOR_CONTROL_I2C1, dev->regs + ISSR3);
+ break;
+ case SENSOR_S5K4E5_CSI_A:
+ dev->af.use_af = 1;
+ dev->sensor.sensor_type = SENSOR_S5K4E5_CSI_A;
+ writel(SENSOR_NAME_S5K4E5, dev->regs + ISSR2);
+ writel(SENSOR_CONTROL_I2C0, dev->regs + ISSR3);
+ break;
+ case SENSOR_S5K4E5_CSI_B:
+ dev->af.use_af = 1;
+ dev->sensor.sensor_type = SENSOR_S5K4E5_CSI_B;
+ writel(SENSOR_NAME_S5K4E5, dev->regs + ISSR2);
+ writel(SENSOR_CONTROL_I2C1, dev->regs + ISSR3);
+ break;
+ }
+ /* Parameter3 : Scenario ID(Initial Scenario) */
+ writel(ISS_PREVIEW_STILL, dev->regs + ISSR4);
+ fimc_is_hw_set_intgr0_gd0(dev);
+
+}
+
+void fimc_is_hw_close_sensor(struct fimc_is_dev *dev, u32 id)
+{
+ if (dev->sensor.id_dual == id) {
+ fimc_is_hw_wait_intmsr0_intmsd0(dev);
+ writel(HIC_CLOSE_SENSOR, dev->regs + ISSR0);
+ writel(dev->sensor.id_dual, dev->regs + ISSR1);
+ writel(dev->sensor.id_dual, dev->regs + ISSR2);
+ fimc_is_hw_set_intgr0_gd0(dev);
+ }
+}
+
+void fimc_is_hw_diable_wdt(struct fimc_is_dev *dev)
+{
+ writel(0x0, dev->regs + WDT);
+}
+
+void fimc_is_hw_set_low_poweroff(struct fimc_is_dev *dev, int on)
+{
+ if (on) {
+ printk(KERN_INFO "Set low poweroff mode\n");
+ __raw_writel(0x0, PMUREG_ISP_ARM_OPTION);
+ __raw_writel(0x1CF82000, PMUREG_ISP_LOW_POWER_OFF);
+ dev->low_power_mode = true;
+ } else {
+ if (dev->low_power_mode) {
+ printk(KERN_INFO "Clear low poweroff mode\n");
+ __raw_writel(0xFFFFFFFF, PMUREG_ISP_ARM_OPTION);
+ __raw_writel(0x8, PMUREG_ISP_LOW_POWER_OFF);
+ }
+ dev->low_power_mode = false;
+ }
+}
+
+void fimc_is_hw_subip_poweroff(struct fimc_is_dev *dev)
+{
+ /* 1. Make FIMC-IS power-off state */
+ fimc_is_hw_wait_intmsr0_intmsd0(dev);
+ writel(HIC_POWER_DOWN, dev->regs + ISSR0);
+ writel(dev->sensor.id_dual, dev->regs + ISSR1);
+ fimc_is_hw_set_intgr0_gd0(dev);
+}
+
+int fimc_is_hw_a5_power_on(struct fimc_is_dev *isp)
+{
+ u32 cfg;
+ u32 timeout;
+
+ mutex_lock(&isp->lock);
+
+ if (isp->low_power_mode)
+ fimc_is_hw_set_low_poweroff(isp, false);
+
+ dbg("%s\n", __func__);
+
+ writel(0x7, PMUREG_ISP_CONFIGURATION);
+ timeout = 1000;
+ while ((__raw_readl(PMUREG_ISP_STATUS) & 0x7) != 0x7) {
+ if (timeout == 0)
+ err("A5 power on failed1\n");
+ timeout--;
+ udelay(1);
+ }
+
+ enable_mipi();
+
+ /* init Clock */
+
+ if (isp->pdata->regulator_on) {
+ isp->pdata->regulator_on(isp->pdev);
+ } else {
+ dev_err(&isp->pdev->dev, "failed to regulator on\n");
+ goto done;
+ }
+
+ if (isp->pdata->clk_cfg) {
+ isp->pdata->clk_cfg(isp->pdev);
+ } else {
+ dev_err(&isp->pdev->dev, "failed to config clock\n");
+ goto done;
+ }
+
+
+ if (isp->pdata->clk_on) {
+ isp->pdata->clk_on(isp->pdev);
+ } else {
+ dev_err(&isp->pdev->dev, "failed to clock on\n");
+ goto done;
+ }
+
+ /* 1. A5 start address setting */
+#if defined(CONFIG_VIDEOBUF2_CMA_PHYS)
+ cfg = isp->mem.base;
+#elif defined(CONFIG_VIDEOBUF2_ION)
+ cfg = isp->mem.dvaddr;
+ if (isp->alloc_ctx)
+ fimc_is_mem_resume(isp->alloc_ctx);
+#endif
+
+ dbg("mem.base(dvaddr) : 0x%08x\n", cfg);
+ dbg("mem.base(kvaddr) : 0x%08x\n", (unsigned int)isp->mem.kvaddr);
+ writel(cfg, isp->regs + BBOAR);
+
+ /* 2. A5 power on*/
+ writel(0x1, PMUREG_ISP_ARM_CONFIGURATION);
+
+ /* 3. enable A5 */
+ writel(0x00018000, PMUREG_ISP_ARM_OPTION);
+ timeout = 1000;
+ while ((__raw_readl(PMUREG_ISP_ARM_STATUS) & 0x1) != 0x1) {
+ if (timeout == 0)
+ err("A5 power on failed2\n");
+ timeout--;
+ udelay(1);
+ }
+
+ /* HACK : fimc_is_irq_handler() cannot
+ * set 1 on FIMC_IS_PWR_ST_POWER_ON_OFF */
+ set_bit(FIMC_IS_PWR_ST_POWER_ON_OFF, &isp->power);
+
+done:
+ mutex_unlock(&isp->lock);
+ return 0;
+}
+
+int fimc_is_hw_a5_power_off(struct fimc_is_dev *isp)
+{
+ u32 timeout;
+
+ dbg("%s\n", __func__);
+
+ mutex_lock(&isp->lock);
+
+#if defined(CONFIG_VIDEOBUF2_ION)
+ if (isp->alloc_ctx)
+ fimc_is_mem_suspend(isp->alloc_ctx);
+#endif
+
+ if (isp->pdata->clk_off) {
+ isp->pdata->clk_off(isp->pdev);
+ } else {
+ dev_err(&isp->pdev->dev, "failed to clock on\n");
+ goto done;
+ }
+
+ /* will be enabled after regulator problem solved*/
+ /*
+ if (isp->pdata->regulator_off) {
+ isp->pdata->regulator_off(isp->pdev);
+ } else {
+ dev_err(&isp->pdev->dev, "failed to regulator off\n");
+ goto done;
+ }
+ */
+
+ /* 1. disable A5 */
+ writel(0x0, PMUREG_ISP_ARM_OPTION);
+
+ /* 2. A5 power off*/
+ writel(0x0, PMUREG_ISP_ARM_CONFIGURATION);
+
+ /* 3. Check A5 power off status register */
+ timeout = 1000;
+ while (__raw_readl(PMUREG_ISP_ARM_STATUS) & 0x1) {
+ if (timeout == 0)
+ err("A5 power off failed\n");
+ timeout--;
+ udelay(1);
+ }
+
+ /* 4. ISP Power down mode (LOWPWR) */
+ writel(0x0, PMUREG_CMU_RESET_ISP_SYS_PWR_REG);
+
+ writel(0x0, PMUREG_ISP_CONFIGURATION);
+
+ timeout = 1000;
+ while ((__raw_readl(PMUREG_ISP_STATUS) & 0x7)) {
+ if (timeout == 0) {
+ err("ISP power off failed --> Retry\n");
+ /* Retry */
+ __raw_writel(0x1CF82000, PMUREG_ISP_LOW_POWER_OFF);
+ timeout = 1000;
+ while ((__raw_readl(PMUREG_ISP_STATUS) & 0x7)) {
+ if (timeout == 0)
+ err("ISP power off failed\n");
+ timeout--;
+ udelay(1);
+ }
+ }
+ timeout--;
+ udelay(1);
+ }
+
+done:
+ mutex_unlock(&isp->lock);
+ return 0;
+}
+
+void fimc_is_hw_a5_power(struct fimc_is_dev *isp, int on)
+{
+#if defined(CONFIG_PM_RUNTIME)
+ struct device *dev = &isp->pdev->dev;
+#endif
+
+ printk(KERN_INFO "%s(%d)\n", __func__, on);
+
+#if defined(CONFIG_PM_RUNTIME)
+ if (on)
+ pm_runtime_get_sync(dev);
+ else
+ pm_runtime_put_sync(dev);
+#else
+ if (on)
+ fimc_is_hw_a5_power_on(isp);
+ else
+ fimc_is_hw_a5_power_off(isp);
+#endif
+}
+
+void fimc_is_hw_set_sensor_num(struct fimc_is_dev *dev)
+{
+ u32 cfg;
+ writel(ISR_DONE, dev->regs + ISSR0);
+ cfg = dev->sensor.id_dual;
+ writel(cfg, dev->regs + ISSR1);
+ /* param 1 */
+ writel(IHC_GET_SENSOR_NUMBER, dev->regs + ISSR2);
+ /* param 2 */
+ cfg = dev->sensor_num;
+ writel(cfg, dev->regs + ISSR3);
+}
+
+void fimc_is_hw_get_setfile_addr(struct fimc_is_dev *dev)
+{
+ /* 1. Get FIMC-IS setfile address */
+ fimc_is_hw_wait_intmsr0_intmsd0(dev);
+ writel(HIC_GET_SET_FILE_ADDR, dev->regs + ISSR0);
+ writel(dev->sensor.id_dual, dev->regs + ISSR1);
+ fimc_is_hw_set_intgr0_gd0(dev);
+}
+
+void fimc_is_hw_load_setfile(struct fimc_is_dev *dev)
+{
+ /* 1. Make FIMC-IS power-off state */
+ fimc_is_hw_wait_intmsr0_intmsd0(dev);
+ writel(HIC_LOAD_SET_FILE, dev->regs + ISSR0);
+ writel(dev->sensor.id_dual, dev->regs + ISSR1);
+ fimc_is_hw_set_intgr0_gd0(dev);
+}
+
+int fimc_is_hw_get_sensor_num(struct fimc_is_dev *dev)
+{
+ u32 cfg = readl(dev->regs + ISSR11);
+ if (dev->sensor_num == cfg)
+ return 0;
+ else
+ return cfg;
+}
+
+void fimc_is_hw_set_debug_level(struct fimc_is_dev *dev,
+ int target,
+ int module,
+ int level)
+{
+ fimc_is_hw_wait_intmsr0_intmsd0(dev);
+ writel(HIC_MSG_CONFIG, dev->regs + ISSR0);
+ writel(dev->sensor.id_dual, dev->regs + ISSR1);
+
+ writel(target, dev->regs + ISSR2);
+ writel(module, dev->regs + ISSR3);
+ writel(level, dev->regs + ISSR4);
+ fimc_is_hw_set_intgr0_gd0(dev);
+}
+
+int fimc_is_hw_set_param(struct fimc_is_dev *dev)
+{
+ fimc_is_hw_wait_intmsr0_intmsd0(dev);
+ writel(HIC_SET_PARAMETER, dev->regs + ISSR0);
+ writel(dev->sensor.id_dual, dev->regs + ISSR1);
+
+ writel(dev->scenario_id, dev->regs + ISSR2);
+
+ writel(atomic_read(&dev->p_region_num), dev->regs + ISSR3);
+ writel(dev->p_region_index1, dev->regs + ISSR4);
+ writel(dev->p_region_index2, dev->regs + ISSR5);
+ dbg("### set param\n");
+ dbg("cmd :0x%08x\n", HIC_SET_PARAMETER);
+ dbg("senorID :0x%08x\n", dev->sensor.id_dual);
+ dbg("parma1 :0x%08x\n", dev->scenario_id);
+ dbg("parma2 :0x%08x\n", atomic_read(&dev->p_region_num));
+ dbg("parma3 :0x%08x\n", (unsigned int)dev->p_region_index1);
+ dbg("parma4 :0x%08x\n", (unsigned int)dev->p_region_index2);
+
+ fimc_is_hw_set_intgr0_gd0(dev);
+ return 0;
+}
+
+int fimc_is_hw_update_bufmask(struct fimc_is_dev *dev, unsigned int dev_num)
+{
+ int buf_mask;
+ int i = 0;
+ int cnt = 0;
+
+ buf_mask = dev->video[dev_num].buf_mask;
+
+ for (i = 0; i < 16; i++) {
+ if (((buf_mask & (1 << i)) >> i) == 1)
+ cnt++;
+ }
+ dbg("dev_num: %u, buf_mask: %#x, cnt: %d\n", dev_num, buf_mask, cnt);
+
+ if (cnt == 1) {
+ err("ERR: Not enough buffers[dev_num: %u, buf_mask: %#x]\n",
+ dev_num, buf_mask);
+ goto done;
+ }
+
+ switch (dev_num) {
+ case 0: /* Bayer */
+ if (readl(dev->regs + ISSR23) != 0x0)
+ dbg("WARN: Bayer buffer mask is unchecked\n");
+
+ writel(buf_mask, dev->regs + ISSR23);
+ break;
+ case 1: /* Scaler-C */
+ if (readl(dev->regs + ISSR31) != 0x0)
+ dbg("WARN: Scaler-C buffer mask is unchecked\n");
+
+ writel(buf_mask, dev->regs + ISSR31);
+ break;
+ case 2: /* 3DNR */
+ if (readl(dev->regs + ISSR39) != 0x0)
+ dbg("WARN: 3DNR buffer mask is unchecked\n");
+
+ writel(buf_mask, dev->regs + ISSR39);
+ break;
+ case 3: /* Scaler-P */
+ if (readl(dev->regs + ISSR47) != 0x0)
+ dbg("WARN: Scaler-P buffer mask is unchecked\n");
+
+ writel(buf_mask, dev->regs + ISSR47);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+done:
+ return 0;
+}
+
+int fimc_is_hw_get_param(struct fimc_is_dev *dev, u16 offset)
+{
+ dev->i2h_cmd.num_valid_args = offset;
+ switch (offset) {
+ case 1:
+ dev->i2h_cmd.arg[0] = readl(dev->regs + ISSR12);
+ dev->i2h_cmd.arg[1] = 0;
+ dev->i2h_cmd.arg[2] = 0;
+ dev->i2h_cmd.arg[3] = 0;
+ break;
+ case 2:
+ dev->i2h_cmd.arg[0] = readl(dev->regs + ISSR12);
+ dev->i2h_cmd.arg[1] = readl(dev->regs + ISSR13);
+ dev->i2h_cmd.arg[2] = 0;
+ dev->i2h_cmd.arg[3] = 0;
+ break;
+ case 3:
+ dev->i2h_cmd.arg[0] = readl(dev->regs + ISSR12);
+ dev->i2h_cmd.arg[1] = readl(dev->regs + ISSR13);
+ dev->i2h_cmd.arg[2] = readl(dev->regs + ISSR14);
+ dev->i2h_cmd.arg[3] = 0;
+ break;
+ case 4:
+ dev->i2h_cmd.arg[0] = readl(dev->regs + ISSR12);
+ dev->i2h_cmd.arg[1] = readl(dev->regs + ISSR13);
+ dev->i2h_cmd.arg[2] = readl(dev->regs + ISSR14);
+ dev->i2h_cmd.arg[3] = readl(dev->regs + ISSR15);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+void fimc_is_hw_set_stream(struct fimc_is_dev *dev, int on)
+{
+ if (on) {
+ fimc_is_hw_wait_intmsr0_intmsd0(dev);
+ writel(HIC_STREAM_ON, dev->regs + ISSR0);
+ writel(dev->sensor.id_dual, dev->regs + ISSR1);
+ fimc_is_hw_set_intgr0_gd0(dev);
+ } else {
+ fimc_is_hw_wait_intmsr0_intmsd0(dev);
+ writel(HIC_STREAM_OFF, dev->regs + ISSR0);
+ writel(dev->sensor.id_dual, dev->regs + ISSR1);
+ fimc_is_hw_set_intgr0_gd0(dev);
+ }
+}
+
+void fimc_is_hw_change_mode(struct fimc_is_dev *dev, int val)
+{
+ switch (val) {
+ case IS_MODE_PREVIEW_STILL:
+ dev->scenario_id = ISS_PREVIEW_STILL;
+ fimc_is_hw_wait_intmsr0_intmsd0(dev);
+ clear_bit(IS_ST_RUN, &dev->state);
+ set_bit(IS_ST_CHANGE_MODE, &dev->state);
+ writel(HIC_PREVIEW_STILL, dev->regs + ISSR0);
+ writel(dev->sensor.id_dual, dev->regs + ISSR1);
+ fimc_is_hw_set_intgr0_gd0(dev);
+ break;
+ case IS_MODE_PREVIEW_VIDEO:
+ dev->scenario_id = ISS_PREVIEW_VIDEO;
+ fimc_is_hw_wait_intmsr0_intmsd0(dev);
+ clear_bit(IS_ST_RUN, &dev->state);
+ set_bit(IS_ST_CHANGE_MODE, &dev->state);
+ writel(HIC_PREVIEW_VIDEO, dev->regs + ISSR0);
+ writel(dev->sensor.id_dual, dev->regs + ISSR1);
+ fimc_is_hw_set_intgr0_gd0(dev);
+ break;
+ case IS_MODE_CAPTURE_STILL:
+ dev->scenario_id = ISS_CAPTURE_STILL;
+ fimc_is_hw_wait_intmsr0_intmsd0(dev);
+ clear_bit(IS_ST_RUN, &dev->state);
+ set_bit(IS_ST_CHANGE_MODE, &dev->state);
+ writel(HIC_CAPTURE_STILL, dev->regs + ISSR0);
+ writel(dev->sensor.id_dual, dev->regs + ISSR1);
+ fimc_is_hw_set_intgr0_gd0(dev);
+ break;
+ case IS_MODE_CAPTURE_VIDEO:
+ dev->scenario_id = ISS_CAPTURE_VIDEO;
+ fimc_is_hw_wait_intmsr0_intmsd0(dev);
+ clear_bit(IS_ST_RUN, &dev->state);
+ set_bit(IS_ST_CHANGE_MODE, &dev->state);
+ writel(HIC_CAPTURE_VIDEO, dev->regs + ISSR0);
+ writel(dev->sensor.id_dual, dev->regs + ISSR1);
+ fimc_is_hw_set_intgr0_gd0(dev);
+ break;
+ }
+}
+/*
+ Group 3. Initial setting
+*/
+void fimc_is_hw_set_init(struct fimc_is_dev *dev)
+{
+ u32 length;
+
+
+ IS_SET_PARAM_GLOBAL_SHOTMODE_CMD(dev, 0);
+ IS_SET_PARAM_BIT(dev, PARAM_GLOBAL_SHOTMODE);
+ IS_INC_PARAM_NUM(dev);
+
+ IS_SENSOR_SET_FRAME_RATE(dev, DEFAULT_PREVIEW_STILL_FRAMERATE);
+ IS_SET_PARAM_BIT(dev, PARAM_SENSOR_FRAME_RATE);
+ IS_INC_PARAM_NUM(dev);
+ /* ISP */
+ IS_ISP_SET_PARAM_CONTROL_CMD(dev,
+ init_val_isp_preview_still.control.cmd);
+ IS_ISP_SET_PARAM_CONTROL_BYPASS(dev,
+ init_val_isp_preview_still.control.bypass);
+ IS_ISP_SET_PARAM_CONTROL_ERR(dev,
+ init_val_isp_preview_still.control.err);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_CONTROL);
+ IS_INC_PARAM_NUM(dev);
+ IS_ISP_SET_PARAM_OTF_INPUT_CMD(dev,
+ init_val_isp_preview_still.otf_input.cmd);
+ IS_ISP_SET_PARAM_OTF_INPUT_WIDTH(dev,
+ init_val_isp_preview_still.otf_input.width);
+ IS_ISP_SET_PARAM_OTF_INPUT_HEIGHT(dev,
+ init_val_isp_preview_still.otf_input.height);
+ dev->sensor.width =
+ init_val_isp_preview_still.otf_input.width;
+ dev->sensor.width =
+ init_val_isp_preview_still.otf_input.height;
+ IS_ISP_SET_PARAM_OTF_INPUT_FORMAT(dev,
+ init_val_isp_preview_still.otf_input.format);
+ IS_ISP_SET_PARAM_OTF_INPUT_BITWIDTH(dev,
+ init_val_isp_preview_still.otf_input.bitwidth);
+ IS_ISP_SET_PARAM_OTF_INPUT_ORDER(dev,
+ init_val_isp_preview_still.otf_input.order);
+ IS_ISP_SET_PARAM_OTF_INPUT_CROP_OFFSET_X(dev,
+ init_val_isp_preview_still.otf_input.crop_offset_x);
+ IS_ISP_SET_PARAM_OTF_INPUT_CROP_OFFSET_Y(dev,
+ init_val_isp_preview_still.otf_input.crop_offset_y);
+ IS_ISP_SET_PARAM_OTF_INPUT_CROP_WIDTH(dev,
+ init_val_isp_preview_still.otf_input.crop_width);
+ IS_ISP_SET_PARAM_OTF_INPUT_CROP_HEIGHT(dev,
+ init_val_isp_preview_still.otf_input.crop_height);
+ IS_ISP_SET_PARAM_OTF_INPUT_FRAMETIME_MIN(dev,
+ init_val_isp_preview_still.otf_input.frametime_min);
+ IS_ISP_SET_PARAM_OTF_INPUT_FRAMETIME_MAX(dev,
+ init_val_isp_preview_still.otf_input.frametime_max);
+ IS_ISP_SET_PARAM_OTF_INPUT_ERR(dev,
+ init_val_isp_preview_still.otf_input.err);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_OTF_INPUT);
+ IS_INC_PARAM_NUM(dev);
+ IS_ISP_SET_PARAM_DMA_INPUT1_CMD(dev,
+ init_val_isp_preview_still.dma1_input.cmd);
+ IS_ISP_SET_PARAM_DMA_INPUT1_WIDTH(dev,
+ init_val_isp_preview_still.dma1_input.width);
+ IS_ISP_SET_PARAM_DMA_INPUT1_HEIGHT(dev,
+ init_val_isp_preview_still.dma1_input.height);
+ IS_ISP_SET_PARAM_DMA_INPUT1_FORMAT(dev,
+ init_val_isp_preview_still.dma1_input.format);
+ IS_ISP_SET_PARAM_DMA_INPUT1_BITWIDTH(dev,
+ init_val_isp_preview_still.dma1_input.bitwidth);
+ IS_ISP_SET_PARAM_DMA_INPUT1_PLANE(dev,
+ init_val_isp_preview_still.dma1_input.plane);
+ IS_ISP_SET_PARAM_DMA_INPUT1_ORDER(dev,
+ init_val_isp_preview_still.dma1_input.order);
+ IS_ISP_SET_PARAM_DMA_INPUT1_BUFFERNUM(dev,
+ init_val_isp_preview_still.dma1_input.buffer_number);
+ IS_ISP_SET_PARAM_DMA_INPUT1_BUFFERADDR(dev,
+ init_val_isp_preview_still.dma1_input.buffer_address);
+ IS_ISP_SET_PARAM_DMA_INPUT1_ERR(dev,
+ init_val_isp_preview_still.dma1_input.err);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_DMA1_INPUT);
+ IS_INC_PARAM_NUM(dev);
+ IS_ISP_SET_PARAM_DMA_INPUT2_CMD(dev,
+ init_val_isp_preview_still.dma2_input.cmd);
+ IS_ISP_SET_PARAM_DMA_INPUT2_WIDTH(dev,
+ init_val_isp_preview_still.dma2_input.width);
+ IS_ISP_SET_PARAM_DMA_INPUT2_HEIGHT(dev,
+ init_val_isp_preview_still.dma2_input.height);
+ IS_ISP_SET_PARAM_DMA_INPUT2_FORMAT(dev,
+ init_val_isp_preview_still.dma2_input.format);
+ IS_ISP_SET_PARAM_DMA_INPUT2_BITWIDTH(dev,
+ init_val_isp_preview_still.dma2_input.bitwidth);
+ IS_ISP_SET_PARAM_DMA_INPUT2_PLANE(dev,
+ init_val_isp_preview_still.dma2_input.plane);
+ IS_ISP_SET_PARAM_DMA_INPUT2_ORDER(dev,
+ init_val_isp_preview_still.dma2_input.order);
+ IS_ISP_SET_PARAM_DMA_INPUT2_BUFFERNUM(dev,
+ init_val_isp_preview_still.dma2_input.buffer_number);
+ IS_ISP_SET_PARAM_DMA_INPUT2_BUFFERADDR(dev,
+ init_val_isp_preview_still.dma2_input.buffer_address);
+ IS_ISP_SET_PARAM_DMA_INPUT2_ERR(dev,
+ init_val_isp_preview_still.dma2_input.err);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_DMA2_INPUT);
+ IS_INC_PARAM_NUM(dev);
+ IS_ISP_SET_PARAM_AA_CMD(dev,
+ init_val_isp_preview_still.aa.cmd);
+ IS_ISP_SET_PARAM_AA_TARGET(dev,
+ init_val_isp_preview_still.aa.target);
+ IS_ISP_SET_PARAM_AA_MODE(dev,
+ init_val_isp_preview_still.aa.mode);
+ IS_ISP_SET_PARAM_AA_FACE(dev,
+ init_val_isp_preview_still.aa.face);
+ IS_ISP_SET_PARAM_AA_TOUCH_X(dev,
+ init_val_isp_preview_still.aa.touch_x);
+ IS_ISP_SET_PARAM_AA_TOUCH_Y(dev,
+ init_val_isp_preview_still.aa.touch_y);
+ IS_ISP_SET_PARAM_AA_MANUAL_AF(dev,
+ init_val_isp_preview_still.aa.manual_af_setting);
+ IS_ISP_SET_PARAM_AA_ERR(dev,
+ init_val_isp_preview_still.aa.err);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_AA);
+ IS_INC_PARAM_NUM(dev);
+ IS_ISP_SET_PARAM_FLASH_CMD(dev,
+ init_val_isp_preview_still.flash.cmd);
+ IS_ISP_SET_PARAM_FLASH_REDEYE(dev,
+ init_val_isp_preview_still.flash.redeye);
+ IS_ISP_SET_PARAM_FLASH_ERR(dev,
+ init_val_isp_preview_still.flash.err);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_FLASH);
+ IS_INC_PARAM_NUM(dev);
+ IS_ISP_SET_PARAM_AWB_CMD(dev,
+ init_val_isp_preview_still.awb.cmd);
+ IS_ISP_SET_PARAM_AWB_ILLUMINATION(dev,
+ init_val_isp_preview_still.awb.illumination);
+ IS_ISP_SET_PARAM_AWB_ERR(dev,
+ init_val_isp_preview_still.awb.err);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_AWB);
+ IS_INC_PARAM_NUM(dev);
+ IS_ISP_SET_PARAM_EFFECT_CMD(dev,
+ init_val_isp_preview_still.effect.cmd);
+ IS_ISP_SET_PARAM_EFFECT_ERR(dev,
+ init_val_isp_preview_still.effect.err);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_IMAGE_EFFECT);
+ IS_INC_PARAM_NUM(dev);
+ IS_ISP_SET_PARAM_ISO_CMD(dev,
+ init_val_isp_preview_still.iso.cmd);
+ IS_ISP_SET_PARAM_ISO_VALUE(dev,
+ init_val_isp_preview_still.iso.value);
+ IS_ISP_SET_PARAM_ISO_ERR(dev,
+ init_val_isp_preview_still.iso.err);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_ISO);
+ IS_INC_PARAM_NUM(dev);
+ IS_ISP_SET_PARAM_ADJUST_CMD(dev,
+ init_val_isp_preview_still.adjust.cmd);
+ IS_ISP_SET_PARAM_ADJUST_CONTRAST(dev,
+ init_val_isp_preview_still.adjust.contrast);
+ IS_ISP_SET_PARAM_ADJUST_SATURATION(dev,
+ init_val_isp_preview_still.adjust.saturation);
+ IS_ISP_SET_PARAM_ADJUST_SHARPNESS(dev,
+ init_val_isp_preview_still.adjust.sharpness);
+ IS_ISP_SET_PARAM_ADJUST_EXPOSURE(dev,
+ init_val_isp_preview_still.adjust.exposure);
+ IS_ISP_SET_PARAM_ADJUST_BRIGHTNESS(dev,
+ init_val_isp_preview_still.adjust.brightness);
+ IS_ISP_SET_PARAM_ADJUST_HUE(dev,
+ init_val_isp_preview_still.adjust.hue);
+ IS_ISP_SET_PARAM_ADJUST_ERR(dev,
+ init_val_isp_preview_still.adjust.err);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_ADJUST);
+ IS_INC_PARAM_NUM(dev);
+ IS_ISP_SET_PARAM_METERING_CMD(dev,
+ init_val_isp_preview_still.metering.cmd);
+ IS_ISP_SET_PARAM_METERING_WIN_POS_X(dev,
+ init_val_isp_preview_still.metering.win_pos_x);
+ IS_ISP_SET_PARAM_METERING_WIN_POS_Y(dev,
+ init_val_isp_preview_still.metering.win_pos_y);
+ IS_ISP_SET_PARAM_METERING_WIN_WIDTH(dev,
+ init_val_isp_preview_still.metering.win_width);
+ IS_ISP_SET_PARAM_METERING_WIN_HEIGHT(dev,
+ init_val_isp_preview_still.metering.win_height);
+ IS_ISP_SET_PARAM_METERING_ERR(dev,
+ init_val_isp_preview_still.metering.err);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_METERING);
+ IS_INC_PARAM_NUM(dev);
+ IS_ISP_SET_PARAM_AFC_CMD(dev,
+ init_val_isp_preview_still.afc.cmd);
+ IS_ISP_SET_PARAM_AFC_MANUAL(dev,
+ init_val_isp_preview_still.afc.manual);
+ IS_ISP_SET_PARAM_AFC_ERR(dev,
+ init_val_isp_preview_still.afc.err);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_AFC);
+ IS_INC_PARAM_NUM(dev);
+ IS_ISP_SET_PARAM_OTF_OUTPUT_CMD(dev,
+ init_val_isp_preview_still.otf_output.cmd);
+ IS_ISP_SET_PARAM_OTF_OUTPUT_WIDTH(dev,
+ init_val_isp_preview_still.otf_output.width);
+ IS_ISP_SET_PARAM_OTF_OUTPUT_HEIGHT(dev,
+ init_val_isp_preview_still.otf_output.height);
+ IS_ISP_SET_PARAM_OTF_OUTPUT_FORMAT(dev,
+ init_val_isp_preview_still.otf_output.format);
+ IS_ISP_SET_PARAM_OTF_OUTPUT_BITWIDTH(dev,
+ init_val_isp_preview_still.otf_output.bitwidth);
+ IS_ISP_SET_PARAM_OTF_OUTPUT_ORDER(dev,
+ init_val_isp_preview_still.otf_output.order);
+ IS_ISP_SET_PARAM_OTF_OUTPUT_ERR(dev,
+ init_val_isp_preview_still.otf_output.err);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_OTF_OUTPUT);
+ IS_INC_PARAM_NUM(dev);
+ IS_ISP_SET_PARAM_DMA_OUTPUT1_CMD(dev,
+ init_val_isp_preview_still.dma1_output.cmd);
+ IS_ISP_SET_PARAM_DMA_OUTPUT1_WIDTH(dev,
+ init_val_isp_preview_still.dma1_output.width);
+ IS_ISP_SET_PARAM_DMA_OUTPUT1_HEIGHT(dev,
+ init_val_isp_preview_still.dma1_output.height);
+ IS_ISP_SET_PARAM_DMA_OUTPUT1_FORMAT(dev,
+ init_val_isp_preview_still.dma1_output.format);
+ IS_ISP_SET_PARAM_DMA_OUTPUT1_BITWIDTH(dev,
+ init_val_isp_preview_still.dma1_output.bitwidth);
+ IS_ISP_SET_PARAM_DMA_OUTPUT1_PLANE(dev,
+ init_val_isp_preview_still.dma1_output.plane);
+ IS_ISP_SET_PARAM_DMA_OUTPUT1_ORDER(dev,
+ init_val_isp_preview_still.dma1_output.order);
+#ifdef DZOOM_EVT0
+ IS_ISP_SET_PARAM_DMA_OUTPUT1_BUFFER_NUMBER(dev,
+ 1);
+ dev->is_p_region->shared[100] = (u32)dev->mem.dvaddr_isp;
+ IS_ISP_SET_PARAM_DMA_OUTPUT1_BUFFER_ADDRESS(dev,
+ (u32)dev->mem.dvaddr_shared + 100*sizeof(u32));
+ dbg("ISP buf daddr : 0x%08x\n", dev->mem.dvaddr_isp);
+ dbg("ISP buf kaddr : 0x%08x\n", dev->mem.kvaddr_isp);
+#else
+ IS_ISP_SET_PARAM_DMA_OUTPUT1_BUFFER_NUMBER(dev,
+ init_val_isp_preview_still.dma1_output.buffer_number);
+ IS_ISP_SET_PARAM_DMA_OUTPUT1_BUFFER_ADDRESS(dev,
+ init_val_isp_preview_still.dma1_output.buffer_address);
+#endif
+ IS_ISP_SET_PARAM_DMA_OUTPUT1_MASK(dev,
+ init_val_isp_preview_still.dma1_output.dma_out_mask);
+ IS_ISP_SET_PARAM_DMA_OUTPUT1_ERR(dev,
+ init_val_isp_preview_still.dma1_output.err);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_DMA1_OUTPUT);
+ IS_INC_PARAM_NUM(dev);
+ IS_ISP_SET_PARAM_DMA_OUTPUT2_CMD(dev,
+ init_val_isp_preview_still.dma2_output.cmd);
+ IS_ISP_SET_PARAM_DMA_OUTPUT2_WIDTH(dev,
+ init_val_isp_preview_still.dma2_output.width);
+ IS_ISP_SET_PARAM_DMA_OUTPUT2_HEIGHT(dev,
+ init_val_isp_preview_still.dma2_output.height);
+ IS_ISP_SET_PARAM_DMA_OUTPUT2_FORMAT(dev,
+ init_val_isp_preview_still.dma2_output.format);
+ IS_ISP_SET_PARAM_DMA_OUTPUT2_BITWIDTH(dev,
+ init_val_isp_preview_still.dma2_output.bitwidth);
+ IS_ISP_SET_PARAM_DMA_OUTPUT2_PLANE(dev,
+ init_val_isp_preview_still.dma2_output.plane);
+ IS_ISP_SET_PARAM_DMA_OUTPUT2_ORDER(dev,
+ init_val_isp_preview_still.dma2_output.order);
+ IS_ISP_SET_PARAM_DMA_OUTPUT2_BUFFER_NUMBER(dev,
+ init_val_isp_preview_still.dma2_output.buffer_number);
+ IS_ISP_SET_PARAM_DMA_OUTPUT2_BUFFER_ADDRESS(dev,
+ init_val_isp_preview_still.dma2_output.buffer_address);
+ IS_ISP_SET_PARAM_DMA_OUTPUT2_MASK(dev,
+ init_val_isp_preview_still.dma2_output.dma_out_mask);
+ IS_ISP_SET_PARAM_DMA_OUTPUT2_ERR(dev,
+ init_val_isp_preview_still.dma2_output.err);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_DMA2_OUTPUT);
+ IS_INC_PARAM_NUM(dev);
+
+ /* DRC */
+ IS_DRC_SET_PARAM_CONTROL_CMD(dev,
+ init_val_drc_preview_still.control.cmd);
+ IS_DRC_SET_PARAM_CONTROL_BYPASS(dev,
+ init_val_drc_preview_still.control.bypass);
+ IS_DRC_SET_PARAM_CONTROL_ERR(dev,
+ init_val_drc_preview_still.control.err);
+ IS_SET_PARAM_BIT(dev, PARAM_DRC_CONTROL);
+ IS_INC_PARAM_NUM(dev);
+ IS_DRC_SET_PARAM_OTF_INPUT_CMD(dev,
+ init_val_drc_preview_still.otf_input.cmd);
+ IS_DRC_SET_PARAM_OTF_INPUT_WIDTH(dev,
+ init_val_drc_preview_still.otf_input.width);
+ IS_DRC_SET_PARAM_OTF_INPUT_HEIGHT(dev,
+ init_val_drc_preview_still.otf_input.height);
+ IS_DRC_SET_PARAM_OTF_INPUT_FORMAT(dev,
+ init_val_drc_preview_still.otf_input.format);
+ IS_DRC_SET_PARAM_OTF_INPUT_BITWIDTH(dev,
+ init_val_drc_preview_still.otf_input.bitwidth);
+ IS_DRC_SET_PARAM_OTF_INPUT_ORDER(dev,
+ init_val_drc_preview_still.otf_input.order);
+ IS_DRC_SET_PARAM_OTF_INPUT_ERR(dev,
+ init_val_drc_preview_still.otf_input.err);
+ IS_SET_PARAM_BIT(dev, PARAM_DRC_OTF_INPUT);
+ IS_INC_PARAM_NUM(dev);
+ IS_DRC_SET_PARAM_DMA_INPUT_CMD(dev,
+ init_val_drc_preview_still.dma_input.cmd);
+ IS_DRC_SET_PARAM_DMA_INPUT_WIDTH(dev,
+ init_val_drc_preview_still.dma_input.width);
+ IS_DRC_SET_PARAM_DMA_INPUT_HEIGHT(dev,
+ init_val_drc_preview_still.dma_input.height);
+ IS_DRC_SET_PARAM_DMA_INPUT_FORMAT(dev,
+ init_val_drc_preview_still.dma_input.format);
+ IS_DRC_SET_PARAM_DMA_INPUT_BITWIDTH(dev,
+ init_val_drc_preview_still.dma_input.bitwidth);
+ IS_DRC_SET_PARAM_DMA_INPUT_PLANE(dev,
+ init_val_drc_preview_still.dma_input.plane);
+ IS_DRC_SET_PARAM_DMA_INPUT_ORDER(dev,
+ init_val_drc_preview_still.dma_input.order);
+ IS_DRC_SET_PARAM_DMA_INPUT_BUFFERNUM(dev,
+ init_val_drc_preview_still.dma_input.buffer_number);
+ IS_DRC_SET_PARAM_DMA_INPUT_BUFFERADDR(dev,
+ init_val_drc_preview_still.dma_input.buffer_address);
+ IS_DRC_SET_PARAM_DMA_INPUT_ERR(dev,
+ init_val_drc_preview_still.dma_input.err);
+ IS_SET_PARAM_BIT(dev, PARAM_DRC_DMA_INPUT);
+ IS_INC_PARAM_NUM(dev);
+
+ IS_DRC_SET_PARAM_OTF_OUTPUT_CMD(dev,
+ init_val_drc_preview_still.otf_output.cmd);
+ IS_DRC_SET_PARAM_OTF_OUTPUT_WIDTH(dev,
+ init_val_drc_preview_still.otf_output.width);
+ IS_DRC_SET_PARAM_OTF_OUTPUT_HEIGHT(dev,
+ init_val_drc_preview_still.otf_output.height);
+ IS_DRC_SET_PARAM_OTF_OUTPUT_FORMAT(dev,
+ init_val_drc_preview_still.otf_output.format);
+ IS_DRC_SET_PARAM_OTF_OUTPUT_BITWIDTH(dev,
+ init_val_drc_preview_still.otf_output.bitwidth);
+ IS_DRC_SET_PARAM_OTF_OUTPUT_ORDER(dev,
+ init_val_drc_preview_still.otf_output.order);
+ IS_DRC_SET_PARAM_OTF_OUTPUT_ERR(dev,
+ init_val_drc_preview_still.otf_output.err);
+ length = init_val_drc_preview_still.otf_output.width*
+ init_val_drc_preview_still.otf_output.height;
+ IS_SET_PARAM_BIT(dev, PARAM_DRC_OTF_OUTPUT);
+ IS_INC_PARAM_NUM(dev);
+
+ /* SCALER-C Macros */
+ IS_SCALERC_SET_PARAM_CONTROL_CMD(dev,
+ init_val_scalerc_preview_still.control.cmd);
+ IS_SCALERC_SET_PARAM_CONTROL_BYPASS(dev,
+ init_val_scalerc_preview_still.control.bypass);
+ IS_SCALERC_SET_PARAM_CONTROL_ERR(dev,
+ init_val_scalerc_preview_still.control.err);
+ IS_SET_PARAM_BIT(dev, PARAM_SCALERC_CONTROL);
+ IS_INC_PARAM_NUM(dev);
+
+ IS_SCALERC_SET_PARAM_OTF_INPUT_CMD(dev,
+ init_val_scalerc_preview_still.otf_input.cmd);
+ IS_SCALERC_SET_PARAM_OTF_INPUT_WIDTH(dev,
+ init_val_scalerc_preview_still.otf_input.width);
+ IS_SCALERC_SET_PARAM_OTF_INPUT_HEIGHT(dev,
+ init_val_scalerc_preview_still.otf_input.height);
+ IS_SCALERC_SET_PARAM_OTF_INPUT_FORMAT(dev,
+ init_val_scalerc_preview_still.otf_input.format);
+ IS_SCALERC_SET_PARAM_OTF_INPUT_BITWIDTH(dev,
+ init_val_scalerc_preview_still.otf_input.bitwidth);
+ IS_SCALERC_SET_PARAM_OTF_INPUT_ORDER(dev,
+ init_val_scalerc_preview_still.otf_input.order);
+ IS_SCALERC_SET_PARAM_OTF_INPUT_ERR(dev,
+ init_val_scalerc_preview_still.otf_input.err);
+ IS_SET_PARAM_BIT(dev, PARAM_SCALERC_OTF_INPUT);
+ IS_INC_PARAM_NUM(dev);
+
+ IS_SCALERC_SET_PARAM_EFFECT_CMD(dev,
+ init_val_scalerc_preview_still.effect.cmd);
+ IS_SCALERC_SET_PARAM_EFFECT_ERR(dev,
+ init_val_scalerc_preview_still.effect.err);
+ IS_SET_PARAM_BIT(dev, PARAM_SCALERC_IMAGE_EFFECT);
+ IS_INC_PARAM_NUM(dev);
+
+ IS_SCALERC_SET_PARAM_INPUT_CROP_CMD(dev,
+ init_val_scalerc_preview_still.input_crop.cmd);
+ IS_SCALERC_SET_PARAM_INPUT_CROP_POS_X(dev,
+ init_val_scalerc_preview_still.input_crop.pos_x);
+ IS_SCALERC_SET_PARAM_INPUT_CROP_POS_Y(dev,
+ init_val_scalerc_preview_still.input_crop.pos_y);
+ IS_SCALERC_SET_PARAM_INPUT_CROP_WIDTH(dev,
+ init_val_scalerc_preview_still.input_crop.crop_width);
+ IS_SCALERC_SET_PARAM_INPUT_CROP_HEIGHT(dev,
+ init_val_scalerc_preview_still.input_crop.crop_height);
+ IS_SCALERC_SET_PARAM_INPUT_CROP_IN_WIDTH(dev,
+ init_val_scalerc_preview_still.input_crop.in_width);
+ IS_SCALERC_SET_PARAM_INPUT_CROP_IN_HEIGHT(dev,
+ init_val_scalerc_preview_still.input_crop.in_height);
+ IS_SCALERC_SET_PARAM_INPUT_CROP_OUT_WIDTH(dev,
+ init_val_scalerc_preview_still.input_crop.out_width);
+ IS_SCALERC_SET_PARAM_INPUT_CROP_OUT_HEIGHT(dev,
+ init_val_scalerc_preview_still.input_crop.out_height);
+ IS_SCALERC_SET_PARAM_INPUT_CROP_ERR(dev,
+ init_val_scalerc_preview_still.input_crop.err);
+ IS_SET_PARAM_BIT(dev, PARAM_SCALERC_INPUT_CROP);
+ IS_INC_PARAM_NUM(dev);
+
+ IS_SCALERC_SET_PARAM_OUTPUT_CROP_CMD(dev,
+ init_val_scalerc_preview_still.output_crop.cmd);
+ IS_SCALERC_SET_PARAM_OUTPUT_CROP_POS_X(dev,
+ init_val_scalerc_preview_still.output_crop.pos_x);
+ IS_SCALERC_SET_PARAM_OUTPUT_CROP_POS_Y(dev,
+ init_val_scalerc_preview_still.output_crop.pos_y);
+ IS_SCALERC_SET_PARAM_OUTPUT_CROP_CROP_WIDTH(dev,
+ init_val_scalerc_preview_still.output_crop.crop_width);
+ IS_SCALERC_SET_PARAM_OUTPUT_CROP_CROP_HEIGHT(dev,
+ init_val_scalerc_preview_still.output_crop.crop_height);
+ IS_SCALERC_SET_PARAM_OUTPUT_CROPG_FORMAT(dev,
+ init_val_scalerc_preview_still.output_crop.format);
+ IS_SCALERC_SET_PARAM_OUTPUT_CROP_ERR(dev,
+ init_val_scalerc_preview_still.output_crop.err);
+ IS_SET_PARAM_BIT(dev, PARAM_SCALERC_OUTPUT_CROP);
+ IS_INC_PARAM_NUM(dev);
+
+ IS_SCALERC_SET_PARAM_OTF_OUTPUT_CMD(dev,
+ init_val_scalerc_preview_still.otf_output.cmd);
+ IS_SCALERC_SET_PARAM_OTF_OUTPUT_WIDTH(dev,
+ init_val_scalerc_preview_still.otf_output.width);
+ IS_SCALERC_SET_PARAM_OTF_OUTPUT_HEIGHT(dev,
+ init_val_scalerc_preview_still.otf_output.height);
+ IS_SCALERC_SET_PARAM_OTF_OUTPUT_FORMAT(dev,
+ init_val_scalerc_preview_still.otf_output.format);
+ IS_SCALERC_SET_PARAM_OTF_OUTPUT_BITWIDTH(dev,
+ init_val_scalerc_preview_still.otf_output.bitwidth);
+ IS_SCALERC_SET_PARAM_OTF_OUTPUT_ORDER(dev,
+ init_val_scalerc_preview_still.otf_output.order);
+ IS_SCALERC_SET_PARAM_OTF_OUTPUT_ERR(dev,
+ init_val_scalerc_preview_still.otf_output.err);
+ IS_SET_PARAM_BIT(dev, PARAM_SCALERC_OTF_OUTPUT);
+ IS_INC_PARAM_NUM(dev);
+
+ IS_SCALERC_SET_PARAM_DMA_OUTPUT_CMD(dev,
+ init_val_scalerc_preview_still.dma_output.cmd);
+ IS_SCALERC_SET_PARAM_DMA_OUTPUT_WIDTH(dev,
+ init_val_scalerc_preview_still.dma_output.width);
+ IS_SCALERC_SET_PARAM_DMA_OUTPUT_HEIGHT(dev,
+ init_val_scalerc_preview_still.dma_output.height);
+ IS_SCALERC_SET_PARAM_DMA_OUTPUT_FORMAT(dev,
+ init_val_scalerc_preview_still.dma_output.format);
+ IS_SCALERC_SET_PARAM_DMA_OUTPUT_BITWIDTH(dev,
+ init_val_scalerc_preview_still.dma_output.bitwidth);
+ IS_SCALERC_SET_PARAM_DMA_OUTPUT_PLANE(dev,
+ init_val_scalerc_preview_still.dma_output.plane);
+ IS_SCALERC_SET_PARAM_DMA_OUTPUT_ORDER(dev,
+ init_val_scalerc_preview_still.dma_output.order);
+ IS_SCALERC_SET_PARAM_DMA_OUTPUT_BUFFERNUM(dev,
+ init_val_scalerc_preview_still.dma_output.buffer_number);
+ IS_SCALERC_SET_PARAM_DMA_OUTPUT_BUFFERADDR(dev,
+ init_val_scalerc_preview_still.dma_output.buffer_address);
+ IS_SCALERC_SET_PARAM_DMA_OUTPUT_MASK(dev,
+ (0xff&0xffffffff));
+ IS_SCALERC_SET_PARAM_DMA_OUTPUT_OUTPATH(dev,
+ init_val_scalerc_preview_still.dma_output.reserved[0]);
+ IS_SCALERC_SET_PARAM_DMA_OUTPUT_ERR(dev,
+ init_val_scalerc_preview_still.dma_output.err);
+ IS_SET_PARAM_BIT(dev, PARAM_SCALERC_DMA_OUTPUT);
+ IS_INC_PARAM_NUM(dev);
+
+ /* ODC Macros */
+ IS_ODC_SET_PARAM_CONTROL_CMD(dev,
+ init_val_odc_preview_still.control.cmd);
+ IS_ODC_SET_PARAM_CONTROL_BYPASS(dev,
+ init_val_odc_preview_still.control.bypass);
+ IS_ODC_SET_PARAM_CONTROL_ERR(dev,
+ init_val_odc_preview_still.control.err);
+ IS_SET_PARAM_BIT(dev, PARAM_ODC_CONTROL);
+ IS_INC_PARAM_NUM(dev);
+
+ IS_ODC_SET_PARAM_OTF_INPUT_CMD(dev,
+ init_val_odc_preview_still.otf_input.cmd);
+ IS_ODC_SET_PARAM_OTF_INPUT_WIDTH(dev,
+ init_val_odc_preview_still.otf_input.width);
+ IS_ODC_SET_PARAM_OTF_INPUT_HEIGHT(dev,
+ init_val_odc_preview_still.otf_input.height);
+ IS_ODC_SET_PARAM_OTF_INPUT_FORMAT(dev,
+ init_val_odc_preview_still.otf_input.format);
+ IS_ODC_SET_PARAM_OTF_INPUT_BITWIDTH(dev,
+ init_val_odc_preview_still.otf_input.bitwidth);
+ IS_ODC_SET_PARAM_OTF_INPUT_ORDER(dev,
+ init_val_odc_preview_still.otf_input.order);
+ IS_ODC_SET_PARAM_OTF_INPUT_ERR(dev,
+ init_val_odc_preview_still.otf_input.err);
+ IS_SET_PARAM_BIT(dev, PARAM_ODC_OTF_INPUT);
+ IS_INC_PARAM_NUM(dev);
+
+ IS_ODC_SET_PARAM_OTF_OUTPUT_CMD(dev,
+ init_val_odc_preview_still.otf_output.cmd);
+ IS_ODC_SET_PARAM_OTF_OUTPUT_WIDTH(dev,
+ init_val_odc_preview_still.otf_output.width);
+ IS_ODC_SET_PARAM_OTF_OUTPUT_HEIGHT(dev,
+ init_val_odc_preview_still.otf_output.height);
+ IS_ODC_SET_PARAM_OTF_OUTPUT_FORMAT(dev,
+ init_val_odc_preview_still.otf_output.format);
+ IS_ODC_SET_PARAM_OTF_OUTPUT_BITWIDTH(dev,
+ init_val_odc_preview_still.otf_output.bitwidth);
+ IS_ODC_SET_PARAM_OTF_OUTPUT_ORDER(dev,
+ init_val_odc_preview_still.otf_output.order);
+ IS_ODC_SET_PARAM_OTF_OUTPUT_ERR(dev,
+ init_val_odc_preview_still.otf_output.err);
+ IS_SET_PARAM_BIT(dev, PARAM_ODC_OTF_OUTPUT);
+ IS_INC_PARAM_NUM(dev);
+
+ /* DIS Macros */
+ IS_DIS_SET_PARAM_CONTROL_CMD(dev,
+ init_val_dis_preview_still.control.cmd);
+ IS_DIS_SET_PARAM_CONTROL_BYPASS(dev,
+ init_val_dis_preview_still.control.bypass);
+ IS_DIS_SET_PARAM_CONTROL_ERR(dev,
+ init_val_dis_preview_still.control.err);
+ IS_SET_PARAM_BIT(dev, PARAM_DIS_CONTROL);
+ IS_INC_PARAM_NUM(dev);
+
+ IS_DIS_SET_PARAM_OTF_INPUT_CMD(dev,
+ init_val_dis_preview_still.otf_input.cmd);
+ IS_DIS_SET_PARAM_OTF_INPUT_WIDTH(dev,
+ init_val_dis_preview_still.otf_input.width);
+ IS_DIS_SET_PARAM_OTF_INPUT_HEIGHT(dev,
+ init_val_dis_preview_still.otf_input.height);
+ IS_DIS_SET_PARAM_OTF_INPUT_FORMAT(dev,
+ init_val_dis_preview_still.otf_input.format);
+ IS_DIS_SET_PARAM_OTF_INPUT_BITWIDTH(dev,
+ init_val_dis_preview_still.otf_input.bitwidth);
+ IS_DIS_SET_PARAM_OTF_INPUT_ORDER(dev,
+ init_val_dis_preview_still.otf_input.order);
+ IS_DIS_SET_PARAM_OTF_INPUT_ERR(dev,
+ init_val_dis_preview_still.otf_input.err);
+ IS_SET_PARAM_BIT(dev, PARAM_DIS_OTF_INPUT);
+ IS_INC_PARAM_NUM(dev);
+
+ IS_DIS_SET_PARAM_OTF_OUTPUT_CMD(dev,
+ init_val_dis_preview_still.otf_output.cmd);
+ IS_DIS_SET_PARAM_OTF_OUTPUT_WIDTH(dev,
+ init_val_dis_preview_still.otf_output.width);
+ IS_DIS_SET_PARAM_OTF_OUTPUT_HEIGHT(dev,
+ init_val_dis_preview_still.otf_output.height);
+ IS_DIS_SET_PARAM_OTF_OUTPUT_FORMAT(dev,
+ init_val_dis_preview_still.otf_output.format);
+ IS_DIS_SET_PARAM_OTF_OUTPUT_BITWIDTH(dev,
+ init_val_dis_preview_still.otf_output.bitwidth);
+ IS_DIS_SET_PARAM_OTF_OUTPUT_ORDER(dev,
+ init_val_dis_preview_still.otf_output.order);
+ IS_DIS_SET_PARAM_OTF_OUTPUT_ERR(dev,
+ init_val_dis_preview_still.otf_output.err);
+ IS_SET_PARAM_BIT(dev, PARAM_DIS_OTF_OUTPUT);
+ IS_INC_PARAM_NUM(dev);
+
+ /* TDNR Macros */
+ IS_TDNR_SET_PARAM_CONTROL_CMD(dev,
+ init_val_tdnr_preview_still.control.cmd);
+ IS_TDNR_SET_PARAM_CONTROL_BYPASS(dev,
+ init_val_tdnr_preview_still.control.bypass);
+ IS_TDNR_SET_PARAM_CONTROL_ERR(dev,
+ init_val_tdnr_preview_still.control.err);
+ IS_SET_PARAM_BIT(dev, PARAM_TDNR_CONTROL);
+ IS_INC_PARAM_NUM(dev);
+
+ IS_TDNR_SET_PARAM_OTF_INPUT_CMD(dev,
+ init_val_tdnr_preview_still.otf_input.cmd);
+ IS_TDNR_SET_PARAM_OTF_INPUT_WIDTH(dev,
+ init_val_tdnr_preview_still.otf_input.width);
+ IS_TDNR_SET_PARAM_OTF_INPUT_HEIGHT(dev,
+ init_val_tdnr_preview_still.otf_input.height);
+ IS_TDNR_SET_PARAM_OTF_INPUT_FORMAT(dev,
+ init_val_tdnr_preview_still.otf_input.format);
+ IS_TDNR_SET_PARAM_OTF_INPUT_BITWIDTH(dev,
+ init_val_tdnr_preview_still.otf_input.bitwidth);
+ IS_TDNR_SET_PARAM_OTF_INPUT_ORDER(dev,
+ init_val_tdnr_preview_still.otf_input.order);
+ IS_TDNR_SET_PARAM_OTF_INPUT_ERR(dev,
+ init_val_tdnr_preview_still.otf_input.err);
+ IS_SET_PARAM_BIT(dev, PARAM_TDNR_OTF_INPUT);
+ IS_INC_PARAM_NUM(dev);
+
+ IS_TDNR_SET_PARAM_FRAME_CMD(dev,
+ init_val_tdnr_preview_still.frame.cmd);
+ IS_TDNR_SET_PARAM_FRAME_ERR(dev,
+ init_val_tdnr_preview_still.frame.err);
+ IS_SET_PARAM_BIT(dev, PARAM_TDNR_1ST_FRAME);
+ IS_INC_PARAM_NUM(dev);
+
+ IS_TDNR_SET_PARAM_OTF_OUTPUT_CMD(dev,
+ init_val_tdnr_preview_still.otf_output.cmd);
+ IS_TDNR_SET_PARAM_OTF_OUTPUT_WIDTH(dev,
+ init_val_tdnr_preview_still.otf_output.width);
+ IS_TDNR_SET_PARAM_OTF_OUTPUT_HEIGHT(dev,
+ init_val_tdnr_preview_still.otf_output.height);
+ IS_TDNR_SET_PARAM_OTF_OUTPUT_FORMAT(dev,
+ init_val_tdnr_preview_still.otf_output.format);
+ IS_TDNR_SET_PARAM_OTF_OUTPUT_BITWIDTH(dev,
+ init_val_tdnr_preview_still.otf_output.bitwidth);
+ IS_TDNR_SET_PARAM_OTF_OUTPUT_ORDER(dev,
+ init_val_tdnr_preview_still.otf_output.order);
+ IS_TDNR_SET_PARAM_OTF_OUTPUT_ERR(dev,
+ init_val_tdnr_preview_still.otf_output.err);
+ IS_SET_PARAM_BIT(dev, PARAM_TDNR_OTF_OUTPUT);
+ IS_INC_PARAM_NUM(dev);
+
+ IS_TDNR_SET_PARAM_DMA_OUTPUT_CMD(dev,
+ init_val_tdnr_preview_still.dma_output.cmd);
+ IS_TDNR_SET_PARAM_DMA_OUTPUT_WIDTH(dev,
+ init_val_tdnr_preview_still.dma_output.width);
+ IS_TDNR_SET_PARAM_DMA_OUTPUT_HEIGHT(dev,
+ init_val_tdnr_preview_still.dma_output.height);
+ IS_TDNR_SET_PARAM_DMA_OUTPUT_FORMAT(dev,
+ init_val_tdnr_preview_still.dma_output.format);
+ IS_TDNR_SET_PARAM_DMA_OUTPUT_BITWIDTH(dev,
+ init_val_tdnr_preview_still.dma_output.bitwidth);
+ IS_TDNR_SET_PARAM_DMA_OUTPUT_PLANE(dev,
+ init_val_tdnr_preview_still.dma_output.plane);
+ IS_TDNR_SET_PARAM_DMA_OUTPUT_ORDER(dev,
+ init_val_tdnr_preview_still.dma_output.order);
+ IS_TDNR_SET_PARAM_DMA_OUTPUT_BUFFERNUM(dev,
+ init_val_tdnr_preview_still.dma_output.buffer_number);
+ IS_TDNR_SET_PARAM_DMA_OUTPUT_BUFFERADDR(dev,
+ init_val_tdnr_preview_still.dma_output.buffer_address);
+ IS_TDNR_SET_PARAM_DMA_OUTPUT_MASK(dev,
+ (0xff&0xffffffff));
+ IS_TDNR_SET_PARAM_DMA_OUTPUT_ERR(dev,
+ init_val_tdnr_preview_still.dma_output.err);
+ IS_SET_PARAM_BIT(dev, PARAM_TDNR_DMA_OUTPUT);
+ IS_INC_PARAM_NUM(dev);
+
+ /* SCALER-P Macros */
+ IS_SCALERP_SET_PARAM_CONTROL_CMD(dev,
+ init_val_scalerp_preview_still.control.cmd);
+ IS_SCALERP_SET_PARAM_CONTROL_BYPASS(dev,
+ init_val_scalerp_preview_still.control.bypass);
+ IS_SCALERP_SET_PARAM_CONTROL_ERR(dev,
+ init_val_scalerp_preview_still.control.err);
+ IS_SET_PARAM_BIT(dev, PARAM_SCALERP_CONTROL);
+ IS_INC_PARAM_NUM(dev);
+
+ IS_SCALERP_SET_PARAM_OTF_INPUT_CMD(dev,
+ init_val_scalerp_preview_still.otf_input.cmd);
+ IS_SCALERP_SET_PARAM_OTF_INPUT_WIDTH(dev,
+ init_val_scalerp_preview_still.otf_input.width);
+ IS_SCALERP_SET_PARAM_OTF_INPUT_HEIGHT(dev,
+ init_val_scalerp_preview_still.otf_input.height);
+ IS_SCALERP_SET_PARAM_OTF_INPUT_FORMAT(dev,
+ init_val_scalerp_preview_still.otf_input.format);
+ IS_SCALERP_SET_PARAM_OTF_INPUT_BITWIDTH(dev,
+ init_val_scalerp_preview_still.otf_input.bitwidth);
+ IS_SCALERP_SET_PARAM_OTF_INPUT_ORDER(dev,
+ init_val_scalerp_preview_still.otf_input.order);
+ IS_SCALERP_SET_PARAM_OTF_INPUT_ERR(dev,
+ init_val_scalerp_preview_still.otf_input.err);
+ IS_SET_PARAM_BIT(dev, PARAM_SCALERP_OTF_INPUT);
+ IS_INC_PARAM_NUM(dev);
+
+ IS_SCALERP_SET_PARAM_EFFECT_CMD(dev,
+ init_val_scalerp_preview_still.effect.cmd);
+ IS_SCALERP_SET_PARAM_EFFECT_ERR(dev,
+ init_val_scalerp_preview_still.effect.err);
+ IS_SET_PARAM_BIT(dev, PARAM_SCALERP_IMAGE_EFFECT);
+ IS_INC_PARAM_NUM(dev);
+
+ IS_SCALERP_SET_PARAM_INPUT_CROP_CMD(dev,
+ init_val_scalerp_preview_still.input_crop.cmd);
+ IS_SCALERP_SET_PARAM_INPUT_CROP_POS_X(dev,
+ init_val_scalerp_preview_still.input_crop.pos_x);
+ IS_SCALERP_SET_PARAM_INPUT_CROP_POS_Y(dev,
+ init_val_scalerp_preview_still.input_crop.pos_y);
+ IS_SCALERP_SET_PARAM_INPUT_CROP_WIDTH(dev,
+ init_val_scalerp_preview_still.input_crop.crop_width);
+ IS_SCALERP_SET_PARAM_INPUT_CROP_HEIGHT(dev,
+ init_val_scalerp_preview_still.input_crop.crop_height);
+ IS_SCALERP_SET_PARAM_INPUT_CROP_IN_WIDTH(dev,
+ init_val_scalerp_preview_still.input_crop.in_width);
+ IS_SCALERP_SET_PARAM_INPUT_CROP_IN_HEIGHT(dev,
+ init_val_scalerp_preview_still.input_crop.in_height);
+ IS_SCALERP_SET_PARAM_INPUT_CROP_OUT_WIDTH(dev,
+ init_val_scalerp_preview_still.input_crop.out_width);
+ IS_SCALERP_SET_PARAM_INPUT_CROP_OUT_HEIGHT(dev,
+ init_val_scalerp_preview_still.input_crop.out_height);
+ IS_SCALERP_SET_PARAM_INPUT_CROP_ERR(dev,
+ init_val_scalerp_preview_still.input_crop.err);
+ IS_SET_PARAM_BIT(dev, PARAM_SCALERP_INPUT_CROP);
+ IS_INC_PARAM_NUM(dev);
+
+ IS_SCALERP_SET_PARAM_OUTPUT_CROP_CMD(dev,
+ init_val_scalerp_preview_still.output_crop.cmd);
+ IS_SCALERP_SET_PARAM_OUTPUT_CROP_POS_X(dev,
+ init_val_scalerp_preview_still.output_crop.pos_x);
+ IS_SCALERP_SET_PARAM_OUTPUT_CROP_POS_Y(dev,
+ init_val_scalerp_preview_still.output_crop.pos_y);
+ IS_SCALERP_SET_PARAM_OUTPUT_CROP_CROP_WIDTH(dev,
+ init_val_scalerp_preview_still.output_crop.crop_width);
+ IS_SCALERP_SET_PARAM_OUTPUT_CROP_CROP_HEIGHT(dev,
+ init_val_scalerp_preview_still.output_crop.crop_height);
+ IS_SCALERP_SET_PARAM_OUTPUT_CROPG_FORMAT(dev,
+ init_val_scalerp_preview_still.output_crop.format);
+ IS_SCALERP_SET_PARAM_OUTPUT_CROP_ERR(dev,
+ init_val_scalerp_preview_still.output_crop.err);
+ IS_SET_PARAM_BIT(dev, PARAM_SCALERP_OUTPUT_CROP);
+ IS_INC_PARAM_NUM(dev);
+
+ IS_SCALERP_SET_PARAM_ROTATION_CMD(dev,
+ init_val_scalerp_preview_still.rotation.cmd);
+ IS_SCALERP_SET_PARAM_ROTATION_ERR(dev,
+ init_val_scalerp_preview_still.rotation.err);
+ IS_SET_PARAM_BIT(dev, PARAM_SCALERP_ROTATION);
+ IS_INC_PARAM_NUM(dev);
+
+ IS_SCALERP_SET_PARAM_FLIP_CMD(dev,
+ init_val_scalerp_preview_still.flip.cmd);
+ IS_SCALERP_SET_PARAM_FLIP_ERR(dev,
+ init_val_scalerp_preview_still.flip.err);
+ IS_SET_PARAM_BIT(dev, PARAM_SCALERP_FLIP);
+ IS_INC_PARAM_NUM(dev);
+
+ IS_SCALERP_SET_PARAM_OTF_OUTPUT_CMD(dev,
+ init_val_scalerp_preview_still.otf_output.cmd);
+ IS_SCALERP_SET_PARAM_OTF_OUTPUT_WIDTH(dev,
+ init_val_scalerp_preview_still.otf_output.width);
+ IS_SCALERP_SET_PARAM_OTF_OUTPUT_HEIGHT(dev,
+ init_val_scalerp_preview_still.otf_output.height);
+ IS_SCALERP_SET_PARAM_OTF_OUTPUT_FORMAT(dev,
+ init_val_scalerp_preview_still.otf_output.format);
+ IS_SCALERP_SET_PARAM_OTF_OUTPUT_BITWIDTH(dev,
+ init_val_scalerp_preview_still.otf_output.bitwidth);
+ IS_SCALERP_SET_PARAM_OTF_OUTPUT_ORDER(dev,
+ init_val_scalerp_preview_still.otf_output.order);
+ IS_SCALERP_SET_PARAM_OTF_OUTPUT_ERR(dev,
+ init_val_scalerp_preview_still.otf_output.err);
+ IS_SET_PARAM_BIT(dev, PARAM_SCALERP_OTF_OUTPUT);
+ IS_INC_PARAM_NUM(dev);
+
+ IS_SCALERP_SET_PARAM_DMA_OUTPUT_CMD(dev,
+ init_val_scalerp_preview_still.dma_output.cmd);
+ IS_SCALERP_SET_PARAM_DMA_OUTPUT_WIDTH(dev,
+ init_val_scalerp_preview_still.dma_output.width);
+ IS_SCALERP_SET_PARAM_DMA_OUTPUT_HEIGHT(dev,
+ init_val_scalerp_preview_still.dma_output.height);
+ IS_SCALERP_SET_PARAM_DMA_OUTPUT_FORMAT(dev,
+ init_val_scalerp_preview_still.dma_output.format);
+ IS_SCALERP_SET_PARAM_DMA_OUTPUT_BITWIDTH(dev,
+ init_val_scalerp_preview_still.dma_output.bitwidth);
+ IS_SCALERP_SET_PARAM_DMA_OUTPUT_PLANE(dev,
+ init_val_scalerp_preview_still.dma_output.plane);
+ IS_SCALERP_SET_PARAM_DMA_OUTPUT_ORDER(dev,
+ init_val_scalerp_preview_still.dma_output.order);
+ IS_SCALERP_SET_PARAM_DMA_OUTPUT_BUFFERNUM(dev,
+ init_val_scalerp_preview_still.dma_output.buffer_number);
+ IS_SCALERP_SET_PARAM_DMA_OUTPUT_BUFFERADDR(dev,
+ init_val_scalerp_preview_still.dma_output.buffer_address);
+ IS_SCALERP_SET_PARAM_DMA_OUTPUT_MASK(dev,
+ (0xff&0xffffffff));
+ IS_SCALERP_SET_PARAM_DMA_OUTPUT_ERR(dev,
+ init_val_scalerp_preview_still.dma_output.err);
+ IS_SET_PARAM_BIT(dev, PARAM_SCALERP_DMA_OUTPUT);
+ IS_INC_PARAM_NUM(dev);
+
+ /* FD */
+ IS_FD_SET_PARAM_CONTROL_CMD(dev,
+ init_val_fd_preview_still.control.cmd);
+ IS_FD_SET_PARAM_CONTROL_BYPASS(dev,
+ init_val_fd_preview_still.control.bypass);
+ IS_FD_SET_PARAM_CONTROL_ERR(dev,
+ init_val_fd_preview_still.control.err);
+ IS_SET_PARAM_BIT(dev, PARAM_FD_CONTROL);
+ IS_INC_PARAM_NUM(dev);
+ IS_FD_SET_PARAM_OTF_INPUT_CMD(dev,
+ init_val_fd_preview_still.otf_input.cmd);
+ IS_FD_SET_PARAM_OTF_INPUT_WIDTH(dev,
+ init_val_fd_preview_still.otf_input.width);
+ IS_FD_SET_PARAM_OTF_INPUT_HEIGHT(dev,
+ init_val_fd_preview_still.otf_input.height);
+ IS_FD_SET_PARAM_OTF_INPUT_FORMAT(dev,
+ init_val_fd_preview_still.otf_input.format);
+ IS_FD_SET_PARAM_OTF_INPUT_BITWIDTH(dev,
+ init_val_fd_preview_still.otf_input.bitwidth);
+ IS_FD_SET_PARAM_OTF_INPUT_ORDER(dev,
+ init_val_fd_preview_still.otf_input.order);
+ IS_FD_SET_PARAM_OTF_INPUT_ERR(dev,
+ init_val_fd_preview_still.otf_input.err);
+ IS_SET_PARAM_BIT(dev, PARAM_FD_OTF_INPUT);
+ IS_INC_PARAM_NUM(dev);
+ IS_FD_SET_PARAM_DMA_INPUT_CMD(dev,
+ init_val_fd_preview_still.dma_input.cmd);
+ IS_FD_SET_PARAM_DMA_INPUT_WIDTH(dev,
+ init_val_fd_preview_still.dma_input.width);
+ IS_FD_SET_PARAM_DMA_INPUT_HEIGHT(dev,
+ init_val_fd_preview_still.dma_input.height);
+ IS_FD_SET_PARAM_DMA_INPUT_FORMAT(dev,
+ init_val_fd_preview_still.dma_input.format);
+ IS_FD_SET_PARAM_DMA_INPUT_BITWIDTH(dev,
+ init_val_fd_preview_still.dma_input.bitwidth);
+ IS_FD_SET_PARAM_DMA_INPUT_PLANE(dev,
+ init_val_fd_preview_still.dma_input.plane);
+ IS_FD_SET_PARAM_DMA_INPUT_ORDER(dev,
+ init_val_fd_preview_still.dma_input.order);
+ IS_FD_SET_PARAM_DMA_INPUT_BUFFERNUM(dev,
+ init_val_fd_preview_still.dma_input.buffer_number);
+ IS_FD_SET_PARAM_DMA_INPUT_BUFFERADDR(dev,
+ init_val_fd_preview_still.dma_input.buffer_address);
+ IS_FD_SET_PARAM_DMA_INPUT_ERR(dev,
+ init_val_fd_preview_still.dma_input.err);
+ IS_SET_PARAM_BIT(dev, PARAM_FD_DMA_INPUT);
+ IS_INC_PARAM_NUM(dev);
+ IS_FD_SET_PARAM_FD_CONFIG_CMD(dev,
+ init_val_fd_preview_still.config.cmd);
+ IS_FD_SET_PARAM_FD_CONFIG_MAX_NUMBER(dev,
+ init_val_fd_preview_still.config.max_number);
+ IS_FD_SET_PARAM_FD_CONFIG_ROLL_ANGLE(dev,
+ init_val_fd_preview_still.config.roll_angle);
+ IS_FD_SET_PARAM_FD_CONFIG_YAW_ANGLE(dev,
+ init_val_fd_preview_still.config.yaw_angle);
+ IS_FD_SET_PARAM_FD_CONFIG_SMILE_MODE(dev,
+ init_val_fd_preview_still.config.smile_mode);
+ IS_FD_SET_PARAM_FD_CONFIG_BLINK_MODE(dev,
+ init_val_fd_preview_still.config.blink_mode);
+ IS_FD_SET_PARAM_FD_CONFIG_EYE_DETECT(dev,
+ init_val_fd_preview_still.config.eye_detect);
+ IS_FD_SET_PARAM_FD_CONFIG_MOUTH_DETECT(dev,
+ init_val_fd_preview_still.config.mouth_detect);
+ IS_FD_SET_PARAM_FD_CONFIG_ORIENTATION(dev,
+ init_val_fd_preview_still.config.orientation);
+ IS_FD_SET_PARAM_FD_CONFIG_ORIENTATION_VALUE(dev,
+ init_val_fd_preview_still.config.orientation_value);
+ IS_FD_SET_PARAM_FD_CONFIG_ERR(dev,
+ init_val_fd_preview_still.config.err);
+ IS_SET_PARAM_BIT(dev, PARAM_FD_CONFIG);
+ IS_INC_PARAM_NUM(dev);
+}
+
+int fimc_is_hw_change_size(struct fimc_is_dev *dev)
+{
+ u32 front_width, front_height, back_width, back_height;
+ u32 dis_width, dis_height;
+ u32 crop_width = 0, crop_height = 0, crop_x = 0, crop_y = 0;
+ u32 front_crop_ratio, back_crop_ratio;
+
+ /* ISP */
+ IS_ISP_SET_PARAM_OTF_INPUT_WIDTH(dev,
+ dev->video[FIMC_IS_VIDEO_NUM_SCALERC].frame.width);
+ IS_ISP_SET_PARAM_OTF_INPUT_HEIGHT(dev,
+ dev->video[FIMC_IS_VIDEO_NUM_SCALERC].frame.height);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_OTF_INPUT);
+ IS_INC_PARAM_NUM(dev);
+
+ IS_ISP_SET_PARAM_METERING_WIN_WIDTH(dev,
+ dev->video[FIMC_IS_VIDEO_NUM_SCALERC].frame.width);
+ IS_ISP_SET_PARAM_METERING_WIN_HEIGHT(dev,
+ dev->video[FIMC_IS_VIDEO_NUM_SCALERC].frame.height);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_METERING);
+ IS_INC_PARAM_NUM(dev);
+
+ IS_ISP_SET_PARAM_OTF_OUTPUT_WIDTH(dev,
+ dev->video[FIMC_IS_VIDEO_NUM_SCALERC].frame.width);
+ IS_ISP_SET_PARAM_OTF_OUTPUT_HEIGHT(dev,
+ dev->video[FIMC_IS_VIDEO_NUM_SCALERC].frame.height);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_OTF_OUTPUT);
+ IS_INC_PARAM_NUM(dev);
+
+ IS_ISP_SET_PARAM_DMA_OUTPUT1_WIDTH(dev,
+ dev->video[FIMC_IS_VIDEO_NUM_SCALERC].frame.width);
+ IS_ISP_SET_PARAM_DMA_OUTPUT1_HEIGHT(dev,
+ dev->video[FIMC_IS_VIDEO_NUM_SCALERC].frame.height);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_DMA1_INPUT);
+ IS_INC_PARAM_NUM(dev);
+
+ IS_ISP_SET_PARAM_DMA_OUTPUT2_WIDTH(dev,
+ dev->video[FIMC_IS_VIDEO_NUM_SCALERC].frame.width);
+ IS_ISP_SET_PARAM_DMA_OUTPUT2_HEIGHT(dev,
+ dev->video[FIMC_IS_VIDEO_NUM_SCALERC].frame.height);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_DMA2_INPUT);
+ IS_INC_PARAM_NUM(dev);
+
+ /* DRC */
+ IS_DRC_SET_PARAM_OTF_INPUT_WIDTH(dev,
+ dev->video[FIMC_IS_VIDEO_NUM_SCALERC].frame.width);
+ IS_DRC_SET_PARAM_OTF_INPUT_HEIGHT(dev,
+ dev->video[FIMC_IS_VIDEO_NUM_SCALERC].frame.height);
+ IS_SET_PARAM_BIT(dev, PARAM_DRC_OTF_INPUT);
+ IS_INC_PARAM_NUM(dev);
+
+ IS_DRC_SET_PARAM_DMA_INPUT_WIDTH(dev,
+ dev->video[FIMC_IS_VIDEO_NUM_SCALERC].frame.width);
+ IS_DRC_SET_PARAM_DMA_INPUT_HEIGHT(dev,
+ dev->video[FIMC_IS_VIDEO_NUM_SCALERC].frame.height);
+ IS_SET_PARAM_BIT(dev, PARAM_DRC_DMA_INPUT);
+ IS_INC_PARAM_NUM(dev);
+
+ IS_DRC_SET_PARAM_OTF_OUTPUT_WIDTH(dev,
+ dev->video[FIMC_IS_VIDEO_NUM_SCALERC].frame.width);
+ IS_DRC_SET_PARAM_OTF_OUTPUT_HEIGHT(dev,
+ dev->video[FIMC_IS_VIDEO_NUM_SCALERC].frame.height);
+ IS_SET_PARAM_BIT(dev, PARAM_DRC_OTF_OUTPUT);
+ IS_INC_PARAM_NUM(dev);
+
+ /* ScalerC */
+ front_width = dev->video[FIMC_IS_VIDEO_NUM_SCALERC].frame.width;
+ front_height = dev->video[FIMC_IS_VIDEO_NUM_SCALERC].frame.height;
+
+ back_width = dev->video[FIMC_IS_VIDEO_NUM_SCALERP].frame.width;
+ back_height = dev->video[FIMC_IS_VIDEO_NUM_SCALERP].frame.height;
+
+ IS_SCALERC_SET_PARAM_OTF_INPUT_WIDTH(dev,
+ front_width);
+ IS_SCALERC_SET_PARAM_OTF_INPUT_HEIGHT(dev,
+ front_height);
+ IS_SET_PARAM_BIT(dev, PARAM_SCALERC_OTF_INPUT);
+ IS_INC_PARAM_NUM(dev);
+
+ IS_SCALERC_SET_PARAM_INPUT_CROP_IN_WIDTH(dev,
+ front_width);
+ IS_SCALERC_SET_PARAM_INPUT_CROP_IN_HEIGHT(dev,
+ front_height);
+
+ front_crop_ratio = front_width * 1000 / front_height;
+ back_crop_ratio = back_width * 1000 / back_height;
+
+ if (front_crop_ratio == back_crop_ratio) {
+ crop_width = front_width;
+ crop_height = front_height;
+
+ } else if (front_crop_ratio < back_crop_ratio) {
+ crop_width = front_width;
+ crop_height = (front_width
+ * (1000 * 100 / back_crop_ratio)) / 100;
+ crop_width = ALIGN(crop_width, 8);
+ crop_height = ALIGN(crop_height, 8);
+
+ } else if (front_crop_ratio > back_crop_ratio) {
+ crop_height = front_height;
+ crop_width = (front_height
+ * (back_crop_ratio * 100 / 1000)) / 100 ;
+ crop_width = ALIGN(crop_width, 8);
+ crop_height = ALIGN(crop_height, 8);
+ }
+
+ if (dev->back.dis_on) {
+ dis_width = back_width * 125 / 100;
+ dis_height = back_height * 125 / 100;
+ } else {
+ dis_width = back_width;
+ dis_height = back_height;
+ }
+
+ IS_SCALERC_SET_PARAM_INPUT_CROP_OUT_WIDTH(dev,
+ crop_width);
+ IS_SCALERC_SET_PARAM_INPUT_CROP_OUT_HEIGHT(dev,
+ crop_height);
+
+ dbg("calulate crop size\n");
+ dbg("front w: %d front h: %d\n", front_width, front_height);
+ dbg("dis w: %d dis h: %d\n", dis_width, dis_height);
+ dbg("back w: %d back h: %d\n", back_width, back_height);
+
+ dbg("front_crop_ratio: %d back_crop_ratio: %d\n",
+ front_crop_ratio, back_crop_ratio);
+
+ crop_x = (front_width - crop_width) / 2;
+ crop_y = (front_height - crop_height) / 2;
+ crop_x &= 0xffe;
+ crop_y &= 0xffe;
+
+ dev->sensor.width = front_width;
+ dev->sensor.height = front_height;
+ dev->front.width = front_width;
+ dev->front.height = front_height;
+ dev->back.width = back_width;
+ dev->back.height = back_height;
+ dev->back.dis_width = dis_width;
+ dev->back.dis_height = dis_height;
+
+ dbg("crop w: %d crop h: %d\n", crop_width, crop_height);
+ dbg("crop x: %d crop y: %d\n", crop_x, crop_y);
+
+ IS_SCALERC_SET_PARAM_INPUT_CROP_WIDTH(dev,
+ crop_width);
+ IS_SCALERC_SET_PARAM_INPUT_CROP_HEIGHT(dev,
+ crop_height);
+ IS_SCALERC_SET_PARAM_INPUT_CROP_POS_X(dev,
+ crop_x);
+ IS_SCALERC_SET_PARAM_INPUT_CROP_POS_Y(dev,
+ crop_y);
+
+ IS_SET_PARAM_BIT(dev, PARAM_SCALERC_INPUT_CROP);
+ IS_INC_PARAM_NUM(dev);
+
+ IS_SCALERC_SET_PARAM_OUTPUT_CROP_CROP_WIDTH(dev,
+ dis_width);
+ IS_SCALERC_SET_PARAM_OUTPUT_CROP_CROP_HEIGHT(dev,
+ dis_height);
+ IS_SET_PARAM_BIT(dev, PARAM_SCALERC_OUTPUT_CROP);
+ IS_INC_PARAM_NUM(dev);
+
+ IS_SCALERC_SET_PARAM_OTF_OUTPUT_WIDTH(dev,
+ dis_width);
+ IS_SCALERC_SET_PARAM_OTF_OUTPUT_HEIGHT(dev,
+ dis_height);
+ IS_SET_PARAM_BIT(dev, PARAM_SCALERC_OTF_OUTPUT);
+ IS_INC_PARAM_NUM(dev);
+
+ IS_SCALERC_SET_PARAM_DMA_OUTPUT_WIDTH(dev,
+ front_width);
+ IS_SCALERC_SET_PARAM_DMA_OUTPUT_HEIGHT(dev,
+ front_height);
+ if ((front_width != dis_width) || (front_height != dis_height))
+ IS_SCALERC_SET_PARAM_DMA_OUTPUT_OUTPATH(dev,
+ 2); /* unscaled image */
+ else
+ IS_SCALERC_SET_PARAM_DMA_OUTPUT_OUTPATH(dev,
+ 1); /* scaled image */
+ IS_SET_PARAM_BIT(dev, PARAM_SCALERC_DMA_OUTPUT);
+ IS_INC_PARAM_NUM(dev);
+
+ /* ODC */
+ IS_ODC_SET_PARAM_OTF_INPUT_WIDTH(dev,
+ dis_width);
+ IS_ODC_SET_PARAM_OTF_INPUT_HEIGHT(dev,
+ dis_height);
+ IS_SET_PARAM_BIT(dev, PARAM_ODC_OTF_INPUT);
+ IS_INC_PARAM_NUM(dev);
+
+ IS_ODC_SET_PARAM_OTF_OUTPUT_WIDTH(dev,
+ dis_width);
+ IS_ODC_SET_PARAM_OTF_OUTPUT_HEIGHT(dev,
+ dis_height);
+ IS_SET_PARAM_BIT(dev, PARAM_ODC_OTF_OUTPUT);
+ IS_INC_PARAM_NUM(dev);
+
+ /* DIS */
+ IS_DIS_SET_PARAM_OTF_INPUT_WIDTH(dev,
+ dis_width);
+ IS_DIS_SET_PARAM_OTF_INPUT_HEIGHT(dev,
+ dis_height);
+ IS_SET_PARAM_BIT(dev, PARAM_DIS_OTF_INPUT);
+ IS_INC_PARAM_NUM(dev);
+
+ IS_DIS_SET_PARAM_OTF_OUTPUT_WIDTH(dev,
+ back_width);
+ IS_DIS_SET_PARAM_OTF_OUTPUT_HEIGHT(dev,
+ back_height);
+ IS_SET_PARAM_BIT(dev, PARAM_DIS_OTF_OUTPUT);
+ IS_INC_PARAM_NUM(dev);
+
+ /* 3DNR */
+ IS_TDNR_SET_PARAM_OTF_INPUT_WIDTH(dev,
+ back_width);
+ IS_TDNR_SET_PARAM_OTF_INPUT_HEIGHT(dev,
+ back_height);
+ IS_SET_PARAM_BIT(dev, PARAM_TDNR_OTF_INPUT);
+ IS_INC_PARAM_NUM(dev);
+
+ IS_TDNR_SET_PARAM_OTF_OUTPUT_WIDTH(dev,
+ back_width);
+ IS_TDNR_SET_PARAM_OTF_OUTPUT_HEIGHT(dev,
+ back_height);
+ IS_SET_PARAM_BIT(dev, PARAM_TDNR_OTF_OUTPUT);
+ IS_INC_PARAM_NUM(dev);
+
+ IS_TDNR_SET_PARAM_DMA_OUTPUT_WIDTH(dev,
+ back_width);
+ IS_TDNR_SET_PARAM_DMA_OUTPUT_HEIGHT(dev,
+ back_height);
+ IS_SET_PARAM_BIT(dev, PARAM_TDNR_DMA_OUTPUT);
+ IS_INC_PARAM_NUM(dev);
+
+ /* ScalerP */
+ IS_SCALERP_SET_PARAM_OTF_INPUT_WIDTH(dev,
+ back_width);
+ IS_SCALERP_SET_PARAM_OTF_INPUT_HEIGHT(dev,
+ back_height);
+ IS_SET_PARAM_BIT(dev, PARAM_SCALERP_OTF_INPUT);
+ IS_INC_PARAM_NUM(dev);
+
+ IS_SCALERP_SET_PARAM_INPUT_CROP_IN_WIDTH(dev,
+ back_width);
+ IS_SCALERP_SET_PARAM_INPUT_CROP_IN_HEIGHT(dev,
+ back_height);
+ IS_SCALERP_SET_PARAM_INPUT_CROP_WIDTH(dev,
+ back_width);
+ IS_SCALERP_SET_PARAM_INPUT_CROP_HEIGHT(dev,
+ back_height);
+ IS_SCALERP_SET_PARAM_INPUT_CROP_OUT_WIDTH(dev,
+ dev->video[FIMC_IS_VIDEO_NUM_SCALERP].frame.width);
+ IS_SCALERP_SET_PARAM_INPUT_CROP_OUT_HEIGHT(dev,
+ dev->video[FIMC_IS_VIDEO_NUM_SCALERP].frame.height);
+ IS_SET_PARAM_BIT(dev, PARAM_SCALERP_INPUT_CROP);
+ IS_INC_PARAM_NUM(dev);
+
+ IS_SCALERP_SET_PARAM_OUTPUT_CROP_CROP_WIDTH(dev,
+ dev->video[FIMC_IS_VIDEO_NUM_SCALERP].frame.width);
+ IS_SCALERP_SET_PARAM_OUTPUT_CROP_CROP_HEIGHT(dev,
+ dev->video[FIMC_IS_VIDEO_NUM_SCALERP].frame.height);
+ IS_SET_PARAM_BIT(dev, PARAM_SCALERP_OUTPUT_CROP);
+ IS_INC_PARAM_NUM(dev);
+
+ IS_SCALERP_SET_PARAM_OTF_OUTPUT_WIDTH(dev,
+ dev->video[FIMC_IS_VIDEO_NUM_SCALERP].frame.width);
+ IS_SCALERP_SET_PARAM_OTF_OUTPUT_HEIGHT(dev,
+ dev->video[FIMC_IS_VIDEO_NUM_SCALERP].frame.height);
+ IS_SET_PARAM_BIT(dev, PARAM_SCALERP_OTF_OUTPUT);
+ IS_INC_PARAM_NUM(dev);
+
+ IS_SCALERP_SET_PARAM_DMA_OUTPUT_WIDTH(dev,
+ dev->video[FIMC_IS_VIDEO_NUM_SCALERP].frame.width);
+ IS_SCALERP_SET_PARAM_DMA_OUTPUT_HEIGHT(dev,
+ dev->video[FIMC_IS_VIDEO_NUM_SCALERP].frame.height);
+ IS_SET_PARAM_BIT(dev, PARAM_SCALERP_DMA_OUTPUT);
+ IS_INC_PARAM_NUM(dev);
+
+ /* FD */
+ IS_FD_SET_PARAM_OTF_INPUT_WIDTH(dev,
+ dev->video[FIMC_IS_VIDEO_NUM_SCALERP].frame.width);
+ IS_FD_SET_PARAM_OTF_INPUT_HEIGHT(dev,
+ dev->video[FIMC_IS_VIDEO_NUM_SCALERP].frame.height);
+ IS_SET_PARAM_BIT(dev, PARAM_FD_OTF_INPUT);
+ IS_INC_PARAM_NUM(dev);
+
+ return 0;
+}
+
+void fimc_is_hw_set_default_size(struct fimc_is_dev *dev, int sensor_id)
+{
+ switch (sensor_id) {
+ case SENSOR_NAME_S5K6A3:
+ dev->video[FIMC_IS_VIDEO_NUM_SCALERC].frame.width =
+ DEFAULT_6A3_STILLSHOT_WIDTH;
+ dev->video[FIMC_IS_VIDEO_NUM_SCALERC].frame.height =
+ DEFAULT_6A3_STILLSHOT_HEIGHT;
+ dev->video[FIMC_IS_VIDEO_NUM_SCALERP].frame.width =
+ DEFAULT_6A3_PREVIEW_WIDTH;
+ dev->video[FIMC_IS_VIDEO_NUM_SCALERP].frame.height =
+ DEFAULT_6A3_PREVIEW_HEIGHT;
+ dev->video[FIMC_IS_VIDEO_NUM_3DNR].frame.width =
+ DEFAULT_6A3_VIDEO_WIDTH;
+ dev->video[FIMC_IS_VIDEO_NUM_3DNR].frame.height =
+ DEFAULT_6A3_VIDEO_HEIGHT;
+ break;
+ case SENSOR_NAME_S5K4E5:
+ dev->video[FIMC_IS_VIDEO_NUM_SCALERC].frame.width =
+ DEFAULT_4E5_STILLSHOT_WIDTH;
+ dev->video[FIMC_IS_VIDEO_NUM_SCALERC].frame.height =
+ DEFAULT_4E5_STILLSHOT_HEIGHT;
+ dev->video[FIMC_IS_VIDEO_NUM_SCALERP].frame.width =
+ DEFAULT_4E5_PREVIEW_WIDTH;
+ dev->video[FIMC_IS_VIDEO_NUM_SCALERP].frame.height =
+ DEFAULT_4E5_PREVIEW_HEIGHT;
+ dev->video[FIMC_IS_VIDEO_NUM_3DNR].frame.width =
+ DEFAULT_4E5_VIDEO_WIDTH;
+ dev->video[FIMC_IS_VIDEO_NUM_3DNR].frame.height =
+ DEFAULT_4E5_VIDEO_HEIGHT;
+ break;
+ default:
+ dev->video[FIMC_IS_VIDEO_NUM_SCALERC].frame.width =
+ DEFAULT_CAPTURE_STILL_WIDTH;
+ dev->video[FIMC_IS_VIDEO_NUM_SCALERC].frame.height =
+ DEFAULT_CAPTURE_STILL_HEIGHT;
+ dev->video[FIMC_IS_VIDEO_NUM_SCALERP].frame.width =
+ DEFAULT_PREVIEW_STILL_WIDTH;
+ dev->video[FIMC_IS_VIDEO_NUM_SCALERP].frame.height =
+ DEFAULT_PREVIEW_STILL_HEIGHT;
+ dev->video[FIMC_IS_VIDEO_NUM_3DNR].frame.width =
+ DEFAULT_CAPTURE_VIDEO_WIDTH;
+ dev->video[FIMC_IS_VIDEO_NUM_3DNR].frame.height =
+ DEFAULT_CAPTURE_VIDEO_HEIGHT;
+ break;
+ }
+}
diff --git a/drivers/media/video/exynos/fimc-is-mc/fimc-is-helper.h b/drivers/media/video/exynos/fimc-is-mc/fimc-is-helper.h
new file mode 100644
index 0000000..906da02
--- /dev/null
+++ b/drivers/media/video/exynos/fimc-is-mc/fimc-is-helper.h
@@ -0,0 +1,81 @@
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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.
+ */
+
+#ifndef FIMC_IS_HELPER_H
+#define FIMC_IS_HELPER_H
+
+#include "fimc-is-core.h"
+
+/* Default setting values */
+#define DEFAULT_PREVIEW_STILL_WIDTH (1280) /* sensor margin : 16 */
+#define DEFAULT_PREVIEW_STILL_HEIGHT (720) /* sensor margin : 12 */
+#define DEFAULT_CAPTURE_VIDEO_WIDTH (1920)
+#define DEFAULT_CAPTURE_VIDEO_HEIGHT (1080)
+#define DEFAULT_CAPTURE_STILL_WIDTH (2560)
+#define DEFAULT_CAPTURE_STILL_HEIGHT (1920)
+#define DEFAULT_CAPTURE_STILL_CROP_WIDTH (2560)
+#define DEFAULT_CAPTURE_STILL_CROP_HEIGHT (1440)
+#define DEFAULT_PREVIEW_VIDEO_WIDTH (640)
+#define DEFAULT_PREVIEW_VIDEO_HEIGHT (480)
+
+#define DEFAULT_4E5_PREVIEW_WIDTH (1920) /* sensor margin : 16 */
+#define DEFAULT_4E5_PREVIEW_HEIGHT (1080) /* sensor margin : 12 */
+#define DEFAULT_4E5_VIDEO_WIDTH (1920)
+#define DEFAULT_4E5_VIDEO_HEIGHT (1080)
+#define DEFAULT_4E5_STILLSHOT_WIDTH (2560)
+#define DEFAULT_4E5_STILLSHOT_HEIGHT (1920)
+
+#define DEFAULT_6A3_PREVIEW_WIDTH (1280) /* sensor margin : 16 */
+#define DEFAULT_6A3_PREVIEW_HEIGHT (720) /* sensor margin : 12 */
+#define DEFAULT_6A3_VIDEO_WIDTH (1280)
+#define DEFAULT_6A3_VIDEO_HEIGHT (720)
+#define DEFAULT_6A3_STILLSHOT_WIDTH (1280)
+#define DEFAULT_6A3_STILLSHOT_HEIGHT (720)
+
+#define DEFAULT_PREVIEW_STILL_FRAMERATE (30)
+#define DEFAULT_CAPTURE_STILL_FRAMERATE (15)
+#define DEFAULT_PREVIEW_VIDEO_FRAMERATE (30)
+#define DEFAULT_CAPTURE_VIDEO_FRAMERATE (30)
+
+int fimc_is_fw_clear_irq2(struct fimc_is_dev *dev);
+int fimc_is_fw_clear_irq1_all(struct fimc_is_dev *dev);
+int fimc_is_fw_clear_irq1(struct fimc_is_dev *dev, unsigned int intr_pos);
+void fimc_is_hw_set_sensor_num(struct fimc_is_dev *dev);
+void fimc_is_hw_get_setfile_addr(struct fimc_is_dev *dev);
+void fimc_is_hw_load_setfile(struct fimc_is_dev *dev);
+int fimc_is_hw_get_sensor_num(struct fimc_is_dev *dev);
+int fimc_is_hw_set_param(struct fimc_is_dev *dev);
+int fimc_is_hw_update_bufmask(struct fimc_is_dev *dev, unsigned int dev_num);
+int fimc_is_hw_get_param(struct fimc_is_dev *dev, u16 offset);
+void fimc_is_hw_set_intgr0_gd0(struct fimc_is_dev *dev);
+int fimc_is_hw_wait_intsr0_intsd0(struct fimc_is_dev *dev);
+int fimc_is_hw_wait_intmsr0_intmsd0(struct fimc_is_dev *dev);
+void fimc_is_hw_a5_power(struct fimc_is_dev *dev, int on);
+int fimc_is_hw_a5_power_on(struct fimc_is_dev *dev);
+int fimc_is_hw_a5_power_off(struct fimc_is_dev *dev);
+void fimc_is_hw_open_sensor(struct fimc_is_dev *dev, u32 id, u32 sensor_index);
+void fimc_is_hw_set_stream(struct fimc_is_dev *dev, int on);
+void fimc_is_hw_set_debug_level(struct fimc_is_dev *dev,
+ int target, int module, int level);
+void fimc_is_hw_set_init(struct fimc_is_dev *dev);
+void fimc_is_hw_change_mode(struct fimc_is_dev *dev, int val);
+void fimc_is_hw_set_lite(struct fimc_is_dev *dev, u32 width, u32 height);
+void fimc_is_hw_diable_wdt(struct fimc_is_dev *dev);
+void fimc_is_hw_set_low_poweroff(struct fimc_is_dev *dev, int on);
+void fimc_is_hw_subip_poweroff(struct fimc_is_dev *dev);
+int fimc_is_fw_clear_insr1(struct fimc_is_dev *dev);
+int fimc_is_hw_get_sensor_type(enum exynos5_sensor_id sensor_id,
+ enum exynos5_flite_id flite_id);
+int fimc_is_hw_get_sensor_max_framerate(struct fimc_is_dev *dev);
+int fimc_is_hw_change_size(struct fimc_is_dev *dev);
+void fimc_is_hw_set_default_size(struct fimc_is_dev *dev, int sensor_id);
+#endif
+
diff --git a/drivers/media/video/exynos/fimc-is-mc/fimc-is-misc.c b/drivers/media/video/exynos/fimc-is-mc/fimc-is-misc.c
new file mode 100644
index 0000000..773a2ba
--- /dev/null
+++ b/drivers/media/video/exynos/fimc-is-mc/fimc-is-misc.c
@@ -0,0 +1,3319 @@
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ * exynos5 fimc-is misc functions(mipi, fimc-lite control)
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/clk.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/memory.h>
+#include <linux/regulator/consumer.h>
+#include <linux/pm_runtime.h>
+#include <linux/videodev2.h>
+#include <linux/jiffies.h>
+
+#include <media/v4l2-subdev.h>
+#include <media/exynos_fimc_is.h>
+#include <linux/videodev2_exynos_camera.h>
+#include <linux/gpio.h>
+#include <plat/gpio-cfg.h>
+#include <mach/map.h>
+#include <mach/regs-clock.h>
+
+#include "fimc-is-core.h"
+#include "fimc-is-helper.h"
+#include "fimc-is-param.h"
+#include "fimc-is-cmd.h"
+#include "fimc-is-regs.h"
+#include "fimc-is-err.h"
+#include "fimc-is-misc.h"
+
+/* PMU for FIMC-IS*/
+#define FIMCLITE0_REG_BASE (S5P_VA_FIMCLITE0) /* phy : 0x13c0_0000 */
+#define FIMCLITE1_REG_BASE (S5P_VA_FIMCLITE1) /* phy : 0x13c1_0000 */
+#define MIPICSI0_REG_BASE (S5P_VA_MIPICSI0) /* phy : 0x13c2_0000 */
+#define MIPICSI1_REG_BASE (S5P_VA_MIPICSI1) /* phy : 0x13c3_0000 */
+#define FIMCLITE2_REG_BASE (S5P_VA_FIMCLITE2) /* phy : 0x13c9_0000 */
+
+#define FLITE_MAX_RESET_READY_TIME (20) /* 100ms */
+#define FLITE_MAX_WIDTH_SIZE (8192)
+#define FLITE_MAX_HEIGHT_SIZE (8192)
+
+
+/*FIMCLite*/
+/* Camera Source size */
+#define FLITE_REG_CISRCSIZE (0x00)
+#define FLITE_REG_CISRCSIZE_SIZE_H(x) ((x) << 16)
+#define FLITE_REG_CISRCSIZE_SIZE_V(x) ((x) << 0)
+#define FLITE_REG_CISRCSIZE_ORDER422_IN_YCBYCR (0 << 14)
+#define FLITE_REG_CISRCSIZE_ORDER422_IN_YCRYCB (1 << 14)
+#define FLITE_REG_CISRCSIZE_ORDER422_IN_CBYCRY (2 << 14)
+#define FLITE_REG_CISRCSIZE_ORDER422_IN_CRYCBY (3 << 14)
+
+/* Global control */
+#define FLITE_REG_CIGCTRL 0x04
+#define FLITE_REG_CIGCTRL_YUV422_1P (0x1E << 24)
+#define FLITE_REG_CIGCTRL_RAW8 (0x2A << 24)
+#define FLITE_REG_CIGCTRL_RAW10 (0x2B << 24)
+#define FLITE_REG_CIGCTRL_RAW12 (0x2C << 24)
+#define FLITE_REG_CIGCTRL_RAW14 (0x2D << 24)
+
+/* User defined formats. x = 0...0xF. */
+#define FLITE_REG_CIGCTRL_USER(x) (0x30 + x - 1)
+#define FLITE_REG_CIGCTRL_SHADOWMASK_DISABLE (1 << 21)
+#define FLITE_REG_CIGCTRL_ODMA_DISABLE (1 << 20)
+#define FLITE_REG_CIGCTRL_SWRST_REQ (1 << 19)
+#define FLITE_REG_CIGCTRL_SWRST_RDY (1 << 18)
+#define FLITE_REG_CIGCTRL_SWRST (1 << 17)
+#define FLITE_REG_CIGCTRL_TEST_PATTERN_COLORBAR (1 << 15)
+#define FLITE_REG_CIGCTRL_INVPOLPCLK (1 << 14)
+#define FLITE_REG_CIGCTRL_INVPOLVSYNC (1 << 13)
+#define FLITE_REG_CIGCTRL_INVPOLHREF (1 << 12)
+#define FLITE_REG_CIGCTRL_IRQ_LASTEN0_ENABLE (0 << 8)
+#define FLITE_REG_CIGCTRL_IRQ_LASTEN0_DISABLE (1 << 8)
+#define FLITE_REG_CIGCTRL_IRQ_ENDEN0_ENABLE (0 << 7)
+#define FLITE_REG_CIGCTRL_IRQ_ENDEN0_DISABLE (1 << 7)
+#define FLITE_REG_CIGCTRL_IRQ_STARTEN0_ENABLE (0 << 6)
+#define FLITE_REG_CIGCTRL_IRQ_STARTEN0_DISABLE (1 << 6)
+#define FLITE_REG_CIGCTRL_IRQ_OVFEN0_ENABLE (0 << 5)
+#define FLITE_REG_CIGCTRL_IRQ_OVFEN0_DISABLE (1 << 5)
+#define FLITE_REG_CIGCTRL_SELCAM_MIPI (1 << 3)
+
+/* Image Capture Enable */
+#define FLITE_REG_CIIMGCPT (0x08)
+#define FLITE_REG_CIIMGCPT_IMGCPTEN (1 << 31)
+#define FLITE_REG_CIIMGCPT_CPT_FREN (1 << 25)
+#define FLITE_REG_CIIMGCPT_CPT_FRPTR(x) ((x) << 19)
+#define FLITE_REG_CIIMGCPT_CPT_MOD_FRCNT (1 << 18)
+#define FLITE_REG_CIIMGCPT_CPT_MOD_FREN (0 << 18)
+#define FLITE_REG_CIIMGCPT_CPT_FRCNT(x) ((x) << 10)
+
+/* Capture Sequence */
+#define FLITE_REG_CICPTSEQ (0x0C)
+#define FLITE_REG_CPT_FRSEQ(x) ((x) << 0)
+
+/* Camera Window Offset */
+#define FLITE_REG_CIWDOFST (0x10)
+#define FLITE_REG_CIWDOFST_WINOFSEN (1 << 31)
+#define FLITE_REG_CIWDOFST_CLROVIY (1 << 31)
+#define FLITE_REG_CIWDOFST_WINHOROFST(x) ((x) << 16)
+#define FLITE_REG_CIWDOFST_HOROFF_MASK (0x1fff << 16)
+#define FLITE_REG_CIWDOFST_CLROVFICB (1 << 15)
+#define FLITE_REG_CIWDOFST_CLROVFICR (1 << 14)
+#define FLITE_REG_CIWDOFST_WINVEROFST(x) ((x) << 0)
+#define FLITE_REG_CIWDOFST_VEROFF_MASK (0x1fff << 0)
+
+/* Cmaera Window Offset2 */
+#define FLITE_REG_CIWDOFST2 (0x14)
+#define FLITE_REG_CIWDOFST2_WINHOROFST2(x) ((x) << 16)
+#define FLITE_REG_CIWDOFST2_WINVEROFST2(x) ((x) << 0)
+
+/* Camera Output DMA Format */
+#define FLITE_REG_CIODMAFMT (0x18)
+#define FLITE_REG_CIODMAFMT_1D_DMA (1 << 15)
+#define FLITE_REG_CIODMAFMT_2D_DMA (0 << 15)
+#define FLITE_REG_CIODMAFMT_PACK12 (1 << 14)
+#define FLITE_REG_CIODMAFMT_NORMAL (0 << 14)
+#define FLITE_REG_CIODMAFMT_CRYCBY (0 << 4)
+#define FLITE_REG_CIODMAFMT_CBYCRY (1 << 4)
+#define FLITE_REG_CIODMAFMT_YCRYCB (2 << 4)
+#define FLITE_REG_CIODMAFMT_YCBYCR (3 << 4)
+
+/* Camera Output Canvas */
+#define FLITE_REG_CIOCAN (0x20)
+#define FLITE_REG_CIOCAN_OCAN_V(x) ((x) << 16)
+#define FLITE_REG_CIOCAN_OCAN_H(x) ((x) << 0)
+
+/* Camera Output DMA Offset */
+#define FLITE_REG_CIOOFF (0x24)
+#define FLITE_REG_CIOOFF_OOFF_V(x) ((x) << 16)
+#define FLITE_REG_CIOOFF_OOFF_H(x) ((x) << 0)
+
+/* Camera Output DMA Address */
+#define FLITE_REG_CIOSA (0x30)
+#define FLITE_REG_CIOSA_OSA(x) ((x) << 0)
+
+/* Camera Status */
+#define FLITE_REG_CISTATUS (0x40)
+#define FLITE_REG_CISTATUS_MIPI_VVALID (1 << 22)
+#define FLITE_REG_CISTATUS_MIPI_HVALID (1 << 21)
+#define FLITE_REG_CISTATUS_MIPI_DVALID (1 << 20)
+#define FLITE_REG_CISTATUS_ITU_VSYNC (1 << 14)
+#define FLITE_REG_CISTATUS_ITU_HREFF (1 << 13)
+#define FLITE_REG_CISTATUS_OVFIY (1 << 10)
+#define FLITE_REG_CISTATUS_OVFICB (1 << 9)
+#define FLITE_REG_CISTATUS_OVFICR (1 << 8)
+#define FLITE_REG_CISTATUS_IRQ_SRC_OVERFLOW (1 << 7)
+#define FLITE_REG_CISTATUS_IRQ_SRC_LASTCAPEND (1 << 6)
+#define FLITE_REG_CISTATUS_IRQ_SRC_FRMSTART (1 << 5)
+#define FLITE_REG_CISTATUS_IRQ_SRC_FRMEND (1 << 4)
+#define FLITE_REG_CISTATUS_IRQ_CAM (1 << 0)
+#define FLITE_REG_CISTATUS_IRQ_MASK (0xf << 4)
+
+/* Camera Status2 */
+#define FLITE_REG_CISTATUS2 (0x44)
+#define FLITE_REG_CISTATUS2_LASTCAPEND (1 << 1)
+#define FLITE_REG_CISTATUS2_FRMEND (1 << 0)
+
+/* Qos Threshold */
+#define FLITE_REG_CITHOLD (0xF0)
+#define FLITE_REG_CITHOLD_W_QOS_EN (1 << 30)
+#define FLITE_REG_CITHOLD_WTH_QOS(x) ((x) << 0)
+
+/* Camera General Purpose */
+#define FLITE_REG_CIGENERAL (0xFC)
+#define FLITE_REG_CIGENERAL_CAM_A (0 << 0)
+#define FLITE_REG_CIGENERAL_CAM_B (1 << 0)
+
+
+/*MIPI*/
+/* CSIS global control */
+#define S5PCSIS_CTRL (0x00)
+#define S5PCSIS_CTRL_DPDN_DEFAULT (0 << 31)
+#define S5PCSIS_CTRL_DPDN_SWAP (1 << 31)
+#define S5PCSIS_CTRL_ALIGN_32BIT (1 << 20)
+#define S5PCSIS_CTRL_UPDATE_SHADOW (1 << 16)
+#define S5PCSIS_CTRL_WCLK_EXTCLK (1 << 8)
+#define S5PCSIS_CTRL_RESET (1 << 4)
+#define S5PCSIS_CTRL_ENABLE (1 << 0)
+
+/* D-PHY control */
+#define S5PCSIS_DPHYCTRL (0x04)
+#define S5PCSIS_DPHYCTRL_HSS_MASK (0x1f << 27)
+#define S5PCSIS_DPHYCTRL_ENABLE (0x7 << 0)
+
+#define S5PCSIS_CONFIG (0x08)
+#define S5PCSIS_CFG_FMT_YCBCR422_8BIT (0x1e << 2)
+#define S5PCSIS_CFG_FMT_RAW8 (0x2a << 2)
+#define S5PCSIS_CFG_FMT_RAW10 (0x2b << 2)
+#define S5PCSIS_CFG_FMT_RAW12 (0x2c << 2)
+/* User defined formats, x = 1...4 */
+#define S5PCSIS_CFG_FMT_USER(x) ((0x30 + x - 1) << 2)
+#define S5PCSIS_CFG_FMT_MASK (0x3f << 2)
+#define S5PCSIS_CFG_NR_LANE_MASK (3)
+
+/* Interrupt mask. */
+#define S5PCSIS_INTMSK (0x10)
+#define S5PCSIS_INTMSK_EN_ALL (0xfc00103f)
+#define S5PCSIS_INTSRC (0x14)
+
+/* Pixel resolution */
+#define S5PCSIS_RESOL (0x2c)
+#define CSIS_MAX_PIX_WIDTH (0xffff)
+#define CSIS_MAX_PIX_HEIGHT (0xffff)
+
+static void flite_hw_set_cam_source_size(unsigned long flite_reg_base,
+ struct flite_frame *f_frame)
+{
+ u32 cfg = 0;
+
+ cfg = readl(flite_reg_base + FLITE_REG_CISRCSIZE);
+
+ cfg |= FLITE_REG_CISRCSIZE_SIZE_H(f_frame->o_width);
+ cfg |= FLITE_REG_CISRCSIZE_SIZE_V(f_frame->o_height);
+
+ writel(cfg, flite_reg_base + FLITE_REG_CISRCSIZE);
+
+ cfg = readl(flite_reg_base + FLITE_REG_CIOCAN);
+ cfg |= FLITE_REG_CIOCAN_OCAN_H(f_frame->o_width);
+ cfg |= FLITE_REG_CIOCAN_OCAN_V(f_frame->o_height);
+
+ writel(cfg, flite_reg_base + FLITE_REG_CIOCAN);
+}
+
+static void flite_hw_set_cam_channel(unsigned long flite_reg_base)
+{
+ u32 cfg = 0;
+
+ if (flite_reg_base == (unsigned long)FIMCLITE0_REG_BASE) {
+ cfg = FLITE_REG_CIGENERAL_CAM_A;
+ writel(cfg, FIMCLITE0_REG_BASE + FLITE_REG_CIGENERAL);
+ writel(cfg, FIMCLITE1_REG_BASE + FLITE_REG_CIGENERAL);
+ writel(cfg, FIMCLITE2_REG_BASE + FLITE_REG_CIGENERAL);
+ } else {
+ cfg = FLITE_REG_CIGENERAL_CAM_B;
+ writel(cfg, FIMCLITE0_REG_BASE + FLITE_REG_CIGENERAL);
+ writel(cfg, FIMCLITE1_REG_BASE + FLITE_REG_CIGENERAL);
+ writel(cfg, FIMCLITE2_REG_BASE + FLITE_REG_CIGENERAL);
+ }
+}
+
+static void flite_hw_set_capture_start(unsigned long flite_reg_base)
+{
+ u32 cfg = 0;
+
+ cfg = readl(flite_reg_base + FLITE_REG_CIIMGCPT);
+ cfg |= FLITE_REG_CIIMGCPT_IMGCPTEN;
+
+ writel(cfg, flite_reg_base + FLITE_REG_CIIMGCPT);
+}
+
+static void flite_hw_set_capture_stop(unsigned long flite_reg_base)
+{
+ u32 cfg = 0;
+
+ cfg = readl(flite_reg_base + FLITE_REG_CIIMGCPT);
+ cfg &= ~FLITE_REG_CIIMGCPT_IMGCPTEN;
+
+ writel(cfg, flite_reg_base + FLITE_REG_CIIMGCPT);
+}
+
+static int flite_hw_set_source_format(unsigned long flite_reg_base)
+{
+ u32 cfg = 0;
+
+ cfg = readl(flite_reg_base + FLITE_REG_CIGCTRL);
+ cfg |= FLITE_REG_CIGCTRL_RAW10;
+ writel(cfg, flite_reg_base + FLITE_REG_CIGCTRL);
+
+ return 0;
+}
+
+static void flite_hw_set_output_dma(unsigned long flite_reg_base, bool enable)
+{
+ u32 cfg = 0;
+ cfg = readl(flite_reg_base + FLITE_REG_CIGCTRL);
+
+ if (enable)
+ cfg &= ~FLITE_REG_CIGCTRL_ODMA_DISABLE;
+ else
+ cfg |= FLITE_REG_CIGCTRL_ODMA_DISABLE;
+
+ writel(cfg, flite_reg_base + FLITE_REG_CIGCTRL);
+}
+
+/* will use for pattern generation testing
+static void flite_hw_set_test_pattern_enable(void)
+{
+ u32 cfg = 0;
+ cfg = readl(flite_reg_base + FLITE_REG_CIGCTRL);
+ cfg |= FLITE_REG_CIGCTRL_TEST_PATTERN_COLORBAR;
+
+ writel(cfg, flite_reg_base + FLITE_REG_CIGCTRL);
+}
+*/
+
+static void flite_hw_set_config_irq(unsigned long flite_reg_base)
+{
+ u32 cfg = 0;
+ cfg = readl(flite_reg_base + FLITE_REG_CIGCTRL);
+ cfg &= ~(FLITE_REG_CIGCTRL_INVPOLPCLK | FLITE_REG_CIGCTRL_INVPOLVSYNC
+ | FLITE_REG_CIGCTRL_INVPOLHREF);
+
+ writel(cfg, flite_reg_base + FLITE_REG_CIGCTRL);
+}
+
+static void flite_hw_set_interrupt_source(unsigned long flite_reg_base)
+{
+ u32 cfg = 0;
+ cfg = readl(flite_reg_base + FLITE_REG_CIGCTRL);
+ cfg |= FLITE_REG_CIGCTRL_IRQ_LASTEN0_ENABLE;
+
+ writel(cfg, flite_reg_base + FLITE_REG_CIGCTRL);
+}
+
+static void flite_hw_set_interrupt_starten0_disable
+ (unsigned long flite_reg_base)
+{
+ u32 cfg = 0;
+ cfg = readl(flite_reg_base + FLITE_REG_CIGCTRL);
+ cfg |= FLITE_REG_CIGCTRL_IRQ_STARTEN0_DISABLE;
+
+ writel(cfg, flite_reg_base + FLITE_REG_CIGCTRL);
+}
+
+static void flite_hw_set_camera_type(unsigned long flite_reg_base)
+{
+ u32 cfg = 0;
+ cfg = readl(flite_reg_base + FLITE_REG_CIGCTRL);
+
+ cfg |= FLITE_REG_CIGCTRL_SELCAM_MIPI;
+
+ writel(cfg, flite_reg_base + FLITE_REG_CIGCTRL);
+}
+
+static void flite_hw_set_window_offset(unsigned long flite_reg_base,
+ struct flite_frame *f_frame)
+{
+ u32 cfg = 0;
+ u32 hoff2, voff2;
+
+ cfg = readl(flite_reg_base + FLITE_REG_CIWDOFST);
+ cfg &= ~(FLITE_REG_CIWDOFST_HOROFF_MASK |
+ FLITE_REG_CIWDOFST_VEROFF_MASK);
+ cfg |= FLITE_REG_CIWDOFST_WINOFSEN |
+ FLITE_REG_CIWDOFST_WINHOROFST(f_frame->offs_h) |
+ FLITE_REG_CIWDOFST_WINVEROFST(f_frame->offs_v);
+
+ writel(cfg, flite_reg_base + FLITE_REG_CIWDOFST);
+
+ hoff2 = f_frame->o_width - f_frame->width - f_frame->offs_h;
+ voff2 = f_frame->o_height - f_frame->height - f_frame->offs_v;
+ cfg = FLITE_REG_CIWDOFST2_WINHOROFST2(hoff2) |
+ FLITE_REG_CIWDOFST2_WINVEROFST2(voff2);
+
+ writel(cfg, flite_reg_base + FLITE_REG_CIWDOFST2);
+}
+
+static void flite_hw_set_last_capture_end_clear(unsigned long flite_reg_base)
+{
+ u32 cfg = 0;
+
+ cfg = readl(flite_reg_base + FLITE_REG_CISTATUS2);
+ cfg &= ~FLITE_REG_CISTATUS2_LASTCAPEND;
+
+ writel(cfg, flite_reg_base + FLITE_REG_CISTATUS2);
+}
+
+static void s5pcsis_enable_interrupts(unsigned long mipi_reg_base, bool on)
+{
+ u32 val = readl(mipi_reg_base + S5PCSIS_INTMSK);
+
+ val = on ? val | S5PCSIS_INTMSK_EN_ALL :
+ val & ~S5PCSIS_INTMSK_EN_ALL;
+ writel(val, mipi_reg_base + S5PCSIS_INTMSK);
+}
+
+static void s5pcsis_reset(unsigned long mipi_reg_base)
+{
+ u32 val = readl(mipi_reg_base + S5PCSIS_CTRL);
+
+ writel(val | S5PCSIS_CTRL_RESET, mipi_reg_base + S5PCSIS_CTRL);
+ udelay(10);
+}
+
+static void s5pcsis_system_enable(unsigned long mipi_reg_base, int on)
+{
+ u32 val;
+
+ val = readl(mipi_reg_base + S5PCSIS_CTRL);
+ if (on) {
+ val |= S5PCSIS_CTRL_ENABLE;
+ val |= S5PCSIS_CTRL_WCLK_EXTCLK;
+ } else
+ val &= ~S5PCSIS_CTRL_ENABLE;
+ writel(val, mipi_reg_base + S5PCSIS_CTRL);
+
+ val = readl(mipi_reg_base + S5PCSIS_DPHYCTRL);
+ if (on)
+ val |= S5PCSIS_DPHYCTRL_ENABLE;
+ else
+ val &= ~S5PCSIS_DPHYCTRL_ENABLE;
+ writel(val, mipi_reg_base + S5PCSIS_DPHYCTRL);
+}
+
+/* Called with the state.lock mutex held */
+static void __s5pcsis_set_format(unsigned long mipi_reg_base,
+ struct flite_frame *f_frame)
+{
+ u32 val;
+
+ /* Color format */
+ val = readl(mipi_reg_base + S5PCSIS_CONFIG);
+ val = (val & ~S5PCSIS_CFG_FMT_MASK) | S5PCSIS_CFG_FMT_RAW10;
+ writel(val, mipi_reg_base + S5PCSIS_CONFIG);
+
+ /* Pixel resolution */
+ val = (f_frame->o_width << 16) | f_frame->o_height;
+ writel(val, mipi_reg_base + S5PCSIS_RESOL);
+}
+
+static void s5pcsis_set_hsync_settle(unsigned long mipi_reg_base)
+{
+ u32 val = readl(mipi_reg_base + S5PCSIS_DPHYCTRL);
+
+ val = (val & ~S5PCSIS_DPHYCTRL_HSS_MASK) | (0x6 << 28);
+ writel(val, mipi_reg_base + S5PCSIS_DPHYCTRL);
+}
+
+static void s5pcsis_set_params(unsigned long mipi_reg_base,
+ struct flite_frame *f_frame)
+{
+ u32 val;
+
+ val = readl(mipi_reg_base + S5PCSIS_CONFIG);
+ val = (val & ~S5PCSIS_CFG_NR_LANE_MASK) | (2 - 1);
+ writel(val, mipi_reg_base + S5PCSIS_CONFIG);
+
+ __s5pcsis_set_format(mipi_reg_base, f_frame);
+ s5pcsis_set_hsync_settle(mipi_reg_base);
+
+ val = readl(mipi_reg_base + S5PCSIS_CTRL);
+ val &= ~S5PCSIS_CTRL_ALIGN_32BIT;
+
+ /* Not using external clock. */
+ val &= ~S5PCSIS_CTRL_WCLK_EXTCLK;
+
+ writel(val, mipi_reg_base + S5PCSIS_CTRL);
+
+ /* Update the shadow register. */
+ val = readl(mipi_reg_base + S5PCSIS_CTRL);
+ writel(val | S5PCSIS_CTRL_UPDATE_SHADOW, mipi_reg_base + S5PCSIS_CTRL);
+}
+
+int start_fimc_lite(int channel, struct flite_frame *f_frame)
+{
+ unsigned long base_reg = (unsigned long)FIMCLITE0_REG_BASE;
+
+ if (channel == FLITE_ID_A)
+ base_reg = (unsigned long)FIMCLITE0_REG_BASE;
+ else if (channel == FLITE_ID_B)
+ base_reg = (unsigned long)FIMCLITE1_REG_BASE;
+
+ flite_hw_set_cam_channel(base_reg);
+ flite_hw_set_cam_source_size(base_reg, f_frame);
+ flite_hw_set_camera_type(base_reg);
+ flite_hw_set_source_format(base_reg);
+ flite_hw_set_output_dma(base_reg, false);
+
+ flite_hw_set_interrupt_source(base_reg);
+ flite_hw_set_interrupt_starten0_disable(base_reg);
+ flite_hw_set_config_irq(base_reg);
+ flite_hw_set_window_offset(base_reg, f_frame);
+ /* flite_hw_set_test_pattern_enable(); */
+
+ flite_hw_set_last_capture_end_clear(base_reg);
+ flite_hw_set_capture_start(base_reg);
+
+ return 0;
+}
+
+int stop_fimc_lite(int channel)
+{
+ unsigned long base_reg = (unsigned long)FIMCLITE0_REG_BASE;
+
+ if (channel == FLITE_ID_A)
+ base_reg = (unsigned long)FIMCLITE0_REG_BASE;
+ else if (channel == FLITE_ID_B)
+ base_reg = (unsigned long)FIMCLITE1_REG_BASE;
+
+ flite_hw_set_capture_stop(base_reg);
+ return 0;
+}
+
+int enable_mipi(void)
+{
+ void __iomem *addr;
+ u32 cfg;
+
+ addr = S5P_MIPI_DPHY_CONTROL(0);
+
+ cfg = __raw_readl(addr);
+ cfg = (cfg | S5P_MIPI_DPHY_SRESETN);
+ __raw_writel(cfg, addr);
+
+ if (1) {
+ cfg |= S5P_MIPI_DPHY_ENABLE;
+ } else if (!(cfg & (S5P_MIPI_DPHY_SRESETN | S5P_MIPI_DPHY_MRESETN)
+ & (~S5P_MIPI_DPHY_SRESETN))) {
+ cfg &= ~S5P_MIPI_DPHY_ENABLE;
+ }
+
+ __raw_writel(cfg, addr);
+
+
+ addr = S5P_MIPI_DPHY_CONTROL(1);
+
+ cfg = __raw_readl(addr);
+ cfg = (cfg | S5P_MIPI_DPHY_SRESETN);
+ __raw_writel(cfg, addr);
+
+ if (1) {
+ cfg |= S5P_MIPI_DPHY_ENABLE;
+ } else if (!(cfg & (S5P_MIPI_DPHY_SRESETN | S5P_MIPI_DPHY_MRESETN)
+ & (~S5P_MIPI_DPHY_SRESETN))) {
+ cfg &= ~S5P_MIPI_DPHY_ENABLE;
+ }
+
+ __raw_writel(cfg, addr);
+ return 0;
+
+}
+
+int start_mipi_csi(int channel, struct flite_frame *f_frame)
+{
+ unsigned long base_reg = (unsigned long)MIPICSI0_REG_BASE;
+
+ if (channel == CSI_ID_A)
+ base_reg = (unsigned long)MIPICSI0_REG_BASE;
+ else if (channel == CSI_ID_B)
+ base_reg = (unsigned long)MIPICSI1_REG_BASE;
+
+ s5pcsis_reset(base_reg);
+ s5pcsis_set_params(base_reg, f_frame);
+ s5pcsis_system_enable(base_reg, true);
+ s5pcsis_enable_interrupts(base_reg, true);
+
+ return 0;
+}
+
+int stop_mipi_csi(int channel)
+{
+ unsigned long base_reg = (unsigned long)MIPICSI0_REG_BASE;
+
+ if (channel == CSI_ID_A)
+ base_reg = (unsigned long)MIPICSI0_REG_BASE;
+ else if (channel == CSI_ID_B)
+ base_reg = (unsigned long)MIPICSI1_REG_BASE;
+
+ s5pcsis_enable_interrupts(base_reg, false);
+ s5pcsis_system_enable(base_reg, false);
+
+ return 0;
+}
+
+/*
+* will be move to setting file
+*/
+
+int fimc_is_ctrl_odc(struct fimc_is_dev *dev, int value)
+{
+ int ret;
+
+ if (value == CAMERA_ODC_ON) {
+ /* buffer addr setting */
+ dev->back.odc_on = 1;
+ dev->is_p_region->shared[250] = (u32)dev->mem.dvaddr_odc;
+
+ IS_ODC_SET_PARAM_CONTROL_BUFFERNUM(dev,
+ SIZE_ODC_INTERNAL_BUF * NUM_ODC_INTERNAL_BUF);
+ IS_ODC_SET_PARAM_CONTROL_BUFFERADDR(dev,
+ (u32)dev->mem.dvaddr_shared + 250 * sizeof(u32));
+ IS_ODC_SET_PARAM_CONTROL_BYPASS(dev, CONTROL_BYPASS_DISABLE);
+
+ } else if (value == CAMERA_ODC_OFF) {
+ dev->back.odc_on = 0;
+ IS_ODC_SET_PARAM_CONTROL_BYPASS(dev, CONTROL_BYPASS_ENABLE);
+ } else {
+ err("invalid ODC setting\n");
+ return -1;
+ }
+
+ if (test_bit(FIMC_IS_STATE_HW_STREAM_ON, &dev->pipe_state)) {
+ clear_bit(IS_ST_STREAM_OFF, &dev->state);
+ fimc_is_hw_set_stream(dev, 0); /*stream off */
+ ret = wait_event_timeout(dev->irq_queue,
+ test_bit(IS_ST_STREAM_OFF, &dev->state),
+ FIMC_IS_SHUTDOWN_TIMEOUT);
+ if (!ret) {
+ dev_err(&dev->pdev->dev,
+ "wait timeout : %s\n", __func__);
+ if (!ret)
+ err("s_power off failed!!\n");
+ return -EBUSY;
+ }
+ }
+
+ IS_SET_PARAM_BIT(dev, PARAM_ODC_CONTROL);
+ IS_INC_PARAM_NUM(dev);
+
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+
+ dev->scenario_id = ISS_PREVIEW_STILL;
+ set_bit(IS_ST_INIT_PREVIEW_STILL, &dev->state);
+ clear_bit(IS_ST_INIT_CAPTURE_STILL, &dev->state);
+ clear_bit(IS_ST_INIT_PREVIEW_VIDEO, &dev->state);
+ fimc_is_hw_set_param(dev);
+ ret = wait_event_timeout(dev->irq_queue,
+ test_bit(IS_ST_INIT_PREVIEW_VIDEO, &dev->state),
+ FIMC_IS_SHUTDOWN_TIMEOUT);
+ if (!ret) {
+ dev_err(&dev->pdev->dev,
+ "wait timeout : %s\n", __func__);
+ return -EBUSY;
+ }
+
+ if (test_bit(FIMC_IS_STATE_HW_STREAM_ON, &dev->pipe_state)) {
+ clear_bit(IS_ST_RUN, &dev->state);
+ set_bit(IS_ST_CHANGE_MODE, &dev->state);
+ fimc_is_hw_change_mode(dev, IS_MODE_PREVIEW_STILL);
+ ret = wait_event_timeout(dev->irq_queue,
+ test_bit(IS_ST_CHANGE_MODE_DONE, &dev->state),
+ (3*HZ)/*FIMC_IS_SHUTDOWN_TIMEOUT*/);
+
+ if (!ret) {
+ dev_err(&dev->pdev->dev,
+ "Mode change timeout:%s\n", __func__);
+ return -EBUSY;
+ }
+
+ clear_bit(IS_ST_STREAM_ON, &dev->state);
+ fimc_is_hw_set_stream(dev, 1);
+
+ ret = wait_event_timeout(dev->irq_queue,
+ test_bit(IS_ST_STREAM_ON, &dev->state),
+ FIMC_IS_SHUTDOWN_TIMEOUT);
+ if (!ret) {
+ dev_err(&dev->pdev->dev,
+ "wait timeout : %s\n", __func__);
+ return -EBUSY;
+ }
+ }
+ clear_bit(IS_ST_STREAM_ON, &dev->state);
+
+ return 0;
+}
+
+int fimc_is_ctrl_dis(struct fimc_is_dev *dev, int value)
+{
+ int ret;
+
+ if (value == CAMERA_DIS_ON) {
+ /* buffer addr setting */
+ dev->back.dis_on = 1;
+ dev->is_p_region->shared[300] = (u32)dev->mem.dvaddr_dis;
+
+ IS_DIS_SET_PARAM_CONTROL_BUFFERNUM(dev,
+ SIZE_DIS_INTERNAL_BUF * NUM_DIS_INTERNAL_BUF);
+ IS_DIS_SET_PARAM_CONTROL_BUFFERADDR(dev,
+ (u32)dev->mem.dvaddr_shared + 300 * sizeof(u32));
+ IS_DIS_SET_PARAM_CONTROL_BYPASS(dev, CONTROL_BYPASS_DISABLE);
+ } else if (value == CAMERA_DIS_OFF) {
+ dev->back.dis_on = 0;
+ IS_DIS_SET_PARAM_CONTROL_BYPASS(dev, CONTROL_BYPASS_ENABLE);
+ } else {
+ err("invalid DIS setting\n");
+ return -1;
+ }
+
+ if (test_bit(FIMC_IS_STATE_HW_STREAM_ON, &dev->pipe_state)) {
+ clear_bit(IS_ST_STREAM_OFF, &dev->state);
+ fimc_is_hw_set_stream(dev, 0); /*stream off */
+ ret = wait_event_timeout(dev->irq_queue,
+ test_bit(IS_ST_STREAM_OFF, &dev->state),
+ FIMC_IS_SHUTDOWN_TIMEOUT);
+ if (!ret) {
+ dev_err(&dev->pdev->dev,
+ "wait timeout : %s\n", __func__);
+ if (!ret)
+ err("s_power off failed!!\n");
+ return -EBUSY;
+ }
+ }
+
+ IS_SET_PARAM_BIT(dev, PARAM_DIS_CONTROL);
+ IS_INC_PARAM_NUM(dev);
+
+ fimc_is_hw_change_size(dev);
+
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+
+ dev->scenario_id = ISS_PREVIEW_STILL;
+ set_bit(IS_ST_INIT_PREVIEW_STILL, &dev->state);
+ clear_bit(IS_ST_INIT_CAPTURE_STILL, &dev->state);
+ clear_bit(IS_ST_INIT_PREVIEW_VIDEO, &dev->state);
+ fimc_is_hw_set_param(dev);
+#ifdef DIS_ENABLE
+ /* FW bug - should be wait */
+ ret = wait_event_timeout(dev->irq_queue,
+ test_bit(IS_ST_INIT_PREVIEW_VIDEO, &dev->state),
+ FIMC_IS_SHUTDOWN_TIMEOUT);
+ if (!ret) {
+ dev_err(&dev->pdev->dev,
+ "set param wait timeout : %s\n", __func__);
+ return -EBUSY;
+ }
+#endif
+
+ if (test_bit(FIMC_IS_STATE_HW_STREAM_ON, &dev->pipe_state)) {
+ clear_bit(IS_ST_RUN, &dev->state);
+ set_bit(IS_ST_CHANGE_MODE, &dev->state);
+ fimc_is_hw_change_mode(dev, IS_MODE_PREVIEW_STILL);
+ ret = wait_event_timeout(dev->irq_queue,
+ test_bit(IS_ST_CHANGE_MODE_DONE, &dev->state),
+ (3*HZ)/*FIMC_IS_SHUTDOWN_TIMEOUT*/);
+
+ if (!ret) {
+ dev_err(&dev->pdev->dev,
+ "Mode change timeout:%s\n", __func__);
+ return -EBUSY;
+ }
+
+ clear_bit(IS_ST_STREAM_ON, &dev->state);
+ fimc_is_hw_set_stream(dev, 1);
+
+ ret = wait_event_timeout(dev->irq_queue,
+ test_bit(IS_ST_STREAM_ON, &dev->state),
+ FIMC_IS_SHUTDOWN_TIMEOUT);
+ if (!ret) {
+ dev_err(&dev->pdev->dev,
+ "stream on wait timeout : %s\n", __func__);
+ return -EBUSY;
+ }
+ clear_bit(IS_ST_STREAM_ON, &dev->state);
+ }
+
+ return 0;
+}
+
+int fimc_is_ctrl_3dnr(struct fimc_is_dev *dev, int value)
+{
+ int ret;
+
+ if (value == CAMERA_3DNR_ON) {
+ /* buffer addr setting */
+ dev->back.tdnr_on = 1;
+ dev->is_p_region->shared[350] = (u32)dev->mem.dvaddr_3dnr;
+ dbg("3dnr buf:0x%08x size : 0x%08x\n",
+ dev->is_p_region->shared[350],
+ SIZE_3DNR_INTERNAL_BUF*NUM_3DNR_INTERNAL_BUF);
+
+ IS_TDNR_SET_PARAM_CONTROL_BUFFERNUM(dev,
+ SIZE_3DNR_INTERNAL_BUF * NUM_3DNR_INTERNAL_BUF);
+ IS_TDNR_SET_PARAM_CONTROL_BUFFERADDR(dev,
+ (u32)dev->mem.dvaddr_shared + 350 * sizeof(u32));
+ IS_TDNR_SET_PARAM_CONTROL_BYPASS(dev, CONTROL_BYPASS_DISABLE);
+
+ } else if (value == CAMERA_3DNR_OFF) {
+ dbg("disable 3DNR\n");
+ dev->back.tdnr_on = 0;
+ IS_TDNR_SET_PARAM_CONTROL_BYPASS(dev, CONTROL_BYPASS_ENABLE);
+ } else {
+ err("invalid ODC setting\n");
+ return -1;
+ }
+
+ dbg("IS_ST_STREAM_OFF\n");
+ clear_bit(IS_ST_STREAM_OFF, &dev->state);
+ fimc_is_hw_set_stream(dev, 0); /*stream off */
+ ret = wait_event_timeout(dev->irq_queue,
+ test_bit(IS_ST_STREAM_OFF, &dev->state),
+ FIMC_IS_SHUTDOWN_TIMEOUT);
+ if (!ret) {
+ dev_err(&dev->pdev->dev,
+ "wait timeout : %s\n", __func__);
+ if (!ret)
+ err("s_power off failed!!\n");
+ return -EBUSY;
+ }
+
+ IS_SET_PARAM_BIT(dev, PARAM_TDNR_CONTROL);
+ IS_INC_PARAM_NUM(dev);
+
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+
+ dev->scenario_id = ISS_PREVIEW_STILL;
+ set_bit(IS_ST_INIT_PREVIEW_STILL, &dev->state);
+ clear_bit(IS_ST_INIT_CAPTURE_STILL, &dev->state);
+ clear_bit(IS_ST_INIT_PREVIEW_VIDEO, &dev->state);
+ fimc_is_hw_set_param(dev);
+ ret = wait_event_timeout(dev->irq_queue,
+ test_bit(IS_ST_INIT_PREVIEW_VIDEO, &dev->state),
+ FIMC_IS_SHUTDOWN_TIMEOUT);
+ if (!ret) {
+ dev_err(&dev->pdev->dev,
+ "wait timeout : %s\n", __func__);
+ return -EBUSY;
+ }
+
+ dbg("IS change mode\n");
+ clear_bit(IS_ST_RUN, &dev->state);
+ set_bit(IS_ST_CHANGE_MODE, &dev->state);
+ fimc_is_hw_change_mode(dev, IS_MODE_PREVIEW_STILL);
+ ret = wait_event_timeout(dev->irq_queue,
+ test_bit(IS_ST_CHANGE_MODE_DONE, &dev->state),
+ (3*HZ)/*FIMC_IS_SHUTDOWN_TIMEOUT*/);
+
+ if (!ret) {
+ dev_err(&dev->pdev->dev,
+ "Mode change timeout:%s\n", __func__);
+ return -EBUSY;
+ }
+
+ dbg("IS_ST_STREAM_ON\n");
+ clear_bit(IS_ST_STREAM_ON, &dev->state);
+ fimc_is_hw_set_stream(dev, 1);
+
+ ret = wait_event_timeout(dev->irq_queue,
+ test_bit(IS_ST_STREAM_ON, &dev->state),
+ FIMC_IS_SHUTDOWN_TIMEOUT);
+ if (!ret) {
+ dev_err(&dev->pdev->dev,
+ "wait timeout : %s\n", __func__);
+ return -EBUSY;
+ }
+ clear_bit(IS_ST_STREAM_ON, &dev->state);
+
+ return 0;
+}
+
+int fimc_is_digital_zoom(struct fimc_is_dev *dev, int value)
+{
+ u32 back_width, back_height;
+ u32 crop_width, crop_height, crop_x, crop_y;
+ u32 zoom;
+ int ret;
+
+ if (dev->back.dis_on) {
+ back_width = dev->back.dis_width;
+ back_height = dev->back.dis_height;
+ } else {
+ back_width = dev->back.width;
+ back_height = dev->back.height;
+ }
+
+ zoom = value+10;
+
+ crop_width = back_width*10/zoom;
+ crop_height = back_height*10/zoom;
+
+ crop_width &= 0xffe;
+ crop_height &= 0xffe;
+
+ crop_x = (back_width - crop_width)/2;
+ crop_y = (back_height - crop_height)/2;
+
+ crop_x &= 0xffe;
+ crop_y &= 0xffe;
+
+ dbg("crop_width : %d crop_height: %d\n", crop_width, crop_height);
+ dbg("crop_x:%d crop_y: %d\n", crop_x, crop_y);
+
+ IS_SCALERC_SET_PARAM_INPUT_CROP_WIDTH(dev,
+ crop_width);
+ IS_SCALERC_SET_PARAM_INPUT_CROP_HEIGHT(dev,
+ crop_height);
+ IS_SCALERC_SET_PARAM_INPUT_CROP_POS_X(dev,
+ crop_x);
+ IS_SCALERC_SET_PARAM_INPUT_CROP_POS_Y(dev,
+ crop_y);
+ IS_SET_PARAM_BIT(dev, PARAM_SCALERC_INPUT_CROP);
+ IS_INC_PARAM_NUM(dev);
+
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+
+ dev->scenario_id = ISS_PREVIEW_STILL;
+ set_bit(IS_ST_INIT_PREVIEW_STILL, &dev->state);
+ clear_bit(IS_ST_INIT_CAPTURE_STILL, &dev->state);
+ clear_bit(IS_ST_INIT_PREVIEW_VIDEO, &dev->state);
+ fimc_is_hw_set_param(dev);
+ ret = wait_event_timeout(dev->irq_queue,
+ test_bit(IS_ST_INIT_PREVIEW_VIDEO, &dev->state),
+ FIMC_IS_SHUTDOWN_TIMEOUT);
+ if (!ret) {
+ dev_err(&dev->pdev->dev,
+ "wait timeout : %s\n", __func__);
+ return -EBUSY;
+ }
+ return 0;
+}
+
+
+int fimc_is_v4l2_isp_scene_mode(struct fimc_is_dev *dev, int mode)
+{
+ int ret = 0;
+ switch (mode) {
+ case SCENE_MODE_NONE:
+ /* ISO */
+ IS_ISP_SET_PARAM_ISO_CMD(dev, ISP_ISO_COMMAND_AUTO);
+ IS_ISP_SET_PARAM_ISO_VALUE(dev, 0);
+ IS_ISP_SET_PARAM_ISO_ERR(dev, ISP_ISO_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_ISO);
+ IS_INC_PARAM_NUM(dev);
+ /* Metering */
+ IS_ISP_SET_PARAM_METERING_CMD(dev,
+ ISP_METERING_COMMAND_AVERAGE);
+ IS_ISP_SET_PARAM_METERING_WIN_POS_X(dev, 0);
+ IS_ISP_SET_PARAM_METERING_WIN_POS_Y(dev, 0);
+ IS_ISP_SET_PARAM_METERING_WIN_WIDTH(dev, 0);
+ IS_ISP_SET_PARAM_METERING_WIN_HEIGHT(dev, 0);
+ IS_ISP_SET_PARAM_METERING_ERR(dev, ISP_METERING_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_METERING);
+ IS_INC_PARAM_NUM(dev);
+ /* AWB */
+ IS_ISP_SET_PARAM_AWB_CMD(dev, ISP_AWB_COMMAND_AUTO);
+ IS_ISP_SET_PARAM_AWB_ILLUMINATION(dev,
+ ISP_AWB_ILLUMINATION_DAYLIGHT);
+ IS_ISP_SET_PARAM_AWB_ERR(dev, ISP_AWB_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_AWB);
+ IS_INC_PARAM_NUM(dev);
+ /* Adjust */
+ IS_ISP_SET_PARAM_ADJUST_CMD(dev,
+ ISP_ADJUST_COMMAND_MANUAL_ALL);
+ IS_ISP_SET_PARAM_ADJUST_CONTRAST(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_SATURATION(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_SHARPNESS(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_EXPOSURE(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_BRIGHTNESS(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_HUE(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_ERR(dev, ISP_ADJUST_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_ADJUST);
+ IS_INC_PARAM_NUM(dev);
+ /* Flash */
+ IS_ISP_SET_PARAM_FLASH_CMD(dev, ISP_FLASH_COMMAND_AUTO);
+ IS_ISP_SET_PARAM_FLASH_REDEYE(dev, ISP_FLASH_REDEYE_ENABLE);
+ IS_ISP_SET_PARAM_FLASH_ERR(dev, ISP_FLASH_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_FLASH);
+ IS_INC_PARAM_NUM(dev);
+ /* AF */
+ dev->af.af_state = FIMC_IS_AF_SETCONFIG;
+ IS_ISP_SET_PARAM_AA_CMD(dev, ISP_AA_COMMAND_START);
+ IS_ISP_SET_PARAM_AA_TARGET(dev, ISP_AA_TARGET_AF);
+ IS_ISP_SET_PARAM_AA_MODE(dev, ISP_AF_MODE_SINGLE);
+ IS_ISP_SET_PARAM_AA_SCENE(dev, ISP_AF_SCENE_NORMAL);
+ IS_ISP_SET_PARAM_AA_FACE(dev, ISP_AF_FACE_DISABLE);
+ IS_ISP_SET_PARAM_AA_TOUCH_X(dev, 0);
+ IS_ISP_SET_PARAM_AA_TOUCH_Y(dev, 0);
+ IS_ISP_SET_PARAM_AA_MANUAL_AF(dev, 0);
+ IS_ISP_SET_PARAM_AA_ERR(dev, ISP_AF_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_AA);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ break;
+ case SCENE_MODE_PORTRAIT:
+ /* ISO */
+ IS_ISP_SET_PARAM_ISO_CMD(dev, ISP_ISO_COMMAND_AUTO);
+ IS_ISP_SET_PARAM_ISO_VALUE(dev, 0);
+ IS_ISP_SET_PARAM_ISO_ERR(dev, ISP_ISO_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_ISO);
+ IS_INC_PARAM_NUM(dev);
+ /* Metering */
+ IS_ISP_SET_PARAM_METERING_CMD(dev,
+ ISP_METERING_COMMAND_AVERAGE);
+ IS_ISP_SET_PARAM_METERING_WIN_POS_X(dev, 0);
+ IS_ISP_SET_PARAM_METERING_WIN_POS_Y(dev, 0);
+ IS_ISP_SET_PARAM_METERING_WIN_WIDTH(dev, 0);
+ IS_ISP_SET_PARAM_METERING_WIN_HEIGHT(dev, 0);
+ IS_ISP_SET_PARAM_METERING_ERR(dev, ISP_METERING_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_METERING);
+ IS_INC_PARAM_NUM(dev);
+ /* AWB */
+ IS_ISP_SET_PARAM_AWB_CMD(dev, ISP_AWB_COMMAND_AUTO);
+ IS_ISP_SET_PARAM_AWB_ILLUMINATION(dev,
+ ISP_AWB_ILLUMINATION_DAYLIGHT);
+ IS_ISP_SET_PARAM_AWB_ERR(dev, ISP_AWB_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_AWB);
+ IS_INC_PARAM_NUM(dev);
+ /* Adjust */
+ IS_ISP_SET_PARAM_ADJUST_CMD(dev, ISP_ADJUST_COMMAND_MANUAL_ALL);
+ IS_ISP_SET_PARAM_ADJUST_CONTRAST(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_SATURATION(dev, -1);
+ IS_ISP_SET_PARAM_ADJUST_SHARPNESS(dev, -1);
+ IS_ISP_SET_PARAM_ADJUST_EXPOSURE(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_BRIGHTNESS(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_HUE(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_ERR(dev, ISP_ADJUST_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_ADJUST);
+ IS_INC_PARAM_NUM(dev);
+ /* Flash */
+ IS_ISP_SET_PARAM_FLASH_CMD(dev, ISP_FLASH_COMMAND_AUTO);
+ IS_ISP_SET_PARAM_FLASH_REDEYE(dev, ISP_FLASH_REDEYE_ENABLE);
+ IS_ISP_SET_PARAM_FLASH_ERR(dev, ISP_FLASH_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_FLASH);
+ IS_INC_PARAM_NUM(dev);
+ /* AF */
+ dev->af.af_state = FIMC_IS_AF_SETCONFIG;
+ IS_ISP_SET_PARAM_AA_CMD(dev, ISP_AA_COMMAND_START);
+ IS_ISP_SET_PARAM_AA_TARGET(dev, ISP_AA_TARGET_AF);
+ IS_ISP_SET_PARAM_AA_MODE(dev, ISP_AF_MODE_SINGLE);
+ IS_ISP_SET_PARAM_AA_SCENE(dev, ISP_AF_SCENE_NORMAL);
+ IS_ISP_SET_PARAM_AA_SLEEP(dev, ISP_AF_SLEEP_OFF);
+ IS_ISP_SET_PARAM_AA_FACE(dev, ISP_AF_FACE_DISABLE);
+ IS_ISP_SET_PARAM_AA_TOUCH_X(dev, 0);
+ IS_ISP_SET_PARAM_AA_TOUCH_Y(dev, 0);
+ IS_ISP_SET_PARAM_AA_MANUAL_AF(dev, 0);
+ IS_ISP_SET_PARAM_AA_ERR(dev, ISP_AF_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_AA);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ break;
+ case SCENE_MODE_LANDSCAPE:
+ /* ISO */
+ IS_ISP_SET_PARAM_ISO_CMD(dev, ISP_ISO_COMMAND_AUTO);
+ IS_ISP_SET_PARAM_ISO_VALUE(dev, 0);
+ IS_ISP_SET_PARAM_ISO_ERR(dev, ISP_ISO_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_ISO);
+ IS_INC_PARAM_NUM(dev);
+ /* Metering */
+ IS_ISP_SET_PARAM_METERING_CMD(dev,
+ ISP_METERING_COMMAND_MATRIX);
+ IS_ISP_SET_PARAM_METERING_WIN_POS_X(dev, 0);
+ IS_ISP_SET_PARAM_METERING_WIN_POS_Y(dev, 0);
+ IS_ISP_SET_PARAM_METERING_WIN_WIDTH(dev, 0);
+ IS_ISP_SET_PARAM_METERING_WIN_HEIGHT(dev, 0);
+ IS_ISP_SET_PARAM_METERING_ERR(dev, ISP_METERING_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_METERING);
+ IS_INC_PARAM_NUM(dev);
+ /* AWB */
+ IS_ISP_SET_PARAM_AWB_CMD(dev, ISP_AWB_COMMAND_AUTO);
+ IS_ISP_SET_PARAM_AWB_ILLUMINATION(dev,
+ ISP_AWB_ILLUMINATION_DAYLIGHT);
+ IS_ISP_SET_PARAM_AWB_ERR(dev, ISP_AWB_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_AWB);
+ IS_INC_PARAM_NUM(dev);
+ /* Adjust */
+ IS_ISP_SET_PARAM_ADJUST_CMD(dev, ISP_ADJUST_COMMAND_MANUAL_ALL);
+ IS_ISP_SET_PARAM_ADJUST_CONTRAST(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_SATURATION(dev, 1);
+ IS_ISP_SET_PARAM_ADJUST_SHARPNESS(dev, 1);
+ IS_ISP_SET_PARAM_ADJUST_EXPOSURE(dev, 1);
+ IS_ISP_SET_PARAM_ADJUST_BRIGHTNESS(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_HUE(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_ERR(dev, ISP_ADJUST_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_ADJUST);
+ IS_INC_PARAM_NUM(dev);
+ /* Flash */
+ IS_ISP_SET_PARAM_FLASH_CMD(dev, ISP_FLASH_COMMAND_DISABLE);
+ IS_ISP_SET_PARAM_FLASH_REDEYE(dev, ISP_FLASH_REDEYE_DISABLE);
+ IS_ISP_SET_PARAM_FLASH_ERR(dev, ISP_FLASH_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_FLASH);
+ IS_INC_PARAM_NUM(dev);
+ /* AF */
+ dev->af.af_state = FIMC_IS_AF_SETCONFIG;
+ IS_ISP_SET_PARAM_AA_CMD(dev, ISP_AA_COMMAND_START);
+ IS_ISP_SET_PARAM_AA_TARGET(dev, ISP_AA_TARGET_AF);
+ IS_ISP_SET_PARAM_AA_MODE(dev, ISP_AF_MODE_SINGLE);
+ IS_ISP_SET_PARAM_AA_SCENE(dev, ISP_AF_SCENE_NORMAL);
+ IS_ISP_SET_PARAM_AA_SLEEP(dev, ISP_AF_SLEEP_OFF);
+ IS_ISP_SET_PARAM_AA_FACE(dev, ISP_AF_FACE_DISABLE);
+ IS_ISP_SET_PARAM_AA_TOUCH_X(dev, 0);
+ IS_ISP_SET_PARAM_AA_TOUCH_Y(dev, 0);
+ IS_ISP_SET_PARAM_AA_MANUAL_AF(dev, 0);
+ IS_ISP_SET_PARAM_AA_ERR(dev, ISP_AF_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_AA);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ break;
+ case SCENE_MODE_SPORTS:
+ /* ISO */
+ IS_ISP_SET_PARAM_ISO_CMD(dev, ISP_ISO_COMMAND_MANUAL);
+ IS_ISP_SET_PARAM_ISO_VALUE(dev, 400);
+ IS_ISP_SET_PARAM_ISO_ERR(dev, ISP_ISO_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_ISO);
+ IS_INC_PARAM_NUM(dev);
+ /* Metering */
+ IS_ISP_SET_PARAM_METERING_CMD(dev,
+ ISP_METERING_COMMAND_AVERAGE);
+ IS_ISP_SET_PARAM_METERING_WIN_POS_X(dev, 0);
+ IS_ISP_SET_PARAM_METERING_WIN_POS_Y(dev, 0);
+ IS_ISP_SET_PARAM_METERING_WIN_WIDTH(dev, 0);
+ IS_ISP_SET_PARAM_METERING_WIN_HEIGHT(dev, 0);
+ IS_ISP_SET_PARAM_METERING_ERR(dev, ISP_METERING_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_METERING);
+ IS_INC_PARAM_NUM(dev);
+ /* AWB */
+ IS_ISP_SET_PARAM_AWB_CMD(dev, ISP_AWB_COMMAND_AUTO);
+ IS_ISP_SET_PARAM_AWB_ILLUMINATION(dev,
+ ISP_AWB_ILLUMINATION_DAYLIGHT);
+ IS_ISP_SET_PARAM_AWB_ERR(dev, ISP_AWB_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_AWB);
+ IS_INC_PARAM_NUM(dev);
+ /* Adjust */
+ IS_ISP_SET_PARAM_ADJUST_CMD(dev, ISP_ADJUST_COMMAND_MANUAL_ALL);
+ IS_ISP_SET_PARAM_ADJUST_CONTRAST(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_SATURATION(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_SHARPNESS(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_EXPOSURE(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_BRIGHTNESS(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_HUE(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_ERR(dev, ISP_ADJUST_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_ADJUST);
+ IS_INC_PARAM_NUM(dev);
+ /* Flash */
+ IS_ISP_SET_PARAM_FLASH_CMD(dev, ISP_FLASH_COMMAND_DISABLE);
+ IS_ISP_SET_PARAM_FLASH_REDEYE(dev, ISP_FLASH_REDEYE_DISABLE);
+ IS_ISP_SET_PARAM_FLASH_ERR(dev, ISP_FLASH_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_FLASH);
+ IS_INC_PARAM_NUM(dev);
+ /* AF */
+ dev->af.af_state = FIMC_IS_AF_SETCONFIG;
+ IS_ISP_SET_PARAM_AA_CMD(dev, ISP_AA_COMMAND_START);
+ IS_ISP_SET_PARAM_AA_TARGET(dev, ISP_AA_TARGET_AF);
+ IS_ISP_SET_PARAM_AA_MODE(dev, ISP_AF_MODE_SINGLE);
+ IS_ISP_SET_PARAM_AA_SCENE(dev, ISP_AF_SCENE_NORMAL);
+ IS_ISP_SET_PARAM_AA_SLEEP(dev, ISP_AF_SLEEP_OFF);
+ IS_ISP_SET_PARAM_AA_FACE(dev, ISP_AF_FACE_DISABLE);
+ IS_ISP_SET_PARAM_AA_TOUCH_X(dev, 0);
+ IS_ISP_SET_PARAM_AA_TOUCH_Y(dev, 0);
+ IS_ISP_SET_PARAM_AA_MANUAL_AF(dev, 0);
+ IS_ISP_SET_PARAM_AA_ERR(dev, ISP_AF_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_AA);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ break;
+ case SCENE_MODE_PARTY_INDOOR:
+ /* ISO */
+ IS_ISP_SET_PARAM_ISO_CMD(dev, ISP_ISO_COMMAND_MANUAL);
+ IS_ISP_SET_PARAM_ISO_VALUE(dev, 200);
+ IS_ISP_SET_PARAM_ISO_ERR(dev, ISP_ISO_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_ISO);
+ IS_INC_PARAM_NUM(dev);
+ /* Metering */
+ IS_ISP_SET_PARAM_METERING_CMD(dev,
+ ISP_METERING_COMMAND_AVERAGE);
+ IS_ISP_SET_PARAM_METERING_WIN_POS_X(dev, 0);
+ IS_ISP_SET_PARAM_METERING_WIN_POS_Y(dev, 0);
+ IS_ISP_SET_PARAM_METERING_WIN_WIDTH(dev, 0);
+ IS_ISP_SET_PARAM_METERING_WIN_HEIGHT(dev, 0);
+ IS_ISP_SET_PARAM_METERING_ERR(dev, ISP_METERING_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_METERING);
+ IS_INC_PARAM_NUM(dev);
+ /* AWB */
+ IS_ISP_SET_PARAM_AWB_CMD(dev, ISP_AWB_COMMAND_AUTO);
+ IS_ISP_SET_PARAM_AWB_ILLUMINATION(dev,
+ ISP_AWB_ILLUMINATION_DAYLIGHT);
+ IS_ISP_SET_PARAM_AWB_ERR(dev, ISP_AWB_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_AWB);
+ IS_INC_PARAM_NUM(dev);
+ /* Adjust */
+ IS_ISP_SET_PARAM_ADJUST_CMD(dev, ISP_ADJUST_COMMAND_MANUAL_ALL);
+ IS_ISP_SET_PARAM_ADJUST_CONTRAST(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_SATURATION(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_SHARPNESS(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_EXPOSURE(dev, 1);
+ IS_ISP_SET_PARAM_ADJUST_BRIGHTNESS(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_HUE(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_ERR(dev, ISP_ADJUST_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_ADJUST);
+ IS_INC_PARAM_NUM(dev);
+ /* Flash */
+ IS_ISP_SET_PARAM_FLASH_CMD(dev, ISP_FLASH_COMMAND_AUTO);
+ IS_ISP_SET_PARAM_FLASH_REDEYE(dev, ISP_FLASH_REDEYE_ENABLE);
+ IS_ISP_SET_PARAM_FLASH_ERR(dev, ISP_FLASH_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_FLASH);
+ IS_INC_PARAM_NUM(dev);
+ /* AF */
+ dev->af.af_state = FIMC_IS_AF_SETCONFIG;
+ IS_ISP_SET_PARAM_AA_CMD(dev, ISP_AA_COMMAND_START);
+ IS_ISP_SET_PARAM_AA_TARGET(dev, ISP_AA_TARGET_AF);
+ IS_ISP_SET_PARAM_AA_MODE(dev, ISP_AF_MODE_SINGLE);
+ IS_ISP_SET_PARAM_AA_SCENE(dev, ISP_AF_SCENE_NORMAL);
+ IS_ISP_SET_PARAM_AA_SLEEP(dev, ISP_AF_SLEEP_OFF);
+ IS_ISP_SET_PARAM_AA_FACE(dev, ISP_AF_FACE_DISABLE);
+ IS_ISP_SET_PARAM_AA_TOUCH_X(dev, 0);
+ IS_ISP_SET_PARAM_AA_TOUCH_Y(dev, 0);
+ IS_ISP_SET_PARAM_AA_MANUAL_AF(dev, 0);
+ IS_ISP_SET_PARAM_AA_ERR(dev, ISP_AF_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_AA);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ break;
+ case SCENE_MODE_BEACH_SNOW:
+ /* ISO */
+ IS_ISP_SET_PARAM_ISO_CMD(dev, ISP_ISO_COMMAND_MANUAL);
+ IS_ISP_SET_PARAM_ISO_VALUE(dev, 50);
+ IS_ISP_SET_PARAM_ISO_ERR(dev, ISP_ISO_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_ISO);
+ IS_INC_PARAM_NUM(dev);
+ /* Metering */
+ IS_ISP_SET_PARAM_METERING_CMD(dev,
+ ISP_METERING_COMMAND_AVERAGE);
+ IS_ISP_SET_PARAM_METERING_WIN_POS_X(dev, 0);
+ IS_ISP_SET_PARAM_METERING_WIN_POS_Y(dev, 0);
+ IS_ISP_SET_PARAM_METERING_WIN_WIDTH(dev, 0);
+ IS_ISP_SET_PARAM_METERING_WIN_HEIGHT(dev, 0);
+ IS_ISP_SET_PARAM_METERING_ERR(dev, ISP_METERING_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_METERING);
+ IS_INC_PARAM_NUM(dev);
+ /* AWB */
+ IS_ISP_SET_PARAM_AWB_CMD(dev, ISP_AWB_COMMAND_AUTO);
+ IS_ISP_SET_PARAM_AWB_ILLUMINATION(dev,
+ ISP_AWB_ILLUMINATION_DAYLIGHT);
+ IS_ISP_SET_PARAM_AWB_ERR(dev, ISP_AWB_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_AWB);
+ IS_INC_PARAM_NUM(dev);
+ /* Adjust */
+ IS_ISP_SET_PARAM_ADJUST_CMD(dev, ISP_ADJUST_COMMAND_MANUAL_ALL);
+ IS_ISP_SET_PARAM_ADJUST_CONTRAST(dev, 1);
+ IS_ISP_SET_PARAM_ADJUST_SATURATION(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_SHARPNESS(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_EXPOSURE(dev, 1);
+ IS_ISP_SET_PARAM_ADJUST_BRIGHTNESS(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_HUE(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_ERR(dev, ISP_ADJUST_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_ADJUST);
+ IS_INC_PARAM_NUM(dev);
+ /* Flash */
+ IS_ISP_SET_PARAM_FLASH_CMD(dev, ISP_FLASH_COMMAND_DISABLE);
+ IS_ISP_SET_PARAM_FLASH_REDEYE(dev, ISP_FLASH_REDEYE_DISABLE);
+ IS_ISP_SET_PARAM_FLASH_ERR(dev, ISP_FLASH_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_FLASH);
+ IS_INC_PARAM_NUM(dev);
+ /* AF */
+ dev->af.af_state = FIMC_IS_AF_SETCONFIG;
+ IS_ISP_SET_PARAM_AA_CMD(dev, ISP_AA_COMMAND_START);
+ IS_ISP_SET_PARAM_AA_TARGET(dev, ISP_AA_TARGET_AF);
+ IS_ISP_SET_PARAM_AA_MODE(dev, ISP_AF_MODE_SINGLE);
+ IS_ISP_SET_PARAM_AA_SCENE(dev, ISP_AF_SCENE_NORMAL);
+ IS_ISP_SET_PARAM_AA_SLEEP(dev, ISP_AF_SLEEP_OFF);
+ IS_ISP_SET_PARAM_AA_FACE(dev, ISP_AF_FACE_DISABLE);
+ IS_ISP_SET_PARAM_AA_TOUCH_X(dev, 0);
+ IS_ISP_SET_PARAM_AA_TOUCH_Y(dev, 0);
+ IS_ISP_SET_PARAM_AA_MANUAL_AF(dev, 0);
+ IS_ISP_SET_PARAM_AA_ERR(dev, ISP_AF_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_AA);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ break;
+ case SCENE_MODE_SUNSET:
+ /* ISO */
+ IS_ISP_SET_PARAM_ISO_CMD(dev, ISP_ISO_COMMAND_AUTO);
+ IS_ISP_SET_PARAM_ISO_VALUE(dev, 0);
+ IS_ISP_SET_PARAM_ISO_ERR(dev, ISP_ISO_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_ISO);
+ IS_INC_PARAM_NUM(dev);
+ /* Metering */
+ IS_ISP_SET_PARAM_METERING_CMD(dev,
+ ISP_METERING_COMMAND_AVERAGE);
+ IS_ISP_SET_PARAM_METERING_WIN_POS_X(dev, 0);
+ IS_ISP_SET_PARAM_METERING_WIN_POS_Y(dev, 0);
+ IS_ISP_SET_PARAM_METERING_WIN_WIDTH(dev, 0);
+ IS_ISP_SET_PARAM_METERING_WIN_HEIGHT(dev, 0);
+ IS_ISP_SET_PARAM_METERING_ERR(dev, ISP_METERING_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_METERING);
+ IS_INC_PARAM_NUM(dev);
+ /* AWB */
+ IS_ISP_SET_PARAM_AWB_CMD(dev,
+ ISP_AWB_COMMAND_ILLUMINATION);
+ IS_ISP_SET_PARAM_AWB_ILLUMINATION(dev,
+ ISP_AWB_ILLUMINATION_DAYLIGHT);
+ IS_ISP_SET_PARAM_AWB_ERR(dev, ISP_AWB_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_AWB);
+ IS_INC_PARAM_NUM(dev);
+ /* Adjust */
+ IS_ISP_SET_PARAM_ADJUST_CMD(dev, ISP_ADJUST_COMMAND_MANUAL_ALL);
+ IS_ISP_SET_PARAM_ADJUST_CONTRAST(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_SATURATION(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_SHARPNESS(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_EXPOSURE(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_BRIGHTNESS(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_HUE(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_ERR(dev, ISP_ADJUST_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_ADJUST);
+ IS_INC_PARAM_NUM(dev);
+ /* Flash */
+ IS_ISP_SET_PARAM_FLASH_CMD(dev, ISP_FLASH_COMMAND_DISABLE);
+ IS_ISP_SET_PARAM_FLASH_REDEYE(dev, ISP_FLASH_REDEYE_DISABLE);
+ IS_ISP_SET_PARAM_FLASH_ERR(dev, ISP_FLASH_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_FLASH);
+ IS_INC_PARAM_NUM(dev);
+ /* AF */
+ dev->af.af_state = FIMC_IS_AF_SETCONFIG;
+ IS_ISP_SET_PARAM_AA_CMD(dev, ISP_AA_COMMAND_START);
+ IS_ISP_SET_PARAM_AA_TARGET(dev, ISP_AA_TARGET_AF);
+ IS_ISP_SET_PARAM_AA_MODE(dev, ISP_AF_MODE_SINGLE);
+ IS_ISP_SET_PARAM_AA_SCENE(dev, ISP_AF_SCENE_NORMAL);
+ IS_ISP_SET_PARAM_AA_SLEEP(dev, ISP_AF_SLEEP_OFF);
+ IS_ISP_SET_PARAM_AA_FACE(dev, ISP_AF_FACE_DISABLE);
+ IS_ISP_SET_PARAM_AA_TOUCH_X(dev, 0);
+ IS_ISP_SET_PARAM_AA_TOUCH_Y(dev, 0);
+ IS_ISP_SET_PARAM_AA_MANUAL_AF(dev, 0);
+ IS_ISP_SET_PARAM_AA_ERR(dev, ISP_AF_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_AA);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ break;
+ case SCENE_MODE_DUSK_DAWN:
+ /* ISO */
+ IS_ISP_SET_PARAM_ISO_CMD(dev, ISP_ISO_COMMAND_AUTO);
+ IS_ISP_SET_PARAM_ISO_VALUE(dev, 0);
+ IS_ISP_SET_PARAM_ISO_ERR(dev, ISP_ISO_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_ISO);
+ IS_INC_PARAM_NUM(dev);
+ /* Metering */
+ IS_ISP_SET_PARAM_METERING_CMD(dev,
+ ISP_METERING_COMMAND_AVERAGE);
+ IS_ISP_SET_PARAM_METERING_WIN_POS_X(dev, 0);
+ IS_ISP_SET_PARAM_METERING_WIN_POS_Y(dev, 0);
+ IS_ISP_SET_PARAM_METERING_WIN_WIDTH(dev, 0);
+ IS_ISP_SET_PARAM_METERING_WIN_HEIGHT(dev, 0);
+ IS_ISP_SET_PARAM_METERING_ERR(dev,
+ ISP_METERING_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_METERING);
+ IS_INC_PARAM_NUM(dev);
+ /* AWB */
+ IS_ISP_SET_PARAM_AWB_CMD(dev,
+ ISP_AWB_COMMAND_ILLUMINATION);
+ IS_ISP_SET_PARAM_AWB_ILLUMINATION(dev,
+ ISP_AWB_ILLUMINATION_FLUORESCENT);
+ IS_ISP_SET_PARAM_AWB_ERR(dev, ISP_AWB_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_AWB);
+ IS_INC_PARAM_NUM(dev);
+ /* Adjust */
+ IS_ISP_SET_PARAM_ADJUST_CMD(dev, ISP_ADJUST_COMMAND_MANUAL_ALL);
+ IS_ISP_SET_PARAM_ADJUST_CONTRAST(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_SATURATION(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_SHARPNESS(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_EXPOSURE(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_BRIGHTNESS(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_HUE(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_ERR(dev, ISP_ADJUST_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_ADJUST);
+ IS_INC_PARAM_NUM(dev);
+ /* Flash */
+ IS_ISP_SET_PARAM_FLASH_CMD(dev, ISP_FLASH_COMMAND_DISABLE);
+ IS_ISP_SET_PARAM_FLASH_REDEYE(dev, ISP_FLASH_REDEYE_DISABLE);
+ IS_ISP_SET_PARAM_FLASH_ERR(dev, ISP_FLASH_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_FLASH);
+ IS_INC_PARAM_NUM(dev);
+ /* AF */
+ dev->af.af_state = FIMC_IS_AF_SETCONFIG;
+ IS_ISP_SET_PARAM_AA_CMD(dev, ISP_AA_COMMAND_START);
+ IS_ISP_SET_PARAM_AA_TARGET(dev, ISP_AA_TARGET_AF);
+ IS_ISP_SET_PARAM_AA_MODE(dev, ISP_AF_MODE_SINGLE);
+ IS_ISP_SET_PARAM_AA_SCENE(dev, ISP_AF_SCENE_NORMAL);
+ IS_ISP_SET_PARAM_AA_SLEEP(dev, ISP_AF_SLEEP_OFF);
+ IS_ISP_SET_PARAM_AA_FACE(dev, ISP_AF_FACE_DISABLE);
+ IS_ISP_SET_PARAM_AA_TOUCH_X(dev, 0);
+ IS_ISP_SET_PARAM_AA_TOUCH_Y(dev, 0);
+ IS_ISP_SET_PARAM_AA_MANUAL_AF(dev, 0);
+ IS_ISP_SET_PARAM_AA_ERR(dev, ISP_AF_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_AA);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ break;
+ case SCENE_MODE_FALL_COLOR:
+ /* ISO */
+ IS_ISP_SET_PARAM_ISO_CMD(dev, ISP_ISO_COMMAND_AUTO);
+ IS_ISP_SET_PARAM_ISO_VALUE(dev, 0);
+ IS_ISP_SET_PARAM_ISO_ERR(dev, ISP_ISO_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_ISO);
+ IS_INC_PARAM_NUM(dev);
+ /* Metering */
+ IS_ISP_SET_PARAM_METERING_CMD(dev,
+ ISP_METERING_COMMAND_AVERAGE);
+ IS_ISP_SET_PARAM_METERING_WIN_POS_X(dev, 0);
+ IS_ISP_SET_PARAM_METERING_WIN_POS_Y(dev, 0);
+ IS_ISP_SET_PARAM_METERING_WIN_WIDTH(dev, 0);
+ IS_ISP_SET_PARAM_METERING_WIN_HEIGHT(dev, 0);
+ IS_ISP_SET_PARAM_METERING_ERR(dev,
+ ISP_METERING_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_METERING);
+ IS_INC_PARAM_NUM(dev);
+ /* AWB */
+ IS_ISP_SET_PARAM_AWB_CMD(dev, ISP_AWB_COMMAND_AUTO);
+ IS_ISP_SET_PARAM_AWB_ILLUMINATION(dev,
+ ISP_AWB_ILLUMINATION_DAYLIGHT);
+ IS_ISP_SET_PARAM_AWB_ERR(dev, ISP_AWB_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_AWB);
+ IS_INC_PARAM_NUM(dev);
+ /* Adjust */
+ IS_ISP_SET_PARAM_ADJUST_CMD(dev, ISP_ADJUST_COMMAND_MANUAL_ALL);
+ IS_ISP_SET_PARAM_ADJUST_CONTRAST(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_SATURATION(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_SHARPNESS(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_EXPOSURE(dev, 2);
+ IS_ISP_SET_PARAM_ADJUST_BRIGHTNESS(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_HUE(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_ERR(dev, ISP_ADJUST_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_ADJUST);
+ IS_INC_PARAM_NUM(dev);
+ /* Flash */
+ IS_ISP_SET_PARAM_FLASH_CMD(dev, ISP_FLASH_COMMAND_DISABLE);
+ IS_ISP_SET_PARAM_FLASH_REDEYE(dev, ISP_FLASH_REDEYE_DISABLE);
+ IS_ISP_SET_PARAM_FLASH_ERR(dev, ISP_FLASH_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_FLASH);
+ IS_INC_PARAM_NUM(dev);
+ /* AF */
+ dev->af.af_state = FIMC_IS_AF_SETCONFIG;
+ IS_ISP_SET_PARAM_AA_CMD(dev, ISP_AA_COMMAND_START);
+ IS_ISP_SET_PARAM_AA_TARGET(dev, ISP_AA_TARGET_AF);
+ IS_ISP_SET_PARAM_AA_MODE(dev, ISP_AF_MODE_SINGLE);
+ IS_ISP_SET_PARAM_AA_SCENE(dev, ISP_AF_SCENE_NORMAL);
+ IS_ISP_SET_PARAM_AA_SLEEP(dev, ISP_AF_SLEEP_OFF);
+ IS_ISP_SET_PARAM_AA_FACE(dev, ISP_AF_FACE_DISABLE);
+ IS_ISP_SET_PARAM_AA_TOUCH_X(dev, 0);
+ IS_ISP_SET_PARAM_AA_TOUCH_Y(dev, 0);
+ IS_ISP_SET_PARAM_AA_MANUAL_AF(dev, 0);
+ IS_ISP_SET_PARAM_AA_ERR(dev, ISP_AF_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_AA);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ break;
+ case SCENE_MODE_NIGHTSHOT:
+ /* ISO */
+ IS_ISP_SET_PARAM_ISO_CMD(dev, ISP_ISO_COMMAND_AUTO);
+ IS_ISP_SET_PARAM_ISO_VALUE(dev, 0);
+ IS_ISP_SET_PARAM_ISO_ERR(dev, ISP_ISO_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_ISO);
+ IS_INC_PARAM_NUM(dev);
+ /* Metering */
+ IS_ISP_SET_PARAM_METERING_CMD(dev,
+ ISP_METERING_COMMAND_AVERAGE);
+ IS_ISP_SET_PARAM_METERING_WIN_POS_X(dev, 0);
+ IS_ISP_SET_PARAM_METERING_WIN_POS_Y(dev, 0);
+ IS_ISP_SET_PARAM_METERING_WIN_WIDTH(dev, 0);
+ IS_ISP_SET_PARAM_METERING_WIN_HEIGHT(dev, 0);
+ IS_ISP_SET_PARAM_METERING_ERR(dev,
+ ISP_METERING_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_METERING);
+ IS_INC_PARAM_NUM(dev);
+ /* AWB */
+ IS_ISP_SET_PARAM_AWB_CMD(dev, ISP_AWB_COMMAND_AUTO);
+ IS_ISP_SET_PARAM_AWB_ILLUMINATION(dev,
+ ISP_AWB_ILLUMINATION_DAYLIGHT);
+ IS_ISP_SET_PARAM_AWB_ERR(dev, ISP_AWB_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_AWB);
+ IS_INC_PARAM_NUM(dev);
+ /* Adjust */
+ IS_ISP_SET_PARAM_ADJUST_CMD(dev, ISP_ADJUST_COMMAND_MANUAL_ALL);
+ IS_ISP_SET_PARAM_ADJUST_CONTRAST(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_SATURATION(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_SHARPNESS(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_EXPOSURE(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_BRIGHTNESS(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_HUE(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_ERR(dev, ISP_ADJUST_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_ADJUST);
+ IS_INC_PARAM_NUM(dev);
+ /* Flash */
+ IS_ISP_SET_PARAM_FLASH_CMD(dev, ISP_FLASH_COMMAND_DISABLE);
+ IS_ISP_SET_PARAM_FLASH_REDEYE(dev, ISP_FLASH_REDEYE_DISABLE);
+ IS_ISP_SET_PARAM_FLASH_ERR(dev, ISP_FLASH_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_FLASH);
+ IS_INC_PARAM_NUM(dev);
+ /* AF */
+ dev->af.af_state = FIMC_IS_AF_SETCONFIG;
+ IS_ISP_SET_PARAM_AA_CMD(dev, ISP_AA_COMMAND_START);
+ IS_ISP_SET_PARAM_AA_TARGET(dev, ISP_AA_TARGET_AF);
+ IS_ISP_SET_PARAM_AA_MODE(dev, ISP_AF_MODE_SINGLE);
+ IS_ISP_SET_PARAM_AA_SCENE(dev, ISP_AF_SCENE_NORMAL);
+ IS_ISP_SET_PARAM_AA_SLEEP(dev, ISP_AF_SLEEP_OFF);
+ IS_ISP_SET_PARAM_AA_FACE(dev, ISP_AF_FACE_DISABLE);
+ IS_ISP_SET_PARAM_AA_TOUCH_X(dev, 0);
+ IS_ISP_SET_PARAM_AA_TOUCH_Y(dev, 0);
+ IS_ISP_SET_PARAM_AA_MANUAL_AF(dev, 0);
+ IS_ISP_SET_PARAM_AA_ERR(dev, ISP_AF_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_AA);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ break;
+ case SCENE_MODE_BACK_LIGHT:
+ /* ISO */
+ IS_ISP_SET_PARAM_ISO_CMD(dev, ISP_ISO_COMMAND_AUTO);
+ IS_ISP_SET_PARAM_ISO_VALUE(dev, 0);
+ IS_ISP_SET_PARAM_ISO_ERR(dev, ISP_ISO_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_ISO);
+ IS_INC_PARAM_NUM(dev);
+ /* Metering */
+ IS_ISP_SET_PARAM_METERING_CMD(dev,
+ ISP_METERING_COMMAND_AVERAGE);
+ IS_ISP_SET_PARAM_METERING_WIN_POS_X(dev, 0);
+ IS_ISP_SET_PARAM_METERING_WIN_POS_Y(dev, 0);
+ IS_ISP_SET_PARAM_METERING_WIN_WIDTH(dev, 0);
+ IS_ISP_SET_PARAM_METERING_WIN_HEIGHT(dev, 0);
+ IS_ISP_SET_PARAM_METERING_ERR(dev,
+ ISP_METERING_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_METERING);
+ IS_INC_PARAM_NUM(dev);
+ /* AWB */
+ IS_ISP_SET_PARAM_AWB_CMD(dev, ISP_AWB_COMMAND_AUTO);
+ IS_ISP_SET_PARAM_AWB_ILLUMINATION(dev,
+ ISP_AWB_ILLUMINATION_DAYLIGHT);
+ IS_ISP_SET_PARAM_AWB_ERR(dev, ISP_AWB_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_AWB);
+ IS_INC_PARAM_NUM(dev);
+ /* Adjust */
+ IS_ISP_SET_PARAM_ADJUST_CMD(dev, ISP_ADJUST_COMMAND_MANUAL_ALL);
+ IS_ISP_SET_PARAM_ADJUST_CONTRAST(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_SATURATION(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_SHARPNESS(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_EXPOSURE(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_BRIGHTNESS(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_HUE(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_ERR(dev, ISP_ADJUST_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_ADJUST);
+ IS_INC_PARAM_NUM(dev);
+ /* Flash */
+ IS_ISP_SET_PARAM_FLASH_CMD(dev, ISP_FLASH_COMMAND_DISABLE);
+ IS_ISP_SET_PARAM_FLASH_REDEYE(dev, ISP_FLASH_REDEYE_DISABLE);
+ IS_ISP_SET_PARAM_FLASH_ERR(dev, ISP_FLASH_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_FLASH);
+ IS_INC_PARAM_NUM(dev);
+ /* AF */
+ IS_ISP_SET_PARAM_AA_CMD(dev, ISP_AA_COMMAND_START);
+ IS_ISP_SET_PARAM_AA_TARGET(dev, ISP_AA_TARGET_AF);
+ IS_ISP_SET_PARAM_AA_MODE(dev, ISP_AF_MODE_SINGLE);
+ IS_ISP_SET_PARAM_AA_SCENE(dev, ISP_AF_SCENE_NORMAL);
+ IS_ISP_SET_PARAM_AA_SLEEP(dev, ISP_AF_SLEEP_OFF);
+ IS_ISP_SET_PARAM_AA_FACE(dev, ISP_AF_FACE_DISABLE);
+ IS_ISP_SET_PARAM_AA_TOUCH_X(dev, 0);
+ IS_ISP_SET_PARAM_AA_TOUCH_Y(dev, 0);
+ IS_ISP_SET_PARAM_AA_MANUAL_AF(dev, 0);
+ IS_ISP_SET_PARAM_AA_ERR(dev, ISP_AF_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_AA);
+ IS_INC_PARAM_NUM(dev);
+ dev->af.af_state = FIMC_IS_AF_SETCONFIG;
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ break;
+ /* FIXME add with SCENE_MODE_BACK_LIGHT (FLASH mode) */
+ case SCENE_MODE_FIREWORKS:
+ /* ISO */
+ IS_ISP_SET_PARAM_ISO_CMD(dev, ISP_ISO_COMMAND_MANUAL);
+ IS_ISP_SET_PARAM_ISO_VALUE(dev, 50);
+ IS_ISP_SET_PARAM_ISO_ERR(dev, ISP_ISO_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_ISO);
+ IS_INC_PARAM_NUM(dev);
+ /* Metering */
+ IS_ISP_SET_PARAM_METERING_CMD(dev,
+ ISP_METERING_COMMAND_AVERAGE);
+ IS_ISP_SET_PARAM_METERING_WIN_POS_X(dev, 0);
+ IS_ISP_SET_PARAM_METERING_WIN_POS_Y(dev, 0);
+ IS_ISP_SET_PARAM_METERING_WIN_WIDTH(dev, 0);
+ IS_ISP_SET_PARAM_METERING_WIN_HEIGHT(dev, 0);
+ IS_ISP_SET_PARAM_METERING_ERR(dev,
+ ISP_METERING_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_METERING);
+ IS_INC_PARAM_NUM(dev);
+ /* AWB */
+ IS_ISP_SET_PARAM_AWB_CMD(dev, ISP_AWB_COMMAND_AUTO);
+ IS_ISP_SET_PARAM_AWB_ILLUMINATION(dev,
+ ISP_AWB_ILLUMINATION_DAYLIGHT);
+ IS_ISP_SET_PARAM_AWB_ERR(dev, ISP_AWB_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_AWB);
+ IS_INC_PARAM_NUM(dev);
+ /* Adjust */
+ IS_ISP_SET_PARAM_ADJUST_CMD(dev, ISP_ADJUST_COMMAND_MANUAL_ALL);
+ IS_ISP_SET_PARAM_ADJUST_CONTRAST(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_SATURATION(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_SHARPNESS(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_EXPOSURE(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_BRIGHTNESS(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_HUE(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_ERR(dev, ISP_ADJUST_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_ADJUST);
+ IS_INC_PARAM_NUM(dev);
+ /* Flash */
+ IS_ISP_SET_PARAM_FLASH_CMD(dev, ISP_FLASH_COMMAND_DISABLE);
+ IS_ISP_SET_PARAM_FLASH_REDEYE(dev, ISP_FLASH_REDEYE_DISABLE);
+ IS_ISP_SET_PARAM_FLASH_ERR(dev, ISP_FLASH_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_FLASH);
+ IS_INC_PARAM_NUM(dev);
+ /* AF */
+ dev->af.af_state = FIMC_IS_AF_SETCONFIG;
+ IS_ISP_SET_PARAM_AA_CMD(dev, ISP_AA_COMMAND_START);
+ IS_ISP_SET_PARAM_AA_TARGET(dev, ISP_AA_TARGET_AF);
+ IS_ISP_SET_PARAM_AA_MODE(dev, ISP_AF_MODE_SINGLE);
+ IS_ISP_SET_PARAM_AA_SCENE(dev, ISP_AF_SCENE_NORMAL);
+ IS_ISP_SET_PARAM_AA_SLEEP(dev, ISP_AF_SLEEP_OFF);
+ IS_ISP_SET_PARAM_AA_FACE(dev, ISP_AF_FACE_DISABLE);
+ IS_ISP_SET_PARAM_AA_TOUCH_X(dev, 0);
+ IS_ISP_SET_PARAM_AA_TOUCH_Y(dev, 0);
+ IS_ISP_SET_PARAM_AA_MANUAL_AF(dev, 0);
+ IS_ISP_SET_PARAM_AA_ERR(dev, ISP_AF_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_AA);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ break;
+ case SCENE_MODE_TEXT:
+ /* ISO */
+ IS_ISP_SET_PARAM_ISO_CMD(dev, ISP_ISO_COMMAND_AUTO);
+ IS_ISP_SET_PARAM_ISO_VALUE(dev, 0);
+ IS_ISP_SET_PARAM_ISO_ERR(dev, ISP_ISO_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_ISO);
+ IS_INC_PARAM_NUM(dev);
+ /* Metering */
+ IS_ISP_SET_PARAM_METERING_CMD(dev,
+ ISP_METERING_COMMAND_AVERAGE);
+ IS_ISP_SET_PARAM_METERING_WIN_POS_X(dev, 0);
+ IS_ISP_SET_PARAM_METERING_WIN_POS_Y(dev, 0);
+ IS_ISP_SET_PARAM_METERING_WIN_WIDTH(dev, 0);
+ IS_ISP_SET_PARAM_METERING_WIN_HEIGHT(dev, 0);
+ IS_ISP_SET_PARAM_METERING_ERR(dev,
+ ISP_METERING_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_METERING);
+ IS_INC_PARAM_NUM(dev);
+ /* AWB */
+ IS_ISP_SET_PARAM_AWB_CMD(dev, ISP_AWB_COMMAND_AUTO);
+ IS_ISP_SET_PARAM_AWB_ILLUMINATION(dev,
+ ISP_AWB_ILLUMINATION_DAYLIGHT);
+ IS_ISP_SET_PARAM_AWB_ERR(dev, ISP_AWB_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_AWB);
+ IS_INC_PARAM_NUM(dev);
+ /* Adjust */
+ IS_ISP_SET_PARAM_ADJUST_CMD(dev, ISP_ADJUST_COMMAND_MANUAL_ALL);
+ IS_ISP_SET_PARAM_ADJUST_CONTRAST(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_SATURATION(dev, 2);
+ IS_ISP_SET_PARAM_ADJUST_SHARPNESS(dev, 2);
+ IS_ISP_SET_PARAM_ADJUST_EXPOSURE(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_BRIGHTNESS(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_HUE(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_ERR(dev, ISP_ADJUST_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_ADJUST);
+ IS_INC_PARAM_NUM(dev);
+ /* Flash */
+ IS_ISP_SET_PARAM_FLASH_CMD(dev, ISP_FLASH_COMMAND_DISABLE);
+ IS_ISP_SET_PARAM_FLASH_REDEYE(dev, ISP_FLASH_REDEYE_DISABLE);
+ IS_ISP_SET_PARAM_FLASH_ERR(dev, ISP_FLASH_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_FLASH);
+ IS_INC_PARAM_NUM(dev);
+ /* AF */
+ dev->af.af_state = FIMC_IS_AF_SETCONFIG;
+ IS_ISP_SET_PARAM_AA_CMD(dev, ISP_AA_COMMAND_START);
+ IS_ISP_SET_PARAM_AA_TARGET(dev, ISP_AA_TARGET_AF);
+ IS_ISP_SET_PARAM_AA_MODE(dev, ISP_AF_MODE_SINGLE);
+ IS_ISP_SET_PARAM_AA_SCENE(dev, ISP_AF_SCENE_NORMAL);
+ IS_ISP_SET_PARAM_AA_SLEEP(dev, ISP_AF_SLEEP_OFF);
+ IS_ISP_SET_PARAM_AA_FACE(dev, ISP_AF_FACE_DISABLE);
+ IS_ISP_SET_PARAM_AA_TOUCH_X(dev, 0);
+ IS_ISP_SET_PARAM_AA_TOUCH_Y(dev, 0);
+ IS_ISP_SET_PARAM_AA_MANUAL_AF(dev, 0);
+ IS_ISP_SET_PARAM_AA_ERR(dev, ISP_AF_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_AA);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ break;
+ case SCENE_MODE_CANDLE_LIGHT:
+ /* ISO */
+ IS_ISP_SET_PARAM_ISO_CMD(dev, ISP_ISO_COMMAND_AUTO);
+ IS_ISP_SET_PARAM_ISO_VALUE(dev, 0);
+ IS_ISP_SET_PARAM_ISO_ERR(dev, ISP_ISO_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_ISO);
+ IS_INC_PARAM_NUM(dev);
+ /* Metering */
+ IS_ISP_SET_PARAM_METERING_CMD(dev,
+ ISP_METERING_COMMAND_AVERAGE);
+ IS_ISP_SET_PARAM_METERING_WIN_POS_X(dev, 0);
+ IS_ISP_SET_PARAM_METERING_WIN_POS_Y(dev, 0);
+ IS_ISP_SET_PARAM_METERING_WIN_WIDTH(dev, 0);
+ IS_ISP_SET_PARAM_METERING_WIN_HEIGHT(dev, 0);
+ IS_ISP_SET_PARAM_METERING_ERR(dev,
+ ISP_METERING_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_METERING);
+ IS_INC_PARAM_NUM(dev);
+ /* AWB */
+ IS_ISP_SET_PARAM_AWB_CMD(dev, ISP_AWB_COMMAND_ILLUMINATION);
+ IS_ISP_SET_PARAM_AWB_ILLUMINATION(dev,
+ ISP_AWB_ILLUMINATION_DAYLIGHT);
+ IS_ISP_SET_PARAM_AWB_ERR(dev, ISP_AWB_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_AWB);
+ IS_INC_PARAM_NUM(dev);
+ /* Adjust */
+ IS_ISP_SET_PARAM_ADJUST_CMD(dev, ISP_ADJUST_COMMAND_MANUAL_ALL);
+ IS_ISP_SET_PARAM_ADJUST_CONTRAST(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_SATURATION(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_SHARPNESS(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_EXPOSURE(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_BRIGHTNESS(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_HUE(dev, 0);
+ IS_ISP_SET_PARAM_ADJUST_ERR(dev, ISP_ADJUST_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_ADJUST);
+ IS_INC_PARAM_NUM(dev);
+ /* Flash */
+ IS_ISP_SET_PARAM_FLASH_CMD(dev, ISP_FLASH_COMMAND_DISABLE);
+ IS_ISP_SET_PARAM_FLASH_REDEYE(dev, ISP_FLASH_REDEYE_DISABLE);
+ IS_ISP_SET_PARAM_FLASH_ERR(dev, ISP_FLASH_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_FLASH);
+ IS_INC_PARAM_NUM(dev);
+ /* AF */
+ dev->af.af_state = FIMC_IS_AF_SETCONFIG;
+ IS_ISP_SET_PARAM_AA_CMD(dev, ISP_AA_COMMAND_START);
+ IS_ISP_SET_PARAM_AA_TARGET(dev, ISP_AA_TARGET_AF);
+ IS_ISP_SET_PARAM_AA_MODE(dev, ISP_AF_MODE_SINGLE);
+ IS_ISP_SET_PARAM_AA_SCENE(dev, ISP_AF_SCENE_NORMAL);
+ IS_ISP_SET_PARAM_AA_SLEEP(dev, ISP_AF_SLEEP_OFF);
+ IS_ISP_SET_PARAM_AA_FACE(dev, ISP_AF_FACE_DISABLE);
+ IS_ISP_SET_PARAM_AA_TOUCH_X(dev, 0);
+ IS_ISP_SET_PARAM_AA_TOUCH_Y(dev, 0);
+ IS_ISP_SET_PARAM_AA_MANUAL_AF(dev, 0);
+ IS_ISP_SET_PARAM_AA_ERR(dev, ISP_AF_ERROR_NO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_AA);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+int fimc_is_af_face(struct fimc_is_dev *dev)
+{
+ int ret = 0, max_confidence = 0, i = 0;
+ int width, height;
+ u32 touch_x = 0, touch_y = 0;
+
+ for (i = dev->fd_header.index;
+ i < (dev->fd_header.index + dev->fd_header.count); i++) {
+ if (max_confidence < dev->is_p_region->face[i].confidence) {
+ max_confidence = dev->is_p_region->face[i].confidence;
+ touch_x = dev->is_p_region->face[i].face.offset_x +
+ (dev->is_p_region->face[i].face.width / 2);
+ touch_y = dev->is_p_region->face[i].face.offset_y +
+ (dev->is_p_region->face[i].face.height / 2);
+ }
+ }
+ width = dev->sensor.width;
+ height = dev->sensor.height;
+ touch_x = 1024 * touch_x / (u32)width;
+ touch_y = 1024 * touch_y / (u32)height;
+
+ if ((touch_x == 0) || (touch_y == 0) || (max_confidence < 50))
+ return ret;
+
+ if (dev->af.prev_pos_x == 0 && dev->af.prev_pos_y == 0) {
+ dev->af.prev_pos_x = touch_x;
+ dev->af.prev_pos_y = touch_y;
+ } else {
+ if (abs(dev->af.prev_pos_x - touch_x) < 100 &&
+ abs(dev->af.prev_pos_y - touch_y) < 100) {
+ return ret;
+ }
+ dbg("AF Face level = %d\n", max_confidence);
+ dbg("AF Face = <%d, %d>\n", touch_x, touch_y);
+ dbg("AF Face = prev <%d, %d>\n",
+ dev->af.prev_pos_x, dev->af.prev_pos_y);
+ dev->af.prev_pos_x = touch_x;
+ dev->af.prev_pos_y = touch_y;
+ }
+
+ IS_ISP_SET_PARAM_AA_CMD(dev, ISP_AA_COMMAND_START);
+ IS_ISP_SET_PARAM_AA_TARGET(dev, ISP_AA_TARGET_AF);
+ IS_ISP_SET_PARAM_AA_MODE(dev, ISP_AF_MODE_TOUCH);
+ IS_ISP_SET_PARAM_AA_SLEEP(dev, ISP_AF_SLEEP_OFF);
+ IS_ISP_SET_PARAM_AA_FACE(dev, ISP_AF_FACE_DISABLE);
+ IS_ISP_SET_PARAM_AA_TOUCH_X(dev, touch_x);
+ IS_ISP_SET_PARAM_AA_TOUCH_Y(dev, touch_y);
+ IS_ISP_SET_PARAM_AA_MANUAL_AF(dev, 0);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_AA);
+ IS_INC_PARAM_NUM(dev);
+ dev->af.af_state = FIMC_IS_AF_SETCONFIG;
+ fimc_is_mem_cache_clean((void *)dev->is_p_region, IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+
+ return ret;
+}
+
+int fimc_is_v4l2_af_mode(struct fimc_is_dev *dev, int value)
+{
+ int ret = 0;
+ switch (value) {
+ case FOCUS_MODE_AUTO:
+ dev->af.mode = IS_FOCUS_MODE_AUTO;
+ break;
+ case FOCUS_MODE_MACRO:
+ dev->af.mode = IS_FOCUS_MODE_MACRO;
+ break;
+ case FOCUS_MODE_INFINITY:
+ dev->af.mode = IS_FOCUS_MODE_INFINITY;
+ IS_ISP_SET_PARAM_AA_CMD(dev, ISP_AA_COMMAND_START);
+ IS_ISP_SET_PARAM_AA_TARGET(dev, ISP_AA_TARGET_AF);
+ IS_ISP_SET_PARAM_AA_MODE(dev, ISP_AF_MODE_MANUAL);
+ IS_ISP_SET_PARAM_AA_SLEEP(dev, ISP_AF_SLEEP_OFF);
+ IS_ISP_SET_PARAM_AA_FACE(dev, ISP_AF_FACE_DISABLE);
+ IS_ISP_SET_PARAM_AA_TOUCH_X(dev, 0);
+ IS_ISP_SET_PARAM_AA_TOUCH_Y(dev, 0);
+ IS_ISP_SET_PARAM_AA_MANUAL_AF(dev, 0);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_AA);
+ IS_INC_PARAM_NUM(dev);
+ dev->af.af_state = FIMC_IS_AF_SETCONFIG;
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ break;
+ case FOCUS_MODE_CONTINOUS:
+ dev->af.mode = IS_FOCUS_MODE_CONTINUOUS;
+ IS_ISP_SET_PARAM_AA_CMD(dev, ISP_AA_COMMAND_START);
+ IS_ISP_SET_PARAM_AA_TARGET(dev, ISP_AA_TARGET_AF);
+ IS_ISP_SET_PARAM_AA_MODE(dev, ISP_AF_MODE_CONTINUOUS);
+ IS_ISP_SET_PARAM_AA_SLEEP(dev, ISP_AF_SLEEP_OFF);
+ IS_ISP_SET_PARAM_AA_FACE(dev, ISP_AF_FACE_DISABLE);
+ IS_ISP_SET_PARAM_AA_TOUCH_X(dev, 0);
+ IS_ISP_SET_PARAM_AA_TOUCH_Y(dev, 0);
+ IS_ISP_SET_PARAM_AA_MANUAL_AF(dev, 0);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_AA);
+ IS_INC_PARAM_NUM(dev);
+ dev->af.af_state = FIMC_IS_AF_SETCONFIG;
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ dev->af.af_lock_state = 0;
+ dev->af.ae_lock_state = 0;
+ dev->af.awb_lock_state = 0;
+ dev->af.prev_pos_x = 0;
+ dev->af.prev_pos_y = 0;
+ break;
+ case FOCUS_MODE_TOUCH:
+ dev->af.mode = IS_FOCUS_MODE_TOUCH;
+ IS_ISP_SET_PARAM_AA_CMD(dev, ISP_AA_COMMAND_START);
+ IS_ISP_SET_PARAM_AA_TARGET(dev, ISP_AA_TARGET_AF);
+ IS_ISP_SET_PARAM_AA_MODE(dev, ISP_AF_MODE_TOUCH);
+ IS_ISP_SET_PARAM_AA_SLEEP(dev, ISP_AF_SLEEP_OFF);
+ IS_ISP_SET_PARAM_AA_FACE(dev, ISP_AF_FACE_DISABLE);
+ IS_ISP_SET_PARAM_AA_TOUCH_X(dev, dev->af.pos_x);
+ IS_ISP_SET_PARAM_AA_TOUCH_Y(dev, dev->af.pos_y);
+ IS_ISP_SET_PARAM_AA_MANUAL_AF(dev, 0);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_AA);
+ IS_INC_PARAM_NUM(dev);
+ dev->af.af_state = FIMC_IS_AF_SETCONFIG;
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ dev->af.af_lock_state = 0;
+ dev->af.ae_lock_state = 0;
+ dev->af.awb_lock_state = 0;
+ break;
+ case FOCUS_MODE_FACEDETECT:
+ dev->af.mode = IS_FOCUS_MODE_FACEDETECT;
+ dev->af.af_lock_state = 0;
+ dev->af.ae_lock_state = 0;
+ dev->af.awb_lock_state = 0;
+ dev->af.prev_pos_x = 0;
+ dev->af.prev_pos_y = 0;
+ break;
+ default:
+ return ret;
+ }
+ return ret;
+}
+
+int fimc_is_v4l2_af_start_stop(struct fimc_is_dev *dev, int value)
+{
+ int ret = 0;
+ switch (value) {
+ case AUTO_FOCUS_OFF:
+ if (!is_af_use(dev)) {
+ /* 6A3 can't support AF */
+ dev->af.af_state = FIMC_IS_AF_IDLE;
+ } else {
+ if (dev->af.af_state == FIMC_IS_AF_IDLE)
+ return ret;
+ /* Abort or lock AF */
+ dev->af.af_state = FIMC_IS_AF_ABORT;
+ IS_ISP_SET_PARAM_AA_CMD(dev, ISP_AA_COMMAND_STOP);
+ IS_ISP_SET_PARAM_AA_TARGET(dev, ISP_AA_TARGET_AF);
+ switch (dev->af.mode) {
+ case IS_FOCUS_MODE_AUTO:
+ IS_ISP_SET_PARAM_AA_MODE(dev,
+ ISP_AF_MODE_SINGLE);
+ IS_ISP_SET_PARAM_AA_SCENE(dev,
+ ISP_AF_SCENE_NORMAL);
+ IS_ISP_SET_PARAM_AA_SLEEP(dev,
+ ISP_AF_SLEEP_OFF);
+ IS_ISP_SET_PARAM_AA_FACE(dev,
+ ISP_AF_FACE_DISABLE);
+ IS_ISP_SET_PARAM_AA_TOUCH_X(dev, 0);
+ IS_ISP_SET_PARAM_AA_TOUCH_Y(dev, 0);
+ IS_ISP_SET_PARAM_AA_MANUAL_AF(dev, 0);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_AA);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean(
+ (void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ break;
+ case IS_FOCUS_MODE_MACRO:
+ IS_ISP_SET_PARAM_AA_MODE(dev,
+ ISP_AF_MODE_SINGLE);
+ IS_ISP_SET_PARAM_AA_SCENE(dev,
+ ISP_AF_SCENE_MACRO);
+ IS_ISP_SET_PARAM_AA_SLEEP(dev,
+ ISP_AF_SLEEP_OFF);
+ IS_ISP_SET_PARAM_AA_FACE(dev,
+ ISP_AF_FACE_DISABLE);
+ IS_ISP_SET_PARAM_AA_TOUCH_X(dev, 0);
+ IS_ISP_SET_PARAM_AA_TOUCH_Y(dev, 0);
+ IS_ISP_SET_PARAM_AA_MANUAL_AF(dev, 0);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_AA);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean(
+ (void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ ret = wait_event_timeout(dev->irq_queue,
+ (dev->af.af_state == FIMC_IS_AF_IDLE), HZ/5);
+ if (!ret) {
+ dev_err(&dev->pdev->dev,
+ "Focus change timeout:%s\n", __func__);
+ return -EBUSY;
+ }
+ break;
+ case IS_FOCUS_MODE_CONTINUOUS:
+ IS_ISP_SET_PARAM_AA_MODE(dev,
+ ISP_AF_MODE_CONTINUOUS);
+ IS_ISP_SET_PARAM_AA_SCENE(dev,
+ ISP_AF_SCENE_NORMAL);
+ IS_ISP_SET_PARAM_AA_SLEEP(dev,
+ ISP_AF_SLEEP_OFF);
+ IS_ISP_SET_PARAM_AA_FACE(dev,
+ ISP_AF_FACE_DISABLE);
+ IS_ISP_SET_PARAM_AA_TOUCH_X(dev, 0);
+ IS_ISP_SET_PARAM_AA_TOUCH_Y(dev, 0);
+ IS_ISP_SET_PARAM_AA_MANUAL_AF(dev, 0);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_AA);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean(
+ (void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ ret = wait_event_timeout(dev->irq_queue,
+ (dev->af.af_state == FIMC_IS_AF_IDLE), HZ/5);
+ if (!ret) {
+ dev_err(&dev->pdev->dev,
+ "Focus change timeout:%s\n", __func__);
+ return -EBUSY;
+ }
+ break;
+ default:
+ /* If other AF mode, there is no
+ cancelation process*/
+ break;
+ }
+ dev->af.mode = IS_FOCUS_MODE_IDLE;
+ }
+ break;
+ case AUTO_FOCUS_ON:
+ if (!is_af_use(dev)) {
+ /* 6A3 can't support AF */
+ dev->af.af_state = FIMC_IS_AF_LOCK;
+ dev->af.af_lock_state = FIMC_IS_AF_LOCKED;
+ dev->is_shared_region->af_status = 1;
+ fimc_is_mem_cache_clean((void *)IS_SHARED(dev),
+ (unsigned long)(sizeof(struct is_share_region)));
+ } else {
+ dev->af.af_lock_state = 0;
+ dev->af.ae_lock_state = 0;
+ dev->af.awb_lock_state = 0;
+ dev->is_shared_region->af_status = 0;
+ fimc_is_mem_cache_clean((void *)IS_SHARED(dev),
+ (unsigned long)(sizeof(struct is_share_region)));
+ IS_ISP_SET_PARAM_AA_CMD(dev,
+ ISP_AA_COMMAND_START);
+ IS_ISP_SET_PARAM_AA_TARGET(dev, ISP_AA_TARGET_AF);
+ IS_ISP_SET_PARAM_AA_MODE(dev, ISP_AF_MODE_SINGLE);
+ IS_ISP_SET_PARAM_AA_SLEEP(dev, ISP_AF_SLEEP_OFF);
+ IS_ISP_SET_PARAM_AA_FACE(dev, ISP_AF_FACE_DISABLE);
+ IS_ISP_SET_PARAM_AA_TOUCH_X(dev, 0);
+ IS_ISP_SET_PARAM_AA_TOUCH_Y(dev, 0);
+ IS_ISP_SET_PARAM_AA_MANUAL_AF(dev, 0);
+ switch (dev->af.mode) {
+ case IS_FOCUS_MODE_AUTO:
+ IS_ISP_SET_PARAM_AA_SCENE(dev,
+ ISP_AF_SCENE_NORMAL);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_AA);
+ IS_INC_PARAM_NUM(dev);
+ dev->af.af_state =
+ FIMC_IS_AF_SETCONFIG;
+ fimc_is_mem_cache_clean(
+ (void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ ret = wait_event_timeout(dev->irq_queue,
+ (dev->af.af_state == FIMC_IS_AF_RUNNING), HZ/5);
+ if (!ret) {
+ dev_err(&dev->pdev->dev,
+ "Focus change timeout:%s\n", __func__);
+ return -EBUSY;
+ }
+ break;
+ case IS_FOCUS_MODE_MACRO:
+ IS_ISP_SET_PARAM_AA_SCENE(dev,
+ ISP_AF_SCENE_MACRO);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_AA);
+ IS_INC_PARAM_NUM(dev);
+ dev->af.af_state =
+ FIMC_IS_AF_SETCONFIG;
+ fimc_is_mem_cache_clean(
+ (void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ ret = wait_event_timeout(dev->irq_queue,
+ (dev->af.af_state == FIMC_IS_AF_RUNNING), HZ/5);
+ if (!ret) {
+ dev_err(&dev->pdev->dev,
+ "Focus change timeout:%s\n", __func__);
+ return -EBUSY;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+int fimc_is_v4l2_touch_af_start_stop(struct fimc_is_dev *dev, int value)
+{
+ int ret = 0;
+ switch (value) {
+ case TOUCH_AF_STOP:
+ if (!is_af_use(dev)) {
+ /* 6A3 can't support AF */
+ dev->af.af_state = FIMC_IS_AF_IDLE;
+ } else {
+ if (dev->af.af_state == FIMC_IS_AF_IDLE)
+ return ret;
+ /* Abort or lock CAF */
+ dev->af.af_state = FIMC_IS_AF_ABORT;
+ IS_ISP_SET_PARAM_AA_CMD(dev, ISP_AA_COMMAND_STOP);
+ IS_ISP_SET_PARAM_AA_TARGET(dev, ISP_AA_TARGET_AF);
+
+ IS_ISP_SET_PARAM_AA_MODE(dev,
+ ISP_AF_MODE_TOUCH);
+ IS_ISP_SET_PARAM_AA_SCENE(dev,
+ ISP_AF_SCENE_NORMAL);
+ IS_ISP_SET_PARAM_AA_SLEEP(dev,
+ ISP_AF_SLEEP_OFF);
+ IS_ISP_SET_PARAM_AA_FACE(dev,
+ ISP_AF_FACE_DISABLE);
+ IS_ISP_SET_PARAM_AA_TOUCH_X(dev, 0);
+ IS_ISP_SET_PARAM_AA_TOUCH_Y(dev, 0);
+ IS_ISP_SET_PARAM_AA_MANUAL_AF(dev, 0);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_AA);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean(
+ (void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ ret = wait_event_timeout(dev->irq_queue,
+ (dev->af.af_state == FIMC_IS_AF_IDLE), HZ/5);
+ if (!ret) {
+ dev_err(&dev->pdev->dev,
+ "Focus change timeout:%s\n", __func__);
+ return -EBUSY;
+ }
+ }
+ break;
+ case TOUCH_AF_START:
+ if (!is_af_use(dev)) {
+ /* 6A3 can't support AF */
+ dev->af.af_state = FIMC_IS_AF_LOCK;
+ dev->af.af_lock_state = FIMC_IS_AF_LOCKED;
+ dev->is_shared_region->af_status = 1;
+ fimc_is_mem_cache_clean((void *)IS_SHARED(dev),
+ (unsigned long)(sizeof(struct is_share_region)));
+ } else {
+ dev->af.mode = IS_FOCUS_MODE_TOUCH;
+ IS_ISP_SET_PARAM_AA_CMD(dev, ISP_AA_COMMAND_START);
+ IS_ISP_SET_PARAM_AA_TARGET(dev, ISP_AA_TARGET_AF);
+ IS_ISP_SET_PARAM_AA_MODE(dev, ISP_AF_MODE_TOUCH);
+ IS_ISP_SET_PARAM_AA_SLEEP(dev, ISP_AF_SLEEP_OFF);
+ IS_ISP_SET_PARAM_AA_FACE(dev, ISP_AF_FACE_DISABLE);
+ IS_ISP_SET_PARAM_AA_TOUCH_X(dev, dev->af.pos_x);
+ IS_ISP_SET_PARAM_AA_TOUCH_Y(dev, dev->af.pos_y);
+ IS_ISP_SET_PARAM_AA_MANUAL_AF(dev, 0);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_AA);
+ IS_INC_PARAM_NUM(dev);
+ dev->af.af_state = FIMC_IS_AF_SETCONFIG;
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ dev->af.af_lock_state = 0;
+ dev->af.ae_lock_state = 0;
+ dev->af.awb_lock_state = 0;
+ }
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+int fimc_is_v4l2_caf_start_stop(struct fimc_is_dev *dev, int value)
+{
+ int ret = 0;
+ switch (value) {
+ case CAF_STOP:
+ if (!is_af_use(dev)) {
+ /* 6A3 can't support AF */
+ dev->af.af_state = FIMC_IS_AF_IDLE;
+ } else {
+ if (dev->af.af_state == FIMC_IS_AF_IDLE)
+ return ret;
+ /* Abort or lock CAF */
+ dev->af.af_state = FIMC_IS_AF_ABORT;
+ IS_ISP_SET_PARAM_AA_CMD(dev, ISP_AA_COMMAND_STOP);
+ IS_ISP_SET_PARAM_AA_TARGET(dev, ISP_AA_TARGET_AF);
+
+ IS_ISP_SET_PARAM_AA_MODE(dev,
+ ISP_AF_MODE_CONTINUOUS);
+ IS_ISP_SET_PARAM_AA_SCENE(dev,
+ ISP_AF_SCENE_NORMAL);
+ IS_ISP_SET_PARAM_AA_SLEEP(dev,
+ ISP_AF_SLEEP_OFF);
+ IS_ISP_SET_PARAM_AA_FACE(dev,
+ ISP_AF_FACE_DISABLE);
+ IS_ISP_SET_PARAM_AA_TOUCH_X(dev, 0);
+ IS_ISP_SET_PARAM_AA_TOUCH_Y(dev, 0);
+ IS_ISP_SET_PARAM_AA_MANUAL_AF(dev, 0);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_AA);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean(
+ (void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ ret = wait_event_timeout(dev->irq_queue,
+ (dev->af.af_state == FIMC_IS_AF_IDLE), HZ/5);
+ if (!ret) {
+ dev_err(&dev->pdev->dev,
+ "Focus change timeout:%s\n", __func__);
+ return -EBUSY;
+ }
+ }
+ break;
+ case CAF_START:
+ if (!is_af_use(dev)) {
+ /* 6A3 can't support AF */
+ dev->af.af_state = FIMC_IS_AF_LOCK;
+ dev->af.af_lock_state = FIMC_IS_AF_LOCKED;
+ dev->is_shared_region->af_status = 1;
+ fimc_is_mem_cache_clean((void *)IS_SHARED(dev),
+ (unsigned long)(sizeof(struct is_share_region)));
+ } else {
+ dev->af.mode = IS_FOCUS_MODE_CONTINUOUS;
+ IS_ISP_SET_PARAM_AA_CMD(dev, ISP_AA_COMMAND_START);
+ IS_ISP_SET_PARAM_AA_TARGET(dev, ISP_AA_TARGET_AF);
+ IS_ISP_SET_PARAM_AA_MODE(dev, ISP_AF_MODE_CONTINUOUS);
+ IS_ISP_SET_PARAM_AA_SLEEP(dev, ISP_AF_SLEEP_OFF);
+ IS_ISP_SET_PARAM_AA_FACE(dev, ISP_AF_FACE_DISABLE);
+ IS_ISP_SET_PARAM_AA_TOUCH_X(dev, 0);
+ IS_ISP_SET_PARAM_AA_TOUCH_Y(dev, 0);
+ IS_ISP_SET_PARAM_AA_MANUAL_AF(dev, 0);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_AA);
+ IS_INC_PARAM_NUM(dev);
+ dev->af.af_state = FIMC_IS_AF_SETCONFIG;
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ dev->af.af_lock_state = 0;
+ dev->af.ae_lock_state = 0;
+ dev->af.awb_lock_state = 0;
+ dev->af.prev_pos_x = 0;
+ dev->af.prev_pos_y = 0;
+ }
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+int fimc_is_v4l2_isp_iso(struct fimc_is_dev *dev, int value)
+{
+ int ret = 0;
+ switch (value) {
+ case ISO_AUTO:
+ IS_ISP_SET_PARAM_ISO_CMD(dev, ISP_ISO_COMMAND_AUTO);
+ IS_ISP_SET_PARAM_ISO_VALUE(dev, 0);
+ break;
+ case ISO_100:
+ IS_ISP_SET_PARAM_ISO_CMD(dev, ISP_ISO_COMMAND_MANUAL);
+ IS_ISP_SET_PARAM_ISO_VALUE(dev, 100);
+ break;
+ case ISO_200:
+ IS_ISP_SET_PARAM_ISO_CMD(dev, ISP_ISO_COMMAND_MANUAL);
+ IS_ISP_SET_PARAM_ISO_VALUE(dev, 200);
+ break;
+ case ISO_400:
+ IS_ISP_SET_PARAM_ISO_CMD(dev, ISP_ISO_COMMAND_MANUAL);
+ IS_ISP_SET_PARAM_ISO_VALUE(dev, 400);
+ break;
+ case ISO_800:
+ IS_ISP_SET_PARAM_ISO_CMD(dev, ISP_ISO_COMMAND_MANUAL);
+ IS_ISP_SET_PARAM_ISO_VALUE(dev, 800);
+ break;
+ case ISO_1600:
+ IS_ISP_SET_PARAM_ISO_CMD(dev, ISP_ISO_COMMAND_MANUAL);
+ IS_ISP_SET_PARAM_ISO_VALUE(dev, 1600);
+ break;
+ default:
+ return ret;
+ }
+ if (value >= ISO_AUTO && value < ISO_MAX) {
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_ISO);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ }
+ return ret;
+}
+
+int fimc_is_v4l2_isp_effect(struct fimc_is_dev *dev, int value)
+{
+ int ret = 0;
+ switch (value) {
+ case IS_IMAGE_EFFECT_DISABLE:
+ IS_ISP_SET_PARAM_EFFECT_CMD(dev, ISP_IMAGE_EFFECT_DISABLE);
+ break;
+ case IS_IMAGE_EFFECT_MONOCHROME:
+ IS_ISP_SET_PARAM_EFFECT_CMD(dev, ISP_IMAGE_EFFECT_MONOCHROME);
+ break;
+ case IS_IMAGE_EFFECT_NEGATIVE_MONO:
+ IS_ISP_SET_PARAM_EFFECT_CMD(dev,
+ ISP_IMAGE_EFFECT_NEGATIVE_MONO);
+ break;
+ case IS_IMAGE_EFFECT_NEGATIVE_COLOR:
+ IS_ISP_SET_PARAM_EFFECT_CMD(dev,
+ ISP_IMAGE_EFFECT_NEGATIVE_COLOR);
+ break;
+ case IS_IMAGE_EFFECT_SEPIA:
+ IS_ISP_SET_PARAM_EFFECT_CMD(dev, ISP_IMAGE_EFFECT_SEPIA);
+ break;
+ }
+ /* only ISP effect in Pegasus */
+ if (value >= 0 && value < 5) {
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_IMAGE_EFFECT);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ }
+ return ret;
+}
+
+int fimc_is_v4l2_isp_effect_legacy(struct fimc_is_dev *dev, int value)
+{
+ int ret = 0;
+ switch (value) {
+ case IMAGE_EFFECT_NONE:
+ IS_ISP_SET_PARAM_EFFECT_CMD(dev, ISP_IMAGE_EFFECT_DISABLE);
+ break;
+ case IMAGE_EFFECT_BNW:
+ IS_ISP_SET_PARAM_EFFECT_CMD(dev, ISP_IMAGE_EFFECT_MONOCHROME);
+ break;
+ case IMAGE_EFFECT_NEGATIVE:
+ IS_ISP_SET_PARAM_EFFECT_CMD(dev,
+ ISP_IMAGE_EFFECT_NEGATIVE_COLOR);
+ break;
+ case IMAGE_EFFECT_SEPIA:
+ IS_ISP_SET_PARAM_EFFECT_CMD(dev, ISP_IMAGE_EFFECT_SEPIA);
+ break;
+ default:
+ return ret;
+ }
+ /* only ISP effect in Pegasus */
+ if (value > IMAGE_EFFECT_BASE && value < IMAGE_EFFECT_MAX) {
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_IMAGE_EFFECT);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ }
+ return ret;
+}
+
+int fimc_is_v4l2_isp_flash_mode(struct fimc_is_dev *dev, int value)
+{
+ int ret = 0;
+ switch (value) {
+ case FLASH_MODE_OFF:
+ IS_ISP_SET_PARAM_FLASH_CMD(dev, ISP_FLASH_COMMAND_DISABLE);
+ IS_ISP_SET_PARAM_FLASH_REDEYE(dev, ISP_FLASH_REDEYE_DISABLE);
+ break;
+ case FLASH_MODE_AUTO:
+ IS_ISP_SET_PARAM_FLASH_CMD(dev, ISP_FLASH_COMMAND_AUTO);
+ IS_ISP_SET_PARAM_FLASH_REDEYE(dev, ISP_FLASH_REDEYE_ENABLE);
+ break;
+ case FLASH_MODE_ON:
+ IS_ISP_SET_PARAM_FLASH_CMD(dev, ISP_FLASH_COMMAND_MANUALON);
+ IS_ISP_SET_PARAM_FLASH_REDEYE(dev, ISP_FLASH_REDEYE_DISABLE);
+ break;
+ case FLASH_MODE_TORCH:
+ IS_ISP_SET_PARAM_FLASH_CMD(dev, ISP_FLASH_COMMAND_TORCH);
+ IS_ISP_SET_PARAM_FLASH_REDEYE(dev, ISP_FLASH_REDEYE_DISABLE);
+ break;
+ default:
+ return ret;
+ }
+ if (value > FLASH_MODE_BASE && value < FLASH_MODE_MAX) {
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_FLASH);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ }
+ return ret;
+}
+
+int fimc_is_v4l2_awb_mode(struct fimc_is_dev *dev, int value)
+{
+ int ret = 0;
+ switch (value) {
+ case IS_AWB_AUTO:
+ IS_ISP_SET_PARAM_AWB_CMD(dev, ISP_AWB_COMMAND_AUTO);
+ IS_ISP_SET_PARAM_AWB_ILLUMINATION(dev, 0);
+ break;
+ case IS_AWB_DAYLIGHT:
+ IS_ISP_SET_PARAM_AWB_CMD(dev, ISP_AWB_COMMAND_ILLUMINATION);
+ IS_ISP_SET_PARAM_AWB_ILLUMINATION(dev,
+ ISP_AWB_ILLUMINATION_DAYLIGHT);
+ break;
+ case IS_AWB_CLOUDY:
+ IS_ISP_SET_PARAM_AWB_CMD(dev, ISP_AWB_COMMAND_ILLUMINATION);
+ IS_ISP_SET_PARAM_AWB_ILLUMINATION(dev,
+ ISP_AWB_ILLUMINATION_CLOUDY);
+ break;
+ case IS_AWB_TUNGSTEN:
+ IS_ISP_SET_PARAM_AWB_CMD(dev, ISP_AWB_COMMAND_ILLUMINATION);
+ IS_ISP_SET_PARAM_AWB_ILLUMINATION(dev,
+ ISP_AWB_ILLUMINATION_TUNGSTEN);
+ break;
+ case IS_AWB_FLUORESCENT:
+ IS_ISP_SET_PARAM_AWB_CMD(dev, ISP_AWB_COMMAND_ILLUMINATION);
+ IS_ISP_SET_PARAM_AWB_ILLUMINATION(dev,
+ ISP_AWB_ILLUMINATION_FLUORESCENT);
+ break;
+ }
+ if (value >= IS_AWB_AUTO && value < IS_AWB_MAX) {
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_AWB);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ }
+ return ret;
+}
+
+int fimc_is_v4l2_awb_mode_legacy(struct fimc_is_dev *dev, int value)
+{
+ int ret = 0;
+ switch (value) {
+ case WHITE_BALANCE_AUTO:
+ IS_ISP_SET_PARAM_AWB_CMD(dev, ISP_AWB_COMMAND_AUTO);
+ IS_ISP_SET_PARAM_AWB_ILLUMINATION(dev, 0);
+ break;
+ case WHITE_BALANCE_SUNNY:
+ IS_ISP_SET_PARAM_AWB_CMD(dev, ISP_AWB_COMMAND_ILLUMINATION);
+ IS_ISP_SET_PARAM_AWB_ILLUMINATION(dev,
+ ISP_AWB_ILLUMINATION_DAYLIGHT);
+ break;
+ case WHITE_BALANCE_CLOUDY:
+ IS_ISP_SET_PARAM_AWB_CMD(dev, ISP_AWB_COMMAND_ILLUMINATION);
+ IS_ISP_SET_PARAM_AWB_ILLUMINATION(dev,
+ ISP_AWB_ILLUMINATION_CLOUDY);
+ break;
+ case WHITE_BALANCE_TUNGSTEN:
+ IS_ISP_SET_PARAM_AWB_CMD(dev, ISP_AWB_COMMAND_ILLUMINATION);
+ IS_ISP_SET_PARAM_AWB_ILLUMINATION(dev,
+ ISP_AWB_ILLUMINATION_TUNGSTEN);
+ break;
+ case WHITE_BALANCE_FLUORESCENT:
+ IS_ISP_SET_PARAM_AWB_CMD(dev, ISP_AWB_COMMAND_ILLUMINATION);
+ IS_ISP_SET_PARAM_AWB_ILLUMINATION(dev,
+ ISP_AWB_ILLUMINATION_FLUORESCENT);
+ break;
+ }
+ if (value > WHITE_BALANCE_BASE && value < WHITE_BALANCE_MAX) {
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_AWB);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ }
+ return ret;
+}
+
+int fimc_is_v4l2_isp_contrast(struct fimc_is_dev *dev, int value)
+{
+ int ret = 0;
+ switch (value) {
+ case IS_CONTRAST_AUTO:
+ IS_ISP_SET_PARAM_ADJUST_CMD(dev, ISP_ADJUST_COMMAND_AUTO);
+ break;
+ case IS_CONTRAST_MINUS_2:
+ IS_ISP_SET_PARAM_ADJUST_CMD(dev,
+ ISP_ADJUST_COMMAND_MANUAL_CONTRAST);
+ IS_ISP_SET_PARAM_ADJUST_CONTRAST(dev, -2);
+ break;
+ case IS_CONTRAST_MINUS_1:
+ IS_ISP_SET_PARAM_ADJUST_CMD(dev,
+ ISP_ADJUST_COMMAND_MANUAL_CONTRAST);
+ IS_ISP_SET_PARAM_ADJUST_CONTRAST(dev, -1);
+ break;
+ case IS_CONTRAST_DEFAULT:
+ IS_ISP_SET_PARAM_ADJUST_CMD(dev,
+ ISP_ADJUST_COMMAND_MANUAL_CONTRAST);
+ IS_ISP_SET_PARAM_ADJUST_CONTRAST(dev, 0);
+ break;
+ case IS_CONTRAST_PLUS_1:
+ IS_ISP_SET_PARAM_ADJUST_CMD(dev,
+ ISP_ADJUST_COMMAND_MANUAL_CONTRAST);
+ IS_ISP_SET_PARAM_ADJUST_CONTRAST(dev, 1);
+ break;
+ case IS_CONTRAST_PLUS_2:
+ IS_ISP_SET_PARAM_ADJUST_CMD(dev,
+ ISP_ADJUST_COMMAND_MANUAL_CONTRAST);
+ IS_ISP_SET_PARAM_ADJUST_CONTRAST(dev, 2);
+ break;
+ default:
+ return ret;
+ }
+ if (value >= 0 && value < IS_CONTRAST_MAX) {
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_ADJUST);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ }
+ return ret;
+}
+
+int fimc_is_v4l2_isp_contrast_legacy(struct fimc_is_dev *dev, int value)
+{
+ int ret = 0;
+ switch (value) {
+ case CONTRAST_MINUS_2:
+ IS_ISP_SET_PARAM_ADJUST_CMD(dev,
+ ISP_ADJUST_COMMAND_MANUAL_CONTRAST);
+ IS_ISP_SET_PARAM_ADJUST_CONTRAST(dev, -2);
+ break;
+ case CONTRAST_MINUS_1:
+ IS_ISP_SET_PARAM_ADJUST_CMD(dev,
+ ISP_ADJUST_COMMAND_MANUAL_CONTRAST);
+ IS_ISP_SET_PARAM_ADJUST_CONTRAST(dev, -1);
+ break;
+ case CONTRAST_DEFAULT:
+ IS_ISP_SET_PARAM_ADJUST_CMD(dev,
+ ISP_ADJUST_COMMAND_MANUAL_CONTRAST);
+ IS_ISP_SET_PARAM_ADJUST_CONTRAST(dev, 0);
+ break;
+ case CONTRAST_PLUS_1:
+ IS_ISP_SET_PARAM_ADJUST_CMD(dev,
+ ISP_ADJUST_COMMAND_MANUAL_CONTRAST);
+ IS_ISP_SET_PARAM_ADJUST_CONTRAST(dev, 1);
+ break;
+ case CONTRAST_PLUS_2:
+ IS_ISP_SET_PARAM_ADJUST_CMD(dev,
+ ISP_ADJUST_COMMAND_MANUAL_CONTRAST);
+ IS_ISP_SET_PARAM_ADJUST_CONTRAST(dev, 2);
+ break;
+ default:
+ return ret;
+ }
+ if (value >= 0 && value < CONTRAST_MAX) {
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_ADJUST);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ }
+ return ret;
+}
+
+int fimc_is_v4l2_isp_saturation(struct fimc_is_dev *dev, int value)
+{
+ int ret = 0;
+ switch (value) {
+ case SATURATION_MINUS_2:
+ IS_ISP_SET_PARAM_ADJUST_CMD(dev,
+ ISP_ADJUST_COMMAND_MANUAL_SATURATION);
+ IS_ISP_SET_PARAM_ADJUST_SATURATION(dev, -2);
+ break;
+ case SATURATION_MINUS_1:
+ IS_ISP_SET_PARAM_ADJUST_CMD(dev,
+ ISP_ADJUST_COMMAND_MANUAL_SATURATION);
+ IS_ISP_SET_PARAM_ADJUST_SATURATION(dev, -1);
+ break;
+ case SATURATION_DEFAULT:
+ IS_ISP_SET_PARAM_ADJUST_CMD(dev,
+ ISP_ADJUST_COMMAND_MANUAL_SATURATION);
+ IS_ISP_SET_PARAM_ADJUST_SATURATION(dev, 0);
+ break;
+ case SATURATION_PLUS_1:
+ IS_ISP_SET_PARAM_ADJUST_CMD(dev,
+ ISP_ADJUST_COMMAND_MANUAL_SATURATION);
+ IS_ISP_SET_PARAM_ADJUST_SATURATION(dev, 1);
+ break;
+ case SATURATION_PLUS_2:
+ IS_ISP_SET_PARAM_ADJUST_CMD(dev,
+ ISP_ADJUST_COMMAND_MANUAL_SATURATION);
+ IS_ISP_SET_PARAM_ADJUST_SATURATION(dev, 2);
+ break;
+ default:
+ return ret;
+ }
+ if (value >= 0 && value < SATURATION_MAX) {
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_ADJUST);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ }
+ return ret;
+}
+
+int fimc_is_v4l2_isp_sharpness(struct fimc_is_dev *dev, int value)
+{
+ int ret = 0;
+
+ switch (value) {
+ case SHARPNESS_MINUS_2:
+ IS_ISP_SET_PARAM_ADJUST_CMD(dev,
+ ISP_ADJUST_COMMAND_MANUAL_SHARPNESS);
+ IS_ISP_SET_PARAM_ADJUST_SHARPNESS(dev, -2);
+ break;
+ case SHARPNESS_MINUS_1:
+ IS_ISP_SET_PARAM_ADJUST_CMD(dev,
+ ISP_ADJUST_COMMAND_MANUAL_SHARPNESS);
+ IS_ISP_SET_PARAM_ADJUST_SHARPNESS(dev, -1);
+ break;
+ case SHARPNESS_DEFAULT:
+ IS_ISP_SET_PARAM_ADJUST_CMD(dev,
+ ISP_ADJUST_COMMAND_MANUAL_SHARPNESS);
+ IS_ISP_SET_PARAM_ADJUST_SHARPNESS(dev, 0);
+ break;
+ case SHARPNESS_PLUS_1:
+ IS_ISP_SET_PARAM_ADJUST_CMD(dev,
+ ISP_ADJUST_COMMAND_MANUAL_SHARPNESS);
+ IS_ISP_SET_PARAM_ADJUST_SHARPNESS(dev, 1);
+ break;
+ case SHARPNESS_PLUS_2:
+ IS_ISP_SET_PARAM_ADJUST_CMD(dev,
+ ISP_ADJUST_COMMAND_MANUAL_SHARPNESS);
+ IS_ISP_SET_PARAM_ADJUST_SHARPNESS(dev, 2);
+ break;
+ default:
+ return ret;
+ }
+ if (value >= 0 && value < SHARPNESS_MAX) {
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_ADJUST);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ }
+ return ret;
+}
+
+int fimc_is_v4l2_isp_exposure(struct fimc_is_dev *dev, int value)
+{
+ int ret = 0;
+ switch (value) {
+ case IS_EXPOSURE_MINUS_4:
+ IS_ISP_SET_PARAM_ADJUST_CMD(dev,
+ ISP_ADJUST_COMMAND_MANUAL_EXPOSURE);
+ IS_ISP_SET_PARAM_ADJUST_EXPOSURE(dev, -4);
+ break;
+ case IS_EXPOSURE_MINUS_3:
+ IS_ISP_SET_PARAM_ADJUST_CMD(dev,
+ ISP_ADJUST_COMMAND_MANUAL_EXPOSURE);
+ IS_ISP_SET_PARAM_ADJUST_EXPOSURE(dev, -3);
+ break;
+ case IS_EXPOSURE_MINUS_2:
+ IS_ISP_SET_PARAM_ADJUST_CMD(dev,
+ ISP_ADJUST_COMMAND_MANUAL_EXPOSURE);
+ IS_ISP_SET_PARAM_ADJUST_EXPOSURE(dev, -2);
+ break;
+ case IS_EXPOSURE_MINUS_1:
+ IS_ISP_SET_PARAM_ADJUST_CMD(dev,
+ ISP_ADJUST_COMMAND_MANUAL_EXPOSURE);
+ IS_ISP_SET_PARAM_ADJUST_EXPOSURE(dev, -1);
+ break;
+ case IS_EXPOSURE_DEFAULT:
+ IS_ISP_SET_PARAM_ADJUST_CMD(dev,
+ ISP_ADJUST_COMMAND_MANUAL_EXPOSURE);
+ IS_ISP_SET_PARAM_ADJUST_EXPOSURE(dev, 0);
+ break;
+ case IS_EXPOSURE_PLUS_1:
+ IS_ISP_SET_PARAM_ADJUST_CMD(dev,
+ ISP_ADJUST_COMMAND_MANUAL_EXPOSURE);
+ IS_ISP_SET_PARAM_ADJUST_EXPOSURE(dev, 1);
+ break;
+ case IS_EXPOSURE_PLUS_2:
+ IS_ISP_SET_PARAM_ADJUST_CMD(dev,
+ ISP_ADJUST_COMMAND_MANUAL_EXPOSURE);
+ IS_ISP_SET_PARAM_ADJUST_EXPOSURE(dev, 2);
+ break;
+ case IS_EXPOSURE_PLUS_3:
+ IS_ISP_SET_PARAM_ADJUST_CMD(dev,
+ ISP_ADJUST_COMMAND_MANUAL_EXPOSURE);
+ IS_ISP_SET_PARAM_ADJUST_EXPOSURE(dev, 3);
+ break;
+ case IS_EXPOSURE_PLUS_4:
+ IS_ISP_SET_PARAM_ADJUST_CMD(dev,
+ ISP_ADJUST_COMMAND_MANUAL_EXPOSURE);
+ IS_ISP_SET_PARAM_ADJUST_EXPOSURE(dev, 4);
+ break;
+ default:
+ return ret;
+ }
+ if (value >= 0 && value < IS_EXPOSURE_MAX) {
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_ADJUST);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ }
+ return ret;
+}
+
+int fimc_is_v4l2_isp_exposure_legacy(struct fimc_is_dev *dev, int value)
+{
+ int ret = 0;
+ if (value >= -4 && value < 5) {
+ IS_ISP_SET_PARAM_ADJUST_CMD(dev,
+ ISP_ADJUST_COMMAND_MANUAL_EXPOSURE);
+ IS_ISP_SET_PARAM_ADJUST_EXPOSURE(dev, value);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_ADJUST);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ }
+ return ret;
+}
+
+int fimc_is_v4l2_isp_brightness(struct fimc_is_dev *dev, int value)
+{
+ int ret = 0;
+ switch (value) {
+ case IS_BRIGHTNESS_MINUS_2:
+ IS_ISP_SET_PARAM_ADJUST_CMD(dev,
+ ISP_ADJUST_COMMAND_MANUAL_BRIGHTNESS);
+ IS_ISP_SET_PARAM_ADJUST_BRIGHTNESS(dev, -2);
+ break;
+ case IS_BRIGHTNESS_MINUS_1:
+ IS_ISP_SET_PARAM_ADJUST_CMD(dev,
+ ISP_ADJUST_COMMAND_MANUAL_BRIGHTNESS);
+ IS_ISP_SET_PARAM_ADJUST_BRIGHTNESS(dev, -1);
+ break;
+ case IS_BRIGHTNESS_DEFAULT:
+ IS_ISP_SET_PARAM_ADJUST_CMD(dev,
+ ISP_ADJUST_COMMAND_MANUAL_BRIGHTNESS);
+ IS_ISP_SET_PARAM_ADJUST_BRIGHTNESS(dev, 0);
+ break;
+ case IS_BRIGHTNESS_PLUS_1:
+ IS_ISP_SET_PARAM_ADJUST_CMD(dev,
+ ISP_ADJUST_COMMAND_MANUAL_BRIGHTNESS);
+ IS_ISP_SET_PARAM_ADJUST_BRIGHTNESS(dev, 1);
+ break;
+ case IS_BRIGHTNESS_PLUS_2:
+ IS_ISP_SET_PARAM_ADJUST_CMD(dev,
+ ISP_ADJUST_COMMAND_MANUAL_BRIGHTNESS);
+ IS_ISP_SET_PARAM_ADJUST_BRIGHTNESS(dev, 2);
+ break;
+ }
+ if (value >= 0 && value < IS_BRIGHTNESS_MAX) {
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_ADJUST);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ }
+ return ret;
+}
+
+int fimc_is_v4l2_isp_hue(struct fimc_is_dev *dev, int value)
+{
+ int ret = 0;
+ switch (value) {
+ case IS_HUE_MINUS_2:
+ IS_ISP_SET_PARAM_ADJUST_CMD(dev,
+ ISP_ADJUST_COMMAND_MANUAL_HUE);
+ IS_ISP_SET_PARAM_ADJUST_HUE(dev, -2);
+ break;
+ case IS_HUE_MINUS_1:
+ IS_ISP_SET_PARAM_ADJUST_CMD(dev,
+ ISP_ADJUST_COMMAND_MANUAL_HUE);
+ IS_ISP_SET_PARAM_ADJUST_HUE(dev, -1);
+ break;
+ case IS_HUE_DEFAULT:
+ IS_ISP_SET_PARAM_ADJUST_CMD(dev,
+ ISP_ADJUST_COMMAND_MANUAL_HUE);
+ IS_ISP_SET_PARAM_ADJUST_HUE(dev, 0);
+ break;
+ case IS_HUE_PLUS_1:
+ IS_ISP_SET_PARAM_ADJUST_CMD(dev,
+ ISP_ADJUST_COMMAND_MANUAL_HUE);
+ IS_ISP_SET_PARAM_ADJUST_HUE(dev, 1);
+ break;
+ case IS_HUE_PLUS_2:
+ IS_ISP_SET_PARAM_ADJUST_CMD(dev,
+ ISP_ADJUST_COMMAND_MANUAL_HUE);
+ IS_ISP_SET_PARAM_ADJUST_HUE(dev, 2);
+ break;
+ default:
+ return ret;
+ }
+ if (value >= IS_HUE_MINUS_2 && value < IS_HUE_MAX) {
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_ADJUST);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ }
+ return ret;
+}
+
+int fimc_is_v4l2_isp_metering(struct fimc_is_dev *dev, int value)
+{
+ int ret = 0;
+ switch (value) {
+ case IS_METERING_AVERAGE:
+ IS_ISP_SET_PARAM_METERING_CMD(dev,
+ ISP_METERING_COMMAND_AVERAGE);
+ break;
+ case IS_METERING_SPOT:
+ IS_ISP_SET_PARAM_METERING_CMD(dev, ISP_METERING_COMMAND_SPOT);
+ break;
+ case IS_METERING_MATRIX:
+ IS_ISP_SET_PARAM_METERING_CMD(dev, ISP_METERING_COMMAND_MATRIX);
+ break;
+ case IS_METERING_CENTER:
+ IS_ISP_SET_PARAM_METERING_CMD(dev, ISP_METERING_COMMAND_CENTER);
+ break;
+ default:
+ return ret;
+ }
+ if (value >= 0 && value < IS_METERING_MAX) {
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_METERING);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ }
+ return ret;
+}
+
+int fimc_is_v4l2_isp_metering_legacy(struct fimc_is_dev *dev, int value)
+{
+ int ret = 0;
+ switch (value) {
+ case METERING_CENTER:
+ IS_ISP_SET_PARAM_METERING_CMD(dev, ISP_METERING_COMMAND_CENTER);
+ break;
+ case METERING_SPOT:
+ IS_ISP_SET_PARAM_METERING_CMD(dev, ISP_METERING_COMMAND_SPOT);
+ break;
+ case METERING_MATRIX:
+ IS_ISP_SET_PARAM_METERING_CMD(dev, ISP_METERING_COMMAND_MATRIX);
+ break;
+ default:
+ return ret;
+ }
+ if (value > METERING_BASE && value < METERING_MAX) {
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_METERING);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ }
+ return ret;
+}
+
+int fimc_is_v4l2_isp_afc(struct fimc_is_dev *dev, int value)
+{
+ int ret = 0;
+ switch (value) {
+ case IS_AFC_DISABLE:
+ IS_ISP_SET_PARAM_AFC_CMD(dev, ISP_AFC_COMMAND_DISABLE);
+ IS_ISP_SET_PARAM_AFC_MANUAL(dev, 0);
+ break;
+ case IS_AFC_AUTO:
+ IS_ISP_SET_PARAM_AFC_CMD(dev, ISP_AFC_COMMAND_AUTO);
+ IS_ISP_SET_PARAM_AFC_MANUAL(dev, 0);
+ break;
+ case IS_AFC_MANUAL_50HZ:
+ IS_ISP_SET_PARAM_AFC_CMD(dev, ISP_AFC_COMMAND_MANUAL);
+ IS_ISP_SET_PARAM_AFC_MANUAL(dev, ISP_AFC_MANUAL_50HZ);
+ break;
+ case IS_AFC_MANUAL_60HZ:
+ IS_ISP_SET_PARAM_AFC_CMD(dev, ISP_AFC_COMMAND_MANUAL);
+ IS_ISP_SET_PARAM_AFC_MANUAL(dev, ISP_AFC_MANUAL_60HZ);
+ break;
+ default:
+ return ret;
+ }
+ if (value >= 0 && value < IS_AFC_MAX) {
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_AFC);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ }
+ return ret;
+}
+
+int fimc_is_v4l2_isp_afc_legacy(struct fimc_is_dev *dev, int value)
+{
+ int ret = 0;
+ switch (value) {
+ case ANTI_BANDING_OFF:
+ IS_ISP_SET_PARAM_AFC_CMD(dev, ISP_AFC_COMMAND_DISABLE);
+ IS_ISP_SET_PARAM_AFC_MANUAL(dev, 0);
+ break;
+ case ANTI_BANDING_AUTO:
+ IS_ISP_SET_PARAM_AFC_CMD(dev, ISP_AFC_COMMAND_AUTO);
+ IS_ISP_SET_PARAM_AFC_MANUAL(dev, 0);
+ break;
+ case ANTI_BANDING_50HZ:
+ IS_ISP_SET_PARAM_AFC_CMD(dev, ISP_AFC_COMMAND_MANUAL);
+ IS_ISP_SET_PARAM_AFC_MANUAL(dev, ISP_AFC_MANUAL_50HZ);
+ break;
+ case ANTI_BANDING_60HZ:
+ IS_ISP_SET_PARAM_AFC_CMD(dev, ISP_AFC_COMMAND_MANUAL);
+ IS_ISP_SET_PARAM_AFC_MANUAL(dev, ISP_AFC_MANUAL_60HZ);
+ break;
+ default:
+ return ret;
+ }
+ if (value >= ANTI_BANDING_OFF && value <= ANTI_BANDING_60HZ) {
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_AFC);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ }
+ return ret;
+}
+
+int fimc_is_v4l2_fd_angle_mode(struct fimc_is_dev *dev, int value)
+{
+ int ret = 0;
+ switch (value) {
+ case IS_FD_ROLL_ANGLE_BASIC:
+ IS_FD_SET_PARAM_FD_CONFIG_CMD(dev,
+ FD_CONFIG_COMMAND_ROLL_ANGLE);
+ IS_FD_SET_PARAM_FD_CONFIG_ROLL_ANGLE(dev, value);
+ IS_SET_PARAM_BIT(dev, PARAM_FD_CONFIG);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ break;
+ case V4L2_CID_IS_FD_SET_YAW_ANGLE:
+ IS_FD_SET_PARAM_FD_CONFIG_CMD(dev,
+ FD_CONFIG_COMMAND_YAW_ANGLE);
+ IS_FD_SET_PARAM_FD_CONFIG_YAW_ANGLE(dev, value);
+ IS_SET_PARAM_BIT(dev, PARAM_FD_CONFIG);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ break;
+ case V4L2_CID_IS_FD_SET_SMILE_MODE:
+ IS_FD_SET_PARAM_FD_CONFIG_CMD(dev,
+ FD_CONFIG_COMMAND_SMILE_MODE);
+ IS_FD_SET_PARAM_FD_CONFIG_SMILE_MODE(dev, value);
+ IS_SET_PARAM_BIT(dev, PARAM_FD_CONFIG);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ break;
+ case V4L2_CID_IS_FD_SET_BLINK_MODE:
+ IS_FD_SET_PARAM_FD_CONFIG_CMD(dev,
+ FD_CONFIG_COMMAND_BLINK_MODE);
+ IS_FD_SET_PARAM_FD_CONFIG_BLINK_MODE(dev, value);
+ IS_SET_PARAM_BIT(dev, PARAM_FD_CONFIG);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ break;
+ case V4L2_CID_IS_FD_SET_EYE_DETECT_MODE:
+ IS_FD_SET_PARAM_FD_CONFIG_CMD(dev,
+ FD_CONFIG_COMMAND_EYES_DETECT);
+ IS_FD_SET_PARAM_FD_CONFIG_EYE_DETECT(dev, value);
+ IS_SET_PARAM_BIT(dev, PARAM_FD_CONFIG);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ break;
+ case V4L2_CID_IS_FD_SET_MOUTH_DETECT_MODE:
+ IS_FD_SET_PARAM_FD_CONFIG_CMD(dev,
+ FD_CONFIG_COMMAND_MOUTH_DETECT);
+ IS_FD_SET_PARAM_FD_CONFIG_MOUTH_DETECT(dev, value);
+ IS_SET_PARAM_BIT(dev, PARAM_FD_CONFIG);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ break;
+ case V4L2_CID_IS_FD_SET_ORIENTATION_MODE:
+ IS_FD_SET_PARAM_FD_CONFIG_CMD(dev,
+ FD_CONFIG_COMMAND_ORIENTATION);
+ IS_FD_SET_PARAM_FD_CONFIG_ORIENTATION(dev, value);
+ IS_SET_PARAM_BIT(dev, PARAM_FD_CONFIG);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ break;
+ case V4L2_CID_IS_FD_SET_ORIENTATION:
+ IS_FD_SET_PARAM_FD_CONFIG_CMD(dev,
+ FD_CONFIG_COMMAND_ORIENTATION_VALUE);
+ IS_FD_SET_PARAM_FD_CONFIG_ORIENTATION_VALUE(dev, value);
+ IS_SET_PARAM_BIT(dev, PARAM_FD_CONFIG);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+int fimc_is_v4l2_frame_rate(struct fimc_is_dev *dev, int value)
+{
+ int ret = 0;
+
+ switch (value) {
+ case 0: /* AUTO Mode */
+ IS_SENSOR_SET_FRAME_RATE(dev, 30);
+ IS_SET_PARAM_BIT(dev, PARAM_SENSOR_FRAME_RATE);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ clear_bit(IS_ST_BLOCK_CMD_CLEARED, &dev->state);
+ fimc_is_hw_set_param(dev);
+ ret = wait_event_timeout(dev->irq_queue,
+ test_bit(IS_ST_BLOCK_CMD_CLEARED, &dev->state),
+ FIMC_IS_SHUTDOWN_TIMEOUT_SENSOR);
+ if (!ret) {
+ err("wait timeout 1 : %s\n", __func__);
+ return -EINVAL;
+ }
+ if (test_bit(FIMC_IS_STATE_HW_STREAM_ON, &dev->pipe_state)) {
+ IS_ISP_SET_PARAM_CONTROL_CMD(dev, CONTROL_COMMAND_STOP);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_CONTROL);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ clear_bit(IS_ST_BLOCK_CMD_CLEARED, &dev->state);
+ fimc_is_hw_set_param(dev);
+ ret = wait_event_timeout(dev->irq_queue,
+ test_bit(IS_ST_BLOCK_CMD_CLEARED, &dev->state),
+ FIMC_IS_SHUTDOWN_TIMEOUT_SENSOR);
+ if (!ret) {
+ err("wait timeout 2: %s\n", __func__);
+ return -EINVAL;
+ }
+ }
+ IS_ISP_SET_PARAM_OTF_INPUT_CMD(dev, OTF_INPUT_COMMAND_ENABLE);
+ IS_ISP_SET_PARAM_OTF_INPUT_FRAMETIME_MIN(dev, 0);
+ IS_ISP_SET_PARAM_OTF_INPUT_FRAMETIME_MAX(dev, 66666);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_OTF_INPUT);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ clear_bit(IS_ST_BLOCK_CMD_CLEARED, &dev->state);
+ fimc_is_hw_set_param(dev);
+ ret = wait_event_timeout(dev->irq_queue,
+ test_bit(IS_ST_BLOCK_CMD_CLEARED, &dev->state),
+ FIMC_IS_SHUTDOWN_TIMEOUT_SENSOR);
+ if (!ret) {
+ err("wait timeout 3: %s\n", __func__);
+ return -EINVAL;
+ }
+ if (test_bit(FIMC_IS_STATE_HW_STREAM_ON, &dev->pipe_state)) {
+ IS_ISP_SET_PARAM_CONTROL_CMD(dev,
+ CONTROL_COMMAND_START);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_CONTROL);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ clear_bit(IS_ST_BLOCK_CMD_CLEARED, &dev->state);
+ fimc_is_hw_set_param(dev);
+ ret = wait_event_timeout(dev->irq_queue,
+ test_bit(IS_ST_BLOCK_CMD_CLEARED, &dev->state),
+ FIMC_IS_SHUTDOWN_TIMEOUT_SENSOR);
+ if (!ret) {
+ err("wait timeout 4: %s\n", __func__);
+ return -EINVAL;
+ }
+ }
+ break;
+ default:
+ IS_SENSOR_SET_FRAME_RATE(dev, value);
+ IS_SET_PARAM_BIT(dev, PARAM_SENSOR_FRAME_RATE);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ clear_bit(IS_ST_BLOCK_CMD_CLEARED, &dev->state);
+ fimc_is_hw_set_param(dev);
+ ret = wait_event_timeout(dev->irq_queue,
+ test_bit(IS_ST_BLOCK_CMD_CLEARED, &dev->state),
+ FIMC_IS_SHUTDOWN_TIMEOUT_SENSOR);
+ if (!ret) {
+ err("wait timeout 1 : %s\n", __func__);
+ return -EINVAL;
+ }
+ if (test_bit(FIMC_IS_STATE_HW_STREAM_ON, &dev->pipe_state)) {
+ IS_ISP_SET_PARAM_CONTROL_CMD(dev, CONTROL_COMMAND_STOP);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_CONTROL);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ clear_bit(IS_ST_BLOCK_CMD_CLEARED, &dev->state);
+ fimc_is_hw_set_param(dev);
+ ret = wait_event_timeout(dev->irq_queue,
+ test_bit(IS_ST_BLOCK_CMD_CLEARED, &dev->state),
+ FIMC_IS_SHUTDOWN_TIMEOUT_SENSOR);
+ if (!ret) {
+ err("wait timeout 2: %s\n", __func__);
+ return -EINVAL;
+ }
+ }
+ IS_ISP_SET_PARAM_OTF_INPUT_CMD(dev, OTF_INPUT_COMMAND_ENABLE);
+ IS_ISP_SET_PARAM_OTF_INPUT_FRAMETIME_MIN(dev, 0);
+ IS_ISP_SET_PARAM_OTF_INPUT_FRAMETIME_MAX(dev,
+ (u32)(1000000/value));
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_OTF_INPUT);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ clear_bit(IS_ST_BLOCK_CMD_CLEARED, &dev->state);
+ fimc_is_hw_set_param(dev);
+ ret = wait_event_timeout(dev->irq_queue,
+ test_bit(IS_ST_BLOCK_CMD_CLEARED, &dev->state),
+ FIMC_IS_SHUTDOWN_TIMEOUT_SENSOR);
+ if (!ret) {
+ err("wait timeout 3: %s\n", __func__);
+ return -EINVAL;
+ }
+ if (test_bit(FIMC_IS_STATE_HW_STREAM_ON, &dev->pipe_state)) {
+ IS_ISP_SET_PARAM_CONTROL_CMD(dev,
+ CONTROL_COMMAND_START);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_CONTROL);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ clear_bit(IS_ST_BLOCK_CMD_CLEARED, &dev->state);
+ fimc_is_hw_set_param(dev);
+ ret = wait_event_timeout(dev->irq_queue,
+ test_bit(IS_ST_BLOCK_CMD_CLEARED, &dev->state),
+ FIMC_IS_SHUTDOWN_TIMEOUT_SENSOR);
+ if (!ret) {
+ err("wait timeout 4: %s\n", __func__);
+ return -EINVAL;
+ }
+ }
+ }
+ return 0;
+}
+
+int fimc_is_v4l2_ae_awb_lockunlock(struct fimc_is_dev *dev, int value)
+{
+ int ret = 0;
+ switch (value) {
+ case AE_UNLOCK_AWB_UNLOCK:
+ IS_ISP_SET_PARAM_AA_CMD(dev, ISP_AA_COMMAND_START);
+ IS_ISP_SET_PARAM_AA_TARGET(dev, ISP_AA_TARGET_AE |
+ ISP_AA_TARGET_AWB);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_AA);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ break;
+ case AE_LOCK_AWB_UNLOCK:
+ IS_ISP_SET_PARAM_AA_CMD(dev, ISP_AA_COMMAND_STOP);
+ IS_ISP_SET_PARAM_AA_TARGET(dev, ISP_AA_TARGET_AE);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_AA);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ IS_ISP_SET_PARAM_AA_CMD(dev, ISP_AA_COMMAND_START);
+ IS_ISP_SET_PARAM_AA_TARGET(dev, ISP_AA_TARGET_AWB);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_AA);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ break;
+ case AE_UNLOCK_AWB_LOCK:
+ IS_ISP_SET_PARAM_AA_CMD(dev, ISP_AA_COMMAND_START);
+ IS_ISP_SET_PARAM_AA_TARGET(dev, ISP_AA_TARGET_AE);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_AA);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ IS_ISP_SET_PARAM_AA_CMD(dev, ISP_AA_COMMAND_STOP);
+ IS_ISP_SET_PARAM_AA_TARGET(dev, ISP_AA_TARGET_AWB);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_AA);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ break;
+ case AE_LOCK_AWB_LOCK:
+ IS_ISP_SET_PARAM_AA_CMD(dev, ISP_AA_COMMAND_STOP);
+ IS_ISP_SET_PARAM_AA_TARGET(dev, ISP_AA_TARGET_AE |
+ ISP_AA_TARGET_AWB);
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_AA);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+int fimc_is_v4l2_set_isp(struct fimc_is_dev *dev, int value)
+{
+ int ret = 0;
+ switch (value) {
+ case IS_ISP_BYPASS_DISABLE:
+ IS_ISP_SET_PARAM_CONTROL_BYPASS(dev, CONTROL_BYPASS_DISABLE);
+ break;
+ case IS_ISP_BYPASS_ENABLE:
+ IS_ISP_SET_PARAM_CONTROL_BYPASS(dev, CONTROL_BYPASS_ENABLE);
+ break;
+ default:
+ return ret;
+ }
+ if (value >= 0 && value < IS_ISP_BYPASS_MAX) {
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_CONTROL);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ }
+ return ret;
+}
+
+int fimc_is_v4l2_set_drc(struct fimc_is_dev *dev, int value)
+{
+ int ret = 0;
+ switch (value) {
+ case IS_DRC_BYPASS_DISABLE:
+ IS_DRC_SET_PARAM_CONTROL_BYPASS(dev, CONTROL_BYPASS_DISABLE);
+ IS_DRC_SET_PARAM_CONTROL_CMD(dev, CONTROL_COMMAND_START);
+ break;
+ case IS_DRC_BYPASS_ENABLE:
+ IS_DRC_SET_PARAM_CONTROL_BYPASS(dev, CONTROL_BYPASS_ENABLE);
+ IS_DRC_SET_PARAM_CONTROL_CMD(dev, CONTROL_COMMAND_START);
+ break;
+ default:
+ return ret;
+ }
+ if (value >= 0 && value < IS_DRC_BYPASS_MAX) {
+ IS_SET_PARAM_BIT(dev, PARAM_DRC_CONTROL);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ }
+ return ret;
+}
+
+int fimc_is_v4l2_cmd_isp(struct fimc_is_dev *dev, int value)
+{
+ int ret = 0;
+ switch (value) {
+ case IS_ISP_COMMAND_STOP:
+ IS_ISP_SET_PARAM_CONTROL_CMD(dev, CONTROL_COMMAND_STOP);
+ break;
+ case IS_ISP_COMMAND_START:
+ IS_ISP_SET_PARAM_CONTROL_CMD(dev, CONTROL_COMMAND_START);
+ break;
+ default:
+ return ret;
+ }
+ if (value >= 0 && value < IS_ISP_COMMAND_MAX) {
+ IS_SET_PARAM_BIT(dev, PARAM_ISP_CONTROL);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ }
+ return ret;
+}
+
+int fimc_is_v4l2_cmd_drc(struct fimc_is_dev *dev, int value)
+{
+ int ret = 0;
+ switch (value) {
+ case IS_DRC_COMMAND_STOP:
+ IS_DRC_SET_PARAM_CONTROL_CMD(dev, CONTROL_COMMAND_STOP);
+ break;
+ case IS_DRC_COMMAND_START:
+ IS_DRC_SET_PARAM_CONTROL_CMD(dev, CONTROL_COMMAND_START);
+ break;
+ }
+ if (value >= 0 && value < IS_ISP_COMMAND_MAX) {
+ IS_SET_PARAM_BIT(dev, PARAM_DRC_CONTROL);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ }
+ return ret;
+}
+
+int fimc_is_v4l2_cmd_fd(struct fimc_is_dev *dev, int value)
+{
+ int ret = 0;
+ switch (value) {
+ case IS_FD_COMMAND_STOP:
+ dbg("IS_FD_COMMAND_STOP\n");
+ IS_FD_SET_PARAM_CONTROL_CMD(dev, CONTROL_COMMAND_STOP);
+ break;
+ case IS_FD_COMMAND_START:
+ dbg("IS_FD_COMMAND_START\n");
+ IS_FD_SET_PARAM_CONTROL_CMD(dev, CONTROL_COMMAND_START);
+ break;
+ }
+ if (value >= 0 && value < IS_ISP_COMMAND_MAX) {
+ IS_SET_PARAM_BIT(dev, PARAM_FD_CONTROL);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ }
+ return ret;
+}
+
+int fimc_is_v4l2_shot_mode(struct fimc_is_dev *dev, int value)
+{
+ int ret = 0;
+
+ dbg("%s\n", __func__);
+ IS_SET_PARAM_GLOBAL_SHOTMODE_CMD(dev, value);
+ IS_SET_PARAM_BIT(dev, PARAM_GLOBAL_SHOTMODE);
+ IS_INC_PARAM_NUM(dev);
+ fimc_is_mem_cache_clean((void *)dev->is_p_region, IS_PARAM_SIZE);
+ fimc_is_hw_set_param(dev);
+ return ret;
+}
diff --git a/drivers/media/video/exynos/fimc-is-mc/fimc-is-misc.h b/drivers/media/video/exynos/fimc-is-mc/fimc-is-misc.h
new file mode 100644
index 0000000..247795c
--- /dev/null
+++ b/drivers/media/video/exynos/fimc-is-mc/fimc-is-misc.h
@@ -0,0 +1,57 @@
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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.
+ */
+#ifndef FIMC_IS_MISC_H
+#define FIMC_IS_MISC_H
+
+int enable_mipi(void);
+int start_fimc_lite(int channel, struct flite_frame *f_frame);
+int stop_fimc_lite(int channel);
+int start_mipi_csi(int channel, struct flite_frame *f_frame);
+int stop_mipi_csi(int channel);
+
+int fimc_is_digital_zoom(struct fimc_is_dev *dev, int value);
+int fimc_is_v4l2_af_start_stop(struct fimc_is_dev *dev, int value);
+int fimc_is_v4l2_touch_af_start_stop(struct fimc_is_dev *dev, int value);
+int fimc_is_v4l2_caf_start_stop(struct fimc_is_dev *dev, int value);
+int fimc_is_ctrl_odc(struct fimc_is_dev *dev, int value);
+int fimc_is_ctrl_dis(struct fimc_is_dev *dev, int value);
+int fimc_is_ctrl_3dnr(struct fimc_is_dev *dev, int value);
+int fimc_is_v4l2_isp_scene_mode(struct fimc_is_dev *dev, int mode);
+int fimc_is_af_face(struct fimc_is_dev *dev);
+int fimc_is_v4l2_af_mode(struct fimc_is_dev *dev, int value);
+int fimc_is_v4l2_isp_iso(struct fimc_is_dev *dev, int value);
+int fimc_is_v4l2_isp_effect(struct fimc_is_dev *dev, int value);
+int fimc_is_v4l2_isp_effect_legacy(struct fimc_is_dev *dev, int value);
+int fimc_is_v4l2_isp_flash_mode(struct fimc_is_dev *dev, int value);
+int fimc_is_v4l2_awb_mode(struct fimc_is_dev *dev, int value);
+int fimc_is_v4l2_awb_mode_legacy(struct fimc_is_dev *dev, int value);
+int fimc_is_v4l2_isp_contrast(struct fimc_is_dev *dev, int value);
+int fimc_is_v4l2_isp_contrast_legacy(struct fimc_is_dev *dev, int value);
+int fimc_is_v4l2_isp_saturation(struct fimc_is_dev *dev, int value);
+int fimc_is_v4l2_isp_sharpness(struct fimc_is_dev *dev, int value);
+int fimc_is_v4l2_isp_exposure(struct fimc_is_dev *dev, int value);
+int fimc_is_v4l2_isp_exposure_legacy(struct fimc_is_dev *dev, int value);
+int fimc_is_v4l2_isp_brightness(struct fimc_is_dev *dev, int value);
+int fimc_is_v4l2_isp_hue(struct fimc_is_dev *dev, int value);
+int fimc_is_v4l2_isp_metering(struct fimc_is_dev *dev, int value);
+int fimc_is_v4l2_isp_metering_legacy(struct fimc_is_dev *dev, int value);
+int fimc_is_v4l2_isp_afc(struct fimc_is_dev *dev, int value);
+int fimc_is_v4l2_isp_afc_legacy(struct fimc_is_dev *dev, int value);
+int fimc_is_v4l2_fd_angle_mode(struct fimc_is_dev *dev, int value);
+int fimc_is_v4l2_frame_rate(struct fimc_is_dev *dev, int value);
+int fimc_is_v4l2_ae_awb_lockunlock(struct fimc_is_dev *dev, int value);
+int fimc_is_v4l2_set_isp(struct fimc_is_dev *dev, int value);
+int fimc_is_v4l2_set_drc(struct fimc_is_dev *dev, int value);
+int fimc_is_v4l2_cmd_isp(struct fimc_is_dev *dev, int value);
+int fimc_is_v4l2_cmd_drc(struct fimc_is_dev *dev, int value);
+int fimc_is_v4l2_cmd_fd(struct fimc_is_dev *dev, int value);
+int fimc_is_v4l2_shot_mode(struct fimc_is_dev *dev, int value);
+#endif/*FIMC_IS_MISC_H*/
diff --git a/drivers/media/video/exynos/fimc-is-mc/fimc-is-param.h b/drivers/media/video/exynos/fimc-is-mc/fimc-is-param.h
new file mode 100644
index 0000000..f5bbc92
--- /dev/null
+++ b/drivers/media/video/exynos/fimc-is-mc/fimc-is-param.h
@@ -0,0 +1,2054 @@
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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.
+ */
+
+#ifndef FIMC_IS_PARAMS_H
+#define FIMC_IS_PARAMS_H
+
+#define IS_REGION_VER 121 /* IS REGION VERSION 1.15 */
+
+/* MACROs */
+#define IS_SET_PARAM_BIT(dev, num) \
+ (num >= 32 ? set_bit((num-32), &dev->p_region_index2) \
+ : set_bit(num, &dev->p_region_index1))
+#define IS_INC_PARAM_NUM(dev) atomic_inc(&dev->p_region_num)
+
+#define IS_PARAM_GLOBAL(dev) (dev->is_p_region->parameter.global)
+#define IS_PARAM_ISP(dev) (dev->is_p_region->parameter.isp)
+#define IS_PARAM_DRC(dev) (dev->is_p_region->parameter.drc)
+#define IS_PARAM_FD(dev) (dev->is_p_region->parameter.fd)
+#define IS_HEADER(dev) (dev->is_p_region->header)
+#define IS_FACE(dev) (dev->is_p_region->face)
+#define IS_SHARED(dev) (dev->is_shared_region)
+#define IS_PARAM_SIZE (FIMC_IS_REGION_SIZE + 1)
+
+/* Global control */
+#define IS_SET_PARAM_GLOBAL_SHOTMODE_CMD(dev, x) \
+ (dev->is_p_region->parameter.global.shotmode.cmd = x)
+#define IS_SET_PARAM_GLOBAL_SHOTMODE_SKIPFRAMES(dev, x) \
+ (dev->is_p_region->parameter.global.shotmode.skip_frames = x)
+
+/* Sensor control */
+#define IS_SENSOR_SET_FRAME_RATE(dev, x) \
+ (dev->is_p_region->parameter.sensor.frame_rate.frame_rate = x)
+
+/* ISP Macros */
+#define IS_ISP_SET_PARAM_CONTROL_CMD(dev, x) \
+ (dev->is_p_region->parameter.isp.control.cmd = x)
+#define IS_ISP_SET_PARAM_CONTROL_BYPASS(dev, x) \
+ (dev->is_p_region->parameter.isp.control.bypass = x)
+#define IS_ISP_SET_PARAM_CONTROL_ERR(dev, x) \
+ (dev->is_p_region->parameter.isp.control.err = x)
+
+#define IS_ISP_SET_PARAM_OTF_INPUT_CMD(dev, x) \
+ (dev->is_p_region->parameter.isp.otf_input.cmd = x)
+#define IS_ISP_SET_PARAM_OTF_INPUT_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.isp.otf_input.width = x)
+#define IS_ISP_SET_PARAM_OTF_INPUT_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.isp.otf_input.height = x)
+#define IS_ISP_SET_PARAM_OTF_INPUT_FORMAT(dev, x) \
+ (dev->is_p_region->parameter.isp.otf_input.format = x)
+#define IS_ISP_SET_PARAM_OTF_INPUT_BITWIDTH(dev, x) \
+ (dev->is_p_region->parameter.isp.otf_input.bitwidth = x)
+#define IS_ISP_SET_PARAM_OTF_INPUT_ORDER(dev, x) \
+ (dev->is_p_region->parameter.isp.otf_input.order = x)
+#define IS_ISP_SET_PARAM_OTF_INPUT_CROP_OFFSET_X(dev, x) \
+ (dev->is_p_region->parameter.isp.otf_input.crop_offset_x = x)
+#define IS_ISP_SET_PARAM_OTF_INPUT_CROP_OFFSET_Y(dev, x) \
+ (dev->is_p_region->parameter.isp.otf_input.crop_offset_y = x)
+#define IS_ISP_SET_PARAM_OTF_INPUT_CROP_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.isp.otf_input.crop_width = x)
+#define IS_ISP_SET_PARAM_OTF_INPUT_CROP_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.isp.otf_input.crop_height = x)
+#define IS_ISP_SET_PARAM_OTF_INPUT_FRAMETIME_MIN(dev, x) \
+ (dev->is_p_region->parameter.isp.otf_input.frametime_min = x)
+#define IS_ISP_SET_PARAM_OTF_INPUT_FRAMETIME_MAX(dev, x) \
+ (dev->is_p_region->parameter.isp.otf_input.frametime_max = x)
+#define IS_ISP_SET_PARAM_OTF_INPUT_ERR(dev, x) \
+ (dev->is_p_region->parameter.isp.otf_input.err = x)
+
+#define IS_ISP_SET_PARAM_DMA_INPUT1_CMD(dev, x) \
+ (dev->is_p_region->parameter.isp.dma1_input.cmd = x)
+#define IS_ISP_SET_PARAM_DMA_INPUT1_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.isp.dma1_input.width = x)
+#define IS_ISP_SET_PARAM_DMA_INPUT1_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.isp.dma1_input.height = x)
+#define IS_ISP_SET_PARAM_DMA_INPUT1_FORMAT(dev, x) \
+ (dev->is_p_region->parameter.isp.dma1_input.format = x)
+#define IS_ISP_SET_PARAM_DMA_INPUT1_BITWIDTH(dev, x) \
+ (dev->is_p_region->parameter.isp.dma1_input.bitwidth = x)
+#define IS_ISP_SET_PARAM_DMA_INPUT1_PLANE(dev, x) \
+ (dev->is_p_region->parameter.isp.dma1_input.plane = x)
+#define IS_ISP_SET_PARAM_DMA_INPUT1_ORDER(dev, x) \
+ (dev->is_p_region->parameter.isp.dma1_input.order = x)
+#define IS_ISP_SET_PARAM_DMA_INPUT1_BUFFERNUM(dev, x) \
+ (dev->is_p_region->parameter.isp.dma1_input.buffer_number = x)
+#define IS_ISP_SET_PARAM_DMA_INPUT1_BUFFERADDR(dev, x) \
+ (dev->is_p_region->parameter.isp.dma1_input.buffer_address = x)
+#define IS_ISP_SET_PARAM_DMA_INPUT1_ERR(dev, x) \
+ (dev->is_p_region->parameter.isp.dma1_input.err = x)
+
+#define IS_ISP_SET_PARAM_DMA_INPUT2_CMD(dev, x) \
+ (dev->is_p_region->parameter.isp.dma2_input.cmd = x)
+#define IS_ISP_SET_PARAM_DMA_INPUT2_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.isp.dma2_input.width = x)
+#define IS_ISP_SET_PARAM_DMA_INPUT2_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.isp.dma2_input.height = x)
+#define IS_ISP_SET_PARAM_DMA_INPUT2_FORMAT(dev, x) \
+ (dev->is_p_region->parameter.isp.dma2_input.format = x)
+#define IS_ISP_SET_PARAM_DMA_INPUT2_BITWIDTH(dev, x) \
+ (dev->is_p_region->parameter.isp.dma2_input.bitwidth = x)
+#define IS_ISP_SET_PARAM_DMA_INPUT2_PLANE(dev, x) \
+ (dev->is_p_region->parameter.isp.dma2_input.plane = x)
+#define IS_ISP_SET_PARAM_DMA_INPUT2_ORDER(dev, x) \
+ (dev->is_p_region->parameter.isp.dma2_input.order = x)
+#define IS_ISP_SET_PARAM_DMA_INPUT2_BUFFERNUM(dev, x) \
+ (dev->is_p_region->parameter.isp.dma2_input.buffer_number = x)
+#define IS_ISP_SET_PARAM_DMA_INPUT2_BUFFERADDR(dev, x) \
+ (dev->is_p_region->parameter.isp.dma2_input.buffer_address = x)
+#define IS_ISP_SET_PARAM_DMA_INPUT2_ERR(dev, x) \
+ (dev->is_p_region->parameter.isp.dma2_input.err = x)
+
+#define IS_ISP_SET_PARAM_AA_CMD(dev, x) \
+ (dev->is_p_region->parameter.isp.aa.cmd = x)
+#define IS_ISP_SET_PARAM_AA_TARGET(dev, x) \
+ (dev->is_p_region->parameter.isp.aa.target = x)
+#define IS_ISP_SET_PARAM_AA_MODE(dev, x) \
+ (dev->is_p_region->parameter.isp.aa.mode = x)
+#define IS_ISP_SET_PARAM_AA_SCENE(dev, x) \
+ (dev->is_p_region->parameter.isp.aa.scene = x)
+#define IS_ISP_SET_PARAM_AA_SLEEP(dev, x) \
+ (dev->is_p_region->parameter.isp.aa.sleep = x)
+#define IS_ISP_SET_PARAM_AA_FACE(dev, x) \
+ (dev->is_p_region->parameter.isp.aa.face = x)
+#define IS_ISP_SET_PARAM_AA_TOUCH_X(dev, x) \
+ (dev->is_p_region->parameter.isp.aa.touch_x = x)
+#define IS_ISP_SET_PARAM_AA_TOUCH_Y(dev, x) \
+ (dev->is_p_region->parameter.isp.aa.touch_y = x)
+#define IS_ISP_SET_PARAM_AA_MANUAL_AF(dev, x) \
+ (dev->is_p_region->parameter.isp.aa.manual_af_setting = x)
+#define IS_ISP_SET_PARAM_AA_ERR(dev, x) \
+ (dev->is_p_region->parameter.isp.aa.err = x)
+
+#define IS_ISP_SET_PARAM_FLASH_CMD(dev, x) \
+ (dev->is_p_region->parameter.isp.flash.cmd = x)
+#define IS_ISP_SET_PARAM_FLASH_REDEYE(dev, x) \
+ (dev->is_p_region->parameter.isp.flash.redeye = x)
+#define IS_ISP_SET_PARAM_FLASH_ERR(dev, x) \
+ (dev->is_p_region->parameter.isp.flash.err = x)
+
+#define IS_ISP_SET_PARAM_AWB_CMD(dev, x) \
+ (dev->is_p_region->parameter.isp.awb.cmd = x)
+#define IS_ISP_SET_PARAM_AWB_ILLUMINATION(dev, x) \
+ (dev->is_p_region->parameter.isp.awb.illumination = x)
+#define IS_ISP_SET_PARAM_AWB_ERR(dev, x) \
+ (dev->is_p_region->parameter.isp.awb.err = x)
+
+#define IS_ISP_SET_PARAM_EFFECT_CMD(dev, x) \
+ (dev->is_p_region->parameter.isp.effect.cmd = x)
+#define IS_ISP_SET_PARAM_EFFECT_ERR(dev, x) \
+ (dev->is_p_region->parameter.isp.effect.err = x)
+
+#define IS_ISP_SET_PARAM_ISO_CMD(dev, x) \
+ (dev->is_p_region->parameter.isp.iso.cmd = x)
+#define IS_ISP_SET_PARAM_ISO_VALUE(dev, x) \
+ (dev->is_p_region->parameter.isp.iso.value = x)
+#define IS_ISP_SET_PARAM_ISO_ERR(dev, x) \
+ (dev->is_p_region->parameter.isp.iso.err = x)
+
+#define IS_ISP_SET_PARAM_ADJUST_CMD(dev, x) \
+ (dev->is_p_region->parameter.isp.adjust.cmd = x)
+#define IS_ISP_SET_PARAM_ADJUST_CONTRAST(dev, x) \
+ (dev->is_p_region->parameter.isp.adjust.contrast = x)
+#define IS_ISP_SET_PARAM_ADJUST_SATURATION(dev, x) \
+ (dev->is_p_region->parameter.isp.adjust.saturation = x)
+#define IS_ISP_SET_PARAM_ADJUST_SHARPNESS(dev, x) \
+ (dev->is_p_region->parameter.isp.adjust.sharpness = x)
+#define IS_ISP_SET_PARAM_ADJUST_EXPOSURE(dev, x) \
+ (dev->is_p_region->parameter.isp.adjust.exposure = x)
+#define IS_ISP_SET_PARAM_ADJUST_BRIGHTNESS(dev, x) \
+ (dev->is_p_region->parameter.isp.adjust.brightness = x)
+#define IS_ISP_SET_PARAM_ADJUST_HUE(dev, x) \
+ (dev->is_p_region->parameter.isp.adjust.hue = x)
+#define IS_ISP_SET_PARAM_ADJUST_ERR(dev, x) \
+ (dev->is_p_region->parameter.isp.adjust.err = x)
+
+#define IS_ISP_SET_PARAM_METERING_CMD(dev, x) \
+ (dev->is_p_region->parameter.isp.metering.cmd = x)
+#define IS_ISP_SET_PARAM_METERING_WIN_POS_X(dev, x) \
+ (dev->is_p_region->parameter.isp.metering.win_pos_x = x)
+#define IS_ISP_SET_PARAM_METERING_WIN_POS_Y(dev, x) \
+ (dev->is_p_region->parameter.isp.metering.win_pos_y = x)
+#define IS_ISP_SET_PARAM_METERING_WIN_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.isp.metering.win_width = x)
+#define IS_ISP_SET_PARAM_METERING_WIN_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.isp.metering.win_height = x)
+#define IS_ISP_SET_PARAM_METERING_ERR(dev, x) \
+ (dev->is_p_region->parameter.isp.metering.err = x)
+
+#define IS_ISP_SET_PARAM_AFC_CMD(dev, x) \
+ (dev->is_p_region->parameter.isp.afc.cmd = x)
+#define IS_ISP_SET_PARAM_AFC_MANUAL(dev, x) \
+ (dev->is_p_region->parameter.isp.afc.manual = x)
+#define IS_ISP_SET_PARAM_AFC_ERR(dev, x) \
+ (dev->is_p_region->parameter.isp.afc.err = x)
+
+#define IS_ISP_SET_PARAM_OTF_OUTPUT_CMD(dev, x) \
+ (dev->is_p_region->parameter.isp.otf_output.cmd = x)
+#define IS_ISP_SET_PARAM_OTF_OUTPUT_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.isp.otf_output.width = x)
+#define IS_ISP_SET_PARAM_OTF_OUTPUT_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.isp.otf_output.height = x)
+#define IS_ISP_SET_PARAM_OTF_OUTPUT_FORMAT(dev, x) \
+ (dev->is_p_region->parameter.isp.otf_output.format = x)
+#define IS_ISP_SET_PARAM_OTF_OUTPUT_BITWIDTH(dev, x) \
+ (dev->is_p_region->parameter.isp.otf_output.bitwidth = x)
+#define IS_ISP_SET_PARAM_OTF_OUTPUT_ORDER(dev, x) \
+ (dev->is_p_region->parameter.isp.otf_output.order = x)
+#define IS_ISP_SET_PARAM_OTF_OUTPUT_ERR(dev, x) \
+ (dev->is_p_region->parameter.isp.otf_output.err = x)
+
+#define IS_ISP_SET_PARAM_DMA_OUTPUT1_CMD(dev, x) \
+ (dev->is_p_region->parameter.isp.dma1_output.cmd = x)
+#define IS_ISP_SET_PARAM_DMA_OUTPUT1_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.isp.dma1_output.width = x)
+#define IS_ISP_SET_PARAM_DMA_OUTPUT1_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.isp.dma1_output.height = x)
+#define IS_ISP_SET_PARAM_DMA_OUTPUT1_FORMAT(dev, x) \
+ (dev->is_p_region->parameter.isp.dma1_output.format = x)
+#define IS_ISP_SET_PARAM_DMA_OUTPUT1_BITWIDTH(dev, x) \
+ (dev->is_p_region->parameter.isp.dma1_output.bitwidth = x)
+#define IS_ISP_SET_PARAM_DMA_OUTPUT1_PLANE(dev, x) \
+ (dev->is_p_region->parameter.isp.dma1_output.plane = x)
+#define IS_ISP_SET_PARAM_DMA_OUTPUT1_ORDER(dev, x) \
+ (dev->is_p_region->parameter.isp.dma1_output.order = x)
+#define IS_ISP_SET_PARAM_DMA_OUTPUT1_BUFFER_NUMBER(dev, x) \
+ (dev->is_p_region->parameter.isp.dma1_output.buffer_number = x)
+#define IS_ISP_SET_PARAM_DMA_OUTPUT1_BUFFER_ADDRESS(dev, x) \
+ (dev->is_p_region->parameter.isp.dma1_output.buffer_address = x)
+#define IS_ISP_SET_PARAM_DMA_OUTPUT1_MASK(dev, x) \
+ (dev->is_p_region->parameter.isp.dma1_output.dma_out_mask = x)
+#define IS_ISP_SET_PARAM_DMA_OUTPUT1_ERR(dev, x) \
+ (dev->is_p_region->parameter.isp.dma1_output.err = x)
+
+#define IS_ISP_SET_PARAM_DMA_OUTPUT2_CMD(dev, x) \
+ (dev->is_p_region->parameter.isp.dma2_output.cmd = x)
+#define IS_ISP_SET_PARAM_DMA_OUTPUT2_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.isp.dma2_output.width = x)
+#define IS_ISP_SET_PARAM_DMA_OUTPUT2_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.isp.dma2_output.height = x)
+#define IS_ISP_SET_PARAM_DMA_OUTPUT2_FORMAT(dev, x) \
+ (dev->is_p_region->parameter.isp.dma2_output.format = x)
+#define IS_ISP_SET_PARAM_DMA_OUTPUT2_BITWIDTH(dev, x) \
+ (dev->is_p_region->parameter.isp.dma2_output.bitwidth = x)
+#define IS_ISP_SET_PARAM_DMA_OUTPUT2_PLANE(dev, x) \
+ (dev->is_p_region->parameter.isp.dma2_output.plane = x)
+#define IS_ISP_SET_PARAM_DMA_OUTPUT2_ORDER(dev, x) \
+ (dev->is_p_region->parameter.isp.dma2_output.order = x)
+#define IS_ISP_SET_PARAM_DMA_OUTPUT2_BUFFER_NUMBER(dev, x) \
+ (dev->is_p_region->parameter.isp.dma2_output.buffer_number = x)
+#define IS_ISP_SET_PARAM_DMA_OUTPUT2_BUFFER_ADDRESS(dev, x) \
+ (dev->is_p_region->parameter.isp.dma2_output.buffer_address = x)
+#define IS_ISP_SET_PARAM_DMA_OUTPUT2_MASK(dev, x) \
+ (dev->is_p_region->parameter.isp.dma2_output.dma_out_mask = x)
+#define IS_ISP_SET_PARAM_DMA_OUTPUT2_DMA_DONE(dev, x) \
+ (dev->is_p_region->parameter.isp.dma2_output.notify_dma_done = x)
+
+#define IS_ISP_SET_PARAM_DMA_OUTPUT2_ERR(dev, x) \
+ (dev->is_p_region->parameter.isp.dma2_output.err = x)
+
+/* DRC Macros */
+#define IS_DRC_SET_PARAM_CONTROL_CMD(dev, x) \
+ (dev->is_p_region->parameter.drc.control.cmd = x)
+#define IS_DRC_SET_PARAM_CONTROL_BYPASS(dev, x) \
+ (dev->is_p_region->parameter.drc.control.bypass = x)
+#define IS_DRC_SET_PARAM_CONTROL_ERR(dev, x) \
+ (dev->is_p_region->parameter.drc.control.err = x)
+
+#define IS_DRC_SET_PARAM_OTF_INPUT_CMD(dev, x) \
+ (dev->is_p_region->parameter.drc.otf_input.cmd = x)
+#define IS_DRC_SET_PARAM_OTF_INPUT_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.drc.otf_input.width = x)
+#define IS_DRC_SET_PARAM_OTF_INPUT_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.drc.otf_input.height = x)
+#define IS_DRC_SET_PARAM_OTF_INPUT_FORMAT(dev, x) \
+ (dev->is_p_region->parameter.drc.otf_input.format = x)
+#define IS_DRC_SET_PARAM_OTF_INPUT_BITWIDTH(dev, x) \
+ (dev->is_p_region->parameter.drc.otf_input.bitwidth = x)
+#define IS_DRC_SET_PARAM_OTF_INPUT_ORDER(dev, x) \
+ (dev->is_p_region->parameter.drc.otf_input.order = x)
+#define IS_DRC_SET_PARAM_OTF_INPUT_ERR(dev, x) \
+ (dev->is_p_region->parameter.drc.otf_input.err = x)
+
+#define IS_DRC_SET_PARAM_DMA_INPUT_CMD(dev, x) \
+ (dev->is_p_region->parameter.drc.dma_input.cmd = x)
+#define IS_DRC_SET_PARAM_DMA_INPUT_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.drc.dma_input.width = x)
+#define IS_DRC_SET_PARAM_DMA_INPUT_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.drc.dma_input.height = x)
+#define IS_DRC_SET_PARAM_DMA_INPUT_FORMAT(dev, x) \
+ (dev->is_p_region->parameter.drc.dma_input.format = x)
+#define IS_DRC_SET_PARAM_DMA_INPUT_BITWIDTH(dev, x) \
+ (dev->is_p_region->parameter.drc.dma_input.bitwidth = x)
+#define IS_DRC_SET_PARAM_DMA_INPUT_PLANE(dev, x) \
+ (dev->is_p_region->parameter.drc.dma_input.plane = x)
+#define IS_DRC_SET_PARAM_DMA_INPUT_ORDER(dev, x) \
+ (dev->is_p_region->parameter.drc.dma_input.order = x)
+#define IS_DRC_SET_PARAM_DMA_INPUT_BUFFERNUM(dev, x) \
+ (dev->is_p_region->parameter.drc.dma_input.buffer_number = x)
+#define IS_DRC_SET_PARAM_DMA_INPUT_BUFFERADDR(dev, x) \
+ (dev->is_p_region->parameter.drc.dma_input.buffer_address = x)
+#define IS_DRC_SET_PARAM_DMA_INPUT_ERR(dev, x) \
+ (dev->is_p_region->parameter.drc.dma_input.err = x)
+
+#define IS_DRC_SET_PARAM_OTF_OUTPUT_CMD(dev, x) \
+ (dev->is_p_region->parameter.drc.otf_output.cmd = x)
+#define IS_DRC_SET_PARAM_OTF_OUTPUT_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.drc.otf_output.width = x)
+#define IS_DRC_SET_PARAM_OTF_OUTPUT_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.drc.otf_output.height = x)
+#define IS_DRC_SET_PARAM_OTF_OUTPUT_FORMAT(dev, x) \
+ (dev->is_p_region->parameter.drc.otf_output.format = x)
+#define IS_DRC_SET_PARAM_OTF_OUTPUT_BITWIDTH(dev, x) \
+ (dev->is_p_region->parameter.drc.otf_output.bitwidth = x)
+#define IS_DRC_SET_PARAM_OTF_OUTPUT_ORDER(dev, x) \
+ (dev->is_p_region->parameter.drc.otf_output.order = x)
+#define IS_DRC_SET_PARAM_OTF_OUTPUT_ERR(dev, x) \
+ (dev->is_p_region->parameter.drc.otf_output.err = x)
+
+/* SCALER-C Macros */
+#define IS_SCALERC_SET_PARAM_CONTROL_CMD(dev, x) \
+ (dev->is_p_region->parameter.scalerc.control.cmd = x)
+#define IS_SCALERC_SET_PARAM_CONTROL_BYPASS(dev, x) \
+ (dev->is_p_region->parameter.scalerc.control.bypass = x)
+#define IS_SCALERC_SET_PARAM_CONTROL_ERR(dev, x) \
+ (dev->is_p_region->parameter.scalerc.control.err = x)
+
+#define IS_SCALERC_SET_PARAM_OTF_INPUT_CMD(dev, x) \
+ (dev->is_p_region->parameter.scalerc.otf_input.cmd = x)
+#define IS_SCALERC_SET_PARAM_OTF_INPUT_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.scalerc.otf_input.width = x)
+#define IS_SCALERC_SET_PARAM_OTF_INPUT_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.scalerc.otf_input.height = x)
+#define IS_SCALERC_SET_PARAM_OTF_INPUT_FORMAT(dev, x) \
+ (dev->is_p_region->parameter.scalerc.otf_input.format = x)
+#define IS_SCALERC_SET_PARAM_OTF_INPUT_BITWIDTH(dev, x) \
+ (dev->is_p_region->parameter.scalerc.otf_input.bitwidth = x)
+#define IS_SCALERC_SET_PARAM_OTF_INPUT_ORDER(dev, x) \
+ (dev->is_p_region->parameter.scalerc.otf_input.order = x)
+#define IS_SCALERC_SET_PARAM_OTF_INPUT_ERR(dev, x) \
+ (dev->is_p_region->parameter.scalerc.otf_input.err = x)
+
+#define IS_SCALERC_SET_PARAM_EFFECT_CMD(dev, x) \
+ (dev->is_p_region->parameter.scalerc.effect.cmd = x)
+#define IS_SCALERC_SET_PARAM_EFFECT_ERR(dev, x) \
+ (dev->is_p_region->parameter.scalerc.effect.err = x)
+
+#define IS_SCALERC_SET_PARAM_INPUT_CROP_CMD(dev, x) \
+ (dev->is_p_region->parameter.scalerc.input_crop.cmd = x)
+#define IS_SCALERC_SET_PARAM_INPUT_CROP_POS_X(dev, x) \
+ (dev->is_p_region->parameter.scalerc.input_crop.pos_x = x)
+#define IS_SCALERC_SET_PARAM_INPUT_CROP_POS_Y(dev, x) \
+ (dev->is_p_region->parameter.scalerc.input_crop.pos_y = x)
+#define IS_SCALERC_SET_PARAM_INPUT_CROP_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.scalerc.input_crop.crop_width = x)
+#define IS_SCALERC_SET_PARAM_INPUT_CROP_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.scalerc.input_crop.crop_height = x)
+#define IS_SCALERC_SET_PARAM_INPUT_CROP_IN_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.scalerc.input_crop.in_width = x)
+#define IS_SCALERC_SET_PARAM_INPUT_CROP_IN_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.scalerc.input_crop.in_height = x)
+#define IS_SCALERC_SET_PARAM_INPUT_CROP_OUT_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.scalerc.input_crop.out_width = x)
+#define IS_SCALERC_SET_PARAM_INPUT_CROP_OUT_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.scalerc.input_crop.out_height = x)
+#define IS_SCALERC_SET_PARAM_INPUT_CROP_ERR(dev, x) \
+ (dev->is_p_region->parameter.scalerc.input_crop.err = x)
+
+#define IS_SCALERC_SET_PARAM_OUTPUT_CROP_CMD(dev, x) \
+ (dev->is_p_region->parameter.scalerc.output_crop.cmd = x)
+#define IS_SCALERC_SET_PARAM_OUTPUT_CROP_POS_X(dev, x) \
+ (dev->is_p_region->parameter.scalerc.output_crop.pos_x = x)
+#define IS_SCALERC_SET_PARAM_OUTPUT_CROP_POS_Y(dev, x) \
+ (dev->is_p_region->parameter.scalerc.output_crop.pos_y = x)
+#define IS_SCALERC_SET_PARAM_OUTPUT_CROP_CROP_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.scalerc.output_crop.crop_width = x)
+#define IS_SCALERC_SET_PARAM_OUTPUT_CROP_CROP_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.scalerc.output_crop.crop_height = x)
+#define IS_SCALERC_SET_PARAM_OUTPUT_CROPG_FORMAT(dev, x) \
+ (dev->is_p_region->parameter.scalerc.output_crop.format = x)
+#define IS_SCALERC_SET_PARAM_OUTPUT_CROP_ERR(dev, x) \
+ (dev->is_p_region->parameter.scalerc.output_crop.err = x)
+
+#define IS_SCALERC_SET_PARAM_OTF_OUTPUT_CMD(dev, x) \
+ (dev->is_p_region->parameter.scalerc.otf_output.cmd = x)
+#define IS_SCALERC_SET_PARAM_OTF_OUTPUT_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.scalerc.otf_output.width = x)
+#define IS_SCALERC_SET_PARAM_OTF_OUTPUT_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.scalerc.otf_output.height = x)
+#define IS_SCALERC_SET_PARAM_OTF_OUTPUT_FORMAT(dev, x) \
+ (dev->is_p_region->parameter.scalerc.otf_output.format = x)
+#define IS_SCALERC_SET_PARAM_OTF_OUTPUT_BITWIDTH(dev, x) \
+ (dev->is_p_region->parameter.scalerc.otf_output.bitwidth = x)
+#define IS_SCALERC_SET_PARAM_OTF_OUTPUT_ORDER(dev, x) \
+ (dev->is_p_region->parameter.scalerc.otf_output.order = x)
+#define IS_SCALERC_SET_PARAM_OTF_OUTPUT_ERR(dev, x) \
+ (dev->is_p_region->parameter.scalerc.otf_output.err = x)
+
+#define IS_SCALERC_SET_PARAM_DMA_OUTPUT_CMD(dev, x) \
+ (dev->is_p_region->parameter.scalerc.dma_output.cmd = x)
+#define IS_SCALERC_SET_PARAM_DMA_OUTPUT_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.scalerc.dma_output.width = x)
+#define IS_SCALERC_SET_PARAM_DMA_OUTPUT_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.scalerc.dma_output.height = x)
+#define IS_SCALERC_SET_PARAM_DMA_OUTPUT_FORMAT(dev, x) \
+ (dev->is_p_region->parameter.scalerc.dma_output.format = x)
+#define IS_SCALERC_SET_PARAM_DMA_OUTPUT_BITWIDTH(dev, x) \
+ (dev->is_p_region->parameter.scalerc.dma_output.bitwidth = x)
+#define IS_SCALERC_SET_PARAM_DMA_OUTPUT_PLANE(dev, x) \
+ (dev->is_p_region->parameter.scalerc.dma_output.plane = x)
+#define IS_SCALERC_SET_PARAM_DMA_OUTPUT_ORDER(dev, x) \
+ (dev->is_p_region->parameter.scalerc.dma_output.order = x)
+#define IS_SCALERC_SET_PARAM_DMA_OUTPUT_BUFFERNUM(dev, x) \
+ (dev->is_p_region->parameter.scalerc.dma_output.buffer_number = x)
+#define IS_SCALERC_SET_PARAM_DMA_OUTPUT_BUFFERADDR(dev, x) \
+ (dev->is_p_region->parameter.scalerc.dma_output.buffer_address = x)
+#define IS_SCALERC_SET_PARAM_DMA_OUTPUT_MASK(dev, x) \
+ (dev->is_p_region->parameter.scalerc.dma_output.dma_out_mask = x)
+#define IS_SCALERC_SET_PARAM_DMA_OUTPUT_OUTPATH(dev, x) \
+ (dev->is_p_region->parameter.scalerc.dma_output.reserved[0] = x)
+#define IS_SCALERC_SET_PARAM_DMA_OUTPUT_ERR(dev, x) \
+ (dev->is_p_region->parameter.scalerc.dma_output.err = x)
+
+/* ODC Macros */
+#define IS_ODC_SET_PARAM_CONTROL_CMD(dev, x) \
+ (dev->is_p_region->parameter.odc.control.cmd = x)
+#define IS_ODC_SET_PARAM_CONTROL_BUFFERNUM(dev, x) \
+ (dev->is_p_region->parameter.odc.control.buffer_number = x)
+#define IS_ODC_SET_PARAM_CONTROL_BUFFERADDR(dev, x) \
+ (dev->is_p_region->parameter.odc.control.buffer_address = x)
+#define IS_ODC_SET_PARAM_CONTROL_BYPASS(dev, x) \
+ (dev->is_p_region->parameter.odc.control.bypass = x)
+#define IS_ODC_SET_PARAM_CONTROL_ERR(dev, x) \
+ (dev->is_p_region->parameter.odc.control.err = x)
+
+#define IS_ODC_SET_PARAM_OTF_INPUT_CMD(dev, x) \
+ (dev->is_p_region->parameter.odc.otf_input.cmd = x)
+#define IS_ODC_SET_PARAM_OTF_INPUT_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.odc.otf_input.width = x)
+#define IS_ODC_SET_PARAM_OTF_INPUT_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.odc.otf_input.height = x)
+#define IS_ODC_SET_PARAM_OTF_INPUT_FORMAT(dev, x) \
+ (dev->is_p_region->parameter.odc.otf_input.format = x)
+#define IS_ODC_SET_PARAM_OTF_INPUT_BITWIDTH(dev, x) \
+ (dev->is_p_region->parameter.odc.otf_input.bitwidth = x)
+#define IS_ODC_SET_PARAM_OTF_INPUT_ORDER(dev, x) \
+ (dev->is_p_region->parameter.odc.otf_input.order = x)
+#define IS_ODC_SET_PARAM_OTF_INPUT_ERR(dev, x) \
+ (dev->is_p_region->parameter.odc.otf_input.err = x)
+
+#define IS_ODC_SET_PARAM_OTF_OUTPUT_CMD(dev, x) \
+ (dev->is_p_region->parameter.odc.otf_output.cmd = x)
+#define IS_ODC_SET_PARAM_OTF_OUTPUT_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.odc.otf_output.width = x)
+#define IS_ODC_SET_PARAM_OTF_OUTPUT_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.odc.otf_output.height = x)
+#define IS_ODC_SET_PARAM_OTF_OUTPUT_FORMAT(dev, x) \
+ (dev->is_p_region->parameter.odc.otf_output.format = x)
+#define IS_ODC_SET_PARAM_OTF_OUTPUT_BITWIDTH(dev, x) \
+ (dev->is_p_region->parameter.odc.otf_output.bitwidth = x)
+#define IS_ODC_SET_PARAM_OTF_OUTPUT_ORDER(dev, x) \
+ (dev->is_p_region->parameter.odc.otf_output.order = x)
+#define IS_ODC_SET_PARAM_OTF_OUTPUT_ERR(dev, x) \
+ (dev->is_p_region->parameter.odc.otf_output.err = x)
+
+/* DIS Macros */
+#define IS_DIS_SET_PARAM_CONTROL_CMD(dev, x) \
+ (dev->is_p_region->parameter.dis.control.cmd = x)
+#define IS_DIS_SET_PARAM_CONTROL_BUFFERNUM(dev, x) \
+ (dev->is_p_region->parameter.dis.control.buffer_number = x)
+#define IS_DIS_SET_PARAM_CONTROL_BUFFERADDR(dev, x) \
+ (dev->is_p_region->parameter.dis.control.buffer_address = x)
+#define IS_DIS_SET_PARAM_CONTROL_BYPASS(dev, x) \
+ (dev->is_p_region->parameter.dis.control.bypass = x)
+#define IS_DIS_SET_PARAM_CONTROL_ERR(dev, x) \
+ (dev->is_p_region->parameter.dis.control.err = x)
+
+#define IS_DIS_SET_PARAM_OTF_INPUT_CMD(dev, x) \
+ (dev->is_p_region->parameter.dis.otf_input.cmd = x)
+#define IS_DIS_SET_PARAM_OTF_INPUT_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.dis.otf_input.width = x)
+#define IS_DIS_SET_PARAM_OTF_INPUT_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.dis.otf_input.height = x)
+#define IS_DIS_SET_PARAM_OTF_INPUT_FORMAT(dev, x) \
+ (dev->is_p_region->parameter.dis.otf_input.format = x)
+#define IS_DIS_SET_PARAM_OTF_INPUT_BITWIDTH(dev, x) \
+ (dev->is_p_region->parameter.dis.otf_input.bitwidth = x)
+#define IS_DIS_SET_PARAM_OTF_INPUT_ORDER(dev, x) \
+ (dev->is_p_region->parameter.dis.otf_input.order = x)
+#define IS_DIS_SET_PARAM_OTF_INPUT_ERR(dev, x) \
+ (dev->is_p_region->parameter.dis.otf_input.err = x)
+
+#define IS_DIS_SET_PARAM_OTF_OUTPUT_CMD(dev, x) \
+ (dev->is_p_region->parameter.dis.otf_output.cmd = x)
+#define IS_DIS_SET_PARAM_OTF_OUTPUT_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.dis.otf_output.width = x)
+#define IS_DIS_SET_PARAM_OTF_OUTPUT_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.dis.otf_output.height = x)
+#define IS_DIS_SET_PARAM_OTF_OUTPUT_FORMAT(dev, x) \
+ (dev->is_p_region->parameter.dis.otf_output.format = x)
+#define IS_DIS_SET_PARAM_OTF_OUTPUT_BITWIDTH(dev, x) \
+ (dev->is_p_region->parameter.dis.otf_output.bitwidth = x)
+#define IS_DIS_SET_PARAM_OTF_OUTPUT_ORDER(dev, x) \
+ (dev->is_p_region->parameter.dis.otf_output.order = x)
+#define IS_DIS_SET_PARAM_OTF_OUTPUT_ERR(dev, x) \
+ (dev->is_p_region->parameter.dis.otf_output.err = x)
+
+/* TDNR Macros */
+#define IS_TDNR_SET_PARAM_CONTROL_CMD(dev, x) \
+ (dev->is_p_region->parameter.tdnr.control.cmd = x)
+#define IS_TDNR_SET_PARAM_CONTROL_BYPASS(dev, x) \
+ (dev->is_p_region->parameter.tdnr.control.bypass = x)
+#define IS_TDNR_SET_PARAM_CONTROL_BUFFERNUM(dev, x) \
+ (dev->is_p_region->parameter.tdnr.control.buffer_number = x)
+#define IS_TDNR_SET_PARAM_CONTROL_BUFFERADDR(dev, x) \
+ (dev->is_p_region->parameter.tdnr.control.buffer_address = x)
+#define IS_TDNR_SET_PARAM_CONTROL_ERR(dev, x) \
+ (dev->is_p_region->parameter.tdnr.control.err = x)
+
+#define IS_TDNR_SET_PARAM_OTF_INPUT_CMD(dev, x) \
+ (dev->is_p_region->parameter.tdnr.otf_input.cmd = x)
+#define IS_TDNR_SET_PARAM_OTF_INPUT_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.tdnr.otf_input.width = x)
+#define IS_TDNR_SET_PARAM_OTF_INPUT_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.tdnr.otf_input.height = x)
+#define IS_TDNR_SET_PARAM_OTF_INPUT_FORMAT(dev, x) \
+ (dev->is_p_region->parameter.tdnr.otf_input.format = x)
+#define IS_TDNR_SET_PARAM_OTF_INPUT_BITWIDTH(dev, x) \
+ (dev->is_p_region->parameter.tdnr.otf_input.bitwidth = x)
+#define IS_TDNR_SET_PARAM_OTF_INPUT_ORDER(dev, x) \
+ (dev->is_p_region->parameter.tdnr.otf_input.order = x)
+#define IS_TDNR_SET_PARAM_OTF_INPUT_ERR(dev, x) \
+ (dev->is_p_region->parameter.tdnr.otf_input.err = x)
+
+#define IS_TDNR_SET_PARAM_FRAME_CMD(dev, x) \
+ (dev->is_p_region->parameter.tdnr.frame.cmd = x)
+#define IS_TDNR_SET_PARAM_FRAME_ERR(dev, x) \
+ (dev->is_p_region->parameter.tdnr.frame.err = x)
+
+#define IS_TDNR_SET_PARAM_OTF_OUTPUT_CMD(dev, x) \
+ (dev->is_p_region->parameter.tdnr.otf_output.cmd = x)
+#define IS_TDNR_SET_PARAM_OTF_OUTPUT_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.tdnr.otf_output.width = x)
+#define IS_TDNR_SET_PARAM_OTF_OUTPUT_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.tdnr.otf_output.height = x)
+#define IS_TDNR_SET_PARAM_OTF_OUTPUT_FORMAT(dev, x) \
+ (dev->is_p_region->parameter.tdnr.otf_output.format = x)
+#define IS_TDNR_SET_PARAM_OTF_OUTPUT_BITWIDTH(dev, x) \
+ (dev->is_p_region->parameter.tdnr.otf_output.bitwidth = x)
+#define IS_TDNR_SET_PARAM_OTF_OUTPUT_ORDER(dev, x) \
+ (dev->is_p_region->parameter.tdnr.otf_output.order = x)
+#define IS_TDNR_SET_PARAM_OTF_OUTPUT_ERR(dev, x) \
+ (dev->is_p_region->parameter.tdnr.otf_output.err = x)
+
+#define IS_TDNR_SET_PARAM_DMA_OUTPUT_CMD(dev, x) \
+ (dev->is_p_region->parameter.tdnr.dma_output.cmd = x)
+#define IS_TDNR_SET_PARAM_DMA_OUTPUT_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.tdnr.dma_output.width = x)
+#define IS_TDNR_SET_PARAM_DMA_OUTPUT_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.tdnr.dma_output.height = x)
+#define IS_TDNR_SET_PARAM_DMA_OUTPUT_FORMAT(dev, x) \
+ (dev->is_p_region->parameter.tdnr.dma_output.format = x)
+#define IS_TDNR_SET_PARAM_DMA_OUTPUT_BITWIDTH(dev, x) \
+ (dev->is_p_region->parameter.tdnr.dma_output.bitwidth = x)
+#define IS_TDNR_SET_PARAM_DMA_OUTPUT_PLANE(dev, x) \
+ (dev->is_p_region->parameter.tdnr.dma_output.plane = x)
+#define IS_TDNR_SET_PARAM_DMA_OUTPUT_ORDER(dev, x) \
+ (dev->is_p_region->parameter.tdnr.dma_output.order = x)
+#define IS_TDNR_SET_PARAM_DMA_OUTPUT_BUFFERNUM(dev, x) \
+ (dev->is_p_region->parameter.tdnr.dma_output.buffer_number = x)
+#define IS_TDNR_SET_PARAM_DMA_OUTPUT_BUFFERADDR(dev, x) \
+ (dev->is_p_region->parameter.tdnr.dma_output.buffer_address = x)
+#define IS_TDNR_SET_PARAM_DMA_OUTPUT_MASK(dev, x) \
+ (dev->is_p_region->parameter.tdnr.dma_output.dma_out_mask = x)
+#define IS_TDNR_SET_PARAM_DMA_OUTPUT_ERR(dev, x) \
+ (dev->is_p_region->parameter.tdnr.dma_output.err = x)
+
+/* SCALER-P Macros */
+#define IS_SCALERP_SET_PARAM_CONTROL_CMD(dev, x) \
+ (dev->is_p_region->parameter.scalerp.control.cmd = x)
+#define IS_SCALERP_SET_PARAM_CONTROL_BYPASS(dev, x) \
+ (dev->is_p_region->parameter.scalerp.control.bypass = x)
+#define IS_SCALERP_SET_PARAM_CONTROL_ERR(dev, x) \
+ (dev->is_p_region->parameter.scalerp.control.err = x)
+
+#define IS_SCALERP_SET_PARAM_OTF_INPUT_CMD(dev, x) \
+ (dev->is_p_region->parameter.scalerp.otf_input.cmd = x)
+#define IS_SCALERP_SET_PARAM_OTF_INPUT_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.scalerp.otf_input.width = x)
+#define IS_SCALERP_SET_PARAM_OTF_INPUT_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.scalerp.otf_input.height = x)
+#define IS_SCALERP_SET_PARAM_OTF_INPUT_FORMAT(dev, x) \
+ (dev->is_p_region->parameter.scalerp.otf_input.format = x)
+#define IS_SCALERP_SET_PARAM_OTF_INPUT_BITWIDTH(dev, x) \
+ (dev->is_p_region->parameter.scalerp.otf_input.bitwidth = x)
+#define IS_SCALERP_SET_PARAM_OTF_INPUT_ORDER(dev, x) \
+ (dev->is_p_region->parameter.scalerp.otf_input.order = x)
+#define IS_SCALERP_SET_PARAM_OTF_INPUT_ERR(dev, x) \
+ (dev->is_p_region->parameter.scalerp.otf_input.err = x)
+
+#define IS_SCALERP_SET_PARAM_EFFECT_CMD(dev, x) \
+ (dev->is_p_region->parameter.scalerp.effect.cmd = x)
+#define IS_SCALERP_SET_PARAM_EFFECT_ERR(dev, x) \
+ (dev->is_p_region->parameter.scalerp.effect.err = x)
+
+#define IS_SCALERP_SET_PARAM_INPUT_CROP_CMD(dev, x) \
+ (dev->is_p_region->parameter.scalerp.input_crop.cmd = x)
+#define IS_SCALERP_SET_PARAM_INPUT_CROP_POS_X(dev, x) \
+ (dev->is_p_region->parameter.scalerp.input_crop.pos_x = x)
+#define IS_SCALERP_SET_PARAM_INPUT_CROP_POS_Y(dev, x) \
+ (dev->is_p_region->parameter.scalerp.input_crop.pos_y = x)
+#define IS_SCALERP_SET_PARAM_INPUT_CROP_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.scalerp.input_crop.crop_width = x)
+#define IS_SCALERP_SET_PARAM_INPUT_CROP_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.scalerp.input_crop.crop_height = x)
+#define IS_SCALERP_SET_PARAM_INPUT_CROP_IN_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.scalerp.input_crop.in_width = x)
+#define IS_SCALERP_SET_PARAM_INPUT_CROP_IN_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.scalerp.input_crop.in_height = x)
+#define IS_SCALERP_SET_PARAM_INPUT_CROP_OUT_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.scalerp.input_crop.out_width = x)
+#define IS_SCALERP_SET_PARAM_INPUT_CROP_OUT_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.scalerp.input_crop.out_height = x)
+#define IS_SCALERP_SET_PARAM_INPUT_CROP_ERR(dev, x) \
+ (dev->is_p_region->parameter.scalerp.input_crop.err = x)
+
+#define IS_SCALERP_SET_PARAM_OUTPUT_CROP_CMD(dev, x) \
+ (dev->is_p_region->parameter.scalerp.output_crop.cmd = x)
+#define IS_SCALERP_SET_PARAM_OUTPUT_CROP_POS_X(dev, x) \
+ (dev->is_p_region->parameter.scalerp.output_crop.pos_x = x)
+#define IS_SCALERP_SET_PARAM_OUTPUT_CROP_POS_Y(dev, x) \
+ (dev->is_p_region->parameter.scalerp.output_crop.pos_y = x)
+#define IS_SCALERP_SET_PARAM_OUTPUT_CROP_CROP_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.scalerp.output_crop.crop_width = x)
+#define IS_SCALERP_SET_PARAM_OUTPUT_CROP_CROP_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.scalerp.output_crop.crop_height = x)
+#define IS_SCALERP_SET_PARAM_OUTPUT_CROPG_FORMAT(dev, x) \
+ (dev->is_p_region->parameter.scalerp.output_crop.format = x)
+#define IS_SCALERP_SET_PARAM_OUTPUT_CROP_ERR(dev, x) \
+ (dev->is_p_region->parameter.scalerp.output_crop.err = x)
+
+#define IS_SCALERP_SET_PARAM_ROTATION_CMD(dev, x) \
+ (dev->is_p_region->parameter.scalerp.rotation.cmd = x)
+#define IS_SCALERP_SET_PARAM_ROTATION_ERR(dev, x) \
+ (dev->is_p_region->parameter.scalerp.rotation.err = x)
+
+#define IS_SCALERP_SET_PARAM_FLIP_CMD(dev, x) \
+ (dev->is_p_region->parameter.scalerp.flip.cmd = x)
+#define IS_SCALERP_SET_PARAM_FLIP_ERR(dev, x) \
+ (dev->is_p_region->parameter.scalerp.flip.err = x)
+
+#define IS_SCALERP_SET_PARAM_OTF_OUTPUT_CMD(dev, x) \
+ (dev->is_p_region->parameter.scalerp.otf_output.cmd = x)
+#define IS_SCALERP_SET_PARAM_OTF_OUTPUT_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.scalerp.otf_output.width = x)
+#define IS_SCALERP_SET_PARAM_OTF_OUTPUT_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.scalerp.otf_output.height = x)
+#define IS_SCALERP_SET_PARAM_OTF_OUTPUT_FORMAT(dev, x) \
+ (dev->is_p_region->parameter.scalerp.otf_output.format = x)
+#define IS_SCALERP_SET_PARAM_OTF_OUTPUT_BITWIDTH(dev, x) \
+ (dev->is_p_region->parameter.scalerp.otf_output.bitwidth = x)
+#define IS_SCALERP_SET_PARAM_OTF_OUTPUT_ORDER(dev, x) \
+ (dev->is_p_region->parameter.scalerp.otf_output.order = x)
+#define IS_SCALERP_SET_PARAM_OTF_OUTPUT_ERR(dev, x) \
+ (dev->is_p_region->parameter.scalerp.otf_output.err = x)
+
+#define IS_SCALERP_SET_PARAM_DMA_OUTPUT_CMD(dev, x) \
+ (dev->is_p_region->parameter.scalerp.dma_output.cmd = x)
+#define IS_SCALERP_SET_PARAM_DMA_OUTPUT_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.scalerp.dma_output.width = x)
+#define IS_SCALERP_SET_PARAM_DMA_OUTPUT_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.scalerp.dma_output.height = x)
+#define IS_SCALERP_SET_PARAM_DMA_OUTPUT_FORMAT(dev, x) \
+ (dev->is_p_region->parameter.scalerp.dma_output.format = x)
+#define IS_SCALERP_SET_PARAM_DMA_OUTPUT_BITWIDTH(dev, x) \
+ (dev->is_p_region->parameter.scalerp.dma_output.bitwidth = x)
+#define IS_SCALERP_SET_PARAM_DMA_OUTPUT_PLANE(dev, x) \
+ (dev->is_p_region->parameter.scalerp.dma_output.plane = x)
+#define IS_SCALERP_SET_PARAM_DMA_OUTPUT_ORDER(dev, x) \
+ (dev->is_p_region->parameter.scalerp.dma_output.order = x)
+#define IS_SCALERP_SET_PARAM_DMA_OUTPUT_BUFFERNUM(dev, x) \
+ (dev->is_p_region->parameter.scalerp.dma_output.buffer_number = x)
+#define IS_SCALERP_SET_PARAM_DMA_OUTPUT_BUFFERADDR(dev, x) \
+ (dev->is_p_region->parameter.scalerp.dma_output.buffer_address = x)
+#define IS_SCALERP_SET_PARAM_DMA_OUTPUT_MASK(dev, x) \
+ (dev->is_p_region->parameter.scalerp.dma_output.dma_out_mask = x)
+#define IS_SCALERP_SET_PARAM_DMA_OUTPUT_ERR(dev, x) \
+ (dev->is_p_region->parameter.scalerp.dma_output.err = x)
+
+/* FD Macros */
+#define IS_FD_SET_PARAM_CONTROL_CMD(dev, x) \
+ (dev->is_p_region->parameter.fd.control.cmd = x)
+#define IS_FD_SET_PARAM_CONTROL_BYPASS(dev, x) \
+ (dev->is_p_region->parameter.fd.control.bypass = x)
+#define IS_FD_SET_PARAM_CONTROL_ERR(dev, x) \
+ (dev->is_p_region->parameter.fd.control.err = x)
+
+#define IS_FD_SET_PARAM_OTF_INPUT_CMD(dev, x) \
+ (dev->is_p_region->parameter.fd.otf_input.cmd = x)
+#define IS_FD_SET_PARAM_OTF_INPUT_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.fd.otf_input.width = x)
+#define IS_FD_SET_PARAM_OTF_INPUT_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.fd.otf_input.height = x)
+#define IS_FD_SET_PARAM_OTF_INPUT_FORMAT(dev, x) \
+ (dev->is_p_region->parameter.fd.otf_input.format = x)
+#define IS_FD_SET_PARAM_OTF_INPUT_BITWIDTH(dev, x) \
+ (dev->is_p_region->parameter.fd.otf_input.bitwidth = x)
+#define IS_FD_SET_PARAM_OTF_INPUT_ORDER(dev, x) \
+ (dev->is_p_region->parameter.fd.otf_input.order = x)
+#define IS_FD_SET_PARAM_OTF_INPUT_ERR(dev, x) \
+ (dev->is_p_region->parameter.fd.otf_input.err = x)
+
+#define IS_FD_SET_PARAM_DMA_INPUT_CMD(dev, x) \
+ (dev->is_p_region->parameter.fd.dma_input.cmd = x)
+#define IS_FD_SET_PARAM_DMA_INPUT_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.fd.dma_input.width = x)
+#define IS_FD_SET_PARAM_DMA_INPUT_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.fd.dma_input.height = x)
+#define IS_FD_SET_PARAM_DMA_INPUT_FORMAT(dev, x) \
+ (dev->is_p_region->parameter.fd.dma_input.format = x)
+#define IS_FD_SET_PARAM_DMA_INPUT_BITWIDTH(dev, x) \
+ (dev->is_p_region->parameter.fd.dma_input.bitwidth = x)
+#define IS_FD_SET_PARAM_DMA_INPUT_PLANE(dev, x) \
+ (dev->is_p_region->parameter.fd.dma_input.plane = x)
+#define IS_FD_SET_PARAM_DMA_INPUT_ORDER(dev, x) \
+ (dev->is_p_region->parameter.fd.dma_input.order = x)
+#define IS_FD_SET_PARAM_DMA_INPUT_BUFFERNUM(dev, x) \
+ (dev->is_p_region->parameter.fd.dma_input.buffer_number = x)
+#define IS_FD_SET_PARAM_DMA_INPUT_BUFFERADDR(dev, x) \
+ (dev->is_p_region->parameter.fd.dma_input.buffer_address = x)
+#define IS_FD_SET_PARAM_DMA_INPUT_ERR(dev, x) \
+ (dev->is_p_region->parameter.fd.dma_input.err = x)
+
+#define IS_FD_SET_PARAM_FD_CONFIG_CMD(dev, x) \
+ (dev->is_p_region->parameter.fd.config.cmd = x)
+#define IS_FD_SET_PARAM_FD_CONFIG_MAX_NUMBER(dev, x) \
+ (dev->is_p_region->parameter.fd.config.max_number = x)
+#define IS_FD_SET_PARAM_FD_CONFIG_ROLL_ANGLE(dev, x) \
+ (dev->is_p_region->parameter.fd.config.roll_angle = x)
+#define IS_FD_SET_PARAM_FD_CONFIG_YAW_ANGLE(dev, x) \
+ (dev->is_p_region->parameter.fd.config.yaw_angle = x)
+#define IS_FD_SET_PARAM_FD_CONFIG_SMILE_MODE(dev, x) \
+ (dev->is_p_region->parameter.fd.config.smile_mode = x)
+#define IS_FD_SET_PARAM_FD_CONFIG_BLINK_MODE(dev, x) \
+ (dev->is_p_region->parameter.fd.config.blink_mode = x)
+#define IS_FD_SET_PARAM_FD_CONFIG_EYE_DETECT(dev, x) \
+ (dev->is_p_region->parameter.fd.config.eye_detect = x)
+#define IS_FD_SET_PARAM_FD_CONFIG_MOUTH_DETECT(dev, x) \
+ (dev->is_p_region->parameter.fd.config.mouth_detect = x)
+#define IS_FD_SET_PARAM_FD_CONFIG_ORIENTATION(dev, x) \
+ (dev->is_p_region->parameter.fd.config.orientation = x)
+#define IS_FD_SET_PARAM_FD_CONFIG_ORIENTATION_VALUE(dev, x) \
+ (dev->is_p_region->parameter.fd.config.orientation_value = x)
+#define IS_FD_SET_PARAM_FD_CONFIG_ERR(dev, x) \
+ (dev->is_p_region->parameter.fd.config.err = x)
+
+#ifndef BIT0
+#define BIT0 0x00000001
+#define BIT1 0x00000002
+#define BIT2 0x00000004
+#define BIT3 0x00000008
+#define BIT4 0x00000010
+#define BIT5 0x00000020
+#define BIT6 0x00000040
+#define BIT7 0x00000080
+#define BIT8 0x00000100
+#define BIT9 0x00000200
+#define BIT10 0x00000400
+#define BIT11 0x00000800
+#define BIT12 0x00001000
+#define BIT13 0x00002000
+#define BIT14 0x00004000
+#define BIT15 0x00008000
+#define BIT16 0x00010000
+#define BIT17 0x00020000
+#define BIT18 0x00040000
+#define BIT19 0x00080000
+#define BIT20 0x00100000
+#define BIT21 0x00200000
+#define BIT22 0x00400000
+#define BIT23 0x00800000
+#define BIT24 0x01000000
+#define BIT25 0x02000000
+#define BIT26 0x04000000
+#define BIT27 0x08000000
+#define BIT28 0x10000000
+#define BIT29 0x20000000
+#define BIT30 0x40000000
+#define BIT31 0x80000000
+#define BIT32 0x0000000100000000ULL
+#define BIT33 0x0000000200000000ULL
+#define BIT34 0x0000000400000000ULL
+#define BIT35 0x0000000800000000ULL
+#define BIT36 0x0000001000000000ULL
+#define BIT37 0x0000002000000000ULL
+#define BIT38 0x0000004000000000ULL
+#define BIT39 0x0000008000000000ULL
+#define BIT40 0x0000010000000000ULL
+#define BIT41 0x0000020000000000ULL
+#define BIT42 0x0000040000000000ULL
+#define BIT43 0x0000080000000000ULL
+#define BIT44 0x0000100000000000ULL
+#define BIT45 0x0000200000000000ULL
+#define BIT46 0x0000400000000000ULL
+#define BIT47 0x0000800000000000ULL
+#define BIT48 0x0001000000000000ULL
+#define BIT49 0x0002000000000000ULL
+#define BIT50 0x0004000000000000ULL
+#define BIT51 0x0008000000000000ULL
+#define BIT52 0x0010000000000000ULL
+#define BIT53 0x0020000000000000ULL
+#define BIT54 0x0040000000000000ULL
+#define BIT55 0x0080000000000000ULL
+#define BIT56 0x0100000000000000ULL
+#define BIT57 0x0200000000000000ULL
+#define BIT58 0x0400000000000000ULL
+#define BIT59 0x0800000000000000ULL
+#define BIT60 0x1000000000000000ULL
+#define BIT61 0x2000000000000000ULL
+#define BIT62 0x4000000000000000ULL
+#define BIT63 0x8000000000000000ULL
+#define INC_BIT(bit) (bit<<1)
+#define INC_NUM(bit) (bit + 1)
+#endif
+
+#define MAGIC_NUMBER 0x01020304
+
+#define PARAMETER_MAX_SIZE 64 /* in byte */
+#define PARAMETER_MAX_MEMBER (PARAMETER_MAX_SIZE/4)
+
+enum is_entry {
+ ENTRY_GLOBAL,
+ ENTRY_BUFFER,
+ ENTRY_SENSOR,
+ ENTRY_ISP,
+ ENTRY_DRC,
+ ENTRY_SCALERC,
+ ENTRY_ODC,
+ ENTRY_DIS,
+ ENTRY_TDNR,
+ ENTRY_SCALERP,
+ ENTRY_LHFD, /* 10 */
+ ENTRY_END
+};
+
+enum is_param_set_bit {
+ PARAM_GLOBAL_SHOTMODE = 0,
+ PARAM_SENSOR_CONTROL,
+ PARAM_SENSOR_OTF_INPUT,
+ PARAM_SENSOR_OTF_OUTPUT,
+ PARAM_SENSOR_FRAME_RATE,
+ PARAM_SENSOR_DMA_OUTPUT,
+ PARAM_BUFFER_CONTROL,
+ PARAM_BUFFER_OTF_INPUT,
+ PARAM_BUFFER_OTF_OUTPUT,
+ PARAM_ISP_CONTROL,
+ PARAM_ISP_OTF_INPUT = 10,
+ PARAM_ISP_DMA1_INPUT,
+ PARAM_ISP_DMA2_INPUT,
+ PARAM_ISP_AA,
+ PARAM_ISP_FLASH,
+ PARAM_ISP_AWB,
+ PARAM_ISP_IMAGE_EFFECT,
+ PARAM_ISP_ISO,
+ PARAM_ISP_ADJUST,
+ PARAM_ISP_METERING,
+ PARAM_ISP_AFC = 20,
+ PARAM_ISP_OTF_OUTPUT,
+ PARAM_ISP_DMA1_OUTPUT,
+ PARAM_ISP_DMA2_OUTPUT,
+ PARAM_DRC_CONTROL,
+ PARAM_DRC_OTF_INPUT,
+ PARAM_DRC_DMA_INPUT,
+ PARAM_DRC_OTF_OUTPUT,
+ PARAM_SCALERC_CONTROL,
+ PARAM_SCALERC_OTF_INPUT,
+ PARAM_SCALERC_IMAGE_EFFECT = 30,
+ PARAM_SCALERC_INPUT_CROP,
+ PARAM_SCALERC_OUTPUT_CROP,
+ PARAM_SCALERC_OTF_OUTPUT,
+ PARAM_SCALERC_DMA_OUTPUT = 34,
+ PARAM_ODC_CONTROL,
+ PARAM_ODC_OTF_INPUT,
+ PARAM_ODC_OTF_OUTPUT,
+ PARAM_DIS_CONTROL,
+ PARAM_DIS_OTF_INPUT,
+ PARAM_DIS_OTF_OUTPUT = 40,
+ PARAM_TDNR_CONTROL,
+ PARAM_TDNR_OTF_INPUT,
+ PARAM_TDNR_1ST_FRAME,
+ PARAM_TDNR_OTF_OUTPUT,
+ PARAM_TDNR_DMA_OUTPUT,
+ PARAM_SCALERP_CONTROL,
+ PARAM_SCALERP_OTF_INPUT,
+ PARAM_SCALERP_IMAGE_EFFECT,
+ PARAM_SCALERP_INPUT_CROP,
+ PARAM_SCALERP_OUTPUT_CROP = 50,
+ PARAM_SCALERP_ROTATION,
+ PARAM_SCALERP_FLIP,
+ PARAM_SCALERP_OTF_OUTPUT,
+ PARAM_SCALERP_DMA_OUTPUT,
+ PARAM_FD_CONTROL,
+ PARAM_FD_OTF_INPUT,
+ PARAM_FD_DMA_INPUT,
+ PARAM_FD_CONFIG = 58,
+ PARAM_END,
+};
+
+#define ADDRESS_TO_OFFSET(start, end) ((uint32)end - (uint32)start)
+#define OFFSET_TO_NUM(offset) ((offset)>>6)
+#define IS_OFFSET_LOWBIT(offset) (OFFSET_TO_NUM(offset) >= \
+ 32 ? false : true)
+#define OFFSET_TO_BIT(offset) \
+ {(IS_OFFSET_LOWBIT(offset) ? (1<<OFFSET_TO_NUM(offset)) \
+ : (1<<(OFFSET_TO_NUM(offset)-32))}
+#define LOWBIT_OF_NUM(num) (num >= 32 ? 0 : BIT0<<num)
+#define HIGHBIT_OF_NUM(num) (num >= 32 ? BIT0<<(num-32) : 0)
+
+/* 0~31 */
+#define PARAM_GLOBAL_SHOTMODE 0
+#define PARAM_SENSOR_CONTROL INC_NUM(PARAM_GLOBAL_SHOTMODE)
+#define PARAM_SENSOR_OTF_INPUT INC_NUM(PARAM_SENSOR_CONTROL)
+#define PARAM_SENSOR_OTF_OUTPUT INC_NUM(PARAM_SENSOR_OTF_INPUT)
+#define PARAM_SENSOR_FRAME_RATE INC_NUM(PARAM_SENSOR_OTF_OUTPUT)
+#define PARAM_SENSOR_DMA_OUTPUT INC_NUM(PARAM_SENSOR_FRAME_RATE)
+#define PARAM_BUFFER_CONTROL INC_NUM(PARAM_SENSOR_DMA_OUTPUT)
+#define PARAM_BUFFER_OTF_INPUT INC_NUM(PARAM_BUFFER_CONTROL)
+#define PARAM_BUFFER_OTF_OUTPUT INC_NUM(PARAM_BUFFER_OTF_INPUT)
+#define PARAM_ISP_CONTROL INC_NUM(PARAM_BUFFER_OTF_OUTPUT)
+#define PARAM_ISP_OTF_INPUT INC_NUM(PARAM_ISP_CONTROL)
+#define PARAM_ISP_DMA1_INPUT INC_NUM(PARAM_ISP_OTF_INPUT)
+#define PARAM_ISP_DMA2_INPUT INC_NUM(PARAM_ISP_DMA1_INPUT)
+#define PARAM_ISP_AA INC_NUM(PARAM_ISP_DMA2_INPUT)
+#define PARAM_ISP_FLASH INC_NUM(PARAM_ISP_AA)
+#define PARAM_ISP_AWB INC_NUM(PARAM_ISP_FLASH)
+#define PARAM_ISP_IMAGE_EFFECT INC_NUM(PARAM_ISP_AWB)
+#define PARAM_ISP_ISO INC_NUM(PARAM_ISP_IMAGE_EFFECT)
+#define PARAM_ISP_ADJUST INC_NUM(PARAM_ISP_ISO)
+#define PARAM_ISP_METERING INC_NUM(PARAM_ISP_ADJUST)
+#define PARAM_ISP_AFC INC_NUM(PARAM_ISP_METERING)
+#define PARAM_ISP_OTF_OUTPUT INC_NUM(PARAM_ISP_AFC)
+#define PARAM_ISP_DMA1_OUTPUT INC_NUM(PARAM_ISP_OTF_OUTPUT)
+#define PARAM_ISP_DMA2_OUTPUT INC_NUM(PARAM_ISP_DMA1_OUTPUT)
+#define PARAM_DRC_CONTROL INC_NUM(PARAM_ISP_DMA2_OUTPUT)
+#define PARAM_DRC_OTF_INPUT INC_NUM(PARAM_DRC_CONTROL)
+#define PARAM_DRC_DMA_INPUT INC_NUM(PARAM_DRC_OTF_INPUT)
+#define PARAM_DRC_OTF_OUTPUT INC_NUM(PARAM_DRC_DMA_INPUT)
+#define PARAM_SCALERC_CONTROL INC_NUM(PARAM_DRC_OTF_OUTPUT)
+#define PARAM_SCALERC_OTF_INPUT INC_NUM(PARAM_SCALERC_CONTROL)
+#define PARAM_SCALERC_IMAGE_EFFECT INC_NUM(PARAM_SCALERC_OTF_INPUT)
+#define PARAM_SCALERC_INPUT_CROP INC_NUM(PARAM_SCALERC_IMAGE_EFFECT)
+#define PARAM_SCALERC_OUTPUT_CROP INC_NUM(PARAM_SCALERC_INPUT_CROP)
+#define PARAM_SCALERC_OTF_OUTPUT INC_NUM(PARAM_SCALERC_OUTPUT_CROP)
+
+/* 32~63 */
+#define PARAM_SCALERC_DMA_OUTPUT INC_NUM(PARAM_SCALERC_OTF_OUTPUT)
+#define PARAM_ODC_CONTROL INC_NUM(PARAM_SCALERC_DMA_OUTPUT)
+#define PARAM_ODC_OTF_INPUT INC_NUM(PARAM_ODC_CONTROL)
+#define PARAM_ODC_OTF_OUTPUT INC_NUM(PARAM_ODC_OTF_INPUT)
+#define PARAM_DIS_CONTROL INC_NUM(PARAM_ODC_OTF_OUTPUT)
+#define PARAM_DIS_OTF_INPUT INC_NUM(PARAM_DIS_CONTROL)
+#define PARAM_DIS_OTF_OUTPUT INC_NUM(PARAM_DIS_OTF_INPUT)
+#define PARAM_TDNR_CONTROL INC_NUM(PARAM_DIS_OTF_OUTPUT)
+#define PARAM_TDNR_OTF_INPUT INC_NUM(PARAM_TDNR_CONTROL)
+#define PARAM_TDNR_1ST_FRAME INC_NUM(PARAM_TDNR_OTF_INPUT)
+#define PARAM_TDNR_OTF_OUTPUT INC_NUM(PARAM_TDNR_1ST_FRAME)
+#define PARAM_TDNR_DMA_OUTPUT INC_NUM(PARAM_TDNR_OTF_OUTPUT)
+#define PARAM_SCALERP_CONTROL INC_NUM(PARAM_TDNR_DMA_OUTPUT)
+#define PARAM_SCALERP_OTF_INPUT INC_NUM(PARAM_SCALERP_CONTROL)
+#define PARAM_SCALERP_IMAGE_EFFECT INC_NUM(PARAM_SCALERP_OTF_INPUT)
+#define PARAM_SCALERP_INPUT_CROP INC_NUM(PARAM_SCALERP_IMAGE_EFFECT)
+#define PARAM_SCALERP_OUTPUT_CROP INC_NUM(PARAM_SCALERP_INPUT_CROP)
+#define PARAM_SCALERP_ROTATION INC_NUM(PARAM_SCALERP_OUTPUT_CROP)
+#define PARAM_SCALERP_FLIP INC_NUM(PARAM_SCALERP_ROTATION)
+#define PARAM_SCALERP_OTF_OUTPUT INC_NUM(PARAM_SCALERP_FLIP)
+#define PARAM_SCALERP_DMA_OUTPUT INC_NUM(PARAM_SCALERP_OTF_OUTPUT)
+#define PARAM_FD_CONTROL INC_NUM(PARAM_SCALERP_DMA_OUTPUT)
+#define PARAM_FD_OTF_INPUT INC_NUM(PARAM_FD_CONTROL)
+#define PARAM_FD_DMA_INPUT INC_NUM(PARAM_FD_OTF_INPUT)
+#define PARAM_FD_CONFIG INC_NUM(PARAM_FD_DMA_INPUT)
+#define PARAM_END INC_NUM(PARAM_FD_CONFIG)
+
+#define PARAM_STRNUM_GLOBAL (PARAM_GLOBAL_SHOTMODE)
+#define PARAM_RANGE_GLOBAL 1
+#define PARAM_STRNUM_SENSOR (PARAM_SENSOR_BYPASS)
+#define PARAM_RANGE_SENSOR 5
+#define PARAM_STRNUM_BUFFER (PARAM_BUFFER_BYPASS)
+#define PARAM_RANGE_BUFFER 3
+#define PARAM_STRNUM_ISP (PARAM_ISP_BYPASS)
+#define PARAM_RANGE_ISP 15
+#define PARAM_STRNUM_DRC (PARAM_DRC_BYPASS)
+#define PARAM_RANGE_DRC 4
+#define PARAM_STRNUM_SCALERC (PARAM_SCALERC_BYPASS)
+#define PARAM_RANGE_SCALERC 7
+#define PARAM_STRNUM_ODC (PARAM_ODC_BYPASS)
+#define PARAM_RANGE_ODC 3
+#define PARAM_STRNUM_DIS (PARAM_DIS_BYPASS)
+#define PARAM_RANGE_DIS 3
+#define PARAM_STRNUM_TDNR (PARAM_TDNR_BYPASS)
+#define PARAM_RANGE_TDNR 5
+#define PARAM_STRNUM_SCALERP (PARAM_SCALERP_BYPASS)
+#define PARAM_RANGE_SCALERP 9
+#define PARAM_STRNUM_LHFD (PARAM_FD_BYPASS)
+#define PARAM_RANGE_LHFD 4
+
+#define PARAM_LOW_MASK (0xFFFFFFFF)
+#define PARAM_HIGH_MASK (0x07FFFFFF)
+
+/* Enumerations
+*
+*/
+/* ---------------------- INTR map-------------------------------- */
+enum interrupt_map {
+ INTR_GENERAL = 0,
+ INTR_FRAME_DONE_ISP = 1,
+ INTR_FRAME_DONE_SCALERC = 2,
+ INTR_FRAME_DONE_TDNR = 3,
+ INTR_FRAME_DONE_SCALERP = 4
+};
+
+/* ---------------------- Input ----------------------------------- */
+enum control_command {
+ CONTROL_COMMAND_STOP = 0,
+ CONTROL_COMMAND_START = 1
+};
+
+enum bypass_command {
+ CONTROL_BYPASS_DISABLE = 0,
+ CONTROL_BYPASS_ENABLE = 1
+};
+
+enum control_error {
+ CONTROL_ERROR_NO = 0
+};
+
+enum otf_input_command {
+ OTF_INPUT_COMMAND_DISABLE = 0,
+ OTF_INPUT_COMMAND_ENABLE = 1
+};
+
+enum otf_input_format {
+ OTF_INPUT_FORMAT_BAYER = 0, /* 1 Channel */
+ OTF_INPUT_FORMAT_YUV444 = 1, /* 3 Channel */
+ OTF_INPUT_FORMAT_YUV422 = 2, /* 3 Channel */
+ OTF_INPUT_FORMAT_YUV420 = 3, /* 3 Channel */
+ OTF_INPUT_FORMAT_STRGEN_COLORBAR_BAYER = 10,
+ OTF_INPUT_FORMAT_BAYER_DMA = 11,
+};
+
+enum otf_input_bitwidth {
+ OTF_INPUT_BIT_WIDTH_14BIT = 14,
+ OTF_INPUT_BIT_WIDTH_12BIT = 12,
+ OTF_INPUT_BIT_WIDTH_11BIT = 11,
+ OTF_INPUT_BIT_WIDTH_10BIT = 10,
+ OTF_INPUT_BIT_WIDTH_9BIT = 9,
+ OTF_INPUT_BIT_WIDTH_8BIT = 8
+};
+
+enum otf_input_order {
+ OTF_INPUT_ORDER_BAYER_GR_BG = 0,
+};
+
+enum otf_intput_error {
+ OTF_INPUT_ERROR_NO = 0 /* Input setting is done */
+};
+
+enum dma_input_command {
+ DMA_INPUT_COMMAND_DISABLE = 0,
+ DMA_INPUT_COMMAND_ENABLE = 1,
+ DMA_INPUT_COMMAND_BUF_MNGR = 2,
+ DMA_INPUT_COMMAND_RUN_SINGLE = 3,
+};
+
+enum dma_inut_format {
+ DMA_INPUT_FORMAT_BAYER = 0,
+ DMA_INPUT_FORMAT_YUV444 = 1,
+ DMA_INPUT_FORMAT_YUV422 = 2,
+ DMA_INPUT_FORMAT_YUV420 = 3,
+};
+
+enum dma_input_bitwidth {
+ DMA_INPUT_BIT_WIDTH_14BIT = 14,
+ DMA_INPUT_BIT_WIDTH_12BIT = 12,
+ DMA_INPUT_BIT_WIDTH_11BIT = 11,
+ DMA_INPUT_BIT_WIDTH_10BIT = 10,
+ DMA_INPUT_BIT_WIDTH_9BIT = 9,
+ DMA_INPUT_BIT_WIDTH_8BIT = 8
+};
+
+enum dma_input_plane {
+ DMA_INPUT_PLANE_3 = 3,
+ DMA_INPUT_PLANE_2 = 2,
+ DMA_INPUT_PLANE_1 = 1
+};
+
+enum dma_input_order {
+ /* (for DMA_INPUT_PLANE_3) */
+ DMA_INPUT_ORDER_NO = 0,
+ /* (only valid at DMA_INPUT_PLANE_2) */
+ DMA_INPUT_ORDER_CbCr = 1,
+ /* (only valid at DMA_INPUT_PLANE_2) */
+ DMA_INPUT_ORDER_CrCb = 2,
+ /* (only valid at DMA_INPUT_PLANE_1 & DMA_INPUT_FORMAT_YUV444) */
+ DMA_INPUT_ORDER_YCbCr = 3,
+ /* (only valid at DMA_INPUT_FORMAT_YUV422 & DMA_INPUT_PLANE_1) */
+ DMA_INPUT_ORDER_YYCbCr = 4,
+ /* (only valid at DMA_INPUT_FORMAT_YUV422 & DMA_INPUT_PLANE_1) */
+ DMA_INPUT_ORDER_YCbYCr = 5,
+ /* (only valid at DMA_INPUT_FORMAT_YUV422 & DMA_INPUT_PLANE_1) */
+ DMA_INPUT_ORDER_YCrYCb = 6,
+ /* (only valid at DMA_INPUT_FORMAT_YUV422 & DMA_INPUT_PLANE_1) */
+ DMA_INPUT_ORDER_CbYCrY = 7,
+ /* (only valid at DMA_INPUT_FORMAT_YUV422 & DMA_INPUT_PLANE_1) */
+ DMA_INPUT_ORDER_CrYCbY = 8,
+ /* (only valid at DMA_INPUT_FORMAT_BAYER) */
+ DMA_INPUT_ORDER_GR_BG = 9
+};
+
+enum dma_input_error {
+ DMA_INPUT_ERROR_NO = 0 /* DMA input setting is done */
+};
+
+/* ---------------------- Output ----------------------------------- */
+enum otf_output_crop {
+ OTF_OUTPUT_CROP_DISABLE = 0,
+ OTF_OUTPUT_CROP_ENABLE = 1
+};
+
+enum otf_output_command {
+ OTF_OUTPUT_COMMAND_DISABLE = 0,
+ OTF_OUTPUT_COMMAND_ENABLE = 1
+};
+
+enum orf_output_format {
+ OTF_OUTPUT_FORMAT_YUV444 = 1,
+ OTF_OUTPUT_FORMAT_YUV422 = 2,
+ OTF_OUTPUT_FORMAT_YUV420 = 3,
+ OTF_OUTPUT_FORMAT_RGB = 4
+};
+
+enum otf_output_bitwidth {
+ OTF_OUTPUT_BIT_WIDTH_14BIT = 14,
+ OTF_OUTPUT_BIT_WIDTH_12BIT = 12,
+ OTF_OUTPUT_BIT_WIDTH_11BIT = 11,
+ OTF_OUTPUT_BIT_WIDTH_10BIT = 10,
+ OTF_OUTPUT_BIT_WIDTH_9BIT = 9,
+ OTF_OUTPUT_BIT_WIDTH_8BIT = 8
+};
+
+enum otf_output_order {
+ OTF_OUTPUT_ORDER_BAYER_GR_BG = 0,
+};
+
+enum otf_output_error {
+ OTF_OUTPUT_ERROR_NO = 0 /* Output Setting is done */
+};
+
+enum dma_output_command {
+ DMA_OUTPUT_COMMAND_DISABLE = 0,
+ DMA_OUTPUT_COMMAND_ENABLE = 1,
+ DMA_OUTPUT_COMMAND_BUF_MNGR = 2,
+ DMA_OUTPUT_UPDATE_MASK_BITS = 3
+};
+
+enum dma_output_format {
+ DMA_OUTPUT_FORMAT_BAYER = 0,
+ DMA_OUTPUT_FORMAT_YUV444 = 1,
+ DMA_OUTPUT_FORMAT_YUV422 = 2,
+ DMA_OUTPUT_FORMAT_YUV420 = 3,
+ DMA_OUTPUT_FORMAT_RGB = 4
+};
+
+enum dma_output_bitwidth {
+ DMA_OUTPUT_BIT_WIDTH_14BIT = 14,
+ DMA_OUTPUT_BIT_WIDTH_12BIT = 12,
+ DMA_OUTPUT_BIT_WIDTH_11BIT = 11,
+ DMA_OUTPUT_BIT_WIDTH_10BIT = 10,
+ DMA_OUTPUT_BIT_WIDTH_9BIT = 9,
+ DMA_OUTPUT_BIT_WIDTH_8BIT = 8
+};
+
+enum dma_output_plane {
+ DMA_OUTPUT_PLANE_3 = 3,
+ DMA_OUTPUT_PLANE_2 = 2,
+ DMA_OUTPUT_PLANE_1 = 1
+};
+
+enum dma_output_order {
+ DMA_OUTPUT_ORDER_NO = 0,
+ /* (for DMA_OUTPUT_PLANE_3) */
+ DMA_OUTPUT_ORDER_CbCr = 1,
+ /* (only valid at DMA_INPUT_PLANE_2) */
+ DMA_OUTPUT_ORDER_CrCb = 2,
+ /* (only valid at DMA_OUTPUT_PLANE_2) */
+ DMA_OUTPUT_ORDER_YYCbCr = 3,
+ /* (only valid at DMA_OUTPUT_FORMAT_YUV422 & DMA_OUTPUT_PLANE_1) */
+ DMA_OUTPUT_ORDER_YCbYCr = 4,
+ /* (only valid at DMA_OUTPUT_FORMAT_YUV422 & DMA_OUTPUT_PLANE_1) */
+ DMA_OUTPUT_ORDER_YCrYCb = 5,
+ /* (only valid at DMA_OUTPUT_FORMAT_YUV422 & DMA_OUTPUT_PLANE_1) */
+ DMA_OUTPUT_ORDER_CbYCrY = 6,
+ /* (only valid at DMA_OUTPUT_FORMAT_YUV422 & DMA_OUTPUT_PLANE_1) */
+ DMA_OUTPUT_ORDER_CrYCbY = 7,
+ /* (only valid at DMA_OUTPUT_FORMAT_YUV422 & DMA_OUTPUT_PLANE_1) */
+ DMA_OUTPUT_ORDER_YCbCr = 8,
+ /* (only valid at DMA_OUTPUT_FORMAT_YUV444 & DMA_OUPUT_PLANE_1) */
+ DMA_OUTPUT_ORDER_CrYCb = 9,
+ /* (only valid at DMA_OUTPUT_FORMAT_YUV444 & DMA_OUPUT_PLANE_1) */
+ DMA_OUTPUT_ORDER_CrCbY = 10,
+ /* (only valid at DMA_OUTPUT_FORMAT_YUV444 & DMA_OUPUT_PLANE_1) */
+ DMA_OUTPUT_ORDER_CbYCr = 11,
+ /* (only valid at DMA_OUTPUT_FORMAT_YUV444 & DMA_OUPUT_PLANE_1) */
+ DMA_OUTPUT_ORDER_YCrCb = 12,
+ /* (only valid at DMA_OUTPUT_FORMAT_YUV444 & DMA_OUPUT_PLANE_1) */
+ DMA_OUTPUT_ORDER_CbCrY = 13,
+ /* (only valid at DMA_OUTPUT_FORMAT_YUV444 & DMA_OUPUT_PLANE_1) */
+ DMA_OUTPUT_ORDER_BGR = 14,
+ /* (only valid at DMA_OUTPUT_FORMAT_RGB) */
+ DMA_OUTPUT_ORDER_GB_BG = 15
+ /* (only valid at DMA_OUTPUT_FORMAT_BAYER) */
+};
+
+enum dma_output_notify_dma_done {
+ DMA_OUTPUT_NOTIFY_DMA_DONE_DISABLE = 0,
+ DMA_OUTPUT_NOTIFY_DMA_DONE_ENBABLE = 1,
+};
+
+enum dma_output_error {
+ DMA_OUTPUT_ERROR_NO = 0 /* DMA output setting is done */
+};
+
+/* ---------------------- Global ----------------------------------- */
+enum global_shotmode_error {
+ GLOBAL_SHOTMODE_ERROR_NO = 0 /* shot-mode setting is done */
+};
+
+/* ------------------------- AA ------------------------------------ */
+enum isp_lock_command {
+ ISP_AA_COMMAND_START = 0,
+ ISP_AA_COMMAND_STOP = 1
+};
+
+enum isp_lock_target {
+ ISP_AA_TARGET_AF = 1,
+ ISP_AA_TARGET_AE = 2,
+ ISP_AA_TARGET_AWB = 4
+};
+
+enum isp_af_mode {
+ ISP_AF_MODE_MANUAL = 0,
+ ISP_AF_MODE_SINGLE = 1,
+ ISP_AF_MODE_CONTINUOUS = 2,
+ ISP_AF_MODE_TOUCH = 3,
+ ISP_AF_MODE_SLEEP = 4,
+ ISP_AF_MODE_INIT = 5,
+ ISP_AF_MODE_SET_CENTER_WINDOW = 6,
+ ISP_AF_MODE_SET_TOUCH_WINDOW = 7,
+ ISP_AF_SET_FACE_WINDOW = 8
+};
+
+enum isp_af_face {
+ ISP_AF_FACE_DISABLE = 0,
+ ISP_AF_FACE_ENABLE = 1
+};
+
+enum isp_af_scene {
+ ISP_AF_SCENE_NORMAL = 0,
+ ISP_AF_SCENE_MACRO = 1
+};
+
+enum isp_af_sleep {
+ ISP_AF_SLEEP_OFF = 0,
+ ISP_AF_SLEEP_ON = 1
+};
+
+enum isp_af_continuous {
+ ISP_AF_CONTINUOUS_DISABLE = 0,
+ ISP_AF_CONTINUOUS_ENABLE = 1
+};
+
+enum isp_af_error {
+ ISP_AF_ERROR_NO = 0, /* AF mode change is done */
+ ISP_AF_EROOR_NO_LOCK_DONE = 1 /* AF lock is done */
+};
+
+/* ------------------------- Flash ------------------------------------- */
+enum isp_flash_command {
+ ISP_FLASH_COMMAND_DISABLE = 0 ,
+ ISP_FLASH_COMMAND_MANUALON = 1, /* (forced flash) */
+ ISP_FLASH_COMMAND_AUTO = 2,
+ ISP_FLASH_COMMAND_TORCH = 3 /* 3 sec */
+};
+
+enum isp_flash_redeye {
+ ISP_FLASH_REDEYE_DISABLE = 0,
+ ISP_FLASH_REDEYE_ENABLE = 1
+};
+
+enum isp_flash_error {
+ ISP_FLASH_ERROR_NO = 0 /* Flash setting is done */
+};
+
+/* -------------------------- AWB ------------------------------------ */
+enum isp_awb_command {
+ ISP_AWB_COMMAND_AUTO = 0,
+ ISP_AWB_COMMAND_ILLUMINATION = 1,
+ ISP_AWB_COMMAND_MANUAL = 2
+};
+
+enum isp_awb_illumination {
+ ISP_AWB_ILLUMINATION_DAYLIGHT = 0,
+ ISP_AWB_ILLUMINATION_CLOUDY = 1,
+ ISP_AWB_ILLUMINATION_TUNGSTEN = 2,
+ ISP_AWB_ILLUMINATION_FLUORESCENT = 3
+};
+
+enum isp_awb_error {
+ ISP_AWB_ERROR_NO = 0 /* AWB setting is done */
+};
+
+/* -------------------------- Effect ----------------------------------- */
+enum isp_imageeffect_command {
+ ISP_IMAGE_EFFECT_DISABLE = 0,
+ ISP_IMAGE_EFFECT_MONOCHROME = 1,
+ ISP_IMAGE_EFFECT_NEGATIVE_MONO = 2,
+ ISP_IMAGE_EFFECT_NEGATIVE_COLOR = 3,
+ ISP_IMAGE_EFFECT_SEPIA = 4
+};
+
+enum isp_imageeffect_error {
+ ISP_IMAGE_EFFECT_ERROR_NO = 0 /* Image effect setting is done */
+};
+
+/* --------------------------- ISO ------------------------------------ */
+enum isp_iso_command {
+ ISP_ISO_COMMAND_AUTO = 0,
+ ISP_ISO_COMMAND_MANUAL = 1
+};
+
+enum iso_error {
+ ISP_ISO_ERROR_NO = 0 /* ISO setting is done */
+};
+
+/* -------------------------- Adjust ----------------------------------- */
+enum iso_adjust_command {
+ ISP_ADJUST_COMMAND_AUTO = 0,
+ ISP_ADJUST_COMMAND_MANUAL_CONTRAST = (1 << 0),
+ ISP_ADJUST_COMMAND_MANUAL_SATURATION = (1 << 1),
+ ISP_ADJUST_COMMAND_MANUAL_SHARPNESS = (1 << 2),
+ ISP_ADJUST_COMMAND_MANUAL_EXPOSURE = (1 << 3),
+ ISP_ADJUST_COMMAND_MANUAL_BRIGHTNESS = (1 << 4),
+ ISP_ADJUST_COMMAND_MANUAL_HUE = (1 << 5),
+ ISP_ADJUST_COMMAND_MANUAL_ALL = 0x7F
+};
+
+enum isp_adjust_error {
+ ISP_ADJUST_ERROR_NO = 0 /* Adjust setting is done */
+};
+
+/* ------------------------- Metering ---------------------------------- */
+enum isp_metering_command {
+ ISP_METERING_COMMAND_AVERAGE = 0,
+ ISP_METERING_COMMAND_SPOT = 1,
+ ISP_METERING_COMMAND_MATRIX = 2,
+ ISP_METERING_COMMAND_CENTER = 3
+};
+
+enum isp_metering_error {
+ ISP_METERING_ERROR_NO = 0 /* Metering setting is done */
+};
+
+/* -------------------------- AFC ----------------------------------- */
+enum isp_afc_command {
+ ISP_AFC_COMMAND_DISABLE = 0,
+ ISP_AFC_COMMAND_AUTO = 1,
+ ISP_AFC_COMMAND_MANUAL = 2
+};
+
+enum isp_afc_manual {
+ ISP_AFC_MANUAL_50HZ = 50,
+ ISP_AFC_MANUAL_60HZ = 60
+};
+
+enum isp_afc_error {
+ ISP_AFC_ERROR_NO = 0 /* AFC setting is done */
+};
+
+enum isp_scene_command {
+ ISP_SCENE_NONE = 0,
+ ISP_SCENE_PORTRAIT = 1,
+ ISP_SCENE_LANDSCAPE = 2,
+ ISP_SCENE_SPORTS = 3,
+ ISP_SCENE_PARTYINDOOR = 4,
+ ISP_SCENE_BEACHSNOW = 5,
+ ISP_SCENE_SUNSET = 6,
+ ISP_SCENE_DAWN = 7,
+ ISP_SCENE_FALL = 8,
+ ISP_SCENE_NIGHT = 9,
+ ISP_SCENE_AGAINSTLIGHTWLIGHT = 10,
+ ISP_SCENE_AGAINSTLIGHTWOLIGHT = 11,
+ ISP_SCENE_FIRE = 12,
+ ISP_SCENE_TEXT = 13,
+ ISP_SCENE_CANDLE = 14
+};
+
+/* -------------------------- Scaler --------------------------------- */
+enum scaler_imageeffect_command {
+ SCALER_IMAGE_EFFECT_COMMNAD_DISABLE = 0,
+ SCALER_IMAGE_EFFECT_COMMNAD_SEPIA_CB = 1,
+ SCALER_IMAGE_EFFECT_COMMAND_SEPIA_CR = 2,
+ SCALER_IMAGE_EFFECT_COMMAND_NEGATIVE = 3,
+ SCALER_IMAGE_EFFECT_COMMAND_ARTFREEZE = 4,
+ SCALER_IMAGE_EFFECT_COMMAND_EMBOSSING = 5,
+ SCALER_IMAGE_EFFECT_COMMAND_SILHOUETTE = 6
+};
+
+enum scaler_imageeffect_error {
+ SCALER_IMAGE_EFFECT_ERROR_NO = 0
+};
+
+enum scaler_crop_command {
+ SCALER_CROP_COMMAND_DISABLE = 0,
+ SCALER_CROP_COMMAND_ENABLE = 1
+};
+
+enum scaler_crop_error {
+ SCALER_CROP_ERROR_NO = 0 /* crop setting is done */
+};
+
+enum scaler_scaling_command {
+ SCALER_SCALING_COMMNAD_DISABLE = 0,
+ SCALER_SCALING_COMMAND_UP = 1,
+ SCALER_SCALING_COMMAND_DOWN = 2
+};
+
+enum scaler_scaling_error {
+ SCALER_SCALING_ERROR_NO = 0
+};
+
+enum scaler_rotation_command {
+ SCALER_ROTATION_COMMAND_DISABLE = 0,
+ SCALER_ROTATION_COMMAND_CLOCKWISE90 = 1
+};
+
+enum scaler_rotation_error {
+ SCALER_ROTATION_ERROR_NO = 0
+};
+
+enum scaler_flip_command {
+ SCALER_FLIP_COMMAND_NORMAL = 0,
+ SCALER_FLIP_COMMAND_X_MIRROR = 1,
+ SCALER_FLIP_COMMAND_Y_MIRROR = 2,
+ SCALER_FLIP_COMMAND_XY_MIRROR = 3 /* (180 rotation) */
+};
+
+enum scaler_flip_error {
+ SCALER_FLIP_ERROR_NO = 0 /* flip setting is done */
+};
+
+/* -------------------------- 3DNR ----------------------------------- */
+enum tdnr_1st_frame_command {
+ TDNR_1ST_FRAME_COMMAND_NOPROCESSING = 0,
+ TDNR_1ST_FRAME_COMMAND_2DNR = 1
+};
+
+enum tdnr_1st_frame_error {
+ TDNR_1ST_FRAME_ERROR_NO = 0
+ /*1st frame setting is done*/
+};
+
+/* ---------------------------- FD ------------------------------------- */
+enum fd_config_command {
+ FD_CONFIG_COMMAND_MAXIMUM_NUMBER = 0x1,
+ FD_CONFIG_COMMAND_ROLL_ANGLE = 0x2,
+ FD_CONFIG_COMMAND_YAW_ANGLE = 0x4,
+ FD_CONFIG_COMMAND_SMILE_MODE = 0x8,
+ FD_CONFIG_COMMAND_BLINK_MODE = 0x10,
+ FD_CONFIG_COMMAND_EYES_DETECT = 0x20,
+ FD_CONFIG_COMMAND_MOUTH_DETECT = 0x40,
+ FD_CONFIG_COMMAND_ORIENTATION = 0x80,
+ FD_CONFIG_COMMAND_ORIENTATION_VALUE = 0x100
+};
+
+enum fd_config_roll_angle {
+ FD_CONFIG_ROLL_ANGLE_BASIC = 0,
+ FD_CONFIG_ROLL_ANGLE_PRECISE_BASIC = 1,
+ FD_CONFIG_ROLL_ANGLE_SIDES = 2,
+ FD_CONFIG_ROLL_ANGLE_PRECISE_SIDES = 3,
+ FD_CONFIG_ROLL_ANGLE_FULL = 4,
+ FD_CONFIG_ROLL_ANGLE_PRECISE_FULL = 5,
+};
+
+enum fd_config_yaw_angle {
+ FD_CONFIG_YAW_ANGLE_0 = 0,
+ FD_CONFIG_YAW_ANGLE_45 = 1,
+ FD_CONFIG_YAW_ANGLE_90 = 2,
+ FD_CONFIG_YAW_ANGLE_45_90 = 3,
+};
+
+enum fd_config_smile_mode {
+ FD_CONFIG_SMILE_MODE_DISABLE = 0,
+ FD_CONFIG_SMILE_MODE_ENABLE = 1
+};
+
+enum fd_config_blink_mode {
+ FD_CONFIG_BLINK_MODE_DISABLE = 0,
+ FD_CONFIG_BLINK_MODE_ENABLE = 1
+};
+
+enum fd_config_eye_result {
+ FD_CONFIG_EYES_DETECT_DISABLE = 0,
+ FD_CONFIG_EYES_DETECT_ENABLE = 1
+};
+
+enum fd_config_mouth_result {
+ FD_CONFIG_MOUTH_DETECT_DISABLE = 0,
+ FD_CONFIG_MOUTH_DETECT_ENABLE = 1
+};
+
+enum fd_config_orientation {
+ FD_CONFIG_ORIENTATION_DISABLE = 0,
+ FD_CONFIG_ORIENTATION_ENABLE = 1
+};
+
+struct param_control {
+ u32 cmd;
+ u32 bypass;
+ u32 buffer_address;
+ u32 buffer_number;
+ u32 first_drop_frame;
+ u32 run_mode; /* 0: continuous, 1: single */
+ u32 reserved[PARAMETER_MAX_MEMBER-7];
+ u32 err;
+};
+
+struct param_otf_input {
+ u32 cmd;
+ u32 width;
+ u32 height;
+ u32 format;
+ u32 bitwidth;
+ u32 order;
+ u32 crop_offset_x;
+ u32 crop_offset_y;
+ u32 crop_width;
+ u32 crop_height;
+ u32 frametime_min;
+ u32 frametime_max;
+ u32 reserved[PARAMETER_MAX_MEMBER-13];
+ u32 err;
+};
+
+struct param_dma_input {
+ u32 cmd;
+ u32 width;
+ u32 height;
+ u32 format;
+ u32 bitwidth;
+ u32 plane;
+ u32 order;
+ u32 buffer_number;
+ u32 buffer_address;
+ u32 reserved[PARAMETER_MAX_MEMBER-10];
+ u32 err;
+};
+
+struct param_otf_output {
+ u32 cmd;
+ u32 width;
+ u32 height;
+ u32 format;
+ u32 bitwidth;
+ u32 order;
+ u32 reserved[PARAMETER_MAX_MEMBER-7];
+ u32 err;
+};
+
+struct param_dma_output {
+ u32 cmd;
+ u32 width;
+ u32 height;
+ u32 format;
+ u32 bitwidth;
+ u32 plane;
+ u32 order;
+ u32 buffer_number;
+ u32 buffer_address;
+ u32 notify_dma_done;
+ u32 dma_out_mask;
+ u32 reserved[PARAMETER_MAX_MEMBER-12];
+ u32 err;
+};
+
+struct param_global_shotmode {
+ u32 cmd;
+ u32 skip_frames;
+ u32 reserved[PARAMETER_MAX_MEMBER-3];
+ u32 err;
+};
+
+struct param_sensor_framerate {
+ u32 frame_rate;
+ u32 reserved[PARAMETER_MAX_MEMBER-2];
+ u32 err;
+};
+
+struct param_isp_aa {
+ u32 cmd;
+ u32 target;
+ u32 mode;
+ u32 scene;
+ u32 sleep;
+ u32 face;
+ u32 touch_x;
+ u32 touch_y;
+ u32 manual_af_setting;
+ u32 reserved[PARAMETER_MAX_MEMBER-10];
+ u32 err;
+};
+struct param_isp_flash {
+ u32 cmd;
+ u32 redeye;
+ u32 reserved[PARAMETER_MAX_MEMBER-3];
+ u32 err;
+};
+
+struct param_isp_awb {
+ u32 cmd;
+ u32 illumination;
+ u32 reserved[PARAMETER_MAX_MEMBER-3];
+ u32 err;
+};
+
+struct param_isp_imageeffect {
+ u32 cmd;
+ u32 reserved[PARAMETER_MAX_MEMBER-2];
+ u32 err;
+};
+
+struct param_isp_iso {
+ u32 cmd;
+ u32 value;
+ u32 reserved[PARAMETER_MAX_MEMBER-3];
+ u32 err;
+};
+
+struct param_isp_adjust {
+ u32 cmd;
+ s32 contrast;
+ s32 saturation;
+ s32 sharpness;
+ s32 exposure;
+ s32 brightness;
+ s32 hue;
+ u32 reserved[PARAMETER_MAX_MEMBER-8];
+ u32 err;
+};
+
+struct param_isp_metering {
+ u32 cmd;
+ u32 win_pos_x;
+ u32 win_pos_y;
+ u32 win_width;
+ u32 win_height;
+ u32 reserved[PARAMETER_MAX_MEMBER-6];
+ u32 err;
+};
+
+struct param_isp_afc {
+ u32 cmd;
+ u32 manual;
+ u32 reserved[PARAMETER_MAX_MEMBER-3];
+ u32 err;
+};
+
+struct param_scaler_imageeffect {
+ u32 cmd;
+ u32 reserved[PARAMETER_MAX_MEMBER-2];
+ u32 err;
+};
+
+struct param_scaler_input_crop {
+ u32 cmd;
+ u32 pos_x;
+ u32 pos_y;
+ u32 crop_width;
+ u32 crop_height;
+ u32 in_width;
+ u32 in_height;
+ u32 out_width;
+ u32 out_height;
+ u32 reserved[PARAMETER_MAX_MEMBER-10];
+ u32 err;
+};
+
+struct param_scaler_output_crop {
+ u32 cmd;
+ u32 pos_x;
+ u32 pos_y;
+ u32 crop_width;
+ u32 crop_height;
+ u32 format;
+ u32 reserved[PARAMETER_MAX_MEMBER-7];
+ u32 err;
+};
+
+struct param_scaler_rotation {
+ u32 cmd;
+ u32 reserved[PARAMETER_MAX_MEMBER-2];
+ u32 err;
+};
+
+struct param_scaler_flip {
+ u32 cmd;
+ u32 reserved[PARAMETER_MAX_MEMBER-2];
+ u32 err;
+};
+
+struct param_3dnr_1stframe {
+ u32 cmd;
+ u32 reserved[PARAMETER_MAX_MEMBER-2];
+ u32 err;
+};
+
+struct param_fd_config {
+ u32 cmd;
+ u32 max_number;
+ u32 roll_angle;
+ u32 yaw_angle;
+ s32 smile_mode;
+ s32 blink_mode;
+ u32 eye_detect;
+ u32 mouth_detect;
+ u32 orientation;
+ u32 orientation_value;
+ u32 reserved[PARAMETER_MAX_MEMBER-11];
+ u32 err;
+};
+
+struct global_param {
+ struct param_global_shotmode shotmode; /* 0 */
+};
+
+/* To be added */
+struct sensor_param {
+ struct param_control control;
+ struct param_otf_input otf_input;
+ struct param_otf_output otf_output;
+ struct param_sensor_framerate frame_rate;
+ struct param_dma_output dma_output;
+};
+
+struct buffer_param {
+ struct param_control control;
+ struct param_otf_input otf_input;
+ struct param_otf_output otf_output;
+};
+
+struct isp_param {
+ struct param_control control;
+ struct param_otf_input otf_input;
+ struct param_dma_input dma1_input;
+ struct param_dma_input dma2_input;
+ struct param_isp_aa aa;
+ struct param_isp_flash flash;
+ struct param_isp_awb awb;
+ struct param_isp_imageeffect effect;
+ struct param_isp_iso iso;
+ struct param_isp_adjust adjust;
+ struct param_isp_metering metering;
+ struct param_isp_afc afc;
+ struct param_otf_output otf_output;
+ struct param_dma_output dma1_output;
+ struct param_dma_output dma2_output;
+};
+
+struct drc_param {
+ struct param_control control;
+ struct param_otf_input otf_input;
+ struct param_dma_input dma_input;
+ struct param_otf_output otf_output;
+};
+
+struct scalerc_param {
+ struct param_control control;
+ struct param_otf_input otf_input;
+ struct param_scaler_imageeffect effect;
+ struct param_scaler_input_crop input_crop;
+ struct param_scaler_output_crop output_crop;
+ struct param_otf_output otf_output;
+ struct param_dma_output dma_output;
+};
+
+struct odc_param {
+ struct param_control control;
+ struct param_otf_input otf_input;
+ struct param_otf_output otf_output;
+};
+
+struct dis_param {
+ struct param_control control;
+ struct param_otf_input otf_input;
+ struct param_otf_output otf_output;
+};
+
+struct tdnr_param {
+ struct param_control control;
+ struct param_otf_input otf_input;
+ struct param_3dnr_1stframe frame;
+ struct param_otf_output otf_output;
+ struct param_dma_output dma_output;
+};
+
+struct scalerp_param {
+ struct param_control control;
+ struct param_otf_input otf_input;
+ struct param_scaler_imageeffect effect;
+ struct param_scaler_input_crop input_crop;
+ struct param_scaler_output_crop output_crop;
+ struct param_scaler_rotation rotation;
+ struct param_scaler_flip flip;
+ struct param_otf_output otf_output;
+ struct param_dma_output dma_output;
+};
+
+struct fd_param {
+ struct param_control control;
+ struct param_otf_input otf_input;
+ struct param_dma_input dma_input;
+ struct param_fd_config config;
+};
+
+struct is_param_region {
+ struct global_param global;
+ struct sensor_param sensor;
+ struct buffer_param buf;
+ struct isp_param isp;
+ struct drc_param drc;
+ struct scalerc_param scalerc;
+ struct odc_param odc;
+ struct dis_param dis;
+ struct tdnr_param tdnr;
+ struct scalerp_param scalerp;
+ struct fd_param fd;
+};
+
+#define NUMBER_OF_GAMMA_CURVE_POINTS 32
+
+struct is_sensor_tune {
+ u32 exposure;
+ u32 analog_gain;
+ u32 frame_rate;
+ u32 actuator_pos;
+};
+
+struct is_tune_gammacurve {
+ u32 num_pts_x[NUMBER_OF_GAMMA_CURVE_POINTS];
+ u32 num_pts_y_r[NUMBER_OF_GAMMA_CURVE_POINTS];
+ u32 num_pts_y_g[NUMBER_OF_GAMMA_CURVE_POINTS];
+ u32 num_pts_y_b[NUMBER_OF_GAMMA_CURVE_POINTS];
+};
+
+struct is_isp_tune {
+ /* Brightness level : range 0~100, default : 7 */
+ u32 brightness_level;
+ /* Contrast level : range -127~127, default : 0 */
+ s32 contrast_level;
+ /* Saturation level : range -127~127, default : 0 */
+ s32 saturation_level;
+ s32 gamma_level;
+ struct is_tune_gammacurve gamma_curve[4];
+ /* Hue : range -127~127, default : 0 */
+ s32 hue;
+ /* Sharpness blur : range -127~127, default : 0 */
+ s32 sharpness_blur;
+ /* Despeckle : range -127~127, default : 0 */
+ s32 despeckle;
+ /* Edge color supression : range -127~127, default : 0 */
+ s32 edge_color_supression;
+ /* Noise reduction : range -127~127, default : 0 */
+ s32 noise_reduction;
+ /* (32*4 + 9)*4 = 548 bytes */
+};
+
+struct is_tune_region {
+ struct is_sensor_tune sensor_tune;
+ struct is_isp_tune isp_tune;
+};
+
+struct rational_t {
+ u32 num;
+ u32 den;
+};
+
+struct srational_t {
+ s32 num;
+ s32 den;
+};
+
+#define FLASH_FIRED_SHIFT 0
+#define FLASH_NOT_FIRED 0
+#define FLASH_FIRED 1
+
+#define FLASH_STROBE_SHIFT 1
+#define FLASH_STROBE_NO_DETECTION 0
+#define FLASH_STROBE_RESERVED 1
+#define FLASH_STROBE_RETURN_LIGHT_NOT_DETECTED 2
+#define FLASH_STROBE_RETURN_LIGHT_DETECTED 3
+
+#define FLASH_MODE_SHIFT 3
+#define FLASH_MODE_UNKNOWN 0
+#define FLASH_MODE_COMPULSORY_FLASH_FIRING 1
+#define FLASH_MODE_COMPULSORY_FLASH_SUPPRESSION 2
+#define FLASH_MODE_AUTO_MODE 3
+
+#define FLASH_FUNCTION_SHIFT 5
+#define FLASH_FUNCTION_PRESENT 0
+#define FLASH_FUNCTION_NONE 1
+
+#define FLASH_RED_EYE_SHIFT 6
+#define FLASH_RED_EYE_DISABLED 0
+#define FLASH_RED_EYE_SUPPORTED 1
+
+enum apex_aperture_value {
+ F1_0 = 0,
+ F1_4 = 1,
+ F2_0 = 2,
+ F2_8 = 3,
+ F4_0 = 4,
+ F5_6 = 5,
+ F8_9 = 6,
+ F11_0 = 7,
+ F16_0 = 8,
+ F22_0 = 9,
+ F32_0 = 10,
+};
+
+struct exif_attribute {
+ struct rational_t exposure_time;
+ struct srational_t shutter_speed;
+ u32 iso_speed_rating;
+ u32 flash;
+ struct srational_t brightness;
+};
+
+struct is_frame_header {
+ u32 valid;
+ u32 bad_mark;
+ u32 captured;
+ u32 frame_number;
+ struct exif_attribute exif;
+};
+
+struct is_fd_rect {
+ u32 offset_x;
+ u32 offset_y;
+ u32 width;
+ u32 height;
+};
+
+struct is_face_marker {
+ u32 frame_number;
+ struct is_fd_rect face;
+ struct is_fd_rect left_eye;
+ struct is_fd_rect right_eye;
+ struct is_fd_rect mouth;
+ u32 roll_angle;
+ u32 yaw_angle;
+ u32 confidence;
+ u32 smile_level;
+ u32 blink_level;
+};
+
+#define MAX_FRAME_COUNT 8
+#define MAX_FRAME_COUNT_PREVIEW 4
+#define MAX_FRAME_COUNT_CAPTURE 1
+#define MAX_FACE_COUNT 16
+
+#define MAX_SHARED_COUNT 500
+
+struct is_region {
+ struct is_param_region parameter;
+ struct is_tune_region tune;
+ struct is_frame_header header[MAX_FRAME_COUNT];
+ struct is_face_marker face[MAX_FACE_COUNT];
+ u32 shared[MAX_SHARED_COUNT];
+};
+
+struct is_debug_frame_descriptor {
+ u32 sensor_frame_time;
+ u32 sensor_exposure_time;
+ u32 sensor_analog_gain;
+ u32 req_lei;
+};
+
+#define MAX_FRAMEDESCRIPTOR_CONTEXT_NUM (30 * 20) /* 600 frame */
+#define MAX_VERSION_DISPLAY_BUF (32)
+
+struct is_share_region {
+ u32 frame_time;
+ u32 exposure_time;
+ u32 analog_gain;
+
+ u32 r_gain;
+ u32 g_gain;
+ u32 b_gain;
+
+ u32 af_position;
+ u32 af_status;
+ u32 af_scene_type;
+
+ u32 frame_descp_onoff_control;
+ u32 frame_descp_update_done;
+ u32 frame_descp_idx;
+ u32 frame_descp_max_idx;
+
+ struct is_debug_frame_descriptor
+ dbg_frame_descp_ctx[MAX_FRAMEDESCRIPTOR_CONTEXT_NUM];
+
+ u32 chip_id;
+ u32 chip_rev_no;
+ u8 ispfw_version_no[MAX_VERSION_DISPLAY_BUF];
+ u8 ispfw_version_date[MAX_VERSION_DISPLAY_BUF];
+ u8 sirc_sdk_version_no[MAX_VERSION_DISPLAY_BUF];
+ u8 sirc_sdk_revsion_no[MAX_VERSION_DISPLAY_BUF];
+ u8 sirc_sdk_version_date[MAX_VERSION_DISPLAY_BUF];
+};
+
+struct is_debug_control {
+ u32 uiWritePoint; /* 0~500KB boundary*/
+ u32 uiAssertFlag; /* 0:Not Inovked, 1:Invoked*/
+ u32 uiPAbortFlag; /* 0:Not Inovked, 1:Invoked*/
+ u32 uiDAbortFlag; /* 0:Not Inovked, 1:Invoked*/
+ u32 uiPDReadyFlag; /* 0:Normal, 1:EnterIdle(Ready to power down)*/
+ u32 uiISPFrameErr; /* Frame Error Count.*/
+ u32 uiDRCFrameErr; /* Frame Error Count.*/
+ u32 uiSCCFrameErr; /* Frame Error Count.*/
+ u32 uiODCFrameErr; /* Frame Error Count.*/
+ u32 uiDISFrameErr; /* Frame Error Count.*/
+ u32 uiTDNRFrameErr; /* Frame Error Count.*/
+ u32 uiSCPFrameErr; /* Frame Error Count.*/
+ u32 uiFDFrameErr; /* Frame Error Count.*/
+ u32 uiISPFrameDrop; /* Frame Drop Count.*/
+ u32 uiDRCFrameDrop; /* Frame Drop Count.*/
+ u32 uiDISFrameDrop; /* Frame Drop Count.*/
+};
+
+#endif
diff --git a/drivers/media/video/exynos/fimc-is-mc/fimc-is-regs.h b/drivers/media/video/exynos/fimc-is-mc/fimc-is-regs.h
new file mode 100644
index 0000000..4883bc0
--- /dev/null
+++ b/drivers/media/video/exynos/fimc-is-mc/fimc-is-regs.h
@@ -0,0 +1,353 @@
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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.
+ */
+
+#ifndef FIMC_IS_REGS_H
+#define FIMC_IS_REGS_H
+
+#include <mach/map.h>
+
+/* WDT_ISP register */
+#define WDT 0x00170000
+/* MCUCTL register */
+#define MCUCTL 0x00180000
+/* MCU Controller Register */
+#define MCUCTLR (MCUCTL+0x00)
+#define MCUCTLR_AXI_ISPX_AWCACHE(x) ((x) << 16)
+#define MCUCTLR_AXI_ISPX_ARCACHE(x) ((x) << 12)
+#define MCUCTLR_MSWRST (1 << 0)
+/* Boot Base OFfset Address Register */
+#define BBOAR (MCUCTL+0x04)
+#define BBOAR_BBOA(x) ((x) << 0)
+/* Interrupt Generation Register 0 from Host CPU to VIC */
+#define INTGR0 (MCUCTL+0x08)
+#define INTGR0_INTGC9 (1 << 25)
+#define INTGR0_INTGC8 (1 << 24)
+#define INTGR0_INTGC7 (1 << 23)
+#define INTGR0_INTGC6 (1 << 22)
+#define INTGR0_INTGC5 (1 << 21)
+#define INTGR0_INTGC4 (1 << 20)
+#define INTGR0_INTGC3 (1 << 19)
+#define INTGR0_INTGC2 (1 << 18)
+#define INTGR0_INTGC1 (1 << 17)
+#define INTGR0_INTGC0 (1 << 16)
+#define INTGR0_INTGD5 (1 << 5)
+#define INTGR0_INTGD4 (1 << 4)
+#define INTGR0_INTGD3 (1 << 3)
+#define INTGR0_INTGD2 (1 << 2)
+#define INTGR0_INTGD1 (1 << 1)
+#define INTGR0_INTGD0 (1 << 0)
+/* Interrupt Clear Register 0 from Host CPU to VIC */
+#define INTCR0 (MCUCTL+0x0c)
+#define INTCR0_INTCC9 (1 << 25)
+#define INTCR0_INTCC8 (1 << 24)
+#define INTCR0_INTCC7 (1 << 23)
+#define INTCR0_INTCC6 (1 << 22)
+#define INTCR0_INTCC5 (1 << 21)
+#define INTCR0_INTCC4 (1 << 20)
+#define INTCR0_INTCC3 (1 << 19)
+#define INTCR0_INTCC2 (1 << 18)
+#define INTCR0_INTCC1 (1 << 17)
+#define INTCR0_INTCC0 (1 << 16)
+#define INTCR0_INTCD5 (1 << 5)
+#define INTCR0_INTCD4 (1 << 4)
+#define INTCR0_INTCD3 (1 << 3)
+#define INTCR0_INTCD2 (1 << 2)
+#define INTCR0_INTCD1 (1 << 1)
+#define INTCR0_INTCD0 (1 << 0)
+/* Interrupt Mask Register 0 from Host CPU to VIC */
+#define INTMR0 (MCUCTL+0x10)
+#define INTMR0_INTMC9 (1 << 25)
+#define INTMR0_INTMC8 (1 << 24)
+#define INTMR0_INTMC7 (1 << 23)
+#define INTMR0_INTMC6 (1 << 22)
+#define INTMR0_INTMC5 (1 << 21)
+#define INTMR0_INTMC4 (1 << 20)
+#define INTMR0_INTMC3 (1 << 19)
+#define INTMR0_INTMC2 (1 << 18)
+#define INTMR0_INTMC1 (1 << 17)
+#define INTMR0_INTMC0 (1 << 16)
+#define INTMR0_INTMD5 (1 << 5)
+#define INTMR0_INTMD4 (1 << 4)
+#define INTMR0_INTMD3 (1 << 3)
+#define INTMR0_INTMD2 (1 << 2)
+#define INTMR0_INTMD1 (1 << 1)
+#define INTMR0_INTMD0 (1 << 0)
+/* Interrupt Status Register 0 from Host CPU to VIC */
+#define INTSR0 (MCUCTL+0x14)
+#define INTSR0_GET_INTSD0(x) (((x) >> 0) & 0x1)
+#define INTSR0_GET_INTSD1(x) (((x) >> 1) & 0x1)
+#define INTSR0_GET_INTSD2(x) (((x) >> 2) & 0x1)
+#define INTSR0_GET_INTSD3(x) (((x) >> 3) & 0x1)
+#define INTSR0_GET_INTSD4(x) (((x) >> 4) & 0x1)
+#define INTSR0_GET_INTSC0(x) (((x) >> 16) & 0x1)
+#define INTSR0_GET_INTSC1(x) (((x) >> 17) & 0x1)
+#define INTSR0_GET_INTSC2(x) (((x) >> 18) & 0x1)
+#define INTSR0_GET_INTSC3(x) (((x) >> 19) & 0x1)
+#define INTSR0_GET_INTSC4(x) (((x) >> 20) & 0x1)
+#define INTSR0_GET_INTSC5(x) (((x) >> 21) & 0x1)
+#define INTSR0_GET_INTSC6(x) (((x) >> 22) & 0x1)
+#define INTSR0_GET_INTSC7(x) (((x) >> 23) & 0x1)
+#define INTSR0_GET_INTSC8(x) (((x) >> 24) & 0x1)
+#define INTSR0_GET_INTSC9(x) (((x) >> 25) & 0x1)
+/* Interrupt Mask Status Register 0 from Host CPU to VIC */
+#define INTMSR0 (MCUCTL+0x18)
+#define INTMSR0_GET_INTMSD0(x) (((x) >> 0) & 0x1)
+#define INTMSR0_GET_INTMSD1(x) (((x) >> 1) & 0x1)
+#define INTMSR0_GET_INTMSD2(x) (((x) >> 2) & 0x1)
+#define INTMSR0_GET_INTMSD3(x) (((x) >> 3) & 0x1)
+#define INTMSR0_GET_INTMSD4(x) (((x) >> 4) & 0x1)
+#define INTMSR0_GET_INTMSC0(x) (((x) >> 16) & 0x1)
+#define INTMSR0_GET_INTMSC1(x) (((x) >> 17) & 0x1)
+#define INTMSR0_GET_INTMSC2(x) (((x) >> 18) & 0x1)
+#define INTMSR0_GET_INTMSC3(x) (((x) >> 19) & 0x1)
+#define INTMSR0_GET_INTMSC4(x) (((x) >> 20) & 0x1)
+#define INTMSR0_GET_INTMSC5(x) (((x) >> 21) & 0x1)
+#define INTMSR0_GET_INTMSC6(x) (((x) >> 22) & 0x1)
+#define INTMSR0_GET_INTMSC7(x) (((x) >> 23) & 0x1)
+#define INTMSR0_GET_INTMSC8(x) (((x) >> 24) & 0x1)
+#define INTMSR0_GET_INTMSC9(x) (((x) >> 25) & 0x1)
+/* Interrupt Generation Register 1 from ISP CPU to Host IC */
+#define INTGR1 (MCUCTL+0x1c)
+#define INTGR1_INTGC9 (1 << 9)
+#define INTGR1_INTGC8 (1 << 8)
+#define INTGR1_INTGC7 (1 << 7)
+#define INTGR1_INTGC6 (1 << 6)
+#define INTGR1_INTGC5 (1 << 5)
+#define INTGR1_INTGC4 (1 << 4)
+#define INTGR1_INTGC3 (1 << 3)
+#define INTGR1_INTGC2 (1 << 2)
+#define INTGR1_INTGC1 (1 << 1)
+#define INTGR1_INTGC0 (1 << 0)
+/* Interrupt Clear Register 1 from ISP CPU to Host IC */
+#define INTCR1 (MCUCTL+0x20)
+#define INTCR1_INTCC9 (1 << 9)
+#define INTCR1_INTCC8 (1 << 8)
+#define INTCR1_INTCC7 (1 << 7)
+#define INTCR1_INTCC6 (1 << 6)
+#define INTCR1_INTCC5 (1 << 5)
+#define INTCR1_INTCC4 (1 << 4)
+#define INTCR1_INTCC3 (1 << 3)
+#define INTCR1_INTCC2 (1 << 2)
+#define INTCR1_INTCC1 (1 << 1)
+#define INTCR1_INTCC0 (1 << 0)
+/* Interrupt Mask Register 1 from ISP CPU to Host IC */
+#define INTMR1 (MCUCTL+0x24)
+#define INTMR1_INTMC9 (1 << 9)
+#define INTMR1_INTMC8 (1 << 8)
+#define INTMR1_INTMC7 (1 << 7)
+#define INTMR1_INTMC6 (1 << 6)
+#define INTMR1_INTMC5 (1 << 5)
+#define INTMR1_INTMC4 (1 << 4)
+#define INTMR1_INTMC3 (1 << 3)
+#define INTMR1_INTMC2 (1 << 2)
+#define INTMR1_INTMC1 (1 << 1)
+#define INTMR1_INTMC0 (1 << 0)
+/* Interrupt Status Register 1 from ISP CPU to Host IC */
+#define INTSR1 (MCUCTL+0x28)
+/* Interrupt Mask Status Register 1 from ISP CPU to Host IC */
+#define INTMSR1 (MCUCTL+0x2c)
+/* Interrupt Clear Register 2 from ISP BLK's interrupts to Host IC */
+#define INTCR2 (MCUCTL+0x30)
+#define INTCR2_INTCC21 (1 << 21)
+#define INTCR2_INTCC20 (1 << 20)
+#define INTCR2_INTCC19 (1 << 19)
+#define INTCR2_INTCC18 (1 << 18)
+#define INTCR2_INTCC17 (1 << 17)
+#define INTCR2_INTCC16 (1 << 16)
+/* Interrupt Mask Register 2 from ISP BLK's interrupts to Host IC */
+#define INTMR2 (MCUCTL+0x34)
+#define INTMR2_INTMCIS25 (1 << 25)
+#define INTMR2_INTMCIS24 (1 << 24)
+#define INTMR2_INTMCIS23 (1 << 23)
+#define INTMR2_INTMCIS22 (1 << 22)
+#define INTMR2_INTMCIS21 (1 << 21)
+#define INTMR2_INTMCIS20 (1 << 20)
+#define INTMR2_INTMCIS19 (1 << 19)
+#define INTMR2_INTMCIS18 (1 << 18)
+#define INTMR2_INTMCIS17 (1 << 17)
+#define INTMR2_INTMCIS16 (1 << 16)
+#define INTMR2_INTMCIS15 (1 << 15)
+#define INTMR2_INTMCIS14 (1 << 14)
+#define INTMR2_INTMCIS13 (1 << 13)
+#define INTMR2_INTMCIS12 (1 << 12)
+#define INTMR2_INTMCIS11 (1 << 11)
+#define INTMR2_INTMCIS10 (1 << 10)
+#define INTMR2_INTMCIS9 (1 << 9)
+#define INTMR2_INTMCIS8 (1 << 8)
+#define INTMR2_INTMCIS7 (1 << 7)
+#define INTMR2_INTMCIS6 (1 << 6)
+#define INTMR2_INTMCIS5 (1 << 5)
+#define INTMR2_INTMCIS4 (1 << 4)
+#define INTMR2_INTMCIS3 (1 << 3)
+#define INTMR2_INTMCIS2 (1 << 2)
+#define INTMR2_INTMCIS1 (1 << 1)
+#define INTMR2_INTMCIS0 (1 << 0)
+/* Interrupt Status Register 2 from ISP BLK's interrupts to Host IC */
+#define INTSR2 (MCUCTL+0x38)
+/* Interrupt Mask Status Register 2 from ISP BLK's interrupts to Host IC */
+#define INTMSR2 (MCUCTL+0x3c)
+/* General Purpose Output Control Register (0~17) */
+#define GPOCTLR (MCUCTL+0x40)
+#define GPOCTLR_GPOG17(x) ((x) << 17)
+#define GPOCTLR_GPOG16(x) ((x) << 16)
+#define GPOCTLR_GPOG15(x) ((x) << 15)
+#define GPOCTLR_GPOG14(x) ((x) << 14)
+#define GPOCTLR_GPOG13(x) ((x) << 13)
+#define GPOCTLR_GPOG12(x) ((x) << 12)
+#define GPOCTLR_GPOG11(x) ((x) << 11)
+#define GPOCTLR_GPOG10(x) ((x) << 10)
+#define GPOCTLR_GPOG9(x) ((x) << 9)
+#define GPOCTLR_GPOG8(x) ((x) << 8)
+#define GPOCTLR_GPOG7(x) ((x) << 7)
+#define GPOCTLR_GPOG6(x) ((x) << 6)
+#define GPOCTLR_GPOG5(x) ((x) << 5)
+#define GPOCTLR_GPOG4(x) ((x) << 4)
+#define GPOCTLR_GPOG3(x) ((x) << 3)
+#define GPOCTLR_GPOG2(x) ((x) << 2)
+#define GPOCTLR_GPOG1(x) ((x) << 1)
+#define GPOCTLR_GPOG0(x) ((x) << 0)
+/* General Purpose Pad Output Enable Register (0~17) */
+#define GPOENCTLR (MCUCTL+0x44)
+#define GPOENCTLR_GPOEN17(x) ((x) << 17)
+#define GPOENCTLR_GPOEN16(x) ((x) << 16)
+#define GPOENCTLR_GPOEN15(x) ((x) << 15)
+#define GPOENCTLR_GPOEN14(x) ((x) << 14)
+#define GPOENCTLR_GPOEN13(x) ((x) << 13)
+#define GPOENCTLR_GPOEN12(x) ((x) << 12)
+#define GPOENCTLR_GPOEN11(x) ((x) << 11)
+#define GPOENCTLR_GPOEN10(x) ((x) << 10)
+#define GPOENCTLR_GPOEN9(x) ((x) << 9)
+#define GPOENCTLR_GPOEN8(x) ((x) << 8)
+#define GPOENCTLR_GPOEN7(x) ((x) << 7)
+#define GPOENCTLR_GPOEN6(x) ((x) << 6)
+#define GPOENCTLR_GPOEN5(x) ((x) << 5)
+#define GPOENCTLR_GPOEN4(x) ((x) << 4)
+#define GPOENCTLR_GPOEN3(x) ((x) << 3)
+#define GPOENCTLR_GPOEN2(x) ((x) << 2)
+#define GPOENCTLR_GPOEN1(x) ((x) << 1)
+#define GPOENCTLR_GPOEN0(x) ((x) << 0)
+/* General Purpose Input Control Register (0~17) */
+#define GPICTLR (MCUCTL+0x48)
+/* IS Shared Register 0 between ISP CPU and HOST CPU */
+#define ISSR0 (MCUCTL+0x80)
+/* Command Host -> IS */
+/* IS Shared Register 1 between ISP CPU and HOST CPU */
+/* Sensor ID for Command */
+#define ISSR1 (MCUCTL+0x84)
+/* IS Shared Register 2 between ISP CPU and HOST CPU */
+/* Parameter 1 */
+#define ISSR2 (MCUCTL+0x88)
+/* IS Shared Register 3 between ISP CPU and HOST CPU */
+/* Parameter 2 */
+#define ISSR3 (MCUCTL+0x8c)
+/* IS Shared Register 4 between ISP CPU and HOST CPU */
+/* Parameter 3 */
+#define ISSR4 (MCUCTL+0x90)
+/* IS Shared Register 5 between ISP CPU and HOST CPU */
+/* Parameter 4 */
+#define ISSR5 (MCUCTL+0x94)
+#define ISSR6 (MCUCTL+0x98)
+#define ISSR7 (MCUCTL+0x9c)
+#define ISSR8 (MCUCTL+0xa0)
+#define ISSR9 (MCUCTL+0xa4)
+/* IS Shared Register 10 between ISP CPU and HOST CPU */
+/* Command IS -> Host */
+#define ISSR10 (MCUCTL+0xa8)
+/* IS Shared Register 11 between ISP CPU and HOST CPU */
+/* Sensor ID for Command */
+#define ISSR11 (MCUCTL+0xac)
+/* IS Shared Register 12 between ISP CPU and HOST CPU */
+/* Parameter 1 */
+#define ISSR12 (MCUCTL+0xb0)
+/* IS Shared Register 13 between ISP CPU and HOST CPU */
+/* Parameter 2 */
+#define ISSR13 (MCUCTL+0xb4)
+/* IS Shared Register 14 between ISP CPU and HOST CPU */
+/* Parameter 3 */
+#define ISSR14 (MCUCTL+0xb8)
+/* IS Shared Register 15 between ISP CPU and HOST CPU */
+/* Parameter 4 */
+#define ISSR15 (MCUCTL+0xbc)
+#define ISSR16 (MCUCTL+0xc0)
+#define ISSR17 (MCUCTL+0xc4)
+#define ISSR18 (MCUCTL+0xc8)
+#define ISSR19 (MCUCTL+0xcc)
+/* IS Shared Register 20 between ISP CPU and HOST CPU */
+/* ISP_FRAME_DONE : SENSOR ID */
+#define ISSR20 (MCUCTL+0xd0)
+/* IS Shared Register 21 between ISP CPU and HOST CPU */
+/* ISP_FRAME_DONE : PARAMETER 1 */
+#define ISSR21 (MCUCTL+0xd4)
+#define ISSR22 (MCUCTL+0xd8)
+#define ISSR23 (MCUCTL+0xdc)
+/* IS Shared Register 24 between ISP CPU and HOST CPU */
+/* SCALERC_FRAME_DONE : SENSOR ID */
+#define ISSR24 (MCUCTL+0xe0)
+/* IS Shared Register 25 between ISP CPU and HOST CPU */
+/* SCALERC_FRAME_DONE : PARAMETER 1 */
+#define ISSR25 (MCUCTL+0xe4)
+#define ISSR26 (MCUCTL+0xe8)
+#define ISSR27 (MCUCTL+0xec)
+/* IS Shared Register 28 between ISP CPU and HOST CPU */
+/* 3DNR_FRAME_DONE : SENSOR ID */
+#define ISSR28 (MCUCTL+0xf0)
+/* IS Shared Register 29 between ISP CPU and HOST CPU */
+/* 3DNR_FRAME_DONE : PARAMETER 1 */
+#define ISSR29 (MCUCTL+0xf4)
+#define ISSR30 (MCUCTL+0xf8)
+#define ISSR31 (MCUCTL+0xfc)
+/* IS Shared Register 32 between ISP CPU and HOST CPU */
+/* SCALERP_FRAME_DONE : SENSOR ID */
+#define ISSR32 (MCUCTL+0x100)
+/* IS Shared Register 33 between ISP CPU and HOST CPU */
+/* SCALERP_FRAME_DONE : PARAMETER 1 */
+#define ISSR33 (MCUCTL+0x104)
+#define ISSR34 (MCUCTL+0x108)
+#define ISSR35 (MCUCTL+0x10c)
+#define ISSR36 (MCUCTL+0x110)
+#define ISSR37 (MCUCTL+0x114)
+#define ISSR38 (MCUCTL+0x118)
+#define ISSR39 (MCUCTL+0x11c)
+#define ISSR40 (MCUCTL+0x120)
+#define ISSR41 (MCUCTL+0x124)
+#define ISSR42 (MCUCTL+0x128)
+#define ISSR43 (MCUCTL+0x12c)
+#define ISSR44 (MCUCTL+0x130)
+#define ISSR45 (MCUCTL+0x134)
+#define ISSR46 (MCUCTL+0x138)
+#define ISSR47 (MCUCTL+0x13c)
+#define ISSR48 (MCUCTL+0x140)
+#define ISSR49 (MCUCTL+0x144)
+#define ISSR50 (MCUCTL+0x148)
+#define ISSR51 (MCUCTL+0x14c)
+#define ISSR52 (MCUCTL+0x150)
+#define ISSR53 (MCUCTL+0x154)
+#define ISSR54 (MCUCTL+0x158)
+#define ISSR55 (MCUCTL+0x15c)
+#define ISSR56 (MCUCTL+0x160)
+#define ISSR57 (MCUCTL+0x164)
+#define ISSR58 (MCUCTL+0x168)
+#define ISSR59 (MCUCTL+0x16c)
+#define ISSR60 (MCUCTL+0x170)
+#define ISSR61 (MCUCTL+0x174)
+#define ISSR62 (MCUCTL+0x178)
+#define ISSR63 (MCUCTL+0x17c)
+
+/* PMU for FIMC-IS*/
+#define PMUREG_CMU_RESET_ISP_SYS_PWR_REG (S5P_VA_PMU + 0x1584)
+#define PMUREG_ISP_ARM_CONFIGURATION (S5P_VA_PMU + 0x2280)
+#define PMUREG_ISP_ARM_STATUS (S5P_VA_PMU + 0x2284)
+#define PMUREG_ISP_ARM_OPTION (S5P_VA_PMU + 0x2288)
+#define PMUREG_ISP_LOW_POWER_OFF (S5P_VA_PMU + 0x0004)
+#define PMUREG_ISP_CONFIGURATION (S5P_VA_PMU + 0x4020)
+#define PMUREG_ISP_STATUS (S5P_VA_PMU + 0x4024)
+
+#endif
diff --git a/drivers/media/video/exynos/fimc-is-mc/fimc-is-vb2.c b/drivers/media/video/exynos/fimc-is-mc/fimc-is-vb2.c
new file mode 100644
index 0000000..25e936c
--- /dev/null
+++ b/drivers/media/video/exynos/fimc-is-mc/fimc-is-vb2.c
@@ -0,0 +1,80 @@
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ * exynos5 fimc-is misc functions(mipi, fimc-lite control)
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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.
+ */
+
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+#include <linux/io.h>
+#include <media/videobuf2-core.h>
+#include <linux/platform_device.h>
+#include "fimc-is-core.h"
+
+#if defined(CONFIG_VIDEOBUF2_CMA_PHYS)
+void *fimc_is_cma_init(struct fimc_is_dev *isp)
+{
+ return vb2_cma_phys_init(&isp->pdev->dev, NULL, 0, false);
+}
+
+int fimc_is_cma_resume(void *alloc_ctx)
+{
+ return 1;
+}
+void fimc_is_cma_suspend(void *alloc_ctx) {}
+void fimc_is_cma_set_cacheable(void *alloc_ctx, bool cacheable) {}
+
+int fimc_is_cma_cache_flush(struct vb2_buffer *vb, u32 plane_no)
+{
+ return 0;
+}
+
+const struct fimc_is_vb2 fimc_is_vb2_cma = {
+ .ops = &vb2_cma_phys_memops,
+ .init = fimc_is_cma_init,
+ .cleanup = vb2_cma_phys_cleanup,
+ .plane_addr = vb2_cma_phys_plane_paddr,
+ .resume = fimc_is_cma_resume,
+ .suspend = fimc_is_cma_suspend,
+ .cache_flush = fimc_is_cma_cache_flush,
+ .set_cacheable = fimc_is_cma_set_cacheable,
+};
+#elif defined(CONFIG_VIDEOBUF2_ION)
+
+static void *fimc_is_ion_init(struct fimc_is_dev *isp)
+{
+ return vb2_ion_create_context(&isp->pdev->dev, SZ_4K,
+ VB2ION_CTX_IOMMU | VB2ION_CTX_VMCONTIG);
+}
+
+static unsigned long plane_addr(struct vb2_buffer *vb, u32 plane_no)
+{
+ void *cookie = vb2_plane_cookie(vb, plane_no);
+ dma_addr_t dva = 0;
+
+ WARN_ON(vb2_ion_dma_address(cookie, &dva) != 0);
+
+ return dva;
+}
+
+const struct fimc_is_vb2 fimc_is_vb2_ion = {
+ .ops = &vb2_ion_memops,
+ .init = fimc_is_ion_init,
+ .cleanup = vb2_ion_destroy_context,
+ .plane_addr = plane_addr,
+ .resume = vb2_ion_attach_iommu,
+ .suspend = vb2_ion_detach_iommu,
+ .cache_flush = vb2_ion_cache_flush,
+ .set_cacheable = vb2_ion_set_cached,
+};
+#endif
+
diff --git a/drivers/media/video/exynos/fimc-is-mc/fimc-is-video.c b/drivers/media/video/exynos/fimc-is-mc/fimc-is-video.c
new file mode 100644
index 0000000..adfb9fa
--- /dev/null
+++ b/drivers/media/video/exynos/fimc-is-mc/fimc-is-video.c
@@ -0,0 +1,3424 @@
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ * exynos5 fimc-is video functions
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <mach/videonode.h>
+#if defined(CONFIG_BUSFREQ_OPP) && defined(CONFIG_CPU_EXYNOS5250)
+#include <mach/dev.h>
+#endif
+#include <plat/bts.h>
+#include <media/exynos_mc.h>
+#include <linux/cma.h>
+#include <asm/cacheflush.h>
+#include <asm/pgtable.h>
+#include <linux/firmware.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/scatterlist.h>
+#include <linux/videodev2_exynos_media.h>
+#include <linux/videodev2_exynos_camera.h>
+#include <linux/v4l2-mediabus.h>
+
+#include "fimc-is-core.h"
+#include "fimc-is-helper.h"
+#include "fimc-is-param.h"
+#include "fimc-is-cmd.h"
+#include "fimc-is-regs.h"
+#include "fimc-is-err.h"
+#include "fimc-is-misc.h"
+
+static struct fimc_is_fmt fimc_is_formats[] = {
+ {
+ .name = "YUV 4:2:2 packed, YCbYCr",
+ .pixelformat = V4L2_PIX_FMT_YUYV,
+ .num_planes = 1,
+ .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8,
+ }, {
+ .name = "YUV 4:2:2 packed, CbYCrY",
+ .pixelformat = V4L2_PIX_FMT_UYVY,
+ .num_planes = 1,
+ .mbus_code = V4L2_MBUS_FMT_UYVY8_2X8,
+ }, {
+ .name = "YUV 4:2:2 planar, Y/Cb/Cr",
+ .pixelformat = V4L2_PIX_FMT_YUV422P,
+ .num_planes = 1,
+ }, {
+ .name = "YUV 4:2:0 planar, YCbCr",
+ .pixelformat = V4L2_PIX_FMT_YUV420,
+ .num_planes = 1,
+ }, {
+ .name = "YUV 4:2:0 planar, YCbCr",
+ .pixelformat = V4L2_PIX_FMT_YVU420,
+ .num_planes = 1,
+ }, {
+ .name = "YUV 4:2:0 planar, Y/CbCr",
+ .pixelformat = V4L2_PIX_FMT_NV12,
+ .num_planes = 1,
+ }, {
+ .name = "YUV 4:2:0 planar, Y/CrCb",
+ .pixelformat = V4L2_PIX_FMT_NV21,
+ .num_planes = 1,
+ }, {
+ .name = "YUV 4:2:0 non-contiguous 2-planar, Y/CbCr",
+ .pixelformat = V4L2_PIX_FMT_NV12M,
+ .num_planes = 2,
+ }, {
+ .name = "YVU 4:2:0 non-contiguous 2-planar, Y/CrCb",
+ .pixelformat = V4L2_PIX_FMT_NV21M,
+ .num_planes = 2,
+ }, {
+ .name = "YUV 4:2:0 non-contiguous 3-planar, Y/Cb/Cr",
+ .pixelformat = V4L2_PIX_FMT_YUV420M,
+ .num_planes = 3,
+ }, {
+ .name = "YUV 4:2:0 non-contiguous 3-planar, Y/Cr/Cb",
+ .pixelformat = V4L2_PIX_FMT_YVU420M,
+ .num_planes = 3,
+ }, {
+ .name = "BAYER 10 bit",
+ .pixelformat = V4L2_PIX_FMT_SBGGR10,
+ .num_planes = 1,
+ }, {
+ .name = "BAYER 12 bit",
+ .pixelformat = V4L2_PIX_FMT_SBGGR12,
+ .num_planes = 1,
+ },
+};
+
+
+static struct fimc_is_fmt *find_format(u32 *pixelformat,
+ u32 *mbus_code,
+ int index)
+{
+ struct fimc_is_fmt *fmt, *def_fmt = NULL;
+ unsigned int i;
+
+ if (index >= ARRAY_SIZE(fimc_is_formats))
+ return NULL;
+
+ for (i = 0; i < ARRAY_SIZE(fimc_is_formats); ++i) {
+ fmt = &fimc_is_formats[i];
+ if (pixelformat && fmt->pixelformat == *pixelformat)
+ return fmt;
+ if (mbus_code && fmt->mbus_code == *mbus_code)
+ return fmt;
+ if (index == i)
+ def_fmt = fmt;
+ }
+ return def_fmt;
+
+}
+
+static void set_plane_size(struct fimc_is_frame *frame, unsigned int sizes[])
+{
+ dbg(" ");
+ switch (frame->format.pixelformat) {
+ case V4L2_PIX_FMT_YUYV:
+ dbg("V4L2_PIX_FMT_YUYV(w:%d)(h:%d)\n",
+ frame->width, frame->height);
+ sizes[0] = frame->width*frame->height*2;
+ break;
+ case V4L2_PIX_FMT_NV12M:
+ dbg("V4L2_PIX_FMT_NV12M(w:%d)(h:%d)\n",
+ frame->width, frame->height);
+ sizes[0] = frame->width*frame->height;
+ sizes[1] = frame->width*frame->height/2;
+ break;
+ case V4L2_PIX_FMT_YVU420M:
+ dbg("V4L2_PIX_FMT_YVU420M(w:%d)(h:%d)\n",
+ frame->width, frame->height);
+ sizes[0] = frame->width*frame->height;
+ sizes[1] = frame->width*frame->height/4;
+ sizes[2] = frame->width*frame->height/4;
+ break;
+ case V4L2_PIX_FMT_SBGGR10:
+ dbg("V4L2_PIX_FMT_SBGGR10(w:%d)(h:%d)\n",
+ frame->width, frame->height);
+ sizes[0] = frame->width*frame->height*2;
+ break;
+ case V4L2_PIX_FMT_SBGGR12:
+ dbg("V4L2_PIX_FMT_SBGGR12(w:%d)(h:%d)\n",
+ frame->width, frame->height);
+ sizes[0] = frame->width*frame->height*2;
+ break;
+ }
+}
+
+/*************************************************************************/
+/* video file opertation */
+/************************************************************************/
+
+static int fimc_is_scalerc_video_open(struct file *file)
+{
+ struct fimc_is_dev *isp = video_drvdata(file);
+
+#if defined(CONFIG_BUSFREQ_OPP) && defined(CONFIG_CPU_EXYNOS5250)
+ mutex_lock(&isp->busfreq_lock);
+ isp->busfreq_num++;
+ if (isp->busfreq_num == 1) {
+ dev_lock(isp->bus_dev, &isp->pdev->dev,
+ (FIMC_IS_FREQ_MIF * 1000) + FIMC_IS_FREQ_INT);
+ dbg("busfreq locked on <%d/%d>MHz\n",
+ FIMC_IS_FREQ_MIF, FIMC_IS_FREQ_INT);
+ }
+ mutex_unlock(&isp->busfreq_lock);
+#endif
+
+ dbg("%s\n", __func__);
+ file->private_data = &isp->video[FIMC_IS_VIDEO_NUM_SCALERC];
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERC].num_buf = 0;
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERC].buf_ref_cnt = 0;
+
+ if (!test_bit(FIMC_IS_STATE_FW_DOWNLOADED, &isp->pipe_state)) {
+ isp->sensor_num = 1;
+ dbg("++++ IS load fw (Scaler C open)\n");
+ mutex_unlock(&isp->lock);
+ fimc_is_load_fw(isp);
+
+ set_bit(FIMC_IS_STATE_FW_DOWNLOADED, &isp->pipe_state);
+ clear_bit(FIMC_IS_STATE_SENSOR_INITIALIZED, &isp->pipe_state);
+ clear_bit(FIMC_IS_STATE_HW_STREAM_ON, &isp->pipe_state);
+ dbg("---- IS load fw (Scaler C open)\n");
+ } else {
+ mutex_unlock(&isp->lock);
+ }
+
+ clear_bit(FIMC_IS_STATE_SCALERC_STREAM_ON, &isp->pipe_state);
+ return 0;
+
+}
+
+static int fimc_is_scalerc_video_close(struct file *file)
+{
+ struct fimc_is_dev *isp = video_drvdata(file);
+ int ret;
+
+ dbg("%s\n", __func__);
+ vb2_queue_release(&isp->video[FIMC_IS_VIDEO_NUM_SCALERC].vbq);
+
+ mutex_lock(&isp->lock);
+ if (!test_bit(FIMC_IS_STATE_SCALERP_STREAM_ON, &isp->pipe_state) &&
+ !test_bit(FIMC_IS_STATE_SCALERC_STREAM_ON, &isp->pipe_state) &&
+ !test_bit(FIMC_IS_STATE_3DNR_STREAM_ON, &isp->pipe_state) &&
+ test_bit(FIMC_IS_STATE_FW_DOWNLOADED, &isp->pipe_state)) {
+
+ dbg("++++ IS local power off (Scaler C close)\n");
+ mutex_unlock(&isp->lock);
+ clear_bit(FIMC_IS_STATE_HW_STREAM_ON, &isp->pipe_state);
+ fimc_is_hw_subip_poweroff(isp);
+ ret = wait_event_timeout(isp->irq_queue,
+ !test_bit(FIMC_IS_PWR_ST_POWER_ON_OFF, &isp->power),
+ FIMC_IS_SHUTDOWN_TIMEOUT_SENSOR);
+ if (!ret) {
+ err("wait timeout FIMC_IS_PWR_ST_POWER_ON_OFF\n");
+ fimc_is_hw_set_low_poweroff(isp, true);
+ clear_bit(FIMC_IS_PWR_ST_POWER_ON_OFF, &isp->power);
+ ret = 0;
+ }
+
+ dbg("stop flite & mipi (pos:%d) (port:%d)\n",
+ isp->sensor.id_position,
+ isp->pdata->
+ sensor_info[isp->sensor.id_position]->flite_id);
+ stop_fimc_lite(isp->pdata->
+ sensor_info[isp->sensor.id_position]->flite_id);
+ stop_mipi_csi(isp->pdata->
+ sensor_info[isp->sensor.id_position]->csi_id);
+
+ fimc_is_hw_a5_power(isp, 0);
+ clear_bit(FIMC_IS_STATE_FW_DOWNLOADED, &isp->pipe_state);
+ dbg("---- IS local power off (Scaler C close)\n");
+ } else {
+ mutex_unlock(&isp->lock);
+ }
+
+#if defined(CONFIG_BUSFREQ_OPP) && defined(CONFIG_CPU_EXYNOS5250)
+ mutex_lock(&isp->busfreq_lock);
+ if (isp->busfreq_num == 1) {
+ dev_unlock(isp->bus_dev, &isp->pdev->dev);
+ printk(KERN_DEBUG "busfreq locked off\n");
+ }
+ isp->busfreq_num--;
+ if (isp->busfreq_num < 0)
+ isp->busfreq_num = 0;
+ mutex_unlock(&isp->busfreq_lock);
+#endif
+
+ return 0;
+}
+
+static unsigned int fimc_is_scalerc_video_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct fimc_is_dev *isp = video_drvdata(file);
+
+ dbg("%s\n", __func__);
+ return vb2_poll(&isp->video[FIMC_IS_VIDEO_NUM_SCALERC].vbq, file, wait);
+
+}
+
+static int fimc_is_scalerc_video_mmap(struct file *file,
+ struct vm_area_struct *vma)
+{
+ struct fimc_is_dev *isp = video_drvdata(file);
+
+ dbg("%s\n", __func__);
+ return vb2_mmap(&isp->video[FIMC_IS_VIDEO_NUM_SCALERC].vbq, vma);
+
+}
+
+/*************************************************************************/
+/* video ioctl operation */
+/************************************************************************/
+
+static int fimc_is_scalerc_video_querycap(struct file *file, void *fh,
+ struct v4l2_capability *cap)
+{
+ struct fimc_is_dev *isp = video_drvdata(file);
+
+ strncpy(cap->driver, isp->pdev->name, sizeof(cap->driver) - 1);
+
+ dbg("(devname : %s)\n", cap->driver);
+ strncpy(cap->card, isp->pdev->name, sizeof(cap->card) - 1);
+ cap->bus_info[0] = 0;
+ cap->version = KERNEL_VERSION(1, 0, 0);
+ cap->capabilities = V4L2_CAP_STREAMING
+ | V4L2_CAP_VIDEO_CAPTURE
+ | V4L2_CAP_VIDEO_CAPTURE_MPLANE;
+
+ return 0;
+}
+
+static int fimc_is_scalerc_video_enum_fmt_mplane(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_scalerc_video_get_format_mplane(struct file *file, void *fh,
+ struct v4l2_format *format)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_scalerc_video_set_format_mplane(struct file *file, void *fh,
+ struct v4l2_format *format)
+{
+ struct fimc_is_dev *isp = video_drvdata(file);
+ struct v4l2_pix_format_mplane *pix;
+ struct fimc_is_fmt *frame;
+
+ dbg("%s\n", __func__);
+
+ pix = &format->fmt.pix_mp;
+ frame = find_format(&pix->pixelformat, NULL, 0);
+
+ if (!frame)
+ return -EINVAL;
+
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERC].frame.format.pixelformat
+ = frame->pixelformat;
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERC].frame.format.mbus_code
+ = frame->mbus_code;
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERC].frame.format.num_planes
+ = frame->num_planes;
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERC].frame.width = pix->width;
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERC].frame.height = pix->height;
+ dbg("num_planes : %d\n", frame->num_planes);
+ dbg("width : %d\n", pix->width);
+ dbg("height : %d\n", pix->height);
+
+ return 0;
+}
+
+static int fimc_is_scalerc_video_try_format_mplane(struct file *file, void *fh,
+ struct v4l2_format *format)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_scalerc_video_cropcap(struct file *file, void *fh,
+ struct v4l2_cropcap *cropcap)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_scalerc_video_get_crop(struct file *file, void *fh,
+ struct v4l2_crop *crop)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_scalerc_video_set_crop(struct file *file, void *fh,
+ struct v4l2_crop *crop)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_scalerc_video_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *buf)
+{
+ int ret;
+ struct fimc_is_video_dev *video = file->private_data;
+ struct fimc_is_dev *isp = video_drvdata(file);
+
+ dbg("(buf->count : %d)\n", buf->count);
+
+ ret = vb2_reqbufs(&video->vbq, buf);
+ if (!ret)
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERC].num_buf = buf->count;
+
+ if (buf->count == 0)
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERC].buf_ref_cnt = 0;
+ dbg("(num_buf : %d)\n",
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERC].num_buf);
+
+ return ret;
+}
+
+static int fimc_is_scalerc_video_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ int ret;
+ struct fimc_is_video_dev *video = file->private_data;
+
+ dbg("%s\n", __func__);
+ ret = vb2_querybuf(&video->vbq, buf);
+
+ return ret;
+}
+
+static int fimc_is_scalerc_video_qbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ int vb_ret;
+ struct fimc_is_video_dev *video = file->private_data;
+ struct fimc_is_dev *isp = video_drvdata(file);
+
+ if (test_bit(FIMC_IS_STATE_SCALERC_BUFFER_PREPARED, &isp->pipe_state)) {
+ video->buf_mask |= (1<<buf->index);
+ IS_INC_PARAM_NUM(isp);
+
+ dbg("index(%d) mask(0x%08x)\n", buf->index, video->buf_mask);
+ } else
+ dbg("index(%d)\n", buf->index);
+
+ vb_ret = vb2_qbuf(&video->vbq, buf);
+
+ return vb_ret;
+}
+
+static int fimc_is_scalerc_video_dqbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ int vb_ret;
+ struct fimc_is_video_dev *video = file->private_data;
+ struct fimc_is_dev *isp = video_drvdata(file);
+
+ vb_ret = vb2_dqbuf(&video->vbq, buf, file->f_flags & O_NONBLOCK);
+
+ video->buf_mask &= ~(1<<buf->index);
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERC].buf_mask = video->buf_mask;
+
+ dbg("index(%d) mask(0x%08x)\n", buf->index, video->buf_mask);
+
+ return vb_ret;
+}
+
+static int fimc_is_scalerc_video_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct fimc_is_dev *isp = video_drvdata(file);
+
+ dbg("%s\n", __func__);
+ return vb2_streamon(&isp->video[FIMC_IS_VIDEO_NUM_SCALERC].vbq, type);
+}
+
+static int fimc_is_scalerc_video_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct fimc_is_dev *isp = video_drvdata(file);
+
+ dbg("%s\n", __func__);
+ return vb2_streamoff(&isp->video[FIMC_IS_VIDEO_NUM_SCALERC].vbq, type);
+}
+
+static int fimc_is_scalerc_video_enum_input(struct file *file, void *priv,
+ struct v4l2_input *input)
+{
+ struct fimc_is_dev *isp = video_drvdata(file);
+ struct exynos5_fimc_is_sensor_info *sensor_info
+ = isp->pdata->sensor_info[input->index];
+
+ dbg("index(%d) sensor(%s)\n",
+ input->index, sensor_info->sensor_name);
+ dbg("pos(%d) sensor_id(%d)\n",
+ sensor_info->sensor_position, sensor_info->sensor_id);
+ dbg("csi_id(%d) flite_id(%d)\n",
+ sensor_info->csi_id, sensor_info->flite_id);
+ dbg("i2c_ch(%d)\n", sensor_info->i2c_channel);
+
+ if (input->index >= FIMC_IS_MAX_CAMIF_CLIENTS)
+ return -EINVAL;
+
+ input->type = V4L2_INPUT_TYPE_CAMERA;
+
+ strncpy(input->name, sensor_info->sensor_name,
+ FIMC_IS_MAX_NAME_LEN);
+ return 0;
+}
+
+static int fimc_is_scalerc_video_g_input(struct file *file, void *priv,
+ unsigned int *input)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_scalerc_video_s_input(struct file *file, void *priv,
+ unsigned int input)
+{
+ struct fimc_is_dev *isp = video_drvdata(file);
+ struct exynos5_fimc_is_sensor_info *sensor_info
+ = isp->pdata->sensor_info[input];
+
+ isp->sensor.id_position = input;
+ isp->sensor.sensor_type
+ = fimc_is_hw_get_sensor_type(sensor_info->sensor_id,
+ sensor_info->flite_id);
+
+ fimc_is_hw_set_default_size(isp, sensor_info->sensor_id);
+
+ dbg("sensor info : pos(%d) type(%d)\n", input, isp->sensor.sensor_type);
+
+
+ return 0;
+}
+
+const struct v4l2_file_operations fimc_is_scalerc_video_fops = {
+ .owner = THIS_MODULE,
+ .open = fimc_is_scalerc_video_open,
+ .release = fimc_is_scalerc_video_close,
+ .poll = fimc_is_scalerc_video_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = fimc_is_scalerc_video_mmap,
+};
+
+const struct v4l2_ioctl_ops fimc_is_scalerc_video_ioctl_ops = {
+ .vidioc_querycap = fimc_is_scalerc_video_querycap,
+ .vidioc_enum_fmt_vid_cap_mplane
+ = fimc_is_scalerc_video_enum_fmt_mplane,
+ .vidioc_g_fmt_vid_cap_mplane
+ = fimc_is_scalerc_video_get_format_mplane,
+ .vidioc_s_fmt_vid_cap_mplane
+ = fimc_is_scalerc_video_set_format_mplane,
+ .vidioc_try_fmt_vid_cap_mplane
+ = fimc_is_scalerc_video_try_format_mplane,
+ .vidioc_cropcap = fimc_is_scalerc_video_cropcap,
+ .vidioc_g_crop = fimc_is_scalerc_video_get_crop,
+ .vidioc_s_crop = fimc_is_scalerc_video_set_crop,
+ .vidioc_reqbufs = fimc_is_scalerc_video_reqbufs,
+ .vidioc_querybuf = fimc_is_scalerc_video_querybuf,
+ .vidioc_qbuf = fimc_is_scalerc_video_qbuf,
+ .vidioc_dqbuf = fimc_is_scalerc_video_dqbuf,
+ .vidioc_streamon = fimc_is_scalerc_video_streamon,
+ .vidioc_streamoff = fimc_is_scalerc_video_streamoff,
+ .vidioc_enum_input = fimc_is_scalerc_video_enum_input,
+ .vidioc_g_input = fimc_is_scalerc_video_g_input,
+ .vidioc_s_input = fimc_is_scalerc_video_s_input,
+};
+
+static int fimc_is_scalerc_queue_setup(struct vb2_queue *vq,
+ const struct v4l2_format *fmt,
+ unsigned int *num_buffers,
+ unsigned int *num_planes, unsigned int sizes[],
+ void *allocators[])
+{
+
+ struct fimc_is_video_dev *video = vq->drv_priv;
+ struct fimc_is_dev *isp = video->dev;
+ int i;
+
+
+ *num_planes = isp->video[FIMC_IS_VIDEO_NUM_SCALERC].
+ frame.format.num_planes;
+ set_plane_size(&isp->video[FIMC_IS_VIDEO_NUM_SCALERC].frame, sizes);
+
+ for (i = 0; i < *num_planes; i++)
+ allocators[i] = isp->alloc_ctx;
+
+ dbg("(num_planes : %d)(size : %d)\n", (int)*num_planes, (int)sizes[0]);
+ return 0;
+}
+static int fimc_is_scalerc_buffer_prepare(struct vb2_buffer *vb)
+{
+ dbg("--%s\n", __func__);
+ return 0;
+}
+
+
+static inline void fimc_is_scalerc_lock(struct vb2_queue *vq)
+{
+ dbg("%s\n", __func__);
+}
+
+static inline void fimc_is_scalerc_unlock(struct vb2_queue *vq)
+{
+ dbg("%s\n", __func__);
+}
+
+static int fimc_is_scalerc_start_streaming(struct vb2_queue *q,
+ unsigned int count)
+{
+ struct fimc_is_video_dev *video = q->drv_priv;
+ struct fimc_is_dev *isp = video->dev;
+ int ret;
+ int i, j;
+ int buf_index;
+
+ dbg("(pipe_state : %d)\n", (int)isp->pipe_state);
+
+ if (test_bit(FIMC_IS_STATE_FW_DOWNLOADED, &isp->pipe_state) &&
+ !test_bit(FIMC_IS_STATE_SENSOR_INITIALIZED, &isp->pipe_state)) {
+
+ dbg("IS change mode\n");
+ set_bit(IS_ST_CHANGE_MODE, &isp->state);
+ fimc_is_hw_change_mode(isp, IS_MODE_PREVIEW_STILL);
+ mutex_lock(&isp->lock);
+ ret = wait_event_timeout(isp->irq_queue,
+ test_bit(IS_ST_CHANGE_MODE_DONE,
+ &isp->state),
+ FIMC_IS_SHUTDOWN_TIMEOUT);
+ mutex_unlock(&isp->lock);
+ if (!ret) {
+ dev_err(&isp->pdev->dev,
+ "Mode change timeout:%s\n", __func__);
+ return -EBUSY;
+ }
+
+ set_bit(FIMC_IS_STATE_SENSOR_INITIALIZED, &isp->pipe_state);
+ }
+
+ if (test_bit(FIMC_IS_STATE_SENSOR_INITIALIZED, &isp->pipe_state) &&
+ test_bit(FIMC_IS_STATE_SCALERC_BUFFER_PREPARED,
+ &isp->pipe_state) &&
+ !test_bit(FIMC_IS_STATE_HW_STREAM_ON, &isp->pipe_state)) {
+ dbg("IS Stream On");
+ fimc_is_hw_set_stream(isp, 1);
+ mutex_lock(&isp->lock);
+ ret = wait_event_timeout(isp->irq_queue,
+ test_bit(IS_ST_STREAM_ON, &isp->state),
+ FIMC_IS_SHUTDOWN_TIMEOUT);
+ mutex_unlock(&isp->lock);
+ if (!ret) {
+ dev_err(&isp->pdev->dev,
+ "wait timeout : %s\n", __func__);
+ return -EBUSY;
+ }
+ clear_bit(IS_ST_STREAM_ON, &isp->state);
+
+ set_bit(FIMC_IS_STATE_HW_STREAM_ON, &isp->pipe_state);
+ }
+
+ if (test_bit(FIMC_IS_STATE_SCALERC_BUFFER_PREPARED, &isp->pipe_state) &&
+ test_bit(FIMC_IS_STATE_HW_STREAM_ON, &isp->pipe_state) &&
+ test_bit(FIMC_IS_STATE_SENSOR_INITIALIZED, &isp->pipe_state)) {
+
+ /* buffer addr setting */
+ for (i = 0; i < isp->video[FIMC_IS_VIDEO_NUM_SCALERC].
+ num_buf; i++)
+ for (j = 0; j < isp->video[FIMC_IS_VIDEO_NUM_SCALERC].
+ frame.format.num_planes; j++) {
+ buf_index
+ = i * isp->video[FIMC_IS_VIDEO_NUM_SCALERC].
+ frame.format.num_planes + j;
+
+ dbg("(%d)set buf(%d:%d) = 0x%08x\n",
+ buf_index, i, j,
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERC].
+ buf[i][j]);
+
+ isp->is_p_region->shared[447+buf_index]
+ = isp->video[FIMC_IS_VIDEO_NUM_SCALERC].
+ buf[i][j];
+ }
+
+ dbg("buf_num:%d buf_plane:%d shared[447] : 0x%p\n",
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERC].num_buf,
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERC].
+ frame.format.num_planes,
+ isp->mem.kvaddr_shared + 447 * sizeof(u32));
+
+ for (i = 0; i < isp->video[FIMC_IS_VIDEO_NUM_SCALERC].
+ num_buf; i++)
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERC].buf_mask
+ |= (1 << i);
+
+ dbg("initial buffer mask : 0x%08x\n",
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERC].buf_mask);
+
+ IS_SCALERC_SET_PARAM_DMA_OUTPUT_CMD(isp,
+ DMA_OUTPUT_COMMAND_ENABLE);
+ IS_SCALERC_SET_PARAM_DMA_OUTPUT_MASK(isp,
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERC].buf_mask);
+ IS_SCALERC_SET_PARAM_DMA_OUTPUT_BUFFERNUM(isp,
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERC].num_buf);
+ IS_SCALERC_SET_PARAM_DMA_OUTPUT_BUFFERADDR(isp,
+ (u32)isp->mem.dvaddr_shared + 447*sizeof(u32));
+
+ IS_SET_PARAM_BIT(isp, PARAM_SCALERC_DMA_OUTPUT);
+ IS_INC_PARAM_NUM(isp);
+
+ fimc_is_mem_cache_clean((void *)isp->is_p_region,
+ IS_PARAM_SIZE);
+
+ isp->scenario_id = ISS_PREVIEW_STILL;
+ set_bit(IS_ST_INIT_PREVIEW_STILL, &isp->state);
+ clear_bit(IS_ST_INIT_CAPTURE_STILL, &isp->state);
+ clear_bit(IS_ST_INIT_PREVIEW_VIDEO, &isp->state);
+ fimc_is_hw_set_param(isp);
+ mutex_lock(&isp->lock);
+ ret = wait_event_timeout(isp->irq_queue,
+ test_bit(IS_ST_INIT_PREVIEW_VIDEO, &isp->state),
+ FIMC_IS_SHUTDOWN_TIMEOUT);
+ mutex_unlock(&isp->lock);
+ if (!ret) {
+ dev_err(&isp->pdev->dev,
+ "wait timeout : %s\n", __func__);
+ return -EBUSY;
+ }
+
+ set_bit(FIMC_IS_STATE_SCALERC_STREAM_ON, &isp->pipe_state);
+ }
+ return 0;
+}
+
+static int fimc_is_scalerc_stop_streaming(struct vb2_queue *q)
+{
+ struct fimc_is_video_dev *video = q->drv_priv;
+ struct fimc_is_dev *isp = video->dev;
+ int ret;
+
+ clear_bit(IS_ST_STREAM_OFF, &isp->state);
+ fimc_is_hw_set_stream(isp, 0);
+ mutex_lock(&isp->lock);
+ ret = wait_event_timeout(isp->irq_queue,
+ test_bit(IS_ST_STREAM_OFF, &isp->state),
+ FIMC_IS_SHUTDOWN_TIMEOUT);
+ mutex_unlock(&isp->lock);
+ if (!ret) {
+ dev_err(&isp->pdev->dev,
+ "wait timeout : %s\n", __func__);
+ if (!ret)
+ err("s_power off failed!!\n");
+ return -EBUSY;
+ }
+
+ IS_SCALERC_SET_PARAM_DMA_OUTPUT_CMD(isp,
+ DMA_OUTPUT_COMMAND_DISABLE);
+ IS_SCALERC_SET_PARAM_DMA_OUTPUT_BUFFERNUM(isp,
+ 0);
+ IS_SCALERC_SET_PARAM_DMA_OUTPUT_BUFFERADDR(isp,
+ 0);
+
+ IS_SET_PARAM_BIT(isp, PARAM_SCALERC_DMA_OUTPUT);
+ IS_INC_PARAM_NUM(isp);
+
+ fimc_is_mem_cache_clean((void *)isp->is_p_region,
+ IS_PARAM_SIZE);
+
+ isp->scenario_id = ISS_PREVIEW_STILL;
+ set_bit(IS_ST_INIT_PREVIEW_STILL, &isp->state);
+ clear_bit(IS_ST_INIT_PREVIEW_VIDEO, &isp->state);
+ fimc_is_hw_set_param(isp);
+
+ mutex_lock(&isp->lock);
+ ret = wait_event_timeout(isp->irq_queue,
+ test_bit(IS_ST_INIT_PREVIEW_VIDEO, &isp->state),
+ FIMC_IS_SHUTDOWN_TIMEOUT);
+ mutex_unlock(&isp->lock);
+ if (!ret) {
+ dev_err(&isp->pdev->dev,
+ "wait timeout 2: %s\n", __func__);
+ return -EBUSY;
+ }
+
+ dbg("IS change mode\n");
+ clear_bit(IS_ST_RUN, &isp->state);
+ set_bit(IS_ST_CHANGE_MODE, &isp->state);
+ fimc_is_hw_change_mode(isp, IS_MODE_PREVIEW_STILL);
+ mutex_lock(&isp->lock);
+ ret = wait_event_timeout(isp->irq_queue,
+ test_bit(IS_ST_CHANGE_MODE_DONE, &isp->state),
+ FIMC_IS_SHUTDOWN_TIMEOUT);
+ mutex_unlock(&isp->lock);
+ if (!ret) {
+ dev_err(&isp->pdev->dev,
+ "Mode change timeout:%s\n", __func__);
+ return -EBUSY;
+ }
+
+ dbg("IS Stream On");
+ fimc_is_hw_set_stream(isp, 1);
+
+ mutex_lock(&isp->lock);
+ ret = wait_event_timeout(isp->irq_queue,
+ test_bit(IS_ST_STREAM_ON, &isp->state),
+ FIMC_IS_SHUTDOWN_TIMEOUT);
+ mutex_unlock(&isp->lock);
+ if (!ret) {
+ dev_err(&isp->pdev->dev,
+ "wait timeout : %s\n", __func__);
+ return -EBUSY;
+ }
+ clear_bit(IS_ST_STREAM_ON, &isp->state);
+
+ if (!test_bit(FIMC_IS_STATE_SCALERP_STREAM_ON, &isp->pipe_state) &&
+ !test_bit(FIMC_IS_STATE_3DNR_STREAM_ON, &isp->pipe_state) &&
+ test_bit(FIMC_IS_STATE_HW_STREAM_ON, &isp->pipe_state)) {
+ clear_bit(IS_ST_STREAM_OFF, &isp->state);
+
+ fimc_is_hw_set_stream(isp, 0);
+ dbg("IS Stream Off");
+ mutex_lock(&isp->lock);
+ ret = wait_event_timeout(isp->irq_queue,
+ test_bit(IS_ST_STREAM_OFF, &isp->state),
+ FIMC_IS_SHUTDOWN_TIMEOUT);
+ mutex_unlock(&isp->lock);
+ if (!ret) {
+ dev_err(&isp->pdev->dev,
+ "wait timeout4 : %s\n", __func__);
+ return -EBUSY;
+ }
+ clear_bit(FIMC_IS_STATE_HW_STREAM_ON, &isp->pipe_state);
+ }
+
+ clear_bit(IS_ST_RUN, &isp->state);
+ clear_bit(IS_ST_STREAM_ON, &isp->state);
+ clear_bit(FIMC_IS_STATE_SCALERC_BUFFER_PREPARED, &isp->pipe_state);
+ clear_bit(FIMC_IS_STATE_SCALERC_STREAM_ON, &isp->pipe_state);
+
+ return 0;
+}
+
+static void fimc_is_scalerc_buffer_queue(struct vb2_buffer *vb)
+{
+ struct fimc_is_video_dev *video = vb->vb2_queue->drv_priv;
+ struct fimc_is_dev *isp = video->dev;
+ unsigned int i;
+
+ dbg("%s\n", __func__);
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERC].frame.format.num_planes
+ = vb->num_planes;
+
+ if (!test_bit(FIMC_IS_STATE_SCALERC_BUFFER_PREPARED,
+ &isp->pipe_state)) {
+ for (i = 0; i < vb->num_planes; i++) {
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERC].
+ buf[vb->v4l2_buf.index][i]
+ = isp->vb2->plane_addr(vb, i);
+
+ dbg("index(%d)(%d) deviceVaddr(0x%08x)\n",
+ vb->v4l2_buf.index, i,
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERC].
+ buf[vb->v4l2_buf.index][i]);
+ }
+
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERC].buf_ref_cnt++;
+
+ if (isp->video[FIMC_IS_VIDEO_NUM_SCALERC].num_buf
+ == isp->video[FIMC_IS_VIDEO_NUM_SCALERC].buf_ref_cnt)
+ set_bit(FIMC_IS_STATE_SCALERC_BUFFER_PREPARED,
+ &isp->pipe_state);
+ }
+
+ if (!test_bit(FIMC_IS_STATE_SCALERC_STREAM_ON, &isp->pipe_state))
+ fimc_is_scalerc_start_streaming(vb->vb2_queue,
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERC].num_buf);
+
+ return;
+}
+
+const struct vb2_ops fimc_is_scalerc_qops = {
+ .queue_setup = fimc_is_scalerc_queue_setup,
+ .buf_prepare = fimc_is_scalerc_buffer_prepare,
+ .buf_queue = fimc_is_scalerc_buffer_queue,
+ .wait_prepare = fimc_is_scalerc_unlock,
+ .wait_finish = fimc_is_scalerc_lock,
+ .start_streaming = fimc_is_scalerc_start_streaming,
+ .stop_streaming = fimc_is_scalerc_stop_streaming,
+};
+
+/*************************************************************************/
+/* video file opertation */
+/************************************************************************/
+
+static int fimc_is_scalerp_video_open(struct file *file)
+{
+ struct fimc_is_dev *isp = video_drvdata(file);
+
+#if defined(CONFIG_BUSFREQ_OPP) && defined(CONFIG_CPU_EXYNOS5250)
+ mutex_lock(&isp->busfreq_lock);
+ isp->busfreq_num++;
+ if (isp->busfreq_num == 1) {
+ dev_lock(isp->bus_dev, &isp->pdev->dev,
+ (FIMC_IS_FREQ_MIF * 1000) + FIMC_IS_FREQ_INT);
+ dbg("busfreq locked on <%d/%d>MHz\n",
+ FIMC_IS_FREQ_MIF, FIMC_IS_FREQ_INT);
+ }
+ mutex_unlock(&isp->busfreq_lock);
+#endif
+
+ dbg("%s\n", __func__);
+ file->private_data = &isp->video[FIMC_IS_VIDEO_NUM_SCALERP];
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERP].num_buf = 0;
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERP].buf_ref_cnt = 0;
+
+ mutex_lock(&isp->lock);
+ if (!test_bit(FIMC_IS_STATE_FW_DOWNLOADED, &isp->pipe_state)) {
+ isp->sensor_num = 1;
+ dbg("++++ IS load fw (Scaler P open)\n");
+ mutex_unlock(&isp->lock);
+ fimc_is_load_fw(isp);
+ bts_change_bus_traffic(&isp->pdev->dev, BTS_INCREASE_BW);
+
+ set_bit(FIMC_IS_STATE_FW_DOWNLOADED, &isp->pipe_state);
+ clear_bit(FIMC_IS_STATE_SENSOR_INITIALIZED, &isp->pipe_state);
+ clear_bit(FIMC_IS_STATE_HW_STREAM_ON, &isp->pipe_state);
+ dbg("---- IS load fw (Scaler P open)\n");
+ } else {
+ mutex_unlock(&isp->lock);
+ }
+
+ clear_bit(FIMC_IS_STATE_SCALERP_STREAM_ON, &isp->pipe_state);
+ return 0;
+
+}
+
+static int fimc_is_scalerp_video_close(struct file *file)
+{
+ struct fimc_is_dev *isp = video_drvdata(file);
+ int ret;
+
+ dbg("%s\n", __func__);
+ vb2_queue_release(&isp->video[FIMC_IS_VIDEO_NUM_SCALERP].vbq);
+
+ mutex_lock(&isp->lock);
+ if (!test_bit(FIMC_IS_STATE_SCALERP_STREAM_ON, &isp->pipe_state) &&
+ !test_bit(FIMC_IS_STATE_SCALERC_STREAM_ON, &isp->pipe_state) &&
+ !test_bit(FIMC_IS_STATE_3DNR_STREAM_ON, &isp->pipe_state) &&
+ test_bit(FIMC_IS_STATE_FW_DOWNLOADED, &isp->pipe_state)) {
+
+ dbg("++++ IS local power off (Scaler P close)\n");
+ mutex_unlock(&isp->lock);
+ clear_bit(FIMC_IS_STATE_HW_STREAM_ON, &isp->pipe_state);
+ fimc_is_hw_subip_poweroff(isp);
+ ret = wait_event_timeout(isp->irq_queue,
+ !test_bit(FIMC_IS_PWR_ST_POWER_ON_OFF, &isp->power),
+ FIMC_IS_SHUTDOWN_TIMEOUT_SENSOR);
+ if (!ret) {
+ err("wait timeout FIMC_IS_PWR_ST_POWER_ON_OFF\n");
+ fimc_is_hw_set_low_poweroff(isp, true);
+ clear_bit(FIMC_IS_PWR_ST_POWER_ON_OFF, &isp->power);
+ ret = 0;
+ }
+
+ dbg("staop flite & mipi (pos:%d) (port:%d)\n",
+ isp->sensor.id_position,
+ isp->pdata->
+ sensor_info[isp->sensor.id_position]->flite_id);
+ stop_fimc_lite(isp->pdata->
+ sensor_info[isp->sensor.id_position]->flite_id);
+ stop_mipi_csi(isp->pdata->
+ sensor_info[isp->sensor.id_position]->csi_id);
+
+ fimc_is_hw_a5_power(isp, 0);
+ bts_change_bus_traffic(&isp->pdev->dev, BTS_DECREASE_BW);
+ clear_bit(FIMC_IS_STATE_FW_DOWNLOADED, &isp->pipe_state);
+ dbg("---- IS local power off (Scaler P close)\n");
+ } else {
+ mutex_unlock(&isp->lock);
+ }
+
+#if defined(CONFIG_BUSFREQ_OPP) && defined(CONFIG_CPU_EXYNOS5250)
+ mutex_lock(&isp->busfreq_lock);
+ if (isp->busfreq_num == 1) {
+ dev_unlock(isp->bus_dev, &isp->pdev->dev);
+ printk(KERN_DEBUG "busfreq locked off\n");
+ }
+ isp->busfreq_num--;
+ if (isp->busfreq_num < 0)
+ isp->busfreq_num = 0;
+ mutex_unlock(&isp->busfreq_lock);
+#endif
+
+ return 0;
+
+}
+
+static unsigned int fimc_is_scalerp_video_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct fimc_is_dev *isp = video_drvdata(file);
+
+ dbg("%s\n", __func__);
+ return vb2_poll(&isp->video[FIMC_IS_VIDEO_NUM_SCALERP].vbq, file, wait);
+
+}
+
+static int fimc_is_scalerp_video_mmap(struct file *file,
+ struct vm_area_struct *vma)
+{
+ struct fimc_is_dev *isp = video_drvdata(file);
+
+ dbg("%s\n", __func__);
+ return vb2_mmap(&isp->video[FIMC_IS_VIDEO_NUM_SCALERP].vbq, vma);
+
+}
+
+/*************************************************************************/
+/* video ioctl operation */
+/************************************************************************/
+
+static int fimc_is_scalerp_video_querycap(struct file *file, void *fh,
+ struct v4l2_capability *cap)
+{
+ struct fimc_is_dev *isp = video_drvdata(file);
+
+ strncpy(cap->driver, isp->pdev->name, sizeof(cap->driver) - 1);
+
+ dbg("%s(devname : %s)\n", __func__, cap->driver);
+ strncpy(cap->card, isp->pdev->name, sizeof(cap->card) - 1);
+ cap->bus_info[0] = 0;
+ cap->version = KERNEL_VERSION(1, 0, 0);
+ cap->capabilities = V4L2_CAP_STREAMING
+ | V4L2_CAP_VIDEO_CAPTURE
+ | V4L2_CAP_VIDEO_CAPTURE_MPLANE;
+
+ return 0;
+}
+
+static int fimc_is_scalerp_video_enum_fmt_mplane(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_scalerp_video_get_format_mplane(struct file *file, void *fh,
+ struct v4l2_format *format)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_scalerp_video_set_format_mplane(struct file *file, void *fh,
+ struct v4l2_format *format)
+{
+ struct fimc_is_dev *isp = video_drvdata(file);
+ struct v4l2_pix_format_mplane *pix;
+ struct fimc_is_fmt *frame;
+
+ dbg("%s\n", __func__);
+
+ pix = &format->fmt.pix_mp;
+ frame = find_format(&pix->pixelformat, NULL, 0);
+
+ if (!frame)
+ return -EINVAL;
+
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERP].frame.format.pixelformat
+ = frame->pixelformat;
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERP].frame.format.mbus_code
+ = frame->mbus_code;
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERP].frame.format.num_planes
+ = frame->num_planes;
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERP].frame.width = pix->width;
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERP].frame.height = pix->height;
+ dbg("num_planes : %d\n", frame->num_planes);
+ dbg("width : %d\n", pix->width);
+ dbg("height : %d\n", pix->height);
+
+ return 0;
+}
+
+static int fimc_is_scalerp_video_try_format_mplane(struct file *file, void *fh,
+ struct v4l2_format *format)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_scalerp_video_cropcap(struct file *file, void *fh,
+ struct v4l2_cropcap *cropcap)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_scalerp_video_get_crop(struct file *file, void *fh,
+ struct v4l2_crop *crop)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_scalerp_video_set_crop(struct file *file, void *fh,
+ struct v4l2_crop *crop)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_scalerp_video_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *buf)
+{
+ int ret;
+ struct fimc_is_video_dev *video = file->private_data;
+ struct fimc_is_dev *isp = video_drvdata(file);
+
+ dbg("(buf->count : %d)\n", buf->count);
+ ret = vb2_reqbufs(&video->vbq, buf);
+ if (!ret)
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERP].num_buf = buf->count;
+
+ if (buf->count == 0)
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERP].buf_ref_cnt = 0;
+
+ dbg("(num_buf | %d)\n",
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERP].num_buf);
+
+ return ret;
+}
+
+static int fimc_is_scalerp_video_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ int ret;
+ struct fimc_is_video_dev *video = file->private_data;
+
+ dbg("%s\n", __func__);
+ ret = vb2_querybuf(&video->vbq, buf);
+
+ return ret;
+}
+
+static int fimc_is_scalerp_video_qbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ int vb_ret;
+ struct fimc_is_video_dev *video = file->private_data;
+ struct fimc_is_dev *isp = video_drvdata(file);
+
+ if (test_bit(FIMC_IS_STATE_SCALERP_BUFFER_PREPARED, &isp->pipe_state)) {
+ video->buf_mask |= (1<<buf->index);
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERP].buf_mask
+ = video->buf_mask;
+
+ dbg("index(%d) mask(0x%08x)\n", buf->index, video->buf_mask);
+ } else
+ dbg("index(%d)\n", buf->index);
+
+ vb_ret = vb2_qbuf(&video->vbq, buf);
+
+ return vb_ret;
+}
+
+static int fimc_is_scalerp_video_dqbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ int vb_ret;
+ struct fimc_is_video_dev *video = file->private_data;
+ struct fimc_is_dev *isp = video_drvdata(file);
+
+ vb_ret = vb2_dqbuf(&video->vbq, buf, file->f_flags & O_NONBLOCK);
+
+ video->buf_mask &= ~(1<<buf->index);
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERP].buf_mask = video->buf_mask;
+
+ dbg("index(%d) mask(0x%08x)\n", buf->index, video->buf_mask);
+
+ return vb_ret;
+}
+
+static int fimc_is_scalerp_video_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct fimc_is_dev *isp = video_drvdata(file);
+
+ dbg("%s\n", __func__);
+ return vb2_streamon(&isp->video[FIMC_IS_VIDEO_NUM_SCALERP].vbq, type);
+}
+
+static int fimc_is_scalerp_video_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct fimc_is_dev *isp = video_drvdata(file);
+
+ dbg("%s\n", __func__);
+ return vb2_streamoff(&isp->video[FIMC_IS_VIDEO_NUM_SCALERP].vbq, type);
+}
+
+static int fimc_is_scalerp_video_enum_input(struct file *file, void *priv,
+ struct v4l2_input *input)
+{
+ struct fimc_is_dev *isp = video_drvdata(file);
+ struct exynos5_fimc_is_sensor_info *sensor_info
+ = isp->pdata->sensor_info[input->index];
+
+ dbg("index(%d) sensor(%s)\n",
+ input->index, sensor_info->sensor_name);
+ dbg("pos(%d) sensor_id(%d)\n",
+ sensor_info->sensor_position, sensor_info->sensor_id);
+ dbg("csi_id(%d) flite_id(%d)\n",
+ sensor_info->csi_id, sensor_info->flite_id);
+ dbg("i2c_ch(%d)\n", sensor_info->i2c_channel);
+
+ if (input->index >= FIMC_IS_MAX_CAMIF_CLIENTS)
+ return -EINVAL;
+
+ input->type = V4L2_INPUT_TYPE_CAMERA;
+
+ strncpy(input->name, sensor_info->sensor_name,
+ FIMC_IS_MAX_NAME_LEN);
+ return 0;
+}
+
+static int fimc_is_scalerp_video_g_input(struct file *file, void *priv,
+ unsigned int *input)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_scalerp_video_s_input(struct file *file, void *priv,
+ unsigned int input)
+{
+ struct fimc_is_dev *isp = video_drvdata(file);
+ struct exynos5_fimc_is_sensor_info *sensor_info
+ = isp->pdata->sensor_info[input];
+
+ isp->sensor.id_position = input;
+ isp->sensor.sensor_type
+ = fimc_is_hw_get_sensor_type(sensor_info->sensor_id,
+ sensor_info->flite_id);
+
+ fimc_is_hw_set_default_size(isp, sensor_info->sensor_id);
+ printk(KERN_INFO "fimc_is_init_set - %d\n", isp->sensor.sensor_type);
+ fimc_is_init_set(isp, isp->sensor.sensor_type);
+
+ dbg("sensor info : pos(%d) type(%d)\n", input, isp->sensor.sensor_type);
+
+
+ return 0;
+}
+static int fimc_is_scalerp_video_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct fimc_is_dev *isp = video_drvdata(file);
+ int ret = 0;
+
+ switch (ctrl->id) {
+ /* EXIF information */
+ case V4L2_CID_IS_CAMERA_EXIF_EXPTIME:
+ case V4L2_CID_CAMERA_EXIF_EXPTIME: /* Exposure Time */
+ fimc_is_mem_cache_inv((void *)IS_HEADER(isp),
+ (unsigned long)(sizeof(struct is_frame_header)*4));
+ ctrl->value = isp->is_p_region->header[0].
+ exif.exposure_time.den;
+ break;
+ case V4L2_CID_IS_CAMERA_EXIF_FLASH:
+ case V4L2_CID_CAMERA_EXIF_FLASH: /* Flash */
+ fimc_is_mem_cache_inv((void *)IS_HEADER(isp),
+ (unsigned long)(sizeof(struct is_frame_header)*4));
+ ctrl->value = isp->is_p_region->header[0].exif.flash;
+ break;
+ case V4L2_CID_IS_CAMERA_EXIF_ISO:
+ case V4L2_CID_CAMERA_EXIF_ISO: /* ISO Speed Rating */
+ fimc_is_mem_cache_inv((void *)IS_HEADER(isp),
+ (unsigned long)(sizeof(struct is_frame_header)*4));
+ ctrl->value = isp->is_p_region->header[0].
+ exif.iso_speed_rating;
+ break;
+ case V4L2_CID_IS_CAMERA_EXIF_SHUTTERSPEED:
+ case V4L2_CID_CAMERA_EXIF_TV: /* Shutter Speed */
+ fimc_is_mem_cache_inv((void *)IS_HEADER(isp),
+ (unsigned long)(sizeof(struct is_frame_header)*4));
+ /* Exposure time = shutter speed by FW */
+ ctrl->value = isp->is_p_region->header[0].
+ exif.exposure_time.den;
+ break;
+ case V4L2_CID_IS_CAMERA_EXIF_BRIGHTNESS:
+ case V4L2_CID_CAMERA_EXIF_BV: /* Brightness */
+ fimc_is_mem_cache_inv((void *)IS_HEADER(isp),
+ (unsigned long)(sizeof(struct is_frame_header)*4));
+ ctrl->value = isp->is_p_region->header[0].exif.brightness.num;
+ break;
+ case V4L2_CID_CAMERA_EXIF_EBV: /* exposure bias */
+ fimc_is_mem_cache_inv((void *)IS_HEADER(isp),
+ (unsigned long)(sizeof(struct is_frame_header)*4));
+ ctrl->value = isp->is_p_region->header[0].exif.brightness.den;
+ break;
+ /* Get x and y offset of sensor */
+ case V4L2_CID_IS_GET_SENSOR_OFFSET_X:
+ ctrl->value = isp->sensor.offset_x;
+ break;
+ case V4L2_CID_IS_GET_SENSOR_OFFSET_Y:
+ ctrl->value = isp->sensor.offset_y;
+ break;
+ case V4L2_CID_IS_FD_GET_DATA:
+ ctrl->value = isp->fd_header.count;
+ fimc_is_mem_cache_inv((void *)IS_FACE(isp),
+ (unsigned long)(sizeof(struct is_face_marker)*MAX_FACE_COUNT));
+ memcpy((void *)isp->fd_header.target_addr,
+ &isp->is_p_region->face[isp->fd_header.index],
+ (sizeof(struct is_face_marker)*isp->fd_header.count));
+ break;
+ /* AF result */
+ case V4L2_CID_CAMERA_AUTO_FOCUS_RESULT:
+ if (!is_af_use(isp))
+ ctrl->value = 0x02;
+ else
+ ctrl->value = isp->af.af_lock_state;
+ break;
+ /* F/W debug region address */
+ case V4L2_CID_IS_FW_DEBUG_REGION_ADDR:
+ ctrl->value = isp->mem.base + FIMC_IS_DEBUG_REGION_ADDR;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return ret;
+}
+
+static int fimc_is_g_ext_ctrls_handler(struct fimc_is_dev *dev,
+ struct v4l2_ext_control *ctrl, int index)
+{
+ int ret = 0;
+ switch (ctrl->id) {
+ /* Face Detection CID handler */
+ /* 1. Overall information */
+ case V4L2_CID_IS_FD_GET_FACE_COUNT:
+ ctrl->value = dev->fd_header.count;
+ break;
+ case V4L2_CID_IS_FD_GET_FACE_FRAME_NUMBER:
+ if (dev->fd_header.offset < dev->fd_header.count) {
+ ctrl->value =
+ dev->is_p_region->face[dev->fd_header.index
+ + dev->fd_header.offset].frame_number;
+ } else {
+ ctrl->value = 0;
+ return -255;
+ }
+ break;
+ case V4L2_CID_IS_FD_GET_FACE_CONFIDENCE:
+ ctrl->value = dev->is_p_region->face[dev->fd_header.index
+ + dev->fd_header.offset].confidence;
+ break;
+ case V4L2_CID_IS_FD_GET_FACE_SMILE_LEVEL:
+ ctrl->value = dev->is_p_region->face[dev->fd_header.index
+ + dev->fd_header.offset].smile_level;
+ break;
+ case V4L2_CID_IS_FD_GET_FACE_BLINK_LEVEL:
+ ctrl->value = dev->is_p_region->face[dev->fd_header.index
+ + dev->fd_header.offset].blink_level;
+ break;
+ /* 2. Face information */
+ case V4L2_CID_IS_FD_GET_FACE_TOPLEFT_X:
+ ctrl->value = dev->is_p_region->face[dev->fd_header.index
+ + dev->fd_header.offset].face.offset_x;
+ break;
+ case V4L2_CID_IS_FD_GET_FACE_TOPLEFT_Y:
+ ctrl->value = dev->is_p_region->face[dev->fd_header.index
+ + dev->fd_header.offset].face.offset_y;
+ break;
+ case V4L2_CID_IS_FD_GET_FACE_BOTTOMRIGHT_X:
+ ctrl->value = dev->is_p_region->face[dev->fd_header.index
+ + dev->fd_header.offset].face.offset_x
+ + dev->is_p_region->face[dev->fd_header.index
+ + dev->fd_header.offset].face.width;
+ break;
+ case V4L2_CID_IS_FD_GET_FACE_BOTTOMRIGHT_Y:
+ ctrl->value = dev->is_p_region->face[dev->fd_header.index
+ + dev->fd_header.offset].face.offset_y
+ + dev->is_p_region->face[dev->fd_header.index
+ + dev->fd_header.offset].face.height;
+ break;
+ /* 3. Left eye information */
+ case V4L2_CID_IS_FD_GET_LEFT_EYE_TOPLEFT_X:
+ ctrl->value = dev->is_p_region->face[dev->fd_header.index
+ + dev->fd_header.offset].left_eye.offset_x;
+ break;
+ case V4L2_CID_IS_FD_GET_LEFT_EYE_TOPLEFT_Y:
+ ctrl->value = dev->is_p_region->face[dev->fd_header.index
+ + dev->fd_header.offset].left_eye.offset_y;
+ break;
+ case V4L2_CID_IS_FD_GET_LEFT_EYE_BOTTOMRIGHT_X:
+ ctrl->value = dev->is_p_region->face[dev->fd_header.index
+ + dev->fd_header.offset].left_eye.offset_x
+ + dev->is_p_region->face[dev->fd_header.index
+ + dev->fd_header.offset].left_eye.width;
+ break;
+ case V4L2_CID_IS_FD_GET_LEFT_EYE_BOTTOMRIGHT_Y:
+ ctrl->value = dev->is_p_region->face[dev->fd_header.index
+ + dev->fd_header.offset].left_eye.offset_y
+ + dev->is_p_region->face[dev->fd_header.index
+ + dev->fd_header.offset].left_eye.height;
+ break;
+ /* 4. Right eye information */
+ case V4L2_CID_IS_FD_GET_RIGHT_EYE_TOPLEFT_X:
+ ctrl->value = dev->is_p_region->face[dev->fd_header.index
+ + dev->fd_header.offset].right_eye.offset_x;
+ break;
+ case V4L2_CID_IS_FD_GET_RIGHT_EYE_TOPLEFT_Y:
+ ctrl->value = dev->is_p_region->face[dev->fd_header.index
+ + dev->fd_header.offset].right_eye.offset_y;
+ break;
+ case V4L2_CID_IS_FD_GET_RIGHT_EYE_BOTTOMRIGHT_X:
+ ctrl->value = dev->is_p_region->face[dev->fd_header.index
+ + dev->fd_header.offset].right_eye.offset_x
+ + dev->is_p_region->face[dev->fd_header.index
+ + dev->fd_header.offset].right_eye.width;
+ break;
+ case V4L2_CID_IS_FD_GET_RIGHT_EYE_BOTTOMRIGHT_Y:
+ ctrl->value = dev->is_p_region->face[dev->fd_header.index
+ + dev->fd_header.offset].right_eye.offset_y
+ + dev->is_p_region->face[dev->fd_header.index
+ + dev->fd_header.offset].right_eye.height;
+ break;
+ /* 5. Mouth eye information */
+ case V4L2_CID_IS_FD_GET_MOUTH_TOPLEFT_X:
+ ctrl->value = dev->is_p_region->face[dev->fd_header.index
+ + dev->fd_header.offset].mouth.offset_x;
+ break;
+ case V4L2_CID_IS_FD_GET_MOUTH_TOPLEFT_Y:
+ ctrl->value = dev->is_p_region->face[dev->fd_header.index
+ + dev->fd_header.offset].mouth.offset_y;
+ break;
+ case V4L2_CID_IS_FD_GET_MOUTH_BOTTOMRIGHT_X:
+ ctrl->value = dev->is_p_region->face[dev->fd_header.index
+ + dev->fd_header.offset].mouth.offset_x
+ + dev->is_p_region->face[dev->fd_header.index
+ + dev->fd_header.offset].mouth.width;
+ break;
+ case V4L2_CID_IS_FD_GET_MOUTH_BOTTOMRIGHT_Y:
+ ctrl->value = dev->is_p_region->face[dev->fd_header.index
+ + dev->fd_header.offset].mouth.offset_y
+ + dev->is_p_region->face[dev->fd_header.index
+ + dev->fd_header.offset].mouth.height;
+ break;
+ /* 6. Angle information */
+ case V4L2_CID_IS_FD_GET_ANGLE:
+ ctrl->value = dev->is_p_region->face[dev->fd_header.index
+ + dev->fd_header.offset].roll_angle;
+ break;
+ case V4L2_CID_IS_FD_GET_YAW_ANGLE:
+ ctrl->value = dev->is_p_region->face[dev->fd_header.index
+ + dev->fd_header.offset].yaw_angle;
+ break;
+ /* 7. Update next face information */
+ case V4L2_CID_IS_FD_GET_NEXT:
+ dev->fd_header.offset++;
+ break;
+ default:
+ return 255;
+ break;
+ }
+ return ret;
+}
+
+static int fimc_is_scalerp_video_g_ext_ctrl(struct file *file, void *priv,
+ struct v4l2_ext_controls *ctrls)
+{
+ struct fimc_is_dev *isp = video_drvdata(file);
+ struct v4l2_ext_control *ctrl;
+ int i, ret = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&isp->slock, flags);
+ ctrl = ctrls->controls;
+ if (!ctrls->ctrl_class == V4L2_CTRL_CLASS_CAMERA)
+ return -EINVAL;
+
+ fimc_is_mem_cache_inv((void *)IS_FACE(isp),
+ (unsigned long)(sizeof(struct is_face_marker)*MAX_FACE_COUNT));
+
+ isp->fd_header.offset = 0;
+
+ isp->fd_header.width = (s32)isp->sensor.width ;
+ isp->fd_header.height = (s32)isp->sensor.height ;
+
+ for (i = 0; i < ctrls->count; i++) {
+ ctrl = ctrls->controls + i;
+ ret = fimc_is_g_ext_ctrls_handler(isp, ctrl, i);
+ if (ret > 0) {
+ ctrls->error_idx = i;
+ break;
+ } else if (ret < 0) {
+ ret = 0;
+ break;
+ }
+ }
+
+ isp->fd_header.index = 0;
+ isp->fd_header.count = 0;
+ spin_unlock_irqrestore(&isp->slock, flags);
+ return ret;
+}
+
+static int fimc_is_scalerp_video_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct fimc_is_dev *isp = video_drvdata(file);
+ int ret = 0;
+
+ dbg("fimc_is_scalerp_video_s_ctrl(%d)(%d)\n", ctrl->id, ctrl->value);
+ switch (ctrl->id) {
+ case V4L2_CID_IS_CAMERA_SHOT_MODE_NORMAL:
+ ret = fimc_is_v4l2_shot_mode(isp, ctrl->value);
+ break;
+ case V4L2_CID_CAMERA_FRAME_RATE:
+#ifdef FRAME_RATE_ENABLE
+ /* FW partially supported it */
+ ret = fimc_is_v4l2_frame_rate(isp, ctrl->value);
+#else
+ err("ERR(%s) disabled FRAME_RATE\n", __func__);
+#endif
+ break;
+ /* Focus */
+ case V4L2_CID_IS_CAMERA_OBJECT_POSITION_X:
+ case V4L2_CID_CAMERA_OBJECT_POSITION_X:
+ isp->af.pos_x = ctrl->value;
+ break;
+ case V4L2_CID_IS_CAMERA_OBJECT_POSITION_Y:
+ case V4L2_CID_CAMERA_OBJECT_POSITION_Y:
+ isp->af.pos_y = ctrl->value;
+ break;
+ case V4L2_CID_CAMERA_FOCUS_MODE:
+ ret = fimc_is_v4l2_af_mode(isp, ctrl->value);
+ break;
+ case V4L2_CID_CAMERA_SET_AUTO_FOCUS:
+ ret = fimc_is_v4l2_af_start_stop(isp, ctrl->value);
+ break;
+ case V4L2_CID_CAMERA_TOUCH_AF_START_STOP:
+ ret = fimc_is_v4l2_touch_af_start_stop(isp, ctrl->value);
+ break;
+ case V4L2_CID_CAMERA_CAF_START_STOP:
+ ret = fimc_is_v4l2_caf_start_stop(isp, ctrl->value);
+ break;
+ /* AWB, AE Lock/Unlock */
+ case V4L2_CID_CAMERA_AEAWB_LOCK_UNLOCK:
+ ret = fimc_is_v4l2_ae_awb_lockunlock(isp, ctrl->value);
+ break;
+ /* FLASH */
+ case V4L2_CID_CAMERA_FLASH_MODE:
+ ret = fimc_is_v4l2_isp_flash_mode(isp, ctrl->value);
+ break;
+ case V4L2_CID_IS_CAMERA_AWB_MODE:
+ ret = fimc_is_v4l2_awb_mode(isp, ctrl->value);
+ break;
+ case V4L2_CID_CAMERA_WHITE_BALANCE:
+ ret = fimc_is_v4l2_awb_mode_legacy(isp, ctrl->value);
+ break;
+ case V4L2_CID_CAMERA_EFFECT:
+ ret = fimc_is_v4l2_isp_effect_legacy(isp, ctrl->value);
+ break;
+ case V4L2_CID_IS_CAMERA_IMAGE_EFFECT:
+ ret = fimc_is_v4l2_isp_effect(isp, ctrl->value);
+ break;
+ case V4L2_CID_IS_CAMERA_ISO:
+ case V4L2_CID_CAMERA_ISO:
+ ret = fimc_is_v4l2_isp_iso(isp, ctrl->value);
+ break;
+ case V4L2_CID_CAMERA_CONTRAST:
+ ret = fimc_is_v4l2_isp_contrast_legacy(isp, ctrl->value);
+ break;
+ case V4L2_CID_IS_CAMERA_CONTRAST:
+ ret = fimc_is_v4l2_isp_contrast(isp, ctrl->value);
+ break;
+ case V4L2_CID_IS_CAMERA_SATURATION:
+ case V4L2_CID_CAMERA_SATURATION:
+ ret = fimc_is_v4l2_isp_saturation(isp, ctrl->value);
+ break;
+ case V4L2_CID_IS_CAMERA_SHARPNESS:
+ case V4L2_CID_CAMERA_SHARPNESS:
+ ret = fimc_is_v4l2_isp_sharpness(isp, ctrl->value);
+ break;
+ case V4L2_CID_IS_CAMERA_EXPOSURE:
+ ret = fimc_is_v4l2_isp_exposure(isp, ctrl->value);
+ break;
+ case V4L2_CID_CAMERA_BRIGHTNESS:
+ ret = fimc_is_v4l2_isp_exposure_legacy(isp, ctrl->value);
+ break;
+ case V4L2_CID_IS_CAMERA_BRIGHTNESS:
+ ret = fimc_is_v4l2_isp_brightness(isp, ctrl->value);
+ break;
+ case V4L2_CID_IS_CAMERA_HUE:
+ ret = fimc_is_v4l2_isp_hue(isp, ctrl->value);
+ break;
+ case V4L2_CID_CAMERA_METERING:
+ ret = fimc_is_v4l2_isp_metering_legacy(isp, ctrl->value);
+ break;
+ case V4L2_CID_IS_CAMERA_METERING:
+ ret = fimc_is_v4l2_isp_metering(isp, ctrl->value);
+ break;
+ /* Ony valid at SPOT Mode */
+ case V4L2_CID_IS_CAMERA_METERING_POSITION_X:
+ IS_ISP_SET_PARAM_METERING_WIN_POS_X(isp, ctrl->value);
+ break;
+ case V4L2_CID_IS_CAMERA_METERING_POSITION_Y:
+ IS_ISP_SET_PARAM_METERING_WIN_POS_Y(isp, ctrl->value);
+ break;
+ case V4L2_CID_IS_CAMERA_METERING_WINDOW_X:
+ IS_ISP_SET_PARAM_METERING_WIN_WIDTH(isp, ctrl->value);
+ break;
+ case V4L2_CID_IS_CAMERA_METERING_WINDOW_Y:
+ IS_ISP_SET_PARAM_METERING_WIN_HEIGHT(isp, ctrl->value);
+ break;
+ case V4L2_CID_CAMERA_ANTI_BANDING:
+ ret = fimc_is_v4l2_isp_afc_legacy(isp, ctrl->value);
+ break;
+ case V4L2_CID_IS_CAMERA_AFC_MODE:
+ ret = fimc_is_v4l2_isp_afc(isp, ctrl->value);
+ break;
+ case V4L2_CID_IS_FD_SET_MAX_FACE_NUMBER:
+ /* TODO */
+ /*
+ if (ctrl->value >= 0) {
+ IS_FD_SET_PARAM_FD_CONFIG_CMD(isp,
+ FD_CONFIG_COMMAND_MAXIMUM_NUMBER);
+ IS_FD_SET_PARAM_FD_CONFIG_MAX_NUMBER(isp, ctrl->value);
+ IS_SET_PARAM_BIT(isp, PARAM_FD_CONFIG);
+ IS_INC_PARAM_NUM(isp);
+ fimc_is_mem_cache_clean((void *)isp->is_p_region,
+ IS_PARAM_SIZE);
+ fimc_is_hw_set_param(isp);
+ }
+ */
+ break;
+ case V4L2_CID_IS_FD_SET_ROLL_ANGLE:
+ ret = fimc_is_v4l2_fd_angle_mode(isp, ctrl->value);
+ break;
+ case V4L2_CID_IS_FD_SET_DATA_ADDRESS:
+ isp->fd_header.target_addr = ctrl->value;
+ break;
+ case V4L2_CID_IS_SET_ISP:
+ ret = fimc_is_v4l2_set_isp(isp, ctrl->value);
+ break;
+ case V4L2_CID_IS_SET_DRC:
+ ret = fimc_is_v4l2_set_drc(isp, ctrl->value);
+ break;
+ case V4L2_CID_IS_CMD_ISP:
+ ret = fimc_is_v4l2_cmd_isp(isp, ctrl->value);
+ break;
+ case V4L2_CID_IS_CMD_DRC:
+ ret = fimc_is_v4l2_cmd_drc(isp, ctrl->value);
+ break;
+ case V4L2_CID_IS_CMD_FD:
+ ret = fimc_is_v4l2_cmd_fd(isp, ctrl->value);
+ break;
+ case V4L2_CID_CAMERA_SCENE_MODE:
+ ret = fimc_is_v4l2_isp_scene_mode(isp, ctrl->value);
+ break;
+ case V4L2_CID_CAMERA_VT_MODE:
+ isp->setfile.sub_index = ctrl->value;
+ if (ctrl->value == 1)
+ printk(KERN_INFO "VT mode is selected\n");
+ break;
+ case V4L2_CID_CAMERA_SET_ODC:
+#ifdef ODC_ENABLE
+ ret = fimc_is_ctrl_odc(isp, ctrl->value);
+#else
+ err("ERR(%s) disabled ODC\n", __func__);
+#endif
+ break;
+ case V4L2_CID_CAMERA_SET_3DNR:
+#ifdef TDNR_ENABLE
+ ret = fimc_is_ctrl_3dnr(isp, ctrl->value);
+#else
+ err("ERR(%s) disabled 3DNR\n", __func__);
+#endif
+ break;
+ case V4L2_CID_CAMERA_ZOOM:
+#ifdef DZOOM_ENABLE
+ /* FW partially supported it */
+ ret = fimc_is_digital_zoom(isp, ctrl->value);
+#else
+ err("ERR(%s) disabled DZOOM\n", __func__);
+#endif
+ break;
+ case V4L2_CID_CAMERA_SET_DIS:
+#ifdef DIS_ENABLE
+ /* FW partially supported it */
+ ret = fimc_is_ctrl_dis(isp, ctrl->value);
+#else
+ err("ERR(%s) disabled DIS\n", __func__);
+#endif
+ break;
+ case V4L2_CID_CAMERA_VGA_BLUR:
+ break;
+ default:
+ err("Invalid control\n");
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+const struct v4l2_file_operations fimc_is_scalerp_video_fops = {
+ .owner = THIS_MODULE,
+ .open = fimc_is_scalerp_video_open,
+ .release = fimc_is_scalerp_video_close,
+ .poll = fimc_is_scalerp_video_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = fimc_is_scalerp_video_mmap,
+};
+
+const struct v4l2_ioctl_ops fimc_is_scalerp_video_ioctl_ops = {
+ .vidioc_querycap = fimc_is_scalerp_video_querycap,
+ .vidioc_enum_fmt_vid_cap_mplane
+ = fimc_is_scalerp_video_enum_fmt_mplane,
+ .vidioc_g_fmt_vid_cap_mplane
+ = fimc_is_scalerp_video_get_format_mplane,
+ .vidioc_s_fmt_vid_cap_mplane
+ = fimc_is_scalerp_video_set_format_mplane,
+ .vidioc_try_fmt_vid_cap_mplane
+ = fimc_is_scalerp_video_try_format_mplane,
+ .vidioc_cropcap = fimc_is_scalerp_video_cropcap,
+ .vidioc_g_crop = fimc_is_scalerp_video_get_crop,
+ .vidioc_s_crop = fimc_is_scalerp_video_set_crop,
+ .vidioc_reqbufs = fimc_is_scalerp_video_reqbufs,
+ .vidioc_querybuf = fimc_is_scalerp_video_querybuf,
+ .vidioc_qbuf = fimc_is_scalerp_video_qbuf,
+ .vidioc_dqbuf = fimc_is_scalerp_video_dqbuf,
+ .vidioc_streamon = fimc_is_scalerp_video_streamon,
+ .vidioc_streamoff = fimc_is_scalerp_video_streamoff,
+ .vidioc_enum_input = fimc_is_scalerp_video_enum_input,
+ .vidioc_g_input = fimc_is_scalerp_video_g_input,
+ .vidioc_s_input = fimc_is_scalerp_video_s_input,
+ .vidioc_g_ctrl = fimc_is_scalerp_video_g_ctrl,
+ .vidioc_s_ctrl = fimc_is_scalerp_video_s_ctrl,
+ .vidioc_g_ext_ctrls = fimc_is_scalerp_video_g_ext_ctrl,
+};
+
+static int fimc_is_scalerp_queue_setup(struct vb2_queue *vq,
+ const struct v4l2_format *fmt,
+ unsigned int *num_buffers,
+ unsigned int *num_planes, unsigned int sizes[],
+ void *allocators[])
+{
+
+ struct fimc_is_video_dev *video = vq->drv_priv;
+ struct fimc_is_dev *isp = video->dev;
+ int i;
+
+
+ *num_planes = isp->video[FIMC_IS_VIDEO_NUM_SCALERP].
+ frame.format.num_planes;
+ set_plane_size(&isp->video[FIMC_IS_VIDEO_NUM_SCALERP].frame, sizes);
+
+ for (i = 0; i < *num_planes; i++)
+ allocators[i] = isp->alloc_ctx;
+
+ dbg("(num_planes : %d)(size : %d)\n", (int)*num_planes, (int)sizes[0]);
+
+ return 0;
+}
+static int fimc_is_scalerp_buffer_prepare(struct vb2_buffer *vb)
+{
+ dbg("--%s\n", __func__);
+ return 0;
+}
+
+
+static inline void fimc_is_scalerp_lock(struct vb2_queue *vq)
+{
+ dbg("%s\n", __func__);
+}
+
+static inline void fimc_is_scalerp_unlock(struct vb2_queue *vq)
+{
+ dbg("%s\n", __func__);
+}
+
+static int fimc_is_scalerp_start_streaming(struct vb2_queue *q,
+ unsigned int count)
+{
+ struct fimc_is_video_dev *video = q->drv_priv;
+ struct fimc_is_dev *isp = video->dev;
+ int ret;
+ int i, j;
+ int buf_index;
+
+ dbg("%s(pipe_state : %d)\n", __func__, (int)isp->pipe_state);
+
+ if (test_bit(FIMC_IS_STATE_FW_DOWNLOADED, &isp->pipe_state) &&
+ !test_bit(FIMC_IS_STATE_SENSOR_INITIALIZED, &isp->pipe_state)) {
+
+ dbg("IS change mode\n");
+ clear_bit(IS_ST_RUN, &isp->state);
+ set_bit(IS_ST_CHANGE_MODE, &isp->state);
+ fimc_is_hw_change_mode(isp, IS_MODE_PREVIEW_STILL);
+ mutex_lock(&isp->lock);
+ ret = wait_event_timeout(isp->irq_queue,
+ test_bit(IS_ST_CHANGE_MODE_DONE,
+ &isp->state),
+ FIMC_IS_SHUTDOWN_TIMEOUT);
+ mutex_unlock(&isp->lock);
+ if (!ret) {
+ dev_err(&isp->pdev->dev,
+ "Mode change timeout:%s\n", __func__);
+ return -EBUSY;
+ }
+
+ set_bit(FIMC_IS_STATE_SENSOR_INITIALIZED, &isp->pipe_state);
+ }
+
+ if (test_bit(FIMC_IS_STATE_SENSOR_INITIALIZED, &isp->pipe_state) &&
+ test_bit(FIMC_IS_STATE_SCALERP_BUFFER_PREPARED,
+ &isp->pipe_state) &&
+ !test_bit(FIMC_IS_STATE_HW_STREAM_ON, &isp->pipe_state)) {
+ dbg("IS Stream On");
+ fimc_is_hw_set_stream(isp, 1);
+ mutex_lock(&isp->lock);
+ ret = wait_event_timeout(isp->irq_queue,
+ test_bit(IS_ST_STREAM_ON, &isp->state),
+ FIMC_IS_SHUTDOWN_TIMEOUT);
+ mutex_unlock(&isp->lock);
+ if (!ret) {
+ dev_err(&isp->pdev->dev,
+ "wait timeout : %s\n", __func__);
+ return -EBUSY;
+ }
+ clear_bit(IS_ST_STREAM_ON, &isp->state);
+
+ set_bit(FIMC_IS_STATE_HW_STREAM_ON, &isp->pipe_state);
+ }
+
+ if (test_bit(FIMC_IS_STATE_SCALERP_BUFFER_PREPARED, &isp->pipe_state) &&
+ test_bit(FIMC_IS_STATE_HW_STREAM_ON, &isp->pipe_state) &&
+ test_bit(FIMC_IS_STATE_SENSOR_INITIALIZED, &isp->pipe_state)) {
+
+ /* buffer addr setting */
+ for (i = 0; i < isp->video[FIMC_IS_VIDEO_NUM_SCALERP].
+ num_buf; i++)
+ for (j = 0; j < isp->video[FIMC_IS_VIDEO_NUM_SCALERP].
+ frame.format.num_planes; j++) {
+ buf_index = i*isp->
+ video[FIMC_IS_VIDEO_NUM_SCALERP].
+ frame.format.num_planes + j;
+
+ dbg("(%d)set buf(%d:%d) = 0x%08x\n",
+ buf_index, i, j,
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERP].
+ buf[i][j]);
+
+ isp->is_p_region->shared[400+buf_index]
+ = isp->video[FIMC_IS_VIDEO_NUM_SCALERP].
+ buf[i][j];
+ }
+
+ dbg("buf_num:%d buf_plane:%d shared[400] : 0x%p\n",
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERP].num_buf,
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERP].
+ frame.format.num_planes,
+ isp->mem.kvaddr_shared + 400 * sizeof(u32));
+
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERP].buf_mask = 0;
+ for (i = 0; i < isp->video[FIMC_IS_VIDEO_NUM_SCALERP].
+ num_buf; i++)
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERP].buf_mask
+ |= (1 << i);
+ dbg("initial buffer mask : 0x%08x\n",
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERP].buf_mask);
+
+ IS_SCALERP_SET_PARAM_DMA_OUTPUT_CMD(isp,
+ DMA_OUTPUT_COMMAND_ENABLE);
+ IS_SCALERP_SET_PARAM_DMA_OUTPUT_MASK(isp,
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERP].buf_mask);
+ IS_SCALERP_SET_PARAM_DMA_OUTPUT_BUFFERNUM(isp,
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERP].num_buf);
+ IS_SCALERP_SET_PARAM_DMA_OUTPUT_BUFFERADDR(isp,
+ (u32)isp->mem.dvaddr_shared + 400*sizeof(u32));
+ IS_SET_PARAM_BIT(isp, PARAM_SCALERP_DMA_OUTPUT);
+ IS_INC_PARAM_NUM(isp);
+
+ fimc_is_mem_cache_clean((void *)isp->is_p_region,
+ IS_PARAM_SIZE);
+
+ isp->scenario_id = ISS_PREVIEW_STILL;
+ set_bit(IS_ST_INIT_PREVIEW_STILL, &isp->state);
+ clear_bit(IS_ST_INIT_CAPTURE_STILL, &isp->state);
+ clear_bit(IS_ST_INIT_PREVIEW_VIDEO, &isp->state);
+ fimc_is_hw_set_param(isp);
+ mutex_lock(&isp->lock);
+ ret = wait_event_timeout(isp->irq_queue,
+ test_bit(IS_ST_INIT_PREVIEW_VIDEO, &isp->state),
+ FIMC_IS_SHUTDOWN_TIMEOUT);
+ mutex_unlock(&isp->lock);
+ if (!ret) {
+ dev_err(&isp->pdev->dev,
+ "wait timeout : %s\n", __func__);
+ return -EBUSY;
+ }
+
+ set_bit(FIMC_IS_STATE_SCALERP_STREAM_ON, &isp->pipe_state);
+
+#ifdef DZOOM_EVT0
+ printk(KERN_INFO "DZOOM_EVT0 is enabled\n");
+ clear_bit(IS_ST_SCALERP_FRAME_DONE, &isp->state);
+ mutex_lock(&isp->lock);
+ ret = wait_event_timeout(isp->irq_queue,
+ test_bit(IS_ST_SCALERP_FRAME_DONE, &isp->state),
+ FIMC_IS_SHUTDOWN_TIMEOUT);
+ mutex_unlock(&isp->lock);
+ if (!ret) {
+ dev_err(&isp->pdev->dev,
+ "wait timeout : %s\n", __func__);
+ return -EBUSY;
+ }
+ dbg("DRC stop\n");
+ IS_DRC_SET_PARAM_CONTROL_CMD(isp,
+ CONTROL_COMMAND_STOP);
+ IS_SET_PARAM_BIT(isp, PARAM_DRC_CONTROL);
+ IS_INC_PARAM_NUM(isp);
+ fimc_is_mem_cache_clean((void *)isp->is_p_region,
+ IS_PARAM_SIZE);
+
+ isp->scenario_id = ISS_PREVIEW_STILL;
+ set_bit(IS_ST_INIT_PREVIEW_STILL, &isp->state);
+ clear_bit(IS_ST_INIT_CAPTURE_STILL, &isp->state);
+ clear_bit(IS_ST_INIT_PREVIEW_VIDEO, &isp->state);
+ fimc_is_hw_set_param(isp);
+ mutex_lock(&isp->lock);
+ ret = wait_event_timeout(isp->irq_queue,
+ test_bit(IS_ST_INIT_PREVIEW_VIDEO, &isp->state),
+ FIMC_IS_SHUTDOWN_TIMEOUT);
+ mutex_unlock(&isp->lock);
+ if (!ret) {
+ dev_err(&isp->pdev->dev,
+ "wait timeout : %s\n", __func__);
+ return -EBUSY;
+ }
+
+ dbg("DRC change path\n");
+ IS_DRC_SET_PARAM_OTF_INPUT_CMD(isp,
+ OTF_INPUT_COMMAND_DISABLE);
+ IS_SET_PARAM_BIT(isp, PARAM_DRC_OTF_INPUT);
+ IS_INC_PARAM_NUM(isp);
+
+ IS_DRC_SET_PARAM_DMA_INPUT_CMD(isp,
+ DMA_INPUT_COMMAND_ENABLE);
+ IS_DRC_SET_PARAM_DMA_INPUT_BUFFERNUM(isp,
+ 1);
+ isp->is_p_region->shared[100] = (u32)isp->mem.dvaddr_isp;
+ IS_DRC_SET_PARAM_DMA_INPUT_BUFFERADDR(isp,
+ (u32)isp->mem.dvaddr_shared + 100*sizeof(u32));
+ dbg("isp phy addr : 0x%08x\n",
+ (long unsigned int)virt_to_phys(isp->mem.kvaddr_isp));
+ dbg("isp dvaddr : 0x%08x\n",
+ (long unsigned int)isp->mem.dvaddr_isp);
+ IS_SET_PARAM_BIT(isp, PARAM_DRC_DMA_INPUT);
+ IS_INC_PARAM_NUM(isp);
+
+ fimc_is_mem_cache_clean((void *)isp->is_p_region,
+ IS_PARAM_SIZE);
+
+ isp->scenario_id = ISS_PREVIEW_STILL;
+ set_bit(IS_ST_INIT_PREVIEW_STILL, &isp->state);
+ clear_bit(IS_ST_INIT_CAPTURE_STILL, &isp->state);
+ clear_bit(IS_ST_INIT_PREVIEW_VIDEO, &isp->state);
+ fimc_is_hw_set_param(isp);
+ mutex_lock(&isp->lock);
+ ret = wait_event_timeout(isp->irq_queue,
+ test_bit(IS_ST_INIT_PREVIEW_VIDEO, &isp->state),
+ FIMC_IS_SHUTDOWN_TIMEOUT);
+ mutex_unlock(&isp->lock);
+ if (!ret) {
+ dev_err(&isp->pdev->dev,
+ "wait timeout : %s\n", __func__);
+ return -EBUSY;
+ }
+
+ dbg("DRC start\n");
+ IS_DRC_SET_PARAM_CONTROL_CMD(isp,
+ CONTROL_COMMAND_START);
+ IS_SET_PARAM_BIT(isp, PARAM_DRC_CONTROL);
+ IS_INC_PARAM_NUM(isp);
+ fimc_is_mem_cache_clean((void *)isp->is_p_region,
+ IS_PARAM_SIZE);
+
+ isp->scenario_id = ISS_PREVIEW_STILL;
+ set_bit(IS_ST_INIT_PREVIEW_STILL, &isp->state);
+ clear_bit(IS_ST_INIT_CAPTURE_STILL, &isp->state);
+ clear_bit(IS_ST_INIT_PREVIEW_VIDEO, &isp->state);
+ fimc_is_hw_set_param(isp);
+ mutex_lock(&isp->lock);
+ ret = wait_event_timeout(isp->irq_queue,
+ test_bit(IS_ST_INIT_PREVIEW_VIDEO, &isp->state),
+ FIMC_IS_SHUTDOWN_TIMEOUT);
+ mutex_unlock(&isp->lock);
+ if (!ret) {
+ dev_err(&isp->pdev->dev,
+ "wait timeout : %s\n", __func__);
+ return -EBUSY;
+ }
+#endif
+ }
+
+ return 0;
+}
+
+static int fimc_is_scalerp_stop_streaming(struct vb2_queue *q)
+{
+ struct fimc_is_video_dev *video = q->drv_priv;
+ struct fimc_is_dev *isp = video->dev;
+ int ret;
+
+
+ clear_bit(IS_ST_STREAM_OFF, &isp->state);
+ fimc_is_hw_set_stream(isp, 0);
+ mutex_lock(&isp->lock);
+ ret = wait_event_timeout(isp->irq_queue,
+ test_bit(IS_ST_STREAM_OFF, &isp->state),
+ FIMC_IS_SHUTDOWN_TIMEOUT);
+ mutex_unlock(&isp->lock);
+ if (!ret) {
+ dev_err(&isp->pdev->dev,
+ "wait timeout : %s\n", __func__);
+ if (!ret)
+ err("s_power off failed!!\n");
+ return -EBUSY;
+ }
+
+ IS_SCALERP_SET_PARAM_DMA_OUTPUT_CMD(isp,
+ DMA_OUTPUT_COMMAND_DISABLE);
+ IS_SCALERP_SET_PARAM_DMA_OUTPUT_BUFFERNUM(isp,
+ 0);
+ IS_SCALERP_SET_PARAM_DMA_OUTPUT_BUFFERADDR(isp,
+ 0);
+
+ IS_SET_PARAM_BIT(isp, PARAM_SCALERP_DMA_OUTPUT);
+ IS_INC_PARAM_NUM(isp);
+
+ fimc_is_mem_cache_clean((void *)isp->is_p_region,
+ IS_PARAM_SIZE);
+
+ isp->scenario_id = ISS_PREVIEW_STILL;
+ set_bit(IS_ST_INIT_PREVIEW_STILL, &isp->state);
+ clear_bit(IS_ST_INIT_PREVIEW_VIDEO, &isp->state);
+ fimc_is_hw_set_param(isp);
+
+ mutex_lock(&isp->lock);
+ ret = wait_event_timeout(isp->irq_queue,
+ test_bit(IS_ST_INIT_PREVIEW_VIDEO, &isp->state),
+ FIMC_IS_SHUTDOWN_TIMEOUT);
+ mutex_unlock(&isp->lock);
+ if (!ret) {
+ dev_err(&isp->pdev->dev,
+ "wait timeout 2: %s\n", __func__);
+ return -EBUSY;
+ }
+
+ dbg("IS change mode\n");
+ clear_bit(IS_ST_RUN, &isp->state);
+ set_bit(IS_ST_CHANGE_MODE, &isp->state);
+ fimc_is_hw_change_mode(isp, IS_MODE_PREVIEW_STILL);
+ mutex_lock(&isp->lock);
+ ret = wait_event_timeout(isp->irq_queue,
+ test_bit(IS_ST_CHANGE_MODE_DONE, &isp->state),
+ FIMC_IS_SHUTDOWN_TIMEOUT);
+ mutex_unlock(&isp->lock);
+ if (!ret) {
+ dev_err(&isp->pdev->dev,
+ "Mode change timeout:%s\n", __func__);
+ return -EBUSY;
+ }
+
+ dbg("IS Stream On\n");
+ fimc_is_hw_set_stream(isp, 1);
+
+ mutex_lock(&isp->lock);
+ ret = wait_event_timeout(isp->irq_queue,
+ test_bit(IS_ST_STREAM_ON, &isp->state),
+ FIMC_IS_SHUTDOWN_TIMEOUT);
+ mutex_unlock(&isp->lock);
+ if (!ret) {
+ dev_err(&isp->pdev->dev,
+ "wait timeout : %s\n", __func__);
+ return -EBUSY;
+ }
+ clear_bit(IS_ST_STREAM_ON, &isp->state);
+
+ if (!test_bit(FIMC_IS_STATE_SCALERC_STREAM_ON, &isp->pipe_state) &&
+ !test_bit(FIMC_IS_STATE_3DNR_STREAM_ON, &isp->pipe_state) &&
+ test_bit(FIMC_IS_STATE_HW_STREAM_ON, &isp->pipe_state)) {
+ clear_bit(IS_ST_STREAM_OFF, &isp->state);
+ dbg("IS Stream Off");
+ fimc_is_hw_set_stream(isp, 0);
+ mutex_lock(&isp->lock);
+ ret = wait_event_timeout(isp->irq_queue,
+ test_bit(IS_ST_STREAM_OFF, &isp->state),
+ FIMC_IS_SHUTDOWN_TIMEOUT);
+ mutex_unlock(&isp->lock);
+ if (!ret) {
+ dev_err(&isp->pdev->dev,
+ "wait timeout 4: %s\n", __func__);
+ return -EBUSY;
+ }
+ clear_bit(FIMC_IS_STATE_HW_STREAM_ON, &isp->pipe_state);
+ }
+ clear_bit(IS_ST_RUN, &isp->state);
+ clear_bit(IS_ST_STREAM_ON, &isp->state);
+ clear_bit(FIMC_IS_STATE_SCALERP_BUFFER_PREPARED, &isp->pipe_state);
+ clear_bit(FIMC_IS_STATE_SCALERP_STREAM_ON, &isp->pipe_state);
+
+ isp->setfile.sub_index = 0;
+
+ return 0;
+}
+
+static void fimc_is_scalerp_buffer_queue(struct vb2_buffer *vb)
+{
+ struct fimc_is_video_dev *video = vb->vb2_queue->drv_priv;
+ struct fimc_is_dev *isp = video->dev;
+ unsigned int i;
+
+ dbg("%s\n", __func__);
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERP].frame.format.num_planes
+ = vb->num_planes;
+
+ if (!test_bit(FIMC_IS_STATE_SCALERP_BUFFER_PREPARED,
+ &isp->pipe_state)) {
+ for (i = 0; i < vb->num_planes; i++) {
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERP].
+ buf[vb->v4l2_buf.index][i]
+ = isp->vb2->plane_addr(vb, i);
+ dbg("index(%d)(%d) deviceVaddr(0x%08x)\n",
+ vb->v4l2_buf.index, i,
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERP].
+ buf[vb->v4l2_buf.index][i]);
+ }
+
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERP].buf_ref_cnt++;
+
+ if (isp->video[FIMC_IS_VIDEO_NUM_SCALERP].num_buf
+ == isp->video[FIMC_IS_VIDEO_NUM_SCALERP].buf_ref_cnt) {
+ set_bit(FIMC_IS_STATE_SCALERP_BUFFER_PREPARED,
+ &isp->pipe_state);
+ dbg("FIMC_IS_STATE_SCALERP_BUFFER_PREPARED\n");
+ }
+ }
+
+ if (!test_bit(FIMC_IS_STATE_SCALERP_STREAM_ON, &isp->pipe_state))
+ fimc_is_scalerp_start_streaming(vb->vb2_queue,
+ isp->video[FIMC_IS_VIDEO_NUM_SCALERP].num_buf);
+
+ return;
+}
+
+const struct vb2_ops fimc_is_scalerp_qops = {
+ .queue_setup = fimc_is_scalerp_queue_setup,
+ .buf_prepare = fimc_is_scalerp_buffer_prepare,
+ .buf_queue = fimc_is_scalerp_buffer_queue,
+ .wait_prepare = fimc_is_scalerp_unlock,
+ .wait_finish = fimc_is_scalerp_lock,
+ .start_streaming = fimc_is_scalerp_start_streaming,
+ .stop_streaming = fimc_is_scalerp_stop_streaming,
+};
+
+
+/*************************************************************************/
+/* video file opertation */
+/************************************************************************/
+
+static int fimc_is_3dnr_video_open(struct file *file)
+{
+ struct fimc_is_dev *isp = video_drvdata(file);
+
+#if defined(CONFIG_BUSFREQ_OPP) && defined(CONFIG_CPU_EXYNOS5250)
+ mutex_lock(&isp->busfreq_lock);
+ isp->busfreq_num++;
+ if (isp->busfreq_num == 1) {
+ dev_lock(isp->bus_dev, &isp->pdev->dev,
+ (FIMC_IS_FREQ_MIF * 1000) + FIMC_IS_FREQ_INT);
+ dbg("busfreq locked on <%d/%d>MHz\n",
+ FIMC_IS_FREQ_MIF, FIMC_IS_FREQ_INT);
+ }
+ mutex_unlock(&isp->busfreq_lock);
+#endif
+
+ dbg("%s\n", __func__);
+ file->private_data = &isp->video[FIMC_IS_VIDEO_NUM_3DNR];
+ isp->video[FIMC_IS_VIDEO_NUM_3DNR].num_buf = 0;
+ isp->video[FIMC_IS_VIDEO_NUM_3DNR].buf_ref_cnt = 0;
+
+ clear_bit(FIMC_IS_STATE_3DNR_STREAM_ON, &isp->pipe_state);
+ return 0;
+
+}
+
+static int fimc_is_3dnr_video_close(struct file *file)
+{
+ struct fimc_is_dev *isp = video_drvdata(file);
+ int ret = 0;
+
+ dbg("%s\n", __func__);
+ vb2_queue_release(&isp->video[FIMC_IS_VIDEO_NUM_3DNR].vbq);
+
+ return ret;
+}
+
+static unsigned int fimc_is_3dnr_video_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct fimc_is_dev *isp = video_drvdata(file);
+
+ dbg("%s\n", __func__);
+ return vb2_poll(&isp->video[FIMC_IS_VIDEO_NUM_3DNR].vbq, file, wait);
+
+}
+
+static int fimc_is_3dnr_video_mmap(struct file *file,
+ struct vm_area_struct *vma)
+{
+ struct fimc_is_dev *isp = video_drvdata(file);
+
+ dbg("%s\n", __func__);
+ return vb2_mmap(&isp->video[FIMC_IS_VIDEO_NUM_3DNR].vbq, vma);
+
+}
+
+/*************************************************************************/
+/* video ioctl operation */
+/************************************************************************/
+
+static int fimc_is_3dnr_video_querycap(struct file *file, void *fh,
+ struct v4l2_capability *cap)
+{
+ struct fimc_is_dev *isp = video_drvdata(file);
+
+ strncpy(cap->driver, isp->pdev->name, sizeof(cap->driver) - 1);
+
+ dbg("%s(devname : %s)\n", __func__, cap->driver);
+ strncpy(cap->card, isp->pdev->name, sizeof(cap->card) - 1);
+ cap->bus_info[0] = 0;
+ cap->version = KERNEL_VERSION(1, 0, 0);
+ cap->capabilities = V4L2_CAP_STREAMING
+ | V4L2_CAP_VIDEO_CAPTURE
+ | V4L2_CAP_VIDEO_CAPTURE_MPLANE;
+
+ return 0;
+}
+
+static int fimc_is_3dnr_video_enum_fmt_mplane(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_3dnr_video_get_format_mplane(struct file *file, void *fh,
+ struct v4l2_format *format)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_3dnr_video_set_format_mplane(struct file *file, void *fh,
+ struct v4l2_format *format)
+{
+ struct fimc_is_dev *isp = video_drvdata(file);
+ struct v4l2_pix_format_mplane *pix;
+ struct fimc_is_fmt *frame;
+
+ dbg("%s\n", __func__);
+
+ pix = &format->fmt.pix_mp;
+ frame = find_format(&pix->pixelformat, NULL, 0);
+
+ if (!frame)
+ return -EINVAL;
+
+ isp->video[FIMC_IS_VIDEO_NUM_3DNR].frame.format.pixelformat
+ = frame->pixelformat;
+ isp->video[FIMC_IS_VIDEO_NUM_3DNR].frame.format.mbus_code
+ = frame->mbus_code;
+ isp->video[FIMC_IS_VIDEO_NUM_3DNR].frame.format.num_planes
+ = frame->num_planes;
+ isp->video[FIMC_IS_VIDEO_NUM_3DNR].frame.width = pix->width;
+ isp->video[FIMC_IS_VIDEO_NUM_3DNR].frame.height = pix->height;
+ dbg("num_planes : %d\n", frame->num_planes);
+ dbg("width : %d\n", pix->width);
+ dbg("height : %d\n", pix->height);
+
+ return 0;
+}
+
+static int fimc_is_3dnr_video_try_format_mplane(struct file *file, void *fh,
+ struct v4l2_format *format)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_3dnr_video_cropcap(struct file *file, void *fh,
+ struct v4l2_cropcap *cropcap)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_3dnr_video_get_crop(struct file *file, void *fh,
+ struct v4l2_crop *crop)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_3dnr_video_set_crop(struct file *file, void *fh,
+ struct v4l2_crop *crop)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_3dnr_video_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *buf)
+{
+ int ret;
+ struct fimc_is_video_dev *video = file->private_data;
+ struct fimc_is_dev *isp = video_drvdata(file);
+
+ dbg("%s\n", __func__);
+ ret = vb2_reqbufs(&video->vbq, buf);
+ if (!ret)
+ isp->video[FIMC_IS_VIDEO_NUM_3DNR].num_buf = buf->count;
+
+ if (buf->count == 0)
+ isp->video[FIMC_IS_VIDEO_NUM_3DNR].buf_ref_cnt = 0;
+
+ dbg("%s(num_buf | %d)\n", __func__,
+ isp->video[FIMC_IS_VIDEO_NUM_3DNR].num_buf);
+
+ return ret;
+}
+
+static int fimc_is_3dnr_video_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ int ret;
+ struct fimc_is_video_dev *video = file->private_data;
+
+ dbg("%s\n", __func__);
+ ret = vb2_querybuf(&video->vbq, buf);
+
+ return ret;
+}
+
+static int fimc_is_3dnr_video_qbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ int vb_ret;
+ struct fimc_is_video_dev *video = file->private_data;
+ struct fimc_is_dev *isp = video_drvdata(file);
+
+ if (test_bit(FIMC_IS_STATE_3DNR_BUFFER_PREPARED, &isp->pipe_state)) {
+ video->buf_mask |= (1<<buf->index);
+ isp->video[FIMC_IS_VIDEO_NUM_3DNR].buf_mask = video->buf_mask;
+
+ dbg("index(%d) mask(0x%08x)\n", buf->index, video->buf_mask);
+ } else {
+ dbg("%s :: index(%d)\n", __func__, buf->index);
+ }
+ vb_ret = vb2_qbuf(&video->vbq, buf);
+
+ return vb_ret;
+}
+
+static int fimc_is_3dnr_video_dqbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ int vb_ret;
+ struct fimc_is_video_dev *video = file->private_data;
+ struct fimc_is_dev *isp = video_drvdata(file);
+
+ vb_ret = vb2_dqbuf(&video->vbq, buf, file->f_flags & O_NONBLOCK);
+
+ video->buf_mask &= ~(1<<buf->index);
+ isp->video[FIMC_IS_VIDEO_NUM_3DNR].buf_mask = video->buf_mask;
+
+ dbg("index(%d) mask(0x%08x)\n", buf->index, video->buf_mask);
+
+ return vb_ret;
+}
+
+static int fimc_is_3dnr_video_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct fimc_is_dev *isp = video_drvdata(file);
+
+ dbg("%s\n", __func__);
+ return vb2_streamon(&isp->video[FIMC_IS_VIDEO_NUM_3DNR].vbq, type);
+}
+
+static int fimc_is_3dnr_video_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct fimc_is_dev *isp = video_drvdata(file);
+
+ dbg("%s\n", __func__);
+ return vb2_streamoff(&isp->video[FIMC_IS_VIDEO_NUM_3DNR].vbq, type);
+}
+
+static int fimc_is_3dnr_video_enum_input(struct file *file, void *priv,
+ struct v4l2_input *input)
+{
+ struct fimc_is_dev *isp = video_drvdata(file);
+ struct exynos5_fimc_is_sensor_info *sensor_info
+ = isp->pdata->sensor_info[input->index];
+
+ dbg("index(%d) sensor(%s)\n",
+ input->index, sensor_info->sensor_name);
+ dbg("pos(%d) sensor_id(%d)\n",
+ sensor_info->sensor_position, sensor_info->sensor_id);
+ dbg("csi_id(%d) flite_id(%d)\n",
+ sensor_info->csi_id, sensor_info->flite_id);
+ dbg("i2c_ch(%d)\n", sensor_info->i2c_channel);
+
+ if (input->index >= FIMC_IS_MAX_CAMIF_CLIENTS)
+ return -EINVAL;
+
+ input->type = V4L2_INPUT_TYPE_CAMERA;
+
+ strncpy(input->name, sensor_info->sensor_name,
+ FIMC_IS_MAX_NAME_LEN);
+ return 0;
+}
+
+static int fimc_is_3dnr_video_g_input(struct file *file, void *priv,
+ unsigned int *input)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_3dnr_video_s_input(struct file *file, void *priv,
+ unsigned int input)
+{
+ struct fimc_is_dev *isp = video_drvdata(file);
+ struct exynos5_fimc_is_sensor_info *sensor_info
+ = isp->pdata->sensor_info[input];
+
+ isp->sensor.id_position = input;
+ isp->sensor.sensor_type
+ = fimc_is_hw_get_sensor_type(sensor_info->sensor_id,
+ sensor_info->flite_id);
+
+ fimc_is_hw_set_default_size(isp, sensor_info->sensor_id);
+
+ dbg("sensor info : pos(%d) type(%d)\n", input, isp->sensor.sensor_type);
+
+
+ return 0;
+}
+
+const struct v4l2_file_operations fimc_is_3dnr_video_fops = {
+ .owner = THIS_MODULE,
+ .open = fimc_is_3dnr_video_open,
+ .release = fimc_is_3dnr_video_close,
+ .poll = fimc_is_3dnr_video_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = fimc_is_3dnr_video_mmap,
+};
+
+const struct v4l2_ioctl_ops fimc_is_3dnr_video_ioctl_ops = {
+ .vidioc_querycap = fimc_is_3dnr_video_querycap,
+ .vidioc_enum_fmt_vid_cap_mplane = fimc_is_3dnr_video_enum_fmt_mplane,
+ .vidioc_g_fmt_vid_cap_mplane = fimc_is_3dnr_video_get_format_mplane,
+ .vidioc_s_fmt_vid_cap_mplane = fimc_is_3dnr_video_set_format_mplane,
+ .vidioc_try_fmt_vid_cap_mplane = fimc_is_3dnr_video_try_format_mplane,
+ .vidioc_cropcap = fimc_is_3dnr_video_cropcap,
+ .vidioc_g_crop = fimc_is_3dnr_video_get_crop,
+ .vidioc_s_crop = fimc_is_3dnr_video_set_crop,
+ .vidioc_reqbufs = fimc_is_3dnr_video_reqbufs,
+ .vidioc_querybuf = fimc_is_3dnr_video_querybuf,
+ .vidioc_qbuf = fimc_is_3dnr_video_qbuf,
+ .vidioc_dqbuf = fimc_is_3dnr_video_dqbuf,
+ .vidioc_streamon = fimc_is_3dnr_video_streamon,
+ .vidioc_streamoff = fimc_is_3dnr_video_streamoff,
+ .vidioc_enum_input = fimc_is_3dnr_video_enum_input,
+ .vidioc_g_input = fimc_is_3dnr_video_g_input,
+ .vidioc_s_input = fimc_is_3dnr_video_s_input,
+};
+
+static int fimc_is_3dnr_queue_setup(struct vb2_queue *vq,
+ const struct v4l2_format *fmt,
+ unsigned int *num_buffers,
+ unsigned int *num_planes, unsigned int sizes[],
+ void *allocators[])
+{
+
+ struct fimc_is_video_dev *video = vq->drv_priv;
+ struct fimc_is_dev *isp = video->dev;
+ int i;
+
+ *num_planes = isp->video[FIMC_IS_VIDEO_NUM_3DNR].
+ frame.format.num_planes;
+ set_plane_size(&isp->video[FIMC_IS_VIDEO_NUM_3DNR].frame, sizes);
+
+ for (i = 0; i < *num_planes; i++)
+ allocators[i] = isp->alloc_ctx;
+
+ dbg("(num_planes : %d)(size : %d)\n", (int)*num_planes, (int)sizes[0]);
+
+ return 0;
+}
+
+static int fimc_is_3dnr_buffer_prepare(struct vb2_buffer *vb)
+{
+ dbg("--%s\n", __func__);
+ return 0;
+}
+
+static inline void fimc_is_3dnr_lock(struct vb2_queue *vq)
+{
+ dbg("%s\n", __func__);
+}
+
+static inline void fimc_is_3dnr_unlock(struct vb2_queue *vq)
+{
+ dbg("%s\n", __func__);
+}
+
+static int fimc_is_3dnr_start_streaming(struct vb2_queue *q,
+ unsigned int count)
+{
+ struct fimc_is_video_dev *video = q->drv_priv;
+ struct fimc_is_dev *isp = video->dev;
+ int ret;
+ int i, j;
+ int buf_index;
+
+ dbg("%s(pipe_state : %d)\n", __func__, (int)isp->pipe_state);
+
+ if (test_bit(FIMC_IS_STATE_FW_DOWNLOADED, &isp->pipe_state) &&
+ !test_bit(FIMC_IS_STATE_SENSOR_INITIALIZED, &isp->pipe_state)) {
+
+ dbg("IS_ST_CHANGE_MODE\n");
+ set_bit(IS_ST_CHANGE_MODE, &isp->state);
+ fimc_is_hw_change_mode(isp, IS_MODE_PREVIEW_STILL);
+ mutex_lock(&isp->lock);
+ ret = wait_event_timeout(isp->irq_queue,
+ test_bit(IS_ST_CHANGE_MODE_DONE,
+ &isp->state),
+ FIMC_IS_SHUTDOWN_TIMEOUT);
+ mutex_unlock(&isp->lock);
+ if (!ret) {
+ dev_err(&isp->pdev->dev,
+ "Mode change timeout:%s\n", __func__);
+ return -EBUSY;
+ }
+
+ set_bit(FIMC_IS_STATE_SENSOR_INITIALIZED, &isp->pipe_state);
+ }
+
+ if (test_bit(FIMC_IS_STATE_SENSOR_INITIALIZED, &isp->pipe_state) &&
+ test_bit(FIMC_IS_STATE_3DNR_BUFFER_PREPARED,
+ &isp->pipe_state) &&
+ !test_bit(FIMC_IS_STATE_HW_STREAM_ON, &isp->pipe_state)) {
+ dbg("IS Stream On\n");
+ fimc_is_hw_set_stream(isp, 1);
+ mutex_lock(&isp->lock);
+ ret = wait_event_timeout(isp->irq_queue,
+ test_bit(IS_ST_STREAM_ON, &isp->state),
+ FIMC_IS_SHUTDOWN_TIMEOUT);
+ mutex_unlock(&isp->lock);
+ if (!ret) {
+ dev_err(&isp->pdev->dev,
+ "wait timeout : %s\n", __func__);
+ return -EBUSY;
+ }
+ clear_bit(IS_ST_STREAM_ON, &isp->state);
+
+ set_bit(FIMC_IS_STATE_HW_STREAM_ON, &isp->pipe_state);
+ }
+
+ if (test_bit(FIMC_IS_STATE_3DNR_BUFFER_PREPARED, &isp->pipe_state) &&
+ test_bit(FIMC_IS_STATE_HW_STREAM_ON, &isp->pipe_state) &&
+ test_bit(FIMC_IS_STATE_SENSOR_INITIALIZED, &isp->pipe_state)) {
+ /* buffer addr setting */
+ for (i = 0; i < isp->video[FIMC_IS_VIDEO_NUM_3DNR].num_buf; i++)
+ for (j = 0; j < isp->video[FIMC_IS_VIDEO_NUM_3DNR].
+ frame.format.num_planes; j++) {
+ buf_index
+ = i * isp->video[FIMC_IS_VIDEO_NUM_3DNR].
+ frame.format.num_planes + j;
+ dbg("(%d)set buf(%d:%d) = 0x%08x\n",
+ buf_index, i, j,
+ isp->video[FIMC_IS_VIDEO_NUM_3DNR].
+ buf[i][j]);
+ isp->is_p_region->shared[350+buf_index]
+ = isp->video[FIMC_IS_VIDEO_NUM_3DNR].buf[i][j];
+ }
+
+ dbg("buf_num:%d buf_plane:%d shared[350] : 0x%p\n",
+ isp->video[FIMC_IS_VIDEO_NUM_3DNR].num_buf,
+ isp->video[FIMC_IS_VIDEO_NUM_3DNR].
+ frame.format.num_planes,
+ isp->mem.kvaddr_shared + 350 * sizeof(u32));
+ for (i = 0; i < isp->video[FIMC_IS_VIDEO_NUM_3DNR].num_buf; i++)
+ isp->video[FIMC_IS_VIDEO_NUM_3DNR].buf_mask |= (1 << i);
+ dbg("initial buffer mask : 0x%08x\n",
+ isp->video[FIMC_IS_VIDEO_NUM_3DNR].buf_mask);
+
+ IS_TDNR_SET_PARAM_DMA_OUTPUT_CMD(isp,
+ DMA_OUTPUT_COMMAND_ENABLE);
+ IS_TDNR_SET_PARAM_DMA_OUTPUT_MASK(isp,
+ isp->video[FIMC_IS_VIDEO_NUM_3DNR].buf_mask);
+ IS_TDNR_SET_PARAM_DMA_OUTPUT_BUFFERNUM(isp,
+ isp->video[FIMC_IS_VIDEO_NUM_3DNR].num_buf);
+ IS_TDNR_SET_PARAM_DMA_OUTPUT_BUFFERADDR(isp,
+ (u32)isp->mem.dvaddr_shared + 350*sizeof(u32));
+
+ IS_SET_PARAM_BIT(isp, PARAM_TDNR_DMA_OUTPUT);
+ IS_INC_PARAM_NUM(isp);
+
+ fimc_is_mem_cache_clean((void *)isp->is_p_region,
+ IS_PARAM_SIZE);
+
+ isp->scenario_id = ISS_PREVIEW_STILL;
+ set_bit(IS_ST_INIT_PREVIEW_STILL, &isp->state);
+ clear_bit(IS_ST_INIT_CAPTURE_STILL, &isp->state);
+ clear_bit(IS_ST_INIT_PREVIEW_VIDEO, &isp->state);
+ fimc_is_hw_set_param(isp);
+ mutex_lock(&isp->lock);
+ ret = wait_event_timeout(isp->irq_queue,
+ test_bit(IS_ST_INIT_PREVIEW_VIDEO, &isp->state),
+ FIMC_IS_SHUTDOWN_TIMEOUT);
+ mutex_unlock(&isp->lock);
+ if (!ret) {
+ dev_err(&isp->pdev->dev,
+ "wait timeout : %s\n", __func__);
+ return -EBUSY;
+ }
+
+ set_bit(FIMC_IS_STATE_3DNR_STREAM_ON, &isp->pipe_state);
+ }
+
+ return 0;
+}
+
+static int fimc_is_3dnr_stop_streaming(struct vb2_queue *q)
+{
+ struct fimc_is_video_dev *video = q->drv_priv;
+ struct fimc_is_dev *isp = video->dev;
+ int ret;
+
+
+
+ clear_bit(IS_ST_STREAM_OFF, &isp->state);
+ fimc_is_hw_set_stream(isp, 0);
+ mutex_lock(&isp->lock);
+ ret = wait_event_timeout(isp->irq_queue,
+ test_bit(IS_ST_STREAM_OFF, &isp->state),
+ FIMC_IS_SHUTDOWN_TIMEOUT);
+ mutex_unlock(&isp->lock);
+ if (!ret) {
+ dev_err(&isp->pdev->dev,
+ "wait timeout : %s\n", __func__);
+ if (!ret)
+ err("s_power off failed!!\n");
+ return -EBUSY;
+ }
+
+ IS_TDNR_SET_PARAM_DMA_OUTPUT_CMD(isp,
+ DMA_OUTPUT_COMMAND_DISABLE);
+ IS_TDNR_SET_PARAM_DMA_OUTPUT_BUFFERNUM(isp,
+ 0);
+ IS_TDNR_SET_PARAM_DMA_OUTPUT_BUFFERADDR(isp,
+ 0);
+
+ IS_SET_PARAM_BIT(isp, PARAM_TDNR_DMA_OUTPUT);
+ IS_INC_PARAM_NUM(isp);
+
+ fimc_is_mem_cache_clean((void *)isp->is_p_region,
+ IS_PARAM_SIZE);
+
+ isp->scenario_id = ISS_PREVIEW_STILL;
+ set_bit(IS_ST_INIT_PREVIEW_STILL, &isp->state);
+ clear_bit(IS_ST_INIT_PREVIEW_VIDEO, &isp->state);
+ fimc_is_hw_set_param(isp);
+
+ mutex_lock(&isp->lock);
+ ret = wait_event_timeout(isp->irq_queue,
+ test_bit(IS_ST_INIT_PREVIEW_VIDEO, &isp->state),
+ FIMC_IS_SHUTDOWN_TIMEOUT);
+ mutex_unlock(&isp->lock);
+ if (!ret) {
+ dev_err(&isp->pdev->dev,
+ "wait timeout 1: %s\n", __func__);
+ return -EBUSY;
+ }
+
+
+ dbg("IS change mode\n");
+ clear_bit(IS_ST_RUN, &isp->state);
+ set_bit(IS_ST_CHANGE_MODE, &isp->state);
+ fimc_is_hw_change_mode(isp, IS_MODE_PREVIEW_STILL);
+ mutex_lock(&isp->lock);
+ ret = wait_event_timeout(isp->irq_queue,
+ test_bit(IS_ST_CHANGE_MODE_DONE, &isp->state),
+ FIMC_IS_SHUTDOWN_TIMEOUT);
+ mutex_unlock(&isp->lock);
+ if (!ret) {
+ dev_err(&isp->pdev->dev,
+ "Mode change timeout:%s\n", __func__);
+ return -EBUSY;
+ }
+
+ dbg("IS Stream On");
+ fimc_is_hw_set_stream(isp, 1);
+
+ mutex_lock(&isp->lock);
+ ret = wait_event_timeout(isp->irq_queue,
+ test_bit(IS_ST_STREAM_ON, &isp->state),
+ FIMC_IS_SHUTDOWN_TIMEOUT);
+ mutex_unlock(&isp->lock);
+ if (!ret) {
+ dev_err(&isp->pdev->dev,
+ "wait timeout : %s\n", __func__);
+ return -EBUSY;
+ }
+ clear_bit(IS_ST_STREAM_ON, &isp->state);
+
+
+ if (!test_bit(FIMC_IS_STATE_SCALERC_STREAM_ON, &isp->pipe_state) &&
+ !test_bit(FIMC_IS_STATE_SCALERP_STREAM_ON, &isp->pipe_state)) {
+ clear_bit(IS_ST_STREAM_OFF, &isp->state);
+ fimc_is_hw_set_stream(isp, 0);
+ dbg("IS Stream Off");
+ mutex_lock(&isp->lock);
+ ret = wait_event_timeout(isp->irq_queue,
+ test_bit(IS_ST_STREAM_OFF, &isp->state),
+ FIMC_IS_SHUTDOWN_TIMEOUT);
+ mutex_unlock(&isp->lock);
+ if (!ret) {
+ dev_err(&isp->pdev->dev,
+ "wait timeout 4: %s\n", __func__);
+ return -EBUSY;
+ }
+ clear_bit(FIMC_IS_STATE_HW_STREAM_ON, &isp->pipe_state);
+ }
+
+ clear_bit(IS_ST_RUN, &isp->state);
+ clear_bit(IS_ST_STREAM_ON, &isp->state);
+ clear_bit(FIMC_IS_STATE_3DNR_BUFFER_PREPARED, &isp->pipe_state);
+ clear_bit(FIMC_IS_STATE_3DNR_STREAM_ON, &isp->pipe_state);
+
+
+ return 0;
+}
+
+static void fimc_is_3dnr_buffer_queue(struct vb2_buffer *vb)
+{
+ struct fimc_is_video_dev *video = vb->vb2_queue->drv_priv;
+ struct fimc_is_dev *isp = video->dev;
+ unsigned int i;
+
+ dbg("%s\n", __func__);
+ isp->video[FIMC_IS_VIDEO_NUM_3DNR].frame.format.num_planes
+ = vb->num_planes;
+
+ if (!test_bit(FIMC_IS_STATE_3DNR_BUFFER_PREPARED, &isp->pipe_state)) {
+ for (i = 0; i < vb->num_planes; i++) {
+ isp->video[FIMC_IS_VIDEO_NUM_3DNR].
+ buf[vb->v4l2_buf.index][i]
+ = isp->vb2->plane_addr(vb, i);
+ dbg("index(%d)(%d) deviceVaddr(0x%08x)\n",
+ vb->v4l2_buf.index, i,
+ isp->video[FIMC_IS_VIDEO_NUM_3DNR].
+ buf[vb->v4l2_buf.index][i]);
+ }
+
+ isp->video[FIMC_IS_VIDEO_NUM_3DNR].buf_ref_cnt++;
+
+ if (isp->video[FIMC_IS_VIDEO_NUM_3DNR].num_buf
+ == isp->video[FIMC_IS_VIDEO_NUM_3DNR].buf_ref_cnt)
+ set_bit(FIMC_IS_STATE_3DNR_BUFFER_PREPARED,
+ &isp->pipe_state);
+ }
+
+ if (!test_bit(FIMC_IS_STATE_3DNR_STREAM_ON, &isp->pipe_state))
+ fimc_is_3dnr_start_streaming(vb->vb2_queue,
+ isp->video[FIMC_IS_VIDEO_NUM_3DNR].num_buf);
+
+ return;
+}
+
+const struct vb2_ops fimc_is_3dnr_qops = {
+ .queue_setup = fimc_is_3dnr_queue_setup,
+ .buf_prepare = fimc_is_3dnr_buffer_prepare,
+ .buf_queue = fimc_is_3dnr_buffer_queue,
+ .wait_prepare = fimc_is_3dnr_unlock,
+ .wait_finish = fimc_is_3dnr_lock,
+ .start_streaming = fimc_is_3dnr_start_streaming,
+ .stop_streaming = fimc_is_3dnr_stop_streaming,
+};
+
+
+/*************************************************************************/
+/* video file opertation */
+/************************************************************************/
+
+static int fimc_is_bayer_video_open(struct file *file)
+{
+ struct fimc_is_dev *isp = video_drvdata(file);
+
+ dbg("%s\n", __func__);
+ file->private_data = &isp->video[FIMC_IS_VIDEO_NUM_BAYER];
+ isp->video[FIMC_IS_VIDEO_NUM_BAYER].num_buf = 0;
+ isp->video[FIMC_IS_VIDEO_NUM_BAYER].buf_ref_cnt = 0;
+
+ if (!test_bit(FIMC_IS_STATE_FW_DOWNLOADED, &isp->pipe_state)) {
+ isp->sensor_num = 1;
+
+ fimc_is_load_fw(isp);
+
+ set_bit(FIMC_IS_STATE_FW_DOWNLOADED, &isp->pipe_state);
+ clear_bit(FIMC_IS_STATE_SENSOR_INITIALIZED, &isp->pipe_state);
+ clear_bit(FIMC_IS_STATE_HW_STREAM_ON, &isp->pipe_state);
+ }
+
+ clear_bit(FIMC_IS_STATE_BAYER_STREAM_ON, &isp->pipe_state);
+ fimc_is_fw_clear_irq1_all(isp);
+ return 0;
+
+}
+
+static int fimc_is_bayer_video_close(struct file *file)
+{
+ struct fimc_is_dev *isp = video_drvdata(file);
+ int ret;
+
+ dbg("%s\n", __func__);
+ vb2_queue_release(&isp->video[FIMC_IS_VIDEO_NUM_BAYER].vbq);
+
+ if (!test_bit(FIMC_IS_STATE_SCALERP_STREAM_ON, &isp->pipe_state) &&
+ !test_bit(FIMC_IS_STATE_SCALERC_STREAM_ON, &isp->pipe_state) &&
+ !test_bit(FIMC_IS_STATE_3DNR_STREAM_ON, &isp->pipe_state) &&
+ test_bit(FIMC_IS_STATE_FW_DOWNLOADED, &isp->power)) {
+ clear_bit(FIMC_IS_STATE_HW_STREAM_ON, &isp->pipe_state);
+ fimc_is_hw_subip_poweroff(isp);
+
+ mutex_lock(&isp->lock);
+ ret = wait_event_timeout(isp->irq_queue,
+ !test_bit(FIMC_IS_PWR_ST_POWER_ON_OFF, &isp->power),
+ FIMC_IS_SHUTDOWN_TIMEOUT_SENSOR);
+ mutex_unlock(&isp->lock);
+
+ if (!ret) {
+ err("wait timeout : %s\n", __func__);
+ ret = -EINVAL;
+ }
+
+ dbg("staop flite & mipi (pos:%d) (port:%d)\n",
+ isp->sensor.id_position,
+ isp->pdata->
+ sensor_info[isp->sensor.id_position]->flite_id);
+
+ stop_fimc_lite(isp->pdata->
+ sensor_info[isp->sensor.id_position]->flite_id);
+ stop_mipi_csi(isp->pdata->
+ sensor_info[isp->sensor.id_position]->csi_id);
+
+ fimc_is_hw_a5_power(isp, 0);
+ clear_bit(FIMC_IS_STATE_FW_DOWNLOADED, &isp->pipe_state);
+ }
+ return 0;
+
+}
+
+static unsigned int fimc_is_bayer_video_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct fimc_is_dev *isp = video_drvdata(file);
+
+ dbg("%s\n", __func__);
+ return vb2_poll(&isp->video[FIMC_IS_VIDEO_NUM_BAYER].vbq, file, wait);
+
+}
+
+static int fimc_is_bayer_video_mmap(struct file *file,
+ struct vm_area_struct *vma)
+{
+ struct fimc_is_dev *isp = video_drvdata(file);
+
+ dbg("%s\n", __func__);
+ return vb2_mmap(&isp->video[FIMC_IS_VIDEO_NUM_BAYER].vbq, vma);
+
+}
+
+/*************************************************************************/
+/* video ioctl operation */
+/************************************************************************/
+
+static int fimc_is_bayer_video_querycap(struct file *file, void *fh,
+ struct v4l2_capability *cap)
+{
+ struct fimc_is_dev *isp = video_drvdata(file);
+
+ strncpy(cap->driver, isp->pdev->name, sizeof(cap->driver) - 1);
+
+ dbg("%s(devname : %s)\n", __func__, cap->driver);
+ strncpy(cap->card, isp->pdev->name, sizeof(cap->card) - 1);
+ cap->bus_info[0] = 0;
+ cap->version = KERNEL_VERSION(1, 0, 0);
+ cap->capabilities = V4L2_CAP_STREAMING
+ | V4L2_CAP_VIDEO_CAPTURE
+ | V4L2_CAP_VIDEO_CAPTURE_MPLANE;
+
+ return 0;
+}
+
+static int fimc_is_bayer_video_enum_fmt_mplane(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_bayer_video_get_format_mplane(struct file *file, void *fh,
+ struct v4l2_format *format)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_bayer_video_set_format_mplane(struct file *file, void *fh,
+ struct v4l2_format *format)
+{
+ struct fimc_is_dev *isp = video_drvdata(file);
+ struct v4l2_pix_format_mplane *pix;
+ struct fimc_is_fmt *frame;
+
+ dbg("%s\n", __func__);
+
+ pix = &format->fmt.pix_mp;
+ frame = find_format(&pix->pixelformat, NULL, 0);
+
+ if (!frame)
+ return -EINVAL;
+
+ isp->video[FIMC_IS_VIDEO_NUM_BAYER].frame.format.pixelformat
+ = frame->pixelformat;
+ isp->video[FIMC_IS_VIDEO_NUM_BAYER].frame.format.mbus_code
+ = frame->mbus_code;
+ isp->video[FIMC_IS_VIDEO_NUM_BAYER].frame.format.num_planes
+ = frame->num_planes;
+ isp->video[FIMC_IS_VIDEO_NUM_BAYER].frame.width = pix->width;
+ isp->video[FIMC_IS_VIDEO_NUM_BAYER].frame.height = pix->height;
+ dbg("num_planes : %d\n", frame->num_planes);
+ dbg("width : %d\n", pix->width);
+ dbg("height : %d\n", pix->height);
+
+ return 0;
+}
+
+static int fimc_is_bayer_video_try_format_mplane(struct file *file, void *fh,
+ struct v4l2_format *format)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_bayer_video_cropcap(struct file *file, void *fh,
+ struct v4l2_cropcap *cropcap)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_bayer_video_get_crop(struct file *file, void *fh,
+ struct v4l2_crop *crop)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_bayer_video_set_crop(struct file *file, void *fh,
+ struct v4l2_crop *crop)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_bayer_video_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *buf)
+{
+ int ret;
+ struct fimc_is_video_dev *video = file->private_data;
+ struct fimc_is_dev *isp = video_drvdata(file);
+
+ dbg("%s\n", __func__);
+ ret = vb2_reqbufs(&video->vbq, buf);
+ if (!ret)
+ isp->video[FIMC_IS_VIDEO_NUM_BAYER].num_buf = buf->count;
+
+ if (buf->count == 0)
+ isp->video[FIMC_IS_VIDEO_NUM_BAYER].buf_ref_cnt = 0;
+
+ dbg("%s(num_buf | %d)\n", __func__,
+ isp->video[FIMC_IS_VIDEO_NUM_BAYER].num_buf);
+
+ return ret;
+}
+
+static int fimc_is_bayer_video_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ int ret;
+ struct fimc_is_video_dev *video = file->private_data;
+
+ dbg("%s\n", __func__);
+ ret = vb2_querybuf(&video->vbq, buf);
+
+ return ret;
+}
+
+static int fimc_is_bayer_video_qbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ int vb_ret;
+ struct fimc_is_video_dev *video = file->private_data;
+ struct fimc_is_dev *isp = video_drvdata(file);
+
+ if (test_bit(FIMC_IS_STATE_BAYER_BUFFER_PREPARED, &isp->pipe_state)) {
+ video->buf_mask |= (1<<buf->index);
+ isp->video[FIMC_IS_VIDEO_NUM_BAYER].buf_mask = video->buf_mask;
+
+ dbg("index(%d) mask(0x%08x)\n", buf->index, video->buf_mask);
+ } else {
+ dbg("index(%d)\n", buf->index);
+ }
+ vb_ret = vb2_qbuf(&video->vbq, buf);
+
+ return vb_ret;
+}
+
+static int fimc_is_bayer_video_dqbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ int vb_ret;
+ struct fimc_is_video_dev *video = file->private_data;
+ struct fimc_is_dev *isp = video_drvdata(file);
+
+ vb_ret = vb2_dqbuf(&video->vbq, buf, file->f_flags & O_NONBLOCK);
+
+ video->buf_mask &= ~(1<<buf->index);
+ isp->video[FIMC_IS_VIDEO_NUM_BAYER].buf_mask = video->buf_mask;
+
+ dbg("index(%d) mask(0x%08x)\n", buf->index, video->buf_mask);
+
+ return vb_ret;
+}
+
+static int fimc_is_bayer_video_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct fimc_is_dev *isp = video_drvdata(file);
+
+ dbg("%s\n", __func__);
+ return vb2_streamon(&isp->video[FIMC_IS_VIDEO_NUM_BAYER].vbq, type);
+}
+
+static int fimc_is_bayer_video_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct fimc_is_dev *isp = video_drvdata(file);
+
+ dbg("%s\n", __func__);
+ return vb2_streamoff(&isp->video[FIMC_IS_VIDEO_NUM_BAYER].vbq, type);
+}
+
+static int fimc_is_bayer_video_enum_input(struct file *file, void *priv,
+ struct v4l2_input *input)
+{
+ struct fimc_is_dev *isp = video_drvdata(file);
+ struct exynos5_fimc_is_sensor_info *sensor_info
+ = isp->pdata->sensor_info[input->index];
+
+ dbg("index(%d) sensor(%s)\n",
+ input->index, sensor_info->sensor_name);
+ dbg("pos(%d) sensor_id(%d)\n",
+ sensor_info->sensor_position, sensor_info->sensor_id);
+ dbg("csi_id(%d) flite_id(%d)\n",
+ sensor_info->csi_id, sensor_info->flite_id);
+ dbg("i2c_ch(%d)\n", sensor_info->i2c_channel);
+
+ if (input->index >= FIMC_IS_MAX_CAMIF_CLIENTS)
+ return -EINVAL;
+
+ input->type = V4L2_INPUT_TYPE_CAMERA;
+
+ strncpy(input->name, sensor_info->sensor_name,
+ FIMC_IS_MAX_NAME_LEN);
+ return 0;
+}
+
+static int fimc_is_bayer_video_g_input(struct file *file, void *priv,
+ unsigned int *input)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_bayer_video_s_input(struct file *file, void *priv,
+ unsigned int input)
+{
+ struct fimc_is_dev *isp = video_drvdata(file);
+ struct exynos5_fimc_is_sensor_info *sensor_info
+ = isp->pdata->sensor_info[input];
+
+ isp->sensor.id_position = input;
+ isp->sensor.sensor_type
+ = fimc_is_hw_get_sensor_type(sensor_info->sensor_id,
+ sensor_info->flite_id);
+
+ fimc_is_hw_set_default_size(isp, sensor_info->sensor_id);
+
+ dbg("sensor info : pos(%d) type(%d)\n", input, isp->sensor.sensor_type);
+
+
+ return 0;
+}
+
+const struct v4l2_file_operations fimc_is_bayer_video_fops = {
+ .owner = THIS_MODULE,
+ .open = fimc_is_bayer_video_open,
+ .release = fimc_is_bayer_video_close,
+ .poll = fimc_is_bayer_video_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = fimc_is_bayer_video_mmap,
+};
+
+const struct v4l2_ioctl_ops fimc_is_bayer_video_ioctl_ops = {
+ .vidioc_querycap = fimc_is_bayer_video_querycap,
+ .vidioc_enum_fmt_vid_cap_mplane = fimc_is_bayer_video_enum_fmt_mplane,
+ .vidioc_g_fmt_vid_cap_mplane = fimc_is_bayer_video_get_format_mplane,
+ .vidioc_s_fmt_vid_cap_mplane = fimc_is_bayer_video_set_format_mplane,
+ .vidioc_try_fmt_vid_cap_mplane = fimc_is_bayer_video_try_format_mplane,
+ .vidioc_cropcap = fimc_is_bayer_video_cropcap,
+ .vidioc_g_crop = fimc_is_bayer_video_get_crop,
+ .vidioc_s_crop = fimc_is_bayer_video_set_crop,
+ .vidioc_reqbufs = fimc_is_bayer_video_reqbufs,
+ .vidioc_querybuf = fimc_is_bayer_video_querybuf,
+ .vidioc_qbuf = fimc_is_bayer_video_qbuf,
+ .vidioc_dqbuf = fimc_is_bayer_video_dqbuf,
+ .vidioc_streamon = fimc_is_bayer_video_streamon,
+ .vidioc_streamoff = fimc_is_bayer_video_streamoff,
+ .vidioc_enum_input = fimc_is_bayer_video_enum_input,
+ .vidioc_g_input = fimc_is_bayer_video_g_input,
+ .vidioc_s_input = fimc_is_bayer_video_s_input,
+};
+
+static int fimc_is_bayer_queue_setup(struct vb2_queue *vq,
+ const struct v4l2_format *fmt,
+ unsigned int *num_buffers,
+ unsigned int *num_planes, unsigned int sizes[],
+ void *allocators[])
+{
+
+ struct fimc_is_video_dev *video = vq->drv_priv;
+ struct fimc_is_dev *isp = video->dev;
+ int i;
+
+ *num_planes = isp->video[FIMC_IS_VIDEO_NUM_BAYER].
+ frame.format.num_planes;
+ set_plane_size(&isp->video[FIMC_IS_VIDEO_NUM_BAYER].frame, sizes);
+
+ for (i = 0; i < *num_planes; i++)
+ allocators[i] = isp->alloc_ctx;
+
+ dbg("(num_planes : %d)(size : %d)\n", (int)*num_planes, (int)sizes[0]);
+
+ return 0;
+}
+
+static int fimc_is_bayer_buffer_prepare(struct vb2_buffer *vb)
+{
+ dbg("--%s\n", __func__);
+ return 0;
+}
+
+static inline void fimc_is_bayer_lock(struct vb2_queue *vq)
+{
+ dbg("%s\n", __func__);
+}
+
+static inline void fimc_is_bayer_unlock(struct vb2_queue *vq)
+{
+ dbg("%s\n", __func__);
+}
+
+static int fimc_is_bayer_start_streaming(struct vb2_queue *q,
+ unsigned int count)
+{
+ struct fimc_is_video_dev *video = q->drv_priv;
+ struct fimc_is_dev *isp = video->dev;
+ int ret;
+ int i, j;
+ int buf_index;
+
+ dbg("%s(pipe_state : %d)\n", __func__, (int)isp->pipe_state);
+
+ if (test_bit(FIMC_IS_STATE_FW_DOWNLOADED, &isp->pipe_state) &&
+ !test_bit(FIMC_IS_STATE_SENSOR_INITIALIZED,
+ &isp->pipe_state)) {
+
+ dbg("IS_ST_CHANGE_MODE\n");
+ set_bit(IS_ST_CHANGE_MODE, &isp->state);
+ fimc_is_hw_change_mode(isp, IS_MODE_PREVIEW_STILL);
+ mutex_lock(&isp->lock);
+ ret = wait_event_timeout(isp->irq_queue,
+ test_bit(IS_ST_CHANGE_MODE_DONE,
+ &isp->state),
+ FIMC_IS_SHUTDOWN_TIMEOUT);
+ mutex_unlock(&isp->lock);
+ if (!ret) {
+ dev_err(&isp->pdev->dev,
+ "Mode change timeout:%s\n", __func__);
+ return -EBUSY;
+ }
+
+ set_bit(FIMC_IS_STATE_SENSOR_INITIALIZED, &isp->pipe_state);
+ }
+
+ if (test_bit(FIMC_IS_STATE_SENSOR_INITIALIZED, &isp->pipe_state) &&
+ test_bit(FIMC_IS_STATE_BAYER_BUFFER_PREPARED,
+ &isp->pipe_state) &&
+ !test_bit(FIMC_IS_STATE_HW_STREAM_ON, &isp->pipe_state)) {
+ dbg("IS Stream On\n");
+ fimc_is_hw_set_stream(isp, 1);
+ mutex_lock(&isp->lock);
+ ret = wait_event_timeout(isp->irq_queue,
+ test_bit(IS_ST_STREAM_ON, &isp->state),
+ FIMC_IS_SHUTDOWN_TIMEOUT);
+ mutex_unlock(&isp->lock);
+ if (!ret) {
+ dev_err(&isp->pdev->dev,
+ "wait timeout : %s\n", __func__);
+ return -EBUSY;
+ }
+ clear_bit(IS_ST_STREAM_ON, &isp->state);
+
+ set_bit(FIMC_IS_STATE_HW_STREAM_ON, &isp->pipe_state);
+ }
+
+ if (test_bit(FIMC_IS_STATE_BAYER_BUFFER_PREPARED, &isp->pipe_state) &&
+ test_bit(FIMC_IS_STATE_HW_STREAM_ON, &isp->pipe_state) &&
+ test_bit(FIMC_IS_STATE_SENSOR_INITIALIZED, &isp->pipe_state)) {
+ /* buffer addr setting */
+ for (i = 0; i < isp->
+ video[FIMC_IS_VIDEO_NUM_BAYER].num_buf; i++)
+ for (j = 0; j < isp->video[FIMC_IS_VIDEO_NUM_BAYER].
+ frame.format.num_planes; j++) {
+ buf_index = i * isp->
+ video[FIMC_IS_VIDEO_NUM_BAYER].
+ frame.format.num_planes + j;
+
+ dbg("(%d)set buf(%d:%d) = 0x%08x\n",
+ buf_index, i, j,
+ isp->video[FIMC_IS_VIDEO_NUM_BAYER].
+ buf[i][j]);
+
+ isp->is_p_region->shared[116 + buf_index]
+ = isp->video[FIMC_IS_VIDEO_NUM_BAYER].buf[i][j];
+ }
+
+ dbg("buf_num:%d buf_plane:%d shared[116] : 0x%p\n",
+ isp->video[FIMC_IS_VIDEO_NUM_BAYER].num_buf,
+ isp->video[FIMC_IS_VIDEO_NUM_BAYER].frame.format.num_planes,
+ isp->mem.kvaddr_shared + 116 * sizeof(u32));
+
+ for (i = 0; i < isp->
+ video[FIMC_IS_VIDEO_NUM_BAYER].num_buf; i++)
+ isp->video[FIMC_IS_VIDEO_NUM_BAYER].buf_mask
+ |= (1 << i);
+
+ dbg("initial buffer mask : 0x%08x\n",
+ isp->video[FIMC_IS_VIDEO_NUM_BAYER].buf_mask);
+
+
+ IS_ISP_SET_PARAM_DMA_OUTPUT2_CMD(isp,
+ DMA_OUTPUT_COMMAND_ENABLE);
+ IS_ISP_SET_PARAM_DMA_OUTPUT2_MASK(isp,
+ isp->video[FIMC_IS_VIDEO_NUM_BAYER].buf_mask);
+ IS_ISP_SET_PARAM_DMA_OUTPUT2_BUFFER_NUMBER(isp,
+ isp->video[FIMC_IS_VIDEO_NUM_BAYER].num_buf);
+ IS_ISP_SET_PARAM_DMA_OUTPUT2_BUFFER_ADDRESS(isp,
+ (u32)isp->mem.dvaddr_shared + 116 * sizeof(u32));
+ IS_ISP_SET_PARAM_DMA_OUTPUT2_BUFFER_ADDRESS(isp,
+ (u32)isp->mem.dvaddr_shared + 116 * sizeof(u32));
+ IS_ISP_SET_PARAM_DMA_OUTPUT2_DMA_DONE(isp,
+ DMA_OUTPUT_NOTIFY_DMA_DONE_ENBABLE);
+
+ IS_SET_PARAM_BIT(isp, PARAM_ISP_DMA2_OUTPUT);
+ IS_INC_PARAM_NUM(isp);
+
+ fimc_is_mem_cache_clean((void *)isp->is_p_region,
+ IS_PARAM_SIZE);
+
+ isp->scenario_id = ISS_PREVIEW_STILL;
+ set_bit(IS_ST_INIT_PREVIEW_STILL, &isp->state);
+ clear_bit(IS_ST_INIT_CAPTURE_STILL, &isp->state);
+ clear_bit(IS_ST_INIT_PREVIEW_VIDEO, &isp->state);
+ fimc_is_hw_set_param(isp);
+ mutex_lock(&isp->lock);
+ ret = wait_event_timeout(isp->irq_queue,
+ test_bit(IS_ST_INIT_PREVIEW_VIDEO, &isp->state),
+ FIMC_IS_SHUTDOWN_TIMEOUT);
+ mutex_unlock(&isp->lock);
+ if (!ret) {
+ dev_err(&isp->pdev->dev,
+ "wait timeout : %s\n", __func__);
+ return -EBUSY;
+ }
+
+ set_bit(FIMC_IS_STATE_BAYER_STREAM_ON, &isp->pipe_state);
+ }
+
+ return 0;
+}
+
+static int fimc_is_bayer_stop_streaming(struct vb2_queue *q)
+{
+ struct fimc_is_video_dev *video = q->drv_priv;
+ struct fimc_is_dev *isp = video->dev;
+ int ret;
+
+
+ IS_ISP_SET_PARAM_DMA_OUTPUT2_CMD(isp,
+ DMA_OUTPUT_COMMAND_DISABLE);
+ IS_ISP_SET_PARAM_DMA_OUTPUT2_BUFFER_NUMBER(isp,
+ 0);
+ IS_ISP_SET_PARAM_DMA_OUTPUT2_BUFFER_ADDRESS(isp,
+ 0);
+
+ IS_SET_PARAM_BIT(isp, PARAM_ISP_DMA2_OUTPUT);
+ IS_INC_PARAM_NUM(isp);
+
+ fimc_is_mem_cache_clean((void *)isp->is_p_region,
+ IS_PARAM_SIZE);
+
+ isp->scenario_id = ISS_PREVIEW_STILL;
+ set_bit(IS_ST_INIT_PREVIEW_STILL, &isp->state);
+ clear_bit(IS_ST_INIT_PREVIEW_VIDEO, &isp->state);
+ fimc_is_hw_set_param(isp);
+ mutex_lock(&isp->lock);
+ ret = wait_event_timeout(isp->irq_queue,
+ test_bit(IS_ST_INIT_PREVIEW_VIDEO, &isp->state),
+ FIMC_IS_SHUTDOWN_TIMEOUT);
+ mutex_unlock(&isp->lock);
+ if (!ret) {
+ dev_err(&isp->pdev->dev,
+ "wait timeout : %s\n", __func__);
+ return -EBUSY;
+ }
+
+
+ if (!test_bit(FIMC_IS_STATE_SCALERC_STREAM_ON, &isp->pipe_state) &&
+ !test_bit(FIMC_IS_STATE_SCALERP_STREAM_ON, &isp->pipe_state)) {
+ clear_bit(IS_ST_STREAM_OFF, &isp->state);
+ fimc_is_hw_set_stream(isp, 0);
+ dbg("IS Stream Off");
+ mutex_lock(&isp->lock);
+ ret = wait_event_timeout(isp->irq_queue,
+ test_bit(IS_ST_STREAM_OFF, &isp->state),
+ FIMC_IS_SHUTDOWN_TIMEOUT);
+ mutex_unlock(&isp->lock);
+ if (!ret) {
+ dev_err(&isp->pdev->dev,
+ "wait timeout : %s\n", __func__);
+ return -EBUSY;
+ }
+ clear_bit(FIMC_IS_STATE_HW_STREAM_ON, &isp->pipe_state);
+ }
+
+ clear_bit(IS_ST_RUN, &isp->state);
+ clear_bit(IS_ST_STREAM_ON, &isp->state);
+ clear_bit(FIMC_IS_STATE_BAYER_BUFFER_PREPARED, &isp->pipe_state);
+ clear_bit(FIMC_IS_STATE_BAYER_STREAM_ON, &isp->pipe_state);
+
+
+ return 0;
+}
+
+static void fimc_is_bayer_buffer_queue(struct vb2_buffer *vb)
+{
+ struct fimc_is_video_dev *video = vb->vb2_queue->drv_priv;
+ struct fimc_is_dev *isp = video->dev;
+ unsigned int i;
+
+ dbg("%s\n", __func__);
+ isp->video[FIMC_IS_VIDEO_NUM_BAYER].frame.format.num_planes
+ = vb->num_planes;
+
+ if (!test_bit(FIMC_IS_STATE_BAYER_BUFFER_PREPARED, &isp->pipe_state)) {
+ for (i = 0; i < vb->num_planes; i++) {
+ isp->video[FIMC_IS_VIDEO_NUM_BAYER].
+ buf[vb->v4l2_buf.index][i]
+ = isp->vb2->plane_addr(vb, i);
+
+ dbg("index(%d)(%d) deviceVaddr(0x%08x)\n",
+ vb->v4l2_buf.index, i,
+ isp->video[FIMC_IS_VIDEO_NUM_BAYER].
+ buf[vb->v4l2_buf.index][i]);
+ }
+
+ isp->video[FIMC_IS_VIDEO_NUM_BAYER].buf_ref_cnt++;
+
+ if (isp->video[FIMC_IS_VIDEO_NUM_BAYER].num_buf
+ == isp->video[FIMC_IS_VIDEO_NUM_BAYER].buf_ref_cnt)
+ set_bit(FIMC_IS_STATE_BAYER_BUFFER_PREPARED,
+ &isp->pipe_state);
+ }
+
+ if (!test_bit(FIMC_IS_STATE_BAYER_STREAM_ON, &isp->pipe_state))
+ fimc_is_bayer_start_streaming(vb->vb2_queue,
+ isp->video[FIMC_IS_VIDEO_NUM_BAYER].num_buf);
+
+ return;
+}
+
+const struct vb2_ops fimc_is_bayer_qops = {
+ .queue_setup = fimc_is_bayer_queue_setup,
+ .buf_prepare = fimc_is_bayer_buffer_prepare,
+ .buf_queue = fimc_is_bayer_buffer_queue,
+ .wait_prepare = fimc_is_bayer_unlock,
+ .wait_finish = fimc_is_bayer_lock,
+ .start_streaming = fimc_is_bayer_start_streaming,
+ .stop_streaming = fimc_is_bayer_stop_streaming,
+};
diff --git a/drivers/media/video/exynos/fimc-is-mc2/Makefile b/drivers/media/video/exynos/fimc-is-mc2/Makefile
new file mode 100644
index 0000000..1aa1d04
--- /dev/null
+++ b/drivers/media/video/exynos/fimc-is-mc2/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_VIDEO_EXYNOS5_FIMC_IS2) += fimc-is-core.o fimc-is-framemgr.o fimc-is-video.o fimc-is-video-sensor.o fimc-is-video-isp.o fimc-is-video-scc.o fimc-is-video-scp.o fimc-is-mem.o fimc-is-device-flite.o fimc-is-device-sensor.o fimc-is-device-ischain.o fimc-is-interface.o fimc-is-time.o fimc-is-spi.o
diff --git a/drivers/media/video/exynos/fimc-is-mc2/fimc-is-cmd.h b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-cmd.h
new file mode 100644
index 0000000..ce0f5e8
--- /dev/null
+++ b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-cmd.h
@@ -0,0 +1,211 @@
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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.
+ */
+
+#ifndef FIMC_IS_CMD_H
+#define FIMC_IS_CMD_H
+
+#define IS_COMMAND_VER 122 /* IS COMMAND VERSION 1.22 */
+
+enum is_cmd {
+ /* HOST -> IS */
+ HIC_PREVIEW_STILL = 0x1,
+ HIC_PREVIEW_VIDEO,
+ HIC_CAPTURE_STILL,
+ HIC_CAPTURE_VIDEO,
+ HIC_PROCESS_START,
+ HIC_PROCESS_STOP,
+ HIC_STREAM_ON,
+ HIC_STREAM_OFF,
+ HIC_SHOT,
+ HIC_GET_STATIC_METADATA,
+ HIC_SET_CAM_CONTROL,
+ HIC_GET_CAM_CONTROL,
+ HIC_SET_PARAMETER,
+ HIC_GET_PARAMETER,
+ HIC_SET_A5_MEM_ACCESS,
+ RESERVED2,
+ HIC_GET_STATUS,
+ /* SENSOR PART*/
+ HIC_OPEN_SENSOR,
+ HIC_CLOSE_SENSOR,
+ HIC_SIMMIAN_INIT,
+ HIC_SIMMIAN_WRITE,
+ HIC_SIMMIAN_READ,
+ HIC_POWER_DOWN,
+ HIC_GET_SET_FILE_ADDR,
+ HIC_LOAD_SET_FILE,
+ HIC_MSG_CONFIG,
+ HIC_MSG_TEST,
+ /* IS -> HOST */
+ IHC_GET_SENSOR_NUMBER = 0x1000,
+ /* Parameter1 : Address of space to copy a setfile */
+ /* Parameter2 : Space szie */
+ IHC_SET_SHOT_MARK,
+ /* PARAM1 : a frame number */
+ /* PARAM2 : confidence level(smile 0~100) */
+ /* PARMA3 : confidence level(blink 0~100) */
+ IHC_SET_FACE_MARK,
+ /* PARAM1 : coordinate count */
+ /* PARAM2 : coordinate buffer address */
+ IHC_FRAME_DONE,
+ /* PARAM1 : frame start number */
+ /* PARAM2 : frame count */
+ IHC_AA_DONE,
+ IHC_NOT_READY,
+ IHC_FLASH_READY
+};
+
+enum is_reply {
+ ISR_DONE = 0x2000,
+ ISR_NDONE
+};
+
+enum is_scenario_id {
+ ISS_PREVIEW_STILL,
+ ISS_PREVIEW_VIDEO,
+ ISS_CAPTURE_STILL,
+ ISS_CAPTURE_VIDEO,
+ ISS_END
+};
+
+enum is_subscenario_id {
+ ISS_SUB_SCENARIO_STILL,
+ ISS_SUB_SCENARIO_VIDEO,
+ ISS_SUB_SCENARIO_SCENE1,
+ ISS_SUB_SCENARIO_SCENE2,
+ ISS_SUB_SCENARIO_SCENE3,
+ ISS_SUB_END
+};
+
+struct is_setfile_header_element {
+ u32 binary_addr;
+ u32 binary_size;
+};
+
+struct is_setfile_header {
+ struct is_setfile_header_element isp[ISS_END];
+ struct is_setfile_header_element drc[ISS_END];
+ struct is_setfile_header_element fd[ISS_END];
+};
+
+#define HOST_SET_INT_BIT 0x00000001
+#define HOST_CLR_INT_BIT 0x00000001
+#define IS_SET_INT_BIT 0x00000001
+#define IS_CLR_INT_BIT 0x00000001
+
+#define HOST_SET_INTERRUPT(base) (base->uiINTGR0 |= HOST_SET_INT_BIT)
+#define HOST_CLR_INTERRUPT(base) (base->uiINTCR0 |= HOST_CLR_INT_BIT)
+#define IS_SET_INTERRUPT(base) (base->uiINTGR1 |= IS_SET_INT_BIT)
+#define IS_CLR_INTERRUPT(base) (base->uiINTCR1 |= IS_CLR_INT_BIT)
+
+struct is_common_reg {
+ u32 hicmd;
+ u32 hic_sensorid;
+ u32 hic_param1;
+ u32 hic_param2;
+ u32 hic_param3;
+ u32 hic_param4;
+
+ u32 reserved1[3];
+
+ u32 ihcmd_iflag;
+ u32 ihcmd;
+ u32 ihc_sensorid;
+ u32 ihc_param1;
+ u32 ihc_param2;
+ u32 ihc_param3;
+ u32 ihc_param4;
+
+ u32 reserved2[3];
+
+ u32 isp_bayer_iflag;
+ u32 isp_bayer_sensor_id;
+ u32 isp_bayer_param1;
+ u32 isp_bayer_param2;
+
+ u32 reserved3[4];
+
+ u32 scc_iflag;
+ u32 scc_sensor_id;
+ u32 scc_param1;
+ u32 scc_param2;
+ u32 scc_param3;
+
+ u32 reserved4[3];
+
+ u32 dnr_iflag;
+ u32 dnr_sensor_id;
+ u32 dnr_param1;
+ u32 dnr_param2;
+
+ u32 reserved5[4];
+
+ u32 scp_iflag;
+ u32 scp_sensor_id;
+ u32 scp_param1;
+ u32 scp_param2;
+ u32 scp_param3;
+
+ u32 reserved6[1];
+
+ u32 isp_yuv_iflag;
+ u32 isp_yuv_sensor_id;
+ u32 isp_yuv_param1;
+ u32 isp_yuv_param2;
+
+ u32 reserved7[1];
+
+ u32 shot_iflag;
+ u32 shot_sensor_id;
+ u32 shot_param1;
+ u32 shot_param2;
+
+ u32 reserved8[1];
+
+ u32 meta_iflag;
+ u32 meta_sensor_id;
+ u32 meta_param1;
+
+ u32 reserved9[1];
+
+ u32 fcount;
+};
+
+struct is_mcuctl_reg {
+ u32 mcuctl;
+ u32 bboar;
+
+ u32 intgr0;
+ u32 intcr0;
+ u32 intmr0;
+ u32 intsr0;
+ u32 intmsr0;
+
+ u32 intgr1;
+ u32 intcr1;
+ u32 intmr1;
+ u32 intsr1;
+ u32 intmsr1;
+
+ u32 intcr2;
+ u32 intmr2;
+ u32 intsr2;
+ u32 intmsr2;
+
+ u32 gpoctrl;
+ u32 cpoenctlr;
+ u32 gpictlr;
+
+ u32 pad[0xD];
+
+ struct is_common_reg common_reg;
+};
+#endif
diff --git a/drivers/media/video/exynos/fimc-is-mc2/fimc-is-core.c b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-core.c
new file mode 100644
index 0000000..7cbdea7
--- /dev/null
+++ b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-core.c
@@ -0,0 +1,954 @@
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ * exynos5 fimc-is core functions
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <mach/videonode.h>
+#include <media/exynos_mc.h>
+#include <linux/cma.h>
+#include <asm/cacheflush.h>
+#include <asm/pgtable.h>
+#include <linux/firmware.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
+#include <linux/videodev2_exynos_camera.h>
+#include <linux/vmalloc.h>
+#include <linux/interrupt.h>
+
+#include "fimc-is-core.h"
+#include "fimc-is-param.h"
+#include "fimc-is-cmd.h"
+#include "fimc-is-regs.h"
+#include "fimc-is-err.h"
+#include "fimc-is-framemgr.h"
+
+static struct fimc_is_device_sensor *to_fimc_is_device_sensor
+ (struct v4l2_subdev *sdev)
+{
+ return container_of(sdev, struct fimc_is_device_sensor, sd);
+}
+
+static struct fimc_is_front_dev *to_fimc_is_front_dev(struct v4l2_subdev *sdev)
+{
+ return container_of(sdev, struct fimc_is_front_dev, sd);
+}
+
+static struct fimc_is_back_dev *to_fimc_is_back_dev(struct v4l2_subdev *sdev)
+{
+ return container_of(sdev, struct fimc_is_back_dev, sd);
+}
+
+static int fimc_is_sensor_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_front_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_back_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_sensor_subdev_get_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_sensor_subdev_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_sensor_subdev_get_crop(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_crop *crop)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_sensor_subdev_set_crop(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_crop *crop)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_front_subdev_get_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_front_subdev_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_front_subdev_get_crop(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_crop *crop)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_front_subdev_set_crop(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_crop *crop)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_back_subdev_get_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_back_subdev_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_back_subdev_get_crop(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_crop *crop)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_back_subdev_set_crop(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_crop *crop)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_sensor_s_ctrl(struct v4l2_subdev *sd,
+ struct v4l2_control *ctrl)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_sensor_g_ctrl(struct v4l2_subdev *sd,
+ struct v4l2_control *ctrl)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_front_s_ctrl(struct v4l2_subdev *sd,
+ struct v4l2_control *ctrl)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_front_g_ctrl(struct v4l2_subdev *sd,
+ struct v4l2_control *ctrl)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+static int fimc_is_back_s_ctrl(struct v4l2_subdev *sd,
+ struct v4l2_control *ctrl)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_back_g_ctrl(struct v4l2_subdev *sd,
+ struct v4l2_control *ctrl)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static struct v4l2_subdev_pad_ops fimc_is_sensor_pad_ops = {
+ .get_fmt = fimc_is_sensor_subdev_get_fmt,
+ .set_fmt = fimc_is_sensor_subdev_set_fmt,
+ .get_crop = fimc_is_sensor_subdev_get_crop,
+ .set_crop = fimc_is_sensor_subdev_set_crop,
+};
+
+static struct v4l2_subdev_pad_ops fimc_is_front_pad_ops = {
+ .get_fmt = fimc_is_front_subdev_get_fmt,
+ .set_fmt = fimc_is_front_subdev_set_fmt,
+ .get_crop = fimc_is_front_subdev_get_crop,
+ .set_crop = fimc_is_front_subdev_set_crop,
+};
+
+static struct v4l2_subdev_pad_ops fimc_is_back_pad_ops = {
+ .get_fmt = fimc_is_back_subdev_get_fmt,
+ .set_fmt = fimc_is_back_subdev_set_fmt,
+ .get_crop = fimc_is_back_subdev_get_crop,
+ .set_crop = fimc_is_back_subdev_set_crop,
+};
+
+static struct v4l2_subdev_video_ops fimc_is_sensor_video_ops = {
+ .s_stream = fimc_is_sensor_s_stream,
+};
+
+static struct v4l2_subdev_video_ops fimc_is_front_video_ops = {
+ .s_stream = fimc_is_front_s_stream,
+};
+
+static struct v4l2_subdev_video_ops fimc_is_back_video_ops = {
+ .s_stream = fimc_is_back_s_stream,
+};
+
+static struct v4l2_subdev_core_ops fimc_is_sensor_core_ops = {
+ .s_ctrl = fimc_is_sensor_s_ctrl,
+ .g_ctrl = fimc_is_sensor_g_ctrl,
+};
+
+static struct v4l2_subdev_core_ops fimc_is_front_core_ops = {
+ .s_ctrl = fimc_is_front_s_ctrl,
+ .g_ctrl = fimc_is_front_g_ctrl,
+};
+
+static struct v4l2_subdev_core_ops fimc_is_back_core_ops = {
+ .s_ctrl = fimc_is_back_s_ctrl,
+ .g_ctrl = fimc_is_back_g_ctrl,
+};
+
+static struct v4l2_subdev_ops fimc_is_sensor_subdev_ops = {
+ .pad = &fimc_is_sensor_pad_ops,
+ .video = &fimc_is_sensor_video_ops,
+ .core = &fimc_is_sensor_core_ops,
+};
+
+static struct v4l2_subdev_ops fimc_is_front_subdev_ops = {
+ .pad = &fimc_is_front_pad_ops,
+ .video = &fimc_is_front_video_ops,
+ .core = &fimc_is_front_core_ops,
+};
+
+static struct v4l2_subdev_ops fimc_is_back_subdev_ops = {
+ .pad = &fimc_is_back_pad_ops,
+ .video = &fimc_is_back_video_ops,
+ .core = &fimc_is_back_core_ops,
+};
+
+static int fimc_is_sensor_init_formats(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_sensor_subdev_close(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_sensor_subdev_registered(struct v4l2_subdev *sd)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static void fimc_is_sensor_subdev_unregistered(struct v4l2_subdev *sd)
+{
+ dbg("%s\n", __func__);
+}
+
+static int fimc_is_front_init_formats(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_front_subdev_close(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_front_subdev_registered(struct v4l2_subdev *sd)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static void fimc_is_front_subdev_unregistered(struct v4l2_subdev *sd)
+{
+ dbg("%s\n", __func__);
+}
+
+static int fimc_is_back_init_formats(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_back_subdev_close(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_back_subdev_registered(struct v4l2_subdev *sd)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static void fimc_is_back_subdev_unregistered(struct v4l2_subdev *sd)
+{
+ dbg("%s\n", __func__);
+}
+
+static const struct v4l2_subdev_internal_ops
+ fimc_is_sensor_v4l2_internal_ops = {
+ .open = fimc_is_sensor_init_formats,
+ .close = fimc_is_sensor_subdev_close,
+ .registered = fimc_is_sensor_subdev_registered,
+ .unregistered = fimc_is_sensor_subdev_unregistered,
+};
+
+static const struct v4l2_subdev_internal_ops fimc_is_front_v4l2_internal_ops = {
+ .open = fimc_is_front_init_formats,
+ .close = fimc_is_front_subdev_close,
+ .registered = fimc_is_front_subdev_registered,
+ .unregistered = fimc_is_front_subdev_unregistered,
+};
+
+static const struct v4l2_subdev_internal_ops fimc_is_back_v4l2_internal_ops = {
+ .open = fimc_is_back_init_formats,
+ .close = fimc_is_back_subdev_close,
+ .registered = fimc_is_back_subdev_registered,
+ .unregistered = fimc_is_back_subdev_unregistered,
+};
+
+static int fimc_is_sensor_link_setup(struct media_entity *entity,
+ const struct media_pad *local,
+ const struct media_pad *remote, u32 flags)
+{
+ struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
+ struct fimc_is_device_sensor *fimc_is_sensor;
+
+ dbg("++%s\n", __func__);
+ dbg("local->index : %d\n", local->index);
+ dbg("media_entity_type(remote->entity) : %d\n",
+ media_entity_type(remote->entity));
+
+ fimc_is_sensor = to_fimc_is_device_sensor(sd);
+
+ switch (local->index | media_entity_type(remote->entity)) {
+ case FIMC_IS_SENSOR_PAD_SOURCE_FRONT | MEDIA_ENT_T_V4L2_SUBDEV:
+ if (flags & MEDIA_LNK_FL_ENABLED)
+ fimc_is_sensor->output = FIMC_IS_SENSOR_OUTPUT_FRONT;
+ else
+ fimc_is_sensor->output = FIMC_IS_SENSOR_OUTPUT_NONE;
+ break;
+
+ default:
+ v4l2_err(sd, "%s : ERR link\n", __func__);
+ return -EINVAL;
+ }
+ dbg("--%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_front_link_setup(struct media_entity *entity,
+ const struct media_pad *local,
+ const struct media_pad *remote, u32 flags)
+{
+ struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
+ struct fimc_is_front_dev *fimc_is_front = to_fimc_is_front_dev(sd);
+
+ dbg("++%s\n", __func__);
+ dbg("local->index : %d\n", local->index);
+
+ switch (local->index | media_entity_type(remote->entity)) {
+ case FIMC_IS_FRONT_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
+ dbg("fimc_is_front sink pad\n");
+ if (flags & MEDIA_LNK_FL_ENABLED) {
+ if (fimc_is_front->input
+ != FIMC_IS_FRONT_INPUT_NONE) {
+ dbg("BUSY\n");
+ return -EBUSY;
+ }
+ if (remote->index == FIMC_IS_SENSOR_PAD_SOURCE_FRONT)
+ fimc_is_front->input
+ = FIMC_IS_FRONT_INPUT_SENSOR;
+ } else {
+ fimc_is_front->input = FIMC_IS_FRONT_INPUT_NONE;
+ }
+ break;
+
+ case FIMC_IS_FRONT_PAD_SOURCE_BACK | MEDIA_ENT_T_V4L2_SUBDEV:
+ if (flags & MEDIA_LNK_FL_ENABLED)
+ fimc_is_front->output |= FIMC_IS_FRONT_OUTPUT_BACK;
+ else
+ fimc_is_front->output = FIMC_IS_FRONT_OUTPUT_NONE;
+ break;
+
+ case FIMC_IS_FRONT_PAD_SOURCE_BAYER | MEDIA_ENT_T_DEVNODE:
+ if (flags & MEDIA_LNK_FL_ENABLED)
+ fimc_is_front->output |= FIMC_IS_FRONT_OUTPUT_BAYER;
+ else
+ fimc_is_front->output = FIMC_IS_FRONT_OUTPUT_NONE;
+ break;
+ case FIMC_IS_FRONT_PAD_SOURCE_SCALERC | MEDIA_ENT_T_DEVNODE:
+ if (flags & MEDIA_LNK_FL_ENABLED)
+ fimc_is_front->output |= FIMC_IS_FRONT_OUTPUT_SCALERC;
+ else
+ fimc_is_front->output = FIMC_IS_FRONT_OUTPUT_NONE;
+ break;
+
+ default:
+ v4l2_err(sd, "%s : ERR link\n", __func__);
+ return -EINVAL;
+ }
+ dbg("--%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_back_link_setup(struct media_entity *entity,
+ const struct media_pad *local,
+ const struct media_pad *remote, u32 flags)
+{
+ struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
+ struct fimc_is_back_dev *fimc_is_back = to_fimc_is_back_dev(sd);
+
+ dbg("++%s\n", __func__);
+ switch (local->index | media_entity_type(remote->entity)) {
+ case FIMC_IS_BACK_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
+ dbg("fimc_is_back sink pad\n");
+ if (flags & MEDIA_LNK_FL_ENABLED) {
+ if (fimc_is_back->input != FIMC_IS_BACK_INPUT_NONE) {
+ dbg("BUSY\n");
+ return -EBUSY;
+ }
+ if (remote->index == FIMC_IS_FRONT_PAD_SOURCE_BACK)
+ fimc_is_back->input = FIMC_IS_BACK_INPUT_FRONT;
+ } else {
+ fimc_is_back->input = FIMC_IS_FRONT_INPUT_NONE;
+ }
+ break;
+ case FIMC_IS_BACK_PAD_SOURCE_3DNR | MEDIA_ENT_T_DEVNODE:
+ if (flags & MEDIA_LNK_FL_ENABLED)
+ fimc_is_back->output |= FIMC_IS_BACK_OUTPUT_3DNR;
+ else
+ fimc_is_back->output = FIMC_IS_FRONT_OUTPUT_NONE;
+ break;
+ case FIMC_IS_BACK_PAD_SOURCE_SCALERP | MEDIA_ENT_T_DEVNODE:
+ if (flags & MEDIA_LNK_FL_ENABLED)
+ fimc_is_back->output |= FIMC_IS_BACK_OUTPUT_SCALERP;
+ else
+ fimc_is_back->output = FIMC_IS_FRONT_OUTPUT_NONE;
+ break;
+ default:
+ v4l2_err(sd, "%s : ERR link\n", __func__);
+ return -EINVAL;
+ }
+ dbg("--%s\n", __func__);
+ return 0;
+}
+
+static const struct media_entity_operations fimc_is_sensor_media_ops = {
+ .link_setup = fimc_is_sensor_link_setup,
+};
+
+static const struct media_entity_operations fimc_is_front_media_ops = {
+ .link_setup = fimc_is_front_link_setup,
+};
+
+static const struct media_entity_operations fimc_is_back_media_ops = {
+ .link_setup = fimc_is_back_link_setup,
+};
+
+int fimc_is_pipeline_s_stream_preview(struct media_entity *start_entity, int on)
+{
+ struct media_pad *pad = &start_entity->pads[0];
+ struct v4l2_subdev *back_sd;
+ struct v4l2_subdev *front_sd;
+ struct v4l2_subdev *sensor_sd;
+ int ret;
+
+ dbg("--%s\n", __func__);
+
+ pad = media_entity_remote_source(pad);
+ if (media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV
+ || pad == NULL)
+ dbg("cannot find back entity\n");
+
+ back_sd = media_entity_to_v4l2_subdev(pad->entity);
+
+ pad = &pad->entity->pads[0];
+
+ pad = media_entity_remote_source(pad);
+ if (media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV
+ || pad == NULL)
+ dbg("cannot find front entity\n");
+
+ front_sd = media_entity_to_v4l2_subdev(pad->entity);
+
+ pad = &pad->entity->pads[0];
+
+ pad = media_entity_remote_source(pad);
+ if (media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV
+ || pad == NULL)
+ dbg("cannot find sensor entity\n");
+
+ sensor_sd = media_entity_to_v4l2_subdev(pad->entity);
+
+ if (on) {
+
+ ret = v4l2_subdev_call(sensor_sd, video, s_stream, 1);
+ if (ret < 0 && ret != -ENOIOCTLCMD)
+ return ret;
+
+ ret = v4l2_subdev_call(front_sd, video, s_stream, 1);
+ if (ret < 0 && ret != -ENOIOCTLCMD)
+ return ret;
+
+ ret = v4l2_subdev_call(back_sd, video, s_stream, 1);
+ if (ret < 0 && ret != -ENOIOCTLCMD)
+ return ret;
+
+ } else {
+ ret = v4l2_subdev_call(back_sd, video, s_stream, 0);
+ if (ret < 0 && ret != -ENOIOCTLCMD)
+ return ret;
+ ret = v4l2_subdev_call(front_sd, video, s_stream, 0);
+ if (ret < 0 && ret != -ENOIOCTLCMD)
+ return ret;
+ ret = v4l2_subdev_call(sensor_sd, video, s_stream, 0);
+ }
+
+ return ret == -ENOIOCTLCMD ? 0 : ret;
+}
+
+
+static int fimc_is_suspend(struct device *dev)
+{
+ printk(KERN_INFO "FIMC_IS Suspend\n");
+ return 0;
+}
+
+static int fimc_is_resume(struct device *dev)
+{
+ printk(KERN_INFO "FIMC_IS Resume\n");
+ return 0;
+}
+
+int fimc_is_runtime_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct fimc_is_core *core
+ = (struct fimc_is_core *)platform_get_drvdata(pdev);
+ struct fimc_is_device_sensor *sensor = &core->sensor;
+ struct fimc_is_enum_sensor *sensor_info
+ = &sensor->enum_sensor[sensor->id_position];
+ int ret = 0;
+
+ printk(KERN_INFO "FIMC_IS runtime suspend\n");
+
+#if defined(CONFIG_VIDEOBUF2_ION)
+ if (core->mem.alloc_ctx)
+ vb2_ion_detach_iommu(core->mem.alloc_ctx);
+#endif
+
+ if (core->pdata->clk_off) {
+ core->pdata->clk_off(core->pdev, sensor_info->flite_ch);
+ } else {
+ err("failed to clock on\n");
+ ret = -EINVAL;
+ goto end;
+ }
+
+ if (core->pdata->sensor_power_off) {
+ core->pdata->sensor_power_off(core->pdev,
+ sensor_info->flite_ch);
+ } else {
+ err("failed to sensor_power_off\n");
+ ret = -EINVAL;
+ goto end;
+ }
+end:
+ pm_relax(dev);
+ return ret;
+}
+
+int fimc_is_runtime_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct fimc_is_core *core
+ = (struct fimc_is_core *)platform_get_drvdata(pdev);
+ struct fimc_is_device_sensor *sensor = &core->sensor;
+ struct fimc_is_enum_sensor *sensor_info
+ = &sensor->enum_sensor[sensor->id_position];
+
+ pm_stay_awake(dev);
+ printk(KERN_INFO "FIMC_IS runtime resume\n");
+
+ /* 1. Enable MIPI */
+ enable_mipi();
+
+ /* 2. Low clock setting */
+ if (core->pdata->clk_cfg) {
+ core->pdata->clk_cfg(core->pdev);
+ } else {
+ err("failed to config clock\n");
+ goto err;
+ }
+
+ /* 3. Sensor power on */
+ if (core->pdata->sensor_power_on) {
+ core->pdata->sensor_power_on(core->pdev,
+ sensor_info->flite_ch);
+ } else {
+ err("failed to sensor_power_on\n");
+ goto err;
+ }
+
+ /* 4. Clock on */
+ if (core->pdata->clk_on) {
+ core->pdata->clk_on(core->pdev, sensor_info->flite_ch);
+ } else {
+ err("failed to clock on\n");
+ goto err;
+ }
+
+ /* 5. High clock setting */
+ if (core->pdata->clk_cfg) {
+ core->pdata->clk_cfg(core->pdev);
+ } else {
+ err("failed to config clock\n");
+ goto err;
+ }
+
+#if defined(CONFIG_VIDEOBUF2_ION)
+ if (core->mem.alloc_ctx)
+ vb2_ion_attach_iommu(core->mem.alloc_ctx);
+#endif
+ return 0;
+
+err:
+ pm_relax(dev);
+ return -EINVAL;
+}
+
+static int fimc_is_get_md_callback(struct device *dev, void *p)
+{
+ struct exynos_md **md_list = p;
+ struct exynos_md *md = NULL;
+
+ md = dev_get_drvdata(dev);
+
+ if (md)
+ *(md_list + md->id) = md;
+
+ return 0; /* non-zero value stops iteration */
+}
+
+static struct exynos_md *fimc_is_get_md(enum mdev_node node)
+{
+ struct device_driver *drv;
+ struct exynos_md *md[MDEV_MAX_NUM] = {NULL,};
+ int ret;
+
+ drv = driver_find(MDEV_MODULE_NAME, &platform_bus_type);
+ if (!drv)
+ return ERR_PTR(-ENODEV);
+
+ ret = driver_for_each_device(drv, NULL, &md[0],
+ fimc_is_get_md_callback);
+ /* put_driver(drv); */
+
+ return ret ? NULL : md[node];
+
+}
+
+static int fimc_is_probe(struct platform_device *pdev)
+{
+ struct resource *mem_res;
+ struct resource *regs_res;
+ struct fimc_is_core *core;
+ int ret = -ENODEV;
+
+ dbg("fimc_is_front_probe\n");
+
+ core = kzalloc(sizeof(struct fimc_is_core), GFP_KERNEL);
+ if (!core)
+ return -ENOMEM;
+
+ core->pdev = pdev;
+ core->pdata = pdev->dev.platform_data;
+ core->id = pdev->id;
+ device_init_wakeup(&pdev->dev, true);
+
+ mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem_res) {
+ dev_err(&pdev->dev, "Failed to get io memory region\n");
+ goto p_err1;
+ }
+
+ regs_res = request_mem_region(mem_res->start, resource_size(mem_res),
+ pdev->name);
+ if (!regs_res) {
+ dev_err(&pdev->dev, "Failed to request io memory region\n");
+ goto p_err1;
+ }
+
+ core->regs_res = regs_res;
+ core->regs = ioremap_nocache(mem_res->start, resource_size(mem_res));
+ if (!core->regs) {
+ dev_err(&pdev->dev, "Failed to remap io region\n");
+ goto p_err2;
+ }
+
+ core->irq = platform_get_irq(pdev, 0);
+ if (core->irq < 0) {
+ dev_err(&pdev->dev, "Failed to get irq\n");
+ goto p_err3;
+ }
+
+ core->mdev = fimc_is_get_md(MDEV_ISP);
+ if (IS_ERR_OR_NULL(core->mdev))
+ goto p_err3;
+
+ fimc_is_mem_probe(&core->mem,
+ core->pdev);
+
+ fimc_is_frame_probe(&core->framemgr_sensor, FRAMEMGR_ID_SENSOR);
+ fimc_is_frame_probe(&core->framemgr_ischain, FRAMEMGR_ID_ISP);
+
+ fimc_is_interface_probe(&core->interface,
+ &core->framemgr_ischain,
+ (u32)core->regs,
+ core->irq,
+ core);
+
+ fimc_is_ischain_probe(&core->ischain,
+ &core->interface,
+ &core->framemgr_ischain,
+ &core->mem,
+ pdev,
+ (u32)core->regs);
+
+ fimc_is_sensor_probe(&core->sensor,
+ &core->video_sensor,
+ &core->framemgr_sensor,
+ &core->ischain,
+ &core->mem);
+#if 1
+ /*sensor entity*/
+ v4l2_subdev_init(&core->sensor.sd, &fimc_is_sensor_subdev_ops);
+ core->sensor.sd.owner = THIS_MODULE;
+ core->sensor.sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
+ snprintf(core->sensor.sd.name, sizeof(core->sensor.sd.name), "%s\n",
+ FIMC_IS_SENSOR_ENTITY_NAME);
+
+ core->sensor.pads.flags = MEDIA_PAD_FL_SOURCE;
+ ret = media_entity_init(&core->sensor.sd.entity, 1,
+ &core->sensor.pads, 0);
+ if (ret < 0)
+ goto p_err3;
+
+ fimc_is_sensor_init_formats(&core->sensor.sd, NULL);
+
+ core->sensor.sd.internal_ops = &fimc_is_sensor_v4l2_internal_ops;
+ core->sensor.sd.entity.ops = &fimc_is_sensor_media_ops;
+
+ ret = v4l2_device_register_subdev(&core->mdev->v4l2_dev,
+ &core->sensor.sd);
+ if (ret)
+ goto p_err3;
+ /* This allows to retrieve the platform device id by the host driver */
+ v4l2_set_subdevdata(&core->sensor.sd, pdev);
+
+
+ /*front entity*/
+ v4l2_subdev_init(&core->front.sd, &fimc_is_front_subdev_ops);
+ core->front.sd.owner = THIS_MODULE;
+ core->front.sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
+ snprintf(core->front.sd.name, sizeof(core->front.sd.name), "%s\n",
+ FIMC_IS_FRONT_ENTITY_NAME);
+
+ core->front.pads[FIMC_IS_FRONT_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+ core->front.pads[FIMC_IS_FRONT_PAD_SOURCE_BACK].flags
+ = MEDIA_PAD_FL_SOURCE;
+ core->front.pads[FIMC_IS_FRONT_PAD_SOURCE_BAYER].flags
+ = MEDIA_PAD_FL_SOURCE;
+ core->front.pads[FIMC_IS_FRONT_PAD_SOURCE_SCALERC].flags
+ = MEDIA_PAD_FL_SOURCE;
+ ret = media_entity_init(&core->front.sd.entity, FIMC_IS_FRONT_PADS_NUM,
+ core->front.pads, 0);
+ if (ret < 0)
+ goto p_err3;
+
+ fimc_is_front_init_formats(&core->front.sd, NULL);
+
+ core->front.sd.internal_ops = &fimc_is_front_v4l2_internal_ops;
+ core->front.sd.entity.ops = &fimc_is_front_media_ops;
+
+ ret = v4l2_device_register_subdev(&core->mdev->v4l2_dev,
+ &core->front.sd);
+ if (ret)
+ goto p_err3;
+ /* This allows to retrieve the platform device id by the host driver */
+ v4l2_set_subdevdata(&core->front.sd, pdev);
+
+
+ /*back entity*/
+ v4l2_subdev_init(&core->back.sd, &fimc_is_back_subdev_ops);
+ core->back.sd.owner = THIS_MODULE;
+ core->back.sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
+ snprintf(core->back.sd.name, sizeof(core->back.sd.name), "%s\n",
+ FIMC_IS_BACK_ENTITY_NAME);
+
+ core->back.pads[FIMC_IS_BACK_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+ core->back.pads[FIMC_IS_BACK_PAD_SOURCE_3DNR].flags
+ = MEDIA_PAD_FL_SOURCE;
+ core->back.pads[FIMC_IS_BACK_PAD_SOURCE_SCALERP].flags
+ = MEDIA_PAD_FL_SOURCE;
+ ret = media_entity_init(&core->back.sd.entity, FIMC_IS_BACK_PADS_NUM,
+ core->back.pads, 0);
+ if (ret < 0)
+ goto p_err3;
+
+ fimc_is_front_init_formats(&core->back.sd, NULL);
+
+ core->back.sd.internal_ops = &fimc_is_back_v4l2_internal_ops;
+ core->back.sd.entity.ops = &fimc_is_back_media_ops;
+
+ ret = v4l2_device_register_subdev(&core->mdev->v4l2_dev,
+ &core->back.sd);
+ if (ret)
+ goto p_err3;
+
+ v4l2_set_subdevdata(&core->back.sd, pdev);
+#endif
+
+ /*real start*/
+
+ /*front video entity - scalerC */
+ fimc_is_scc_video_probe(core);
+
+ /* back video entity - scalerP*/
+ fimc_is_scp_video_probe(core);
+
+ /* back video entity - bayer*/
+ fimc_is_sensor_video_probe(core);
+
+ /* back video entity - isp*/
+ fimc_is_isp_video_probe(core);
+
+ platform_set_drvdata(pdev, core);
+
+ /* register subdev nodes*/
+ ret = v4l2_device_register_subdev_nodes(&core->mdev->v4l2_dev);
+ if (ret)
+ err("v4l2_device_register_subdev_nodes failed\n");
+
+#if defined(CONFIG_PM_RUNTIME)
+ pm_runtime_enable(&pdev->dev);
+#endif
+
+ dbg("%s : fimc_is_front_%d probe success\n", __func__, pdev->id);
+ return 0;
+
+p_err3:
+ iounmap(core->regs);
+p_err2:
+ release_mem_region(regs_res->start, resource_size(regs_res));
+p_err1:
+ kfree(core);
+ return ret;
+}
+
+static int fimc_is_remove(struct platform_device *pdev)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static const struct dev_pm_ops fimc_is_pm_ops = {
+ .suspend = fimc_is_suspend,
+ .resume = fimc_is_resume,
+ .runtime_suspend = fimc_is_runtime_suspend,
+ .runtime_resume = fimc_is_runtime_resume,
+};
+
+static struct platform_driver fimc_is_driver = {
+ .probe = fimc_is_probe,
+ .remove = __devexit_p(fimc_is_remove),
+ .driver = {
+ .name = FIMC_IS_MODULE_NAME,
+ .owner = THIS_MODULE,
+ .pm = &fimc_is_pm_ops,
+ }
+};
+
+static int __init fimc_is_init(void)
+{
+ int ret = platform_driver_register(&fimc_is_driver);
+ if (ret)
+ err("platform_driver_register failed: %d\n", ret);
+ return ret;
+}
+
+static void __exit fimc_is_exit(void)
+{
+ platform_driver_unregister(&fimc_is_driver);
+}
+module_init(fimc_is_init);
+module_exit(fimc_is_exit);
+
+MODULE_AUTHOR("Jiyoung Shin<idon.shin@samsung.com>");
+MODULE_DESCRIPTION("Exynos FIMC_IS2 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/exynos/fimc-is-mc2/fimc-is-core.h b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-core.h
new file mode 100644
index 0000000..aeb1331
--- /dev/null
+++ b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-core.h
@@ -0,0 +1,331 @@
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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.
+ */
+
+#ifndef FIMC_IS_CORE_H
+#define FIMC_IS_CORE_H
+
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/pm_runtime.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-mediabus.h>
+#include <media/exynos_fimc_is.h>
+#include <media/v4l2-ioctl.h>
+#include <media/exynos_mc.h>
+#include <media/videobuf2-core.h>
+#if defined(CONFIG_VIDEOBUF2_CMA_PHYS)
+#include <media/videobuf2-cma-phys.h>
+#elif defined(CONFIG_VIDEOBUF2_ION)
+#include <media/videobuf2-ion.h>
+#endif
+#include "fimc-is-param.h"
+
+#include "fimc-is-device-sensor.h"
+#include "fimc-is-interface.h"
+#include "fimc-is-framemgr.h"
+#include "fimc-is-device-ischain.h"
+
+#include "fimc-is-video-sensor.h"
+#include "fimc-is-video-isp.h"
+#include "fimc-is-video-scc.h"
+#include "fimc-is-video-scp.h"
+#include "fimc-is-mem.h"
+
+#define FIMC_IS_MODULE_NAME "exynos5-fimc-is2"
+#define FIMC_IS_SENSOR_ENTITY_NAME "exynos5-fimc-is2-sensor"
+#define FIMC_IS_FRONT_ENTITY_NAME "exynos5-fimc-is2-front"
+#define FIMC_IS_BACK_ENTITY_NAME "exynos5-fimc-is2-back"
+#define FIMC_IS_VIDEO_BAYER_NAME "exynos5-fimc-is2-bayer"
+#define FIMC_IS_VIDEO_ISP_NAME "exynos5-fimc-is2-isp"
+#define FIMC_IS_VIDEO_SCALERC_NAME "exynos5-fimc-is2-scalerc"
+#define FIMC_IS_VIDEO_3DNR_NAME "exynos5-fimc-is2-3dnr"
+#define FIMC_IS_VIDEO_SCALERP_NAME "exynos5-fimc-is2-scalerp"
+
+#define FIMC_IS_COMMAND_TIMEOUT (3*HZ)
+#define FIMC_IS_STARTUP_TIMEOUT (3*HZ)
+#define FIMC_IS_SHUTDOWN_TIMEOUT (10*HZ)
+#define FIMC_IS_FLITE_STOP_TIMEOUT (3*HZ)
+
+#define FIMC_IS_SENSOR_MAX_ENTITIES (1)
+#define FIMC_IS_SENSOR_PAD_SOURCE_FRONT (0)
+#define FIMC_IS_SENSOR_PADS_NUM (1)
+
+#define FIMC_IS_FRONT_MAX_ENTITIES (1)
+#define FIMC_IS_FRONT_PAD_SINK (0)
+#define FIMC_IS_FRONT_PAD_SOURCE_BACK (1)
+#define FIMC_IS_FRONT_PAD_SOURCE_BAYER (2)
+#define FIMC_IS_FRONT_PAD_SOURCE_SCALERC (3)
+#define FIMC_IS_FRONT_PADS_NUM (4)
+
+#define FIMC_IS_BACK_MAX_ENTITIES (1)
+#define FIMC_IS_BACK_PAD_SINK (0)
+#define FIMC_IS_BACK_PAD_SOURCE_3DNR (1)
+#define FIMC_IS_BACK_PAD_SOURCE_SCALERP (2)
+#define FIMC_IS_BACK_PADS_NUM (3)
+
+#define FIMC_IS_MAX_SENSOR_NAME_LEN (16)
+
+#define FW_SHARED_OFFSET (0x8C0000)
+#define DEBUG_CNT (500*1024)
+#define DEBUG_OFFSET (0x840000)
+#define DEBUGCTL_OFFSET (0x8BD000)
+#define DEBUG_FCOUNT (0x8C64C0)
+
+#ifdef err
+#undef err
+#endif
+#define err(fmt, args...) \
+ printk(KERN_ERR "ERR:%s:%d: " fmt "\n", __func__, __LINE__, ##args)
+
+#ifdef warn
+#undef warn
+#endif
+#define warn(fmt, args...) \
+ printk(KERN_WARNING "%s:%d: " fmt "\n", __func__, __LINE__, ##args)
+
+/* configuration - default post processing */
+/*#define ENABLE_DRC*/
+/*#define ENABLE_ODC*/
+#define ENABLE_VDIS
+#define ENABLE_TDNR
+#define ENABLE_FD
+
+/*#define DEBUG*/
+/*#define DBG_STREAMING*/
+/*#define DBG_FLITEISR*/
+/*#define AUTO_MODE*/
+#define FW_DEBUG
+/*#define RESERVED_MEM*/
+#define USE_FRAME_SYNC
+#define USE_ADVANCED_DZOOM
+/*#define TASKLET_MSG*/
+/*#define PRINT_BUFADDR*/
+/*#define PRINT_DZOOM*/
+#define CHECK_FDROP
+#define ISDRV_VERSION 111
+
+#ifdef DEBUG
+#define dbg(fmt, args...) \
+ /*printk(KERN_DEBUG "%s:%d: " fmt "\n", __func__, __LINE__, ##args)*/
+
+#define dbg_warning(fmt, args...) \
+ printk(KERN_INFO "%s[WAR] Warning! " fmt, __func__, ##args)
+
+#define dbg_sensor(fmt, args...) \
+ printk(KERN_INFO "[SEN] " fmt, ##args)
+
+#define dbg_isp(fmt, args...) \
+ printk(KERN_INFO "[ISP] " fmt, ##args)
+
+#define dbg_scp(fmt, args...) \
+ printk(KERN_INFO "[SCP] " fmt, ##args)
+
+#define dbg_scc(fmt, args...) \
+ printk(KERN_INFO "[SCC] " fmt, ##args)
+
+#define dbg_front(fmt, args...) \
+ printk(KERN_INFO "[FRT] " fmt, ##args)
+
+#define dbg_back(fmt, args...) \
+ printk(KERN_INFO "[BAK] " fmt, ##args)
+
+#define dbg_ischain(fmt, args...) \
+ printk(KERN_INFO "[ISC] " fmt, ##args)
+
+#define dbg_core(fmt, args...) \
+ printk(KERN_INFO "[COR] " fmt, ##args)
+
+
+
+#ifdef DBG_STREAMING
+#define dbg_interface(fmt, args...) \
+ printk(KERN_INFO "[ITF] " fmt, ##args)
+#define dbg_frame(fmt, args...) \
+ printk(KERN_INFO "[FRM] " fmt, ##args)
+#else
+#define dbg_interface(fmt, args...)
+#define dbg_frame(fmt, args...)
+#endif
+#else
+#define dbg(fmt, args...)
+#define dbg_warning(fmt, args...)
+#define dbg_sensor(fmt, args...)
+#define dbg_isp(fmt, args...)
+#define dbg_scp(fmt, args...)
+#define dbg_scc(fmt, args...)
+#define dbg_front(fmt, args...)
+#define dbg_back(fmt, args...)
+#define dbg_ischain(fmt, args...)
+#define dbg_core(fmt, args...)
+#define dbg_interface(fmt, args...)
+#define dbg_frame(fmt, args...)
+#endif
+
+enum fimc_is_debug_device {
+ FIMC_IS_DEBUG_MAIN = 0,
+ FIMC_IS_DEBUG_EC,
+ FIMC_IS_DEBUG_SENSOR,
+ FIMC_IS_DEBUG_ISP,
+ FIMC_IS_DEBUG_DRC,
+ FIMC_IS_DEBUG_FD,
+ FIMC_IS_DEBUG_SDK,
+ FIMC_IS_DEBUG_SCALERC,
+ FIMC_IS_DEBUG_ODC,
+ FIMC_IS_DEBUG_DIS,
+ FIMC_IS_DEBUG_TDNR,
+ FIMC_IS_DEBUG_SCALERP
+};
+
+enum fimc_is_debug_target {
+ FIMC_IS_DEBUG_UART = 0,
+ FIMC_IS_DEBUG_MEMORY,
+ FIMC_IS_DEBUG_DCC3
+};
+
+enum fimc_is_front_input_entity {
+ FIMC_IS_FRONT_INPUT_NONE = 0,
+ FIMC_IS_FRONT_INPUT_SENSOR,
+};
+
+enum fimc_is_front_output_entity {
+ FIMC_IS_FRONT_OUTPUT_NONE = 0,
+ FIMC_IS_FRONT_OUTPUT_BACK,
+ FIMC_IS_FRONT_OUTPUT_BAYER,
+ FIMC_IS_FRONT_OUTPUT_SCALERC,
+};
+
+enum fimc_is_back_input_entity {
+ FIMC_IS_BACK_INPUT_NONE = 0,
+ FIMC_IS_BACK_INPUT_FRONT,
+};
+
+enum fimc_is_back_output_entity {
+ FIMC_IS_BACK_OUTPUT_NONE = 0,
+ FIMC_IS_BACK_OUTPUT_3DNR,
+ FIMC_IS_BACK_OUTPUT_SCALERP,
+};
+
+enum fimc_is_front_state {
+ FIMC_IS_FRONT_ST_POWERED = 0,
+ FIMC_IS_FRONT_ST_STREAMING,
+ FIMC_IS_FRONT_ST_SUSPENDED,
+};
+
+enum fimc_is_video_dev_num {
+ FIMC_IS_VIDEO_NUM_BAYER = 0,
+ FIMC_IS_VIDEO_NUM_ISP,
+ FIMC_IS_VIDEO_NUM_SCALERC,
+ FIMC_IS_VIDEO_NUM_3DNR,
+ FIMC_IS_VIDEO_NUM_SCALERP,
+ FIMC_IS_VIDEO_MAX_NUM,
+};
+
+struct fimc_is_core;
+
+struct fimc_is_front_dev {
+ struct v4l2_subdev sd;
+ struct media_pad pads[FIMC_IS_FRONT_PADS_NUM];
+ struct v4l2_mbus_framefmt mbus_fmt[FIMC_IS_FRONT_PADS_NUM];
+ enum fimc_is_front_input_entity input;
+ enum fimc_is_front_output_entity output;
+ u32 width;
+ u32 height;
+
+};
+
+struct fimc_is_back_dev {
+ struct v4l2_subdev sd;
+ struct media_pad pads[FIMC_IS_BACK_PADS_NUM];
+ struct v4l2_mbus_framefmt mbus_fmt[FIMC_IS_BACK_PADS_NUM];
+ enum fimc_is_back_input_entity input;
+ enum fimc_is_back_output_entity output;
+ int dis_on;
+ int odc_on;
+ int tdnr_on;
+ u32 width;
+ u32 height;
+ u32 dis_width;
+ u32 dis_height;
+};
+
+struct fimc_is_core {
+ struct platform_device *pdev;
+ struct resource *regs_res;
+ void __iomem *regs;
+ int irq;
+ u32 id;
+
+ /* depended on isp */
+ struct exynos5_platform_fimc_is *pdata;
+ struct exynos_md *mdev;
+
+ struct fimc_is_mem mem;
+ struct fimc_is_framemgr framemgr_sensor;
+ struct fimc_is_framemgr framemgr_ischain;
+ struct fimc_is_interface interface;
+
+ struct fimc_is_device_sensor sensor;
+ struct fimc_is_device_ischain ischain;
+ struct fimc_is_front_dev front;
+ struct fimc_is_back_dev back;
+
+ /* 0-bayer, 1-scalerC, 2-3DNR, 3-scalerP */
+ struct fimc_is_video_sensor video_sensor;
+ struct fimc_is_video_isp video_isp;
+ struct fimc_is_video_scc video_scc;
+ struct fimc_is_video_scp video_scp;
+
+};
+
+extern const struct v4l2_file_operations fimc_is_bayer_video_fops;
+extern const struct v4l2_ioctl_ops fimc_is_bayer_video_ioctl_ops;
+extern const struct vb2_ops fimc_is_bayer_qops;
+
+extern const struct v4l2_file_operations fimc_is_isp_video_fops;
+extern const struct v4l2_ioctl_ops fimc_is_isp_video_ioctl_ops;
+extern const struct vb2_ops fimc_is_isp_qops;
+
+extern const struct v4l2_file_operations fimc_is_scalerc_video_fops;
+extern const struct v4l2_ioctl_ops fimc_is_scalerc_video_ioctl_ops;
+extern const struct vb2_ops fimc_is_scalerc_qops;
+
+extern const struct v4l2_file_operations fimc_is_scalerp_video_fops;
+extern const struct v4l2_ioctl_ops fimc_is_scalerp_video_ioctl_ops;
+extern const struct vb2_ops fimc_is_scalerp_qops;
+
+extern const struct v4l2_file_operations fimc_is_3dnr_video_fops;
+extern const struct v4l2_ioctl_ops fimc_is_3dnr_video_ioctl_ops;
+extern const struct vb2_ops fimc_is_3dnr_qops;
+
+#if defined(CONFIG_VIDEOBUF2_CMA_PHYS)
+extern const struct fimc_is_vb2 fimc_is_vb2_cma;
+#elif defined(CONFIG_VIDEOBUF2_ION)
+extern const struct fimc_is_vb2 fimc_is_vb2_ion;
+#endif
+
+void fimc_is_mem_suspend(void *alloc_ctxes);
+void fimc_is_mem_resume(void *alloc_ctxes);
+void fimc_is_mem_cache_clean(const void *start_addr, unsigned long size);
+void fimc_is_mem_cache_inv(const void *start_addr, unsigned long size);
+int fimc_is_pipeline_s_stream_preview
+ (struct media_entity *start_entity, int on);
+int fimc_is_init_set(struct fimc_is_core *dev , u32 val);
+int fimc_is_load_fw(struct fimc_is_core *dev);
+int fimc_is_load_setfile(struct fimc_is_core *dev);
+int fimc_is_spi_read(void *buf, size_t size);
+int fimc_is_runtime_suspend(struct device *dev);
+int fimc_is_runtime_resume(struct device *dev);
+#endif /* FIMC_IS_CORE_H_ */
diff --git a/drivers/media/video/exynos/fimc-is-mc2/fimc-is-device-flite.c b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-device-flite.c
new file mode 100644
index 0000000..a4c11f6
--- /dev/null
+++ b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-device-flite.c
@@ -0,0 +1,929 @@
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ * exynos5 fimc-is video functions
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <mach/videonode.h>
+#ifdef CONFIG_BUSFREQ_OPP
+#ifdef CONFIG_CPU_EXYNOS5250
+#include <mach/dev.h>
+#endif
+#endif
+#include <media/exynos_mc.h>
+#include <linux/cma.h>
+#include <asm/cacheflush.h>
+#include <asm/pgtable.h>
+#include <linux/firmware.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
+#include <linux/videodev2.h>
+#include <linux/videodev2_exynos_camera.h>
+#include <linux/videodev2_exynos_media.h>
+#include <linux/v4l2-mediabus.h>
+
+#include <mach/map.h>
+#include <mach/regs-clock.h>
+
+#include "fimc-is-time.h"
+#include "fimc-is-core.h"
+#include "fimc-is-regs.h"
+#include "fimc-is-interface.h"
+#include "fimc-is-device-flite.h"
+
+#define FIMCLITE0_REG_BASE (S5P_VA_FIMCLITE0) /* phy : 0x13c0_0000 */
+#define FIMCLITE1_REG_BASE (S5P_VA_FIMCLITE1) /* phy : 0x13c1_0000 */
+#define FIMCLITE2_REG_BASE (S5P_VA_FIMCLITE2) /* phy : 0x13c9_0000 */
+
+#define FLITE_MAX_RESET_READY_TIME (20) /* 100ms */
+#define FLITE_MAX_WIDTH_SIZE (8192)
+#define FLITE_MAX_HEIGHT_SIZE (8192)
+
+/*FIMCLite*/
+/* Camera Source size */
+#define FLITE_REG_CISRCSIZE (0x00)
+#define FLITE_REG_CISRCSIZE_SIZE_H(x) ((x) << 16)
+#define FLITE_REG_CISRCSIZE_SIZE_V(x) ((x) << 0)
+#define FLITE_REG_CISRCSIZE_ORDER422_IN_YCBYCR (0 << 14)
+#define FLITE_REG_CISRCSIZE_ORDER422_IN_YCRYCB (1 << 14)
+#define FLITE_REG_CISRCSIZE_ORDER422_IN_CBYCRY (2 << 14)
+#define FLITE_REG_CISRCSIZE_ORDER422_IN_CRYCBY (3 << 14)
+
+/* Global control */
+#define FLITE_REG_CIGCTRL 0x04
+#define FLITE_REG_CIGCTRL_YUV422_1P (0x1E << 24)
+#define FLITE_REG_CIGCTRL_RAW8 (0x2A << 24)
+#define FLITE_REG_CIGCTRL_RAW10 (0x2B << 24)
+#define FLITE_REG_CIGCTRL_RAW12 (0x2C << 24)
+#define FLITE_REG_CIGCTRL_RAW14 (0x2D << 24)
+
+/* User defined formats. x = 0...0xF. */
+#define FLITE_REG_CIGCTRL_USER(x) (0x30 + x - 1)
+#define FLITE_REG_CIGCTRL_OLOCAL_DISABLE (1 << 22)
+#define FLITE_REG_CIGCTRL_SHADOWMASK_DISABLE (1 << 21)
+#define FLITE_REG_CIGCTRL_ODMA_DISABLE (1 << 20)
+#define FLITE_REG_CIGCTRL_SWRST_REQ (1 << 19)
+#define FLITE_REG_CIGCTRL_SWRST_RDY (1 << 18)
+#define FLITE_REG_CIGCTRL_SWRST (1 << 17)
+#define FLITE_REG_CIGCTRL_TEST_PATTERN_COLORBAR (1 << 15)
+#define FLITE_REG_CIGCTRL_INVPOLPCLK (1 << 14)
+#define FLITE_REG_CIGCTRL_INVPOLVSYNC (1 << 13)
+#define FLITE_REG_CIGCTRL_INVPOLHREF (1 << 12)
+#define FLITE_REG_CIGCTRL_IRQ_LASTEN0_ENABLE (0 << 8)
+#define FLITE_REG_CIGCTRL_IRQ_LASTEN0_DISABLE (1 << 8)
+#define FLITE_REG_CIGCTRL_IRQ_ENDEN0_ENABLE (0 << 7)
+#define FLITE_REG_CIGCTRL_IRQ_ENDEN0_DISABLE (1 << 7)
+#define FLITE_REG_CIGCTRL_IRQ_STARTEN0_ENABLE (0 << 6)
+#define FLITE_REG_CIGCTRL_IRQ_STARTEN0_DISABLE (1 << 6)
+#define FLITE_REG_CIGCTRL_IRQ_OVFEN0_ENABLE (0 << 5)
+#define FLITE_REG_CIGCTRL_IRQ_OVFEN0_DISABLE (1 << 5)
+#define FLITE_REG_CIGCTRL_SELCAM_MIPI (1 << 3)
+
+/* Image Capture Enable */
+#define FLITE_REG_CIIMGCPT (0x08)
+#define FLITE_REG_CIIMGCPT_IMGCPTEN (1 << 31)
+#define FLITE_REG_CIIMGCPT_CPT_FREN (1 << 25)
+#define FLITE_REG_CIIMGCPT_CPT_FRPTR(x) ((x) << 19)
+#define FLITE_REG_CIIMGCPT_CPT_MOD_FRCNT (1 << 18)
+#define FLITE_REG_CIIMGCPT_CPT_MOD_FREN (0 << 18)
+#define FLITE_REG_CIIMGCPT_CPT_FRCNT(x) ((x) << 10)
+
+/* Capture Sequence */
+#define FLITE_REG_CICPTSEQ (0x0C)
+#define FLITE_REG_CPT_FRSEQ(x) ((x) << 0)
+
+/* Camera Window Offset */
+#define FLITE_REG_CIWDOFST (0x10)
+#define FLITE_REG_CIWDOFST_WINOFSEN (1 << 31)
+#define FLITE_REG_CIWDOFST_CLROVIY (1 << 31)
+#define FLITE_REG_CIWDOFST_WINHOROFST(x) ((x) << 16)
+#define FLITE_REG_CIWDOFST_HOROFF_MASK (0x1fff << 16)
+#define FLITE_REG_CIWDOFST_CLROVFICB (1 << 15)
+#define FLITE_REG_CIWDOFST_CLROVFICR (1 << 14)
+#define FLITE_REG_CIWDOFST_WINVEROFST(x) ((x) << 0)
+#define FLITE_REG_CIWDOFST_VEROFF_MASK (0x1fff << 0)
+
+/* Cmaera Window Offset2 */
+#define FLITE_REG_CIWDOFST2 (0x14)
+#define FLITE_REG_CIWDOFST2_WINHOROFST2(x) ((x) << 16)
+#define FLITE_REG_CIWDOFST2_WINVEROFST2(x) ((x) << 0)
+
+/* Camera Output DMA Format */
+#define FLITE_REG_CIODMAFMT (0x18)
+#define FLITE_REG_CIODMAFMT_1D_DMA (1 << 15)
+#define FLITE_REG_CIODMAFMT_2D_DMA (0 << 15)
+#define FLITE_REG_CIODMAFMT_PACK12 (1 << 14)
+#define FLITE_REG_CIODMAFMT_NORMAL (0 << 14)
+#define FLITE_REG_CIODMAFMT_CRYCBY (0 << 4)
+#define FLITE_REG_CIODMAFMT_CBYCRY (1 << 4)
+#define FLITE_REG_CIODMAFMT_YCRYCB (2 << 4)
+#define FLITE_REG_CIODMAFMT_YCBYCR (3 << 4)
+
+/* Camera Output Canvas */
+#define FLITE_REG_CIOCAN (0x20)
+#define FLITE_REG_CIOCAN_OCAN_V(x) ((x) << 16)
+#define FLITE_REG_CIOCAN_OCAN_H(x) ((x) << 0)
+
+/* Camera Output DMA Offset */
+#define FLITE_REG_CIOOFF (0x24)
+#define FLITE_REG_CIOOFF_OOFF_V(x) ((x) << 16)
+#define FLITE_REG_CIOOFF_OOFF_H(x) ((x) << 0)
+
+/* Camera Output DMA Address */
+#define FLITE_REG_CIOSA (0x30)
+#define FLITE_REG_CIOSA_OSA(x) ((x) << 0)
+
+/* Camera Status */
+#define FLITE_REG_CISTATUS (0x40)
+#define FLITE_REG_CISTATUS_MIPI_VVALID (1 << 22)
+#define FLITE_REG_CISTATUS_MIPI_HVALID (1 << 21)
+#define FLITE_REG_CISTATUS_MIPI_DVALID (1 << 20)
+#define FLITE_REG_CISTATUS_ITU_VSYNC (1 << 14)
+#define FLITE_REG_CISTATUS_ITU_HREFF (1 << 13)
+#define FLITE_REG_CISTATUS_OVFIY (1 << 10)
+#define FLITE_REG_CISTATUS_OVFICB (1 << 9)
+#define FLITE_REG_CISTATUS_OVFICR (1 << 8)
+#define FLITE_REG_CISTATUS_IRQ_SRC_OVERFLOW (1 << 7)
+#define FLITE_REG_CISTATUS_IRQ_SRC_LASTCAPEND (1 << 6)
+#define FLITE_REG_CISTATUS_IRQ_SRC_FRMSTART (1 << 5)
+#define FLITE_REG_CISTATUS_IRQ_SRC_FRMEND (1 << 4)
+#define FLITE_REG_CISTATUS_IRQ_CAM (1 << 0)
+#define FLITE_REG_CISTATUS_IRQ_MASK (0xf << 4)
+
+/* Camera Status2 */
+#define FLITE_REG_CISTATUS2 (0x44)
+#define FLITE_REG_CISTATUS2_LASTCAPEND (1 << 1)
+#define FLITE_REG_CISTATUS2_FRMEND (1 << 0)
+
+/* Camera Status3 */
+#define FLITE_REG_CISTATUS3 0x48
+#define FLITE_REG_CISTATUS3_PRESENT_MASK (0x3F)
+
+/* Qos Threshold */
+#define FLITE_REG_CITHOLD (0xF0)
+#define FLITE_REG_CITHOLD_W_QOS_EN (1 << 30)
+#define FLITE_REG_CITHOLD_WTH_QOS(x) ((x) << 0)
+
+/* Camera General Purpose */
+#define FLITE_REG_CIGENERAL (0xFC)
+#define FLITE_REG_CIGENERAL_CAM_A (0 << 0)
+#define FLITE_REG_CIGENERAL_CAM_B (1 << 0)
+
+#define FLITE_REG_CIFCNTSEQ 0x100
+
+static void flite_hw_set_cam_source_size(unsigned long flite_reg_base,
+ struct fimc_is_frame_info *f_frame)
+{
+ u32 cfg = 0;
+
+ cfg = readl(flite_reg_base + FLITE_REG_CISRCSIZE);
+
+ cfg |= FLITE_REG_CISRCSIZE_SIZE_H(f_frame->o_width);
+ cfg |= FLITE_REG_CISRCSIZE_SIZE_V(f_frame->o_height);
+
+ writel(cfg, flite_reg_base + FLITE_REG_CISRCSIZE);
+
+ cfg = readl(flite_reg_base + FLITE_REG_CIOCAN);
+ cfg |= FLITE_REG_CIOCAN_OCAN_H(f_frame->o_width);
+ cfg |= FLITE_REG_CIOCAN_OCAN_V(f_frame->o_height);
+
+ writel(cfg, flite_reg_base + FLITE_REG_CIOCAN);
+}
+
+static void flite_hw_set_cam_channel(unsigned long flite_reg_base)
+{
+ u32 cfg = 0;
+
+ if (flite_reg_base == (unsigned long)FIMCLITE0_REG_BASE) {
+ cfg = FLITE_REG_CIGENERAL_CAM_A;
+ writel(cfg, FIMCLITE0_REG_BASE + FLITE_REG_CIGENERAL);
+ writel(cfg, FIMCLITE1_REG_BASE + FLITE_REG_CIGENERAL);
+ writel(cfg, FIMCLITE2_REG_BASE + FLITE_REG_CIGENERAL);
+ } else {
+ cfg = FLITE_REG_CIGENERAL_CAM_B;
+ writel(cfg, FIMCLITE0_REG_BASE + FLITE_REG_CIGENERAL);
+ writel(cfg, FIMCLITE1_REG_BASE + FLITE_REG_CIGENERAL);
+ writel(cfg, FIMCLITE2_REG_BASE + FLITE_REG_CIGENERAL);
+ }
+}
+
+void flite_hw_set_capture_start(unsigned long flite_reg_base)
+{
+ u32 cfg = 0;
+
+ cfg = readl(flite_reg_base + FLITE_REG_CIIMGCPT);
+ cfg |= FLITE_REG_CIIMGCPT_IMGCPTEN;
+
+ writel(cfg, flite_reg_base + FLITE_REG_CIIMGCPT);
+}
+
+static void flite_hw_set_capture_stop(unsigned long flite_reg_base)
+{
+ u32 cfg = 0;
+
+ cfg = readl(flite_reg_base + FLITE_REG_CIIMGCPT);
+ cfg &= ~FLITE_REG_CIIMGCPT_IMGCPTEN;
+
+ writel(cfg, flite_reg_base + FLITE_REG_CIIMGCPT);
+}
+
+static int flite_hw_set_source_format(unsigned long flite_reg_base)
+{
+ u32 cfg = 0;
+
+ cfg = readl(flite_reg_base + FLITE_REG_CIGCTRL);
+ cfg |= FLITE_REG_CIGCTRL_RAW10;
+ writel(cfg, flite_reg_base + FLITE_REG_CIGCTRL);
+
+ return 0;
+}
+
+void flite_hw_set_output_dma(unsigned long flite_reg_base, bool enable)
+{
+ u32 cfg = 0;
+ cfg = readl(flite_reg_base + FLITE_REG_CIGCTRL);
+
+ if (enable)
+ cfg &= ~FLITE_REG_CIGCTRL_ODMA_DISABLE;
+ else
+ cfg |= FLITE_REG_CIGCTRL_ODMA_DISABLE;
+
+ writel(cfg, flite_reg_base + FLITE_REG_CIGCTRL);
+}
+
+void flite_hw_set_output_local(unsigned long flite_reg_base, bool enable)
+{
+ u32 cfg = 0;
+ cfg = readl(flite_reg_base + FLITE_REG_CIGCTRL);
+
+ if (enable)
+ cfg &= ~FLITE_REG_CIGCTRL_OLOCAL_DISABLE;
+ else
+ cfg |= FLITE_REG_CIGCTRL_OLOCAL_DISABLE;
+
+ writel(cfg, flite_reg_base + FLITE_REG_CIGCTRL);
+}
+
+/* will use for pattern generation testing
+static void flite_hw_set_test_pattern_enable(void)
+{
+ u32 cfg = 0;
+ cfg = readl(flite_reg_base + FLITE_REG_CIGCTRL);
+ cfg |= FLITE_REG_CIGCTRL_TEST_PATTERN_COLORBAR;
+
+ writel(cfg, flite_reg_base + FLITE_REG_CIGCTRL);
+}
+*/
+
+static void flite_hw_set_config_irq(unsigned long flite_reg_base)
+{
+ u32 cfg = 0;
+ cfg = readl(flite_reg_base + FLITE_REG_CIGCTRL);
+ cfg &= ~(FLITE_REG_CIGCTRL_INVPOLPCLK | FLITE_REG_CIGCTRL_INVPOLVSYNC
+ | FLITE_REG_CIGCTRL_INVPOLHREF);
+
+ writel(cfg, flite_reg_base + FLITE_REG_CIGCTRL);
+}
+
+static void flite_hw_set_interrupt_source(unsigned long flite_reg_base)
+{
+ u32 cfg = 0;
+ cfg = readl(flite_reg_base + FLITE_REG_CIGCTRL);
+
+ /*
+ for checking stop complete
+ */
+ cfg &= ~FLITE_REG_CIGCTRL_IRQ_LASTEN0_DISABLE;
+
+ /*
+ for checking frame done
+ */
+ cfg &= ~FLITE_REG_CIGCTRL_IRQ_ENDEN0_DISABLE;
+
+ writel(cfg, flite_reg_base + FLITE_REG_CIGCTRL);
+}
+
+static void flite_hw_set_interrupt_starten0_disable
+ (unsigned long flite_reg_base)
+{
+ u32 cfg = 0;
+ cfg = readl(flite_reg_base + FLITE_REG_CIGCTRL);
+ cfg |= FLITE_REG_CIGCTRL_IRQ_STARTEN0_DISABLE;
+
+ writel(cfg, flite_reg_base + FLITE_REG_CIGCTRL);
+}
+
+static void flite_hw_set_camera_type(unsigned long flite_reg_base)
+{
+ u32 cfg = 0;
+ cfg = readl(flite_reg_base + FLITE_REG_CIGCTRL);
+
+ cfg |= FLITE_REG_CIGCTRL_SELCAM_MIPI;
+
+ writel(cfg, flite_reg_base + FLITE_REG_CIGCTRL);
+}
+
+static void flite_hw_set_window_offset(unsigned long flite_reg_base,
+ struct fimc_is_frame_info *f_frame)
+{
+ u32 cfg = 0;
+ u32 hoff2, voff2;
+
+ cfg = readl(flite_reg_base + FLITE_REG_CIWDOFST);
+ cfg &= ~(FLITE_REG_CIWDOFST_HOROFF_MASK |
+ FLITE_REG_CIWDOFST_VEROFF_MASK);
+ cfg |= FLITE_REG_CIWDOFST_WINOFSEN |
+ FLITE_REG_CIWDOFST_WINHOROFST(f_frame->offs_h) |
+ FLITE_REG_CIWDOFST_WINVEROFST(f_frame->offs_v);
+
+ writel(cfg, flite_reg_base + FLITE_REG_CIWDOFST);
+
+ hoff2 = f_frame->o_width - f_frame->width - f_frame->offs_h;
+ voff2 = f_frame->o_height - f_frame->height - f_frame->offs_v;
+ cfg = FLITE_REG_CIWDOFST2_WINHOROFST2(hoff2) |
+ FLITE_REG_CIWDOFST2_WINVEROFST2(voff2);
+
+ writel(cfg, flite_reg_base + FLITE_REG_CIWDOFST2);
+}
+
+static void flite_hw_set_last_capture_end_clear(unsigned long flite_reg_base)
+{
+ u32 cfg = 0;
+
+ cfg = readl(flite_reg_base + FLITE_REG_CISTATUS2);
+ cfg &= ~FLITE_REG_CISTATUS2_LASTCAPEND;
+
+ writel(cfg, flite_reg_base + FLITE_REG_CISTATUS2);
+}
+
+int flite_hw_get_present_frame_buffer(unsigned long flite_reg_base)
+{
+ u32 status = 0;
+
+ status = readl(flite_reg_base + FLITE_REG_CISTATUS3);
+ status &= FLITE_REG_CISTATUS3_PRESENT_MASK;
+
+ return status;
+}
+
+int flite_hw_get_status2(unsigned long flite_reg_base)
+{
+ u32 status = 0;
+
+ status = readl(flite_reg_base + FLITE_REG_CISTATUS2);
+
+ return status;
+}
+
+void flite_hw_set_status1(unsigned long flite_reg_base, u32 val)
+{
+ writel(val, flite_reg_base + FLITE_REG_CISTATUS);
+}
+
+int flite_hw_get_status1(unsigned long flite_reg_base)
+{
+ u32 status = 0;
+
+ status = readl(flite_reg_base + FLITE_REG_CISTATUS);
+
+ return status;
+}
+
+int flite_hw_getnclr_status1(unsigned long flite_reg_base)
+{
+ u32 status = 0;
+
+ status = readl(flite_reg_base + FLITE_REG_CISTATUS);
+ writel(0, flite_reg_base + FLITE_REG_CISTATUS);
+
+ return status;
+}
+
+void flite_hw_set_status2(unsigned long flite_reg_base, u32 val)
+{
+ writel(val, flite_reg_base + FLITE_REG_CISTATUS2);
+}
+
+void flite_hw_set_start_addr(unsigned long flite_reg_base, u32 number, u32 addr)
+{
+ u32 target;
+ if (number == 0) {
+ target = flite_reg_base + 0x30;
+ } else if (number >= 1) {
+ number--;
+ target = flite_reg_base + 0x200 + (0x4*number);
+ } else
+ target = 0;
+
+ writel(addr, target);
+}
+
+void flite_hw_set_use_buffer(unsigned long flite_reg_base, u32 number)
+{
+ u32 buffer;
+ buffer = readl(flite_reg_base + FLITE_REG_CIFCNTSEQ);
+ buffer |= 1<<number;
+ writel(buffer, flite_reg_base + FLITE_REG_CIFCNTSEQ);
+}
+
+void flite_hw_set_unuse_buffer(unsigned long flite_reg_base, u32 number)
+{
+ u32 buffer;
+ buffer = readl(flite_reg_base + FLITE_REG_CIFCNTSEQ);
+ buffer &= ~(1<<number);
+ writel(buffer, flite_reg_base + FLITE_REG_CIFCNTSEQ);
+}
+
+u32 flite_hw_get_buffer_seq(unsigned long flite_reg_base)
+{
+ u32 buffer;
+ buffer = readl(flite_reg_base + FLITE_REG_CIFCNTSEQ);
+ return buffer;
+}
+
+int init_fimc_lite(unsigned long mipi_reg_base)
+{
+ int i;
+
+ writel(0, mipi_reg_base + FLITE_REG_CIFCNTSEQ);
+
+ for (i = 0; i < 32; i++)
+ flite_hw_set_start_addr(mipi_reg_base , i, 0xffffffff);
+
+ return 0;
+}
+
+int start_fimc_lite(unsigned long mipi_reg_base,
+ struct fimc_is_frame_info *f_frame)
+{
+ flite_hw_set_cam_channel(mipi_reg_base);
+ flite_hw_set_cam_source_size(mipi_reg_base, f_frame);
+ flite_hw_set_camera_type(mipi_reg_base);
+ flite_hw_set_source_format(mipi_reg_base);
+ /*flite_hw_set_output_dma(mipi_reg_base, false);
+ flite_hw_set_output_local(base_reg, false);*/
+
+ flite_hw_set_interrupt_source(mipi_reg_base);
+ /*flite_hw_set_interrupt_starten0_disable(mipi_reg_base);*/
+ flite_hw_set_config_irq(mipi_reg_base);
+ flite_hw_set_window_offset(mipi_reg_base, f_frame);
+ /* flite_hw_set_test_pattern_enable(); */
+
+ flite_hw_set_last_capture_end_clear(mipi_reg_base);
+ flite_hw_set_capture_start(mipi_reg_base);
+
+ /*dbg_front("lite config : %08X\n",
+ *((unsigned int*)(base_reg + FLITE_REG_CIFCNTSEQ)));*/
+
+ return 0;
+}
+
+int stop_fimc_lite(unsigned long mipi_reg_base)
+{
+ flite_hw_set_capture_stop(mipi_reg_base);
+ return 0;
+}
+
+static void wq_func_automode(struct work_struct *data)
+{
+ struct fimc_is_device_flite *flite;
+ struct fimc_is_device_sensor *sensor;
+ struct fimc_is_device_ischain *ischain;
+
+ flite = container_of(data, struct fimc_is_device_flite, work_queue);
+ sensor = (struct fimc_is_device_sensor *)flite->private_data;
+ ischain = sensor->ischain;
+
+ fimc_is_ischain_isp_buffer_queue(ischain, flite->work);
+}
+
+static void tasklet_func_flite_str(unsigned long data)
+{
+ struct fimc_is_device_flite *flite;
+ struct fimc_is_device_sensor *sensor;
+ struct fimc_is_device_ischain *ischain;
+ struct fimc_is_framemgr *framemgr;
+ struct fimc_is_frame_shot *frame;
+ u32 bstart;
+ u32 fcount;
+
+ flite = (struct fimc_is_device_flite *)data;
+ sensor = (struct fimc_is_device_sensor *)flite->private_data;
+ ischain = sensor->ischain;
+ framemgr = flite->framemgr;
+
+ bstart = flite->tasklet_param_str;
+ fcount = atomic_read(&flite->fcount);
+
+#ifdef DBG_STREAMING
+ printk(KERN_INFO "S%d %d\n", bstart, fcount);
+#endif
+
+ framemgr_e_barrier(framemgr, FMGR_IDX_0 + bstart);
+
+ fimc_is_frame_process_head(framemgr, &frame);
+ if (frame) {
+#ifdef MEASURE_TIME
+#ifndef INTERNAL_TIME
+ do_gettimeofday(&frame->tzone[TM_FLITE_STR]);
+#endif
+#endif
+ frame->fcount = fcount;
+ fimc_is_ischain_camctl(ischain, frame, fcount);
+ fimc_is_ischain_tag(ischain, frame);
+ } else {
+ fimc_is_ischain_camctl(ischain, NULL, fcount);
+
+#ifdef TASKLET_MSG
+ err("process shot is empty");
+#endif
+ fimc_is_frame_print_all(framemgr);
+ }
+
+ framemgr_x_barrier(framemgr, FMGR_IDX_0 + bstart);
+}
+
+static void tasklet_func_flite_end(unsigned long data)
+{
+ struct fimc_is_device_flite *flite;
+ struct fimc_is_device_sensor *sensor;
+ struct fimc_is_framemgr *framemgr;
+ struct fimc_is_frame_shot *frame;
+ u32 index, bdone;
+ u32 fcount;
+
+ flite = (struct fimc_is_device_flite *)data;
+ sensor = (struct fimc_is_device_sensor *)flite->private_data;
+ framemgr = flite->framemgr;
+ bdone = flite->tasklet_param_end;
+
+ fcount = atomic_read(&flite->fcount);
+
+#ifdef DBG_STREAMING
+ printk(KERN_INFO "E%d %d\n", bdone, fcount);
+#endif
+
+ framemgr_e_barrier(framemgr, FMGR_IDX_1 + bdone);
+ spin_lock(&flite->slock_state);
+
+ if (test_bit(bdone, &flite->state)) {
+ fimc_is_frame_process_head(framemgr, &frame);
+ if (frame) {
+#ifdef MEASURE_TIME
+#ifndef INTERNAL_TIME
+ do_gettimeofday(&frame->tzone[TM_FLITE_END]);
+#endif
+#endif
+ index = frame->index;
+ fimc_is_frame_trans_pro_to_com(framemgr, frame);
+
+#ifdef AUTO_MODE
+ if (!work_pending(&flite->work_queue)) {
+ flite->work = index;
+ schedule_work(&flite->work_queue);
+ } else {
+ struct fimc_is_device_ischain *ischain;
+ ischain = sensor->ischain;
+
+ frame->shot_ext->request_scc = 0;
+ frame->shot_ext->request_scp = 0;
+ buffer_done(flite->video, index);
+ err("work pending, %d frame drop", index);
+ fimc_is_frame_print_all(ischain->framemgr);
+ }
+#else
+ buffer_done(flite->video, index);
+#endif
+ fimc_is_frame_request_head(framemgr, &frame);
+ if (frame) {
+ flite_hw_set_start_addr(flite->regs, bdone,
+ frame->dvaddr_buffer[0]);
+ set_bit(bdone, &flite->state);
+ fimc_is_frame_trans_req_to_pro(framemgr, frame);
+ } else {
+ flite_hw_set_unuse_buffer(flite->regs, bdone);
+ clear_bit(bdone, &flite->state);
+#ifdef TASKLET_MSG
+ err("request shot is empty0(%d slot)", bdone);
+#endif
+ fimc_is_frame_print_all(framemgr);
+
+ /*this is debugging ponit for deadlock*/
+ /*
+ fimc_is_ischain_print_status(sensor->ischain);
+ */
+ }
+ } else {
+#ifdef TASKLET_MSG
+ err("process shot is empty(state is invalid(%d, %ld))",
+ bdone, flite->state);
+#endif
+ fimc_is_frame_print_all(framemgr);
+ }
+ } else {
+ fimc_is_frame_request_head(framemgr, &frame);
+ if (frame) {
+ flite_hw_set_start_addr(flite->regs, bdone,
+ frame->dvaddr_buffer[0]);
+ flite_hw_set_use_buffer(flite->regs, bdone);
+ set_bit(bdone, &flite->state);
+ fimc_is_frame_trans_req_to_pro(framemgr, frame);
+ } else {
+#ifdef TASKLET_MSG
+ err("request shot is empty1(%d slot)", bdone);
+#endif
+ fimc_is_frame_print_all(framemgr);
+ }
+ }
+
+ spin_unlock(&flite->slock_state);
+ framemgr_x_barrier(framemgr, FMGR_IDX_1 + bdone);
+}
+
+static irqreturn_t fimc_is_flite_irq_handler(int irq, void *data)
+{
+ u32 status, status1, status2;
+ struct fimc_is_device_flite *flite;
+
+ flite = data;
+ status1 = flite_hw_getnclr_status1(flite->regs);
+ status = status1 & (3<<4);
+ /* status3 = flite_hw_get_present_frame_buffer(flite->regs); */
+
+ if (test_bit(FIMC_IS_FLITE_LAST_CAPTURE, &flite->state))
+ goto exit;
+
+ if (status) {
+ if (status == (3<<4)) {
+#ifdef DBG_FLITEISR
+ printk(KERN_CONT "*");
+#endif
+ /* frame both interrupt since latency */
+ if (flite->sw_checker) {
+#ifdef DBG_FLITEISR
+ printk(KERN_CONT ">");
+#endif
+ /* frame end interrupt */
+ flite->sw_checker = EXPECT_FRAME_START;
+ *notify_fcount = atomic_read(&flite->fcount);
+ flite->tasklet_param_end = flite->sw_trigger;
+ tasklet_schedule(&flite->tasklet_flite_end);
+
+#ifdef DBG_FLITEISR
+ printk(KERN_CONT "<");
+#endif
+ /* frame start interrupt */
+ flite->sw_checker = EXPECT_FRAME_END;
+ if (flite->sw_trigger)
+ flite->sw_trigger = FLITE_A_SLOT_VALID;
+ else
+ flite->sw_trigger = FLITE_B_SLOT_VALID;
+ flite->tasklet_param_str = flite->sw_trigger;
+ atomic_inc(&flite->fcount);
+ tasklet_schedule(&flite->tasklet_flite_str);
+ } else {
+#ifdef DBG_FLITEISR
+ printk(KERN_CONT "<");
+#endif
+ /* frame start interrupt */
+ flite->sw_checker = EXPECT_FRAME_END;
+ if (flite->sw_trigger)
+ flite->sw_trigger = FLITE_A_SLOT_VALID;
+ else
+ flite->sw_trigger = FLITE_B_SLOT_VALID;
+ flite->tasklet_param_str = flite->sw_trigger;
+ atomic_inc(&flite->fcount);
+ tasklet_schedule(&flite->tasklet_flite_str);
+#ifdef DBG_FLITEISR
+ printk(KERN_CONT ">");
+#endif
+ /* frame end interrupt */
+ flite->sw_checker = EXPECT_FRAME_START;
+ *notify_fcount = atomic_read(&flite->fcount);
+ flite->tasklet_param_end = flite->sw_trigger;
+ tasklet_schedule(&flite->tasklet_flite_end);
+ }
+ } else if (status == (2<<4)) {
+#ifdef DBG_FLITEISR
+ printk(KERN_CONT "<");
+#endif
+ /* frame start interrupt */
+ flite->sw_checker = EXPECT_FRAME_END;
+ if (flite->sw_trigger)
+ flite->sw_trigger = FLITE_A_SLOT_VALID;
+ else
+ flite->sw_trigger = FLITE_B_SLOT_VALID;
+ flite->tasklet_param_str = flite->sw_trigger;
+ atomic_inc(&flite->fcount);
+ tasklet_schedule(&flite->tasklet_flite_str);
+ } else {
+#ifdef DBG_FLITEISR
+ printk(KERN_CONT ">");
+#endif
+ /* frame end interrupt */
+ flite->sw_checker = EXPECT_FRAME_START;
+ *notify_fcount = atomic_read(&flite->fcount);
+ flite->tasklet_param_end = flite->sw_trigger;
+ tasklet_schedule(&flite->tasklet_flite_end);
+ }
+ }
+
+ if (status1 & (1<<6)) {
+ /* Last Frame Capture Interrupt */
+ printk(KERN_INFO "[CamIF_0]Last Frame Capture\n");
+
+ /* Clear LastCaptureEnd bit */
+ status2 = flite_hw_get_status2(flite->regs);
+ status2 &= ~(0x1 << 1);
+ flite_hw_set_status2(flite->regs, status2);
+
+ /* Notify last capture */
+ set_bit(FIMC_IS_FLITE_LAST_CAPTURE, &flite->state);
+ wake_up(&flite->wait_queue);
+ }
+
+ if (status1 & (1<<8)) {
+ u32 ciwdofst;
+
+ err("[CamIF_0]Overflow Cr\n");
+ ciwdofst = readl(flite->regs + 0x10);
+ ciwdofst |= (0x1 << 14);
+ writel(ciwdofst, flite->regs + 0x10);
+ ciwdofst &= ~(0x1 << 14);
+ writel(ciwdofst, flite->regs + 0x10);
+ /*uCIWDOFST |= (0x1 << 14);*/
+ }
+
+ if (status1 & (1<<9)) {
+ u32 ciwdofst;
+
+ err("[CamIF_0]Overflow Cb\n");
+ ciwdofst = readl(flite->regs + 0x10);
+ ciwdofst |= (0x1 << 15);
+ writel(ciwdofst, flite->regs + 0x10);
+ ciwdofst &= ~(0x1 << 15);
+ writel(ciwdofst, flite->regs + 0x10);
+ /*uCIWDOFST |= (0x1 << 15);*/
+ }
+
+ if (status1 & (1<<10)) {
+ u32 ciwdofst;
+
+ err("[CamIF_0]Overflow Y\n");
+ ciwdofst = readl(flite->regs + 0x10);
+ ciwdofst |= (0x1 << 30);
+ writel(ciwdofst, flite->regs + 0x10);
+ ciwdofst &= ~(0x1 << 30);
+ writel(ciwdofst, flite->regs + 0x10);
+ /*uCIWDOFST |= (0x1 << 30);*/
+ }
+
+exit:
+ return IRQ_HANDLED;
+}
+
+
+int fimc_is_flite_probe(struct fimc_is_device_flite *this,
+ struct fimc_is_video_common *video,
+ struct fimc_is_framemgr *framemgr,
+ u32 channel,
+ u32 data)
+{
+ int ret = 0;
+
+ this->channel = channel;
+ this->framemgr = framemgr;
+ this->video = video;
+ this->private_data = data;
+ spin_lock_init(&this->slock_state);
+ init_waitqueue_head(&this->wait_queue);
+
+ tasklet_init(&this->tasklet_flite_str,
+ tasklet_func_flite_str,
+ (unsigned long)this);
+
+ tasklet_init(&this->tasklet_flite_end,
+ tasklet_func_flite_end,
+ (unsigned long)this);
+
+ if (channel == FLITE_ID_A) {
+ this->regs = (unsigned long)S5P_VA_FIMCLITE0;
+
+ ret = request_irq(IRQ_FIMC_LITE0,
+ fimc_is_flite_irq_handler,
+ 0,
+ "fimc-lite0",
+ this);
+ if (ret)
+ err("request_irq(L0) failed\n");
+ } else if (channel == FLITE_ID_B) {
+ this->regs = (unsigned long)S5P_VA_FIMCLITE1;
+
+ ret = request_irq(IRQ_FIMC_LITE1,
+ fimc_is_flite_irq_handler,
+ 0,
+ "fimc-lite1",
+ this);
+ if (ret)
+ err("request_irq(L1) failed\n");
+ } else
+ err("unresolved channel input");
+
+ INIT_WORK(&this->work_queue, wq_func_automode);
+
+ return ret;
+}
+
+int fimc_is_flite_open(struct fimc_is_device_flite *this)
+{
+ int ret = 0;
+
+ atomic_set(&this->fcount, 0);
+
+ clear_bit(FIMC_IS_FLITE_LAST_CAPTURE, &this->state);
+ clear_bit(FLITE_A_SLOT_VALID, &this->state);
+ clear_bit(FLITE_B_SLOT_VALID, &this->state);
+
+ return ret;
+}
+
+int fimc_is_flite_start(struct fimc_is_device_flite *this,
+ struct fimc_is_frame_info *frame,
+ struct fimc_is_video_common *video)
+{
+ int ret = 0;
+ unsigned long flags;
+ struct fimc_is_frame_shot *item;
+ struct fimc_is_framemgr *framemgr;
+
+ framemgr = this->framemgr;
+
+ this->sw_trigger = FLITE_B_SLOT_VALID;
+ this->sw_checker = EXPECT_FRAME_START;
+ this->tasklet_param_str = 0;
+ this->tasklet_param_end = 0;
+
+ clear_bit(FIMC_IS_FLITE_LAST_CAPTURE, &this->state);
+ init_fimc_lite(this->regs);
+
+ framemgr_e_barrier_irqs(framemgr, 0, flags);
+
+ flite_hw_set_use_buffer(this->regs, 0);
+ flite_hw_set_start_addr(this->regs, 0, video->buf_dva[0][0]);
+ set_bit(FLITE_A_SLOT_VALID, &this->state);
+ fimc_is_frame_request_head(framemgr, &item);
+ fimc_is_frame_trans_req_to_pro(framemgr, item);
+
+ flite_hw_set_use_buffer(this->regs, 1);
+ flite_hw_set_start_addr(this->regs, 1, video->buf_dva[1][0]);
+ set_bit(FLITE_B_SLOT_VALID, &this->state);
+ fimc_is_frame_request_head(framemgr, &item);
+ fimc_is_frame_trans_req_to_pro(framemgr, item);
+
+ framemgr_x_barrier_irqr(framemgr, 0, flags);
+
+ /*flite_hw_set_use_buffer(this->regs, 0);*/
+ flite_hw_set_output_dma(this->regs, true);
+ flite_hw_set_output_local(this->regs, false);
+
+ start_fimc_lite(this->regs, frame);
+
+ return ret;
+}
+
+int fimc_is_flite_stop(struct fimc_is_device_flite *this)
+{
+ int ret = 0;
+
+ stop_fimc_lite(this->regs);
+
+ dbg_back("waiting last capture\n");
+ ret = wait_event_timeout(this->wait_queue,
+ test_bit(FIMC_IS_FLITE_LAST_CAPTURE, &this->state),
+ FIMC_IS_FLITE_STOP_TIMEOUT);
+ if (!ret) {
+ /* forcely stop */
+ err("last capture timeout:%s\n", __func__);
+ stop_fimc_lite(this->regs);
+ msleep(60);
+ set_bit(FIMC_IS_FLITE_LAST_CAPTURE, &this->state);
+ ret = -ETIME;
+ } else
+ ret = 0;
+
+ return ret;
+}
diff --git a/drivers/media/video/exynos/fimc-is-mc2/fimc-is-device-flite.h b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-device-flite.h
new file mode 100644
index 0000000..37c2e61
--- /dev/null
+++ b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-device-flite.h
@@ -0,0 +1,74 @@
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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.
+ */
+
+#ifndef FIMC_IS_DEVICE_FLITE_H
+#define FIMC_IS_DEVICE_FLITE_H
+
+#define EXPECT_FRAME_START 0
+#define EXPECT_FRAME_END 1
+
+struct fimc_is_frame_info {
+ u32 o_width;
+ u32 o_height;
+ u32 width;
+ u32 height;
+ u32 offs_h;
+ u32 offs_v;
+};
+
+enum fimc_is_flite_state {
+ /* buffer state*/
+ FLITE_A_SLOT_VALID = 0,
+ FLITE_B_SLOT_VALID,
+ /* global state */
+ FIMC_IS_FLITE_LAST_CAPTURE
+};
+
+struct fimc_is_device_flite {
+ atomic_t fcount;
+ wait_queue_head_t wait_queue;
+
+ unsigned long state;
+ spinlock_t slock_state;
+
+ struct fimc_is_video_common *video;
+ u32 tasklet_param_str;
+ struct tasklet_struct tasklet_flite_str;
+ u32 tasklet_param_end;
+ struct tasklet_struct tasklet_flite_end;
+
+ u32 channel;
+ u32 regs;
+
+ struct fimc_is_framemgr *framemgr;
+
+ u32 work;
+ u32 sw_checker;
+ u32 sw_trigger;
+ struct work_struct work_queue;
+
+ u32 private_data;
+};
+
+int fimc_is_flite_probe(struct fimc_is_device_flite *this,
+ struct fimc_is_video_common *video,
+ struct fimc_is_framemgr *framemgr,
+ u32 channel,
+ u32 data);
+int fimc_is_flite_open(struct fimc_is_device_flite *this);
+int fimc_is_flite_start(struct fimc_is_device_flite *this,
+ struct fimc_is_frame_info *frame,
+ struct fimc_is_video_common *video);
+int fimc_is_flite_stop(struct fimc_is_device_flite *this);
+
+extern u32 __iomem *notify_fcount;
+
+#endif
diff --git a/drivers/media/video/exynos/fimc-is-mc2/fimc-is-device-ischain.c b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-device-ischain.c
new file mode 100755
index 0000000..7c63803
--- /dev/null
+++ b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-device-ischain.c
@@ -0,0 +1,4319 @@
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ * exynos5 fimc-is video functions
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <mach/videonode.h>
+#include <media/exynos_mc.h>
+#include <linux/cma.h>
+#include <asm/cacheflush.h>
+#include <asm/pgtable.h>
+#include <linux/firmware.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
+#include <linux/videodev2.h>
+#include <linux/videodev2_exynos_camera.h>
+#include <linux/videodev2_exynos_media.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/vmalloc.h>
+#include <linux/kthread.h>
+#include <linux/pm_qos.h>
+#include <linux/debugfs.h>
+
+#include <mach/map.h>
+#include <mach/regs-clock.h>
+#include <mach/exynos5_bus.h>
+#include <plat/bts.h>
+
+#include "fimc-is-time.h"
+#include "fimc-is-core.h"
+#include "fimc-is-param.h"
+#include "fimc-is-cmd.h"
+#include "fimc-is-regs.h"
+#include "fimc-is-err.h"
+#include "fimc-is-video.h"
+
+#include "fimc-is-device-ischain.h"
+
+#define SDCARD_FW
+#define FIMC_IS_SETFILE_SDCARD_PATH "/data/"
+#define FIMC_IS_FW "fimc_is_fw2.bin"
+#define FIMC_IS_FW_SDCARD "/data/fimc_is_fw2.bin"
+#define FIMC_IS_FW_BASE_MASK ((1 << 26) - 1)
+#define FIMC_IS_VERSION_SIZE 39
+
+#define FIMC_IS_MAX_CAL_SIZE (1196)
+#define FIMC_IS_CAL_START_ADDR (0x8D0000)
+
+/* Default setting values */
+#define DEFAULT_PREVIEW_STILL_WIDTH (1280) /* sensor margin : 16 */
+#define DEFAULT_PREVIEW_STILL_HEIGHT (720) /* sensor margin : 12 */
+#define DEFAULT_CAPTURE_VIDEO_WIDTH (1920)
+#define DEFAULT_CAPTURE_VIDEO_HEIGHT (1080)
+#define DEFAULT_CAPTURE_STILL_WIDTH (2560)
+#define DEFAULT_CAPTURE_STILL_HEIGHT (1920)
+#define DEFAULT_CAPTURE_STILL_CROP_WIDTH (2560)
+#define DEFAULT_CAPTURE_STILL_CROP_HEIGHT (1440)
+#define DEFAULT_PREVIEW_VIDEO_WIDTH (640)
+#define DEFAULT_PREVIEW_VIDEO_HEIGHT (480)
+
+static struct pm_qos_request pm_qos_req_cpu;
+static struct exynos5_bus_int_handle *isp_int_handle_min;
+static struct exynos5_bus_mif_handle *isp_mif_handle_min;
+
+#ifdef FW_DEBUG
+#define DEBUG_FS_ROOT_NAME "fimc-is"
+#define DEBUG_FS_FILE_NAME "isfw-msg"
+static struct dentry *debugfs_root;
+static struct dentry *debugfs_file;
+
+static int isfw_debug_open(struct inode *inode, struct file *file)
+{
+ if (inode->i_private)
+ file->private_data = inode->i_private;
+
+ return 0;
+}
+
+static int isfw_debug_read(struct file *file, char __user *user_buf,
+ size_t buf_len, loff_t *ppos)
+{
+ int debug_cnt;
+ char *debug;
+ int count1, count2;
+ struct fimc_is_device_ischain *ischain;
+
+ count1 = 0;
+ count2 = 0;
+ debug_cnt = 0;
+ ischain = (struct fimc_is_device_ischain *)file->private_data;
+
+ if (!ischain) {
+ err("file->private_data is null");
+ return 0;
+ }
+
+ if (!test_bit(FIMC_IS_ISCHAIN_OPEN, &ischain->state)) {
+ err("isp video node is not open");
+ goto exit;
+ }
+
+ if (!test_bit(FIMC_IS_ISCHAIN_POWER_ON, &ischain->state)) {
+ err("firmware is not loaded");
+ goto exit;
+ }
+
+ vb2_ion_sync_for_device(ischain->minfo.fw_cookie, DEBUG_OFFSET,
+ DEBUG_CNT, DMA_FROM_DEVICE);
+
+ debug_cnt = *((int *)(ischain->minfo.kvaddr + DEBUGCTL_OFFSET))
+ - DEBUG_OFFSET;
+
+ if (ischain->debug_cnt > debug_cnt) {
+ count1 = DEBUG_CNT - ischain->debug_cnt;
+ count2 = debug_cnt;
+ } else {
+ count1 = debug_cnt - ischain->debug_cnt;
+ count2 = 0;
+ }
+
+ if (count1) {
+ debug = (char *)(ischain->minfo.kvaddr + DEBUG_OFFSET +
+ ischain->debug_cnt);
+
+ if (count1 > buf_len)
+ count1 = buf_len;
+
+ memcpy(user_buf, debug, count1);
+ ischain->debug_cnt += count1;
+ }
+
+ if (count1 == buf_len) {
+ count2 = 0;
+ goto exit;
+ }
+
+ if (count2) {
+ ischain->debug_cnt = 0;
+ debug = (char *)(ischain->minfo.kvaddr + DEBUG_OFFSET);
+
+ if ((count1 + count2) > buf_len)
+ count2 = buf_len - count1;
+
+ memcpy(user_buf, debug, count2);
+ ischain->debug_cnt += count2;
+ }
+
+exit:
+ /* this printk need to be remained for debugging */
+ /*printk(KERN_INFO "buffer point(%d:%d), copy size : %d\n",
+ debug_cnt, ischain->debug_cnt, (count1 + count2));*/
+ return count1 + count2;
+}
+
+static const struct file_operations debug_fops = {
+ .open = isfw_debug_open,
+ .read = isfw_debug_read,
+ .llseek = default_llseek
+};
+
+#endif
+
+static const struct sensor_param init_sensor_param = {
+ .frame_rate = {
+ .frame_rate = 30,
+ },
+};
+
+static const struct isp_param init_isp_param = {
+ .control = {
+ .cmd = CONTROL_COMMAND_START,
+ .bypass = CONTROL_BYPASS_DISABLE,
+ .err = CONTROL_ERROR_NO,
+ },
+ .otf_input = {
+ .cmd = OTF_INPUT_COMMAND_ENABLE,
+ .width = DEFAULT_CAPTURE_STILL_WIDTH,
+ .height = DEFAULT_CAPTURE_STILL_HEIGHT,
+ .format = OTF_INPUT_FORMAT_BAYER,
+ .bitwidth = OTF_INPUT_BIT_WIDTH_10BIT,
+ .order = OTF_INPUT_ORDER_BAYER_GR_BG,
+ .crop_offset_x = 0,
+ .crop_offset_y = 0,
+ .crop_width = 0,
+ .crop_height = 0,
+ .frametime_min = 0,
+ .frametime_max = 33333,
+ .err = OTF_INPUT_ERROR_NO,
+ },
+ .dma1_input = {
+ .cmd = DMA_INPUT_COMMAND_DISABLE,
+ .width = 0,
+ .height = 0,
+ .format = 0,
+ .bitwidth = 0,
+ .plane = 0,
+ .order = 0,
+ .buffer_number = 0,
+ .buffer_address = 0,
+ .err = 0,
+ },
+ .dma2_input = {
+ .cmd = DMA_INPUT_COMMAND_DISABLE,
+ .width = 0, .height = 0,
+ .format = 0, .bitwidth = 0, .plane = 0,
+ .order = 0, .buffer_number = 0, .buffer_address = 0,
+ .err = 0,
+ },
+ .aa = {
+ .cmd = ISP_AA_COMMAND_START,
+ .target = ISP_AA_TARGET_AF | ISP_AA_TARGET_AE |
+ ISP_AA_TARGET_AWB,
+ .mode = 0,
+ .scene = 0,
+ .sleep = 0,
+ .uiAfFace = 0,
+ .touch_x = 0, .touch_y = 0,
+ .manual_af_setting = 0,
+ .err = ISP_AF_ERROR_NO,
+ },
+ .flash = {
+ .cmd = ISP_FLASH_COMMAND_DISABLE,
+ .redeye = ISP_FLASH_REDEYE_DISABLE,
+ .err = ISP_FLASH_ERROR_NO,
+ },
+ .awb = {
+ .cmd = ISP_AWB_COMMAND_AUTO,
+ .illumination = 0,
+ .err = ISP_AWB_ERROR_NO,
+ },
+ .effect = {
+ .cmd = ISP_IMAGE_EFFECT_DISABLE,
+ .err = ISP_IMAGE_EFFECT_ERROR_NO,
+ },
+ .iso = {
+ .cmd = ISP_ISO_COMMAND_AUTO,
+ .value = 0,
+ .err = ISP_ISO_ERROR_NO,
+ },
+ .adjust = {
+ .cmd = ISP_ADJUST_COMMAND_AUTO,
+ .contrast = 0,
+ .saturation = 0,
+ .sharpness = 0,
+ .exposure = 0,
+ .brightness = 0,
+ .hue = 0,
+ .err = ISP_ADJUST_ERROR_NO,
+ },
+ .metering = {
+ .cmd = ISP_METERING_COMMAND_CENTER,
+ .win_pos_x = 0, .win_pos_y = 0,
+ .win_width = DEFAULT_CAPTURE_STILL_WIDTH,
+ .win_height = DEFAULT_CAPTURE_STILL_HEIGHT,
+ .err = ISP_METERING_ERROR_NO,
+ },
+ .afc = {
+ .cmd = ISP_AFC_COMMAND_AUTO,
+ .manual = 0, .err = ISP_AFC_ERROR_NO,
+ },
+ .otf_output = {
+ .cmd = OTF_OUTPUT_COMMAND_ENABLE,
+ .width = DEFAULT_CAPTURE_STILL_WIDTH,
+ .height = DEFAULT_CAPTURE_STILL_HEIGHT,
+ .format = OTF_OUTPUT_FORMAT_YUV444,
+ .bitwidth = OTF_OUTPUT_BIT_WIDTH_12BIT,
+ .order = OTF_OUTPUT_ORDER_BAYER_GR_BG,
+ .uiCropOffsetX = 0,
+ .uiCropOffsetX = 0,
+ .err = OTF_OUTPUT_ERROR_NO,
+ },
+ .dma1_output = {
+ .cmd = DMA_OUTPUT_COMMAND_DISABLE,
+ .dma_out_mask = 0,
+ .width = DEFAULT_CAPTURE_STILL_WIDTH,
+ .height = DEFAULT_CAPTURE_STILL_HEIGHT,
+ .format = DMA_INPUT_FORMAT_YUV444,
+ .bitwidth = DMA_INPUT_BIT_WIDTH_8BIT,
+ .plane = DMA_INPUT_PLANE_1,
+ .order = DMA_INPUT_ORDER_YCbCr,
+ .buffer_number = 0,
+ .buffer_address = 0,
+ .err = DMA_OUTPUT_ERROR_NO,
+ },
+ .dma2_output = {
+ .cmd = DMA_OUTPUT_COMMAND_DISABLE,
+ .width = DEFAULT_CAPTURE_STILL_WIDTH,
+ .height = DEFAULT_CAPTURE_STILL_HEIGHT,
+ .format = DMA_OUTPUT_FORMAT_BAYER,
+ .bitwidth = DMA_OUTPUT_BIT_WIDTH_12BIT,
+ .plane = DMA_OUTPUT_PLANE_1,
+ .order = DMA_OUTPUT_ORDER_GB_BG,
+ .buffer_number = 0,
+ .buffer_address = 0,
+ .dma_out_mask = 0xFFFFFFFF,
+ .err = DMA_OUTPUT_ERROR_NO,
+ },
+};
+
+static const struct drc_param init_drc_param = {
+ .control = {
+ .cmd = CONTROL_COMMAND_START,
+ .bypass = CONTROL_BYPASS_ENABLE,
+ .err = CONTROL_ERROR_NO,
+ },
+ .otf_input = {
+ .cmd = OTF_INPUT_COMMAND_ENABLE,
+ .width = DEFAULT_CAPTURE_STILL_WIDTH,
+ .height = DEFAULT_CAPTURE_STILL_HEIGHT,
+ .format = OTF_INPUT_FORMAT_YUV444,
+ .bitwidth = OTF_INPUT_BIT_WIDTH_12BIT,
+ .order = OTF_INPUT_ORDER_BAYER_GR_BG,
+ .err = OTF_INPUT_ERROR_NO,
+ },
+ .dma_input = {
+ .cmd = DMA_INPUT_COMMAND_DISABLE,
+ .width = DEFAULT_CAPTURE_STILL_WIDTH,
+ .height = DEFAULT_CAPTURE_STILL_HEIGHT,
+ .format = DMA_INPUT_FORMAT_YUV444,
+ .bitwidth = DMA_INPUT_BIT_WIDTH_8BIT,
+ .plane = DMA_INPUT_PLANE_1,
+ .order = DMA_INPUT_ORDER_YCbCr,
+ .buffer_number = 0,
+ .buffer_address = 0,
+ .err = 0,
+ },
+ .otf_output = {
+ .cmd = OTF_OUTPUT_COMMAND_ENABLE,
+ .width = DEFAULT_CAPTURE_STILL_WIDTH,
+ .height = DEFAULT_CAPTURE_STILL_HEIGHT,
+ .format = OTF_OUTPUT_FORMAT_YUV444,
+ .bitwidth = OTF_INPUT_BIT_WIDTH_8BIT,
+ .order = OTF_OUTPUT_ORDER_BAYER_GR_BG,
+ .uiCropOffsetX = 0,
+ .uiCropOffsetX = 0,
+ .err = OTF_OUTPUT_ERROR_NO,
+ },
+};
+
+static const struct scalerc_param init_scalerc_param = {
+ .control = {
+ .cmd = CONTROL_COMMAND_START,
+ .bypass = CONTROL_BYPASS_ENABLE,
+ .err = CONTROL_ERROR_NO,
+ },
+ .otf_input = {
+ .cmd = OTF_INPUT_COMMAND_ENABLE,
+ .width = DEFAULT_CAPTURE_STILL_WIDTH,
+ .height = DEFAULT_CAPTURE_STILL_HEIGHT,
+ .format = OTF_INPUT_FORMAT_YUV444,
+ .bitwidth = OTF_INPUT_BIT_WIDTH_12BIT,
+ .order = OTF_INPUT_ORDER_BAYER_GR_BG,
+ .crop_offset_x = 0,
+ .crop_offset_y = 0,
+ .crop_width = 0,
+ .crop_height = 0,
+ .err = OTF_INPUT_ERROR_NO,
+ },
+ .effect = {
+ .cmd = 0,
+ .err = 0,
+ },
+ .input_crop = {
+ .cmd = OTF_INPUT_COMMAND_ENABLE,
+ .pos_x = 0,
+ .pos_y = 0,
+ .crop_width = DEFAULT_CAPTURE_STILL_CROP_WIDTH,
+ .crop_height = DEFAULT_CAPTURE_STILL_CROP_HEIGHT,
+ .in_width = DEFAULT_CAPTURE_STILL_WIDTH,
+ .in_height = DEFAULT_CAPTURE_STILL_HEIGHT,
+ .out_width = DEFAULT_CAPTURE_VIDEO_WIDTH,
+ .out_height = DEFAULT_CAPTURE_VIDEO_HEIGHT,
+ .err = 0,
+ },
+ .output_crop = {
+ .cmd = SCALER_CROP_COMMAND_DISABLE,
+ .pos_x = 0,
+ .pos_y = 0,
+ .crop_width = DEFAULT_CAPTURE_STILL_WIDTH,
+ .crop_height = DEFAULT_CAPTURE_STILL_HEIGHT,
+ .format = DMA_OUTPUT_FORMAT_YUV422,
+ .err = 0,
+ },
+ .otf_output = {
+ .cmd = OTF_OUTPUT_COMMAND_ENABLE,
+ .width = DEFAULT_CAPTURE_VIDEO_WIDTH,
+ .height = DEFAULT_CAPTURE_VIDEO_HEIGHT,
+ .format = OTF_OUTPUT_FORMAT_YUV444,
+ .bitwidth = OTF_OUTPUT_BIT_WIDTH_8BIT,
+ .order = OTF_OUTPUT_ORDER_BAYER_GR_BG,
+ .uiCropOffsetX = 0,
+ .uiCropOffsetX = 0,
+ .err = OTF_OUTPUT_ERROR_NO,
+ },
+ .dma_output = {
+ .cmd = DMA_OUTPUT_COMMAND_DISABLE,
+ .width = DEFAULT_CAPTURE_STILL_WIDTH,
+ .height = DEFAULT_CAPTURE_STILL_HEIGHT,
+ .format = DMA_OUTPUT_FORMAT_YUV422,
+ .bitwidth = DMA_OUTPUT_BIT_WIDTH_8BIT,
+ .plane = DMA_OUTPUT_PLANE_1,
+ .order = DMA_OUTPUT_ORDER_CrYCbY,
+ .buffer_number = 0,
+ .buffer_address = 0,
+ .dma_out_mask = 0xffff,
+ .reserved[0] = 2, /* unscaled*/
+ .err = DMA_OUTPUT_ERROR_NO,
+ },
+};
+
+static const struct odc_param init_odc_param = {
+ .control = {
+ .cmd = CONTROL_COMMAND_START,
+ .bypass = CONTROL_BYPASS_ENABLE,
+ .err = CONTROL_ERROR_NO,
+ },
+ .otf_input = {
+ .cmd = OTF_INPUT_COMMAND_ENABLE,
+ .width = DEFAULT_CAPTURE_VIDEO_WIDTH,
+ .height = DEFAULT_CAPTURE_VIDEO_HEIGHT,
+ .format = OTF_INPUT_FORMAT_YUV444,
+ .bitwidth = OTF_INPUT_BIT_WIDTH_8BIT,
+ .order = OTF_INPUT_ORDER_BAYER_GR_BG,
+ .crop_offset_x = 0,
+ .crop_offset_y = 0,
+ .crop_width = 0,
+ .crop_height = 0,
+ .err = OTF_INPUT_ERROR_NO,
+ },
+ .otf_output = {
+ .cmd = OTF_OUTPUT_COMMAND_ENABLE,
+ .width = DEFAULT_CAPTURE_VIDEO_WIDTH,
+ .height = DEFAULT_CAPTURE_VIDEO_HEIGHT,
+ .format = OTF_OUTPUT_FORMAT_YUV422,
+ .bitwidth = OTF_OUTPUT_BIT_WIDTH_8BIT,
+ .order = OTF_OUTPUT_ORDER_BAYER_GR_BG,
+ .uiCropOffsetX = 0,
+ .uiCropOffsetX = 0,
+ .err = OTF_OUTPUT_ERROR_NO,
+ },
+};
+
+static const struct dis_param init_dis_param = {
+ .control = {
+ .cmd = CONTROL_COMMAND_START,
+ .bypass = CONTROL_BYPASS_ENABLE,
+ .err = CONTROL_ERROR_NO,
+ },
+ .otf_input = {
+ .cmd = OTF_INPUT_COMMAND_ENABLE,
+ .width = DEFAULT_CAPTURE_VIDEO_WIDTH,
+ .height = DEFAULT_CAPTURE_VIDEO_HEIGHT,
+ .format = OTF_INPUT_FORMAT_YUV422,
+ .bitwidth = OTF_INPUT_BIT_WIDTH_8BIT,
+ .order = OTF_INPUT_ORDER_BAYER_GR_BG,
+ .crop_offset_x = 0,
+ .crop_offset_y = 0,
+ .crop_width = 0,
+ .crop_height = 0,
+ .err = OTF_INPUT_ERROR_NO,
+ },
+ .otf_output = {
+ .cmd = OTF_OUTPUT_COMMAND_ENABLE,
+ .width = DEFAULT_CAPTURE_VIDEO_WIDTH,
+ .height = DEFAULT_CAPTURE_VIDEO_HEIGHT,
+ .format = OTF_OUTPUT_FORMAT_YUV422,
+ .bitwidth = OTF_OUTPUT_BIT_WIDTH_8BIT,
+ .order = OTF_OUTPUT_ORDER_BAYER_GR_BG,
+ .uiCropOffsetX = 0,
+ .uiCropOffsetX = 0,
+ .err = OTF_OUTPUT_ERROR_NO,
+ },
+};
+static const struct tdnr_param init_tdnr_param = {
+ .control = {
+ .cmd = CONTROL_COMMAND_START,
+ .bypass = CONTROL_BYPASS_ENABLE,
+ .err = CONTROL_ERROR_NO,
+ },
+ .otf_input = {
+ .cmd = OTF_INPUT_COMMAND_ENABLE,
+ .width = DEFAULT_CAPTURE_VIDEO_WIDTH,
+ .height = DEFAULT_CAPTURE_VIDEO_HEIGHT,
+ .format = OTF_INPUT_FORMAT_YUV422,
+ .bitwidth = OTF_INPUT_BIT_WIDTH_8BIT,
+ .order = OTF_INPUT_ORDER_BAYER_GR_BG,
+ .err = OTF_INPUT_ERROR_NO,
+ },
+ .frame = {
+ .cmd = 0,
+ .err = 0,
+ },
+ .otf_output = {
+ .cmd = OTF_OUTPUT_COMMAND_ENABLE,
+ .width = DEFAULT_CAPTURE_VIDEO_WIDTH,
+ .height = DEFAULT_CAPTURE_VIDEO_HEIGHT,
+ .format = OTF_OUTPUT_FORMAT_YUV444,
+ .bitwidth = OTF_INPUT_BIT_WIDTH_8BIT,
+ .order = OTF_OUTPUT_ORDER_BAYER_GR_BG,
+ .uiCropOffsetX = 0,
+ .uiCropOffsetX = 0,
+ .err = OTF_OUTPUT_ERROR_NO,
+ },
+ .dma_output = {
+ .cmd = DMA_OUTPUT_COMMAND_DISABLE,
+ .width = DEFAULT_CAPTURE_VIDEO_WIDTH,
+ .height = DEFAULT_CAPTURE_VIDEO_HEIGHT,
+ .format = DMA_OUTPUT_FORMAT_YUV420,
+ .bitwidth = DMA_OUTPUT_BIT_WIDTH_8BIT,
+ .plane = DMA_OUTPUT_PLANE_2,
+ .order = DMA_OUTPUT_ORDER_CbCr,
+ .buffer_number = 0,
+ .buffer_address = 0,
+ .dma_out_mask = 0xffff,
+ .err = DMA_OUTPUT_ERROR_NO,
+ },
+};
+
+static const struct scalerp_param init_scalerp_param = {
+ .control = {
+ .cmd = CONTROL_COMMAND_START,
+ .bypass = CONTROL_BYPASS_ENABLE,
+ .err = CONTROL_ERROR_NO,
+ },
+ .otf_input = {
+ .cmd = OTF_INPUT_COMMAND_ENABLE,
+ .width = DEFAULT_CAPTURE_VIDEO_WIDTH,
+ .height = DEFAULT_CAPTURE_VIDEO_HEIGHT,
+ .format = OTF_INPUT_FORMAT_YUV444,
+ .bitwidth = OTF_INPUT_BIT_WIDTH_8BIT,
+ .order = OTF_INPUT_ORDER_BAYER_GR_BG,
+ .crop_offset_x = 0,
+ .crop_offset_y = 0,
+ .crop_width = 0,
+ .crop_height = 0,
+ .err = OTF_INPUT_ERROR_NO,
+ },
+ .effect = {
+ .cmd = 0,
+ .err = 0,
+ },
+ .input_crop = {
+ .cmd = OTF_INPUT_COMMAND_ENABLE,
+ .pos_x = 0,
+ .pos_y = 0,
+ .crop_width = DEFAULT_CAPTURE_VIDEO_WIDTH,
+ .crop_height = DEFAULT_CAPTURE_VIDEO_HEIGHT,
+ .in_width = DEFAULT_CAPTURE_VIDEO_WIDTH,
+ .in_height = DEFAULT_CAPTURE_VIDEO_HEIGHT,
+ .out_width = DEFAULT_PREVIEW_STILL_WIDTH,
+ .out_height = DEFAULT_PREVIEW_STILL_HEIGHT,
+ .err = 0,
+ },
+ .output_crop = {
+ .cmd = SCALER_CROP_COMMAND_DISABLE,
+ .pos_x = 0,
+ .pos_y = 0,
+ .crop_width = DEFAULT_PREVIEW_STILL_WIDTH,
+ .crop_height = DEFAULT_PREVIEW_STILL_HEIGHT,
+ .format = OTF_OUTPUT_FORMAT_YUV420,
+ .err = 0,
+ },
+ .rotation = {
+ .cmd = 0,
+ .err = 0,
+ },
+ .flip = {
+ .cmd = 0,
+ .err = 0,
+ },
+ .otf_output = {
+ .cmd = OTF_OUTPUT_COMMAND_ENABLE,
+ .width = DEFAULT_PREVIEW_STILL_WIDTH,
+ .height = DEFAULT_PREVIEW_STILL_HEIGHT,
+ .format = OTF_INPUT_FORMAT_YUV444,
+ .bitwidth = OTF_INPUT_BIT_WIDTH_8BIT,
+ .order = OTF_OUTPUT_ORDER_BAYER_GR_BG,
+ .uiCropOffsetX = 0,
+ .uiCropOffsetX = 0,
+ .err = OTF_OUTPUT_ERROR_NO,
+ },
+ .dma_output = {
+ .cmd = DMA_OUTPUT_COMMAND_DISABLE,
+ .width = DEFAULT_PREVIEW_STILL_WIDTH,
+ .height = DEFAULT_PREVIEW_STILL_HEIGHT,
+ .format = OTF_OUTPUT_FORMAT_YUV420,
+ .bitwidth = DMA_OUTPUT_BIT_WIDTH_8BIT,
+ .plane = DMA_OUTPUT_PLANE_3,
+ .order = DMA_OUTPUT_ORDER_NO,
+ .buffer_number = 0,
+ .buffer_address = 0,
+ .dma_out_mask = 0xffff,
+ .err = DMA_OUTPUT_ERROR_NO,
+ },
+};
+
+static const struct fd_param init_fd_param = {
+ .control = {
+ .cmd = CONTROL_COMMAND_STOP,
+ .bypass = CONTROL_BYPASS_DISABLE,
+ .err = CONTROL_ERROR_NO,
+ },
+ .otf_input = {
+ .cmd = OTF_INPUT_COMMAND_ENABLE,
+ .width = DEFAULT_PREVIEW_STILL_WIDTH,
+ .height = DEFAULT_PREVIEW_STILL_HEIGHT,
+ .format = OTF_INPUT_FORMAT_YUV444,
+ .bitwidth = OTF_INPUT_BIT_WIDTH_8BIT,
+ .order = OTF_INPUT_ORDER_BAYER_GR_BG,
+ .err = OTF_INPUT_ERROR_NO,
+ },
+ .dma_input = {
+ .cmd = DMA_INPUT_COMMAND_DISABLE,
+ .width = 0, .height = 0,
+ .format = 0, .bitwidth = 0, .plane = 0,
+ .order = 0, .buffer_number = 0, .buffer_address = 0,
+ .err = 0,
+ },
+ .config = {
+ .cmd = FD_CONFIG_COMMAND_MAXIMUM_NUMBER |
+ FD_CONFIG_COMMAND_ROLL_ANGLE |
+ FD_CONFIG_COMMAND_YAW_ANGLE |
+ FD_CONFIG_COMMAND_SMILE_MODE |
+ FD_CONFIG_COMMAND_BLINK_MODE |
+ FD_CONFIG_COMMAND_EYES_DETECT |
+ FD_CONFIG_COMMAND_MOUTH_DETECT |
+ FD_CONFIG_COMMAND_ORIENTATION |
+ FD_CONFIG_COMMAND_ORIENTATION_VALUE,
+ .max_number = CAMERA2_MAX_FACES,
+ .roll_angle = FD_CONFIG_ROLL_ANGLE_FULL,
+ .yaw_angle = FD_CONFIG_YAW_ANGLE_45_90,
+ .smile_mode = FD_CONFIG_SMILE_MODE_DISABLE,
+ .blink_mode = FD_CONFIG_BLINK_MODE_DISABLE,
+ .eye_detect = FD_CONFIG_EYES_DETECT_ENABLE,
+ .mouth_detect = FD_CONFIG_MOUTH_DETECT_DISABLE,
+ .orientation = FD_CONFIG_ORIENTATION_DISABLE,
+ .orientation_value = 0,
+ .err = ERROR_FD_NO,
+ },
+};
+
+static int testnset_state(struct fimc_is_device_ischain *this,
+ unsigned long state)
+{
+ int ret = 0;
+
+ mutex_lock(&this->mutex_state);
+
+ if (test_bit(state, &this->state)) {
+ ret = -EINVAL;
+ goto exit;
+ }
+ set_bit(state, &this->state);
+
+exit:
+ mutex_unlock(&this->mutex_state);
+ return ret;
+}
+
+static int testnclr_state(struct fimc_is_device_ischain *this,
+ unsigned long state)
+{
+ int ret = 0;
+
+ mutex_lock(&this->mutex_state);
+
+ if (!test_bit(state, &this->state)) {
+ ret = -EINVAL;
+ goto exit;
+ }
+ clear_bit(state, &this->state);
+
+exit:
+ mutex_unlock(&this->mutex_state);
+ return ret;
+}
+
+static int fimc_is_ischain_allocmem(struct fimc_is_device_ischain *this)
+{
+ int ret = 0;
+ void *fw_cookie;
+
+ dbg_ischain("Allocating memory for FIMC-IS firmware.\n");
+
+ fw_cookie = vb2_ion_private_alloc(this->mem->alloc_ctx,
+ FIMC_IS_A5_MEM_SIZE + FIMC_IS_A5_SEN_SIZE +
+#ifdef ENABLE_ODC
+ SIZE_ODC_INTERNAL_BUF * NUM_ODC_INTERNAL_BUF +
+#endif
+#ifdef ENABLE_VDIS
+ SIZE_DIS_INTERNAL_BUF * NUM_DIS_INTERNAL_BUF +
+#endif
+#ifdef ENABLE_TDNR
+ SIZE_DNR_INTERNAL_BUF * NUM_DNR_INTERNAL_BUF +
+#endif
+ 0);
+
+ if (IS_ERR(fw_cookie)) {
+ err("Allocating bitprocessor buffer failed");
+ fw_cookie = NULL;
+ ret = -ENOMEM;
+ goto exit;
+ }
+
+ ret = vb2_ion_dma_address(fw_cookie, &this->minfo.dvaddr);
+ if ((ret < 0) || (this->minfo.dvaddr & FIMC_IS_FW_BASE_MASK)) {
+ err("The base memory is not aligned to 64MB.");
+ vb2_ion_private_free(fw_cookie);
+ this->minfo.dvaddr = 0;
+ fw_cookie = NULL;
+ ret = -EIO;
+ goto exit;
+ }
+ dbg_ischain("Device vaddr = %08x , size = %08x\n",
+ this->minfo.dvaddr, FIMC_IS_A5_MEM_SIZE);
+
+ this->minfo.kvaddr = (u32)vb2_ion_private_vaddr(fw_cookie);
+ if (IS_ERR((void *)this->minfo.kvaddr)) {
+ err("Bitprocessor memory remap failed");
+ vb2_ion_private_free(fw_cookie);
+ this->minfo.kvaddr = 0;
+ fw_cookie = NULL;
+ ret = -EIO;
+ goto exit;
+ }
+
+exit:
+ dbg_ischain("Virtual address for FW: %08lx\n",
+ (long unsigned int)this->minfo.kvaddr);
+ this->minfo.fw_cookie = fw_cookie;
+
+ return ret;
+}
+
+static int fimc_is_ishcain_initmem(struct fimc_is_device_ischain *this)
+{
+ int ret = 0;
+ u32 offset;
+
+ dbg_ischain("fimc_is_init_mem - ION\n");
+
+ ret = fimc_is_ischain_allocmem(this);
+ if (ret) {
+ err("Couldn't alloc for FIMC-IS firmware\n");
+ ret = -ENOMEM;
+ goto exit;
+ }
+
+ offset = FW_SHARED_OFFSET;
+ this->minfo.dvaddr_fshared = this->minfo.dvaddr + offset;
+ this->minfo.kvaddr_fshared = this->minfo.kvaddr + offset;
+
+ offset = FIMC_IS_A5_MEM_SIZE - FIMC_IS_REGION_SIZE;
+ this->minfo.dvaddr_region = this->minfo.dvaddr + offset;
+ this->minfo.kvaddr_region = this->minfo.kvaddr + offset;
+
+ this->is_region =
+ (struct is_region *)this->minfo.kvaddr_region;
+
+ this->minfo.dvaddr_shared = this->minfo.dvaddr +
+ ((u32)&this->is_region->shared[0] - this->minfo.kvaddr);
+ this->minfo.kvaddr_shared = this->minfo.kvaddr +
+ ((u32)&this->is_region->shared[0] - this->minfo.kvaddr);
+
+ offset = FIMC_IS_A5_MEM_SIZE;
+#ifdef ENABLE_ODC
+ this->minfo.dvaddr_odc = this->minfo.dvaddr + offset;
+ this->minfo.kvaddr_odc = this->minfo.kvaddr + offset;
+ offset += (SIZE_ODC_INTERNAL_BUF * NUM_ODC_INTERNAL_BUF);
+#else
+ this->minfo.dvaddr_odc = 0;
+ this->minfo.kvaddr_odc = 0;
+#endif
+
+#ifdef ENABLE_VDIS
+ this->minfo.dvaddr_dis = this->minfo.dvaddr + offset;
+ this->minfo.kvaddr_dis = this->minfo.kvaddr + offset;
+ offset += (SIZE_DIS_INTERNAL_BUF * NUM_DIS_INTERNAL_BUF);
+#else
+ this->minfo.dvaddr_dis = 0;
+ this->minfo.kvaddr_dis = 0;
+#endif
+
+#ifdef ENABLE_TDNR
+ this->minfo.dvaddr_3dnr = this->minfo.dvaddr + offset;
+ this->minfo.kvaddr_3dnr = this->minfo.kvaddr + offset;
+#else
+ this->minfo.dvaddr_3dnr = 0;
+ this->minfo.kvaddr_3dnr = 0;
+#endif
+
+ dbg_ischain("fimc_is_init_mem done\n");
+
+exit:
+ return ret;
+}
+
+#ifndef RESERVED_MEM
+static int fimc_is_ishcain_deinitmem(struct fimc_is_device_ischain *this)
+{
+ int ret = 0;
+
+ vb2_ion_private_free(this->minfo.fw_cookie);
+
+ return ret;
+}
+#endif
+
+static void fimc_is_ischain_cache_flush(struct fimc_is_device_ischain *this,
+ u32 offset, u32 size)
+{
+ vb2_ion_sync_for_device(this->minfo.fw_cookie,
+ offset,
+ size,
+ DMA_BIDIRECTIONAL);
+}
+
+static void fimc_is_ischain_region_invalid(struct fimc_is_device_ischain *this)
+{
+ vb2_ion_sync_for_device(
+ this->minfo.fw_cookie,
+ (this->minfo.kvaddr_region - this->minfo.kvaddr),
+ sizeof(struct is_region),
+ DMA_FROM_DEVICE);
+}
+
+static void fimc_is_ischain_region_flush(struct fimc_is_device_ischain *this)
+{
+ vb2_ion_sync_for_device(
+ this->minfo.fw_cookie,
+ (this->minfo.kvaddr_region - this->minfo.kvaddr),
+ sizeof(struct is_region),
+ DMA_TO_DEVICE);
+}
+
+static void fimc_is_ischain_version(char *name, const char *load_bin, u32 size)
+{
+ char version_str[FIMC_IS_VERSION_SIZE];
+
+ memcpy(version_str, &load_bin[size - FIMC_IS_VERSION_SIZE],
+ FIMC_IS_VERSION_SIZE);
+ version_str[FIMC_IS_VERSION_SIZE-1] = '\0';
+ printk(KERN_INFO "%s version : %s\n", name, version_str);
+}
+
+static int fimc_is_ischain_loadfirm(struct fimc_is_device_ischain *this)
+{
+ int ret = 0;
+ int location = 0;
+ struct firmware *fw_blob;
+ u8 *buf = NULL;
+#ifdef SDCARD_FW
+ struct file *fp;
+ mm_segment_t old_fs;
+ long fsize, nread;
+ int fw_requested = 1;
+
+ dbg_ischain("%s\n", __func__);
+
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ fp = filp_open(FIMC_IS_FW_SDCARD, O_RDONLY, 0);
+ if (IS_ERR(fp))
+ goto request_fw;
+
+ location = 1;
+ fw_requested = 0;
+ fsize = fp->f_path.dentry->d_inode->i_size;
+ dbg_ischain("start, file path %s, size %ld Bytes\n",
+ FIMC_IS_FW_SDCARD, fsize);
+ buf = vmalloc(fsize);
+ if (!buf) {
+ dev_err(&this->pdev->dev,
+ "failed to allocate memory\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+ nread = vfs_read(fp, (char __user *)buf, fsize, &fp->f_pos);
+ if (nread != fsize) {
+ dev_err(&this->pdev->dev,
+ "failed to read firmware file, %ld Bytes\n", nread);
+ ret = -EIO;
+ goto out;
+ }
+
+ memcpy((void *)this->minfo.kvaddr, (void *)buf, fsize);
+ fimc_is_ischain_cache_flush(this, 0, fsize + 1);
+ fimc_is_ischain_version(FIMC_IS_FW, buf, fsize);
+
+request_fw:
+ if (fw_requested) {
+ set_fs(old_fs);
+#endif
+ ret = request_firmware((const struct firmware **)&fw_blob,
+ FIMC_IS_FW, &this->pdev->dev);
+ if (ret) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ memcpy((void *)this->minfo.kvaddr, fw_blob->data,
+ fw_blob->size);
+ fimc_is_ischain_cache_flush(this, 0, fw_blob->size + 1);
+ fimc_is_ischain_version(FIMC_IS_FW, fw_blob->data,
+ fw_blob->size);
+
+ release_firmware(fw_blob);
+#ifdef SDCARD_FW
+ }
+#endif
+
+out:
+#ifdef SDCARD_FW
+ if (!fw_requested) {
+ vfree(buf);
+ filp_close(fp, current->files);
+ set_fs(old_fs);
+ }
+#endif
+
+ if (ret)
+ err("firmware loading is fail");
+ else
+ printk(KERN_INFO "firmware is loaded successfully from %s\n",
+ location ? FIMC_IS_FW_SDCARD : "fimc_is_fw2.bin");
+
+ return ret;
+}
+
+static int fimc_is_ischain_loadsetf(struct fimc_is_device_ischain *this,
+ u32 load_addr, char *setfile_name)
+{
+ int ret = 0;
+ int location = 0;
+ void *address;
+ struct firmware *fw_blob;
+ u8 *buf = NULL;
+#ifdef SDCARD_FW
+ struct file *fp;
+ mm_segment_t old_fs;
+ long fsize, nread;
+ int fw_requested = 1;
+ char setfile_path[256];
+
+ dbg_ischain("%s\n", __func__);
+
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ memset(setfile_path, 0x00, sizeof(setfile_path));
+ sprintf(setfile_path, "%s%s",
+ FIMC_IS_SETFILE_SDCARD_PATH, setfile_name);
+ fp = filp_open(setfile_path, O_RDONLY, 0);
+ if (IS_ERR(fp))
+ goto request_fw;
+
+ location = 1;
+ fw_requested = 0;
+ fsize = fp->f_path.dentry->d_inode->i_size;
+ dbg_ischain("start, file path %s, size %ld Bytes\n",
+ setfile_path, fsize);
+ buf = vmalloc(fsize);
+ if (!buf) {
+ dev_err(&this->pdev->dev,
+ "failed to allocate memory\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+ nread = vfs_read(fp, (char __user *)buf, fsize, &fp->f_pos);
+ if (nread != fsize) {
+ dev_err(&this->pdev->dev,
+ "failed to read firmware file, %ld Bytes\n", nread);
+ ret = -EIO;
+ goto out;
+ }
+
+ address = (void *)(this->minfo.kvaddr + load_addr);
+ memcpy((void *)address, (void *)buf, fsize);
+ fimc_is_ischain_cache_flush(this, load_addr, fsize + 1);
+ fimc_is_ischain_version(setfile_name, buf, fsize);
+
+request_fw:
+ if (fw_requested) {
+ set_fs(old_fs);
+#endif
+
+ ret = request_firmware((const struct firmware **)&fw_blob,
+ setfile_name, &this->pdev->dev);
+ if (ret) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ address = (void *)(this->minfo.kvaddr + load_addr);
+ memcpy(address, fw_blob->data, fw_blob->size);
+ fimc_is_ischain_cache_flush(this, load_addr, fw_blob->size + 1);
+ fimc_is_ischain_version(setfile_name, fw_blob->data,
+ (u32)fw_blob->size);
+
+ release_firmware(fw_blob);
+#ifdef SDCARD_FW
+ }
+#endif
+
+out:
+#ifdef SDCARD_FW
+ if (!fw_requested) {
+ vfree(buf);
+ filp_close(fp, current->files);
+ set_fs(old_fs);
+ }
+#endif
+
+ if (ret)
+ err("setfile loading is fail");
+ else
+ printk(KERN_INFO "setfile is loaded successfully from %s\n",
+ location ? setfile_path : setfile_name);
+
+ return ret;
+}
+
+static int fimc_is_ischain_loadcalb(struct fimc_is_device_ischain *this,
+ struct fimc_is_enum_sensor *active_sensor)
+{
+ int ret = 0;
+ char *buf;
+ char *cal_ptr;
+
+ buf = kmalloc(FIMC_IS_MAX_CAL_SIZE, GFP_KERNEL);
+ if (!buf) {
+ err("kmalloc fail");
+ ret = -ENOMEM;
+ goto exit;
+ }
+
+ memset(buf, 0xff, FIMC_IS_MAX_CAL_SIZE);
+
+ ret = fimc_is_spi_read(buf, FIMC_IS_MAX_CAL_SIZE);
+ if (ret < 0) {
+ err("failed to fimc_is_spi_read (%d)\n", ret);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ cal_ptr = (char *)(this->minfo.kvaddr + FIMC_IS_CAL_START_ADDR);
+
+ if (active_sensor->sensor == SENSOR_NAME_S5K6A3) {
+ buf[0x1a] = 0;
+ buf[0x1b] = 0;
+ }
+
+ if (active_sensor->sensor == SENSOR_NAME_S5K6A3)
+ printk(KERN_INFO "sensor name : 6A3\n");
+ else if (active_sensor->sensor == SENSOR_NAME_S5K4E5)
+ printk(KERN_INFO "sensor name : 4E5\n");
+ else {
+ printk(KERN_INFO "sensor name : Unknown\n");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ printk(KERN_INFO "FROM DATA(0x1A): 0x%08x\n", buf[0x1a]);
+ printk(KERN_INFO "FROM DATA(0x1B): 0x%08x\n", buf[0x1b]);
+
+ memcpy(cal_ptr, buf, FIMC_IS_MAX_CAL_SIZE);
+ fimc_is_ischain_cache_flush(this, FIMC_IS_CAL_START_ADDR,
+ FIMC_IS_MAX_CAL_SIZE + 1);
+
+exit:
+ kfree(buf);
+ return ret;
+}
+
+static void fimc_is_ischain_forcedown(struct fimc_is_device_ischain *this,
+ bool on)
+{
+ if (on) {
+ printk(KERN_INFO "Set low poweroff mode\n");
+ __raw_writel(0x0, PMUREG_ISP_ARM_OPTION);
+ __raw_writel(0x1CF82000, PMUREG_ISP_LOW_POWER_OFF);
+ this->force_down = true;
+ } else {
+ printk(KERN_INFO "Clear low poweroff mode\n");
+ __raw_writel(0xFFFFFFFF, PMUREG_ISP_ARM_OPTION);
+ __raw_writel(0x8, PMUREG_ISP_LOW_POWER_OFF);
+ this->force_down = false;
+ }
+}
+
+int fimc_is_ischain_power(struct fimc_is_device_ischain *this, int on)
+{
+ int ret = 0;
+ u32 timeout;
+ struct device *dev = &this->pdev->dev;
+ struct fimc_is_core *core
+ = (struct fimc_is_core *)platform_get_drvdata(this->pdev);
+ struct fimc_is_device_sensor *sensor = &core->sensor;
+ struct fimc_is_enum_sensor *sensor_info
+ = &sensor->enum_sensor[sensor->id_position];
+
+ printk(KERN_INFO "%s(%d)\n", __func__, on);
+
+ if (on) {
+ /* 1. force poweroff setting */
+ if (this->force_down)
+ fimc_is_ischain_forcedown(this, false);
+
+ /* 2. FIMC-IS local power enable */
+#if defined(CONFIG_PM_RUNTIME)
+ dbg_ischain("pm_runtime_suspended = %d\n",
+ pm_runtime_suspended(dev));
+ pm_runtime_get_sync(dev);
+#else
+ fimc_is_runtime_resume(dev);
+#endif
+
+ /* 3. Load calibration data from sensor */
+ fimc_is_ischain_loadcalb(this, sensor_info);
+
+ /* 4. A5 start address setting */
+ dbg_ischain("minfo.base(dvaddr) : 0x%08x\n",
+ this->minfo.dvaddr);
+ dbg_ischain("minfo.base(kvaddr) : 0x%08X\n",
+ this->minfo.kvaddr);
+
+ if (!this->minfo.dvaddr) {
+ err("firmware device virtual is null");
+ ret = -ENOMEM;
+ goto exit;
+ }
+
+ writel(this->minfo.dvaddr, this->regs + BBOAR);
+
+ /* 5. A5 power on*/
+ writel(0x1, PMUREG_ISP_ARM_CONFIGURATION);
+
+ /* 6. enable A5 */
+ writel(0x00018000, PMUREG_ISP_ARM_OPTION);
+ timeout = 1000;
+ while ((__raw_readl(PMUREG_ISP_ARM_STATUS) & 0x1) != 0x1) {
+ if (timeout == 0)
+ err("A5 power on failed\n");
+ timeout--;
+ udelay(1);
+ }
+
+ set_bit(FIMC_IS_ISCHAIN_POWER_ON, &this->state);
+ } else {
+ /* 1. disable A5 */
+ writel(0x10000, PMUREG_ISP_ARM_OPTION);
+ /* 2. A5 power off*/
+ writel(0x0, PMUREG_ISP_ARM_CONFIGURATION);
+
+ /* 3. Check A5 power off status register */
+ timeout = 1000;
+ while (__raw_readl(PMUREG_ISP_ARM_STATUS) & 0x1) {
+ if (timeout == 0) {
+ printk(KERN_ERR "A5 power off failed\n");
+ fimc_is_ischain_forcedown(this, true);
+ }
+ timeout--;
+ udelay(1);
+ }
+
+ writel(0x0, PMUREG_CMU_RESET_ISP_SYS_PWR_REG);
+
+ /* 4. FIMC-IS local power down */
+#if defined(CONFIG_PM_RUNTIME)
+ pm_runtime_put_sync(dev);
+ dbg_ischain("pm_runtime_suspended = %d\n",
+ pm_runtime_suspended(dev));
+#else
+ fimc_is_runtime_suspend(dev);
+#endif
+ clear_bit(FIMC_IS_ISCHAIN_POWER_ON, &this->state);
+ }
+
+exit:
+ return ret;
+}
+
+static int fimc_is_itf_s_param(struct fimc_is_device_ischain *this,
+ u32 indexes, u32 lindex, u32 hindex)
+{
+ int ret = 0;
+
+ fimc_is_ischain_region_flush(this);
+
+ if (lindex || hindex) {
+ ret = fimc_is_hw_s_param(this->interface,
+ this->instance,
+ indexes,
+ lindex,
+ hindex);
+ }
+
+ return ret;
+}
+
+static int fimc_is_itf_a_param(struct fimc_is_device_ischain *this)
+{
+ int ret = 0;
+
+ ret = fimc_is_hw_a_param(this->interface, this->instance,
+ HIC_PREVIEW_STILL, this->setfile);
+
+ return ret;
+}
+
+static int fimc_is_itf_f_param(struct fimc_is_device_ischain *this)
+{
+ int ret = 0;
+#ifdef DEBUG
+ u32 navailable = 0;
+ struct is_region *region = this->is_region;
+#endif
+
+ dbg_ischain(" NAME ON BYPASS SIZE FORMAT\n");
+ dbg_ischain("ISP OO : %2d %4d %04dx%04d %d\n",
+ region->parameter.isp.control.cmd,
+ region->parameter.isp.control.bypass,
+ region->parameter.isp.otf_output.width,
+ region->parameter.isp.otf_output.height,
+ region->parameter.isp.otf_output.format
+ );
+ dbg_ischain("DRC OI : %2d %4d %04dx%04d %d\n",
+ region->parameter.drc.control.cmd,
+ region->parameter.drc.control.bypass,
+ region->parameter.drc.otf_input.width,
+ region->parameter.drc.otf_input.height,
+ region->parameter.drc.otf_input.format
+ );
+ dbg_ischain("DRC OO : %2d %4d %04dx%04d %d\n",
+ region->parameter.drc.control.cmd,
+ region->parameter.drc.control.bypass,
+ region->parameter.drc.otf_output.width,
+ region->parameter.drc.otf_output.height,
+ region->parameter.drc.otf_output.format
+ );
+ dbg_ischain("SCC OI : %2d %4d %04dx%04d %d\n",
+ region->parameter.scalerc.control.cmd,
+ region->parameter.scalerc.control.bypass,
+ region->parameter.scalerc.otf_input.width,
+ region->parameter.scalerc.otf_input.height,
+ region->parameter.scalerc.otf_input.format
+ );
+ dbg_ischain("SCC OO : %2d %4d %04dx%04d %d\n",
+ region->parameter.scalerc.control.cmd,
+ region->parameter.scalerc.control.bypass,
+ region->parameter.scalerc.otf_output.width,
+ region->parameter.scalerc.otf_output.height,
+ region->parameter.scalerc.otf_output.format
+ );
+ dbg_ischain("ODC OI : %2d %4d %04dx%04d %d\n",
+ region->parameter.odc.control.cmd,
+ region->parameter.odc.control.bypass,
+ region->parameter.odc.otf_input.width,
+ region->parameter.odc.otf_input.height,
+ region->parameter.odc.otf_input.format
+ );
+ dbg_ischain("ODC OO : %2d %4d %04dx%04d %d\n",
+ region->parameter.odc.control.cmd,
+ region->parameter.odc.control.bypass,
+ region->parameter.odc.otf_output.width,
+ region->parameter.odc.otf_output.height,
+ region->parameter.odc.otf_output.format
+ );
+ dbg_ischain("DIS OI : %2d %4d %04dx%04d %d\n",
+ region->parameter.dis.control.cmd,
+ region->parameter.dis.control.bypass,
+ region->parameter.dis.otf_input.width,
+ region->parameter.dis.otf_input.height,
+ region->parameter.dis.otf_input.format
+ );
+ dbg_ischain("DIS OO : %2d %4d %04dx%04d %d\n",
+ region->parameter.dis.control.cmd,
+ region->parameter.dis.control.bypass,
+ region->parameter.dis.otf_output.width,
+ region->parameter.dis.otf_output.height,
+ region->parameter.dis.otf_output.format
+ );
+ dbg_ischain("DNR OI : %2d %4d %04dx%04d %d\n",
+ region->parameter.tdnr.control.cmd,
+ region->parameter.tdnr.control.bypass,
+ region->parameter.tdnr.otf_input.width,
+ region->parameter.tdnr.otf_input.height,
+ region->parameter.tdnr.otf_input.format
+ );
+ dbg_ischain("DNR OO : %2d %4d %04dx%04d %d\n",
+ region->parameter.tdnr.control.cmd,
+ region->parameter.tdnr.control.bypass,
+ region->parameter.tdnr.otf_output.width,
+ region->parameter.tdnr.otf_output.height,
+ region->parameter.tdnr.otf_output.format
+ );
+ dbg_ischain("SCP OI : %2d %4d %04dx%04d %d\n",
+ region->parameter.scalerp.control.cmd,
+ region->parameter.scalerp.control.bypass,
+ region->parameter.scalerp.otf_input.width,
+ region->parameter.scalerp.otf_input.height,
+ region->parameter.scalerp.otf_input.format
+ );
+ dbg_ischain("SCP DO : %2d %4d %04dx%04d %d,%d\n",
+ region->parameter.scalerp.dma_output.cmd,
+ region->parameter.scalerp.control.bypass,
+ region->parameter.scalerp.dma_output.width,
+ region->parameter.scalerp.dma_output.height,
+ region->parameter.scalerp.dma_output.format,
+ region->parameter.scalerp.dma_output.plane
+ );
+ dbg_ischain("SCP OO : %2d %4d %04dx%04d %d\n",
+ region->parameter.scalerp.control.cmd,
+ region->parameter.scalerp.control.bypass,
+ region->parameter.scalerp.otf_output.width,
+ region->parameter.scalerp.otf_output.height,
+ region->parameter.scalerp.otf_output.format
+ );
+ dbg_ischain(" FD OI : %2d %4d %04dx%04d %d\n",
+ region->parameter.fd.control.cmd,
+ region->parameter.fd.control.bypass,
+ region->parameter.fd.otf_input.width,
+ region->parameter.fd.otf_input.height,
+ region->parameter.fd.otf_input.format
+ );
+ dbg_ischain(" NAME CMD IN_SZIE OT_SIZE CROP POS\n");
+ dbg_ischain("SCC CI : %d %04dx%04d %04dx%04d %04dx%04d %04dx%04d\n",
+ region->parameter.scalerc.input_crop.cmd,
+ region->parameter.scalerc.input_crop.in_width,
+ region->parameter.scalerc.input_crop.in_height,
+ region->parameter.scalerc.input_crop.out_width,
+ region->parameter.scalerc.input_crop.out_height,
+ region->parameter.scalerc.input_crop.crop_width,
+ region->parameter.scalerc.input_crop.crop_height,
+ region->parameter.scalerc.input_crop.pos_x,
+ region->parameter.scalerc.input_crop.pos_y
+ );
+ dbg_ischain("SCC CO : %d %04dx%04d %04dx%04d %04dx%04d %04dx%04d\n",
+ region->parameter.scalerc.output_crop.cmd,
+ navailable,
+ navailable,
+ navailable,
+ navailable,
+ region->parameter.scalerc.output_crop.crop_width,
+ region->parameter.scalerc.output_crop.crop_height,
+ region->parameter.scalerc.output_crop.pos_x,
+ region->parameter.scalerc.output_crop.pos_y
+ );
+ dbg_ischain("SCP CI : %d %04dx%04d %04dx%04d %04dx%04d %04dx%04d\n",
+ region->parameter.scalerp.input_crop.cmd,
+ region->parameter.scalerp.input_crop.in_width,
+ region->parameter.scalerp.input_crop.in_height,
+ region->parameter.scalerp.input_crop.out_width,
+ region->parameter.scalerp.input_crop.out_height,
+ region->parameter.scalerp.input_crop.crop_width,
+ region->parameter.scalerp.input_crop.crop_height,
+ region->parameter.scalerp.input_crop.pos_x,
+ region->parameter.scalerp.input_crop.pos_y
+ );
+ dbg_ischain("SCP CO : %d %04dx%04d %04dx%04d %04dx%04d %04dx%04d\n",
+ region->parameter.scalerp.output_crop.cmd,
+ navailable,
+ navailable,
+ navailable,
+ navailable,
+ region->parameter.scalerp.output_crop.crop_width,
+ region->parameter.scalerp.output_crop.crop_height,
+ region->parameter.scalerp.output_crop.pos_x,
+ region->parameter.scalerp.output_crop.pos_y
+ );
+ dbg_ischain(" NAME BUFS MASK\n");
+ dbg_ischain("SCP DO : %2d %04X\n",
+ region->parameter.scalerp.dma_output.buffer_number,
+ region->parameter.scalerp.dma_output.dma_out_mask
+ );
+
+ ret = fimc_is_hw_f_param(this->interface, this->instance);
+
+ return ret;
+}
+
+static int fimc_is_itf_enum(struct fimc_is_device_ischain *this)
+{
+ int ret = 0;
+
+ dbg_ischain("%s()\n", __func__);
+
+ ret = fimc_is_hw_enum(this->interface);
+ if (ret)
+ err("fimc_is_itf_enum is fail(%d)", ret);
+
+ return ret;
+}
+
+static int fimc_is_itf_open(struct fimc_is_device_ischain *this,
+ u32 input, u32 channel, u32 ext)
+{
+ int ret = 0;
+ struct is_region *region = this->is_region;
+
+ fimc_is_ischain_region_flush(this);
+
+ ret = fimc_is_hw_open(this->interface, this->instance, input, channel,
+ ext, &this->margin_width, &this->margin_height);
+ if (ret) {
+ err("fimc_is_hw_open is fail");
+ goto exit;
+ }
+
+ /*hack*/
+ this->margin_left = 8;
+ this->margin_right = 8;
+ this->margin_top = 6;
+ this->margin_bottom = 4;
+ this->margin_width = this->margin_left + this->margin_right;
+ this->margin_height = this->margin_top + this->margin_bottom;
+ dbg_ischain("margin %dx%d\n",
+ this->margin_width, this->margin_height);
+
+ if (region->shared[MAX_SHARED_COUNT-1] != MAGIC_NUMBER) {
+ err("MAGIC NUMBER error\n");
+ ret = 1;
+ goto exit;
+ }
+
+ memset(®ion->parameter, 0x0, sizeof(struct is_param_region));
+
+ memcpy(®ion->parameter.sensor, &init_sensor_param,
+ sizeof(struct sensor_param));
+ memcpy(®ion->parameter.isp, &init_isp_param,
+ sizeof(struct isp_param));
+ memcpy(®ion->parameter.drc, &init_drc_param,
+ sizeof(struct drc_param));
+ memcpy(®ion->parameter.scalerc, &init_scalerc_param,
+ sizeof(struct scalerc_param));
+ memcpy(®ion->parameter.odc, &init_odc_param,
+ sizeof(struct odc_param));
+ memcpy(®ion->parameter.dis, &init_dis_param,
+ sizeof(struct dis_param));
+ memcpy(®ion->parameter.tdnr, &init_tdnr_param,
+ sizeof(struct tdnr_param));
+ memcpy(®ion->parameter.scalerp, &init_scalerp_param,
+ sizeof(struct scalerp_param));
+ memcpy(®ion->parameter.fd, &init_fd_param,
+ sizeof(struct fd_param));
+
+exit:
+ return ret;
+}
+
+static int fimc_is_itf_setfile(struct fimc_is_device_ischain *this,
+ char *setfile_name)
+{
+ int ret = 0;
+ u32 setfile_addr;
+
+ dbg_ischain("%s(setfile : %s)\n", __func__, setfile_name);
+
+ ret = fimc_is_hw_saddr(this->interface, this->instance, &setfile_addr);
+ fimc_is_ischain_loadsetf(this, setfile_addr, setfile_name);
+ fimc_is_hw_setfile(this->interface, this->instance);
+
+ return ret;
+}
+
+static int fimc_is_itf_cfg_mem(struct fimc_is_device_ischain *this,
+ u32 shot_addr, u32 shot_size)
+{
+ int ret = 0;
+
+ dbg_ischain("%s()\n", __func__);
+
+ ret = fimc_is_hw_cfg_mem(this->interface, this->instance,
+ shot_addr, shot_size);
+
+ return ret;
+}
+
+static int fimc_is_itf_s_camctrl(struct fimc_is_device_ischain *this,
+ u32 address, u32 fnumber)
+{
+ int ret = 0;
+
+ fimc_is_ischain_region_flush(this);
+
+ ret = fimc_is_hw_s_camctrl_nblk(this->interface,
+ this->instance,
+ address,
+ fnumber);
+
+ return ret;
+}
+
+int fimc_is_itf_stream_on(struct fimc_is_device_ischain *this)
+{
+ int ret = 0;
+
+ ret = fimc_is_hw_stream_on(this->interface, this->instance);
+
+ return ret;
+}
+
+int fimc_is_itf_stream_off(struct fimc_is_device_ischain *this)
+{
+ int ret = 0;
+
+ ret = fimc_is_hw_stream_off(this->interface, this->instance);
+
+ return ret;
+}
+
+int fimc_is_itf_process_on(struct fimc_is_device_ischain *this)
+{
+ int ret = 0;
+
+ ret = fimc_is_hw_process_on(this->interface, this->instance);
+
+ return ret;
+}
+
+int fimc_is_itf_process_off(struct fimc_is_device_ischain *this)
+{
+ int ret = 0;
+
+ ret = fimc_is_hw_process_off(this->interface, this->instance);
+
+ return ret;
+}
+
+int fimc_is_itf_g_capability(struct fimc_is_device_ischain *this)
+{
+ int ret = 0;
+ u32 metadata;
+ u32 index;
+ struct camera2_sm *capability;
+
+ ret = fimc_is_hw_g_capability(this->interface, this->instance,
+ (this->minfo.kvaddr_shared - this->minfo.kvaddr));
+
+ fimc_is_ischain_region_invalid(this);
+
+ memcpy(&this->capability, &this->is_region->shared,
+ sizeof(struct camera2_sm));
+ capability = &this->capability;
+
+#if 1
+ dbg_ischain("===ColorC================================\n");
+#if 0
+ index = 0;
+ metadata = capability->color.availableModes[index];
+ while (metadata) {
+ dbg_ischain("availableModes : %d\n", metadata);
+ index++;
+ metadata = capability->color.availableModes[index];
+ }
+#endif
+
+ dbg_ischain("===ToneMapping===========================\n");
+ metadata = capability->tonemap.maxCurvePoints;
+ dbg_ischain("maxCurvePoints : %d\n", metadata);
+
+ dbg_ischain("===Scaler================================\n");
+ dbg_ischain("foramt : %d, %d, %d, %d\n",
+ capability->scaler.availableFormats[0],
+ capability->scaler.availableFormats[1],
+ capability->scaler.availableFormats[2],
+ capability->scaler.availableFormats[3]);
+
+ dbg_ischain("===StatisTicsG===========================\n");
+ index = 0;
+ metadata = capability->stats.availableFaceDetectModes[index];
+ while (metadata) {
+ dbg_ischain("availableFaceDetectModes : %d\n", metadata);
+ index++;
+ metadata = capability->stats.availableFaceDetectModes[index];
+ }
+ dbg_ischain("maxFaceCount : %d\n",
+ capability->stats.maxFaceCount);
+ dbg_ischain("histogrambucketCount : %d\n",
+ capability->stats.histogramBucketCount);
+ dbg_ischain("maxHistogramCount : %d\n",
+ capability->stats.maxHistogramCount);
+ dbg_ischain("sharpnessMapSize : %dx%d\n",
+ capability->stats.sharpnessMapSize[0],
+ capability->stats.sharpnessMapSize[1]);
+ dbg_ischain("maxSharpnessMapValue : %d\n",
+ capability->stats.maxSharpnessMapValue);
+
+ dbg_ischain("===3A====================================\n");
+#if 0
+ index = 0;
+ metadata = capability->aa.availableModes[index];
+ while (metadata) {
+ dbg_ischain("availableModes : %d\n", metadata);
+ index++;
+ metadata = capability->aa.availableModes[index];
+ }
+#endif
+
+ dbg_ischain("maxRegions : %d\n", capability->aa.maxRegions);
+
+ index = 0;
+ metadata = capability->aa.aeAvailableModes[index];
+ while (metadata) {
+ dbg_ischain("aeAvailableModes : %d\n", metadata);
+ index++;
+ metadata = capability->aa.aeAvailableModes[index];
+ }
+ dbg_ischain("aeCompensationStep : %d,%d\n",
+ capability->aa.aeCompensationStep.num,
+ capability->aa.aeCompensationStep.den);
+ dbg_ischain("aeCompensationRange : %d ~ %d\n",
+ capability->aa.aeCompensationRange[0],
+ capability->aa.aeCompensationRange[1]);
+ index = 0;
+ metadata = capability->aa.aeAvailableTargetFpsRanges[index][0];
+ while (metadata) {
+ dbg_ischain("TargetFpsRanges : %d ~ %d\n", metadata,
+ capability->aa.aeAvailableTargetFpsRanges[index][1]);
+ index++;
+ metadata = capability->aa.aeAvailableTargetFpsRanges[index][0];
+ }
+ index = 0;
+ metadata = capability->aa.aeAvailableAntibandingModes[index];
+ while (metadata) {
+ dbg_ischain("aeAvailableAntibandingModes : %d\n", metadata);
+ index++;
+ metadata = capability->aa.aeAvailableAntibandingModes[index];
+ }
+ index = 0;
+ metadata = capability->aa.awbAvailableModes[index];
+ while (metadata) {
+ dbg_ischain("awbAvailableModes : %d\n", metadata);
+ index++;
+ metadata = capability->aa.awbAvailableModes[index];
+ }
+ index = 0;
+ metadata = capability->aa.afAvailableModes[index];
+ while (metadata) {
+ dbg_ischain("afAvailableModes : %d\n", metadata);
+ index++;
+ metadata = capability->aa.afAvailableModes[index];
+ }
+#endif
+
+ return ret;
+}
+
+static int fimc_is_itf_power_down(struct fimc_is_device_ischain *this)
+{
+ int ret = 0;
+
+ ret = fimc_is_hw_power_down(this->interface, this->instance);
+
+ return ret;
+}
+
+static int fimc_is_itf_shot(struct fimc_is_device_ischain *this,
+ struct fimc_is_frame_shot *frame)
+{
+ int ret = 0;
+
+ this->fcount++;
+ if (frame->shot->dm.request.frameCount != this->fcount) {
+#ifdef CHECK_FDROP
+ printk(KERN_INFO "shot mismatch(%d, %d)",
+ frame->shot->dm.request.frameCount, this->fcount);
+#endif
+
+ if (!frame->shot->dm.request.frameCount) {
+ frame->fcount = this->fcount;
+ frame->shot->dm.request.frameCount = this->fcount;
+ }
+
+ this->fcount = frame->shot->dm.request.frameCount;
+ }
+
+ /* Cache Flush */
+ vb2_ion_sync_for_device((void *)frame->cookie_shot, 0, frame->shot_size,
+ DMA_TO_DEVICE);
+
+ if (frame->shot->magicNumber != 0x23456789) {
+ err("shot magic number error(0x%08X)\n",
+ frame->shot->magicNumber);
+ ret = 1;
+ goto exit;
+ }
+
+#ifdef MEASURE_TIME
+#ifdef INTERNAL_TIME
+ do_gettimeofday(&frame->time_shot);
+#else
+ do_gettimeofday(&frame->tzone[TM_SHOT]);
+#endif
+#endif
+
+#ifdef DBG_STREAMING
+ printk(KERN_INFO "shot(%d)\n", frame->shot->dm.request.frameCount);
+#endif
+
+ ret = fimc_is_hw_shot_nblk(this->interface, this->instance,
+ frame->dvaddr_buffer[0],
+ frame->dvaddr_shot,
+ frame->shot->dm.request.frameCount,
+ frame->shot->ctl.request.frameCount);
+
+exit:
+ return ret;
+}
+
+int fimc_is_ischain_probe(struct fimc_is_device_ischain *this,
+ struct fimc_is_interface *interface,
+ struct fimc_is_framemgr *framemgr,
+ struct fimc_is_mem *mem,
+ struct platform_device *pdev,
+ u32 regs)
+{
+ int ret = 0;
+ struct fimc_is_ischain_dev *scc, *scp;
+
+ /*this initialization should be just one time*/
+
+ if (interface == NULL) {
+ err("interface is null");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (framemgr == NULL) {
+ err("framemgr is null");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (mem == NULL) {
+ err("mem is null");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (pdev == NULL) {
+ err("pdev is null");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ scc = &this->scc;
+ scp = &this->scp;
+
+#if defined(CONFIG_BUSFREQ_OPP) && defined(CONFIG_CPU_EXYNOS5250)
+ this->bus_dev = dev_get("exynos-busfreq");
+#endif
+
+ this->force_down = false;
+ this->interface = interface;
+ this->framemgr = framemgr;
+ this->mem = mem;
+ this->pdev = pdev;
+ this->pdata = pdev->dev.platform_data;
+ this->regs = (void *)regs;
+
+#ifdef RESERVED_MEM
+ fimc_is_ishcain_initmem(this);
+#endif
+
+ this->margin_left = 0;
+ this->margin_right = 0;
+ this->margin_width = 0;
+ this->margin_top = 0;
+ this->margin_bottom = 0;
+ this->margin_height = 0;
+ this->sensor_width = 0;
+ this->sensor_height = 0;
+ this->chain0_width = 0;
+ this->chain0_height = 0;
+ this->chain1_width = 0;
+ this->chain1_height = 0;
+ this->chain2_width = 0;
+ this->chain2_height = 0;
+ this->chain3_width = 0;
+ this->chain3_height = 0;
+ this->crop_x = 0;
+ this->crop_y = 0;
+ this->crop_width = 0;
+ this->crop_height = 0;
+ this->force_down = false;
+
+ /*scc probe*/
+ fimc_is_frame_probe(&scc->framemgr, FRAMEMGR_ID_SCC);
+
+ /*scp probe*/
+ fimc_is_frame_probe(&scp->framemgr, FRAMEMGR_ID_SCP);
+
+ clear_bit(FIMC_IS_ISCHAIN_OPEN, &this->state);
+ clear_bit(FIMC_IS_ISCHAIN_LOADED, &this->state);
+ clear_bit(FIMC_IS_ISCHAIN_POWER_ON, &this->state);
+ clear_bit(FIMC_IS_ISCHAIN_RUN, &this->state);
+
+ mutex_init(&this->mutex_state);
+ spin_lock_init(&this->slock_state);
+
+#ifdef FW_DEBUG
+ debugfs_root = debugfs_create_dir(DEBUG_FS_ROOT_NAME, NULL);
+ if (debugfs_root)
+ dbg_ischain("debugfs %s is created", DEBUG_FS_ROOT_NAME);
+
+ debugfs_file = debugfs_create_file(DEBUG_FS_FILE_NAME, S_IRUSR,
+ debugfs_root, this, &debug_fops);
+ if (debugfs_file)
+ dbg_ischain("debugfs %s is created", DEBUG_FS_FILE_NAME);
+#endif
+
+exit:
+ return 0;
+}
+
+int fimc_is_ischain_open(struct fimc_is_device_ischain *this,
+ struct fimc_is_video_common *video)
+{
+ int ret = 0;
+
+ if (testnset_state(this, FIMC_IS_ISCHAIN_OPEN)) {
+ err("already open");
+ ret = -EMFILE;
+ goto exit;
+ }
+
+ printk(KERN_INFO "+++%s()\n", __func__);
+
+ clear_bit(FIMC_IS_ISCHAIN_LOADED, &this->state);
+ clear_bit(FIMC_IS_ISCHAIN_POWER_ON, &this->state);
+ clear_bit(FIMC_IS_ISCHAIN_RUN, &this->state);
+
+#ifndef RESERVED_MEM
+ /* 1. init memory */
+ ret = fimc_is_ishcain_initmem(this);
+ if (ret) {
+ err("fimc_is_ishcain_initmem is fail(%d)\n", ret);
+ goto exit;
+ }
+#endif
+
+ /* 2. Init variables */
+ memset(&this->cur_peri_ctl, 0,
+ sizeof(struct camera2_uctl));
+ memset(&this->peri_ctls, 0,
+ sizeof(struct camera2_uctl)*SENSOR_MAX_CTL);
+ memset(&this->capability, 0,
+ sizeof(struct camera2_sm));
+
+ /* initial state, it's real apply to setting when opening*/
+ this->margin_left = 0;
+ this->margin_right = 0;
+ this->margin_width = 0;
+ this->margin_top = 0;
+ this->margin_bottom = 0;
+ this->margin_height = 0;
+ /* open function is called later than set input
+ so this code is commented.
+ this code will be used after sensor and
+ ischain power is seperated */
+ /*
+ this->sensor_width = 0;
+ this->sensor_height = 0;
+ this->chain0_width = 0;
+ this->chain0_height = 0;
+ this->chain1_width = 0;
+ this->chain1_height = 0;
+ this->chain2_width = 0;
+ this->chain2_height = 0;
+ this->chain3_width = 0;
+ this->chain3_height = 0;
+ */
+
+ this->fcount = 0;
+ this->setfile = 0;
+ this->debug_cnt = 0;
+ this->dzoom_width = 0;
+
+ /* frame manager open */
+ fimc_is_interface_open(this->interface);
+
+ /* other device open */
+ fimc_is_ischain_dev_open(&this->isp, ENTRY_ISP, video,
+ NULL);
+ fimc_is_ischain_dev_open(&this->drc, ENTRY_DRC, NULL,
+ &init_drc_param.control);
+ fimc_is_ischain_dev_open(&this->dis, ENTRY_DIS, NULL,
+ &init_dis_param.control);
+ fimc_is_ischain_dev_open(&this->dnr, ENTRY_TDNR, NULL,
+ &init_tdnr_param.control);
+ /* FD see only control.command not bypass */
+ fimc_is_ischain_dev_open(&this->fd, ENTRY_LHFD, NULL,
+ NULL);
+
+ /*fimc_is_fw_clear_irq1_all(core);*/
+
+ /* 3. Load IS firmware */
+ ret = fimc_is_ischain_loadfirm(this);
+ if (ret) {
+ err("failed to fimc_is_request_firmware (%d)\n", ret);
+ clear_bit(FIMC_IS_ISCHAIN_LOADED, &this->state);
+ ret = -EINVAL;
+ goto exit;
+ }
+ set_bit(FIMC_IS_ISCHAIN_LOADED, &this->state);
+
+ /* 4. Disable AFTR cpu low power idle enter */
+ pm_qos_add_request(&pm_qos_req_cpu, PM_QOS_CPU_DMA_LATENCY, 100);
+
+ /* memory minimun clock : 667Mhz */
+ if (!isp_mif_handle_min) {
+ isp_mif_handle_min = exynos5_bus_mif_min(667000);
+ if (!isp_mif_handle_min)
+ err("exynos5_bus_mif_min is fail");
+ } else
+ err("exynos5_bus_mif_min is already applied");
+
+ /* internal bus lock to 266Mhz */
+ if (!isp_int_handle_min) {
+ isp_int_handle_min = exynos5_bus_int_min(266000);
+ if (!isp_int_handle_min)
+ err("exynos5_bus_int_min is fail");
+ } else
+ err("exynos5_bus_int_min is already applied");
+
+ /* 5. A5 power on */
+ ret = fimc_is_ischain_power(this, 1);
+ if (ret) {
+ err("failed to fimc_is_ischain_power (%d)\n", ret);
+ ret = -EINVAL;
+ goto exit;
+ }
+ dbg_ischain("power up and loaded firmware\n");
+
+ /* bts api for bandwidth guarantee */
+ bts_change_bus_traffic(&this->pdev->dev, BTS_INCREASE_BW);
+
+ printk(KERN_INFO "---%s(%d)\n", __func__, ret);
+
+exit:
+ return ret;
+}
+
+int fimc_is_ischain_close(struct fimc_is_device_ischain *this)
+{
+ int ret = 0;
+
+ if (testnclr_state(this, FIMC_IS_ISCHAIN_OPEN)) {
+ err("already close");
+ ret = -EMFILE;
+ goto exit;
+ }
+
+ printk(KERN_INFO "+++%s\n", __func__);
+
+ /* 1. Stop all request */
+ ret = fimc_is_ischain_isp_stop(this);
+ if (ret)
+ err("fimc_is_ischain_isp_stop is fail");
+
+ /* 2. Stop a5 and other devices operation */
+ ret = fimc_is_itf_power_down(this);
+ if (ret)
+ err("power down is failed, retry forcelly");
+
+ /* 3. Deinit variables */
+ ret = fimc_is_interface_close(this->interface);
+ if (ret)
+ err("fimc_is_interface_close is failed");
+
+ /* 4. bus traffic low */
+ bts_change_bus_traffic(&this->pdev->dev, BTS_DECREASE_BW);
+
+ /* 5. Power down */
+ ret = fimc_is_ischain_power(this, 0);
+ if (ret)
+ err("fimc_is_ischain_power is failed");
+
+ /* 6. Enable AFTR cpu low power idle enter */
+ pm_qos_remove_request(&pm_qos_req_cpu);
+
+ /* memory clock unlock */
+ if (isp_mif_handle_min) {
+ exynos5_bus_mif_put(isp_mif_handle_min);
+ isp_mif_handle_min = NULL;
+ } else
+ err("exynos5_bus_mif_put is already applied");
+
+ /* internal bus unlock */
+ if (isp_int_handle_min) {
+ exynos5_bus_int_put(isp_int_handle_min);
+ isp_int_handle_min = NULL;
+ } else
+ err("exynos5_bus_int_put is already applied");
+
+#ifndef RESERVED_MEM
+ /* 7. Dealloc memroy */
+ fimc_is_ishcain_deinitmem(this);
+#endif
+
+ printk(KERN_INFO "---%s(%d)\n", __func__, ret);
+
+exit:
+ return ret;
+}
+
+int fimc_is_ischain_init(struct fimc_is_device_ischain *this,
+ u32 input, u32 channel, struct sensor_open_extended *ext,
+ char *setfile_name)
+{
+ int ret = 0;
+
+ dbg_ischain("%s(input : %d, channel : %d, Af : %d)\n",
+ __func__, input, channel, ext->actuator_con.product_name);
+
+ ret = fimc_is_itf_enum(this);
+ if (ret) {
+ err("enum fail");
+ goto exit;
+ }
+
+ memcpy(&this->is_region->shared[0], ext,
+ sizeof(struct sensor_open_extended));
+
+ ret = fimc_is_itf_open(this, input, channel, this->minfo.dvaddr_shared);
+ if (ret) {
+ err("open fail");
+ goto exit;
+ }
+
+ ret = fimc_is_itf_setfile(this, setfile_name);
+ if (ret) {
+ err("setfile fail");
+ goto exit;
+ }
+
+ ret = fimc_is_itf_stream_off(this);
+ if (ret) {
+ err("streamoff fail");
+ goto exit;
+ }
+
+ ret = fimc_is_itf_process_off(this);
+ if (ret) {
+ err("processoff fail");
+ goto exit;
+ }
+
+exit:
+ return ret;
+}
+
+static int fimc_is_ischain_s_setfile(struct fimc_is_device_ischain *this)
+{
+ int ret = 0;
+ bool process = true;
+
+ printk(KERN_INFO "setfile is %d\n", this->setfile);
+
+ if (this->setfile >= ISS_SUB_END) {
+ err("setfile id(%d) is invalid\n", this->setfile);
+ goto exit;
+ }
+ process = false;
+
+ ret = fimc_is_itf_process_off(this);
+ if (ret) {
+ err("fimc_is_itf_process_off fail\n");
+ goto exit;
+ }
+
+ ret = fimc_is_itf_a_param(this);
+ if (ret) {
+ err("fimc_is_itf_a_param is fail\n");
+ goto exit;
+ }
+
+ ret = fimc_is_itf_process_on(this);
+ if (ret) {
+ err("fimc_is_itf_process_on fail1\n");
+ goto exit;
+ }
+ process = true;
+
+exit:
+ if (!process)
+ if (fimc_is_itf_process_on(this))
+ err("fimc_is_itf_process_on fail2\n");
+
+ return ret;
+}
+
+static int fimc_is_ischain_s_chain0_size(struct fimc_is_device_ischain *this,
+ u32 width, u32 height)
+{
+ int ret = 0;
+ struct isp_param *isp_param;
+ struct drc_param *drc_param;
+ struct scalerc_param *scc_param;
+
+ u32 chain0_width, chain0_height;
+ u32 indexes, lindex, hindex;
+
+ isp_param = &this->is_region->parameter.isp;
+ drc_param = &this->is_region->parameter.drc;
+ scc_param = &this->is_region->parameter.scalerc;
+ indexes = lindex = hindex = 0;
+ chain0_width = width;
+ chain0_height = height;
+
+ dbg_ischain("request chain0 size : %dx%d\n",
+ chain0_width, chain0_height);
+
+ isp_param->otf_output.cmd = OTF_OUTPUT_COMMAND_ENABLE;
+ isp_param->otf_output.width = chain0_width;
+ isp_param->otf_output.height = chain0_height;
+ isp_param->otf_output.format = OTF_OUTPUT_FORMAT_YUV444;
+ isp_param->otf_output.bitwidth = OTF_OUTPUT_BIT_WIDTH_12BIT;
+ isp_param->otf_output.order = OTF_INPUT_ORDER_BAYER_GR_BG;
+ lindex |= LOWBIT_OF(PARAM_ISP_OTF_OUTPUT);
+ hindex |= HIGHBIT_OF(PARAM_ISP_OTF_OUTPUT);
+ indexes++;
+
+ isp_param->dma1_output.cmd = DMA_OUTPUT_COMMAND_DISABLE;
+ lindex |= LOWBIT_OF(PARAM_ISP_DMA1_OUTPUT);
+ hindex |= HIGHBIT_OF(PARAM_ISP_DMA1_OUTPUT);
+ indexes++;
+
+ isp_param->dma2_output.cmd = DMA_OUTPUT_COMMAND_DISABLE;
+ lindex |= LOWBIT_OF(PARAM_ISP_DMA2_OUTPUT);
+ hindex |= HIGHBIT_OF(PARAM_ISP_DMA2_OUTPUT);
+ indexes++;
+
+ /* DRC */
+ drc_param->otf_input.cmd = OTF_INPUT_COMMAND_ENABLE;
+ drc_param->otf_input.width = chain0_width;
+ drc_param->otf_input.height = chain0_height;
+ lindex |= LOWBIT_OF(PARAM_DRC_OTF_INPUT);
+ hindex |= HIGHBIT_OF(PARAM_DRC_OTF_INPUT);
+ indexes++;
+
+ drc_param->otf_output.cmd = OTF_OUTPUT_COMMAND_ENABLE;
+ drc_param->otf_output.width = chain0_width;
+ drc_param->otf_output.height = chain0_height;
+ lindex |= LOWBIT_OF(PARAM_DRC_OTF_OUTPUT);
+ hindex |= HIGHBIT_OF(PARAM_DRC_OTF_OUTPUT);
+ indexes++;
+
+ /* SCC */
+ scc_param->otf_input.cmd = OTF_INPUT_COMMAND_ENABLE;
+ scc_param->otf_input.width = chain0_width;
+ scc_param->otf_input.height = chain0_height;
+ lindex |= LOWBIT_OF(PARAM_SCALERC_OTF_INPUT);
+ hindex |= HIGHBIT_OF(PARAM_SCALERC_OTF_INPUT);
+ indexes++;
+
+ return ret;
+}
+
+static int fimc_is_ischain_s_chain1_size(struct fimc_is_device_ischain *this,
+ u32 width, u32 height)
+{
+ int ret = 0;
+ struct scalerc_param *scc_param;
+ struct odc_param *odc_param;
+ struct dis_param *dis_param;
+ u32 chain0_width, chain0_height;
+ u32 chain1_width, chain1_height;
+ u32 indexes, lindex, hindex;
+
+ scc_param = &this->is_region->parameter.scalerc;
+ odc_param = &this->is_region->parameter.odc;
+ dis_param = &this->is_region->parameter.dis;
+ indexes = lindex = hindex = 0;
+ chain0_width = this->chain0_width;
+ chain0_height = this->chain0_height;
+ chain1_width = width;
+ chain1_height = height;
+
+ dbg_ischain("current chain0 size : %dx%d\n",
+ chain0_width, chain0_height);
+ dbg_ischain("current chain1 size : %dx%d\n",
+ this->chain1_width, this->chain1_height);
+ dbg_ischain("request chain1 size : %dx%d\n",
+ chain1_width, chain1_height);
+
+ if (!chain0_width) {
+ err("chain0 width is zero");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (!chain0_height) {
+ err("chain0 height is zero");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (!chain1_width) {
+ err("chain1 width is zero");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (!chain1_height) {
+ err("chain1 height is zero");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ /* SCC OUTPUT */
+ scc_param->input_crop.cmd = SCALER_CROP_COMMAND_ENABLE;
+ scc_param->input_crop.pos_x = 0;
+ scc_param->input_crop.pos_y = 0;
+ scc_param->input_crop.crop_width = chain0_width;
+ scc_param->input_crop.crop_height = chain0_height;
+ scc_param->input_crop.in_width = chain0_width;
+ scc_param->input_crop.in_height = chain0_height;
+ scc_param->input_crop.out_width = chain1_width;
+ scc_param->input_crop.out_height = chain1_height;
+ lindex |= LOWBIT_OF(PARAM_SCALERC_INPUT_CROP);
+ hindex |= HIGHBIT_OF(PARAM_SCALERC_INPUT_CROP);
+ indexes++;
+
+ scc_param->output_crop.cmd = SCALER_CROP_COMMAND_DISABLE;
+ scc_param->output_crop.pos_x = 0;
+ scc_param->output_crop.pos_y = 0;
+ scc_param->output_crop.crop_width = chain1_width;
+ scc_param->output_crop.crop_height = chain1_height;
+ lindex |= LOWBIT_OF(PARAM_SCALERC_OUTPUT_CROP);
+ hindex |= HIGHBIT_OF(PARAM_SCALERC_OUTPUT_CROP);
+ indexes++;
+
+ scc_param->otf_output.cmd = OTF_OUTPUT_COMMAND_ENABLE;
+ scc_param->otf_output.width = chain1_width;
+ scc_param->otf_output.height = chain1_height;
+ lindex |= LOWBIT_OF(PARAM_SCALERC_OTF_OUTPUT);
+ hindex |= HIGHBIT_OF(PARAM_SCALERC_OTF_OUTPUT);
+ indexes++;
+
+ /* ODC */
+ odc_param->otf_input.width = chain1_width;
+ odc_param->otf_input.height = chain1_height;
+ lindex |= LOWBIT_OF(PARAM_ODC_OTF_INPUT);
+ hindex |= HIGHBIT_OF(PARAM_ODC_OTF_INPUT);
+ indexes++;
+
+ odc_param->otf_output.width = chain1_width;
+ odc_param->otf_output.height = chain1_height;
+ lindex |= LOWBIT_OF(PARAM_ODC_OTF_OUTPUT);
+ hindex |= HIGHBIT_OF(PARAM_ODC_OTF_OUTPUT);
+ indexes++;
+
+ /* DIS INPUT */
+ dis_param->otf_input.width = chain1_width;
+ dis_param->otf_input.height = chain1_height;
+ lindex |= LOWBIT_OF(PARAM_DIS_OTF_INPUT);
+ hindex |= HIGHBIT_OF(PARAM_DIS_OTF_INPUT);
+ indexes++;
+
+ this->lindex |= lindex;
+ this->hindex |= hindex;
+ this->indexes += indexes;
+
+exit:
+ return ret;
+}
+
+static int fimc_is_ischain_s_chain2_size(struct fimc_is_device_ischain *this,
+ u32 width, u32 height)
+{
+ int ret = 0;
+ struct dis_param *dis_param;
+ struct tdnr_param *tdnr_param;
+ struct scalerp_param *scp_param;
+
+ u32 chain2_width, chain2_height;
+ u32 indexes, lindex, hindex;
+
+ dbg_ischain("request chain2 size : %dx%d\n", width, height);
+ dbg_ischain("current chain2 size : %dx%d\n",
+ this->chain2_width, this->chain2_height);
+
+ dis_param = &this->is_region->parameter.dis;
+ tdnr_param = &this->is_region->parameter.tdnr;
+ scp_param = &this->is_region->parameter.scalerp;
+ indexes = lindex = hindex = 0;
+
+ /* CALCULATION */
+ chain2_width = width;
+ chain2_height = height;
+
+ /* DIS OUTPUT */
+ dis_param->otf_output.width = chain2_width;
+ dis_param->otf_output.height = chain2_height;
+ lindex |= LOWBIT_OF(PARAM_DIS_OTF_OUTPUT);
+ hindex |= HIGHBIT_OF(PARAM_DIS_OTF_OUTPUT);
+ indexes++;
+
+ /* 3DNR */
+ tdnr_param->otf_input.width = chain2_width;
+ tdnr_param->otf_input.height = chain2_height;
+ lindex |= LOWBIT_OF(PARAM_TDNR_OTF_INPUT);
+ hindex |= HIGHBIT_OF(PARAM_TDNR_OTF_INPUT);
+ indexes++;
+
+ tdnr_param->dma_output.width = chain2_width;
+ tdnr_param->dma_output.height = chain2_height;
+ lindex |= LOWBIT_OF(PARAM_TDNR_DMA_OUTPUT);
+ hindex |= HIGHBIT_OF(PARAM_TDNR_DMA_OUTPUT);
+ indexes++;
+
+ tdnr_param->otf_output.width = chain2_width;
+ tdnr_param->otf_output.height = chain2_height;
+ lindex |= LOWBIT_OF(PARAM_TDNR_OTF_OUTPUT);
+ hindex |= HIGHBIT_OF(PARAM_TDNR_OTF_OUTPUT);
+ indexes++;
+
+ /* SCALERP INPUT */
+ scp_param->otf_input.width = chain2_width;
+ scp_param->otf_input.height = chain2_height;
+ lindex |= LOWBIT_OF(PARAM_SCALERP_OTF_INPUT);
+ hindex |= HIGHBIT_OF(PARAM_SCALERP_OTF_INPUT);
+ indexes++;
+
+ this->lindex |= lindex;
+ this->hindex |= hindex;
+ this->indexes += indexes;
+
+ return ret;
+}
+
+static int fimc_is_ischain_s_chain3_size(struct fimc_is_device_ischain *this,
+ u32 width, u32 height)
+{
+ int ret = 0;
+ struct scalerp_param *scp_param;
+ struct fd_param *fd_param;
+ struct fimc_is_video_common *video;
+ u32 chain2_width, chain2_height;
+ u32 chain3_width, chain3_height;
+ u32 scp_crop_width, scp_crop_height;
+ u32 scp_crop_x, scp_crop_y;
+ u32 indexes, lindex, hindex;
+
+ scp_param = &this->is_region->parameter.scalerp;
+ fd_param = &this->is_region->parameter.fd;
+ video = this->scp.video;
+ indexes = lindex = hindex = 0;
+
+ chain2_width = this->chain2_width;
+ chain2_height = this->chain2_height;
+
+ chain3_width = width;
+ chain3_height = height;
+
+ scp_crop_x = 0;
+ scp_crop_y = 0;
+ scp_crop_width = chain2_width;
+ scp_crop_height = chain2_height;
+
+ dbg_ischain("request chain3 size : %dx%d\n", width, height);
+ dbg_ischain("current chain3 size : %dx%d\n",
+ this->chain3_width, this->chain3_height);
+
+ /*SCALERP*/
+ scp_param->input_crop.cmd = SCALER_CROP_COMMAND_ENABLE;
+ scp_param->input_crop.pos_x = scp_crop_x;
+ scp_param->input_crop.pos_y = scp_crop_y;
+ scp_param->input_crop.crop_width = scp_crop_width;
+ scp_param->input_crop.crop_height = scp_crop_height;
+ scp_param->input_crop.in_width = chain2_width;
+ scp_param->input_crop.in_height = chain2_height;
+ scp_param->input_crop.out_width = chain3_width;
+ scp_param->input_crop.out_height = chain3_height;
+ lindex |= LOWBIT_OF(PARAM_SCALERP_INPUT_CROP);
+ hindex |= HIGHBIT_OF(PARAM_SCALERP_INPUT_CROP);
+ indexes++;
+
+ /* sclaer can't apply stride to each plane, only y plane.
+ cb, cr plane should be half of y plane, it's automatically set
+ 3 plane : all plane can be 32 stride or 16, 8
+ 2 plane : y plane only can be 32, 16 stride, other should be half of y
+ 1 plane : all plane can be 8 plane */
+ if (video->frame.width_stride[0]) {
+ scp_param->output_crop.cmd = SCALER_CROP_COMMAND_ENABLE;
+ scp_param->output_crop.pos_x = 0;
+ scp_param->output_crop.pos_y = 0;
+ scp_param->output_crop.crop_width = chain3_width +
+ video->frame.width_stride[0];
+ scp_param->output_crop.crop_height = chain3_height;
+ lindex |= LOWBIT_OF(PARAM_SCALERP_OUTPUT_CROP);
+ hindex |= HIGHBIT_OF(PARAM_SCALERP_OUTPUT_CROP);
+ indexes++;
+ } else {
+ scp_param->output_crop.cmd = SCALER_CROP_COMMAND_DISABLE;
+ lindex |= LOWBIT_OF(PARAM_SCALERP_OUTPUT_CROP);
+ hindex |= HIGHBIT_OF(PARAM_SCALERP_OUTPUT_CROP);
+ indexes++;
+ }
+
+ scp_param->otf_output.width = chain3_width;
+ scp_param->otf_output.height = chain3_height;
+ lindex |= LOWBIT_OF(PARAM_SCALERP_OTF_OUTPUT);
+ hindex |= HIGHBIT_OF(PARAM_SCALERP_OTF_OUTPUT);
+ indexes++;
+
+ scp_param->dma_output.width = chain3_width;
+ scp_param->dma_output.height = chain3_height;
+ lindex |= LOWBIT_OF(PARAM_SCALERP_DMA_OUTPUT);
+ hindex |= HIGHBIT_OF(PARAM_SCALERP_DMA_OUTPUT);
+ indexes++;
+
+ /* FD */
+ fd_param->otf_input.width = chain3_width;
+ fd_param->otf_input.height = chain3_height;
+ lindex |= LOWBIT_OF(PARAM_FD_OTF_INPUT);
+ hindex |= HIGHBIT_OF(PARAM_FD_OTF_INPUT);
+ indexes++;
+
+ this->lindex |= lindex;
+ this->hindex |= hindex;
+ this->indexes += indexes;
+
+ return ret;
+}
+
+static int fimc_is_ischain_s_chain1_stop(struct fimc_is_device_ischain *this)
+{
+ int ret = 0;
+ struct scalerc_param *scc_param;
+ struct odc_param *odc_param;
+ struct dis_param *dis_param;
+
+ u32 indexes, lindex, hindex;
+
+ scc_param = &this->is_region->parameter.scalerc;
+ odc_param = &this->is_region->parameter.odc;
+ dis_param = &this->is_region->parameter.dis;
+ indexes = lindex = hindex = 0;
+
+ /* SCC OUTPUT */
+ scc_param->control.cmd = CONTROL_COMMAND_STOP;
+ lindex |= LOWBIT_OF(PARAM_SCALERC_CONTROL);
+ hindex |= HIGHBIT_OF(PARAM_SCALERC_CONTROL);
+ indexes++;
+
+ /* ODC */
+ odc_param->control.cmd = CONTROL_COMMAND_STOP;
+ lindex |= LOWBIT_OF(PARAM_ODC_CONTROL);
+ hindex |= HIGHBIT_OF(PARAM_ODC_CONTROL);
+ indexes++;
+
+ /* DIS INPUT */
+ dis_param->control.cmd = CONTROL_COMMAND_STOP;
+ lindex |= LOWBIT_OF(PARAM_DIS_CONTROL);
+ hindex |= HIGHBIT_OF(PARAM_DIS_CONTROL);
+ indexes++;
+
+ this->lindex |= lindex;
+ this->hindex |= hindex;
+ this->indexes += indexes;
+
+ return ret;
+}
+
+static int fimc_is_ischain_s_chain1_start(struct fimc_is_device_ischain *this)
+{
+ int ret = 0;
+ struct scalerc_param *scc_param;
+ struct odc_param *odc_param;
+ struct dis_param *dis_param;
+ u32 indexes, lindex, hindex;
+
+ scc_param = &this->is_region->parameter.scalerc;
+ odc_param = &this->is_region->parameter.odc;
+ dis_param = &this->is_region->parameter.dis;
+ indexes = lindex = hindex = 0;
+
+ /* SCC OUTPUT */
+ scc_param->control.cmd = CONTROL_COMMAND_START;
+ lindex |= LOWBIT_OF(PARAM_SCALERC_CONTROL);
+ hindex |= HIGHBIT_OF(PARAM_SCALERC_CONTROL);
+ indexes++;
+
+ /* ODC */
+ odc_param->control.cmd = CONTROL_COMMAND_START;
+ lindex |= LOWBIT_OF(PARAM_ODC_CONTROL);
+ hindex |= HIGHBIT_OF(PARAM_ODC_CONTROL);
+ indexes++;
+
+ /* DIS INPUT */
+ dis_param->control.cmd = CONTROL_COMMAND_START;
+ lindex |= LOWBIT_OF(PARAM_DIS_CONTROL);
+ hindex |= HIGHBIT_OF(PARAM_DIS_CONTROL);
+ indexes++;
+
+ this->lindex |= lindex;
+ this->hindex |= hindex;
+ this->indexes += indexes;
+
+ return ret;
+}
+
+static int fimc_is_ischain_s_dzoom(struct fimc_is_device_ischain *this,
+ u32 crop_x, u32 crop_y, u32 crop_width)
+{
+ int ret = 0;
+ u32 indexes, lindex, hindex;
+ u32 chain0_width, chain0_height;
+ u32 temp_width, temp_height, input_width;
+ u32 zoom_input, zoom_target;
+ u32 crop_cx, crop_cy, crop_cwidth, crop_cheight;
+ struct scalerc_param *scc_param;
+#ifdef USE_ADVANCED_DZOOM
+ u32 zoom_pre, zoom_post, zoom_pre_max;
+ u32 crop_px, crop_py, crop_pwidth, crop_pheight;
+ u32 chain1_width, chain1_height;
+ u32 chain2_width, chain2_height;
+ struct scalerp_param *scp_param;
+
+ scc_param = &this->is_region->parameter.scalerc;
+ scp_param = &this->is_region->parameter.scalerp;
+ indexes = lindex = hindex = 0;
+ chain0_width = this->chain0_width;
+ chain0_height = this->chain0_height;
+ chain1_width = this->chain1_width;
+ chain1_height = this->chain1_height;
+ chain2_width = this->chain2_width;
+ chain2_height = this->chain2_height;
+#ifdef PRINT_DZOOM
+ printk(KERN_INFO "chain0(%d, %d), chain1(%d, %d), chain2(%d, %d)\n",
+ chain0_width, chain0_height,
+ chain1_width, chain1_height,
+ chain2_width, chain2_height);
+#endif
+#else
+ scc_param = &this->is_region->parameter.scalerc;
+ indexes = lindex = hindex = 0;
+ chain0_width = this->chain0_width;
+ chain0_height = this->chain0_height;
+#ifdef PRINT_DZOOM
+ printk(KERN_INFO "chain0(%d, %d)\n", chain0_width, chain0_height);
+#endif
+#endif
+
+ /* CHECK */
+ input_width = crop_width;
+ temp_width = crop_width + (crop_x<<1);
+ if (temp_width != chain0_width) {
+ err("input width is not valid(%d != %d)",
+ temp_width, chain0_width);
+ /* if invalid input come, dzoom is not apply and
+ shot command is sent to firmware */
+ ret = 0;
+ goto exit;
+ }
+
+#ifdef USE_ADVANCED_DZOOM
+ zoom_input = (chain0_width * 1000) / crop_width;
+ zoom_pre_max = (chain0_width * 1000) / chain1_width;
+
+ if (zoom_pre_max < 1000)
+ zoom_pre_max = 1000;
+
+#ifdef PRINT_DZOOM
+ printk(KERN_INFO "zoom input : %d, premax-zoom : %d\n",
+ zoom_input, zoom_pre_max);
+#endif
+
+ if (test_bit(FIMC_IS_ISDEV_DSTART, &this->dis.state))
+ zoom_target = (zoom_input * 91 + 34000) / 125;
+ else
+ zoom_target = zoom_input;
+
+ if (zoom_target > zoom_pre_max) {
+ zoom_pre = zoom_pre_max;
+ zoom_post = (zoom_target * 1000) / zoom_pre;
+ } else {
+ zoom_pre = zoom_target;
+ zoom_post = 1000;
+ }
+
+ /* CALCULATION */
+ temp_width = (chain0_width * 1000) / zoom_pre;
+ temp_height = (chain0_height * 1000) / zoom_pre;
+ crop_cx = (chain0_width - temp_width)>>1;
+ crop_cy = (chain0_height - temp_height)>>1;
+ crop_cwidth = chain0_width - (crop_cx<<1);
+ crop_cheight = chain0_height - (crop_cy<<1);
+
+ scc_param->input_crop.cmd = SCALER_CROP_COMMAND_ENABLE;
+ scc_param->input_crop.pos_x = crop_cx;
+ scc_param->input_crop.pos_y = crop_cy;
+ scc_param->input_crop.crop_width = crop_cwidth;
+ scc_param->input_crop.crop_height = crop_cheight;
+ lindex |= LOWBIT_OF(PARAM_SCALERC_INPUT_CROP);
+ hindex |= HIGHBIT_OF(PARAM_SCALERC_INPUT_CROP);
+ indexes++;
+
+#ifdef PRINT_DZOOM
+ printk(KERN_INFO "pre-zoom target : %d(%d, %d, %d %d)\n",
+ zoom_pre, crop_cx, crop_cy, crop_cwidth, crop_cheight);
+#endif
+
+ temp_width = (chain2_width * 1000) / zoom_post;
+ temp_height = (chain2_height * 1000) / zoom_post;
+ crop_px = (chain2_width - temp_width)>>1;
+ crop_py = (chain2_height - temp_height)>>1;
+ crop_pwidth = chain2_width - (crop_px<<1);
+ crop_pheight = chain2_height - (crop_py<<1);
+
+ scp_param->input_crop.cmd = SCALER_CROP_COMMAND_ENABLE;
+ scp_param->input_crop.pos_x = crop_px;
+ scp_param->input_crop.pos_y = crop_py;
+ scp_param->input_crop.crop_width = crop_pwidth;
+ scp_param->input_crop.crop_height = crop_pheight;
+ lindex |= LOWBIT_OF(PARAM_SCALERP_INPUT_CROP);
+ hindex |= HIGHBIT_OF(PARAM_SCALERP_INPUT_CROP);
+ indexes++;
+
+#ifdef PRINT_DZOOM
+ printk(KERN_INFO "post-zoom target : %d(%d, %d, %d %d)\n",
+ zoom_post, crop_px, crop_py, crop_pwidth, crop_pheight);
+#endif
+#else
+ zoom_input = (chain0_width * 1000) / crop_width;
+
+ if (test_bit(FIMC_IS_ISDEV_DSTART, &this->dis.state))
+ zoom_target = (zoom_input * 91 + 34000) / 125;
+ else
+ zoom_target = zoom_input;
+
+ temp_width = (chain0_width * 1000) / zoom_target;
+ temp_height = (chain0_height * 1000) / zoom_target;
+ crop_cx = (chain0_width - temp_width)>>1;
+ crop_cy = (chain0_height - temp_height)>>1;
+ crop_cwidth = chain0_width - (crop_cx<<1);
+ crop_cheight = chain0_height - (crop_cy<<1);
+
+ scc_param->input_crop.cmd = SCALER_CROP_COMMAND_ENABLE;
+ scc_param->input_crop.pos_x = crop_cx;
+ scc_param->input_crop.pos_y = crop_cy;
+ scc_param->input_crop.crop_width = crop_cwidth;
+ scc_param->input_crop.crop_height = crop_cheight;
+ lindex |= LOWBIT_OF(PARAM_SCALERC_INPUT_CROP);
+ hindex |= HIGHBIT_OF(PARAM_SCALERC_INPUT_CROP);
+ indexes++;
+
+#ifdef PRINT_DZOOM
+ printk(KERN_INFO "zoom input : %d, zoom target : %d(%d, %d, %d %d)\n",
+ zoom_input, zoom_target,
+ crop_cx, crop_cy, crop_cwidth, crop_cheight);
+#endif
+#endif
+
+ ret = fimc_is_itf_s_param(this, indexes, lindex, hindex);
+ if (ret) {
+ err("fimc_is_itf_s_param is fail\n");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ this->crop_x = crop_cx;
+ this->crop_y = crop_cy;
+ this->crop_width = crop_cwidth;
+ this->crop_height = crop_cheight;
+ this->dzoom_width = input_width;
+
+exit:
+ return ret;
+}
+
+static int fimc_is_ischain_drc_bypass(struct fimc_is_device_ischain *this,
+ bool bypass)
+{
+ int ret = 0;
+ struct drc_param *drc_param;
+ u32 indexes, lindex, hindex;
+
+ dbg_ischain("%s\n", __func__);
+
+ drc_param = &this->is_region->parameter.drc;
+ indexes = lindex = hindex = 0;
+
+ if (bypass)
+ drc_param->control.bypass = CONTROL_BYPASS_ENABLE;
+ else
+ drc_param->control.bypass = CONTROL_BYPASS_DISABLE;
+
+ lindex |= LOWBIT_OF(PARAM_DRC_CONTROL);
+ hindex |= HIGHBIT_OF(PARAM_DRC_CONTROL);
+ indexes++;
+
+ ret = fimc_is_itf_s_param(this, indexes, lindex, hindex);
+ if (ret) {
+ err("fimc_is_itf_s_param is fail\n");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (bypass) {
+ clear_bit(FIMC_IS_ISDEV_DSTART, &this->drc.state);
+ dbg_ischain("DRC off\n");
+ } else {
+ set_bit(FIMC_IS_ISDEV_DSTART, &this->drc.state);
+ dbg_ischain("DRC on\n");
+ }
+
+exit:
+ return ret;
+}
+
+static int fimc_is_ischain_dis_bypass(struct fimc_is_device_ischain *this,
+ bool bypass)
+{
+ int ret = 0;
+ bool process = true;
+ u32 chain1_width, chain1_height;
+ struct dis_param *dis_param;
+
+ dbg_ischain("%s(%d)\n", __func__, bypass);
+
+ dis_param = &this->is_region->parameter.dis;
+
+ ret = fimc_is_itf_process_off(this);
+ if (ret) {
+ err("fimc_is_itf_process_off is fail\n");
+ ret = -EINVAL;
+ goto exit;
+ }
+ process = false;
+
+ if (bypass) {
+ chain1_width = this->chain2_width;
+ chain1_height = this->chain2_height;
+ } else {
+ chain1_width = ALIGN(this->chain1_width*125/100, 4);
+ chain1_height = ALIGN(this->chain1_height*125/100, 2);
+ }
+
+ this->lindex = this->hindex = this->indexes = 0;
+ fimc_is_ischain_s_chain1_size(this, chain1_width, chain1_height);
+
+ if (bypass)
+ dis_param->control.bypass = CONTROL_BYPASS_ENABLE;
+ else {
+ dis_param->control.bypass = CONTROL_BYPASS_DISABLE;
+ dis_param->control.buffer_number =
+ SIZE_DIS_INTERNAL_BUF * NUM_DIS_INTERNAL_BUF;
+ dis_param->control.buffer_address =
+ this->minfo.dvaddr_shared + 300 * sizeof(u32);
+ this->is_region->shared[300] = this->minfo.dvaddr_dis;
+ }
+
+ this->lindex |= LOWBIT_OF(PARAM_DIS_CONTROL);
+ this->hindex |= HIGHBIT_OF(PARAM_DIS_CONTROL);
+ this->indexes++;
+
+ ret = fimc_is_itf_s_param(this,
+ this->indexes, this->lindex, this->hindex);
+ if (ret) {
+ err("fimc_is_itf_s_param is fail\n");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ ret = fimc_is_itf_a_param(this);
+ if (ret) {
+ err("fimc_is_itf_a_param is fail\n");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ ret = fimc_is_itf_process_on(this);
+ if (ret) {
+ err("fimc_is_itf_process_on is fail1\n");
+ ret = -EINVAL;
+ goto exit;
+ }
+ process = true;
+
+ if (bypass) {
+ clear_bit(FIMC_IS_ISDEV_DSTART, &this->dis.state);
+ dbg_ischain("DIS off\n");
+ } else {
+ set_bit(FIMC_IS_ISDEV_DSTART, &this->dis.state);
+ dbg_ischain("DIS on\n");
+ }
+
+ this->chain1_width = chain1_width;
+ this->chain1_height = chain1_height;
+
+exit:
+ if (!process)
+ if (fimc_is_itf_process_on(this))
+ err("fimc_is_itf_process_on fail2\n");
+
+ return ret;
+}
+
+static int fimc_is_ischain_dnr_bypass(struct fimc_is_device_ischain *this,
+ bool bypass)
+{
+ int ret = 0;
+ struct tdnr_param *dnr_param;
+ u32 indexes, lindex, hindex;
+
+ dbg_ischain("%s\n", __func__);
+
+ dnr_param = &this->is_region->parameter.tdnr;
+ indexes = lindex = hindex = 0;
+
+ if (bypass)
+ dnr_param->control.bypass = CONTROL_BYPASS_ENABLE;
+ else {
+ dnr_param->control.bypass = CONTROL_BYPASS_DISABLE;
+ dnr_param->control.buffer_number =
+ SIZE_DNR_INTERNAL_BUF * NUM_DNR_INTERNAL_BUF;
+ dnr_param->control.buffer_address =
+ this->minfo.dvaddr_shared + 350 * sizeof(u32);
+ this->is_region->shared[350] = this->minfo.dvaddr_3dnr;
+ }
+
+ lindex |= LOWBIT_OF(PARAM_TDNR_CONTROL);
+ hindex |= HIGHBIT_OF(PARAM_TDNR_CONTROL);
+ indexes++;
+
+ ret = fimc_is_itf_s_param(this, indexes, lindex, hindex);
+ if (ret) {
+ err("fimc_is_itf_s_param is fail\n");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (bypass) {
+ clear_bit(FIMC_IS_ISDEV_DSTART, &this->dnr.state);
+ dbg_ischain("TDNR off\n");
+ } else {
+ set_bit(FIMC_IS_ISDEV_DSTART, &this->dnr.state);
+ dbg_ischain("TNDR on\n");
+ }
+
+exit:
+ return ret;
+}
+
+static int fimc_is_ischain_fd_bypass(struct fimc_is_device_ischain *this,
+ bool bypass)
+{
+ int ret = 0;
+ bool process = true;
+ struct fd_param *fd_param;
+ u32 indexes, lindex, hindex;
+
+ dbg_ischain("%s(%d)\n", __func__, bypass);
+
+ fd_param = &this->is_region->parameter.fd;
+ indexes = lindex = hindex = 0;
+
+ ret = fimc_is_itf_process_off(this);
+ if (ret) {
+ err("fimc_is_itf_process_off is fail\n");
+ ret = -EINVAL;
+ goto exit;
+ }
+ process = false;
+
+ if (bypass) {
+ fd_param->control.cmd = CONTROL_COMMAND_STOP;
+ fd_param->control.bypass = CONTROL_BYPASS_DISABLE;
+ } else {
+ fd_param->control.cmd = CONTROL_COMMAND_START;
+ fd_param->control.bypass = CONTROL_BYPASS_DISABLE;
+ }
+
+ lindex |= LOWBIT_OF(PARAM_FD_CONTROL);
+ hindex |= HIGHBIT_OF(PARAM_FD_CONTROL);
+ indexes++;
+
+ ret = fimc_is_itf_s_param(this, indexes, lindex, hindex);
+ if (ret) {
+ err("fimc_is_itf_s_param is fail\n");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ ret = fimc_is_itf_process_on(this);
+ if (ret) {
+ err("fimc_is_itf_process_on is fail1\n");
+ ret = -EINVAL;
+ goto exit;
+ }
+ process = true;
+
+ if (bypass) {
+ clear_bit(FIMC_IS_ISDEV_DSTART, &this->fd.state);
+ dbg_ischain("FD off\n");
+ } else {
+ set_bit(FIMC_IS_ISDEV_DSTART, &this->fd.state);
+ dbg_ischain("FD on\n");
+ }
+
+exit:
+ if (!process)
+ if (fimc_is_itf_process_on(this))
+ err("fimc_is_itf_process_on fail2\n");
+
+ return ret;
+}
+
+int fimc_is_ischain_isp_start(struct fimc_is_device_ischain *this,
+ struct fimc_is_video_common *video)
+{
+ int ret = 0;
+ struct isp_param *isp_param;
+ struct fimc_is_framemgr *framemgr;
+ struct fimc_is_ischain_dev *isp;
+ u32 crop_x, crop_y, crop_width, crop_height;
+ u32 sensor_width, sensor_height, sensor_ratio;
+ u32 chain3_width, chain3_height, chain3_ratio;
+ u32 chain1_wmin, chain1_hmin;
+ u32 lindex, hindex, indexes;
+
+ dbg_isp("%s()\n", __func__);
+
+ indexes = lindex = hindex = 0;
+
+ isp = &this->isp;
+ framemgr = this->framemgr;
+ isp_param = &this->is_region->parameter.isp;
+
+ if (test_bit(FIMC_IS_ISDEV_DSTART, &isp->state)) {
+ err("already start");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ /* 1. crop calculation */
+ sensor_width = this->sensor_width;
+ sensor_height = this->sensor_height;
+ chain3_width = this->chain3_width;
+ chain3_height = this->chain3_height;
+ crop_width = sensor_width;
+ crop_height = sensor_height;
+ crop_x = crop_y = 0;
+
+ sensor_ratio = sensor_width * 1000 / sensor_height;
+ chain3_ratio = chain3_width * 1000 / chain3_height;
+
+ if (sensor_ratio == chain3_ratio) {
+ crop_width = sensor_width;
+ crop_height = sensor_height;
+ } else if (sensor_ratio < chain3_ratio) {
+ /* isp dma input limitation
+ height : 2 times */
+ crop_height =
+ (sensor_width * chain3_height) / chain3_width;
+ crop_height = ALIGN(crop_height, 2);
+ crop_y = ((sensor_height - crop_height) >> 1) & 0xFFFFFFFE;
+ } else {
+ /* isp dma input limitation
+ width : 4 times */
+ crop_width =
+ (sensor_height * chain3_width) / chain3_height;
+ crop_width = ALIGN(crop_width, 4);
+ crop_x = ((sensor_width - crop_width) >> 1) & 0xFFFFFFFE;
+ }
+
+ this->dzoom_width = crop_width;
+ this->chain0_width = crop_width;
+ this->chain0_height = crop_height;
+ this->crop_width = crop_width;
+ this->crop_height = crop_height;
+ this->crop_x = crop_x;
+ this->crop_y = crop_y;
+
+ dbg_isp("crop_x : %d, crop y : %d\n", crop_x, crop_y);
+ dbg_isp("crop width : %d, crop height : %d\n",
+ crop_width, crop_height);
+
+ /* 2. scaling calculation */
+ chain1_wmin = (crop_width >> 4) & 0xFFFFFFFE;
+ chain1_hmin = (crop_height >> 4) & 0xFFFFFFFE;
+
+ if (chain1_wmin > this->chain1_width) {
+ printk(KERN_INFO "scc down scale limited : (%d,%d)->(%d,%d)\n",
+ this->chain1_width, this->chain1_height,
+ chain1_wmin, chain1_hmin);
+ this->chain1_width = chain1_wmin;
+ this->chain1_height = chain1_hmin;
+ this->chain2_width = chain1_wmin;
+ this->chain2_height = chain1_hmin;
+ }
+
+ fimc_is_ischain_s_chain0_size(this,
+ this->chain0_width, this->chain0_height);
+
+ fimc_is_ischain_s_chain1_size(this,
+ this->chain1_width, this->chain1_height);
+
+ fimc_is_ischain_s_chain2_size(this,
+ this->chain2_width, this->chain2_height);
+
+ fimc_is_ischain_s_chain3_size(this,
+ this->chain3_width, this->chain3_height);
+
+ isp_param->control.cmd = CONTROL_COMMAND_START;
+ isp_param->control.bypass = CONTROL_BYPASS_DISABLE;
+ isp_param->control.run_mode = 1;
+ lindex |= LOWBIT_OF(PARAM_ISP_CONTROL);
+ hindex |= HIGHBIT_OF(PARAM_ISP_CONTROL);
+ indexes++;
+
+ isp_param->otf_input.cmd = OTF_INPUT_COMMAND_DISABLE;
+ isp_param->otf_input.format = OTF_INPUT_FORMAT_BAYER_DMA;
+ isp_param->otf_input.bitwidth = OTF_INPUT_BIT_WIDTH_10BIT;
+ isp_param->otf_input.order = OTF_INPUT_ORDER_BAYER_GR_BG;
+ isp_param->otf_input.frametime_max = 33333;
+ lindex |= LOWBIT_OF(PARAM_ISP_OTF_INPUT);
+ hindex |= HIGHBIT_OF(PARAM_ISP_OTF_INPUT);
+ indexes++;
+
+ isp_param->dma1_input.cmd = DMA_INPUT_COMMAND_BUF_MNGR;
+ isp_param->dma1_input.width = sensor_width;
+ isp_param->dma1_input.height = sensor_height;
+ isp_param->dma1_input.uiDmaCropOffsetX = crop_x;
+ isp_param->dma1_input.uiDmaCropOffsetY = crop_y;
+ isp_param->dma1_input.uiDmaCropWidth = crop_width;
+ isp_param->dma1_input.uiDmaCropHeight = crop_height;
+ isp_param->dma1_input.uiBayerCropOffsetX = 0;
+ isp_param->dma1_input.uiBayerCropOffsetY = 0;
+ isp_param->dma1_input.uiBayerCropWidth = 0;
+ isp_param->dma1_input.uiBayerCropHeight = 0;
+ isp_param->dma1_input.uiUserMinFrameTime = 0;
+ isp_param->dma1_input.uiUserMaxFrameTime = 66666;
+ isp_param->dma1_input.uiWideFrameGap = 1;
+ isp_param->dma1_input.uiFrameGap = 4096;
+ isp_param->dma1_input.uiLineGap = 45;
+ isp_param->dma1_input.bitwidth = DMA_INPUT_BIT_WIDTH_10BIT;
+ isp_param->dma1_input.order = DMA_INPUT_ORDER_GR_BG;
+ isp_param->dma1_input.plane = 1;
+ isp_param->dma1_input.buffer_number = 1;
+ isp_param->dma1_input.buffer_address = 0;
+ /* hidden spec
+ [0] : sensor size is dma input size
+ [X] : sneosr size is reserved field */
+ isp_param->dma1_input.uiReserved[1] = 0;
+ isp_param->dma1_input.uiReserved[2] = 0;
+ lindex |= LOWBIT_OF(PARAM_ISP_DMA1_INPUT);
+ hindex |= HIGHBIT_OF(PARAM_ISP_DMA1_INPUT);
+ indexes++;
+
+ lindex = 0xFFFFFFFF;
+ hindex = 0xFFFFFFFF;
+
+ ret = fimc_is_itf_s_param(this , indexes, lindex, hindex);
+ if (ret) {
+ err("fimc_is_itf_s_param is fail\n");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ ret = fimc_is_itf_f_param(this);
+ if (ret) {
+ err("fimc_is_itf_f_param is fail\n");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ ret = fimc_is_itf_g_capability(this);
+ if (ret) {
+ err("fimc_is_itf_g_capability is fail\n");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ ret = fimc_is_itf_process_on(this);
+ if (ret) {
+ err("fimc_is_itf_process_on is fail\n");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ set_bit(FIMC_IS_ISDEV_DSTART, &isp->state);
+
+exit:
+ return ret;
+}
+
+int fimc_is_ischain_isp_stop(struct fimc_is_device_ischain *this)
+{
+ int ret = 0;
+ int retry;
+ struct fimc_is_ischain_dev *isp;
+ struct fimc_is_interface *itf;
+ struct fimc_is_framemgr *framemgr;
+
+ dbg_isp("%s()\n", __func__);
+
+ isp = &this->isp;
+ itf = this->interface;
+ framemgr = this->framemgr;
+
+ if (!test_bit(FIMC_IS_ISDEV_DSTART, &isp->state)) {
+ warn("already stop");
+ goto exit;
+ }
+
+ /*
+ video node is stream off state if this function is called.
+ that is, a request can NOT enter buffer queue.
+ mutex can be locked for entering ischain_callback function,
+ in this case the below code should be blocked until mutex is released.
+ */
+ retry = 10;
+ while (retry) {
+ mutex_lock(&this->mutex_state);
+ if (!test_bit(FIMC_IS_ISCHAIN_RUN, &this->state)) {
+ mutex_unlock(&this->mutex_state);
+ break;
+ }
+ mutex_unlock(&this->mutex_state);
+ retry--;
+ }
+
+ if (!retry)
+ err("waiting complete is fail0");
+
+ retry = 10;
+ while (framemgr->frame_request_cnt && retry) {
+ printk(KERN_INFO "%d frame reqs waiting...\n",
+ framemgr->frame_request_cnt);
+ msleep(20);
+ retry--;
+ }
+
+ if (!retry)
+ err("waiting complete is fail1");
+
+ retry = 10;
+ while (framemgr->frame_process_cnt && retry) {
+ printk(KERN_INFO "%d frame pros waiting...\n",
+ framemgr->frame_process_cnt);
+ msleep(20);
+ retry--;
+ }
+
+ if (!retry)
+ err("waiting complete is fail2");
+
+ ret = fimc_is_itf_process_off(this);
+ if (ret) {
+ err("fimc_is_itf_process_off is fail");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ clear_bit(FIMC_IS_ISDEV_DSTART, &isp->state);
+
+#ifdef MEASURE_TIME
+#ifdef INTERNAL_TIME
+ measure_init();
+#endif
+#endif
+
+exit:
+ return ret;
+}
+
+int fimc_is_ischain_isp_s_format(struct fimc_is_device_ischain *this,
+ u32 width, u32 height)
+{
+ int ret = 0;
+
+ this->sensor_width = width - this->margin_width;
+ this->sensor_height = height - this->margin_height;
+
+ return ret;
+}
+
+int fimc_is_ischain_isp_buffer_queue(struct fimc_is_device_ischain *this,
+ u32 index)
+{
+ int ret = 0;
+ unsigned long flags;
+ struct fimc_is_frame_shot *frame;
+ struct fimc_is_framemgr *framemgr;
+ struct fimc_is_video_common *scc_video, *scp_video;
+
+#ifdef DBG_STREAMING
+ /*printk(KERN_INFO "%s\n", __func__);*/
+#endif
+
+ if (index >= FRAMEMGR_MAX_REQUEST) {
+ err("index(%d) is invalid", index);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ framemgr = this->framemgr;
+ if (framemgr == NULL) {
+ err("framemgr is null\n");
+ ret = EINVAL;
+ goto exit;
+ }
+
+ frame = &framemgr->frame[index];
+ if (frame == NULL) {
+ err("frame is null\n");
+ ret = EINVAL;
+ goto exit;
+ }
+
+#ifdef MEASURE_TIME
+#ifdef INTERNAL_TIME
+ do_gettimeofday(&frame->time_queued);
+#endif
+#endif
+
+ if (frame->init == FRAME_UNI_MEM) {
+ err("frame %d is NOT init", index);
+ ret = EINVAL;
+ goto exit;
+ }
+
+ scc_video = this->scc.video;
+ scp_video = this->scp.video;
+
+ framemgr_e_barrier_irqs(framemgr, index, flags);
+
+ if (frame->state == FIMC_IS_FRAME_STATE_FREE) {
+ if (frame->req_flag) {
+ dbg_warning("%d request flag is not clear(%08X)\n",
+ frame->index, (u32)frame->req_flag);
+ frame->req_flag = 0;
+ }
+
+ if (frame->scc_out == FIMC_IS_FOUT_REQ)
+ err("scc output is not generated");
+
+ if (frame->scp_out == FIMC_IS_FOUT_REQ)
+ err("scp output is not generated");
+
+ frame->fcount = frame->shot->dm.request.frameCount;
+
+ if (frame->shot_ext->request_scp &&
+ !test_bit(FIMC_IS_VIDEO_STREAM_ON, &scp_video->state)) {
+ frame->shot_ext->request_scp = 0;
+ err("scp %d frame is drop2", frame->fcount);
+ }
+
+ if (frame->shot_ext->request_scc &&
+ !test_bit(FIMC_IS_VIDEO_STREAM_ON, &scc_video->state)) {
+ frame->shot_ext->request_scc = 0;
+ err("scc %d frame is drop2", frame->fcount);
+ }
+
+ fimc_is_frame_trans_fre_to_req(framemgr, frame);
+ } else {
+ err("frame(%d) is not free state(%d)\n", index, frame->state);
+ fimc_is_frame_print_all(framemgr);
+ }
+
+ framemgr_x_barrier_irqr(framemgr, index, flags);
+
+ mutex_lock(&this->mutex_state);
+ if (!test_bit(FIMC_IS_ISCHAIN_RUN, &this->state))
+ fimc_is_ischain_callback(this);
+ mutex_unlock(&this->mutex_state);
+
+exit:
+ return ret;
+}
+
+int fimc_is_ischain_isp_buffer_finish(struct fimc_is_device_ischain *this,
+ u32 index)
+{
+ int ret = 0;
+ struct fimc_is_frame_shot *frame;
+ struct fimc_is_framemgr *framemgr = this->framemgr;
+
+#ifdef DBG_STREAMING
+ /*dbg_ischain("%s\n", __func__);*/
+#endif
+
+ framemgr_e_barrier_irq(framemgr, index+0xf0);
+
+ fimc_is_frame_complete_head(framemgr, &frame);
+ if (frame) {
+ if (index == frame->index)
+ fimc_is_frame_trans_com_to_fre(framemgr, frame);
+ else {
+ dbg_warning("buffer index is NOT matched(%d != %d)\n",
+ index, frame->index);
+ fimc_is_frame_print_all(framemgr);
+ }
+ } else {
+ err("frame is empty from complete");
+ fimc_is_frame_print_all(framemgr);
+ }
+
+ framemgr_x_barrier_irq(framemgr, index+0xf0);
+
+#ifdef MEASURE_TIME
+#ifdef INTERNAL_TIME
+ do_gettimeofday(&frame->time_dequeued);
+ measure_internal_time(&frame->time_queued, &frame->time_shot,
+ &frame->time_shotdone, &frame->time_dequeued);
+#endif
+#endif
+
+ return ret;
+}
+
+int fimc_is_ischain_scc_start(struct fimc_is_device_ischain *this)
+{
+ int ret = 0;
+ u32 planes, i, j, buf_index;
+ u32 indexes, lindex, hindex;
+ struct scalerc_param *scc_param;
+ struct fimc_is_ischain_dev *scc;
+ struct fimc_is_video_common *video;
+
+ dbg_ischain("%s\n", __func__);
+
+ scc = &this->scc;
+ video = scc->video;
+
+ planes = video->frame.format.num_planes;
+ for (i = 0; i < video->buffers; i++) {
+ for (j = 0; j < planes; j++) {
+ buf_index = i*planes + j;
+
+ /*dbg_ischain("(%d)set buf(%d:%d) = 0x%08x\n",
+ buf_index, i, j, video->buf_dva[i][j]);*/
+
+ this->is_region->shared[447+buf_index] =
+ video->buf_dva[i][j];
+ }
+ }
+
+ dbg_ischain("buf_num:%d buf_plane:%d shared[447] : 0x%X\n",
+ video->buffers,
+ video->frame.format.num_planes,
+ this->minfo.kvaddr_shared + 447 * sizeof(u32));
+
+ video->buf_mask = 0;
+ for (i = 0; i < video->buffers; i++)
+ video->buf_mask |= (1 << i);
+
+ indexes = 0;
+ lindex = hindex = 0;
+
+ scc_param = &this->is_region->parameter.scalerc;
+ scc_param->dma_output.cmd = DMA_OUTPUT_COMMAND_ENABLE;
+ scc_param->dma_output.dma_out_mask = video->buf_mask;
+ scc_param->dma_output.buffer_number = video->buffers;
+#ifdef USE_FRAME_SYNC
+ scc_param->dma_output.plane = video->frame.format.num_planes - 1;
+#else
+ scc_param->dma_output.plane = video->frame.format.num_planes;
+#endif
+ scc_param->dma_output.buffer_address =
+ this->minfo.dvaddr_shared + 447*sizeof(u32);
+ lindex |= LOWBIT_OF(PARAM_SCALERC_DMA_OUTPUT);
+ hindex |= HIGHBIT_OF(PARAM_SCALERC_DMA_OUTPUT);
+ indexes++;
+
+ ret = fimc_is_itf_s_param(this, indexes, lindex, hindex);
+ if (!ret)
+ set_bit(FIMC_IS_ISDEV_DSTART, &scc->state);
+ else
+ err("fimc_is_itf_s_param is fail\n");
+
+ if (!this->interface->streaming)
+ fimc_is_itf_a_param(this);
+
+ return ret;
+}
+
+int fimc_is_ischain_scc_stop(struct fimc_is_device_ischain *this)
+{
+ int ret = 0;
+ u32 indexes, lindex, hindex;
+ struct scalerc_param *scc_param;
+ struct fimc_is_ischain_dev *scc;
+
+ dbg_ischain("%s\n", __func__);
+
+ indexes = 0;
+ lindex = hindex = 0;
+ scc = &this->scc;
+
+ scc_param = &this->is_region->parameter.scalerc;
+ scc_param->dma_output.cmd = DMA_OUTPUT_COMMAND_DISABLE;
+
+ lindex |= LOWBIT_OF(PARAM_SCALERC_DMA_OUTPUT);
+ hindex |= HIGHBIT_OF(PARAM_SCALERC_DMA_OUTPUT);
+ indexes++;
+
+ ret = fimc_is_itf_s_param(this, indexes, lindex, hindex);
+ if (!ret)
+ clear_bit(FIMC_IS_ISDEV_DSTART, &scc->state);
+ else
+ err("fimc_is_itf_s_param is fail\n");
+
+ if (!this->interface->streaming)
+ fimc_is_itf_a_param(this);
+
+ return ret;
+}
+
+int fimc_is_ischain_scp_start(struct fimc_is_device_ischain *this)
+{
+ int ret = 0;
+ u32 planes, i, j, buf_index;
+ u32 indexes, lindex, hindex;
+ struct scalerp_param *scp_param;
+ struct fimc_is_ischain_dev *scp;
+ struct fimc_is_video_common *video;
+
+ dbg_ischain("%s\n", __func__);
+
+ scp = &this->scp;
+ video = scp->video;
+
+ planes = video->frame.format.num_planes;
+ for (i = 0; i < video->buffers; i++) {
+ for (j = 0; j < planes; j++) {
+ buf_index = i*planes + j;
+
+ /*dbg_ischain("(%d)set buf(%d:%d) = 0x%08x\n",
+ buf_index, i, j, video->buf_dva[i][j]);*/
+
+ this->is_region->shared[400+buf_index] =
+ video->buf_dva[i][j];
+ }
+ }
+
+ dbg_ischain("buf_num:%d buf_plane:%d shared[400] : 0x%X\n",
+ video->buffers,
+ video->frame.format.num_planes,
+ this->minfo.kvaddr_shared + 400 * sizeof(u32));
+
+ video->buf_mask = 0;
+ for (i = 0; i < video->buffers; i++)
+ video->buf_mask |= (1 << i);
+
+ indexes = 0;
+ lindex = hindex = 0;
+
+ scp_param = &this->is_region->parameter.scalerp;
+ scp_param->dma_output.cmd = DMA_OUTPUT_COMMAND_ENABLE;
+ scp_param->dma_output.dma_out_mask = video->buf_mask;
+ scp_param->dma_output.buffer_number = video->buffers;
+#ifdef USE_FRAME_SYNC
+ scp_param->dma_output.plane = video->frame.format.num_planes - 1;
+#else
+ scp_param->dma_output.plane = video->frame.format.num_planes;
+#endif
+ scp_param->dma_output.buffer_address =
+ this->minfo.dvaddr_shared + 400*sizeof(u32);
+
+ lindex |= LOWBIT_OF(PARAM_SCALERP_DMA_OUTPUT);
+ hindex |= HIGHBIT_OF(PARAM_SCALERP_DMA_OUTPUT);
+ indexes++;
+
+ ret = fimc_is_itf_s_param(this, indexes, lindex, hindex);
+ if (!ret)
+ set_bit(FIMC_IS_ISDEV_DSTART, &scp->state);
+ else
+ err("fimc_is_itf_s_param is fail\n");
+
+ if (!this->interface->streaming)
+ fimc_is_itf_a_param(this);
+
+ return ret;
+}
+
+int fimc_is_ischain_scp_stop(struct fimc_is_device_ischain *this)
+{
+ int ret = 0;
+ u32 indexes, lindex, hindex;
+ struct scalerp_param *scp_param;
+ struct fimc_is_ischain_dev *scp;
+
+ dbg_ischain("%s\n", __func__);
+
+ indexes = 0;
+ lindex = hindex = 0;
+ scp = &this->scp;
+
+ scp_param = &this->is_region->parameter.scalerp;
+ scp_param->dma_output.cmd = DMA_OUTPUT_COMMAND_DISABLE;
+
+ lindex |= LOWBIT_OF(PARAM_SCALERP_DMA_OUTPUT);
+ hindex |= HIGHBIT_OF(PARAM_SCALERP_DMA_OUTPUT);
+ indexes++;
+
+ ret = fimc_is_itf_s_param(this, indexes, lindex, hindex);
+ if (!ret)
+ clear_bit(FIMC_IS_ISDEV_DSTART, &scp->state);
+ else
+ err("fimc_is_itf_s_param is fail\n");
+
+ if (!this->interface->streaming)
+ fimc_is_itf_a_param(this);
+
+ return ret;
+}
+
+int fimc_is_ischain_scp_s_format(struct fimc_is_device_ischain *this,
+ u32 width, u32 height)
+{
+ int ret = 0;
+
+ this->chain1_width = width;
+ this->chain1_height = height;
+ this->chain2_width = width;
+ this->chain2_height = height;
+ this->chain3_width = width;
+ this->chain3_height = height;
+
+ return ret;
+}
+
+int fimc_is_ischain_dev_open(struct fimc_is_ischain_dev *this,
+ enum is_entry entry,
+ struct fimc_is_video_common *video,
+ const struct param_control *init_ctl)
+{
+ int ret = 0;
+
+ mutex_init(&this->mutex_state);
+ this->entry = entry;
+ this->video = video;
+
+ if (init_ctl) {
+ if (init_ctl->cmd != CONTROL_COMMAND_START) {
+ err("%d entry is not start", entry);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (init_ctl->bypass == CONTROL_BYPASS_ENABLE)
+ clear_bit(FIMC_IS_ISDEV_DSTART, &this->state);
+ else if (init_ctl->bypass == CONTROL_BYPASS_DISABLE)
+ set_bit(FIMC_IS_ISDEV_DSTART, &this->state);
+ else {
+ err("%d entry has invalid bypass value(%d)",
+ entry, init_ctl->bypass);
+ ret = -EINVAL;
+ goto exit;
+ }
+ } else /* isp, scc, scp do not use bypass(memory interface)*/
+ clear_bit(FIMC_IS_ISDEV_DSTART, &this->state);
+
+exit:
+ return ret;
+}
+
+int fimc_is_ischain_dev_start(struct fimc_is_ischain_dev *this)
+{
+ int ret = 0;
+ struct fimc_is_framemgr *framemgr;
+
+ framemgr = &this->framemgr;
+
+ ret = framemgr->frame_request_cnt;
+ if (!ret) {
+ err("buffer queued is empty, can't start(%d)", ret);
+ ret = -EINVAL;
+ goto exit;
+ } else
+ ret = 0;
+
+exit:
+ return ret;
+}
+
+int fimc_is_ischain_dev_stop(struct fimc_is_ischain_dev *this)
+{
+ int ret = 0;
+ unsigned long flags;
+ struct fimc_is_frame_shot *frame;
+ struct fimc_is_framemgr *framemgr;
+
+ framemgr = &this->framemgr;
+
+ framemgr_e_barrier_irqs(framemgr, FMGR_IDX_4, flags);
+
+ fimc_is_frame_complete_head(framemgr, &frame);
+ while (frame) {
+ fimc_is_frame_trans_com_to_fre(framemgr, frame);
+ fimc_is_frame_complete_head(framemgr, &frame);
+ }
+
+ fimc_is_frame_process_head(framemgr, &frame);
+ while (frame) {
+ fimc_is_frame_trans_pro_to_fre(framemgr, frame);
+ fimc_is_frame_process_head(framemgr, &frame);
+ }
+
+ fimc_is_frame_request_head(framemgr, &frame);
+ while (frame) {
+ fimc_is_frame_trans_req_to_fre(framemgr, frame);
+ fimc_is_frame_request_head(framemgr, &frame);
+ }
+
+ framemgr_x_barrier_irqr(framemgr, FMGR_IDX_4, flags);
+
+ return ret;
+}
+
+int fimc_is_ischain_dev_buffer_queue(struct fimc_is_ischain_dev *this,
+ u32 index)
+{
+ int ret = 0;
+ struct fimc_is_frame_shot *frame;
+ struct fimc_is_framemgr *framemgr;
+
+#ifdef DBG_STREAMING
+ dbg_ischain("%s\n", __func__);
+#endif
+
+ if (index >= FRAMEMGR_MAX_REQUEST) {
+ err("index(%d) is invalid", index);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ framemgr = &this->framemgr;
+ if (framemgr == NULL) {
+ err("framemgr is null\n");
+ ret = EINVAL;
+ goto exit;
+ }
+
+ frame = &framemgr->frame[index];
+ if (frame == NULL) {
+ err("frame is null\n");
+ ret = EINVAL;
+ goto exit;
+ }
+
+ if (frame->init == FRAME_UNI_MEM) {
+ err("frame %d is NOT init", index);
+ ret = EINVAL;
+ goto exit;
+ }
+
+ framemgr_e_barrier_irq(framemgr, index);
+
+ if (frame->state == FIMC_IS_FRAME_STATE_FREE) {
+ if (frame->req_flag) {
+ dbg_warning("%d request flag is not clear(%08X)\n",
+ frame->index, (u32)frame->req_flag);
+ frame->req_flag = 0;
+ }
+
+ fimc_is_frame_trans_fre_to_req(framemgr, frame);
+ } else {
+ err("frame(%d) is not free state(%d)\n", index, frame->state);
+ fimc_is_frame_print_all(framemgr);
+ }
+
+ framemgr_x_barrier_irq(framemgr, index);
+
+exit:
+ return ret;
+}
+
+int fimc_is_ischain_dev_buffer_finish(struct fimc_is_ischain_dev *this,
+ u32 index)
+{
+ int ret = 0;
+ struct fimc_is_frame_shot *frame;
+ struct fimc_is_framemgr *framemgr;
+
+#ifdef DBG_STREAMING
+ /*dbg_ischain("%s\n", __func__);*/
+#endif
+
+ framemgr = &this->framemgr;
+
+ framemgr_e_barrier_irq(framemgr, index);
+
+ fimc_is_frame_complete_head(framemgr, &frame);
+ if (frame) {
+ if (index == frame->index)
+ fimc_is_frame_trans_com_to_fre(framemgr, frame);
+ else {
+ dbg_warning("buffer index is NOT matched(%d != %d)\n",
+ index, frame->index);
+ fimc_is_frame_print_all(framemgr);
+ }
+ } else {
+ err("frame is empty from complete");
+ fimc_is_frame_print_all(framemgr);
+ }
+
+ framemgr_x_barrier_irq(framemgr, index);
+
+ return ret;
+}
+
+int fimc_is_ischain_g_capability(struct fimc_is_device_ischain *this,
+ u32 user_ptr)
+{
+ int ret = 0;
+
+ ret = copy_to_user((void *)user_ptr, &this->capability,
+ sizeof(struct camera2_sm));
+
+ return ret;
+}
+
+int fimc_is_ischain_print_status(struct fimc_is_device_ischain *this)
+{
+ int ret = 0;
+ struct fimc_is_framemgr *framemgr;
+ struct fimc_is_interface *itf;
+
+ framemgr = this->framemgr;
+ itf = this->interface;
+
+ fimc_is_frame_print_free_list(framemgr);
+ fimc_is_frame_print_request_list(framemgr);
+ fimc_is_frame_print_process_list(framemgr);
+ fimc_is_frame_print_complete_list(framemgr);
+ print_fre_work_list(&itf->work_list[INTR_META_DONE]);
+ print_req_work_list(&itf->work_list[INTR_META_DONE]);
+
+ return ret;
+}
+
+int fimc_is_ischain_callback(struct fimc_is_device_ischain *this)
+{
+ int ret = 0;
+ bool scc_req, scp_req;
+ unsigned long flags;
+ u32 crop_width;
+ u32 setfile_save;
+ struct fimc_is_framemgr *isp_framemgr, *scc_framemgr, *scp_framemgr;
+ struct fimc_is_frame_shot *isp_frame, *scc_frame, *scp_frame;
+ struct fimc_is_ischain_dev *scc, *scp;
+
+#ifdef DBG_STREAMING
+ dbg_ischain("%s\n", __func__);
+#endif
+
+ scc = &this->scc;
+ scp = &this->scp;
+ isp_framemgr = this->framemgr;
+ scc_framemgr = &scc->framemgr;
+ scp_framemgr = &scp->framemgr;
+ scc_req = scp_req = false;
+
+ /*
+ BE CAREFUL WITH THIS
+ 1. buffer queue, all compoenent stop, so it's good
+ 2. interface callback, all component will be stop until new one is came
+ therefore, i expect lock object is not necessary in here
+ */
+
+ if (!isp_framemgr) {
+ err("isp_framemgr is NULL");
+ return -EINVAL;
+ }
+
+ if (!scc_framemgr) {
+ err("scc_framemgr is NULL");
+ return -EINVAL;
+ }
+
+ if (!scp_framemgr) {
+ err("scp_framemgr is NULL");
+ return -EINVAL;
+ }
+
+ fimc_is_frame_request_head(isp_framemgr, &isp_frame);
+ if (!isp_frame) {
+ clear_bit(FIMC_IS_ISCHAIN_RUN, &this->state);
+#ifdef DBG_STREAMING
+ dbg_warning("ischain is stopped\n");
+#endif
+ return 0;
+ }
+
+ if (!isp_frame->shot_ext) {
+ err("shot_ext is NULL");
+ return -EINVAL;
+ }
+
+ if (!isp_frame->shot) {
+ err("shot is NULL");
+ return -EINVAL;
+ }
+
+ if (isp_frame->init == FRAME_INI_MEM) {
+ fimc_is_itf_cfg_mem(this, isp_frame->dvaddr_shot,
+ isp_frame->shot_size);
+ isp_frame->init = FRAME_CFG_MEM;
+ }
+
+ if (isp_frame->shot_ext->setfile != this->setfile) {
+ setfile_save = this->setfile;
+ this->setfile = isp_frame->shot_ext->setfile;
+
+ ret = fimc_is_ischain_s_setfile(this);
+ if (ret) {
+ err("fimc_is_ischain_s_setfile is fail");
+ this->setfile = setfile_save;
+ goto exit;
+ }
+ }
+
+ if (isp_frame->shot_ext->request_scc) {
+ if (!test_bit(FIMC_IS_ISDEV_DSTART, &this->scc.state)) {
+ ret = fimc_is_ischain_scc_start(this);
+ if (ret) {
+ err("fimc_is_ischain_scc_start is fail");
+ goto exit;
+ }
+ }
+
+ scc_req = true;
+ } else {
+ if (test_bit(FIMC_IS_ISDEV_DSTART, &this->scc.state)) {
+ ret = fimc_is_ischain_scc_stop(this);
+ if (ret) {
+ err("fimc_is_ischain_scc_stop is fail");
+ goto exit;
+ }
+ }
+ }
+
+ if (isp_frame->shot_ext->request_scp) {
+ if (!test_bit(FIMC_IS_ISDEV_DSTART, &this->scp.state)) {
+ ret = fimc_is_ischain_scp_start(this);
+ if (ret) {
+ err("fimc_is_ischain_scp_start is fail");
+ goto exit;
+ }
+ }
+
+ scp_req = true;
+ } else {
+ if (test_bit(FIMC_IS_ISDEV_DSTART, &this->scp.state)) {
+ ret = fimc_is_ischain_scp_stop(this);
+ if (ret) {
+ err("fimc_is_ischain_scp_stop is fail");
+ goto exit;
+ }
+ }
+ }
+
+#ifdef ENABLE_DRC
+ if (isp_frame->shot_ext->drc_bypass) {
+ if (test_bit(FIMC_IS_ISDEV_DSTART, &this->drc.state)) {
+ ret = fimc_is_ischain_drc_bypass(this, true);
+ if (ret) {
+ err("fimc_is_ischain_drc_bypass(1) is fail");
+ goto exit;
+ }
+ }
+ } else {
+ if (!test_bit(FIMC_IS_ISDEV_DSTART, &this->drc.state)) {
+ ret = fimc_is_ischain_drc_bypass(this, false);
+ if (ret) {
+ err("fimc_is_ischain_drc_bypass(0) is fail");
+ goto exit;
+ }
+ }
+ }
+#endif
+
+#ifdef ENABLE_VDIS
+ if (isp_frame->shot_ext->dis_bypass) {
+ if (test_bit(FIMC_IS_ISDEV_DSTART, &this->dis.state)) {
+ ret = fimc_is_ischain_dis_bypass(this, true);
+ if (ret) {
+ err("fimc_is_ischain_dis_bypass(1) is fail");
+ goto exit;
+ }
+ }
+ } else {
+ if (!test_bit(FIMC_IS_ISDEV_DSTART, &this->dis.state)) {
+ ret = fimc_is_ischain_dis_bypass(this, false);
+ if (ret) {
+ err("fimc_is_ischain_dis_bypass(0) is fail");
+ goto exit;
+ }
+ }
+ }
+#endif
+
+#ifdef ENABLE_TDNR
+ if (isp_frame->shot_ext->dnr_bypass) {
+ if (test_bit(FIMC_IS_ISDEV_DSTART, &this->dnr.state)) {
+ ret = fimc_is_ischain_dnr_bypass(this, true);
+ if (ret) {
+ err("fimc_is_ischain_dnr_bypass(1) is fail");
+ goto exit;
+ }
+ }
+ } else {
+ if (!test_bit(FIMC_IS_ISDEV_DSTART, &this->dnr.state)) {
+ ret = fimc_is_ischain_dnr_bypass(this, false);
+ if (ret) {
+ err("fimc_is_ischain_dnr_bypass(0) is fail");
+ goto exit;
+ }
+ }
+ }
+#endif
+
+#ifdef ENABLE_FD
+ if (isp_frame->shot_ext->fd_bypass) {
+ if (test_bit(FIMC_IS_ISDEV_DSTART, &this->fd.state)) {
+ ret = fimc_is_ischain_fd_bypass(this, true);
+ if (ret) {
+ err("fimc_is_ischain_fd_bypass(1) is fail");
+ goto exit;
+ }
+ }
+ } else {
+ if (!test_bit(FIMC_IS_ISDEV_DSTART, &this->fd.state)) {
+ ret = fimc_is_ischain_fd_bypass(this, false);
+ if (ret) {
+ err("fimc_is_ischain_fd_bypass(0) is fail");
+ goto exit;
+ }
+ }
+ }
+#endif
+
+ crop_width = isp_frame->shot->ctl.scaler.cropRegion[2];
+ if (crop_width && (crop_width != this->dzoom_width)) {
+ ret = fimc_is_ischain_s_dzoom(this,
+ isp_frame->shot->ctl.scaler.cropRegion[0],
+ isp_frame->shot->ctl.scaler.cropRegion[1],
+ isp_frame->shot->ctl.scaler.cropRegion[2]);
+ if (ret) {
+ err("fimc_is_ischain_s_dzoom(%d, %d, %d) is fail",
+ isp_frame->shot->ctl.scaler.cropRegion[0],
+ isp_frame->shot->ctl.scaler.cropRegion[1],
+ isp_frame->shot->ctl.scaler.cropRegion[2]);
+ goto exit;
+ }
+ }
+
+ if (scc_req) {
+ framemgr_e_barrier_irqs(scc_framemgr, FMGR_IDX_8, flags);
+
+ fimc_is_frame_request_head(scc_framemgr, &scc_frame);
+ if (scc_frame) {
+ isp_frame->shot->uctl.scalerUd.sccTargetAddress[0] =
+ scc_frame->dvaddr_buffer[0];
+ isp_frame->shot->uctl.scalerUd.sccTargetAddress[1] =
+ scc_frame->dvaddr_buffer[1];
+ isp_frame->shot->uctl.scalerUd.sccTargetAddress[2] =
+ scc_frame->dvaddr_buffer[2];
+ scc_frame->stream->findex = isp_frame->index;
+ isp_frame->scc_out = FIMC_IS_FOUT_REQ;
+
+ set_bit(REQ_FRAME, &scc_frame->req_flag);
+ fimc_is_frame_trans_req_to_pro(scc_framemgr, scc_frame);
+ } else {
+ isp_frame->shot->uctl.scalerUd.sccTargetAddress[0] = 0;
+ isp_frame->shot->uctl.scalerUd.sccTargetAddress[1] = 0;
+ isp_frame->shot->uctl.scalerUd.sccTargetAddress[2] = 0;
+ isp_frame->shot_ext->request_scc = 0;
+ err("scc %d frame is drop", isp_frame->fcount);
+ }
+
+ framemgr_x_barrier_irqr(scc_framemgr, FMGR_IDX_8, flags);
+ } else {
+ isp_frame->shot->uctl.scalerUd.sccTargetAddress[0] = 0;
+ isp_frame->shot->uctl.scalerUd.sccTargetAddress[1] = 0;
+ isp_frame->shot->uctl.scalerUd.sccTargetAddress[2] = 0;
+ isp_frame->shot_ext->request_scc = 0;
+ }
+
+ if (scp_req) {
+ framemgr_e_barrier_irqs(scp_framemgr, FMGR_IDX_9, flags);
+
+ fimc_is_frame_request_head(scp_framemgr, &scp_frame);
+ if (scp_frame) {
+ isp_frame->shot->uctl.scalerUd.scpTargetAddress[0] =
+ scp_frame->dvaddr_buffer[0];
+ isp_frame->shot->uctl.scalerUd.scpTargetAddress[1] =
+ scp_frame->dvaddr_buffer[1];
+ isp_frame->shot->uctl.scalerUd.scpTargetAddress[2] =
+ scp_frame->dvaddr_buffer[2];
+ scp_frame->stream->findex = isp_frame->index;
+ isp_frame->scp_out = FIMC_IS_FOUT_REQ;
+
+ set_bit(REQ_FRAME, &scp_frame->req_flag);
+ fimc_is_frame_trans_req_to_pro(scp_framemgr, scp_frame);
+ } else {
+ isp_frame->shot->uctl.scalerUd.scpTargetAddress[0] = 0;
+ isp_frame->shot->uctl.scalerUd.scpTargetAddress[1] = 0;
+ isp_frame->shot->uctl.scalerUd.scpTargetAddress[2] = 0;
+ isp_frame->shot_ext->request_scp = 0;
+ err("scp %d frame is drop", isp_frame->fcount);
+ }
+
+ framemgr_x_barrier_irqr(scp_framemgr, FMGR_IDX_9, flags);
+ } else {
+ isp_frame->shot->uctl.scalerUd.scpTargetAddress[0] = 0;
+ isp_frame->shot->uctl.scalerUd.scpTargetAddress[1] = 0;
+ isp_frame->shot->uctl.scalerUd.scpTargetAddress[2] = 0;
+ isp_frame->shot_ext->request_scp = 0;
+ }
+
+exit:
+ if (ret) {
+ clear_bit(FIMC_IS_ISCHAIN_RUN, &this->state);
+ clear_bit(REQ_FRAME, &isp_frame->req_flag);
+ isp_frame->shot_ext->request_isp = 0;
+ isp_frame->shot_ext->request_scc = 0;
+ isp_frame->shot_ext->request_scp = 0;
+ fimc_is_frame_trans_req_to_com(isp_framemgr, isp_frame);
+
+ buffer_done(this->isp.video, isp_frame->index);
+ err("shot(index : %d) is skipped(error : %d)",
+ isp_frame->index, ret);
+ } else {
+ set_bit(REQ_SHOT, &isp_frame->req_flag);
+ set_bit(FIMC_IS_ISCHAIN_RUN, &this->state);
+ fimc_is_frame_trans_req_to_pro(isp_framemgr, isp_frame);
+
+ fimc_is_itf_shot(this, isp_frame);
+ }
+
+ return ret;
+}
+
+#if 0 /* will be used if host control sensor */
+int fimc_is_ischain_camctl(struct fimc_is_device_ischain *this,
+ struct fimc_is_frame_shot *frame,
+ u32 fcount)
+{
+ int ret = 0;
+ u32 updated = 0;
+ struct fimc_is_interface *itf;
+ struct camera2_uctl *applied_ctl;
+
+ struct camera2_sensor_uctl *cur_sensor_uctl;
+ struct camera2_sensor_uctl *isp_sensor_uctl;
+ struct camera2_sensor_ctl *cur_sensor_ctl;
+ struct camera2_sensor_ctl *isp_sensor_ctl;
+ struct camera2_sensor_ctl *req_sensor_ctl;
+
+ struct camera2_lens_uctl *cur_lens_uctl;
+ struct camera2_lens_uctl *isp_lens_uctl;
+ struct camera2_lens_ctl *cur_lens_ctl;
+ struct camera2_lens_ctl *isp_lens_ctl;
+ struct camera2_lens_ctl *req_lens_ctl;
+
+ struct camera2_flash_uctl *cur_flash_uctl;
+ struct camera2_flash_uctl *isp_flash_uctl;
+ struct camera2_flash_ctl *cur_flash_ctl;
+ struct camera2_flash_ctl *isp_flash_ctl;
+ struct camera2_flash_ctl *req_flash_ctl;
+
+ u32 index;
+ u64 frameDuration;
+ u64 exposureTime;
+ u32 sensitivity;
+ u32 focusDistance;
+ u32 flashMode;
+
+#ifdef DBG_STREAMING
+ dbg_ischain("%s\n", __func__);
+#endif
+
+ itf = this->interface;
+ cur_sensor_uctl = &this->cur_peri_ctl.sensorUd;
+ cur_sensor_ctl = &cur_sensor_uctl->ctl;
+ isp_sensor_uctl = &itf->isp_peri_ctl.sensorUd;
+ isp_sensor_ctl = &isp_sensor_uctl->ctl;
+
+ cur_lens_uctl = &this->cur_peri_ctl.lensUd;
+ cur_lens_ctl = &cur_lens_uctl->ctl;
+ isp_lens_uctl = &itf->isp_peri_ctl.lensUd;
+ isp_lens_ctl = &isp_lens_uctl->ctl;
+
+ cur_flash_uctl = &this->cur_peri_ctl.flashUd;
+ cur_flash_ctl = &cur_flash_uctl->ctl;
+ isp_flash_uctl = &itf->isp_peri_ctl.flashUd;
+ isp_flash_ctl = &isp_flash_uctl->ctl;
+
+ this->cur_peri_ctl.uUpdateBitMap = 0;
+
+ if (frame) {
+ req_sensor_ctl = &frame->shot->ctl.sensor;
+ req_lens_ctl = &frame->shot->ctl.lens;
+ req_flash_ctl = &frame->shot->ctl.flash;
+ } else {
+ req_sensor_ctl = NULL;
+ req_lens_ctl = NULL;
+ req_flash_ctl = NULL;
+ }
+
+ /*sensor part*/
+ if (req_sensor_ctl && req_sensor_ctl->frameDuration)
+ frameDuration = req_sensor_ctl->frameDuration;
+ else
+ frameDuration = isp_sensor_ctl->frameDuration;
+
+ if (cur_sensor_ctl->frameDuration != frameDuration) {
+ cur_sensor_ctl->frameDuration = frameDuration;
+ /*dbg_ischain("fduration : %d\n", (u32)duration);*/
+ updated |= CAM_SENSOR_CMD;
+ }
+
+ if (req_sensor_ctl && req_sensor_ctl->exposureTime)
+ exposureTime = req_sensor_ctl->exposureTime;
+ else
+ exposureTime = isp_sensor_ctl->exposureTime;
+
+ if (cur_sensor_ctl->exposureTime != exposureTime) {
+ cur_sensor_ctl->exposureTime = exposureTime;
+ /*dbg_ischain("exposure : %d\n", (u32)exposure);*/
+ updated |= CAM_SENSOR_CMD;
+ }
+
+ if (req_sensor_ctl && req_sensor_ctl->sensitivity)
+ sensitivity = req_sensor_ctl->sensitivity;
+ else
+ sensitivity = isp_sensor_ctl->sensitivity;
+
+ if (cur_sensor_ctl->sensitivity != sensitivity) {
+ cur_sensor_ctl->sensitivity = sensitivity;
+ /*dbg_ischain("sensitivity : %d\n", (u32)exposure);*/
+ updated |= CAM_SENSOR_CMD;
+ }
+
+ /*lens part*/
+ if (req_lens_ctl && req_lens_ctl->focusDistance)
+ focusDistance = req_lens_ctl->focusDistance;
+ else
+ focusDistance = isp_lens_ctl->focusDistance;
+
+ if (cur_lens_ctl->focusDistance != focusDistance) {
+ cur_lens_ctl->focusDistance = focusDistance;
+ /*dbg_ischain("focusDistance : %d\n", focusDistance);*/
+ updated |= CAM_LENS_CMD;
+ }
+
+ if (cur_lens_uctl->slewRate != isp_lens_uctl->slewRate) {
+ cur_lens_uctl->slewRate = isp_lens_uctl->slewRate;
+ updated |= CAM_LENS_CMD;
+ }
+
+ if (cur_lens_uctl->maxPos != isp_lens_uctl->maxPos) {
+ cur_lens_uctl->maxPos = isp_lens_uctl->maxPos;
+ updated |= CAM_LENS_CMD;
+ }
+
+ /*flash part*/
+ if (req_flash_ctl && req_flash_ctl->flashMode)
+ flashMode = req_flash_ctl->flashMode;
+ else
+ flashMode = isp_flash_ctl->flashMode;
+
+ if (cur_flash_ctl->flashMode != flashMode) {
+ cur_flash_ctl->flashMode = flashMode;
+ dbg_ischain("flashMode : %d\n", flashMode);
+ updated |= CAM_FLASH_CMD;
+ }
+
+ if (cur_flash_ctl->firingPower != isp_flash_ctl->firingPower) {
+ cur_flash_ctl->firingPower = isp_flash_ctl->firingPower;
+ updated |= CAM_FLASH_CMD;
+ }
+
+ if (cur_flash_ctl->firingTime != isp_flash_ctl->firingTime) {
+ cur_flash_ctl->firingTime = isp_flash_ctl->firingTime;
+ updated |= CAM_FLASH_CMD;
+ }
+ /*printk("%d %d %d\n", cur_lens_ctl->focusDistance,
+ cur_lens_uctl->maxPos,
+ cur_lens_uctl->slewRate);*/
+
+ if (updated) {
+ this->cur_peri_ctl.uUpdateBitMap = updated;
+ memcpy(this->is_region->shared, &this->cur_peri_ctl,
+ sizeof(struct camera2_uctl));
+ fimc_is_itf_s_camctrl(this, this->minfo.dvaddr_shared, fcount);
+ }
+
+ /*lens*/
+ index = (fcount + 1) & SENSOR_MAX_CTL_MASK;
+ applied_ctl = &this->peri_ctls[index];
+ applied_ctl->lensUd.ctl.focusDistance = cur_lens_ctl->focusDistance;
+ applied_ctl->lensUd.maxPos = cur_lens_uctl->maxPos;
+ applied_ctl->lensUd.slewRate = cur_lens_uctl->slewRate;
+
+ /*sensor*/
+ index = (fcount + 3) & SENSOR_MAX_CTL_MASK;
+ applied_ctl = &this->peri_ctls[index];
+ applied_ctl->sensorUd.ctl.exposureTime = cur_sensor_ctl->exposureTime;
+ applied_ctl->sensorUd.ctl.frameDuration = cur_sensor_ctl->frameDuration;
+ applied_ctl->sensorUd.ctl.sensitivity = cur_sensor_ctl->sensitivity;
+
+ /*flash*/
+ index = (fcount + 0) & SENSOR_MAX_CTL_MASK;
+ applied_ctl = &this->peri_ctls[index];
+ applied_ctl->flashUd.ctl.flashMode = cur_flash_ctl->flashMode;
+ applied_ctl->flashUd.ctl.firingPower = cur_flash_ctl->firingPower;
+ applied_ctl->flashUd.ctl.firingTime = cur_flash_ctl->firingTime;
+
+ return ret;
+}
+#else
+int fimc_is_ischain_camctl(struct fimc_is_device_ischain *this,
+ struct fimc_is_frame_shot *frame,
+ u32 fcount)
+{
+ int ret = 0;
+ struct fimc_is_interface *itf;
+ struct camera2_uctl *applied_ctl;
+
+ struct camera2_sensor_ctl *isp_sensor_ctl;
+ struct camera2_lens_ctl *isp_lens_ctl;
+ struct camera2_flash_ctl *isp_flash_ctl;
+
+ u32 index;
+
+#ifdef DBG_STREAMING
+ dbg_ischain("%s\n", __func__);
+#endif
+
+ itf = this->interface;
+ isp_sensor_ctl = &itf->isp_peri_ctl.sensorUd.ctl;
+ isp_lens_ctl = &itf->isp_peri_ctl.lensUd.ctl;
+ isp_flash_ctl = &itf->isp_peri_ctl.flashUd.ctl;
+
+ /*lens*/
+ index = (fcount + 0) & SENSOR_MAX_CTL_MASK;
+ applied_ctl = &this->peri_ctls[index];
+ applied_ctl->lensUd.ctl.focusDistance = isp_lens_ctl->focusDistance;
+
+ /*sensor*/
+ index = (fcount + 1) & SENSOR_MAX_CTL_MASK;
+ applied_ctl = &this->peri_ctls[index];
+ applied_ctl->sensorUd.ctl.exposureTime = isp_sensor_ctl->exposureTime;
+ applied_ctl->sensorUd.ctl.frameDuration = isp_sensor_ctl->frameDuration;
+ applied_ctl->sensorUd.ctl.sensitivity = isp_sensor_ctl->sensitivity;
+
+ /*flash*/
+ index = (fcount + 0) & SENSOR_MAX_CTL_MASK;
+ applied_ctl = &this->peri_ctls[index];
+ applied_ctl->flashUd.ctl.flashMode = isp_flash_ctl->flashMode;
+ applied_ctl->flashUd.ctl.firingPower = isp_flash_ctl->firingPower;
+ applied_ctl->flashUd.ctl.firingTime = isp_flash_ctl->firingTime;
+
+ return ret;
+}
+#endif
+
+int fimc_is_ischain_tag(struct fimc_is_device_ischain *ischain,
+ struct fimc_is_frame_shot *frame)
+{
+ int ret = 0;
+ struct camera2_uctl *applied_ctl;
+ struct timeval curtime;
+ u32 fcount;
+
+ fcount = frame->fcount;
+ applied_ctl = &ischain->peri_ctls[fcount & SENSOR_MAX_CTL_MASK];
+
+ do_gettimeofday(&curtime);
+
+ /* Request */
+ frame->shot->dm.request.frameCount = fcount;
+
+ /* Lens */
+ frame->shot->dm.lens.focusDistance =
+ applied_ctl->lensUd.ctl.focusDistance;
+
+ /* Sensor */
+ frame->shot->dm.sensor.exposureTime =
+ applied_ctl->sensorUd.ctl.exposureTime;
+ frame->shot->dm.sensor.sensitivity =
+ applied_ctl->sensorUd.ctl.sensitivity;
+ frame->shot->dm.sensor.frameDuration =
+ applied_ctl->sensorUd.ctl.frameDuration;
+ frame->shot->dm.sensor.timeStamp =
+ curtime.tv_sec*1000000 + curtime.tv_usec;
+
+ /* Flash */
+ frame->shot->dm.flash.flashMode =
+ applied_ctl->flashUd.ctl.flashMode;
+ frame->shot->dm.flash.firingPower =
+ applied_ctl->flashUd.ctl.firingPower;
+ frame->shot->dm.flash.firingTime =
+ applied_ctl->flashUd.ctl.firingTime;
+
+ return ret;
+}
diff --git a/drivers/media/video/exynos/fimc-is-mc2/fimc-is-device-ischain.h b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-device-ischain.h
new file mode 100644
index 0000000..a5ab00b
--- /dev/null
+++ b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-device-ischain.h
@@ -0,0 +1,230 @@
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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.
+ */
+
+#ifndef FIMC_IS_DEVICE_ISCHAIN_H
+#define FIMC_IS_DEVICE_ISCHAIN_H
+
+#include "fimc-is-mem.h"
+
+#define FIMC_IS_A5_MEM_SIZE (0x00A00000)
+#define FIMC_IS_A5_SEN_SIZE (0x00100000)
+#define FIMC_IS_REGION_SIZE (0x5000)
+#define FIMC_IS_SETFILE_SIZE (0xc0d8)
+#define FIMC_IS_TDNR_MEM_SIZE (1920*1080*4)
+#define FIMC_IS_DEBUG_REGION_ADDR (0x00840000)
+#define FIMC_IS_SHARED_REGION_ADDR (0x008C0000)
+
+#define MAX_ODC_INTERNAL_BUF_WIDTH (2560) /* 4808 in HW */
+#define MAX_ODC_INTERNAL_BUF_HEIGHT (1920) /* 3356 in HW */
+#define SIZE_ODC_INTERNAL_BUF \
+ (MAX_ODC_INTERNAL_BUF_WIDTH * MAX_ODC_INTERNAL_BUF_HEIGHT * 3)
+
+#define MAX_DIS_INTERNAL_BUF_WIDTH (2400)
+#define MAX_DIS_INTERNAL_BUF_HEIGHT (1360)
+#define SIZE_DIS_INTERNAL_BUF \
+ (MAX_DIS_INTERNAL_BUF_WIDTH * MAX_DIS_INTERNAL_BUF_HEIGHT * 2)
+
+#define MAX_3DNR_INTERNAL_BUF_WIDTH (1920)
+#define MAX_3DNR_INTERNAL_BUF_HEIGHT (1088)
+#define SIZE_DNR_INTERNAL_BUF \
+ (MAX_3DNR_INTERNAL_BUF_WIDTH * MAX_3DNR_INTERNAL_BUF_HEIGHT * 2)
+
+#define NUM_ODC_INTERNAL_BUF (2)
+#define NUM_DIS_INTERNAL_BUF (5)
+#define NUM_DNR_INTERNAL_BUF (2)
+
+#define SENSOR_MAX_CTL 0x10
+#define SENSOR_MAX_CTL_MASK (SENSOR_MAX_CTL-1)
+
+/*global state*/
+enum fimc_is_ischain_state {
+ FIMC_IS_ISCHAIN_OPEN,
+ FIMC_IS_ISCHAIN_LOADED,
+ FIMC_IS_ISCHAIN_POWER_ON,
+ FIMC_IS_ISCHAIN_RUN
+};
+
+struct fimc_is_ishcain_mem {
+ dma_addr_t base; /* buffer base */
+ size_t size; /* total length */
+ dma_addr_t vaddr_base; /* buffer base */
+ dma_addr_t vaddr_curr; /* current addr */
+ void *fw_cookie;
+
+ u32 dvaddr;
+ u32 kvaddr;
+ u32 dvaddr_debug;
+ u32 kvaddr_debug;
+ u32 dvaddr_fshared;
+ u32 kvaddr_fshared;
+ u32 dvaddr_region;
+ u32 kvaddr_region;
+ u32 dvaddr_shared; /*shared region of is region*/
+ u32 kvaddr_shared;
+ u32 dvaddr_odc;
+ u32 kvaddr_odc;
+ u32 dvaddr_dis;
+ u32 kvaddr_dis;
+ u32 dvaddr_3dnr;
+ u32 kvaddr_3dnr;
+};
+
+/*device state*/
+enum fimc_is_isdev_state {
+ FIMC_IS_ISDEV_DSTART
+};
+
+struct fimc_is_ischain_dev {
+ enum is_entry entry;
+ unsigned long state;
+ struct mutex mutex_state;
+
+ struct fimc_is_framemgr framemgr;
+ struct fimc_is_video_common *video;
+};
+
+struct fimc_is_device_ischain {
+ struct platform_device *pdev;
+ struct device *bus_dev;
+ struct exynos5_platform_fimc_is *pdata;
+ void __iomem *regs;
+
+ struct fimc_is_ishcain_mem minfo;
+
+ struct fimc_is_interface *interface;
+ struct fimc_is_framemgr *framemgr;
+ struct fimc_is_mem *mem;
+
+ struct is_region *is_region;
+
+ bool force_down;
+ unsigned long state;
+ struct mutex mutex_state;
+ spinlock_t slock_state;
+
+ u32 instance;
+ u32 dzoom_width;
+ u32 setfile;
+ u32 fcount;
+ u32 debug_cnt;
+
+ struct camera2_sm capability;
+ struct camera2_uctl cur_peri_ctl;
+ struct camera2_uctl peri_ctls[SENSOR_MAX_CTL];
+
+ /*isp margin*/
+ u32 sensor_width;
+ u32 sensor_height;
+ u32 margin_left;
+ u32 margin_right;
+ u32 margin_width;
+ u32 margin_top;
+ u32 margin_bottom;
+ u32 margin_height;
+
+ /*isp ~ scc*/
+ u32 chain0_width;
+ u32 chain0_height;
+ struct fimc_is_ischain_dev isp;
+ struct fimc_is_ischain_dev drc;
+
+ /*scc ~ dis*/
+ u32 chain1_width;
+ u32 chain1_height;
+ u32 crop_x;
+ u32 crop_y;
+ u32 crop_width;
+ u32 crop_height;
+ struct fimc_is_ischain_dev scc;
+ struct fimc_is_ischain_dev dis;
+
+ /*dis ~ scp*/
+ u32 chain2_width;
+ u32 chain2_height;
+ struct fimc_is_ischain_dev dnr;
+
+ /*scp ~ fd*/
+ u32 chain3_width;
+ u32 chain3_height;
+ struct fimc_is_ischain_dev scp;
+ struct fimc_is_ischain_dev fd;
+
+ u32 lindex;
+ u32 hindex;
+ u32 indexes;
+
+ u32 private_data;
+};
+
+/*global function*/
+int fimc_is_ischain_probe(struct fimc_is_device_ischain *this,
+ struct fimc_is_interface *interface,
+ struct fimc_is_framemgr *framemgr,
+ struct fimc_is_mem *mem,
+ struct platform_device *pdev,
+ u32 regs);
+int fimc_is_ischain_open(struct fimc_is_device_ischain *this,
+ struct fimc_is_video_common *video);
+int fimc_is_ischain_close(struct fimc_is_device_ischain *this);
+int fimc_is_ischain_init(struct fimc_is_device_ischain *this,
+ u32 input, u32 channel, struct sensor_open_extended *ext,
+ char *setfile_name);
+int fimc_is_ischain_g_capability(struct fimc_is_device_ischain *this,
+ u32 user_ptr);
+int fimc_is_ischain_print_status(struct fimc_is_device_ischain *this);
+
+/*isp subdev*/
+int fimc_is_ischain_isp_start(struct fimc_is_device_ischain *this,
+ struct fimc_is_video_common *video);
+int fimc_is_ischain_isp_stop(struct fimc_is_device_ischain *this);
+int fimc_is_ischain_isp_s_format(struct fimc_is_device_ischain *this,
+ u32 width, u32 height);
+int fimc_is_ischain_isp_buffer_queue(struct fimc_is_device_ischain *this,
+ u32 index);
+int fimc_is_ischain_isp_buffer_finish(struct fimc_is_device_ischain *this,
+ u32 index);
+
+/*scc subdev*/
+int fimc_is_ischain_scc_start(struct fimc_is_device_ischain *this);
+int fimc_is_ischain_scc_stop(struct fimc_is_device_ischain *this);
+
+/*scp subdev*/
+int fimc_is_ischain_scp_start(struct fimc_is_device_ischain *this);
+int fimc_is_ischain_scp_stop(struct fimc_is_device_ischain *this);
+int fimc_is_ischain_scp_s_format(struct fimc_is_device_ischain *this,
+ u32 width, u32 height);
+
+/*common subdev*/
+int fimc_is_ischain_dev_start(struct fimc_is_ischain_dev *this);
+int fimc_is_ischain_dev_stop(struct fimc_is_ischain_dev *this);
+int fimc_is_ischain_dev_open(struct fimc_is_ischain_dev *this,
+ enum is_entry entry,
+ struct fimc_is_video_common *video,
+ const struct param_control *init_ctl);
+int fimc_is_ischain_dev_buffer_queue(struct fimc_is_ischain_dev *this,
+ u32 index);
+int fimc_is_ischain_dev_buffer_finish(struct fimc_is_ischain_dev *this,
+ u32 index);
+
+/*special api for sensor*/
+int fimc_is_ischain_callback(struct fimc_is_device_ischain *this);
+int fimc_is_ischain_camctl(struct fimc_is_device_ischain *this,
+ struct fimc_is_frame_shot *frame,
+ u32 fcount);
+int fimc_is_ischain_tag(struct fimc_is_device_ischain *ischain,
+ struct fimc_is_frame_shot *frame);
+
+int fimc_is_itf_process_on(struct fimc_is_device_ischain *this);
+int fimc_is_itf_process_off(struct fimc_is_device_ischain *this);
+int fimc_is_itf_stream_on(struct fimc_is_device_ischain *this);
+int fimc_is_itf_stream_off(struct fimc_is_device_ischain *this);
+
+#endif
diff --git a/drivers/media/video/exynos/fimc-is-mc2/fimc-is-device-sensor.c b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-device-sensor.c
new file mode 100644
index 0000000..f90f91a
--- /dev/null
+++ b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-device-sensor.c
@@ -0,0 +1,742 @@
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ * exynos5 fimc-is video functions
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <mach/videonode.h>
+#include <media/exynos_mc.h>
+#include <linux/cma.h>
+#include <asm/cacheflush.h>
+#include <asm/pgtable.h>
+#include <linux/firmware.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
+#include <linux/videodev2.h>
+#include <linux/videodev2_exynos_camera.h>
+#include <linux/videodev2_exynos_media.h>
+#include <linux/v4l2-mediabus.h>
+
+#include <mach/map.h>
+#include <mach/regs-clock.h>
+
+#include "fimc-is-core.h"
+#include "fimc-is-param.h"
+#include "fimc-is-cmd.h"
+#include "fimc-is-regs.h"
+#include "fimc-is-err.h"
+#include "fimc-is-video.h"
+
+#include "fimc-is-device-sensor.h"
+
+/* PMU for FIMC-IS*/
+#define MIPICSI0_REG_BASE (S5P_VA_MIPICSI0) /* phy : 0x13c2_0000 */
+#define MIPICSI1_REG_BASE (S5P_VA_MIPICSI1) /* phy : 0x13c3_0000 */
+
+/*MIPI*/
+/* CSIS global control */
+#define S5PCSIS_CTRL (0x00)
+#define S5PCSIS_CTRL_DPDN_DEFAULT (0 << 31)
+#define S5PCSIS_CTRL_DPDN_SWAP (1 << 31)
+#define S5PCSIS_CTRL_ALIGN_32BIT (1 << 20)
+#define S5PCSIS_CTRL_UPDATE_SHADOW (1 << 16)
+#define S5PCSIS_CTRL_WCLK_EXTCLK (1 << 8)
+#define S5PCSIS_CTRL_RESET (1 << 4)
+#define S5PCSIS_CTRL_ENABLE (1 << 0)
+
+/* D-PHY control */
+#define S5PCSIS_DPHYCTRL (0x04)
+#define S5PCSIS_DPHYCTRL_HSS_MASK (0x1f << 27)
+#define S5PCSIS_DPHYCTRL_ENABLE (0x7 << 0)
+
+#define S5PCSIS_CONFIG (0x08)
+#define S5PCSIS_CFG_FMT_YCBCR422_8BIT (0x1e << 2)
+#define S5PCSIS_CFG_FMT_RAW8 (0x2a << 2)
+#define S5PCSIS_CFG_FMT_RAW10 (0x2b << 2)
+#define S5PCSIS_CFG_FMT_RAW12 (0x2c << 2)
+/* User defined formats, x = 1...4 */
+#define S5PCSIS_CFG_FMT_USER(x) ((0x30 + x - 1) << 2)
+#define S5PCSIS_CFG_FMT_MASK (0x3f << 2)
+#define S5PCSIS_CFG_NR_LANE_MASK (3)
+
+/* Interrupt mask. */
+#define S5PCSIS_INTMSK (0x10)
+#define S5PCSIS_INTMSK_EN_ALL (0xfc00103f)
+#define S5PCSIS_INTSRC (0x14)
+
+/* Pixel resolution */
+#define S5PCSIS_RESOL (0x2c)
+#define CSIS_MAX_PIX_WIDTH (0xffff)
+#define CSIS_MAX_PIX_HEIGHT (0xffff)
+
+static void s5pcsis_enable_interrupts(unsigned long mipi_reg_base, bool on)
+{
+ u32 val = readl(mipi_reg_base + S5PCSIS_INTMSK);
+
+ val = on ? val | S5PCSIS_INTMSK_EN_ALL :
+ val & ~S5PCSIS_INTMSK_EN_ALL;
+ writel(val, mipi_reg_base + S5PCSIS_INTMSK);
+}
+
+static void s5pcsis_reset(unsigned long mipi_reg_base)
+{
+ u32 val = readl(mipi_reg_base + S5PCSIS_CTRL);
+
+ writel(val | S5PCSIS_CTRL_RESET, mipi_reg_base + S5PCSIS_CTRL);
+ udelay(10);
+}
+
+static void s5pcsis_system_enable(unsigned long mipi_reg_base, int on)
+{
+ u32 val;
+
+ val = readl(mipi_reg_base + S5PCSIS_CTRL);
+ if (on) {
+ val |= S5PCSIS_CTRL_ENABLE;
+ val |= S5PCSIS_CTRL_WCLK_EXTCLK;
+ } else
+ val &= ~S5PCSIS_CTRL_ENABLE;
+ writel(val, mipi_reg_base + S5PCSIS_CTRL);
+
+ val = readl(mipi_reg_base + S5PCSIS_DPHYCTRL);
+ if (on)
+ val |= S5PCSIS_DPHYCTRL_ENABLE;
+ else
+ val &= ~S5PCSIS_DPHYCTRL_ENABLE;
+ writel(val, mipi_reg_base + S5PCSIS_DPHYCTRL);
+}
+
+/* Called with the state.lock mutex held */
+static void __s5pcsis_set_format(unsigned long mipi_reg_base,
+ struct fimc_is_frame_info *f_frame)
+{
+ u32 val;
+
+ /* Color format */
+ val = readl(mipi_reg_base + S5PCSIS_CONFIG);
+ val = (val & ~S5PCSIS_CFG_FMT_MASK) | S5PCSIS_CFG_FMT_RAW10;
+ writel(val, mipi_reg_base + S5PCSIS_CONFIG);
+
+ /* Pixel resolution */
+ val = (f_frame->o_width << 16) | f_frame->o_height;
+ writel(val, mipi_reg_base + S5PCSIS_RESOL);
+}
+
+static void s5pcsis_set_hsync_settle(unsigned long mipi_reg_base)
+{
+ u32 val = readl(mipi_reg_base + S5PCSIS_DPHYCTRL);
+
+ val = (val & ~S5PCSIS_DPHYCTRL_HSS_MASK) | (0x6 << 28);
+ writel(val, mipi_reg_base + S5PCSIS_DPHYCTRL);
+}
+
+static void s5pcsis_set_params(unsigned long mipi_reg_base,
+ struct fimc_is_frame_info *f_frame)
+{
+ u32 val;
+
+ val = readl(mipi_reg_base + S5PCSIS_CONFIG);
+ val = (val & ~S5PCSIS_CFG_NR_LANE_MASK) | (2 - 1);
+ writel(val, mipi_reg_base + S5PCSIS_CONFIG);
+
+ __s5pcsis_set_format(mipi_reg_base, f_frame);
+ s5pcsis_set_hsync_settle(mipi_reg_base);
+
+ val = readl(mipi_reg_base + S5PCSIS_CTRL);
+ val &= ~S5PCSIS_CTRL_ALIGN_32BIT;
+
+ /* Not using external clock. */
+ val &= ~S5PCSIS_CTRL_WCLK_EXTCLK;
+
+ writel(val, mipi_reg_base + S5PCSIS_CTRL);
+
+ /* Update the shadow register. */
+ val = readl(mipi_reg_base + S5PCSIS_CTRL);
+ writel(val | S5PCSIS_CTRL_UPDATE_SHADOW, mipi_reg_base + S5PCSIS_CTRL);
+}
+
+int enable_mipi(void)
+{
+ void __iomem *addr;
+ u32 cfg;
+
+ addr = S5P_MIPI_DPHY_CONTROL(0);
+
+ cfg = __raw_readl(addr);
+ cfg = (cfg | S5P_MIPI_DPHY_SRESETN);
+ __raw_writel(cfg, addr);
+
+ if (1) {
+ cfg |= S5P_MIPI_DPHY_ENABLE;
+ } else if (!(cfg & (S5P_MIPI_DPHY_SRESETN | S5P_MIPI_DPHY_MRESETN)
+ & (~S5P_MIPI_DPHY_SRESETN))) {
+ cfg &= ~S5P_MIPI_DPHY_ENABLE;
+ }
+
+ __raw_writel(cfg, addr);
+
+
+ addr = S5P_MIPI_DPHY_CONTROL(1);
+
+ cfg = __raw_readl(addr);
+ cfg = (cfg | S5P_MIPI_DPHY_SRESETN);
+ __raw_writel(cfg, addr);
+
+ if (1) {
+ cfg |= S5P_MIPI_DPHY_ENABLE;
+ } else if (!(cfg & (S5P_MIPI_DPHY_SRESETN | S5P_MIPI_DPHY_MRESETN)
+ & (~S5P_MIPI_DPHY_SRESETN))) {
+ cfg &= ~S5P_MIPI_DPHY_ENABLE;
+ }
+
+ __raw_writel(cfg, addr);
+ return 0;
+
+}
+
+int start_mipi_csi(int channel, struct fimc_is_frame_info *f_frame)
+{
+ unsigned long base_reg = (unsigned long)MIPICSI0_REG_BASE;
+
+ if (channel == CSI_ID_A)
+ base_reg = (unsigned long)MIPICSI0_REG_BASE;
+ else if (channel == CSI_ID_B)
+ base_reg = (unsigned long)MIPICSI1_REG_BASE;
+
+ s5pcsis_reset(base_reg);
+ s5pcsis_set_params(base_reg, f_frame);
+ s5pcsis_system_enable(base_reg, true);
+ s5pcsis_enable_interrupts(base_reg, true);
+
+ return 0;
+}
+
+int stop_mipi_csi(int channel)
+{
+ unsigned long base_reg = (unsigned long)MIPICSI0_REG_BASE;
+
+ if (channel == CSI_ID_A)
+ base_reg = (unsigned long)MIPICSI0_REG_BASE;
+ else if (channel == CSI_ID_B)
+ base_reg = (unsigned long)MIPICSI1_REG_BASE;
+
+ s5pcsis_enable_interrupts(base_reg, false);
+ s5pcsis_system_enable(base_reg, false);
+
+ return 0;
+}
+
+static int testnset_state(struct fimc_is_device_sensor *this,
+ unsigned long state)
+{
+ int ret = 0;
+
+ spin_lock(&this->slock_state);
+
+ if (test_bit(state, &this->state)) {
+ ret = -EINVAL;
+ goto exit;
+ }
+ set_bit(state, &this->state);
+
+exit:
+ spin_unlock(&this->slock_state);
+ return ret;
+}
+
+static int testnclr_state(struct fimc_is_device_sensor *this,
+ unsigned long state)
+{
+ int ret = 0;
+
+ spin_lock(&this->slock_state);
+
+ if (!test_bit(state, &this->state)) {
+ ret = -EINVAL;
+ goto exit;
+ }
+ clear_bit(state, &this->state);
+
+exit:
+ spin_unlock(&this->slock_state);
+ return ret;
+}
+
+int fimc_is_sensor_probe(struct fimc_is_device_sensor *this,
+ struct fimc_is_video_sensor *video,
+ struct fimc_is_framemgr *framemgr,
+ struct fimc_is_device_ischain *ischain,
+ struct fimc_is_mem *mem)
+{
+ int ret = 0;
+ struct sensor_open_extended *ext;
+ struct fimc_is_enum_sensor *enum_sensor;
+
+ enum_sensor = this->enum_sensor;
+
+ if (video == NULL) {
+ err("video is null");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (framemgr == NULL) {
+ err("framemgr is null");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (ischain == NULL) {
+ err("ischain is null");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (mem == NULL) {
+ err("mem is null");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ /*sensor init*/
+ clear_bit(FIMC_IS_SENSOR_OPEN, &this->state);
+ clear_bit(FIMC_IS_SENSOR_FRONT_START, &this->state);
+ clear_bit(FIMC_IS_SENSOR_BACK_START, &this->state);
+
+ this->framemgr = framemgr;
+ this->mem = mem;
+ this->ischain = ischain;
+ this->video = video;
+
+ enum_sensor[SENSOR_NAME_S5K3H2].sensor = SENSOR_NAME_S5K3H2;
+ enum_sensor[SENSOR_NAME_S5K3H2].pixel_width = 0;
+ enum_sensor[SENSOR_NAME_S5K3H2].pixel_height = 0;
+ enum_sensor[SENSOR_NAME_S5K3H2].active_width = 0;
+ enum_sensor[SENSOR_NAME_S5K3H2].active_height = 0;
+ enum_sensor[SENSOR_NAME_S5K3H2].max_framerate = 0;
+ enum_sensor[SENSOR_NAME_S5K3H2].csi_ch = 0;
+ enum_sensor[SENSOR_NAME_S5K3H2].flite_ch = 0;
+ enum_sensor[SENSOR_NAME_S5K3H2].i2c_ch = 0;
+ enum_sensor[SENSOR_NAME_S5K3H2].setfile_name =
+ "setfile_3h2.bin";
+
+ ext = &enum_sensor[SENSOR_NAME_S5K3H2].ext;
+ memset(ext, 0x0, sizeof(struct sensor_open_extended));
+
+ enum_sensor[SENSOR_NAME_S5K6A3].sensor = SENSOR_NAME_S5K6A3;
+ enum_sensor[SENSOR_NAME_S5K6A3].pixel_width = 1392 + 16;
+ enum_sensor[SENSOR_NAME_S5K6A3].pixel_height = 1392 + 10;
+ enum_sensor[SENSOR_NAME_S5K6A3].active_width = 1392;
+ enum_sensor[SENSOR_NAME_S5K6A3].active_height = 1392;
+ enum_sensor[SENSOR_NAME_S5K6A3].max_framerate = 30;
+ enum_sensor[SENSOR_NAME_S5K6A3].csi_ch = 1;
+ enum_sensor[SENSOR_NAME_S5K6A3].flite_ch = FLITE_ID_B;
+ enum_sensor[SENSOR_NAME_S5K6A3].i2c_ch = 1;
+ enum_sensor[SENSOR_NAME_S5K6A3].setfile_name =
+ "setfile_6a3.bin";
+
+ ext = &enum_sensor[SENSOR_NAME_S5K6A3].ext;
+ memset(ext, 0x0, sizeof(struct sensor_open_extended));
+
+ enum_sensor[SENSOR_NAME_S5K4E5].sensor = SENSOR_NAME_S5K4E5;
+ enum_sensor[SENSOR_NAME_S5K4E5].pixel_width = 2560 + 16;
+ enum_sensor[SENSOR_NAME_S5K4E5].pixel_height = 1920 + 10;
+ enum_sensor[SENSOR_NAME_S5K4E5].active_width = 2560;
+ enum_sensor[SENSOR_NAME_S5K4E5].active_height = 1920;
+ enum_sensor[SENSOR_NAME_S5K4E5].max_framerate = 30;
+ enum_sensor[SENSOR_NAME_S5K4E5].csi_ch = 0;
+ enum_sensor[SENSOR_NAME_S5K4E5].flite_ch = FLITE_ID_A;
+ enum_sensor[SENSOR_NAME_S5K4E5].i2c_ch = 0;
+ enum_sensor[SENSOR_NAME_S5K4E5].setfile_name =
+ "setfile_4e5.bin";
+
+ ext = &enum_sensor[SENSOR_NAME_S5K4E5].ext;
+ ext->actuator_con.product_name = ACTUATOR_NAME_DWXXXX;
+ ext->actuator_con.peri_type = SE_I2C;
+ ext->actuator_con.peri_setting.i2c.channel
+ = SENSOR_CONTROL_I2C0;
+
+ ext->flash_con.product_name = FLADRV_NAME_KTD267;
+ ext->flash_con.peri_type = SE_GPIO;
+ ext->flash_con.peri_setting.gpio.first_gpio_port_no = 1;
+ ext->flash_con.peri_setting.gpio.second_gpio_port_no = 2;
+
+ ext->from_con.product_name = FROMDRV_NAME_NOTHING;
+ ext->mclk = 0;
+ ext->mipi_lane_num = 0;
+ ext->mipi_speed = 0;
+ ext->fast_open_sensor = 0;
+ ext->self_calibration_mode = 0;
+
+ enum_sensor[SENSOR_NAME_S5K3H7].sensor = SENSOR_NAME_S5K3H7;
+ enum_sensor[SENSOR_NAME_S5K3H7].pixel_width = 3200 + 16;
+ enum_sensor[SENSOR_NAME_S5K3H7].pixel_height = 2400 + 10;
+ enum_sensor[SENSOR_NAME_S5K3H7].active_width = 3200;
+ enum_sensor[SENSOR_NAME_S5K3H7].active_height = 2400;
+ enum_sensor[SENSOR_NAME_S5K3H7].max_framerate = 30;
+ enum_sensor[SENSOR_NAME_S5K3H7].csi_ch = 0;
+ enum_sensor[SENSOR_NAME_S5K3H7].flite_ch = FLITE_ID_A;
+ enum_sensor[SENSOR_NAME_S5K3H7].i2c_ch = 0;
+ enum_sensor[SENSOR_NAME_S5K3H7].setfile_name =
+ "setfile_3h7.bin";
+
+ ext = &enum_sensor[SENSOR_NAME_S5K3H7].ext;
+ ext->actuator_con.product_name = ACTUATOR_NAME_AK7343;
+ ext->actuator_con.peri_type = SE_I2C;
+ ext->actuator_con.peri_setting.i2c.channel
+ = SENSOR_CONTROL_I2C0;
+
+ ext->flash_con.product_name = FLADRV_NAME_KTD267;
+ ext->flash_con.peri_type = SE_GPIO;
+ ext->flash_con.peri_setting.gpio.first_gpio_port_no = 17;
+ ext->flash_con.peri_setting.gpio.second_gpio_port_no = 16;
+
+ ext->from_con.product_name = FROMDRV_NAME_NOTHING;
+ ext->mclk = 0;
+ ext->mipi_lane_num = 0;
+ ext->mipi_speed = 0;
+ ext->fast_open_sensor = 0;
+ ext->self_calibration_mode = 0;
+
+ fimc_is_flite_probe(&this->flite0,
+ &video->common,
+ framemgr,
+ FLITE_ID_A,
+ (u32)this);
+
+ fimc_is_flite_probe(&this->flite1,
+ &video->common,
+ framemgr,
+ FLITE_ID_B,
+ (u32)this);
+
+ spin_lock_init(&this->slock_state);
+
+exit:
+ return ret;
+}
+
+int fimc_is_sensor_open(struct fimc_is_device_sensor *this)
+{
+ int ret = 0;
+
+ if (testnset_state(this, FIMC_IS_SENSOR_OPEN)) {
+ err("already open");
+ ret = -EMFILE;
+ goto exit;
+ }
+
+ printk(KERN_INFO "+++%s()\n", __func__);
+
+ clear_bit(FIMC_IS_SENSOR_FRONT_START, &this->state);
+ clear_bit(FIMC_IS_SENSOR_BACK_START, &this->state);
+
+ this->active_sensor = &this->enum_sensor[SENSOR_NAME_S5K4E5];
+
+ printk(KERN_INFO "---%s(%d)\n", __func__, ret);
+
+exit:
+ return ret;
+}
+
+int fimc_is_sensor_close(struct fimc_is_device_sensor *this)
+{
+ int ret = 0;
+ struct fimc_is_device_ischain *ischain;
+
+ if (testnclr_state(this, FIMC_IS_SENSOR_OPEN)) {
+ err("already close");
+ ret = -EMFILE;
+ goto exit;
+ }
+
+ /* it can not be accessed to register firmawre
+ after clock gating and power down. ischain close do clock gating and
+ power down */
+ ischain = this->ischain;
+ mutex_lock(&ischain->mutex_state);
+ if (!test_bit(FIMC_IS_ISCHAIN_OPEN, &ischain->state)) {
+ mutex_unlock(&ischain->mutex_state);
+ err("ischain device is already close, skip");
+ ret = -EINVAL;
+ goto exit;
+ }
+ mutex_unlock(&ischain->mutex_state);
+
+ printk(KERN_INFO "+++%s\n", __func__);
+
+ fimc_is_sensor_back_stop(this);
+ fimc_is_sensor_front_stop(this);
+
+ printk(KERN_INFO "---%s(%d)\n", __func__, ret);
+
+exit:
+ return ret;
+}
+
+int fimc_is_sensor_s_active_sensor(struct fimc_is_device_sensor *this,
+ u32 input)
+{
+ int ret = 0;
+
+ this->active_sensor = &this->enum_sensor[input];
+ if (this->active_sensor->flite_ch == FLITE_ID_A)
+ this->active_flite = &this->flite0;
+ else
+ this->active_flite = &this->flite1;
+
+ ret = fimc_is_flite_open(this->active_flite);
+
+ return ret;
+}
+
+int fimc_is_sensor_buffer_queue(struct fimc_is_device_sensor *this,
+ u32 index)
+{
+ int ret = 0;
+ unsigned long flags;
+ struct fimc_is_frame_shot *frame;
+ struct fimc_is_framemgr *framemgr;
+
+ if (index >= FRAMEMGR_MAX_REQUEST) {
+ err("index(%d) is invalid", index);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ framemgr = this->framemgr;
+ if (framemgr == NULL) {
+ err("framemgr is null\n");
+ ret = EINVAL;
+ goto exit;
+ }
+
+ frame = &framemgr->frame[index];
+ if (frame == NULL) {
+ err("frame is null\n");
+ ret = EINVAL;
+ goto exit;
+ }
+
+ if (frame->init == FRAME_UNI_MEM) {
+ err("frame %d is NOT init", index);
+ ret = EINVAL;
+ goto exit;
+ }
+
+ framemgr_e_barrier_irqs(framemgr, FMGR_IDX_2 + index, flags);
+
+ if (frame->state == FIMC_IS_FRAME_STATE_FREE)
+ fimc_is_frame_trans_fre_to_req(framemgr, frame);
+ else {
+ err("frame(%d) is not free state(%d)", index, frame->state);
+ fimc_is_frame_print_all(framemgr);
+ }
+
+ framemgr_x_barrier_irqr(framemgr, FMGR_IDX_2 + index, flags);
+
+exit:
+ return ret;
+}
+
+int fimc_is_sensor_buffer_finish(struct fimc_is_device_sensor *this,
+ u32 index)
+{
+ int ret = 0;
+ unsigned long flags;
+ struct fimc_is_frame_shot *frame;
+ struct fimc_is_framemgr *framemgr;
+
+ if (index >= FRAMEMGR_MAX_REQUEST) {
+ err("index(%d) is invalid", index);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ framemgr = this->framemgr;
+ frame = &framemgr->frame[index];
+
+ framemgr_e_barrier_irqs(framemgr, FMGR_IDX_3 + index, flags);
+
+ if (frame->state == FIMC_IS_FRAME_STATE_COMPLETE) {
+ if (!frame->shot->dm.request.frameCount)
+ err("request.frameCount is 0\n");
+ fimc_is_frame_trans_com_to_fre(framemgr, frame);
+ } else {
+ err("frame(%d) is not com state(%d)", index, frame->state);
+ fimc_is_frame_print_all(framemgr);
+ }
+
+ framemgr_x_barrier_irqr(framemgr, FMGR_IDX_3 + index, flags);
+
+exit:
+ return ret;
+}
+
+int fimc_is_sensor_back_start(struct fimc_is_device_sensor *this,
+ struct fimc_is_video_common *video)
+{
+ int ret = 0;
+ struct fimc_is_frame_info frame;
+ struct fimc_is_enum_sensor *active_sensor;
+ struct fimc_is_device_flite *active_flite;
+
+ dbg_back("%s\n", __func__);
+
+ if (testnset_state(this, FIMC_IS_SENSOR_BACK_START)) {
+ err("already back start");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ active_sensor = this->active_sensor;
+ active_flite = this->active_flite;
+
+ frame.o_width = active_sensor->pixel_width;
+ frame.o_height = active_sensor->pixel_height;
+ frame.offs_h = 0;
+ frame.offs_v = 0;
+ frame.width = active_sensor->pixel_width;
+ frame.height = active_sensor->pixel_height;
+
+ /*start flite*/
+ fimc_is_flite_start(active_flite, &frame, video);
+
+ /*start mipi*/
+ dbg_back("start flite (pos:%d) (port:%d) : %d x %d\n",
+ active_sensor->sensor,
+ active_sensor->flite_ch,
+ frame.width, frame.height);
+
+exit:
+ return ret;
+}
+
+int fimc_is_sensor_back_stop(struct fimc_is_device_sensor *this)
+{
+ int ret = 0;
+ unsigned long flags;
+ struct fimc_is_frame_shot *frame;
+ struct fimc_is_framemgr *framemgr;
+ struct fimc_is_device_flite *active_flite;
+
+ dbg_back("%s\n", __func__);
+
+ if (testnclr_state(this, FIMC_IS_SENSOR_BACK_START)) {
+ warn("already back stop");
+ goto exit;
+ }
+
+ framemgr = this->framemgr;
+ active_flite = this->active_flite;
+
+ ret = fimc_is_flite_stop(active_flite);
+ if (ret)
+ err("fimc_is_flite_stop is fail");
+
+ framemgr_e_barrier_irqs(framemgr, FMGR_IDX_3, flags);
+
+ fimc_is_frame_complete_head(framemgr, &frame);
+ while (frame) {
+ fimc_is_frame_trans_com_to_fre(framemgr, frame);
+ fimc_is_frame_complete_head(framemgr, &frame);
+ }
+
+ fimc_is_frame_process_head(framemgr, &frame);
+ while (frame) {
+ fimc_is_frame_trans_pro_to_fre(framemgr, frame);
+ fimc_is_frame_process_head(framemgr, &frame);
+ }
+
+ fimc_is_frame_request_head(framemgr, &frame);
+ while (frame) {
+ fimc_is_frame_trans_req_to_fre(framemgr, frame);
+ fimc_is_frame_request_head(framemgr, &frame);
+ }
+
+ framemgr_x_barrier_irqr(framemgr, FMGR_IDX_3, flags);
+
+exit:
+ return ret;
+}
+
+int fimc_is_sensor_front_start(struct fimc_is_device_sensor *this)
+{
+ int ret = 0;
+ struct fimc_is_frame_info frame;
+ struct fimc_is_enum_sensor *active_sensor;
+
+ dbg_front("%s\n", __func__);
+
+ if (testnset_state(this, FIMC_IS_SENSOR_FRONT_START)) {
+ err("already front start");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ active_sensor = this->active_sensor;
+
+ frame.o_width = active_sensor->pixel_width;
+ frame.o_height = active_sensor->pixel_height;
+ frame.offs_h = 0;
+ frame.offs_v = 0;
+ frame.width = active_sensor->pixel_width;
+ frame.height = active_sensor->pixel_height;
+
+ start_mipi_csi(active_sensor->csi_ch, &frame);
+
+ /*start mipi*/
+ dbg_front("start mipi (snesor id:%d) (port:%d) : %d x %d\n",
+ active_sensor->sensor,
+ active_sensor->csi_ch,
+ frame.width, frame.height);
+
+ ret = fimc_is_itf_stream_on(this->ischain);
+ if (ret)
+ err("sensor stream on is failed(error %d)\n", ret);
+ else
+ dbg_front("sensor stream on\n");
+
+exit:
+ return ret;
+}
+
+int fimc_is_sensor_front_stop(struct fimc_is_device_sensor *this)
+{
+ int ret = 0;
+ struct fimc_is_enum_sensor *active_sensor;
+
+ dbg_front("%s\n", __func__);
+
+ if (testnclr_state(this, FIMC_IS_SENSOR_FRONT_START)) {
+ warn("already front stop");
+ goto exit;
+ }
+
+ active_sensor = this->active_sensor;
+
+ ret = fimc_is_itf_stream_off(this->ischain);
+ if (ret)
+ err("sensor stream off is failed(error %d)\n", ret);
+ else
+ dbg_front("sensor stream off\n");
+
+ stop_mipi_csi(active_sensor->csi_ch);
+
+exit:
+ return ret;
+}
diff --git a/drivers/media/video/exynos/fimc-is-mc2/fimc-is-device-sensor.h b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-device-sensor.h
new file mode 100644
index 0000000..3abbc1d
--- /dev/null
+++ b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-device-sensor.h
@@ -0,0 +1,102 @@
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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.
+ */
+
+#ifndef FIMC_IS_DEVICE_SENSOR_H
+#define FIMC_IS_DEVICE_SENSOR_H
+
+#include "fimc-is-framemgr.h"
+#include "fimc-is-interface.h"
+#include "fimc-is-metadata.h"
+#include "fimc-is-video.h"
+#include "fimc-is-device-ischain.h"
+#include "fimc-is-device-flite.h"
+
+#define SENSOR_MAX_ENUM 10
+
+enum fimc_is_sensor_output_entity {
+ FIMC_IS_SENSOR_OUTPUT_NONE = 0,
+ FIMC_IS_SENSOR_OUTPUT_FRONT,
+};
+
+struct fimc_is_enum_sensor {
+ u32 sensor;
+ u32 pixel_width;
+ u32 pixel_height;
+ u32 active_width;
+ u32 active_height;
+ u32 max_framerate;
+ u32 csi_ch;
+ u32 flite_ch;
+ u32 i2c_ch;
+ struct sensor_open_extended ext;
+ char *setfile_name;
+};
+
+enum fimc_is_sensor_state {
+ FIMC_IS_SENSOR_OPEN,
+ FIMC_IS_SENSOR_FRONT_START,
+ FIMC_IS_SENSOR_BACK_START
+};
+
+struct fimc_is_device_sensor {
+ struct v4l2_subdev sd;
+ struct media_pad pads;
+ struct v4l2_mbus_framefmt mbus_fmt;
+ enum fimc_is_sensor_output_entity output;
+ int id_dual; /* for dual camera scenario */
+ int id_position; /* 0 : rear camera, 1: front camera */
+ u32 width;
+ u32 height;
+ u32 offset_x;
+ u32 offset_y;
+
+ struct fimc_is_mem *mem;
+
+ struct fimc_is_video_sensor *video;
+ struct fimc_is_framemgr *framemgr;
+ struct fimc_is_device_ischain *ischain;
+
+ struct fimc_is_enum_sensor enum_sensor[SENSOR_MAX_ENUM];
+ struct fimc_is_enum_sensor *active_sensor;
+
+ unsigned long state;
+ spinlock_t slock_state;
+
+ void *dev_data;
+
+ struct fimc_is_device_flite *active_flite;
+ struct fimc_is_device_flite flite0;
+ struct fimc_is_device_flite flite1;
+};
+
+int fimc_is_sensor_probe(struct fimc_is_device_sensor *this,
+ struct fimc_is_video_sensor *video,
+ struct fimc_is_framemgr *framemgr,
+ struct fimc_is_device_ischain *ischain,
+ struct fimc_is_mem *mem);
+int fimc_is_sensor_open(struct fimc_is_device_sensor *this);
+int fimc_is_sensor_close(struct fimc_is_device_sensor *this);
+int fimc_is_sensor_s_active_sensor(struct fimc_is_device_sensor *this,
+ u32 input);
+int fimc_is_sensor_buffer_queue(struct fimc_is_device_sensor *sensor,
+ u32 index);
+int fimc_is_sensor_buffer_finish(struct fimc_is_device_sensor *this,
+ u32 index);
+
+int fimc_is_sensor_front_start(struct fimc_is_device_sensor *this);
+int fimc_is_sensor_front_stop(struct fimc_is_device_sensor *this);
+int fimc_is_sensor_back_start(struct fimc_is_device_sensor *this,
+ struct fimc_is_video_common *video);
+int fimc_is_sensor_back_stop(struct fimc_is_device_sensor *this);
+
+int enable_mipi(void);
+
+#endif
diff --git a/drivers/media/video/exynos/fimc-is-mc2/fimc-is-err.h b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-err.h
new file mode 100644
index 0000000..de1a188
--- /dev/null
+++ b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-err.h
Binary files differ
diff --git a/drivers/media/video/exynos/fimc-is-mc2/fimc-is-framemgr.c b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-framemgr.c
new file mode 100644
index 0000000..ccaff3f
--- /dev/null
+++ b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-framemgr.c
@@ -0,0 +1,613 @@
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ * exynos5 fimc-is video functions
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <mach/videonode.h>
+#include <media/exynos_mc.h>
+#include <linux/cma.h>
+#include <asm/cacheflush.h>
+#include <asm/pgtable.h>
+#include <linux/firmware.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
+#include <linux/videodev2.h>
+#include <linux/videodev2_exynos_camera.h>
+#include <linux/videodev2_exynos_media.h>
+#include <linux/v4l2-mediabus.h>
+
+#include <mach/map.h>
+#include <mach/regs-clock.h>
+
+#include "fimc-is-core.h"
+#include "fimc-is-param.h"
+#include "fimc-is-cmd.h"
+#include "fimc-is-regs.h"
+#include "fimc-is-err.h"
+#include "fimc-is-video.h"
+
+#include "fimc-is-device-sensor.h"
+
+int fimc_is_frame_s_free_shot(struct fimc_is_framemgr *this,
+ struct fimc_is_frame_shot *item)
+{
+ int ret = 0;
+
+ if (item) {
+ item->state = FIMC_IS_FRAME_STATE_FREE;
+
+ list_add_tail(&item->list, &this->frame_free_head);
+ this->frame_free_cnt++;
+
+#ifdef TRACE_FRAME
+ fimc_is_frame_print_free_list(this);
+#endif
+ } else {
+ ret = -EFAULT;
+ err("item is null ptr\n");
+ }
+
+ return ret;
+}
+
+
+int fimc_is_frame_g_free_shot(struct fimc_is_framemgr *this,
+ struct fimc_is_frame_shot **item)
+{
+ int ret = 0;
+
+ if (item) {
+ if (this->frame_free_cnt) {
+ *item = container_of(this->frame_free_head.next,
+ struct fimc_is_frame_shot, list);
+ list_del(&(*item)->list);
+ this->frame_free_cnt--;
+
+ (*item)->state = FIMC_IS_FRAME_STATE_INVALID;
+ } else {
+ *item = NULL;
+ }
+ } else {
+ ret = -EFAULT;
+ err("item is null ptr\n");
+ }
+
+ return ret;
+}
+
+void fimc_is_frame_free_head(struct fimc_is_framemgr *this,
+ struct fimc_is_frame_shot **item)
+{
+ if (this->frame_free_cnt)
+ *item = container_of(this->frame_free_head.next,
+ struct fimc_is_frame_shot, list);
+ else
+ *item = NULL;
+}
+
+void fimc_is_frame_print_free_list(struct fimc_is_framemgr *this)
+{
+ struct list_head *temp;
+ struct fimc_is_frame_shot *shot;
+
+ if (!(TRACE_ID & this->id))
+ return;
+
+ printk(KERN_CONT "[FRM] fre(%d, %d) :", this->id, this->frame_free_cnt);
+
+ list_for_each(temp, &this->frame_free_head) {
+ shot = list_entry(temp, struct fimc_is_frame_shot, list);
+ printk(KERN_CONT "%d->", shot->index);
+ }
+
+ printk(KERN_CONT "X\n");
+}
+
+int fimc_is_frame_s_request_shot(struct fimc_is_framemgr *this,
+ struct fimc_is_frame_shot *item)
+{
+ int ret = 0;
+
+ if (item) {
+ list_add_tail(&item->list, &this->frame_request_head);
+ this->frame_request_cnt++;
+
+ item->state = FIMC_IS_FRAME_STATE_REQUEST;
+
+#ifdef TRACE_FRAME
+ fimc_is_frame_print_request_list(this);
+#endif
+ } else {
+ ret = -EFAULT;
+ err("item is null ptr\n");
+ }
+
+ return ret;
+}
+
+int fimc_is_frame_g_request_shot(struct fimc_is_framemgr *this,
+ struct fimc_is_frame_shot **item)
+{
+ int ret = 0;
+
+ if (item) {
+ if (this->frame_request_cnt) {
+ *item = container_of(this->frame_request_head.next,
+ struct fimc_is_frame_shot, list);
+ list_del(&(*item)->list);
+ this->frame_request_cnt--;
+
+ (*item)->state = FIMC_IS_FRAME_STATE_INVALID;
+ } else {
+ *item = NULL;
+ }
+ } else {
+ ret = -EFAULT;
+ err("item is null ptr\n");
+ }
+
+ return ret;
+}
+
+void fimc_is_frame_request_head(struct fimc_is_framemgr *this,
+ struct fimc_is_frame_shot **item)
+{
+ if (this->frame_request_cnt)
+ *item = container_of(this->frame_request_head.next,
+ struct fimc_is_frame_shot, list);
+ else
+ *item = NULL;
+}
+
+void fimc_is_frame_print_request_list(struct fimc_is_framemgr *this)
+{
+ struct list_head *temp;
+ struct fimc_is_frame_shot *shot;
+
+ if (!(TRACE_ID & this->id))
+ return;
+
+ printk(KERN_CONT "[FRM] req(%d, %d) :",
+ this->id, this->frame_request_cnt);
+
+ list_for_each(temp, &this->frame_request_head) {
+ shot = list_entry(temp, struct fimc_is_frame_shot, list);
+ printk(KERN_CONT "%d->", shot->index);
+ }
+
+ printk(KERN_CONT "X\n");
+}
+
+int fimc_is_frame_s_process_shot(struct fimc_is_framemgr *this,
+ struct fimc_is_frame_shot *item)
+{
+ int ret = 0;
+
+ if (item) {
+ list_add_tail(&item->list, &this->frame_process_head);
+ this->frame_process_cnt++;
+
+ item->state = FIMC_IS_FRAME_STATE_PROCESS;
+
+#ifdef TRACE_FRAME
+ fimc_is_frame_print_process_list(this);
+#endif
+ } else {
+ ret = -EFAULT;
+ err("item is null ptr\n");
+ }
+
+ return ret;
+}
+
+int fimc_is_frame_g_process_shot(struct fimc_is_framemgr *this,
+ struct fimc_is_frame_shot **item)
+{
+ int ret = 0;
+
+ if (item) {
+ if (this->frame_process_cnt) {
+ *item = container_of(this->frame_process_head.next,
+ struct fimc_is_frame_shot, list);
+ list_del(&(*item)->list);
+ this->frame_process_cnt--;
+
+ (*item)->state = FIMC_IS_FRAME_STATE_INVALID;
+ } else {
+ *item = NULL;
+ }
+ } else {
+ ret = -EFAULT;
+ err("item is null ptr\n");
+ }
+
+ return ret;
+}
+
+void fimc_is_frame_process_head(struct fimc_is_framemgr *this,
+ struct fimc_is_frame_shot **item)
+{
+ if (this->frame_process_cnt)
+ *item = container_of(this->frame_process_head.next,
+ struct fimc_is_frame_shot, list);
+ else
+ *item = NULL;
+}
+
+void fimc_is_frame_print_process_list(struct fimc_is_framemgr *this)
+{
+ struct list_head *temp;
+ struct fimc_is_frame_shot *shot;
+
+ if (!(TRACE_ID & this->id))
+ return;
+
+ printk(KERN_CONT "[FRM] pro(%d, %d) :",
+ this->id, this->frame_process_cnt);
+
+ list_for_each(temp, &this->frame_process_head) {
+ shot = list_entry(temp, struct fimc_is_frame_shot, list);
+ printk(KERN_CONT "%d(%d)->", shot->index, shot->fcount);
+ }
+
+ printk(KERN_CONT "X\n");
+}
+
+int fimc_is_frame_s_complete_shot(struct fimc_is_framemgr *this,
+ struct fimc_is_frame_shot *item)
+{
+ int ret = 0;
+
+ if (item) {
+ list_add_tail(&item->list, &this->frame_complete_head);
+ this->frame_complete_cnt++;
+
+ item->state = FIMC_IS_FRAME_STATE_COMPLETE;
+
+#ifdef TRACE_FRAME
+ fimc_is_frame_print_complete_list(this);
+#endif
+ } else {
+ ret = -EFAULT;
+ err("item is null ptr\n");
+ }
+
+ return ret;
+}
+
+
+int fimc_is_frame_g_complete_shot(struct fimc_is_framemgr *this,
+ struct fimc_is_frame_shot **item)
+{
+ int ret = 0;
+
+ if (item) {
+ if (this->frame_complete_cnt) {
+ *item = container_of(this->frame_complete_head.next,
+ struct fimc_is_frame_shot, list);
+ list_del(&(*item)->list);
+ this->frame_complete_cnt--;
+
+ (*item)->state = FIMC_IS_FRAME_STATE_INVALID;
+ } else {
+ *item = NULL;
+ }
+ } else {
+ ret = -EFAULT;
+ err("item is null ptr\n");
+ }
+
+ return ret;
+}
+
+void fimc_is_frame_complete_head(struct fimc_is_framemgr *this,
+ struct fimc_is_frame_shot **item)
+{
+ if (this->frame_complete_cnt)
+ *item = container_of(this->frame_complete_head.next,
+ struct fimc_is_frame_shot, list);
+ else
+ *item = NULL;
+}
+
+void fimc_is_frame_print_complete_list(struct fimc_is_framemgr *this)
+{
+ struct list_head *temp;
+ struct fimc_is_frame_shot *shot;
+
+ if (!(TRACE_ID & this->id))
+ return;
+
+ printk(KERN_CONT "[FRM] com(%d, %d) :",
+ this->id, this->frame_complete_cnt);
+
+ list_for_each(temp, &this->frame_complete_head) {
+ shot = list_entry(temp, struct fimc_is_frame_shot, list);
+ printk(KERN_CONT "%d->", shot->index);
+ }
+
+ printk(KERN_CONT "X\n");
+}
+
+int fimc_is_frame_trans_fre_to_req(struct fimc_is_framemgr *this,
+ struct fimc_is_frame_shot *item)
+{
+ int ret = 0;
+
+ if (!this->frame_free_cnt) {
+ err("shot free count is zero\n");
+ ret = -EFAULT;
+ goto exit;
+ }
+
+ list_del(&item->list);
+ this->frame_free_cnt--;
+
+ fimc_is_frame_s_request_shot(this, item);
+
+exit:
+ return ret;
+}
+
+int fimc_is_frame_trans_req_to_pro(struct fimc_is_framemgr *this,
+ struct fimc_is_frame_shot *item)
+{
+ int ret = 0;
+
+ if (!this->frame_request_cnt) {
+ err("shot request count is zero\n");
+ ret = -EFAULT;
+ goto exit;
+ }
+
+ list_del(&item->list);
+ this->frame_request_cnt--;
+
+ fimc_is_frame_s_process_shot(this, item);
+
+exit:
+ return ret;
+}
+
+int fimc_is_frame_trans_req_to_com(struct fimc_is_framemgr *this,
+ struct fimc_is_frame_shot *item)
+{
+ int ret = 0;
+
+ if (!this->frame_request_cnt) {
+ err("shot request count is zero\n");
+ ret = -EFAULT;
+ goto exit;
+ }
+
+ list_del(&item->list);
+ this->frame_request_cnt--;
+
+ fimc_is_frame_s_complete_shot(this, item);
+
+exit:
+ return ret;
+}
+
+int fimc_is_frame_trans_req_to_fre(struct fimc_is_framemgr *this,
+ struct fimc_is_frame_shot *item)
+{
+ int ret = 0;
+
+ if (!this->frame_request_cnt) {
+ err("shot request count is zero\n");
+ ret = -EFAULT;
+ goto exit;
+ }
+
+ list_del(&item->list);
+ this->frame_request_cnt--;
+
+ fimc_is_frame_s_free_shot(this, item);
+
+exit:
+ return ret;
+}
+
+int fimc_is_frame_trans_pro_to_com(struct fimc_is_framemgr *this,
+ struct fimc_is_frame_shot *item)
+{
+ int ret = 0;
+
+ if (!this->frame_process_cnt) {
+ err("shot process count is zero\n");
+ ret = -EFAULT;
+ goto exit;
+ }
+
+ list_del(&item->list);
+ this->frame_process_cnt--;
+
+ fimc_is_frame_s_complete_shot(this, item);
+
+exit:
+ return ret;
+}
+
+int fimc_is_frame_trans_pro_to_fre(struct fimc_is_framemgr *this,
+ struct fimc_is_frame_shot *item)
+{
+ int ret = 0;
+
+ if (!this->frame_process_cnt) {
+ err("shot process count is zero\n");
+ ret = -EFAULT;
+ goto exit;
+ }
+
+ list_del(&item->list);
+ this->frame_process_cnt--;
+
+ fimc_is_frame_s_free_shot(this, item);
+
+exit:
+ return ret;
+}
+
+int fimc_is_frame_trans_fre_to_com(struct fimc_is_framemgr *this,
+ struct fimc_is_frame_shot *item)
+{
+ int ret = 0;
+
+ if (!this->frame_free_cnt) {
+ err("shot free count is zero\n");
+ ret = -EFAULT;
+ goto exit;
+ }
+
+ list_del(&item->list);
+ this->frame_free_cnt--;
+
+ fimc_is_frame_s_complete_shot(this, item);
+
+exit:
+ return ret;
+}
+
+int fimc_is_frame_trans_com_to_fre(struct fimc_is_framemgr *this,
+ struct fimc_is_frame_shot *item)
+{
+ int ret = 0;
+
+ if (!this->frame_complete_cnt) {
+ err("shot complete count is zero\n");
+ ret = -EFAULT;
+ goto exit;
+ }
+
+ list_del(&item->list);
+ this->frame_complete_cnt--;
+
+ fimc_is_frame_s_free_shot(this, item);
+
+exit:
+ return ret;
+}
+
+int fimc_is_frame_probe(struct fimc_is_framemgr *this, u32 id)
+{
+ int ret = 0;
+ u32 i;
+
+ this->id = id;
+
+ for (i = 0; i < FRAMEMGR_MAX_REQUEST; ++i) {
+ this->frame[i].init = FRAME_UNI_MEM;
+ this->frame[i].state = FIMC_IS_FRAME_STATE_INVALID;
+ }
+
+ return ret;
+}
+
+int fimc_is_frame_open(struct fimc_is_framemgr *this, u32 buffers)
+{
+ int ret = 0;
+ u32 i, j;
+
+ spin_lock_init(&this->slock);
+
+ INIT_LIST_HEAD(&this->frame_free_head);
+ INIT_LIST_HEAD(&this->frame_request_head);
+ INIT_LIST_HEAD(&this->frame_process_head);
+ INIT_LIST_HEAD(&this->frame_complete_head);
+
+ this->frame_cnt = buffers;
+ this->frame_free_cnt = 0;
+ this->frame_request_cnt = 0;
+ this->frame_process_cnt = 0;
+ this->frame_complete_cnt = 0;
+
+ for (i = 0; i < buffers; ++i) {
+ this->frame[i].init = FRAME_UNI_MEM;
+ this->frame[i].scp_out = FIMC_IS_FOUT_NONE;
+ this->frame[i].scc_out = FIMC_IS_FOUT_NONE;
+ this->frame[i].index = i;
+ this->frame[i].fcount = 0;
+ this->frame[i].req_flag = 0;
+
+ this->frame[i].vb = NULL;
+ this->frame[i].shot = NULL;
+ this->frame[i].shot_ext = NULL;
+ this->frame[i].shot_size = 0;
+
+ this->frame[i].stream = NULL;
+ this->frame[i].stream_size = 0;
+
+ this->frame[i].planes = 0;
+ for (j = 0; j < FIMC_IS_MAX_PLANES; ++j) {
+ this->frame[i].kvaddr_buffer[j] = 0;
+ this->frame[i].dvaddr_buffer[j] = 0;
+ }
+
+ this->frame[i].kvaddr_shot = 0;
+ this->frame[i].dvaddr_shot = 0;
+ fimc_is_frame_s_free_shot(this, &this->frame[i]);
+ }
+
+ fimc_is_frame_print_free_list(this);
+
+ return ret;
+}
+
+int fimc_is_frame_close(struct fimc_is_framemgr *this)
+{
+ int ret = 0;
+ u32 buffers;
+ u32 i, j;
+
+ buffers = this->frame_cnt;
+
+ for (i = 0; i < buffers; ++i) {
+ this->frame[i].init = FRAME_UNI_MEM;
+ this->frame[i].index = i;
+ this->frame[i].fcount = 0;
+ this->frame[i].req_flag = 0;
+
+ this->frame[i].vb = NULL;
+ this->frame[i].shot = NULL;
+ this->frame[i].shot_ext = NULL;
+ this->frame[i].shot_size = 0;
+
+ this->frame[i].stream = NULL;
+ this->frame[i].stream_size = 0;
+
+ this->frame[i].planes = 0;
+ for (j = 0; j < FIMC_IS_MAX_PLANES; ++j) {
+ this->frame[i].kvaddr_buffer[j] = 0;
+ this->frame[i].dvaddr_buffer[j] = 0;
+ }
+
+ this->frame[i].kvaddr_shot = 0;
+ this->frame[i].dvaddr_shot = 0;
+ }
+
+ return ret;
+}
+
+void fimc_is_frame_print_all(struct fimc_is_framemgr *this)
+{
+ fimc_is_frame_print_free_list(this);
+ fimc_is_frame_print_request_list(this);
+ fimc_is_frame_print_process_list(this);
+ fimc_is_frame_print_complete_list(this);
+}
diff --git a/drivers/media/video/exynos/fimc-is-mc2/fimc-is-framemgr.h b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-framemgr.h
new file mode 100644
index 0000000..53290a3
--- /dev/null
+++ b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-framemgr.h
@@ -0,0 +1,208 @@
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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.
+ */
+
+#ifndef FIMC_IS_FRAME_MGR_H
+#define FIMC_IS_FRAME_MGR_H
+
+#define FRAMEMGR_ID_SENSOR 0x100 /*256*/
+#define FRAMEMGR_ID_ISP 0x200 /*512*/
+#define FRAMEMGR_ID_SCC 0x400
+#define FRAMEMGR_ID_SCP 0x800
+
+/*#define TRACE_FRAME*/
+/*#define TRACE_ID (0xF00)*/
+#define TRACE_ID (0x0)
+
+#define FRAMEMGR_MAX_REQUEST 20
+
+/*flite frame start tasklet*/
+#define FMGR_IDX_0 (0x10)
+/*flite frame end tasklet*/
+#define FMGR_IDX_1 (0x20)
+/*sensor queue*/
+#define FMGR_IDX_2 (0x30)
+/*sensor dequeue*/
+#define FMGR_IDX_3 (0x40)
+/*dev framedone*/
+#define FMGR_IDX_4 (0x50)
+/*scc framedone*/
+#define FMGR_IDX_5 (0x60)
+/*scp framedone*/
+#define FMGR_IDX_6 (0x70)
+/*isp framedone*/
+#define FMGR_IDX_7 (0x80)
+/*scc callback*/
+#define FMGR_IDX_8 (0x90)
+/*scp callback*/
+#define FMGR_IDX_9 (0xA0)
+
+#define framemgr_e_barrier_irqs(this, index, flag) \
+ spin_lock_irqsave(&this->slock, flag)
+#define framemgr_x_barrier_irqr(this, index, flag) \
+ spin_unlock_irqrestore(&this->slock, flag)
+#define framemgr_e_barrier_irq(this, index) \
+ spin_lock_irq(&this->slock)
+#define framemgr_x_barrier_irq(this, index) \
+ spin_unlock_irq(&this->slock)
+#define framemgr_e_barrier(this, index) \
+ spin_lock(&this->slock)
+#define framemgr_x_barrier(this, index) \
+ spin_unlock(&this->slock)
+
+enum fimc_is_frame_output {
+ FIMC_IS_FOUT_NONE,
+ FIMC_IS_FOUT_REQ,
+ FIMC_IS_FOUT_DONE,
+};
+
+enum fimc_is_frame_shot_state {
+ FIMC_IS_FRAME_STATE_FREE,
+ FIMC_IS_FRAME_STATE_REQUEST,
+ FIMC_IS_FRAME_STATE_PROCESS,
+ FIMC_IS_FRAME_STATE_COMPLETE,
+ FIMC_IS_FRAME_STATE_INVALID
+};
+
+enum fimc_is_frame_reqeust {
+ /* SCC, SCP frame done,
+ ISP meta done */
+ REQ_FRAME,
+ /* ISP shot done */
+ REQ_SHOT
+};
+
+enum fimc_is_frame_init {
+ /* uninitialized memory */
+ FRAME_UNI_MEM,
+ /* initialized memory */
+ FRAME_INI_MEM,
+ /* configured memory */
+ FRAME_CFG_MEM
+};
+
+struct fimc_is_frame_shot {
+ struct list_head list;
+
+ /* sensor and isp use */
+ enum fimc_is_frame_init init;
+ struct camera2_shot *shot;
+ struct camera2_shot_ext *shot_ext;
+ u32 kvaddr_shot;
+ u32 dvaddr_shot;
+ u32 cookie_shot;
+ u32 shot_size;
+
+ /* stream use */
+ struct camera2_stream *stream;
+ u32 stream_size;
+
+ /* common use */
+ u32 planes;
+ u32 kvaddr_buffer[4];
+ u32 dvaddr_buffer[4];
+
+ /* time measure */
+ struct timeval *tzone;
+
+ /* internal use */
+ u32 state;
+ u32 fcount;
+ u32 index;
+ unsigned long req_flag;
+ struct vb2_buffer *vb;
+
+ enum fimc_is_frame_output scc_out;
+ enum fimc_is_frame_output scp_out;
+
+ /* time measure internally */
+ struct timeval time_queued;
+ struct timeval time_shot;
+ struct timeval time_shotdone;
+ struct timeval time_dequeued;
+};
+
+struct fimc_is_framemgr {
+ struct fimc_is_frame_shot frame[FRAMEMGR_MAX_REQUEST];
+
+ struct list_head frame_free_head;
+ struct list_head frame_request_head;
+ struct list_head frame_process_head;
+ struct list_head frame_complete_head;
+
+ spinlock_t slock;
+
+ u32 frame_cnt;
+ u32 frame_free_cnt;
+ u32 frame_request_cnt;
+ u32 frame_process_cnt;
+ u32 frame_complete_cnt;
+
+ unsigned long output_image_flag;
+ u32 output_image_cnt;
+
+ u32 id;
+};
+
+int fimc_is_frame_probe(struct fimc_is_framemgr *this, u32 id);
+int fimc_is_frame_open(struct fimc_is_framemgr *this, u32 buffers);
+int fimc_is_frame_close(struct fimc_is_framemgr *this);
+void fimc_is_frame_print_all(struct fimc_is_framemgr *this);
+
+int fimc_is_frame_s_free_shot(struct fimc_is_framemgr *this,
+ struct fimc_is_frame_shot *frame);
+int fimc_is_frame_g_free_shot(struct fimc_is_framemgr *this,
+ struct fimc_is_frame_shot **frame);
+void fimc_is_frame_free_head(struct fimc_is_framemgr *this,
+ struct fimc_is_frame_shot **frame);
+void fimc_is_frame_print_free_list(struct fimc_is_framemgr *this);
+
+int fimc_is_frame_s_request_shot(struct fimc_is_framemgr *this,
+ struct fimc_is_frame_shot *frame);
+int fimc_is_frame_g_request_shot(struct fimc_is_framemgr *this,
+ struct fimc_is_frame_shot **frame);
+void fimc_is_frame_request_head(struct fimc_is_framemgr *this,
+ struct fimc_is_frame_shot **frame);
+void fimc_is_frame_print_request_list(struct fimc_is_framemgr *this);
+
+int fimc_is_frame_s_process_shot(struct fimc_is_framemgr *this,
+ struct fimc_is_frame_shot *frame);
+int fimc_is_frame_g_process_shot(struct fimc_is_framemgr *this,
+ struct fimc_is_frame_shot **frame);
+void fimc_is_frame_process_head(struct fimc_is_framemgr *this,
+ struct fimc_is_frame_shot **frame);
+void fimc_is_frame_print_process_list(struct fimc_is_framemgr *this);
+
+int fimc_is_frame_s_complete_shot(struct fimc_is_framemgr *this,
+ struct fimc_is_frame_shot *frame);
+int fimc_is_frame_g_complete_shot(struct fimc_is_framemgr *this,
+ struct fimc_is_frame_shot **frame);
+void fimc_is_frame_complete_head(struct fimc_is_framemgr *this,
+ struct fimc_is_frame_shot **frame);
+void fimc_is_frame_print_complete_list(struct fimc_is_framemgr *this);
+
+int fimc_is_frame_trans_fre_to_req(struct fimc_is_framemgr *this,
+ struct fimc_is_frame_shot *frame);
+int fimc_is_frame_trans_fre_to_com(struct fimc_is_framemgr *this,
+ struct fimc_is_frame_shot *frame);
+int fimc_is_frame_trans_req_to_pro(struct fimc_is_framemgr *this,
+ struct fimc_is_frame_shot *frame);
+int fimc_is_frame_trans_req_to_com(struct fimc_is_framemgr *this,
+ struct fimc_is_frame_shot *frame);
+int fimc_is_frame_trans_req_to_fre(struct fimc_is_framemgr *this,
+ struct fimc_is_frame_shot *item);
+int fimc_is_frame_trans_pro_to_com(struct fimc_is_framemgr *this,
+ struct fimc_is_frame_shot *frame);
+int fimc_is_frame_trans_pro_to_fre(struct fimc_is_framemgr *this,
+ struct fimc_is_frame_shot *frame);
+int fimc_is_frame_trans_com_to_fre(struct fimc_is_framemgr *this,
+ struct fimc_is_frame_shot *frame);
+
+#endif
diff --git a/drivers/media/video/exynos/fimc-is-mc2/fimc-is-interface.c b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-interface.c
new file mode 100644
index 0000000..5223e82
--- /dev/null
+++ b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-interface.c
@@ -0,0 +1,1839 @@
+#include <linux/workqueue.h>
+
+#include "fimc-is-time.h"
+#include "fimc-is-core.h"
+#include "fimc-is-cmd.h"
+#include "fimc-is-regs.h"
+#include "fimc-is-err.h"
+
+#include "fimc-is-interface.h"
+
+u32 __iomem *notify_fcount;
+
+#define init_request_barrier(itf) mutex_init(&itf->request_barrier)
+#define enter_request_barrier(itf) mutex_lock(&itf->request_barrier);
+#define exit_request_barrier(itf) mutex_unlock(&itf->request_barrier);
+#define init_process_barrier(itf) spin_lock_init(&itf->process_barrier);
+#define enter_process_barrier(itf) spin_lock_irq(&itf->process_barrier);
+#define exit_process_barrier(itf) spin_unlock_irq(&itf->process_barrier);
+
+int print_fre_work_list(struct fimc_is_work_list *this)
+{
+ struct list_head *temp;
+ struct fimc_is_work *work;
+
+ if (!(this->id & TRACE_WORK_ID_MASK))
+ return 0;
+
+ printk(KERN_CONT "[INF] fre(%02X, %02d) :",
+ this->id, this->work_free_cnt);
+
+ list_for_each(temp, &this->work_free_head) {
+ work = list_entry(temp, struct fimc_is_work, list);
+ printk(KERN_CONT "%X(%d)->", work->msg.command, work->fcount);
+ }
+
+ printk(KERN_CONT "X\n");
+
+ return 0;
+}
+
+static int set_free_work(struct fimc_is_work_list *this,
+ struct fimc_is_work *work)
+{
+ int ret = 0;
+ unsigned long flags;
+
+ if (work) {
+ spin_lock_irqsave(&this->slock_free, flags);
+
+ list_add_tail(&work->list, &this->work_free_head);
+ this->work_free_cnt++;
+#ifdef TRACE_WORK
+ print_fre_work_list(this);
+#endif
+
+ spin_unlock_irqrestore(&this->slock_free, flags);
+ } else {
+ ret = -EFAULT;
+ err("item is null ptr\n");
+ }
+
+ return ret;
+}
+
+static int get_free_work(struct fimc_is_work_list *this,
+ struct fimc_is_work **work)
+{
+ int ret = 0;
+ unsigned long flags;
+
+ if (work) {
+ spin_lock_irqsave(&this->slock_free, flags);
+
+ if (this->work_free_cnt) {
+ *work = container_of(this->work_free_head.next,
+ struct fimc_is_work, list);
+ list_del(&(*work)->list);
+ this->work_free_cnt--;
+ } else
+ *work = NULL;
+
+ spin_unlock_irqrestore(&this->slock_free, flags);
+ } else {
+ ret = EFAULT;
+ err("item is null ptr");
+ }
+
+ return ret;
+}
+
+static int get_free_work_irq(struct fimc_is_work_list *this,
+ struct fimc_is_work **work)
+{
+ int ret = 0;
+
+ if (work) {
+ spin_lock(&this->slock_free);
+
+ if (this->work_free_cnt) {
+ *work = container_of(this->work_free_head.next,
+ struct fimc_is_work, list);
+ list_del(&(*work)->list);
+ this->work_free_cnt--;
+ } else
+ *work = NULL;
+
+ spin_unlock(&this->slock_free);
+ } else {
+ ret = EFAULT;
+ err("item is null ptr");
+ }
+
+ return ret;
+}
+
+int print_req_work_list(struct fimc_is_work_list *this)
+{
+ struct list_head *temp;
+ struct fimc_is_work *work;
+
+ if (!(this->id & TRACE_WORK_ID_MASK))
+ return 0;
+
+ printk(KERN_CONT "[INF] req(%02X, %02d) :",
+ this->id, this->work_request_cnt);
+
+ list_for_each(temp, &this->work_request_head) {
+ work = list_entry(temp, struct fimc_is_work, list);
+ printk(KERN_CONT "%X(%d)->", work->msg.command, work->fcount);
+ }
+
+ printk(KERN_CONT "X\n");
+
+ return 0;
+}
+
+static int set_req_work(struct fimc_is_work_list *this,
+ struct fimc_is_work *work)
+{
+ int ret = 0;
+ unsigned long flags;
+
+ if (work) {
+ spin_lock_irqsave(&this->slock_request, flags);
+
+ list_add_tail(&work->list, &this->work_request_head);
+ this->work_request_cnt++;
+#ifdef TRACE_WORK
+ print_req_work_list(this);
+#endif
+
+ spin_unlock_irqrestore(&this->slock_request, flags);
+ } else {
+ ret = EFAULT;
+ err("item is null ptr\n");
+ }
+
+ return ret;
+}
+
+static int set_req_work_irq(struct fimc_is_work_list *this,
+ struct fimc_is_work *work)
+{
+ int ret = 0;
+
+ if (work) {
+ spin_lock(&this->slock_request);
+
+ list_add_tail(&work->list, &this->work_request_head);
+ this->work_request_cnt++;
+#ifdef TRACE_WORK
+ print_req_work_list(this);
+#endif
+
+ spin_unlock(&this->slock_request);
+ } else {
+ ret = EFAULT;
+ err("item is null ptr\n");
+ }
+
+ return ret;
+}
+
+static int get_req_work(struct fimc_is_work_list *this,
+ struct fimc_is_work **work)
+{
+ int ret = 0;
+ unsigned long flags;
+
+ if (work) {
+ spin_lock_irqsave(&this->slock_request, flags);
+
+ if (this->work_request_cnt) {
+ *work = container_of(this->work_request_head.next,
+ struct fimc_is_work, list);
+ list_del(&(*work)->list);
+ this->work_request_cnt--;
+ } else
+ *work = NULL;
+
+ spin_unlock_irqrestore(&this->slock_request, flags);
+ } else {
+ ret = EFAULT;
+ err("item is null ptr\n");
+ }
+
+ return ret;
+}
+
+static void init_work_list(struct fimc_is_work_list *this, u32 id, u32 count)
+{
+ u32 i;
+
+ this->id = id;
+ this->work_free_cnt = 0;
+ this->work_request_cnt = 0;
+ INIT_LIST_HEAD(&this->work_free_head);
+ INIT_LIST_HEAD(&this->work_request_head);
+ spin_lock_init(&this->slock_free);
+ spin_lock_init(&this->slock_request);
+ for (i = 0; i < count; ++i)
+ set_free_work(this, &this->work[i]);
+
+ init_waitqueue_head(&this->wait_queue);
+}
+
+static void set_state(struct fimc_is_interface *this,
+ unsigned long state)
+{
+ spin_lock(&this->slock_state);
+ set_bit(state, &this->state);
+ spin_unlock(&this->slock_state);
+}
+
+static void clr_state(struct fimc_is_interface *this,
+ unsigned long state)
+{
+ spin_lock(&this->slock_state);
+ clear_bit(state, &this->state);
+ spin_unlock(&this->slock_state);
+}
+
+static int test_state(struct fimc_is_interface *this,
+ unsigned long state)
+{
+ int ret = 0;
+
+ spin_lock(&this->slock_state);
+ ret = test_bit(state, &this->state);
+ spin_unlock(&this->slock_state);
+
+ return ret;
+}
+
+static int wait_idlestate(struct fimc_is_interface *this)
+{
+ int ret = 0;
+
+ ret = wait_event_timeout(this->wait_queue,
+ !test_state(this, IS_IF_STATE_BUSY), FIMC_IS_COMMAND_TIMEOUT);
+
+ if (ret)
+ ret = 0;
+ else {
+ err("timeout");
+ ret = -ETIME;
+ }
+
+ return ret;
+}
+
+static int wait_initstate(struct fimc_is_interface *this)
+{
+ int ret = 0;
+
+ ret = wait_event_timeout(this->init_wait_queue,
+ test_state(this, IS_IF_STATE_START), FIMC_IS_STARTUP_TIMEOUT);
+
+ if (ret)
+ ret = 0;
+ else {
+ err("timeout");
+ ret = -ETIME;
+ }
+
+ return ret;
+}
+
+static int testnset_state(struct fimc_is_interface *this,
+ unsigned long state)
+{
+ int ret = 0;
+
+ spin_lock(&this->slock_state);
+
+ if (test_bit(state, &this->state)) {
+ ret = -EINVAL;
+ goto exit;
+ }
+ set_bit(state, &this->state);
+
+exit:
+ spin_unlock(&this->slock_state);
+ return ret;
+}
+
+static int testnclr_state(struct fimc_is_interface *this,
+ unsigned long state)
+{
+ int ret = 0;
+
+ spin_lock(&this->slock_state);
+
+ if (!test_bit(state, &this->state)) {
+ ret = -EINVAL;
+ goto exit;
+ }
+ clear_bit(state, &this->state);
+
+exit:
+ spin_unlock(&this->slock_state);
+ return ret;
+}
+
+static void testnclr_wakeup(struct fimc_is_interface *this)
+{
+ int ret = 0;
+
+ ret = testnclr_state(this, IS_IF_STATE_BUSY);
+ if (ret)
+ err("current state is not invalid(%ld)", this->state);
+ else
+ wake_up(&this->wait_queue);
+}
+
+static int waiting_is_ready(struct fimc_is_interface *interface)
+{
+ int ret = 0;
+ u32 try_count = TRY_RECV_AWARE_COUNT;
+ u32 cfg = readl(interface->regs + INTMSR0);
+ u32 status = INTMSR0_GET_INTMSD0(cfg);
+
+ while (status) {
+ cfg = readl(interface->regs + INTMSR0);
+ status = INTMSR0_GET_INTMSD0(cfg);
+
+ if (try_count-- == 0) {
+ try_count = TRY_RECV_AWARE_COUNT;
+ err("INTMSR0's 0 bit is not cleared.");
+ ret = -EINVAL;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static void send_interrupt(struct fimc_is_interface *interface)
+{
+ writel(INTGR0_INTGD0, interface->regs + INTGR0);
+}
+
+static int fimc_is_set_cmd(struct fimc_is_interface *itf,
+ struct fimc_is_msg *msg)
+{
+ int ret = 0;
+ bool block_io, send_cmd;
+
+ dbg_interface("TP#1\n");
+ enter_request_barrier(itf);
+ dbg_interface("TP#2\n");
+
+ switch (msg->command) {
+ case HIC_STREAM_ON:
+ if (itf->streaming == IS_IF_STREAMING_ON) {
+ send_cmd = false;
+ } else {
+ send_cmd = true;
+ block_io = true;
+ }
+ break;
+ case HIC_STREAM_OFF:
+ if (itf->streaming == IS_IF_STREAMING_OFF) {
+ send_cmd = false;
+ } else {
+ send_cmd = true;
+ block_io = true;
+ }
+ break;
+ case HIC_PROCESS_START:
+ if (itf->processing == IS_IF_PROCESSING_ON) {
+ send_cmd = false;
+ } else {
+ send_cmd = true;
+ block_io = true;
+ }
+ break;
+ case HIC_PROCESS_STOP:
+ if (itf->processing == IS_IF_PROCESSING_OFF) {
+ send_cmd = false;
+ } else {
+ send_cmd = true;
+ block_io = true;
+ }
+ break;
+ case HIC_POWER_DOWN:
+ if (itf->pdown_ready == IS_IF_POWER_DOWN_READY) {
+ send_cmd = false;
+ } else {
+ send_cmd = true;
+ block_io = true;
+ }
+ break;
+ case HIC_OPEN_SENSOR:
+ case HIC_GET_SET_FILE_ADDR:
+ case HIC_SET_PARAMETER:
+ case HIC_PREVIEW_STILL:
+ case HIC_GET_STATIC_METADATA:
+ case HIC_SET_A5_MEM_ACCESS:
+ case HIC_SET_CAM_CONTROL:
+ send_cmd = true;
+ block_io = true;
+ break;
+ case HIC_SHOT:
+ case ISR_DONE:
+ send_cmd = true;
+ block_io = false;
+ break;
+ default:
+ send_cmd = true;
+ block_io = true;
+ break;
+ }
+
+ if (!send_cmd) {
+ dbg_interface("skipped\n");
+ goto exit;
+ }
+
+ enter_process_barrier(itf);
+
+ ret = waiting_is_ready(itf);
+ if (ret) {
+ err("waiting for ready is fail");
+ ret = -EBUSY;
+ exit_process_barrier(itf);
+ goto exit;
+ }
+
+ set_state(itf, IS_IF_STATE_BUSY);
+ itf->com_regs->hicmd = msg->command;
+ itf->com_regs->hic_sensorid = msg->instance;
+ itf->com_regs->hic_param1 = msg->parameter1;
+ itf->com_regs->hic_param2 = msg->parameter2;
+ itf->com_regs->hic_param3 = msg->parameter3;
+ itf->com_regs->hic_param4 = msg->parameter4;
+ send_interrupt(itf);
+
+ exit_process_barrier(itf);
+
+ if (!block_io)
+ goto exit;
+
+ ret = wait_idlestate(itf);
+ if (ret) {
+ err("%d command is timeout", msg->command);
+ clr_state(itf, IS_IF_STATE_BUSY);
+ ret = -ETIME;
+ goto exit;
+ }
+
+ if (itf->reply.command == ISR_DONE) {
+ switch (msg->command) {
+ case HIC_STREAM_ON:
+ itf->streaming = IS_IF_STREAMING_ON;
+ break;
+ case HIC_STREAM_OFF:
+ itf->streaming = IS_IF_STREAMING_OFF;
+ break;
+ case HIC_PROCESS_START:
+ itf->processing = IS_IF_PROCESSING_ON;
+ break;
+ case HIC_PROCESS_STOP:
+ itf->processing = IS_IF_PROCESSING_OFF;
+ break;
+ case HIC_POWER_DOWN:
+ itf->pdown_ready = IS_IF_POWER_DOWN_READY;
+ break;
+ case HIC_OPEN_SENSOR:
+ if (itf->reply.parameter1 == HIC_POWER_DOWN) {
+ err("firmware power down");
+ itf->pdown_ready = IS_IF_POWER_DOWN_READY;
+ ret = -ECANCELED;
+ goto exit;
+ } else
+ itf->pdown_ready = IS_IF_POWER_DOWN_NREADY;
+ break;
+ default:
+ break;
+ }
+ } else {
+ err("ISR_NDONE is occured");
+ ret = -EINVAL;
+ }
+
+exit:
+ exit_request_barrier(itf);
+
+ if (ret)
+ fimc_is_hw_print(itf);
+
+ return ret;
+}
+
+static int fimc_is_set_cmd_shot(struct fimc_is_interface *this,
+ struct fimc_is_msg *msg)
+{
+ int ret = 0;
+
+ enter_process_barrier(this);
+
+ ret = waiting_is_ready(this);
+ if (ret) {
+ err("waiting for ready is fail");
+ ret = -EBUSY;
+ goto exit;
+ }
+
+ this->com_regs->hicmd = msg->command;
+ this->com_regs->hic_sensorid = msg->instance;
+ this->com_regs->hic_param1 = msg->parameter1;
+ this->com_regs->hic_param2 = msg->parameter2;
+ this->com_regs->hic_param3 = msg->parameter3;
+ this->com_regs->hic_param4 = msg->parameter4;
+ send_interrupt(this);
+
+exit:
+ exit_process_barrier(this);
+ return ret;
+}
+
+static int fimc_is_set_cmd_nblk(struct fimc_is_interface *this,
+ struct fimc_is_work *work)
+{
+ int ret = 0;
+ struct fimc_is_msg *msg;
+
+ msg = &work->msg;
+ switch (msg->command) {
+ case HIC_SET_CAM_CONTROL:
+ set_req_work(&this->nblk_cam_ctrl, work);
+ break;
+ default:
+ err("unresolved command\n");
+ break;
+ }
+
+ enter_process_barrier(this);
+
+ ret = waiting_is_ready(this);
+ if (ret) {
+ err("waiting for ready is fail");
+ ret = -EBUSY;
+ goto exit;
+ }
+
+ this->com_regs->hicmd = msg->command;
+ this->com_regs->hic_sensorid = msg->instance;
+ this->com_regs->hic_param1 = msg->parameter1;
+ this->com_regs->hic_param2 = msg->parameter2;
+ this->com_regs->hic_param3 = msg->parameter3;
+ this->com_regs->hic_param4 = msg->parameter4;
+ send_interrupt(this);
+
+exit:
+ exit_process_barrier(this);
+ return ret;
+}
+
+static inline void fimc_is_get_cmd(struct fimc_is_interface *itf,
+ struct fimc_is_msg *msg, u32 index)
+{
+ struct is_common_reg __iomem *com_regs = itf->com_regs;
+
+ switch (index) {
+ case INTR_GENERAL:
+ msg->id = 0;
+ msg->command = com_regs->ihcmd;
+ msg->instance = com_regs->ihc_sensorid;
+ msg->parameter1 = com_regs->ihc_param1;
+ msg->parameter2 = com_regs->ihc_param2;
+ msg->parameter3 = com_regs->ihc_param3;
+ msg->parameter4 = com_regs->ihc_param4;
+ break;
+ case INTR_SCC_FDONE:
+ msg->id = 0;
+ msg->command = IHC_FRAME_DONE;
+ msg->instance = com_regs->scc_sensor_id;
+ msg->parameter1 = com_regs->scc_param1;
+ msg->parameter2 = com_regs->scc_param2;
+ msg->parameter3 = com_regs->scc_param3;
+ msg->parameter4 = 0;
+ break;
+ case INTR_SCP_FDONE:
+ msg->id = 0;
+ msg->command = IHC_FRAME_DONE;
+ msg->instance = com_regs->scp_sensor_id;
+ msg->parameter1 = com_regs->scp_param1;
+ msg->parameter2 = com_regs->scp_param2;
+ msg->parameter3 = com_regs->scp_param3;
+ msg->parameter4 = 0;
+ break;
+ case INTR_META_DONE:
+ msg->id = 0;
+ msg->command = IHC_FRAME_DONE;
+ msg->instance = com_regs->meta_sensor_id;
+ msg->parameter1 = com_regs->meta_param1;
+ msg->parameter2 = 0;
+ msg->parameter3 = 0;
+ msg->parameter4 = 0;
+ break;
+ case INTR_SHOT_DONE:
+ msg->id = 0;
+ msg->command = IHC_FRAME_DONE;
+ msg->instance = com_regs->shot_sensor_id;
+ msg->parameter1 = com_regs->shot_param1;
+ msg->parameter2 = com_regs->shot_param2;
+ msg->parameter3 = 0;
+ msg->parameter4 = 0;
+ break;
+ default:
+ msg->id = 0;
+ msg->command = 0;
+ msg->instance = 0;
+ msg->parameter1 = 0;
+ msg->parameter2 = 0;
+ msg->parameter3 = 0;
+ msg->parameter4 = 0;
+ err("unknown command getting\n");
+ break;
+ }
+}
+
+static inline u32 fimc_is_get_intr(struct fimc_is_interface *itf)
+{
+ u32 status;
+ struct is_common_reg __iomem *com_regs = itf->com_regs;
+
+ status = readl(itf->regs + INTMSR1) | com_regs->ihcmd_iflag |
+ com_regs->scc_iflag |
+ com_regs->scp_iflag |
+ com_regs->meta_iflag |
+ com_regs->shot_iflag;
+
+ return status;
+}
+
+static inline void fimc_is_clr_intr(struct fimc_is_interface *itf,
+ u32 index)
+{
+ struct is_common_reg __iomem *com_regs = itf->com_regs;
+
+ switch (index) {
+ case INTR_GENERAL:
+ writel((1<<INTR_GENERAL), itf->regs + INTCR1);
+ com_regs->ihcmd_iflag = 0;
+ break;
+ case INTR_SCC_FDONE:
+ writel((1<<INTR_SCC_FDONE), itf->regs + INTCR1);
+ com_regs->scc_iflag = 0;
+ break;
+ case INTR_SCP_FDONE:
+ writel((1<<INTR_SCP_FDONE), itf->regs + INTCR1);
+ com_regs->scp_iflag = 0;
+ break;
+ case INTR_META_DONE:
+ writel((1<<INTR_META_DONE), itf->regs + INTCR1);
+ com_regs->meta_iflag = 0;
+ break;
+ case INTR_SHOT_DONE:
+ writel((1<<INTR_SHOT_DONE), itf->regs + INTCR1);
+ com_regs->shot_iflag = 0;
+ break;
+ default:
+ err("unknown command clear\n");
+ break;
+ }
+}
+
+static void wq_func_general(struct work_struct *data)
+{
+ struct fimc_is_interface *itf;
+ struct fimc_is_msg *msg;
+ struct fimc_is_work *work;
+ struct fimc_is_work *nblk_work;
+
+ itf = container_of(data, struct fimc_is_interface,
+ work_queue[INTR_GENERAL]);
+
+ get_req_work(&itf->work_list[INTR_GENERAL], &work);
+ while (work) {
+ msg = &work->msg;
+ switch (msg->command) {
+ case IHC_GET_SENSOR_NUMBER:
+ printk(KERN_INFO "IS version : %d.%d\n",
+ ISDRV_VERSION, msg->parameter1);
+ set_state(itf, IS_IF_STATE_START);
+ wake_up(&itf->init_wait_queue);
+ break;
+ case ISR_DONE:
+ switch (msg->parameter1) {
+ case HIC_OPEN_SENSOR:
+ dbg_interface("open done\n");
+ memcpy(&itf->reply, msg,
+ sizeof(struct fimc_is_msg));
+ testnclr_wakeup(itf);
+ break;
+ case HIC_GET_SET_FILE_ADDR:
+ dbg_interface("saddr(%p) done\n",
+ (void *)msg->parameter2);
+ memcpy(&itf->reply, msg,
+ sizeof(struct fimc_is_msg));
+ testnclr_wakeup(itf);
+ break;
+ case HIC_LOAD_SET_FILE:
+ dbg_interface("setfile done\n");
+ memcpy(&itf->reply, msg,
+ sizeof(struct fimc_is_msg));
+ testnclr_wakeup(itf);
+ break;
+ case HIC_SET_A5_MEM_ACCESS:
+ dbg_interface("cfgmem done\n");
+ memcpy(&itf->reply, msg,
+ sizeof(struct fimc_is_msg));
+ testnclr_wakeup(itf);
+ break;
+ case HIC_PROCESS_START:
+ dbg_interface("process_on done\n");
+ memcpy(&itf->reply, msg,
+ sizeof(struct fimc_is_msg));
+ testnclr_wakeup(itf);
+ break;
+ case HIC_PROCESS_STOP:
+ dbg_interface("process_off done\n");
+ memcpy(&itf->reply, msg,
+ sizeof(struct fimc_is_msg));
+ testnclr_wakeup(itf);
+ break;
+ case HIC_STREAM_ON:
+ dbg_interface("stream_on done\n");
+ memcpy(&itf->reply, msg,
+ sizeof(struct fimc_is_msg));
+ testnclr_wakeup(itf);
+ break;
+ case HIC_STREAM_OFF:
+ dbg_interface("stream_off done\n");
+ memcpy(&itf->reply, msg,
+ sizeof(struct fimc_is_msg));
+ testnclr_wakeup(itf);
+ break;
+ case HIC_SET_PARAMETER:
+ dbg_interface("s_param done\n");
+ memcpy(&itf->reply, msg,
+ sizeof(struct fimc_is_msg));
+ testnclr_wakeup(itf);
+ break;
+ case HIC_GET_STATIC_METADATA:
+ dbg_interface("g_capability done\n");
+ memcpy(&itf->reply, msg,
+ sizeof(struct fimc_is_msg));
+ testnclr_wakeup(itf);
+ break;
+ case HIC_PREVIEW_STILL:
+ dbg_interface("a_param(%dx%d) done\n",
+ msg->parameter2,
+ msg->parameter3);
+ memcpy(&itf->reply, msg,
+ sizeof(struct fimc_is_msg));
+ testnclr_wakeup(itf);
+ break;
+ case HIC_POWER_DOWN:
+ dbg_interface("powerdown done\n");
+ memcpy(&itf->reply, msg,
+ sizeof(struct fimc_is_msg));
+ testnclr_wakeup(itf);
+ break;
+ /*non-blocking command*/
+ case HIC_SHOT:
+ err("shot done is not acceptable\n");
+ break;
+ case HIC_SET_CAM_CONTROL:
+ /* this code will be used latter */
+#if 0
+ dbg_interface("camctrl done\n");
+ get_req_work(&itf->nblk_cam_ctrl , &nblk_work);
+ if (nblk_work) {
+ nblk_work->msg.command = ISR_DONE;
+ set_free_work(&itf->nblk_cam_ctrl,
+ nblk_work);
+ } else {
+ err("nblk camctrl request is empty");
+ print_fre_work_list(
+ &itf->nblk_cam_ctrl);
+ print_req_work_list(
+ &itf->nblk_cam_ctrl);
+ }
+#else
+ err("camctrl is not acceptable\n");
+#endif
+ break;
+ default:
+ err("unknown done is invokded\n");
+ break;
+ }
+ break;
+ case ISR_NDONE:
+ switch (msg->parameter1) {
+ case HIC_SHOT:
+ err("shot NOT done is not acceptable\n");
+ break;
+ case HIC_SET_CAM_CONTROL:
+ dbg_interface("camctrl NOT done\n");
+ get_req_work(&itf->nblk_cam_ctrl , &nblk_work);
+ nblk_work->msg.command = ISR_NDONE;
+ set_free_work(&itf->nblk_cam_ctrl, nblk_work);
+ break;
+ case HIC_SET_PARAMETER:
+ err("s_param NOT done");
+ err("param2 : 0x%08X", msg->parameter2);
+ err("param3 : 0x%08X", msg->parameter3);
+ err("param4 : 0x%08X", msg->parameter4);
+ memcpy(&itf->reply, msg,
+ sizeof(struct fimc_is_msg));
+ testnclr_wakeup(itf);
+ break;
+ default:
+ err("a command(%d) not done", msg->parameter1);
+ memcpy(&itf->reply, msg,
+ sizeof(struct fimc_is_msg));
+ testnclr_wakeup(itf);
+ break;
+ }
+ break;
+ case IHC_SET_FACE_MARK:
+ err("FACE_MARK(%d,%d,%d) is not acceptable\n",
+ msg->parameter1,
+ msg->parameter2,
+ msg->parameter3);
+ break;
+ case IHC_AA_DONE:
+ err("AA_DONE(%d,%d,%d) is not acceptable\n",
+ msg->parameter1,
+ msg->parameter2,
+ msg->parameter3);
+ break;
+ case IHC_FLASH_READY:
+ err("IHC_FLASH_READY is not acceptable");
+ break;
+ case IHC_NOT_READY:
+ err("IHC_NOT_READY is occured, need reset");
+ break;
+ default:
+ err("func_general unknown(0x%08X) end\n", msg->command);
+ break;
+ }
+
+ set_free_work(&itf->work_list[INTR_GENERAL], work);
+ get_req_work(&itf->work_list[INTR_GENERAL], &work);
+ }
+}
+
+static void wq_func_scc(struct work_struct *data)
+{
+ struct fimc_is_interface *itf;
+ struct fimc_is_msg *msg;
+ struct fimc_is_framemgr *isp_framemgr;
+ struct fimc_is_framemgr *scc_framemgr;
+ struct fimc_is_frame_shot *isp_frame;
+ struct fimc_is_frame_shot *scc_frame;
+ struct fimc_is_device_ischain *ischain;
+ struct fimc_is_ischain_dev *dev;
+ struct fimc_is_video_common *video;
+ struct fimc_is_work *work;
+ unsigned long flags;
+ u32 fcount;
+ u32 rcount;
+ u32 findex;
+
+ itf = container_of(data, struct fimc_is_interface,
+ work_queue[INTR_SCC_FDONE]);
+ video = itf->video_scc;
+ ischain = video->device;
+ dev = &ischain->scc;
+ isp_framemgr = ischain->framemgr;
+ scc_framemgr = &dev->framemgr;
+
+ get_req_work(&itf->work_list[INTR_SCC_FDONE], &work);
+ while (work) {
+ msg = &work->msg;
+ fcount = msg->parameter1;
+ rcount = msg->parameter3;
+
+ framemgr_e_barrier_irqs(scc_framemgr, FMGR_IDX_4, flags);
+
+ fimc_is_frame_process_head(scc_framemgr, &scc_frame);
+ if (scc_frame && test_bit(REQ_FRAME, &scc_frame->req_flag)) {
+ clear_bit(REQ_FRAME, &scc_frame->req_flag);
+
+#ifdef DBG_STREAMING
+ printk(KERN_INFO "C%d(%d,%d)\n", scc_frame->index,
+ fcount, rcount);
+#endif
+#ifdef USE_FRAME_SYNC
+ findex = scc_frame->stream->findex;
+ isp_frame = &isp_framemgr->frame[findex];
+ if (isp_frame->fcount != fcount)
+ err("scc mismatched(%d, %d)",
+ isp_frame->fcount, fcount);
+
+ scc_frame->stream->fcount = fcount;
+ scc_frame->stream->rcount = rcount;
+ isp_frame->scc_out = FIMC_IS_FOUT_DONE;
+#endif
+
+ fimc_is_frame_trans_pro_to_com(scc_framemgr, scc_frame);
+ buffer_done(video, scc_frame->index);
+ } else
+ err("done(%p) is occured without request\n", scc_frame);
+
+ framemgr_x_barrier_irqr(scc_framemgr, FMGR_IDX_4, flags);
+
+ set_free_work(&itf->work_list[INTR_SCC_FDONE], work);
+ get_req_work(&itf->work_list[INTR_SCC_FDONE], &work);
+ }
+}
+
+static void wq_func_scp(struct work_struct *data)
+{
+ struct fimc_is_interface *itf;
+ struct fimc_is_msg *msg;
+ struct fimc_is_framemgr *isp_framemgr;
+ struct fimc_is_framemgr *scp_framemgr;
+ struct fimc_is_frame_shot *isp_frame;
+ struct fimc_is_frame_shot *scp_frame;
+ struct fimc_is_device_ischain *ischain;
+ struct fimc_is_ischain_dev *dev;
+ struct fimc_is_video_common *video;
+ struct fimc_is_work *work;
+ unsigned long flags;
+ u32 fcount;
+ u32 rcount;
+ u32 findex;
+
+ itf = container_of(data, struct fimc_is_interface,
+ work_queue[INTR_SCP_FDONE]);
+ video = itf->video_scp;
+ ischain = video->device;
+ dev = &ischain->scp;
+ isp_framemgr = ischain->framemgr;
+ scp_framemgr = &dev->framemgr;
+
+ get_req_work(&itf->work_list[INTR_SCP_FDONE], &work);
+ while (work) {
+ msg = &work->msg;
+ fcount = msg->parameter1;
+ rcount = msg->parameter3;
+
+ framemgr_e_barrier_irqs(scp_framemgr, FMGR_IDX_4, flags);
+
+ fimc_is_frame_process_head(scp_framemgr, &scp_frame);
+ if (scp_frame && test_bit(REQ_FRAME, &scp_frame->req_flag)) {
+ clear_bit(REQ_FRAME, &scp_frame->req_flag);
+
+#ifdef DBG_STREAMING
+ printk(KERN_INFO "P%d(%d,%d)\n", scp_frame->index,
+ fcount, rcount);
+#endif
+#ifdef USE_FRAME_SYNC
+ findex = scp_frame->stream->findex;
+ isp_frame = &isp_framemgr->frame[findex];
+ if (isp_frame->fcount != fcount)
+ err("scp mismatched(%d, %d)",
+ isp_frame->fcount, fcount);
+
+ scp_frame->stream->fcount = fcount;
+ scp_frame->stream->rcount = rcount;
+ isp_frame->scp_out = FIMC_IS_FOUT_DONE;
+#endif
+
+ fimc_is_frame_trans_pro_to_com(scp_framemgr, scp_frame);
+ buffer_done(video, scp_frame->index);
+ } else
+ err("done is occured without request(%p)", scp_frame);
+
+ framemgr_x_barrier_irqr(scp_framemgr, FMGR_IDX_4, flags);
+
+ set_free_work(&itf->work_list[INTR_SCP_FDONE], work);
+ get_req_work(&itf->work_list[INTR_SCP_FDONE], &work);
+ }
+}
+
+static void wq_func_isp(struct fimc_is_interface *itf,
+ struct fimc_is_framemgr *framemgr,
+ struct fimc_is_frame_shot *frame)
+{
+ u32 index;
+ struct camera2_lens_uctl *isp_lens_uctl;
+ struct camera2_lens_uctl *lens_uctl;
+ struct camera2_sensor_uctl *isp_sensor_uctl;
+ struct camera2_sensor_uctl *sensor_uctl;
+ struct camera2_flash_uctl *isp_flash_uctl;
+ struct camera2_flash_uctl *flash_uctl;
+
+ index = frame->index;
+ isp_lens_uctl = &itf->isp_peri_ctl.lensUd;
+ isp_sensor_uctl = &itf->isp_peri_ctl.sensorUd;
+ isp_flash_uctl = &itf->isp_peri_ctl.flashUd;
+
+#ifdef DBG_STREAMING
+ printk(KERN_CONT "M%d %d\n", index, frame->fcount);
+#endif
+
+ /* Cache Invalidation */
+ vb2_ion_sync_for_device((void *)frame->cookie_shot, 0, frame->shot_size,
+ DMA_FROM_DEVICE);
+
+ if (frame->shot->uctl.uUpdateBitMap & CAM_SENSOR_CMD) {
+ sensor_uctl = &frame->shot->uctl.sensorUd;
+ isp_sensor_uctl->ctl.exposureTime =
+ sensor_uctl->ctl.exposureTime;
+ isp_sensor_uctl->ctl.frameDuration =
+ sensor_uctl->ctl.frameDuration;
+ isp_sensor_uctl->ctl.sensitivity =
+ sensor_uctl->ctl.sensitivity;
+
+ frame->shot->uctl.uUpdateBitMap &=
+ ~CAM_SENSOR_CMD;
+ }
+
+ if (frame->shot->uctl.uUpdateBitMap & CAM_LENS_CMD) {
+ lens_uctl = &frame->shot->uctl.lensUd;
+ isp_lens_uctl->ctl.focusDistance =
+ lens_uctl->ctl.focusDistance;
+ isp_lens_uctl->maxPos =
+ lens_uctl->maxPos;
+ isp_lens_uctl->slewRate =
+ lens_uctl->slewRate;
+
+ frame->shot->uctl.uUpdateBitMap &=
+ ~CAM_LENS_CMD;
+ }
+
+ if (frame->shot->uctl.uUpdateBitMap & CAM_FLASH_CMD) {
+ flash_uctl = &frame->shot->uctl.flashUd;
+ isp_flash_uctl->ctl.flashMode =
+ flash_uctl->ctl.flashMode;
+ isp_flash_uctl->ctl.firingPower =
+ flash_uctl->ctl.firingPower;
+ isp_flash_uctl->ctl.firingTime =
+ flash_uctl->ctl.firingTime;
+
+ frame->shot->uctl.uUpdateBitMap &=
+ ~CAM_FLASH_CMD;
+ }
+
+#ifdef AUTO_MODE
+ fimc_is_frame_trans_pro_to_fre(framemgr, frame);
+ buffer_done(itf->video_sensor, index);
+#else
+ fimc_is_frame_trans_pro_to_com(framemgr, frame);
+ buffer_done(itf->video_isp, index);
+#endif
+}
+
+static void wq_func_meta(struct work_struct *data)
+{
+ struct fimc_is_interface *itf;
+ struct fimc_is_msg *msg;
+ struct fimc_is_framemgr *framemgr;
+ struct fimc_is_device_ischain *ischain;
+ struct fimc_is_frame_shot *frame;
+ struct fimc_is_work_list *work_list;
+ struct fimc_is_work *work;
+ unsigned long flags;
+ u32 fcount;
+ bool req_done;
+
+ req_done = false;
+ itf = container_of(data, struct fimc_is_interface,
+ work_queue[INTR_META_DONE]);
+ work_list = &itf->work_list[INTR_META_DONE];
+ framemgr = itf->framemgr;
+ ischain = itf->video_isp->device;
+
+ get_req_work(work_list, &work);
+ while (work) {
+ msg = &work->msg;
+ fcount = msg->parameter1;
+
+ framemgr_e_barrier_irqs(framemgr, FMGR_IDX_7, flags);
+
+ fimc_is_frame_process_head(framemgr, &frame);
+ if (frame) {
+ /* comparing input fcount and output fcount
+ just error printing although this error is occured */
+ if (fcount != frame->fcount)
+ err("frame mismatch(%d != %d)",
+ fcount, frame->fcount);
+
+ if (test_bit(REQ_FRAME, &frame->req_flag)) {
+ clear_bit(REQ_FRAME, &frame->req_flag);
+ if (!frame->req_flag) {
+ wq_func_isp(itf, framemgr, frame);
+ req_done = true;
+ }
+ }
+ }
+
+ framemgr_x_barrier_irqr(framemgr, FMGR_IDX_7, flags);
+
+ if (req_done) {
+ mutex_lock(&ischain->mutex_state);
+ fimc_is_ischain_callback(ischain);
+ mutex_unlock(&ischain->mutex_state);
+ }
+
+ set_free_work(work_list, work);
+ get_req_work(work_list, &work);
+ }
+}
+
+static void wq_func_shot(struct work_struct *data)
+{
+ struct fimc_is_interface *itf;
+ struct fimc_is_msg *msg;
+ struct fimc_is_framemgr *framemgr;
+ struct fimc_is_device_ischain *ischain;
+ struct fimc_is_frame_shot *frame;
+ struct fimc_is_work_list *work_list;
+ struct fimc_is_work *work;
+ unsigned long flags;
+ u32 fcount;
+ u32 status;
+ bool req_done;
+
+ req_done = false;
+ itf = container_of(data, struct fimc_is_interface,
+ work_queue[INTR_SHOT_DONE]);
+ work_list = &itf->work_list[INTR_SHOT_DONE];
+ framemgr = itf->framemgr;
+ ischain = itf->video_isp->device;
+
+ get_req_work(work_list, &work);
+ while (work) {
+ msg = &work->msg;
+ fcount = msg->parameter1;
+ status = msg->parameter2;
+
+ framemgr_e_barrier_irqs(framemgr, FMGR_IDX_7, flags);
+
+ fimc_is_frame_process_head(framemgr, &frame);
+ if (frame) {
+#ifdef MEASURE_TIME
+#ifdef INTERNAL_TIME
+ do_gettimeofday(&frame->time_shotdone);
+#else
+ do_gettimeofday(&frame->tzone[TM_SHOT_D]);
+#endif
+#endif
+ /* comparing input fcount and output fcount
+ just error printing although this error is occured */
+ if (fcount != frame->fcount)
+ err("frame mismatch(%d != %d)",
+ fcount, frame->fcount);
+
+ /* need error handling */
+ if (status != ISR_DONE)
+ err("shot done is invalid(0x%08X)", status);
+
+ if (test_bit(REQ_SHOT, &frame->req_flag)) {
+ clear_bit(REQ_SHOT, &frame->req_flag);
+ if (!frame->req_flag) {
+ wq_func_isp(itf, framemgr, frame);
+ req_done = true;
+ }
+ }
+ } else {
+ err("Shot done is occured without request2");
+ fimc_is_frame_print_all(framemgr);
+ }
+
+ framemgr_x_barrier_irqr(framemgr, FMGR_IDX_7, flags);
+
+ if (req_done) {
+ mutex_lock(&ischain->mutex_state);
+ fimc_is_ischain_callback(ischain);
+ mutex_unlock(&ischain->mutex_state);
+ }
+
+ set_free_work(work_list, work);
+ get_req_work(work_list, &work);
+ }
+}
+
+static irqreturn_t interface_isr(int irq, void *data)
+{
+ struct fimc_is_interface *itf;
+ struct work_struct *work_queue;
+ struct fimc_is_work_list *work_list;
+ struct fimc_is_work *work;
+ u32 status;
+
+ itf = (struct fimc_is_interface *)data;
+ status = fimc_is_get_intr(itf);
+
+ if (status & (1<<INTR_SHOT_DONE)) {
+ work_queue = &itf->work_queue[INTR_SHOT_DONE];
+ work_list = &itf->work_list[INTR_SHOT_DONE];
+
+ get_free_work_irq(work_list, &work);
+ if (work) {
+ fimc_is_get_cmd(itf, &work->msg, INTR_SHOT_DONE);
+ work->fcount = work->msg.parameter1;
+ set_req_work_irq(work_list, work);
+
+ if (!work_pending(work_queue))
+ schedule_work(work_queue);
+ } else
+ err("free work item is empty5");
+
+ status &= ~(1<<INTR_SHOT_DONE);
+ fimc_is_clr_intr(itf, INTR_SHOT_DONE);
+ }
+
+ if (status & (1<<INTR_GENERAL)) {
+ work_queue = &itf->work_queue[INTR_GENERAL];
+ work_list = &itf->work_list[INTR_GENERAL];
+
+ get_free_work_irq(&itf->work_list[INTR_GENERAL], &work);
+ if (work) {
+ fimc_is_get_cmd(itf, &work->msg, INTR_GENERAL);
+ set_req_work_irq(work_list, work);
+
+ if (!work_pending(work_queue))
+ schedule_work(work_queue);
+ } else
+ err("free work item is empty1");
+
+ status &= ~(1<<INTR_GENERAL);
+ fimc_is_clr_intr(itf, INTR_GENERAL);
+ }
+
+ if (status & (1<<INTR_SCC_FDONE)) {
+ work_queue = &itf->work_queue[INTR_SCC_FDONE];
+ work_list = &itf->work_list[INTR_SCC_FDONE];
+
+ get_free_work_irq(work_list, &work);
+ if (work) {
+ fimc_is_get_cmd(itf, &work->msg, INTR_SCC_FDONE);
+ set_req_work_irq(work_list, work);
+
+ if (!work_pending(work_queue))
+ schedule_work(work_queue);
+ } else
+ err("free work item is empty2");
+
+ status &= ~(1<<INTR_SCC_FDONE);
+ fimc_is_clr_intr(itf, INTR_SCC_FDONE);
+ }
+
+ if (status & (1<<INTR_SCP_FDONE)) {
+ work_queue = &itf->work_queue[INTR_SCP_FDONE];
+ work_list = &itf->work_list[INTR_SCP_FDONE];
+
+ get_free_work_irq(work_list, &work);
+ if (work) {
+ fimc_is_get_cmd(itf, &work->msg, INTR_SCP_FDONE);
+ set_req_work_irq(work_list, work);
+
+ if (!work_pending(work_queue))
+ schedule_work(work_queue);
+ } else
+ err("free work item is empty3");
+
+ status &= ~(1<<INTR_SCP_FDONE);
+ fimc_is_clr_intr(itf, INTR_SCP_FDONE);
+ }
+
+ if (status & (1<<INTR_META_DONE)) {
+ work_queue = &itf->work_queue[INTR_META_DONE];
+ work_list = &itf->work_list[INTR_META_DONE];
+
+ /* meta done is not needed now
+ this can be used in the future */
+#if 0
+ get_free_work_irq(work_list, &work);
+ if (work) {
+ fimc_is_get_cmd(itf, &work->msg, INTR_META_DONE);
+ work->fcount = work->msg.parameter1;
+ set_req_work_irq(work_list, work);
+
+ if (!work_pending(work_queue))
+ schedule_work(work_queue);
+ } else
+ err("free work item is empty4");
+#endif
+ status &= ~(1<<INTR_META_DONE);
+ fimc_is_clr_intr(itf, INTR_META_DONE);
+ }
+
+ if (status != 0)
+ err("status is NOT all clear(0x%08X)", status);
+
+ return IRQ_HANDLED;
+}
+
+
+int fimc_is_interface_probe(struct fimc_is_interface *this,
+ struct fimc_is_framemgr *framemgr,
+ u32 regs,
+ u32 irq,
+ void *core_data)
+{
+ int ret = 0;
+ struct fimc_is_core *core = (struct fimc_is_core *)core_data;
+
+ dbg_interface("%s\n", __func__);
+
+ init_request_barrier(this);
+ init_process_barrier(this);
+ spin_lock_init(&this->slock_state);
+ init_waitqueue_head(&this->init_wait_queue);
+ init_waitqueue_head(&this->wait_queue);
+
+ INIT_WORK(&this->work_queue[INTR_GENERAL], wq_func_general);
+ INIT_WORK(&this->work_queue[INTR_SCC_FDONE], wq_func_scc);
+ INIT_WORK(&this->work_queue[INTR_SCP_FDONE], wq_func_scp);
+ INIT_WORK(&this->work_queue[INTR_META_DONE], wq_func_meta);
+ INIT_WORK(&this->work_queue[INTR_SHOT_DONE], wq_func_shot);
+
+ this->regs = (void *)regs;
+ this->com_regs = (struct is_common_reg *)(regs + ISSR0);
+
+ ret = request_irq(irq, interface_isr, 0, "mcuctl", this);
+ if (ret)
+ err("request_irq failed\n");
+
+ notify_fcount = &this->com_regs->fcount;
+ this->framemgr = framemgr;
+ this->core = (void *)core;
+ this->video_isp = &core->video_isp.common;
+ this->video_sensor = &core->video_sensor.common;
+ this->video_scp = &core->video_scp.common;
+ this->video_scc = &core->video_scc.common;
+ clear_bit(IS_IF_STATE_OPEN, &this->state);
+ clear_bit(IS_IF_STATE_START, &this->state);
+ clear_bit(IS_IF_STATE_BUSY, &this->state);
+
+ init_work_list(&this->nblk_cam_ctrl, TRACE_WORK_ID_CAMCTRL,
+ MAX_NBLOCKING_COUNT);
+ init_work_list(&this->work_list[INTR_GENERAL],
+ TRACE_WORK_ID_GENERAL, MAX_WORK_COUNT);
+ init_work_list(&this->work_list[INTR_SCC_FDONE],
+ TRACE_WORK_ID_SCC, MAX_WORK_COUNT);
+ init_work_list(&this->work_list[INTR_SCP_FDONE],
+ TRACE_WORK_ID_SCP, MAX_WORK_COUNT);
+ init_work_list(&this->work_list[INTR_META_DONE],
+ TRACE_WORK_ID_META, MAX_WORK_COUNT);
+ init_work_list(&this->work_list[INTR_SHOT_DONE],
+ TRACE_WORK_ID_SHOT, MAX_WORK_COUNT);
+
+ return ret;
+}
+
+int fimc_is_interface_open(struct fimc_is_interface *this)
+{
+ int ret = 0;
+
+ if (testnset_state(this, IS_IF_STATE_OPEN)) {
+ err("already open");
+ ret = -EMFILE;
+ goto exit;
+ }
+
+ dbg_interface("%s\n", __func__);
+
+ /* common register init */
+ this->com_regs->ihcmd_iflag = 0;
+ this->com_regs->scc_iflag = 0;
+ this->com_regs->scp_iflag = 0;
+ this->com_regs->meta_iflag = 0;
+ this->com_regs->shot_iflag = 0;
+
+ this->streaming = IS_IF_STREAMING_INIT;
+ this->processing = IS_IF_PROCESSING_INIT;
+ this->pdown_ready = IS_IF_POWER_DOWN_READY;
+ clr_state(this, IS_IF_STATE_START);
+ set_state(this, IS_IF_STATE_BUSY);
+
+exit:
+ return ret;
+}
+
+int fimc_is_interface_close(struct fimc_is_interface *this)
+{
+ int ret = 0;
+ int retry;
+
+ if (testnclr_state(this, IS_IF_STATE_OPEN)) {
+ err("already close");
+ ret = -EMFILE;
+ goto exit;
+ }
+
+ retry = 10;
+ while (test_state(this, IS_IF_STATE_BUSY) && retry) {
+ err("interface is busy");
+ msleep(20);
+ retry--;
+ }
+
+ if (!retry)
+ err("waiting idle is fail");
+
+ dbg_interface("%s\n", __func__);
+
+exit:
+ return ret;
+}
+
+int fimc_is_hw_print(struct fimc_is_interface *this)
+{
+ int debug_cnt;
+ char *debug;
+ char letter;
+ int count = 0, i;
+ struct fimc_is_device_ischain *ischain;
+
+ if (!test_state(this, IS_IF_STATE_OPEN)) {
+ err("interface is closed");
+ return 0;
+ }
+
+ ischain = this->video_isp->device;
+
+ vb2_ion_sync_for_device(ischain->minfo.fw_cookie,
+ DEBUG_OFFSET, DEBUG_CNT, DMA_FROM_DEVICE);
+
+ debug = (char *)(ischain->minfo.kvaddr + DEBUG_OFFSET);
+ debug_cnt = *((int *)(ischain->minfo.kvaddr + DEBUGCTL_OFFSET))
+ - DEBUG_OFFSET;
+
+ if (ischain->debug_cnt > debug_cnt)
+ count = (DEBUG_CNT - ischain->debug_cnt) + debug_cnt;
+ else
+ count = debug_cnt - ischain->debug_cnt;
+
+ if (count) {
+ printk(KERN_INFO "start(%d %d)\n", debug_cnt, count);
+ for (i = ischain->debug_cnt; count > 0; count--) {
+ letter = debug[i];
+ if (letter)
+ printk(KERN_CONT "%c", letter);
+ i++;
+ if (i > DEBUG_CNT)
+ i = 0;
+ }
+ ischain->debug_cnt = debug_cnt;
+ printk(KERN_INFO "end\n");
+ }
+
+ return count;
+}
+
+int fimc_is_hw_enum(struct fimc_is_interface *this)
+{
+ int ret = 0;
+ struct fimc_is_msg msg;
+
+ dbg_interface("enum(%d)\n", instances);
+
+ ret = wait_initstate(this);
+ if (ret) {
+ err("enum time out");
+ ret = -ETIME;
+ goto exit;
+ }
+
+ msg.id = 0;
+ msg.command = ISR_DONE;
+ msg.instance = 0;
+ msg.parameter1 = IHC_GET_SENSOR_NUMBER;
+ /* this mean sensor numbers */
+ msg.parameter2 = 1;
+ msg.parameter3 = 0;
+ msg.parameter4 = 0;
+
+ waiting_is_ready(this);
+ this->com_regs->hicmd = msg.command;
+ this->com_regs->hic_sensorid = msg.instance;
+ this->com_regs->hic_param1 = msg.parameter1;
+ this->com_regs->hic_param2 = msg.parameter2;
+ this->com_regs->hic_param3 = msg.parameter3;
+ this->com_regs->hic_param4 = msg.parameter4;
+ send_interrupt(this);
+
+exit:
+ return ret;
+}
+
+int fimc_is_hw_saddr(struct fimc_is_interface *this,
+ u32 instance, u32 *setfile_addr)
+{
+ struct fimc_is_msg msg;
+
+ dbg_interface("saddr(%d)\n", instance);
+
+ msg.id = 0;
+ msg.command = HIC_GET_SET_FILE_ADDR;
+ msg.instance = instance;
+ msg.parameter1 = 0;
+ msg.parameter2 = 0;
+ msg.parameter3 = 0;
+ msg.parameter4 = 0;
+
+ fimc_is_set_cmd(this, &msg);
+ *setfile_addr = this->reply.parameter2;
+
+ return 0;
+}
+
+int fimc_is_hw_setfile(struct fimc_is_interface *this,
+ u32 instance)
+{
+ struct fimc_is_msg msg;
+
+ dbg_interface("setfile(%d)\n", instance);
+
+ msg.id = 0;
+ msg.command = HIC_LOAD_SET_FILE;
+ msg.instance = instance;
+ msg.parameter1 = 0;
+ msg.parameter2 = 0;
+ msg.parameter3 = 0;
+ msg.parameter4 = 0;
+
+ fimc_is_set_cmd(this, &msg);
+
+ return 0;
+}
+
+int fimc_is_hw_open(struct fimc_is_interface *this,
+ u32 instance, u32 sensor, u32 channel, u32 ext,
+ u32 *mwidth, u32 *mheight)
+{
+ int ret;
+ struct fimc_is_msg msg;
+
+ dbg_interface("open(%d)\n", sensor);
+
+ msg.id = 0;
+ msg.command = HIC_OPEN_SENSOR;
+ msg.instance = instance;
+ msg.parameter1 = sensor;
+ msg.parameter2 = channel;
+ msg.parameter3 = ext;
+ msg.parameter4 = 0;
+
+ ret = fimc_is_set_cmd(this, &msg);
+
+ *mwidth = this->reply.parameter2;
+ *mheight = this->reply.parameter3;
+
+ return ret;
+}
+
+int fimc_is_hw_stream_on(struct fimc_is_interface *this,
+ u32 instance)
+{
+ int ret;
+ struct fimc_is_msg msg;
+
+ dbg_interface("stream_on(%d)\n", instance);
+
+ msg.id = 0;
+ msg.command = HIC_STREAM_ON;
+ msg.instance = instance;
+ msg.parameter1 = 0;
+ msg.parameter2 = 0;
+ msg.parameter3 = 0;
+ msg.parameter4 = 0;
+
+ ret = fimc_is_set_cmd(this, &msg);
+
+ return ret;
+}
+
+int fimc_is_hw_stream_off(struct fimc_is_interface *this,
+ u32 instance)
+{
+ int ret;
+ struct fimc_is_msg msg;
+
+ dbg_interface("stream_off(%d)\n", instance);
+
+ msg.id = 0;
+ msg.command = HIC_STREAM_OFF;
+ msg.instance = instance;
+ msg.parameter1 = 0;
+ msg.parameter2 = 0;
+ msg.parameter3 = 0;
+ msg.parameter4 = 0;
+
+ ret = fimc_is_set_cmd(this, &msg);
+
+ return ret;
+}
+
+int fimc_is_hw_process_on(struct fimc_is_interface *this,
+ u32 instance)
+{
+ int ret;
+ struct fimc_is_msg msg;
+
+ dbg_interface("process_on(%d)\n", instance);
+
+ msg.id = 0;
+ msg.command = HIC_PROCESS_START;
+ msg.instance = instance;
+ msg.parameter1 = 0;
+ msg.parameter2 = 0;
+ msg.parameter3 = 0;
+ msg.parameter4 = 0;
+
+ ret = fimc_is_set_cmd(this, &msg);
+
+ return ret;
+}
+
+int fimc_is_hw_process_off(struct fimc_is_interface *this,
+ u32 instance)
+{
+ int ret;
+ struct fimc_is_msg msg;
+
+ dbg_interface("process_off(%d)\n", instance);
+
+ msg.id = 0;
+ msg.command = HIC_PROCESS_STOP;
+ msg.instance = instance;
+ msg.parameter1 = 0;
+ msg.parameter2 = 0;
+ msg.parameter3 = 0;
+ msg.parameter4 = 0;
+
+ ret = fimc_is_set_cmd(this, &msg);
+
+ return ret;
+}
+
+int fimc_is_hw_s_param(struct fimc_is_interface *this,
+ u32 instance, u32 indexes, u32 lindex, u32 hindex)
+{
+ int ret;
+ struct fimc_is_msg msg;
+
+ dbg_interface("s_param(%d)\n", instance);
+
+ msg.id = 0;
+ msg.command = HIC_SET_PARAMETER;
+ msg.instance = instance;
+ msg.parameter1 = ISS_PREVIEW_STILL;
+ msg.parameter2 = indexes;
+ msg.parameter3 = lindex;
+ msg.parameter4 = hindex;
+
+ ret = fimc_is_set_cmd(this, &msg);
+
+ return ret;
+}
+
+int fimc_is_hw_a_param(struct fimc_is_interface *this,
+ u32 instance, u32 mode, u32 sub_mode)
+{
+ int ret = 0;
+ struct fimc_is_msg msg;
+
+ dbg_interface("a_param(%d)\n", instance);
+
+ msg.id = 0;
+ msg.command = mode;
+ msg.instance = instance;
+ msg.parameter1 = sub_mode;
+ msg.parameter2 = 0;
+ msg.parameter3 = 0;
+ msg.parameter4 = 0;
+
+ ret = fimc_is_set_cmd(this, &msg);
+
+ return ret;
+}
+
+int fimc_is_hw_f_param(struct fimc_is_interface *this,
+ u32 instance)
+{
+ int ret;
+ struct fimc_is_msg msg;
+
+ dbg_interface("f_param(%d)\n", instance);
+
+ msg.id = 0;
+ msg.command = HIC_PREVIEW_STILL;
+ msg.instance = instance;
+ msg.parameter1 = 0;
+ msg.parameter2 = 0;
+ msg.parameter3 = 0;
+ msg.parameter4 = 0;
+
+ ret = fimc_is_set_cmd(this, &msg);
+
+ return ret;
+}
+
+int fimc_is_hw_g_capability(struct fimc_is_interface *this,
+ u32 instance, u32 address)
+{
+ int ret;
+ struct fimc_is_msg msg;
+
+ dbg_interface("g_capability(%d)\n", instance);
+
+ msg.id = 0;
+ msg.command = HIC_GET_STATIC_METADATA;
+ msg.instance = instance;
+ msg.parameter1 = address;
+ msg.parameter2 = 0;
+ msg.parameter3 = 0;
+ msg.parameter4 = 0;
+
+ ret = fimc_is_set_cmd(this, &msg);
+
+ return ret;
+}
+
+int fimc_is_hw_cfg_mem(struct fimc_is_interface *this,
+ u32 instance, u32 address, u32 size)
+{
+ int ret;
+ struct fimc_is_msg msg;
+
+ dbg_interface("cfg_mem(%d, 0x%08X)\n", instance, address);
+
+ msg.id = 0;
+ msg.command = HIC_SET_A5_MEM_ACCESS;
+ msg.instance = instance;
+ msg.parameter1 = address;
+ msg.parameter2 = size;
+ msg.parameter3 = 0;
+ msg.parameter4 = 0;
+
+ ret = fimc_is_set_cmd(this, &msg);
+
+ return ret;
+}
+
+int fimc_is_hw_power_down(struct fimc_is_interface *this,
+ u32 instance)
+{
+ int ret = 0;
+ struct fimc_is_msg msg;
+
+ dbg_interface("pwr_down(%d)\n", instance);
+
+ msg.id = 0;
+ msg.command = HIC_POWER_DOWN;
+ msg.instance = instance;
+ msg.parameter1 = 0;
+ msg.parameter2 = 0;
+ msg.parameter3 = 0;
+ msg.parameter4 = 0;
+
+ ret = fimc_is_set_cmd(this, &msg);
+
+ return ret;
+}
+
+int fimc_is_hw_shot_nblk(struct fimc_is_interface *this,
+ u32 instance, u32 bayer, u32 shot, u32 fcount, u32 rcount)
+{
+ int ret = 0;
+ struct fimc_is_msg msg;
+
+ /*dbg_interface("shot_nblk(%d, %d)\n", instance, fcount);*/
+
+ msg.id = 0;
+ msg.command = HIC_SHOT;
+ msg.instance = instance;
+ msg.parameter1 = bayer;
+ msg.parameter2 = shot;
+ msg.parameter3 = fcount;
+ msg.parameter4 = rcount;
+
+ ret = fimc_is_set_cmd_shot(this, &msg);
+
+ return ret;
+}
+
+int fimc_is_hw_s_camctrl_nblk(struct fimc_is_interface *this,
+ u32 instance, u32 address, u32 fcount)
+{
+ int ret = 0;
+ struct fimc_is_work *work;
+ struct fimc_is_msg *msg;
+
+ dbg_interface("cam_ctrl_nblk(%d)\n", instance);
+
+ get_free_work(&this->nblk_cam_ctrl, &work);
+
+ if (work) {
+ work->fcount = fcount;
+ msg = &work->msg;
+ msg->id = 0;
+ msg->command = HIC_SET_CAM_CONTROL;
+ msg->instance = instance;
+ msg->parameter1 = address;
+ msg->parameter2 = fcount;
+ msg->parameter3 = 0;
+ msg->parameter4 = 0;
+
+ ret = fimc_is_set_cmd_nblk(this, work);
+ } else {
+ err("g_free_nblk return NULL");
+ print_fre_work_list(&this->nblk_cam_ctrl);
+ print_req_work_list(&this->nblk_cam_ctrl);
+ ret = 1;
+ }
+
+ return ret;
+}
diff --git a/drivers/media/video/exynos/fimc-is-mc2/fimc-is-interface.h b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-interface.h
new file mode 100644
index 0000000..e812df4
--- /dev/null
+++ b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-interface.h
@@ -0,0 +1,175 @@
+#ifndef FIMC_IS_INTERFACE_H
+#define FIMC_IS_INTERFACE_H
+
+#include "fimc-is-metadata.h"
+#include "fimc-is-framemgr.h"
+#include "fimc-is-video.h"
+
+/*#define TRACE_WORK*/
+/* cam_ctrl : 1
+ shot : 2 */
+#define TRACE_WORK_ID_CAMCTRL 0x1
+#define TRACE_WORK_ID_SHOT 0x2
+#define TRACE_WORK_ID_GENERAL 0x4
+#define TRACE_WORK_ID_SCC 0x8
+#define TRACE_WORK_ID_SCP 0x10
+#define TRACE_WORK_ID_META 0x20
+#define TRACE_WORK_ID_MASK 0xFF
+
+#define MAX_NBLOCKING_COUNT 3
+#define MAX_WORK_COUNT 10
+
+#define TRY_RECV_AWARE_COUNT 100
+
+#define LOWBIT_OF(num) (num >= 32 ? 0 : (u32)1<<num)
+#define HIGHBIT_OF(num) (num >= 32 ? (u32)1<<(num-32) : 0)
+
+enum fimc_is_interface_state {
+ IS_IF_STATE_OPEN,
+ IS_IF_STATE_START,
+ IS_IF_STATE_BUSY
+};
+
+enum interrupt_map {
+ INTR_GENERAL = 0,
+ INTR_ISP_FDONE = 1,
+ INTR_SCC_FDONE = 2,
+ INTR_DNR_FDONE = 3,
+ INTR_SCP_FDONE = 4,
+ /* 5 is ISP YUV DONE */
+ INTR_META_DONE = 6,
+ INTR_SHOT_DONE = 7,
+ INTR_MAX_MAP
+};
+
+enum streaming_state {
+ IS_IF_STREAMING_INIT,
+ IS_IF_STREAMING_OFF,
+ IS_IF_STREAMING_ON
+};
+
+enum processing_state {
+ IS_IF_PROCESSING_INIT,
+ IS_IF_PROCESSING_OFF,
+ IS_IF_PROCESSING_ON
+};
+
+enum pdown_ready_state {
+ IS_IF_POWER_DOWN_READY,
+ IS_IF_POWER_DOWN_NREADY
+};
+
+struct fimc_is_msg {
+ u32 id;
+ u32 command;
+ u32 instance;
+ u32 parameter1;
+ u32 parameter2;
+ u32 parameter3;
+ u32 parameter4;
+};
+
+struct fimc_is_work {
+ struct list_head list;
+ struct fimc_is_msg msg;
+ u32 fcount;
+ struct fimc_is_frame_shot *frame;
+};
+
+struct fimc_is_work_list {
+ u32 id;
+ struct fimc_is_work work[MAX_WORK_COUNT];
+ spinlock_t slock_free;
+ spinlock_t slock_request;
+ struct list_head work_free_head;
+ u32 work_free_cnt;
+ struct list_head work_request_head;
+ u32 work_request_cnt;
+ wait_queue_head_t wait_queue;
+};
+
+struct fimc_is_interface {
+ void __iomem *regs;
+ struct is_common_reg __iomem *com_regs;
+ unsigned long state;
+ /* this spinlock is needed for data coincidence.
+ it need to update SCU tag between different thread */
+ spinlock_t slock_state;
+ spinlock_t process_barrier;
+ struct mutex request_barrier;
+
+ wait_queue_head_t init_wait_queue;
+ wait_queue_head_t wait_queue;
+ struct fimc_is_msg reply;
+
+ struct work_struct work_queue[INTR_MAX_MAP];
+ struct fimc_is_work_list work_list[INTR_MAX_MAP];
+
+ /* sensor streaming flag */
+ enum streaming_state streaming;
+ /* firmware processing flag */
+ enum processing_state processing;
+ /* frrmware power down ready flag */
+ enum pdown_ready_state pdown_ready;
+
+ struct fimc_is_framemgr *framemgr;
+
+ void *core;
+ struct fimc_is_video_common *video_sensor;
+ struct fimc_is_video_common *video_isp;
+ struct fimc_is_video_common *video_scc;
+ struct fimc_is_video_common *video_scp;
+
+ struct fimc_is_work_list nblk_cam_ctrl;
+
+ struct camera2_uctl isp_peri_ctl;
+};
+
+int fimc_is_interface_probe(struct fimc_is_interface *this,
+ struct fimc_is_framemgr *framemgr,
+ u32 regs,
+ u32 irq,
+ void *core_data);
+int fimc_is_interface_open(struct fimc_is_interface *this);
+int fimc_is_interface_close(struct fimc_is_interface *this);
+
+/*for debugging*/
+int print_fre_work_list(struct fimc_is_work_list *this);
+int print_req_work_list(struct fimc_is_work_list *this);
+
+int fimc_is_hw_print(struct fimc_is_interface *this);
+int fimc_is_hw_enum(struct fimc_is_interface *this);
+int fimc_is_hw_open(struct fimc_is_interface *this,
+ u32 instance, u32 sensor, u32 channel, u32 ext,
+ u32 *mwidth, u32 *mheight);
+int fimc_is_hw_saddr(struct fimc_is_interface *interface,
+ u32 instance, u32 *setfile_addr);
+int fimc_is_hw_setfile(struct fimc_is_interface *interface,
+ u32 instance);
+int fimc_is_hw_process_on(struct fimc_is_interface *interface,
+ u32 instance);
+int fimc_is_hw_process_off(struct fimc_is_interface *interface,
+ u32 instance);
+int fimc_is_hw_stream_on(struct fimc_is_interface *interface,
+ u32 instance);
+int fimc_is_hw_stream_off(struct fimc_is_interface *interface,
+ u32 instance);
+int fimc_is_hw_s_param(struct fimc_is_interface *interface,
+ u32 instance, u32 indexes, u32 lindex, u32 hindex);
+int fimc_is_hw_a_param(struct fimc_is_interface *this,
+ u32 instance, u32 mode, u32 sub_mode);
+int fimc_is_hw_f_param(struct fimc_is_interface *interface,
+ u32 instance);
+int fimc_is_hw_g_capability(struct fimc_is_interface *this,
+ u32 instance, u32 address);
+int fimc_is_hw_cfg_mem(struct fimc_is_interface *interface,
+ u32 instance, u32 address, u32 size);
+int fimc_is_hw_power_down(struct fimc_is_interface *interface,
+ u32 instance);
+
+int fimc_is_hw_shot_nblk(struct fimc_is_interface *this,
+ u32 instance, u32 bayer, u32 shot, u32 fcount, u32 rcount);
+int fimc_is_hw_s_camctrl_nblk(struct fimc_is_interface *this,
+ u32 instance, u32 address, u32 fcount);
+
+#endif
diff --git a/drivers/media/video/exynos/fimc-is-mc2/fimc-is-mem.c b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-mem.c
new file mode 100644
index 0000000..f9c25c5
--- /dev/null
+++ b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-mem.c
@@ -0,0 +1,92 @@
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ * exynos5 fimc-is core functions
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <mach/videonode.h>
+#if defined(CONFIG_BUSFREQ_OPP) && defined(CONFIG_CPU_EXYNOS5250)
+#include <mach/dev.h>
+#endif
+#include <media/exynos_mc.h>
+#include <linux/cma.h>
+#include <asm/cacheflush.h>
+#include <asm/pgtable.h>
+#include <linux/firmware.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
+#include <linux/videodev2_exynos_camera.h>
+#include <linux/vmalloc.h>
+#include <linux/interrupt.h>
+
+#include "fimc-is-core.h"
+#include "fimc-is-param.h"
+#include "fimc-is-cmd.h"
+#include "fimc-is-regs.h"
+#include "fimc-is-err.h"
+
+static void *fimc_is_ion_init(struct platform_device *pdev)
+{
+ return vb2_ion_create_context(&pdev->dev, SZ_4K,
+ VB2ION_CTX_IOMMU | VB2ION_CTX_VMCONTIG);
+}
+
+static unsigned long plane_addr(struct vb2_buffer *vb, u32 plane_no)
+{
+ void *cookie = vb2_plane_cookie(vb, plane_no);
+ dma_addr_t dva = 0;
+
+ WARN_ON(vb2_ion_dma_address(cookie, &dva) != 0);
+
+ return dva;
+}
+
+static unsigned long plane_kvaddr(struct vb2_buffer *vb, u32 plane_no)
+{
+ void *kvaddr = vb2_plane_vaddr(vb, plane_no);
+
+ return (unsigned long)kvaddr;
+}
+
+const struct fimc_is_vb2 fimc_is_vb2_ion = {
+ .ops = &vb2_ion_memops,
+ .init = fimc_is_ion_init,
+ .cleanup = vb2_ion_destroy_context,
+ .plane_addr = plane_addr,
+ .plane_kvaddr = plane_kvaddr,
+ .resume = vb2_ion_attach_iommu,
+ .suspend = vb2_ion_detach_iommu,
+ .cache_flush = vb2_ion_cache_flush,
+ .set_cacheable = vb2_ion_set_cached,
+};
+
+int fimc_is_mem_probe(struct fimc_is_mem *this,
+ struct platform_device *pdev)
+{
+ u32 ret = 0;
+
+ this->vb2 = &fimc_is_vb2_ion;
+
+ this->alloc_ctx = this->vb2->init(pdev);
+ if (IS_ERR(this->alloc_ctx)) {
+ ret = PTR_ERR(this->alloc_ctx);
+ goto p_err;
+ }
+
+p_err:
+ return ret;
+}
diff --git a/drivers/media/video/exynos/fimc-is-mc2/fimc-is-mem.h b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-mem.h
new file mode 100644
index 0000000..b566a35
--- /dev/null
+++ b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-mem.h
@@ -0,0 +1,40 @@
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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.
+ */
+
+#ifndef FIMC_IS_MEM_H
+#define FIMC_IS_MEM_H
+
+struct fimc_is_vb2 {
+ const struct vb2_mem_ops *ops;
+ void *(*init)(struct platform_device *pdev);
+ void (*cleanup)(void *alloc_ctx);
+
+ unsigned long (*plane_addr)(struct vb2_buffer *vb, u32 plane_no);
+ unsigned long (*plane_kvaddr)(struct vb2_buffer *vb, u32 plane_no);
+
+ int (*resume)(void *alloc_ctx);
+ void (*suspend)(void *alloc_ctx);
+
+ int (*cache_flush)(struct vb2_buffer *vb, u32 num_planes);
+ void (*set_cacheable)(void *alloc_ctx, bool cacheable);
+};
+
+struct fimc_is_mem {
+ struct platform_device *pdev;
+ struct vb2_alloc_ctx *alloc_ctx;
+
+ const struct fimc_is_vb2 *vb2;
+};
+
+int fimc_is_mem_probe(struct fimc_is_mem *this,
+ struct platform_device *pdev);
+
+#endif
diff --git a/drivers/media/video/exynos/fimc-is-mc2/fimc-is-metadata.h b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-metadata.h
new file mode 100644
index 0000000..850893f
--- /dev/null
+++ b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-metadata.h
@@ -0,0 +1,964 @@
+/*
+ * Copyright (c) 2012, Samsung Electronics Co. LTD
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are
+ * those of the authors and should not be interpreted as representing official
+ * policies, either expressed or implied, of the FreeBSD Project.
+ */
+
+#ifndef FIMC_IS_METADATA_H_
+#define FIMC_IS_METADATA_H_
+
+struct rational {
+ uint32_t num;
+ uint32_t den;
+};
+
+#define CAMERA2_MAX_AVAILABLE_MODE 21
+#define CAMERA2_MAX_FACES 16
+
+/*
+ *controls/dynamic metadata
+*/
+
+/* android.request */
+
+enum metadata_mode {
+ METADATA_MODE_NONE,
+ METADATA_MODE_FULL
+};
+
+struct camera2_request_ctl {
+ uint32_t id;
+ enum metadata_mode metadataMode;
+ uint8_t outputStreams[16];
+ uint32_t frameCount;
+};
+
+struct camera2_request_dm {
+ uint32_t id;
+ enum metadata_mode metadataMode;
+ uint32_t frameCount;
+};
+
+
+
+/* android.lens */
+
+enum optical_stabilization_mode {
+ OPTICAL_STABILIZATION_MODE_OFF,
+ OPTICAL_STABILIZATION_MODE_ON
+};
+
+enum lens_facing {
+ LENS_FACING_BACK,
+ LENS_FACING_FRONT
+};
+
+struct camera2_lens_ctl {
+ uint32_t focusDistance;
+ float aperture;
+ float focalLength;
+ float filterDensity;
+ enum optical_stabilization_mode opticalStabilizationMode;
+
+};
+
+struct camera2_lens_dm {
+ uint32_t focusDistance;
+ float aperture;
+ float focalLength;
+ float filterDensity;
+ enum optical_stabilization_mode opticalStabilizationMode;
+ float focusRange[2];
+};
+
+struct camera2_lens_sm {
+ float minimumFocusDistance;
+ float hyperfocalDistance;
+ float availableFocalLength[2];
+ float availableApertures;
+ /*assuming 1 aperture*/
+ float availableFilterDensities;
+ /*assuming 1 ND filter value*/
+ enum optical_stabilization_mode availableOpticalStabilization;
+ /*assuming 1*/
+ uint32_t shadingMapSize;
+ float shadingMap[3][40][30];
+ uint32_t geometricCorrectionMapSize;
+ float geometricCorrectionMap[2][3][40][30];
+ enum lens_facing facing;
+ float position[2];
+};
+
+/* android.sensor */
+
+enum sensor_colorfilterarrangement {
+ SENSOR_COLORFILTERARRANGEMENT_RGGB,
+ SENSOR_COLORFILTERARRANGEMENT_GRBG,
+ SENSOR_COLORFILTERARRANGEMENT_GBRG,
+ SENSOR_COLORFILTERARRANGEMENT_BGGR,
+ SENSOR_COLORFILTERARRANGEMENT_RGB
+};
+
+enum sensor_ref_illuminant {
+ SENSOR_ILLUMINANT_DAYLIGHT = 1,
+ SENSOR_ILLUMINANT_FLUORESCENT = 2,
+ SENSOR_ILLUMINANT_TUNGSTEN = 3,
+ SENSOR_ILLUMINANT_FLASH = 4,
+ SENSOR_ILLUMINANT_FINE_WEATHER = 9,
+ SENSOR_ILLUMINANT_CLOUDY_WEATHER = 10,
+ SENSOR_ILLUMINANT_SHADE = 11,
+ SENSOR_ILLUMINANT_DAYLIGHT_FLUORESCENT = 12,
+ SENSOR_ILLUMINANT_DAY_WHITE_FLUORESCENT = 13,
+ SENSOR_ILLUMINANT_COOL_WHITE_FLUORESCENT = 14,
+ SENSOR_ILLUMINANT_WHITE_FLUORESCENT = 15,
+ SENSOR_ILLUMINANT_STANDARD_A = 17,
+ SENSOR_ILLUMINANT_STANDARD_B = 18,
+ SENSOR_ILLUMINANT_STANDARD_C = 19,
+ SENSOR_ILLUMINANT_D55 = 20,
+ SENSOR_ILLUMINANT_D65 = 21,
+ SENSOR_ILLUMINANT_D75 = 22,
+ SENSOR_ILLUMINANT_D50 = 23,
+ SENSOR_ILLUMINANT_ISO_STUDIO_TUNGSTEN = 24
+};
+
+struct camera2_sensor_ctl {
+ /* unit : nano */
+ uint64_t exposureTime;
+ /* unit : nano(It's min frame duration */
+ uint64_t frameDuration;
+ /* unit : percent(need to change ISO value?) */
+ uint32_t sensitivity;
+};
+
+struct camera2_sensor_dm {
+ uint64_t exposureTime;
+ uint64_t frameDuration;
+ uint32_t sensitivity;
+ uint64_t timeStamp;
+};
+
+struct camera2_sensor_sm {
+ uint32_t exposureTimeRange[2];
+ uint32_t maxFrameDuration;
+ /* list of available sensitivities. */
+ uint32_t availableSensitivities[10];
+ enum sensor_colorfilterarrangement colorFilterArrangement;
+ float physicalSize[2];
+ uint32_t pixelArraySize[2];
+ uint32_t activeArraySize[4];
+ uint32_t whiteLevel;
+ uint32_t blackLevelPattern[4];
+ struct rational colorTransform1[9];
+ struct rational colorTransform2[9];
+ enum sensor_ref_illuminant referenceIlluminant1;
+ enum sensor_ref_illuminant referenceIlluminant2;
+ struct rational forwardMatrix1[9];
+ struct rational forwardMatrix2[9];
+ struct rational calibrationTransform1[9];
+ struct rational calibrationTransform2[9];
+ struct rational baseGainFactor;
+ uint32_t maxAnalogSensitivity;
+ float noiseModelCoefficients[2];
+ uint32_t orientation;
+};
+
+
+
+/* android.flash */
+
+enum flash_mode {
+ CAM2_FLASH_MODE_OFF = 1,
+ CAM2_FLASH_MODE_SINGLE,
+ CAM2_FLASH_MODE_TORCH,
+ CAM2_FLASH_MODE_BEST
+};
+
+struct camera2_flash_ctl {
+ enum flash_mode flashMode;
+ uint32_t firingPower;
+ uint64_t firingTime;
+};
+
+struct camera2_flash_dm {
+ enum flash_mode flashMode;
+ /*10 is max power*/
+ uint32_t firingPower;
+ /*unit : microseconds*/
+ uint64_t firingTime;
+ /*1 : stable, 0 : unstable*/
+ uint32_t firingStable;
+ /*1 : success, 0 : fail*/
+ uint32_t decision;
+};
+
+struct camera2_flash_sm {
+ uint32_t available;
+ uint64_t chargeDuration;
+};
+
+
+/* android.hotpixel */
+
+enum processing_mode {
+ PROCESSING_MODE_OFF = 1,
+ PROCESSING_MODE_FAST,
+ PROCESSING_MODE_HIGH_QUALITY
+};
+
+
+struct camera2_hotpixel_ctl {
+ enum processing_mode mode;
+};
+
+struct camera2_hotpixel_dm {
+ enum processing_mode mode;
+};
+
+
+
+/* android.demosaic */
+
+struct camera2_demosaic_ctl {
+ enum processing_mode mode;
+};
+
+struct camera2_demosaic_dm {
+ enum processing_mode mode;
+};
+
+
+
+/* android.noiseReduction */
+
+struct camera2_noisereduction_ctl {
+ enum processing_mode mode;
+ uint32_t strength;
+};
+
+struct camera2_noisereduction_dm {
+ enum processing_mode mode;
+ uint32_t strength;
+};
+
+
+
+/* android.shading */
+
+struct camera2_shading_ctl {
+ enum processing_mode mode;
+};
+
+struct camera2_shading_dm {
+ enum processing_mode mode;
+};
+
+
+
+/* android.geometric */
+
+struct camera2_geometric_ctl {
+ enum processing_mode mode;
+};
+
+struct camera2_geometric_dm {
+ enum processing_mode mode;
+};
+
+
+
+/* android.colorCorrection */
+
+enum colorcorrection_mode {
+ COLORCORRECTION_MODE_FAST = 1,
+ COLORCORRECTION_MODE_HIGH_QUALITY,
+ COLORCORRECTION_MODE_TRANSFORM_MATRIX,
+ COLORCORRECTION_MODE_EFFECT_MONO,
+ COLORCORRECTION_MODE_EFFECT_NEGATIVE,
+ COLORCORRECTION_MODE_EFFECT_SOLARIZE,
+ COLORCORRECTION_MODE_EFFECT_SEPIA,
+ COLORCORRECTION_MODE_EFFECT_POSTERIZE,
+ COLORCORRECTION_MODE_EFFECT_WHITEBOARD,
+ COLORCORRECTION_MODE_EFFECT_BLACKBOARD,
+ COLORCORRECTION_MODE_EFFECT_AQUA
+};
+
+
+struct camera2_colorcorrection_ctl {
+ enum colorcorrection_mode mode;
+ float transform[9];
+ uint32_t hue;
+ uint32_t saturation;
+ uint32_t brightness;
+};
+
+struct camera2_colorcorrection_dm {
+ enum colorcorrection_mode mode;
+ float transform[9];
+ uint32_t hue;
+ uint32_t saturation;
+ uint32_t brightness;
+};
+
+struct camera2_colorcorrection_sm {
+ /*assuming 10 supported modes*/
+ uint8_t availableModes[CAMERA2_MAX_AVAILABLE_MODE];
+ uint32_t hueRange[2];
+ uint32_t saturationRange[2];
+ uint32_t brightnessRange[2];
+};
+
+
+/* android.tonemap */
+
+enum tonemap_mode {
+ TONEMAP_MODE_FAST = 1,
+ TONEMAP_MODE_HIGH_QUALITY,
+ TONEMAP_MODE_CONTRAST_CURVE
+};
+
+struct camera2_tonemap_ctl {
+ enum tonemap_mode mode;
+ /* assuming maxCurvePoints = 64 */
+ float curveRed[64];
+ float curveGreen[64];
+ float curveBlue[64];
+};
+
+struct camera2_tonemap_dm {
+ enum tonemap_mode mode;
+ /* assuming maxCurvePoints = 64 */
+ float curveRed[64];
+ float curveGreen[64];
+ float curveBlue[64];
+};
+
+struct camera2_tonemap_sm {
+ uint32_t maxCurvePoints;
+};
+
+/* android.edge */
+
+struct camera2_edge_ctl {
+ enum processing_mode mode;
+ uint32_t strength;
+};
+
+struct camera2_edge_dm {
+ enum processing_mode mode;
+ uint32_t strength;
+};
+
+
+
+/* android.scaler */
+
+enum scaler_availableformats {
+ SCALER_FORMAT_BAYER_RAW,
+ SCALER_FORMAT_YV12,
+ SCALER_FORMAT_NV21,
+ SCALER_FORMAT_JPEG,
+ SCALER_FORMAT_UNKNOWN
+};
+
+struct camera2_scaler_ctl {
+ uint32_t cropRegion[3];
+};
+
+struct camera2_scaler_dm {
+ uint32_t cropRegion[3];
+};
+
+struct camera2_scaler_sm {
+ enum scaler_availableformats availableFormats[4];
+ /*assuming # of availableFormats = 4*/
+ uint32_t availableRawSizes;
+ uint64_t availableRawMinDurations;
+ /* needs check */
+ uint32_t availableProcessedSizes[8];
+ uint64_t availableProcessedMinDurations[8];
+ uint32_t availableJpegSizes[8][2];
+ uint64_t availableJpegMinDurations[8];
+ uint32_t availableMaxDigitalZoom[8];
+};
+
+/* android.jpeg */
+struct camera2_jpeg_ctl {
+ uint32_t quality;
+ uint32_t thumbnailSize[2];
+ uint32_t thumbnailQuality;
+ double gpsCoordinates[3];
+ uint32_t gpsProcessingMethod;
+ uint64_t gpsTimestamp;
+ uint32_t orientation;
+};
+
+struct camera2_jpeg_dm {
+ uint32_t quality;
+ uint32_t thumbnailSize[2];
+ uint32_t thumbnailQuality;
+ double gpsCoordinates[3];
+ uint32_t gpsProcessingMethod;
+ uint64_t gpsTimestamp;
+ uint32_t orientation;
+};
+
+struct camera2_jpeg_sm {
+ uint32_t availableThumbnailSizes[8][2];
+ uint32_t maxSize;
+ /*assuming supported size=8*/
+};
+
+
+
+/* android.statistics */
+
+enum facedetect_mode {
+ FACEDETECT_MODE_OFF = 1,
+ FACEDETECT_MODE_SIMPLE,
+ FACEDETECT_MODE_FULL
+};
+
+enum stats_mode {
+ STATS_MODE_OFF = 1,
+ STATS_MODE_ON
+};
+
+struct camera2_stats_ctl {
+ enum facedetect_mode faceDetectMode;
+ enum stats_mode histogramMode;
+ enum stats_mode sharpnessMapMode;
+};
+
+
+struct camera2_stats_dm {
+ enum facedetect_mode faceDetectMode;
+ uint32_t faceRectangles[CAMERA2_MAX_FACES][4];
+ uint8_t faceScores[CAMERA2_MAX_FACES];
+ uint32_t faceLandmarks[CAMERA2_MAX_FACES][6];
+ uint32_t faceIds[CAMERA2_MAX_FACES];
+/* PAYTON_CHECK_20120712 : histogram_mode -> stats_mode */
+ enum stats_mode histogramMode;
+/* [hj529.kim, 2012/07/19] androd.statistics.histogram */
+ uint32_t histogram[3 * 256];
+/* PAYTON_CHECK_20120712 : sharpnessmap_mode -> stats_mode */
+ enum stats_mode sharpnessMapMode;
+ /*sharpnessMap*/
+};
+
+
+struct camera2_stats_sm {
+ uint8_t availableFaceDetectModes[CAMERA2_MAX_AVAILABLE_MODE];
+ /*assuming supported modes = 3;*/
+ uint32_t maxFaceCount;
+ uint32_t histogramBucketCount;
+ uint32_t maxHistogramCount;
+ uint32_t sharpnessMapSize[2];
+ uint32_t maxSharpnessMapValue;
+};
+
+/* android.control */
+
+enum aa_capture_intent {
+ AA_CAPTURE_INTENT_CUSTOM = 0,
+ AA_CAPTURE_INTENT_PREVIEW,
+ AA_CAPTURE_INTENT_STILL_CAPTURE,
+ AA_CAPTURE_INTENT_VIDEO_RECORD,
+ AA_CAPTURE_INTENT_VIDEO_SNAPSHOT,
+ AA_CAPTURE_INTENT_ZERO_SHUTTER_LAG
+};
+
+enum aa_mode {
+ AA_CONTROL_OFF = 1,
+ AA_CONTROL_AUTO,
+ AA_CONTROL_USE_SCENE_MODE
+};
+
+enum aa_scene_mode {
+ AA_SCENE_MODE_UNSUPPORTED = 1,
+ AA_SCENE_MODE_FACE_PRIORITY,
+ AA_SCENE_MODE_ACTION,
+ AA_SCENE_MODE_PORTRAIT,
+ AA_SCENE_MODE_LANDSCAPE,
+ AA_SCENE_MODE_NIGHT,
+ AA_SCENE_MODE_NIGHT_PORTRAIT,
+ AA_SCENE_MODE_THEATRE,
+ AA_SCENE_MODE_BEACH,
+ AA_SCENE_MODE_SNOW,
+ AA_SCENE_MODE_SUNSET,
+ AA_SCENE_MODE_STEADYPHOTO,
+ AA_SCENE_MODE_FIREWORKS,
+ AA_SCENE_MODE_SPORTS,
+ AA_SCENE_MODE_PARTY,
+ AA_SCENE_MODE_CANDLELIGHT,
+ AA_SCENE_MODE_BARCODE,
+ AA_SCENE_MODE_NIGHT_CAPTURE
+};
+
+enum aa_effect_mode {
+ AA_EFFECT_OFF = 1,
+ AA_EFFECT_MONO,
+ AA_EFFECT_NEGATIVE,
+ AA_EFFECT_SOLARIZE,
+ AA_EFFECT_SEPIA,
+ AA_EFFECT_POSTERIZE,
+ AA_EFFECT_WHITEBOARD,
+ AA_EFFECT_BLACKBOARD,
+ AA_EFFECT_AQUA
+};
+
+enum aa_aemode {
+ AA_AEMODE_OFF = 1,
+ AA_AEMODE_LOCKED,
+ AA_AEMODE_ON,
+ AA_AEMODE_ON_AUTO_FLASH,
+ AA_AEMODE_ON_ALWAYS_FLASH,
+ AA_AEMODE_ON_AUTO_FLASH_REDEYE
+};
+
+enum aa_ae_flashmode {
+ /*all flash control stop*/
+ AA_FLASHMODE_OFF = 1,
+ /*internal 3A can control flash*/
+ AA_FLASHMODE_ON,
+ /*internal 3A can do auto flash algorithm*/
+ AA_FLASHMODE_AUTO,
+ /*internal 3A can fire flash by auto result*/
+ AA_FLASHMODE_CAPTURE,
+ /*internal 3A can control flash forced*/
+ AA_FLASHMODE_ON_ALWAYS
+
+};
+
+enum aa_ae_antibanding_mode {
+ AA_AE_ANTIBANDING_OFF = 1,
+ AA_AE_ANTIBANDING_50HZ,
+ AA_AE_ANTIBANDING_60HZ,
+ AA_AE_ANTIBANDING_AUTO
+};
+
+enum aa_awbmode {
+ AA_AWBMODE_OFF = 1,
+ AA_AWBMODE_LOCKED,
+ AA_AWBMODE_WB_AUTO,
+ AA_AWBMODE_WB_INCANDESCENT,
+ AA_AWBMODE_WB_FLUORESCENT,
+ AA_AWBMODE_WB_WARM_FLUORESCENT,
+ AA_AWBMODE_WB_DAYLIGHT,
+ AA_AWBMODE_WB_CLOUDY_DAYLIGHT,
+ AA_AWBMODE_WB_TWILIGHT,
+ AA_AWBMODE_WB_SHADE
+};
+
+enum aa_afmode {
+ AA_AFMODE_OFF = 1,
+ AA_AFMODE_AUTO,
+ AA_AFMODE_MACRO,
+ AA_AFMODE_CONTINUOUS_VIDEO,
+ AA_AFMODE_CONTINUOUS_PICTURE,
+ AA_AFMODE_EDOF
+};
+
+enum aa_afstate {
+ AA_AFSTATE_INACTIVE = 1,
+ AA_AFSTATE_PASSIVE_SCAN,
+ AA_AFSTATE_ACTIVE_SCAN,
+ AA_AFSTATE_AF_ACQUIRED_FOCUS,
+ AA_AFSTATE_AF_FAILED_FOCUS
+};
+
+enum ae_state {
+ AE_STATE_INACTIVE = 1,
+ AE_STATE_SEARCHING,
+ AE_STATE_CONVERGED,
+ AE_STATE_LOCKED,
+ AE_STATE_FLASH_REQUIRED,
+ AE_STATE_PRECAPTURE
+};
+
+enum awb_state {
+ AWB_STATE_INACTIVE = 1,
+ AWB_STATE_SEARCHING,
+ AWB_STATE_CONVERGED,
+ AWB_STATE_LOCKED
+};
+
+enum aa_isomode {
+ AA_ISOMODE_AUTO = 1,
+ AA_ISOMODE_MANUAL,
+};
+
+struct camera2_aa_ctl {
+ enum aa_capture_intent captureIntent;
+ enum aa_mode mode;
+ /*enum aa_effect_mode effectMode;*/
+ enum aa_scene_mode sceneMode;
+ uint32_t videoStabilizationMode;
+ enum aa_aemode aeMode;
+ uint32_t aeRegions[5];
+ /*5 per region(x1,y1,x2,y2,weight). currently assuming 1 region.*/
+ int32_t aeExpCompensation;
+ uint32_t aeTargetFpsRange[2];
+ enum aa_ae_antibanding_mode aeAntibandingMode;
+ enum aa_ae_flashmode aeflashMode;
+ enum aa_awbmode awbMode;
+ uint32_t awbRegions[5];
+ /*5 per region(x1,y1,x2,y2,weight). currently assuming 1 region.*/
+ enum aa_afmode afMode;
+ uint32_t afRegions[5];
+ /*5 per region(x1,y1,x2,y2,weight). currently assuming 1 region.*/
+ uint32_t afTrigger;
+ enum aa_isomode isoMode;
+ uint32_t isoValue;
+
+};
+
+struct camera2_aa_dm {
+ enum aa_mode mode;
+ enum aa_effect_mode effectMode;
+ enum aa_scene_mode sceneMode;
+ uint32_t videoStabilizationMode;
+ enum aa_aemode aeMode;
+ /*needs check*/
+ uint32_t aeRegions[5];
+ /*5 per region(x1,y1,x2,y2,weight). currently assuming 1 region.*/
+ enum ae_state aeState;
+ enum aa_ae_flashmode aeflashMode;
+ /*needs check*/
+ enum aa_awbmode awbMode;
+ uint32_t awbRegions[5];
+ enum awb_state awbState;
+ /*5 per region(x1,y1,x2,y2,weight). currently assuming 1 region.*/
+ enum aa_afmode afMode;
+ uint32_t afRegions[5];
+ /*5 per region(x1,y1,x2,y2,weight). currently assuming 1 region*/
+ enum aa_afstate afState;
+ enum aa_isomode isoMode;
+ uint32_t isoValue;
+};
+
+struct camera2_aa_sm {
+ uint8_t availableSceneModes[CAMERA2_MAX_AVAILABLE_MODE];
+ uint8_t availableEffects[CAMERA2_MAX_AVAILABLE_MODE];
+ /*assuming # of available scene modes = 10*/
+ uint32_t maxRegions;
+ uint8_t aeAvailableModes[CAMERA2_MAX_AVAILABLE_MODE];
+ /*assuming # of available ae modes = 8*/
+ struct rational aeCompensationStep;
+ int32_t aeCompensationRange[2];
+ uint32_t aeAvailableTargetFpsRanges[CAMERA2_MAX_AVAILABLE_MODE][2];
+ uint8_t aeAvailableAntibandingModes[CAMERA2_MAX_AVAILABLE_MODE];
+ uint8_t awbAvailableModes[CAMERA2_MAX_AVAILABLE_MODE];
+ /*assuming # of awbAvailableModes = 10*/
+ uint8_t afAvailableModes[CAMERA2_MAX_AVAILABLE_MODE];
+ /*assuming # of afAvailableModes = 4*/
+ uint8_t availableVideoStabilizationModes[4];
+ /*assuming # of availableVideoStabilizationModes = 4*/
+ uint32_t isoRange[2];
+};
+
+struct camera2_lens_usm {
+ /** Frame delay between sending command and applying frame data */
+ uint32_t focusDistanceFrameDelay;
+};
+
+struct camera2_sensor_usm {
+ /** Frame delay between sending command and applying frame data */
+ uint32_t exposureTimeFrameDelay;
+ uint32_t frameDurationFrameDelay;
+ uint32_t sensitivityFrameDelay;
+};
+
+struct camera2_flash_usm {
+ /** Frame delay between sending command and applying frame data */
+ uint32_t flashModeFrameDelay;
+ uint32_t firingPowerFrameDelay;
+ uint64_t firingTimeFrameDelay;
+};
+
+struct camera2_ctl {
+ struct camera2_request_ctl request;
+ struct camera2_lens_ctl lens;
+ struct camera2_sensor_ctl sensor;
+ struct camera2_flash_ctl flash;
+ struct camera2_hotpixel_ctl hotpixel;
+ struct camera2_demosaic_ctl demosaic;
+ struct camera2_noisereduction_ctl noise;
+ struct camera2_shading_ctl shading;
+ struct camera2_geometric_ctl geometric;
+ struct camera2_colorcorrection_ctl color;
+ struct camera2_tonemap_ctl tonemap;
+ struct camera2_edge_ctl edge;
+ struct camera2_scaler_ctl scaler;
+ struct camera2_jpeg_ctl jpeg;
+ struct camera2_stats_ctl stats;
+ struct camera2_aa_ctl aa;
+};
+
+struct camera2_dm {
+ struct camera2_request_dm request;
+ struct camera2_lens_dm lens;
+ struct camera2_sensor_dm sensor;
+ struct camera2_flash_dm flash;
+ struct camera2_hotpixel_dm hotpixel;
+ struct camera2_demosaic_dm demosaic;
+ struct camera2_noisereduction_dm noise;
+ struct camera2_shading_dm shading;
+ struct camera2_geometric_dm geometric;
+ struct camera2_colorcorrection_dm color;
+ struct camera2_tonemap_dm tonemap;
+ struct camera2_edge_dm edge;
+ struct camera2_scaler_dm scaler;
+ struct camera2_jpeg_dm jpeg;
+ struct camera2_stats_dm stats;
+ struct camera2_aa_dm aa;
+};
+
+struct camera2_sm {
+ struct camera2_lens_sm lens;
+ struct camera2_sensor_sm sensor;
+ struct camera2_flash_sm flash;
+ struct camera2_colorcorrection_sm color;
+ struct camera2_tonemap_sm tonemap;
+ struct camera2_scaler_sm scaler;
+ struct camera2_jpeg_sm jpeg;
+ struct camera2_stats_sm stats;
+ struct camera2_aa_sm aa;
+
+ /** User-defined(ispfw specific) static metadata. */
+ struct camera2_lens_usm lensUd;
+ struct camera2_sensor_usm sensorUd;
+ struct camera2_flash_usm flashUd;
+};
+
+/** \brief
+ User-defined control for lens.
+*/
+struct camera2_lens_uctl {
+ struct camera2_lens_ctl ctl;
+
+ /** It depends by af algorithm(normally 255 or 1023) */
+ uint32_t maxPos;
+ /** Some actuator support slew rate control. */
+ uint32_t slewRate;
+};
+
+/** \brief
+ User-defined metadata for lens.
+*/
+struct camera2_lens_udm {
+ /** It depends by af algorithm(normally 255 or 1023) */
+ uint32_t maxPos;
+ /** Some actuator support slew rate control. */
+ uint32_t slewRate;
+};
+
+/** \brief
+ User-defined control for sensor.
+*/
+struct camera2_sensor_uctl {
+ struct camera2_sensor_ctl ctl;
+ /** Dynamic frame duration.
+ This feature is decided to max. value between
+ 'sensor.exposureTime'+alpha and 'sensor.frameDuration'.
+ */
+ uint64_t dynamicFrameDuration;
+};
+
+struct camera2_scaler_uctl {
+ /** \brief
+ target address for next frame.
+ \remarks
+ [0] invalid address, stop
+ [others] valid address
+ */
+ uint32_t sccTargetAddress[4];
+ uint32_t scpTargetAddress[4];
+};
+
+struct camera2_flash_uctl {
+ struct camera2_flash_ctl ctl;
+};
+
+/** \brief
+ User-defined control area.
+ \remarks
+ sensor, lens, flash category is empty value.
+ It should be filled by a5 for SET_CAM_CONTROL command.
+ Other category is filled already from host.
+*/
+struct camera2_uctl {
+ /** \brief
+ Set sensor, lens, flash control for next frame.
+ \remarks
+ This flag can be combined.
+ [0 bit] lens
+ [1 bit] sensor
+ [2 bit] flash
+ */
+ uint32_t uUpdateBitMap;
+
+ /** For debugging */
+ uint32_t uFrameNumber;
+
+ /** ispfw specific control(user-defined) of lens. */
+ struct camera2_lens_uctl lensUd;
+ /** ispfw specific control(user-defined) of sensor. */
+ struct camera2_sensor_uctl sensorUd;
+ /** ispfw specific control(user-defined) of flash. */
+ struct camera2_flash_uctl flashUd;
+
+ struct camera2_scaler_uctl scalerUd;
+};
+
+struct camera2_udm {
+ struct camera2_lens_udm lens;
+};
+
+struct camera2_shot {
+ /*google standard area*/
+ struct camera2_ctl ctl;
+ struct camera2_dm dm;
+ /*user defined area*/
+ struct camera2_uctl uctl;
+ struct camera2_udm udm;
+ /*magic : 23456789*/
+ uint32_t magicNumber;
+};
+
+/** \brief
+ Structure for interfacing between HAL and driver.
+*/
+struct camera2_shot_ext {
+ /** \brief
+ setfile change
+ \remarks
+ [x] mode for setfile
+ */
+ uint32_t setfile;
+
+ /** \brief
+ stream control
+ \remarks
+ [0] disable stream out
+ [1] enable stream out
+ */
+ uint32_t request_isp;
+ uint32_t request_scc;
+ uint32_t request_scp;
+
+ /** \brief
+ post processing control(DRC)
+ \remarks
+ [0] bypass off
+ [1] bypass on
+ */
+ uint32_t drc_bypass;
+
+ /** \brief
+ post processing control(DIS)
+ \remarks
+ [0] bypass off
+ [1] bypass on
+ */
+ uint32_t dis_bypass;
+
+ /** \brief
+ post processing control(3DNR)
+ \remarks
+ [0] bypass off
+ [1] bypass on
+ */
+ uint32_t dnr_bypass;
+
+ /** \brief
+ post processing control(FD)
+ \remarks
+ [0] bypass off
+ [1] bypass on
+ */
+ uint32_t fd_bypass;
+
+ /* reserved for future */
+ uint32_t reserved[20];
+
+ /** \brief
+ processing time debugging
+ \remarks
+ taken time(unit : struct timeval)
+ [0][x] flite start
+ [1][x] flite end
+ [2][x] DRV Shot
+ [3][x] DRV Shot done
+ [4][x] DRV Meta done
+ */
+ uint32_t timeZone[10][2];
+
+ struct camera2_shot shot;
+};
+
+/** \brief
+ stream structure for scaler.
+*/
+struct camera2_stream {
+ /** \brief
+ this address for verifying conincidence of index and address
+ \remarks
+ [X] kernel virtual address for this buffer
+ */
+ uint32_t address;
+
+ /** \brief
+ this frame count is from FLITE through dm.request.fcount,
+ this count increases every frame end. initial value is 1.
+ \remarks
+ [X] frame count
+ */
+ uint32_t fcount;
+
+ /** \brief
+ this request count is from HAL through ctl.request.fcount,
+ this count is the unique.
+ \remarks
+ [X] request count
+ */
+ uint32_t rcount;
+
+ /** \brief
+ frame index of isp framemgr.
+ this value is for driver internal debugging
+ \remarks
+ [X] frame index
+ */
+ uint32_t findex;
+};
+
+#define CAM_LENS_CMD (0x1 << 0x0)
+#define CAM_SENSOR_CMD (0x1 << 0x1)
+#define CAM_FLASH_CMD (0x1 << 0x2)
+
+
+#endif
diff --git a/drivers/media/video/exynos/fimc-is-mc2/fimc-is-param.h b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-param.h
new file mode 100644
index 0000000..af2b8dd
--- /dev/null
+++ b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-param.h
@@ -0,0 +1,2162 @@
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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.
+ */
+
+#ifndef FIMC_IS_PARAMS_H
+#define FIMC_IS_PARAMS_H
+
+#define IS_REGION_VER 145 /* IS REGION VERSION 1.45 */
+
+/* MACROs */
+#define IS_SET_PARAM_BIT(dev, num) \
+ (num >= 32 ? set_bit((num-32), &dev->p_region_index2) \
+ : set_bit(num, &dev->p_region_index1))
+#define IS_INC_PARAM_NUM(dev) atomic_inc(&dev->p_region_num)
+
+#define IS_PARAM_GLOBAL(dev) (dev->is_p_region->parameter.global)
+#define IS_PARAM_ISP(dev) (dev->is_p_region->parameter.isp)
+#define IS_PARAM_DRC(dev) (dev->is_p_region->parameter.drc)
+#define IS_PARAM_FD(dev) (dev->is_p_region->parameter.fd)
+#define IS_HEADER(dev) (dev->is_p_region->header)
+#define IS_FACE(dev) (dev->is_p_region->face)
+#define IS_SHARED(dev) (dev->is_shared_region)
+#define IS_PARAM_SIZE (FIMC_IS_REGION_SIZE + 1)
+
+/* Global control */
+#define IS_SET_PARAM_GLOBAL_SHOTMODE_CMD(dev, x) \
+ (dev->is_p_region->parameter.global.shotmode.cmd = x)
+#define IS_SET_PARAM_GLOBAL_SHOTMODE_SKIPFRAMES(dev, x) \
+ (dev->is_p_region->parameter.global.shotmode.skip_frames = x)
+
+/* Sensor control */
+#define IS_SENSOR_SET_FRAME_RATE(dev, x) \
+ (dev->is_p_region->parameter.sensor.frame_rate.frame_rate = x)
+
+/* ISP Macros */
+#define IS_ISP_SET_PARAM_CONTROL_CMD(dev, x) \
+ (dev->is_p_region->parameter.isp.control.cmd = x)
+#define IS_ISP_SET_PARAM_CONTROL_BYPASS(dev, x) \
+ (dev->is_p_region->parameter.isp.control.bypass = x)
+#define IS_ISP_SET_PARAM_CONTROL_RUNMODE(dev, x) \
+ (dev->is_p_region->parameter.isp.control.run_mode = x)
+#define IS_ISP_SET_PARAM_CONTROL_ERR(dev, x) \
+ (dev->is_p_region->parameter.isp.control.err = x)
+
+#define IS_ISP_SET_PARAM_OTF_INPUT_CMD(dev, x) \
+ (dev->is_p_region->parameter.isp.otf_input.cmd = x)
+#define IS_ISP_SET_PARAM_OTF_INPUT_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.isp.otf_input.width = x)
+#define IS_ISP_SET_PARAM_OTF_INPUT_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.isp.otf_input.height = x)
+#define IS_ISP_SET_PARAM_OTF_INPUT_FORMAT(dev, x) \
+ (dev->is_p_region->parameter.isp.otf_input.format = x)
+#define IS_ISP_SET_PARAM_OTF_INPUT_BITWIDTH(dev, x) \
+ (dev->is_p_region->parameter.isp.otf_input.bitwidth = x)
+#define IS_ISP_SET_PARAM_OTF_INPUT_ORDER(dev, x) \
+ (dev->is_p_region->parameter.isp.otf_input.order = x)
+#define IS_ISP_SET_PARAM_OTF_INPUT_CROP_OFFSET_X(dev, x) \
+ (dev->is_p_region->parameter.isp.otf_input.crop_offset_x = x)
+#define IS_ISP_SET_PARAM_OTF_INPUT_CROP_OFFSET_Y(dev, x) \
+ (dev->is_p_region->parameter.isp.otf_input.crop_offset_y = x)
+#define IS_ISP_SET_PARAM_OTF_INPUT_CROP_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.isp.otf_input.crop_width = x)
+#define IS_ISP_SET_PARAM_OTF_INPUT_CROP_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.isp.otf_input.crop_height = x)
+#define IS_ISP_SET_PARAM_OTF_INPUT_FRAMETIME_MIN(dev, x) \
+ (dev->is_p_region->parameter.isp.otf_input.frametime_min = x)
+#define IS_ISP_SET_PARAM_OTF_INPUT_FRAMETIME_MAX(dev, x) \
+ (dev->is_p_region->parameter.isp.otf_input.frametime_max = x)
+#define IS_ISP_SET_PARAM_OTF_INPUT_ERR(dev, x) \
+ (dev->is_p_region->parameter.isp.otf_input.err = x)
+
+#define IS_ISP_SET_PARAM_DMA_INPUT1_CMD(dev, x) \
+ (dev->is_p_region->parameter.isp.dma1_input.cmd = x)
+#define IS_ISP_SET_PARAM_DMA_INPUT1_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.isp.dma1_input.width = x)
+#define IS_ISP_SET_PARAM_DMA_INPUT1_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.isp.dma1_input.height = x)
+#define IS_ISP_SET_PARAM_DMA_INPUT1_FORMAT(dev, x) \
+ (dev->is_p_region->parameter.isp.dma1_input.format = x)
+#define IS_ISP_SET_PARAM_DMA_INPUT1_BITWIDTH(dev, x) \
+ (dev->is_p_region->parameter.isp.dma1_input.bitwidth = x)
+#define IS_ISP_SET_PARAM_DMA_INPUT1_PLANE(dev, x) \
+ (dev->is_p_region->parameter.isp.dma1_input.plane = x)
+#define IS_ISP_SET_PARAM_DMA_INPUT1_ORDER(dev, x) \
+ (dev->is_p_region->parameter.isp.dma1_input.order = x)
+#define IS_ISP_SET_PARAM_DMA_INPUT1_BUFFERNUM(dev, x) \
+ (dev->is_p_region->parameter.isp.dma1_input.buffer_number = x)
+#define IS_ISP_SET_PARAM_DMA_INPUT1_BUFFERADDR(dev, x) \
+ (dev->is_p_region->parameter.isp.dma1_input.buffer_address = x)
+#define IS_ISP_SET_PARAM_DMA_INPUT1_ERR(dev, x) \
+ (dev->is_p_region->parameter.isp.dma1_input.err = x)
+
+#define IS_ISP_SET_PARAM_DMA_INPUT2_CMD(dev, x) \
+ (dev->is_p_region->parameter.isp.dma2_input.cmd = x)
+#define IS_ISP_SET_PARAM_DMA_INPUT2_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.isp.dma2_input.width = x)
+#define IS_ISP_SET_PARAM_DMA_INPUT2_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.isp.dma2_input.height = x)
+#define IS_ISP_SET_PARAM_DMA_INPUT2_FORMAT(dev, x) \
+ (dev->is_p_region->parameter.isp.dma2_input.format = x)
+#define IS_ISP_SET_PARAM_DMA_INPUT2_BITWIDTH(dev, x) \
+ (dev->is_p_region->parameter.isp.dma2_input.bitwidth = x)
+#define IS_ISP_SET_PARAM_DMA_INPUT2_PLANE(dev, x) \
+ (dev->is_p_region->parameter.isp.dma2_input.plane = x)
+#define IS_ISP_SET_PARAM_DMA_INPUT2_ORDER(dev, x) \
+ (dev->is_p_region->parameter.isp.dma2_input.order = x)
+#define IS_ISP_SET_PARAM_DMA_INPUT2_BUFFERNUM(dev, x) \
+ (dev->is_p_region->parameter.isp.dma2_input.buffer_number = x)
+#define IS_ISP_SET_PARAM_DMA_INPUT2_BUFFERADDR(dev, x) \
+ (dev->is_p_region->parameter.isp.dma2_input.buffer_address = x)
+#define IS_ISP_SET_PARAM_DMA_INPUT2_ERR(dev, x) \
+ (dev->is_p_region->parameter.isp.dma2_input.err = x)
+
+#define IS_ISP_SET_PARAM_AA_CMD(dev, x) \
+ (dev->is_p_region->parameter.isp.aa.cmd = x)
+#define IS_ISP_SET_PARAM_AA_TARGET(dev, x) \
+ (dev->is_p_region->parameter.isp.aa.target = x)
+#define IS_ISP_SET_PARAM_AA_MODE(dev, x) \
+ (dev->is_p_region->parameter.isp.aa.mode = x)
+#define IS_ISP_SET_PARAM_AA_SCENE(dev, x) \
+ (dev->is_p_region->parameter.isp.aa.scene = x)
+#define IS_ISP_SET_PARAM_AA_SLEEP(dev, x) \
+ (dev->is_p_region->parameter.isp.aa.sleep = x)
+#define IS_ISP_SET_PARAM_AA_FACE(dev, x) \
+ (dev->is_p_region->parameter.isp.aa.uiAfFace = x)
+#define IS_ISP_SET_PARAM_AA_TOUCH_X(dev, x) \
+ (dev->is_p_region->parameter.isp.aa.touch_x = x)
+#define IS_ISP_SET_PARAM_AA_TOUCH_Y(dev, x) \
+ (dev->is_p_region->parameter.isp.aa.touch_y = x)
+#define IS_ISP_SET_PARAM_AA_MANUAL_AF(dev, x) \
+ (dev->is_p_region->parameter.isp.aa.manual_af_setting = x)
+#define IS_ISP_SET_PARAM_AA_ERR(dev, x) \
+ (dev->is_p_region->parameter.isp.aa.err = x)
+
+#define IS_ISP_SET_PARAM_FLASH_CMD(dev, x) \
+ (dev->is_p_region->parameter.isp.flash.cmd = x)
+#define IS_ISP_SET_PARAM_FLASH_REDEYE(dev, x) \
+ (dev->is_p_region->parameter.isp.flash.redeye = x)
+#define IS_ISP_SET_PARAM_FLASH_ERR(dev, x) \
+ (dev->is_p_region->parameter.isp.flash.err = x)
+
+#define IS_ISP_SET_PARAM_AWB_CMD(dev, x) \
+ (dev->is_p_region->parameter.isp.awb.cmd = x)
+#define IS_ISP_SET_PARAM_AWB_ILLUMINATION(dev, x) \
+ (dev->is_p_region->parameter.isp.awb.illumination = x)
+#define IS_ISP_SET_PARAM_AWB_ERR(dev, x) \
+ (dev->is_p_region->parameter.isp.awb.err = x)
+
+#define IS_ISP_SET_PARAM_EFFECT_CMD(dev, x) \
+ (dev->is_p_region->parameter.isp.effect.cmd = x)
+#define IS_ISP_SET_PARAM_EFFECT_ERR(dev, x) \
+ (dev->is_p_region->parameter.isp.effect.err = x)
+
+#define IS_ISP_SET_PARAM_ISO_CMD(dev, x) \
+ (dev->is_p_region->parameter.isp.iso.cmd = x)
+#define IS_ISP_SET_PARAM_ISO_VALUE(dev, x) \
+ (dev->is_p_region->parameter.isp.iso.value = x)
+#define IS_ISP_SET_PARAM_ISO_ERR(dev, x) \
+ (dev->is_p_region->parameter.isp.iso.err = x)
+
+#define IS_ISP_SET_PARAM_ADJUST_CMD(dev, x) \
+ (dev->is_p_region->parameter.isp.adjust.cmd = x)
+#define IS_ISP_SET_PARAM_ADJUST_CONTRAST(dev, x) \
+ (dev->is_p_region->parameter.isp.adjust.contrast = x)
+#define IS_ISP_SET_PARAM_ADJUST_SATURATION(dev, x) \
+ (dev->is_p_region->parameter.isp.adjust.saturation = x)
+#define IS_ISP_SET_PARAM_ADJUST_SHARPNESS(dev, x) \
+ (dev->is_p_region->parameter.isp.adjust.sharpness = x)
+#define IS_ISP_SET_PARAM_ADJUST_EXPOSURE(dev, x) \
+ (dev->is_p_region->parameter.isp.adjust.exposure = x)
+#define IS_ISP_SET_PARAM_ADJUST_BRIGHTNESS(dev, x) \
+ (dev->is_p_region->parameter.isp.adjust.brightness = x)
+#define IS_ISP_SET_PARAM_ADJUST_HUE(dev, x) \
+ (dev->is_p_region->parameter.isp.adjust.hue = x)
+#define IS_ISP_SET_PARAM_ADJUST_ERR(dev, x) \
+ (dev->is_p_region->parameter.isp.adjust.err = x)
+
+#define IS_ISP_SET_PARAM_METERING_CMD(dev, x) \
+ (dev->is_p_region->parameter.isp.metering.cmd = x)
+#define IS_ISP_SET_PARAM_METERING_WIN_POS_X(dev, x) \
+ (dev->is_p_region->parameter.isp.metering.win_pos_x = x)
+#define IS_ISP_SET_PARAM_METERING_WIN_POS_Y(dev, x) \
+ (dev->is_p_region->parameter.isp.metering.win_pos_y = x)
+#define IS_ISP_SET_PARAM_METERING_WIN_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.isp.metering.win_width = x)
+#define IS_ISP_SET_PARAM_METERING_WIN_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.isp.metering.win_height = x)
+#define IS_ISP_SET_PARAM_METERING_ERR(dev, x) \
+ (dev->is_p_region->parameter.isp.metering.err = x)
+
+#define IS_ISP_SET_PARAM_AFC_CMD(dev, x) \
+ (dev->is_p_region->parameter.isp.afc.cmd = x)
+#define IS_ISP_SET_PARAM_AFC_MANUAL(dev, x) \
+ (dev->is_p_region->parameter.isp.afc.manual = x)
+#define IS_ISP_SET_PARAM_AFC_ERR(dev, x) \
+ (dev->is_p_region->parameter.isp.afc.err = x)
+
+#define IS_ISP_SET_PARAM_OTF_OUTPUT_CMD(dev, x) \
+ (dev->is_p_region->parameter.isp.otf_output.cmd = x)
+#define IS_ISP_SET_PARAM_OTF_OUTPUT_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.isp.otf_output.width = x)
+#define IS_ISP_SET_PARAM_OTF_OUTPUT_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.isp.otf_output.height = x)
+#define IS_ISP_SET_PARAM_OTF_OUTPUT_FORMAT(dev, x) \
+ (dev->is_p_region->parameter.isp.otf_output.format = x)
+#define IS_ISP_SET_PARAM_OTF_OUTPUT_BITWIDTH(dev, x) \
+ (dev->is_p_region->parameter.isp.otf_output.bitwidth = x)
+#define IS_ISP_SET_PARAM_OTF_OUTPUT_ORDER(dev, x) \
+ (dev->is_p_region->parameter.isp.otf_output.order = x)
+#define IS_ISP_SET_PARAM_OTF_OUTPUT_ERR(dev, x) \
+ (dev->is_p_region->parameter.isp.otf_output.err = x)
+
+#define IS_ISP_SET_PARAM_DMA_OUTPUT1_CMD(dev, x) \
+ (dev->is_p_region->parameter.isp.dma1_output.cmd = x)
+#define IS_ISP_SET_PARAM_DMA_OUTPUT1_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.isp.dma1_output.width = x)
+#define IS_ISP_SET_PARAM_DMA_OUTPUT1_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.isp.dma1_output.height = x)
+#define IS_ISP_SET_PARAM_DMA_OUTPUT1_FORMAT(dev, x) \
+ (dev->is_p_region->parameter.isp.dma1_output.format = x)
+#define IS_ISP_SET_PARAM_DMA_OUTPUT1_BITWIDTH(dev, x) \
+ (dev->is_p_region->parameter.isp.dma1_output.bitwidth = x)
+#define IS_ISP_SET_PARAM_DMA_OUTPUT1_PLANE(dev, x) \
+ (dev->is_p_region->parameter.isp.dma1_output.plane = x)
+#define IS_ISP_SET_PARAM_DMA_OUTPUT1_ORDER(dev, x) \
+ (dev->is_p_region->parameter.isp.dma1_output.order = x)
+#define IS_ISP_SET_PARAM_DMA_OUTPUT1_BUFFER_NUMBER(dev, x) \
+ (dev->is_p_region->parameter.isp.dma1_output.buffer_number = x)
+#define IS_ISP_SET_PARAM_DMA_OUTPUT1_BUFFER_ADDRESS(dev, x) \
+ (dev->is_p_region->parameter.isp.dma1_output.buffer_address = x)
+#define IS_ISP_SET_PARAM_DMA_OUTPUT1_MASK(dev, x) \
+ (dev->is_p_region->parameter.isp.dma1_output.dma_out_mask = x)
+#define IS_ISP_SET_PARAM_DMA_OUTPUT1_ERR(dev, x) \
+ (dev->is_p_region->parameter.isp.dma1_output.err = x)
+
+#define IS_ISP_SET_PARAM_DMA_OUTPUT2_CMD(dev, x) \
+ (dev->is_p_region->parameter.isp.dma2_output.cmd = x)
+#define IS_ISP_SET_PARAM_DMA_OUTPUT2_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.isp.dma2_output.width = x)
+#define IS_ISP_SET_PARAM_DMA_OUTPUT2_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.isp.dma2_output.height = x)
+#define IS_ISP_SET_PARAM_DMA_OUTPUT2_FORMAT(dev, x) \
+ (dev->is_p_region->parameter.isp.dma2_output.format = x)
+#define IS_ISP_SET_PARAM_DMA_OUTPUT2_BITWIDTH(dev, x) \
+ (dev->is_p_region->parameter.isp.dma2_output.bitwidth = x)
+#define IS_ISP_SET_PARAM_DMA_OUTPUT2_PLANE(dev, x) \
+ (dev->is_p_region->parameter.isp.dma2_output.plane = x)
+#define IS_ISP_SET_PARAM_DMA_OUTPUT2_ORDER(dev, x) \
+ (dev->is_p_region->parameter.isp.dma2_output.order = x)
+#define IS_ISP_SET_PARAM_DMA_OUTPUT2_BUFFER_NUMBER(dev, x) \
+ (dev->is_p_region->parameter.isp.dma2_output.buffer_number = x)
+#define IS_ISP_SET_PARAM_DMA_OUTPUT2_BUFFER_ADDRESS(dev, x) \
+ (dev->is_p_region->parameter.isp.dma2_output.buffer_address = x)
+#define IS_ISP_SET_PARAM_DMA_OUTPUT2_MASK(dev, x) \
+ (dev->is_p_region->parameter.isp.dma2_output.dma_out_mask = x)
+#define IS_ISP_SET_PARAM_DMA_OUTPUT2_DMA_DONE(dev, x) \
+ (dev->is_p_region->parameter.isp.dma2_output.notify_dma_done = x)
+
+#define IS_ISP_SET_PARAM_DMA_OUTPUT2_ERR(dev, x) \
+ (dev->is_p_region->parameter.isp.dma2_output.err = x)
+
+/* DRC Macros */
+#define IS_DRC_SET_PARAM_CONTROL_CMD(dev, x) \
+ (dev->is_p_region->parameter.drc.control.cmd = x)
+#define IS_DRC_SET_PARAM_CONTROL_BYPASS(dev, x) \
+ (dev->is_p_region->parameter.drc.control.bypass = x)
+#define IS_DRC_SET_PARAM_CONTROL_ERR(dev, x) \
+ (dev->is_p_region->parameter.drc.control.err = x)
+
+#define IS_DRC_SET_PARAM_OTF_INPUT_CMD(dev, x) \
+ (dev->is_p_region->parameter.drc.otf_input.cmd = x)
+#define IS_DRC_SET_PARAM_OTF_INPUT_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.drc.otf_input.width = x)
+#define IS_DRC_SET_PARAM_OTF_INPUT_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.drc.otf_input.height = x)
+#define IS_DRC_SET_PARAM_OTF_INPUT_FORMAT(dev, x) \
+ (dev->is_p_region->parameter.drc.otf_input.format = x)
+#define IS_DRC_SET_PARAM_OTF_INPUT_BITWIDTH(dev, x) \
+ (dev->is_p_region->parameter.drc.otf_input.bitwidth = x)
+#define IS_DRC_SET_PARAM_OTF_INPUT_ORDER(dev, x) \
+ (dev->is_p_region->parameter.drc.otf_input.order = x)
+#define IS_DRC_SET_PARAM_OTF_INPUT_ERR(dev, x) \
+ (dev->is_p_region->parameter.drc.otf_input.err = x)
+
+#define IS_DRC_SET_PARAM_DMA_INPUT_CMD(dev, x) \
+ (dev->is_p_region->parameter.drc.dma_input.cmd = x)
+#define IS_DRC_SET_PARAM_DMA_INPUT_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.drc.dma_input.width = x)
+#define IS_DRC_SET_PARAM_DMA_INPUT_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.drc.dma_input.height = x)
+#define IS_DRC_SET_PARAM_DMA_INPUT_FORMAT(dev, x) \
+ (dev->is_p_region->parameter.drc.dma_input.format = x)
+#define IS_DRC_SET_PARAM_DMA_INPUT_BITWIDTH(dev, x) \
+ (dev->is_p_region->parameter.drc.dma_input.bitwidth = x)
+#define IS_DRC_SET_PARAM_DMA_INPUT_PLANE(dev, x) \
+ (dev->is_p_region->parameter.drc.dma_input.plane = x)
+#define IS_DRC_SET_PARAM_DMA_INPUT_ORDER(dev, x) \
+ (dev->is_p_region->parameter.drc.dma_input.order = x)
+#define IS_DRC_SET_PARAM_DMA_INPUT_BUFFERNUM(dev, x) \
+ (dev->is_p_region->parameter.drc.dma_input.buffer_number = x)
+#define IS_DRC_SET_PARAM_DMA_INPUT_BUFFERADDR(dev, x) \
+ (dev->is_p_region->parameter.drc.dma_input.buffer_address = x)
+#define IS_DRC_SET_PARAM_DMA_INPUT_ERR(dev, x) \
+ (dev->is_p_region->parameter.drc.dma_input.err = x)
+
+#define IS_DRC_SET_PARAM_OTF_OUTPUT_CMD(dev, x) \
+ (dev->is_p_region->parameter.drc.otf_output.cmd = x)
+#define IS_DRC_SET_PARAM_OTF_OUTPUT_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.drc.otf_output.width = x)
+#define IS_DRC_SET_PARAM_OTF_OUTPUT_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.drc.otf_output.height = x)
+#define IS_DRC_SET_PARAM_OTF_OUTPUT_FORMAT(dev, x) \
+ (dev->is_p_region->parameter.drc.otf_output.format = x)
+#define IS_DRC_SET_PARAM_OTF_OUTPUT_BITWIDTH(dev, x) \
+ (dev->is_p_region->parameter.drc.otf_output.bitwidth = x)
+#define IS_DRC_SET_PARAM_OTF_OUTPUT_ORDER(dev, x) \
+ (dev->is_p_region->parameter.drc.otf_output.order = x)
+#define IS_DRC_SET_PARAM_OTF_OUTPUT_ERR(dev, x) \
+ (dev->is_p_region->parameter.drc.otf_output.err = x)
+
+/* SCALER-C Macros */
+#define IS_SCALERC_SET_PARAM_CONTROL_CMD(dev, x) \
+ (dev->is_p_region->parameter.scalerc.control.cmd = x)
+#define IS_SCALERC_SET_PARAM_CONTROL_BYPASS(dev, x) \
+ (dev->is_p_region->parameter.scalerc.control.bypass = x)
+#define IS_SCALERC_SET_PARAM_CONTROL_ERR(dev, x) \
+ (dev->is_p_region->parameter.scalerc.control.err = x)
+
+#define IS_SCALERC_SET_PARAM_OTF_INPUT_CMD(dev, x) \
+ (dev->is_p_region->parameter.scalerc.otf_input.cmd = x)
+#define IS_SCALERC_SET_PARAM_OTF_INPUT_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.scalerc.otf_input.width = x)
+#define IS_SCALERC_SET_PARAM_OTF_INPUT_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.scalerc.otf_input.height = x)
+#define IS_SCALERC_SET_PARAM_OTF_INPUT_FORMAT(dev, x) \
+ (dev->is_p_region->parameter.scalerc.otf_input.format = x)
+#define IS_SCALERC_SET_PARAM_OTF_INPUT_BITWIDTH(dev, x) \
+ (dev->is_p_region->parameter.scalerc.otf_input.bitwidth = x)
+#define IS_SCALERC_SET_PARAM_OTF_INPUT_ORDER(dev, x) \
+ (dev->is_p_region->parameter.scalerc.otf_input.order = x)
+#define IS_SCALERC_SET_PARAM_OTF_INPUT_ERR(dev, x) \
+ (dev->is_p_region->parameter.scalerc.otf_input.err = x)
+
+#define IS_SCALERC_SET_PARAM_EFFECT_CMD(dev, x) \
+ (dev->is_p_region->parameter.scalerc.effect.cmd = x)
+#define IS_SCALERC_SET_PARAM_EFFECT_ERR(dev, x) \
+ (dev->is_p_region->parameter.scalerc.effect.err = x)
+
+#define IS_SCALERC_SET_PARAM_INPUT_CROP_CMD(dev, x) \
+ (dev->is_p_region->parameter.scalerc.input_crop.cmd = x)
+#define IS_SCALERC_SET_PARAM_INPUT_CROP_POS_X(dev, x) \
+ (dev->is_p_region->parameter.scalerc.input_crop.pos_x = x)
+#define IS_SCALERC_SET_PARAM_INPUT_CROP_POS_Y(dev, x) \
+ (dev->is_p_region->parameter.scalerc.input_crop.pos_y = x)
+#define IS_SCALERC_SET_PARAM_INPUT_CROP_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.scalerc.input_crop.crop_width = x)
+#define IS_SCALERC_SET_PARAM_INPUT_CROP_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.scalerc.input_crop.crop_height = x)
+#define IS_SCALERC_SET_PARAM_INPUT_CROP_IN_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.scalerc.input_crop.in_width = x)
+#define IS_SCALERC_SET_PARAM_INPUT_CROP_IN_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.scalerc.input_crop.in_height = x)
+#define IS_SCALERC_SET_PARAM_INPUT_CROP_OUT_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.scalerc.input_crop.out_width = x)
+#define IS_SCALERC_SET_PARAM_INPUT_CROP_OUT_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.scalerc.input_crop.out_height = x)
+#define IS_SCALERC_SET_PARAM_INPUT_CROP_ERR(dev, x) \
+ (dev->is_p_region->parameter.scalerc.input_crop.err = x)
+
+#define IS_SCALERC_SET_PARAM_OUTPUT_CROP_CMD(dev, x) \
+ (dev->is_p_region->parameter.scalerc.output_crop.cmd = x)
+#define IS_SCALERC_SET_PARAM_OUTPUT_CROP_POS_X(dev, x) \
+ (dev->is_p_region->parameter.scalerc.output_crop.pos_x = x)
+#define IS_SCALERC_SET_PARAM_OUTPUT_CROP_POS_Y(dev, x) \
+ (dev->is_p_region->parameter.scalerc.output_crop.pos_y = x)
+#define IS_SCALERC_SET_PARAM_OUTPUT_CROP_CROP_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.scalerc.output_crop.crop_width = x)
+#define IS_SCALERC_SET_PARAM_OUTPUT_CROP_CROP_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.scalerc.output_crop.crop_height = x)
+#define IS_SCALERC_SET_PARAM_OUTPUT_CROPG_FORMAT(dev, x) \
+ (dev->is_p_region->parameter.scalerc.output_crop.format = x)
+#define IS_SCALERC_SET_PARAM_OUTPUT_CROP_ERR(dev, x) \
+ (dev->is_p_region->parameter.scalerc.output_crop.err = x)
+
+#define IS_SCALERC_SET_PARAM_OTF_OUTPUT_CMD(dev, x) \
+ (dev->is_p_region->parameter.scalerc.otf_output.cmd = x)
+#define IS_SCALERC_SET_PARAM_OTF_OUTPUT_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.scalerc.otf_output.width = x)
+#define IS_SCALERC_SET_PARAM_OTF_OUTPUT_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.scalerc.otf_output.height = x)
+#define IS_SCALERC_SET_PARAM_OTF_OUTPUT_FORMAT(dev, x) \
+ (dev->is_p_region->parameter.scalerc.otf_output.format = x)
+#define IS_SCALERC_SET_PARAM_OTF_OUTPUT_BITWIDTH(dev, x) \
+ (dev->is_p_region->parameter.scalerc.otf_output.bitwidth = x)
+#define IS_SCALERC_SET_PARAM_OTF_OUTPUT_ORDER(dev, x) \
+ (dev->is_p_region->parameter.scalerc.otf_output.order = x)
+#define IS_SCALERC_SET_PARAM_OTF_OUTPUT_ERR(dev, x) \
+ (dev->is_p_region->parameter.scalerc.otf_output.err = x)
+
+#define IS_SCALERC_SET_PARAM_DMA_OUTPUT_CMD(dev, x) \
+ (dev->is_p_region->parameter.scalerc.dma_output.cmd = x)
+#define IS_SCALERC_SET_PARAM_DMA_OUTPUT_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.scalerc.dma_output.width = x)
+#define IS_SCALERC_SET_PARAM_DMA_OUTPUT_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.scalerc.dma_output.height = x)
+#define IS_SCALERC_SET_PARAM_DMA_OUTPUT_FORMAT(dev, x) \
+ (dev->is_p_region->parameter.scalerc.dma_output.format = x)
+#define IS_SCALERC_SET_PARAM_DMA_OUTPUT_BITWIDTH(dev, x) \
+ (dev->is_p_region->parameter.scalerc.dma_output.bitwidth = x)
+#define IS_SCALERC_SET_PARAM_DMA_OUTPUT_PLANE(dev, x) \
+ (dev->is_p_region->parameter.scalerc.dma_output.plane = x)
+#define IS_SCALERC_SET_PARAM_DMA_OUTPUT_ORDER(dev, x) \
+ (dev->is_p_region->parameter.scalerc.dma_output.order = x)
+#define IS_SCALERC_SET_PARAM_DMA_OUTPUT_BUFFERNUM(dev, x) \
+ (dev->is_p_region->parameter.scalerc.dma_output.buffer_number = x)
+#define IS_SCALERC_SET_PARAM_DMA_OUTPUT_BUFFERADDR(dev, x) \
+ (dev->is_p_region->parameter.scalerc.dma_output.buffer_address = x)
+#define IS_SCALERC_SET_PARAM_DMA_OUTPUT_MASK(dev, x) \
+ (dev->is_p_region->parameter.scalerc.dma_output.dma_out_mask = x)
+#define IS_SCALERC_SET_PARAM_DMA_OUTPUT_OUTPATH(dev, x) \
+ (dev->is_p_region->parameter.scalerc.dma_output.reserved[0] = x)
+#define IS_SCALERC_SET_PARAM_DMA_OUTPUT_ERR(dev, x) \
+ (dev->is_p_region->parameter.scalerc.dma_output.err = x)
+
+/* ODC Macros */
+#define IS_ODC_SET_PARAM_CONTROL_CMD(dev, x) \
+ (dev->is_p_region->parameter.odc.control.cmd = x)
+#define IS_ODC_SET_PARAM_CONTROL_BUFFERNUM(dev, x) \
+ (dev->is_p_region->parameter.odc.control.buffer_number = x)
+#define IS_ODC_SET_PARAM_CONTROL_BUFFERADDR(dev, x) \
+ (dev->is_p_region->parameter.odc.control.buffer_address = x)
+#define IS_ODC_SET_PARAM_CONTROL_BYPASS(dev, x) \
+ (dev->is_p_region->parameter.odc.control.bypass = x)
+#define IS_ODC_SET_PARAM_CONTROL_ERR(dev, x) \
+ (dev->is_p_region->parameter.odc.control.err = x)
+
+#define IS_ODC_SET_PARAM_OTF_INPUT_CMD(dev, x) \
+ (dev->is_p_region->parameter.odc.otf_input.cmd = x)
+#define IS_ODC_SET_PARAM_OTF_INPUT_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.odc.otf_input.width = x)
+#define IS_ODC_SET_PARAM_OTF_INPUT_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.odc.otf_input.height = x)
+#define IS_ODC_SET_PARAM_OTF_INPUT_FORMAT(dev, x) \
+ (dev->is_p_region->parameter.odc.otf_input.format = x)
+#define IS_ODC_SET_PARAM_OTF_INPUT_BITWIDTH(dev, x) \
+ (dev->is_p_region->parameter.odc.otf_input.bitwidth = x)
+#define IS_ODC_SET_PARAM_OTF_INPUT_ORDER(dev, x) \
+ (dev->is_p_region->parameter.odc.otf_input.order = x)
+#define IS_ODC_SET_PARAM_OTF_INPUT_ERR(dev, x) \
+ (dev->is_p_region->parameter.odc.otf_input.err = x)
+
+#define IS_ODC_SET_PARAM_OTF_OUTPUT_CMD(dev, x) \
+ (dev->is_p_region->parameter.odc.otf_output.cmd = x)
+#define IS_ODC_SET_PARAM_OTF_OUTPUT_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.odc.otf_output.width = x)
+#define IS_ODC_SET_PARAM_OTF_OUTPUT_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.odc.otf_output.height = x)
+#define IS_ODC_SET_PARAM_OTF_OUTPUT_FORMAT(dev, x) \
+ (dev->is_p_region->parameter.odc.otf_output.format = x)
+#define IS_ODC_SET_PARAM_OTF_OUTPUT_BITWIDTH(dev, x) \
+ (dev->is_p_region->parameter.odc.otf_output.bitwidth = x)
+#define IS_ODC_SET_PARAM_OTF_OUTPUT_ORDER(dev, x) \
+ (dev->is_p_region->parameter.odc.otf_output.order = x)
+#define IS_ODC_SET_PARAM_OTF_OUTPUT_ERR(dev, x) \
+ (dev->is_p_region->parameter.odc.otf_output.err = x)
+
+/* DIS Macros */
+#define IS_DIS_SET_PARAM_CONTROL_CMD(dev, x) \
+ (dev->is_p_region->parameter.dis.control.cmd = x)
+#define IS_DIS_SET_PARAM_CONTROL_BUFFERNUM(dev, x) \
+ (dev->is_p_region->parameter.dis.control.buffer_number = x)
+#define IS_DIS_SET_PARAM_CONTROL_BUFFERADDR(dev, x) \
+ (dev->is_p_region->parameter.dis.control.buffer_address = x)
+#define IS_DIS_SET_PARAM_CONTROL_BYPASS(dev, x) \
+ (dev->is_p_region->parameter.dis.control.bypass = x)
+#define IS_DIS_SET_PARAM_CONTROL_ERR(dev, x) \
+ (dev->is_p_region->parameter.dis.control.err = x)
+
+#define IS_DIS_SET_PARAM_OTF_INPUT_CMD(dev, x) \
+ (dev->is_p_region->parameter.dis.otf_input.cmd = x)
+#define IS_DIS_SET_PARAM_OTF_INPUT_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.dis.otf_input.width = x)
+#define IS_DIS_SET_PARAM_OTF_INPUT_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.dis.otf_input.height = x)
+#define IS_DIS_SET_PARAM_OTF_INPUT_FORMAT(dev, x) \
+ (dev->is_p_region->parameter.dis.otf_input.format = x)
+#define IS_DIS_SET_PARAM_OTF_INPUT_BITWIDTH(dev, x) \
+ (dev->is_p_region->parameter.dis.otf_input.bitwidth = x)
+#define IS_DIS_SET_PARAM_OTF_INPUT_ORDER(dev, x) \
+ (dev->is_p_region->parameter.dis.otf_input.order = x)
+#define IS_DIS_SET_PARAM_OTF_INPUT_ERR(dev, x) \
+ (dev->is_p_region->parameter.dis.otf_input.err = x)
+
+#define IS_DIS_SET_PARAM_OTF_OUTPUT_CMD(dev, x) \
+ (dev->is_p_region->parameter.dis.otf_output.cmd = x)
+#define IS_DIS_SET_PARAM_OTF_OUTPUT_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.dis.otf_output.width = x)
+#define IS_DIS_SET_PARAM_OTF_OUTPUT_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.dis.otf_output.height = x)
+#define IS_DIS_SET_PARAM_OTF_OUTPUT_FORMAT(dev, x) \
+ (dev->is_p_region->parameter.dis.otf_output.format = x)
+#define IS_DIS_SET_PARAM_OTF_OUTPUT_BITWIDTH(dev, x) \
+ (dev->is_p_region->parameter.dis.otf_output.bitwidth = x)
+#define IS_DIS_SET_PARAM_OTF_OUTPUT_ORDER(dev, x) \
+ (dev->is_p_region->parameter.dis.otf_output.order = x)
+#define IS_DIS_SET_PARAM_OTF_OUTPUT_ERR(dev, x) \
+ (dev->is_p_region->parameter.dis.otf_output.err = x)
+
+/* TDNR Macros */
+#define IS_TDNR_SET_PARAM_CONTROL_CMD(dev, x) \
+ (dev->is_p_region->parameter.tdnr.control.cmd = x)
+#define IS_TDNR_SET_PARAM_CONTROL_BYPASS(dev, x) \
+ (dev->is_p_region->parameter.tdnr.control.bypass = x)
+#define IS_TDNR_SET_PARAM_CONTROL_BUFFERNUM(dev, x) \
+ (dev->is_p_region->parameter.tdnr.control.buffer_number = x)
+#define IS_TDNR_SET_PARAM_CONTROL_BUFFERADDR(dev, x) \
+ (dev->is_p_region->parameter.tdnr.control.buffer_address = x)
+#define IS_TDNR_SET_PARAM_CONTROL_ERR(dev, x) \
+ (dev->is_p_region->parameter.tdnr.control.err = x)
+
+#define IS_TDNR_SET_PARAM_OTF_INPUT_CMD(dev, x) \
+ (dev->is_p_region->parameter.tdnr.otf_input.cmd = x)
+#define IS_TDNR_SET_PARAM_OTF_INPUT_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.tdnr.otf_input.width = x)
+#define IS_TDNR_SET_PARAM_OTF_INPUT_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.tdnr.otf_input.height = x)
+#define IS_TDNR_SET_PARAM_OTF_INPUT_FORMAT(dev, x) \
+ (dev->is_p_region->parameter.tdnr.otf_input.format = x)
+#define IS_TDNR_SET_PARAM_OTF_INPUT_BITWIDTH(dev, x) \
+ (dev->is_p_region->parameter.tdnr.otf_input.bitwidth = x)
+#define IS_TDNR_SET_PARAM_OTF_INPUT_ORDER(dev, x) \
+ (dev->is_p_region->parameter.tdnr.otf_input.order = x)
+#define IS_TDNR_SET_PARAM_OTF_INPUT_ERR(dev, x) \
+ (dev->is_p_region->parameter.tdnr.otf_input.err = x)
+
+#define IS_TDNR_SET_PARAM_FRAME_CMD(dev, x) \
+ (dev->is_p_region->parameter.tdnr.frame.cmd = x)
+#define IS_TDNR_SET_PARAM_FRAME_ERR(dev, x) \
+ (dev->is_p_region->parameter.tdnr.frame.err = x)
+
+#define IS_TDNR_SET_PARAM_OTF_OUTPUT_CMD(dev, x) \
+ (dev->is_p_region->parameter.tdnr.otf_output.cmd = x)
+#define IS_TDNR_SET_PARAM_OTF_OUTPUT_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.tdnr.otf_output.width = x)
+#define IS_TDNR_SET_PARAM_OTF_OUTPUT_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.tdnr.otf_output.height = x)
+#define IS_TDNR_SET_PARAM_OTF_OUTPUT_FORMAT(dev, x) \
+ (dev->is_p_region->parameter.tdnr.otf_output.format = x)
+#define IS_TDNR_SET_PARAM_OTF_OUTPUT_BITWIDTH(dev, x) \
+ (dev->is_p_region->parameter.tdnr.otf_output.bitwidth = x)
+#define IS_TDNR_SET_PARAM_OTF_OUTPUT_ORDER(dev, x) \
+ (dev->is_p_region->parameter.tdnr.otf_output.order = x)
+#define IS_TDNR_SET_PARAM_OTF_OUTPUT_ERR(dev, x) \
+ (dev->is_p_region->parameter.tdnr.otf_output.err = x)
+
+#define IS_TDNR_SET_PARAM_DMA_OUTPUT_CMD(dev, x) \
+ (dev->is_p_region->parameter.tdnr.dma_output.cmd = x)
+#define IS_TDNR_SET_PARAM_DMA_OUTPUT_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.tdnr.dma_output.width = x)
+#define IS_TDNR_SET_PARAM_DMA_OUTPUT_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.tdnr.dma_output.height = x)
+#define IS_TDNR_SET_PARAM_DMA_OUTPUT_FORMAT(dev, x) \
+ (dev->is_p_region->parameter.tdnr.dma_output.format = x)
+#define IS_TDNR_SET_PARAM_DMA_OUTPUT_BITWIDTH(dev, x) \
+ (dev->is_p_region->parameter.tdnr.dma_output.bitwidth = x)
+#define IS_TDNR_SET_PARAM_DMA_OUTPUT_PLANE(dev, x) \
+ (dev->is_p_region->parameter.tdnr.dma_output.plane = x)
+#define IS_TDNR_SET_PARAM_DMA_OUTPUT_ORDER(dev, x) \
+ (dev->is_p_region->parameter.tdnr.dma_output.order = x)
+#define IS_TDNR_SET_PARAM_DMA_OUTPUT_BUFFERNUM(dev, x) \
+ (dev->is_p_region->parameter.tdnr.dma_output.buffer_number = x)
+#define IS_TDNR_SET_PARAM_DMA_OUTPUT_BUFFERADDR(dev, x) \
+ (dev->is_p_region->parameter.tdnr.dma_output.buffer_address = x)
+#define IS_TDNR_SET_PARAM_DMA_OUTPUT_MASK(dev, x) \
+ (dev->is_p_region->parameter.tdnr.dma_output.dma_out_mask = x)
+#define IS_TDNR_SET_PARAM_DMA_OUTPUT_ERR(dev, x) \
+ (dev->is_p_region->parameter.tdnr.dma_output.err = x)
+
+/* SCALER-P Macros */
+#define IS_SCALERP_SET_PARAM_CONTROL_CMD(dev, x) \
+ (dev->is_p_region->parameter.scalerp.control.cmd = x)
+#define IS_SCALERP_SET_PARAM_CONTROL_BYPASS(dev, x) \
+ (dev->is_p_region->parameter.scalerp.control.bypass = x)
+#define IS_SCALERP_SET_PARAM_CONTROL_ERR(dev, x) \
+ (dev->is_p_region->parameter.scalerp.control.err = x)
+
+#define IS_SCALERP_SET_PARAM_OTF_INPUT_CMD(dev, x) \
+ (dev->is_p_region->parameter.scalerp.otf_input.cmd = x)
+#define IS_SCALERP_SET_PARAM_OTF_INPUT_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.scalerp.otf_input.width = x)
+#define IS_SCALERP_SET_PARAM_OTF_INPUT_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.scalerp.otf_input.height = x)
+#define IS_SCALERP_SET_PARAM_OTF_INPUT_FORMAT(dev, x) \
+ (dev->is_p_region->parameter.scalerp.otf_input.format = x)
+#define IS_SCALERP_SET_PARAM_OTF_INPUT_BITWIDTH(dev, x) \
+ (dev->is_p_region->parameter.scalerp.otf_input.bitwidth = x)
+#define IS_SCALERP_SET_PARAM_OTF_INPUT_ORDER(dev, x) \
+ (dev->is_p_region->parameter.scalerp.otf_input.order = x)
+#define IS_SCALERP_SET_PARAM_OTF_INPUT_ERR(dev, x) \
+ (dev->is_p_region->parameter.scalerp.otf_input.err = x)
+
+#define IS_SCALERP_SET_PARAM_EFFECT_CMD(dev, x) \
+ (dev->is_p_region->parameter.scalerp.effect.cmd = x)
+#define IS_SCALERP_SET_PARAM_EFFECT_ERR(dev, x) \
+ (dev->is_p_region->parameter.scalerp.effect.err = x)
+
+#define IS_SCALERP_SET_PARAM_INPUT_CROP_CMD(dev, x) \
+ (dev->is_p_region->parameter.scalerp.input_crop.cmd = x)
+#define IS_SCALERP_SET_PARAM_INPUT_CROP_POS_X(dev, x) \
+ (dev->is_p_region->parameter.scalerp.input_crop.pos_x = x)
+#define IS_SCALERP_SET_PARAM_INPUT_CROP_POS_Y(dev, x) \
+ (dev->is_p_region->parameter.scalerp.input_crop.pos_y = x)
+#define IS_SCALERP_SET_PARAM_INPUT_CROP_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.scalerp.input_crop.crop_width = x)
+#define IS_SCALERP_SET_PARAM_INPUT_CROP_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.scalerp.input_crop.crop_height = x)
+#define IS_SCALERP_SET_PARAM_INPUT_CROP_IN_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.scalerp.input_crop.in_width = x)
+#define IS_SCALERP_SET_PARAM_INPUT_CROP_IN_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.scalerp.input_crop.in_height = x)
+#define IS_SCALERP_SET_PARAM_INPUT_CROP_OUT_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.scalerp.input_crop.out_width = x)
+#define IS_SCALERP_SET_PARAM_INPUT_CROP_OUT_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.scalerp.input_crop.out_height = x)
+#define IS_SCALERP_SET_PARAM_INPUT_CROP_ERR(dev, x) \
+ (dev->is_p_region->parameter.scalerp.input_crop.err = x)
+
+#define IS_SCALERP_SET_PARAM_OUTPUT_CROP_CMD(dev, x) \
+ (dev->is_p_region->parameter.scalerp.output_crop.cmd = x)
+#define IS_SCALERP_SET_PARAM_OUTPUT_CROP_POS_X(dev, x) \
+ (dev->is_p_region->parameter.scalerp.output_crop.pos_x = x)
+#define IS_SCALERP_SET_PARAM_OUTPUT_CROP_POS_Y(dev, x) \
+ (dev->is_p_region->parameter.scalerp.output_crop.pos_y = x)
+#define IS_SCALERP_SET_PARAM_OUTPUT_CROP_CROP_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.scalerp.output_crop.crop_width = x)
+#define IS_SCALERP_SET_PARAM_OUTPUT_CROP_CROP_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.scalerp.output_crop.crop_height = x)
+#define IS_SCALERP_SET_PARAM_OUTPUT_CROPG_FORMAT(dev, x) \
+ (dev->is_p_region->parameter.scalerp.output_crop.format = x)
+#define IS_SCALERP_SET_PARAM_OUTPUT_CROP_ERR(dev, x) \
+ (dev->is_p_region->parameter.scalerp.output_crop.err = x)
+
+#define IS_SCALERP_SET_PARAM_ROTATION_CMD(dev, x) \
+ (dev->is_p_region->parameter.scalerp.rotation.cmd = x)
+#define IS_SCALERP_SET_PARAM_ROTATION_ERR(dev, x) \
+ (dev->is_p_region->parameter.scalerp.rotation.err = x)
+
+#define IS_SCALERP_SET_PARAM_FLIP_CMD(dev, x) \
+ (dev->is_p_region->parameter.scalerp.flip.cmd = x)
+#define IS_SCALERP_SET_PARAM_FLIP_ERR(dev, x) \
+ (dev->is_p_region->parameter.scalerp.flip.err = x)
+
+#define IS_SCALERP_SET_PARAM_OTF_OUTPUT_CMD(dev, x) \
+ (dev->is_p_region->parameter.scalerp.otf_output.cmd = x)
+#define IS_SCALERP_SET_PARAM_OTF_OUTPUT_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.scalerp.otf_output.width = x)
+#define IS_SCALERP_SET_PARAM_OTF_OUTPUT_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.scalerp.otf_output.height = x)
+#define IS_SCALERP_SET_PARAM_OTF_OUTPUT_FORMAT(dev, x) \
+ (dev->is_p_region->parameter.scalerp.otf_output.format = x)
+#define IS_SCALERP_SET_PARAM_OTF_OUTPUT_BITWIDTH(dev, x) \
+ (dev->is_p_region->parameter.scalerp.otf_output.bitwidth = x)
+#define IS_SCALERP_SET_PARAM_OTF_OUTPUT_ORDER(dev, x) \
+ (dev->is_p_region->parameter.scalerp.otf_output.order = x)
+#define IS_SCALERP_SET_PARAM_OTF_OUTPUT_ERR(dev, x) \
+ (dev->is_p_region->parameter.scalerp.otf_output.err = x)
+
+#define IS_SCALERP_SET_PARAM_DMA_OUTPUT_CMD(dev, x) \
+ (dev->is_p_region->parameter.scalerp.dma_output.cmd = x)
+#define IS_SCALERP_SET_PARAM_DMA_OUTPUT_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.scalerp.dma_output.width = x)
+#define IS_SCALERP_SET_PARAM_DMA_OUTPUT_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.scalerp.dma_output.height = x)
+#define IS_SCALERP_SET_PARAM_DMA_OUTPUT_FORMAT(dev, x) \
+ (dev->is_p_region->parameter.scalerp.dma_output.format = x)
+#define IS_SCALERP_SET_PARAM_DMA_OUTPUT_BITWIDTH(dev, x) \
+ (dev->is_p_region->parameter.scalerp.dma_output.bitwidth = x)
+#define IS_SCALERP_SET_PARAM_DMA_OUTPUT_PLANE(dev, x) \
+ (dev->is_p_region->parameter.scalerp.dma_output.plane = x)
+#define IS_SCALERP_SET_PARAM_DMA_OUTPUT_ORDER(dev, x) \
+ (dev->is_p_region->parameter.scalerp.dma_output.order = x)
+#define IS_SCALERP_SET_PARAM_DMA_OUTPUT_BUFFERNUM(dev, x) \
+ (dev->is_p_region->parameter.scalerp.dma_output.buffer_number = x)
+#define IS_SCALERP_SET_PARAM_DMA_OUTPUT_BUFFERADDR(dev, x) \
+ (dev->is_p_region->parameter.scalerp.dma_output.buffer_address = x)
+#define IS_SCALERP_SET_PARAM_DMA_OUTPUT_MASK(dev, x) \
+ (dev->is_p_region->parameter.scalerp.dma_output.dma_out_mask = x)
+#define IS_SCALERP_SET_PARAM_DMA_OUTPUT_ERR(dev, x) \
+ (dev->is_p_region->parameter.scalerp.dma_output.err = x)
+
+/* FD Macros */
+#define IS_FD_SET_PARAM_CONTROL_CMD(dev, x) \
+ (dev->is_p_region->parameter.fd.control.cmd = x)
+#define IS_FD_SET_PARAM_CONTROL_BYPASS(dev, x) \
+ (dev->is_p_region->parameter.fd.control.bypass = x)
+#define IS_FD_SET_PARAM_CONTROL_ERR(dev, x) \
+ (dev->is_p_region->parameter.fd.control.err = x)
+
+#define IS_FD_SET_PARAM_OTF_INPUT_CMD(dev, x) \
+ (dev->is_p_region->parameter.fd.otf_input.cmd = x)
+#define IS_FD_SET_PARAM_OTF_INPUT_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.fd.otf_input.width = x)
+#define IS_FD_SET_PARAM_OTF_INPUT_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.fd.otf_input.height = x)
+#define IS_FD_SET_PARAM_OTF_INPUT_FORMAT(dev, x) \
+ (dev->is_p_region->parameter.fd.otf_input.format = x)
+#define IS_FD_SET_PARAM_OTF_INPUT_BITWIDTH(dev, x) \
+ (dev->is_p_region->parameter.fd.otf_input.bitwidth = x)
+#define IS_FD_SET_PARAM_OTF_INPUT_ORDER(dev, x) \
+ (dev->is_p_region->parameter.fd.otf_input.order = x)
+#define IS_FD_SET_PARAM_OTF_INPUT_ERR(dev, x) \
+ (dev->is_p_region->parameter.fd.otf_input.err = x)
+
+#define IS_FD_SET_PARAM_DMA_INPUT_CMD(dev, x) \
+ (dev->is_p_region->parameter.fd.dma_input.cmd = x)
+#define IS_FD_SET_PARAM_DMA_INPUT_WIDTH(dev, x) \
+ (dev->is_p_region->parameter.fd.dma_input.width = x)
+#define IS_FD_SET_PARAM_DMA_INPUT_HEIGHT(dev, x) \
+ (dev->is_p_region->parameter.fd.dma_input.height = x)
+#define IS_FD_SET_PARAM_DMA_INPUT_FORMAT(dev, x) \
+ (dev->is_p_region->parameter.fd.dma_input.format = x)
+#define IS_FD_SET_PARAM_DMA_INPUT_BITWIDTH(dev, x) \
+ (dev->is_p_region->parameter.fd.dma_input.bitwidth = x)
+#define IS_FD_SET_PARAM_DMA_INPUT_PLANE(dev, x) \
+ (dev->is_p_region->parameter.fd.dma_input.plane = x)
+#define IS_FD_SET_PARAM_DMA_INPUT_ORDER(dev, x) \
+ (dev->is_p_region->parameter.fd.dma_input.order = x)
+#define IS_FD_SET_PARAM_DMA_INPUT_BUFFERNUM(dev, x) \
+ (dev->is_p_region->parameter.fd.dma_input.buffer_number = x)
+#define IS_FD_SET_PARAM_DMA_INPUT_BUFFERADDR(dev, x) \
+ (dev->is_p_region->parameter.fd.dma_input.buffer_address = x)
+#define IS_FD_SET_PARAM_DMA_INPUT_ERR(dev, x) \
+ (dev->is_p_region->parameter.fd.dma_input.err = x)
+
+#define IS_FD_SET_PARAM_FD_CONFIG_CMD(dev, x) \
+ (dev->is_p_region->parameter.fd.config.cmd = x)
+#define IS_FD_SET_PARAM_FD_CONFIG_MAX_NUMBER(dev, x) \
+ (dev->is_p_region->parameter.fd.config.max_number = x)
+#define IS_FD_SET_PARAM_FD_CONFIG_ROLL_ANGLE(dev, x) \
+ (dev->is_p_region->parameter.fd.config.roll_angle = x)
+#define IS_FD_SET_PARAM_FD_CONFIG_YAW_ANGLE(dev, x) \
+ (dev->is_p_region->parameter.fd.config.yaw_angle = x)
+#define IS_FD_SET_PARAM_FD_CONFIG_SMILE_MODE(dev, x) \
+ (dev->is_p_region->parameter.fd.config.smile_mode = x)
+#define IS_FD_SET_PARAM_FD_CONFIG_BLINK_MODE(dev, x) \
+ (dev->is_p_region->parameter.fd.config.blink_mode = x)
+#define IS_FD_SET_PARAM_FD_CONFIG_EYE_DETECT(dev, x) \
+ (dev->is_p_region->parameter.fd.config.eye_detect = x)
+#define IS_FD_SET_PARAM_FD_CONFIG_MOUTH_DETECT(dev, x) \
+ (dev->is_p_region->parameter.fd.config.mouth_detect = x)
+#define IS_FD_SET_PARAM_FD_CONFIG_ORIENTATION(dev, x) \
+ (dev->is_p_region->parameter.fd.config.orientation = x)
+#define IS_FD_SET_PARAM_FD_CONFIG_ORIENTATION_VALUE(dev, x) \
+ (dev->is_p_region->parameter.fd.config.orientation_value = x)
+#define IS_FD_SET_PARAM_FD_CONFIG_ERR(dev, x) \
+ (dev->is_p_region->parameter.fd.config.err = x)
+
+#ifndef BIT0
+#define BIT0 0x00000001
+#define BIT1 0x00000002
+#define BIT2 0x00000004
+#define BIT3 0x00000008
+#define BIT4 0x00000010
+#define BIT5 0x00000020
+#define BIT6 0x00000040
+#define BIT7 0x00000080
+#define BIT8 0x00000100
+#define BIT9 0x00000200
+#define BIT10 0x00000400
+#define BIT11 0x00000800
+#define BIT12 0x00001000
+#define BIT13 0x00002000
+#define BIT14 0x00004000
+#define BIT15 0x00008000
+#define BIT16 0x00010000
+#define BIT17 0x00020000
+#define BIT18 0x00040000
+#define BIT19 0x00080000
+#define BIT20 0x00100000
+#define BIT21 0x00200000
+#define BIT22 0x00400000
+#define BIT23 0x00800000
+#define BIT24 0x01000000
+#define BIT25 0x02000000
+#define BIT26 0x04000000
+#define BIT27 0x08000000
+#define BIT28 0x10000000
+#define BIT29 0x20000000
+#define BIT30 0x40000000
+#define BIT31 0x80000000
+#define BIT32 0x0000000100000000ULL
+#define BIT33 0x0000000200000000ULL
+#define BIT34 0x0000000400000000ULL
+#define BIT35 0x0000000800000000ULL
+#define BIT36 0x0000001000000000ULL
+#define BIT37 0x0000002000000000ULL
+#define BIT38 0x0000004000000000ULL
+#define BIT39 0x0000008000000000ULL
+#define BIT40 0x0000010000000000ULL
+#define BIT41 0x0000020000000000ULL
+#define BIT42 0x0000040000000000ULL
+#define BIT43 0x0000080000000000ULL
+#define BIT44 0x0000100000000000ULL
+#define BIT45 0x0000200000000000ULL
+#define BIT46 0x0000400000000000ULL
+#define BIT47 0x0000800000000000ULL
+#define BIT48 0x0001000000000000ULL
+#define BIT49 0x0002000000000000ULL
+#define BIT50 0x0004000000000000ULL
+#define BIT51 0x0008000000000000ULL
+#define BIT52 0x0010000000000000ULL
+#define BIT53 0x0020000000000000ULL
+#define BIT54 0x0040000000000000ULL
+#define BIT55 0x0080000000000000ULL
+#define BIT56 0x0100000000000000ULL
+#define BIT57 0x0200000000000000ULL
+#define BIT58 0x0400000000000000ULL
+#define BIT59 0x0800000000000000ULL
+#define BIT60 0x1000000000000000ULL
+#define BIT61 0x2000000000000000ULL
+#define BIT62 0x4000000000000000ULL
+#define BIT63 0x8000000000000000ULL
+#define INC_BIT(bit) (bit<<1)
+#define INC_NUM(bit) (bit + 1)
+#endif
+
+#define MAGIC_NUMBER 0x01020304
+
+#define PARAMETER_MAX_SIZE 128 /* in byte */
+#define PARAMETER_MAX_MEMBER (PARAMETER_MAX_SIZE/4)
+
+enum is_entry {
+ ENTRY_GLOBAL,
+ ENTRY_BUFFER,
+ ENTRY_SENSOR,
+ ENTRY_ISP,
+ ENTRY_DRC,
+ ENTRY_SCALERC,
+ ENTRY_ODC,
+ ENTRY_DIS,
+ ENTRY_TDNR,
+ ENTRY_SCALERP,
+ ENTRY_LHFD, /* 10 */
+ ENTRY_END
+};
+
+enum is_param_set_bit {
+ PARAM_GLOBAL_SHOTMODE = 0,
+ PARAM_SENSOR_CONTROL,
+ PARAM_SENSOR_OTF_INPUT,
+ PARAM_SENSOR_OTF_OUTPUT,
+ PARAM_SENSOR_FRAME_RATE,
+ PARAM_SENSOR_DMA_OUTPUT,
+ PARAM_BUFFER_CONTROL,
+ PARAM_BUFFER_OTF_INPUT,
+ PARAM_BUFFER_OTF_OUTPUT,
+ PARAM_ISP_CONTROL,
+ PARAM_ISP_OTF_INPUT = 10,
+ PARAM_ISP_DMA1_INPUT,
+ PARAM_ISP_DMA2_INPUT,
+ PARAM_ISP_AA,
+ PARAM_ISP_FLASH,
+ PARAM_ISP_AWB,
+ PARAM_ISP_IMAGE_EFFECT,
+ PARAM_ISP_ISO,
+ PARAM_ISP_ADJUST,
+ PARAM_ISP_METERING,
+ PARAM_ISP_AFC = 20,
+ PARAM_ISP_OTF_OUTPUT,
+ PARAM_ISP_DMA1_OUTPUT,
+ PARAM_ISP_DMA2_OUTPUT,
+ PARAM_DRC_CONTROL,
+ PARAM_DRC_OTF_INPUT,
+ PARAM_DRC_DMA_INPUT,
+ PARAM_DRC_OTF_OUTPUT,
+ PARAM_SCALERC_CONTROL,
+ PARAM_SCALERC_OTF_INPUT,
+ PARAM_SCALERC_IMAGE_EFFECT = 30,
+ PARAM_SCALERC_INPUT_CROP,
+ PARAM_SCALERC_OUTPUT_CROP,
+ PARAM_SCALERC_OTF_OUTPUT,
+ PARAM_SCALERC_DMA_OUTPUT = 34,
+ PARAM_ODC_CONTROL,
+ PARAM_ODC_OTF_INPUT,
+ PARAM_ODC_OTF_OUTPUT,
+ PARAM_DIS_CONTROL,
+ PARAM_DIS_OTF_INPUT,
+ PARAM_DIS_OTF_OUTPUT = 40,
+ PARAM_TDNR_CONTROL,
+ PARAM_TDNR_OTF_INPUT,
+ PARAM_TDNR_1ST_FRAME,
+ PARAM_TDNR_OTF_OUTPUT,
+ PARAM_TDNR_DMA_OUTPUT,
+ PARAM_SCALERP_CONTROL,
+ PARAM_SCALERP_OTF_INPUT,
+ PARAM_SCALERP_IMAGE_EFFECT,
+ PARAM_SCALERP_INPUT_CROP,
+ PARAM_SCALERP_OUTPUT_CROP = 50,
+ PARAM_SCALERP_ROTATION,
+ PARAM_SCALERP_FLIP,
+ PARAM_SCALERP_OTF_OUTPUT,
+ PARAM_SCALERP_DMA_OUTPUT,
+ PARAM_FD_CONTROL,
+ PARAM_FD_OTF_INPUT,
+ PARAM_FD_DMA_INPUT,
+ PARAM_FD_CONFIG = 58,
+ PARAM_END,
+};
+
+#define ADDRESS_TO_OFFSET(start, end) ((uint32)end - (uint32)start)
+#define OFFSET_TO_NUM(offset) ((offset)>>6)
+#define IS_OFFSET_LOWBIT(offset) (OFFSET_TO_NUM(offset) >= \
+ 32 ? false : true)
+#define OFFSET_TO_BIT(offset) \
+ {(IS_OFFSET_LOWBIT(offset) ? (1<<OFFSET_TO_NUM(offset)) \
+ : (1<<(OFFSET_TO_NUM(offset)-32))}
+#define LOWBIT_OF_NUM(num) (num >= 32 ? 0 : BIT0<<num)
+#define HIGHBIT_OF_NUM(num) (num >= 32 ? BIT0<<(num-32) : 0)
+
+/* 0~31 */
+#define PARAM_GLOBAL_SHOTMODE 0
+#define PARAM_SENSOR_CONTROL INC_NUM(PARAM_GLOBAL_SHOTMODE)
+#define PARAM_SENSOR_OTF_INPUT INC_NUM(PARAM_SENSOR_CONTROL)
+#define PARAM_SENSOR_OTF_OUTPUT INC_NUM(PARAM_SENSOR_OTF_INPUT)
+#define PARAM_SENSOR_FRAME_RATE INC_NUM(PARAM_SENSOR_OTF_OUTPUT)
+#define PARAM_SENSOR_DMA_OUTPUT INC_NUM(PARAM_SENSOR_FRAME_RATE)
+#define PARAM_BUFFER_CONTROL INC_NUM(PARAM_SENSOR_DMA_OUTPUT)
+#define PARAM_BUFFER_OTF_INPUT INC_NUM(PARAM_BUFFER_CONTROL)
+#define PARAM_BUFFER_OTF_OUTPUT INC_NUM(PARAM_BUFFER_OTF_INPUT)
+#define PARAM_ISP_CONTROL INC_NUM(PARAM_BUFFER_OTF_OUTPUT)
+#define PARAM_ISP_OTF_INPUT INC_NUM(PARAM_ISP_CONTROL)
+#define PARAM_ISP_DMA1_INPUT INC_NUM(PARAM_ISP_OTF_INPUT)
+#define PARAM_ISP_DMA2_INPUT INC_NUM(PARAM_ISP_DMA1_INPUT)
+#define PARAM_ISP_AA INC_NUM(PARAM_ISP_DMA2_INPUT)
+#define PARAM_ISP_FLASH INC_NUM(PARAM_ISP_AA)
+#define PARAM_ISP_AWB INC_NUM(PARAM_ISP_FLASH)
+#define PARAM_ISP_IMAGE_EFFECT INC_NUM(PARAM_ISP_AWB)
+#define PARAM_ISP_ISO INC_NUM(PARAM_ISP_IMAGE_EFFECT)
+#define PARAM_ISP_ADJUST INC_NUM(PARAM_ISP_ISO)
+#define PARAM_ISP_METERING INC_NUM(PARAM_ISP_ADJUST)
+#define PARAM_ISP_AFC INC_NUM(PARAM_ISP_METERING)
+#define PARAM_ISP_OTF_OUTPUT INC_NUM(PARAM_ISP_AFC)
+#define PARAM_ISP_DMA1_OUTPUT INC_NUM(PARAM_ISP_OTF_OUTPUT)
+#define PARAM_ISP_DMA2_OUTPUT INC_NUM(PARAM_ISP_DMA1_OUTPUT)
+#define PARAM_DRC_CONTROL INC_NUM(PARAM_ISP_DMA2_OUTPUT)
+#define PARAM_DRC_OTF_INPUT INC_NUM(PARAM_DRC_CONTROL)
+#define PARAM_DRC_DMA_INPUT INC_NUM(PARAM_DRC_OTF_INPUT)
+#define PARAM_DRC_OTF_OUTPUT INC_NUM(PARAM_DRC_DMA_INPUT)
+#define PARAM_SCALERC_CONTROL INC_NUM(PARAM_DRC_OTF_OUTPUT)
+#define PARAM_SCALERC_OTF_INPUT INC_NUM(PARAM_SCALERC_CONTROL)
+#define PARAM_SCALERC_IMAGE_EFFECT INC_NUM(PARAM_SCALERC_OTF_INPUT)
+#define PARAM_SCALERC_INPUT_CROP INC_NUM(PARAM_SCALERC_IMAGE_EFFECT)
+#define PARAM_SCALERC_OUTPUT_CROP INC_NUM(PARAM_SCALERC_INPUT_CROP)
+#define PARAM_SCALERC_OTF_OUTPUT INC_NUM(PARAM_SCALERC_OUTPUT_CROP)
+
+/* 32~63 */
+#define PARAM_SCALERC_DMA_OUTPUT INC_NUM(PARAM_SCALERC_OTF_OUTPUT)
+#define PARAM_ODC_CONTROL INC_NUM(PARAM_SCALERC_DMA_OUTPUT)
+#define PARAM_ODC_OTF_INPUT INC_NUM(PARAM_ODC_CONTROL)
+#define PARAM_ODC_OTF_OUTPUT INC_NUM(PARAM_ODC_OTF_INPUT)
+#define PARAM_DIS_CONTROL INC_NUM(PARAM_ODC_OTF_OUTPUT)
+#define PARAM_DIS_OTF_INPUT INC_NUM(PARAM_DIS_CONTROL)
+#define PARAM_DIS_OTF_OUTPUT INC_NUM(PARAM_DIS_OTF_INPUT)
+#define PARAM_TDNR_CONTROL INC_NUM(PARAM_DIS_OTF_OUTPUT)
+#define PARAM_TDNR_OTF_INPUT INC_NUM(PARAM_TDNR_CONTROL)
+#define PARAM_TDNR_1ST_FRAME INC_NUM(PARAM_TDNR_OTF_INPUT)
+#define PARAM_TDNR_OTF_OUTPUT INC_NUM(PARAM_TDNR_1ST_FRAME)
+#define PARAM_TDNR_DMA_OUTPUT INC_NUM(PARAM_TDNR_OTF_OUTPUT)
+#define PARAM_SCALERP_CONTROL INC_NUM(PARAM_TDNR_DMA_OUTPUT)
+#define PARAM_SCALERP_OTF_INPUT INC_NUM(PARAM_SCALERP_CONTROL)
+#define PARAM_SCALERP_IMAGE_EFFECT INC_NUM(PARAM_SCALERP_OTF_INPUT)
+#define PARAM_SCALERP_INPUT_CROP INC_NUM(PARAM_SCALERP_IMAGE_EFFECT)
+#define PARAM_SCALERP_OUTPUT_CROP INC_NUM(PARAM_SCALERP_INPUT_CROP)
+#define PARAM_SCALERP_ROTATION INC_NUM(PARAM_SCALERP_OUTPUT_CROP)
+#define PARAM_SCALERP_FLIP INC_NUM(PARAM_SCALERP_ROTATION)
+#define PARAM_SCALERP_OTF_OUTPUT INC_NUM(PARAM_SCALERP_FLIP)
+#define PARAM_SCALERP_DMA_OUTPUT INC_NUM(PARAM_SCALERP_OTF_OUTPUT)
+#define PARAM_FD_CONTROL INC_NUM(PARAM_SCALERP_DMA_OUTPUT)
+#define PARAM_FD_OTF_INPUT INC_NUM(PARAM_FD_CONTROL)
+#define PARAM_FD_DMA_INPUT INC_NUM(PARAM_FD_OTF_INPUT)
+#define PARAM_FD_CONFIG INC_NUM(PARAM_FD_DMA_INPUT)
+#define PARAM_END INC_NUM(PARAM_FD_CONFIG)
+
+#define PARAM_STRNUM_GLOBAL (PARAM_GLOBAL_SHOTMODE)
+#define PARAM_RANGE_GLOBAL 1
+#define PARAM_STRNUM_SENSOR (PARAM_SENSOR_BYPASS)
+#define PARAM_RANGE_SENSOR 5
+#define PARAM_STRNUM_BUFFER (PARAM_BUFFER_BYPASS)
+#define PARAM_RANGE_BUFFER 3
+#define PARAM_STRNUM_ISP (PARAM_ISP_BYPASS)
+#define PARAM_RANGE_ISP 15
+#define PARAM_STRNUM_DRC (PARAM_DRC_BYPASS)
+#define PARAM_RANGE_DRC 4
+#define PARAM_STRNUM_SCALERC (PARAM_SCALERC_BYPASS)
+#define PARAM_RANGE_SCALERC 7
+#define PARAM_STRNUM_ODC (PARAM_ODC_BYPASS)
+#define PARAM_RANGE_ODC 3
+#define PARAM_STRNUM_DIS (PARAM_DIS_BYPASS)
+#define PARAM_RANGE_DIS 3
+#define PARAM_STRNUM_TDNR (PARAM_TDNR_BYPASS)
+#define PARAM_RANGE_TDNR 5
+#define PARAM_STRNUM_SCALERP (PARAM_SCALERP_BYPASS)
+#define PARAM_RANGE_SCALERP 9
+#define PARAM_STRNUM_LHFD (PARAM_FD_BYPASS)
+#define PARAM_RANGE_LHFD 4
+
+#define PARAM_LOW_MASK (0xFFFFFFFF)
+#define PARAM_HIGH_MASK (0x07FFFFFF)
+
+/* Enumerations
+*
+*/
+
+/* ---------------------- Input ----------------------------------- */
+enum control_command {
+ CONTROL_COMMAND_STOP = 0,
+ CONTROL_COMMAND_START = 1,
+ CONTROL_COMMAND_TEST = 2
+};
+
+enum bypass_command {
+ CONTROL_BYPASS_DISABLE = 0,
+ CONTROL_BYPASS_ENABLE = 1
+};
+
+enum control_error {
+ CONTROL_ERROR_NO = 0
+};
+
+enum otf_input_command {
+ OTF_INPUT_COMMAND_DISABLE = 0,
+ OTF_INPUT_COMMAND_ENABLE = 1
+};
+
+enum otf_input_format {
+ OTF_INPUT_FORMAT_BAYER = 0, /* 1 Channel */
+ OTF_INPUT_FORMAT_YUV444 = 1, /* 3 Channel */
+ OTF_INPUT_FORMAT_YUV422 = 2, /* 3 Channel */
+ OTF_INPUT_FORMAT_YUV420 = 3, /* 3 Channel */
+ OTF_INPUT_FORMAT_STRGEN_COLORBAR_BAYER = 10,
+ OTF_INPUT_FORMAT_BAYER_DMA = 11,
+};
+
+enum otf_input_bitwidth {
+ OTF_INPUT_BIT_WIDTH_14BIT = 14,
+ OTF_INPUT_BIT_WIDTH_12BIT = 12,
+ OTF_INPUT_BIT_WIDTH_11BIT = 11,
+ OTF_INPUT_BIT_WIDTH_10BIT = 10,
+ OTF_INPUT_BIT_WIDTH_9BIT = 9,
+ OTF_INPUT_BIT_WIDTH_8BIT = 8
+};
+
+enum otf_input_order {
+ OTF_INPUT_ORDER_BAYER_GR_BG = 0,
+ OTF_INPUT_ORDER_BAYER_RG_GB = 1,
+ OTF_INPUT_ORDER_BAYER_BG_GR = 2,
+ OTF_INPUT_ORDER_BAYER_GB_RG = 3
+};
+
+enum otf_intput_error {
+ OTF_INPUT_ERROR_NO = 0 /* Input setting is done */
+};
+
+enum dma_input_command {
+ DMA_INPUT_COMMAND_DISABLE = 0,
+ DMA_INPUT_COMMAND_ENABLE = 1,
+ DMA_INPUT_COMMAND_BUF_MNGR = 2,
+ DMA_INPUT_COMMAND_RUN_SINGLE = 3,
+};
+
+enum dma_inut_format {
+ DMA_INPUT_FORMAT_BAYER = 0,
+ DMA_INPUT_FORMAT_YUV444 = 1,
+ DMA_INPUT_FORMAT_YUV422 = 2,
+ DMA_INPUT_FORMAT_YUV420 = 3,
+};
+
+enum dma_input_bitwidth {
+ DMA_INPUT_BIT_WIDTH_14BIT = 14,
+ DMA_INPUT_BIT_WIDTH_12BIT = 12,
+ DMA_INPUT_BIT_WIDTH_11BIT = 11,
+ DMA_INPUT_BIT_WIDTH_10BIT = 10,
+ DMA_INPUT_BIT_WIDTH_9BIT = 9,
+ DMA_INPUT_BIT_WIDTH_8BIT = 8
+};
+
+enum dma_input_plane {
+ DMA_INPUT_PLANE_3 = 3,
+ DMA_INPUT_PLANE_2 = 2,
+ DMA_INPUT_PLANE_1 = 1
+};
+
+enum dma_input_order {
+ /* (for DMA_INPUT_PLANE_3) */
+ DMA_INPUT_ORDER_NO = 0,
+ /* (only valid at DMA_INPUT_PLANE_2) */
+ DMA_INPUT_ORDER_CbCr = 1,
+ /* (only valid at DMA_INPUT_PLANE_2) */
+ DMA_INPUT_ORDER_CrCb = 2,
+ /* (only valid at DMA_INPUT_PLANE_1 & DMA_INPUT_FORMAT_YUV444) */
+ DMA_INPUT_ORDER_YCbCr = 3,
+ /* (only valid at DMA_INPUT_FORMAT_YUV422 & DMA_INPUT_PLANE_1) */
+ DMA_INPUT_ORDER_YYCbCr = 4,
+ /* (only valid at DMA_INPUT_FORMAT_YUV422 & DMA_INPUT_PLANE_1) */
+ DMA_INPUT_ORDER_YCbYCr = 5,
+ /* (only valid at DMA_INPUT_FORMAT_YUV422 & DMA_INPUT_PLANE_1) */
+ DMA_INPUT_ORDER_YCrYCb = 6,
+ /* (only valid at DMA_INPUT_FORMAT_YUV422 & DMA_INPUT_PLANE_1) */
+ DMA_INPUT_ORDER_CbYCrY = 7,
+ /* (only valid at DMA_INPUT_FORMAT_YUV422 & DMA_INPUT_PLANE_1) */
+ DMA_INPUT_ORDER_CrYCbY = 8,
+ /* (only valid at DMA_INPUT_FORMAT_BAYER) */
+ DMA_INPUT_ORDER_GR_BG = 9
+};
+
+enum dma_input_error {
+ DMA_INPUT_ERROR_NO = 0 /* DMA input setting is done */
+};
+
+/* ---------------------- Output ----------------------------------- */
+enum otf_output_crop {
+ OTF_OUTPUT_CROP_DISABLE = 0,
+ OTF_OUTPUT_CROP_ENABLE = 1
+};
+
+enum otf_output_command {
+ OTF_OUTPUT_COMMAND_DISABLE = 0,
+ OTF_OUTPUT_COMMAND_ENABLE = 1
+};
+
+enum orf_output_format {
+ OTF_OUTPUT_FORMAT_YUV444 = 1,
+ OTF_OUTPUT_FORMAT_YUV422 = 2,
+ OTF_OUTPUT_FORMAT_YUV420 = 3,
+ OTF_OUTPUT_FORMAT_RGB = 4
+};
+
+enum otf_output_bitwidth {
+ OTF_OUTPUT_BIT_WIDTH_14BIT = 14,
+ OTF_OUTPUT_BIT_WIDTH_12BIT = 12,
+ OTF_OUTPUT_BIT_WIDTH_11BIT = 11,
+ OTF_OUTPUT_BIT_WIDTH_10BIT = 10,
+ OTF_OUTPUT_BIT_WIDTH_9BIT = 9,
+ OTF_OUTPUT_BIT_WIDTH_8BIT = 8
+};
+
+enum otf_output_order {
+ OTF_OUTPUT_ORDER_BAYER_GR_BG = 0,
+};
+
+enum otf_output_error {
+ OTF_OUTPUT_ERROR_NO = 0 /* Output Setting is done */
+};
+
+enum dma_output_command {
+ DMA_OUTPUT_COMMAND_DISABLE = 0,
+ DMA_OUTPUT_COMMAND_ENABLE = 1,
+ DMA_OUTPUT_COMMAND_BUF_MNGR = 2,
+ DMA_OUTPUT_UPDATE_MASK_BITS = 3
+};
+
+enum dma_output_format {
+ DMA_OUTPUT_FORMAT_BAYER = 0,
+ DMA_OUTPUT_FORMAT_YUV444 = 1,
+ DMA_OUTPUT_FORMAT_YUV422 = 2,
+ DMA_OUTPUT_FORMAT_YUV420 = 3,
+ DMA_OUTPUT_FORMAT_RGB = 4
+};
+
+enum dma_output_bitwidth {
+ DMA_OUTPUT_BIT_WIDTH_14BIT = 14,
+ DMA_OUTPUT_BIT_WIDTH_12BIT = 12,
+ DMA_OUTPUT_BIT_WIDTH_11BIT = 11,
+ DMA_OUTPUT_BIT_WIDTH_10BIT = 10,
+ DMA_OUTPUT_BIT_WIDTH_9BIT = 9,
+ DMA_OUTPUT_BIT_WIDTH_8BIT = 8
+};
+
+enum dma_output_plane {
+ DMA_OUTPUT_PLANE_3 = 3,
+ DMA_OUTPUT_PLANE_2 = 2,
+ DMA_OUTPUT_PLANE_1 = 1
+};
+
+enum dma_output_order {
+ DMA_OUTPUT_ORDER_NO = 0,
+ /* (for DMA_OUTPUT_PLANE_3) */
+ DMA_OUTPUT_ORDER_CbCr = 1,
+ /* (only valid at DMA_INPUT_PLANE_2) */
+ DMA_OUTPUT_ORDER_CrCb = 2,
+ /* (only valid at DMA_OUTPUT_PLANE_2) */
+ DMA_OUTPUT_ORDER_YYCbCr = 3,
+ /* (only valid at DMA_OUTPUT_FORMAT_YUV422 & DMA_OUTPUT_PLANE_1) */
+ DMA_OUTPUT_ORDER_YCbYCr = 4,
+ /* (only valid at DMA_OUTPUT_FORMAT_YUV422 & DMA_OUTPUT_PLANE_1) */
+ DMA_OUTPUT_ORDER_YCrYCb = 5,
+ /* (only valid at DMA_OUTPUT_FORMAT_YUV422 & DMA_OUTPUT_PLANE_1) */
+ DMA_OUTPUT_ORDER_CbYCrY = 6,
+ /* (only valid at DMA_OUTPUT_FORMAT_YUV422 & DMA_OUTPUT_PLANE_1) */
+ DMA_OUTPUT_ORDER_CrYCbY = 7,
+ /* (only valid at DMA_OUTPUT_FORMAT_YUV422 & DMA_OUTPUT_PLANE_1) */
+ DMA_OUTPUT_ORDER_YCbCr = 8,
+ /* (only valid at DMA_OUTPUT_FORMAT_YUV444 & DMA_OUPUT_PLANE_1) */
+ DMA_OUTPUT_ORDER_CrYCb = 9,
+ /* (only valid at DMA_OUTPUT_FORMAT_YUV444 & DMA_OUPUT_PLANE_1) */
+ DMA_OUTPUT_ORDER_CrCbY = 10,
+ /* (only valid at DMA_OUTPUT_FORMAT_YUV444 & DMA_OUPUT_PLANE_1) */
+ DMA_OUTPUT_ORDER_CbYCr = 11,
+ /* (only valid at DMA_OUTPUT_FORMAT_YUV444 & DMA_OUPUT_PLANE_1) */
+ DMA_OUTPUT_ORDER_YCrCb = 12,
+ /* (only valid at DMA_OUTPUT_FORMAT_YUV444 & DMA_OUPUT_PLANE_1) */
+ DMA_OUTPUT_ORDER_CbCrY = 13,
+ /* (only valid at DMA_OUTPUT_FORMAT_YUV444 & DMA_OUPUT_PLANE_1) */
+ DMA_OUTPUT_ORDER_BGR = 14,
+ /* (only valid at DMA_OUTPUT_FORMAT_RGB) */
+ DMA_OUTPUT_ORDER_GB_BG = 15
+ /* (only valid at DMA_OUTPUT_FORMAT_BAYER) */
+};
+
+enum dma_output_notify_dma_done {
+ DMA_OUTPUT_NOTIFY_DMA_DONE_DISABLE = 0,
+ DMA_OUTPUT_NOTIFY_DMA_DONE_ENBABLE = 1,
+};
+
+enum dma_output_error {
+ DMA_OUTPUT_ERROR_NO = 0 /* DMA output setting is done */
+};
+
+/* ---------------------- Global ----------------------------------- */
+enum global_shotmode_error {
+ GLOBAL_SHOTMODE_ERROR_NO = 0 /* shot-mode setting is done */
+};
+
+/* ------------------------- AA ------------------------------------ */
+enum isp_lock_command {
+ ISP_AA_COMMAND_START = 0,
+ ISP_AA_COMMAND_STOP = 1
+};
+
+enum isp_lock_target {
+ ISP_AA_TARGET_AF = 1,
+ ISP_AA_TARGET_AE = 2,
+ ISP_AA_TARGET_AWB = 4
+};
+
+enum isp_af_mode {
+ ISP_AF_MANUAL = 0,
+ ISP_AF_SINGLE,
+ ISP_AF_CONTINUOUS,
+ ISP_AF_REGION,
+ ISP_AF_SLEEP,
+ ISP_AF_INIT,
+ ISP_AF_SET_CENTER_WINDOW,
+ ISP_AF_SET_TOUCH_WINDOW,
+ ISP_AF_SET_FACE_WINDOW
+};
+
+enum isp_af_scene {
+ ISP_AF_SCENE_NORMAL = 0,
+ ISP_AF_SCENE_MACRO = 1
+};
+
+enum isp_af_touch {
+ ISP_AF_TOUCH_DISABLE = 0,
+ ISP_AF_TOUCH_ENABLE
+};
+
+enum isp_af_face {
+ ISP_AF_FACE_DISABLE = 0,
+ ISP_AF_FACE_ENABLE
+};
+
+enum isp_af_reponse {
+ ISP_AF_RESPONSE_PREVIEW = 0,
+ ISP_AF_RESPONSE_MOVIE
+};
+
+enum isp_af_sleep {
+ ISP_AF_SLEEP_OFF = 0,
+ ISP_AF_SLEEP_ON = 1
+};
+
+enum isp_af_continuous {
+ ISP_AF_CONTINUOUS_DISABLE = 0,
+ ISP_AF_CONTINUOUS_ENABLE = 1
+};
+
+enum isp_af_error {
+ ISP_AF_ERROR_NO = 0, /* AF mode change is done */
+ ISP_AF_EROOR_NO_LOCK_DONE = 1 /* AF lock is done */
+};
+
+/* ------------------------- Flash ------------------------------------- */
+enum isp_flash_command {
+ ISP_FLASH_COMMAND_DISABLE = 0,
+ ISP_FLASH_COMMAND_MANUALON = 1, /* (forced flash) */
+ ISP_FLASH_COMMAND_AUTO = 2,
+ ISP_FLASH_COMMAND_TORCH = 3, /* 3 sec */
+ ISP_FLASH_COMMAND_FLASH_ON = 4,
+ ISP_FLASH_COMMAND_CAPTURE = 5,
+ ISP_FLASH_COMMAND_TRIGGER = 6,
+ ISP_FLASH_COMMAND_CALIBRATION = 7
+};
+
+enum isp_flash_redeye {
+ ISP_FLASH_REDEYE_DISABLE = 0,
+ ISP_FLASH_REDEYE_ENABLE = 1
+};
+
+enum isp_flash_error {
+ ISP_FLASH_ERROR_NO = 0 /* Flash setting is done */
+};
+
+/* -------------------------- AWB ------------------------------------ */
+enum isp_awb_command {
+ ISP_AWB_COMMAND_AUTO = 0,
+ ISP_AWB_COMMAND_ILLUMINATION = 1,
+ ISP_AWB_COMMAND_MANUAL = 2
+};
+
+enum isp_awb_illumination {
+ ISP_AWB_ILLUMINATION_DAYLIGHT = 0,
+ ISP_AWB_ILLUMINATION_CLOUDY = 1,
+ ISP_AWB_ILLUMINATION_TUNGSTEN = 2,
+ ISP_AWB_ILLUMINATION_FLUORESCENT = 3
+};
+
+enum isp_awb_error {
+ ISP_AWB_ERROR_NO = 0 /* AWB setting is done */
+};
+
+/* -------------------------- Effect ----------------------------------- */
+enum isp_imageeffect_command {
+ ISP_IMAGE_EFFECT_DISABLE = 0,
+ ISP_IMAGE_EFFECT_MONOCHROME = 1,
+ ISP_IMAGE_EFFECT_NEGATIVE_MONO = 2,
+ ISP_IMAGE_EFFECT_NEGATIVE_COLOR = 3,
+ ISP_IMAGE_EFFECT_SEPIA = 4,
+ ISP_IMAGE_EFFECT_AQUA = 5,
+ ISP_IMAGE_EFFECT_EMBOSS = 6,
+ ISP_IMAGE_EFFECT_EMBOSS_MONO = 7,
+ ISP_IMAGE_EFFECT_SKETCH = 8,
+ ISP_IMAGE_EFFECT_RED_YELLOW_POINT = 9,
+ ISP_IMAGE_EFFECT_GREEN_POINT = 10,
+ ISP_IMAGE_EFFECT_BLUE_POINT = 11,
+ ISP_IMAGE_EFFECT_MAGENTA_POINT = 12,
+ ISP_IMAGE_EFFECT_WARM_VINTAGE = 13,
+ ISP_IMAGE_EFFECT_COLD_VINTAGE = 14,
+ ISP_IMAGE_EFFECT_POSTERIZE = 15,
+ ISP_IMAGE_EFFECT_SOLARIZE = 16,
+ ISP_IMAGE_EFFECT_WASHED = 17,
+ ISP_IMAGE_EFFECT_CCM = 18,
+};
+
+enum isp_imageeffect_error {
+ ISP_IMAGE_EFFECT_ERROR_NO = 0 /* Image effect setting is done */
+};
+
+/* --------------------------- ISO ------------------------------------ */
+enum isp_iso_command {
+ ISP_ISO_COMMAND_AUTO = 0,
+ ISP_ISO_COMMAND_MANUAL = 1
+};
+
+enum iso_error {
+ ISP_ISO_ERROR_NO = 0 /* ISO setting is done */
+};
+
+/* -------------------------- Adjust ----------------------------------- */
+enum iso_adjust_command {
+ ISP_ADJUST_COMMAND_AUTO = 0,
+ ISP_ADJUST_COMMAND_MANUAL_CONTRAST = (1 << 0),
+ ISP_ADJUST_COMMAND_MANUAL_SATURATION = (1 << 1),
+ ISP_ADJUST_COMMAND_MANUAL_SHARPNESS = (1 << 2),
+ ISP_ADJUST_COMMAND_MANUAL_EXPOSURE = (1 << 3),
+ ISP_ADJUST_COMMAND_MANUAL_BRIGHTNESS = (1 << 4),
+ ISP_ADJUST_COMMAND_MANUAL_HUE = (1 << 5),
+ ISP_ADJUST_COMMAND_MANUAL_HOTPIXEL = (1 << 6),
+ ISP_ADJUST_COMMAND_MANUAL_NOISEREDUCTION = (1 << 7),
+ ISP_ADJUST_COMMAND_MANUAL_SHADING = (1 << 8),
+ ISP_ADJUST_COMMAND_MANUAL_GAMMA = (1 << 9),
+ ISP_ADJUST_COMMAND_MANUAL_EDGEENHANCEMENT = (1 << 10),
+ ISP_ADJUST_COMMAND_MANUAL_SCENE = (1 << 11),
+ ISP_ADJUST_COMMAND_MANUAL_FRAMETIME = (1 << 12),
+ ISP_ADJUST_COMMAND_MANUAL_ALL = 0x1FFF
+};
+
+enum isp_adjust_scene_index {
+ ISP_ADJUST_SCENE_NORMAL = 0,
+ ISP_ADJUST_SCENE_NIGHT_PREVIEW = 1,
+ ISP_ADJUST_SCENE_NIGHT_CAPTURE = 2
+};
+
+
+enum isp_adjust_error {
+ ISP_ADJUST_ERROR_NO = 0 /* Adjust setting is done */
+};
+
+/* ------------------------- Metering ---------------------------------- */
+enum isp_metering_command {
+ ISP_METERING_COMMAND_AVERAGE = 0,
+ ISP_METERING_COMMAND_SPOT = 1,
+ ISP_METERING_COMMAND_MATRIX = 2,
+ ISP_METERING_COMMAND_CENTER = 3,
+ ISP_METERING_COMMAND_EXPOSURE_MODE = (1 << 8)
+};
+
+enum isp_exposure_mode {
+ ISP_EXPOSUREMODE_OFF = 1,
+ ISP_EXPOSUREMODE_AUTO = 2
+};
+
+enum isp_metering_error {
+ ISP_METERING_ERROR_NO = 0 /* Metering setting is done */
+};
+
+/* -------------------------- AFC ----------------------------------- */
+enum isp_afc_command {
+ ISP_AFC_COMMAND_DISABLE = 0,
+ ISP_AFC_COMMAND_AUTO = 1,
+ ISP_AFC_COMMAND_MANUAL = 2
+};
+
+enum isp_afc_manual {
+ ISP_AFC_MANUAL_50HZ = 50,
+ ISP_AFC_MANUAL_60HZ = 60
+};
+
+enum isp_afc_error {
+ ISP_AFC_ERROR_NO = 0 /* AFC setting is done */
+};
+
+enum isp_scene_command {
+ ISP_SCENE_NONE = 0,
+ ISP_SCENE_PORTRAIT = 1,
+ ISP_SCENE_LANDSCAPE = 2,
+ ISP_SCENE_SPORTS = 3,
+ ISP_SCENE_PARTYINDOOR = 4,
+ ISP_SCENE_BEACHSNOW = 5,
+ ISP_SCENE_SUNSET = 6,
+ ISP_SCENE_DAWN = 7,
+ ISP_SCENE_FALL = 8,
+ ISP_SCENE_NIGHT = 9,
+ ISP_SCENE_AGAINSTLIGHTWLIGHT = 10,
+ ISP_SCENE_AGAINSTLIGHTWOLIGHT = 11,
+ ISP_SCENE_FIRE = 12,
+ ISP_SCENE_TEXT = 13,
+ ISP_SCENE_CANDLE = 14
+};
+
+/* -------------------------- Scaler --------------------------------- */
+enum scaler_imageeffect_command {
+ SCALER_IMAGE_EFFECT_COMMNAD_DISABLE = 0,
+ SCALER_IMAGE_EFFECT_COMMNAD_SEPIA_CB = 1,
+ SCALER_IMAGE_EFFECT_COMMAND_SEPIA_CR = 2,
+ SCALER_IMAGE_EFFECT_COMMAND_NEGATIVE = 3,
+ SCALER_IMAGE_EFFECT_COMMAND_ARTFREEZE = 4,
+ SCALER_IMAGE_EFFECT_COMMAND_EMBOSSING = 5,
+ SCALER_IMAGE_EFFECT_COMMAND_SILHOUETTE = 6
+};
+
+enum scaler_imageeffect_error {
+ SCALER_IMAGE_EFFECT_ERROR_NO = 0
+};
+
+enum scaler_crop_command {
+ SCALER_CROP_COMMAND_DISABLE = 0,
+ SCALER_CROP_COMMAND_ENABLE = 1
+};
+
+enum scaler_crop_error {
+ SCALER_CROP_ERROR_NO = 0 /* crop setting is done */
+};
+
+enum scaler_scaling_command {
+ SCALER_SCALING_COMMNAD_DISABLE = 0,
+ SCALER_SCALING_COMMAND_UP = 1,
+ SCALER_SCALING_COMMAND_DOWN = 2
+};
+
+enum scaler_scaling_error {
+ SCALER_SCALING_ERROR_NO = 0
+};
+
+enum scaler_rotation_command {
+ SCALER_ROTATION_COMMAND_DISABLE = 0,
+ SCALER_ROTATION_COMMAND_CLOCKWISE90 = 1
+};
+
+enum scaler_rotation_error {
+ SCALER_ROTATION_ERROR_NO = 0
+};
+
+enum scaler_flip_command {
+ SCALER_FLIP_COMMAND_NORMAL = 0,
+ SCALER_FLIP_COMMAND_X_MIRROR = 1,
+ SCALER_FLIP_COMMAND_Y_MIRROR = 2,
+ SCALER_FLIP_COMMAND_XY_MIRROR = 3 /* (180 rotation) */
+};
+
+enum scaler_flip_error {
+ SCALER_FLIP_ERROR_NO = 0 /* flip setting is done */
+};
+
+/* -------------------------- 3DNR ----------------------------------- */
+enum tdnr_1st_frame_command {
+ TDNR_1ST_FRAME_COMMAND_NOPROCESSING = 0,
+ TDNR_1ST_FRAME_COMMAND_2DNR = 1
+};
+
+enum tdnr_1st_frame_error {
+ TDNR_1ST_FRAME_ERROR_NO = 0
+ /*1st frame setting is done*/
+};
+
+/* ---------------------------- FD ------------------------------------- */
+enum fd_config_command {
+ FD_CONFIG_COMMAND_MAXIMUM_NUMBER = 0x1,
+ FD_CONFIG_COMMAND_ROLL_ANGLE = 0x2,
+ FD_CONFIG_COMMAND_YAW_ANGLE = 0x4,
+ FD_CONFIG_COMMAND_SMILE_MODE = 0x8,
+ FD_CONFIG_COMMAND_BLINK_MODE = 0x10,
+ FD_CONFIG_COMMAND_EYES_DETECT = 0x20,
+ FD_CONFIG_COMMAND_MOUTH_DETECT = 0x40,
+ FD_CONFIG_COMMAND_ORIENTATION = 0x80,
+ FD_CONFIG_COMMAND_ORIENTATION_VALUE = 0x100
+};
+
+enum fd_config_roll_angle {
+ FD_CONFIG_ROLL_ANGLE_BASIC = 0,
+ FD_CONFIG_ROLL_ANGLE_PRECISE_BASIC = 1,
+ FD_CONFIG_ROLL_ANGLE_SIDES = 2,
+ FD_CONFIG_ROLL_ANGLE_PRECISE_SIDES = 3,
+ FD_CONFIG_ROLL_ANGLE_FULL = 4,
+ FD_CONFIG_ROLL_ANGLE_PRECISE_FULL = 5,
+};
+
+enum fd_config_yaw_angle {
+ FD_CONFIG_YAW_ANGLE_0 = 0,
+ FD_CONFIG_YAW_ANGLE_45 = 1,
+ FD_CONFIG_YAW_ANGLE_90 = 2,
+ FD_CONFIG_YAW_ANGLE_45_90 = 3,
+};
+
+enum fd_config_smile_mode {
+ FD_CONFIG_SMILE_MODE_DISABLE = 0,
+ FD_CONFIG_SMILE_MODE_ENABLE = 1
+};
+
+enum fd_config_blink_mode {
+ FD_CONFIG_BLINK_MODE_DISABLE = 0,
+ FD_CONFIG_BLINK_MODE_ENABLE = 1
+};
+
+enum fd_config_eye_result {
+ FD_CONFIG_EYES_DETECT_DISABLE = 0,
+ FD_CONFIG_EYES_DETECT_ENABLE = 1
+};
+
+enum fd_config_mouth_result {
+ FD_CONFIG_MOUTH_DETECT_DISABLE = 0,
+ FD_CONFIG_MOUTH_DETECT_ENABLE = 1
+};
+
+enum fd_config_orientation {
+ FD_CONFIG_ORIENTATION_DISABLE = 0,
+ FD_CONFIG_ORIENTATION_ENABLE = 1
+};
+
+struct param_control {
+ u32 cmd;
+ u32 bypass;
+ u32 buffer_address;
+ u32 buffer_number;
+ /* 0: continuous, 1: single */
+ u32 run_mode;
+ u32 reserved[PARAMETER_MAX_MEMBER-6];
+ u32 err;
+};
+
+struct param_otf_input {
+ u32 cmd;
+ u32 width;
+ u32 height;
+ u32 format;
+ u32 bitwidth;
+ u32 order;
+ u32 crop_offset_x;
+ u32 crop_offset_y;
+ u32 crop_width;
+ u32 crop_height;
+ u32 frametime_min;
+ u32 frametime_max;
+ u32 reserved[PARAMETER_MAX_MEMBER-13];
+ u32 err;
+};
+
+struct param_dma_input {
+ u32 cmd;
+ u32 width;
+ u32 height;
+ u32 format;
+ u32 bitwidth;
+ u32 plane;
+ u32 order;
+ u32 buffer_number;
+ u32 buffer_address;
+ u32 uiBayerCropOffsetX;
+ u32 uiBayerCropOffsetY;
+ u32 uiBayerCropWidth;
+ u32 uiBayerCropHeight;
+ u32 uiDmaCropOffsetX;
+ u32 uiDmaCropOffsetY;
+ u32 uiDmaCropWidth;
+ u32 uiDmaCropHeight;
+ u32 uiUserMinFrameTime;
+ u32 uiUserMaxFrameTime;
+ u32 uiWideFrameGap;
+ u32 uiFrameGap;
+ u32 uiLineGap;
+ u32 uiReserved[PARAMETER_MAX_MEMBER-23];
+ u32 err;
+};
+
+struct param_otf_output {
+ u32 cmd;
+ u32 width;
+ u32 height;
+ u32 format;
+ u32 bitwidth;
+ u32 order;
+ u32 uiCropOffsetX;
+ u32 uiCropOffsetY;
+ u32 reserved[PARAMETER_MAX_MEMBER-9];
+ u32 err;
+};
+
+struct param_dma_output {
+ u32 cmd;
+ u32 width;
+ u32 height;
+ u32 format;
+ u32 bitwidth;
+ u32 plane;
+ u32 order;
+ u32 buffer_number;
+ u32 buffer_address;
+ u32 notify_dma_done;
+ u32 dma_out_mask;
+ u32 reserved[PARAMETER_MAX_MEMBER-12];
+ u32 err;
+};
+
+struct param_global_shotmode {
+ u32 cmd;
+ u32 skip_frames;
+ u32 reserved[PARAMETER_MAX_MEMBER-3];
+ u32 err;
+};
+
+struct param_sensor_framerate {
+ u32 frame_rate;
+ u32 reserved[PARAMETER_MAX_MEMBER-2];
+ u32 err;
+};
+
+struct param_isp_aa {
+ u32 cmd;
+ u32 target;
+ u32 mode;
+ u32 scene;
+ u32 uiAfTouch;
+ u32 uiAfFace;
+ u32 uiAfResponse;
+ u32 sleep;
+ u32 touch_x;
+ u32 touch_y;
+ u32 manual_af_setting;
+ /*0: Legacy, 1: Camera 2.0*/
+ u32 uiCamApi2P0;
+ /* For android.control.afRegions in Camera 2.0,
+ Resolution based on YUV output size*/
+ u32 uiAfRegionLeft;
+ /* For android.control.afRegions in Camera 2.0,
+ Resolution based on YUV output size*/
+ u32 uiAfRegionTop;
+ /* For android.control.afRegions in Camera 2.0,
+ Resolution based on YUV output size*/
+ u32 uiAfRegionRight;
+ /* For android.control.afRegions in Camera 2.0,
+ Resolution based on YUV output size*/
+ u32 uiAfRegionBottom;
+ u32 reserved[PARAMETER_MAX_MEMBER-17];
+ u32 err;
+};
+
+struct param_isp_flash {
+ u32 cmd;
+ u32 redeye;
+ u32 flashintensity;
+ u32 reserved[PARAMETER_MAX_MEMBER-4];
+ u32 err;
+};
+
+struct param_isp_awb {
+ u32 cmd;
+ u32 illumination;
+ u32 reserved[PARAMETER_MAX_MEMBER-3];
+ u32 err;
+};
+
+struct param_isp_imageeffect {
+ u32 cmd;
+ u32 reserved[PARAMETER_MAX_MEMBER-2];
+ u32 err;
+};
+
+struct param_isp_iso {
+ u32 cmd;
+ u32 value;
+ u32 reserved[PARAMETER_MAX_MEMBER-3];
+ u32 err;
+};
+
+struct param_isp_adjust {
+ u32 cmd;
+ s32 contrast;
+ s32 saturation;
+ s32 sharpness;
+ s32 exposure;
+ s32 brightness;
+ s32 hue;
+ /* 0 or 1 */
+ u32 uiHotPixelEnable;
+ /* -127 ~ 127 */
+ s32 uiNoiseReductionStrength;
+ /* 0 or 1 */
+ u32 uiShadingCorrectionEnable;
+ /* 0 or 1 */
+ u32 uiUserGammaEnable;
+ /* -127 ~ 127 */
+ s32 uiEdgeEnhancementStrength;
+ /* ISP_AdjustSceneIndexEnum */
+ u32 uiUserSceneMode;
+ u32 uiMinFrameTime;
+ u32 uiMaxFrameTime;
+ u32 uiReserved[PARAMETER_MAX_MEMBER-16];
+ u32 err;
+};
+
+struct param_isp_metering {
+ u32 cmd;
+ u32 win_pos_x;
+ u32 win_pos_y;
+ u32 win_width;
+ u32 win_height;
+ u32 exposure_mode;
+ /* 0: Legacy, 1: Camera 2.0 */
+ u32 uiCamApi2P0;
+ u32 reserved[PARAMETER_MAX_MEMBER-8];
+ u32 err;
+};
+
+struct param_isp_afc {
+ u32 cmd;
+ u32 manual;
+ u32 reserved[PARAMETER_MAX_MEMBER-3];
+ u32 err;
+};
+
+struct param_scaler_imageeffect {
+ u32 cmd;
+ u32 reserved[PARAMETER_MAX_MEMBER-2];
+ u32 err;
+};
+
+struct param_scaler_input_crop {
+ u32 cmd;
+ u32 pos_x;
+ u32 pos_y;
+ u32 crop_width;
+ u32 crop_height;
+ u32 in_width;
+ u32 in_height;
+ u32 out_width;
+ u32 out_height;
+ u32 reserved[PARAMETER_MAX_MEMBER-10];
+ u32 err;
+};
+
+struct param_scaler_output_crop {
+ u32 cmd;
+ u32 pos_x;
+ u32 pos_y;
+ u32 crop_width;
+ u32 crop_height;
+ u32 format;
+ u32 reserved[PARAMETER_MAX_MEMBER-7];
+ u32 err;
+};
+
+struct param_scaler_rotation {
+ u32 cmd;
+ u32 reserved[PARAMETER_MAX_MEMBER-2];
+ u32 err;
+};
+
+struct param_scaler_flip {
+ u32 cmd;
+ u32 reserved[PARAMETER_MAX_MEMBER-2];
+ u32 err;
+};
+
+struct param_3dnr_1stframe {
+ u32 cmd;
+ u32 reserved[PARAMETER_MAX_MEMBER-2];
+ u32 err;
+};
+
+struct param_fd_config {
+ u32 cmd;
+ u32 max_number;
+ u32 roll_angle;
+ u32 yaw_angle;
+ s32 smile_mode;
+ s32 blink_mode;
+ u32 eye_detect;
+ u32 mouth_detect;
+ u32 orientation;
+ u32 orientation_value;
+ u32 reserved[PARAMETER_MAX_MEMBER-11];
+ u32 err;
+};
+
+struct global_param {
+ struct param_global_shotmode shotmode; /* 0 */
+};
+
+/* To be added */
+struct sensor_param {
+ struct param_control control;
+ struct param_otf_input otf_input;
+ struct param_otf_output otf_output;
+ struct param_sensor_framerate frame_rate;
+ struct param_dma_output dma_output;
+};
+
+struct buffer_param {
+ struct param_control control;
+ struct param_otf_input otf_input;
+ struct param_otf_output otf_output;
+};
+
+struct isp_param {
+ struct param_control control;
+ struct param_otf_input otf_input;
+ struct param_dma_input dma1_input;
+ struct param_dma_input dma2_input;
+ struct param_isp_aa aa;
+ struct param_isp_flash flash;
+ struct param_isp_awb awb;
+ struct param_isp_imageeffect effect;
+ struct param_isp_iso iso;
+ struct param_isp_adjust adjust;
+ struct param_isp_metering metering;
+ struct param_isp_afc afc;
+ struct param_otf_output otf_output;
+ struct param_dma_output dma1_output;
+ struct param_dma_output dma2_output;
+};
+
+struct drc_param {
+ struct param_control control;
+ struct param_otf_input otf_input;
+ struct param_dma_input dma_input;
+ struct param_otf_output otf_output;
+};
+
+struct scalerc_param {
+ struct param_control control;
+ struct param_otf_input otf_input;
+ struct param_scaler_imageeffect effect;
+ struct param_scaler_input_crop input_crop;
+ struct param_scaler_output_crop output_crop;
+ struct param_otf_output otf_output;
+ struct param_dma_output dma_output;
+};
+
+struct odc_param {
+ struct param_control control;
+ struct param_otf_input otf_input;
+ struct param_otf_output otf_output;
+};
+
+struct dis_param {
+ struct param_control control;
+ struct param_otf_input otf_input;
+ struct param_otf_output otf_output;
+};
+
+struct tdnr_param {
+ struct param_control control;
+ struct param_otf_input otf_input;
+ struct param_3dnr_1stframe frame;
+ struct param_otf_output otf_output;
+ struct param_dma_output dma_output;
+};
+
+struct scalerp_param {
+ struct param_control control;
+ struct param_otf_input otf_input;
+ struct param_scaler_imageeffect effect;
+ struct param_scaler_input_crop input_crop;
+ struct param_scaler_output_crop output_crop;
+ struct param_scaler_rotation rotation;
+ struct param_scaler_flip flip;
+ struct param_otf_output otf_output;
+ struct param_dma_output dma_output;
+};
+
+struct fd_param {
+ struct param_control control;
+ struct param_otf_input otf_input;
+ struct param_dma_input dma_input;
+ struct param_fd_config config;
+};
+
+struct is_param_region {
+ struct global_param global;
+ struct sensor_param sensor;
+ struct buffer_param buf;
+ struct isp_param isp;
+ struct drc_param drc;
+ struct scalerc_param scalerc;
+ struct odc_param odc;
+ struct dis_param dis;
+ struct tdnr_param tdnr;
+ struct scalerp_param scalerp;
+ struct fd_param fd;
+};
+
+#define NUMBER_OF_GAMMA_CURVE_POINTS 32
+
+struct is_sensor_tune {
+ u32 exposure;
+ u32 analog_gain;
+ u32 frame_rate;
+ u32 actuator_pos;
+};
+
+struct is_tune_gammacurve {
+ u32 num_pts_x[NUMBER_OF_GAMMA_CURVE_POINTS];
+ u32 num_pts_y_r[NUMBER_OF_GAMMA_CURVE_POINTS];
+ u32 num_pts_y_g[NUMBER_OF_GAMMA_CURVE_POINTS];
+ u32 num_pts_y_b[NUMBER_OF_GAMMA_CURVE_POINTS];
+};
+
+struct is_isp_tune {
+ /* Brightness level : range 0~100, default : 7 */
+ u32 brightness_level;
+ /* Contrast level : range -127~127, default : 0 */
+ s32 contrast_level;
+ /* Saturation level : range -127~127, default : 0 */
+ s32 saturation_level;
+ s32 gamma_level;
+ struct is_tune_gammacurve gamma_curve[4];
+ /* Hue : range -127~127, default : 0 */
+ s32 hue;
+ /* Sharpness blur : range -127~127, default : 0 */
+ s32 sharpness_blur;
+ /* Despeckle : range -127~127, default : 0 */
+ s32 despeckle;
+ /* Edge color supression : range -127~127, default : 0 */
+ s32 edge_color_supression;
+ /* Noise reduction : range -127~127, default : 0 */
+ s32 noise_reduction;
+ /* (32*4 + 9)*4 = 548 bytes */
+};
+
+struct is_tune_region {
+ struct is_sensor_tune sensor_tune;
+ struct is_isp_tune isp_tune;
+};
+
+struct rational_t {
+ u32 num;
+ u32 den;
+};
+
+struct srational_t {
+ s32 num;
+ s32 den;
+};
+
+#define FLASH_FIRED_SHIFT 0
+#define FLASH_NOT_FIRED 0
+#define FLASH_FIRED 1
+
+#define FLASH_STROBE_SHIFT 1
+#define FLASH_STROBE_NO_DETECTION 0
+#define FLASH_STROBE_RESERVED 1
+#define FLASH_STROBE_RETURN_LIGHT_NOT_DETECTED 2
+#define FLASH_STROBE_RETURN_LIGHT_DETECTED 3
+
+#define FLASH_MODE_SHIFT 3
+#define FLASH_MODE_UNKNOWN 0
+#define FLASH_MODE_COMPULSORY_FLASH_FIRING 1
+#define FLASH_MODE_COMPULSORY_FLASH_SUPPRESSION 2
+#define FLASH_MODE_AUTO_MODE 3
+
+#define FLASH_FUNCTION_SHIFT 5
+#define FLASH_FUNCTION_PRESENT 0
+#define FLASH_FUNCTION_NONE 1
+
+#define FLASH_RED_EYE_SHIFT 6
+#define FLASH_RED_EYE_DISABLED 0
+#define FLASH_RED_EYE_SUPPORTED 1
+
+enum apex_aperture_value {
+ F1_0 = 0,
+ F1_4 = 1,
+ F2_0 = 2,
+ F2_8 = 3,
+ F4_0 = 4,
+ F5_6 = 5,
+ F8_9 = 6,
+ F11_0 = 7,
+ F16_0 = 8,
+ F22_0 = 9,
+ F32_0 = 10,
+};
+
+struct exif_attribute {
+ struct rational_t exposure_time;
+ struct srational_t shutter_speed;
+ u32 iso_speed_rating;
+ u32 flash;
+ struct srational_t brightness;
+};
+
+struct is_frame_header {
+ u32 valid;
+ u32 bad_mark;
+ u32 captured;
+ u32 frame_number;
+ struct exif_attribute exif;
+};
+
+struct is_fd_rect {
+ u32 offset_x;
+ u32 offset_y;
+ u32 width;
+ u32 height;
+};
+
+struct is_face_marker {
+ u32 frame_number;
+ struct is_fd_rect face;
+ struct is_fd_rect left_eye;
+ struct is_fd_rect right_eye;
+ struct is_fd_rect mouth;
+ u32 roll_angle;
+ u32 yaw_angle;
+ u32 confidence;
+ u32 uiIsTracked;
+ u32 uiTrackedFaceID;
+ u32 smile_level;
+ u32 blink_level;
+};
+
+#define MAX_FRAME_COUNT 8
+#define MAX_FRAME_COUNT_PREVIEW 4
+#define MAX_FRAME_COUNT_CAPTURE 1
+#define MAX_FACE_COUNT 16
+
+#define MAX_SHARED_COUNT 500
+
+struct is_region {
+ struct is_param_region parameter;
+ struct is_tune_region tune;
+ struct is_frame_header header[MAX_FRAME_COUNT];
+ struct is_face_marker face[MAX_FACE_COUNT];
+ u32 shared[MAX_SHARED_COUNT];
+};
+
+struct is_time_measure_us {
+ u32 min_time_us;
+ u32 max_time_us;
+ u32 avrg_time_us;
+ u32 current_time_us;
+};
+
+struct is_debug_frame_descriptor {
+ u32 sensor_frame_time;
+ u32 sensor_exposure_time;
+ u32 sensor_analog_gain;
+ u32 req_lei;
+};
+
+#define MAX_FRAMEDESCRIPTOR_CONTEXT_NUM (30 * 20) /* 600 frame */
+#define MAX_VERSION_DISPLAY_BUF (32)
+
+struct is_share_region {
+ u32 frame_time;
+ u32 exposure_time;
+ u32 analog_gain;
+
+ u32 r_gain;
+ u32 g_gain;
+ u32 b_gain;
+
+ u32 af_position;
+ u32 af_status;
+ u32 af_scene_type;
+
+ u32 frame_descp_onoff_control;
+ u32 frame_descp_update_done;
+ u32 frame_descp_idx;
+ u32 frame_descp_max_idx;
+
+ struct is_debug_frame_descriptor
+ dbg_frame_descp_ctx[MAX_FRAMEDESCRIPTOR_CONTEXT_NUM];
+
+ u32 chip_id;
+ u32 chip_rev_no;
+ u8 ispfw_version_no[MAX_VERSION_DISPLAY_BUF];
+ u8 ispfw_version_date[MAX_VERSION_DISPLAY_BUF];
+ u8 sirc_sdk_version_no[MAX_VERSION_DISPLAY_BUF];
+ u8 sirc_sdk_revsion_no[MAX_VERSION_DISPLAY_BUF];
+ u8 sirc_sdk_version_date[MAX_VERSION_DISPLAY_BUF];
+
+ /*measure timing*/
+ struct is_time_measure_us isp_sdk_Time;
+};
+
+struct is_debug_control {
+ u32 write_point; /* 0~500KB boundary*/
+ u32 assert_flag; /* 0:Not Inovked, 1:Invoked*/
+ u32 pabort_flag; /* 0:Not Inovked, 1:Invoked*/
+ u32 dabort_flag; /* 0:Not Inovked, 1:Invoked*/
+ u32 pd_Ready_flag; /* 0:Normal, 1:EnterIdle(Ready to power down)*/
+ u32 isp_frameErr; /* Frame Error Count.*/
+ u32 drc_frame_err; /* Frame Error Count.*/
+ u32 scc_frame_err; /* Frame Error Count.*/
+ u32 odc_frame_err; /* Frame Error Count.*/
+ u32 dis_frame_err; /* Frame Error Count.*/
+ u32 tdnr_frame_err; /* Frame Error Count.*/
+ u32 scp_frame_err; /* Frame Error Count.*/
+ u32 fd_frame_err; /* Frame Error Count.*/
+ u32 isp_frame_drop; /* Frame Drop Count.*/
+ u32 drc_frame_drop; /* Frame Drop Count.*/
+ u32 dis_frame_drop; /* Frame Drop Count.*/
+ u32 uiFDFrameDrop;
+};
+#endif
diff --git a/drivers/media/video/exynos/fimc-is-mc2/fimc-is-regs.h b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-regs.h
new file mode 100644
index 0000000..4883bc0
--- /dev/null
+++ b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-regs.h
@@ -0,0 +1,353 @@
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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.
+ */
+
+#ifndef FIMC_IS_REGS_H
+#define FIMC_IS_REGS_H
+
+#include <mach/map.h>
+
+/* WDT_ISP register */
+#define WDT 0x00170000
+/* MCUCTL register */
+#define MCUCTL 0x00180000
+/* MCU Controller Register */
+#define MCUCTLR (MCUCTL+0x00)
+#define MCUCTLR_AXI_ISPX_AWCACHE(x) ((x) << 16)
+#define MCUCTLR_AXI_ISPX_ARCACHE(x) ((x) << 12)
+#define MCUCTLR_MSWRST (1 << 0)
+/* Boot Base OFfset Address Register */
+#define BBOAR (MCUCTL+0x04)
+#define BBOAR_BBOA(x) ((x) << 0)
+/* Interrupt Generation Register 0 from Host CPU to VIC */
+#define INTGR0 (MCUCTL+0x08)
+#define INTGR0_INTGC9 (1 << 25)
+#define INTGR0_INTGC8 (1 << 24)
+#define INTGR0_INTGC7 (1 << 23)
+#define INTGR0_INTGC6 (1 << 22)
+#define INTGR0_INTGC5 (1 << 21)
+#define INTGR0_INTGC4 (1 << 20)
+#define INTGR0_INTGC3 (1 << 19)
+#define INTGR0_INTGC2 (1 << 18)
+#define INTGR0_INTGC1 (1 << 17)
+#define INTGR0_INTGC0 (1 << 16)
+#define INTGR0_INTGD5 (1 << 5)
+#define INTGR0_INTGD4 (1 << 4)
+#define INTGR0_INTGD3 (1 << 3)
+#define INTGR0_INTGD2 (1 << 2)
+#define INTGR0_INTGD1 (1 << 1)
+#define INTGR0_INTGD0 (1 << 0)
+/* Interrupt Clear Register 0 from Host CPU to VIC */
+#define INTCR0 (MCUCTL+0x0c)
+#define INTCR0_INTCC9 (1 << 25)
+#define INTCR0_INTCC8 (1 << 24)
+#define INTCR0_INTCC7 (1 << 23)
+#define INTCR0_INTCC6 (1 << 22)
+#define INTCR0_INTCC5 (1 << 21)
+#define INTCR0_INTCC4 (1 << 20)
+#define INTCR0_INTCC3 (1 << 19)
+#define INTCR0_INTCC2 (1 << 18)
+#define INTCR0_INTCC1 (1 << 17)
+#define INTCR0_INTCC0 (1 << 16)
+#define INTCR0_INTCD5 (1 << 5)
+#define INTCR0_INTCD4 (1 << 4)
+#define INTCR0_INTCD3 (1 << 3)
+#define INTCR0_INTCD2 (1 << 2)
+#define INTCR0_INTCD1 (1 << 1)
+#define INTCR0_INTCD0 (1 << 0)
+/* Interrupt Mask Register 0 from Host CPU to VIC */
+#define INTMR0 (MCUCTL+0x10)
+#define INTMR0_INTMC9 (1 << 25)
+#define INTMR0_INTMC8 (1 << 24)
+#define INTMR0_INTMC7 (1 << 23)
+#define INTMR0_INTMC6 (1 << 22)
+#define INTMR0_INTMC5 (1 << 21)
+#define INTMR0_INTMC4 (1 << 20)
+#define INTMR0_INTMC3 (1 << 19)
+#define INTMR0_INTMC2 (1 << 18)
+#define INTMR0_INTMC1 (1 << 17)
+#define INTMR0_INTMC0 (1 << 16)
+#define INTMR0_INTMD5 (1 << 5)
+#define INTMR0_INTMD4 (1 << 4)
+#define INTMR0_INTMD3 (1 << 3)
+#define INTMR0_INTMD2 (1 << 2)
+#define INTMR0_INTMD1 (1 << 1)
+#define INTMR0_INTMD0 (1 << 0)
+/* Interrupt Status Register 0 from Host CPU to VIC */
+#define INTSR0 (MCUCTL+0x14)
+#define INTSR0_GET_INTSD0(x) (((x) >> 0) & 0x1)
+#define INTSR0_GET_INTSD1(x) (((x) >> 1) & 0x1)
+#define INTSR0_GET_INTSD2(x) (((x) >> 2) & 0x1)
+#define INTSR0_GET_INTSD3(x) (((x) >> 3) & 0x1)
+#define INTSR0_GET_INTSD4(x) (((x) >> 4) & 0x1)
+#define INTSR0_GET_INTSC0(x) (((x) >> 16) & 0x1)
+#define INTSR0_GET_INTSC1(x) (((x) >> 17) & 0x1)
+#define INTSR0_GET_INTSC2(x) (((x) >> 18) & 0x1)
+#define INTSR0_GET_INTSC3(x) (((x) >> 19) & 0x1)
+#define INTSR0_GET_INTSC4(x) (((x) >> 20) & 0x1)
+#define INTSR0_GET_INTSC5(x) (((x) >> 21) & 0x1)
+#define INTSR0_GET_INTSC6(x) (((x) >> 22) & 0x1)
+#define INTSR0_GET_INTSC7(x) (((x) >> 23) & 0x1)
+#define INTSR0_GET_INTSC8(x) (((x) >> 24) & 0x1)
+#define INTSR0_GET_INTSC9(x) (((x) >> 25) & 0x1)
+/* Interrupt Mask Status Register 0 from Host CPU to VIC */
+#define INTMSR0 (MCUCTL+0x18)
+#define INTMSR0_GET_INTMSD0(x) (((x) >> 0) & 0x1)
+#define INTMSR0_GET_INTMSD1(x) (((x) >> 1) & 0x1)
+#define INTMSR0_GET_INTMSD2(x) (((x) >> 2) & 0x1)
+#define INTMSR0_GET_INTMSD3(x) (((x) >> 3) & 0x1)
+#define INTMSR0_GET_INTMSD4(x) (((x) >> 4) & 0x1)
+#define INTMSR0_GET_INTMSC0(x) (((x) >> 16) & 0x1)
+#define INTMSR0_GET_INTMSC1(x) (((x) >> 17) & 0x1)
+#define INTMSR0_GET_INTMSC2(x) (((x) >> 18) & 0x1)
+#define INTMSR0_GET_INTMSC3(x) (((x) >> 19) & 0x1)
+#define INTMSR0_GET_INTMSC4(x) (((x) >> 20) & 0x1)
+#define INTMSR0_GET_INTMSC5(x) (((x) >> 21) & 0x1)
+#define INTMSR0_GET_INTMSC6(x) (((x) >> 22) & 0x1)
+#define INTMSR0_GET_INTMSC7(x) (((x) >> 23) & 0x1)
+#define INTMSR0_GET_INTMSC8(x) (((x) >> 24) & 0x1)
+#define INTMSR0_GET_INTMSC9(x) (((x) >> 25) & 0x1)
+/* Interrupt Generation Register 1 from ISP CPU to Host IC */
+#define INTGR1 (MCUCTL+0x1c)
+#define INTGR1_INTGC9 (1 << 9)
+#define INTGR1_INTGC8 (1 << 8)
+#define INTGR1_INTGC7 (1 << 7)
+#define INTGR1_INTGC6 (1 << 6)
+#define INTGR1_INTGC5 (1 << 5)
+#define INTGR1_INTGC4 (1 << 4)
+#define INTGR1_INTGC3 (1 << 3)
+#define INTGR1_INTGC2 (1 << 2)
+#define INTGR1_INTGC1 (1 << 1)
+#define INTGR1_INTGC0 (1 << 0)
+/* Interrupt Clear Register 1 from ISP CPU to Host IC */
+#define INTCR1 (MCUCTL+0x20)
+#define INTCR1_INTCC9 (1 << 9)
+#define INTCR1_INTCC8 (1 << 8)
+#define INTCR1_INTCC7 (1 << 7)
+#define INTCR1_INTCC6 (1 << 6)
+#define INTCR1_INTCC5 (1 << 5)
+#define INTCR1_INTCC4 (1 << 4)
+#define INTCR1_INTCC3 (1 << 3)
+#define INTCR1_INTCC2 (1 << 2)
+#define INTCR1_INTCC1 (1 << 1)
+#define INTCR1_INTCC0 (1 << 0)
+/* Interrupt Mask Register 1 from ISP CPU to Host IC */
+#define INTMR1 (MCUCTL+0x24)
+#define INTMR1_INTMC9 (1 << 9)
+#define INTMR1_INTMC8 (1 << 8)
+#define INTMR1_INTMC7 (1 << 7)
+#define INTMR1_INTMC6 (1 << 6)
+#define INTMR1_INTMC5 (1 << 5)
+#define INTMR1_INTMC4 (1 << 4)
+#define INTMR1_INTMC3 (1 << 3)
+#define INTMR1_INTMC2 (1 << 2)
+#define INTMR1_INTMC1 (1 << 1)
+#define INTMR1_INTMC0 (1 << 0)
+/* Interrupt Status Register 1 from ISP CPU to Host IC */
+#define INTSR1 (MCUCTL+0x28)
+/* Interrupt Mask Status Register 1 from ISP CPU to Host IC */
+#define INTMSR1 (MCUCTL+0x2c)
+/* Interrupt Clear Register 2 from ISP BLK's interrupts to Host IC */
+#define INTCR2 (MCUCTL+0x30)
+#define INTCR2_INTCC21 (1 << 21)
+#define INTCR2_INTCC20 (1 << 20)
+#define INTCR2_INTCC19 (1 << 19)
+#define INTCR2_INTCC18 (1 << 18)
+#define INTCR2_INTCC17 (1 << 17)
+#define INTCR2_INTCC16 (1 << 16)
+/* Interrupt Mask Register 2 from ISP BLK's interrupts to Host IC */
+#define INTMR2 (MCUCTL+0x34)
+#define INTMR2_INTMCIS25 (1 << 25)
+#define INTMR2_INTMCIS24 (1 << 24)
+#define INTMR2_INTMCIS23 (1 << 23)
+#define INTMR2_INTMCIS22 (1 << 22)
+#define INTMR2_INTMCIS21 (1 << 21)
+#define INTMR2_INTMCIS20 (1 << 20)
+#define INTMR2_INTMCIS19 (1 << 19)
+#define INTMR2_INTMCIS18 (1 << 18)
+#define INTMR2_INTMCIS17 (1 << 17)
+#define INTMR2_INTMCIS16 (1 << 16)
+#define INTMR2_INTMCIS15 (1 << 15)
+#define INTMR2_INTMCIS14 (1 << 14)
+#define INTMR2_INTMCIS13 (1 << 13)
+#define INTMR2_INTMCIS12 (1 << 12)
+#define INTMR2_INTMCIS11 (1 << 11)
+#define INTMR2_INTMCIS10 (1 << 10)
+#define INTMR2_INTMCIS9 (1 << 9)
+#define INTMR2_INTMCIS8 (1 << 8)
+#define INTMR2_INTMCIS7 (1 << 7)
+#define INTMR2_INTMCIS6 (1 << 6)
+#define INTMR2_INTMCIS5 (1 << 5)
+#define INTMR2_INTMCIS4 (1 << 4)
+#define INTMR2_INTMCIS3 (1 << 3)
+#define INTMR2_INTMCIS2 (1 << 2)
+#define INTMR2_INTMCIS1 (1 << 1)
+#define INTMR2_INTMCIS0 (1 << 0)
+/* Interrupt Status Register 2 from ISP BLK's interrupts to Host IC */
+#define INTSR2 (MCUCTL+0x38)
+/* Interrupt Mask Status Register 2 from ISP BLK's interrupts to Host IC */
+#define INTMSR2 (MCUCTL+0x3c)
+/* General Purpose Output Control Register (0~17) */
+#define GPOCTLR (MCUCTL+0x40)
+#define GPOCTLR_GPOG17(x) ((x) << 17)
+#define GPOCTLR_GPOG16(x) ((x) << 16)
+#define GPOCTLR_GPOG15(x) ((x) << 15)
+#define GPOCTLR_GPOG14(x) ((x) << 14)
+#define GPOCTLR_GPOG13(x) ((x) << 13)
+#define GPOCTLR_GPOG12(x) ((x) << 12)
+#define GPOCTLR_GPOG11(x) ((x) << 11)
+#define GPOCTLR_GPOG10(x) ((x) << 10)
+#define GPOCTLR_GPOG9(x) ((x) << 9)
+#define GPOCTLR_GPOG8(x) ((x) << 8)
+#define GPOCTLR_GPOG7(x) ((x) << 7)
+#define GPOCTLR_GPOG6(x) ((x) << 6)
+#define GPOCTLR_GPOG5(x) ((x) << 5)
+#define GPOCTLR_GPOG4(x) ((x) << 4)
+#define GPOCTLR_GPOG3(x) ((x) << 3)
+#define GPOCTLR_GPOG2(x) ((x) << 2)
+#define GPOCTLR_GPOG1(x) ((x) << 1)
+#define GPOCTLR_GPOG0(x) ((x) << 0)
+/* General Purpose Pad Output Enable Register (0~17) */
+#define GPOENCTLR (MCUCTL+0x44)
+#define GPOENCTLR_GPOEN17(x) ((x) << 17)
+#define GPOENCTLR_GPOEN16(x) ((x) << 16)
+#define GPOENCTLR_GPOEN15(x) ((x) << 15)
+#define GPOENCTLR_GPOEN14(x) ((x) << 14)
+#define GPOENCTLR_GPOEN13(x) ((x) << 13)
+#define GPOENCTLR_GPOEN12(x) ((x) << 12)
+#define GPOENCTLR_GPOEN11(x) ((x) << 11)
+#define GPOENCTLR_GPOEN10(x) ((x) << 10)
+#define GPOENCTLR_GPOEN9(x) ((x) << 9)
+#define GPOENCTLR_GPOEN8(x) ((x) << 8)
+#define GPOENCTLR_GPOEN7(x) ((x) << 7)
+#define GPOENCTLR_GPOEN6(x) ((x) << 6)
+#define GPOENCTLR_GPOEN5(x) ((x) << 5)
+#define GPOENCTLR_GPOEN4(x) ((x) << 4)
+#define GPOENCTLR_GPOEN3(x) ((x) << 3)
+#define GPOENCTLR_GPOEN2(x) ((x) << 2)
+#define GPOENCTLR_GPOEN1(x) ((x) << 1)
+#define GPOENCTLR_GPOEN0(x) ((x) << 0)
+/* General Purpose Input Control Register (0~17) */
+#define GPICTLR (MCUCTL+0x48)
+/* IS Shared Register 0 between ISP CPU and HOST CPU */
+#define ISSR0 (MCUCTL+0x80)
+/* Command Host -> IS */
+/* IS Shared Register 1 between ISP CPU and HOST CPU */
+/* Sensor ID for Command */
+#define ISSR1 (MCUCTL+0x84)
+/* IS Shared Register 2 between ISP CPU and HOST CPU */
+/* Parameter 1 */
+#define ISSR2 (MCUCTL+0x88)
+/* IS Shared Register 3 between ISP CPU and HOST CPU */
+/* Parameter 2 */
+#define ISSR3 (MCUCTL+0x8c)
+/* IS Shared Register 4 between ISP CPU and HOST CPU */
+/* Parameter 3 */
+#define ISSR4 (MCUCTL+0x90)
+/* IS Shared Register 5 between ISP CPU and HOST CPU */
+/* Parameter 4 */
+#define ISSR5 (MCUCTL+0x94)
+#define ISSR6 (MCUCTL+0x98)
+#define ISSR7 (MCUCTL+0x9c)
+#define ISSR8 (MCUCTL+0xa0)
+#define ISSR9 (MCUCTL+0xa4)
+/* IS Shared Register 10 between ISP CPU and HOST CPU */
+/* Command IS -> Host */
+#define ISSR10 (MCUCTL+0xa8)
+/* IS Shared Register 11 between ISP CPU and HOST CPU */
+/* Sensor ID for Command */
+#define ISSR11 (MCUCTL+0xac)
+/* IS Shared Register 12 between ISP CPU and HOST CPU */
+/* Parameter 1 */
+#define ISSR12 (MCUCTL+0xb0)
+/* IS Shared Register 13 between ISP CPU and HOST CPU */
+/* Parameter 2 */
+#define ISSR13 (MCUCTL+0xb4)
+/* IS Shared Register 14 between ISP CPU and HOST CPU */
+/* Parameter 3 */
+#define ISSR14 (MCUCTL+0xb8)
+/* IS Shared Register 15 between ISP CPU and HOST CPU */
+/* Parameter 4 */
+#define ISSR15 (MCUCTL+0xbc)
+#define ISSR16 (MCUCTL+0xc0)
+#define ISSR17 (MCUCTL+0xc4)
+#define ISSR18 (MCUCTL+0xc8)
+#define ISSR19 (MCUCTL+0xcc)
+/* IS Shared Register 20 between ISP CPU and HOST CPU */
+/* ISP_FRAME_DONE : SENSOR ID */
+#define ISSR20 (MCUCTL+0xd0)
+/* IS Shared Register 21 between ISP CPU and HOST CPU */
+/* ISP_FRAME_DONE : PARAMETER 1 */
+#define ISSR21 (MCUCTL+0xd4)
+#define ISSR22 (MCUCTL+0xd8)
+#define ISSR23 (MCUCTL+0xdc)
+/* IS Shared Register 24 between ISP CPU and HOST CPU */
+/* SCALERC_FRAME_DONE : SENSOR ID */
+#define ISSR24 (MCUCTL+0xe0)
+/* IS Shared Register 25 between ISP CPU and HOST CPU */
+/* SCALERC_FRAME_DONE : PARAMETER 1 */
+#define ISSR25 (MCUCTL+0xe4)
+#define ISSR26 (MCUCTL+0xe8)
+#define ISSR27 (MCUCTL+0xec)
+/* IS Shared Register 28 between ISP CPU and HOST CPU */
+/* 3DNR_FRAME_DONE : SENSOR ID */
+#define ISSR28 (MCUCTL+0xf0)
+/* IS Shared Register 29 between ISP CPU and HOST CPU */
+/* 3DNR_FRAME_DONE : PARAMETER 1 */
+#define ISSR29 (MCUCTL+0xf4)
+#define ISSR30 (MCUCTL+0xf8)
+#define ISSR31 (MCUCTL+0xfc)
+/* IS Shared Register 32 between ISP CPU and HOST CPU */
+/* SCALERP_FRAME_DONE : SENSOR ID */
+#define ISSR32 (MCUCTL+0x100)
+/* IS Shared Register 33 between ISP CPU and HOST CPU */
+/* SCALERP_FRAME_DONE : PARAMETER 1 */
+#define ISSR33 (MCUCTL+0x104)
+#define ISSR34 (MCUCTL+0x108)
+#define ISSR35 (MCUCTL+0x10c)
+#define ISSR36 (MCUCTL+0x110)
+#define ISSR37 (MCUCTL+0x114)
+#define ISSR38 (MCUCTL+0x118)
+#define ISSR39 (MCUCTL+0x11c)
+#define ISSR40 (MCUCTL+0x120)
+#define ISSR41 (MCUCTL+0x124)
+#define ISSR42 (MCUCTL+0x128)
+#define ISSR43 (MCUCTL+0x12c)
+#define ISSR44 (MCUCTL+0x130)
+#define ISSR45 (MCUCTL+0x134)
+#define ISSR46 (MCUCTL+0x138)
+#define ISSR47 (MCUCTL+0x13c)
+#define ISSR48 (MCUCTL+0x140)
+#define ISSR49 (MCUCTL+0x144)
+#define ISSR50 (MCUCTL+0x148)
+#define ISSR51 (MCUCTL+0x14c)
+#define ISSR52 (MCUCTL+0x150)
+#define ISSR53 (MCUCTL+0x154)
+#define ISSR54 (MCUCTL+0x158)
+#define ISSR55 (MCUCTL+0x15c)
+#define ISSR56 (MCUCTL+0x160)
+#define ISSR57 (MCUCTL+0x164)
+#define ISSR58 (MCUCTL+0x168)
+#define ISSR59 (MCUCTL+0x16c)
+#define ISSR60 (MCUCTL+0x170)
+#define ISSR61 (MCUCTL+0x174)
+#define ISSR62 (MCUCTL+0x178)
+#define ISSR63 (MCUCTL+0x17c)
+
+/* PMU for FIMC-IS*/
+#define PMUREG_CMU_RESET_ISP_SYS_PWR_REG (S5P_VA_PMU + 0x1584)
+#define PMUREG_ISP_ARM_CONFIGURATION (S5P_VA_PMU + 0x2280)
+#define PMUREG_ISP_ARM_STATUS (S5P_VA_PMU + 0x2284)
+#define PMUREG_ISP_ARM_OPTION (S5P_VA_PMU + 0x2288)
+#define PMUREG_ISP_LOW_POWER_OFF (S5P_VA_PMU + 0x0004)
+#define PMUREG_ISP_CONFIGURATION (S5P_VA_PMU + 0x4020)
+#define PMUREG_ISP_STATUS (S5P_VA_PMU + 0x4024)
+
+#endif
diff --git a/drivers/media/video/exynos/fimc-is-mc2/fimc-is-spi.c b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-spi.c
new file mode 100644
index 0000000..6ab9605
--- /dev/null
+++ b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-spi.c
@@ -0,0 +1,149 @@
+/*
+ * driver for FIMC-IS SPI
+ *
+ * Copyright (c) 2011, Samsung Electronics. All rights reserved
+ *
+ * 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 <linux/init.h>
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include "fimc-is-core.h"
+
+#define STREAM_TO_U16(var16, p) {(var16) = ((u16)(*((u8 *)p+1)) + \
+ ((u8)(*((u8 *)p) << 8))); }
+
+static struct spi_device *g_spi;
+
+int fimc_is_spi_read(void *buf, size_t size)
+{
+ unsigned char req_info[4] = { 0x90, 0x00, 0x00, 0x00};
+ unsigned char req_data[4] = { 0x03, };
+ unsigned char res[2] = { 0x00, 0x00};
+ unsigned int rx_addr = 0x00;
+ int ret;
+
+ struct spi_transfer t_c;
+ struct spi_transfer t_r;
+
+ struct spi_message m;
+
+ memset(&t_c, 0x00, sizeof(t_c));
+ memset(&t_r, 0x00, sizeof(t_r));
+
+ t_c.tx_buf = req_info;
+ t_c.len = 4;
+ t_c.cs_change = 1;
+
+ t_r.rx_buf = res;
+ t_r.len = 2;
+ t_r.cs_change = 0;
+
+ spi_message_init(&m);
+ spi_message_add_tail(&t_c, &m);
+ spi_message_add_tail(&t_r, &m);
+
+ ret = spi_sync(g_spi, &m);
+ if (ret) {
+ err("spi sync error - can't get device information");
+ return -EIO;
+ }
+
+ printk(KERN_INFO "Manufacturer ID : 0x%08x\n", res[0]);
+ printk(KERN_INFO "Device ID : 0x%08x\n", res[1]);
+
+ memset(&t_c, 0x00, sizeof(t_c));
+ memset(&t_r, 0x00, sizeof(t_r));
+
+ req_data[1] = (rx_addr & 0xFF0000) >> 16;
+ req_data[2] = (rx_addr & 0xFF00) >> 8;
+ req_data[3] = (rx_addr & 0xFF);
+
+ t_c.tx_buf = req_data;
+ t_c.len = 4;
+ t_c.cs_change = 1;
+
+ t_r.rx_buf = buf;
+ t_r.len = size;
+ t_r.cs_change = 0;
+
+ spi_message_init(&m);
+ spi_message_add_tail(&t_c, &m);
+ spi_message_add_tail(&t_r, &m);
+
+ ret = spi_sync(g_spi, &m);
+ if (ret) {
+ err("spi sync error - can't read data");
+ return -EIO;
+ } else
+ return 0;
+}
+
+static int __devinit fimc_is_spi_probe(struct spi_device *spi)
+{
+ int ret;
+
+ /* spi->bits_per_word = 16; */
+ if (spi_setup(spi)) {
+ pr_err("failed to setup spi for fimc_is_spi\n");
+ ret = -EINVAL;
+ goto err_setup;
+ }
+
+ g_spi = spi;
+
+ printk(KERN_INFO "fimc_is_spi successfully probed\n");
+ return 0;
+
+err_setup:
+ return ret;
+}
+
+static int __devexit fimc_is_spi_remove(struct spi_device *spi)
+{
+ return 0;
+}
+
+static
+struct spi_driver fimc_is_spi_driver = {
+ .driver = {
+ .name = "fimc_is_spi",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ .probe = fimc_is_spi_probe,
+ .remove = __devexit_p(fimc_is_spi_remove),
+};
+
+static
+int __init fimc_is_spi_init(void)
+{
+ int ret;
+
+ ret = spi_register_driver(&fimc_is_spi_driver);
+
+ if (ret)
+ pr_err("failed to register imc_is_spi- %x\n", ret);
+
+ return ret;
+}
+
+static
+void __exit fimc_is_spi_exit(void)
+{
+ spi_unregister_driver(&fimc_is_spi_driver);
+}
+
+module_init(fimc_is_spi_init);
+module_exit(fimc_is_spi_exit);
+
+MODULE_DESCRIPTION("FIMC-IS SPI driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/exynos/fimc-is-mc2/fimc-is-time.c b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-time.c
new file mode 100644
index 0000000..953c758
--- /dev/null
+++ b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-time.c
@@ -0,0 +1,106 @@
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/time.h>
+
+#include "fimc-is-time.h"
+
+#ifdef MEASURE_TIME
+#ifdef INTERNAL_TIME
+
+static u32 time_count;
+static u32 time1_min;
+static u32 time1_max;
+static u32 time1_avg;
+static u32 time2_min;
+static u32 time2_max;
+static u32 time2_avg;
+static u32 time3_min;
+static u32 time3_max;
+static u32 time3_avg;
+static u32 time4_cur;
+static u32 time4_old;
+static u32 time4_avg;
+
+void measure_init(void)
+{
+ time_count = 0;
+ time1_min = 0;
+ time1_max = 0;
+ time1_avg = 0;
+ time2_min = 0;
+ time2_max = 0;
+ time2_avg = 0;
+ time3_min = 0;
+ time3_max = 0;
+ time3_avg = 0;
+ time4_cur = 0;
+ time4_old = 0;
+ time4_avg = 0;
+}
+
+void measure_internal_time(struct timeval *time_queued,
+ struct timeval *time_shot,
+ struct timeval *time_shotdone,
+ struct timeval *time_dequeued)
+{
+ u32 temp1, temp2, temp3;
+
+ temp1 = (time_shot->tv_sec - time_queued->tv_sec)*1000000 +
+ (time_shot->tv_usec - time_queued->tv_usec);
+ temp2 = (time_shotdone->tv_sec - time_shot->tv_sec)*1000000 +
+ (time_shotdone->tv_usec - time_shot->tv_usec);
+ temp3 = (time_dequeued->tv_sec - time_shotdone->tv_sec)*1000000 +
+ (time_dequeued->tv_usec - time_shotdone->tv_usec);
+
+ if (!time_count) {
+ time1_min = temp1;
+ time1_max = temp1;
+ time2_min = temp2;
+ time2_max = temp2;
+ time3_min = temp3;
+ time3_max = temp3;
+ } else {
+ if (time1_min > temp1)
+ time1_min = temp1;
+
+ if (time1_max < temp1)
+ time1_max = temp1;
+
+ if (time2_min > temp2)
+ time2_min = temp2;
+
+ if (time2_max < temp2)
+ time2_max = temp2;
+
+ if (time3_min > temp3)
+ time3_min = temp3;
+
+ if (time3_max < temp3)
+ time3_max = temp3;
+ }
+
+ time1_avg += temp1;
+ time2_avg += temp2;
+ time3_avg += temp3;
+
+ time4_cur = time_queued->tv_sec*1000000 + time_queued->tv_usec;
+ time4_avg += (time4_cur - time4_old);
+ time4_old = time4_cur;
+
+ time_count++;
+
+ if (time_count % 33)
+ return;
+
+ printk(KERN_INFO "t1(%d,%d,%d), t2(%d,%d,%d), t3(%d,%d,%d) : %d(%dfps)",
+ temp1, time1_max, time1_avg/time_count,
+ temp2, time2_max, time2_avg/time_count,
+ temp3, time3_max, time3_avg/time_count,
+ time4_avg/33, 33000000/time4_avg);
+
+ time4_avg = 0;
+}
+
+#endif
+#endif
diff --git a/drivers/media/video/exynos/fimc-is-mc2/fimc-is-time.h b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-time.h
new file mode 100644
index 0000000..3cea695
--- /dev/null
+++ b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-time.h
@@ -0,0 +1,35 @@
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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.
+ */
+
+#ifndef FIMC_IS_TIME_H
+#define FIMC_IS_TIME_H
+
+/*#define MEASURE_TIME*/
+#define INTERNAL_TIME
+
+#define TM_FLITE_STR 0
+#define TM_FLITE_END 1
+#define TM_SHOT 2
+#define TM_SHOT_D 3
+#define TM_META_D 4
+#define TM_MAX_INDEX 5
+
+#ifdef MEASURE_TIME
+#ifdef INTERNAL_TIME
+void measure_init(void);
+void measure_internal_time(struct timeval *time_queued,
+ struct timeval *time_shot,
+ struct timeval *time_shotdone,
+ struct timeval *time_dequeued);
+#endif
+#endif
+
+#endif
diff --git a/drivers/media/video/exynos/fimc-is-mc2/fimc-is-vb2.c b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-vb2.c
new file mode 100644
index 0000000..31c0d6a
--- /dev/null
+++ b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-vb2.c
@@ -0,0 +1,79 @@
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ * exynos5 fimc-is misc functions(mipi, fimc-lite control)
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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.
+ */
+
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+#include <linux/io.h>
+#include <media/videobuf2-core.h>
+#include <linux/platform_device.h>
+#include "fimc-is-core.h"
+
+#if defined(CONFIG_VIDEOBUF2_CMA_PHYS)
+void *fimc_is_cma_init(struct fimc_is_core *isp)
+{
+ return vb2_cma_phys_init(&isp->pdev->dev, NULL, 0, false);
+}
+
+int fimc_is_cma_resume(void *alloc_ctx)
+{
+ return 1;
+}
+void fimc_is_cma_suspend(void *alloc_ctx) {}
+void fimc_is_cma_set_cacheable(void *alloc_ctx, bool cacheable) {}
+
+int fimc_is_cma_cache_flush(struct vb2_buffer *vb, u32 plane_no)
+{
+ return 0;
+}
+
+const struct fimc_is_vb2 fimc_is_vb2_cma = {
+ .ops = &vb2_cma_phys_memops,
+ .init = fimc_is_cma_init,
+ .cleanup = vb2_cma_phys_cleanup,
+ .plane_addr = vb2_cma_phys_plane_paddr,
+ .resume = fimc_is_cma_resume,
+ .suspend = fimc_is_cma_suspend,
+ .cache_flush = fimc_is_cma_cache_flush,
+ .set_cacheable = fimc_is_cma_set_cacheable,
+};
+#elif defined(CONFIG_VIDEOBUF2_ION)
+static void *fimc_is_ion_init(struct platform_device *pdev)
+{
+ return vb2_ion_create_context(&pdev->dev, SZ_4K,
+ VB2ION_CTX_IOMMU | VB2ION_CTX_VMCONTIG);
+}
+
+static unsigned long plane_addr(struct vb2_buffer *vb, u32 plane_no)
+{
+ void *cookie = vb2_plane_cookie(vb, plane_no);
+ dma_addr_t dva = 0;
+
+ WARN_ON(vb2_ion_dma_address(cookie, &dva) != 0);
+
+ return dva;
+}
+
+const struct fimc_is_vb2 fimc_is_vb2_ion = {
+ .ops = &vb2_ion_memops,
+ .init = fimc_is_ion_init,
+ .cleanup = vb2_ion_destroy_context,
+ .plane_addr = plane_addr,
+ .resume = vb2_ion_attach_iommu,
+ .suspend = vb2_ion_detach_iommu,
+ .cache_flush = vb2_ion_cache_flush,
+ .set_cacheable = vb2_ion_set_cached,
+ .plane_kvaddr = vb2_plane_vaddr,
+};
+#endif
diff --git a/drivers/media/video/exynos/fimc-is-mc2/fimc-is-video-isp.c b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-video-isp.c
new file mode 100644
index 0000000..8f952c4
--- /dev/null
+++ b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-video-isp.c
@@ -0,0 +1,550 @@
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ * exynos5 fimc-is video functions
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <mach/videonode.h>
+#include <media/exynos_mc.h>
+#include <linux/cma.h>
+#include <asm/cacheflush.h>
+#include <asm/pgtable.h>
+#include <linux/firmware.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
+#include <linux/videodev2_exynos_media.h>
+#include <linux/videodev2_exynos_camera.h>
+#include <linux/v4l2-mediabus.h>
+
+#include "fimc-is-core.h"
+#include "fimc-is-param.h"
+#include "fimc-is-cmd.h"
+#include "fimc-is-regs.h"
+#include "fimc-is-err.h"
+#include "fimc-is-video.h"
+#include "fimc-is-metadata.h"
+
+/*************************************************************************/
+/* video file opertation */
+/************************************************************************/
+int fimc_is_isp_video_probe(void *data)
+{
+ int ret = 0;
+ struct fimc_is_core *core = (struct fimc_is_core *)data;
+ struct fimc_is_video_isp *video = &core->video_isp;
+
+ dbg_isp("%s\n", __func__);
+
+ ret = fimc_is_video_probe(&video->common,
+ data,
+ video,
+ FIMC_IS_VIDEO_ISP_NAME,
+ FIMC_IS_VIDEO_NUM_ISP,
+ V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
+ &fimc_is_isp_video_fops,
+ &fimc_is_isp_video_ioctl_ops,
+ &fimc_is_isp_qops);
+
+ return ret;
+}
+
+static int fimc_is_isp_video_open(struct file *file)
+{
+ struct fimc_is_core *core = video_drvdata(file);
+ struct fimc_is_video_isp *video = &core->video_isp;
+ struct fimc_is_device_ischain *ischain = &core->ischain;
+
+ dbg_isp("%s\n", __func__);
+
+ file->private_data = video;
+ fimc_is_video_open(&video->common, ischain, VIDEO_ISP_READY_BUFFERS);
+
+ return 0;
+}
+
+static int fimc_is_isp_video_close(struct file *file)
+{
+ struct fimc_is_video_isp *video = file->private_data;
+ struct fimc_is_video_common *common = &video->common;
+ struct fimc_is_device_ischain *ischain = common->device;
+
+ printk(KERN_INFO "%s\n", __func__);
+
+ if (test_bit(FIMC_IS_VIDEO_STREAM_ON, &common->state))
+ clear_bit(FIMC_IS_VIDEO_STREAM_ON, &common->state);
+
+ file->private_data = 0;
+ fimc_is_ischain_close(ischain);
+ fimc_is_video_close(&video->common, ischain->framemgr);
+
+ return 0;
+}
+
+static unsigned int fimc_is_isp_video_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct fimc_is_video_isp *video = file->private_data;
+
+ return vb2_poll(&video->common.vbq, file, wait);
+}
+
+static int fimc_is_isp_video_mmap(struct file *file,
+ struct vm_area_struct *vma)
+{
+ struct fimc_is_video_isp *video = file->private_data;
+
+ return vb2_mmap(&video->common.vbq, vma);
+}
+
+/*************************************************************************/
+/* video ioctl operation */
+/************************************************************************/
+
+static int fimc_is_isp_video_querycap(struct file *file, void *fh,
+ struct v4l2_capability *cap)
+{
+ struct fimc_is_core *isp = video_drvdata(file);
+
+ strncpy(cap->driver, isp->pdev->name, sizeof(cap->driver) - 1);
+
+ dbg_isp("%s(devname : %s)\n", __func__, cap->driver);
+ strncpy(cap->card, isp->pdev->name, sizeof(cap->card) - 1);
+ cap->bus_info[0] = 0;
+ cap->version = KERNEL_VERSION(1, 0, 0);
+ cap->capabilities = V4L2_CAP_STREAMING
+ | V4L2_CAP_VIDEO_CAPTURE
+ | V4L2_CAP_VIDEO_CAPTURE_MPLANE;
+
+ return 0;
+}
+
+static int fimc_is_isp_video_enum_fmt_mplane(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ dbg_isp("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_isp_video_get_format_mplane(struct file *file, void *fh,
+ struct v4l2_format *format)
+{
+ dbg_isp("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_isp_video_set_format_mplane(struct file *file, void *fh,
+ struct v4l2_format *format)
+{
+ int ret = 0;
+ struct fimc_is_video_isp *video = file->private_data;
+ struct fimc_is_device_ischain *ischain = video->common.device;
+
+ dbg_isp("%s\n", __func__);
+
+ ret = fimc_is_video_set_format_mplane(&video->common, format);
+
+ dbg_isp("req w : %d req h : %d\n",
+ video->common.frame.width,
+ video->common.frame.height);
+
+ fimc_is_ischain_isp_s_format(ischain,
+ video->common.frame.width,
+ video->common.frame.height);
+
+ return ret;
+}
+
+static int fimc_is_isp_video_try_format_mplane(struct file *file, void *fh,
+ struct v4l2_format *format)
+{
+ dbg_isp("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_isp_video_cropcap(struct file *file, void *fh,
+ struct v4l2_cropcap *cropcap)
+{
+ dbg_isp("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_isp_video_get_crop(struct file *file, void *fh,
+ struct v4l2_crop *crop)
+{
+ dbg_isp("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_isp_video_set_crop(struct file *file, void *fh,
+ struct v4l2_crop *crop)
+{
+ dbg_isp("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_isp_video_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *buf)
+{
+ int ret;
+ struct fimc_is_video_isp *video = file->private_data;
+ struct fimc_is_video_common *common = &video->common;
+ struct fimc_is_device_ischain *ischain = common->device;
+
+ dbg_isp("%s(buffers : %d)\n", __func__, buf->count);
+
+ ret = fimc_is_video_reqbufs(common, ischain->framemgr, buf);
+ if (ret)
+ err("fimc_is_video_reqbufs is fail(error %d)", ret);
+
+ return ret;
+}
+
+static int fimc_is_isp_video_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ int ret;
+ struct fimc_is_video_isp *video = file->private_data;
+
+ dbg_isp("%s\n", __func__);
+ ret = vb2_querybuf(&video->common.vbq, buf);
+
+ return ret;
+}
+
+static int fimc_is_isp_video_qbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ int ret = 0;
+ struct fimc_is_video_isp *video = file->private_data;
+ struct fimc_is_video_common *common = &video->common;
+
+#ifdef DBG_STREAMING
+ /*dbg_isp("%s\n", __func__);*/
+#endif
+
+ if (test_bit(FIMC_IS_VIDEO_STREAM_ON, &common->state))
+ ret = fimc_is_video_qbuf(common, buf);
+ else {
+ err("stream off state, can NOT qbuf");
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int fimc_is_isp_video_dqbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ int ret = 0;
+ struct fimc_is_video_isp *video = file->private_data;
+ bool blocking = file->f_flags & O_NONBLOCK;
+
+ ret = fimc_is_video_dqbuf(&video->common, buf, blocking);
+
+#ifdef DBG_STREAMING
+ dbg_isp("%s(index : %d)\n", __func__, buf->index);
+#endif
+
+ return ret;
+}
+
+static int fimc_is_isp_video_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ int ret = 0;
+ struct fimc_is_video_isp *video = file->private_data;
+
+ dbg_isp("%s\n", __func__);
+
+ ret = fimc_is_video_streamon(&video->common, type);
+
+ return ret;
+}
+
+static int fimc_is_isp_video_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ int ret = 0;
+ struct fimc_is_video_isp *video = file->private_data;
+
+ dbg_isp("%s\n", __func__);
+
+ ret = fimc_is_video_streamoff(&video->common, type);
+
+ return ret;
+}
+
+static int fimc_is_isp_video_enum_input(struct file *file, void *priv,
+ struct v4l2_input *input)
+{
+ struct fimc_is_core *isp = video_drvdata(file);
+ struct exynos5_fimc_is_sensor_info *sensor_info;
+
+ sensor_info = isp->pdata->sensor_info[input->index];
+
+ dbg_isp("index(%d) sensor(%s)\n",
+ input->index, sensor_info->sensor_name);
+ dbg_isp("pos(%d) sensor_id(%d)\n",
+ sensor_info->sensor_position, sensor_info->sensor_id);
+ dbg_isp("csi_id(%d) flite_id(%d)\n",
+ sensor_info->csi_id, sensor_info->flite_id);
+ dbg_isp("i2c_ch(%d)\n", sensor_info->i2c_channel);
+
+ if (input->index >= FIMC_IS_MAX_CAMIF_CLIENTS)
+ return -EINVAL;
+
+ input->type = V4L2_INPUT_TYPE_CAMERA;
+
+ strncpy(input->name, sensor_info->sensor_name,
+ FIMC_IS_MAX_SENSOR_NAME_LEN);
+ return 0;
+}
+
+static int fimc_is_isp_video_g_input(struct file *file, void *priv,
+ unsigned int *input)
+{
+ dbg_isp("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_isp_video_s_input(struct file *file, void *priv,
+ unsigned int input)
+{
+ int ret = 0;
+ struct fimc_is_video_isp *video = file->private_data;
+ struct fimc_is_device_ischain *ischain = video->common.device;
+ struct fimc_is_core *core = video->common.core;
+ struct fimc_is_device_sensor *sensor = &core->sensor;
+
+ dbg_isp("%s(input : %d)\n", __func__, input);
+ core->sensor.id_position = input;
+
+ ret = fimc_is_ischain_open(ischain, &video->common);
+ if (ret) {
+ err("fimc_is_ischain_open is fail\n");
+ goto exit;
+ }
+
+ ret = fimc_is_ischain_init(ischain,
+ input,
+ sensor->enum_sensor[input].i2c_ch,
+ &sensor->enum_sensor[input].ext,
+ sensor->enum_sensor[input].setfile_name);
+ if (ret) {
+ err("fimc_is_ischain_init is fail\n");
+ goto exit;
+ }
+
+exit:
+ return ret;
+}
+
+static int fimc_is_isp_video_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ int ret = 0;
+ struct fimc_is_video_isp *video = file->private_data;
+ struct fimc_is_device_ischain *ischain = video->common.device;
+
+ dbg_isp("%s\n", __func__);
+
+ switch (ctrl->id) {
+ case V4L2_CID_IS_S_STREAM:
+ if (ctrl->value == IS_ENABLE_STREAM)
+ ret = fimc_is_itf_process_on(ischain);
+ else
+ ret = fimc_is_itf_process_off(ischain);
+ break;
+ case V4L2_CID_IS_G_CAPABILITY:
+ ret = fimc_is_ischain_g_capability(ischain, ctrl->value);
+ dbg_isp("V4L2_CID_IS_G_CAPABILITY : %X\n", ctrl->value);
+ break;
+ default:
+ err("unsupported ioctl(%d)\n", ctrl->id);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int fimc_is_isp_video_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ int ret = 0;
+
+ dbg_isp("%s\n", __func__);
+
+ return ret;
+}
+
+static int fimc_is_isp_video_g_ext_ctrl(struct file *file, void *priv,
+ struct v4l2_ext_controls *ctrls)
+{
+ int ret = 0;
+
+ return ret;
+}
+
+const struct v4l2_file_operations fimc_is_isp_video_fops = {
+ .owner = THIS_MODULE,
+ .open = fimc_is_isp_video_open,
+ .release = fimc_is_isp_video_close,
+ .poll = fimc_is_isp_video_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = fimc_is_isp_video_mmap,
+};
+
+const struct v4l2_ioctl_ops fimc_is_isp_video_ioctl_ops = {
+ .vidioc_querycap = fimc_is_isp_video_querycap,
+ .vidioc_enum_fmt_vid_out_mplane = fimc_is_isp_video_enum_fmt_mplane,
+ .vidioc_g_fmt_vid_out_mplane = fimc_is_isp_video_get_format_mplane,
+ .vidioc_s_fmt_vid_out_mplane = fimc_is_isp_video_set_format_mplane,
+ .vidioc_try_fmt_vid_out_mplane = fimc_is_isp_video_try_format_mplane,
+ .vidioc_cropcap = fimc_is_isp_video_cropcap,
+ .vidioc_g_crop = fimc_is_isp_video_get_crop,
+ .vidioc_s_crop = fimc_is_isp_video_set_crop,
+ .vidioc_reqbufs = fimc_is_isp_video_reqbufs,
+ .vidioc_querybuf = fimc_is_isp_video_querybuf,
+ .vidioc_qbuf = fimc_is_isp_video_qbuf,
+ .vidioc_dqbuf = fimc_is_isp_video_dqbuf,
+ .vidioc_streamon = fimc_is_isp_video_streamon,
+ .vidioc_streamoff = fimc_is_isp_video_streamoff,
+ .vidioc_enum_input = fimc_is_isp_video_enum_input,
+ .vidioc_g_input = fimc_is_isp_video_g_input,
+ .vidioc_s_input = fimc_is_isp_video_s_input,
+ .vidioc_s_ctrl = fimc_is_isp_video_s_ctrl,
+ .vidioc_g_ctrl = fimc_is_isp_video_g_ctrl,
+ .vidioc_g_ext_ctrls = fimc_is_isp_video_g_ext_ctrl,
+};
+
+static int fimc_is_isp_queue_setup(struct vb2_queue *vq,
+ const struct v4l2_format *fmt,
+ unsigned int *num_buffers, unsigned int *num_planes,
+ unsigned int sizes[],
+ void *allocators[])
+{
+ int ret = 0;
+ struct fimc_is_video_isp *video = vq->drv_priv;
+
+ dbg_sensor("%s\n", __func__);
+
+ ret = fimc_is_video_queue_setup(&video->common,
+ num_planes,
+ sizes,
+ allocators);
+
+ dbg_sensor("(num_planes : %d)(size : %d)\n",
+ (int)*num_planes, (int)sizes[0]);
+
+ return ret;
+}
+
+static int fimc_is_isp_buffer_prepare(struct vb2_buffer *vb)
+{
+ /*dbg_isp("%s\n", __func__);*/
+ return 0;
+}
+
+static inline void fimc_is_isp_wait_prepare(struct vb2_queue *q)
+{
+}
+
+static inline void fimc_is_isp_wait_finish(struct vb2_queue *q)
+{
+}
+
+static int fimc_is_isp_start_streaming(struct vb2_queue *q,
+ unsigned int count)
+{
+ int ret = 0;
+ struct fimc_is_video_isp *video = q->drv_priv;
+ struct fimc_is_video_common *common = &video->common;
+ struct fimc_is_device_ischain *ischain = common->device;
+
+ dbg_isp("%s\n", __func__);
+
+ if (!test_bit(FIMC_IS_VIDEO_STREAM_ON, &common->state)) {
+ set_bit(FIMC_IS_VIDEO_STREAM_ON, &common->state);
+ fimc_is_ischain_isp_start(ischain, common);
+ } else {
+ err("already stream on or buffer is not ready(%ld)",
+ common->state);
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int fimc_is_isp_stop_streaming(struct vb2_queue *q)
+{
+ int ret = 0;
+ struct fimc_is_video_isp *video = q->drv_priv;
+ struct fimc_is_video_common *common = &video->common;
+ struct fimc_is_device_ischain *ischain = common->device;
+
+ if (test_bit(FIMC_IS_VIDEO_STREAM_ON, &common->state)) {
+ clear_bit(FIMC_IS_VIDEO_STREAM_ON, &common->state);
+ clear_bit(FIMC_IS_VIDEO_BUFFER_PREPARED, &common->state);
+ fimc_is_ischain_isp_stop(ischain);
+ } else {
+ err("already stream off");
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static void fimc_is_isp_buffer_queue(struct vb2_buffer *vb)
+{
+ struct fimc_is_video_isp *video = vb->vb2_queue->drv_priv;
+ struct fimc_is_video_common *common = &video->common;
+ struct fimc_is_device_ischain *ischain = common->device;
+
+#ifdef DBG_STREAMING
+ dbg_isp("%s(%d)\n", __func__, index);
+#endif
+
+ fimc_is_video_buffer_queue(common, vb, ischain->framemgr);
+ fimc_is_ischain_isp_buffer_queue(ischain, vb->v4l2_buf.index);
+}
+
+static int fimc_is_isp_buffer_finish(struct vb2_buffer *vb)
+{
+ int ret = 0;
+ struct fimc_is_video_sensor *video = vb->vb2_queue->drv_priv;
+ struct fimc_is_device_ischain *ischain = video->common.device;
+
+#ifdef DBG_STREAMING
+ dbg_isp("%s(%d)\n", __func__, vb->v4l2_buf.index);
+#endif
+
+ ret = fimc_is_ischain_isp_buffer_finish(ischain, vb->v4l2_buf.index);
+
+ return ret;
+}
+
+const struct vb2_ops fimc_is_isp_qops = {
+ .queue_setup = fimc_is_isp_queue_setup,
+ .buf_prepare = fimc_is_isp_buffer_prepare,
+ .buf_queue = fimc_is_isp_buffer_queue,
+ .buf_finish = fimc_is_isp_buffer_finish,
+ .wait_prepare = fimc_is_isp_wait_prepare,
+ .wait_finish = fimc_is_isp_wait_finish,
+ .start_streaming = fimc_is_isp_start_streaming,
+ .stop_streaming = fimc_is_isp_stop_streaming,
+};
diff --git a/drivers/media/video/exynos/fimc-is-mc2/fimc-is-video-isp.h b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-video-isp.h
new file mode 100644
index 0000000..30a00be
--- /dev/null
+++ b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-video-isp.h
@@ -0,0 +1,14 @@
+#ifndef FIMC_IS_VIDEO_ISP_H
+#define FIMC_IS_VIDEO_ISP_H
+
+#include "fimc-is-video.h"
+
+#define VIDEO_ISP_READY_BUFFERS 0
+
+struct fimc_is_video_isp {
+ struct fimc_is_video_common common;
+};
+
+int fimc_is_isp_video_probe(void *data);
+
+#endif
diff --git a/drivers/media/video/exynos/fimc-is-mc2/fimc-is-video-scc.c b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-video-scc.c
new file mode 100644
index 0000000..d7af147
--- /dev/null
+++ b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-video-scc.c
@@ -0,0 +1,580 @@
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ * exynos5 fimc-is video functions
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <mach/videonode.h>
+#include <media/exynos_mc.h>
+#include <linux/cma.h>
+#include <asm/cacheflush.h>
+#include <asm/pgtable.h>
+#include <linux/firmware.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
+#include <linux/videodev2_exynos_media.h>
+#include <linux/videodev2_exynos_camera.h>
+#include <linux/v4l2-mediabus.h>
+
+#include "fimc-is-core.h"
+#include "fimc-is-param.h"
+#include "fimc-is-cmd.h"
+#include "fimc-is-regs.h"
+#include "fimc-is-err.h"
+#include "fimc-is-video.h"
+#include "fimc-is-metadata.h"
+#include "fimc-is-device-ischain.h"
+
+int fimc_is_scc_video_probe(void *core_data)
+{
+ int ret = 0;
+ struct fimc_is_core *core = (struct fimc_is_core *)core_data;
+ struct fimc_is_video_scc *video = &core->video_scc;
+
+ dbg_scc("%s\n", __func__);
+
+ ret = fimc_is_video_probe(&video->common,
+ core_data,
+ video,
+ FIMC_IS_VIDEO_SCALERC_NAME,
+ FIMC_IS_VIDEO_NUM_SCALERC,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
+ &fimc_is_scalerc_video_fops,
+ &fimc_is_scalerc_video_ioctl_ops,
+ &fimc_is_scalerc_qops);
+
+ return ret;
+}
+
+/*************************************************************************/
+/* video file opertation */
+/************************************************************************/
+
+static int fimc_is_scalerc_video_open(struct file *file)
+{
+ struct fimc_is_core *core = video_drvdata(file);
+ struct fimc_is_video_scc *video = &core->video_scc;
+ struct fimc_is_device_ischain *ischain = &core->ischain;
+ struct fimc_is_ischain_dev *scc = &ischain->scc;
+
+ dbg_scc("%s\n", __func__);
+
+ file->private_data = video;
+ fimc_is_video_open(&video->common, ischain, VIDEO_SCC_READY_BUFFERS);
+ fimc_is_ischain_dev_open(scc, ENTRY_SCALERC, &video->common, NULL);
+
+ return 0;
+}
+
+static int fimc_is_scalerc_video_close(struct file *file)
+{
+ int ret = 0;
+ struct fimc_is_video_scc *video = file->private_data;
+ struct fimc_is_video_common *common = &video->common;
+ struct fimc_is_device_ischain *ischain = common->device;
+ struct fimc_is_ischain_dev *scc = &ischain->scc;
+
+ printk(KERN_INFO "%s\n", __func__);
+
+ if (test_bit(FIMC_IS_VIDEO_STREAM_ON, &common->state))
+ clear_bit(FIMC_IS_VIDEO_STREAM_ON, &common->state);
+
+ file->private_data = 0;
+ fimc_is_video_close(&video->common, &scc->framemgr);
+
+ return ret;
+}
+
+static unsigned int fimc_is_scalerc_video_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct fimc_is_video_scc *video = file->private_data;
+
+ dbg("%s\n", __func__);
+ return vb2_poll(&video->common.vbq, file, wait);
+
+}
+
+static int fimc_is_scalerc_video_mmap(struct file *file,
+ struct vm_area_struct *vma)
+{
+ struct fimc_is_video_scc *video = file->private_data;
+
+ dbg("%s\n", __func__);
+ return vb2_mmap(&video->common.vbq, vma);
+
+}
+
+/*************************************************************************/
+/* video ioctl operation */
+/************************************************************************/
+
+static int fimc_is_scalerc_video_querycap(struct file *file, void *fh,
+ struct v4l2_capability *cap)
+{
+ struct fimc_is_core *isp = video_drvdata(file);
+
+ strncpy(cap->driver, isp->pdev->name, sizeof(cap->driver) - 1);
+
+ dbg("(devname : %s)\n", cap->driver);
+ strncpy(cap->card, isp->pdev->name, sizeof(cap->card) - 1);
+ cap->bus_info[0] = 0;
+ cap->version = KERNEL_VERSION(1, 0, 0);
+ cap->capabilities = V4L2_CAP_STREAMING
+ | V4L2_CAP_VIDEO_CAPTURE
+ | V4L2_CAP_VIDEO_CAPTURE_MPLANE;
+
+ return 0;
+}
+
+static int fimc_is_scalerc_video_enum_fmt_mplane(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_scalerc_video_get_format_mplane(struct file *file, void *fh,
+ struct v4l2_format *format)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_scalerc_video_set_format_mplane(struct file *file, void *fh,
+ struct v4l2_format *format)
+{
+ int ret = 0;
+ struct fimc_is_video_scc *video = file->private_data;
+
+ dbg_scp("%s\n", __func__);
+
+ ret = fimc_is_video_set_format_mplane(&video->common, format);
+
+ dbg_scc("req w : %d req h : %d\n",
+ video->common.frame.width,
+ video->common.frame.height);
+
+ return ret;
+}
+
+static int fimc_is_scalerc_video_try_format_mplane(struct file *file, void *fh,
+ struct v4l2_format *format)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_scalerc_video_cropcap(struct file *file, void *fh,
+ struct v4l2_cropcap *cropcap)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_scalerc_video_get_crop(struct file *file, void *fh,
+ struct v4l2_crop *crop)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_scalerc_video_set_crop(struct file *file, void *fh,
+ struct v4l2_crop *crop)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_scalerc_video_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *buf)
+{
+ int ret = 0;
+ struct fimc_is_video_scc *video = file->private_data;
+ struct fimc_is_video_common *common = &video->common;
+ struct fimc_is_device_ischain *ischain = common->device;
+ struct fimc_is_ischain_dev *isp = &ischain->isp;
+ struct fimc_is_ischain_dev *scc = &ischain->scc;
+
+ dbg_scc("%s(buffers : %d)\n", __func__, buf->count);
+
+ if (test_bit(FIMC_IS_ISDEV_DSTART, &isp->state)) {
+ err("isp still running, not applied");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ ret = fimc_is_video_reqbufs(common, &scc->framemgr, buf);
+ if (ret)
+ err("fimc_is_video_reqbufs is fail(error %d)", ret);
+
+exit:
+ return ret;
+}
+
+static int fimc_is_scalerc_video_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ int ret;
+ struct fimc_is_video_scc *video = file->private_data;
+
+ dbg("%s\n", __func__);
+ ret = vb2_querybuf(&video->common.vbq, buf);
+
+ return ret;
+}
+
+static int fimc_is_scalerc_video_qbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ int ret = 0;
+ struct fimc_is_video_scc *video = file->private_data;
+
+#ifdef DBG_STREAMING
+ /*dbg_scc("%s(index : %d)\n", __func__, buf->index);*/
+#endif
+
+ ret = fimc_is_video_qbuf(&video->common, buf);
+
+ return ret;
+}
+
+static int fimc_is_scalerc_video_dqbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ int ret = 0;
+ struct fimc_is_video_scc *video = file->private_data;
+
+ ret = fimc_is_video_dqbuf(&video->common, buf,
+ file->f_flags & O_NONBLOCK);
+
+#ifdef DBG_STREAMING
+ /*dbg_scc("%s(index : %d)\n", __func__, buf->index);*/
+#endif
+
+ return ret;
+}
+
+static int fimc_is_scalerc_video_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ int ret = 0;
+ struct fimc_is_video_scc *video = file->private_data;
+
+ dbg_scc("%s\n", __func__);
+
+ ret = fimc_is_video_streamon(&video->common, type);
+
+ return ret;
+}
+
+static int fimc_is_scalerc_video_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ int ret = 0;
+ struct fimc_is_video_scc *video = file->private_data;
+
+ dbg_scc("%s\n", __func__);
+
+ ret = fimc_is_video_streamoff(&video->common, type);
+
+ return ret;
+}
+
+static int fimc_is_scalerc_video_enum_input(struct file *file, void *priv,
+ struct v4l2_input *input)
+{
+ struct fimc_is_core *isp = video_drvdata(file);
+ struct exynos5_fimc_is_sensor_info *sensor_info
+ = isp->pdata->sensor_info[input->index];
+
+ dbg("index(%d) sensor(%s)\n",
+ input->index, sensor_info->sensor_name);
+ dbg("pos(%d) sensor_id(%d)\n",
+ sensor_info->sensor_position, sensor_info->sensor_id);
+ dbg("csi_id(%d) flite_id(%d)\n",
+ sensor_info->csi_id, sensor_info->flite_id);
+ dbg("i2c_ch(%d)\n", sensor_info->i2c_channel);
+
+ if (input->index >= FIMC_IS_MAX_CAMIF_CLIENTS)
+ return -EINVAL;
+
+ input->type = V4L2_INPUT_TYPE_CAMERA;
+
+ strncpy(input->name, sensor_info->sensor_name,
+ FIMC_IS_MAX_SENSOR_NAME_LEN);
+ return 0;
+}
+
+static int fimc_is_scalerc_video_g_input(struct file *file, void *priv,
+ unsigned int *input)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_scalerc_video_s_input(struct file *file, void *priv,
+ unsigned int input)
+{
+ return 0;
+}
+
+static int fimc_is_scalerc_video_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ int ret = 0;
+ struct fimc_is_video_scc *video = file->private_data;
+ struct fimc_is_video_common *common = &video->common;
+ struct fimc_is_device_ischain *ischain = common->device;
+ struct fimc_is_ischain_dev *scc = &ischain->scc;
+ struct fimc_is_framemgr *framemgr = &scc->framemgr;
+
+ dbg_scc("%s\n", __func__);
+
+ switch (ctrl->id) {
+ case V4L2_CID_IS_G_COMPLETES:
+ ctrl->value = framemgr->frame_complete_cnt;
+ break;
+ default:
+ err("unsupported ioctl(%d)\n", ctrl->id);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int fimc_is_scalerc_video_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ int ret = 0;
+ unsigned long flags;
+ struct fimc_is_video_scp *video = file->private_data;
+ struct fimc_is_video_common *common = &video->common;
+ struct fimc_is_device_ischain *ischain = common->device;
+ struct fimc_is_ischain_dev *scc = &ischain->scc;
+ struct fimc_is_framemgr *framemgr = &scc->framemgr;
+ struct fimc_is_frame_shot *frame;
+
+ dbg_scc("%s\n", __func__);
+
+ switch (ctrl->id) {
+ case V4L2_CID_IS_FORCE_DONE:
+ if (framemgr->frame_process_cnt) {
+ err("force done can be performed(process count %d)",
+ framemgr->frame_process_cnt);
+ ret = -EINVAL;
+ } else if (!framemgr->frame_request_cnt) {
+ err("force done can be performed(request count %d)",
+ framemgr->frame_request_cnt);
+ ret = -EINVAL;
+ } else {
+ framemgr_e_barrier_irqs(framemgr, 0, flags);
+
+ fimc_is_frame_request_head(framemgr, &frame);
+ if (frame) {
+ fimc_is_frame_trans_req_to_com(framemgr, frame);
+ buffer_done(common, frame->index);
+ } else {
+ err("frame is NULL");
+ ret = -EINVAL;
+ }
+
+ framemgr_x_barrier_irqr(framemgr, 0, flags);
+ }
+ break;
+ default:
+ err("unsupported ioctl(%d)\n", ctrl->id);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+const struct v4l2_file_operations fimc_is_scalerc_video_fops = {
+ .owner = THIS_MODULE,
+ .open = fimc_is_scalerc_video_open,
+ .release = fimc_is_scalerc_video_close,
+ .poll = fimc_is_scalerc_video_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = fimc_is_scalerc_video_mmap,
+};
+
+const struct v4l2_ioctl_ops fimc_is_scalerc_video_ioctl_ops = {
+ .vidioc_querycap = fimc_is_scalerc_video_querycap,
+ .vidioc_enum_fmt_vid_cap_mplane
+ = fimc_is_scalerc_video_enum_fmt_mplane,
+ .vidioc_g_fmt_vid_cap_mplane
+ = fimc_is_scalerc_video_get_format_mplane,
+ .vidioc_s_fmt_vid_cap_mplane
+ = fimc_is_scalerc_video_set_format_mplane,
+ .vidioc_try_fmt_vid_cap_mplane
+ = fimc_is_scalerc_video_try_format_mplane,
+ .vidioc_cropcap = fimc_is_scalerc_video_cropcap,
+ .vidioc_g_crop = fimc_is_scalerc_video_get_crop,
+ .vidioc_s_crop = fimc_is_scalerc_video_set_crop,
+ .vidioc_reqbufs = fimc_is_scalerc_video_reqbufs,
+ .vidioc_querybuf = fimc_is_scalerc_video_querybuf,
+ .vidioc_qbuf = fimc_is_scalerc_video_qbuf,
+ .vidioc_dqbuf = fimc_is_scalerc_video_dqbuf,
+ .vidioc_streamon = fimc_is_scalerc_video_streamon,
+ .vidioc_streamoff = fimc_is_scalerc_video_streamoff,
+ .vidioc_enum_input = fimc_is_scalerc_video_enum_input,
+ .vidioc_g_input = fimc_is_scalerc_video_g_input,
+ .vidioc_s_input = fimc_is_scalerc_video_s_input,
+ .vidioc_g_ctrl = fimc_is_scalerc_video_g_ctrl,
+ .vidioc_s_ctrl = fimc_is_scalerc_video_s_ctrl,
+};
+
+static int fimc_is_scalerc_queue_setup(struct vb2_queue *vq,
+ const struct v4l2_format *fmt,
+ unsigned int *num_buffers,
+ unsigned int *num_planes, unsigned int sizes[],
+ void *allocators[])
+{
+ int ret = 0;
+ struct fimc_is_video_scc *video = vq->drv_priv;
+
+ dbg_scc("%s\n", __func__);
+
+ ret = fimc_is_video_queue_setup(&video->common,
+ num_planes,
+ sizes,
+ allocators);
+
+ dbg_scc("(num_planes : %d)(size : %d)\n",
+ (int)*num_planes, (int)sizes[0]);
+
+ return ret;
+}
+static int fimc_is_scalerc_buffer_prepare(struct vb2_buffer *vb)
+{
+ return 0;
+}
+
+static inline void fimc_is_scalerc_wait_prepare(struct vb2_queue *q)
+{
+}
+
+static inline void fimc_is_scalerc_wait_finish(struct vb2_queue *q)
+{
+}
+
+static int fimc_is_scalerc_start_streaming(struct vb2_queue *q,
+ unsigned int count)
+{
+ int ret = 0;
+ struct fimc_is_video_scc *video = q->drv_priv;
+ struct fimc_is_video_common *common = &video->common;
+ struct fimc_is_device_ischain *ischain = common->device;
+ struct fimc_is_ischain_dev *scc = &ischain->scc;
+
+ dbg_scc("%s\n", __func__);
+
+ if (!test_bit(FIMC_IS_VIDEO_STREAM_ON, &common->state) &&
+ test_bit(FIMC_IS_VIDEO_BUFFER_READY, &common->state)) {
+ set_bit(FIMC_IS_VIDEO_STREAM_ON, &common->state);
+ fimc_is_ischain_dev_start(scc);
+ } else {
+ err("already stream on or buffer is not ready(%ld)",
+ common->state);
+ clear_bit(FIMC_IS_VIDEO_BUFFER_READY, &common->state);
+ clear_bit(FIMC_IS_VIDEO_BUFFER_PREPARED, &common->state);
+ fimc_is_ischain_dev_stop(scc);
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int fimc_is_scalerc_stop_streaming(struct vb2_queue *q)
+{
+ int ret = 0;
+ unsigned long flags;
+ struct fimc_is_video_scc *video = q->drv_priv;
+ struct fimc_is_video_common *common = &video->common;
+ struct fimc_is_device_ischain *ischain = common->device;
+ struct fimc_is_ischain_dev *scc = &ischain->scc;
+ struct fimc_is_framemgr *framemgr = &scc->framemgr;
+
+ dbg_scc("%s\n", __func__);
+
+ if (test_bit(FIMC_IS_VIDEO_STREAM_ON, &common->state)) {
+ framemgr_e_barrier_irqs(framemgr, 0, flags);
+ ret = framemgr->frame_process_cnt;
+ framemgr_x_barrier_irqr(framemgr, 0, flags);
+ if (ret) {
+ err("being processed, can't stop");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ clear_bit(FIMC_IS_VIDEO_STREAM_ON, &common->state);
+ clear_bit(FIMC_IS_VIDEO_BUFFER_READY, &common->state);
+ clear_bit(FIMC_IS_VIDEO_BUFFER_PREPARED, &common->state);
+ fimc_is_ischain_dev_stop(scc);
+ } else {
+ err("already stream off");
+ ret = -EINVAL;
+ }
+
+exit:
+ return ret;
+}
+
+static void fimc_is_scalerc_buffer_queue(struct vb2_buffer *vb)
+{
+ struct fimc_is_video_scc *video = vb->vb2_queue->drv_priv;
+ struct fimc_is_video_common *common = &video->common;
+ struct fimc_is_device_ischain *ischain = common->device;
+ struct fimc_is_ischain_dev *scc = &ischain->scc;
+
+#ifdef DBG_STREAMING
+ dbg_scc("%s\n", __func__);
+#endif
+
+ fimc_is_video_buffer_queue(common, vb, &scc->framemgr);
+ fimc_is_ischain_dev_buffer_queue(scc, vb->v4l2_buf.index);
+}
+
+static int fimc_is_scalerc_buffer_finish(struct vb2_buffer *vb)
+{
+ int ret = 0;
+ struct fimc_is_video_scc *video = vb->vb2_queue->drv_priv;
+ struct fimc_is_device_ischain *ischain = video->common.device;
+ struct fimc_is_ischain_dev *scc = &ischain->scc;
+
+#ifdef DBG_STREAMING
+ dbg_scc("%s(%d)\n", __func__, vb->v4l2_buf.index);
+#endif
+
+ ret = fimc_is_ischain_dev_buffer_finish(scc, vb->v4l2_buf.index);
+
+ return ret;
+}
+
+const struct vb2_ops fimc_is_scalerc_qops = {
+ .queue_setup = fimc_is_scalerc_queue_setup,
+ .buf_prepare = fimc_is_scalerc_buffer_prepare,
+ .buf_queue = fimc_is_scalerc_buffer_queue,
+ .buf_finish = fimc_is_scalerc_buffer_finish,
+ .wait_prepare = fimc_is_scalerc_wait_prepare,
+ .wait_finish = fimc_is_scalerc_wait_finish,
+ .start_streaming = fimc_is_scalerc_start_streaming,
+ .stop_streaming = fimc_is_scalerc_stop_streaming,
+};
diff --git a/drivers/media/video/exynos/fimc-is-mc2/fimc-is-video-scc.h b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-video-scc.h
new file mode 100644
index 0000000..d3ace96
--- /dev/null
+++ b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-video-scc.h
@@ -0,0 +1,14 @@
+#ifndef FIMC_IS_VIDEO_SCC_H
+#define FIMC_IS_VIDEO_SCC_H
+
+#include "fimc-is-video.h"
+
+#define VIDEO_SCC_READY_BUFFERS 8
+
+struct fimc_is_video_scc {
+ struct fimc_is_video_common common;
+};
+
+int fimc_is_scc_video_probe(void *core_data);
+
+#endif
diff --git a/drivers/media/video/exynos/fimc-is-mc2/fimc-is-video-scp.c b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-video-scp.c
new file mode 100644
index 0000000..8132aca
--- /dev/null
+++ b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-video-scp.c
@@ -0,0 +1,597 @@
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ * exynos5 fimc-is video functions
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <mach/videonode.h>
+#include <media/exynos_mc.h>
+#include <linux/cma.h>
+#include <asm/cacheflush.h>
+#include <asm/pgtable.h>
+#include <linux/firmware.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
+#include <linux/videodev2_exynos_media.h>
+#include <linux/videodev2_exynos_camera.h>
+#include <linux/v4l2-mediabus.h>
+
+#include "fimc-is-core.h"
+#include "fimc-is-param.h"
+#include "fimc-is-cmd.h"
+#include "fimc-is-regs.h"
+#include "fimc-is-err.h"
+#include "fimc-is-video.h"
+
+/*************************************************************************/
+/* video file opertation */
+/************************************************************************/
+int fimc_is_scp_video_probe(void *data)
+{
+ int ret = 0;
+ struct fimc_is_core *core = (struct fimc_is_core *)data;
+ struct fimc_is_video_scp *video = &core->video_scp;
+
+ ret = fimc_is_video_probe(&video->common,
+ data,
+ video,
+ FIMC_IS_VIDEO_SCALERP_NAME,
+ FIMC_IS_VIDEO_NUM_SCALERP,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
+ &fimc_is_scalerp_video_fops,
+ &fimc_is_scalerp_video_ioctl_ops,
+ &fimc_is_scalerp_qops);
+
+ return ret;
+}
+
+static int fimc_is_scalerp_video_open(struct file *file)
+{
+ struct fimc_is_core *core = video_drvdata(file);
+ struct fimc_is_video_scp *video = &core->video_scp;
+ struct fimc_is_device_ischain *ischain = &core->ischain;
+ struct fimc_is_ischain_dev *scp = &ischain->scp;
+
+ dbg_scp("%s\n", __func__);
+
+ file->private_data = video;
+ fimc_is_video_open(&video->common, ischain, VIDEO_SCP_READY_BUFFERS);
+ fimc_is_ischain_dev_open(scp, ENTRY_SCALERP, &video->common, NULL);
+
+ return 0;
+}
+
+static int fimc_is_scalerp_video_close(struct file *file)
+{
+ int ret = 0;
+ struct fimc_is_video_scp *video = file->private_data;
+ struct fimc_is_video_common *common = &video->common;
+ struct fimc_is_device_ischain *ischain = common->device;
+ struct fimc_is_ischain_dev *scp = &ischain->scp;
+
+ printk(KERN_INFO "%s\n", __func__);
+
+ if (test_bit(FIMC_IS_VIDEO_STREAM_ON, &common->state))
+ clear_bit(FIMC_IS_VIDEO_STREAM_ON, &common->state);
+
+ file->private_data = 0;
+ fimc_is_video_close(common, &scp->framemgr);
+
+ return ret;
+}
+
+static unsigned int fimc_is_scalerp_video_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct fimc_is_video_scp *video = file->private_data;
+
+ dbg("%s\n", __func__);
+ return vb2_poll(&video->common.vbq, file, wait);
+
+}
+
+static int fimc_is_scalerp_video_mmap(struct file *file,
+ struct vm_area_struct *vma)
+{
+ struct fimc_is_video_scp *video = file->private_data;
+
+ dbg("%s\n", __func__);
+ return vb2_mmap(&video->common.vbq, vma);
+
+}
+
+/*************************************************************************/
+/* video ioctl operation */
+/************************************************************************/
+
+static int fimc_is_scalerp_video_querycap(struct file *file, void *fh,
+ struct v4l2_capability *cap)
+{
+ struct fimc_is_core *isp = video_drvdata(file);
+
+ strncpy(cap->driver, isp->pdev->name, sizeof(cap->driver) - 1);
+
+ dbg("%s(devname : %s)\n", __func__, cap->driver);
+ strncpy(cap->card, isp->pdev->name, sizeof(cap->card) - 1);
+ cap->bus_info[0] = 0;
+ cap->version = KERNEL_VERSION(1, 0, 0);
+ cap->capabilities = V4L2_CAP_STREAMING
+ | V4L2_CAP_VIDEO_CAPTURE
+ | V4L2_CAP_VIDEO_CAPTURE_MPLANE;
+
+ return 0;
+}
+
+static int fimc_is_scalerp_video_enum_fmt_mplane(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_scalerp_video_get_format_mplane(struct file *file, void *fh,
+ struct v4l2_format *format)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_scalerp_video_set_format_mplane(struct file *file, void *fh,
+ struct v4l2_format *format)
+{
+ int ret = 0;
+ struct fimc_is_video_scp *video = file->private_data;
+ struct fimc_is_device_ischain *ischain = video->common.device;
+
+ dbg_scp("%s\n", __func__);
+
+ format->fmt.pix_mp.plane_fmt[0].bytesperline =
+ ALIGN(format->fmt.pix_mp.width, 32);
+ format->fmt.pix_mp.plane_fmt[1].bytesperline =
+ ALIGN(format->fmt.pix_mp.width, 32);
+ format->fmt.pix_mp.plane_fmt[2].bytesperline =
+ ALIGN(format->fmt.pix_mp.width, 32);
+ format->fmt.pix_mp.plane_fmt[3].bytesperline = 0;
+
+ ret = fimc_is_video_set_format_mplane(&video->common, format);
+
+ dbg_scp("req w : %d req h : %d\n",
+ video->common.frame.width,
+ video->common.frame.height);
+
+ fimc_is_ischain_scp_s_format(ischain,
+ video->common.frame.width,
+ video->common.frame.height);
+
+ return ret;
+}
+
+static int fimc_is_scalerp_video_try_format_mplane(struct file *file, void *fh,
+ struct v4l2_format *format)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_scalerp_video_cropcap(struct file *file, void *fh,
+ struct v4l2_cropcap *cropcap)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_scalerp_video_get_crop(struct file *file, void *fh,
+ struct v4l2_crop *crop)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_scalerp_video_set_crop(struct file *file, void *fh,
+ struct v4l2_crop *crop)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_scalerp_video_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *buf)
+{
+ int ret = 0;
+ struct fimc_is_video_scp *video = file->private_data;
+ struct fimc_is_video_common *common = &video->common;
+ struct fimc_is_device_ischain *ischain = common->device;
+ struct fimc_is_ischain_dev *isp = &ischain->isp;
+ struct fimc_is_ischain_dev *scp = &ischain->scp;
+
+ dbg_scp("%s(buffers : %d)\n", __func__, buf->count);
+
+ if (test_bit(FIMC_IS_ISDEV_DSTART, &isp->state)) {
+ err("isp still running, not applied");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ ret = fimc_is_video_reqbufs(common, &scp->framemgr, buf);
+ if (ret)
+ err("fimc_is_video_reqbufs is fail(error %d)", ret);
+
+exit:
+ return ret;
+}
+
+static int fimc_is_scalerp_video_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ int ret;
+ struct fimc_is_video_scp *video = file->private_data;
+
+ dbg("%s\n", __func__);
+ ret = vb2_querybuf(&video->common.vbq, buf);
+
+ return ret;
+}
+
+static int fimc_is_scalerp_video_qbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ int ret = 0;
+ struct fimc_is_video_scp *video = file->private_data;
+
+#ifdef DBG_STREAMING
+ /*dbg_scp("%s(index : %d)\n", __func__, buf->index);*/
+#endif
+
+ ret = fimc_is_video_qbuf(&video->common, buf);
+
+ return ret;
+}
+
+static int fimc_is_scalerp_video_dqbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ int ret = 0;
+ struct fimc_is_video_scp *video = file->private_data;
+
+ ret = fimc_is_video_dqbuf(&video->common, buf,
+ file->f_flags & O_NONBLOCK);
+
+#ifdef DBG_STREAMING
+ /*dbg_scp("%s(index : %d)\n", __func__, buf->index);*/
+#endif
+
+ return ret;
+}
+
+static int fimc_is_scalerp_video_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ int ret = 0;
+ struct fimc_is_video_scp *video = file->private_data;
+
+ dbg_scp("%s\n", __func__);
+
+ ret = fimc_is_video_streamon(&video->common, type);
+
+ return ret;
+}
+
+static int fimc_is_scalerp_video_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ int ret = 0;
+ struct fimc_is_video_scp *video = file->private_data;
+
+ dbg_scp("%s\n", __func__);
+
+ ret = fimc_is_video_streamoff(&video->common, type);
+
+ return ret;
+}
+
+static int fimc_is_scalerp_video_enum_input(struct file *file, void *priv,
+ struct v4l2_input *input)
+{
+ struct fimc_is_core *isp = video_drvdata(file);
+ struct exynos5_fimc_is_sensor_info *sensor_info
+ = isp->pdata->sensor_info[input->index];
+
+ dbg("index(%d) sensor(%s)\n",
+ input->index, sensor_info->sensor_name);
+ dbg("pos(%d) sensor_id(%d)\n",
+ sensor_info->sensor_position, sensor_info->sensor_id);
+ dbg("csi_id(%d) flite_id(%d)\n",
+ sensor_info->csi_id, sensor_info->flite_id);
+ dbg("i2c_ch(%d)\n", sensor_info->i2c_channel);
+
+ if (input->index >= FIMC_IS_MAX_CAMIF_CLIENTS)
+ return -EINVAL;
+
+ input->type = V4L2_INPUT_TYPE_CAMERA;
+
+ strncpy(input->name, sensor_info->sensor_name,
+ FIMC_IS_MAX_SENSOR_NAME_LEN);
+ return 0;
+}
+
+static int fimc_is_scalerp_video_g_input(struct file *file, void *priv,
+ unsigned int *input)
+{
+ dbg("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_scalerp_video_s_input(struct file *file, void *priv,
+ unsigned int input)
+{
+ return 0;
+}
+
+static int fimc_is_scalerp_video_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ int ret = 0;
+ struct fimc_is_video_scp *video = file->private_data;
+ struct fimc_is_video_common *common = &video->common;
+ struct fimc_is_device_ischain *ischain = common->device;
+ struct fimc_is_ischain_dev *scp = &ischain->scp;
+ struct fimc_is_framemgr *framemgr = &scp->framemgr;
+
+ dbg_scp("%s\n", __func__);
+
+ switch (ctrl->id) {
+ case V4L2_CID_IS_G_COMPLETES:
+ ctrl->value = framemgr->frame_complete_cnt;
+ break;
+ default:
+ err("unsupported ioctl(%d)\n", ctrl->id);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int fimc_is_scalerp_video_g_ext_ctrl(struct file *file, void *priv,
+ struct v4l2_ext_controls *ctrls)
+{
+ return 0;
+}
+
+static int fimc_is_scalerp_video_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ int ret = 0;
+ unsigned long flags;
+ struct fimc_is_video_scp *video = file->private_data;
+ struct fimc_is_video_common *common = &video->common;
+ struct fimc_is_device_ischain *ischain = common->device;
+ struct fimc_is_ischain_dev *scp = &ischain->scp;
+ struct fimc_is_framemgr *framemgr = &scp->framemgr;
+ struct fimc_is_frame_shot *frame;
+
+ dbg_scp("%s\n", __func__);
+
+ switch (ctrl->id) {
+ case V4L2_CID_IS_FORCE_DONE:
+ if (framemgr->frame_process_cnt) {
+ err("force done can be performed(process count %d)",
+ framemgr->frame_process_cnt);
+ ret = -EINVAL;
+ } else if (!framemgr->frame_request_cnt) {
+ err("force done can be performed(request count %d)",
+ framemgr->frame_request_cnt);
+ ret = -EINVAL;
+ } else {
+ framemgr_e_barrier_irqs(framemgr, 0, flags);
+
+ fimc_is_frame_request_head(framemgr, &frame);
+ if (frame) {
+ fimc_is_frame_trans_req_to_com(framemgr, frame);
+ buffer_done(common, frame->index);
+ } else {
+ err("frame is NULL");
+ ret = -EINVAL;
+ }
+
+ framemgr_x_barrier_irqr(framemgr, 0, flags);
+ }
+ break;
+ default:
+ err("unsupported ioctl(%d)\n", ctrl->id);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+const struct v4l2_file_operations fimc_is_scalerp_video_fops = {
+ .owner = THIS_MODULE,
+ .open = fimc_is_scalerp_video_open,
+ .release = fimc_is_scalerp_video_close,
+ .poll = fimc_is_scalerp_video_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = fimc_is_scalerp_video_mmap,
+};
+
+const struct v4l2_ioctl_ops fimc_is_scalerp_video_ioctl_ops = {
+ .vidioc_querycap = fimc_is_scalerp_video_querycap,
+ .vidioc_enum_fmt_vid_cap_mplane
+ = fimc_is_scalerp_video_enum_fmt_mplane,
+ .vidioc_g_fmt_vid_cap_mplane
+ = fimc_is_scalerp_video_get_format_mplane,
+ .vidioc_s_fmt_vid_cap_mplane
+ = fimc_is_scalerp_video_set_format_mplane,
+ .vidioc_try_fmt_vid_cap_mplane
+ = fimc_is_scalerp_video_try_format_mplane,
+ .vidioc_cropcap = fimc_is_scalerp_video_cropcap,
+ .vidioc_g_crop = fimc_is_scalerp_video_get_crop,
+ .vidioc_s_crop = fimc_is_scalerp_video_set_crop,
+ .vidioc_reqbufs = fimc_is_scalerp_video_reqbufs,
+ .vidioc_querybuf = fimc_is_scalerp_video_querybuf,
+ .vidioc_qbuf = fimc_is_scalerp_video_qbuf,
+ .vidioc_dqbuf = fimc_is_scalerp_video_dqbuf,
+ .vidioc_streamon = fimc_is_scalerp_video_streamon,
+ .vidioc_streamoff = fimc_is_scalerp_video_streamoff,
+ .vidioc_enum_input = fimc_is_scalerp_video_enum_input,
+ .vidioc_g_input = fimc_is_scalerp_video_g_input,
+ .vidioc_s_input = fimc_is_scalerp_video_s_input,
+ .vidioc_g_ctrl = fimc_is_scalerp_video_g_ctrl,
+ .vidioc_s_ctrl = fimc_is_scalerp_video_s_ctrl,
+ .vidioc_g_ext_ctrls = fimc_is_scalerp_video_g_ext_ctrl,
+};
+
+static int fimc_is_scalerp_queue_setup(struct vb2_queue *vq,
+ const struct v4l2_format *fmt,
+ unsigned int *num_buffers,
+ unsigned int *num_planes,
+ unsigned int sizes[],
+ void *allocators[])
+{
+ int ret = 0;
+ struct fimc_is_video_scp *video = vq->drv_priv;
+
+ dbg_scp("%s\n", __func__);
+
+ ret = fimc_is_video_queue_setup(&video->common,
+ num_planes,
+ sizes,
+ allocators);
+
+ dbg_scp("(num_planes : %d)(size : %d)\n",
+ (int)*num_planes, (int)sizes[0]);
+
+ return ret;
+}
+
+static int fimc_is_scalerp_buffer_prepare(struct vb2_buffer *vb)
+{
+ return 0;
+}
+
+static inline void fimc_is_scalerp_wait_prepare(struct vb2_queue *q)
+{
+}
+
+static inline void fimc_is_scalerp_wait_finish(struct vb2_queue *q)
+{
+}
+
+static int fimc_is_scalerp_start_streaming(struct vb2_queue *q,
+ unsigned int count)
+{
+ int ret = 0;
+ struct fimc_is_video_scp *video = q->drv_priv;
+ struct fimc_is_video_common *common = &video->common;
+ struct fimc_is_device_ischain *ischain = common->device;
+ struct fimc_is_ischain_dev *scp = &ischain->scp;
+
+ dbg_scp("%s\n", __func__);
+
+ if (!test_bit(FIMC_IS_VIDEO_STREAM_ON, &common->state) &&
+ test_bit(FIMC_IS_VIDEO_BUFFER_READY, &common->state)) {
+ set_bit(FIMC_IS_VIDEO_STREAM_ON, &common->state);
+ fimc_is_ischain_dev_start(scp);
+ } else {
+ err("already stream on or buffer is not ready(%ld)",
+ common->state);
+ clear_bit(FIMC_IS_VIDEO_BUFFER_READY, &common->state);
+ clear_bit(FIMC_IS_VIDEO_BUFFER_PREPARED, &common->state);
+ fimc_is_ischain_dev_stop(scp);
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int fimc_is_scalerp_stop_streaming(struct vb2_queue *q)
+{
+ int ret = 0;
+ unsigned long flags;
+ struct fimc_is_video_scp *video = q->drv_priv;
+ struct fimc_is_video_common *common = &video->common;
+ struct fimc_is_device_ischain *ischain = common->device;
+ struct fimc_is_ischain_dev *scp = &ischain->scp;
+ struct fimc_is_framemgr *framemgr = &scp->framemgr;
+
+ dbg_scp("%s\n", __func__);
+
+ if (test_bit(FIMC_IS_VIDEO_STREAM_ON, &common->state)) {
+ framemgr_e_barrier_irqs(framemgr, 0, flags);
+ ret = framemgr->frame_process_cnt;
+ framemgr_x_barrier_irqr(framemgr, 0, flags);
+ if (ret) {
+ err("being processed, can't stop");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ clear_bit(FIMC_IS_VIDEO_STREAM_ON, &common->state);
+ clear_bit(FIMC_IS_VIDEO_BUFFER_READY, &common->state);
+ clear_bit(FIMC_IS_VIDEO_BUFFER_PREPARED, &common->state);
+ fimc_is_ischain_dev_stop(scp);
+ } else {
+ err("already stream off");
+ ret = -EINVAL;
+ }
+
+exit:
+ return ret;
+}
+
+static void fimc_is_scalerp_buffer_queue(struct vb2_buffer *vb)
+{
+ struct fimc_is_video_scp *video = vb->vb2_queue->drv_priv;
+ struct fimc_is_video_common *common = &video->common;
+ struct fimc_is_device_ischain *ischain = common->device;
+ struct fimc_is_ischain_dev *scp = &ischain->scp;
+
+#ifdef DBG_STREAMING
+ dbg_scp("%s\n", __func__);
+#endif
+
+ fimc_is_video_buffer_queue(common, vb, &scp->framemgr);
+ fimc_is_ischain_dev_buffer_queue(scp, vb->v4l2_buf.index);
+}
+
+static int fimc_is_scalerp_buffer_finish(struct vb2_buffer *vb)
+{
+ int ret = 0;
+ struct fimc_is_video_scc *video = vb->vb2_queue->drv_priv;
+ struct fimc_is_device_ischain *ischain = video->common.device;
+ struct fimc_is_ischain_dev *scp = &ischain->scp;
+
+#ifdef DBG_STREAMING
+ dbg_scp("%s(%d)\n", __func__, vb->v4l2_buf.index);
+#endif
+
+ ret = fimc_is_ischain_dev_buffer_finish(scp, vb->v4l2_buf.index);
+
+ return ret;
+}
+
+const struct vb2_ops fimc_is_scalerp_qops = {
+ .queue_setup = fimc_is_scalerp_queue_setup,
+ .buf_prepare = fimc_is_scalerp_buffer_prepare,
+ .buf_queue = fimc_is_scalerp_buffer_queue,
+ .buf_finish = fimc_is_scalerp_buffer_finish,
+ .wait_prepare = fimc_is_scalerp_wait_prepare,
+ .wait_finish = fimc_is_scalerp_wait_finish,
+ .start_streaming = fimc_is_scalerp_start_streaming,
+ .stop_streaming = fimc_is_scalerp_stop_streaming,
+};
diff --git a/drivers/media/video/exynos/fimc-is-mc2/fimc-is-video-scp.h b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-video-scp.h
new file mode 100644
index 0000000..a2615f3
--- /dev/null
+++ b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-video-scp.h
@@ -0,0 +1,14 @@
+#ifndef FIMC_IS_VIDEO_SCP_H
+#define FIMC_IS_VIDEO_SCP_H
+
+#include "fimc-is-video.h"
+
+#define VIDEO_SCP_READY_BUFFERS 8
+
+struct fimc_is_video_scp {
+ struct fimc_is_video_common common;
+};
+
+int fimc_is_scp_video_probe(void *data);
+
+#endif
diff --git a/drivers/media/video/exynos/fimc-is-mc2/fimc-is-video-sensor.c b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-video-sensor.c
new file mode 100644
index 0000000..d56bb33
--- /dev/null
+++ b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-video-sensor.c
@@ -0,0 +1,505 @@
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ * exynos5 fimc-is video functions
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <mach/videonode.h>
+#include <media/exynos_mc.h>
+#include <linux/cma.h>
+#include <asm/cacheflush.h>
+#include <asm/pgtable.h>
+#include <linux/firmware.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
+#include <linux/videodev2_exynos_media.h>
+#include <linux/videodev2_exynos_camera.h>
+#include <linux/v4l2-mediabus.h>
+
+#include "fimc-is-core.h"
+#include "fimc-is-param.h"
+#include "fimc-is-cmd.h"
+#include "fimc-is-regs.h"
+#include "fimc-is-err.h"
+#include "fimc-is-video.h"
+#include "fimc-is-metadata.h"
+
+/*************************************************************************/
+/* video file opertation */
+/************************************************************************/
+int fimc_is_sensor_video_probe(void *data)
+{
+ int ret = 0;
+ struct fimc_is_core *core = (struct fimc_is_core *)data;
+ struct fimc_is_video_sensor *video = &core->video_sensor;
+
+ dbg_sensor("%s\n", __func__);
+
+ ret = fimc_is_video_probe(&video->common,
+ data,
+ video,
+ FIMC_IS_VIDEO_BAYER_NAME,
+ FIMC_IS_VIDEO_NUM_BAYER,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
+ &fimc_is_bayer_video_fops,
+ &fimc_is_bayer_video_ioctl_ops,
+ &fimc_is_bayer_qops);
+
+ return ret;
+}
+
+static int fimc_is_bayer_video_open(struct file *file)
+{
+ struct fimc_is_core *core = video_drvdata(file);
+ struct fimc_is_video_sensor *video = &core->video_sensor;
+ struct fimc_is_device_sensor *sensor = &core->sensor;
+
+ dbg_sensor("%s\n", __func__);
+
+ file->private_data = video;
+ fimc_is_video_open(&video->common, sensor,
+ VIDEO_SENSOR_READY_BUFFERS);
+ fimc_is_sensor_open(sensor);
+
+ return 0;
+}
+
+static int fimc_is_bayer_video_close(struct file *file)
+{
+ struct fimc_is_video_sensor *video = file->private_data;
+ struct fimc_is_video_common *common = &video->common;
+ struct fimc_is_device_sensor *sensor = common->device;
+
+ printk(KERN_INFO "%s\n", __func__);
+
+ if (test_bit(FIMC_IS_VIDEO_STREAM_ON, &common->state))
+ clear_bit(FIMC_IS_VIDEO_STREAM_ON, &common->state);
+
+ file->private_data = 0;
+ fimc_is_sensor_close(sensor);
+ fimc_is_video_close(&video->common, sensor->framemgr);
+
+ return 0;
+}
+
+static unsigned int fimc_is_bayer_video_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct fimc_is_core *isp = video_drvdata(file);
+
+ dbg_sensor("%s\n", __func__);
+ return vb2_poll(&isp->video_sensor.common.vbq, file, wait);
+}
+
+static int fimc_is_bayer_video_mmap(struct file *file,
+ struct vm_area_struct *vma)
+{
+ struct fimc_is_core *is = video_drvdata(file);
+
+ return vb2_mmap(&is->video_sensor.common.vbq, vma);
+}
+
+/*************************************************************************/
+/* video ioctl operation */
+/************************************************************************/
+
+static int fimc_is_bayer_video_querycap(struct file *file, void *fh,
+ struct v4l2_capability *cap)
+{
+ struct fimc_is_core *isp = video_drvdata(file);
+
+ strncpy(cap->driver, isp->pdev->name, sizeof(cap->driver) - 1);
+
+ dbg_sensor("%s(devname : %s)\n", __func__, cap->driver);
+ strncpy(cap->card, isp->pdev->name, sizeof(cap->card) - 1);
+ cap->bus_info[0] = 0;
+ cap->version = KERNEL_VERSION(1, 0, 0);
+ cap->capabilities = V4L2_CAP_STREAMING
+ | V4L2_CAP_VIDEO_CAPTURE
+ | V4L2_CAP_VIDEO_CAPTURE_MPLANE;
+
+ return 0;
+}
+
+static int fimc_is_bayer_video_enum_fmt_mplane(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ dbg_sensor("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_bayer_video_get_format_mplane(struct file *file, void *fh,
+ struct v4l2_format *format)
+{
+ dbg_sensor("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_bayer_video_set_format_mplane(struct file *file, void *fh,
+ struct v4l2_format *format)
+{
+ int ret = 0;
+ struct fimc_is_video_sensor *video = file->private_data;
+
+ dbg_scp("%s\n", __func__);
+
+ ret = fimc_is_video_set_format_mplane(&video->common, format);
+
+ dbg_sensor("req w : %d req h : %d\n",
+ video->common.frame.width,
+ video->common.frame.height);
+
+ return ret;
+}
+
+static int fimc_is_bayer_video_try_format_mplane(struct file *file, void *fh,
+ struct v4l2_format *format)
+{
+ dbg_sensor("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_bayer_video_cropcap(struct file *file, void *fh,
+ struct v4l2_cropcap *cropcap)
+{
+ dbg_sensor("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_bayer_video_get_crop(struct file *file, void *fh,
+ struct v4l2_crop *crop)
+{
+ dbg_sensor("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_bayer_video_set_crop(struct file *file, void *fh,
+ struct v4l2_crop *crop)
+{
+ dbg_sensor("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_bayer_video_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *buf)
+{
+ int ret = 0;
+ struct fimc_is_video_sensor *video = file->private_data;
+ struct fimc_is_video_common *common = &video->common;
+ struct fimc_is_device_sensor *sensor = common->device;
+
+ dbg_sensor("%s(buffers : %d)\n", __func__, buf->count);
+
+ ret = fimc_is_video_reqbufs(common, sensor->framemgr, buf);
+ if (ret)
+ err("fimc_is_video_reqbufs is fail(error %d)", ret);
+
+ return ret;
+}
+
+static int fimc_is_bayer_video_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ int ret;
+ struct fimc_is_video_sensor *video = file->private_data;
+
+ dbg_sensor("%s\n", __func__);
+
+ ret = vb2_querybuf(&video->common.vbq, buf);
+
+ return ret;
+}
+
+static int fimc_is_bayer_video_qbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ int ret = 0;
+ struct fimc_is_video_sensor *video = file->private_data;
+
+#ifdef DBG_STREAMING
+ /*dbg_sensor("%s\n", __func__);*/
+#endif
+
+ ret = fimc_is_video_qbuf(&video->common, buf);
+
+ return ret;
+}
+
+static int fimc_is_bayer_video_dqbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ int ret = 0;
+ struct fimc_is_video_sensor *video = file->private_data;
+ bool blocking = file->f_flags & O_NONBLOCK;
+
+ ret = fimc_is_video_dqbuf(&video->common, buf, blocking);
+
+#ifdef DBG_STREAMING
+ /*dbg_sensor("%s(index : %d)\n", __func__, buf->index);*/
+#endif
+
+ return ret;
+}
+
+static int fimc_is_bayer_video_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ int ret = 0;
+ struct fimc_is_video_sensor *video = file->private_data;
+
+ dbg_sensor("%s\n", __func__);
+
+ ret = fimc_is_video_streamon(&video->common, type);
+
+ return ret;
+}
+
+static int fimc_is_bayer_video_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ int ret = 0;
+ struct fimc_is_video_sensor *video = file->private_data;
+
+ dbg_sensor("%s\n", __func__);
+
+ ret = fimc_is_video_streamoff(&video->common, type);
+
+ return ret;
+}
+
+static int fimc_is_bayer_video_enum_input(struct file *file, void *priv,
+ struct v4l2_input *input)
+{
+ struct fimc_is_core *isp = video_drvdata(file);
+ struct exynos5_fimc_is_sensor_info *sensor_info;
+
+ sensor_info = isp->pdata->sensor_info[input->index];
+
+ dbg_sensor("index(%d) sensor(%s)\n",
+ input->index, sensor_info->sensor_name);
+ dbg_sensor("pos(%d) sensor_id(%d)\n",
+ sensor_info->sensor_position, sensor_info->sensor_id);
+ dbg_sensor("csi_id(%d) flite_id(%d)\n",
+ sensor_info->csi_id, sensor_info->flite_id);
+ dbg_sensor("i2c_ch(%d)\n", sensor_info->i2c_channel);
+
+ if (input->index >= FIMC_IS_MAX_CAMIF_CLIENTS)
+ return -EINVAL;
+
+ input->type = V4L2_INPUT_TYPE_CAMERA;
+
+ strncpy(input->name, sensor_info->sensor_name,
+ FIMC_IS_MAX_SENSOR_NAME_LEN);
+ return 0;
+}
+
+static int fimc_is_bayer_video_g_input(struct file *file, void *priv,
+ unsigned int *input)
+{
+ dbg_sensor("%s\n", __func__);
+ return 0;
+}
+
+static int fimc_is_bayer_video_s_input(struct file *file, void *priv,
+ unsigned int input)
+{
+ int ret = 0;
+ struct fimc_is_video_sensor *video = file->private_data;
+ struct fimc_is_device_sensor *sensor = video->common.device;
+
+ dbg_sensor("%s(input : %d)\n", __func__, input);
+
+ fimc_is_sensor_s_active_sensor(sensor, input);
+
+ return ret;
+}
+
+static int fimc_is_bayer_video_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ int ret = 0;
+ struct fimc_is_video_sensor *video = file->private_data;
+ struct fimc_is_device_sensor *sensor = video->common.device;
+
+ switch (ctrl->id) {
+ case V4L2_CID_IS_S_STREAM:
+ if (ctrl->value == IS_ENABLE_STREAM)
+ ret = fimc_is_sensor_front_start(sensor);
+ else
+ ret = fimc_is_sensor_front_stop(sensor);
+ break;
+ }
+
+ return ret;
+}
+
+const struct v4l2_file_operations fimc_is_bayer_video_fops = {
+ .owner = THIS_MODULE,
+ .open = fimc_is_bayer_video_open,
+ .release = fimc_is_bayer_video_close,
+ .poll = fimc_is_bayer_video_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = fimc_is_bayer_video_mmap,
+};
+
+const struct v4l2_ioctl_ops fimc_is_bayer_video_ioctl_ops = {
+ .vidioc_querycap = fimc_is_bayer_video_querycap,
+ .vidioc_enum_fmt_vid_cap_mplane = fimc_is_bayer_video_enum_fmt_mplane,
+ .vidioc_g_fmt_vid_cap_mplane = fimc_is_bayer_video_get_format_mplane,
+ .vidioc_s_fmt_vid_cap_mplane = fimc_is_bayer_video_set_format_mplane,
+ .vidioc_try_fmt_vid_cap_mplane = fimc_is_bayer_video_try_format_mplane,
+ .vidioc_cropcap = fimc_is_bayer_video_cropcap,
+ .vidioc_g_crop = fimc_is_bayer_video_get_crop,
+ .vidioc_s_crop = fimc_is_bayer_video_set_crop,
+ .vidioc_reqbufs = fimc_is_bayer_video_reqbufs,
+ .vidioc_querybuf = fimc_is_bayer_video_querybuf,
+ .vidioc_qbuf = fimc_is_bayer_video_qbuf,
+ .vidioc_dqbuf = fimc_is_bayer_video_dqbuf,
+ .vidioc_streamon = fimc_is_bayer_video_streamon,
+ .vidioc_streamoff = fimc_is_bayer_video_streamoff,
+ .vidioc_enum_input = fimc_is_bayer_video_enum_input,
+ .vidioc_g_input = fimc_is_bayer_video_g_input,
+ .vidioc_s_input = fimc_is_bayer_video_s_input,
+ .vidioc_s_ctrl = fimc_is_bayer_video_s_ctrl
+};
+
+static int fimc_is_bayer_queue_setup(struct vb2_queue *vq,
+ const struct v4l2_format *fmt,
+ unsigned int *num_buffers, unsigned int *num_planes,
+ unsigned int sizes[],
+ void *allocators[])
+{
+ int ret = 0;
+ struct fimc_is_video_sensor *video = vq->drv_priv;
+
+ dbg_sensor("%s\n", __func__);
+
+ ret = fimc_is_video_queue_setup(&video->common,
+ num_planes,
+ sizes,
+ allocators);
+
+ dbg_sensor("(num_planes : %d)(size : %d)\n",
+ (int)*num_planes, (int)sizes[0]);
+
+ return ret;
+}
+
+static int fimc_is_bayer_buffer_prepare(struct vb2_buffer *vb)
+{
+ /*dbg_sensor("-%s\n", __func__);*/
+
+ return 0;
+}
+
+static inline void fimc_is_bayer_wait_prepare(struct vb2_queue *q)
+{
+}
+
+static inline void fimc_is_bayer_wait_finish(struct vb2_queue *q)
+{
+}
+
+static int fimc_is_bayer_start_streaming(struct vb2_queue *q,
+ unsigned int count)
+{
+ int ret = 0;
+ struct fimc_is_video_sensor *video = q->drv_priv;
+ struct fimc_is_video_common *common = &video->common;
+ struct fimc_is_device_sensor *sensor = common->device;
+
+ dbg_sensor("%s\n", __func__);
+
+ if (!test_bit(FIMC_IS_VIDEO_STREAM_ON, &common->state) &&
+ test_bit(FIMC_IS_VIDEO_BUFFER_READY, &common->state)) {
+ set_bit(FIMC_IS_VIDEO_STREAM_ON, &common->state);
+ fimc_is_sensor_back_start(sensor, common);
+ } else {
+ err("already stream on or buffer is not ready(%ld)",
+ common->state);
+ clear_bit(FIMC_IS_VIDEO_BUFFER_READY, &common->state);
+ clear_bit(FIMC_IS_VIDEO_BUFFER_PREPARED, &common->state);
+ fimc_is_sensor_back_stop(sensor);
+ ret = -EINVAL;
+ }
+
+ return 0;
+}
+
+static int fimc_is_bayer_stop_streaming(struct vb2_queue *q)
+{
+ int ret = 0;
+ struct fimc_is_video_sensor *video = q->drv_priv;
+ struct fimc_is_video_common *common = &video->common;
+ struct fimc_is_device_sensor *sensor = video->common.device;
+
+ dbg_sensor("%s\n", __func__);
+
+ if (test_bit(FIMC_IS_VIDEO_STREAM_ON, &common->state)) {
+ clear_bit(FIMC_IS_VIDEO_STREAM_ON, &common->state);
+ clear_bit(FIMC_IS_VIDEO_BUFFER_READY, &common->state);
+ clear_bit(FIMC_IS_VIDEO_BUFFER_PREPARED, &common->state);
+ ret = fimc_is_sensor_back_stop(sensor);
+ } else {
+ err("already stream off");
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static void fimc_is_bayer_buffer_queue(struct vb2_buffer *vb)
+{
+ struct fimc_is_video_sensor *video = vb->vb2_queue->drv_priv;
+ struct fimc_is_video_common *common = &video->common;
+ struct fimc_is_device_sensor *sensor = common->device;
+
+#ifdef DBG_STREAMING
+ dbg_sensor("%s(%d)\n", __func__, vb->v4l2_buf.index);
+#endif
+
+ fimc_is_video_buffer_queue(common, vb, sensor->framemgr);
+ fimc_is_sensor_buffer_queue(sensor, vb->v4l2_buf.index);
+}
+
+static int fimc_is_bayer_buffer_finish(struct vb2_buffer *vb)
+{
+ int ret = 0;
+ struct fimc_is_video_sensor *video = vb->vb2_queue->drv_priv;
+ struct fimc_is_device_sensor *sensor = video->common.device;
+
+#ifdef DBG_STREAMING
+ dbg_sensor("%s(%d)\n", __func__, vb->v4l2_buf.index);
+#endif
+
+ ret = fimc_is_sensor_buffer_finish(
+ sensor,
+ vb->v4l2_buf.index);
+
+ return 0;
+}
+
+const struct vb2_ops fimc_is_bayer_qops = {
+ .queue_setup = fimc_is_bayer_queue_setup,
+ .buf_prepare = fimc_is_bayer_buffer_prepare,
+ .buf_queue = fimc_is_bayer_buffer_queue,
+ .buf_finish = fimc_is_bayer_buffer_finish,
+ .wait_prepare = fimc_is_bayer_wait_prepare,
+ .wait_finish = fimc_is_bayer_wait_finish,
+ .start_streaming = fimc_is_bayer_start_streaming,
+ .stop_streaming = fimc_is_bayer_stop_streaming,
+};
diff --git a/drivers/media/video/exynos/fimc-is-mc2/fimc-is-video-sensor.h b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-video-sensor.h
new file mode 100644
index 0000000..56f69f8
--- /dev/null
+++ b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-video-sensor.h
@@ -0,0 +1,14 @@
+#ifndef FIMC_IS_VIDEO_SENSOR_H
+#define FIMC_IS_VIDEO_SENSOR_H
+
+#include "fimc-is-video.h"
+
+#define VIDEO_SENSOR_READY_BUFFERS 3
+
+struct fimc_is_video_sensor {
+ struct fimc_is_video_common common;
+};
+
+int fimc_is_sensor_video_probe(void *data);
+
+#endif
diff --git a/drivers/media/video/exynos/fimc-is-mc2/fimc-is-video.c b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-video.c
new file mode 100644
index 0000000..9a40df2
--- /dev/null
+++ b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-video.c
@@ -0,0 +1,592 @@
+/*
+* Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ * exynos5 fimc-is video functions
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <mach/videonode.h>
+#include <media/exynos_mc.h>
+#include <linux/cma.h>
+#include <asm/cacheflush.h>
+#include <asm/pgtable.h>
+#include <linux/firmware.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
+#include <linux/videodev2_exynos_media.h>
+#include <linux/videodev2_exynos_camera.h>
+#include <linux/v4l2-mediabus.h>
+
+#include "fimc-is-time.h"
+#include "fimc-is-core.h"
+#include "fimc-is-param.h"
+#include "fimc-is-cmd.h"
+#include "fimc-is-regs.h"
+#include "fimc-is-err.h"
+
+#ifdef USE_FRAME_SYNC
+#define SPARE_PLANE 1
+#define SPARE_SIZE (4*1024)
+#else
+#define SPARE_PLANE 0
+#define SPARE_SIZE 0
+#endif
+
+struct fimc_is_fmt fimc_is_formats[] = {
+ {
+ .name = "YUV 4:2:2 packed, YCbYCr",
+ .pixelformat = V4L2_PIX_FMT_YUYV,
+ .num_planes = 1 + SPARE_PLANE,
+ .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8,
+ }, {
+ .name = "YUV 4:2:2 packed, CbYCrY",
+ .pixelformat = V4L2_PIX_FMT_UYVY,
+ .num_planes = 1 + SPARE_PLANE,
+ .mbus_code = V4L2_MBUS_FMT_UYVY8_2X8,
+ }, {
+ .name = "YUV 4:2:2 planar, Y/Cb/Cr",
+ .pixelformat = V4L2_PIX_FMT_YUV422P,
+ .num_planes = 1 + SPARE_PLANE,
+ }, {
+ .name = "YUV 4:2:0 planar, YCbCr",
+ .pixelformat = V4L2_PIX_FMT_YUV420,
+ .num_planes = 1 + SPARE_PLANE,
+ }, {
+ .name = "YUV 4:2:0 planar, YCbCr",
+ .pixelformat = V4L2_PIX_FMT_YVU420,
+ .num_planes = 1 + SPARE_PLANE,
+ }, {
+ .name = "YUV 4:2:0 planar, Y/CbCr",
+ .pixelformat = V4L2_PIX_FMT_NV12,
+ .num_planes = 1 + SPARE_PLANE,
+ }, {
+ .name = "YUV 4:2:0 planar, Y/CrCb",
+ .pixelformat = V4L2_PIX_FMT_NV21,
+ .num_planes = 1 + SPARE_PLANE,
+ }, {
+ .name = "YUV 4:2:0 non-contiguous 2-planar, Y/CbCr",
+ .pixelformat = V4L2_PIX_FMT_NV12M,
+ .num_planes = 2 + SPARE_PLANE,
+ }, {
+ .name = "YVU 4:2:0 non-contiguous 2-planar, Y/CrCb",
+ .pixelformat = V4L2_PIX_FMT_NV21M,
+ .num_planes = 2 + SPARE_PLANE,
+ }, {
+ .name = "YUV 4:2:0 non-contiguous 3-planar, Y/Cb/Cr",
+ .pixelformat = V4L2_PIX_FMT_YUV420M,
+ .num_planes = 3 + SPARE_PLANE,
+ }, {
+ .name = "YUV 4:2:0 non-contiguous 3-planar, Y/Cr/Cb",
+ .pixelformat = V4L2_PIX_FMT_YVU420M,
+ .num_planes = 3 + SPARE_PLANE,
+ }, {
+ .name = "BAYER 10 bit",
+ .pixelformat = V4L2_PIX_FMT_SBGGR10,
+ .num_planes = 2,
+ }, {
+ .name = "BAYER 12 bit",
+ .pixelformat = V4L2_PIX_FMT_SBGGR12,
+ .num_planes = 2,
+ }, {
+ .name = "BAYER 16 bit",
+ .pixelformat = V4L2_PIX_FMT_SBGGR16,
+ .num_planes = 2,
+ },
+};
+
+struct fimc_is_fmt *fimc_is_find_format(u32 *pixelformat,
+ u32 *mbus_code, int index)
+{
+ struct fimc_is_fmt *fmt, *def_fmt = NULL;
+ unsigned int i;
+
+ if (index >= ARRAY_SIZE(fimc_is_formats))
+ return NULL;
+
+ for (i = 0; i < ARRAY_SIZE(fimc_is_formats); ++i) {
+ fmt = &fimc_is_formats[i];
+ if (pixelformat && fmt->pixelformat == *pixelformat)
+ return fmt;
+ if (mbus_code && fmt->mbus_code == *mbus_code)
+ return fmt;
+ if (index == i)
+ def_fmt = fmt;
+ }
+ return def_fmt;
+
+}
+
+void fimc_is_set_plane_size(struct fimc_is_frame *frame, unsigned int sizes[])
+{
+ u32 plane;
+ u32 width[FIMC_IS_MAX_PLANES];
+
+ for (plane = 0; plane < FIMC_IS_MAX_PLANES; ++plane)
+ width[plane] = frame->width + frame->width_stride[plane];
+
+ switch (frame->format.pixelformat) {
+ case V4L2_PIX_FMT_YUYV:
+ dbg("V4L2_PIX_FMT_YUYV(w:%d)(h:%d)\n",
+ frame->width, frame->height);
+ sizes[0] = width[0]*frame->height*2;
+#ifdef USE_FRAME_SYNC
+ sizes[1] = SPARE_SIZE;
+#endif
+ break;
+ case V4L2_PIX_FMT_NV12M:
+ dbg("V4L2_PIX_FMT_NV12M(w:%d)(h:%d)\n",
+ frame->width, frame->height);
+ sizes[0] = width[0]*frame->height;
+ sizes[1] = width[1]*frame->height/2;
+#ifdef USE_FRAME_SYNC
+ sizes[2] = SPARE_SIZE;
+#endif
+ break;
+ case V4L2_PIX_FMT_YUV420M:
+ case V4L2_PIX_FMT_YVU420M:
+ dbg("V4L2_PIX_FMT_YVU420M(w:%d)(h:%d)\n",
+ frame->width, frame->height);
+ sizes[0] = width[0]*frame->height;
+ sizes[1] = width[1]*frame->height/4;
+ sizes[2] = width[2]*frame->height/4;
+#ifdef USE_FRAME_SYNC
+ sizes[3] = SPARE_SIZE;
+#endif
+ break;
+ case V4L2_PIX_FMT_SBGGR10:
+ dbg("V4L2_PIX_FMT_SBGGR10(w:%d)(h:%d)\n",
+ frame->width, frame->height);
+ sizes[0] = frame->width*frame->height*2;
+ sizes[1] = 8*1024;
+ break;
+ case V4L2_PIX_FMT_SBGGR16:
+ dbg("V4L2_PIX_FMT_SBGGR16(w:%d)(h:%d)\n",
+ frame->width, frame->height);
+ sizes[0] = frame->width*frame->height*2;
+ sizes[1] = 8*1024;
+ break;
+ case V4L2_PIX_FMT_SBGGR12:
+ dbg("V4L2_PIX_FMT_SBGGR12(w:%d)(h:%d)\n",
+ frame->width, frame->height);
+ sizes[0] = frame->width*frame->height*2;
+ sizes[1] = 8*1024;
+ break;
+ default:
+ err("unknown pixelformat\n");
+ break;
+ }
+}
+
+int fimc_is_video_probe(struct fimc_is_video_common *video,
+ void *core_data,
+ void *video_data,
+ char *video_name,
+ u32 video_number,
+ u32 vbq_type,
+ const struct v4l2_file_operations *fops,
+ const struct v4l2_ioctl_ops *ioctl_ops,
+ const struct vb2_ops *vb2_ops)
+{
+ int ret = 0;
+ struct fimc_is_core *core = core_data;
+ struct vb2_queue *vbq;
+
+ snprintf(video->vd.name, sizeof(video->vd.name),
+ "%s", video_name);
+
+ mutex_init(&video->lock);
+
+ video->core = core;
+ video->vb2 = core->mem.vb2;
+ video->vd.fops = fops;
+ video->vd.ioctl_ops = ioctl_ops;
+ video->vd.v4l2_dev = &core->mdev->v4l2_dev;
+ video->vd.minor = -1;
+ video->vd.release = video_device_release;
+ video->vd.lock = &video->lock;
+ video_set_drvdata(&video->vd, core);
+
+ vbq = &video->vbq;
+ memset(vbq, 0, sizeof(struct vb2_queue));
+ vbq->type = vbq_type;
+ vbq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
+ vbq->drv_priv = video_data;
+ vbq->ops = vb2_ops;
+ vbq->mem_ops = core->mem.vb2->ops;
+
+ vb2_queue_init(vbq);
+
+ ret = video_register_device(&video->vd,
+ VFL_TYPE_GRABBER,
+ video_number
+ + EXYNOS_VIDEONODE_FIMC_IS);
+ if (ret) {
+ err("Failed to register ScalerP video device\n");
+ goto p_err;
+ }
+
+ video->pads.flags = MEDIA_PAD_FL_SINK;
+ ret = media_entity_init(&video->vd.entity,
+ 1, &video->pads, 0);
+ if (ret) {
+ err("Failed to media_entity_init ScalerP video device\n");
+ goto p_err;
+ }
+
+p_err:
+ return ret;
+}
+
+int fimc_is_video_open(struct fimc_is_video_common *video,
+ void *device, u32 buffers_ready)
+{
+ int ret = 0;
+
+ video->buffers = 0;
+ video->buffers_ready = buffers_ready;
+ video->buf_ref_cnt = 0;
+ video->device = device;
+
+ clear_bit(FIMC_IS_VIDEO_BUFFER_PREPARED, &video->state);
+ clear_bit(FIMC_IS_VIDEO_BUFFER_READY, &video->state);
+ clear_bit(FIMC_IS_VIDEO_STREAM_ON, &video->state);
+
+ memset(&video->frame, 0, sizeof(struct fimc_is_frame));
+
+ return ret;
+}
+
+int fimc_is_video_close(struct fimc_is_video_common *video,
+ struct fimc_is_framemgr *framemgr)
+{
+ int ret = 0;
+
+ video->buffers = 0;
+ video->buf_ref_cnt = 0;
+ video->device = 0;
+
+ clear_bit(FIMC_IS_VIDEO_BUFFER_PREPARED, &video->state);
+ clear_bit(FIMC_IS_VIDEO_BUFFER_READY, &video->state);
+ clear_bit(FIMC_IS_VIDEO_STREAM_ON, &video->state);
+ fimc_is_frame_close(framemgr);
+
+ vb2_queue_release(&video->vbq);
+
+ return ret;
+}
+
+int fimc_is_video_reqbufs(struct fimc_is_video_common *video,
+ struct fimc_is_framemgr *framemgr,
+ struct v4l2_requestbuffers *request)
+{
+ int ret = 0;
+
+ if (test_bit(FIMC_IS_VIDEO_STREAM_ON, &video->state)) {
+ err("video is stream on, not applied");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ ret = vb2_reqbufs(&video->vbq, request);
+ if (ret) {
+ err("(type, mem) : vbq(%d,%d) != req(%d,%d)",
+ video->vbq.type, video->vbq.memory,
+ request->type, request->memory);
+ goto exit;
+ }
+
+ video->buffers = request->count;
+
+ if (video->buffers == 0) {
+ video->buf_ref_cnt = 0;
+ fimc_is_frame_close(framemgr);
+ } else {
+ if (video->buffers < video->buffers_ready) {
+ err("buffer count is not invalid(%d < %d)",
+ video->buffers, video->buffers_ready);
+ ret = -EINVAL;
+ goto exit;
+ }
+ fimc_is_frame_open(framemgr, video->buffers);
+ }
+
+exit:
+ return ret;
+}
+
+int fimc_is_video_set_format_mplane(struct fimc_is_video_common *video,
+ struct v4l2_format *format)
+{
+ int ret = 0;
+ u32 plane;
+ struct v4l2_pix_format_mplane *pix;
+ struct fimc_is_fmt *frame;
+
+ pix = &format->fmt.pix_mp;
+ frame = fimc_is_find_format(&pix->pixelformat, NULL, 0);
+ if (!frame) {
+ err("pixel format is not found\n");
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ video->frame.format.pixelformat = frame->pixelformat;
+ video->frame.format.mbus_code = frame->mbus_code;
+ video->frame.format.num_planes = frame->num_planes;
+ video->frame.width = pix->width;
+ video->frame.height = pix->height;
+
+ for (plane = 0; plane < frame->num_planes; ++plane) {
+ if (pix->plane_fmt[plane].bytesperline)
+ video->frame.width_stride[plane] =
+ pix->plane_fmt[plane].bytesperline - pix->width;
+ else
+ video->frame.width_stride[plane] = 0;
+ }
+
+p_err:
+ return ret;
+}
+
+int fimc_is_video_qbuf(struct fimc_is_video_common *video,
+ struct v4l2_buffer *buf)
+{
+ int ret = 0;
+
+ buf->flags &= ~V4L2_BUF_FLAG_USE_SYNC;
+
+ ret = vb2_qbuf(&video->vbq, buf);
+ if (ret)
+ err("vb2_qbuf is failed(%d)", ret);
+
+ return ret;
+}
+
+int fimc_is_video_dqbuf(struct fimc_is_video_common *video,
+ struct v4l2_buffer *buf, bool blocking)
+{
+ int ret = 0;
+
+ ret = vb2_dqbuf(&video->vbq, buf, blocking);
+ if (ret)
+ err("vb2_dqbuf is failed(%d)", ret);
+
+ video->buf_mask &= ~(1<<buf->index);
+
+ return ret;
+}
+
+int fimc_is_video_streamon(struct fimc_is_video_common *video,
+ enum v4l2_buf_type type)
+{
+ int ret = 0;
+
+ ret = vb2_streamon(&video->vbq, type);
+ if (ret)
+ err("vb2_streamon is failed(%d)", ret);
+
+ return ret;
+}
+
+int fimc_is_video_streamoff(struct fimc_is_video_common *video,
+ enum v4l2_buf_type type)
+{
+ int ret = 0;
+
+ ret = vb2_streamoff(&video->vbq, type);
+ if (ret)
+ err("vb2_streamoff is failed(%d)", ret);
+
+ return ret;
+}
+
+int fimc_is_video_queue_setup(struct fimc_is_video_common *video,
+ unsigned int *num_planes,
+ unsigned int sizes[],
+ void *allocators[])
+{
+ u32 ret = 0, i;
+ struct fimc_is_core *core = video->core;
+
+ *num_planes = (unsigned int)(video->frame.format.num_planes);
+ fimc_is_set_plane_size(&video->frame, sizes);
+
+ for (i = 0; i < *num_planes; i++) {
+ allocators[i] = core->mem.alloc_ctx;
+ video->frame.size[i] = sizes[i];
+ }
+
+ return ret;
+}
+
+int fimc_is_video_buffer_queue(struct fimc_is_video_common *video,
+ struct vb2_buffer *vb, struct fimc_is_framemgr *framemgr)
+{
+ u32 ret = 0, i;
+ u32 index;
+ u32 ext_size;
+ u32 spare;
+ struct fimc_is_core *core = video->core;
+ struct fimc_is_frame_shot *frame;
+
+ index = vb->v4l2_buf.index;
+
+ if (!framemgr) {
+ err("framemgr is null");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ /* plane address is updated for checking everytime */
+ if (video->frame.format.pixelformat == V4L2_PIX_FMT_YVU420M) {
+ video->buf_dva[index][0] = core->mem.vb2->plane_addr(vb, 0);
+ video->buf_kva[index][0] = core->mem.vb2->plane_kvaddr(vb, 0);
+
+ video->buf_dva[index][1] = core->mem.vb2->plane_addr(vb, 2);
+ video->buf_kva[index][1] = core->mem.vb2->plane_kvaddr(vb, 2);
+
+ video->buf_dva[index][2] = core->mem.vb2->plane_addr(vb, 1);
+ video->buf_kva[index][2] = core->mem.vb2->plane_kvaddr(vb, 1);
+
+#ifdef USE_FRAME_SYNC
+ video->buf_dva[index][3] = core->mem.vb2->plane_addr(vb, 3);
+ video->buf_kva[index][3] = core->mem.vb2->plane_kvaddr(vb, 3);
+#endif
+ } else {
+ for (i = 0; i < vb->num_planes; i++) {
+ video->buf_dva[index][i]
+ = core->mem.vb2->plane_addr(vb, i);
+ video->buf_kva[index][i]
+ = core->mem.vb2->plane_kvaddr(vb, i);
+ }
+ }
+
+ frame = &framemgr->frame[index];
+
+ /* uninitialized frame need to get info */
+ if (frame->init == FRAME_UNI_MEM)
+ goto set_info;
+
+ /* plane count check */
+ if (frame->planes != vb->num_planes) {
+ err("plane count is changed(%08X != %08X)",
+ frame->planes, vb->num_planes);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ /* plane address check */
+ for (i = 0; i < frame->planes; i++) {
+ if (frame->kvaddr_buffer[i] !=
+ video->buf_kva[index][i]) {
+ err("buffer %d plane %d is changed(%08X != %08X)",
+ index, i,
+ frame->kvaddr_buffer[i],
+ video->buf_kva[index][i]);
+ ret = -EINVAL;
+ goto exit;
+ }
+ }
+
+ goto exit;
+
+set_info:
+ if (test_bit(FIMC_IS_VIDEO_BUFFER_PREPARED, &video->state)) {
+ err("already prepared but new index(%d) is came", index);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ frame->vb = vb;
+ frame->planes = vb->num_planes;
+ spare = frame->planes - 1;
+
+ for (i = 0; i < frame->planes; i++) {
+ frame->dvaddr_buffer[i] = video->buf_dva[index][i];
+ frame->kvaddr_buffer[i] = video->buf_kva[index][i];
+#ifdef PRINT_BUFADDR
+ printk(KERN_INFO "0x%04X buf[%d][%d] : 0x%08X\n", framemgr->id,
+ index, i, frame->dvaddr_buffer[i]);
+#endif
+ }
+
+ if (framemgr->id & (FRAMEMGR_ID_SENSOR | FRAMEMGR_ID_ISP)) {
+ ext_size = sizeof(struct camera2_shot_ext) -
+ sizeof(struct camera2_shot);
+
+ frame->dvaddr_shot = video->buf_dva[index][spare] + ext_size;
+ frame->kvaddr_shot = video->buf_kva[index][spare] + ext_size;
+ frame->cookie_shot = (u32)vb2_plane_cookie(vb, spare);
+ frame->shot = (struct camera2_shot *)frame->kvaddr_shot;
+ frame->shot_ext = (struct camera2_shot_ext *)
+ (video->buf_kva[index][spare]);
+ frame->shot_size = video->frame.size[spare];
+#ifdef MEASURE_TIME
+ frame->tzone = (struct timeval *)frame->shot_ext->timeZone;
+#endif
+ } else {
+#ifdef USE_FRAME_SYNC
+ frame->stream = (struct camera2_stream *)
+ video->buf_kva[index][spare];
+ frame->stream->address = video->buf_kva[index][spare];
+ frame->stream_size = video->frame.size[spare];
+#else
+ frame->stream = NULL;
+ frame->stream_size = 0;
+#endif
+ }
+
+ frame->init = FRAME_INI_MEM;
+
+ video->buf_ref_cnt++;
+
+ if (video->buffers_ready == video->buf_ref_cnt)
+ set_bit(FIMC_IS_VIDEO_BUFFER_READY, &video->state);
+
+ if (video->buffers == video->buf_ref_cnt)
+ set_bit(FIMC_IS_VIDEO_BUFFER_PREPARED, &video->state);
+
+exit:
+ return ret;
+}
+
+int buffer_done(struct fimc_is_video_common *video, u32 index)
+{
+ int ret = 0;
+
+ if (!video) {
+ err("video is NULL");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (index == FIMC_IS_INVALID_BUF_INDEX) {
+ err("buffer done had invalid index(%d)", index);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (!test_bit(FIMC_IS_VIDEO_STREAM_ON, &video->state)) {
+ warn("video state is not stream on");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ vb2_buffer_done(video->vbq.bufs[index], VB2_BUF_STATE_DONE);
+
+exit:
+ return ret;
+}
diff --git a/drivers/media/video/exynos/fimc-is-mc2/fimc-is-video.h b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-video.h
new file mode 100644
index 0000000..5d22b27
--- /dev/null
+++ b/drivers/media/video/exynos/fimc-is-mc2/fimc-is-video.h
@@ -0,0 +1,89 @@
+#ifndef FIMC_IS_VIDEO_H
+#define FIMC_IS_VIDEO_H
+
+#define FIMC_IS_MAX_BUF_NUM (16)
+#define FIMC_IS_MAX_PLANES (4)
+#define FIMC_IS_INVALID_BUF_INDEX (0xFF)
+
+enum fimc_is_video_state {
+ FIMC_IS_VIDEO_BUFFER_PREPARED,
+ FIMC_IS_VIDEO_BUFFER_READY,
+ FIMC_IS_VIDEO_STREAM_ON
+};
+
+struct fimc_is_fmt {
+ enum v4l2_mbus_pixelcode mbus_code;
+ char *name;
+ u32 pixelformat;
+ u16 num_planes;
+};
+
+struct fimc_is_frame {
+ struct fimc_is_fmt format;
+ u16 width;
+ u16 height;
+ u16 width_stride[FIMC_IS_MAX_PLANES];
+ u32 size[FIMC_IS_MAX_PLANES];
+};
+
+struct fimc_is_video_common {
+ struct video_device vd;
+ struct media_pad pads;
+ struct vb2_queue vbq;
+ const struct fimc_is_vb2 *vb2;
+ struct mutex lock;
+ struct fimc_is_frame frame;
+ u32 buffers;
+ u32 buffers_ready;
+ u32 buf_ref_cnt;
+ u32 buf_mask;
+
+ unsigned long state;
+
+ void *core;
+ void *device;
+
+ u32 buf_dva[FIMC_IS_MAX_BUF_NUM][FIMC_IS_MAX_PLANES];
+ u32 buf_kva[FIMC_IS_MAX_BUF_NUM][FIMC_IS_MAX_PLANES];
+};
+
+struct fimc_is_fmt *fimc_is_find_format(u32 *pixelformat,
+ u32 *mbus_code, int index);
+void fimc_is_set_plane_size(struct fimc_is_frame *frame,
+ unsigned int sizes[]);
+
+int fimc_is_video_probe(struct fimc_is_video_common *video,
+ void *core_data,
+ void *video_data,
+ char *video_name,
+ u32 video_number,
+ u32 vbq_type,
+ const struct v4l2_file_operations *fops,
+ const struct v4l2_ioctl_ops *ioctl_ops,
+ const struct vb2_ops *vb2_ops);
+int fimc_is_video_open(struct fimc_is_video_common *video,
+ void *device, u32 buffers_ready);
+int fimc_is_video_close(struct fimc_is_video_common *video,
+ struct fimc_is_framemgr *framemgr);
+int fimc_is_video_reqbufs(struct fimc_is_video_common *video,
+ struct fimc_is_framemgr *framemgr,
+ struct v4l2_requestbuffers *request);
+int fimc_is_video_set_format_mplane(struct fimc_is_video_common *video,
+ struct v4l2_format *format);
+int fimc_is_video_qbuf(struct fimc_is_video_common *video,
+ struct v4l2_buffer *buf);
+int fimc_is_video_dqbuf(struct fimc_is_video_common *video,
+ struct v4l2_buffer *buf, bool blocking);
+int fimc_is_video_streamon(struct fimc_is_video_common *video,
+ enum v4l2_buf_type type);
+int fimc_is_video_streamoff(struct fimc_is_video_common *video,
+ enum v4l2_buf_type type);
+int fimc_is_video_queue_setup(struct fimc_is_video_common *video,
+ unsigned int *num_planes,
+ unsigned int sizes[],
+ void *allocators[]);
+int fimc_is_video_buffer_queue(struct fimc_is_video_common *video,
+ struct vb2_buffer *vb, struct fimc_is_framemgr *framemgr);
+
+int buffer_done(struct fimc_is_video_common *video, u32 index);
+#endif
diff --git a/drivers/media/video/exynos/fimc-lite/Kconfig b/drivers/media/video/exynos/fimc-lite/Kconfig
new file mode 100644
index 0000000..703e035
--- /dev/null
+++ b/drivers/media/video/exynos/fimc-lite/Kconfig
@@ -0,0 +1,18 @@
+config VIDEO_EXYNOS_FIMC_LITE
+ bool "Exynos Camera Interface(FIMC-Lite) driver"
+ depends on VIDEO_EXYNOS && (ARCH_EXYNOS4 || ARCH_EXYNOS5)
+ select MEDIA_EXYNOS
+ default n
+ help
+ This is a v4l2 driver for exynos camera interface device.
+
+if VIDEO_EXYNOS_FIMC_LITE && VIDEOBUF2_CMA_PHYS
+comment "Reserved memory configurations"
+config VIDEO_SAMSUNG_MEMSIZE_FLITE0
+ int "Memory size in kbytes for FLITE0"
+ default "10240"
+
+config VIDEO_SAMSUNG_MEMSIZE_FLITE1
+ int "Memory size in kbytes for FLITE1"
+ default "10240"
+endif
diff --git a/drivers/media/video/exynos/fimc-lite/Makefile b/drivers/media/video/exynos/fimc-lite/Makefile
new file mode 100644
index 0000000..256d8d9
--- /dev/null
+++ b/drivers/media/video/exynos/fimc-lite/Makefile
@@ -0,0 +1,6 @@
+ifeq ($(CONFIG_ARCH_EXYNOS5),y)
+fimc-lite-objs := fimc-lite-core.o fimc-lite-reg.o fimc-lite-vb2.o
+else
+fimc-lite-objs := fimc-lite-core.o fimc-lite-reg.o
+endif
+obj-$(CONFIG_VIDEO_EXYNOS_FIMC_LITE) += fimc-lite.o
diff --git a/drivers/media/video/exynos/fimc-lite/fimc-lite-core.c b/drivers/media/video/exynos/fimc-lite/fimc-lite-core.c
new file mode 100644
index 0000000..0ad1a87
--- /dev/null
+++ b/drivers/media/video/exynos/fimc-lite/fimc-lite-core.c
@@ -0,0 +1,2180 @@
+/*
+ * Register interface file for Samsung Camera Interface (FIMC-Lite) driver
+ *
+ * Copyright (c) 2011 Samsung Electronics
+ *
+ * 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.
+*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#if defined(CONFIG_MEDIA_CONTROLLER) && defined(CONFIG_ARCH_EXYNOS5)
+#include <mach/videonode.h>
+#include <media/exynos_mc.h>
+#endif
+#include "fimc-lite-core.h"
+
+#define MODULE_NAME "exynos-fimc-lite"
+#define DEFAULT_FLITE_SINK_WIDTH 800
+#define DEFAULT_FLITE_SINK_HEIGHT 480
+#define CAMIF_TOP_CLK "camif_top"
+
+static struct flite_fmt flite_formats[] = {
+ {
+ .name = "YUV422 8-bit 1 plane(UYVY)",
+ .pixelformat = V4L2_PIX_FMT_UYVY,
+ .depth = { 16 },
+ .code = V4L2_MBUS_FMT_UYVY8_2X8,
+ .fmt_reg = FLITE_REG_CIGCTRL_YUV422_1P,
+ .is_yuv = 1,
+ }, {
+ .name = "YUV422 8-bit 1 plane(VYUY)",
+ .pixelformat = V4L2_PIX_FMT_VYUY,
+ .depth = { 16 },
+ .code = V4L2_MBUS_FMT_VYUY8_2X8,
+ .fmt_reg = FLITE_REG_CIGCTRL_YUV422_1P,
+ .is_yuv = 1,
+ }, {
+ .name = "YUV422 8-bit 1 plane(YUYV)",
+ .pixelformat = V4L2_PIX_FMT_YUYV,
+ .depth = { 16 },
+ .code = V4L2_MBUS_FMT_YUYV8_2X8,
+ .fmt_reg = FLITE_REG_CIGCTRL_YUV422_1P,
+ .is_yuv = 1,
+ }, {
+ .name = "YUV422 8-bit 1 plane(YVYU)",
+ .pixelformat = V4L2_PIX_FMT_YVYU,
+ .depth = { 16 },
+ .code = V4L2_MBUS_FMT_YVYU8_2X8,
+ .fmt_reg = FLITE_REG_CIGCTRL_YUV422_1P,
+ .is_yuv = 1,
+ }, {
+ .name = "RAW8(GRBG)",
+ .pixelformat = V4L2_PIX_FMT_SGRBG8,
+ .depth = { 8 },
+ .code = V4L2_MBUS_FMT_SGRBG8_1X8,
+ .fmt_reg = FLITE_REG_CIGCTRL_RAW8,
+ .is_yuv = 0,
+ }, {
+ .name = "RAW10(GRBG)",
+ .pixelformat = V4L2_PIX_FMT_SGRBG10,
+ .depth = { 10 },
+ .code = V4L2_MBUS_FMT_SGRBG10_1X10,
+ .fmt_reg = FLITE_REG_CIGCTRL_RAW10,
+ .is_yuv = 0,
+ }, {
+ .name = "RAW12(GRBG)",
+ .pixelformat = V4L2_PIX_FMT_SGRBG12,
+ .depth = { 12 },
+ .code = V4L2_MBUS_FMT_SGRBG12_1X12,
+ .fmt_reg = FLITE_REG_CIGCTRL_RAW12,
+ .is_yuv = 0,
+ }, {
+ .name = "User Defined(JPEG)",
+ .code = V4L2_MBUS_FMT_JPEG_1X8,
+ .depth = { 8 },
+ .fmt_reg = FLITE_REG_CIGCTRL_USER(1),
+ .is_yuv = 0,
+ },
+};
+
+#if defined(CONFIG_MEDIA_CONTROLLER) && defined(CONFIG_ARCH_EXYNOS5)
+static struct flite_variant variant = {
+ .max_w = 8192,
+ .max_h = 8192,
+ .align_win_offs_w = 2,
+ .align_out_w = 8,
+ .align_out_offs_w = 8,
+};
+
+static struct flite_fmt *get_format(int index)
+{
+ return &flite_formats[index];
+}
+
+static struct flite_fmt *find_format(u32 *pixelformat, u32 *mbus_code, int index)
+{
+ struct flite_fmt *fmt, *def_fmt = NULL;
+ unsigned int i;
+
+ if (index >= ARRAY_SIZE(flite_formats))
+ return NULL;
+
+ for (i = 0; i < ARRAY_SIZE(flite_formats); ++i) {
+ fmt = get_format(i);
+ if (pixelformat && fmt->pixelformat == *pixelformat)
+ return fmt;
+ if (mbus_code && fmt->code == *mbus_code)
+ return fmt;
+ if (index == i)
+ def_fmt = fmt;
+ }
+ return def_fmt;
+
+}
+#endif
+
+inline struct flite_fmt const *find_flite_format(struct v4l2_mbus_framefmt *mf)
+{
+ int num_fmt = ARRAY_SIZE(flite_formats);
+
+ while (num_fmt--)
+ if (mf->code == flite_formats[num_fmt].code)
+ break;
+ if (num_fmt < 0)
+ return NULL;
+
+ return &flite_formats[num_fmt];
+}
+
+static int flite_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)
+{
+ struct flite_dev *flite = v4l2_get_subdevdata(sd);
+ struct flite_fmt const *f_fmt = find_flite_format(mf);
+ struct flite_frame *f_frame = &flite->s_frame;
+
+ flite_dbg("w: %d, h: %d", mf->width, mf->height);
+
+ if (unlikely(!f_fmt)) {
+ flite_err("f_fmt is null");
+ return -EINVAL;
+ }
+
+ flite->mbus_fmt = *mf;
+
+ /*
+ * These are the datas from fimc
+ * If you want to crop the image, you can use s_crop
+ */
+ f_frame->o_width = mf->width;
+ f_frame->o_height = mf->height;
+ f_frame->width = mf->width;
+ f_frame->height = mf->height;
+ f_frame->offs_h = 0;
+ f_frame->offs_v = 0;
+
+ return 0;
+}
+
+static int flite_g_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)
+{
+ struct flite_dev *flite = v4l2_get_subdevdata(sd);
+
+ mf = &flite->mbus_fmt;
+
+ return 0;
+}
+
+static int flite_subdev_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *cc)
+{
+ struct flite_dev *flite = v4l2_get_subdevdata(sd);
+ struct flite_frame *f;
+
+ f = &flite->s_frame;
+
+ cc->bounds.left = 0;
+ cc->bounds.top = 0;
+ cc->bounds.width = f->o_width;
+ cc->bounds.height = f->o_height;
+ cc->defrect = cc->bounds;
+
+ return 0;
+}
+
+static int flite_subdev_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *crop)
+{
+ struct flite_dev *flite = v4l2_get_subdevdata(sd);
+ struct flite_frame *f;
+
+ f = &flite->s_frame;
+
+ crop->c.left = f->offs_h;
+ crop->c.top = f->offs_v;
+ crop->c.width = f->width;
+ crop->c.height = f->height;
+
+ return 0;
+}
+
+static int flite_subdev_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *crop)
+{
+ struct flite_dev *flite = v4l2_get_subdevdata(sd);
+ struct flite_frame *f;
+
+ f = &flite->s_frame;
+
+ if (crop->c.left + crop->c.width > f->o_width) {
+ flite_err("Unsupported crop width");
+ return -EINVAL;
+ }
+ if (crop->c.top + crop->c.height > f->o_height) {
+ flite_err("Unsupported crop height");
+ return -EINVAL;
+ }
+
+ f->width = crop->c.width;
+ f->height = crop->c.height;
+ f->offs_h = crop->c.left;
+ f->offs_v = crop->c.top;
+
+ flite_dbg("width : %d, height : %d, offs_h : %d, off_v : %dn",
+ f->width, f->height, f->offs_h, f->offs_v);
+
+ return 0;
+}
+
+static int flite_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct flite_dev *flite = v4l2_get_subdevdata(sd);
+ u32 index = flite->pdata->active_cam_index;
+ struct s3c_platform_camera *cam = NULL;
+ u32 int_src = 0;
+ unsigned long flags;
+ int ret = 0;
+
+ if (!(flite->output & FLITE_OUTPUT_MEM)) {
+ if (enable)
+ flite_hw_reset(flite);
+ cam = flite->pdata->cam[index];
+ }
+
+ spin_lock_irqsave(&flite->slock, flags);
+
+ if (test_bit(FLITE_ST_SUSPEND, &flite->state))
+ goto s_stream_unlock;
+
+ if (enable) {
+ flite_hw_set_cam_channel(flite);
+ flite_hw_set_cam_source_size(flite);
+
+ if (!(flite->output & FLITE_OUTPUT_MEM)) {
+ flite_info("@local out start@");
+ flite_hw_set_camera_type(flite, cam);
+ flite_hw_set_config_irq(flite, cam);
+ if (IS_ERR_OR_NULL(cam)) {
+ flite_err("cam is null");
+ goto s_stream_unlock;
+ }
+ if (cam->use_isp)
+ flite_hw_set_output_dma(flite, false);
+ int_src = FLITE_REG_CIGCTRL_IRQ_OVFEN0_ENABLE |
+ FLITE_REG_CIGCTRL_IRQ_LASTEN0_ENABLE |
+ FLITE_REG_CIGCTRL_IRQ_ENDEN0_DISABLE |
+ FLITE_REG_CIGCTRL_IRQ_STARTEN0_DISABLE;
+ } else {
+ flite_info("@mem out start@");
+ flite_hw_set_sensor_type(flite);
+ flite_hw_set_inverse_polarity(flite);
+ set_bit(FLITE_ST_PEND, &flite->state);
+ flite_hw_set_output_dma(flite, true);
+ int_src = FLITE_REG_CIGCTRL_IRQ_OVFEN0_ENABLE |
+ FLITE_REG_CIGCTRL_IRQ_LASTEN0_ENABLE |
+ FLITE_REG_CIGCTRL_IRQ_ENDEN0_ENABLE |
+ FLITE_REG_CIGCTRL_IRQ_STARTEN0_DISABLE;
+ flite_hw_set_out_order(flite);
+ flite_hw_set_output_size(flite);
+ flite_hw_set_dma_offset(flite);
+ }
+ ret = flite_hw_set_source_format(flite);
+ if (unlikely(ret < 0))
+ goto s_stream_unlock;
+
+ flite_hw_set_interrupt_source(flite, int_src);
+ flite_hw_set_window_offset(flite);
+ flite_hw_set_capture_start(flite);
+
+ set_bit(FLITE_ST_STREAM, &flite->state);
+ } else {
+ if (test_bit(FLITE_ST_STREAM, &flite->state)) {
+ flite_hw_set_capture_stop(flite);
+ spin_unlock_irqrestore(&flite->slock, flags);
+ ret = wait_event_timeout(flite->irq_queue,
+ !test_bit(FLITE_ST_STREAM, &flite->state), HZ/20); /* 50 ms */
+ if (unlikely(!ret)) {
+ v4l2_err(sd, "wait timeout\n");
+ ret = -EBUSY;
+ }
+ return ret;
+ } else {
+ goto s_stream_unlock;
+ }
+ }
+s_stream_unlock:
+ spin_unlock_irqrestore(&flite->slock, flags);
+ return ret;
+}
+
+static irqreturn_t flite_irq_handler(int irq, void *priv)
+{
+ struct flite_dev *flite = priv;
+#if defined(CONFIG_MEDIA_CONTROLLER) && defined(CONFIG_ARCH_EXYNOS5)
+ struct flite_buffer *buf;
+#endif
+ u32 int_src = 0;
+
+ flite_hw_get_int_src(flite, &int_src);
+ flite_hw_clear_irq(flite);
+
+ spin_lock(&flite->slock);
+
+ switch (int_src & FLITE_REG_CISTATUS_IRQ_MASK) {
+ case FLITE_REG_CISTATUS_IRQ_SRC_OVERFLOW:
+ clear_bit(FLITE_ST_RUN, &flite->state);
+ flite_err("overflow generated");
+ break;
+ case FLITE_REG_CISTATUS_IRQ_SRC_LASTCAPEND:
+ flite_hw_set_last_capture_end_clear(flite);
+ flite_info("last capture end");
+ clear_bit(FLITE_ST_STREAM, &flite->state);
+ wake_up(&flite->irq_queue);
+ break;
+ case FLITE_REG_CISTATUS_IRQ_SRC_FRMSTART:
+ flite_dbg("frame start");
+ break;
+ case FLITE_REG_CISTATUS_IRQ_SRC_FRMEND:
+ set_bit(FLITE_ST_RUN, &flite->state);
+ flite_dbg("frame end");
+ break;
+ }
+#if defined(CONFIG_MEDIA_CONTROLLER) && defined(CONFIG_ARCH_EXYNOS5)
+ if (flite->output & FLITE_OUTPUT_MEM) {
+ if (!list_empty(&flite->active_buf_q)) {
+ buf = active_queue_pop(flite);
+ if (!test_bit(FLITE_ST_RUN, &flite->state)) {
+ flite_info("error interrupt");
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+ goto unlock;
+ }
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
+ flite_dbg("done_index : %d", buf->vb.v4l2_buf.index);
+ }
+ if (!list_empty(&flite->pending_buf_q)) {
+ buf = pending_queue_pop(flite);
+ flite_hw_set_output_addr(flite, &buf->paddr,
+ buf->vb.v4l2_buf.index);
+ active_queue_add(flite, buf);
+ }
+ if (flite->active_buf_cnt == 0) {
+ clear_bit(FLITE_ST_RUN, &flite->state);
+ }
+ }
+unlock:
+#endif
+ spin_unlock(&flite->slock);
+
+ return IRQ_HANDLED;
+}
+
+static int flite_runtime_resume(struct device *dev);
+static int flite_runtime_suspend(struct device *dev);
+static int flite_s_power(struct v4l2_subdev *sd, int on)
+{
+ struct flite_dev *flite = v4l2_get_subdevdata(sd);
+ int ret = 0;
+
+ if (on) {
+#ifdef CONFIG_PM_RUNTIME
+ pm_runtime_get_sync(&flite->pdev->dev);
+#else
+ flite_runtime_resume(&flite->pdev->dev);
+#endif
+ set_bit(FLITE_ST_POWER, &flite->state);
+ } else {
+#ifdef CONFIG_PM_RUNTIME
+ pm_runtime_put_sync(&flite->pdev->dev);
+#else
+ flite_runtime_suspend(&flite->pdev->dev);
+#endif
+ clear_bit(FLITE_ST_POWER, &flite->state);
+ }
+
+ return ret;
+}
+
+#if defined(CONFIG_MEDIA_CONTROLLER) && defined(CONFIG_ARCH_EXYNOS5)
+static int flite_subdev_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ if (code->index >= ARRAY_SIZE(flite_formats))
+ return -EINVAL;
+
+ code->code = flite_formats[code->index].code;
+
+ return 0;
+}
+
+static struct v4l2_mbus_framefmt *__flite_get_format(
+ struct flite_dev *flite, struct v4l2_subdev_fh *fh,
+ u32 pad, enum v4l2_subdev_format_whence which)
+{
+ if (which == V4L2_SUBDEV_FORMAT_TRY)
+ return fh ? v4l2_subdev_get_try_format(fh, pad) : NULL;
+ else
+ return &flite->mbus_fmt;
+}
+
+static void flite_try_format(struct flite_dev *flite, struct v4l2_subdev_fh *fh,
+ struct v4l2_mbus_framefmt *fmt,
+ enum v4l2_subdev_format_whence which)
+{
+ struct flite_fmt const *ffmt;
+ struct flite_frame *f = &flite->s_frame;
+ ffmt = find_flite_format(fmt);
+ if (ffmt == NULL)
+ ffmt = &flite_formats[1];
+
+ fmt->code = ffmt->code;
+ fmt->width = clamp_t(u32, fmt->width, 1, variant.max_w);
+ fmt->height = clamp_t(u32, fmt->height, 1, variant.max_h);
+
+ f->offs_h = f->offs_v = 0;
+ f->width = f->o_width = fmt->width;
+ f->height = f->o_height = fmt->height;
+
+ fmt->colorspace = V4L2_COLORSPACE_JPEG;
+ fmt->field = V4L2_FIELD_NONE;
+}
+
+static int flite_subdev_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ struct flite_dev *flite = v4l2_get_subdevdata(sd);
+ struct v4l2_mbus_framefmt *mf;
+
+ mf = __flite_get_format(flite, fh, fmt->pad, fmt->which);
+ if (mf == NULL) {
+ flite_err("__flite_get_format is null");
+ return -EINVAL;
+ }
+
+ fmt->format = *mf;
+
+ if (fmt->pad != FLITE_PAD_SINK) {
+ struct flite_frame *f = &flite->s_frame;
+ fmt->format.width = f->width;
+ fmt->format.height = f->height;
+ }
+
+ return 0;
+}
+
+static int flite_subdev_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ struct flite_dev *flite = v4l2_get_subdevdata(sd);
+ struct v4l2_mbus_framefmt *mf;
+
+ if (fmt->pad != FLITE_PAD_SINK)
+ return -EPERM;
+
+ mf = __flite_get_format(flite, fh, fmt->pad, fmt->which);
+ if (mf == NULL) {
+ flite_err("__flite_get_format is null");
+ return -EINVAL;
+ }
+
+ flite_try_format(flite, fh, &fmt->format, fmt->which);
+ *mf = fmt->format;
+
+ return 0;
+}
+
+static void flite_try_crop(struct flite_dev *flite, struct v4l2_subdev_crop *crop)
+{
+ struct flite_frame *f_frame = flite_get_frame(flite, crop->pad);
+
+ u32 max_left = f_frame->o_width - crop->rect.width;
+ u32 max_top = f_frame->o_height - crop->rect.height;
+ u32 crop_max_w = f_frame->o_width - crop->rect.left;
+ u32 crop_max_h = f_frame->o_height - crop->rect.top;
+
+ crop->rect.left = clamp_t(u32, crop->rect.left, 0, max_left);
+ crop->rect.top = clamp_t(u32, crop->rect.top, 0, max_top);
+ crop->rect.width = clamp_t(u32, crop->rect.width, 2, crop_max_w);
+ crop->rect.height = clamp_t(u32, crop->rect.height, 1, crop_max_h);
+}
+
+static int __flite_get_crop(struct flite_dev *flite, struct v4l2_subdev_fh *fh,
+ unsigned int pad, enum v4l2_subdev_format_whence which,
+ struct v4l2_rect *crop)
+{
+ struct flite_frame *frame = &flite->s_frame;
+
+ if (which == V4L2_SUBDEV_FORMAT_TRY) {
+ crop = v4l2_subdev_get_try_crop(fh, pad);
+ } else {
+ crop->left = frame->offs_h;
+ crop->top = frame->offs_v;
+ crop->width = frame->width;
+ crop->height = frame->height;
+ }
+
+ return 0;
+}
+
+static int flite_subdev_get_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_crop *crop)
+{
+ struct flite_dev *flite = v4l2_get_subdevdata(sd);
+ struct v4l2_rect fcrop;
+
+ fcrop.left = fcrop.top = fcrop.width = fcrop.height = 0;
+
+ if (crop->pad != FLITE_PAD_SINK) {
+ flite_err("crop is supported only sink pad");
+ return -EINVAL;
+ }
+
+ __flite_get_crop(flite, fh, crop->pad, crop->which, &fcrop);
+ crop->rect = fcrop;
+
+ return 0;
+}
+
+static int flite_subdev_set_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_crop *crop)
+{
+ struct flite_dev *flite = v4l2_get_subdevdata(sd);
+ struct flite_frame *f_frame = flite_get_frame(flite, crop->pad);
+
+ if (!(flite->output & FLITE_OUTPUT_MEM) && (crop->pad != FLITE_PAD_SINK)) {
+ flite_err("crop is supported only sink pad");
+ return -EINVAL;
+ }
+
+ flite_try_crop(flite, crop);
+
+ if (crop->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+ f_frame->offs_h = crop->rect.left;
+ f_frame->offs_v = crop->rect.top;
+ f_frame->width = crop->rect.width;
+ f_frame->height = crop->rect.height;
+ }
+
+ return 0;
+}
+
+static int flite_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+ struct v4l2_subdev_format format;
+ struct flite_dev *flite = v4l2_get_subdevdata(sd);
+
+ if (!test_bit(FLITE_ST_SUBDEV_OPEN, &flite->state)) {
+ flite->s_frame.fmt = get_format(2);
+ memset(&format, 0, sizeof(format));
+ format.pad = FLITE_PAD_SINK;
+ format.which = fh ?
+ V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
+ format.format.code = flite->s_frame.fmt->code;
+ format.format.width = DEFAULT_FLITE_SINK_WIDTH;
+ format.format.height = DEFAULT_FLITE_SINK_HEIGHT;
+
+ flite_subdev_set_fmt(sd, fh, &format);
+
+ flite->d_frame.fmt = get_format(2);
+ set_bit(FLITE_ST_SUBDEV_OPEN, &flite->state);
+ }
+
+ return 0;
+}
+
+static int flite_subdev_close(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh)
+{
+ struct flite_dev *flite = v4l2_get_subdevdata(sd);
+
+ flite_info("");
+ clear_bit(FLITE_ST_SUBDEV_OPEN, &flite->state);
+ return 0;
+}
+
+static int flite_subdev_registered(struct v4l2_subdev *sd)
+{
+ flite_dbg("");
+ return 0;
+}
+
+static void flite_subdev_unregistered(struct v4l2_subdev *sd)
+{
+ flite_dbg("");
+}
+
+static const struct v4l2_subdev_internal_ops flite_v4l2_internal_ops = {
+ .open = flite_init_formats,
+ .close = flite_subdev_close,
+ .registered = flite_subdev_registered,
+ .unregistered = flite_subdev_unregistered,
+};
+
+static int flite_link_setup(struct media_entity *entity,
+ const struct media_pad *local,
+ const struct media_pad *remote, u32 flags)
+{
+ struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
+ struct flite_dev *flite = v4l2_get_subdevdata(sd);
+
+ switch (local->index | media_entity_type(remote->entity)) {
+ case FLITE_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
+ if (flags & MEDIA_LNK_FL_ENABLED) {
+ flite_info("sink link enabled");
+ if (flite->input != FLITE_INPUT_NONE) {
+ flite_err("link is busy");
+ return -EBUSY;
+ }
+ if (remote->index == CSIS_PAD_SOURCE)
+ flite->input = FLITE_INPUT_CSIS;
+ else
+ flite->input = FLITE_INPUT_SENSOR;
+ } else {
+ flite_info("sink link disabled");
+ flite->input = FLITE_INPUT_NONE;
+ }
+ break;
+
+ case FLITE_PAD_SOURCE_PREV | MEDIA_ENT_T_V4L2_SUBDEV: /* fall through */
+ case FLITE_PAD_SOURCE_CAMCORD | MEDIA_ENT_T_V4L2_SUBDEV:
+ if (flags & MEDIA_LNK_FL_ENABLED) {
+ flite_info("source link enabled");
+ flite->output |= FLITE_OUTPUT_GSC;
+ } else {
+ flite_info("source link disabled");
+ flite->output &= ~FLITE_OUTPUT_GSC;
+ }
+ break;
+ case FLITE_PAD_SOURCE_MEM | MEDIA_ENT_T_DEVNODE:
+ if (flags & MEDIA_LNK_FL_ENABLED) {
+ flite_info("source link enabled");
+ flite->output |= FLITE_OUTPUT_MEM;
+ } else {
+ flite_info("source link disabled");
+ flite->output &= ~FLITE_OUTPUT_MEM;
+ }
+ break;
+ default:
+ flite_err("ERR link");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct media_entity_operations flite_media_ops = {
+ .link_setup = flite_link_setup,
+};
+
+static struct v4l2_subdev_pad_ops flite_pad_ops = {
+ .enum_mbus_code = flite_subdev_enum_mbus_code,
+ .get_fmt = flite_subdev_get_fmt,
+ .set_fmt = flite_subdev_set_fmt,
+ .get_crop = flite_subdev_get_crop,
+ .set_crop = flite_subdev_set_crop,
+};
+
+static void flite_pipeline_prepare(struct flite_dev *flite, struct media_entity *me)
+{
+ struct media_entity_graph graph;
+ struct v4l2_subdev *sd;
+
+ media_entity_graph_walk_start(&graph, me);
+
+ while ((me = media_entity_graph_walk_next(&graph))) {
+ flite_info("me->name : %s", me->name);
+ if (media_entity_type(me) != MEDIA_ENT_T_V4L2_SUBDEV)
+ continue;
+ sd = media_entity_to_v4l2_subdev(me);
+ switch (sd->grp_id) {
+ case FLITE_GRP_ID:
+ flite->pipeline.flite = sd;
+ break;
+ case SENSOR_GRP_ID:
+ flite->pipeline.sensor = sd;
+ break;
+ case CSIS_GRP_ID:
+ flite->pipeline.csis = sd;
+ break;
+ default:
+ flite_warn("Another link's group id");
+ break;
+ }
+ }
+
+ flite_info("flite->pipeline.flite : 0x%p", flite->pipeline.flite);
+ flite_info("flite->pipeline.sensor : 0x%p", flite->pipeline.sensor);
+ flite_info("flite->pipeline.csis : 0x%p", flite->pipeline.csis);
+}
+
+static void flite_set_cam_clock(struct flite_dev *flite, bool on)
+{
+ struct v4l2_subdev *sd = flite->pipeline.sensor;
+
+ clk_enable(flite->gsc_clk);
+ if (flite->pipeline.sensor) {
+ struct flite_sensor_info *s_info = v4l2_get_subdev_hostdata(sd);
+ on ? clk_enable(s_info->camclk) : clk_disable(s_info->camclk);
+ }
+}
+
+static int __subdev_set_power(struct v4l2_subdev *sd, int on)
+{
+ int *use_count;
+ int ret;
+
+ if (sd == NULL)
+ return -ENXIO;
+
+ use_count = &sd->entity.use_count;
+ if (on && (*use_count)++ > 0)
+ return 0;
+ else if (!on && (*use_count == 0 || --(*use_count) > 0))
+ return 0;
+ ret = v4l2_subdev_call(sd, core, s_power, on);
+
+ return ret != -ENOIOCTLCMD ? ret : 0;
+}
+
+static int flite_pipeline_s_power(struct flite_dev *flite, int state)
+{
+ int ret = 0;
+
+ if (!flite->pipeline.sensor)
+ return -ENXIO;
+
+ if (state) {
+ ret = __subdev_set_power(flite->pipeline.flite, 1);
+ if (ret && ret != -ENXIO)
+ return ret;
+ ret = __subdev_set_power(flite->pipeline.csis, 1);
+ if (ret && ret != -ENXIO)
+ return ret;
+ ret = __subdev_set_power(flite->pipeline.sensor, 1);
+ } else {
+ ret = __subdev_set_power(flite->pipeline.flite, 0);
+ if (ret && ret != -ENXIO)
+ return ret;
+ ret = __subdev_set_power(flite->pipeline.sensor, 0);
+ if (ret && ret != -ENXIO)
+ return ret;
+ ret = __subdev_set_power(flite->pipeline.csis, 0);
+ }
+ return ret == -ENXIO ? 0 : ret;
+}
+
+static int __flite_pipeline_initialize(struct flite_dev *flite,
+ struct media_entity *me, bool prep)
+{
+ int ret = 0;
+
+ if (prep)
+ flite_pipeline_prepare(flite, me);
+
+ if (!flite->pipeline.sensor)
+ return -EINVAL;
+
+ flite_set_cam_clock(flite, true);
+
+ if (flite->pipeline.sensor)
+ ret = flite_pipeline_s_power(flite, 1);
+
+ return ret;
+}
+
+static int flite_pipeline_initialize(struct flite_dev *flite,
+ struct media_entity *me, bool prep)
+{
+ int ret;
+
+ mutex_lock(&me->parent->graph_mutex);
+ ret = __flite_pipeline_initialize(flite, me, prep);
+ mutex_unlock(&me->parent->graph_mutex);
+
+ return ret;
+}
+
+static int flite_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct flite_dev *flite = ctrl_to_dev(ctrl);
+
+ switch (ctrl->id) {
+ case V4L2_CID_CACHEABLE:
+ user_to_drv(flite->flite_ctrls.cacheable, ctrl->val);
+ break;
+ default:
+ flite_err("unsupported ctrl id");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+const struct v4l2_ctrl_ops flite_ctrl_ops = {
+ .s_ctrl = flite_s_ctrl,
+};
+
+static const struct v4l2_ctrl_config flite_custom_ctrl[] = {
+ {
+ .ops = &flite_ctrl_ops,
+ .id = V4L2_CID_CACHEABLE,
+ .name = "Set cacheable",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .flags = V4L2_CTRL_FLAG_SLIDER,
+ .max = 1,
+ .def = true,
+ },
+};
+
+static int flite_ctrls_create(struct flite_dev *flite)
+{
+ if (flite->ctrls_rdy)
+ return 0;
+
+ v4l2_ctrl_handler_init(&flite->ctrl_handler, FLITE_MAX_CTRL_NUM);
+ flite->flite_ctrls.cacheable = v4l2_ctrl_new_custom(&flite->ctrl_handler,
+ &flite_custom_ctrl[0], NULL);
+ flite->ctrls_rdy = flite->ctrl_handler.error == 0;
+
+ if (flite->ctrl_handler.error) {
+ int err = flite->ctrl_handler.error;
+ v4l2_ctrl_handler_free(&flite->ctrl_handler);
+ flite_err("Failed to flite control hander create");
+ return err;
+ }
+
+ return 0;
+}
+
+static void flite_ctrls_delete(struct flite_dev *flite)
+{
+ if (flite->ctrls_rdy) {
+ v4l2_ctrl_handler_free(&flite->ctrl_handler);
+ flite->ctrls_rdy = false;
+ }
+}
+
+static int flite_open(struct file *file)
+{
+ struct flite_dev *flite = video_drvdata(file);
+ int ret = v4l2_fh_open(file);
+
+ if (ret)
+ return ret;
+
+ if (test_bit(FLITE_ST_OPEN, &flite->state)) {
+ v4l2_fh_release(file);
+ return -EBUSY;
+ }
+
+ set_bit(FLITE_ST_OPEN, &flite->state);
+
+ if (++flite->refcnt == 1) {
+ ret = flite_pipeline_initialize(flite, &flite->vfd->entity, true);
+ if (ret < 0) {
+ flite_err("flite pipeline initialization failed\n");
+ goto err;
+ }
+
+ ret = flite_ctrls_create(flite);
+ if (ret) {
+ flite_err("failed to create controls\n");
+ goto err;
+ }
+
+ }
+
+ flite_info("pid: %d, state: 0x%lx", task_pid_nr(current), flite->state);
+
+ return 0;
+
+err:
+ v4l2_fh_release(file);
+ clear_bit(FLITE_ST_OPEN, &flite->state);
+ return ret;
+}
+
+int __flite_pipeline_shutdown(struct flite_dev *flite)
+{
+ int ret = 0;
+
+ if (flite->pipeline.sensor)
+ ret = flite_pipeline_s_power(flite, 0);
+
+ if (ret && ret != -ENXIO)
+ flite_set_cam_clock(flite, false);
+
+ flite->pipeline.flite = NULL;
+ flite->pipeline.csis = NULL;
+ flite->pipeline.sensor = NULL;
+
+ return ret == -ENXIO ? 0 : ret;
+}
+
+int flite_pipeline_shutdown(struct flite_dev *flite)
+{
+ struct media_entity *me = &flite->vfd->entity;
+ int ret;
+
+ mutex_lock(&me->parent->graph_mutex);
+ ret = __flite_pipeline_shutdown(flite);
+ mutex_unlock(&me->parent->graph_mutex);
+
+ return ret;
+}
+
+static int flite_close(struct file *file)
+{
+ struct flite_dev *flite = video_drvdata(file);
+ struct flite_buffer *buf;
+
+ flite_info("pid: %d, state: 0x%lx", task_pid_nr(current), flite->state);
+
+ if (--flite->refcnt == 0) {
+ clear_bit(FLITE_ST_OPEN, &flite->state);
+ flite_info("FIMC-LITE h/w disable control");
+ flite_hw_set_capture_stop(flite);
+ clear_bit(FLITE_ST_STREAM, &flite->state);
+ flite_pipeline_shutdown(flite);
+ clear_bit(FLITE_ST_SUSPEND, &flite->state);
+ }
+
+ if (flite->refcnt == 0) {
+ while (!list_empty(&flite->pending_buf_q)) {
+ flite_info("clean pending q");
+ buf = pending_queue_pop(flite);
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+ }
+
+ while (!list_empty(&flite->active_buf_q)) {
+ flite_info("clean active q");
+ buf = active_queue_pop(flite);
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+ }
+ vb2_queue_release(&flite->vbq);
+ flite_ctrls_delete(flite);
+ }
+
+ return v4l2_fh_release(file);
+}
+
+static unsigned int flite_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct flite_dev *flite = video_drvdata(file);
+
+ return vb2_poll(&flite->vbq, file, wait);
+}
+
+static int flite_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct flite_dev *flite = video_drvdata(file);
+
+ return vb2_mmap(&flite->vbq, vma);
+}
+
+/*
+ * videobuf2 operations
+ */
+
+int flite_pipeline_s_stream(struct flite_dev *flite, int on)
+{
+ struct flite_pipeline *p = &flite->pipeline;
+ int ret = 0;
+
+ if (!p->sensor)
+ return -ENODEV;
+
+ if (on) {
+ ret = v4l2_subdev_call(p->flite, video, s_stream, 1);
+ if (ret < 0 && ret != -ENOIOCTLCMD)
+ return ret;
+ ret = v4l2_subdev_call(p->csis, video, s_stream, 1);
+ if (ret < 0 && ret != -ENOIOCTLCMD)
+ return ret;
+ ret = v4l2_subdev_call(p->sensor, video, s_stream, 1);
+ } else {
+ ret = v4l2_subdev_call(p->sensor, video, s_stream, 0);
+ if (ret < 0 && ret != -ENOIOCTLCMD)
+ return ret;
+ ret = v4l2_subdev_call(p->csis, video, s_stream, 0);
+ if (ret < 0 && ret != -ENOIOCTLCMD)
+ return ret;
+ ret = v4l2_subdev_call(p->flite, video, s_stream, 0);
+ }
+
+ return ret == -ENOIOCTLCMD ? 0 : ret;
+}
+
+static int flite_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+ struct flite_dev *flite = q->drv_priv;
+
+ flite->active_buf_cnt = 0;
+ flite->pending_buf_cnt = 0;
+
+ flite->mdev->is_flite_on= true;
+
+ if (!test_bit(FLITE_ST_STREAM, &flite->state)) {
+ if (!test_and_set_bit(FLITE_ST_PIPE_STREAM, &flite->state))
+ flite_pipeline_s_stream(flite, 1);
+ }
+
+ return 0;
+}
+
+static int flite_state_cleanup(struct flite_dev *flite)
+{
+ unsigned long flags;
+ bool streaming;
+
+ spin_lock_irqsave(&flite->slock, flags);
+ streaming = flite->state & (1 << FLITE_ST_PIPE_STREAM);
+
+ flite->state &= ~(1 << FLITE_ST_RUN | 1 << FLITE_ST_STREAM |
+ 1 << FLITE_ST_PIPE_STREAM | 1 << FLITE_ST_PEND);
+
+ set_bit(FLITE_ST_SUSPEND, &flite->state);
+ spin_unlock_irqrestore(&flite->slock, flags);
+
+ if (streaming)
+ return flite_pipeline_s_stream(flite, 0);
+ else
+ return 0;
+}
+
+static int flite_stop_capture(struct flite_dev *flite)
+{
+ if (!flite_active(flite)) {
+ flite_warn("already stopped\n");
+ return 0;
+ }
+ flite_info("FIMC-Lite H/W disable control");
+ flite_hw_set_capture_stop(flite);
+ clear_bit(FLITE_ST_STREAM, &flite->state);
+
+ return flite_state_cleanup(flite);
+}
+
+static int flite_stop_streaming(struct vb2_queue *q)
+{
+ struct flite_dev *flite = q->drv_priv;
+
+ if (!flite_active(flite))
+ return -EINVAL;
+
+ flite->mdev->is_flite_on= false;
+
+ return flite_stop_capture(flite);
+}
+
+static u32 get_plane_size(struct flite_frame *frame, unsigned int plane)
+{
+ if (!frame) {
+ flite_err("frame is null");
+ return 0;
+ }
+
+ return frame->payload;
+}
+
+static int flite_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
+ unsigned int *num_buffers, unsigned int *num_planes,
+ unsigned int sizes[], void *allocators[])
+{
+ struct flite_dev *flite = vq->drv_priv;
+ struct flite_fmt *ffmt = flite->d_frame.fmt;
+
+ if (!ffmt)
+ return -EINVAL;
+
+ *num_planes = 1;
+
+ sizes[0] = get_plane_size(&flite->d_frame, 0);
+ allocators[0] = flite->alloc_ctx;
+
+ return 0;
+}
+
+static int flite_buf_prepare(struct vb2_buffer *vb)
+{
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct flite_dev *flite = vq->drv_priv;
+ struct flite_frame *frame = &flite->d_frame;
+ unsigned long size;
+
+ if (frame->fmt == NULL)
+ return -EINVAL;
+
+ size = frame->payload;
+
+ if (vb2_plane_size(vb, 0) < size) {
+ v4l2_err(flite->vfd, "User buffer too small (%ld < %ld)\n",
+ vb2_plane_size(vb, 0), size);
+ return -EINVAL;
+ }
+ vb2_set_plane_payload(vb, 0, size);
+
+ if (frame->cacheable)
+ flite->vb2->cache_flush(vb, 1);
+
+ return 0;
+}
+
+/* The color format (nr_comp, num_planes) must be already configured. */
+int flite_prepare_addr(struct flite_dev *flite, struct vb2_buffer *vb,
+ struct flite_frame *frame, struct flite_addr *addr)
+{
+ if (IS_ERR(vb) || IS_ERR(frame)) {
+ flite_err("Invalid argument");
+ return -EINVAL;
+ }
+
+ addr->y = flite->vb2->plane_addr(vb, 0);
+
+ flite_dbg("ADDR: y= 0x%X", addr->y);
+
+ return 0;
+}
+
+
+static void flite_buf_queue(struct vb2_buffer *vb)
+{
+ struct flite_buffer *buf = container_of(vb, struct flite_buffer, vb);
+ struct flite_dev *flite = vb2_get_drv_priv(vb->vb2_queue);
+ int min_bufs;
+ unsigned long flags;
+
+ spin_lock_irqsave(&flite->slock, flags);
+ flite_prepare_addr(flite, &buf->vb, &flite->d_frame, &buf->paddr);
+
+ min_bufs = flite->reqbufs_cnt > 1 ? 2 : 1;
+
+ if (flite->active_buf_cnt < FLITE_MAX_OUT_BUFS) {
+ active_queue_add(flite, buf);
+ flite_hw_set_output_addr(flite, &buf->paddr, vb->v4l2_buf.index);
+ } else {
+ pending_queue_add(flite, buf);
+ }
+
+ if (vb2_is_streaming(&flite->vbq) &&
+ (flite->pending_buf_cnt >= min_bufs) &&
+ !test_bit(FLITE_ST_STREAM, &flite->state)) {
+ if (!test_and_set_bit(FLITE_ST_PIPE_STREAM, &flite->state)) {
+ spin_unlock_irqrestore(&flite->slock, flags);
+ flite_pipeline_s_stream(flite, 1);
+ return;
+ }
+
+ if (!test_bit(FLITE_ST_STREAM, &flite->state)) {
+ flite_info("G-Scaler h/w enable control");
+ flite_hw_set_capture_start(flite);
+ set_bit(FLITE_ST_STREAM, &flite->state);
+ }
+ }
+ spin_unlock_irqrestore(&flite->slock, flags);
+
+ return;
+}
+
+static struct vb2_ops flite_qops = {
+ .queue_setup = flite_queue_setup,
+ .buf_prepare = flite_buf_prepare,
+ .buf_queue = flite_buf_queue,
+ .wait_prepare = flite_unlock,
+ .wait_finish = flite_lock,
+ .start_streaming = flite_start_streaming,
+ .stop_streaming = flite_stop_streaming,
+};
+
+/*
+ * The video node ioctl operations
+ */
+static int flite_vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct flite_dev *flite = video_drvdata(file);
+
+ strncpy(cap->driver, flite->pdev->name, sizeof(cap->driver) - 1);
+ strncpy(cap->card, flite->pdev->name, sizeof(cap->card) - 1);
+ cap->bus_info[0] = 0;
+ cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE_MPLANE;
+
+ return 0;
+}
+
+static int flite_enum_fmt_mplane(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ struct flite_fmt *fmt;
+
+ fmt = find_format(NULL, NULL, f->index);
+ if (!fmt)
+ return -EINVAL;
+
+ strncpy(f->description, fmt->name, sizeof(f->description) - 1);
+ f->pixelformat = fmt->pixelformat;
+
+ return 0;
+}
+
+static int flite_try_fmt_mplane(struct file *file, void *fh, struct v4l2_format *f)
+{
+ struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+ struct flite_fmt *fmt;
+ u32 max_w, max_h, mod_x, mod_y;
+ u32 min_w, min_h, tmp_w, tmp_h;
+ int i;
+
+ if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ return -EINVAL;
+
+ flite_dbg("user put w: %d, h: %d", pix_mp->width, pix_mp->height);
+
+ fmt = find_format(&pix_mp->pixelformat, NULL, 0);
+ if (!fmt) {
+ flite_err("pixelformat format (0x%X) invalid\n", pix_mp->pixelformat);
+ return -EINVAL;
+ }
+
+ max_w = variant.max_w;
+ max_h = variant.max_h;
+ min_w = min_h = mod_y = 0;
+
+ if (fmt->is_yuv)
+ mod_x = ffs(variant.align_out_w / 2) - 1;
+ else
+ mod_x = ffs(variant.align_out_w) - 1;
+
+ flite_dbg("mod_x: %d, mod_y: %d, max_w: %d, max_h = %d",
+ mod_x, mod_y, max_w, max_h);
+ /* To check if image size is modified to adjust parameter against
+ hardware abilities */
+ tmp_w = pix_mp->width;
+ tmp_h = pix_mp->height;
+
+ v4l_bound_align_image(&pix_mp->width, min_w, max_w, mod_x,
+ &pix_mp->height, min_h, max_h, mod_y, 0);
+ if (tmp_w != pix_mp->width || tmp_h != pix_mp->height)
+ flite_info("Image size has been modified from %dx%d to %dx%d",
+ tmp_w, tmp_h, pix_mp->width, pix_mp->height);
+
+ pix_mp->num_planes = 1;
+
+ for (i = 0; i < pix_mp->num_planes; ++i) {
+ int bpl = (pix_mp->width * fmt->depth[i]) >> 3;
+ pix_mp->plane_fmt[i].bytesperline = bpl;
+ pix_mp->plane_fmt[i].sizeimage = bpl * pix_mp->height;
+
+ flite_dbg("[%d]: bpl: %d, sizeimage: %d",
+ i, bpl, pix_mp->plane_fmt[i].sizeimage);
+ }
+
+ return 0;
+}
+
+void flite_set_frame_size(struct flite_frame *frame, int width, int height)
+{
+ frame->o_width = width;
+ frame->o_height = height;
+ frame->width = width;
+ frame->height = height;
+ frame->offs_h = 0;
+ frame->offs_v = 0;
+}
+
+static int flite_s_fmt_mplane(struct file *file, void *fh, struct v4l2_format *f)
+{
+ struct flite_dev *flite = video_drvdata(file);
+ struct flite_frame *frame;
+ struct v4l2_pix_format_mplane *pix;
+ int ret = 0;
+
+ ret = flite_try_fmt_mplane(file, fh, f);
+ if (ret)
+ return ret;
+
+ if (vb2_is_streaming(&flite->vbq)) {
+ flite_err("queue (%d) busy", f->type);
+ return -EBUSY;
+ }
+
+ frame = &flite->d_frame;
+
+ pix = &f->fmt.pix_mp;
+ frame->fmt = find_format(&pix->pixelformat, NULL, 0);
+ if (!frame->fmt)
+ return -EINVAL;
+
+ frame->payload = pix->plane_fmt[0].bytesperline * pix->height;
+ flite_set_frame_size(frame, pix->width, pix->height);
+
+ flite_info("f_w: %d, f_h: %d", frame->o_width, frame->o_height);
+
+ return 0;
+}
+
+static int flite_g_fmt_mplane(struct file *file, void *fh, struct v4l2_format *f)
+{
+ struct flite_dev *flite = video_drvdata(file);
+ struct flite_frame *frame;
+ struct v4l2_pix_format_mplane *pix_mp;
+ int i;
+
+ if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ return -EINVAL;
+
+ frame = &flite->d_frame;
+
+ if (IS_ERR(frame))
+ return PTR_ERR(frame);
+
+ pix_mp = &f->fmt.pix_mp;
+
+ pix_mp->width = frame->o_width;
+ pix_mp->height = frame->o_height;
+ pix_mp->field = V4L2_FIELD_NONE;
+ pix_mp->pixelformat = frame->fmt->pixelformat;
+ pix_mp->colorspace = V4L2_COLORSPACE_JPEG;
+ pix_mp->num_planes = 1;
+
+ for (i = 0; i < pix_mp->num_planes; ++i) {
+ pix_mp->plane_fmt[i].bytesperline = (frame->o_width *
+ frame->fmt->depth[i]) / 8;
+ pix_mp->plane_fmt[i].sizeimage = pix_mp->plane_fmt[i].bytesperline *
+ frame->o_height;
+ }
+
+ return 0;
+}
+
+static int flite_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *reqbufs)
+{
+ struct flite_dev *flite = video_drvdata(file);
+ struct flite_frame *frame;
+ int ret;
+
+ frame = &flite->d_frame;
+ frame->cacheable = flite->flite_ctrls.cacheable->val;
+ flite->vb2->set_cacheable(flite->alloc_ctx, frame->cacheable);
+
+ ret = vb2_reqbufs(&flite->vbq, reqbufs);
+ if (!ret)
+ flite->reqbufs_cnt = reqbufs->count;
+
+ return ret;
+}
+
+static int flite_querybuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+ struct flite_dev *flite = video_drvdata(file);
+
+ return vb2_querybuf(&flite->vbq, buf);
+}
+
+static int flite_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+ struct flite_dev *flite = video_drvdata(file);
+
+ return vb2_qbuf(&flite->vbq, buf);
+}
+
+static int flite_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+ struct flite_dev *flite = video_drvdata(file);
+
+ return vb2_dqbuf(&flite->vbq, buf, file->f_flags & O_NONBLOCK);
+}
+
+static int flite_link_validate(struct flite_dev *flite)
+{
+ struct v4l2_subdev_format sink_fmt, src_fmt;
+ struct v4l2_subdev *sd;
+ struct media_pad *pad;
+ int ret;
+
+ /* Get the source pad connected with flite-video */
+ pad = media_entity_remote_source(&flite->vd_pad);
+ if (pad == NULL)
+ return -EPIPE;
+ /* Get the subdev of source pad */
+ sd = media_entity_to_v4l2_subdev(pad->entity);
+
+ while (1) {
+ /* Find sink pad of the subdev*/
+ pad = &sd->entity.pads[0];
+ if (!(pad->flags & MEDIA_PAD_FL_SINK))
+ break;
+ if (sd == flite->sd_flite) {
+ struct flite_frame *f = &flite->s_frame;
+ sink_fmt.format.width = f->o_width;
+ sink_fmt.format.height = f->o_height;
+ sink_fmt.format.code = f->fmt ? f->fmt->code : 0;
+ } else {
+ sink_fmt.pad = pad->index;
+ sink_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+ ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &sink_fmt);
+ if (ret < 0 && ret != -ENOIOCTLCMD) {
+ flite_err("failed %s subdev get_fmt", sd->name);
+ return -EPIPE;
+ }
+ }
+ flite_info("sink sd name : %s", sd->name);
+ /* Get the source pad connected with remote sink pad */
+ pad = media_entity_remote_source(pad);
+ if (pad == NULL ||
+ media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+ break;
+
+ /* Get the subdev of source pad */
+ sd = media_entity_to_v4l2_subdev(pad->entity);
+ flite_info("source sd name : %s", sd->name);
+
+ src_fmt.pad = pad->index;
+ src_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+ ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &src_fmt);
+ if (ret < 0 && ret != -ENOIOCTLCMD) {
+ flite_err("failed %s subdev get_fmt", sd->name);
+ return -EPIPE;
+ }
+
+ flite_info("src_width : %d, src_height : %d, src_code : %d",
+ src_fmt.format.width, src_fmt.format.height,
+ src_fmt.format.code);
+ flite_info("sink_width : %d, sink_height : %d, sink_code : %d",
+ sink_fmt.format.width, sink_fmt.format.height,
+ sink_fmt.format.code);
+
+ if (src_fmt.format.width != sink_fmt.format.width ||
+ src_fmt.format.height != sink_fmt.format.height ||
+ src_fmt.format.code != sink_fmt.format.code) {
+ flite_err("mismatch sink and source");
+ return -EPIPE;
+ }
+ }
+
+ return 0;
+}
+static int flite_streamon(struct file *file, void *priv, enum v4l2_buf_type type)
+{
+ struct flite_dev *flite = video_drvdata(file);
+ struct flite_pipeline *p = &flite->pipeline;
+ int ret;
+
+ if (flite_active(flite))
+ return -EBUSY;
+
+ if (p->sensor) {
+ media_entity_pipeline_start(&p->sensor->entity, p->pipe);
+ } else {
+ flite_err("Error pipeline");
+ return -EPIPE;
+ }
+
+ ret = flite_link_validate(flite);
+ if (ret)
+ return ret;
+
+ flite_hw_reset(flite);
+
+ return vb2_streamon(&flite->vbq, type);
+}
+
+static int flite_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct flite_dev *flite = video_drvdata(file);
+ struct v4l2_subdev *sd = flite->pipeline.sensor;
+ int ret;
+
+ ret = vb2_streamoff(&flite->vbq, type);
+ if (ret == 0)
+ media_entity_pipeline_stop(&sd->entity);
+ return ret;
+}
+
+static int flite_enum_input(struct file *file, void *priv,
+ struct v4l2_input *i)
+{
+ struct flite_dev *flite = video_drvdata(file);
+ struct exynos_platform_flite *pdata = flite->pdata;
+ struct exynos_isp_info *isp_info;
+
+ if (i->index >= MAX_CAMIF_CLIENTS)
+ return -EINVAL;
+
+ isp_info = pdata->isp_info[i->index];
+ if (isp_info == NULL)
+ return -EINVAL;
+
+ i->type = V4L2_INPUT_TYPE_CAMERA;
+
+ strncpy(i->name, isp_info->board_info->type, 32);
+
+ return 0;
+
+}
+
+static int flite_s_input(struct file *file, void *priv, unsigned int i)
+{
+ return i == 0 ? 0 : -EINVAL;
+}
+
+static int flite_g_input(struct file *file, void *priv, unsigned int *i)
+{
+ *i = 0;
+ return 0;
+}
+
+
+static const struct v4l2_ioctl_ops flite_capture_ioctl_ops = {
+ .vidioc_querycap = flite_vidioc_querycap,
+
+ .vidioc_enum_fmt_vid_cap_mplane = flite_enum_fmt_mplane,
+ .vidioc_try_fmt_vid_cap_mplane = flite_try_fmt_mplane,
+ .vidioc_s_fmt_vid_cap_mplane = flite_s_fmt_mplane,
+ .vidioc_g_fmt_vid_cap_mplane = flite_g_fmt_mplane,
+
+ .vidioc_reqbufs = flite_reqbufs,
+ .vidioc_querybuf = flite_querybuf,
+
+ .vidioc_qbuf = flite_qbuf,
+ .vidioc_dqbuf = flite_dqbuf,
+
+ .vidioc_streamon = flite_streamon,
+ .vidioc_streamoff = flite_streamoff,
+
+ .vidioc_enum_input = flite_enum_input,
+ .vidioc_s_input = flite_s_input,
+ .vidioc_g_input = flite_g_input,
+};
+
+static const struct v4l2_file_operations flite_fops = {
+ .owner = THIS_MODULE,
+ .open = flite_open,
+ .release = flite_close,
+ .poll = flite_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = flite_mmap,
+};
+
+static int flite_config_camclk(struct flite_dev *flite,
+ struct exynos_isp_info *isp_info, int i)
+{
+ struct clk *camclk;
+ struct clk *srclk;
+
+ camclk = clk_get(&flite->pdev->dev, isp_info->cam_clk_name);
+ if (IS_ERR_OR_NULL(camclk)) {
+ flite_err("failed to get cam clk");
+ return -ENXIO;
+ }
+ flite->sensor[i].camclk = camclk;
+
+ srclk = clk_get(&flite->pdev->dev, isp_info->cam_srclk_name);
+ if (IS_ERR_OR_NULL(srclk)) {
+ clk_put(camclk);
+ flite_err("failed to get cam source clk\n");
+ return -ENXIO;
+ }
+ clk_set_parent(camclk, srclk);
+ clk_set_rate(camclk, isp_info->clk_frequency);
+ clk_put(srclk);
+
+ flite->gsc_clk = clk_get(&flite->pdev->dev, "gscl");
+ if (IS_ERR_OR_NULL(flite->gsc_clk)) {
+ flite_err("failed to get gscl clk");
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
+static struct v4l2_subdev *flite_register_sensor(struct flite_dev *flite,
+ int i)
+{
+ struct exynos_platform_flite *pdata = flite->pdata;
+ struct exynos_isp_info *isp_info = pdata->isp_info[i];
+ struct exynos_md *mdev = flite->mdev;
+ struct i2c_adapter *adapter;
+ struct v4l2_subdev *sd = NULL;
+
+ adapter = i2c_get_adapter(isp_info->i2c_bus_num);
+ if (!adapter)
+ return NULL;
+ sd = v4l2_i2c_new_subdev_board(&mdev->v4l2_dev, adapter,
+ isp_info->board_info, NULL);
+ if (IS_ERR_OR_NULL(sd)) {
+ v4l2_err(&mdev->v4l2_dev, "Failed to acquire subdev\n");
+ return NULL;
+ }
+ v4l2_set_subdev_hostdata(sd, &flite->sensor[i]);
+ sd->grp_id = SENSOR_GRP_ID;
+
+ v4l2_info(&mdev->v4l2_dev, "Registered sensor subdevice %s\n",
+ isp_info->board_info->type);
+
+ return sd;
+}
+
+static int flite_register_sensor_entities(struct flite_dev *flite)
+{
+ struct exynos_platform_flite *pdata = flite->pdata;
+ u32 num_clients = pdata->num_clients;
+ int i;
+
+ for (i = 0; i < num_clients; i++) {
+ flite->sensor[i].pdata = pdata->isp_info[i];
+ flite->sensor[i].sd = flite_register_sensor(flite, i);
+ if (IS_ERR_OR_NULL(flite->sensor[i].sd)) {
+ flite_err("failed to get register sensor");
+ return -EINVAL;
+ }
+ flite->mdev->sensor_sd[i] = flite->sensor[i].sd;
+ }
+
+ return 0;
+}
+
+static int flite_create_subdev(struct flite_dev *flite, struct v4l2_subdev *sd)
+{
+ struct v4l2_device *v4l2_dev;
+ int ret;
+
+ sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+ flite->pads[FLITE_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+ flite->pads[FLITE_PAD_SOURCE_PREV].flags = MEDIA_PAD_FL_SOURCE;
+ flite->pads[FLITE_PAD_SOURCE_CAMCORD].flags = MEDIA_PAD_FL_SOURCE;
+ flite->pads[FLITE_PAD_SOURCE_MEM].flags = MEDIA_PAD_FL_SOURCE;
+
+ ret = media_entity_init(&sd->entity, FLITE_PADS_NUM,
+ flite->pads, 0);
+ if (ret)
+ goto err_ent;
+
+ sd->internal_ops = &flite_v4l2_internal_ops;
+ sd->entity.ops = &flite_media_ops;
+ sd->grp_id = FLITE_GRP_ID;
+ v4l2_dev = &flite->mdev->v4l2_dev;
+ flite->mdev->flite_sd[flite->id] = sd;
+
+ ret = v4l2_device_register_subdev(v4l2_dev, sd);
+ if (ret)
+ goto err_sub;
+
+ flite_init_formats(sd, NULL);
+
+ return 0;
+
+err_sub:
+ media_entity_cleanup(&sd->entity);
+err_ent:
+ return ret;
+}
+
+static int flite_create_link(struct flite_dev *flite)
+{
+ struct media_entity *source, *sink;
+ struct exynos_platform_flite *pdata = flite->pdata;
+ struct exynos_isp_info *isp_info;
+ u32 num_clients = pdata->num_clients;
+ int ret, i;
+ enum cam_port id;
+
+ /* FIMC-LITE-SUBDEV ------> FIMC-LITE-VIDEO (Always link enable) */
+ source = &flite->sd_flite->entity;
+ sink = &flite->vfd->entity;
+ if (source && sink) {
+ ret = media_entity_create_link(source, FLITE_PAD_SOURCE_MEM, sink,
+ 0, 0);
+ if (ret) {
+ flite_err("failed link flite-subdev to flite-video\n");
+ return ret;
+ }
+ }
+ /* link sensor to mipi-csis */
+ for (i = 0; i < num_clients; i++) {
+ isp_info = pdata->isp_info[i];
+ id = isp_info->cam_port;
+ switch (isp_info->bus_type) {
+ case CAM_TYPE_ITU:
+ /* SENSOR ------> FIMC-LITE */
+ source = &flite->sensor[i].sd->entity;
+ sink = &flite->sd_flite->entity;
+ if (source && sink) {
+ ret = media_entity_create_link(source, 0,
+ sink, FLITE_PAD_SINK, 0);
+ if (ret) {
+ flite_err("failed link sensor to flite\n");
+ return ret;
+ }
+ }
+ break;
+ case CAM_TYPE_MIPI:
+ /* SENSOR ------> MIPI-CSI2 */
+ source = &flite->sensor[i].sd->entity;
+ sink = &flite->sd_csis->entity;
+ if (source && sink) {
+ ret = media_entity_create_link(source, 0,
+ sink, CSIS_PAD_SINK, 0);
+ if (ret) {
+ flite_err("failed link sensor to csis\n");
+ return ret;
+ }
+ }
+ /* MIPI-CSI2 ------> FIMC-LITE */
+ source = &flite->sd_csis->entity;
+ sink = &flite->sd_flite->entity;
+ if (source && sink) {
+ ret = media_entity_create_link(source,
+ CSIS_PAD_SOURCE,
+ sink, FLITE_PAD_SINK, 0);
+ if (ret) {
+ flite_err("failed link csis to flite\n");
+ return ret;
+ }
+ }
+ break;
+ }
+ }
+
+ flite->input = FLITE_INPUT_NONE;
+ flite->output = FLITE_OUTPUT_NONE;
+
+ return 0;
+}
+static int flite_register_video_device(struct flite_dev *flite)
+{
+ struct video_device *vfd;
+ struct vb2_queue *q;
+ int ret = -ENOMEM;
+
+ vfd = video_device_alloc();
+ if (!vfd) {
+ printk("Failed to allocate video device\n");
+ return ret;
+ }
+
+ snprintf(vfd->name, sizeof(vfd->name), "%s", dev_name(&flite->pdev->dev));
+
+ vfd->fops = &flite_fops;
+ vfd->ioctl_ops = &flite_capture_ioctl_ops;
+ vfd->v4l2_dev = &flite->mdev->v4l2_dev;
+ vfd->minor = -1;
+ vfd->release = video_device_release;
+ vfd->lock = &flite->lock;
+ video_set_drvdata(vfd, flite);
+
+ flite->vfd = vfd;
+ flite->refcnt = 0;
+ flite->reqbufs_cnt = 0;
+ INIT_LIST_HEAD(&flite->active_buf_q);
+ INIT_LIST_HEAD(&flite->pending_buf_q);
+
+ q = &flite->vbq;
+ memset(q, 0, sizeof(*q));
+ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ q->io_modes = VB2_MMAP | VB2_USERPTR;
+ q->drv_priv = flite;
+ q->ops = &flite_qops;
+ q->mem_ops = flite->vb2->ops;
+
+ vb2_queue_init(q);
+
+ ret = video_register_device(vfd, VFL_TYPE_GRABBER,
+ EXYNOS_VIDEONODE_FLITE(flite->id));
+ if (ret) {
+ flite_err("failed to register video device");
+ goto err_vfd_alloc;
+ }
+
+ flite->vd_pad.flags = MEDIA_PAD_FL_SOURCE;
+ ret = media_entity_init(&vfd->entity, 1, &flite->vd_pad, 0);
+ if (ret) {
+ flite_err("failed to initialize entity");
+ goto err_unreg_video;
+ }
+
+ vfd->ctrl_handler = &flite->ctrl_handler;
+ flite_dbg("flite video-device driver registered as /dev/video%d", vfd->num);
+
+ return 0;
+
+err_unreg_video:
+ video_unregister_device(vfd);
+err_vfd_alloc:
+ video_device_release(vfd);
+
+ return ret;
+}
+
+static int flite_get_md_callback(struct device *dev, void *p)
+{
+ struct exynos_md **md_list = p;
+ struct exynos_md *md = NULL;
+
+ md = dev_get_drvdata(dev);
+
+ if (md)
+ *(md_list + md->id) = md;
+
+ return 0; /* non-zero value stops iteration */
+}
+
+static struct exynos_md *flite_get_capture_md(enum mdev_node node)
+{
+ struct device_driver *drv;
+ struct exynos_md *md[MDEV_MAX_NUM] = {NULL,};
+ int ret;
+
+ drv = driver_find(MDEV_MODULE_NAME, &platform_bus_type);
+ if (!drv)
+ return ERR_PTR(-ENODEV);
+
+ ret = driver_for_each_device(drv, NULL, &md[0],
+ flite_get_md_callback);
+
+ return ret ? NULL : md[node];
+
+}
+
+static void flite_destroy_subdev(struct flite_dev *flite)
+{
+ struct v4l2_subdev *sd = flite->sd_flite;
+
+ if (!sd)
+ return;
+ media_entity_cleanup(&sd->entity);
+ v4l2_device_unregister_subdev(sd);
+ kfree(sd);
+ sd = NULL;
+}
+
+void flite_unregister_device(struct flite_dev *flite)
+{
+ struct video_device *vfd = flite->vfd;
+
+ if (vfd) {
+ media_entity_cleanup(&vfd->entity);
+ /* Can also be called if video device was
+ not registered */
+ video_unregister_device(vfd);
+ }
+ flite_destroy_subdev(flite);
+}
+#endif
+
+static int flite_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct v4l2_subdev *sd = platform_get_drvdata(pdev);
+ struct flite_dev *flite = v4l2_get_subdevdata(sd);
+
+ if (test_bit(FLITE_ST_STREAM, &flite->state))
+ flite_s_stream(sd, false);
+ if (test_bit(FLITE_ST_POWER, &flite->state))
+ flite_s_power(sd, false);
+
+ set_bit(FLITE_ST_SUSPEND, &flite->state);
+
+ return 0;
+}
+
+static int flite_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct v4l2_subdev *sd = platform_get_drvdata(pdev);
+ struct flite_dev *flite = v4l2_get_subdevdata(sd);
+
+ if (test_bit(FLITE_ST_POWER, &flite->state))
+ flite_s_power(sd, true);
+ if (test_bit(FLITE_ST_STREAM, &flite->state))
+ flite_s_stream(sd, true);
+
+ clear_bit(FLITE_ST_SUSPEND, &flite->state);
+
+ return 0;
+}
+
+static int flite_runtime_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct v4l2_subdev *sd = platform_get_drvdata(pdev);
+ struct flite_dev *flite = v4l2_get_subdevdata(sd);
+ unsigned long flags;
+
+#if defined(CONFIG_MEDIA_CONTROLLER) && defined(CONFIG_ARCH_EXYNOS5)
+ flite->vb2->suspend(flite->alloc_ctx);
+ clk_disable(flite->camif_clk);
+#endif
+ spin_lock_irqsave(&flite->slock, flags);
+ set_bit(FLITE_ST_SUSPEND, &flite->state);
+ spin_unlock_irqrestore(&flite->slock, flags);
+
+ return 0;
+}
+
+static int flite_runtime_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct v4l2_subdev *sd = platform_get_drvdata(pdev);
+ struct flite_dev *flite = v4l2_get_subdevdata(sd);
+ unsigned long flags;
+
+#if defined(CONFIG_MEDIA_CONTROLLER) && defined(CONFIG_ARCH_EXYNOS5)
+ clk_enable(flite->camif_clk);
+ flite->vb2->resume(flite->alloc_ctx);
+#endif
+ spin_lock_irqsave(&flite->slock, flags);
+ clear_bit(FLITE_ST_SUSPEND, &flite->state);
+ spin_unlock_irqrestore(&flite->slock, flags);
+
+ return 0;
+}
+
+static struct v4l2_subdev_core_ops flite_core_ops = {
+ .s_power = flite_s_power,
+};
+
+static struct v4l2_subdev_video_ops flite_video_ops = {
+ .g_mbus_fmt = flite_g_mbus_fmt,
+ .s_mbus_fmt = flite_s_mbus_fmt,
+ .s_stream = flite_s_stream,
+ .cropcap = flite_subdev_cropcap,
+ .g_crop = flite_subdev_g_crop,
+ .s_crop = flite_subdev_s_crop,
+};
+
+static struct v4l2_subdev_ops flite_subdev_ops = {
+ .core = &flite_core_ops,
+#if defined(CONFIG_MEDIA_CONTROLLER) && defined(CONFIG_ARCH_EXYNOS5)
+ .pad = &flite_pad_ops,
+#endif
+ .video = &flite_video_ops,
+};
+
+static int flite_probe(struct platform_device *pdev)
+{
+ struct resource *mem_res;
+ struct resource *regs_res;
+ struct flite_dev *flite;
+ struct v4l2_subdev *sd;
+ int ret = -ENODEV;
+#if defined(CONFIG_MEDIA_CONTROLLER) && defined(CONFIG_ARCH_EXYNOS5)
+ struct exynos_isp_info *isp_info;
+ int i;
+#endif
+ if (!pdev->dev.platform_data) {
+ dev_err(&pdev->dev, "platform data is NULL\n");
+ return -EINVAL;
+ }
+
+ flite = kzalloc(sizeof(struct flite_dev), GFP_KERNEL);
+ if (!flite)
+ return -ENOMEM;
+
+ flite->pdev = pdev;
+ flite->pdata = pdev->dev.platform_data;
+
+ flite->id = pdev->id;
+
+ init_waitqueue_head(&flite->irq_queue);
+ spin_lock_init(&flite->slock);
+
+ mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem_res) {
+ dev_err(&pdev->dev, "Failed to get io memory region\n");
+ goto err_flite;
+ }
+
+ regs_res = request_mem_region(mem_res->start, resource_size(mem_res),
+ pdev->name);
+ if (!regs_res) {
+ dev_err(&pdev->dev, "Failed to request io memory region\n");
+ goto err_resource;
+ }
+
+ flite->regs_res = regs_res;
+ flite->regs = ioremap(mem_res->start, resource_size(mem_res));
+ if (!flite->regs) {
+ dev_err(&pdev->dev, "Failed to remap io region\n");
+ goto err_reg_region;
+ }
+
+ flite->irq = platform_get_irq(pdev, 0);
+ if (flite->irq < 0) {
+ dev_err(&pdev->dev, "Failed to get irq\n");
+ goto err_reg_unmap;
+ }
+
+ ret = request_irq(flite->irq, flite_irq_handler, 0, dev_name(&pdev->dev), flite);
+ if (ret) {
+ dev_err(&pdev->dev, "request_irq failed\n");
+ goto err_reg_unmap;
+ }
+
+ sd = kzalloc(sizeof(*sd), GFP_KERNEL);
+ if (!sd)
+ goto err_irq;
+ v4l2_subdev_init(sd, &flite_subdev_ops);
+ snprintf(sd->name, sizeof(sd->name), "flite-subdev.%d", flite->id);
+
+ flite->sd_flite = sd;
+ v4l2_set_subdevdata(flite->sd_flite, flite);
+ if (soc_is_exynos4212() || soc_is_exynos4412())
+ v4l2_set_subdev_hostdata(sd, pdev);
+#if defined(CONFIG_MEDIA_CONTROLLER) && defined(CONFIG_ARCH_EXYNOS5)
+#if defined(CONFIG_VIDEOBUF2_CMA_PHYS)
+ flite->vb2 = &flite_vb2_cma;
+#elif defined(CONFIG_VIDEOBUF2_ION)
+ flite->vb2 = &flite_vb2_ion;
+#endif
+ mutex_init(&flite->lock);
+ flite->mdev = flite_get_capture_md(MDEV_CAPTURE);
+ if (IS_ERR_OR_NULL(flite->mdev))
+ goto err_irq;
+
+ flite_dbg("mdev = 0x%08x", (u32)flite->mdev);
+
+ ret = flite_register_video_device(flite);
+ if (ret)
+ goto err_irq;
+
+ /* Get mipi-csis subdev ptr using mdev */
+ flite->sd_csis = flite->mdev->csis_sd[flite->id];
+
+ for (i = 0; i < flite->pdata->num_clients; i++) {
+ isp_info = flite->pdata->isp_info[i];
+ ret = flite_config_camclk(flite, isp_info, i);
+ if (ret) {
+ flite_err("failed setup cam clk");
+ goto err_vfd_alloc;
+ }
+ }
+
+ ret = flite_register_sensor_entities(flite);
+ if (ret) {
+ flite_err("failed register sensor entities");
+ goto err_clk;
+ }
+
+ ret = flite_create_subdev(flite, sd);
+ if (ret) {
+ flite_err("failed create subdev");
+ goto err_clk;
+ }
+
+ ret = flite_create_link(flite);
+ if (ret) {
+ flite_err("failed create link");
+ goto err_entity;
+ }
+
+ flite->alloc_ctx = flite->vb2->init(flite);
+ if (IS_ERR(flite->alloc_ctx)) {
+ ret = PTR_ERR(flite->alloc_ctx);
+ goto err_entity;
+ }
+
+ flite->camif_clk = clk_get(&flite->pdev->dev, CAMIF_TOP_CLK);
+ if (IS_ERR(flite->camif_clk)) {
+ flite_err("failed to get flite.%d clock", flite->id);
+ goto err_entity;
+ }
+ flite->mdev->is_flite_on= false;
+#endif
+ platform_set_drvdata(flite->pdev, flite->sd_flite);
+ pm_runtime_enable(&pdev->dev);
+
+ flite_info("FIMC-LITE%d probe success", pdev->id);
+
+ return 0;
+
+#if defined(CONFIG_MEDIA_CONTROLLER) && defined(CONFIG_ARCH_EXYNOS5)
+err_entity:
+ media_entity_cleanup(&sd->entity);
+err_clk:
+ for (i = 0; i < flite->pdata->num_clients; i++)
+ clk_put(flite->sensor[i].camclk);
+err_vfd_alloc:
+ media_entity_cleanup(&flite->vfd->entity);
+ video_device_release(flite->vfd);
+#endif
+err_irq:
+ free_irq(flite->irq, flite);
+err_reg_unmap:
+ iounmap(flite->regs);
+err_reg_region:
+ release_mem_region(regs_res->start, resource_size(regs_res));
+err_resource:
+ release_resource(flite->regs_res);
+ kfree(flite->regs_res);
+err_flite:
+ kfree(flite);
+ return ret;
+}
+
+static int flite_remove(struct platform_device *pdev)
+{
+ struct v4l2_subdev *sd = platform_get_drvdata(pdev);
+ struct flite_dev *flite = v4l2_get_subdevdata(sd);
+ struct resource *res = flite->regs_res;
+
+ flite_s_power(flite->sd_flite, 0);
+#if defined(CONFIG_MEDIA_CONTROLLER) && defined(CONFIG_ARCH_EXYNOS5)
+ flite_subdev_close(sd, NULL);
+ flite_unregister_device(flite);
+ flite->vb2->cleanup(flite->alloc_ctx);
+#endif
+ pm_runtime_disable(&pdev->dev);
+ free_irq(flite->irq, flite);
+ iounmap(flite->regs);
+ release_mem_region(res->start, resource_size(res));
+ kfree(flite);
+
+ return 0;
+}
+
+
+static const struct dev_pm_ops flite_pm_ops = {
+ .suspend = flite_suspend,
+ .resume = flite_resume,
+ .runtime_suspend = flite_runtime_suspend,
+ .runtime_resume = flite_runtime_resume,
+};
+
+static struct platform_driver flite_driver = {
+ .probe = flite_probe,
+ .remove = __devexit_p(flite_remove),
+ .driver = {
+ .name = MODULE_NAME,
+ .owner = THIS_MODULE,
+ .pm = &flite_pm_ops,
+ }
+};
+
+static int __init flite_init(void)
+{
+ int ret = platform_driver_register(&flite_driver);
+ if (ret)
+ flite_err("platform_driver_register failed: %d", ret);
+ return ret;
+}
+
+static void __exit flite_exit(void)
+{
+ platform_driver_unregister(&flite_driver);
+}
+module_init(flite_init);
+module_exit(flite_exit);
+
+MODULE_AUTHOR("Sky Kang<sungchun.kang@samsung.com>");
+MODULE_DESCRIPTION("Exynos FIMC-Lite driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/exynos/fimc-lite/fimc-lite-core.h b/drivers/media/video/exynos/fimc-lite/fimc-lite-core.h
new file mode 100644
index 0000000..ceb5374
--- /dev/null
+++ b/drivers/media/video/exynos/fimc-lite/fimc-lite-core.h
@@ -0,0 +1,354 @@
+/*
+ * Register interface file for Samsung Camera Interface (FIMC-Lite) driver
+ *
+ * Copyright (c) 2011 Samsung Electronics
+ *
+ * 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.
+*/
+#ifndef FLITE_CORE_H_
+#define FLITE_CORE_H_
+
+/* #define DEBUG */
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+#include <linux/videodev2_exynos_media.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/pm_runtime.h>
+#include <media/videobuf2-core.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-mediabus.h>
+#include <media/exynos_flite.h>
+#include <media/v4l2-ioctl.h>
+#ifdef CONFIG_ARCH_EXYNOS5
+#include <media/exynos_mc.h>
+#endif
+
+#if defined(CONFIG_VIDEOBUF2_CMA_PHYS)
+#include <media/videobuf2-cma-phys.h>
+#elif defined(CONFIG_VIDEOBUF2_ION)
+#include <media/videobuf2-ion.h>
+#endif
+#include <plat/cpu.h>
+
+#include "fimc-lite-reg.h"
+
+#define flite_info(fmt, args...) \
+ printk(KERN_INFO "[INFO]%s:%d: "fmt "\n", __func__, __LINE__, ##args)
+#define flite_err(fmt, args...) \
+ printk(KERN_ERR "[ERROR]%s:%d: "fmt "\n", __func__, __LINE__, ##args)
+#define flite_warn(fmt, args...) \
+ printk(KERN_WARNING "[WARNNING]%s:%d: "fmt "\n", __func__, __LINE__, ##args)
+
+#ifdef DEBUG
+#define flite_dbg(fmt, args...) \
+ printk(KERN_DEBUG "[DEBUG]%s:%d: " fmt "\n", __func__, __LINE__, ##args)
+#else
+#define flite_dbg(fmt, args...)
+#endif
+
+#define FLITE_MAX_RESET_READY_TIME 20 /* 100ms */
+#define FLITE_MAX_CTRL_NUM 1
+#define FLITE_MAX_OUT_BUFS 1
+#ifdef CONFIG_ARCH_EXYNOS4
+#define FLITE_MAX_MBUS_NUM 1
+#endif
+enum flite_input_entity {
+ FLITE_INPUT_NONE,
+ FLITE_INPUT_SENSOR,
+ FLITE_INPUT_CSIS,
+};
+
+enum flite_output_entity {
+ FLITE_OUTPUT_NONE = (1 << 0),
+ FLITE_OUTPUT_GSC = (1 << 1),
+ FLITE_OUTPUT_MEM = (1 << 2),
+};
+
+enum flite_out_path {
+ FLITE_ISP,
+ FLITE_DMA,
+};
+
+enum flite_state {
+ FLITE_ST_OPEN,
+ FLITE_ST_SUBDEV_OPEN,
+ FLITE_ST_POWER,
+ FLITE_ST_STREAM,
+ FLITE_ST_SUSPEND,
+ FLITE_ST_RUN,
+ FLITE_ST_PIPE_STREAM,
+ FLITE_ST_PEND,
+};
+
+#define flite_active(dev) test_bit(FLITE_ST_RUN, &(dev)->state)
+#define ctrl_to_dev(__ctrl) \
+ container_of((__ctrl)->handler, struct flite_dev, ctrl_handler)
+#define flite_get_frame(flite, pad)\
+ ((pad == FLITE_PAD_SINK) ? &flite->s_frame : &flite->d_frame)
+
+struct flite_variant {
+ u16 max_w;
+ u16 max_h;
+ u16 align_win_offs_w;
+ u16 align_out_w;
+ u16 align_out_offs_w;
+};
+
+/**
+ * struct flite_fmt - driver's color format data
+ * @name : format description
+ * @code : Media Bus pixel code
+ * @fmt_reg : H/W bit for setting format
+ */
+struct flite_fmt {
+ char *name;
+ u32 pixelformat;
+ enum v4l2_mbus_pixelcode code;
+ u32 fmt_reg;
+ u32 is_yuv;
+ u8 depth[VIDEO_MAX_PLANES];
+};
+
+struct flite_addr {
+ dma_addr_t y;
+};
+
+/**
+ * struct flite_frame - source/target frame properties
+ * @o_width: buffer width as set by S_FMT
+ * @o_height: buffer height as set by S_FMT
+ * @width: image pixel width
+ * @height: image pixel weight
+ * @offs_h: image horizontal pixel offset
+ * @offs_v: image vertical pixel offset
+ */
+
+/*
+ o_width
+ ---------------------
+ | width(cropped) |
+ | ----- |
+ |offs_h | | |
+ | ----- |
+ | |
+ ---------------------
+ */
+struct flite_frame {
+ u32 o_width;
+ u32 o_height;
+ u32 width;
+ u32 height;
+ u32 offs_h;
+ u32 offs_v;
+ unsigned long payload;
+ struct flite_addr addr;
+ struct flite_fmt *fmt;
+ bool cacheable;
+};
+
+struct flite_pipeline {
+ struct media_pipeline *pipe;
+ struct v4l2_subdev *flite;
+ struct v4l2_subdev *csis;
+ struct v4l2_subdev *sensor;
+};
+
+struct flite_sensor_info {
+ struct exynos_isp_info *pdata;
+ struct v4l2_subdev *sd;
+ struct clk *camclk;
+};
+
+struct flite_ctrls {
+ struct v4l2_ctrl *cacheable;
+};
+/**
+ * struct flite_dev - top structure of FIMC-Lite device
+ * @pdev : pointer to the FIMC-Lite platform device
+ * @lock : the mutex protecting this data structure
+ * @sd : subdevice pointer of FIMC-Lite
+ * @fmt : Media bus format of FIMC-Lite
+ * @regs_res : ioremapped regs of FIMC-Lite
+ * @regs : SFR of FIMC-Lite
+ */
+struct flite_dev {
+ struct platform_device *pdev;
+ struct exynos_platform_flite *pdata; /* depended on isp */
+ spinlock_t slock;
+ struct v4l2_subdev *sd_flite;
+#if defined(CONFIG_MEDIA_CONTROLLER) && defined(CONFIG_ARCH_EXYNOS5)
+ struct exynos_md *mdev;
+ struct v4l2_subdev *sd_csis;
+ struct flite_sensor_info sensor[SENSOR_MAX_ENTITIES];
+ struct media_pad pads[FLITE_PADS_NUM];
+ struct media_pad vd_pad;
+ struct flite_frame d_frame;
+ struct mutex lock;
+ struct video_device *vfd;
+ int refcnt;
+ u32 reqbufs_cnt;
+ struct vb2_queue vbq;
+ struct vb2_alloc_ctx *alloc_ctx;
+ const struct flite_vb2 *vb2;
+ struct flite_pipeline pipeline;
+ struct v4l2_ctrl_handler ctrl_handler;
+ struct flite_ctrls flite_ctrls;
+ bool ctrls_rdy;
+ struct list_head pending_buf_q;
+ struct list_head active_buf_q;
+ int active_buf_cnt;
+ int pending_buf_cnt;
+ int buf_index;
+ struct clk *gsc_clk;
+ struct clk *camif_clk;
+#endif
+ struct v4l2_mbus_framefmt mbus_fmt;
+ struct flite_frame s_frame;
+ struct resource *regs_res;
+ void __iomem *regs;
+ int irq;
+ unsigned long state;
+ u32 out_path;
+ wait_queue_head_t irq_queue;
+ u32 id;
+ enum flite_input_entity input;
+ enum flite_output_entity output;
+};
+
+struct flite_vb2 {
+ const struct vb2_mem_ops *ops;
+ void *(*init)(struct flite_dev *flite);
+ void (*cleanup)(void *alloc_ctx);
+
+ unsigned long (*plane_addr)(struct vb2_buffer *vb, u32 plane_no);
+
+ int (*resume)(void *alloc_ctx);
+ void (*suspend)(void *alloc_ctx);
+
+ int (*cache_flush)(struct vb2_buffer *vb, u32 num_planes);
+ void (*set_cacheable)(void *alloc_ctx, bool cacheable);
+ void (*set_sharable)(void *alloc_ctx, bool sharable);
+};
+
+struct flite_buffer {
+ struct vb2_buffer vb;
+ struct list_head list;
+ struct flite_addr paddr;
+ int index;
+};
+/* fimc-reg.c */
+void flite_hw_set_cam_source_size(struct flite_dev *dev);
+void flite_hw_set_cam_channel(struct flite_dev *dev);
+void flite_hw_set_camera_type(struct flite_dev *dev, struct s3c_platform_camera *cam);
+int flite_hw_set_source_format(struct flite_dev *dev);
+void flite_hw_set_output_dma(struct flite_dev *dev, bool enable);
+void flite_hw_set_interrupt_source(struct flite_dev *dev, u32 source);
+void flite_hw_set_config_irq(struct flite_dev *dev, struct s3c_platform_camera *cam);
+void flite_hw_set_window_offset(struct flite_dev *dev);
+void flite_hw_set_capture_start(struct flite_dev *dev);
+void flite_hw_set_capture_stop(struct flite_dev *dev);
+void flite_hw_reset(struct flite_dev *dev);
+void flite_hw_set_last_capture_end_clear(struct flite_dev *dev);
+void flite_hw_set_inverse_polarity(struct flite_dev *dev);
+void flite_hw_set_sensor_type(struct flite_dev *dev);
+void flite_hw_set_out_order(struct flite_dev *dev);
+void flite_hw_set_output_size(struct flite_dev *dev);
+void flite_hw_set_dma_offset(struct flite_dev *dev);
+void flite_hw_set_output_addr(struct flite_dev *dev, struct flite_addr *addr,
+ int index);
+
+#if defined(CONFIG_VIDEOBUF2_CMA_PHYS)
+extern const struct flite_vb2 flite_vb2_cma;
+#elif defined(CONFIG_VIDEOBUF2_ION)
+extern const struct flite_vb2 flite_vb2_ion;
+#endif
+
+/* inline function for performance-sensitive region */
+static inline void flite_hw_clear_irq(struct flite_dev *dev)
+{
+ u32 cfg = readl(dev->regs + FLITE_REG_CISTATUS);
+ cfg &= ~FLITE_REG_CISTATUS_IRQ_CAM;
+ writel(cfg, dev->regs + FLITE_REG_CISTATUS);
+}
+
+static inline void flite_hw_get_int_src(struct flite_dev *dev, u32 *src)
+{
+ *src = readl(dev->regs + FLITE_REG_CISTATUS);
+ *src &= FLITE_REG_CISTATUS_IRQ_MASK;
+}
+
+static inline void user_to_drv(struct v4l2_ctrl *ctrl, s32 value)
+{
+ ctrl->cur.val = ctrl->val = value;
+}
+
+inline struct flite_fmt const *find_flite_format(struct v4l2_mbus_framefmt *mf);
+
+/*
+ * Add buf to the capture active buffers queue.
+ * Locking: Need to be called with fimc_dev::slock held.
+ */
+
+#if defined(CONFIG_MEDIA_CONTROLLER) && defined(CONFIG_ARCH_EXYNOS5)
+static inline void active_queue_add(struct flite_dev *flite,
+ struct flite_buffer *buf)
+{
+ list_add_tail(&buf->list, &flite->active_buf_q);
+ flite->active_buf_cnt++;
+}
+
+/*
+ * Pop a video buffer from the capture active buffers queue
+ * Locking: Need to be called with fimc_dev::slock held.
+ */
+static inline struct flite_buffer *active_queue_pop(struct flite_dev *flite)
+{
+ struct flite_buffer *buf;
+
+ buf = list_entry(flite->active_buf_q.next, struct flite_buffer, list);
+ list_del(&buf->list);
+ flite->active_buf_cnt--;
+
+ return buf;
+}
+
+/* Add video buffer to the capture pending buffers queue */
+static inline void pending_queue_add(struct flite_dev *flite,
+ struct flite_buffer *buf)
+{
+ list_add_tail(&buf->list, &flite->pending_buf_q);
+ flite->pending_buf_cnt++;
+}
+
+/* Add video buffer to the capture pending buffers queue */
+static inline struct flite_buffer *pending_queue_pop(struct flite_dev *flite)
+{
+ struct flite_buffer *buf;
+
+ buf = list_entry(flite->pending_buf_q.next, struct flite_buffer, list);
+ list_del(&buf->list);
+ flite->pending_buf_cnt--;
+
+ return buf;
+}
+
+static inline void flite_lock(struct vb2_queue *vq)
+{
+ struct flite_dev *flite = vb2_get_drv_priv(vq);
+ mutex_lock(&flite->lock);
+}
+
+static inline void flite_unlock(struct vb2_queue *vq)
+{
+ struct flite_dev *flite = vb2_get_drv_priv(vq);
+ mutex_unlock(&flite->lock);
+}
+#endif
+#endif /* FLITE_CORE_H */
diff --git a/drivers/media/video/exynos/fimc-lite/fimc-lite-reg.c b/drivers/media/video/exynos/fimc-lite/fimc-lite-reg.c
new file mode 100644
index 0000000..e330395
--- /dev/null
+++ b/drivers/media/video/exynos/fimc-lite/fimc-lite-reg.c
@@ -0,0 +1,342 @@
+/*
+ * Register interface file for Samsung Camera Interface (FIMC-Lite) driver
+ *
+ * Copyright (c) 2011 Samsung Electronics
+ *
+ * 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.
+*/
+
+#include <linux/io.h>
+#include <media/exynos_flite.h>
+#include <mach/map.h>
+#include <plat/cpu.h>
+
+#include "fimc-lite-core.h"
+
+void flite_hw_set_cam_source_size(struct flite_dev *dev)
+{
+ struct flite_frame *f_frame = &dev->s_frame;
+ u32 cfg = 0;
+
+ cfg = readl(dev->regs + FLITE_REG_CISRCSIZE);
+
+ cfg |= FLITE_REG_CISRCSIZE_SIZE_H(f_frame->o_width);
+ cfg |= FLITE_REG_CISRCSIZE_SIZE_V(f_frame->o_height);
+
+ writel(cfg, dev->regs + FLITE_REG_CISRCSIZE);
+}
+
+void flite_hw_set_cam_channel(struct flite_dev *dev)
+{
+ u32 cfg = readl(dev->regs + FLITE_REG_CIGENERAL);
+
+ if (dev->id == 0)
+ cfg &= FLITE_REG_CIGENERAL_CAM_A;
+ else
+ cfg |= FLITE_REG_CIGENERAL_CAM_B;
+
+ writel(cfg, dev->regs + FLITE_REG_CIGENERAL);
+}
+
+void flite_hw_reset(struct flite_dev *dev)
+{
+ u32 cfg = 0;
+ unsigned long timeo = jiffies + FLITE_MAX_RESET_READY_TIME;
+
+ cfg = readl(dev->regs + FLITE_REG_CIGCTRL);
+ cfg |= FLITE_REG_CIGCTRL_SWRST_REQ;
+ writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
+
+ do {
+ if (cfg & FLITE_REG_CIGCTRL_SWRST_RDY)
+ break;
+ usleep_range(1000, 5000);
+ } while (time_before(jiffies, timeo));
+
+ flite_dbg("wait time : %d ms",
+ jiffies_to_msecs(jiffies - timeo + FLITE_MAX_RESET_READY_TIME));
+
+ cfg |= FLITE_REG_CIGCTRL_SWRST;
+ writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
+}
+
+/* Support only FreeRun mode
+ * If output DMA is supported, I will implement one shot mode
+ * with Cpt_FrCnt and Cpt_FrEn
+ */
+
+void flite_hw_set_capture_start(struct flite_dev *dev)
+{
+ u32 cfg = 0;
+
+ cfg = readl(dev->regs + FLITE_REG_CIIMGCPT);
+ cfg |= FLITE_REG_CIIMGCPT_IMGCPTEN;
+
+ writel(cfg, dev->regs + FLITE_REG_CIIMGCPT);
+}
+
+void flite_hw_set_capture_stop(struct flite_dev *dev)
+{
+ u32 cfg = 0;
+
+ cfg = readl(dev->regs + FLITE_REG_CIIMGCPT);
+ cfg &= ~FLITE_REG_CIIMGCPT_IMGCPTEN;
+
+ writel(cfg, dev->regs + FLITE_REG_CIIMGCPT);
+
+ if (soc_is_exynos4212() || soc_is_exynos4412())
+ clear_bit(FLITE_ST_STREAM, &dev->state);
+}
+
+int flite_hw_set_source_format(struct flite_dev *dev)
+{
+ struct v4l2_mbus_framefmt *mbus_fmt = &dev->mbus_fmt;
+ struct flite_fmt const *f_fmt = find_flite_format(mbus_fmt);
+ u32 cfg = 0;
+
+ if (!f_fmt) {
+ flite_err("f_fmt is null");
+ return -EINVAL;
+ }
+
+ cfg = readl(dev->regs + FLITE_REG_CIGCTRL);
+ cfg |= f_fmt->fmt_reg;
+ writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
+
+ if (f_fmt->is_yuv) {
+ cfg = readl(dev->regs + FLITE_REG_CISRCSIZE);
+
+ switch (f_fmt->code) {
+ case V4L2_MBUS_FMT_YUYV8_2X8:
+ cfg |= FLITE_REG_CISRCSIZE_ORDER422_IN_YCBYCR;
+ break;
+ case V4L2_MBUS_FMT_YVYU8_2X8:
+ cfg |= FLITE_REG_CISRCSIZE_ORDER422_IN_YCRYCB;
+ break;
+ case V4L2_MBUS_FMT_UYVY8_2X8:
+ cfg |= FLITE_REG_CISRCSIZE_ORDER422_IN_CBYCRY;
+ break;
+ case V4L2_MBUS_FMT_VYUY8_2X8:
+ cfg |= FLITE_REG_CISRCSIZE_ORDER422_IN_CRYCBY;
+ break;
+ default:
+ flite_err("not supported mbus code");
+ return -EINVAL;
+ }
+ writel(cfg, dev->regs + FLITE_REG_CISRCSIZE);
+ }
+ return 0;
+}
+
+void flite_hw_set_shadow_mask(struct flite_dev *dev, bool enable)
+{
+ u32 cfg = 0;
+ cfg = readl(dev->regs + FLITE_REG_CIGCTRL);
+
+ if (enable)
+ cfg &= ~FLITE_REG_CIGCTRL_SHADOWMASK_DISABLE;
+ else
+ cfg |= FLITE_REG_CIGCTRL_SHADOWMASK_DISABLE;
+
+ writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
+}
+
+void flite_hw_set_output_dma(struct flite_dev *dev, bool enable)
+{
+ u32 cfg = 0;
+ cfg = readl(dev->regs + FLITE_REG_CIGCTRL);
+
+ if (enable)
+ cfg &= ~FLITE_REG_CIGCTRL_ODMA_DISABLE;
+ else
+ cfg |= FLITE_REG_CIGCTRL_ODMA_DISABLE;
+
+ writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
+}
+
+void flite_hw_set_test_pattern_enable(struct flite_dev *dev)
+{
+ u32 cfg = 0;
+ cfg = readl(dev->regs + FLITE_REG_CIGCTRL);
+ cfg |= FLITE_REG_CIGCTRL_TEST_PATTERN_COLORBAR;
+
+ writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
+}
+
+void flite_hw_set_config_irq(struct flite_dev *dev, struct s3c_platform_camera *cam)
+{
+ u32 cfg = 0;
+ cfg = readl(dev->regs + FLITE_REG_CIGCTRL);
+ cfg &= ~(FLITE_REG_CIGCTRL_INVPOLPCLK | FLITE_REG_CIGCTRL_INVPOLVSYNC
+ | FLITE_REG_CIGCTRL_INVPOLHREF);
+
+ if (cam->inv_pclk)
+ cfg |= FLITE_REG_CIGCTRL_INVPOLPCLK;
+ if (cam->inv_vsync)
+ cfg |= FLITE_REG_CIGCTRL_INVPOLVSYNC;
+ if (cam->inv_href)
+ cfg |= FLITE_REG_CIGCTRL_INVPOLHREF;
+
+ writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
+}
+
+void flite_hw_set_interrupt_source(struct flite_dev *dev, u32 source)
+{
+ u32 cfg = 0;
+ cfg = readl(dev->regs + FLITE_REG_CIGCTRL);
+ cfg |= source;
+
+ writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
+}
+
+void flite_hw_set_camera_type(struct flite_dev *dev, struct s3c_platform_camera *cam)
+{
+ u32 cfg = 0;
+ cfg = readl(dev->regs + FLITE_REG_CIGCTRL);
+
+ if (cam->type == CAM_TYPE_ITU)
+ cfg &= ~FLITE_REG_CIGCTRL_SELCAM_MIPI;
+ else
+ cfg |= FLITE_REG_CIGCTRL_SELCAM_MIPI;
+
+ writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
+}
+
+void flite_hw_set_window_offset(struct flite_dev *dev)
+{
+ u32 cfg = 0;
+ u32 hoff2, voff2;
+ struct flite_frame *f_frame = &dev->s_frame;
+
+ cfg = readl(dev->regs + FLITE_REG_CIWDOFST);
+ cfg &= ~(FLITE_REG_CIWDOFST_HOROFF_MASK |
+ FLITE_REG_CIWDOFST_VEROFF_MASK);
+ cfg |= FLITE_REG_CIWDOFST_WINOFSEN |
+ FLITE_REG_CIWDOFST_WINHOROFST(f_frame->offs_h) |
+ FLITE_REG_CIWDOFST_WINVEROFST(f_frame->offs_v);
+
+ writel(cfg, dev->regs + FLITE_REG_CIWDOFST);
+
+ hoff2 = f_frame->o_width - f_frame->width - f_frame->offs_h;
+ voff2 = f_frame->o_height - f_frame->height - f_frame->offs_v;
+ cfg = FLITE_REG_CIWDOFST2_WINHOROFST2(hoff2) |
+ FLITE_REG_CIWDOFST2_WINVEROFST2(voff2);
+
+ writel(cfg, dev->regs + FLITE_REG_CIWDOFST2);
+}
+
+void flite_hw_set_last_capture_end_clear(struct flite_dev *dev)
+{
+ u32 cfg = 0;
+
+ cfg = readl(dev->regs + FLITE_REG_CISTATUS2);
+ cfg &= ~FLITE_REG_CISTATUS2_LASTCAPEND;
+
+ writel(cfg, dev->regs + FLITE_REG_CISTATUS2);
+}
+
+#if defined(CONFIG_MEDIA_CONTROLLER) && defined(CONFIG_ARCH_EXYNOS5)
+void flite_hw_set_inverse_polarity(struct flite_dev *dev)
+{
+ struct v4l2_subdev *sd = dev->pipeline.sensor;
+ struct flite_sensor_info *s_info = v4l2_get_subdev_hostdata(sd);
+ u32 cfg = 0;
+ cfg = readl(dev->regs + FLITE_REG_CIGCTRL);
+ cfg &= ~(FLITE_REG_CIGCTRL_INVPOLPCLK | FLITE_REG_CIGCTRL_INVPOLVSYNC
+ | FLITE_REG_CIGCTRL_INVPOLHREF);
+
+ if (s_info->pdata->flags & CAM_CLK_INV_PCLK)
+ cfg |= FLITE_REG_CIGCTRL_INVPOLPCLK;
+ if (s_info->pdata->flags & CAM_CLK_INV_VSYNC)
+ cfg |= FLITE_REG_CIGCTRL_INVPOLVSYNC;
+ if (s_info->pdata->flags & CAM_CLK_INV_HREF)
+ cfg |= FLITE_REG_CIGCTRL_INVPOLHREF;
+
+ writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
+}
+
+void flite_hw_set_sensor_type(struct flite_dev *dev)
+{
+ struct v4l2_subdev *sd = dev->pipeline.sensor;
+ struct flite_sensor_info *s_info = v4l2_get_subdev_hostdata(sd);
+ u32 cfg = 0;
+ cfg = readl(dev->regs + FLITE_REG_CIGCTRL);
+
+ if (s_info->pdata->bus_type == CAM_TYPE_ITU)
+ cfg &= ~FLITE_REG_CIGCTRL_SELCAM_MIPI;
+ else
+ cfg |= FLITE_REG_CIGCTRL_SELCAM_MIPI;
+
+ writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
+
+}
+
+void flite_hw_set_dma_offset(struct flite_dev *dev)
+{
+ u32 cfg = 0;
+ struct flite_frame *f_frame = &dev->d_frame;
+ cfg = readl(dev->regs + FLITE_REG_CIOOFF);
+ cfg |= FLITE_REG_CIOOFF_OOFF_H(f_frame->offs_h) |
+ FLITE_REG_CIOOFF_OOFF_V(f_frame->offs_v);
+
+ writel(cfg, dev->regs + FLITE_REG_CIOOFF);
+}
+
+void flite_hw_set_output_addr(struct flite_dev *dev,
+ struct flite_addr *addr, int index)
+{
+ flite_info("dst_buf[%d]: 0x%X", index, addr->y);
+
+ writel(addr->y, dev->regs + FLITE_REG_CIOSA);
+}
+
+void flite_hw_set_out_order(struct flite_dev *dev)
+{
+ struct flite_frame *frame = &dev->d_frame;
+ u32 cfg = readl(dev->regs + FLITE_REG_CIODMAFMT);
+ if (frame->fmt->is_yuv) {
+ switch (frame->fmt->code) {
+ case V4L2_MBUS_FMT_UYVY8_2X8:
+ cfg |= FLITE_REG_CIODMAFMT_CBYCRY;
+ break;
+ case V4L2_MBUS_FMT_VYUY8_2X8:
+ cfg |= FLITE_REG_CIODMAFMT_CRYCBY;
+ break;
+ case V4L2_MBUS_FMT_YUYV8_2X8:
+ cfg |= FLITE_REG_CIODMAFMT_YCBYCR;
+ break;
+ case V4L2_MBUS_FMT_YVYU8_2X8:
+ cfg |= FLITE_REG_CIODMAFMT_YCRYCB;
+ break;
+ default:
+ flite_err("not supported mbus_code");
+ break;
+
+ }
+ }
+ writel(cfg, dev->regs + FLITE_REG_CIODMAFMT);
+}
+
+void flite_hw_set_output_size(struct flite_dev *dev)
+{
+ struct flite_frame *f_frame = &dev->d_frame;
+ u32 cfg = 0;
+
+ cfg = readl(dev->regs + FLITE_REG_CIOCAN);
+
+ cfg |= FLITE_REG_CIOCAN_OCAN_V(f_frame->o_height);
+ cfg |= FLITE_REG_CIOCAN_OCAN_H(f_frame->o_width);
+
+ writel(cfg, dev->regs + FLITE_REG_CIOCAN);
+}
+#else
+void flite_hw_set_inverse_polarity(struct flite_dev *dev) {}
+void flite_hw_set_sensor_type(struct flite_dev *dev) {}
+void flite_hw_set_dma_offset(struct flite_dev *dev) {}
+void flite_hw_set_output_addr(struct flite_dev *dev,
+ struct flite_addr *addr, int index) {}
+void flite_hw_set_out_order(struct flite_dev *dev) {}
+void flite_hw_set_output_size(struct flite_dev *dev) {}
+#endif
diff --git a/drivers/media/video/exynos/fimc-lite/fimc-lite-reg.h b/drivers/media/video/exynos/fimc-lite/fimc-lite-reg.h
new file mode 100644
index 0000000..df99fa5
--- /dev/null
+++ b/drivers/media/video/exynos/fimc-lite/fimc-lite-reg.h
@@ -0,0 +1,135 @@
+/*
+ * Register interface file for Samsung Camera Interface (FIMC-Lite) driver
+ *
+ * Copyright (c) 2011 Samsung Electronics
+ *
+ * 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.
+*/
+
+#ifndef FIMC_LITE_REG_H_
+#define FIMC_LITE_REG_H_
+
+/* Camera Source size */
+#define FLITE_REG_CISRCSIZE 0x00
+#define FLITE_REG_CISRCSIZE_SIZE_H(x) ((x) << 16)
+#define FLITE_REG_CISRCSIZE_SIZE_V(x) ((x) << 0)
+#define FLITE_REG_CISRCSIZE_ORDER422_IN_YCBYCR (0 << 14)
+#define FLITE_REG_CISRCSIZE_ORDER422_IN_YCRYCB (1 << 14)
+#define FLITE_REG_CISRCSIZE_ORDER422_IN_CBYCRY (2 << 14)
+#define FLITE_REG_CISRCSIZE_ORDER422_IN_CRYCBY (3 << 14)
+
+/* Global control */
+#define FLITE_REG_CIGCTRL 0x04
+#define FLITE_REG_CIGCTRL_YUV422_1P (0x1E << 24)
+#define FLITE_REG_CIGCTRL_RAW8 (0x2A << 24)
+#define FLITE_REG_CIGCTRL_RAW10 (0x2B << 24)
+#define FLITE_REG_CIGCTRL_RAW12 (0x2C << 24)
+#define FLITE_REG_CIGCTRL_RAW14 (0x2D << 24)
+/* User defined formats. x = 0...0xF. */
+#define FLITE_REG_CIGCTRL_USER(x) (0x30 + x - 1)
+#define FLITE_REG_CIGCTRL_SHADOWMASK_DISABLE (1 << 21)
+#define FLITE_REG_CIGCTRL_ODMA_DISABLE (1 << 20)
+#define FLITE_REG_CIGCTRL_SWRST_REQ (1 << 19)
+#define FLITE_REG_CIGCTRL_SWRST_RDY (1 << 18)
+#define FLITE_REG_CIGCTRL_SWRST (1 << 17)
+#define FLITE_REG_CIGCTRL_TEST_PATTERN_COLORBAR (1 << 15)
+#define FLITE_REG_CIGCTRL_INVPOLPCLK (1 << 14)
+#define FLITE_REG_CIGCTRL_INVPOLVSYNC (1 << 13)
+#define FLITE_REG_CIGCTRL_INVPOLHREF (1 << 12)
+#define FLITE_REG_CIGCTRL_IRQ_LASTEN0_ENABLE (0 << 8)
+#define FLITE_REG_CIGCTRL_IRQ_LASTEN0_DISABLE (1 << 8)
+#define FLITE_REG_CIGCTRL_IRQ_ENDEN0_ENABLE (0 << 7)
+#define FLITE_REG_CIGCTRL_IRQ_ENDEN0_DISABLE (1 << 7)
+#define FLITE_REG_CIGCTRL_IRQ_STARTEN0_ENABLE (0 << 6)
+#define FLITE_REG_CIGCTRL_IRQ_STARTEN0_DISABLE (1 << 6)
+#define FLITE_REG_CIGCTRL_IRQ_OVFEN0_ENABLE (0 << 5)
+#define FLITE_REG_CIGCTRL_IRQ_OVFEN0_DISABLE (1 << 5)
+#define FLITE_REG_CIGCTRL_SELCAM_MIPI (1 << 3)
+
+/* Image Capture Enable */
+#define FLITE_REG_CIIMGCPT 0x08
+#define FLITE_REG_CIIMGCPT_IMGCPTEN (1 << 31)
+#define FLITE_REG_CIIMGCPT_CPT_FREN (1 << 25)
+#define FLITE_REG_CIIMGCPT_CPT_FRPTR(x) ((x) << 19)
+#define FLITE_REG_CIIMGCPT_CPT_MOD_FRCNT (1 << 18)
+#define FLITE_REG_CIIMGCPT_CPT_MOD_FREN (0 << 18)
+#define FLITE_REG_CIIMGCPT_CPT_FRCNT(x) ((x) << 10)
+
+/* Capture Sequence */
+#define FLITE_REG_CICPTSEQ 0x0C
+#define FLITE_REG_CPT_FRSEQ(x) ((x) << 0)
+
+/* Camera Window Offset */
+#define FLITE_REG_CIWDOFST 0x10
+#define FLITE_REG_CIWDOFST_WINOFSEN (1 << 31)
+#define FLITE_REG_CIWDOFST_CLROVIY (1 << 31)
+#define FLITE_REG_CIWDOFST_WINHOROFST(x) ((x) << 16)
+#define FLITE_REG_CIWDOFST_HOROFF_MASK (0x1fff << 16)
+#define FLITE_REG_CIWDOFST_CLROVFICB (1 << 15)
+#define FLITE_REG_CIWDOFST_CLROVFICR (1 << 14)
+#define FLITE_REG_CIWDOFST_WINVEROFST(x) ((x) << 0)
+#define FLITE_REG_CIWDOFST_VEROFF_MASK (0x1fff << 0)
+
+/* Cmaera Window Offset2 */
+#define FLITE_REG_CIWDOFST2 0x14
+#define FLITE_REG_CIWDOFST2_WINHOROFST2(x) ((x) << 16)
+#define FLITE_REG_CIWDOFST2_WINVEROFST2(x) ((x) << 0)
+
+/* Camera Output DMA Format */
+#define FLITE_REG_CIODMAFMT 0x18
+#define FLITE_REG_CIODMAFMT_1D_DMA (1 << 15)
+#define FLITE_REG_CIODMAFMT_2D_DMA (0 << 15)
+#define FLITE_REG_CIODMAFMT_PACK12 (1 << 14)
+#define FLITE_REG_CIODMAFMT_NORMAL (0 << 14)
+#define FLITE_REG_CIODMAFMT_CRYCBY (0 << 4)
+#define FLITE_REG_CIODMAFMT_CBYCRY (1 << 4)
+#define FLITE_REG_CIODMAFMT_YCRYCB (2 << 4)
+#define FLITE_REG_CIODMAFMT_YCBYCR (3 << 4)
+
+/* Camera Output Canvas */
+#define FLITE_REG_CIOCAN 0x20
+#define FLITE_REG_CIOCAN_OCAN_V(x) ((x) << 16)
+#define FLITE_REG_CIOCAN_OCAN_H(x) ((x) << 0)
+
+/* Camera Output DMA Offset */
+#define FLITE_REG_CIOOFF 0x24
+#define FLITE_REG_CIOOFF_OOFF_V(x) ((x) << 16)
+#define FLITE_REG_CIOOFF_OOFF_H(x) ((x) << 0)
+
+/* Camera Output DMA Address */
+#define FLITE_REG_CIOSA 0x30
+
+/* Camera Status */
+#define FLITE_REG_CISTATUS 0x40
+#define FLITE_REG_CISTATUS_MIPI_VVALID (1 << 22)
+#define FLITE_REG_CISTATUS_MIPI_HVALID (1 << 21)
+#define FLITE_REG_CISTATUS_MIPI_DVALID (1 << 20)
+#define FLITE_REG_CISTATUS_ITU_VSYNC (1 << 14)
+#define FLITE_REG_CISTATUS_ITU_HREFF (1 << 13)
+#define FLITE_REG_CISTATUS_OVFIY (1 << 10)
+#define FLITE_REG_CISTATUS_OVFICB (1 << 9)
+#define FLITE_REG_CISTATUS_OVFICR (1 << 8)
+#define FLITE_REG_CISTATUS_IRQ_SRC_OVERFLOW (1 << 7)
+#define FLITE_REG_CISTATUS_IRQ_SRC_LASTCAPEND (1 << 6)
+#define FLITE_REG_CISTATUS_IRQ_SRC_FRMSTART (1 << 5)
+#define FLITE_REG_CISTATUS_IRQ_SRC_FRMEND (1 << 4)
+#define FLITE_REG_CISTATUS_IRQ_CAM (1 << 0)
+#define FLITE_REG_CISTATUS_IRQ_MASK (0xf << 4)
+/* Camera Status2 */
+#define FLITE_REG_CISTATUS2 0x44
+#define FLITE_REG_CISTATUS2_LASTCAPEND (1 << 1)
+#define FLITE_REG_CISTATUS2_FRMEND (1 << 0)
+
+/* Qos Threshold */
+#define FLITE_REG_CITHOLD 0xF0
+#define FLITE_REG_CITHOLD_W_QOS_EN (1 << 30)
+#define FLITE_REG_CITHOLD_WTH_QOS(x) ((x) << 0)
+
+/* Camera General Purpose */
+#define FLITE_REG_CIGENERAL 0xFC
+#define FLITE_REG_CIGENERAL_CAM_A (0 << 0)
+#define FLITE_REG_CIGENERAL_CAM_B (1 << 0)
+
+#endif /* FIMC_LITE_REG_H */
diff --git a/drivers/media/video/exynos/fimc-lite/fimc-lite-vb2.c b/drivers/media/video/exynos/fimc-lite/fimc-lite-vb2.c
new file mode 100644
index 0000000..0e79dd2
--- /dev/null
+++ b/drivers/media/video/exynos/fimc-lite/fimc-lite-vb2.c
@@ -0,0 +1,68 @@
+/* linux/drivers/media/video/exynos/flite-vb2.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Videobuf2 allocator operations file
+ *
+ * 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.
+*/
+
+#include <linux/platform_device.h>
+#include "fimc-lite-core.h"
+
+#if defined(CONFIG_VIDEOBUF2_CMA_PHYS)
+void *flite_cma_init(struct flite_dev *flite)
+{
+ return vb2_cma_phys_init(&flite->pdev->dev, NULL, 0, false);
+}
+
+int flite_cma_resume(void *alloc_ctx) {}
+void flite_cma_suspend(void *alloc_ctx) {}
+void flite_cma_set_cacheable(void *alloc_ctx, bool cacheable) {}
+
+int flite_cma_cache_flush(struct vb2_buffer *vb, u32 plane_no)
+{
+ return 0;
+}
+
+const struct flite_vb2 flite_vb2_cma = {
+ .ops = &vb2_cma_phys_memops,
+ .init = flite_cma_init,
+ .cleanup = vb2_cma_phys_cleanup,
+ .plane_addr = vb2_cma_phys_plane_paddr,
+ .resume = flite_cma_resume,
+ .suspend = flite_cma_suspend,
+ .cache_flush = flite_cma_cache_flush,
+ .set_cacheable = flite_cma_set_cacheable,
+};
+#elif defined(CONFIG_VIDEOBUF2_ION)
+void *flite_ion_init(struct flite_dev *flite)
+{
+ return vb2_ion_create_context(&flite->pdev->dev, SZ_4K,
+ VB2ION_CTX_VMCONTIG | VB2ION_CTX_IOMMU | VB2ION_CTX_UNCACHED);
+}
+
+static unsigned long flite_vb2_plane_addr(struct vb2_buffer *vb, u32 plane_no)
+{
+ void *cookie = vb2_plane_cookie(vb, plane_no);
+ dma_addr_t dva = 0;
+
+ WARN_ON(vb2_ion_dma_address(cookie, &dva) != 0);
+
+ return dva;
+}
+
+const struct flite_vb2 flite_vb2_ion = {
+ .ops = &vb2_ion_memops,
+ .init = flite_ion_init,
+ .cleanup = vb2_ion_destroy_context,
+ .plane_addr = flite_vb2_plane_addr,
+ .resume = vb2_ion_attach_iommu,
+ .suspend = vb2_ion_detach_iommu,
+ .cache_flush = vb2_ion_cache_flush,
+ .set_cacheable = vb2_ion_set_cached,
+};
+#endif
diff --git a/drivers/media/video/exynos/fimg2d/Kconfig b/drivers/media/video/exynos/fimg2d/Kconfig
new file mode 100644
index 0000000..884ea94
--- /dev/null
+++ b/drivers/media/video/exynos/fimg2d/Kconfig
@@ -0,0 +1,21 @@
+# drivers/media/video/exynos/fimg2d/Kconfig
+#
+# Copyright (c) 2011 Samsung Electronics Co., Ltd.
+# http://www.samsung.com/
+#
+# Licensed under GPLv2
+
+config VIDEO_EXYNOS_FIMG2D
+ bool "Samsung Graphics 2D Driver"
+ depends on VIDEO_EXYNOS && (ARCH_EXYNOS4 || ARCH_EXYNOS5)
+ default n
+ ---help---
+ This is a graphics 2D driver for Samsung ARM based SoC.
+
+config VIDEO_FIMG2D_DEBUG
+ bool "Enables FIMG2D debug messages"
+ depends on VIDEO_EXYNOS_FIMG2D
+ default n
+ ---help---
+ This enables FIMG2D driver debug messages.
+
diff --git a/drivers/media/video/exynos/fimg2d/Makefile b/drivers/media/video/exynos/fimg2d/Makefile
new file mode 100644
index 0000000..c25578f
--- /dev/null
+++ b/drivers/media/video/exynos/fimg2d/Makefile
@@ -0,0 +1,19 @@
+# drivers/media/video/exynos/fimg2d/Makefile
+#
+# Copyright (c) 2011 Samsung Electronics Co., Ltd.
+# http://www.samsung.com/
+#
+# Licensed under GPLv2
+
+obj-y :=
+obj-m :=
+obj-n :=
+obj- :=
+
+obj-$(CONFIG_VIDEO_EXYNOS_FIMG2D) += fimg2d_drv.o fimg2d_clk.o \
+ fimg2d_ctx.o fimg2d_cache.o fimg2d_helper.o \
+ fimg2d4x_blt.o fimg2d4x_hw.o
+
+ifeq ($(CONFIG_VIDEO_FIMG2D_DEBUG),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
diff --git a/drivers/media/video/exynos/fimg2d/fimg2d.h b/drivers/media/video/exynos/fimg2d/fimg2d.h
new file mode 100644
index 0000000..81fe690
--- /dev/null
+++ b/drivers/media/video/exynos/fimg2d/fimg2d.h
@@ -0,0 +1,506 @@
+/* linux/drivers/media/video/samsung/fimg2d4x/fimg2d.h
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Samsung Graphics 2D driver
+ *
+ * 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.
+*/
+
+#ifndef __FIMG2D_H
+#define __FIMG2D_H __FILE__
+
+#ifdef __KERNEL__
+
+#include <linux/clk.h>
+#include <linux/list.h>
+#include <linux/device.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+#include <linux/atomic.h>
+#include <linux/dma-mapping.h>
+#include <asm/cacheflush.h>
+
+#define FIMG2D_MINOR (240)
+#define to_fimg2d_plat(d) (to_platform_device(d)->dev.platform_data)
+
+#ifdef CONFIG_VIDEO_FIMG2D_DEBUG
+#define fimg2d_debug(fmt, arg...) printk(KERN_INFO "[%s] " fmt, __func__, ## arg)
+#else
+#define fimg2d_debug(fmt, arg...) do { } while (0)
+#endif
+
+#endif /* __KERNEL__ */
+
+/* ioctl commands */
+#define FIMG2D_IOCTL_MAGIC 'F'
+#define FIMG2D_BITBLT_BLIT _IOWR(FIMG2D_IOCTL_MAGIC, 0, struct fimg2d_blit)
+#define FIMG2D_BITBLT_SYNC _IOW(FIMG2D_IOCTL_MAGIC, 1, int)
+#define FIMG2D_BITBLT_VERSION _IOR(FIMG2D_IOCTL_MAGIC, 2, struct fimg2d_version)
+
+struct fimg2d_version {
+ unsigned int hw;
+ unsigned int sw;
+};
+
+/**
+ * @BLIT_SYNC: sync mode, to wait for blit done irq
+ * @BLIT_ASYNC: async mode, not to wait for blit done irq
+ *
+ */
+enum blit_sync {
+ BLIT_SYNC,
+ BLIT_ASYNC,
+};
+
+/**
+ * @ADDR_PHYS: physical address
+ * @ADDR_USER: user virtual address (physically Non-contiguous)
+ * @ADDR_USER_RSVD: user virtual address (physically Contiguous)
+ * @ADDR_DEVICE: specific device virtual address
+ */
+enum addr_space {
+ ADDR_NONE,
+ ADDR_PHYS,
+ ADDR_KERN,
+ ADDR_USER,
+ ADDR_USER_RSVD,
+ ADDR_DEVICE,
+};
+
+/**
+ * Pixel order complies with little-endian style
+ *
+ * DO NOT CHANGE THIS ORDER
+ */
+enum pixel_order {
+ AX_RGB = 0,
+ RGB_AX,
+ AX_BGR,
+ BGR_AX,
+ ARGB_ORDER_END,
+
+ P1_CRY1CBY0,
+ P1_CBY1CRY0,
+ P1_Y1CRY0CB,
+ P1_Y1CBY0CR,
+ P1_ORDER_END,
+
+ P2_CRCB,
+ P2_CBCR,
+ P2_ORDER_END,
+};
+
+/**
+ * DO NOT CHANGE THIS ORDER
+ */
+enum color_format {
+ CF_XRGB_8888 = 0,
+ CF_ARGB_8888,
+ CF_RGB_565,
+ CF_XRGB_1555,
+ CF_ARGB_1555,
+ CF_XRGB_4444,
+ CF_ARGB_4444,
+ CF_RGB_888,
+ CF_YCBCR_444,
+ CF_YCBCR_422,
+ CF_YCBCR_420,
+ CF_A8,
+ CF_L8,
+ SRC_DST_FORMAT_END,
+
+ CF_MSK_1BIT,
+ CF_MSK_4BIT,
+ CF_MSK_8BIT,
+ CF_MSK_16BIT_565,
+ CF_MSK_16BIT_1555,
+ CF_MSK_16BIT_4444,
+ CF_MSK_32BIT_8888,
+ MSK_FORMAT_END,
+};
+
+enum rotation {
+ ORIGIN,
+ ROT_90, /* clockwise */
+ ROT_180,
+ ROT_270,
+ XFLIP, /* x-axis flip */
+ YFLIP, /* y-axis flip */
+};
+
+/**
+ * @NO_REPEAT: no effect
+ * @REPEAT_NORMAL: repeat horizontally and vertically
+ * @REPEAT_PAD: pad with pad color
+ * @REPEAT_REFLECT: reflect horizontally and vertically
+ * @REPEAT_CLAMP: pad with edge color of original image
+ *
+ * DO NOT CHANGE THIS ORDER
+ */
+enum repeat {
+ NO_REPEAT = 0,
+ REPEAT_NORMAL, /* default setting */
+ REPEAT_PAD,
+ REPEAT_REFLECT, REPEAT_MIRROR = REPEAT_REFLECT,
+ REPEAT_CLAMP,
+};
+
+enum scaling {
+ NO_SCALING,
+ SCALING_NEAREST,
+ SCALING_BILINEAR,
+};
+
+/**
+ * @SCALING_PIXELS: ratio in pixels
+ * @SCALING_RATIO: ratio in fixed point 16
+ */
+enum scaling_factor {
+ SCALING_PIXELS,
+ SCALING_RATIO,
+};
+
+/**
+ * premultiplied alpha
+ */
+enum premultiplied {
+ PREMULTIPLIED,
+ NON_PREMULTIPLIED,
+};
+
+/**
+ * @TRANSP: discard bluescreen color
+ * @BLUSCR: replace bluescreen color with background color
+ */
+enum bluescreen {
+ OPAQUE,
+ TRANSP,
+ BLUSCR,
+};
+
+/**
+ * DO NOT CHANGE THIS ORDER
+ */
+enum blit_op {
+ BLIT_OP_SOLID_FILL = 0,
+
+ BLIT_OP_CLR,
+ BLIT_OP_SRC, BLIT_OP_SRC_COPY = BLIT_OP_SRC,
+ BLIT_OP_DST,
+ BLIT_OP_SRC_OVER,
+ BLIT_OP_DST_OVER, BLIT_OP_OVER_REV = BLIT_OP_DST_OVER,
+ BLIT_OP_SRC_IN,
+ BLIT_OP_DST_IN, BLIT_OP_IN_REV = BLIT_OP_DST_IN,
+ BLIT_OP_SRC_OUT,
+ BLIT_OP_DST_OUT, BLIT_OP_OUT_REV = BLIT_OP_DST_OUT,
+ BLIT_OP_SRC_ATOP,
+ BLIT_OP_DST_ATOP, BLIT_OP_ATOP_REV = BLIT_OP_DST_ATOP,
+ BLIT_OP_XOR,
+
+ BLIT_OP_ADD,
+ BLIT_OP_MULTIPLY,
+ BLIT_OP_SCREEN,
+ BLIT_OP_DARKEN,
+ BLIT_OP_LIGHTEN,
+
+ BLIT_OP_DISJ_SRC_OVER,
+ BLIT_OP_DISJ_DST_OVER, BLIT_OP_SATURATE = BLIT_OP_DISJ_DST_OVER,
+ BLIT_OP_DISJ_SRC_IN,
+ BLIT_OP_DISJ_DST_IN, BLIT_OP_DISJ_IN_REV = BLIT_OP_DISJ_DST_IN,
+ BLIT_OP_DISJ_SRC_OUT,
+ BLIT_OP_DISJ_DST_OUT, BLIT_OP_DISJ_OUT_REV = BLIT_OP_DISJ_DST_OUT,
+ BLIT_OP_DISJ_SRC_ATOP,
+ BLIT_OP_DISJ_DST_ATOP, BLIT_OP_DISJ_ATOP_REV = BLIT_OP_DISJ_DST_ATOP,
+ BLIT_OP_DISJ_XOR,
+
+ BLIT_OP_CONJ_SRC_OVER,
+ BLIT_OP_CONJ_DST_OVER, BLIT_OP_CONJ_OVER_REV = BLIT_OP_CONJ_DST_OVER,
+ BLIT_OP_CONJ_SRC_IN,
+ BLIT_OP_CONJ_DST_IN, BLIT_OP_CONJ_IN_REV = BLIT_OP_CONJ_DST_IN,
+ BLIT_OP_CONJ_SRC_OUT,
+ BLIT_OP_CONJ_DST_OUT, BLIT_OP_CONJ_OUT_REV = BLIT_OP_CONJ_DST_OUT,
+ BLIT_OP_CONJ_SRC_ATOP,
+ BLIT_OP_CONJ_DST_ATOP, BLIT_OP_CONJ_ATOP_REV = BLIT_OP_CONJ_DST_ATOP,
+ BLIT_OP_CONJ_XOR,
+
+ /* user select coefficient manually */
+ BLIT_OP_USER_COEFF,
+
+ BLIT_OP_USER_SRC_GA,
+
+ /* Add new operation type here */
+
+ /* end of blit operation */
+ BLIT_OP_END,
+};
+#define MAX_FIMG2D_BLIT_OP (int)BLIT_OP_END
+
+#ifdef __KERNEL__
+
+/**
+ * @TMP: temporary buffer for 2-step blit at a single command
+ *
+ * DO NOT CHANGE THIS ORDER
+ */
+enum image_object {
+ IMAGE_SRC = 0,
+ IMAGE_MSK,
+ IMAGE_TMP,
+ IMAGE_DST,
+ IMAGE_END,
+};
+#define MAX_IMAGES IMAGE_END
+#define ISRC IMAGE_SRC
+#define IMSK IMAGE_MSK
+#define ITMP IMAGE_TMP
+#define IDST IMAGE_DST
+#define image_table(u) \
+ { \
+ (u)->src, \
+ (u)->msk, \
+ (u)->tmp, \
+ (u)->dst \
+ }
+
+/**
+ * @size: dma size of image
+ * @cached: cached dma size of image
+ */
+struct fimg2d_dma {
+ unsigned long addr;
+ size_t size;
+ size_t cached;
+};
+
+#endif /* __KERNEL__ */
+
+/**
+ * @start: start address or unique id of image
+ */
+struct fimg2d_addr {
+ enum addr_space type;
+ unsigned long start;
+};
+
+struct fimg2d_rect {
+ int x1;
+ int y1;
+ int x2; /* x1 + width */
+ int y2; /* y1 + height */
+};
+
+/**
+ * pixels can be different from src, dst or clip rect
+ */
+struct fimg2d_scale {
+ enum scaling mode;
+
+ /* ratio in pixels */
+ int src_w, src_h;
+ int dst_w, dst_h;
+};
+
+struct fimg2d_clip {
+ bool enable;
+ int x1;
+ int y1;
+ int x2; /* x1 + width */
+ int y2; /* y1 + height */
+};
+
+struct fimg2d_repeat {
+ enum repeat mode;
+ unsigned long pad_color;
+};
+
+/**
+ * @bg_color: bg_color is valid only if bluescreen mode is BLUSCR.
+ */
+struct fimg2d_bluscr {
+ enum bluescreen mode;
+ unsigned long bs_color;
+ unsigned long bg_color;
+};
+
+/**
+ * @plane2: address info for CbCr in YCbCr 2plane mode
+ * @rect: crop/clip rect
+ * @need_cacheopr: true if cache coherency is required
+ */
+struct fimg2d_image {
+ int width;
+ int height;
+ int stride;
+ enum pixel_order order;
+ enum color_format fmt;
+ struct fimg2d_addr addr;
+ struct fimg2d_addr plane2;
+ struct fimg2d_rect rect;
+ bool need_cacheopr;
+};
+
+/**
+ * @solid_color:
+ * src color instead of src image / dst color instead of dst read image.
+ * color format and order must be ARGB8888(A is MSB).
+ * premultiplied format must be same to 'premult' of this struct.
+ * @g_alpha: global(constant) alpha. 0xff is opaque, 0 is transparnet
+ * @dither: dithering
+ * @rotate: rotation degree in clockwise
+ * @premult: alpha premultiplied mode for read & write
+ * @scaling: common scaling info for src and mask image.
+ * @repeat: repeat type (tile mode)
+ * @bluscr: blue screen and transparent mode
+ */
+struct fimg2d_param {
+ unsigned long solid_color;
+ unsigned char g_alpha;
+ bool dither;
+ enum rotation rotate;
+ enum premultiplied premult;
+ struct fimg2d_scale scaling;
+ struct fimg2d_repeat repeat;
+ struct fimg2d_bluscr bluscr;
+};
+
+/**
+ * @op: blit operation mode
+ * @src: set when using src image
+ * @msk: set when using mask image
+ * @tmp: set when using 2-step blit at a single command
+ * @dst: dst must not be null
+ * * tmp image must be the same to dst except memory address
+ * @seq_no: user debugging info.
+ * for example, user can set sequence number or pid.
+ */
+struct fimg2d_blit {
+ enum blit_op op;
+ struct fimg2d_param param;
+ struct fimg2d_image *src;
+ struct fimg2d_image *msk;
+ struct fimg2d_image *tmp;
+ struct fimg2d_image *dst;
+ enum blit_sync sync;
+ unsigned int seq_no;
+};
+
+#ifdef __KERNEL__
+
+/**
+ * Enables definition to estimate performance.
+ * These debug codes includes printk, so perf
+ * data are unreliable under multi instance environment
+ */
+#undef PERF_PROFILE
+#define PERF_TIMEVAL
+
+enum perf_desc {
+ PERF_INNERCACHE,
+ PERF_OUTERCACHE,
+ PERF_BLIT,
+ PERF_END
+};
+#define MAX_PERF_DESCS PERF_END
+
+struct fimg2d_perf {
+ int valid;
+#ifdef PERF_TIMEVAL
+ struct timeval start;
+ struct timeval end;
+#else
+ unsigned long long start;
+ unsigned long long end;
+#endif
+};
+
+/**
+ * @pgd: base address of arm mmu pagetable
+ * @ncmd: request count in blit command queue
+ * @wait_q: conext wait queue head
+*/
+struct fimg2d_context {
+ struct mm_struct *mm;
+ atomic_t ncmd;
+ wait_queue_head_t wait_q;
+ struct fimg2d_perf perf[MAX_PERF_DESCS];
+};
+
+/**
+ * @op: blit operation mode
+ * @sync: sync/async blit mode (currently support sync mode only)
+ * @image: array of image object.
+ * [0] is for src image
+ * [1] is for mask image
+ * [2] is for temporary buffer
+ * set when using 2-step blit at a single command
+ * [3] is for dst, dst must not be null
+ * * tmp image must be the same to dst except memory address
+ * @seq_no: user debugging info.
+ * for example, user can set sequence number or pid.
+ * @dma_all: total dma size of src, msk, dst
+ * @dma: array of dma info for each src, msk, tmp and dst
+ * @ctx: context is created when user open fimg2d device.
+ * @node: list head of blit command queue
+ */
+struct fimg2d_bltcmd {
+ enum blit_op op;
+ enum blit_sync sync;
+ unsigned int seq_no;
+ size_t dma_all;
+ struct fimg2d_param param;
+ struct fimg2d_image image[MAX_IMAGES];
+ struct fimg2d_dma dma[MAX_IMAGES];
+ struct fimg2d_context *ctx;
+ struct list_head node;
+};
+
+/**
+ * @suspended: in suspend mode
+ * @clkon: power status for runtime pm
+ * @mem: resource platform device
+ * @regs: base address of hardware
+ * @dev: pointer to device struct
+ * @err: true if hardware is timed out while blitting
+ * @irq: irq number
+ * @nctx: context count
+ * @busy: 1 if hardware is running
+ * @bltlock: spinlock for blit
+ * @wait_q: blit wait queue head
+ * @cmd_q: blit command queue
+ * @workqueue: workqueue_struct for kfimg2dd
+*/
+struct fimg2d_control {
+ atomic_t suspended;
+ atomic_t clkon;
+ struct clk *clock;
+ struct device *dev;
+ struct resource *mem;
+ void __iomem *regs;
+
+ bool err;
+ int irq;
+ atomic_t nctx;
+ atomic_t busy;
+ atomic_t active;
+ spinlock_t bltlock;
+ wait_queue_head_t wait_q;
+ struct list_head cmd_q;
+ struct workqueue_struct *work_q;
+
+ void (*blit)(struct fimg2d_control *info);
+ void (*configure)(struct fimg2d_control *info, struct fimg2d_bltcmd *cmd);
+ void (*run)(struct fimg2d_control *info);
+ void (*stop)(struct fimg2d_control *info);
+ void (*dump)(struct fimg2d_control *info);
+ void (*finalize)(struct fimg2d_control *info);
+};
+
+int fimg2d_register_ops(struct fimg2d_control *info);
+
+#endif /* __KERNEL__ */
+
+#endif /* __FIMG2D_H__ */
diff --git a/drivers/media/video/exynos/fimg2d/fimg2d4x.h b/drivers/media/video/exynos/fimg2d/fimg2d4x.h
new file mode 100644
index 0000000..0b1070c
--- /dev/null
+++ b/drivers/media/video/exynos/fimg2d/fimg2d4x.h
@@ -0,0 +1,201 @@
+/* linux/drivers/media/video/samsung/fimg2d4x/fimg2d4x.h
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Samsung Graphics 2D driver
+ *
+ * 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.
+*/
+
+#ifndef __FIMG2D4X_H
+#define __FIMG2D4X_H __FILE__
+
+#include "fimg2d4x_regs.h"
+
+/**
+ * @IMG_MEMORY: read from external memory
+ * @IMG_FGCOLOR: read from foreground color
+ * @IMG_BGCOLOR: read from background color
+ */
+enum image_sel {
+ IMG_MEMORY,
+ IMG_FGCOLOR,
+ IMG_BGCOLOR,
+};
+
+/**
+ * @FORWARD_ADDRESSING: read data in forward direction
+ * @REVERSE_ADDRESSING: read data in reverse direction
+ */
+enum addressing {
+ FORWARD_ADDRESSING,
+ REVERSE_ADDRESSING,
+};
+
+/**
+ * The other addressing modes can cause data corruption,
+ * if src and dst are overlapped.
+ */
+enum dir_addressing {
+ UP_FORWARD,
+ DOWN_REVERSE,
+ LEFT_FORWARD,
+ RIGHT_REVERSE,
+ VALID_ADDRESSING_END,
+};
+
+/**
+ * DO NOT CHANGE THIS ORDER
+ */
+enum max_burst_len {
+ MAX_BURST_2 = 0,
+ MAX_BURST_4,
+ MAX_BURST_8, /* initial value */
+ MAX_BURST_16,
+};
+
+#define DEFAULT_MAX_BURST_LEN MAX_BURST_8
+
+/**
+ * mask operation type for 16-bpp, 32-bpp mask image
+ * @MSK_ALPHA: use mask alpha for src argb
+ * @MSK_ARGB: use mask argb for src argb
+ * @MSK_MIXED: use mask alpha for src alpha and mask rgb for src rgb
+ */
+enum mask_opr {
+ MSK_ALPHA, /* initial value */
+ MSK_ARGB,
+ MSK_MIXED,
+};
+
+#define DEFAULT_MSK_OPR MSK_ALPHA
+
+/**
+ * @ALPHA_PERPIXEL: perpixel alpha
+ * @ALPHA_PERPIXEL_SUM_GLOBAL: perpixel + global
+ * @ALPHA_PERPIXEL_MUL_GLOBAL: perpixel x global
+ *
+ * DO NOT CHANGE THIS ORDER
+ */
+enum alpha_opr {
+ ALPHA_PERPIXEL = 0, /* initial value */
+ ALPHA_PERPIXEL_SUM_GLOBAL,
+ ALPHA_PERPIXEL_MUL_GLOBAL,
+};
+
+#define DEFAULT_ALPHA_OPR ALPHA_PERPIXEL
+
+/**
+ * @COEFF_ONE: 1
+ * @COEFF_ZERO: 0
+ * @COEFF_SA: src alpha
+ * @COEFF_SC: src color
+ * @COEFF_DA: dst alpha
+ * @COEFF_DC: dst color
+ * @COEFF_GA: global(constant) alpha
+ * @COEFF_GC: global(constant) color
+ * @COEFF_DISJ_S:
+ * @COEFF_DISJ_D:
+ * @COEFF_CONJ_S:
+ * @COEFF_CONJ_D:
+ *
+ * DO NOT CHANGE THIS ORDER
+ */
+enum fimg2d_coeff {
+ COEFF_ONE = 0,
+ COEFF_ZERO,
+ COEFF_SA,
+ COEFF_SC,
+ COEFF_DA,
+ COEFF_DC,
+ COEFF_GA,
+ COEFF_GC,
+ COEFF_DISJ_S,
+ COEFF_DISJ_D,
+ COEFF_CONJ_S,
+ COEFF_CONJ_D,
+};
+
+/**
+ * @PREMULT_ROUND_0: (A*B) >> 8
+ * @PREMULT_ROUND_1: (A+1)*B) >> 8
+ * @PREMULT_ROUND_2: (A+(A>>7))* B) >> 8
+ * @PREMULT_ROUND_3: TMP= A*8 + 0x80, (TMP + (TMP >> 8)) >> 8
+ *
+ * DO NOT CHANGE THIS ORDER
+ */
+enum premult_round {
+ PREMULT_ROUND_0 = 0,
+ PREMULT_ROUND_1,
+ PREMULT_ROUND_2,
+ PREMULT_ROUND_3, /* initial value */
+};
+
+#define DEFAULT_PREMULT_ROUND_MODE PREMULT_ROUND_3
+
+/**
+ * @BLEND_ROUND_0: (A+1)*B) >> 8
+ * @BLEND_ROUND_1: (A+(A>>7))* B) >> 8
+ * @BLEND_ROUND_2: TMP= A*8 + 0x80, (TMP + (TMP >> 8)) >> 8
+ * @BLEND_ROUND_3: TMP= (A*B + C*D + 0x80), (TMP + (TMP >> 8)) >> 8
+ *
+ * DO NOT CHANGE THIS ORDER
+ */
+enum blend_round {
+ BLEND_ROUND_0 = 0,
+ BLEND_ROUND_1,
+ BLEND_ROUND_2,
+ BLEND_ROUND_3, /* initial value */
+};
+
+#define DEFAULT_BLEND_ROUND_MODE BLEND_ROUND_3
+
+struct fimg2d_blend_coeff {
+ bool s_coeff_inv;
+ enum fimg2d_coeff s_coeff;
+ bool d_coeff_inv;
+ enum fimg2d_coeff d_coeff;
+};
+
+void fimg2d4x_reset(struct fimg2d_control *info);
+void fimg2d4x_enable_irq(struct fimg2d_control *info);
+void fimg2d4x_disable_irq(struct fimg2d_control *info);
+void fimg2d4x_clear_irq(struct fimg2d_control *info);
+int fimg2d4x_is_blit_done(struct fimg2d_control *info);
+int fimg2d4x_blit_done_status(struct fimg2d_control *info);
+void fimg2d4x_start_blit(struct fimg2d_control *info);
+void fimg2d4x_set_max_burst_length(struct fimg2d_control *info, enum max_burst_len len);
+void fimg2d4x_set_src_type(struct fimg2d_control *info, enum image_sel type);
+void fimg2d4x_set_src_image(struct fimg2d_control *info, struct fimg2d_image *s);
+void fimg2d4x_set_src_rect(struct fimg2d_control *info, struct fimg2d_rect *r);
+void fimg2d4x_set_dst_type(struct fimg2d_control *info, enum image_sel type);
+void fimg2d4x_set_dst_image(struct fimg2d_control *info, struct fimg2d_image *d);
+void fimg2d4x_set_dst_rect(struct fimg2d_control *info, struct fimg2d_rect *r);
+void fimg2d4x_enable_msk(struct fimg2d_control *info);
+void fimg2d4x_set_msk_image(struct fimg2d_control *info, struct fimg2d_image *m);
+void fimg2d4x_set_msk_rect(struct fimg2d_control *info, struct fimg2d_rect *r);
+void fimg2d4x_set_color_fill(struct fimg2d_control *info, unsigned long color);
+void fimg2d4x_set_premultiplied(struct fimg2d_control *info);
+void fimg2d4x_src_premultiply(struct fimg2d_control *info);
+void fimg2d4x_dst_premultiply(struct fimg2d_control *info);
+void fimg2d4x_dst_depremultiply(struct fimg2d_control *info);
+void fimg2d4x_enable_transparent(struct fimg2d_control *info);
+void fimg2d4x_set_bluescreen(struct fimg2d_control *info, struct fimg2d_bluscr *bluscr);
+void fimg2d4x_enable_clipping(struct fimg2d_control *info, struct fimg2d_rect *c);
+void fimg2d4x_enable_dithering(struct fimg2d_control *info);
+void fimg2d4x_set_src_scaling(struct fimg2d_control *info, struct fimg2d_scale *s);
+void fimg2d4x_set_msk_scaling(struct fimg2d_control *info, struct fimg2d_scale *s);
+void fimg2d4x_set_src_repeat(struct fimg2d_control *info, struct fimg2d_repeat *r);
+void fimg2d4x_set_msk_repeat(struct fimg2d_control *info, struct fimg2d_repeat *r);
+void fimg2d4x_set_rotation(struct fimg2d_control *info, enum rotation rot);
+void fimg2d4x_set_fgcolor(struct fimg2d_control *info, unsigned long fg);
+void fimg2d4x_set_bgcolor(struct fimg2d_control *info, unsigned long bg);
+void fimg2d4x_enable_alpha(struct fimg2d_control *info, unsigned char g_alpha);
+void fimg2d4x_set_alpha_composite(struct fimg2d_control *info,
+ enum blit_op op, unsigned char g_alpha);
+void fimg2d4x_dump_regs(struct fimg2d_control *info);
+
+#endif /* __FIMG2D4X_H__ */
diff --git a/drivers/media/video/exynos/fimg2d/fimg2d4x_blt.c b/drivers/media/video/exynos/fimg2d/fimg2d4x_blt.c
new file mode 100644
index 0000000..734da50
--- /dev/null
+++ b/drivers/media/video/exynos/fimg2d/fimg2d4x_blt.c
@@ -0,0 +1,319 @@
+/* linux/drivers/media/video/samsung/fimg2d4x/fimg2d4x_blt.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Samsung Graphics 2D driver
+ *
+ * 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.
+*/
+
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
+#include <linux/atomic.h>
+#include <linux/dma-mapping.h>
+#include <asm/cacheflush.h>
+#include <plat/sysmmu.h>
+#ifdef CONFIG_PM_RUNTIME
+#include <plat/devs.h>
+#include <linux/pm_runtime.h>
+#endif
+#include "fimg2d.h"
+#include "fimg2d_clk.h"
+#include "fimg2d4x.h"
+#include "fimg2d_ctx.h"
+#include "fimg2d_cache.h"
+#include "fimg2d_helper.h"
+
+#define BLIT_TIMEOUT msecs_to_jiffies(2000)
+
+static inline void fimg2d4x_blit_wait(struct fimg2d_control *info, struct fimg2d_bltcmd *cmd)
+{
+ if (!wait_event_timeout(info->wait_q, !atomic_read(&info->busy), BLIT_TIMEOUT)) {
+ printk(KERN_ERR "[%s] blit wait timeout\n", __func__);
+ fimg2d_dump_command(cmd);
+
+ if (!fimg2d4x_blit_done_status(info))
+ info->err = true; /* device error */
+ }
+}
+
+static void fimg2d4x_pre_bitblt(struct fimg2d_control *info, struct fimg2d_bltcmd *cmd)
+{
+ /* TODO */
+}
+
+void fimg2d4x_bitblt(struct fimg2d_control *info)
+{
+ struct fimg2d_context *ctx;
+ struct fimg2d_bltcmd *cmd;
+ unsigned long *pgd;
+
+ fimg2d_debug("enter blitter\n");
+
+#ifdef CONFIG_PM_RUNTIME
+ pm_runtime_get_sync(info->dev);
+ fimg2d_debug("pm_runtime_get_sync\n");
+#endif
+ fimg2d_clk_on(info);
+
+ while ((cmd = fimg2d_get_first_command(info))) {
+ ctx = cmd->ctx;
+ if (info->err) {
+ printk(KERN_ERR "[%s] device error\n", __func__);
+ goto blitend;
+ }
+
+ atomic_set(&info->busy, 1);
+
+ info->configure(info, cmd);
+
+ if (cmd->image[IDST].addr.type != ADDR_PHYS) {
+ pgd = (unsigned long *)ctx->mm->pgd;
+ exynos_sysmmu_enable(info->dev, (unsigned long)virt_to_phys(pgd));
+ fimg2d_debug("sysmmu enable: pgd %p ctx %p seq_no(%u)\n",
+ pgd, ctx, cmd->seq_no);
+ }
+
+ fimg2d4x_pre_bitblt(info, cmd);
+
+#ifdef PERF_PROFILE
+ perf_start(cmd->ctx, PERF_BLIT);
+#endif
+ /* start blit */
+ info->run(info);
+ fimg2d4x_blit_wait(info, cmd);
+
+#ifdef PERF_PROFILE
+ perf_end(cmd->ctx, PERF_BLIT);
+#endif
+ if (cmd->image[IDST].addr.type != ADDR_PHYS) {
+ exynos_sysmmu_disable(info->dev);
+ fimg2d_debug("sysmmu disable\n");
+ }
+blitend:
+ spin_lock(&info->bltlock);
+ fimg2d_dequeue(&cmd->node);
+ kfree(cmd);
+ atomic_dec(&ctx->ncmd);
+
+ /* wake up context */
+ if (!atomic_read(&ctx->ncmd))
+ wake_up(&ctx->wait_q);
+ spin_unlock(&info->bltlock);
+ }
+
+ atomic_set(&info->active, 0);
+
+ fimg2d_clk_off(info);
+#ifdef CONFIG_PM_RUNTIME
+ pm_runtime_put_sync(info->dev);
+ fimg2d_debug("pm_runtime_put_sync\n");
+#endif
+
+ fimg2d_debug("exit blitter\n");
+}
+
+static int fast_op(struct fimg2d_bltcmd *cmd)
+{
+ int sa, da, ga;
+ int fop = cmd->op;
+ struct fimg2d_image *sm, *dm;
+ struct fimg2d_param *p = &cmd->param;
+
+ if (cmd->image[IMSK].addr.type != ADDR_NONE)
+ return fop;
+
+ sm = &cmd->image[ISRC];
+ dm = &cmd->image[IDST];
+
+ if (sm->addr.type == ADDR_NONE)
+ sa = (p->solid_color >> 24) & 0xff;
+ else
+ sa = is_opaque(sm->fmt) ? 0xff : 0;
+
+ da = is_opaque(dm->fmt) ? 0xff : 0;
+ ga = p->g_alpha;
+
+ switch (cmd->op) {
+ case BLIT_OP_SOLID_FILL:
+ case BLIT_OP_CLR:
+ case BLIT_OP_SRC:
+ case BLIT_OP_DST:
+ break;
+ case BLIT_OP_SRC_OVER:
+ /* Sc + (1-Sa)*Dc = Sc */
+ if (sa == 0xff && ga == 0xff)
+ fop = BLIT_OP_SRC;
+ break;
+ case BLIT_OP_DST_OVER:
+ /* (1-Da)*Sc + Dc = Dc */
+ if (da == 0xff)
+ fop = BLIT_OP_DST;
+ break;
+ case BLIT_OP_SRC_IN:
+ /* Da*Sc = Sc */
+ if (da == 0xff)
+ fop = BLIT_OP_SRC;
+ break;
+ case BLIT_OP_DST_IN:
+ /* Sa*Dc = Dc */
+ if (sa == 0xff && ga == 0xff)
+ fop = BLIT_OP_DST;
+ break;
+ case BLIT_OP_SRC_OUT:
+ /* (1-Da)*Sc = 0 */
+ if (da == 0xff)
+ fop = BLIT_OP_CLR;
+ break;
+ case BLIT_OP_DST_OUT:
+ /* (1-Sa)*Dc = 0 */
+ if (sa == 0xff && ga == 0xff)
+ fop = BLIT_OP_CLR;
+ break;
+ case BLIT_OP_SRC_ATOP:
+ /* Da*Sc + (1-Sa)*Dc = Sc */
+ if (sa == 0xff && da == 0xff && ga == 0xff)
+ fop = BLIT_OP_SRC;
+ break;
+ case BLIT_OP_DST_ATOP:
+ /* (1-Da)*Sc + Sa*Dc = Dc */
+ if (sa == 0xff && da == 0xff && ga == 0xff)
+ fop = BLIT_OP_DST;
+ break;
+ default:
+ break;
+ }
+
+ if (fop == BLIT_OP_SRC) {
+ if (sm->addr.type == ADDR_NONE && sa == 0xff && ga == 0xff)
+ fop = BLIT_OP_SOLID_FILL;
+ }
+
+ return fop;
+}
+
+static void fimg2d4x_configure(struct fimg2d_control *info, struct fimg2d_bltcmd *cmd)
+{
+ int op;
+ enum image_sel srcsel, dstsel;
+ struct fimg2d_param *p = &cmd->param;
+
+ fimg2d_debug("ctx %p seq_no(%u)\n", cmd->ctx, cmd->seq_no);
+
+ /* TODO: batch blit */
+ fimg2d4x_reset(info);
+
+ /* src and dst select */
+ srcsel = dstsel = IMG_MEMORY;
+
+ op = fast_op(cmd);
+
+ switch (op) {
+ case BLIT_OP_SOLID_FILL:
+ srcsel = dstsel = IMG_FGCOLOR;
+ fimg2d4x_set_color_fill(info, p->solid_color);
+ break;
+ case BLIT_OP_CLR:
+ srcsel = dstsel = IMG_FGCOLOR;
+ fimg2d4x_set_color_fill(info, 0);
+ break;
+ case BLIT_OP_DST:
+ srcsel = IMG_FGCOLOR;
+ break;
+ default:
+ if (cmd->image[ISRC].addr.type == ADDR_NONE) {
+ srcsel = IMG_FGCOLOR;
+ fimg2d4x_set_fgcolor(info, p->solid_color);
+ }
+
+ if (op == BLIT_OP_SRC)
+ dstsel = IMG_FGCOLOR;
+
+ fimg2d4x_enable_alpha(info, p->g_alpha);
+ fimg2d4x_set_alpha_composite(info, op, p->g_alpha);
+ if (p->premult == NON_PREMULTIPLIED)
+ fimg2d4x_set_premultiplied(info);
+ break;
+ }
+
+ fimg2d4x_set_src_type(info, srcsel);
+ fimg2d4x_set_dst_type(info, dstsel);
+
+ /* src */
+ if (cmd->image[ISRC].addr.type != ADDR_NONE) {
+ fimg2d4x_set_src_image(info, &cmd->image[ISRC]);
+ fimg2d4x_set_src_rect(info, &cmd->image[ISRC].rect);
+ fimg2d4x_set_src_repeat(info, &p->repeat);
+ if (p->scaling.mode != NO_SCALING)
+ fimg2d4x_set_src_scaling(info, &p->scaling);
+ }
+
+ /* msk */
+ if (cmd->image[IMSK].addr.type != ADDR_NONE) {
+ fimg2d4x_enable_msk(info);
+ fimg2d4x_set_msk_image(info, &cmd->image[IMSK]);
+ fimg2d4x_set_msk_rect(info, &cmd->image[IMSK].rect);
+ fimg2d4x_set_msk_repeat(info, &p->repeat);
+ if (p->scaling.mode != NO_SCALING)
+ fimg2d4x_set_msk_scaling(info, &p->scaling);
+ }
+
+ /* dst */
+ if (cmd->image[IDST].addr.type != ADDR_NONE) {
+ fimg2d4x_set_dst_image(info, &cmd->image[IDST]);
+ fimg2d4x_set_dst_rect(info, &cmd->image[IDST].rect);
+ fimg2d4x_enable_clipping(info, &cmd->image[IDST].rect);
+ }
+
+ /* bluescreen */
+ if (p->bluscr.mode != OPAQUE)
+ fimg2d4x_set_bluescreen(info, &p->bluscr);
+
+ /* rotation */
+ if (p->rotate != ORIGIN)
+ fimg2d4x_set_rotation(info, p->rotate);
+
+ /* dithering */
+ if (p->dither)
+ fimg2d4x_enable_dithering(info);
+}
+
+static void fimg2d4x_run(struct fimg2d_control *info)
+{
+ fimg2d_debug("start blit\n");
+ fimg2d4x_enable_irq(info);
+ fimg2d4x_clear_irq(info);
+ fimg2d4x_start_blit(info);
+}
+
+static void fimg2d4x_stop(struct fimg2d_control *info)
+{
+ if (fimg2d4x_is_blit_done(info)) {
+ fimg2d_debug("blit done\n");
+ fimg2d4x_disable_irq(info);
+ fimg2d4x_clear_irq(info);
+ atomic_set(&info->busy, 0);
+ wake_up(&info->wait_q);
+ }
+}
+
+static void fimg2d4x_dump(struct fimg2d_control *info)
+{
+ fimg2d4x_dump_regs(info);
+}
+
+int fimg2d_register_ops(struct fimg2d_control *info)
+{
+ info->blit = fimg2d4x_bitblt;
+ info->configure = fimg2d4x_configure;
+ info->run = fimg2d4x_run;
+ info->dump = fimg2d4x_dump;
+ info->stop = fimg2d4x_stop;
+
+ return 0;
+}
diff --git a/drivers/media/video/exynos/fimg2d/fimg2d4x_hw.c b/drivers/media/video/exynos/fimg2d/fimg2d4x_hw.c
new file mode 100644
index 0000000..7a5b181
--- /dev/null
+++ b/drivers/media/video/exynos/fimg2d/fimg2d4x_hw.c
@@ -0,0 +1,822 @@
+/* linux/drivers/media/video/samsung/fimg2d4x/fimg2d4x_hw.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Samsung Graphics 2D driver
+ *
+ * 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.
+*/
+
+#include <linux/io.h>
+#include <linux/sched.h>
+
+#include "fimg2d.h"
+#include "fimg2d4x.h"
+#include "fimg2d_clk.h"
+
+#undef SOFT_RESET_ENABLED
+#undef FIMG2D_RESET_WA
+
+static const int a8_rgbcolor = (int)0x0;
+static const int msk_oprmode = (int)MSK_ARGB;
+static const int premult_round_mode = (int)PREMULT_ROUND_1; /* (A+1)*B) >> 8 */
+static const int blend_round_mode = (int)BLEND_ROUND_0; /* (A+1)*B) >> 8 */
+
+void fimg2d4x_reset(struct fimg2d_control *info)
+{
+#ifdef SOFT_RESET_ENABLED
+#ifdef FIMG2D_RESET_WA
+ fimg2d_clk_save(info);
+#endif
+ writel(FIMG2D_SOFT_RESET, info->regs + FIMG2D_SOFT_RESET_REG);
+#ifdef FIMG2D_RESET_WA
+ fimg2d_clk_restore(info);
+#endif
+#else
+ writel(FIMG2D_SFR_CLEAR, info->regs + FIMG2D_SOFT_RESET_REG);
+#endif
+ /* turn off wince option */
+ writel(0x0, info->regs + FIMG2D_BLEND_FUNCTION_REG);
+
+ /* set default repeat mode to clamp */
+ writel(FIMG2D_SRC_REPEAT_CLAMP, info->regs + FIMG2D_SRC_REPEAT_MODE_REG);
+ writel(FIMG2D_MSK_REPEAT_CLAMP, info->regs + FIMG2D_MSK_REPEAT_MODE_REG);
+}
+
+void fimg2d4x_enable_irq(struct fimg2d_control *info)
+{
+ writel(FIMG2D_BLIT_INT_ENABLE, info->regs + FIMG2D_INTEN_REG);
+}
+
+void fimg2d4x_disable_irq(struct fimg2d_control *info)
+{
+ writel(0, info->regs + FIMG2D_INTEN_REG);
+}
+
+void fimg2d4x_clear_irq(struct fimg2d_control *info)
+{
+ writel(FIMG2D_BLIT_INT_FLAG, info->regs + FIMG2D_INTC_PEND_REG);
+}
+
+int fimg2d4x_is_blit_done(struct fimg2d_control *info)
+{
+ return readl(info->regs + FIMG2D_INTC_PEND_REG) & FIMG2D_BLIT_INT_FLAG;
+}
+
+int fimg2d4x_blit_done_status(struct fimg2d_control *info)
+{
+ volatile unsigned long sts;
+
+ /* read twice */
+ sts = readl(info->regs + FIMG2D_FIFO_STAT_REG);
+ sts = readl(info->regs + FIMG2D_FIFO_STAT_REG);
+
+ return (int)(sts & FIMG2D_BLIT_FINISHED);
+}
+
+void fimg2d4x_start_blit(struct fimg2d_control *info)
+{
+ writel(FIMG2D_START_BITBLT, info->regs + FIMG2D_BITBLT_START_REG);
+}
+
+void fimg2d4x_set_max_burst_length(struct fimg2d_control *info, enum max_burst_len len)
+{
+ unsigned long cfg;
+
+ cfg = readl(info->regs + FIMG2D_AXI_MODE_REG);
+
+ cfg &= ~FIMG2D_MAX_BURST_LEN_MASK;
+ cfg |= len << FIMG2D_MAX_BURST_LEN_SHIFT;
+}
+
+void fimg2d4x_set_src_type(struct fimg2d_control *info, enum image_sel type)
+{
+ unsigned long cfg;
+
+ if (type == IMG_MEMORY)
+ cfg = FIMG2D_IMAGE_TYPE_MEMORY;
+ else if (type == IMG_FGCOLOR)
+ cfg = FIMG2D_IMAGE_TYPE_FGCOLOR;
+ else
+ cfg = FIMG2D_IMAGE_TYPE_BGCOLOR;
+
+ writel(cfg, info->regs + FIMG2D_SRC_SELECT_REG);
+}
+
+void fimg2d4x_set_src_image(struct fimg2d_control *info, struct fimg2d_image *s)
+{
+ unsigned long cfg;
+
+ writel(FIMG2D_ADDR(s->addr.start), info->regs + FIMG2D_SRC_BASE_ADDR_REG);
+ writel(FIMG2D_STRIDE(s->stride), info->regs + FIMG2D_SRC_STRIDE_REG);
+
+ if (s->order < ARGB_ORDER_END) { /* argb */
+ cfg = s->order << FIMG2D_RGB_ORDER_SHIFT;
+ if (s->fmt == CF_A8)
+ writel(a8_rgbcolor, info->regs + FIMG2D_SRC_A8_RGB_EXT_REG);
+ } else if (s->order < P1_ORDER_END) { /* YCbC1 1plane */
+ cfg = (s->order - P1_CRY1CBY0) << FIMG2D_YCBCR_ORDER_SHIFT;
+ } else { /* YCbCr 2plane */
+ cfg = (s->order - P2_CRCB) << FIMG2D_YCBCR_ORDER_SHIFT;
+ cfg |= FIMG2D_YCBCR_2PLANE;
+
+ writel(FIMG2D_ADDR(s->plane2.start),
+ info->regs + FIMG2D_SRC_PLANE2_BASE_ADDR_REG);
+ }
+
+ cfg |= s->fmt << FIMG2D_COLOR_FORMAT_SHIFT;
+
+ writel(cfg, info->regs + FIMG2D_SRC_COLOR_MODE_REG);
+}
+
+void fimg2d4x_set_src_rect(struct fimg2d_control *info, struct fimg2d_rect *r)
+{
+ writel(FIMG2D_OFFSET(r->x1, r->y1), info->regs + FIMG2D_SRC_LEFT_TOP_REG);
+ writel(FIMG2D_OFFSET(r->x2, r->y2), info->regs + FIMG2D_SRC_RIGHT_BOTTOM_REG);
+}
+
+void fimg2d4x_set_dst_type(struct fimg2d_control *info, enum image_sel type)
+{
+ unsigned long cfg;
+
+ if (type == IMG_MEMORY)
+ cfg = FIMG2D_IMAGE_TYPE_MEMORY;
+ else if (type == IMG_FGCOLOR)
+ cfg = FIMG2D_IMAGE_TYPE_FGCOLOR;
+ else
+ cfg = FIMG2D_IMAGE_TYPE_BGCOLOR;
+
+ writel(cfg, info->regs + FIMG2D_DST_SELECT_REG);
+}
+
+/**
+ * @d: set base address, stride, color format, order
+*/
+void fimg2d4x_set_dst_image(struct fimg2d_control *info, struct fimg2d_image *d)
+{
+ unsigned long cfg;
+
+ writel(FIMG2D_ADDR(d->addr.start), info->regs + FIMG2D_DST_BASE_ADDR_REG);
+ writel(FIMG2D_STRIDE(d->stride), info->regs + FIMG2D_DST_STRIDE_REG);
+
+ if (d->order < ARGB_ORDER_END) {
+ cfg = d->order << FIMG2D_RGB_ORDER_SHIFT;
+ if (d->fmt == CF_A8)
+ writel(a8_rgbcolor, info->regs + FIMG2D_DST_A8_RGB_EXT_REG);
+ } else if (d->order < P1_ORDER_END) {
+ cfg = (d->order - P1_CRY1CBY0) << FIMG2D_YCBCR_ORDER_SHIFT;
+ } else {
+ cfg = (d->order - P2_CRCB) << FIMG2D_YCBCR_ORDER_SHIFT;
+ cfg |= FIMG2D_YCBCR_2PLANE;
+
+ writel(FIMG2D_ADDR(d->plane2.start),
+ info->regs + FIMG2D_DST_PLANE2_BASE_ADDR_REG);
+ }
+
+ cfg |= d->fmt << FIMG2D_COLOR_FORMAT_SHIFT;
+
+ writel(cfg, info->regs + FIMG2D_DST_COLOR_MODE_REG);
+}
+
+void fimg2d4x_set_dst_rect(struct fimg2d_control *info, struct fimg2d_rect *r)
+{
+ writel(FIMG2D_OFFSET(r->x1, r->y1), info->regs + FIMG2D_DST_LEFT_TOP_REG);
+ writel(FIMG2D_OFFSET(r->x2, r->y2), info->regs + FIMG2D_DST_RIGHT_BOTTOM_REG);
+}
+
+void fimg2d4x_enable_msk(struct fimg2d_control *info)
+{
+ unsigned long cfg;
+
+ cfg = readl(info->regs + FIMG2D_BITBLT_COMMAND_REG);
+ cfg |= FIMG2D_ENABLE_NORMAL_MSK;
+
+ writel(cfg, info->regs + FIMG2D_BITBLT_COMMAND_REG);
+}
+
+void fimg2d4x_set_msk_image(struct fimg2d_control *info, struct fimg2d_image *m)
+{
+ unsigned long cfg;
+
+ writel(FIMG2D_ADDR(m->addr.start), info->regs + FIMG2D_MSK_BASE_ADDR_REG);
+ writel(FIMG2D_STRIDE(m->stride), info->regs + FIMG2D_MSK_STRIDE_REG);
+
+ cfg = m->order << FIMG2D_MSK_ORDER_SHIFT;
+ cfg |= (m->fmt - CF_MSK_1BIT) << FIMG2D_MSK_FORMAT_SHIFT;
+
+ /* 16, 32bit mask only */
+ if (m->fmt >= CF_MSK_16BIT_565) {
+ if (msk_oprmode == MSK_ALPHA)
+ cfg |= FIMG2D_MSK_TYPE_ALPHA;
+ else if (msk_oprmode == MSK_ARGB)
+ cfg |= FIMG2D_MSK_TYPE_ARGB;
+ else
+ cfg |= FIMG2D_MSK_TYPE_MIXED;
+ }
+
+ writel(cfg, info->regs + FIMG2D_MSK_MODE_REG);
+}
+
+void fimg2d4x_set_msk_rect(struct fimg2d_control *info, struct fimg2d_rect *r)
+{
+ writel(FIMG2D_OFFSET(r->x1, r->y1), info->regs + FIMG2D_MSK_LEFT_TOP_REG);
+ writel(FIMG2D_OFFSET(r->x2, r->y2), info->regs + FIMG2D_MSK_RIGHT_BOTTOM_REG);
+}
+
+/**
+ * If solid color fill is enabled, other blit command is ignored.
+ * Color format of solid color is considered to be
+ * the same as destination color format
+ * Channel order of solid color is A-R-G-B or Y-Cb-Cr
+ */
+void fimg2d4x_set_color_fill(struct fimg2d_control *info, unsigned long color)
+{
+ writel(FIMG2D_SOLID_FILL, info->regs + FIMG2D_BITBLT_COMMAND_REG);
+
+ /* sf color */
+ writel(color, info->regs + FIMG2D_SF_COLOR_REG);
+
+ /* set 16 burst for performance */
+ fimg2d4x_set_max_burst_length(info, MAX_BURST_16);
+}
+
+/**
+ * set alpha-multiply mode for src, dst, pat read (pre-bitblt)
+ * set alpha-demultiply for dst write (post-bitblt)
+ */
+void fimg2d4x_set_premultiplied(struct fimg2d_control *info)
+{
+ unsigned long cfg;
+
+ cfg = readl(info->regs + FIMG2D_BITBLT_COMMAND_REG);
+ cfg |= FIMG2D_PREMULT_ALL;
+
+ writel(cfg, info->regs + FIMG2D_BITBLT_COMMAND_REG);
+}
+
+void fimg2d4x_src_premultiply(struct fimg2d_control *info)
+{
+ unsigned long cfg;
+
+ cfg = readl(info->regs + FIMG2D_BITBLT_COMMAND_REG);
+ cfg |= FIMG2D_SRC_PREMULT;
+
+ writel(cfg, info->regs + FIMG2D_BITBLT_COMMAND_REG);
+}
+
+void fimg2d4x_dst_premultiply(struct fimg2d_control *info)
+{
+ unsigned long cfg;
+
+ cfg = readl(info->regs + FIMG2D_BITBLT_COMMAND_REG);
+ cfg |= FIMG2D_DST_RD_PREMULT;
+
+ writel(cfg, info->regs + FIMG2D_BITBLT_COMMAND_REG);
+}
+
+void fimg2d4x_dst_depremultiply(struct fimg2d_control *info)
+{
+ unsigned long cfg;
+
+ cfg = readl(info->regs + FIMG2D_BITBLT_COMMAND_REG);
+ cfg |= FIMG2D_DST_WR_DEPREMULT;
+
+ writel(cfg, info->regs + FIMG2D_BITBLT_COMMAND_REG);
+}
+
+/**
+ * set transp/bluscr mode, bs color, bg color
+ */
+void fimg2d4x_set_bluescreen(struct fimg2d_control *info,
+ struct fimg2d_bluscr *bluscr)
+{
+ unsigned long cfg;
+
+ cfg = readl(info->regs + FIMG2D_BITBLT_COMMAND_REG);
+
+ if (bluscr->mode == TRANSP)
+ cfg |= FIMG2D_TRANSP_MODE;
+ else if (bluscr->mode == BLUSCR)
+ cfg |= FIMG2D_BLUSCR_MODE;
+ else /* opaque: initial value */
+ return;
+
+ writel(cfg, info->regs + FIMG2D_BITBLT_COMMAND_REG);
+
+ /* bs color */
+ if (bluscr->bs_color)
+ writel(bluscr->bs_color, info->regs + FIMG2D_BS_COLOR_REG);
+
+ /* bg color */
+ if (bluscr->mode == BLUSCR && bluscr->bg_color)
+ writel(bluscr->bg_color, info->regs + FIMG2D_BG_COLOR_REG);
+}
+
+/**
+ * @c: destination clipping region
+ */
+void fimg2d4x_enable_clipping(struct fimg2d_control *info, struct fimg2d_rect *c)
+{
+ unsigned long cfg;
+
+ cfg = readl(info->regs + FIMG2D_BITBLT_COMMAND_REG);
+ cfg |= FIMG2D_ENABLE_CW;
+
+ writel(cfg, info->regs + FIMG2D_BITBLT_COMMAND_REG);
+
+ writel(FIMG2D_OFFSET(c->x1, c->y1), info->regs + FIMG2D_CW_LT_REG);
+ writel(FIMG2D_OFFSET(c->x2, c->y2), info->regs + FIMG2D_CW_RB_REG);
+}
+
+void fimg2d4x_enable_dithering(struct fimg2d_control *info)
+{
+ unsigned long cfg;
+
+ cfg = readl(info->regs + FIMG2D_BITBLT_COMMAND_REG);
+ cfg |= FIMG2D_ENABLE_DITHER;
+
+ writel(cfg, info->regs + FIMG2D_BITBLT_COMMAND_REG);
+}
+
+#define MAX_PRECISION 16
+#define DEFAULT_SCALE_RATIO 0x10000
+
+/**
+ * scale_factor_to_fixed16 - convert scale factor to fixed pint 16
+ * @n: numerator
+ * @d: denominator
+ */
+static inline unsigned long scale_factor_to_fixed16(int n, int d)
+{
+ int i;
+ u32 fixed16;
+
+ if (!d)
+ return DEFAULT_SCALE_RATIO;
+
+ fixed16 = (n/d) << 16;
+ n %= d;
+
+ for (i = 0; i < MAX_PRECISION; i++) {
+ if (!n)
+ break;
+ n <<= 1;
+ if (n/d)
+ fixed16 |= 1 << (15-i);
+ n %= d;
+ }
+
+ return fixed16;
+}
+
+void fimg2d4x_set_src_scaling(struct fimg2d_control *info, struct fimg2d_scale *s)
+{
+ unsigned long wcfg, hcfg;
+ unsigned long mode;
+
+ /*
+ * scaling ratio in pixels
+ * e.g scale-up: src(1,1)-->dst(2,2), src factor: 0.5 (0x000080000)
+ * scale-down: src(2,2)-->dst(1,1), src factor: 2.0 (0x000200000)
+ */
+
+ /* inversed scaling factor: src is numerator */
+ wcfg = scale_factor_to_fixed16(s->src_w, s->dst_w);
+ hcfg = scale_factor_to_fixed16(s->src_h, s->dst_h);
+
+ if (wcfg == DEFAULT_SCALE_RATIO && hcfg == DEFAULT_SCALE_RATIO)
+ return;
+
+ writel(wcfg, info->regs + FIMG2D_SRC_XSCALE_REG);
+ writel(hcfg, info->regs + FIMG2D_SRC_YSCALE_REG);
+
+ /* scaling algorithm */
+ if (s->mode == SCALING_NEAREST)
+ mode = FIMG2D_SCALE_MODE_NEAREST;
+ else
+ mode = FIMG2D_SCALE_MODE_BILINEAR;
+
+ writel(mode, info->regs + FIMG2D_SRC_SCALE_CTRL_REG);
+
+}
+
+void fimg2d4x_set_msk_scaling(struct fimg2d_control *info, struct fimg2d_scale *s)
+{
+ unsigned long wcfg, hcfg;
+ unsigned long mode;
+
+ /*
+ * scaling ratio in pixels
+ * e.g scale-up: src(1,1)-->dst(2,2), msk factor: 0.5 (0x000080000)
+ * scale-down: src(2,2)-->dst(1,1), msk factor: 2.0 (0x000200000)
+ */
+
+ /* inversed scaling factor: src is numerator */
+ wcfg = scale_factor_to_fixed16(s->src_w, s->dst_w);
+ hcfg = scale_factor_to_fixed16(s->src_h, s->dst_h);
+
+ if (wcfg == DEFAULT_SCALE_RATIO && hcfg == DEFAULT_SCALE_RATIO)
+ return;
+
+ writel(wcfg, info->regs + FIMG2D_MSK_XSCALE_REG);
+ writel(hcfg, info->regs + FIMG2D_MSK_YSCALE_REG);
+
+ /* scaling algorithm */
+ if (s->mode == SCALING_NEAREST)
+ mode = FIMG2D_SCALE_MODE_NEAREST;
+ else
+ mode = FIMG2D_SCALE_MODE_BILINEAR;
+
+ writel(mode, info->regs + FIMG2D_MSK_SCALE_CTRL_REG);
+}
+
+void fimg2d4x_set_src_repeat(struct fimg2d_control *info, struct fimg2d_repeat *r)
+{
+ unsigned long cfg;
+
+ if (r->mode == NO_REPEAT)
+ return;
+
+ cfg = (r->mode - REPEAT_NORMAL) << FIMG2D_SRC_REPEAT_SHIFT;
+
+ writel(cfg, info->regs + FIMG2D_SRC_REPEAT_MODE_REG);
+
+ /* src pad color */
+ if (r->mode == REPEAT_PAD)
+ writel(r->pad_color, info->regs + FIMG2D_SRC_PAD_VALUE_REG);
+}
+
+void fimg2d4x_set_msk_repeat(struct fimg2d_control *info, struct fimg2d_repeat *r)
+{
+ unsigned long cfg;
+
+ if (r->mode == NO_REPEAT)
+ return;
+
+ cfg = (r->mode - REPEAT_NORMAL) << FIMG2D_MSK_REPEAT_SHIFT;
+
+ writel(cfg, info->regs + FIMG2D_MSK_REPEAT_MODE_REG);
+
+ /* mask pad color */
+ if (r->mode == REPEAT_PAD)
+ writel(r->pad_color, info->regs + FIMG2D_MSK_PAD_VALUE_REG);
+}
+
+void fimg2d4x_set_rotation(struct fimg2d_control *info, enum rotation rot)
+{
+ int rev_rot90; /* counter clockwise, 4.1 specific */
+ unsigned long cfg;
+ enum addressing dirx, diry;
+
+ rev_rot90 = 0;
+ dirx = diry = FORWARD_ADDRESSING;
+
+ switch (rot) {
+ case ROT_90: /* -270 degree */
+ rev_rot90 = 1; /* fall through */
+ case ROT_180:
+ dirx = REVERSE_ADDRESSING;
+ diry = REVERSE_ADDRESSING;
+ break;
+ case ROT_270: /* -90 degree */
+ rev_rot90 = 1;
+ break;
+ case XFLIP:
+ diry = REVERSE_ADDRESSING;
+ break;
+ case YFLIP:
+ dirx = REVERSE_ADDRESSING;
+ break;
+ case ORIGIN:
+ default:
+ break;
+ }
+
+ /* destination direction */
+ if (dirx == REVERSE_ADDRESSING || diry == REVERSE_ADDRESSING) {
+ cfg = readl(info->regs + FIMG2D_DST_PAT_DIRECT_REG);
+
+ if (dirx == REVERSE_ADDRESSING)
+ cfg |= FIMG2D_DST_X_DIR_NEGATIVE;
+
+ if (diry == REVERSE_ADDRESSING)
+ cfg |= FIMG2D_DST_Y_DIR_NEGATIVE;
+
+ writel(cfg, info->regs + FIMG2D_DST_PAT_DIRECT_REG);
+ }
+
+ /* rotation -90 */
+ if (rev_rot90) {
+ cfg = readl(info->regs + FIMG2D_ROTATE_REG);
+ cfg |= FIMG2D_SRC_ROTATE_90;
+ cfg |= FIMG2D_MSK_ROTATE_90;
+
+ writel(cfg, info->regs + FIMG2D_ROTATE_REG);
+ }
+}
+
+void fimg2d4x_set_fgcolor(struct fimg2d_control *info, unsigned long fg)
+{
+ writel(fg, info->regs + FIMG2D_FG_COLOR_REG);
+ writel(fg, info->regs + FIMG2D_FG_COLOR_REG);
+}
+
+void fimg2d4x_set_bgcolor(struct fimg2d_control *info, unsigned long bg)
+{
+ writel(bg, info->regs + FIMG2D_BG_COLOR_REG);
+ writel(bg, info->regs + FIMG2D_BG_COLOR_REG);
+}
+
+void fimg2d4x_enable_alpha(struct fimg2d_control *info, unsigned char g_alpha)
+{
+ unsigned long cfg;
+
+ /* enable alpha */
+ cfg = readl(info->regs + FIMG2D_BITBLT_COMMAND_REG);
+ cfg |= FIMG2D_ALPHA_BLEND_MODE;
+
+ writel(cfg, info->regs + FIMG2D_BITBLT_COMMAND_REG);
+
+ /*
+ * global(constant) alpha
+ * ex. if global alpha is 0x80, must set 0x80808080
+ */
+ cfg = g_alpha;
+ cfg |= g_alpha << 8;
+ cfg |= g_alpha << 16;
+ cfg |= g_alpha << 24;
+ writel(cfg, info->regs + FIMG2D_ALPHA_REG);
+}
+
+/**
+ * Four channels of the image are computed with:
+ * R = [ coeff(S)*Sc + coeff(D)*Dc ]
+ * where
+ * Rc is result color or alpha
+ * Sc is source color or alpha
+ * Dc is destination color or alpha
+ *
+ * Caution: supposed that Sc and Dc are perpixel-alpha-premultiplied value
+ *
+ * MODE: Formula
+ * ----------------------------------------------------------------------------
+ * FILL:
+ * CLEAR: R = 0
+ * SRC: R = Sc
+ * DST: R = Dc
+ * SRC_OVER: R = Sc + (1-Sa)*Dc
+ * DST_OVER: R = (1-Da)*Sc + Dc
+ * SRC_IN: R = Da*Sc
+ * DST_IN: R = Sa*Dc
+ * SRC_OUT: R = (1-Da)*Sc
+ * DST_OUT: R = (1-Sa)*Dc
+ * SRC_ATOP: R = Da*Sc + (1-Sa)*Dc
+ * DST_ATOP: R = (1-Da)*Sc + Sa*Dc
+ * XOR: R = (1-Da)*Sc + (1-Sa)*Dc
+ * ADD: R = Sc + Dc
+ * MULTIPLY: R = Sc*Dc
+ * SCREEN: R = Sc + (1-Sc)*Dc
+ * DARKEN: R = (Da*Sc<Sa*Dc)? Sc+(1-Sa)*Dc : (1-Da)*Sc+Dc
+ * LIGHTEN: R = (Da*Sc>Sa*Dc)? Sc+(1-Sa)*Dc : (1-Da)*Sc+Dc
+ * DISJ_SRC_OVER: R = Sc + (min(1,(1-Sa)/Da))*Dc
+ * DISJ_DST_OVER: R = (min(1,(1-Da)/Sa))*Sc + Dc
+ * DISJ_SRC_IN: R = (max(1-(1-Da)/Sa,0))*Sc
+ * DISJ_DST_IN: R = (max(1-(1-Sa)/Da,0))*Dc
+ * DISJ_SRC_OUT: R = (min(1,(1-Da)/Sa))*Sc
+ * DISJ_DST_OUT: R = (min(1,(1-Sa)/Da))*Dc
+ * DISJ_SRC_ATOP: R = (max(1-(1-Da)/Sa,0))*Sc + (min(1,(1-Sa)/Da))*Dc
+ * DISJ_DST_ATOP: R = (min(1,(1-Da)/Sa))*Sc + (max(1-(1-Sa)/Da,0))*Dc
+ * DISJ_XOR: R = (min(1,(1-Da)/Sa))*Sc + (min(1,(1-Sa)/Da))*Dc
+ * CONJ_SRC_OVER: R = Sc + (max(1-Sa/Da,0))*Dc
+ * CONJ_DST_OVER: R = (max(1-Da/Sa,0))*Sc + Dc
+ * CONJ_SRC_IN: R = (min(1,Da/Sa))*Sc
+ * CONJ_DST_IN: R = (min(1,Sa/Da))*Dc
+ * CONJ_SRC_OUT: R = (max(1-Da/Sa,0)*Sc
+ * CONJ_DST_OUT: R = (max(1-Sa/Da,0))*Dc
+ * CONJ_SRC_ATOP: R = (min(1,Da/Sa))*Sc + (max(1-Sa/Da,0))*Dc
+ * CONJ_DST_ATOP: R = (max(1-Da/Sa,0))*Sc + (min(1,Sa/Da))*Dc
+ * CONJ_XOR: R = (max(1-Da/Sa,0))*Sc + (max(1-Sa/Da,0))*Dc
+ */
+static struct fimg2d_blend_coeff const coeff_table[MAX_FIMG2D_BLIT_OP] = {
+ { 0, 0, 0, 0 }, /* FILL */
+ { 0, COEFF_ZERO, 0, COEFF_ZERO }, /* CLEAR */
+ { 0, COEFF_ONE, 0, COEFF_ZERO }, /* SRC */
+ { 0, COEFF_ZERO, 0, COEFF_ONE }, /* DST */
+ { 0, COEFF_ONE, 1, COEFF_SA }, /* SRC_OVER */
+ { 1, COEFF_DA, 0, COEFF_ONE }, /* DST_OVER */
+ { 0, COEFF_DA, 0, COEFF_ZERO }, /* SRC_IN */
+ { 0, COEFF_ZERO, 0, COEFF_SA }, /* DST_IN */
+ { 1, COEFF_DA, 0, COEFF_ZERO }, /* SRC_OUT */
+ { 0, COEFF_ZERO, 1, COEFF_SA }, /* DST_OUT */
+ { 0, COEFF_DA, 1, COEFF_SA }, /* SRC_ATOP */
+ { 1, COEFF_DA, 0, COEFF_SA }, /* DST_ATOP */
+ { 1, COEFF_DA, 1, COEFF_SA }, /* XOR */
+ { 0, COEFF_ONE, 0, COEFF_ONE }, /* ADD */
+ { 0, COEFF_DC, 0, COEFF_ZERO }, /* MULTIPLY */
+ { 0, COEFF_ONE, 1, COEFF_SC }, /* SCREEN */
+ { 0, 0, 0, 0 }, /* DARKEN */
+ { 0, 0, 0, 0 }, /* LIGHTEN */
+ { 0, COEFF_ONE, 0, COEFF_DISJ_S }, /* DISJ_SRC_OVER */
+ { 0, COEFF_DISJ_D, 0, COEFF_ONE }, /* DISJ_DST_OVER */
+ { 1, COEFF_DISJ_D, 0, COEFF_ZERO }, /* DISJ_SRC_IN */
+ { 0, COEFF_ZERO, 1, COEFF_DISJ_S }, /* DISJ_DST_IN */
+ { 0, COEFF_DISJ_D, 0, COEFF_ONE }, /* DISJ_SRC_OUT */
+ { 0, COEFF_ZERO, 0, COEFF_DISJ_S }, /* DISJ_DST_OUT */
+ { 1, COEFF_DISJ_D, 0, COEFF_DISJ_S }, /* DISJ_SRC_ATOP */
+ { 0, COEFF_DISJ_D, 1, COEFF_DISJ_S }, /* DISJ_DST_ATOP */
+ { 0, COEFF_DISJ_D, 0, COEFF_DISJ_S }, /* DISJ_XOR */
+ { 0, COEFF_ONE, 1, COEFF_DISJ_S }, /* CONJ_SRC_OVER */
+ { 1, COEFF_DISJ_D, 0, COEFF_ONE }, /* CONJ_DST_OVER */
+ { 0, COEFF_CONJ_D, 0, COEFF_ONE }, /* CONJ_SRC_IN */
+ { 0, COEFF_ZERO, 0, COEFF_CONJ_S }, /* CONJ_DST_IN */
+ { 1, COEFF_CONJ_D, 0, COEFF_ZERO }, /* CONJ_SRC_OUT */
+ { 0, COEFF_ZERO, 1, COEFF_CONJ_S }, /* CONJ_DST_OUT */
+ { 0, COEFF_CONJ_D, 1, COEFF_CONJ_S }, /* CONJ_SRC_ATOP */
+ { 1, COEFF_CONJ_D, 0, COEFF_CONJ_D }, /* CONJ_DST_ATOP */
+ { 1, COEFF_CONJ_D, 1, COEFF_CONJ_S }, /* CONJ_XOR */
+ { 0, 0, 0, 0 }, /* USER */
+ { 1, COEFF_GA, 1, COEFF_ZERO }, /* USER_SRC_GA */
+};
+
+/*
+ * coefficient table with global (constant) alpha
+ * replace COEFF_ONE with COEFF_GA
+ *
+ * MODE: Formula with Global Alpha (Ga is multiplied to both Sc and Sa)
+ * ----------------------------------------------------------------------------
+ * FILL:
+ * CLEAR: R = 0
+ * SRC: R = Ga*Sc
+ * DST: R = Dc
+ * SRC_OVER: R = Ga*Sc + (1-Sa*Ga)*Dc
+ * DST_OVER: R = (1-Da)*Ga*Sc + Dc --> (W/A) 1st:Ga*Sc, 2nd:DST_OVER
+ * SRC_IN: R = Da*Ga*Sc
+ * DST_IN: R = Sa*Ga*Dc
+ * SRC_OUT: R = (1-Da)*Ga*Sc --> (W/A) 1st: Ga*Sc, 2nd:SRC_OUT
+ * DST_OUT: R = (1-Sa*Ga)*Dc
+ * SRC_ATOP: R = Da*Ga*Sc + (1-Sa*Ga)*Dc
+ * DST_ATOP: R = (1-Da)*Ga*Sc + Sa*Ga*Dc --> (W/A) 1st: Ga*Sc, 2nd:DST_ATOP
+ * XOR: R = (1-Da)*Ga*Sc + (1-Sa*Ga)*Dc --> (W/A) 1st: Ga*Sc, 2nd:XOR
+ * ADD: R = Ga*Sc + Dc
+ * MULTIPLY: R = Ga*Sc*Dc --> (W/A) 1st: Ga*Sc, 2nd: MULTIPLY
+ * SCREEN: R = Ga*Sc + (1-Ga*Sc)*Dc --> (W/A) 1st: Ga*Sc, 2nd: SCREEN
+ * DARKEN: R = (W/A) 1st: Ga*Sc, 2nd: OP
+ * LIGHTEN: R = (W/A) 1st: Ga*Sc, 2nd: OP
+ * DISJ_SRC_OVER: R = (W/A) 1st: Ga*Sc, 2nd: OP
+ * DISJ_DST_OVER: R = (W/A) 1st: Ga*Sc, 2nd: OP
+ * DISJ_SRC_IN: R = (W/A) 1st: Ga*Sc, 2nd: OP
+ * DISJ_DST_IN: R = (W/A) 1st: Ga*Sc, 2nd: OP
+ * DISJ_SRC_OUT: R = (W/A) 1st: Ga*Sc, 2nd: OP
+ * DISJ_DST_OUT: R = (W/A) 1st: Ga*Sc, 2nd: OP
+ * DISJ_SRC_ATOP: R = (W/A) 1st: Ga*Sc, 2nd: OP
+ * DISJ_DST_ATOP: R = (W/A) 1st: Ga*Sc, 2nd: OP
+ * DISJ_XOR: R = (W/A) 1st: Ga*Sc, 2nd: OP
+ * CONJ_SRC_OVER: R = (W/A) 1st: Ga*Sc, 2nd: OP
+ * CONJ_DST_OVER: R = (W/A) 1st: Ga*Sc, 2nd: OP
+ * CONJ_SRC_IN: R = (W/A) 1st: Ga*Sc, 2nd: OP
+ * CONJ_DST_IN: R = (W/A) 1st: Ga*Sc, 2nd: OP
+ * CONJ_SRC_OUT: R = (W/A) 1st: Ga*Sc, 2nd: OP
+ * CONJ_DST_OUT: R = (W/A) 1st: Ga*Sc, 2nd: OP
+ * CONJ_SRC_ATOP: R = (W/A) 1st: Ga*Sc, 2nd: OP
+ * CONJ_DST_ATOP: R = (W/A) 1st: Ga*Sc, 2nd: OP
+ * CONJ_XOR: R = (W/A) 1st: Ga*Sc, 2nd: OP
+ */
+static struct fimg2d_blend_coeff const ga_coeff_table[MAX_FIMG2D_BLIT_OP] = {
+ { 0, 0, 0, 0 }, /* FILL */
+ { 0, COEFF_ZERO, 0, COEFF_ZERO }, /* CLEAR */
+ { 0, COEFF_GA, 0, COEFF_ZERO }, /* SRC */
+ { 0, COEFF_ZERO, 0, COEFF_ONE }, /* DST */
+ { 0, COEFF_GA, 1, COEFF_SA }, /* SRC_OVER */
+ { 1, COEFF_DA, 0, COEFF_ONE }, /* DST_OVER (use W/A) */
+ { 0, COEFF_DA, 0, COEFF_ZERO }, /* SRC_IN */
+ { 0, COEFF_ZERO, 0, COEFF_SA }, /* DST_IN */
+ { 1, COEFF_DA, 0, COEFF_ZERO }, /* SRC_OUT (use W/A) */
+ { 0, COEFF_ZERO, 1, COEFF_SA }, /* DST_OUT */
+ { 0, COEFF_DA, 1, COEFF_SA }, /* SRC_ATOP */
+ { 1, COEFF_DA, 0, COEFF_SA }, /* DST_ATOP (use W/A) */
+ { 1, COEFF_DA, 1, COEFF_SA }, /* XOR (use W/A) */
+ { 0, COEFF_GA, 0, COEFF_ONE }, /* ADD */
+ { 0, COEFF_DC, 0, COEFF_ZERO }, /* MULTIPLY (use W/A) */
+ { 0, COEFF_ONE, 1, COEFF_SC }, /* SCREEN (use W/A) */
+ { 0, 0, 0, 0 }, /* DARKEN (use W/A) */
+ { 0, 0, 0, 0 }, /* LIGHTEN (use W/A) */
+ { 0, COEFF_ONE, 0, COEFF_DISJ_S }, /* DISJ_SRC_OVER (use W/A) */
+ { 0, COEFF_DISJ_D, 0, COEFF_ONE }, /* DISJ_DST_OVER (use W/A) */
+ { 1, COEFF_DISJ_D, 0, COEFF_ZERO }, /* DISJ_SRC_IN (use W/A) */
+ { 0, COEFF_ZERO, 1, COEFF_DISJ_S }, /* DISJ_DST_IN (use W/A) */
+ { 0, COEFF_DISJ_D, 0, COEFF_ONE }, /* DISJ_SRC_OUT (use W/A) */
+ { 0, COEFF_ZERO, 0, COEFF_DISJ_S }, /* DISJ_DST_OUT (use W/A) */
+ { 1, COEFF_DISJ_D, 0, COEFF_DISJ_S }, /* DISJ_SRC_ATOP (use W/A) */
+ { 0, COEFF_DISJ_D, 1, COEFF_DISJ_S }, /* DISJ_DST_ATOP (use W/A) */
+ { 0, COEFF_DISJ_D, 0, COEFF_DISJ_S }, /* DISJ_XOR (use W/A) */
+ { 0, COEFF_ONE, 1, COEFF_DISJ_S }, /* CONJ_SRC_OVER (use W/A) */
+ { 1, COEFF_DISJ_D, 0, COEFF_ONE }, /* CONJ_DST_OVER (use W/A) */
+ { 0, COEFF_CONJ_D, 0, COEFF_ONE }, /* CONJ_SRC_IN (use W/A) */
+ { 0, COEFF_ZERO, 0, COEFF_CONJ_S }, /* CONJ_DST_IN (use W/A) */
+ { 1, COEFF_CONJ_D, 0, COEFF_ZERO }, /* CONJ_SRC_OUT (use W/A) */
+ { 0, COEFF_ZERO, 1, COEFF_CONJ_S }, /* CONJ_DST_OUT (use W/A) */
+ { 0, COEFF_CONJ_D, 1, COEFF_CONJ_S }, /* CONJ_SRC_ATOP (use W/A) */
+ { 1, COEFF_CONJ_D, 0, COEFF_CONJ_D }, /* CONJ_DST_ATOP (use W/A) */
+ { 1, COEFF_CONJ_D, 1, COEFF_CONJ_S }, /* CONJ_XOR (use W/A) */
+ { 0, 0, 0, 0 }, /* USER */
+ { 1, COEFF_GA, 1, COEFF_ZERO }, /* USER_SRC_GA */
+};
+
+void fimg2d4x_set_alpha_composite(struct fimg2d_control *info,
+ enum blit_op op, unsigned char g_alpha)
+{
+ int alphamode;
+ unsigned long cfg = 0;
+ struct fimg2d_blend_coeff const *tbl;
+
+ switch (op) {
+ case BLIT_OP_SOLID_FILL:
+ case BLIT_OP_CLR:
+ /* nop */
+ return;
+ case BLIT_OP_DARKEN:
+ cfg |= FIMG2D_DARKEN;
+ break;
+ case BLIT_OP_LIGHTEN:
+ cfg |= FIMG2D_LIGHTEN;
+ break;
+ case BLIT_OP_USER_COEFF:
+ /* TODO */
+ return;
+ default:
+ if (g_alpha < 0xff) { /* with global alpha */
+ tbl = &ga_coeff_table[op];
+ alphamode = ALPHA_PERPIXEL_MUL_GLOBAL;
+ } else {
+ tbl = &coeff_table[op];
+ alphamode = ALPHA_PERPIXEL;
+ }
+
+ /* src coefficient */
+ cfg |= tbl->s_coeff << FIMG2D_SRC_COEFF_SHIFT;
+
+ cfg |= alphamode << FIMG2D_SRC_COEFF_SA_SHIFT;
+ cfg |= alphamode << FIMG2D_SRC_COEFF_DA_SHIFT;
+
+ if (tbl->s_coeff_inv)
+ cfg |= FIMG2D_INV_SRC_COEFF;
+
+ /* dst coefficient */
+ cfg |= tbl->d_coeff << FIMG2D_DST_COEFF_SHIFT;
+
+ cfg |= alphamode << FIMG2D_DST_COEFF_DA_SHIFT;
+ cfg |= alphamode << FIMG2D_DST_COEFF_SA_SHIFT;
+
+ if (tbl->d_coeff_inv)
+ cfg |= FIMG2D_INV_DST_COEFF;
+
+ break;
+ }
+
+ writel(cfg, info->regs + FIMG2D_BLEND_FUNCTION_REG);
+
+ /* round mode: depremult round mode is not used */
+ cfg = readl(info->regs + FIMG2D_ROUND_MODE_REG);
+
+ /* premult */
+ cfg &= ~FIMG2D_PREMULT_ROUND_MASK;
+ cfg |= premult_round_mode << FIMG2D_PREMULT_ROUND_SHIFT;
+
+ /* blend */
+ cfg &= ~FIMG2D_BLEND_ROUND_MASK;
+ cfg |= blend_round_mode << FIMG2D_BLEND_ROUND_SHIFT;
+
+ writel(cfg, info->regs + FIMG2D_ROUND_MODE_REG);
+}
+
+void fimg2d4x_dump_regs(struct fimg2d_control *info)
+{
+ int i, offset;
+ unsigned long table[][2] = {
+ /* start, end */
+ {0x0000, 0x0030}, /* general */
+ {0x0080, 0x00a0}, /* host dma */
+ {0x0100, 0x0110}, /* commands */
+ {0x0200, 0x0210}, /* rotation & direction */
+ {0x0300, 0x0340}, /* source */
+ {0x0400, 0x0420}, /* dest */
+ {0x0500, 0x0550}, /* pattern & mask */
+ {0x0600, 0x0710}, /* clip, rop, alpha and color */
+ {0x0, 0x0}
+ };
+
+ for (i = 0; table[i][1] != 0x0; i++) {
+ offset = table[i][0];
+ do {
+ printk(KERN_INFO "[0x%04x] 0x%08x 0x%08x 0x%08x 0x%08x\n", offset,
+ readl(info->regs + offset),
+ readl(info->regs + offset+0x4),
+ readl(info->regs + offset+0x8),
+ readl(info->regs + offset+0xc));
+ offset += 0x10;
+ } while (offset < table[i][1]);
+ }
+}
diff --git a/drivers/media/video/exynos/fimg2d/fimg2d4x_regs.h b/drivers/media/video/exynos/fimg2d/fimg2d4x_regs.h
new file mode 100644
index 0000000..91c7ac8
--- /dev/null
+++ b/drivers/media/video/exynos/fimg2d/fimg2d4x_regs.h
@@ -0,0 +1,460 @@
+/* linux/drivers/media/video/samsung/fimg2d4x/fimg2d4x_regs.h
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Register Definitions for Samsung Graphics 2D Hardware
+ *
+ * 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.
+*/
+
+#ifndef __FIMG2D4X_REGS_H
+#define __FIMG2D4x_REGS_H __FILE__
+
+/* Macros */
+#define FIMG2D_ADDR(v) ((v) << 0)
+#define FIMG2D_STRIDE(v) (((v) & (0xffff)) << 0)
+#define FIMG2D_OFFSET(x, y) ((((y) & 0x1fff) << 16) | (((x) & 0x1fff) << 0))
+#define FIMG2D_SIZE(w, h) ((((h) & 0x1fff) << 16) | (((w) & 0x1fff) << 0))
+#define FIMG2D_COLOR(v) ((v) << 0)
+
+/* Registers */
+#define FIMG2D_SOFT_RESET_REG (0x000)
+#define FIMG2D_INTEN_REG (0x004)
+#define FIMG2D_INTC_PEND_REG (0x00c)
+#define FIMG2D_FIFO_STAT_REG (0x010)
+#define FIMG2D_AXI_MODE_REG (0x01c)
+#define FIMG2D_DMA_SFR_BASE_ADDR_REG (0x080)
+#define FIMG2D_DMA_COMMAND_REG (0x084)
+#define FIMG2D_DMA_EXE_LIST_NUM_REG (0x088)
+#define FIMG2D_DMA_STATUS_REG (0x08c)
+#define FIMG2D_DMA_HOLD_CMD_REG (0x090)
+#define FIMG2D_BITBLT_START_REG (0x100)
+#define FIMG2D_BITBLT_COMMAND_REG (0x104)
+#define FIMG2D_BLEND_FUNCTION_REG (0x108)
+#define FIMG2D_ROUND_MODE_REG (0x10c)
+#define FIMG2D_ROTATE_REG (0x200)
+#define FIMG2D_SRC_MSK_DIRECT_REG (0x204)
+#define FIMG2D_DST_PAT_DIRECT_REG (0x208)
+#define FIMG2D_SRC_SELECT_REG (0x300)
+#define FIMG2D_SRC_BASE_ADDR_REG (0x304)
+#define FIMG2D_SRC_STRIDE_REG (0x308)
+#define FIMG2D_SRC_COLOR_MODE_REG (0x30c)
+#define FIMG2D_SRC_LEFT_TOP_REG (0x310)
+#define FIMG2D_SRC_RIGHT_BOTTOM_REG (0x314)
+#define FIMG2D_SRC_PLANE2_BASE_ADDR_REG (0x318)
+#define FIMG2D_SRC_REPEAT_MODE_REG (0x31c)
+#define FIMG2D_SRC_PAD_VALUE_REG (0x320)
+#define FIMG2D_SRC_A8_RGB_EXT_REG (0x324)
+#define FIMG2D_SRC_SCALE_CTRL_REG (0x328)
+#define FIMG2D_SRC_XSCALE_REG (0x32c)
+#define FIMG2D_SRC_YSCALE_REG (0x330)
+#define FIMG2D_DST_SELECT_REG (0x400)
+#define FIMG2D_DST_BASE_ADDR_REG (0x404)
+#define FIMG2D_DST_STRIDE_REG (0x408)
+#define FIMG2D_DST_COLOR_MODE_REG (0x40c)
+#define FIMG2D_DST_LEFT_TOP_REG (0x410)
+#define FIMG2D_DST_RIGHT_BOTTOM_REG (0x414)
+#define FIMG2D_DST_PLANE2_BASE_ADDR_REG (0x418)
+#define FIMG2D_DST_A8_RGB_EXT_REG (0x41c)
+#define FIMG2D_PAT_BASE_ADDR_REG (0x500)
+#define FIMG2D_PAT_SIZE_REG (0x504)
+#define FIMG2D_PAT_COLOR_MODE_REG (0x508)
+#define FIMG2D_PAT_OFFSET_REG (0x50c)
+#define FIMG2D_PAT_STRIDE_REG (0x510)
+#define FIMG2D_MSK_BASE_ADDR_REG (0x520)
+#define FIMG2D_MSK_STRIDE_REG (0x524)
+#define FIMG2D_MSK_LEFT_TOP_REG (0x528)
+#define FIMG2D_MSK_RIGHT_BOTTOM_REG (0x52c)
+#define FIMG2D_MSK_MODE_REG (0x530)
+#define FIMG2D_MSK_REPEAT_MODE_REG (0x534)
+#define FIMG2D_MSK_PAD_VALUE_REG (0x538)
+#define FIMG2D_MSK_SCALE_CTRL_REG (0x53c)
+#define FIMG2D_MSK_XSCALE_REG (0x540)
+#define FIMG2D_MSK_YSCALE_REG (0x544)
+#define FIMG2D_CW_LT_REG (0x600)
+#define FIMG2D_CW_RB_REG (0x604)
+#define FIMG2D_THIRD_OPERAND_REG (0x610)
+#define FIMG2D_ROP4_REG (0x614)
+#define FIMG2D_ALPHA_REG (0x618)
+#define FIMG2D_FG_COLOR_REG (0x700)
+#define FIMG2D_BG_COLOR_REG (0x704)
+#define FIMG2D_BS_COLOR_REG (0x708)
+#define FIMG2D_SF_COLOR_REG (0x70c)
+#define FIMG2D_SRC_COLORKEY_CTRL_REG (0x710)
+#define FIMG2D_SRC_COLORKEY_DR_MIN_REG (0x714)
+#define FIMG2D_SRC_COLORKEY_DR_MAX_REG (0x718)
+#define FIMG2D_DST_COLORKEY_CTRL_REG (0x71c)
+#define FIMG2D_DST_COLORKEY_DR_MIN_REG (0x720)
+#define FIMG2D_DST_COLORKEY_DR_MAX_REG (0x724)
+#define FIMG2D_YCBCR_SRC_COLORKEY_CTRL_REG (0x728)
+#define FIMG2D_YCBCR_SRC_COLORKEY_DR_MIN_REG (0x72c)
+#define FIMG2D_YCBCR_SRC_COLORKEY_DR_MAX_REG (0x730)
+#define FIMG2D_YCBCR_DST_COLORKEY_CTRL_REG (0x734)
+#define FIMG2D_YCBCR_DST_COLORKEY_DR_MIN_REG (0x738)
+#define FIMG2D_YCBCR_DST_COLORKEY_DR_MAX_REG (0x73c)
+#define FIMG2D_GAMMA_TABLE0_0_REG (0x800)
+#define FIMG2D_GAMMA_TABLE0_1_REG (0x804)
+#define FIMG2D_GAMMA_TABLE0_2_REG (0x808)
+#define FIMG2D_GAMMA_TABLE0_3_REG (0x80c)
+#define FIMG2D_GAMMA_TABLE0_4_REG (0x810)
+#define FIMG2D_GAMMA_TABLE0_5_REG (0x814)
+#define FIMG2D_GAMMA_TABLE0_6_REG (0x818)
+#define FIMG2D_GAMMA_TABLE0_7_REG (0x81c)
+#define FIMG2D_GAMMA_TABLE0_8_REG (0x820)
+#define FIMG2D_GAMMA_TABLE0_9_REG (0x824)
+#define FIMG2D_GAMMA_TABLE0_10_REG (0x828)
+#define FIMG2D_GAMMA_TABLE0_11_REG (0x82c)
+#define FIMG2D_GAMMA_TABLE0_12_REG (0x830)
+#define FIMG2D_GAMMA_TABLE0_13_REG (0x834)
+#define FIMG2D_GAMMA_TABLE0_14_REG (0x838)
+#define FIMG2D_GAMMA_TABLE0_15_REG (0x83c)
+#define FIMG2D_GAMMA_TABLE1_0_REG (0x840)
+#define FIMG2D_GAMMA_TABLE1_1_REG (0x844)
+#define FIMG2D_GAMMA_TABLE1_2_REG (0x848)
+#define FIMG2D_GAMMA_TABLE1_3_REG (0x84c)
+#define FIMG2D_GAMMA_TABLE1_4_REG (0x850)
+#define FIMG2D_GAMMA_TABLE1_5_REG (0x854)
+#define FIMG2D_GAMMA_TABLE1_6_REG (0x858)
+#define FIMG2D_GAMMA_TABLE1_7_REG (0x85c)
+#define FIMG2D_GAMMA_TABLE1_8_REG (0x860)
+#define FIMG2D_GAMMA_TABLE1_9_REG (0x864)
+#define FIMG2D_GAMMA_TABLE1_10_REG (0x868)
+#define FIMG2D_GAMMA_TABLE1_11_REG (0x86c)
+#define FIMG2D_GAMMA_TABLE1_12_REG (0x870)
+#define FIMG2D_GAMMA_TABLE1_13_REG (0x874)
+#define FIMG2D_GAMMA_TABLE1_14_REG (0x878)
+#define FIMG2D_GAMMA_TABLE1_15_REG (0x87c)
+#define FIMG2D_GAMMA_REF_COLOR_REG (0x880)
+
+/* Bit Definitions */
+
+/* FIMG2D_SOFT_RESET_REG */
+#define FIMG2D_SFR_CLEAR (1 << 1)
+#define FIMG2D_SOFT_RESET (1 << 0)
+
+/* FIMG2D_INTEN_REG */
+#define FIMG2D_INT_TYPE_EDGE (1 << 4)
+#define FIMG2D_INT_TYPE_LEVEL (0 << 4)
+
+#define FIMG2D_ACF_INT_ENABLE (1 << 3)
+#define FIMG2D_UCF_INT_ENABLE (1 << 2)
+#define FIMG2D_GCF_INT_ENABLE (1 << 1)
+#define FIMG2D_BLIT_INT_ENABLE (1 << 0)
+
+/* FIMG2D_INTC_PEND_REG */
+#define FIMG2D_ACMD_INT_FLAG (1 << 3)
+#define FIMG2D_UCMD_INT_FLAG (1 << 2)
+#define FIMG2D_GCMD_INT_FLAG (1 << 1)
+#define FIMG2D_BLIT_INT_FLAG (1 << 0)
+
+/* FIMG2D_FIFO_STAT_REG */
+#define FIMG2D_BLIT_FINISHED (1 << 0)
+
+/* FIMG2D_AXI_MODE_REG */
+#define FIMG2D_MAX_BURST_LEN_2 (0 << 24)
+#define FIMG2D_MAX_BURST_LEN_4 (1 << 24)
+#define FIMG2D_MAX_BURST_LEN_8 (2 << 24)
+#define FIMG2D_MAX_BURST_LEN_16 (3 << 24)
+#define FIMG2D_MAX_BURST_LEN_MASK (3 << 24)
+#define FIMG2D_MAX_BURST_LEN_SHIFT (24)
+
+#define FIMG2D_AXI_AWUSERS_SHIFT (16)
+#define FIMG2D_AXI_ARUSERS_SHIFT (8)
+#define FIMG2D_AXI_AWCACHE_SHIFT (4)
+#define FIMG2D_AXI_ARCACHE_SHIFT (0)
+
+/* FIMG2D_DMA_SFR_BASE_ADDR_REG */
+
+/* FIMG2D_DMA_COMMAND_REG */
+#define FIMG2D_BATCH_BLIT_HALT (1 << 2)
+#define FIMG2D_BATCH_BLIT_CONT (1 << 1)
+#define FIMG2D_BATCH_BLIT_START (1 << 0)
+
+/* FIMG2D_DMA_EXE_LIST_NUM_REG */
+#define FIMG2D_BATCH_BLIT_EXELIST_NUM_MASK (0xff)
+#define FIMG2D_BATCH_BLIT_EXELIST_NUM_SHIFT (0)
+
+/* FIMG2D_DMA_STATUS_REG */
+#define FIMG2D_BATCH_BLIT_DONELIST_CNT_MASK (0xff)
+#define FIMG2D_BATCH_BLIT_DONELIST_CNT_SHIFT (17)
+
+#define FIMG2D_BATCH_BLIT_DONEBLIT_CNT_MASK (0xffff)
+#define FIMG2D_BATCH_BLIT_DONEBLIT_CNT_SHIFT (1)
+
+#define FIMG2D_BATCH_BLIT_DONE_MASK (1)
+#define FIMG2D_BATCH_BLIT_DONE_SHIFT (0)
+
+/* FIMG2D_DMA_HOLD_CMD_REG */
+#define FIMG2D_BATCH_BLIT_USER_HOLD (1 << 2)
+#define FIMG2D_BATCH_BLIT_LIST_HOLD (1 << 1)
+#define FIMG2D_BATCH_BLIT_BLIT_HOLD (1 << 0)
+
+/* FIMG2D_BITBLT_START_REG */
+#define FIMG2D_START_N_HOLD (1 << 1)
+#define FIMG2D_START_BITBLT (1 << 0)
+
+/* FIMG2D_BITBLT_COMMAND_REG */
+#define FIMG2D_SOLID_FILL (1 << 28)
+
+#define FIMG2D_DST_WR_DEPREMULT (1 << 27)
+#define FIMG2D_DST_RD_PREMULT (1 << 26)
+#define FIMG2D_PAT_PREMULT (1 << 25)
+#define FIMG2D_SRC_PREMULT (1 << 24)
+#define FIMG2D_PREMULT_ALL (0xf << 24)
+
+#define FIMG2D_ALPHA_BLEND_MODE (1 << 20)
+
+#define FIMG2D_COLORKEY_SRC_RGBA (1 << 16)
+#define FIMG2D_COLORKEY_DST_RGBA (2 << 16)
+#define FIMG2D_COLORKEY_SRC_YCBCR (4 << 16)
+#define FIMG2D_COLORKEY_DST_YCBCR (8 << 16)
+
+#define FIMG2D_OPAQUE_MODE (0 << 12)
+#define FIMG2D_TRANSP_MODE (1 << 12)
+#define FIMG2D_BLUSCR_MODE (2 << 12)
+
+#define FIMG2D_ENABLE_CW (1 << 8)
+#define FIMG2D_ENABLE_DITHER (1 << 3)
+
+#define FIMG2D_ENABLE_SRC_ALPHA (0 << 2)
+#define FIMG2D_ENABLE_ROP_ALPHA (1 << 2)
+
+#define FIMG2D_ENABLE_ROP4_MSK (1 << 0)
+#define FIMG2D_ENABLE_NORMAL_MSK (2 << 0)
+
+/* FIMG2D_BLEND_FUNCTION_REG */
+#define FIMG2D_WINCE_SRC_OVER (1 << 22)
+#define FIMG2D_DARKEN (1 << 21)
+#define FIMG2D_LIGHTEN (1 << 20)
+#define FIMG2D_INV_DST_COEFF (1 << 18)
+#define FIMG2D_INV_SRC_COEFF (1 << 16)
+
+#define FIMG2D_DST_COEFF_DA_SHIFT (14)
+#define FIMG2D_DST_COEFF_SA_SHIFT (12)
+#define FIMG2D_SRC_COEFF_DA_SHIFT (6)
+#define FIMG2D_SRC_COEFF_SA_SHIFT (4)
+
+#define FIMG2D_DST_COEFF_SHIFT (8)
+#define FIMG2D_SRC_COEFF_SHIFT (0)
+
+/* FIMG2D_ROUND_MODE_REG */
+#define FIMG2D_PREMULT_ROUND_MASK (3 << 4)
+#define FIMG2D_PREMULT_ROUND_SHIFT (4)
+
+#define FIMG2D_BLEND_ROUND_MASK (3 << 0)
+#define FIMG2D_BLEND_ROUND_SHIFT (0)
+
+/* FIMG2D_ROTATE_REG */
+#define FIMG2D_MSK_ROTATE_90 (1 << 8)
+#define FIMG2D_PAT_ROTATE_90 (1 << 4)
+#define FIMG2D_SRC_ROTATE_90 (1 << 0)
+
+/* FIMG2D_SRC_MSK_DIRECT_REG */
+#define FIMG2D_MSK_Y_DIR_NEGATIVE (1 << 5)
+#define FIMG2D_MSK_X_DIR_NEGATIVE (1 << 4)
+
+#define FIMG2D_SRC_Y_DIR_NEGATIVE (1 << 1)
+#define FIMG2D_SRC_X_DIR_NEGATIVE (1 << 0)
+
+/* FIMG2D_DST_PAT_DIRECT_REG */
+#define FIMG2D_PAT_Y_DIR_NEGATIVE (1 << 5)
+#define FIMG2D_PAT_X_DIR_NEGATIVE (1 << 4)
+
+#define FIMG2D_DST_Y_DIR_NEGATIVE (1 << 1)
+#define FIMG2D_DST_X_DIR_NEGATIVE (1 << 0)
+
+/* FIMG2D_SRC_SELECT_REG & FIMG2D_DST_SELECT_REG */
+#define FIMG2D_IMAGE_TYPE_MEMORY (0 << 0)
+#define FIMG2D_IMAGE_TYPE_FGCOLOR (1 << 0)
+#define FIMG2D_IMAGE_TYPE_BGCOLOR (2 << 0)
+
+/* FIMG2D_SRC_BASE_ADDR_REG */
+/* FIMG2D_DST_BASE_ADDR_REG */
+/* FIMG2D_PAT_BASE_ADDR_REG */
+/* FIMG2D_MSK_BASE_ADDR_REG */
+
+/* FIMG2D_SRC_STRIDE_REG */
+/* FIMG2D_DST_STRIDE_REG */
+/* FIMG2D_PAT_STRIDE_REG */
+/* FIMG2D_MSK_STRIDE_REG */
+
+/* FIMG2D_SRC_COLOR_MODE_REG & FIMG2D_DST_COLOR_MODE_REG */
+#define FIMG2D_YCBCR_NARROW (0 << 17)
+#define FIMG2D_YCBCR_WIDE (1 << 17)
+
+#define FIMG2D_CSC_601 (0 << 16)
+#define FIMG2D_CSC_709 (1 << 16)
+
+#define FIMG2D_YCBCR_ORDER_P1_CRY1CBY0 (0 << 12)
+#define FIMG2D_YCBCR_ORDER_P1_CBY1CRY0 (0 << 12)
+#define FIMG2D_YCBCR_ORDER_P1_Y1CRY0CB (0 << 12)
+#define FIMG2D_YCBCR_ORDER_P1_Y1CBY0CR (0 << 12)
+#define FIMG2D_YCBCR_ORDER_P2_CRCB (0 << 12)
+#define FIMG2D_YCBCR_ORDER_P2_CBCR (1 << 12)
+#define FIMG2D_YCBCR_ORDER_SHIFT (12)
+
+#define FIMG2D_YCBCR_1PLANE (0 << 8)
+#define FIMG2D_YCBCR_2PLANE (1 << 8)
+
+#define FIMG2D_RGB_ORDER_AXRGB (0 << 4)
+#define FIMG2D_RGB_ORDER_RGBAX (1 << 4)
+#define FIMG2D_RGB_ORDER_AXBGR (2 << 4)
+#define FIMG2D_RGB_ORDER_BGRAX (3 << 4)
+#define FIMG2D_RGB_ORDER_SHIFT (4)
+
+#define FIMG2D_COLOR_FORMAT_XRGB_8888 (0 << 0)
+#define FIMG2D_COLOR_FORMAT_ARGB_8888 (1 << 0)
+#define FIMG2D_COLOR_FORMAT_RGB_565 (2 << 0)
+#define FIMG2D_COLOR_FORMAT_XRGB_1555 (3 << 0)
+#define FIMG2D_COLOR_FORMAT_ARGB_1555 (4 << 0)
+#define FIMG2D_COLOR_FORMAT_XRGB_4444 (5 << 0)
+#define FIMG2D_COLOR_FORMAT_ARGB_4444 (6 << 0)
+#define FIMG2D_COLOR_FORMAT_PACKED_RGB_888 (7 << 0)
+#define FIMG2D_COLOR_FORMAT_YCBCR_444 (8 << 0)
+#define FIMG2D_COLOR_FORMAT_YCBCR_422 (9 << 0)
+#define FIMG2D_COLOR_FORMAT_YCBCR_420 (10 << 0)
+#define FIMG2D_COLOR_FORMAT_A8 (11 << 0)
+#define FIMG2D_COLOR_FORMAT_L8 (12 << 0)
+#define FIMG2D_COLOR_FORMAT_SHIFT (0)
+
+/* FIMG2D_PAT_COLOR_MODE_REG */
+#define FIMG2D_PAT_ORDER_AXRGB (0 << 4)
+#define FIMG2D_PAT_ORDER_RGBAX (1 << 4)
+#define FIMG2D_PAT_ORDER_AXBGR (2 << 4)
+#define FIMG2D_PAT_ORDER_BGRAX (3 << 4)
+
+#define FIMG2D_PAT_FORMAT_XRGB_8888 (0 << 0)
+#define FIMG2D_PAT_FORMAT_ARGB_8888 (1 << 0)
+#define FIMG2D_PAT_FORMAT_RGB_565 (2 << 0)
+#define FIMG2D_PAT_FORMAT_XRGB_1555 (3 << 0)
+#define FIMG2D_PAT_FORMAT_ARGB_1555 (4 << 0)
+#define FIMG2D_PAT_FORMAT_XRGB_4444 (5 << 0)
+#define FIMG2D_PAT_FORMAT_ARGB_4444 (6 << 0)
+#define FIMG2D_PAT_FORMAT_PACKED_RGB_888 (7 << 0)
+
+/* FIMG2D_SRC_LEFT_TOP_REG & FIMG2D_SRC_RIGHT_BOTTOM_REG */
+/* FIMG2D_DST_LEFT_TOP_REG & FIMG2D_DST_RIGHT_BOTTOM_REG */
+/* FIMG2D_MSK_LEFT_TOP_REG & FIMG2D_MSK_RIGHT_BOTTOM_REG */
+#define FIMG2D_COORD_LT_Y_SHIFT (16)
+#define FIMG2D_COORD_LT_X_SHIFT (0)
+#define FIMG2D_COORD_RB_Y_SHIFT (16)
+#define FIMG2D_COORD_RB_X_SHIFT (0)
+#define FIMG2D_COORD_MAX_HEIGHT (8000)
+#define FIMG2D_COORD_MAX_WIDTH (8000)
+
+/* FIMG2D_SRC_PLANE2_BASE_ADDR_REG */
+/* FIMG2D_DST_PLANE2_BASE_ADDR_REG */
+
+/* FIMG2D_SRC_REPEAT_MODE_REG */
+#define FIMG2D_SRC_REPEAT_NORMAL (0 << 0)
+#define FIMG2D_SRC_REPEAT_PAD (1 << 0)
+#define FIMG2D_SRC_REPEAT_REFLECT (2 << 0)
+#define FIMG2D_SRC_REPEAT_CLAMP (3 << 0)
+#define FIMG2D_SRC_REPEAT_NONE (4 << 0)
+#define FIMG2D_SRC_REPEAT_SHIFT (0)
+
+/* FIMG2D_MSK_REPEAT_MODE_REG */
+#define FIMG2D_MSK_REPEAT_NORMAL (0 << 0)
+#define FIMG2D_MSK_REPEAT_PAD (1 << 0)
+#define FIMG2D_MSK_REPEAT_REFLECT (2 << 0)
+#define FIMG2D_MSK_REPEAT_CLAMP (3 << 0)
+#define FIMG2D_MSK_REPEAT_SHIFT (0)
+
+/* FIMG2D_SRC_PAD_VALUE_REG */
+/* FIMG2D_MSK_PAD_VALUE_REG */
+
+/* FIMG2D_SRC_A8_RGB_EXT_REG */
+/* FIMG2D_DST_A8_RGB_EXT_REG */
+
+/* FIMG2D_SRC_SCALE_CTRL_REG & FIMG2D_MSK_SCALE_CTRL_REG */
+#define FIMG2D_SCALE_MODE_NEAREST (1 << 0)
+#define FIMG2D_SCALE_MODE_BILINEAR (2 << 0)
+
+/* FIMG2D_SRC_XSCALE_REG & FIMG2D_SRC_YSCALE_REG */
+/* FIMG2D_MSK_XSCALE_REG & FIMG2D_MSK_YSCALE_REG */
+#define FIMG2D_SCALE_FACTOR_INTG_SHIFT (16)
+#define FIMG2D_SCALE_FACTOR_FRAC_SHIFT (0)
+
+/* FIMG2D_PAT_SIZE_REG */
+#define FIMG2D_PAT_HEIGHT_SHIFT (16)
+#define FIMG2D_PAT_WIDTH_SHIFT (0)
+#define FIMG2D_MAX_PAT_HEIGHT (8000)
+#define FIMG2D_MAX_PAT_WIDTH (8000)
+
+/* FIMG2D_PAT_OFFSET_REG */
+#define FIMG2D_PAT_Y_OFFSET_SHIFT (16)
+#define FIMG2D_PAT_X_OFFSET_SHIFT (0)
+#define FIMG2D_MAX_PAT_Y_OFFSET (7999)
+#define FIMG2D_MAX_PAT_X_OFFSET (7999)
+
+/* FIMG2D_MSK_MODE_REG */
+#define FIMG2D_MSK_TYPE_ALPHA (0 << 8)
+#define FIMG2D_MSK_TYPE_ARGB (1 << 8)
+#define FIMG2D_MSK_TYPE_MIXED (2 << 8)
+
+#define FIMG2D_MSK_ORDER_AXRGB (0 << 4)
+#define FIMG2D_MSK_ORDER_RGBAX (1 << 4)
+#define FIMG2D_MSK_ORDER_AXBGR (2 << 4)
+#define FIMG2D_MSK_ORDER_BGRAX (3 << 4)
+#define FIMG2D_MSK_ORDER_SHIFT (4)
+
+#define FIMG2D_1BIT_MSK (0 << 0)
+#define FIMG2D_4BIT_MSK (1 << 0)
+#define FIMG2D_8BIT_MSK (2 << 0)
+#define FIMG2D_16BIT_MSK_565 (3 << 0)
+#define FIMG2D_16BIT_MSK_1555 (4 << 0)
+#define FIMG2D_16BIT_MSK_4444 (5 << 0)
+#define FIMG2D_32BIT_MSK_8888 (6 << 0)
+#define FIMG2D_4BIT_MSK_WINCE_AA_FONT (7 << 0)
+#define FIMG2D_MSK_FORMAT_SHIFT (0)
+
+/* FIMG2D_CW_LT_REG */
+#define FIMG2D_CW_COORD_LT_Y_SHIFT (16)
+#define FIMG2D_CW_COORD_LT_X_SHIFT (0)
+#define FIMG2D_CW_COORD_RB_Y_SHIFT (16)
+#define FIMG2D_CW_COORD_RB_X_SHIFT (0)
+
+/* FIMG2D_THIRD_OPERAND_REG */
+#define FIMG2D_OPR3_MSKSEL_PAT (0 << 4)
+#define FIMG2D_OPR3_MSKSEL_FGCOLOR (1 << 4)
+#define FIMG2D_OPR3_MSKSEL_BGCOLOR (2 << 4)
+#define FIMG2D_OPR3_UNMSKSEL_PAT (0 << 0)
+#define FIMG2D_OPR3_UNMSKSEL_FGCOLOR (1 << 0)
+#define FIMG2D_OPR3_UNMSKSEL_BGCOLOR (2 << 0)
+
+/* FIMG2D_ROP4_REG */
+#define FIMG2D_MASKED_ROP3_SHIFT (8)
+#define FIMG2D_UNMASKED_ROP3_SHIFT (0)
+
+/* FIMG2D_ALPHA_REG */
+#define FIMG2D_GCOLOR_RGB_MASK (0xffffff)
+#define FIMG2D_GCOLOR_SHIFT (8)
+
+#define FIMG2D_GALPHA_MASK (0xff)
+#define FIMG2D_GALPHA_SHIFT (0)
+
+/* FIMG2D_FG_COLOR_REG */
+/* FIMG2D_BG_COLOR_REG */
+/* FIMG2D_BS_COLOR_REG */
+/* FIMG2D_SF_COLOR_REG */
+
+/* FIMG2D_SRC_COLORKEY_CTRL_REG */
+/* FIMG2D_SRC_COLORKEY_DR_MIN_REG */
+/* FIMG2D_SRC_COLORKEY_DR_MAX_REG */
+
+/* FIMG2D_DST_COLORKEY_CTRL_REG */
+/* FIMG2D_DST_COLORKEY_DR_MIN_REG */
+/* FIMG2D_DST_COLORKEY_DR_MAX_REG */
+
+/* FIMG2D_YCBCR_SRC_COLORKEY_CTRL_REG */
+/* FIMG2D_YCBCR_SRC_COLORKEY_DR_MIN_REG */
+/* FIMG2D_YCBCR_SRC_COLORKEY_DR_MAX_REG */
+
+/* FIMG2D_YCBCR_DST_COLORKEY_CTRL_REG */
+/* FIMG2D_YCBCR_DST_COLORKEY_DR_MIN_REG */
+/* FIMG2D_YCBCR_DST_COLORKEY_DR_MAX_REG */
+
+#endif /* __FIMG2D4X_REGS_H */
diff --git a/drivers/media/video/exynos/fimg2d/fimg2d_cache.c b/drivers/media/video/exynos/fimg2d/fimg2d_cache.c
new file mode 100644
index 0000000..43489e4
--- /dev/null
+++ b/drivers/media/video/exynos/fimg2d/fimg2d_cache.c
@@ -0,0 +1,168 @@
+/* linux/drivers/media/video/samsung/fimg2d4x/fimg2d_cache.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Samsung Graphics 2D driver
+ *
+ * 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.
+*/
+
+#include <asm/pgtable.h>
+#include <asm/cacheflush.h>
+#include <linux/dma-mapping.h>
+
+#include "fimg2d.h"
+#include "fimg2d_cache.h"
+
+#define LV1_SHIFT 20
+#define LV1_PT_SIZE SZ_1M
+#define LV2_PT_SIZE SZ_1K
+#define LV2_BASE_MASK 0x3ff
+#define LV2_PT_MASK 0xff000
+#define LV2_SHIFT 12
+#define LV1_DESC_MASK 0x3
+#define LV2_DESC_MASK 0x2
+
+static inline unsigned long virt2phys(struct mm_struct *mm, unsigned long vaddr)
+{
+ unsigned long *pgd;
+ unsigned long *lv1d, *lv2d;
+
+ pgd = (unsigned long *)mm->pgd;
+
+ lv1d = pgd + (vaddr >> LV1_SHIFT);
+
+ if ((*lv1d & LV1_DESC_MASK) != 0x1) {
+ fimg2d_debug("invalid LV1 descriptor, "
+ "pgd %p lv1d 0x%lx vaddr 0x%lx\n",
+ pgd, *lv1d, vaddr);
+ return 0;
+ }
+
+ lv2d = (unsigned long *)phys_to_virt(*lv1d & ~LV2_BASE_MASK) +
+ ((vaddr & LV2_PT_MASK) >> LV2_SHIFT);
+
+ if ((*lv2d & LV2_DESC_MASK) != 0x2) {
+ fimg2d_debug("invalid LV2 descriptor, "
+ "pgd %p lv2d 0x%lx vaddr 0x%lx\n",
+ pgd, *lv2d, vaddr);
+ return 0;
+ }
+
+ return (*lv2d & PAGE_MASK) | (vaddr & (PAGE_SIZE-1));
+}
+
+#ifdef CONFIG_OUTER_CACHE
+void fimg2d_dma_sync_outer(struct mm_struct *mm, unsigned long vaddr,
+ size_t size, enum cache_opr opr)
+{
+ int len;
+ unsigned long cur, end, next, paddr;
+
+ cur = vaddr;
+ end = vaddr + size;
+
+ if (opr == CACHE_CLEAN) {
+ while (cur < end) {
+ next = (cur + PAGE_SIZE) & PAGE_MASK;
+ if (next > end)
+ next = end;
+ len = next - cur;
+
+ paddr = virt2phys(mm, cur);
+ if (paddr)
+ outer_clean_range(paddr, paddr + len);
+ cur += len;
+ }
+ } else if (opr == CACHE_FLUSH) {
+ while (cur < end) {
+ next = (cur + PAGE_SIZE) & PAGE_MASK;
+ if (next > end)
+ next = end;
+ len = next - cur;
+
+ paddr = virt2phys(mm, cur);
+ if (paddr)
+ outer_flush_range(paddr, paddr + len);
+ cur += len;
+ }
+ }
+}
+
+void fimg2d_clean_outer_pagetable(struct mm_struct *mm, unsigned long vaddr,
+ size_t size)
+{
+ unsigned long *pgd;
+ unsigned long *lv1, *lv1end;
+ unsigned long lv2pa;
+
+ pgd = (unsigned long *)mm->pgd;
+
+ lv1 = pgd + (vaddr >> LV1_SHIFT);
+ lv1end = pgd + ((vaddr + size + LV1_PT_SIZE-1) >> LV1_SHIFT);
+
+ /* clean level1 page table */
+ outer_clean_range(virt_to_phys(lv1), virt_to_phys(lv1end));
+
+ do {
+ lv2pa = *lv1 & ~LV2_BASE_MASK; /* lv2 pt base */
+ /* clean level2 page table */
+ outer_clean_range(lv2pa, lv2pa + LV2_PT_SIZE);
+ lv1++;
+ } while (lv1 != lv1end);
+}
+#endif /* CONFIG_OUTER_CACHE */
+
+enum pt_status fimg2d_check_pagetable(struct mm_struct *mm, unsigned long vaddr,
+ size_t size)
+{
+ unsigned long *pgd;
+ unsigned long *lv1d, *lv2d;
+
+ pgd = (unsigned long *)mm->pgd;
+
+ size += offset_in_page(vaddr);
+ size = PAGE_ALIGN(size);
+
+ while ((long)size > 0) {
+ lv1d = pgd + (vaddr >> LV1_SHIFT);
+
+ /*
+ * check level 1 descriptor
+ * lv1 desc[1:0] = 00 --> fault
+ * lv1 desc[1:0] = 01 --> page table
+ * lv1 desc[1:0] = 10 --> section or supersection
+ * lv1 desc[1:0] = 11 --> reserved
+ */
+ if ((*lv1d & LV1_DESC_MASK) != 0x1) {
+ fimg2d_debug("invalid LV1 descriptor, "
+ "pgd %p lv1d 0x%lx vaddr 0x%lx\n",
+ pgd, *lv1d, vaddr);
+ return PT_FAULT;
+ }
+
+ lv2d = (unsigned long *)phys_to_virt(*lv1d & ~LV2_BASE_MASK) +
+ ((vaddr & LV2_PT_MASK) >> LV2_SHIFT);
+
+ /*
+ * check level 2 descriptor
+ * lv2 desc[1:0] = 00 --> fault
+ * lv2 desc[1:0] = 01 --> 64k pgae
+ * lv2 desc[1:0] = 1x --> 4k page
+ */
+ if ((*lv2d & LV2_DESC_MASK) != 0x2) {
+ fimg2d_debug("invalid LV2 descriptor, "
+ "pgd %p lv2d 0x%lx vaddr 0x%lx\n",
+ pgd, *lv2d, vaddr);
+ return PT_FAULT;
+ }
+
+ vaddr += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+
+ return PT_NORMAL;
+}
diff --git a/drivers/media/video/exynos/fimg2d/fimg2d_cache.h b/drivers/media/video/exynos/fimg2d/fimg2d_cache.h
new file mode 100644
index 0000000..f337ea5
--- /dev/null
+++ b/drivers/media/video/exynos/fimg2d/fimg2d_cache.h
@@ -0,0 +1,96 @@
+/* linux/drivers/media/video/samsung/fimg2d4x/fimg2d_cache.h
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Samsung Graphics 2D driver
+ *
+ * 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.
+*/
+
+#include <asm/cacheflush.h>
+#include <linux/dma-mapping.h>
+#include <plat/cpu.h>
+#include "fimg2d.h"
+
+#define L1_CACHE_SIZE SZ_64K
+#define L2_CACHE_SIZE SZ_1M
+#define LINE_FLUSH_THRESHOLD SZ_1K
+
+/**
+ * cache_opr - [kernel] cache operation mode
+ * @CACHE_INVAL: do cache invalidate
+ * @CACHE_CLEAN: do cache clean for src and msk image
+ * @CACHE_FLUSH: do cache clean and invalidate for dst image
+ * @CACHE_FLUSH_INNER_ALL: clean and invalidate for innercache
+ * @CACHE_FLUSH_ALL: clean and invalidate for whole caches
+ */
+enum cache_opr {
+ CACHE_INVAL,
+ CACHE_CLEAN,
+ CACHE_FLUSH,
+ CACHE_FLUSH_INNER_ALL,
+ CACHE_FLUSH_ALL
+};
+
+/**
+ * @PT_NORMAL: pagetable exists
+ * @PT_FAULT: invalid pagetable
+ */
+enum pt_status {
+ PT_NORMAL,
+ PT_FAULT,
+};
+
+static inline bool is_inner_flushall(size_t size)
+{
+ if (soc_is_exynos5250())
+ return (size >= SZ_1M * 25) ? true : false;
+ else
+ return (size >= L1_CACHE_SIZE) ? true : false;
+}
+
+static inline bool is_outer_flushall(size_t size)
+{
+ return (size >= L2_CACHE_SIZE) ? true : false;
+}
+
+static inline bool is_inner_flushrange(size_t hole)
+{
+ if (!soc_is_exynos5250())
+ return true;
+ else {
+ if (hole < LINE_FLUSH_THRESHOLD)
+ return true;
+ else
+ return false; /* line-by-line flush */
+ }
+}
+
+static inline bool is_outer_flushrange(size_t hole)
+{
+ if (hole < LINE_FLUSH_THRESHOLD)
+ return true;
+ else
+ return false; /* line-by-line flush */
+}
+
+static inline void fimg2d_dma_sync_inner(unsigned long addr, size_t size, int dir)
+{
+ if (dir == DMA_TO_DEVICE)
+ dmac_map_area((void *)addr, size, dir);
+ else if (dir == DMA_BIDIRECTIONAL)
+ dmac_flush_range((void *)addr, (void *)(addr + size));
+}
+
+static inline void fimg2d_dma_unsync_inner(unsigned long addr, size_t size, int dir)
+{
+ if (dir == DMA_TO_DEVICE)
+ dmac_unmap_area((void *)addr, size, dir);
+}
+
+void fimg2d_clean_outer_pagetable(struct mm_struct *mm, unsigned long addr, size_t size);
+void fimg2d_dma_sync_outer(struct mm_struct *mm, unsigned long addr, size_t size, enum cache_opr opr);
+enum pt_status fimg2d_check_pagetable(struct mm_struct *mm, unsigned long addr, size_t size);
diff --git a/drivers/media/video/exynos/fimg2d/fimg2d_clk.c b/drivers/media/video/exynos/fimg2d/fimg2d_clk.c
new file mode 100644
index 0000000..24a80ae
--- /dev/null
+++ b/drivers/media/video/exynos/fimg2d/fimg2d_clk.c
@@ -0,0 +1,170 @@
+/* linux/drivers/media/video/samsung/fimg2d4x/fimg2d_clk.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Samsung Graphics 2D driver
+ *
+ * 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.
+*/
+
+#include <linux/clk.h>
+#include <linux/atomic.h>
+#include <linux/sched.h>
+#include <plat/cpu.h>
+#include <plat/fimg2d.h>
+#include "fimg2d.h"
+#include "fimg2d_clk.h"
+
+void fimg2d_clk_on(struct fimg2d_control *info)
+{
+ spin_lock(&info->bltlock);
+ clk_enable(info->clock);
+ atomic_set(&info->clkon, 1);
+ spin_unlock(&info->bltlock);
+
+ fimg2d_debug("clock enable\n");
+}
+
+void fimg2d_clk_off(struct fimg2d_control *info)
+{
+ spin_lock(&info->bltlock);
+ atomic_set(&info->clkon, 0);
+ clk_disable(info->clock);
+ spin_unlock(&info->bltlock);
+
+ fimg2d_debug("clock disable\n");
+}
+
+void fimg2d_clk_save(struct fimg2d_control *info)
+{
+ if (soc_is_exynos4212() || soc_is_exynos4412()) {
+ struct fimg2d_platdata *pdata;
+ struct clk *sclk;
+
+ pdata = to_fimg2d_plat(info->dev);
+
+ spin_lock(&info->bltlock);
+ sclk = clk_get(info->dev, pdata->clkname);
+ clk_set_rate(sclk, 50*MHZ); /* 800MHz/16=50MHz */
+ spin_unlock(&info->bltlock);
+
+ fimg2d_debug("%s clkrate=%lu\n", pdata->clkname, clk_get_rate(sclk));
+ }
+}
+
+void fimg2d_clk_restore(struct fimg2d_control *info)
+{
+ if (soc_is_exynos4212() || soc_is_exynos4412()) {
+ struct fimg2d_platdata *pdata;
+ struct clk *sclk, *pclk;
+
+ pdata = to_fimg2d_plat(info->dev);
+
+ spin_lock(&info->bltlock);
+ sclk = clk_get(info->dev, pdata->clkname);
+ pclk = clk_get(NULL, "pclk_acp");
+ clk_set_rate(sclk, clk_get_rate(pclk) * 2);
+ spin_unlock(&info->bltlock);
+
+ fimg2d_debug("%s(%lu) pclk_acp(%lu)\n", pdata->clkname,
+ clk_get_rate(sclk), clk_get_rate(pclk));
+ }
+}
+
+void fimg2d_clk_dump(struct fimg2d_control *info)
+{
+ struct fimg2d_platdata *pdata;
+ struct clk *sclk, *pclk, *aclk;
+
+ pdata = to_fimg2d_plat(info->dev);
+
+ if (soc_is_exynos4212() || soc_is_exynos4412()) {
+ sclk = clk_get(info->dev, pdata->clkname);
+ pclk = clk_get(NULL, "pclk_acp");
+
+ printk(KERN_INFO "%s(%lu) pclk_acp(%lu)\n",
+ pdata->clkname,
+ clk_get_rate(sclk), clk_get_rate(pclk));
+ } else {
+ aclk = clk_get(NULL, "aclk_acp");
+ pclk = clk_get(NULL, "pclk_acp");
+
+ printk(KERN_INFO "aclk_acp(%lu) pclk_acp(%lu)\n",
+ clk_get_rate(aclk), clk_get_rate(pclk));
+ }
+}
+
+int fimg2d_clk_setup(struct fimg2d_control *info)
+{
+ struct fimg2d_platdata *pdata;
+ struct clk *parent, *sclk;
+ int ret = 0;
+
+ sclk = parent = NULL;
+ pdata = to_fimg2d_plat(info->dev);
+
+ if (soc_is_exynos4212() || soc_is_exynos4412()) {
+ /* clock for setting parent and rate */
+ parent = clk_get(info->dev, pdata->parent_clkname);
+ if (IS_ERR(parent)) {
+ printk(KERN_ERR "FIMG2D failed to get parent clk\n");
+ ret = -ENOENT;
+ goto err_clk1;
+ }
+ fimg2d_debug("parent clk: %s\n", pdata->parent_clkname);
+
+ sclk = clk_get(info->dev, pdata->clkname);
+ if (IS_ERR(sclk)) {
+ printk(KERN_ERR "FIMG2D failed to get sclk\n");
+ ret = -ENOENT;
+ goto err_clk2;
+ }
+ fimg2d_debug("sclk: %s\n", pdata->clkname);
+
+ if (clk_set_parent(sclk, parent))
+ printk(KERN_ERR "FIMG2D failed to set parent\n");
+
+ clk_set_rate(sclk, pdata->clkrate);
+ fimg2d_debug("clkrate: %ld parent clkrate: %ld\n",
+ clk_get_rate(sclk), clk_get_rate(parent));
+ } else {
+ fimg2d_debug("aclk_acp(%lu) pclk_acp(%lu)\n",
+ clk_get_rate(clk_get(NULL, "aclk_acp")),
+ clk_get_rate(clk_get(NULL, "pclk_acp")));
+ }
+
+ /* clock for gating */
+ info->clock = clk_get(info->dev, pdata->gate_clkname);
+ if (IS_ERR(info->clock)) {
+ printk(KERN_ERR "FIMG2D failed to get gate clk\n");
+ ret = -ENOENT;
+ goto err_clk3;
+ }
+ fimg2d_debug("gate clk: %s\n", pdata->gate_clkname);
+ return ret;
+
+err_clk3:
+ if (sclk)
+ clk_put(sclk);
+
+err_clk2:
+ if (parent)
+ clk_put(parent);
+
+err_clk1:
+ return ret;
+}
+
+void fimg2d_clk_release(struct fimg2d_control *info)
+{
+ clk_put(info->clock);
+ if (soc_is_exynos4212() || soc_is_exynos4412()) {
+ struct fimg2d_platdata *pdata;
+ pdata = to_fimg2d_plat(info->dev);
+ clk_put(clk_get(info->dev, pdata->clkname));
+ clk_put(clk_get(info->dev, pdata->parent_clkname));
+ }
+}
diff --git a/drivers/media/video/exynos/fimg2d/fimg2d_clk.h b/drivers/media/video/exynos/fimg2d/fimg2d_clk.h
new file mode 100644
index 0000000..c3fbf674
--- /dev/null
+++ b/drivers/media/video/exynos/fimg2d/fimg2d_clk.h
@@ -0,0 +1,26 @@
+/* linux/drivers/media/video/samsung/fimg2d4x/fimg2d_clk.h
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Samsung Graphics 2D driver
+ *
+ * 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.
+*/
+
+#ifndef __FIMG2D_CLK_H__
+#define __FIMG2D_CLK_H__
+
+#include "fimg2d.h"
+
+int fimg2d_clk_setup(struct fimg2d_control *info);
+void fimg2d_clk_release(struct fimg2d_control *info);
+void fimg2d_clk_on(struct fimg2d_control *info);
+void fimg2d_clk_off(struct fimg2d_control *info);
+void fimg2d_clk_save(struct fimg2d_control *info);
+void fimg2d_clk_restore(struct fimg2d_control *info);
+void fimg2d_clk_dump(struct fimg2d_control *info);
+
+#endif /* __FIMG2D_CLK_H__ */
diff --git a/drivers/media/video/exynos/fimg2d/fimg2d_ctx.c b/drivers/media/video/exynos/fimg2d/fimg2d_ctx.c
new file mode 100644
index 0000000..de67935
--- /dev/null
+++ b/drivers/media/video/exynos/fimg2d/fimg2d_ctx.c
@@ -0,0 +1,290 @@
+/* linux/drivers/media/video/samsung/fimg2d4x/fimg2d_ctx.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Samsung Graphics 2D driver
+ *
+ * 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.
+*/
+
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
+#include <plat/fimg2d.h>
+#include "fimg2d.h"
+#include "fimg2d_ctx.h"
+#include "fimg2d_cache.h"
+#include "fimg2d_helper.h"
+
+static int fimg2d_check_params(struct fimg2d_blit __user *u)
+{
+ int w, h, i;
+ struct fimg2d_scale *s;
+ struct fimg2d_param *p = &u->param;
+ struct fimg2d_image *m, *um[MAX_IMAGES] = image_table(u);
+ struct fimg2d_rect *r;
+
+ if (!u->dst)
+ return -1;
+
+ /* DST op makes no effect */
+ if (u->op < 0 || u->op == BLIT_OP_DST || u->op >= BLIT_OP_END)
+ return -1;
+
+ if (p->scaling.mode) {
+ s = &p->scaling;
+ if (!s->src_w || !s->src_h || !s->dst_w || !s->dst_h)
+ return -1;
+ }
+
+ for (i = 0; i < MAX_IMAGES; i++) {
+ if (!um[i])
+ continue;
+
+ m = um[i];
+ r = &m->rect;
+ w = m->width;
+ h = m->height;
+
+ /* 8000: max width & height */
+ if (w > 8000 || h > 8000 ||
+ r->x1 < 0 || r->x2 > w ||
+ r->y1 < 0 || r->y2 > h ||
+ r->x1 == r->x2 || r->y1 == r->y2) {
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static void fimg2d_fixup_params(struct fimg2d_bltcmd *cmd)
+{
+ struct fimg2d_param *p = &cmd->param;
+ struct fimg2d_scale *s;
+ struct fimg2d_image *m;
+ struct fimg2d_rect *r;
+
+ m = &cmd->image[IDST];
+ r = &m->rect;
+
+ if (r->x2 > m->width)
+ r->x2 = m->width;
+
+ if (r->y2 > m->height)
+ r->y2 = m->height;
+
+ if (p->scaling.mode) {
+ s = &p->scaling;
+ if ((s->src_w == s->dst_w) && (s->src_h == s->dst_h))
+ s->mode = NO_SCALING;
+ }
+}
+
+static int fimg2d_check_dma_sync(struct fimg2d_bltcmd *cmd)
+{
+ struct mm_struct *mm = cmd->ctx->mm;
+ struct fimg2d_image *m;
+ struct fimg2d_rect *r;
+ struct fimg2d_dma *c;
+ enum pt_status pt;
+ int clip_x, clip_w, clip_h, y, dir, i;
+ unsigned long clip_start;
+
+ for (i = 0; i < MAX_IMAGES; i++) {
+ m = &cmd->image[i];
+ c = &cmd->dma[i];
+ r = &m->rect;
+
+ if (m->addr.type == ADDR_NONE)
+ continue;
+
+ /* caculate horizontally clipped region */
+ c->addr = m->addr.start + (m->stride * r->y1);
+ c->size = m->stride * (r->y2 - r->y1);
+
+ /* check pagetable */
+ if (m->addr.type == ADDR_USER) {
+ pt = fimg2d_check_pagetable(mm, c->addr, c->size);
+ if (pt == PT_FAULT)
+ return -1;
+ }
+
+ if (m->need_cacheopr && i != IMAGE_TMP) {
+ c->cached = c->size;
+ cmd->dma_all += c->cached;
+ }
+ }
+
+#ifdef PERF_PROFILE
+ perf_start(cmd->ctx, PERF_INNERCACHE);
+#endif
+ if (is_inner_flushall(cmd->dma_all))
+ flush_all_cpu_caches();
+ else {
+ for (i = 0; i < MAX_IMAGES; i++) {
+ m = &cmd->image[i];
+ c = &cmd->dma[i];
+ r = &m->rect;
+
+ if (m->addr.type == ADDR_NONE)
+ continue;
+
+ if (c->cached) {
+ if (i == IMAGE_DST)
+ dir = DMA_BIDIRECTIONAL;
+ else
+ dir = DMA_TO_DEVICE;
+
+ clip_w = width2bytes(r->x2 - r->x1, m->fmt);
+
+ if (is_inner_flushrange(m->stride - clip_w))
+ fimg2d_dma_sync_inner(c->addr, c->cached, dir);
+ else {
+ clip_x = pixel2offset(r->x1, m->fmt);
+ clip_h = r->y2 - r->y1;
+ for (y = 0; y < clip_h; y++) {
+ clip_start = c->addr + (m->stride * y) + clip_x;
+ fimg2d_dma_sync_inner(clip_start, clip_w, dir);
+ }
+ }
+ }
+ }
+ }
+#ifdef PERF_PROFILE
+ perf_end(cmd->ctx, PERF_INNERCACHE);
+#endif
+
+#ifdef CONFIG_OUTER_CACHE
+#ifdef PERF_PROFILE
+ perf_start(cmd->ctx, PERF_OUTERCACHE);
+#endif
+ if (is_outer_flushall(cmd->dma_all))
+ outer_flush_all();
+ else {
+ for (i = 0; i < MAX_IMAGES; i++) {
+ m = &cmd->image[i];
+ c = &cmd->dma[i];
+ r = &m->rect;
+
+ if (m->addr.type == ADDR_NONE)
+ continue;
+
+ /* clean pagetable */
+ if (m->addr.type == ADDR_USER)
+ fimg2d_clean_outer_pagetable(mm, c->addr, c->size);
+
+ if (c->cached) {
+ if (i == IMAGE_DST)
+ dir = CACHE_FLUSH;
+ else
+ dir = CACHE_CLEAN;
+
+ clip_w = width2bytes(r->x2 - r->x1, m->fmt);
+
+ if (is_outer_flushrange(m->stride - clip_w))
+ fimg2d_dma_sync_outer(mm, c->addr, c->cached, dir);
+ else {
+ clip_x = pixel2offset(r->x1, m->fmt);
+ clip_h = r->y2 - r->y1;
+ for (y = 0; y < clip_h; y++) {
+ clip_start = c->addr + (m->stride * y) + clip_x;
+ fimg2d_dma_sync_outer(mm, clip_start, clip_w, dir);
+ }
+ }
+ }
+ }
+ }
+#ifdef PERF_PROFILE
+ perf_end(cmd->ctx, PERF_OUTERCACHE);
+#endif
+#endif
+
+ return 0;
+}
+
+int fimg2d_add_command(struct fimg2d_control *info, struct fimg2d_context *ctx,
+ struct fimg2d_blit __user *u)
+{
+ int i;
+ struct fimg2d_bltcmd *cmd;
+ struct fimg2d_image *um[MAX_IMAGES] = image_table(u);
+
+#ifdef CONFIG_VIDEO_FIMG2D_DEBUG
+ fimg2d_print_params(u);
+#endif
+
+ if (info->err) {
+ printk(KERN_ERR "[%s] device error, do sw fallback\n", __func__);
+ return -EFAULT;
+ }
+
+ if (fimg2d_check_params(u)) {
+ printk(KERN_ERR "[%s] invalid params\n", __func__);
+ fimg2d_print_params(u);
+ return -EINVAL;
+ }
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd)
+ return -ENOMEM;
+
+ cmd->ctx = ctx;
+ cmd->op = u->op;
+ cmd->seq_no = u->seq_no;
+ cmd->sync = u->sync;
+
+ if (copy_from_user(&cmd->param, &u->param, sizeof(cmd->param)))
+ goto err_user;
+
+ for (i = 0; i < MAX_IMAGES; i++) {
+ if (!um[i])
+ continue;
+
+ if (copy_from_user(&cmd->image[i], um[i], sizeof(cmd->image[i])))
+ goto err_user;
+ }
+
+ fimg2d_fixup_params(cmd);
+
+ if (fimg2d_check_dma_sync(cmd))
+ goto err_user;
+
+ /* add command node and increase ncmd */
+ spin_lock(&info->bltlock);
+ if (atomic_read(&info->suspended)) {
+ fimg2d_debug("fimg2d suspended, do sw fallback\n");
+ spin_unlock(&info->bltlock);
+ goto err_user;
+ }
+ atomic_inc(&ctx->ncmd);
+ fimg2d_enqueue(&cmd->node, &info->cmd_q);
+ fimg2d_debug("ctx %p pgd %p ncmd(%d) seq_no(%u)\n",
+ cmd->ctx, (unsigned long *)cmd->ctx->mm->pgd,
+ atomic_read(&ctx->ncmd), cmd->seq_no);
+ spin_unlock(&info->bltlock);
+
+ return 0;
+
+err_user:
+ kfree(cmd);
+ return -EFAULT;
+}
+
+void fimg2d_add_context(struct fimg2d_control *info, struct fimg2d_context *ctx)
+{
+ atomic_set(&ctx->ncmd, 0);
+ init_waitqueue_head(&ctx->wait_q);
+
+ atomic_inc(&info->nctx);
+ fimg2d_debug("ctx %p nctx(%d)\n", ctx, atomic_read(&info->nctx));
+}
+
+void fimg2d_del_context(struct fimg2d_control *info, struct fimg2d_context *ctx)
+{
+ atomic_dec(&info->nctx);
+ fimg2d_debug("ctx %p nctx(%d)\n", ctx, atomic_read(&info->nctx));
+}
diff --git a/drivers/media/video/exynos/fimg2d/fimg2d_ctx.h b/drivers/media/video/exynos/fimg2d/fimg2d_ctx.h
new file mode 100644
index 0000000..19c9658
--- /dev/null
+++ b/drivers/media/video/exynos/fimg2d/fimg2d_ctx.h
@@ -0,0 +1,42 @@
+/* linux/drivers/media/video/samsung/fimg2d4x/fimg2d_ctx.h
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Samsung Graphics 2D driver
+ *
+ * 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.
+*/
+
+#include "fimg2d.h"
+#include "fimg2d_helper.h"
+
+static inline void fimg2d_enqueue(struct list_head *node, struct list_head *q)
+{
+ list_add_tail(node, q);
+}
+
+static inline void fimg2d_dequeue(struct list_head *node)
+{
+ list_del(node);
+}
+
+static inline int fimg2d_queue_is_empty(struct list_head *q)
+{
+ return list_empty(q);
+}
+
+static inline struct fimg2d_bltcmd *fimg2d_get_first_command(struct fimg2d_control *info)
+{
+ if (list_empty(&info->cmd_q))
+ return NULL;
+ else
+ return list_first_entry(&info->cmd_q, struct fimg2d_bltcmd, node);
+}
+
+void fimg2d_add_context(struct fimg2d_control *info, struct fimg2d_context *ctx);
+void fimg2d_del_context(struct fimg2d_control *info, struct fimg2d_context *ctx);
+int fimg2d_add_command(struct fimg2d_control *info, struct fimg2d_context *ctx,
+ struct fimg2d_blit __user *u);
diff --git a/drivers/media/video/exynos/fimg2d/fimg2d_drv.c b/drivers/media/video/exynos/fimg2d/fimg2d_drv.c
new file mode 100644
index 0000000..4513c08
--- /dev/null
+++ b/drivers/media/video/exynos/fimg2d/fimg2d_drv.c
@@ -0,0 +1,476 @@
+/* linux/drivers/media/video/samsung/fimg2d4x/fimg2d_drv.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Samsung Graphics 2D driver
+ *
+ * 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.
+*/
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/poll.h>
+#include <linux/platform_device.h>
+#include <linux/miscdevice.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/dma-mapping.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/atomic.h>
+#include <linux/delay.h>
+#include <asm/cacheflush.h>
+#include <plat/cpu.h>
+#include <plat/fimg2d.h>
+#include <plat/sysmmu.h>
+#ifdef CONFIG_PM_RUNTIME
+#include <linux/pm_runtime.h>
+#endif
+#include "fimg2d.h"
+#include "fimg2d_clk.h"
+#include "fimg2d_ctx.h"
+#include "fimg2d_helper.h"
+
+#define CTX_TIMEOUT msecs_to_jiffies(5000)
+
+static struct fimg2d_control *info;
+
+static void fimg2d_worker(struct work_struct *work)
+{
+ fimg2d_debug("start kernel thread\n");
+ info->blit(info);
+}
+
+static DECLARE_WORK(fimg2d_work, fimg2d_worker);
+
+/**
+ * @irq: irq number
+ * @dev_id: pointer to private data
+ */
+static irqreturn_t fimg2d_irq(int irq, void *dev_id)
+{
+ fimg2d_debug("irq\n");
+ info->stop(info);
+
+ return IRQ_HANDLED;
+}
+
+static int fimg2d_sysmmu_fault_handler(struct device *dev,
+ enum exynos_sysmmu_inttype itype,
+ unsigned long pgtable_base, unsigned long fault_addr)
+{
+ struct fimg2d_bltcmd *cmd;
+
+ if (itype == SYSMMU_PAGEFAULT) {
+ printk(KERN_ERR "[%s] sysmmu page fault(0x%lx), pgd(0x%lx)\n",
+ __func__, fault_addr, pgtable_base);
+ } else {
+ printk(KERN_ERR "[%s] sysmmu interrupt "
+ "type(%d) pgd(0x%lx) addr(0x%lx)\n",
+ __func__, itype, pgtable_base, fault_addr);
+ }
+
+ cmd = fimg2d_get_first_command(info);
+ if (!cmd) {
+ printk(KERN_ERR "[%s] null command\n", __func__);
+ goto next;
+ }
+
+ if (cmd->ctx->mm->pgd != phys_to_virt(pgtable_base)) {
+ printk(KERN_ERR "[%s] pgtable base is different from current command\n",
+ __func__);
+ goto next;
+ }
+
+ fimg2d_dump_command(cmd);
+
+next:
+ fimg2d_clk_dump(info);
+ info->dump(info);
+
+ BUG();
+ return 0;
+}
+
+static void fimg2d_context_wait(struct fimg2d_context *ctx)
+{
+ while (atomic_read(&ctx->ncmd)) {
+ if (!wait_event_timeout(ctx->wait_q, !atomic_read(&ctx->ncmd), CTX_TIMEOUT)) {
+ fimg2d_debug("[%s] ctx %p blit wait timeout\n", __func__, ctx);
+ if (info->err)
+ break;
+ }
+ }
+}
+
+static void fimg2d_request_bitblt(struct fimg2d_context *ctx)
+{
+ if (!atomic_read(&info->active)) {
+ atomic_set(&info->active, 1);
+ fimg2d_debug("dispatch ctx %p to kernel thread\n", ctx);
+ queue_work(info->work_q, &fimg2d_work);
+ }
+ fimg2d_context_wait(ctx);
+}
+
+static int fimg2d_open(struct inode *inode, struct file *file)
+{
+ struct fimg2d_context *ctx;
+
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx) {
+ printk(KERN_ERR "[%s] not enough memory for ctx\n", __func__);
+ return -ENOMEM;
+ }
+ file->private_data = (void *)ctx;
+
+ ctx->mm = current->mm;
+ fimg2d_debug("ctx %p current pgd %p init_mm pgd %p\n",
+ ctx, (unsigned long *)ctx->mm->pgd,
+ (unsigned long *)init_mm.pgd);
+
+ fimg2d_add_context(info, ctx);
+ return 0;
+}
+
+static int fimg2d_release(struct inode *inode, struct file *file)
+{
+ struct fimg2d_context *ctx = file->private_data;
+
+ fimg2d_debug("ctx %p\n", ctx);
+ while (1) {
+ if (!atomic_read(&ctx->ncmd))
+ break;
+
+ mdelay(2);
+ }
+ fimg2d_del_context(info, ctx);
+
+ kfree(ctx);
+ return 0;
+}
+
+static int fimg2d_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ return 0;
+}
+
+static unsigned int fimg2d_poll(struct file *file, struct poll_table_struct *wait)
+{
+ return 0;
+}
+
+static long fimg2d_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ int ret = 0;
+ struct fimg2d_context *ctx;
+ struct fimg2d_platdata *pdata;
+ union {
+ struct fimg2d_blit *blit;
+ struct fimg2d_version ver;
+ } u;
+
+ ctx = file->private_data;
+ if (!ctx) {
+ printk(KERN_ERR "[%s] missing ctx\n", __func__);
+ return -EFAULT;
+ }
+
+ switch (cmd) {
+ case FIMG2D_BITBLT_BLIT:
+ fimg2d_debug("FIMG2D_BITBLT_BLIT ctx: %p\n", ctx);
+ u.blit = (struct fimg2d_blit *)arg;
+
+ ret = fimg2d_add_command(info, ctx, u.blit);
+ if (!ret)
+ fimg2d_request_bitblt(ctx);
+#ifdef PERF_PROFILE
+ perf_print(ctx, u.blit->seq_no);
+ perf_clear(ctx);
+#endif
+ break;
+
+ case FIMG2D_BITBLT_SYNC:
+ fimg2d_debug("FIMG2D_BITBLT_SYNC ctx: %p\n", ctx);
+ /* FIXME: */
+ break;
+
+ case FIMG2D_BITBLT_VERSION:
+ fimg2d_debug("FIMG2D_BITBLT_VERSION ctx: %p\n", ctx);
+ pdata = to_fimg2d_plat(info->dev);
+ u.ver.hw = pdata->hw_ver;
+ u.ver.sw = 0;
+ fimg2d_debug("fimg2d version, hw: 0x%x sw: 0x%x\n", u.ver.hw, u.ver.sw);
+ if (copy_to_user((void *)arg, &u.ver, sizeof(u.ver)))
+ return -EFAULT;
+ break;
+
+ default:
+ printk(KERN_ERR "[%s] unknown ioctl\n", __func__);
+ ret = -EFAULT;
+ break;
+ }
+
+ return ret;
+}
+
+/* fops */
+static const struct file_operations fimg2d_fops = {
+ .owner = THIS_MODULE,
+ .open = fimg2d_open,
+ .release = fimg2d_release,
+ .mmap = fimg2d_mmap,
+ .poll = fimg2d_poll,
+ .unlocked_ioctl = fimg2d_ioctl,
+};
+
+/* miscdev */
+static struct miscdevice fimg2d_dev = {
+ .minor = FIMG2D_MINOR,
+ .name = "fimg2d",
+ .fops = &fimg2d_fops,
+};
+
+static int fimg2d_setup_controller(struct fimg2d_control *info)
+{
+ atomic_set(&info->suspended, 0);
+ atomic_set(&info->clkon, 0);
+ atomic_set(&info->busy, 0);
+ atomic_set(&info->nctx, 0);
+ atomic_set(&info->active, 0);
+
+ spin_lock_init(&info->bltlock);
+
+ INIT_LIST_HEAD(&info->cmd_q);
+ init_waitqueue_head(&info->wait_q);
+ fimg2d_register_ops(info);
+
+ info->work_q = create_singlethread_workqueue("kfimg2dd");
+ if (!info->work_q)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int fimg2d_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct fimg2d_platdata *pdata;
+ int ret;
+
+ pdata = to_fimg2d_plat(&pdev->dev);
+ if (!pdata) {
+ printk(KERN_ERR "FIMG2D failed to get platform data\n");
+ ret = -ENOMEM;
+ goto err_plat;
+ }
+
+ /* global structure */
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
+ if (!info) {
+ printk(KERN_ERR "FIMG2D failed to allocate memory for controller\n");
+ ret = -ENOMEM;
+ goto err_plat;
+ }
+
+ /* setup global info */
+ ret = fimg2d_setup_controller(info);
+ if (ret) {
+ printk(KERN_ERR "FIMG2D failed to setup controller\n");
+ goto err_setup;
+ }
+ info->dev = &pdev->dev;
+
+ /* memory region */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ printk(KERN_ERR "FIMG2D failed to get resource\n");
+ ret = -ENOENT;
+ goto err_res;
+ }
+
+ info->mem = request_mem_region(res->start, resource_size(res),
+ pdev->name);
+ if (!info->mem) {
+ printk(KERN_ERR "FIMG2D failed to request memory region\n");
+ ret = -ENOMEM;
+ goto err_region;
+ }
+
+ /* ioremap */
+ info->regs = ioremap(res->start, resource_size(res));
+ if (!info->regs) {
+ printk(KERN_ERR "FIMG2D failed to ioremap for SFR\n");
+ ret = -ENOENT;
+ goto err_map;
+ }
+ fimg2d_debug("device name: %s base address: 0x%lx\n",
+ pdev->name, (unsigned long)res->start);
+
+ /* irq */
+ info->irq = platform_get_irq(pdev, 0);
+ if (!info->irq) {
+ printk(KERN_ERR "FIMG2D failed to get irq resource\n");
+ ret = -ENOENT;
+ goto err_map;
+ }
+ fimg2d_debug("irq: %d\n", info->irq);
+
+ ret = request_irq(info->irq, fimg2d_irq, IRQF_DISABLED, pdev->name, info);
+ if (ret) {
+ printk(KERN_ERR "FIMG2D failed to request irq\n");
+ ret = -ENOENT;
+ goto err_irq;
+ }
+
+ ret = fimg2d_clk_setup(info);
+ if (ret) {
+ printk(KERN_ERR "FIMG2D failed to setup clk\n");
+ ret = -ENOENT;
+ goto err_clk;
+ }
+
+#ifdef CONFIG_PM_RUNTIME
+ pm_runtime_enable(info->dev);
+ fimg2d_debug("enable runtime pm\n");
+#endif
+
+ exynos_sysmmu_set_fault_handler(info->dev, fimg2d_sysmmu_fault_handler);
+ fimg2d_debug("register sysmmu page fault handler\n");
+
+ /* misc register */
+ ret = misc_register(&fimg2d_dev);
+ if (ret) {
+ printk(KERN_ERR "FIMG2D failed to register misc driver\n");
+ goto err_reg;
+ }
+
+ printk(KERN_INFO "Samsung Graphics 2D driver, (c) 2011 Samsung Electronics\n");
+ return 0;
+
+err_reg:
+ fimg2d_clk_release(info);
+
+err_clk:
+ free_irq(info->irq, NULL);
+
+err_irq:
+ iounmap(info->regs);
+
+err_map:
+ kfree(info->mem);
+
+err_region:
+ release_resource(info->mem);
+
+err_res:
+ destroy_workqueue(info->work_q);
+
+err_setup:
+ kfree(info);
+
+err_plat:
+ return ret;
+}
+
+static int fimg2d_remove(struct platform_device *pdev)
+{
+ free_irq(info->irq, NULL);
+
+ if (info->mem) {
+ iounmap(info->regs);
+ release_resource(info->mem);
+ kfree(info->mem);
+ }
+
+ destroy_workqueue(info->work_q);
+ misc_deregister(&fimg2d_dev);
+ kfree(info);
+
+#ifdef CONFIG_PM_RUNTIME
+ pm_runtime_disable(&pdev->dev);
+ fimg2d_debug("disable runtime pm\n");
+#endif
+
+ return 0;
+}
+
+static int fimg2d_suspend(struct device *dev)
+{
+ fimg2d_debug("suspend... start\n");
+ atomic_set(&info->suspended, 1);
+ while (1) {
+ if (fimg2d_queue_is_empty(&info->cmd_q))
+ break;
+
+ mdelay(2);
+ }
+ fimg2d_debug("suspend... done\n");
+ return 0;
+}
+
+static int fimg2d_resume(struct device *dev)
+{
+ fimg2d_debug("resume... start\n");
+ atomic_set(&info->suspended, 0);
+ fimg2d_debug("resume... done\n");
+ return 0;
+}
+
+#ifdef CONFIG_PM_RUNTIME
+static int fimg2d_runtime_suspend(struct device *dev)
+{
+ fimg2d_debug("runtime suspend... done\n");
+ return 0;
+}
+
+static int fimg2d_runtime_resume(struct device *dev)
+{
+ fimg2d_debug("runtime resume... done\n");
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops fimg2d_pm_ops = {
+ .suspend = fimg2d_suspend,
+ .resume = fimg2d_resume,
+#ifdef CONFIG_PM_RUNTIME
+ .runtime_suspend = fimg2d_runtime_suspend,
+ .runtime_resume = fimg2d_runtime_resume,
+#endif
+};
+
+static struct platform_driver fimg2d_driver = {
+ .probe = fimg2d_probe,
+ .remove = fimg2d_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "s5p-fimg2d",
+ .pm = &fimg2d_pm_ops,
+ },
+};
+
+static int __init fimg2d_register(void)
+{
+ return platform_driver_register(&fimg2d_driver);
+}
+
+static void __exit fimg2d_unregister(void)
+{
+ platform_driver_unregister(&fimg2d_driver);
+}
+
+module_init(fimg2d_register);
+module_exit(fimg2d_unregister);
+
+MODULE_AUTHOR("Eunseok Choi <es10.choi@samsung.com>");
+MODULE_AUTHOR("Jinsung Yang <jsgood.yang@samsung.com>");
+MODULE_DESCRIPTION("Samsung Graphics 2D driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/exynos/fimg2d/fimg2d_helper.c b/drivers/media/video/exynos/fimg2d/fimg2d_helper.c
new file mode 100644
index 0000000..c14df00
--- /dev/null
+++ b/drivers/media/video/exynos/fimg2d/fimg2d_helper.c
@@ -0,0 +1,148 @@
+/* linux/drivers/media/video/samsung/fimg2d4x/fimg2d_helper.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Samsung Graphics 2D driver
+ *
+ * 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.
+*/
+
+#include "fimg2d.h"
+#include "fimg2d_cache.h"
+#include "fimg2d_helper.h"
+
+static int bpptable[MSK_FORMAT_END+1] = {
+ 32, 32, 16, 16, 16, 16, 16, 24, /* rgb */
+ 8, 8, 8, 8, 8, 0, /* yuv */
+ 1, 4, 8, 16, 16, 16, 32, 0, /* msk */
+};
+
+int pixel2offset(int pixel, enum color_format cf)
+{
+ return (pixel * bpptable[cf]) >> 3;
+}
+
+int width2bytes(int width, enum color_format cf)
+{
+ int bpp = bpptable[cf];
+
+ switch (bpp) {
+ case 1:
+ return (width + 7) >> 3;
+ case 4:
+ return (width + 1) >> 1;
+ case 8:
+ case 16:
+ case 24:
+ case 32:
+ return width * bpp >> 3;
+ default:
+ return 0;
+ }
+}
+
+void perf_print(struct fimg2d_context *ctx, int seq_no)
+{
+ int i;
+ long time;
+ struct fimg2d_perf *perf;
+
+ for (i = 0; i < MAX_PERF_DESCS; i++) {
+ perf = &ctx->perf[i];
+ if (perf->valid != 0x11)
+ continue;
+ time = elapsed_usec(ctx, i);
+ printk(KERN_INFO "[FIMG2D PERF (%8s)] ctx(0x%08x) seq(%d) %8ld usec\n",
+ perfname(i), (unsigned int)ctx, seq_no, time);
+ }
+ printk(KERN_INFO "[FIMG2D PERF **]\n");
+}
+
+void fimg2d_print_params(struct fimg2d_blit __user *u)
+{
+ int i;
+ struct fimg2d_param *p = &u->param;
+ struct fimg2d_image *m, *ui[MAX_IMAGES] = image_table(u);
+ struct fimg2d_rect *r;
+
+ printk(KERN_INFO "op: %d\n", u->op);
+ printk(KERN_INFO "solid color: 0x%lx\n", p->solid_color);
+ printk(KERN_INFO "g_alpha: 0x%x\n", p->g_alpha);
+ printk(KERN_INFO "premultiplied: %d\n", p->premult);
+ printk(KERN_INFO "dither: %d\n", p->dither);
+ printk(KERN_INFO "rotate: %d\n", p->rotate);
+ printk(KERN_INFO "repeat mode: %d, pad color: 0x%lx\n",
+ p->repeat.mode, p->repeat.pad_color);
+ printk(KERN_INFO "bluescreen mode: %d, bs_color: 0x%lx bg_color: 0x%lx\n",
+ p->bluscr.mode,
+ p->bluscr.bs_color, p->bluscr.bg_color);
+ printk(KERN_INFO "scaling mode: %d, src:%d,%d dst:%d,%d\n",
+ p->scaling.mode,
+ p->scaling.src_w, p->scaling.src_h,
+ p->scaling.dst_w, p->scaling.dst_h);
+
+ for (i = 0; i < MAX_IMAGES; i++) {
+ if (!ui[i])
+ continue;
+
+ m = ui[i];
+ r = &m->rect;
+
+ printk(KERN_INFO "%s type: %d addr: 0x%lx\n",
+ imagename(i), m->addr.type, m->addr.start);
+ printk(KERN_INFO "%s width: %d height: %d stride: %d order: %d format: %d\n",
+ imagename(i), m->width, m->height, m->stride, m->order, m->fmt);
+ printk(KERN_INFO "%s rect LT(%d,%d) RB(%d,%d)\n",
+ imagename(i), r->x1, r->y1, r->x2, r->y2);
+ printk(KERN_INFO "%s cacheopr: %d\n", imagename(i), m->need_cacheopr);
+ }
+}
+
+void fimg2d_dump_command(struct fimg2d_bltcmd *cmd)
+{
+ int i;
+ struct fimg2d_param *p = &cmd->param;
+ struct fimg2d_image *m;
+ struct fimg2d_rect *r;
+ struct fimg2d_dma *c;
+
+ printk(KERN_INFO " op: %d\n", cmd->op);
+ printk(KERN_INFO " solid color: 0x%lx\n", p->solid_color);
+ printk(KERN_INFO " g_alpha: 0x%x\n", p->g_alpha);
+ printk(KERN_INFO " premultiplied: %d\n", p->premult);
+ printk(KERN_INFO " dither: %d\n", p->dither);
+ printk(KERN_INFO " rotate: %d\n", p->rotate);
+ printk(KERN_INFO " repeat mode: %d, pad color: 0x%lx\n",
+ p->repeat.mode, p->repeat.pad_color);
+ printk(KERN_INFO " bluescreen mode: %d, bs_color: 0x%lx bg_color: 0x%lx\n",
+ p->bluscr.mode, p->bluscr.bs_color, p->bluscr.bg_color);
+ printk(KERN_INFO " scaling mode: %d, s:%d,%d d:%d,%d\n",
+ p->scaling.mode,
+ p->scaling.src_w, p->scaling.src_h,
+ p->scaling.dst_w, p->scaling.dst_h);
+
+ for (i = 0; i < MAX_IMAGES; i++) {
+ m = &cmd->image[i];
+ if (m->addr.type == ADDR_NONE)
+ continue;
+
+ c = &cmd->dma[i];
+ r = &m->rect;
+
+ printk(KERN_INFO " %s type: %d addr: 0x%lx\n",
+ imagename(i), m->addr.type, m->addr.start);
+ printk(KERN_INFO " %s width: %d height: %d stride: %d order: %d format: %d\n",
+ imagename(i), m->width, m->height, m->stride, m->order, m->fmt);
+ printk(KERN_INFO " %s rect LT(%d,%d) RB(%d,%d)\n",
+ imagename(i), r->x1, r->y1, r->x2, r->y2);
+ printk(KERN_INFO " %s dma addr: 0x%lx size: 0x%x cached: 0x%x\n",
+ imagename(i), c->addr, c->size, c->cached);
+ }
+
+ printk(KERN_INFO " dma size all: 0x%x bytes\n", cmd->dma_all);
+ printk(KERN_INFO " ctx: %p seq_no(%u) sync(%d)\n",
+ cmd->ctx, cmd->seq_no, cmd->sync);
+}
diff --git a/drivers/media/video/exynos/fimg2d/fimg2d_helper.h b/drivers/media/video/exynos/fimg2d/fimg2d_helper.h
new file mode 100644
index 0000000..02e21ac
--- /dev/null
+++ b/drivers/media/video/exynos/fimg2d/fimg2d_helper.h
@@ -0,0 +1,141 @@
+/* linux/drivers/media/video/samsung/fimg2d4x/fimg2d_helper.h
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Samsung Graphics 2D driver
+ *
+ * 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.
+*/
+
+#ifndef __FIMG2D_HELPER_H
+#define __FIMG2D_HELPER_H
+
+#include <linux/sched.h>
+#include "fimg2d.h"
+
+static inline char *perfname(enum perf_desc id)
+{
+ switch (id) {
+ case PERF_INNERCACHE:
+ return "INNER$";
+ case PERF_OUTERCACHE:
+ return "OUTER$";
+ case PERF_BLIT:
+ return "BITBLT";
+ default:
+ return "";
+ }
+}
+
+static inline char *imagename(enum image_object image)
+{
+ switch (image) {
+ case IDST:
+ return "DST";
+ case ISRC:
+ return "SRC";
+ case IMSK:
+ return "MSK";
+ default:
+ return NULL;
+ }
+}
+
+static inline int is_opaque(enum color_format fmt)
+{
+ switch (fmt) {
+ case CF_ARGB_8888:
+ case CF_ARGB_1555:
+ case CF_ARGB_4444:
+ return 0;
+
+ case CF_XRGB_8888:
+ case CF_XRGB_1555:
+ case CF_XRGB_4444:
+ return 1;
+
+ case CF_RGB_565:
+ case CF_RGB_888:
+ return 1;
+
+ default:
+ break;
+ }
+
+ return 1;
+}
+
+static inline long elapsed_usec(struct fimg2d_context *ctx, enum perf_desc desc)
+{
+ struct fimg2d_perf *perf = &ctx->perf[desc];
+#ifdef PERF_TIMEVAL
+ struct timeval *start = &perf->start;
+ struct timeval *end = &perf->end;
+ long sec, usec;
+
+ sec = end->tv_sec - start->tv_sec;
+ if (end->tv_usec >= start->tv_usec) {
+ usec = end->tv_usec - start->tv_usec;
+ } else {
+ usec = end->tv_usec + 1000000 - start->tv_usec;
+ sec--;
+ }
+ return sec * 1000000 + usec;
+#else
+ return (long)(perf->end - perf->start)/1000;
+#endif
+}
+
+static inline void perf_start(struct fimg2d_context *ctx, enum perf_desc desc)
+{
+ struct fimg2d_perf *perf = &ctx->perf[desc];
+
+ if (!perf->valid) {
+#ifdef PERF_TIMEVAL
+ struct timeval time;
+ do_gettimeofday(&time);
+ perf->start = time;
+#else
+ long time;
+ perf->start = sched_clock();
+ time = perf->start / 1000;
+#endif
+ perf->valid = 0x01;
+ }
+}
+
+static inline void perf_end(struct fimg2d_context *ctx, enum perf_desc desc)
+{
+ struct fimg2d_perf *perf = &ctx->perf[desc];
+
+ if (perf->valid == 0x01) {
+#ifdef PERF_TIMEVAL
+ struct timeval time;
+ do_gettimeofday(&time);
+ perf->end = time;
+#else
+ long time;
+ perf->end = sched_clock();
+ time = perf->end / 1000;
+#endif
+ perf->valid |= 0x10;
+ }
+}
+
+static inline void perf_clear(struct fimg2d_context *ctx)
+{
+ int i;
+ for (i = 0; i < MAX_PERF_DESCS; i++)
+ ctx->perf[i].valid = 0;
+}
+
+int pixel2offset(int pixel, enum color_format cf);
+int width2bytes(int width, enum color_format cf);
+void perf_print(struct fimg2d_context *ctx, int seq_no);
+void fimg2d_print_params(struct fimg2d_blit __user *u);
+void fimg2d_dump_command(struct fimg2d_bltcmd *cmd);
+
+#endif /* __FIMG2D_HELPER_H */
diff --git a/drivers/media/video/exynos/gsc/Kconfig b/drivers/media/video/exynos/gsc/Kconfig
new file mode 100644
index 0000000..8d8b49d
--- /dev/null
+++ b/drivers/media/video/exynos/gsc/Kconfig
@@ -0,0 +1,28 @@
+config VIDEO_EXYNOS_GSCALER
+ bool "Exynos G-Scaler driver"
+ depends on VIDEO_EXYNOS
+ select MEDIA_EXYNOS
+ select V4L2_MEM2MEM_DEV
+ default n
+ help
+ This is a v4l2 driver for exynos G-Scaler device.
+
+if VIDEO_EXYNOS_GSCALER && VIDEOBUF2_CMA_PHYS
+comment "Reserved memory configurations"
+config VIDEO_SAMSUNG_MEMSIZE_GSC0
+ int "Memory size in kbytes for GSC0"
+ default "5120"
+
+config VIDEO_SAMSUNG_MEMSIZE_GSC1
+ int "Memory size in kbytes for GSC1"
+ default "5120"
+
+config VIDEO_SAMSUNG_MEMSIZE_GSC2
+ int "Memory size in kbytes for GSC2"
+ default "5120"
+
+config VIDEO_SAMSUNG_MEMSIZE_GSC3
+ int "Memory size in kbytes for GSC3"
+ default "5120"
+endif
+
diff --git a/drivers/media/video/exynos/gsc/Makefile b/drivers/media/video/exynos/gsc/Makefile
new file mode 100644
index 0000000..488ca2c
--- /dev/null
+++ b/drivers/media/video/exynos/gsc/Makefile
@@ -0,0 +1,2 @@
+gsc-objs := gsc-core.o gsc-vb2.o gsc-m2m.o gsc-output.o gsc-capture.o gsc-regs.o coef.o
+obj-$(CONFIG_VIDEO_EXYNOS_GSCALER) += gsc.o
diff --git a/drivers/media/video/exynos/gsc/coef.c b/drivers/media/video/exynos/gsc/coef.c
new file mode 100644
index 0000000..9fb9137
--- /dev/null
+++ b/drivers/media/video/exynos/gsc/coef.c
@@ -0,0 +1,275 @@
+/* linux/drivers/media/video/exynos/gsc/coef.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * G-scaler poly-phase filter coefficients
+ *
+ * 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.
+ */
+
+#include <linux/types.h>
+#include "gsc-core.h"
+
+/* 8-tap Filter Coefficient */
+const int h_coef_8t[7][16][8] = {
+ { /* Ratio <= 65536 (~8:8) */
+ { 0, 0, 0, 128, 0, 0, 0, 0 },/* 0 */
+ { -1, 2, -6, 127, 7, -2, 1, 0 },/* 1 */
+ { -1, 4, -12, 125, 16, -5, 1, 0 },/* 2 */
+ { -1, 5, -15, 120, 25, -8, 2, 0 },/* 3 */
+ { -1, 6, -18, 114, 35, -10, 3, -1 },/* 4 */
+ { -1, 6, -20, 107, 46, -13, 4, -1 },/* 5 */
+ { -2, 7, -21, 99, 57, -16, 5, -1 },/* 6 */
+ { -1, 6, -20, 89, 68, -18, 5, -1 },/* 7 */
+ { -1, 6, -20, 79, 79, -20, 6, -1 },/* 8 */
+ { -1, 5, -18, 68, 89, -20, 6, -1 },/* 9 */
+ { -1, 5, -16, 57, 99, -21, 7, -2 },/* 10 */
+ { -1, 4, -13, 46, 107, -20, 6, -1 },/* 11 */
+ { -1, 3, -10, 35, 114, -18, 6, -1 },/* 12 */
+ { 0, 2, -8, 25, 120, -15, 5, -1 },/* 13 */
+ { 0, 1, -5, 16, 125, -12, 4, -1 },/* 14 */
+ { 0, 1, -2, 7, 127, -6, 2, -1 } /* 15 */
+ },
+ { /* 65536 < Ratio <= 74898 (~8:7) */
+ { 3, -8, 14, 111, 13, -8, 3, 0 },/* 0 */
+ { 2, -6, 7, 112, 21, -10, 3, -1 },/* 1 */
+ { 2, -4, 1, 110, 28, -12, 4, -1 },/* 2 */
+ { 1, -2, -3, 106, 36, -13, 4, -1 },/* 3 */
+ { 1, -1, -7, 103, 44, -15, 4, -1 },/* 4 */
+ { 1, 1, -11, 97, 53, -16, 4, -1 },/* 5 */
+ { 0, 2, -13, 91, 61, -16, 4, -1 },/* 6 */
+ { 0, 3, -15, 85, 69, -17, 4, -1 },/* 7 */
+ { 0, 3, -16, 77, 77, -16, 3, 0 },/* 8 */
+ { -1, 4, -17, 69, 85, -15, 3, 0 },/* 9 */
+ { -1, 4, -16, 61, 91, -13, 2, 0 },/* 10 */
+ { -1, 4, -16, 53, 97, -11, 1, 1 },/* 11 */
+ { -1, 4, -15, 44, 103, -7, -1, 1 },/* 12 */
+ { -1, 4, -13, 36, 106, -3, -2, 1 },/* 13 */
+ { -1, 4, -12, 28, 110, 1, -4, 2 },/* 14 */
+ { -1, 3, -10, 21, 112, 7, -6, 2 } /* 15 */
+ },
+ { /* 74898 < Ratio <= 87381 (~8:6) */
+ { 2, -11, 25, 96, 25, -11, 2, 0 },/* 0 */
+ { 2, -10, 19, 96, 31, -12, 2, 0 },/* 1 */
+ { 2, -9, 14, 94, 37, -12, 2, 0 },/* 2 */
+ { 2, -8, 10, 92, 43, -12, 1, 0 },/* 3 */
+ { 2, -7, 5, 90, 49, -12, 1, 0 },/* 4 */
+ { 2, -5, 1, 86, 55, -12, 0, 1 },/* 5 */
+ { 2, -4, -2, 82, 61, -11, -1, 1 },/* 6 */
+ { 1, -3, -5, 77, 67, -9, -1, 1 },/* 7 */
+ { 1, -2, -7, 72, 72, -7, -2, 1 },/* 8 */
+ { 1, -1, -9, 67, 77, -5, -3, 1 },/* 9 */
+ { 1, -1, -11, 61, 82, -2, -4, 2 },/* 10 */
+ { 1, 0, -12, 55, 86, 1, -5, 2 },/* 11 */
+ { 0, 1, -12, 49, 90, 5, -7, 2 },/* 12 */
+ { 0, 1, -12, 43, 92, 10, -8, 2 },/* 13 */
+ { 0, 2, -12, 37, 94, 14, -9, 2 },/* 14 */
+ { 0, 2, -12, 31, 96, 19, -10, 2 } /* 15 */
+ },
+ { /* 87381 < Ratio <= 104857 (~8:5) */
+ { -1, -8, 33, 80, 33, -8, -1, 0 },/* 0 */
+ { -1, -8, 28, 80, 37, -7, -2, 1 },/* 1 */
+ { 0, -8, 24, 79, 41, -7, -2, 1 },/* 2 */
+ { 0, -8, 20, 78, 46, -6, -3, 1 },/* 3 */
+ { 0, -8, 16, 76, 50, -4, -3, 1 },/* 4 */
+ { 0, -7, 13, 74, 54, -3, -4, 1 },/* 5 */
+ { 1, -7, 10, 71, 58, -1, -5, 1 },/* 6 */
+ { 1, -6, 6, 68, 62, 1, -5, 1 },/* 7 */
+ { 1, -6, 4, 65, 65, 4, -6, 1 },/* 8 */
+ { 1, -5, 1, 62, 68, 6, -6, 1 },/* 9 */
+ { 1, -5, -1, 58, 71, 10, -7, 1 },/* 10 */
+ { 1, -4, -3, 54, 74, 13, -7, 0 },/* 11 */
+ { 1, -3, -4, 50, 76, 16, -8, 0 },/* 12 */
+ { 1, -3, -6, 46, 78, 20, -8, 0 },/* 13 */
+ { 1, -2, -7, 41, 79, 24, -8, 0 },/* 14 */
+ { 1, -2, -7, 37, 80, 28, -8, -1 } /* 15 */
+ },
+ { /* 104857 < Ratio <= 131072 (~8:4) */
+ { -3, 0, 35, 64, 35, 0, -3, 0 },/* 0 */
+ { -3, -1, 32, 64, 38, 1, -3, 0 },/* 1 */
+ { -2, -2, 29, 63, 41, 2, -3, 0 },/* 2 */
+ { -2, -3, 27, 63, 43, 4, -4, 0 },/* 3 */
+ { -2, -3, 24, 61, 46, 6, -4, 0 },/* 4 */
+ { -2, -3, 21, 60, 49, 7, -4, 0 },/* 5 */
+ { -1, -4, 19, 59, 51, 9, -4, -1 },/* 6 */
+ { -1, -4, 16, 57, 53, 12, -4, -1 },/* 7 */
+ { -1, -4, 14, 55, 55, 14, -4, -1 },/* 8 */
+ { -1, -4, 12, 53, 57, 16, -4, -1 },/* 9 */
+ { -1, -4, 9, 51, 59, 19, -4, -1 },/* 10 */
+ { 0, -4, 7, 49, 60, 21, -3, -2 },/* 11 */
+ { 0, -4, 6, 46, 61, 24, -3, -2 },/* 12 */
+ { 0, -4, 4, 43, 63, 27, -3, -2 },/* 13 */
+ { 0, -3, 2, 41, 63, 29, -2, -2 },/* 14 */
+ { 0, -3, 1, 38, 64, 32, -1, -3 } /* 15 */
+ },
+ { /* 131072 < Ratio <= 174762 (~8:3) */
+ { -1, 8, 33, 48, 33, 8, -1, 0 },/* 0 */
+ { -1, 7, 31, 49, 35, 9, -1, -1 },/* 1 */
+ { -1, 6, 30, 49, 36, 10, -1, -1 },/* 2 */
+ { -1, 5, 28, 48, 38, 12, -1, -1 },/* 3 */
+ { -1, 4, 26, 48, 39, 13, 0, -1 },/* 4 */
+ { -1, 3, 24, 47, 41, 15, 0, -1 },/* 5 */
+ { -1, 2, 23, 47, 42, 16, 0, -1 },/* 6 */
+ { -1, 2, 21, 45, 43, 18, 1, -1 },/* 7 */
+ { -1, 1, 19, 45, 45, 19, 1, -1 },/* 8 */
+ { -1, 1, 18, 43, 45, 21, 2, -1 },/* 9 */
+ { -1, 0, 16, 42, 47, 23, 2, -1 },/* 10 */
+ { -1, 0, 15, 41, 47, 24, 3, -1 },/* 11 */
+ { -1, 0, 13, 39, 48, 26, 4, -1 },/* 12 */
+ { -1, -1, 12, 38, 48, 28, 5, -1 },/* 13 */
+ { -1, -1, 10, 36, 49, 30, 6, -1 },/* 14 */
+ { -1, -1, 9, 35, 49, 31, 7, -1 } /* 15 */
+ },
+ { /* 174762 < Ratio <= 262144 (~8:2) */
+ { 2, 13, 30, 38, 30, 13, 2, 0 },/* 0 */
+ { 2, 12, 29, 38, 30, 14, 3, 0 },/* 1 */
+ { 2, 11, 28, 38, 31, 15, 3, 0 },/* 2 */
+ { 2, 10, 26, 38, 32, 16, 4, 0 },/* 3 */
+ { 1, 10, 26, 37, 33, 17, 4, 0 },/* 4 */
+ { 1, 9, 24, 37, 34, 18, 5, 0 },/* 5 */
+ { 1, 8, 24, 37, 34, 19, 5, 0 },/* 6 */
+ { 1, 7, 22, 36, 35, 20, 6, 1 },/* 7 */
+ { 1, 6, 21, 36, 36, 21, 6, 1 },/* 8 */
+ { 1, 6, 20, 35, 36, 22, 7, 1 },/* 9 */
+ { 0, 5, 19, 34, 37, 24, 8, 1 },/* 10 */
+ { 0, 5, 18, 34, 37, 24, 9, 1 },/* 11 */
+ { 0, 4, 17, 33, 37, 26, 10, 1 },/* 12 */
+ { 0, 4, 16, 32, 38, 26, 10, 2 },/* 13 */
+ { 0, 3, 15, 31, 38, 28, 11, 2 },/* 14 */
+ { 0, 3, 14, 30, 38, 29, 12, 2 } /* 15 */
+ }
+};
+
+/* 4-tap Filter Coefficient */
+const int v_coef_4t[7][16][4] = {
+ { /* Ratio <= 65536 (~8:8) */
+ { 0, 128, 0, 0 },/* 0 */
+ { -4, 127, 5, 0 },/* 1 */
+ { -6, 124, 11, -1 },/* 2 */
+ { -8, 118, 19, -1 },/* 3 */
+ { -8, 111, 27, -2 },/* 4 */
+ { -8, 102, 37, -3 },/* 5 */
+ { -8, 92, 48, -4 },/* 6 */
+ { -7, 81, 59, -5 },/* 7 */
+ { -6, 70, 70, -6 },/* 8 */
+ { -5, 59, 81, -7 },/* 9 */
+ { -4, 48, 92, -8 },/* 10 */
+ { -3, 37, 102, -8 },/* 11 */
+ { -2, 27, 111, -8 },/* 12 */
+ { -1, 19, 118, -8 },/* 13 */
+ { -1, 11, 124, -6 },/* 14 */
+ { 0, 5, 127, -4 } /* 15 */
+ },
+ { /* 65536 < Ratio <= 74898 (~8:7) */
+ { 8, 112, 8, 0 },/* 0 */
+ { 4, 111, 14, -1 },/* 1 */
+ { 1, 109, 20, -2 },/* 2 */
+ { -2, 105, 27, -2 },/* 3 */
+ { -3, 100, 34, -3 },/* 4 */
+ { -5, 93, 43, -3 },/* 5 */
+ { -5, 86, 51, -4 },/* 6 */
+ { -5, 77, 60, -4 },/* 7 */
+ { -5, 69, 69, -5 },/* 8 */
+ { -4, 60, 77, -5 },/* 9 */
+ { -4, 51, 86, -5 },/* 10 */
+ { -3, 43, 93, -5 },/* 11 */
+ { -3, 34, 100, -3 },/* 12 */
+ { -2, 27, 105, -2 },/* 13 */
+ { -2, 20, 109, 1 },/* 14 */
+ { -1, 14, 111, 4 } /* 15 */
+ },
+ { /* 74898 < Ratio <= 87381 (~8:6) */
+ { 16, 96, 16, 0 },/* 0 */
+ { 12, 97, 21, -2 },/* 1 */
+ { 8, 96, 26, -2 },/* 2 */
+ { 5, 93, 32, -2 },/* 3 */
+ { 2, 89, 39, -2 },/* 4 */
+ { 0, 84, 46, -2 },/* 5 */
+ { -1, 79, 53, -3 },/* 6 */
+ { -2, 73, 59, -2 },/* 7 */
+ { -2, 66, 66, -2 },/* 8 */
+ { -2, 59, 73, -2 },/* 9 */
+ { -3, 53, 79, -1 },/* 10 */
+ { -2, 46, 84, 0 },/* 11 */
+ { -2, 39, 89, 2 },/* 12 */
+ { -2, 32, 93, 5 },/* 13 */
+ { -2, 26, 96, 8 },/* 14 */
+ { -2, 21, 97, 12 } /* 15 */
+ },
+ { /* 87381 < Ratio <= 104857 (~8:5) */
+ { 22, 84, 22, 0 },/* 0 */
+ { 18, 85, 26, -1 },/* 1 */
+ { 14, 84, 31, -1 },/* 2 */
+ { 11, 82, 36, -1 },/* 3 */
+ { 8, 79, 42, -1 },/* 4 */
+ { 6, 76, 47, -1 },/* 5 */
+ { 4, 72, 52, 0 },/* 6 */
+ { 2, 68, 58, 0 },/* 7 */
+ { 1, 63, 63, 1 },/* 8 */
+ { 0, 58, 68, 2 },/* 9 */
+ { 0, 52, 72, 4 },/* 10 */
+ { -1, 47, 76, 6 },/* 11 */
+ { -1, 42, 79, 8 },/* 12 */
+ { -1, 36, 82, 11 },/* 13 */
+ { -1, 31, 84, 14 },/* 14 */
+ { -1, 26, 85, 18 } /* 15 */
+ },
+ { /* 104857 < Ratio <= 131072 (~8:4) */
+ { 26, 76, 26, 0 },/* 0 */
+ { 22, 76, 30, 0 },/* 1 */
+ { 19, 75, 34, 0 },/* 2 */
+ { 16, 73, 38, 1 },/* 3 */
+ { 13, 71, 43, 1 },/* 4 */
+ { 10, 69, 47, 2 },/* 5 */
+ { 8, 66, 51, 3 },/* 6 */
+ { 6, 63, 55, 4 },/* 7 */
+ { 5, 59, 59, 5 },/* 8 */
+ { 4, 55, 63, 6 },/* 9 */
+ { 3, 51, 66, 8 },/* 10 */
+ { 2, 47, 69, 10 },/* 11 */
+ { 1, 43, 71, 13 },/* 12 */
+ { 1, 38, 73, 16 },/* 13 */
+ { 0, 34, 75, 19 },/* 14 */
+ { 0, 30, 76, 22 } /* 15 */
+ },
+ { /* 131072 < Ratio <= 174762 (~8:3) */
+ { 29, 70, 29, 0 },/* 0 */
+ { 26, 68, 32, 2 },/* 1 */
+ { 23, 67, 36, 2 },/* 2 */
+ { 20, 66, 39, 3 },/* 3 */
+ { 17, 65, 43, 3 },/* 4 */
+ { 15, 63, 46, 4 },/* 5 */
+ { 12, 61, 50, 5 },/* 6 */
+ { 10, 58, 53, 7 },/* 7 */
+ { 8, 56, 56, 8 },/* 8 */
+ { 7, 53, 58, 10 },/* 9 */
+ { 5, 50, 61, 12 },/* 10 */
+ { 4, 46, 63, 15 },/* 11 */
+ { 3, 43, 65, 17 },/* 12 */
+ { 3, 39, 66, 20 },/* 13 */
+ { 2, 36, 67, 23 },/* 14 */
+ { 2, 32, 68, 26 } /* 15 */
+ },
+ { /* 174762 < Ratio <= 262144 (~8:2) */
+ { 32, 64, 32, 0 },/* 0 */
+ { 28, 63, 34, 3 },/* 1 */
+ { 25, 62, 37, 4 },/* 2 */
+ { 22, 62, 40, 4 },/* 3 */
+ { 19, 61, 43, 5 },/* 4 */
+ { 17, 59, 46, 6 },/* 5 */
+ { 15, 58, 48, 7 },/* 6 */
+ { 13, 55, 51, 9 },/* 7 */
+ { 11, 53, 53, 11 },/* 8 */
+ { 9, 51, 55, 13 },/* 9 */
+ { 7, 48, 58, 15 },/* 10 */
+ { 6, 46, 59, 17 },/* 11 */
+ { 5, 43, 61, 19 },/* 12 */
+ { 4, 40, 62, 22 },/* 13 */
+ { 4, 37, 62, 25 },/* 14 */
+ { 3, 34, 63, 28 } /* 15 */
+ }
+};
diff --git a/drivers/media/video/exynos/gsc/gsc-capture.c b/drivers/media/video/exynos/gsc/gsc-capture.c
new file mode 100644
index 0000000..8897c00
--- /dev/null
+++ b/drivers/media/video/exynos/gsc/gsc-capture.c
@@ -0,0 +1,1656 @@
+/* linux/drivers/media/video/exynos/gsc/gsc-capture.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Samsung EXYNOS5 SoC series G-scaler driver
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/bug.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/list.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/string.h>
+#include <linux/i2c.h>
+#include <media/v4l2-ioctl.h>
+#include <media/exynos_gscaler.h>
+#include <plat/bts.h>
+
+#include "gsc-core.h"
+
+static int gsc_capture_queue_setup(struct vb2_queue *vq,
+ const struct v4l2_format *fmt, unsigned int *num_buffers,
+ unsigned int *num_planes, unsigned int sizes[],
+ void *allocators[])
+{
+ struct gsc_ctx *ctx = vq->drv_priv;
+ struct gsc_fmt *ffmt = ctx->d_frame.fmt;
+ int i;
+
+ if (!ffmt)
+ return -EINVAL;
+
+ *num_planes = ffmt->num_planes;
+
+ for (i = 0; i < ffmt->num_planes; i++) {
+ sizes[i] = get_plane_size(&ctx->d_frame, i);
+ allocators[i] = ctx->gsc_dev->alloc_ctx;
+ }
+
+ return 0;
+}
+static int gsc_capture_buf_prepare(struct vb2_buffer *vb)
+{
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct gsc_ctx *ctx = vq->drv_priv;
+ struct gsc_dev *gsc = ctx->gsc_dev;
+ struct gsc_frame *frame = &ctx->d_frame;
+ int i;
+
+ if (frame->fmt == NULL)
+ return -EINVAL;
+
+ for (i = 0; i < frame->fmt->num_planes; i++) {
+ unsigned long size = frame->payload[i];
+
+ if (vb2_plane_size(vb, i) < size) {
+ v4l2_err(ctx->gsc_dev->cap.vfd,
+ "User buffer too small (%ld < %ld)\n",
+ vb2_plane_size(vb, i), size);
+ return -EINVAL;
+ }
+ vb2_set_plane_payload(vb, i, size);
+ }
+
+ if (frame->cacheable)
+ gsc->vb2->cache_flush(vb, frame->fmt->num_planes);
+
+ return 0;
+}
+
+int gsc_cap_pipeline_s_stream(struct gsc_dev *gsc, int on)
+{
+ struct gsc_pipeline *p = &gsc->pipeline;
+ int ret = 0;
+
+ if ((!p->sensor || !p->flite) && (!p->disp))
+ return -ENODEV;
+
+ if (on) {
+ gsc_info("start stream");
+ ret = v4l2_subdev_call(p->sd_gsc, video, s_stream, 1);
+ if (ret < 0 && ret != -ENOIOCTLCMD)
+ return ret;
+ if (p->disp) {
+ ret = v4l2_subdev_call(p->disp, video, s_stream, 1);
+ if (ret < 0 && ret != -ENOIOCTLCMD)
+ return ret;
+ } else {
+ ret = v4l2_subdev_call(p->flite, video, s_stream, 1);
+ if (ret < 0 && ret != -ENOIOCTLCMD)
+ return ret;
+ ret = v4l2_subdev_call(p->csis, video, s_stream, 1);
+ if (ret < 0 && ret != -ENOIOCTLCMD)
+ return ret;
+ ret = v4l2_subdev_call(p->sensor, video, s_stream, 1);
+ }
+ } else {
+ gsc_info("stop stream");
+ if (p->disp) {
+ ret = v4l2_subdev_call(p->disp, video, s_stream, 0);
+ if (ret < 0 && ret != -ENOIOCTLCMD)
+ return ret;
+ } else {
+ ret = v4l2_subdev_call(p->sensor, video, s_stream, 0);
+ if (ret < 0 && ret != -ENOIOCTLCMD)
+ return ret;
+ ret = v4l2_subdev_call(p->csis, video, s_stream, 0);
+ if (ret < 0 && ret != -ENOIOCTLCMD)
+ return ret;
+ ret = v4l2_subdev_call(p->flite, video, s_stream, 0);
+ }
+
+ ret = v4l2_subdev_call(p->sd_gsc, video, s_stream, 0);
+ if (ret < 0 && ret != -ENOIOCTLCMD)
+ return ret;
+ }
+
+ return ret == -ENOIOCTLCMD ? 0 : ret;
+}
+
+static int gsc_capture_set_addr(struct vb2_buffer *vb)
+{
+ struct gsc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+ struct gsc_dev *gsc = ctx->gsc_dev;
+ int ret;
+
+ ret = gsc_prepare_addr(ctx, vb, &ctx->d_frame, &ctx->d_frame.addr);
+ if (ret) {
+ gsc_err("Prepare G-Scaler address failed\n");
+ return -EINVAL;
+ }
+
+ gsc_hw_set_output_addr(gsc, &ctx->d_frame.addr, vb->v4l2_buf.index);
+
+ return 0;
+}
+
+static void gsc_capture_buf_queue(struct vb2_buffer *vb)
+{
+ struct gsc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+ struct gsc_dev *gsc = ctx->gsc_dev;
+ struct gsc_capture_device *cap = &gsc->cap;
+ struct exynos_md *mdev = gsc->mdev[MDEV_CAPTURE];
+ int min_bufs, ret;
+ unsigned long flags;
+
+ spin_lock_irqsave(&gsc->slock, flags);
+ ret = gsc_capture_set_addr(vb);
+ if (ret)
+ gsc_err("Failed to prepare output addr");
+
+ gsc_hw_set_output_buf_masking(gsc, vb->v4l2_buf.index, 0);
+
+ min_bufs = cap->reqbufs_cnt > 1 ? 2 : 1;
+
+ if (vb2_is_streaming(&cap->vbq) &&
+ (gsc_hw_get_nr_unmask_bits(gsc) >= min_bufs) &&
+ !test_bit(ST_CAPT_STREAM, &gsc->state)) {
+ if (!test_and_set_bit(ST_CAPT_PIPE_STREAM, &gsc->state)) {
+ spin_unlock_irqrestore(&gsc->slock, flags);
+ if (!mdev->is_flite_on)
+ gsc_cap_pipeline_s_stream(gsc, 1);
+ else
+ v4l2_subdev_call(gsc->cap.sd_cap, video,
+ s_stream, 1);
+ return;
+ }
+
+ if (!test_bit(ST_CAPT_STREAM, &gsc->state)) {
+ gsc_info("G-Scaler h/w enable control");
+ gsc_hw_enable_control(gsc, true);
+ set_bit(ST_CAPT_STREAM, &gsc->state);
+ }
+ }
+ spin_unlock_irqrestore(&gsc->slock, flags);
+
+ return;
+}
+
+static int gsc_capture_get_scaler_factor(u32 src, u32 tar, u32 *ratio)
+{
+ u32 sh = 3;
+ tar *= 4;
+ if (tar >= src) {
+ *ratio = 1;
+ return 0;
+ }
+
+ while (--sh) {
+ u32 tmp = 1 << sh;
+ if (src >= tar * tmp)
+ *ratio = sh;
+ }
+ return 0;
+}
+
+static int gsc_capture_scaler_info(struct gsc_ctx *ctx)
+{
+ struct gsc_frame *s_frame = &ctx->s_frame;
+ struct gsc_frame *d_frame = &ctx->d_frame;
+ struct gsc_scaler *sc = &ctx->scaler;
+
+ gsc_capture_get_scaler_factor(s_frame->crop.width, d_frame->crop.width,
+ &sc->pre_hratio);
+ gsc_capture_get_scaler_factor(s_frame->crop.height, d_frame->crop.width,
+ &sc->pre_vratio);
+
+ sc->main_hratio = (s_frame->crop.width << 16) / d_frame->crop.width;
+ sc->main_vratio = (s_frame->crop.height << 16) / d_frame->crop.height;
+
+ gsc_info("src width : %d, src height : %d, dst width : %d,\
+ dst height : %d", s_frame->crop.width, s_frame->crop.height,\
+ d_frame->crop.width, d_frame->crop.height);
+ gsc_info("pre_hratio : 0x%x, pre_vratio : 0x%x, main_hratio : 0x%lx,\
+ main_vratio : 0x%lx", sc->pre_hratio,\
+ sc->pre_vratio, sc->main_hratio, sc->main_vratio);
+
+ return 0;
+}
+
+static int gsc_capture_subdev_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct gsc_dev *gsc = v4l2_get_subdevdata(sd);
+ struct gsc_capture_device *cap = &gsc->cap;
+ struct gsc_ctx *ctx = cap->ctx;
+
+ if (enable) {
+ gsc_info("start");
+ gsc_hw_set_frm_done_irq_mask(gsc, false);
+ gsc_hw_set_overflow_irq_mask(gsc, false);
+ gsc_hw_set_one_frm_mode(gsc, false);
+ gsc_hw_set_gsc_irq_enable(gsc, true);
+
+ if (gsc->pipeline.disp)
+ gsc_hw_set_sysreg_writeback(ctx);
+ else
+ gsc_hw_set_pxlasync_camif_lo_mask(gsc, true);
+
+ gsc_hw_set_input_path(ctx);
+ gsc_hw_set_in_size(ctx);
+ gsc_hw_set_in_image_format(ctx);
+ gsc_hw_set_output_path(ctx);
+ gsc_hw_set_out_size(ctx);
+ gsc_hw_set_out_image_format(ctx);
+ gsc_hw_set_global_alpha(ctx);
+
+ gsc_capture_scaler_info(ctx);
+ gsc_hw_set_prescaler(ctx);
+ gsc_hw_set_mainscaler(ctx);
+ gsc_hw_set_h_coef(ctx);
+ gsc_hw_set_v_coef(ctx);
+
+ set_bit(ST_CAPT_PEND, &gsc->state);
+
+ gsc_hw_enable_control(gsc, true);
+ set_bit(ST_CAPT_STREAM, &gsc->state);
+ } else {
+ gsc_info("stop");
+ }
+
+ return 0;
+}
+
+static int gsc_capture_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+ struct gsc_ctx *ctx = q->drv_priv;
+ struct gsc_dev *gsc = ctx->gsc_dev;
+ struct gsc_capture_device *cap = &gsc->cap;
+ struct exynos_md *mdev = gsc->mdev[MDEV_CAPTURE];
+ int min_bufs;
+
+ min_bufs = cap->reqbufs_cnt > 1 ? 2 : 1;
+ if ((gsc_hw_get_nr_unmask_bits(gsc) >= min_bufs) &&
+ !test_bit(ST_CAPT_STREAM, &gsc->state)) {
+ if (!test_and_set_bit(ST_CAPT_PIPE_STREAM, &gsc->state)) {
+ gsc_info("");
+ if (!mdev->is_flite_on)
+ gsc_cap_pipeline_s_stream(gsc, 1);
+ else
+ v4l2_subdev_call(gsc->cap.sd_cap, video,
+ s_stream, 1);
+ }
+ }
+
+ return 0;
+}
+
+static int gsc_capture_state_cleanup(struct gsc_dev *gsc)
+{
+ struct exynos_md *mdev = gsc->mdev[MDEV_CAPTURE];
+ unsigned long flags;
+ bool streaming;
+
+ spin_lock_irqsave(&gsc->slock, flags);
+ streaming = gsc->state & (1 << ST_CAPT_PIPE_STREAM);
+
+ gsc->state &= ~(1 << ST_CAPT_RUN | 1 << ST_CAPT_STREAM |
+ 1 << ST_CAPT_PIPE_STREAM | 1 << ST_CAPT_PEND);
+
+ spin_unlock_irqrestore(&gsc->slock, flags);
+
+ if (streaming) {
+ if (!mdev->is_flite_on)
+ return gsc_cap_pipeline_s_stream(gsc, 0);
+ else
+ return v4l2_subdev_call(gsc->cap.sd_cap, video,
+ s_stream, 0);
+ } else {
+ return 0;
+}
+}
+
+static int gsc_cap_stop_capture(struct gsc_dev *gsc)
+{
+ int ret;
+ if (!gsc_cap_active(gsc)) {
+ gsc_warn("already stopped\n");
+ return 0;
+ }
+ gsc_info("G-Scaler h/w disable control");
+ gsc_hw_enable_control(gsc, false);
+ clear_bit(ST_CAPT_STREAM, &gsc->state);
+ ret = gsc_wait_stop(gsc);
+ if (ret) {
+ gsc_err("GSCALER_OP_STATUS is operating\n");
+ return ret;
+ }
+
+ bts_change_bus_traffic(&gsc->pdev->dev, BTS_DECREASE_BW);
+ return gsc_capture_state_cleanup(gsc);
+}
+
+static int gsc_capture_stop_streaming(struct vb2_queue *q)
+{
+ struct gsc_ctx *ctx = q->drv_priv;
+ struct gsc_dev *gsc = ctx->gsc_dev;
+
+ if (!gsc_cap_active(gsc))
+ return -EINVAL;
+
+ return gsc_cap_stop_capture(gsc);
+}
+
+static struct vb2_ops gsc_capture_qops = {
+ .queue_setup = gsc_capture_queue_setup,
+ .buf_prepare = gsc_capture_buf_prepare,
+ .buf_queue = gsc_capture_buf_queue,
+ .wait_prepare = gsc_unlock,
+ .wait_finish = gsc_lock,
+ .start_streaming = gsc_capture_start_streaming,
+ .stop_streaming = gsc_capture_stop_streaming,
+};
+
+/*
+ * The video node ioctl operations
+ */
+static int gsc_vidioc_querycap_capture(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct gsc_dev *gsc = video_drvdata(file);
+
+ strncpy(cap->driver, gsc->pdev->name, sizeof(cap->driver) - 1);
+ strncpy(cap->card, gsc->pdev->name, sizeof(cap->card) - 1);
+ cap->bus_info[0] = 0;
+ cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE_MPLANE;
+
+ return 0;
+}
+
+static int gsc_capture_enum_fmt_mplane(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ return gsc_enum_fmt_mplane(f);
+}
+
+static int gsc_capture_try_fmt_mplane(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct gsc_dev *gsc = video_drvdata(file);
+
+ if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ return -EINVAL;
+
+ return gsc_try_fmt_mplane(gsc->cap.ctx, f);
+}
+
+static int gsc_capture_s_fmt_mplane(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct gsc_dev *gsc = video_drvdata(file);
+ struct gsc_ctx *ctx = gsc->cap.ctx;
+ struct gsc_frame *frame;
+ struct v4l2_pix_format_mplane *pix;
+ int i, ret = 0;
+
+ ret = gsc_capture_try_fmt_mplane(file, fh, f);
+ if (ret)
+ return ret;
+
+ if (vb2_is_streaming(&gsc->cap.vbq)) {
+ gsc_err("queue (%d) busy", f->type);
+ return -EBUSY;
+ }
+
+ frame = &ctx->d_frame;
+
+ pix = &f->fmt.pix_mp;
+ frame->fmt = find_format(&pix->pixelformat, NULL, 0);
+ if (!frame->fmt)
+ return -EINVAL;
+
+ for (i = 0; i < frame->fmt->nr_comp; i++)
+ frame->payload[i] =
+ pix->plane_fmt[i].bytesperline * pix->height;
+
+ gsc_set_frame_size(frame, pix->width, pix->height);
+
+ gsc_info("f_w: %d, f_h: %d", frame->f_width, frame->f_height);
+
+ return 0;
+}
+
+static int gsc_capture_g_fmt_mplane(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct gsc_dev *gsc = video_drvdata(file);
+ struct gsc_ctx *ctx = gsc->cap.ctx;
+
+ if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ return -EINVAL;
+
+ return gsc_g_fmt_mplane(ctx, f);
+}
+
+static int gsc_capture_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *reqbufs)
+{
+ struct gsc_dev *gsc = video_drvdata(file);
+ struct gsc_capture_device *cap = &gsc->cap;
+ struct gsc_frame *frame;
+ int ret;
+
+ frame = ctx_get_frame(cap->ctx, reqbufs->type);
+ frame->cacheable = cap->ctx->gsc_ctrls.cacheable->val;
+ gsc->vb2->set_cacheable(gsc->alloc_ctx, frame->cacheable);
+
+ ret = vb2_reqbufs(&cap->vbq, reqbufs);
+ if (!ret)
+ cap->reqbufs_cnt = reqbufs->count;
+
+ return ret;
+
+}
+
+static int gsc_capture_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct gsc_dev *gsc = video_drvdata(file);
+ struct gsc_capture_device *cap = &gsc->cap;
+
+ return vb2_querybuf(&cap->vbq, buf);
+}
+
+static int gsc_capture_qbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct gsc_dev *gsc = video_drvdata(file);
+ struct gsc_capture_device *cap = &gsc->cap;
+
+ return vb2_qbuf(&cap->vbq, buf);
+}
+
+static int gsc_capture_dqbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct gsc_dev *gsc = video_drvdata(file);
+ return vb2_dqbuf(&gsc->cap.vbq, buf,
+ file->f_flags & O_NONBLOCK);
+}
+
+static int gsc_capture_cropcap(struct file *file, void *fh,
+ struct v4l2_cropcap *cr)
+{
+ struct gsc_dev *gsc = video_drvdata(file);
+ struct gsc_ctx *ctx = gsc->cap.ctx;
+
+ if (cr->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ return -EINVAL;
+
+ cr->bounds.left = 0;
+ cr->bounds.top = 0;
+ cr->bounds.width = ctx->d_frame.f_width;
+ cr->bounds.height = ctx->d_frame.f_height;
+ cr->defrect = cr->bounds;
+
+ return 0;
+}
+
+static int gsc_capture_enum_input(struct file *file, void *priv,
+ struct v4l2_input *i)
+{
+ struct gsc_dev *gsc = video_drvdata(file);
+ struct exynos_platform_gscaler *pdata = gsc->pdata;
+ struct exynos_isp_info *isp_info;
+
+ if (i->index >= MAX_CAMIF_CLIENTS)
+ return -EINVAL;
+
+ isp_info = pdata->isp_info[i->index];
+ if (isp_info == NULL)
+ return -EINVAL;
+
+ i->type = V4L2_INPUT_TYPE_CAMERA;
+
+ strncpy(i->name, isp_info->board_info->type, 32);
+
+ return 0;
+}
+
+static int gsc_capture_s_input(struct file *file, void *priv, unsigned int i)
+{
+ return i == 0 ? 0 : -EINVAL;
+}
+
+static int gsc_capture_g_input(struct file *file, void *priv, unsigned int *i)
+{
+ *i = 0;
+ return 0;
+}
+
+int gsc_capture_ctrls_create(struct gsc_dev *gsc)
+{
+ int ret;
+
+ if (WARN_ON(gsc->cap.ctx == NULL))
+ return -ENXIO;
+ if (gsc->cap.ctx->ctrls_rdy)
+ return 0;
+ ret = gsc_ctrls_create(gsc->cap.ctx);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+void gsc_cap_pipeline_prepare(struct gsc_dev *gsc, struct media_entity *me)
+{
+ struct media_entity_graph graph;
+ struct v4l2_subdev *sd;
+
+ media_entity_graph_walk_start(&graph, me);
+
+ while ((me = media_entity_graph_walk_next(&graph))) {
+ gsc_info("me->name : %s", me->name);
+ if (media_entity_type(me) != MEDIA_ENT_T_V4L2_SUBDEV)
+ continue;
+ sd = media_entity_to_v4l2_subdev(me);
+
+ switch (sd->grp_id) {
+ case GSC_CAP_GRP_ID:
+ gsc->pipeline.sd_gsc = sd;
+ break;
+ case FLITE_GRP_ID:
+ gsc->pipeline.flite = sd;
+ break;
+ case SENSOR_GRP_ID:
+ gsc->pipeline.sensor = sd;
+ break;
+ case CSIS_GRP_ID:
+ gsc->pipeline.csis = sd;
+ break;
+ case FIMD_GRP_ID:
+ gsc->pipeline.disp = sd;
+ break;
+ default:
+ gsc_err("Unsupported group id");
+ break;
+ }
+ }
+
+ gsc_info("gsc->pipeline.sd_gsc : 0x%p", gsc->pipeline.sd_gsc);
+ gsc_info("gsc->pipeline.flite : 0x%p", gsc->pipeline.flite);
+ gsc_info("gsc->pipeline.sensor : 0x%p", gsc->pipeline.sensor);
+ gsc_info("gsc->pipeline.csis : 0x%p", gsc->pipeline.csis);
+ gsc_info("gsc->pipeline.disp : 0x%p", gsc->pipeline.disp);
+}
+
+static int __subdev_set_power(struct v4l2_subdev *sd, int on)
+{
+ int *use_count;
+ int ret;
+
+ if (sd == NULL)
+ return -ENXIO;
+
+ use_count = &sd->entity.use_count;
+ if (on && (*use_count)++ > 0)
+ return 0;
+ else if (!on && (*use_count == 0 || --(*use_count) > 0))
+ return 0;
+ ret = v4l2_subdev_call(sd, core, s_power, on);
+
+ return ret != -ENOIOCTLCMD ? ret : 0;
+}
+
+int gsc_cap_pipeline_s_power(struct gsc_dev *gsc, int state)
+{
+ int ret = 0;
+
+ if (!gsc->pipeline.sensor || !gsc->pipeline.flite)
+ return -ENXIO;
+
+ if (state) {
+ ret = __subdev_set_power(gsc->pipeline.flite, 1);
+ if (ret && ret != -ENXIO)
+ return ret;
+ ret = __subdev_set_power(gsc->pipeline.csis, 1);
+ if (ret && ret != -ENXIO)
+ return ret;
+ ret = __subdev_set_power(gsc->pipeline.sensor, 1);
+ } else {
+ ret = __subdev_set_power(gsc->pipeline.flite, 0);
+ if (ret && ret != -ENXIO)
+ return ret;
+ ret = __subdev_set_power(gsc->pipeline.sensor, 0);
+ if (ret && ret != -ENXIO)
+ return ret;
+ ret = __subdev_set_power(gsc->pipeline.csis, 0);
+ }
+ return ret == -ENXIO ? 0 : ret;
+}
+
+static void gsc_set_cam_clock(struct gsc_dev *gsc, bool on)
+{
+ struct v4l2_subdev *sd = NULL;
+ struct gsc_sensor_info *s_info = NULL;
+
+ if (gsc->pipeline.sensor) {
+ sd = gsc->pipeline.sensor;
+ s_info = v4l2_get_subdev_hostdata(sd);
+ }
+ if (on) {
+ clk_enable(gsc->clock);
+ if (gsc->pipeline.sensor)
+ clk_enable(s_info->camclk);
+ } else {
+ clk_disable(gsc->clock);
+ if (gsc->pipeline.sensor)
+ clk_disable(s_info->camclk);
+ }
+}
+
+static int __gsc_cap_pipeline_initialize(struct gsc_dev *gsc,
+ struct media_entity *me, bool prep)
+{
+ struct exynos_md *mdev = gsc->mdev[MDEV_CAPTURE];
+ int ret = 0;
+
+ if (prep) {
+ gsc_cap_pipeline_prepare(gsc, me);
+ if ((!gsc->pipeline.sensor || !gsc->pipeline.flite) &&
+ !gsc->pipeline.disp)
+ return -EINVAL;
+ }
+
+ gsc_set_cam_clock(gsc, true);
+
+ if (!mdev->is_flite_on && gsc->pipeline.sensor && gsc->pipeline.flite)
+ ret = gsc_cap_pipeline_s_power(gsc, 1);
+
+ return ret;
+}
+
+int gsc_cap_pipeline_initialize(struct gsc_dev *gsc, struct media_entity *me,
+ bool prep)
+{
+ int ret;
+
+ mutex_lock(&me->parent->graph_mutex);
+ ret = __gsc_cap_pipeline_initialize(gsc, me, prep);
+ mutex_unlock(&me->parent->graph_mutex);
+
+ return ret;
+}
+static int gsc_capture_open(struct file *file)
+{
+ struct gsc_dev *gsc = video_drvdata(file);
+ int ret = v4l2_fh_open(file);
+
+ if (ret)
+ return ret;
+
+ if (gsc_m2m_opened(gsc) || gsc_out_opened(gsc) || gsc_cap_opened(gsc)) {
+ v4l2_fh_release(file);
+ return -EBUSY;
+ }
+
+ set_bit(ST_CAPT_OPEN, &gsc->state);
+
+ pm_runtime_get_sync(&gsc->pdev->dev);
+
+ if (++gsc->cap.refcnt == 1) {
+ ret = gsc_cap_pipeline_initialize(gsc, &gsc->cap.vfd->entity, true);
+ if (ret < 0) {
+ gsc_err("gsc pipeline initialization failed\n");
+ goto err;
+ }
+
+ ret = gsc_capture_ctrls_create(gsc);
+ if (ret) {
+ gsc_err("failed to create controls\n");
+ goto err;
+ }
+ }
+
+ gsc_info("pid: %d, state: 0x%lx", task_pid_nr(current), gsc->state);
+
+ return 0;
+
+err:
+ pm_runtime_put_sync(&gsc->pdev->dev);
+ v4l2_fh_release(file);
+ clear_bit(ST_CAPT_OPEN, &gsc->state);
+ return ret;
+}
+
+int __gsc_cap_pipeline_shutdown(struct gsc_dev *gsc)
+{
+ struct exynos_md *mdev = gsc->mdev[MDEV_CAPTURE];
+ int ret = 0;
+
+ if (!mdev->is_flite_on && gsc->pipeline.sensor && gsc->pipeline.flite)
+ ret = gsc_cap_pipeline_s_power(gsc, 0);
+
+ if (ret && ret != -ENXIO)
+ gsc_set_cam_clock(gsc, false);
+
+ gsc->pipeline.sd_gsc= NULL;
+ gsc->pipeline.disp= NULL;
+ gsc->pipeline.flite = NULL;
+ gsc->pipeline.csis = NULL;
+ gsc->pipeline.sensor = NULL;
+
+ return ret == -ENXIO ? 0 : ret;
+}
+
+int gsc_cap_pipeline_shutdown(struct gsc_dev *gsc)
+{
+ struct media_entity *me = &gsc->cap.vfd->entity;
+ int ret;
+
+ mutex_lock(&me->parent->graph_mutex);
+ ret = __gsc_cap_pipeline_shutdown(gsc);
+ mutex_unlock(&me->parent->graph_mutex);
+
+ return ret;
+}
+
+static int gsc_capture_close(struct file *file)
+{
+ struct gsc_dev *gsc = video_drvdata(file);
+
+ gsc_info("pid: %d, state: 0x%lx", task_pid_nr(current), gsc->state);
+
+ if (--gsc->cap.refcnt == 0) {
+ clear_bit(ST_CAPT_OPEN, &gsc->state);
+ gsc_info("G-Scaler h/w disable control");
+ gsc_hw_enable_control(gsc, false);
+ clear_bit(ST_CAPT_STREAM, &gsc->state);
+ gsc_cap_pipeline_shutdown(gsc);
+ }
+
+ pm_runtime_put(&gsc->pdev->dev);
+
+ if (gsc->cap.refcnt == 0) {
+ vb2_queue_release(&gsc->cap.vbq);
+ gsc_ctrls_delete(gsc->cap.ctx);
+ }
+
+ return v4l2_fh_release(file);
+}
+
+static unsigned int gsc_capture_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct gsc_dev *gsc = video_drvdata(file);
+
+ return vb2_poll(&gsc->cap.vbq, file, wait);
+}
+
+static int gsc_capture_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct gsc_dev *gsc = video_drvdata(file);
+
+ return vb2_mmap(&gsc->cap.vbq, vma);
+}
+
+static int gsc_cap_link_validate(struct gsc_dev *gsc)
+{
+ struct gsc_capture_device *cap = &gsc->cap;
+ struct v4l2_subdev_format sink_fmt, src_fmt;
+ struct v4l2_subdev *sd;
+ struct media_pad *pad;
+ int ret;
+
+ /* Get the source pad connected with gsc-video */
+ pad = media_entity_remote_source(&cap->vd_pad);
+ if (pad == NULL)
+ return -EPIPE;
+ /* Get the subdev of source pad */
+ sd = media_entity_to_v4l2_subdev(pad->entity);
+
+ while (1) {
+ /* Find sink pad of the subdev*/
+ pad = &sd->entity.pads[0];
+ if (!(pad->flags & MEDIA_PAD_FL_SINK))
+ break;
+ if (sd == cap->sd_cap) {
+ struct gsc_frame *gf = &cap->ctx->s_frame;
+ sink_fmt.format.width = gf->crop.width;
+ sink_fmt.format.height = gf->crop.height;
+ sink_fmt.format.code = gf->fmt ? gf->fmt->mbus_code : 0;
+ } else {
+ sink_fmt.pad = pad->index;
+ sink_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+ ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &sink_fmt);
+ if (ret < 0 && ret != -ENOIOCTLCMD) {
+ gsc_err("failed %s subdev get_fmt", sd->name);
+ return -EPIPE;
+ }
+ }
+ gsc_info("sink sd name : %s", sd->name);
+ /* Get the source pad connected with remote sink pad */
+ pad = media_entity_remote_source(pad);
+ if (pad == NULL ||
+ media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+ break;
+
+ /* Get the subdev of source pad */
+ sd = media_entity_to_v4l2_subdev(pad->entity);
+ gsc_info("source sd name : %s", sd->name);
+
+ src_fmt.pad = pad->index;
+ src_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+ ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &src_fmt);
+ if (ret < 0 && ret != -ENOIOCTLCMD) {
+ gsc_err("failed %s subdev get_fmt", sd->name);
+ return -EPIPE;
+ }
+
+ gsc_info("src_width : %d, src_height : %d, src_code : %d",
+ src_fmt.format.width, src_fmt.format.height,
+ src_fmt.format.code);
+ gsc_info("sink_width : %d, sink_height : %d, sink_code : %d",
+ sink_fmt.format.width, sink_fmt.format.height,
+ sink_fmt.format.code);
+
+ if (src_fmt.format.width != sink_fmt.format.width ||
+ src_fmt.format.height != sink_fmt.format.height ||
+ src_fmt.format.code != sink_fmt.format.code) {
+ gsc_err("mismatch sink and source");
+ return -EPIPE;
+ }
+ }
+
+ return 0;
+}
+
+static int gsc_capture_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct gsc_dev *gsc = video_drvdata(file);
+ struct gsc_pipeline *p = &gsc->pipeline;
+ int ret;
+
+ if (gsc_cap_active(gsc))
+ return -EBUSY;
+
+ if (p->disp) {
+ media_entity_pipeline_start(&p->disp->entity, p->pipe);
+ } else if (p->sensor) {
+ media_entity_pipeline_start(&p->sensor->entity, p->pipe);
+ } else {
+ gsc_err("Error pipeline");
+ return -EPIPE;
+ }
+
+ ret = gsc_cap_link_validate(gsc);
+ if (ret)
+ return ret;
+
+ bts_change_bus_traffic(&gsc->pdev->dev, BTS_INCREASE_BW);
+ gsc_hw_set_sw_reset(gsc);
+ gsc_wait_reset(gsc);
+ gsc_hw_set_output_buf_mask_all(gsc);
+ return vb2_streamon(&gsc->cap.vbq, type);
+}
+
+static int gsc_capture_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct gsc_dev *gsc = video_drvdata(file);
+ struct v4l2_subdev *sd;
+ struct gsc_pipeline *p = &gsc->pipeline;
+ int ret;
+
+ if (p->disp) {
+ sd = gsc->pipeline.disp;
+ } else if (p->sensor) {
+ sd = gsc->pipeline.sensor;
+ } else {
+ gsc_err("Error pipeline");
+ return -EPIPE;
+ }
+
+ ret = vb2_streamoff(&gsc->cap.vbq, type);
+ if (ret == 0) {
+ if (p->disp)
+ media_entity_pipeline_stop(&p->disp->entity);
+ else if (p->sensor)
+ media_entity_pipeline_stop(&p->sensor->entity);
+ }
+
+ return ret;
+}
+
+static struct v4l2_subdev *gsc_cap_remote_subdev(struct gsc_dev *gsc, u32 *pad)
+{
+ struct media_pad *remote;
+
+ remote = media_entity_remote_source(&gsc->cap.vd_pad);
+
+ if (remote == NULL ||
+ media_entity_type(remote->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+ return NULL;
+
+ if (pad)
+ *pad = remote->index;
+
+ return media_entity_to_v4l2_subdev(remote->entity);
+}
+
+static int gsc_capture_g_crop(struct file *file, void *fh, struct v4l2_crop *crop)
+{
+ struct gsc_dev *gsc = video_drvdata(file);
+ struct v4l2_subdev *subdev;
+ struct v4l2_subdev_crop subdev_crop;
+ int ret;
+
+ subdev = gsc_cap_remote_subdev(gsc, NULL);
+ if (subdev == NULL)
+ return -EINVAL;
+
+ /* Try the get crop operation first and fallback to get format if not
+ * implemented.
+ */
+ subdev_crop.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+ subdev_crop.pad = GSC_PAD_SOURCE;
+ ret = v4l2_subdev_call(subdev, pad, get_crop, NULL, &subdev_crop);
+ if (ret < 0)
+ return ret == -ENOIOCTLCMD ? -EINVAL : ret;
+
+ crop->c.left = subdev_crop.rect.left;
+ crop->c.top = subdev_crop.rect.top;
+ crop->c.width = subdev_crop.rect.width;
+ crop->c.height = subdev_crop.rect.height;
+
+ return 0;
+}
+
+static int gsc_capture_s_crop(struct file *file, void *fh, struct v4l2_crop *crop)
+{
+ struct gsc_dev *gsc = video_drvdata(file);
+ struct v4l2_subdev *subdev;
+ struct v4l2_subdev_crop subdev_crop;
+ int ret;
+
+ subdev = gsc_cap_remote_subdev(gsc, NULL);
+ if (subdev == NULL)
+ return -EINVAL;
+
+ subdev_crop.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+ subdev_crop.pad = GSC_PAD_SOURCE;
+ subdev_crop.rect.left = crop->c.left;
+ subdev_crop.rect.top = crop->c.top;
+ subdev_crop.rect.width = crop->c.width;
+ subdev_crop.rect.height = crop->c.height;
+
+ ret = v4l2_subdev_call(subdev, pad, set_crop, NULL, &subdev_crop);
+
+ return ret == -ENOIOCTLCMD ? -EINVAL : ret;
+}
+
+
+static const struct v4l2_ioctl_ops gsc_capture_ioctl_ops = {
+ .vidioc_querycap = gsc_vidioc_querycap_capture,
+
+ .vidioc_enum_fmt_vid_cap_mplane = gsc_capture_enum_fmt_mplane,
+ .vidioc_try_fmt_vid_cap_mplane = gsc_capture_try_fmt_mplane,
+ .vidioc_s_fmt_vid_cap_mplane = gsc_capture_s_fmt_mplane,
+ .vidioc_g_fmt_vid_cap_mplane = gsc_capture_g_fmt_mplane,
+
+ .vidioc_reqbufs = gsc_capture_reqbufs,
+ .vidioc_querybuf = gsc_capture_querybuf,
+
+ .vidioc_qbuf = gsc_capture_qbuf,
+ .vidioc_dqbuf = gsc_capture_dqbuf,
+
+ .vidioc_streamon = gsc_capture_streamon,
+ .vidioc_streamoff = gsc_capture_streamoff,
+
+ .vidioc_g_crop = gsc_capture_g_crop,
+ .vidioc_s_crop = gsc_capture_s_crop,
+ .vidioc_cropcap = gsc_capture_cropcap,
+
+ .vidioc_enum_input = gsc_capture_enum_input,
+ .vidioc_s_input = gsc_capture_s_input,
+ .vidioc_g_input = gsc_capture_g_input,
+};
+
+static const struct v4l2_file_operations gsc_capture_fops = {
+ .owner = THIS_MODULE,
+ .open = gsc_capture_open,
+ .release = gsc_capture_close,
+ .poll = gsc_capture_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = gsc_capture_mmap,
+};
+
+/*
+ * __gsc_cap_get_format - helper function for getting gscaler format
+ * @res : pointer to resizer private structure
+ * @pad : pad number
+ * @fh : V4L2 subdev file handle
+ * @which : wanted subdev format
+ * return zero
+ */
+static struct v4l2_mbus_framefmt *__gsc_cap_get_format(struct gsc_dev *gsc,
+ struct v4l2_subdev_fh *fh, unsigned int pad,
+ enum v4l2_subdev_format_whence which)
+{
+ if (which == V4L2_SUBDEV_FORMAT_TRY)
+ return v4l2_subdev_get_try_format(fh, pad);
+ else
+ return &gsc->cap.mbus_fmt[pad];
+}
+static void gsc_cap_check_limit_size(struct gsc_dev *gsc, unsigned int pad,
+ struct v4l2_mbus_framefmt *fmt)
+{
+ struct gsc_variant *variant = gsc->variant;
+ struct gsc_ctx *ctx = gsc->cap.ctx;
+ u32 min_w = 0, min_h = 0, max_w = 0, max_h = 0;
+
+ switch (pad) {
+ case GSC_PAD_SINK:
+ if (gsc_cap_opened(gsc) &&
+ (ctx->gsc_ctrls.rotate->val == 90 ||
+ ctx->gsc_ctrls.rotate->val == 270)) {
+ min_w = variant->pix_min->real_w;
+ min_h = variant->pix_min->real_h;
+ max_w = variant->pix_max->real_rot_en_w;
+ max_h = variant->pix_max->real_rot_en_h;
+ } else {
+ min_w = variant->pix_min->real_w;
+ min_h = variant->pix_min->real_h;
+ max_w = variant->pix_max->real_rot_dis_w;
+ max_h = variant->pix_max->real_rot_dis_h;
+ }
+ break;
+
+ case GSC_PAD_SOURCE:
+ min_w = variant->pix_min->target_rot_dis_w;
+ min_h = variant->pix_min->target_rot_dis_h;
+ max_w = variant->pix_max->target_rot_dis_w;
+ max_h = variant->pix_max->target_rot_dis_h;
+ break;
+ }
+
+ fmt->width = clamp_t(u32, fmt->width, min_w, max_w);
+ fmt->height = clamp_t(u32, fmt->height , min_h, max_h);
+}
+static void gsc_cap_try_format(struct gsc_dev *gsc,
+ struct v4l2_subdev_fh *fh, unsigned int pad,
+ struct v4l2_mbus_framefmt *fmt,
+ enum v4l2_subdev_format_whence which)
+{
+ struct gsc_fmt *gfmt;
+
+ gfmt = find_format(NULL, &fmt->code, 0);
+ WARN_ON(!gfmt);
+
+ if (pad == GSC_PAD_SINK) {
+ struct gsc_ctx *ctx = gsc->cap.ctx;
+ struct gsc_frame *frame = &ctx->s_frame;
+
+ frame->fmt = gfmt;
+ }
+
+ gsc_cap_check_limit_size(gsc, pad, fmt);
+
+ fmt->colorspace = V4L2_COLORSPACE_JPEG;
+ fmt->field = V4L2_FIELD_NONE;
+}
+
+static int gsc_capture_subdev_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ struct gsc_dev *gsc = v4l2_get_subdevdata(sd);
+ struct v4l2_mbus_framefmt *mf;
+ struct gsc_ctx *ctx = gsc->cap.ctx;
+ struct gsc_frame *frame;
+
+ mf = __gsc_cap_get_format(gsc, fh, fmt->pad, fmt->which);
+ if (mf == NULL)
+ return -EINVAL;
+
+ gsc_cap_try_format(gsc, fh, fmt->pad, &fmt->format, fmt->which);
+ *mf = fmt->format;
+
+ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
+ return 0;
+
+ frame = gsc_capture_get_frame(ctx, fmt->pad);
+
+ if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+ frame->crop.left = 0;
+ frame->crop.top = 0;
+ frame->f_width = mf->width;
+ frame->f_height = mf->height;
+ frame->crop.width = mf->width;
+ frame->crop.height = mf->height;
+ }
+ gsc_dbg("offs_h : %d, offs_v : %d, f_width : %d, f_height :%d,\
+ width : %d, height : %d", frame->crop.left,\
+ frame->crop.top, frame->f_width,
+ frame->f_height,\
+ frame->crop.width, frame->crop.height);
+
+ return 0;
+}
+
+static int gsc_capture_subdev_get_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ struct gsc_dev *gsc = v4l2_get_subdevdata(sd);
+ struct v4l2_mbus_framefmt *mf;
+
+ mf = __gsc_cap_get_format(gsc, fh, fmt->pad, fmt->which);
+ if (mf == NULL)
+ return -EINVAL;
+
+ fmt->format = *mf;
+
+ return 0;
+}
+
+static int __gsc_cap_get_crop(struct gsc_dev *gsc, struct v4l2_subdev_fh *fh,
+ unsigned int pad, enum v4l2_subdev_format_whence which,
+ struct v4l2_rect *crop)
+{
+ struct gsc_ctx *ctx = gsc->cap.ctx;
+ struct gsc_frame *frame = gsc_capture_get_frame(ctx, pad);
+
+ if (which == V4L2_SUBDEV_FORMAT_TRY) {
+ crop = v4l2_subdev_get_try_crop(fh, pad);
+ } else {
+ crop->left = frame->crop.left;
+ crop->top = frame->crop.top;
+ crop->width = frame->crop.width;
+ crop->height = frame->crop.height;
+ }
+
+ return 0;
+}
+
+static void gsc_cap_try_crop(struct gsc_dev *gsc, struct v4l2_rect *crop,
+ u32 pad)
+{
+ struct gsc_variant *variant = gsc->variant;
+ struct gsc_ctx *ctx = gsc->cap.ctx;
+ struct gsc_frame *frame = gsc_capture_get_frame(ctx, pad);
+
+ u32 crop_min_w = variant->pix_min->target_rot_dis_w;
+ u32 crop_min_h = variant->pix_min->target_rot_dis_h;
+ u32 crop_max_w = frame->f_width;
+ u32 crop_max_h = frame->f_height;
+
+ crop->left = clamp_t(u32, crop->left, 0, crop_max_w - crop_min_w);
+ crop->top = clamp_t(u32, crop->top, 0, crop_max_h - crop_min_h);
+ crop->width = clamp_t(u32, crop->width, crop_min_w, crop_max_w);
+ crop->height = clamp_t(u32, crop->height, crop_min_h, crop_max_h);
+}
+
+static int gsc_capture_subdev_set_crop(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_crop *crop)
+{
+ struct gsc_dev *gsc = v4l2_get_subdevdata(sd);
+ struct gsc_ctx *ctx = gsc->cap.ctx;
+ struct gsc_frame *frame = gsc_capture_get_frame(ctx, crop->pad);
+
+ gsc_cap_try_crop(gsc, &crop->rect, crop->pad);
+
+ if (crop->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+ frame->crop = crop->rect;
+
+ return 0;
+}
+
+static int gsc_capture_subdev_get_crop(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_crop *crop)
+{
+ struct gsc_dev *gsc = v4l2_get_subdevdata(sd);
+ struct v4l2_rect gcrop = {0, };
+
+ __gsc_cap_get_crop(gsc, fh, crop->pad, crop->which, &gcrop);
+ crop->rect = gcrop;
+
+ return 0;
+}
+
+static struct v4l2_subdev_pad_ops gsc_cap_subdev_pad_ops = {
+ .get_fmt = gsc_capture_subdev_get_fmt,
+ .set_fmt = gsc_capture_subdev_set_fmt,
+ .get_crop = gsc_capture_subdev_get_crop,
+ .set_crop = gsc_capture_subdev_set_crop,
+};
+
+static struct v4l2_subdev_video_ops gsc_cap_subdev_video_ops = {
+ .s_stream = gsc_capture_subdev_s_stream,
+};
+
+static struct v4l2_subdev_ops gsc_cap_subdev_ops = {
+ .pad = &gsc_cap_subdev_pad_ops,
+ .video = &gsc_cap_subdev_video_ops,
+};
+
+static int gsc_capture_init_formats(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh)
+{
+ struct v4l2_subdev_format format;
+ struct gsc_dev *gsc = v4l2_get_subdevdata(sd);
+ struct gsc_ctx *ctx = gsc->cap.ctx;
+
+ ctx->s_frame.fmt = get_format(2);
+ memset(&format, 0, sizeof(format));
+ format.pad = GSC_PAD_SINK;
+ format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
+ format.format.code = ctx->s_frame.fmt->mbus_code;
+ format.format.width = DEFAULT_GSC_SINK_WIDTH;
+ format.format.height = DEFAULT_GSC_SINK_HEIGHT;
+ gsc_capture_subdev_set_fmt(sd, fh, &format);
+
+ /* G-scaler should not propagate, because it is possible that sink
+ * format different from source format. But the operation of source pad
+ * is not needed.
+ */
+ ctx->d_frame.fmt = get_format(2);
+
+ return 0;
+}
+
+static int gsc_capture_subdev_close(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh)
+{
+ gsc_dbg("");
+
+ return 0;
+}
+
+static int gsc_capture_subdev_registered(struct v4l2_subdev *sd)
+{
+ gsc_dbg("");
+
+ return 0;
+}
+
+static void gsc_capture_subdev_unregistered(struct v4l2_subdev *sd)
+{
+ gsc_dbg("");
+}
+
+static const struct v4l2_subdev_internal_ops gsc_cap_v4l2_internal_ops = {
+ .open = gsc_capture_init_formats,
+ .close = gsc_capture_subdev_close,
+ .registered = gsc_capture_subdev_registered,
+ .unregistered = gsc_capture_subdev_unregistered,
+};
+
+static int gsc_capture_link_setup(struct media_entity *entity,
+ const struct media_pad *local,
+ const struct media_pad *remote, u32 flags)
+{
+ struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
+ struct gsc_dev *gsc = v4l2_get_subdevdata(sd);
+ struct gsc_capture_device *cap = &gsc->cap;
+
+ switch (local->index | media_entity_type(remote->entity)) {
+ case GSC_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
+ if (flags & MEDIA_LNK_FL_ENABLED) {
+ gsc_info("local to gsc-subdev link enable");
+ if (cap->input != 0)
+ return -EBUSY;
+ /* Write-Back link enabled */
+ if (!strcmp(remote->entity->name, FIMD_MODULE_NAME)) {
+ gsc->cap.sd_disp =
+ media_entity_to_v4l2_subdev(remote->entity);
+ gsc->cap.sd_disp->grp_id = FIMD_GRP_ID;
+ cap->ctx->in_path = GSC_WRITEBACK;
+ cap->input = GSC_IN_FIMD_WRITEBACK;
+ } else if (remote->index == FLITE_PAD_SOURCE_PREV) {
+ cap->ctx->in_path = GSC_CAMERA;
+ cap->input = GSC_IN_FLITE_PREVIEW;
+ } else {
+ cap->ctx->in_path = GSC_CAMERA;
+ cap->input = GSC_IN_FLITE_CAMCORDING;
+ }
+ } else {
+ if (cap->input == GSC_IN_FIMD_WRITEBACK)
+ gsc->pipeline.disp = NULL;
+ else if ((cap->input == GSC_IN_FLITE_PREVIEW) ||
+ (cap->input == GSC_IN_FLITE_CAMCORDING))
+ gsc->pipeline.flite = NULL;
+ gsc_info("local to gsc-subdev link disable");
+ cap->input = GSC_IN_NONE;
+ }
+ break;
+ case GSC_PAD_SOURCE | MEDIA_ENT_T_DEVNODE:
+ if (flags & MEDIA_LNK_FL_ENABLED)
+ gsc_info("gsc-subdev to gsc-video link enable");
+ else
+ gsc_info("gsc-subdev to gsc-video link disable");
+ break;
+ }
+
+ return 0;
+}
+
+static const struct media_entity_operations gsc_cap_media_ops = {
+ .link_setup = gsc_capture_link_setup,
+};
+
+static int gsc_capture_create_subdev(struct gsc_dev *gsc)
+{
+ struct v4l2_device *v4l2_dev;
+ struct v4l2_subdev *sd;
+ int ret;
+
+ sd = kzalloc(sizeof(*sd), GFP_KERNEL);
+ if (!sd)
+ return -ENOMEM;
+
+ v4l2_subdev_init(sd, &gsc_cap_subdev_ops);
+ sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
+ snprintf(sd->name, sizeof(sd->name), "gsc-cap-subdev.%d", gsc->id);
+
+ gsc->cap.sd_pads[GSC_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+ gsc->cap.sd_pads[GSC_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+ ret = media_entity_init(&sd->entity, GSC_PADS_NUM,
+ gsc->cap.sd_pads, 0);
+ if (ret)
+ goto err_ent;
+
+ sd->internal_ops = &gsc_cap_v4l2_internal_ops;
+ sd->entity.ops = &gsc_cap_media_ops;
+ sd->grp_id = GSC_CAP_GRP_ID;
+ v4l2_dev = &gsc->mdev[MDEV_CAPTURE]->v4l2_dev;
+
+ ret = v4l2_device_register_subdev(v4l2_dev, sd);
+ if (ret)
+ goto err_sub;
+
+ gsc->mdev[MDEV_CAPTURE]->gsc_cap_sd[gsc->id] = sd;
+ gsc->cap.sd_cap = sd;
+ v4l2_set_subdevdata(sd, gsc);
+ gsc_capture_init_formats(sd, NULL);
+
+ return 0;
+
+err_sub:
+ media_entity_cleanup(&sd->entity);
+err_ent:
+ kfree(sd);
+ return ret;
+}
+
+static int gsc_capture_create_link(struct gsc_dev *gsc)
+{
+ struct media_entity *source, *sink;
+ struct exynos_platform_gscaler *pdata = gsc->pdata;
+ struct exynos_isp_info *isp_info;
+ u32 num_clients = pdata->num_clients;
+ int ret, i;
+ enum cam_port id;
+
+ /* GSC-SUBDEV ------> GSC-VIDEO (Always link enable) */
+ source = &gsc->cap.sd_cap->entity;
+ sink = &gsc->cap.vfd->entity;
+ if (source && sink) {
+ ret = media_entity_create_link(source, GSC_PAD_SOURCE, sink, 0, 0);
+ if (ret) {
+ gsc_err("failed link flite to gsc\n");
+ return ret;
+ }
+ }
+ for (i = 0; i < num_clients; i++) {
+ isp_info = pdata->isp_info[i];
+ id = isp_info->cam_port;
+ /* FIMC-LITE ------> GSC-SUBDEV (ITU & MIPI common) */
+ source = &gsc->cap.sd_flite[id]->entity;
+ sink = &gsc->cap.sd_cap->entity;
+ if (source && sink) {
+ if (pdata->cam_preview)
+ ret = media_entity_create_link(source,
+ FLITE_PAD_SOURCE_PREV,
+ sink, GSC_PAD_SINK, 0);
+ if (!ret && pdata->cam_camcording)
+ ret = media_entity_create_link(source,
+ FLITE_PAD_SOURCE_CAMCORD,
+ sink, GSC_PAD_SINK, 0);
+ if (ret) {
+ gsc_err("failed link flite to gsc\n");
+ return ret;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static struct v4l2_subdev *gsc_cap_register_sensor(struct gsc_dev *gsc, int i)
+{
+ struct exynos_md *mdev = gsc->mdev[MDEV_CAPTURE];
+ struct v4l2_subdev *sd = NULL;
+
+ sd = mdev->sensor_sd[i];
+ if (!sd)
+ return NULL;
+
+ v4l2_set_subdev_hostdata(sd, &gsc->cap.sensor[i]);
+
+ return sd;
+}
+
+static int gsc_cap_register_sensor_entities(struct gsc_dev *gsc)
+{
+ struct exynos_platform_gscaler *pdata = gsc->pdata;
+ u32 num_clients = pdata->num_clients;
+ int i;
+
+ for (i = 0; i < num_clients; i++) {
+ gsc->cap.sensor[i].pdata = pdata->isp_info[i];
+ gsc->cap.sensor[i].sd = gsc_cap_register_sensor(gsc, i);
+ if (IS_ERR_OR_NULL(gsc->cap.sensor[i].sd)) {
+ gsc_err("failed to get register sensor");
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static int gsc_cap_config_camclk(struct gsc_dev *gsc,
+ struct exynos_isp_info *isp_info, int i)
+{
+ struct gsc_capture_device *gsc_cap = &gsc->cap;
+ struct clk *camclk;
+ struct clk *srclk;
+
+ camclk = clk_get(&gsc->pdev->dev, isp_info->cam_clk_name);
+ if (IS_ERR_OR_NULL(camclk)) {
+ gsc_err("failed to get cam clk");
+ return -ENXIO;
+ }
+ gsc_cap->sensor[i].camclk = camclk;
+
+ srclk = clk_get(&gsc->pdev->dev, isp_info->cam_srclk_name);
+ if (IS_ERR_OR_NULL(srclk)) {
+ clk_put(camclk);
+ gsc_err("failed to get cam source clk\n");
+ return -ENXIO;
+ }
+ clk_set_parent(camclk, srclk);
+ clk_set_rate(camclk, isp_info->clk_frequency);
+ clk_put(srclk);
+
+ return 0;
+}
+
+int gsc_register_capture_device(struct gsc_dev *gsc)
+{
+ struct video_device *vfd;
+ struct gsc_capture_device *gsc_cap;
+ struct gsc_ctx *ctx;
+ struct vb2_queue *q;
+ struct exynos_platform_gscaler *pdata = gsc->pdata;
+ struct exynos_isp_info *isp_info;
+ int ret = -ENOMEM;
+ int i;
+
+ ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ ctx->gsc_dev = gsc;
+ ctx->in_path = GSC_CAMERA;
+ ctx->out_path = GSC_DMA;
+ ctx->state = GSC_CTX_CAP;
+
+ vfd = video_device_alloc();
+ if (!vfd) {
+ printk("Failed to allocate video device\n");
+ goto err_ctx_alloc;
+ }
+
+ snprintf(vfd->name, sizeof(vfd->name), "%s.capture",
+ dev_name(&gsc->pdev->dev));
+
+ vfd->fops = &gsc_capture_fops;
+ vfd->ioctl_ops = &gsc_capture_ioctl_ops;
+ vfd->v4l2_dev = &gsc->mdev[MDEV_CAPTURE]->v4l2_dev;
+ vfd->minor = -1;
+ vfd->release = video_device_release;
+ vfd->lock = &gsc->lock;
+ video_set_drvdata(vfd, gsc);
+
+ gsc_cap = &gsc->cap;
+ gsc_cap->vfd = vfd;
+ gsc_cap->refcnt = 0;
+ gsc_cap->active_buf_cnt = 0;
+ gsc_cap->reqbufs_cnt = 0;
+
+ spin_lock_init(&ctx->slock);
+ gsc_cap->ctx = ctx;
+
+ q = &gsc->cap.vbq;
+ memset(q, 0, sizeof(*q));
+ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ q->io_modes = VB2_MMAP | VB2_DMABUF;
+ q->drv_priv = gsc->cap.ctx;
+ q->ops = &gsc_capture_qops;
+ q->mem_ops = gsc->vb2->ops;
+
+ vb2_queue_init(q);
+
+ /* Get mipi-csis and fimc-lite subdev ptr using mdev */
+ for (i = 0; i < FLITE_MAX_ENTITIES; i++)
+ gsc->cap.sd_flite[i] = gsc->mdev[MDEV_CAPTURE]->flite_sd[i];
+
+ for (i = 0; i < CSIS_MAX_ENTITIES; i++)
+ gsc->cap.sd_csis[i] = gsc->mdev[MDEV_CAPTURE]->csis_sd[i];
+
+ for (i = 0; i < pdata->num_clients; i++) {
+ isp_info = pdata->isp_info[i];
+ ret = gsc_cap_config_camclk(gsc, isp_info, i);
+ if (ret) {
+ gsc_err("failed setup cam clk");
+ goto err_ctx_alloc;
+ }
+ }
+
+ ret = gsc_cap_register_sensor_entities(gsc);
+ if (ret) {
+ gsc_err("failed register sensor entities");
+ goto err_clk;
+ }
+
+ ret = video_register_device(vfd, VFL_TYPE_GRABBER,
+ EXYNOS_VIDEONODE_GSC_CAP(gsc->id));
+ if (ret) {
+ gsc_err("failed to register video device");
+ goto err_clk;
+ }
+
+ gsc->cap.vd_pad.flags = MEDIA_PAD_FL_SOURCE;
+ ret = media_entity_init(&vfd->entity, 1, &gsc->cap.vd_pad, 0);
+ if (ret) {
+ gsc_err("failed to initialize entity");
+ goto err_ent;
+ }
+
+ ret = gsc_capture_create_subdev(gsc);
+ if (ret) {
+ gsc_err("failed create subdev");
+ goto err_sd_reg;
+ }
+
+ ret = gsc_capture_create_link(gsc);
+ if (ret) {
+ gsc_err("failed create link");
+ goto err_sd_reg;
+ }
+
+ vfd->ctrl_handler = &ctx->ctrl_handler;
+ gsc_dbg("gsc capture driver registered as /dev/video%d", vfd->num);
+
+ return 0;
+
+err_sd_reg:
+ media_entity_cleanup(&vfd->entity);
+err_ent:
+ video_device_release(vfd);
+err_clk:
+ for (i = 0; i < pdata->num_clients; i++)
+ clk_put(gsc_cap->sensor[i].camclk);
+err_ctx_alloc:
+ kfree(ctx);
+
+ return ret;
+}
+
+static void gsc_capture_destroy_subdev(struct gsc_dev *gsc)
+{
+ struct v4l2_subdev *sd = gsc->cap.sd_cap;
+
+ if (!sd)
+ return;
+ media_entity_cleanup(&sd->entity);
+ v4l2_device_unregister_subdev(sd);
+ kfree(sd);
+ sd = NULL;
+}
+
+void gsc_unregister_capture_device(struct gsc_dev *gsc)
+{
+ struct video_device *vfd = gsc->cap.vfd;
+
+ if (vfd) {
+ media_entity_cleanup(&vfd->entity);
+ /* Can also be called if video device was
+ not registered */
+ video_unregister_device(vfd);
+ }
+ gsc_capture_destroy_subdev(gsc);
+ kfree(gsc->cap.ctx);
+ gsc->cap.ctx = NULL;
+}
+
diff --git a/drivers/media/video/exynos/gsc/gsc-core.c b/drivers/media/video/exynos/gsc/gsc-core.c
new file mode 100755
index 0000000..2569b3c
--- /dev/null
+++ b/drivers/media/video/exynos/gsc/gsc-core.c
@@ -0,0 +1,1632 @@
+/* linux/drivers/media/video/exynos/gsc/gsc-core.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Samsung EXYNOS5 SoC series G-scaler driver
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/bug.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/list.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <media/v4l2-ioctl.h>
+#include <plat/sysmmu.h>
+
+#include "gsc-core.h"
+#define GSC_CLOCK_GATE_NAME "gscl"
+
+int gsc_dbg = 6;
+module_param(gsc_dbg, int, 0644);
+
+static struct gsc_fmt gsc_formats[] = {
+ {
+ .name = "RGB565",
+ .pixelformat = V4L2_PIX_FMT_RGB565X,
+ .depth = { 16 },
+ .num_planes = 1,
+ .nr_comp = 1,
+ }, {
+ .name = "XRGB-8-8-8-8, 32 bpp",
+ .pixelformat = V4L2_PIX_FMT_RGB32,
+ .depth = { 32 },
+ .num_planes = 1,
+ .nr_comp = 1,
+ .mbus_code = V4L2_MBUS_FMT_XRGB8888_4X8_LE,
+ }, {
+ .name = "XBGR-8-8-8-8, 32 bpp",
+ .pixelformat = V4L2_PIX_FMT_BGR32,
+ .depth = { 32 },
+ .num_planes = 1,
+ .nr_comp = 1,
+ .mbus_code = V4L2_MBUS_FMT_XRGB8888_4X8_LE,
+ }, {
+ .name = "YUV 4:2:2 packed, YCbYCr",
+ .pixelformat = V4L2_PIX_FMT_YUYV,
+ .depth = { 16 },
+ .yorder = GSC_LSB_Y,
+ .corder = GSC_CBCR,
+ .num_planes = 1,
+ .nr_comp = 1,
+ .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8,
+ }, {
+ .name = "YUV 4:2:2 packed, CbYCrY",
+ .pixelformat = V4L2_PIX_FMT_UYVY,
+ .depth = { 16 },
+ .yorder = GSC_LSB_C,
+ .corder = GSC_CBCR,
+ .num_planes = 1,
+ .nr_comp = 1,
+ .mbus_code = V4L2_MBUS_FMT_UYVY8_2X8,
+ }, {
+ .name = "YUV 4:2:2 packed, CrYCbY",
+ .pixelformat = V4L2_PIX_FMT_VYUY,
+ .depth = { 16 },
+ .yorder = GSC_LSB_C,
+ .corder = GSC_CRCB,
+ .num_planes = 1,
+ .nr_comp = 1,
+ .mbus_code = V4L2_MBUS_FMT_VYUY8_2X8,
+ }, {
+ .name = "YUV 4:2:2 packed, YCrYCb",
+ .pixelformat = V4L2_PIX_FMT_YVYU,
+ .depth = { 16 },
+ .yorder = GSC_LSB_Y,
+ .corder = GSC_CRCB,
+ .num_planes = 1,
+ .nr_comp = 1,
+ .mbus_code = V4L2_MBUS_FMT_YVYU8_2X8,
+ }, {
+ .name = "YUV 4:4:4 planar, YCbYCr",
+ .pixelformat = V4L2_PIX_FMT_YUV32,
+ .depth = { 32 },
+ .yorder = GSC_LSB_Y,
+ .corder = GSC_CBCR,
+ .num_planes = 1,
+ .nr_comp = 1,
+ .mbus_code = V4L2_MBUS_FMT_YUV8_1X24,
+ }, {
+ .name = "YUV 4:2:2 planar, Y/Cb/Cr",
+ .pixelformat = V4L2_PIX_FMT_YUV422P,
+ .depth = { 16 },
+ .yorder = GSC_LSB_Y,
+ .corder = GSC_CBCR,
+ .num_planes = 1,
+ .nr_comp = 3,
+ }, {
+ .name = "YUV 4:2:2 planar, Y/CbCr",
+ .pixelformat = V4L2_PIX_FMT_NV16,
+ .depth = { 16 },
+ .yorder = GSC_LSB_Y,
+ .corder = GSC_CBCR,
+ .num_planes = 1,
+ .nr_comp = 2,
+ }, {
+ .name = "YUV 4:2:2 planar, Y/CrCb",
+ .pixelformat = V4L2_PIX_FMT_NV61,
+ .depth = { 16 },
+ .yorder = GSC_LSB_Y,
+ .corder = GSC_CRCB,
+ .num_planes = 1,
+ .nr_comp = 2,
+ }, {
+ .name = "YUV 4:2:0 planar, YCbCr",
+ .pixelformat = V4L2_PIX_FMT_YUV420,
+ .depth = { 12 },
+ .yorder = GSC_LSB_Y,
+ .corder = GSC_CBCR,
+ .num_planes = 1,
+ .nr_comp = 3,
+ }, {
+ .name = "YUV 4:2:0 planar, YCbCr",
+ .pixelformat = V4L2_PIX_FMT_YVU420,
+ .depth = { 12 },
+ .yorder = GSC_LSB_Y,
+ .corder = GSC_CRCB,
+ .num_planes = 1,
+ .nr_comp = 3,
+
+ }, {
+ .name = "YUV 4:2:0 planar, Y/CbCr",
+ .pixelformat = V4L2_PIX_FMT_NV12,
+ .depth = { 12 },
+ .yorder = GSC_LSB_Y,
+ .corder = GSC_CBCR,
+ .num_planes = 1,
+ .nr_comp = 2,
+ }, {
+ .name = "YUV 4:2:0 planar, Y/CrCb",
+ .pixelformat = V4L2_PIX_FMT_NV21,
+ .depth = { 12 },
+ .yorder = GSC_LSB_Y,
+ .corder = GSC_CRCB,
+ .num_planes = 1,
+ .nr_comp = 2,
+ }, {
+ .name = "YUV 4:2:0 non-contiguous 2-planar, Y/CbCr",
+ .pixelformat = V4L2_PIX_FMT_NV12M,
+ .depth = { 8, 4 },
+ .yorder = GSC_LSB_Y,
+ .corder = GSC_CBCR,
+ .num_planes = 2,
+ .nr_comp = 2,
+ }, {
+ .name = "YVU 4:2:0 non-contiguous 2-planar, Y/CrCb",
+ .pixelformat = V4L2_PIX_FMT_NV21M,
+ .depth = { 8, 4 },
+ .yorder = GSC_LSB_Y,
+ .corder = GSC_CRCB,
+ .num_planes = 2,
+ .nr_comp = 2,
+ }, {
+ .name = "YUV 4:2:0 non-contiguous 3-planar, Y/Cb/Cr",
+ .pixelformat = V4L2_PIX_FMT_YUV420M,
+ .depth = { 8, 2, 2 },
+ .yorder = GSC_LSB_Y,
+ .corder = GSC_CBCR,
+ .num_planes = 3,
+ .nr_comp = 3,
+ }, {
+ .name = "YUV 4:2:0 non-contiguous 3-planar, Y/Cr/Cb",
+ .pixelformat = V4L2_PIX_FMT_YVU420M,
+ .depth = { 8, 2, 2 },
+ .yorder = GSC_LSB_Y,
+ .corder = GSC_CRCB,
+ .num_planes = 3,
+ .nr_comp = 3,
+ }, {
+ .name = "YUV 4:2:0 non-contiguous 2-planar, Y/CbCr, tiled",
+ .pixelformat = V4L2_PIX_FMT_NV12MT_16X16,
+ .depth = { 8, 4 },
+ .yorder = GSC_LSB_Y,
+ .corder = GSC_CBCR,
+ .num_planes = 2,
+ .nr_comp = 2,
+ },
+};
+
+struct gsc_fmt *get_format(int index)
+{
+ return &gsc_formats[index];
+}
+
+struct gsc_fmt *find_format(u32 *pixelformat, u32 *mbus_code, int index)
+{
+ struct gsc_fmt *fmt, *def_fmt = NULL;
+ unsigned int i;
+
+ if (index >= ARRAY_SIZE(gsc_formats))
+ return NULL;
+
+ for (i = 0; i < ARRAY_SIZE(gsc_formats); ++i) {
+ fmt = get_format(i);
+ if (pixelformat && fmt->pixelformat == *pixelformat)
+ return fmt;
+ if (mbus_code && fmt->mbus_code == *mbus_code)
+ return fmt;
+ if (index == i)
+ def_fmt = fmt;
+ }
+ return def_fmt;
+
+}
+
+void gsc_set_frame_size(struct gsc_frame *frame, int width, int height)
+{
+ frame->f_width = width;
+ frame->f_height = height;
+ frame->crop.width = width;
+ frame->crop.height = height;
+ frame->crop.left = 0;
+ frame->crop.top = 0;
+}
+
+int gsc_cal_prescaler_ratio(struct gsc_variant *var, u32 src, u32 dst, u32 *ratio)
+{
+ if ((dst > src) || (dst >= src / var->poly_sc_down_max)) {
+ *ratio = 1;
+ return 0;
+ }
+
+ if ((src / var->poly_sc_down_max / var->pre_sc_down_max) > dst) {
+ gsc_err("scale ratio exceeded maximun scale down ratio(1/16)");
+ return -EINVAL;
+ }
+
+ *ratio = (dst > (src / 8)) ? 2 : 4;
+
+ return 0;
+}
+
+void gsc_get_prescaler_shfactor(u32 hratio, u32 vratio, u32 *sh)
+{
+ if (hratio == 4 && vratio == 4)
+ *sh = 4;
+ else if ((hratio == 4 && vratio == 2) ||
+ (hratio == 2 && vratio == 4))
+ *sh = 3;
+ else if ((hratio == 4 && vratio == 1) ||
+ (hratio == 1 && vratio == 4) ||
+ (hratio == 2 && vratio == 2))
+ *sh = 2;
+ else if (hratio == 1 && vratio == 1)
+ *sh = 0;
+ else
+ *sh = 1;
+}
+
+void gsc_check_src_scale_info(struct gsc_variant *var, struct gsc_frame *s_frame,
+ u32 *wratio, u32 tx, u32 ty, u32 *hratio, int rot)
+{
+ int remainder = 0, walign, halign;
+ int poly_sc_walign, poly_sc_halign;
+
+ poly_sc_walign = var->pix_align->real_w;
+ poly_sc_halign = var->pix_align->real_h;
+
+ if (is_yuv420(s_frame->fmt->pixelformat)) {
+ walign = *wratio << poly_sc_walign;
+ halign = *hratio << poly_sc_halign;
+ } else if (is_yuv422(s_frame->fmt->pixelformat)) {
+ walign = *wratio << poly_sc_walign;
+ if (rot == 90 || rot == 270)
+ halign = *hratio << poly_sc_halign;
+ else
+ halign = *hratio << (poly_sc_halign - 1);
+ } else {
+ if (rot == 90 || rot == 270) {
+ walign = *wratio << poly_sc_walign;
+ halign = *hratio << poly_sc_halign;
+ } else {
+ walign = *wratio << (poly_sc_walign - 1);
+ halign = *hratio << (poly_sc_halign - 1);
+ }
+ }
+
+ remainder = s_frame->crop.width % walign;
+ if (remainder) {
+ s_frame->crop.width -= remainder;
+ gsc_cal_prescaler_ratio(var, s_frame->crop.width, tx, wratio);
+ gsc_dbg("cropped src width size is recalculated from %d to %d",
+ s_frame->crop.width + remainder, s_frame->crop.width);
+ }
+
+ remainder = s_frame->crop.height % halign;
+ if (remainder) {
+ s_frame->crop.height -= remainder;
+ gsc_cal_prescaler_ratio(var, s_frame->crop.height, ty, hratio);
+ gsc_dbg("cropped src height size is recalculated from %d to %d",
+ s_frame->crop.height + remainder, s_frame->crop.height);
+ }
+}
+
+int gsc_enum_fmt_mplane(struct v4l2_fmtdesc *f)
+{
+ struct gsc_fmt *fmt;
+
+ fmt = find_format(NULL, NULL, f->index);
+ if (!fmt)
+ return -EINVAL;
+
+ strncpy(f->description, fmt->name, sizeof(f->description) - 1);
+ f->pixelformat = fmt->pixelformat;
+
+ return 0;
+}
+
+u32 get_plane_size(struct gsc_frame *frame, unsigned int plane)
+{
+ if (!frame || plane >= frame->fmt->num_planes) {
+ gsc_err("Invalid argument");
+ return 0;
+ }
+
+ return frame->payload[plane];
+}
+
+u32 get_plane_info(struct gsc_frame frm, u32 addr, u32 *index)
+{
+ if (frm.addr.y == addr) {
+ *index = 0;
+ return frm.addr.y;
+ } else if (frm.addr.cb == addr) {
+ *index = 1;
+ return frm.addr.cb;
+ } else if (frm.addr.cr == addr) {
+ *index = 2;
+ return frm.addr.cr;
+ } else {
+ gsc_err("Plane address is wrong");
+ return -EINVAL;
+ }
+}
+
+void gsc_set_prefbuf(struct gsc_dev *gsc, struct gsc_frame frm)
+{
+ u32 f_chk_addr, f_chk_len, s_chk_addr, s_chk_len;
+ f_chk_addr = f_chk_len = s_chk_addr = s_chk_len = 0;
+
+ f_chk_addr = frm.addr.y;
+ f_chk_len = frm.payload[0];
+ if (frm.fmt->num_planes == 2) {
+ s_chk_addr = frm.addr.cb;
+ s_chk_len = frm.payload[1];
+ } else if (frm.fmt->num_planes == 3) {
+ u32 low_addr, low_plane, mid_addr, mid_plane, high_addr, high_plane;
+ u32 t_min, t_max;
+
+ t_min = min3(frm.addr.y, frm.addr.cb, frm.addr.cr);
+ low_addr = get_plane_info(frm, t_min, &low_plane);
+ t_max = max3(frm.addr.y, frm.addr.cb, frm.addr.cr);
+ high_addr = get_plane_info(frm, t_max, &high_plane);
+
+ mid_plane = 3 - (low_plane + high_plane);
+ if (mid_plane == 0)
+ mid_addr = frm.addr.y;
+ else if (mid_plane == 1)
+ mid_addr = frm.addr.cb;
+ else if (mid_plane == 2)
+ mid_addr = frm.addr.cr;
+ else
+ return;
+
+ f_chk_addr = low_addr;
+ if (mid_addr + frm.payload[mid_plane] - low_addr >
+ high_addr + frm.payload[high_plane] - mid_addr) {
+ f_chk_len = frm.payload[low_plane];
+ s_chk_addr = mid_addr;
+ s_chk_len = high_addr + frm.payload[high_plane] - mid_addr;
+ } else {
+ f_chk_len = mid_addr + frm.payload[mid_plane] - low_addr;
+ s_chk_addr = high_addr;
+ s_chk_len = frm.payload[high_plane];
+ }
+ }
+ exynos_sysmmu_set_prefbuf(&gsc->pdev->dev, f_chk_addr, f_chk_len,
+ s_chk_addr, s_chk_len);
+ gsc_dbg("f_addr = 0x%08x, f_len = %d, s_addr = 0x%08x, s_len = %d\n",
+ f_chk_addr, f_chk_len, s_chk_addr, s_chk_len);
+}
+
+int gsc_try_fmt_mplane(struct gsc_ctx *ctx, struct v4l2_format *f)
+{
+ struct gsc_dev *gsc = ctx->gsc_dev;
+ struct gsc_variant *variant = gsc->variant;
+ struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+ struct gsc_fmt *fmt;
+ u32 max_w, max_h, mod_x, mod_y;
+ u32 min_w, min_h, tmp_w, tmp_h;
+ int i;
+
+ gsc_dbg("user put w: %d, h: %d", pix_mp->width, pix_mp->height);
+
+ fmt = find_format(&pix_mp->pixelformat, NULL, 0);
+ if (!fmt) {
+ gsc_err("pixelformat format (0x%X) invalid\n", pix_mp->pixelformat);
+ return -EINVAL;
+ }
+
+ if (pix_mp->field == V4L2_FIELD_ANY)
+ pix_mp->field = V4L2_FIELD_NONE;
+ else if (pix_mp->field != V4L2_FIELD_NONE) {
+ gsc_err("Not supported field order(%d)\n", pix_mp->field);
+ return -EINVAL;
+ }
+
+ max_w = variant->pix_max->target_rot_dis_w;
+ max_h = variant->pix_max->target_rot_dis_h;
+ if (V4L2_TYPE_IS_OUTPUT(f->type)) {
+ mod_x = ffs(variant->pix_align->org_w) - 1;
+ if (is_yuv420(fmt->pixelformat))
+ mod_y = ffs(variant->pix_align->org_h) - 1;
+ else
+ mod_y = ffs(variant->pix_align->org_h) - 2;
+ min_w = variant->pix_min->org_w;
+ min_h = variant->pix_min->org_h;
+ } else {
+ mod_x = ffs(variant->pix_align->org_w) - 1;
+ if (is_yuv420(fmt->pixelformat))
+ mod_y = ffs(variant->pix_align->org_h) - 1;
+ else
+ mod_y = ffs(variant->pix_align->org_h) - 2;
+ min_w = variant->pix_min->target_rot_dis_w;
+ min_h = variant->pix_min->target_rot_dis_h;
+ }
+ gsc_dbg("mod_x: %d, mod_y: %d, max_w: %d, max_h = %d",
+ mod_x, mod_y, max_w, max_h);
+ /* To check if image size is modified to adjust parameter against
+ hardware abilities */
+ tmp_w = pix_mp->width;
+ tmp_h = pix_mp->height;
+
+ v4l_bound_align_image(&pix_mp->width, min_w, max_w, mod_x,
+ &pix_mp->height, min_h, max_h, mod_y, 0);
+ if (tmp_w != pix_mp->width || tmp_h != pix_mp->height)
+ gsc_dbg("Image size has been modified from %dx%d to %dx%d",
+ tmp_w, tmp_h, pix_mp->width, pix_mp->height);
+
+ pix_mp->num_planes = fmt->num_planes;
+
+ if (ctx->gsc_ctrls.csc_eq_mode->val)
+ ctx->gsc_ctrls.csc_eq->val =
+ (pix_mp->width >= 1280) ? 1 : 0;
+ if (ctx->gsc_ctrls.csc_eq->val) /* HD */
+ pix_mp->colorspace = V4L2_COLORSPACE_REC709;
+ else /* SD */
+ pix_mp->colorspace = V4L2_COLORSPACE_SMPTE170M;
+
+
+ for (i = 0; i < pix_mp->num_planes; ++i) {
+ int bpl = (pix_mp->width * fmt->depth[i]) >> 3;
+ pix_mp->plane_fmt[i].bytesperline = bpl;
+ pix_mp->plane_fmt[i].sizeimage = bpl * pix_mp->height;
+
+ gsc_dbg("[%d]: bpl: %d, sizeimage: %d",
+ i, bpl, pix_mp->plane_fmt[i].sizeimage);
+ }
+
+ return 0;
+}
+
+int gsc_g_fmt_mplane(struct gsc_ctx *ctx, struct v4l2_format *f)
+{
+ struct gsc_frame *frame;
+ struct v4l2_pix_format_mplane *pix_mp;
+ int i;
+
+ frame = ctx_get_frame(ctx, f->type);
+ if (IS_ERR(frame))
+ return PTR_ERR(frame);
+
+ pix_mp = &f->fmt.pix_mp;
+
+ pix_mp->width = frame->f_width;
+ pix_mp->height = frame->f_height;
+ pix_mp->field = V4L2_FIELD_NONE;
+ pix_mp->pixelformat = frame->fmt->pixelformat;
+ pix_mp->colorspace = V4L2_COLORSPACE_JPEG;
+ pix_mp->num_planes = frame->fmt->num_planes;
+
+ for (i = 0; i < pix_mp->num_planes; ++i) {
+ pix_mp->plane_fmt[i].bytesperline = (frame->f_width *
+ frame->fmt->depth[i]) / 8;
+ pix_mp->plane_fmt[i].sizeimage = pix_mp->plane_fmt[i].bytesperline *
+ frame->f_height;
+ }
+
+ return 0;
+}
+
+void gsc_check_crop_change(u32 tmp_w, u32 tmp_h, u32 *w, u32 *h)
+{
+ if (tmp_w != *w || tmp_h != *h) {
+ gsc_dbg("Image cropped size has been modified from %dx%d to %dx%d",
+ *w, *h, tmp_w, tmp_h);
+ *w = tmp_w;
+ *h = tmp_h;
+ }
+}
+
+int gsc_g_crop(struct gsc_ctx *ctx, struct v4l2_crop *cr)
+{
+ struct gsc_frame *frame;
+
+ frame = ctx_get_frame(ctx, cr->type);
+ if (IS_ERR(frame))
+ return PTR_ERR(frame);
+
+ memcpy(&cr->c, &frame->crop, sizeof(struct v4l2_rect));
+
+ return 0;
+}
+
+int gsc_try_crop(struct gsc_ctx *ctx, struct v4l2_crop *cr)
+{
+ struct gsc_frame *f;
+ struct gsc_dev *gsc = ctx->gsc_dev;
+ struct gsc_variant *variant = gsc->variant;
+ u32 mod_x = 0, mod_y = 0, tmp_w, tmp_h;
+ u32 min_w, min_h, max_w, max_h;
+
+ if (cr->c.top < 0 || cr->c.left < 0) {
+ gsc_err("doesn't support negative values for top & left\n");
+ return -EINVAL;
+ }
+ gsc_dbg("user put w: %d, h: %d", cr->c.width, cr->c.height);
+
+ if (cr->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ f = &ctx->d_frame;
+ else if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ f = &ctx->s_frame;
+ else
+ return -EINVAL;
+
+ max_w = f->f_width;
+ max_h = f->f_height;
+ tmp_w = cr->c.width;
+ tmp_h = cr->c.height;
+
+ if (V4L2_TYPE_IS_OUTPUT(cr->type)) {
+ if ((is_yuv422(f->fmt->pixelformat) && f->fmt->nr_comp == 1) ||
+ is_rgb(f->fmt->pixelformat))
+ min_w = 32;
+ else
+ min_w = 64;
+ if ((is_yuv422(f->fmt->pixelformat) && f->fmt->nr_comp == 3) ||
+ is_yuv420(f->fmt->pixelformat))
+ min_h = 32;
+ else
+ min_h = 16;
+ } else {
+ if (is_yuv420(f->fmt->pixelformat) ||
+ is_yuv422(f->fmt->pixelformat))
+ mod_x = ffs(variant->pix_align->target_w) - 1;
+ if (is_yuv420(f->fmt->pixelformat))
+ mod_y = ffs(variant->pix_align->target_h) - 1;
+ if (ctx->gsc_ctrls.rotate->val == 90 ||
+ ctx->gsc_ctrls.rotate->val == 270) {
+ max_w = f->f_height;
+ max_h = f->f_width;
+ min_w = variant->pix_min->target_rot_en_w;
+ min_h = variant->pix_min->target_rot_en_h;
+ tmp_w = cr->c.height;
+ tmp_h = cr->c.width;
+ } else {
+ min_w = variant->pix_min->target_rot_dis_w;
+ min_h = variant->pix_min->target_rot_dis_h;
+ }
+ }
+ gsc_dbg("mod_x: %d, mod_y: %d, min_w: %d, min_h = %d,\
+ tmp_w : %d, tmp_h : %d",
+ mod_x, mod_y, min_w, min_h, tmp_w, tmp_h);
+
+ v4l_bound_align_image(&tmp_w, min_w, max_w, mod_x,
+ &tmp_h, min_h, max_h, mod_y, 0);
+
+ if (!V4L2_TYPE_IS_OUTPUT(cr->type) &&
+ (ctx->gsc_ctrls.rotate->val == 90 ||
+ ctx->gsc_ctrls.rotate->val == 270)) {
+ gsc_check_crop_change(tmp_h, tmp_w, &cr->c.width, &cr->c.height);
+ } else {
+ gsc_check_crop_change(tmp_w, tmp_h, &cr->c.width, &cr->c.height);
+ }
+
+ /* adjust left/top if cropping rectangle is out of bounds */
+ /* Need to add code to algin left value with 2's multiple */
+ if (cr->c.left + tmp_w > max_w)
+ cr->c.left = max_w - tmp_w;
+ if (cr->c.top + tmp_h > max_h)
+ cr->c.top = max_h - tmp_h;
+
+ if (is_yuv420(f->fmt->pixelformat) || is_yuv422(f->fmt->pixelformat))
+ if (cr->c.left % 2)
+ cr->c.left -= 1;
+
+ gsc_dbg("Aligned l:%d, t:%d, w:%d, h:%d, f_w: %d, f_h: %d",
+ cr->c.left, cr->c.top, cr->c.width, cr->c.height, max_w, max_h);
+
+ return 0;
+}
+
+int gsc_check_scaler_ratio(struct gsc_variant *var, int sw, int sh, int dw,
+ int dh, int rot, int out_path)
+{
+ int tmp_w, tmp_h, sc_down_max;
+ sc_down_max =
+ (out_path == GSC_DMA) ? var->sc_down_max : var->local_sc_down;
+
+ if (rot == 90 || rot == 270) {
+ tmp_w = dh;
+ tmp_h = dw;
+ } else {
+ tmp_w = dw;
+ tmp_h = dh;
+ }
+
+ if ((sw > (tmp_w * sc_down_max)) ||
+ (sh > (tmp_h * sc_down_max)) ||
+ (tmp_w > (sw * var->sc_up_max)) ||
+ (tmp_h > (sh * var->sc_up_max)))
+ return -EINVAL;
+
+ return 0;
+}
+
+int gsc_set_scaler_info(struct gsc_ctx *ctx)
+{
+ struct gsc_scaler *sc = &ctx->scaler;
+ struct gsc_frame *s_frame = &ctx->s_frame;
+ struct gsc_frame *d_frame = &ctx->d_frame;
+ struct gsc_variant *variant = ctx->gsc_dev->variant;
+ int tx, ty, rot;
+ int ret;
+
+ rot = ctx->gsc_ctrls.rotate->val;
+
+ ret = gsc_check_scaler_ratio(variant, s_frame->crop.width,
+ s_frame->crop.height, d_frame->crop.width, d_frame->crop.height,
+ ctx->gsc_ctrls.rotate->val, ctx->out_path);
+ if (ret) {
+ gsc_err("out of scaler range");
+ return ret;
+ }
+
+ if (rot == 90 || rot == 270) {
+ ty = d_frame->crop.width;
+ tx = d_frame->crop.height;
+ } else {
+ tx = d_frame->crop.width;
+ ty = d_frame->crop.height;
+ }
+
+ ret = gsc_cal_prescaler_ratio(variant, s_frame->crop.width,
+ tx, &sc->pre_hratio);
+ if (ret) {
+ gsc_err("Horizontal scale ratio is out of range");
+ return ret;
+ }
+
+ ret = gsc_cal_prescaler_ratio(variant, s_frame->crop.height,
+ ty, &sc->pre_vratio);
+ if (ret) {
+ gsc_err("Vertical scale ratio is out of range");
+ return ret;
+ }
+
+ gsc_check_src_scale_info(variant, s_frame, &sc->pre_hratio,
+ tx, ty, &sc->pre_vratio, rot);
+
+ gsc_get_prescaler_shfactor(sc->pre_hratio, sc->pre_vratio,
+ &sc->pre_shfactor);
+
+ sc->main_hratio = (s_frame->crop.width << 16) / tx;
+ sc->main_vratio = (s_frame->crop.height << 16) / ty;
+
+ gsc_dbg("scaler input/output size : sx = %d, sy = %d, tx = %d, ty = %d",
+ s_frame->crop.width, s_frame->crop.height, tx, ty);
+ gsc_dbg("scaler ratio info : pre_shfactor : %d, pre_h : %d, pre_v :%d,\
+ main_h : %ld, main_v : %ld", sc->pre_shfactor, sc->pre_hratio,
+ sc->pre_vratio, sc->main_hratio, sc->main_vratio);
+
+ return 0;
+}
+
+int gsc_pipeline_s_stream(struct gsc_dev *gsc, bool on)
+{
+ struct gsc_pipeline *p = &gsc->pipeline;
+ struct exynos_entity_data md_data;
+ int ret = 0;
+
+ /* If gscaler subdev calls the mixer's s_stream, the gscaler must
+ inform the mixer subdev pipeline started from gscaler */
+ if (!strncmp(p->disp->name, MXR_SUBDEV_NAME,
+ sizeof(MXR_SUBDEV_NAME) - 1)) {
+ md_data.mxr_data_from = FROM_GSC_SD;
+ v4l2_set_subdevdata(p->disp, &md_data);
+ }
+
+ ret = v4l2_subdev_call(p->disp, video, s_stream, on);
+ if (ret)
+ gsc_err("Display s_stream on failed\n");
+
+ return ret;
+}
+
+int gsc_out_link_validate(const struct media_pad *source,
+ const struct media_pad *sink)
+{
+ struct v4l2_subdev_format src_fmt;
+ struct v4l2_subdev_crop dst_crop;
+ struct v4l2_subdev *sd;
+ struct gsc_dev *gsc;
+ struct gsc_frame *f;
+ int ret;
+
+ if (media_entity_type(source->entity) != MEDIA_ENT_T_V4L2_SUBDEV ||
+ media_entity_type(sink->entity) != MEDIA_ENT_T_V4L2_SUBDEV) {
+ gsc_err("media entity type isn't subdev\n");
+ return 0;
+ }
+
+ sd = media_entity_to_v4l2_subdev(source->entity);
+ gsc = entity_data_to_gsc(v4l2_get_subdevdata(sd));
+ f = &gsc->out.ctx->d_frame;
+
+ src_fmt.format.width = f->crop.width;
+ src_fmt.format.height = f->crop.height;
+ src_fmt.format.code = f->fmt->mbus_code;
+
+ sd = media_entity_to_v4l2_subdev(sink->entity);
+ /* To check if G-Scaler destination size and Mixer destinatin size
+ are the same */
+ dst_crop.pad = sink->index;
+ dst_crop.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+ ret = v4l2_subdev_call(sd, pad, get_crop, NULL, &dst_crop);
+ if (ret < 0 && ret != -ENOIOCTLCMD) {
+ gsc_err("subdev get_fmt is failed\n");
+ return -EPIPE;
+ }
+
+ if (src_fmt.format.width != dst_crop.rect.width ||
+ src_fmt.format.height != dst_crop.rect.height) {
+ gsc_err("sink and source format is different\
+ src_fmt.w = %d, src_fmt.h = %d,\
+ dst_crop.w = %d, dst_crop.h = %d, rotation = %d",
+ src_fmt.format.width, src_fmt.format.height,
+ dst_crop.rect.width, dst_crop.rect.height,
+ gsc->out.ctx->gsc_ctrls.rotate->val);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ * Set alpha blending for all layers of mixer when gscaler is connected
+ * to mixer only
+ */
+static int gsc_s_ctrl_to_mxr(struct v4l2_ctrl *ctrl)
+{
+ struct gsc_ctx *ctx = ctrl_to_ctx(ctrl);
+ struct media_pad *pad = &ctx->gsc_dev->out.sd_pads[GSC_PAD_SOURCE];
+ struct v4l2_subdev *sd, *gsc_sd;
+ struct v4l2_control control;
+
+ pad = media_entity_remote_source(pad);
+ if (IS_ERR(pad)) {
+ gsc_err("No sink pad conncted with a gscaler source pad");
+ return PTR_ERR(pad);
+ }
+
+ sd = media_entity_to_v4l2_subdev(pad->entity);
+ gsc_sd = ctx->gsc_dev->out.sd;
+ gsc_dbg("%s is connected to %s\n", gsc_sd->name, sd->name);
+ if (strcmp(sd->name, "s5p-mixer0") && strcmp(sd->name, "s5p-mixer1")) {
+ gsc_err("%s is not connected to mixer\n", gsc_sd->name);
+ return -ENODEV;
+ }
+
+ switch (ctrl->id) {
+ case V4L2_CID_TV_LAYER_BLEND_ENABLE:
+ case V4L2_CID_TV_LAYER_BLEND_ALPHA:
+ case V4L2_CID_TV_PIXEL_BLEND_ENABLE:
+ case V4L2_CID_TV_CHROMA_ENABLE:
+ case V4L2_CID_TV_CHROMA_VALUE:
+ case V4L2_CID_TV_LAYER_PRIO:
+ control.id = ctrl->id;
+ control.value = ctrl->val;
+ v4l2_subdev_call(sd, core, s_ctrl, &control);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ * V4L2 controls handling
+ */
+static int gsc_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct gsc_ctx *ctx = ctrl_to_ctx(ctrl);
+ int ret;
+
+ switch (ctrl->id) {
+ case V4L2_CID_HFLIP:
+ update_ctrl_value(ctx->gsc_ctrls.hflip, ctrl->val);
+ break;
+
+ case V4L2_CID_VFLIP:
+ update_ctrl_value(ctx->gsc_ctrls.vflip, ctrl->val);
+ break;
+
+ case V4L2_CID_ROTATE:
+ update_ctrl_value(ctx->gsc_ctrls.rotate, ctrl->val);
+ break;
+
+ case V4L2_CID_GLOBAL_ALPHA:
+ update_ctrl_value(ctx->gsc_ctrls.global_alpha, ctrl->val);
+ break;
+
+ case V4L2_CID_CACHEABLE:
+ update_ctrl_value(ctx->gsc_ctrls.cacheable, ctrl->val);
+ break;
+
+ case V4L2_CID_CSC_EQ_MODE:
+ update_ctrl_value(ctx->gsc_ctrls.csc_eq_mode, ctrl->val);
+ break;
+
+ case V4L2_CID_CSC_EQ:
+ update_ctrl_value(ctx->gsc_ctrls.csc_eq, ctrl->val);
+ break;
+
+ case V4L2_CID_CSC_RANGE:
+ update_ctrl_value(ctx->gsc_ctrls.csc_range, ctrl->val);
+ break;
+
+ case V4L2_CID_CONTENT_PROTECTION:
+ update_ctrl_value(ctx->gsc_ctrls.drm_en, ctrl->val);
+ break;
+ default:
+ ret = gsc_s_ctrl_to_mxr(ctrl);
+ if (ret) {
+ gsc_err("Invalid control\n");
+ return ret;
+ }
+ }
+
+ if (gsc_m2m_opened(ctx->gsc_dev))
+ gsc_ctx_state_lock_set(GSC_PARAMS, ctx);
+
+ return 0;
+}
+
+const struct v4l2_ctrl_ops gsc_ctrl_ops = {
+ .s_ctrl = gsc_s_ctrl,
+};
+
+static const struct v4l2_ctrl_config gsc_custom_ctrl[] = {
+ {
+ .ops = &gsc_ctrl_ops,
+ .id = V4L2_CID_GLOBAL_ALPHA,
+ .name = "Set RGB alpha",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .flags = V4L2_CTRL_FLAG_SLIDER,
+ .max = 255,
+ .step = 1,
+ .def = 0,
+ }, {
+ .ops = &gsc_ctrl_ops,
+ .id = V4L2_CID_CACHEABLE,
+ .name = "Set cacheable",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .flags = V4L2_CTRL_FLAG_SLIDER,
+ .max = 1,
+ .def = true,
+ }, {
+ .ops = &gsc_ctrl_ops,
+ .id = V4L2_CID_TV_LAYER_BLEND_ENABLE,
+ .name = "Enable layer alpha blending",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .flags = V4L2_CTRL_FLAG_SLIDER,
+ }, {
+ .ops = &gsc_ctrl_ops,
+ .id = V4L2_CID_TV_LAYER_BLEND_ALPHA,
+ .name = "Set alpha for layer blending",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .flags = V4L2_CTRL_FLAG_SLIDER,
+ .min = 0,
+ .max = 255,
+ .step = 1,
+ }, {
+ .ops = &gsc_ctrl_ops,
+ .id = V4L2_CID_TV_PIXEL_BLEND_ENABLE,
+ .name = "Enable pixel alpha blending",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .flags = V4L2_CTRL_FLAG_SLIDER,
+ }, {
+ .ops = &gsc_ctrl_ops,
+ .id = V4L2_CID_TV_CHROMA_ENABLE,
+ .name = "Enable chromakey",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .flags = V4L2_CTRL_FLAG_SLIDER,
+ }, {
+ .ops = &gsc_ctrl_ops,
+ .id = V4L2_CID_TV_CHROMA_VALUE,
+ .name = "Set chromakey value",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .flags = V4L2_CTRL_FLAG_SLIDER,
+ .min = 0,
+ .max = 255,
+ .step = 1,
+ }, {
+ .ops = &gsc_ctrl_ops,
+ .id = V4L2_CID_TV_LAYER_PRIO,
+ .name = "Set layer priority",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .flags = V4L2_CTRL_FLAG_SLIDER,
+ .min = 0,
+ .max = 15,
+ .def = 1,
+ .step = 1,
+ }, {
+ .ops = &gsc_ctrl_ops,
+ .id = V4L2_CID_CSC_EQ_MODE,
+ .name = "Set CSC equation mode",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .flags = V4L2_CTRL_FLAG_SLIDER,
+ .max = DEFAULT_CSC_EQ,
+ .def = DEFAULT_CSC_EQ,
+ }, {
+ .ops = &gsc_ctrl_ops,
+ .id = V4L2_CID_CSC_EQ,
+ .name = "Set CSC equation",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .flags = V4L2_CTRL_FLAG_SLIDER,
+ .max = 8,
+ .step = 1,
+ .def = V4L2_COLORSPACE_REC709,
+ }, {
+ .ops = &gsc_ctrl_ops,
+ .id = V4L2_CID_CSC_RANGE,
+ .name = "Set CSC range",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .flags = V4L2_CTRL_FLAG_SLIDER,
+ .max = DEFAULT_CSC_RANGE,
+ .def = DEFAULT_CSC_RANGE,
+ }, {
+ .ops = &gsc_ctrl_ops,
+ .id = V4L2_CID_CONTENT_PROTECTION,
+ .name = "Enable content protection",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .flags = V4L2_CTRL_FLAG_SLIDER,
+ .max = 1,
+ .def = DEFAULT_CONTENT_PROTECTION,
+ },
+};
+
+int gsc_ctrls_create(struct gsc_ctx *ctx)
+{
+ if (ctx->ctrls_rdy) {
+ gsc_err("Control handler of this context was created already");
+ return 0;
+ }
+
+ v4l2_ctrl_handler_init(&ctx->ctrl_handler, GSC_MAX_CTRL_NUM);
+
+ ctx->gsc_ctrls.rotate = v4l2_ctrl_new_std(&ctx->ctrl_handler,
+ &gsc_ctrl_ops, V4L2_CID_ROTATE, 0, 270, 90, 0);
+ ctx->gsc_ctrls.hflip = v4l2_ctrl_new_std(&ctx->ctrl_handler,
+ &gsc_ctrl_ops, V4L2_CID_HFLIP, 0, 1, 1, 0);
+ ctx->gsc_ctrls.vflip = v4l2_ctrl_new_std(&ctx->ctrl_handler,
+ &gsc_ctrl_ops, V4L2_CID_VFLIP, 0, 1, 1, 0);
+
+ ctx->gsc_ctrls.global_alpha = v4l2_ctrl_new_custom(&ctx->ctrl_handler,
+ &gsc_custom_ctrl[0], NULL);
+ ctx->gsc_ctrls.cacheable = v4l2_ctrl_new_custom(&ctx->ctrl_handler,
+ &gsc_custom_ctrl[1], NULL);
+ /* for mixer control */
+ ctx->gsc_ctrls.layer_blend_en = v4l2_ctrl_new_custom(&ctx->ctrl_handler,
+ &gsc_custom_ctrl[2], NULL);
+ ctx->gsc_ctrls.layer_alpha = v4l2_ctrl_new_custom(&ctx->ctrl_handler,
+ &gsc_custom_ctrl[3], NULL);
+ ctx->gsc_ctrls.pixel_blend_en = v4l2_ctrl_new_custom(&ctx->ctrl_handler,
+ &gsc_custom_ctrl[4], NULL);
+ ctx->gsc_ctrls.chroma_en = v4l2_ctrl_new_custom(&ctx->ctrl_handler,
+ &gsc_custom_ctrl[5], NULL);
+ ctx->gsc_ctrls.chroma_val = v4l2_ctrl_new_custom(&ctx->ctrl_handler,
+ &gsc_custom_ctrl[6], NULL);
+ ctx->gsc_ctrls.prio = v4l2_ctrl_new_custom(&ctx->ctrl_handler,
+ &gsc_custom_ctrl[7], NULL);
+
+ /* for CSC equation */
+ ctx->gsc_ctrls.csc_eq_mode = v4l2_ctrl_new_custom(&ctx->ctrl_handler,
+ &gsc_custom_ctrl[8], NULL);
+ ctx->gsc_ctrls.csc_eq = v4l2_ctrl_new_custom(&ctx->ctrl_handler,
+ &gsc_custom_ctrl[9], NULL);
+ ctx->gsc_ctrls.csc_range = v4l2_ctrl_new_custom(&ctx->ctrl_handler,
+ &gsc_custom_ctrl[10], NULL);
+
+ ctx->gsc_ctrls.drm_en = v4l2_ctrl_new_custom(&ctx->ctrl_handler,
+ &gsc_custom_ctrl[11], NULL);
+
+ ctx->ctrls_rdy = ctx->ctrl_handler.error == 0;
+
+ if (ctx->ctrl_handler.error) {
+ int err = ctx->ctrl_handler.error;
+ v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+ gsc_err("Failed to gscaler control hander create");
+ return err;
+ }
+
+ return 0;
+}
+
+void gsc_ctrls_delete(struct gsc_ctx *ctx)
+{
+ if (ctx->ctrls_rdy) {
+ v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+ ctx->ctrls_rdy = false;
+ }
+}
+
+/* The color format (nr_comp, num_planes) must be already configured. */
+int gsc_prepare_addr(struct gsc_ctx *ctx, struct vb2_buffer *vb,
+ struct gsc_frame *frame, struct gsc_addr *addr)
+{
+ struct gsc_dev *gsc = ctx->gsc_dev;
+ int ret = 0;
+ u32 pix_size;
+
+ if (IS_ERR(vb) || IS_ERR(frame)) {
+ gsc_err("Invalid argument");
+ return -EINVAL;
+ }
+
+ pix_size = frame->f_width * frame->f_height;
+
+ gsc_dbg("num_planes= %d, nr_comp= %d, pix_size= %d",
+ frame->fmt->num_planes, frame->fmt->nr_comp, pix_size);
+
+ addr->y = gsc->vb2->plane_addr(vb, 0);
+
+ if (frame->fmt->num_planes == 1) {
+ switch (frame->fmt->nr_comp) {
+ case 1:
+ addr->cb = 0;
+ addr->cr = 0;
+ break;
+ case 2:
+ /* decompose Y into Y/Cb */
+ addr->cb = (dma_addr_t)(addr->y + pix_size);
+ addr->cr = 0;
+ break;
+ case 3:
+ addr->cb = (dma_addr_t)(addr->y + pix_size);
+ addr->cr = (dma_addr_t)(addr->cb + (pix_size >> 2));
+ break;
+ default:
+ gsc_err("Invalid the number of color planes");
+ return -EINVAL;
+ }
+ } else {
+ if (frame->fmt->num_planes >= 2)
+ addr->cb = gsc->vb2->plane_addr(vb, 1);
+
+ if (frame->fmt->num_planes == 3)
+ addr->cr = gsc->vb2->plane_addr(vb, 2);
+ }
+
+ if (frame->fmt->pixelformat == V4L2_PIX_FMT_YVU420 ||
+ frame->fmt->pixelformat == V4L2_PIX_FMT_YVU420M) {
+ u32 t_cb = addr->cb;
+ addr->cb = addr->cr;
+ addr->cr = t_cb;
+ }
+
+ gsc_dbg("ADDR: y= 0x%X cb= 0x%X cr= 0x%X ret= %d",
+ addr->y, addr->cb, addr->cr, ret);
+
+ return ret;
+}
+
+void gsc_wq_suspend(struct work_struct *work)
+{
+ struct gsc_dev *gsc = container_of(work, struct gsc_dev,
+ work_struct);
+ pm_runtime_put_sync(&gsc->pdev->dev);
+}
+
+void gsc_cap_irq_handler(struct gsc_dev *gsc)
+{
+ int done_index;
+
+ done_index = gsc_hw_get_done_output_buf_index(gsc);
+ gsc_dbg("done_index : %d", done_index);
+ if (done_index < 0)
+ gsc_err("All buffers are masked\n");
+ test_bit(ST_CAPT_RUN, &gsc->state) ? :
+ set_bit(ST_CAPT_RUN, &gsc->state);
+ vb2_buffer_done(gsc->cap.vbq.bufs[done_index], VB2_BUF_STATE_DONE);
+}
+
+static irqreturn_t gsc_irq_handler(int irq, void *priv)
+{
+ struct gsc_dev *gsc = priv;
+ int gsc_irq;
+
+ gsc_irq = gsc_hw_get_irq_status(gsc);
+ gsc_hw_clear_irq(gsc, gsc_irq);
+
+ if (gsc_irq == GSC_OR_IRQ) {
+ gsc_err("Local path input over-run interrupt has occurred!\n");
+ return IRQ_HANDLED;
+ }
+
+ spin_lock(&gsc->slock);
+
+ if (test_and_clear_bit(ST_M2M_RUN, &gsc->state)) {
+ struct vb2_buffer *src_vb, *dst_vb;
+ struct gsc_ctx *ctx =
+ v4l2_m2m_get_curr_priv(gsc->m2m.m2m_dev);
+
+ if (!ctx || !ctx->m2m_ctx)
+ goto isr_unlock;
+
+ src_vb = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
+ dst_vb = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
+ if (src_vb && dst_vb) {
+ v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
+ v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE);
+
+ if (test_and_clear_bit(ST_STOP_REQ, &gsc->state))
+ wake_up(&gsc->irq_queue);
+ else
+ v4l2_m2m_job_finish(gsc->m2m.m2m_dev, ctx->m2m_ctx);
+
+ /* wake_up job_abort, stop_streaming */
+ spin_lock(&ctx->slock);
+ if (ctx->state & GSC_CTX_STOP_REQ) {
+ ctx->state &= ~GSC_CTX_STOP_REQ;
+ wake_up(&gsc->irq_queue);
+ }
+ spin_unlock(&ctx->slock);
+ }
+ /* schedule pm_runtime_put_sync */
+ queue_work(gsc->irq_workqueue, &gsc->work_struct);
+ } else if (test_bit(ST_OUTPUT_STREAMON, &gsc->state)) {
+ if (!list_empty(&gsc->out.active_buf_q)) {
+ struct gsc_input_buf *done_buf;
+ done_buf = active_queue_pop(&gsc->out, gsc);
+ gsc_hw_set_input_buf_masking(gsc, done_buf->idx, true);
+ if (!list_is_last(&done_buf->list, &gsc->out.active_buf_q)) {
+ vb2_buffer_done(&done_buf->vb, VB2_BUF_STATE_DONE);
+ list_del(&done_buf->list);
+ }
+ }
+ } else if (test_bit(ST_CAPT_PEND, &gsc->state)) {
+ gsc_cap_irq_handler(gsc);
+ }
+
+isr_unlock:
+ spin_unlock(&gsc->slock);
+ return IRQ_HANDLED;
+}
+
+static int gsc_get_media_info(struct device *dev, void *p)
+{
+ struct exynos_md **mdev = p;
+ struct platform_device *pdev = to_platform_device(dev);
+
+ mdev[pdev->id] = dev_get_drvdata(dev);
+ if (!mdev[pdev->id])
+ return -ENODEV;
+
+ return 0;
+}
+
+int gsc_bus_request_get(struct gsc_dev *gsc)
+{
+ if (!gsc->mif_min_hd) {
+ gsc->mif_min_hd = exynos5_bus_mif_min(667000);
+ if (!gsc->mif_min_hd)
+ gsc_err("failed to request min_freq");
+ }
+
+ if (!gsc->int_min_hd) {
+ gsc->int_min_hd = exynos5_bus_int_min(200000);
+ if (!gsc->int_min_hd)
+ gsc_err("failed to request min_freq");
+ }
+
+ return 0;
+}
+
+void gsc_bus_request_put(struct gsc_dev *gsc)
+{
+ if (gsc->mif_min_hd) {
+ exynos5_bus_mif_put(gsc->mif_min_hd);
+ gsc->mif_min_hd = NULL;
+ }
+ if (gsc->int_min_hd) {
+ exynos5_bus_int_put(gsc->int_min_hd);
+ gsc->int_min_hd = NULL;
+ }
+}
+
+int gsc_set_protected_content(struct gsc_dev *gsc, bool enable)
+{
+ if (gsc->protected_content == enable)
+ return 0;
+
+ if (enable)
+ pm_runtime_get_sync(&gsc->pdev->dev);
+
+ gsc->vb2->set_protected(gsc->alloc_ctx, enable);
+
+ if (!enable)
+ pm_runtime_put_sync(&gsc->pdev->dev);
+
+ gsc->protected_content = enable;
+
+ return 0;
+}
+
+static int gsc_runtime_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct gsc_dev *gsc = (struct gsc_dev *)platform_get_drvdata(pdev);
+
+ if (gsc_m2m_opened(gsc))
+ gsc->m2m.ctx = NULL;
+
+ gsc->vb2->suspend(gsc->alloc_ctx);
+ clk_disable(gsc->clock);
+ clear_bit(ST_PWR_ON, &gsc->state);
+
+ return 0;
+}
+
+static int gsc_runtime_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct gsc_dev *gsc = (struct gsc_dev *)platform_get_drvdata(pdev);
+
+ clk_enable(gsc->clock);
+ gsc->vb2->resume(gsc->alloc_ctx);
+ set_bit(ST_PWR_ON, &gsc->state);
+ return 0;
+}
+
+static void gsc_pm_runtime_enable(struct device *dev)
+{
+#ifdef CONFIG_PM_RUNTIME
+ pm_runtime_enable(dev);
+#else
+ gsc_runtime_resume(dev);
+#endif
+}
+
+static void gsc_pm_runtime_disable(struct device *dev)
+{
+#ifdef CONFIG_PM_RUNTIME
+ pm_runtime_disable(dev);
+#else
+ gsc_runtime_suspend(dev);
+#endif
+}
+
+static int gsc_probe(struct platform_device *pdev)
+{
+ struct gsc_dev *gsc;
+ struct resource *res;
+ struct gsc_driverdata *drv_data;
+ struct device_driver *driver;
+ struct exynos_md *mdev[MDEV_MAX_NUM] = {NULL,};
+ int ret = 0;
+ char workqueue_name[WORKQUEUE_NAME_SIZE];
+
+ dev_dbg(&pdev->dev, "%s():\n", __func__);
+ drv_data = (struct gsc_driverdata *)
+ platform_get_device_id(pdev)->driver_data;
+
+ if (pdev->id >= drv_data->num_entities) {
+ dev_err(&pdev->dev, "Invalid platform device id: %d\n",
+ pdev->id);
+ return -EINVAL;
+ }
+
+ gsc = kzalloc(sizeof(struct gsc_dev), GFP_KERNEL);
+ if (!gsc)
+ return -ENOMEM;
+
+ gsc->id = pdev->id;
+ gsc->variant = drv_data->variant[gsc->id];
+ gsc->pdev = pdev;
+ gsc->pdata = pdev->dev.platform_data;
+
+ init_waitqueue_head(&gsc->irq_queue);
+ spin_lock_init(&gsc->slock);
+ mutex_init(&gsc->lock);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "failed to find the registers\n");
+ ret = -ENOENT;
+ goto err_info;
+ }
+
+ gsc->regs_res = request_mem_region(res->start, resource_size(res),
+ dev_name(&pdev->dev));
+ if (!gsc->regs_res) {
+ dev_err(&pdev->dev, "failed to obtain register region\n");
+ ret = -ENOENT;
+ goto err_info;
+ }
+
+ gsc->regs = ioremap(res->start, resource_size(res));
+ if (!gsc->regs) {
+ dev_err(&pdev->dev, "failed to map registers\n");
+ ret = -ENXIO;
+ goto err_req_region;
+ }
+
+ /* Get Gscaler clock */
+ gsc->clock = clk_get(&gsc->pdev->dev, GSC_CLOCK_GATE_NAME);
+ if (IS_ERR(gsc->clock)) {
+ gsc_err("failed to get gscaler.%d clock", gsc->id);
+ goto err_regs_unmap;
+ }
+ clk_put(gsc->clock);
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "failed to get IRQ resource\n");
+ ret = -ENXIO;
+ goto err_regs_unmap;
+ }
+ gsc->irq = res->start;
+
+ ret = request_irq(gsc->irq, gsc_irq_handler, 0, pdev->name, gsc);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to install irq (%d)\n", ret);
+ goto err_regs_unmap;
+ }
+
+#if defined(CONFIG_VIDEOBUF2_CMA_PHYS)
+ gsc->vb2 = &gsc_vb2_cma;
+#elif defined(CONFIG_VIDEOBUF2_ION)
+ gsc->vb2 = &gsc_vb2_ion;
+#endif
+
+ platform_set_drvdata(pdev, gsc);
+
+ ret = gsc_register_m2m_device(gsc);
+ if (ret)
+ goto err_irq;
+
+ /* find media device */
+ driver = driver_find(MDEV_MODULE_NAME, &platform_bus_type);
+ if (!driver)
+ goto err_irq;
+
+ ret = driver_for_each_device(driver, NULL, &mdev[0],
+ gsc_get_media_info);
+ if (ret)
+ goto err_irq;
+
+ gsc->mdev[MDEV_OUTPUT] = mdev[MDEV_OUTPUT];
+ gsc->mdev[MDEV_CAPTURE] = mdev[MDEV_CAPTURE];
+
+ gsc_dbg("mdev->mdev[%d] = 0x%08x, mdev->mdev[%d] = 0x%08x",
+ MDEV_OUTPUT, (u32)gsc->mdev[MDEV_OUTPUT], MDEV_CAPTURE,
+ (u32)gsc->mdev[MDEV_CAPTURE]);
+
+ ret = gsc_register_output_device(gsc);
+ if (ret)
+ goto err_irq;
+
+ if (gsc->pdata) {
+ ret = gsc_register_capture_device(gsc);
+ if (ret)
+ goto err_irq;
+ }
+
+ sprintf(workqueue_name, "gsc%d_irq_wq_name", gsc->id);
+ gsc->irq_workqueue = create_singlethread_workqueue(workqueue_name);
+ if (gsc->irq_workqueue == NULL) {
+ dev_err(&pdev->dev, "failed to create workqueue for gsc\n");
+ goto err_irq;
+ }
+ INIT_WORK(&gsc->work_struct, gsc_wq_suspend);
+
+ gsc->alloc_ctx = gsc->vb2->init(gsc);
+ if (IS_ERR(gsc->alloc_ctx)) {
+ ret = PTR_ERR(gsc->alloc_ctx);
+ goto err_wq;
+ }
+ gsc_pm_runtime_enable(&pdev->dev);
+
+ gsc_info("gsc-%d registered successfully", gsc->id);
+
+ return 0;
+
+err_wq:
+ destroy_workqueue(gsc->irq_workqueue);
+err_irq:
+ free_irq(gsc->irq, gsc);
+err_regs_unmap:
+ iounmap(gsc->regs);
+err_req_region:
+ release_resource(gsc->regs_res);
+ kfree(gsc->regs_res);
+err_info:
+ kfree(gsc);
+
+ return ret;
+}
+
+static int __devexit gsc_remove(struct platform_device *pdev)
+{
+ struct gsc_dev *gsc =
+ (struct gsc_dev *)platform_get_drvdata(pdev);
+
+ free_irq(gsc->irq, gsc);
+
+ gsc_unregister_m2m_device(gsc);
+ gsc_unregister_output_device(gsc);
+ gsc_unregister_capture_device(gsc);
+
+ gsc->vb2->cleanup(gsc->alloc_ctx);
+ gsc_pm_runtime_disable(&pdev->dev);
+
+ iounmap(gsc->regs);
+ release_resource(gsc->regs_res);
+ kfree(gsc->regs_res);
+ kfree(gsc);
+
+ dev_info(&pdev->dev, "%s driver unloaded\n", pdev->name);
+ return 0;
+}
+
+static int gsc_suspend(struct device *dev)
+{
+ struct platform_device *pdev;
+ struct gsc_dev *gsc;
+ int ret = 0;
+
+ pdev = to_platform_device(dev);
+ gsc = (struct gsc_dev *)platform_get_drvdata(pdev);
+
+ if (gsc_m2m_run(gsc)) {
+ set_bit(ST_STOP_REQ, &gsc->state);
+ ret = wait_event_timeout(gsc->irq_queue,
+ !test_bit(ST_STOP_REQ, &gsc->state),
+ GSC_SHUTDOWN_TIMEOUT);
+ if (ret == 0)
+ dev_err(&gsc->pdev->dev, "wait timeout : %s\n",
+ __func__);
+ }
+ if (gsc_cap_active(gsc)) {
+ gsc_err("capture device is running!!");
+ return -EINVAL;
+ }
+#ifdef CONFIG_PM_RUNTIME
+ pm_runtime_put_sync(dev);
+#else
+ gsc_runtime_suspend(dev);
+#endif
+
+ return ret;
+}
+
+static int gsc_resume(struct device *dev)
+{
+ struct platform_device *pdev;
+ struct gsc_driverdata *drv_data;
+ struct gsc_dev *gsc;
+ struct gsc_ctx *ctx;
+
+ pdev = to_platform_device(dev);
+ gsc = (struct gsc_dev *)platform_get_drvdata(pdev);
+ drv_data = (struct gsc_driverdata *)
+ platform_get_device_id(pdev)->driver_data;
+
+#ifdef CONFIG_PM_RUNTIME
+ pm_runtime_get_sync(dev);
+#else
+ gsc_runtime_resume(dev);
+#endif
+ if (gsc_m2m_opened(gsc)) {
+ ctx = v4l2_m2m_get_curr_priv(gsc->m2m.m2m_dev);
+ if (ctx != NULL) {
+ gsc->m2m.ctx = NULL;
+ v4l2_m2m_job_finish(gsc->m2m.m2m_dev, ctx->m2m_ctx);
+ }
+ }
+
+ return 0;
+}
+
+static const struct dev_pm_ops gsc_pm_ops = {
+ .suspend = gsc_suspend,
+ .resume = gsc_resume,
+ .runtime_suspend = gsc_runtime_suspend,
+ .runtime_resume = gsc_runtime_resume,
+};
+
+struct gsc_pix_max gsc_v_max = {
+ .org_scaler_bypass_w = 8192,
+ .org_scaler_bypass_h = 8192,
+ .org_scaler_input_w = 4800,
+ .org_scaler_input_h = 3344,
+ .real_rot_dis_w = 4800,
+ .real_rot_dis_h = 3344,
+ .real_rot_en_w = 2047,
+ .real_rot_en_h = 2047,
+ .target_rot_dis_w = 4800,
+ .target_rot_dis_h = 3344,
+ .target_rot_en_w = 2016,
+ .target_rot_en_h = 2016,
+};
+
+struct gsc_pix_min gsc_v_min = {
+ .org_w = 64,
+ .org_h = 32,
+ .real_w = 64,
+ .real_h = 32,
+ .target_rot_dis_w = 32,
+ .target_rot_dis_h = 16,
+ .target_rot_en_w = 16,
+ .target_rot_en_h = 8,
+};
+
+struct gsc_pix_align gsc_v_align = {
+ .org_h = 16,
+ .org_w = 16,
+ .offset_h = 2,
+ .real_w = 1,
+ .real_h = 1,
+ .target_w = 2,
+ .target_h = 2,
+};
+
+struct gsc_variant gsc_v_200_variant = {
+ .pix_max = &gsc_v_max,
+ .pix_min = &gsc_v_min,
+ .pix_align = &gsc_v_align,
+ .in_buf_cnt = 4,
+ .out_buf_cnt = 16,
+ .sc_up_max = 8,
+ .sc_down_max = 16,
+ .poly_sc_down_max = 4,
+ .pre_sc_down_max = 4,
+ .local_sc_down = 4,
+};
+
+static struct gsc_driverdata gsc_v_200_drvdata = {
+ .variant = {
+ [0] = &gsc_v_200_variant,
+ [1] = &gsc_v_200_variant,
+ [2] = &gsc_v_200_variant,
+ [3] = &gsc_v_200_variant,
+ },
+ .num_entities = 4,
+};
+
+static struct platform_device_id gsc_driver_ids[] = {
+ {
+ .name = "exynos-gsc",
+ .driver_data = (unsigned long)&gsc_v_200_drvdata,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(platform, gsc_driver_ids);
+
+static struct platform_driver gsc_driver = {
+ .probe = gsc_probe,
+ .remove = __devexit_p(gsc_remove),
+ .id_table = gsc_driver_ids,
+ .driver = {
+ .name = GSC_MODULE_NAME,
+ .owner = THIS_MODULE,
+ .pm = &gsc_pm_ops,
+ }
+};
+
+static int __init gsc_init(void)
+{
+ int ret = platform_driver_register(&gsc_driver);
+ if (ret)
+ gsc_err("platform_driver_register failed: %d\n", ret);
+ return ret;
+}
+
+static void __exit gsc_exit(void)
+{
+ platform_driver_unregister(&gsc_driver);
+}
+
+module_init(gsc_init);
+module_exit(gsc_exit);
+
+MODULE_AUTHOR("Hyunwong Kim <khw0178.kim@samsung.com>");
+MODULE_DESCRIPTION("Samsung EXYNOS5 Soc series G-Scaler driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/exynos/gsc/gsc-core.h b/drivers/media/video/exynos/gsc/gsc-core.h
new file mode 100644
index 0000000..be4c4ea
--- /dev/null
+++ b/drivers/media/video/exynos/gsc/gsc-core.h
@@ -0,0 +1,823 @@
+/* linux/drivers/media/video/exynos/gsc/gsc-core.h
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * header file for Samsung EXYNOS5 SoC series G-scaler driver
+
+ * 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.
+ */
+
+#ifndef GSC_CORE_H_
+#define GSC_CORE_H_
+
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+#include <linux/videodev2_exynos_media.h>
+#include <linux/io.h>
+#include <linux/pm_runtime.h>
+#include <mach/videonode.h>
+#include <mach/exynos5_bus.h>
+#include <media/videobuf2-core.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/v4l2-mediabus.h>
+#include <media/exynos_mc.h>
+#include <media/exynos_gscaler.h>
+#include "regs-gsc.h"
+
+#if defined(CONFIG_VIDEOBUF2_CMA_PHYS)
+#include <media/videobuf2-cma-phys.h>
+#elif defined(CONFIG_VIDEOBUF2_ION)
+#include <media/videobuf2-ion.h>
+#endif
+
+extern const int h_coef_8t[7][16][8];
+extern const int v_coef_4t[7][16][4];
+extern int gsc_dbg;
+
+#define gsc_info(fmt, args...) \
+ do { \
+ if (gsc_dbg >= 6) \
+ printk(KERN_INFO "[INFO]%s:%d: "fmt "\n", \
+ __func__, __LINE__, ##args); \
+ } while (0)
+
+#define gsc_err(fmt, args...) \
+ do { \
+ if (gsc_dbg >= 3) \
+ printk(KERN_ERR "[ERROR]%s:%d: "fmt "\n", \
+ __func__, __LINE__, ##args); \
+ } while (0)
+
+#define gsc_warn(fmt, args...) \
+ do { \
+ if (gsc_dbg >= 4) \
+ printk(KERN_WARNING "[WARN]%s:%d: "fmt "\n", \
+ __func__, __LINE__, ##args); \
+ } while (0)
+
+#define gsc_dbg(fmt, args...) \
+ do { \
+ if (gsc_dbg >= 7) \
+ printk(KERN_DEBUG "[DEBUG]%s:%d: "fmt "\n", \
+ __func__, __LINE__, ##args); \
+ } while (0)
+
+#define GSC_MAX_CLOCKS 3
+#define GSC_SHUTDOWN_TIMEOUT ((100*HZ)/1000)
+#define GSC_MAX_DEVS 4
+#define WORKQUEUE_NAME_SIZE 32
+#define FIMD_NAME_SIZE 32
+#define GSC_M2M_BUF_NUM 0
+#define GSC_OUT_BUF_MAX 2
+#define GSC_MAX_CTRL_NUM 12
+#define GSC_OUT_MAX_MASK_NUM 7
+#define GSC_OUT_DEF_SRC 15
+#define GSC_OUT_DEF_DST 7
+#define DEFAULT_GSC_SINK_WIDTH 800
+#define DEFAULT_GSC_SINK_HEIGHT 480
+#define DEFAULT_GSC_SOURCE_WIDTH 800
+#define DEFAULT_GSC_SOURCE_HEIGHT 480
+#define DEFAULT_CSC_EQ 1
+#define DEFAULT_CSC_RANGE 1
+#define DEFAULT_CONTENT_PROTECTION 0
+
+#define GSC_LAST_DEV_ID 3
+#define GSC_PAD_SINK 0
+#define GSC_PAD_SOURCE 1
+#define GSC_PADS_NUM 2
+
+#define GSC_PARAMS (1 << 0)
+#define GSC_SRC_FMT (1 << 1)
+#define GSC_DST_FMT (1 << 2)
+#define GSC_CTX_M2M (1 << 3)
+#define GSC_CTX_OUTPUT (1 << 4)
+#define GSC_CTX_START (1 << 5)
+#define GSC_CTX_STOP_REQ (1 << 6)
+#define GSC_CTX_CAP (1 << 10)
+
+#define GSC_SC_UP_MAX_RATIO 65536
+#define GSC_SC_DOWN_RATIO_7_8 74898
+#define GSC_SC_DOWN_RATIO_6_8 87381
+#define GSC_SC_DOWN_RATIO_5_8 104857
+#define GSC_SC_DOWN_RATIO_4_8 131072
+#define GSC_SC_DOWN_RATIO_3_8 174762
+#define GSC_SC_DOWN_RATIO_2_8 262144
+
+enum gsc_dev_flags {
+ /* for global */
+ ST_PWR_ON,
+ ST_STOP_REQ,
+ /* for m2m node */
+ ST_M2M_OPEN,
+ ST_M2M_RUN,
+ /* for output node */
+ ST_OUTPUT_OPEN,
+ ST_OUTPUT_STREAMON,
+ /* for capture node */
+ ST_CAPT_OPEN,
+ ST_CAPT_PEND,
+ ST_CAPT_RUN,
+ ST_CAPT_STREAM,
+ ST_CAPT_PIPE_STREAM,
+ ST_CAPT_SHUT,
+ ST_CAPT_APPLY_CFG,
+ ST_CAPT_JPEG,
+};
+
+enum gsc_cap_input_entity {
+ GSC_IN_NONE,
+ GSC_IN_FLITE_PREVIEW,
+ GSC_IN_FLITE_CAMCORDING,
+ GSC_IN_FIMD_WRITEBACK,
+};
+
+enum gsc_irq {
+ GSC_OR_IRQ = 17,
+ GSC_DONE_IRQ = 16,
+};
+
+/**
+ * enum gsc_datapath - the path of data used for gscaler
+ * @GSC_CAMERA: from camera
+ * @GSC_DMA: from/to DMA
+ * @GSC_LOCAL: to local path
+ * @GSC_WRITEBACK: from FIMD
+ */
+enum gsc_datapath {
+ GSC_CAMERA = 0x1,
+ GSC_DMA,
+ GSC_MIXER,
+ GSC_FIMD,
+ GSC_WRITEBACK,
+};
+
+enum gsc_yuv_fmt {
+ GSC_LSB_Y = 0x10,
+ GSC_LSB_C,
+ GSC_CBCR = 0x20,
+ GSC_CRCB,
+};
+
+#define fh_to_ctx(__fh) container_of(__fh, struct gsc_ctx, fh)
+
+#define is_rgb(img) ((img == V4L2_PIX_FMT_RGB565X) | (img == V4L2_PIX_FMT_RGB32) | \
+ (img == V4L2_PIX_FMT_BGR32))
+#define is_yuv422(img) ((img == V4L2_PIX_FMT_YUYV) | (img == V4L2_PIX_FMT_UYVY) | \
+ (img == V4L2_PIX_FMT_VYUY) | (img == V4L2_PIX_FMT_YVYU) | \
+ (img == V4L2_PIX_FMT_YUV422P) | (img == V4L2_PIX_FMT_NV16) | \
+ (img == V4L2_PIX_FMT_NV61))
+#define is_yuv420(img) ((img == V4L2_PIX_FMT_YUV420) | (img == V4L2_PIX_FMT_YVU420) | \
+ (img == V4L2_PIX_FMT_NV12) | (img == V4L2_PIX_FMT_NV21) | \
+ (img == V4L2_PIX_FMT_NV12M) | (img == V4L2_PIX_FMT_NV21M) | \
+ (img == V4L2_PIX_FMT_YUV420M) | (img == V4L2_PIX_FMT_YVU420M) | \
+ (img == V4L2_PIX_FMT_NV12MT_16X16))
+#define is_AYV12(img) (img == V4L2_PIX_FMT_YVU420M)
+
+#define gsc_m2m_run(dev) test_bit(ST_M2M_RUN, &(dev)->state)
+#define gsc_m2m_opened(dev) test_bit(ST_M2M_OPEN, &(dev)->state)
+#define gsc_out_run(dev) test_bit(ST_OUTPUT_STREAMON, &(dev)->state)
+#define gsc_out_opened(dev) test_bit(ST_OUTPUT_OPEN, &(dev)->state)
+#define gsc_cap_opened(dev) test_bit(ST_CAPT_OPEN, &(dev)->state)
+#define gsc_cap_active(dev) test_bit(ST_CAPT_RUN, &(dev)->state)
+
+#define ctrl_to_ctx(__ctrl) \
+ container_of((__ctrl)->handler, struct gsc_ctx, ctrl_handler)
+#define entity_data_to_gsc(data) \
+ container_of(data, struct gsc_dev, md_data)
+#define gsc_capture_get_frame(ctx, pad)\
+ ((pad == GSC_PAD_SINK) ? &ctx->s_frame : &ctx->d_frame)
+/**
+ * struct gsc_fmt - the driver's internal color format data
+ * @mbus_code: Media Bus pixel code, -1 if not applicable
+ * @name: format description
+ * @pixelformat: the fourcc code for this format, 0 if not applicable
+ * @yorder: Y/C order
+ * @corder: Chrominance order control
+ * @num_planes: number of physically non-contiguous data planes
+ * @nr_comp: number of physically contiguous data planes
+ * @depth: per plane driver's private 'number of bits per pixel'
+ * @flags: flags indicating which operation mode format applies to
+ */
+struct gsc_fmt {
+ enum v4l2_mbus_pixelcode mbus_code;
+ char *name;
+ u32 pixelformat;
+ u32 yorder;
+ u32 corder;
+ u16 num_planes;
+ u16 nr_comp;
+ u8 depth[VIDEO_MAX_PLANES];
+ u32 flags;
+};
+
+/**
+ * struct gsc_input_buf - the driver's video buffer
+ * @vb: videobuf2 buffer
+ * @list : linked list structure for buffer queue
+ * @idx : index of G-Scaler input buffer
+ */
+struct gsc_input_buf {
+ struct vb2_buffer vb;
+ struct list_head list;
+ int idx;
+};
+
+/**
+ * struct gsc_addr - the G-Scaler physical address set
+ * @y: luminance plane address
+ * @cb: Cb plane address
+ * @cr: Cr plane address
+ */
+struct gsc_addr {
+ dma_addr_t y;
+ dma_addr_t cb;
+ dma_addr_t cr;
+};
+
+/* struct gsc_ctrls - the G-Scaler control set
+ * @rotate: rotation degree
+ * @hflip: horizontal flip
+ * @vflip: vertical flip
+ * @global_alpha: the alpha value of current frame
+ * @cacheable: cacheability of current frame
+ * @layer_blend_en: enable mixer layer alpha blending
+ * @layer_alpha: set alpha value for mixer layer
+ * @pixel_blend_en: enable mixer pixel alpha blending
+ * @chroma_en: enable chromakey
+ * @chroma_val: set value for chromakey
+ * @csc_eq_mode: mode to select csc equation of current frame
+ * @csc_eq: csc equation of current frame
+ * @csc_range: csc range of current frame
+ * @drm_en: control content protection
+ */
+struct gsc_ctrls {
+ struct v4l2_ctrl *rotate;
+ struct v4l2_ctrl *hflip;
+ struct v4l2_ctrl *vflip;
+ struct v4l2_ctrl *global_alpha;
+ struct v4l2_ctrl *cacheable;
+ struct v4l2_ctrl *layer_blend_en;
+ struct v4l2_ctrl *layer_alpha;
+ struct v4l2_ctrl *pixel_blend_en;
+ struct v4l2_ctrl *chroma_en;
+ struct v4l2_ctrl *chroma_val;
+ struct v4l2_ctrl *prio;
+ struct v4l2_ctrl *csc_eq_mode;
+ struct v4l2_ctrl *csc_eq;
+ struct v4l2_ctrl *csc_range;
+ struct v4l2_ctrl *drm_en;
+};
+
+/**
+ * struct gsc_scaler - the configuration data for G-Scaler inetrnal scaler
+ * @pre_shfactor: pre sclaer shift factor
+ * @pre_hratio: horizontal ratio of the prescaler
+ * @pre_vratio: vertical ratio of the prescaler
+ * @main_hratio: the main scaler's horizontal ratio
+ * @main_vratio: the main scaler's vertical ratio
+ */
+struct gsc_scaler {
+ u32 pre_shfactor;
+ u32 pre_hratio;
+ u32 pre_vratio;
+ unsigned long main_hratio;
+ unsigned long main_vratio;
+};
+
+struct gsc_dev;
+
+struct gsc_ctx;
+
+/**
+ * struct gsc_frame - source/target frame properties
+ * @f_width: SRC : SRCIMG_WIDTH, DST : OUTPUTDMA_WHOLE_IMG_WIDTH
+ * @f_height: SRC : SRCIMG_HEIGHT, DST : OUTPUTDMA_WHOLE_IMG_HEIGHT
+ * @crop: cropped(source)/scaled(destination) size
+ * @payload: image size in bytes (w x h x bpp)
+ * @addr: image frame buffer physical addresses
+ * @fmt: G-scaler color format pointer
+ * @cacheable: frame's cacheability
+ * @alph: frame's alpha value
+ */
+struct gsc_frame {
+ u32 f_width;
+ u32 f_height;
+ struct v4l2_rect crop;
+ unsigned long payload[VIDEO_MAX_PLANES];
+ struct gsc_addr addr;
+ struct gsc_fmt *fmt;
+ bool cacheable;
+ u8 alpha;
+};
+
+struct gsc_sensor_info {
+ struct exynos_isp_info *pdata;
+ struct v4l2_subdev *sd;
+ struct clk *camclk;
+};
+
+struct gsc_capture_device {
+ struct gsc_ctx *ctx;
+ struct video_device *vfd;
+ struct v4l2_subdev *sd_cap;
+ struct v4l2_subdev *sd_disp;
+ struct v4l2_subdev *sd_flite[FLITE_MAX_ENTITIES];
+ struct v4l2_subdev *sd_csis[CSIS_MAX_ENTITIES];
+ struct gsc_sensor_info sensor[SENSOR_MAX_ENTITIES];
+ struct media_pad vd_pad;
+ struct media_pad sd_pads[GSC_PADS_NUM];
+ struct v4l2_mbus_framefmt mbus_fmt[GSC_PADS_NUM];
+ struct vb2_queue vbq;
+ int active_buf_cnt;
+ int buf_index;
+ int input_index;
+ int refcnt;
+ u32 frame_cnt;
+ u32 reqbufs_cnt;
+ enum gsc_cap_input_entity input;
+ u32 cam_index;
+ bool user_subdev_api;
+};
+
+/**
+ * struct gsc_output_device - v4l2 output device data
+ * @vfd: the video device node for v4l2 output mode
+ * @alloc_ctx: v4l2 memory-to-memory device data
+ * @ctx: hardware context data
+ * @sd: v4l2 subdev pointer of gscaler
+ * @vbq: videobuf2 queue of gscaler output device
+ * @vb_pad: the pad of gscaler video entity
+ * @sd_pads: pads of gscaler subdev entity
+ * @active_buf_q: linked list structure of input buffer
+ * @req_cnt: the number of requested buffer
+ */
+struct gsc_output_device {
+ struct video_device *vfd;
+ struct vb2_alloc_ctx *alloc_ctx;
+ struct gsc_ctx *ctx;
+ struct v4l2_subdev *sd;
+ struct vb2_queue vbq;
+ struct media_pad vd_pad;
+ struct media_pad sd_pads[GSC_PADS_NUM];
+ struct list_head active_buf_q;
+ int req_cnt;
+};
+
+/**
+ * struct gsc_m2m_device - v4l2 memory-to-memory device data
+ * @vfd: the video device node for v4l2 m2m mode
+ * @m2m_dev: v4l2 memory-to-memory device data
+ * @ctx: hardware context data
+ * @refcnt: the reference counter
+ */
+struct gsc_m2m_device {
+ struct video_device *vfd;
+ struct v4l2_m2m_dev *m2m_dev;
+ struct gsc_ctx *ctx;
+ int refcnt;
+};
+
+/**
+ * struct gsc_pix_max - image pixel size limits in various IP configurations
+ *
+ * @org_scaler_bypass_w: max pixel width when the scaler is disabled
+ * @org_scaler_bypass_h: max pixel height when the scaler is disabled
+ * @org_scaler_input_w: max pixel width when the scaler is enabled
+ * @org_scaler_input_h: max pixel height when the scaler is enabled
+ * @real_rot_dis_w: max pixel src cropped height with the rotator is off
+ * @real_rot_dis_h: max pixel src croppped width with the rotator is off
+ * @real_rot_en_w: max pixel src cropped width with the rotator is on
+ * @real_rot_en_h: max pixel src cropped height with the rotator is on
+ * @target_rot_dis_w: max pixel dst scaled width with the rotator is off
+ * @target_rot_dis_h: max pixel dst scaled height with the rotator is off
+ * @target_rot_en_w: max pixel dst scaled width with the rotator is on
+ * @target_rot_en_h: max pixel dst scaled height with the rotator is on
+ */
+struct gsc_pix_max {
+ u16 org_scaler_bypass_w;
+ u16 org_scaler_bypass_h;
+ u16 org_scaler_input_w;
+ u16 org_scaler_input_h;
+ u16 real_rot_dis_w;
+ u16 real_rot_dis_h;
+ u16 real_rot_en_w;
+ u16 real_rot_en_h;
+ u16 target_rot_dis_w;
+ u16 target_rot_dis_h;
+ u16 target_rot_en_w;
+ u16 target_rot_en_h;
+};
+
+/**
+ * struct gsc_pix_min - image pixel size limits in various IP configurations
+ *
+ * @org_w: minimum source pixel width
+ * @org_h: minimum source pixel height
+ * @real_w: minimum input crop pixel width
+ * @real_h: minimum input crop pixel height
+ * @target_rot_dis_w: minimum output scaled pixel height when rotator is off
+ * @target_rot_dis_h: minimum output scaled pixel height when rotator is off
+ * @target_rot_en_w: minimum output scaled pixel height when rotator is on
+ * @target_rot_en_h: minimum output scaled pixel height when rotator is on
+ */
+struct gsc_pix_min {
+ u16 org_w;
+ u16 org_h;
+ u16 real_w;
+ u16 real_h;
+ u16 target_rot_dis_w;
+ u16 target_rot_dis_h;
+ u16 target_rot_en_w;
+ u16 target_rot_en_h;
+};
+
+struct gsc_pix_align {
+ u16 org_h;
+ u16 org_w;
+ u16 offset_h;
+ u16 real_w;
+ u16 real_h;
+ u16 target_w;
+ u16 target_h;
+};
+
+/**
+ * struct gsc_variant - G-Scaler variant information
+ */
+struct gsc_variant {
+ struct gsc_pix_max *pix_max;
+ struct gsc_pix_min *pix_min;
+ struct gsc_pix_align *pix_align;
+ u16 in_buf_cnt;
+ u16 out_buf_cnt;
+ u16 sc_up_max;
+ u16 sc_down_max;
+ u16 poly_sc_down_max;
+ u16 pre_sc_down_max;
+ u16 local_sc_down;
+};
+
+/**
+ * struct gsc_driverdata - per device type driver data for init time.
+ *
+ * @variant: the variant information for this driver.
+ * @num_entities: the number of g-scalers
+ */
+struct gsc_driverdata {
+ struct gsc_variant *variant[GSC_MAX_DEVS];
+ int num_entities;
+};
+
+struct gsc_vb2 {
+ const struct vb2_mem_ops *ops;
+ void *(*init)(struct gsc_dev *gsc);
+ void (*cleanup)(void *alloc_ctx);
+
+ unsigned long (*plane_addr)(struct vb2_buffer *vb, u32 plane_no);
+
+ int (*resume)(void *alloc_ctx);
+ void (*suspend)(void *alloc_ctx);
+
+ int (*cache_flush)(struct vb2_buffer *vb, u32 num_planes);
+ void (*set_cacheable)(void *alloc_ctx, bool cacheable);
+ void (*set_sharable)(void *alloc_ctx, bool sharable);
+ void (*set_protected)(void *alloc_ctx, bool ctx_protected);
+};
+
+struct gsc_pipeline {
+ struct media_pipeline *pipe;
+ struct v4l2_subdev *sd_gsc;
+ struct v4l2_subdev *disp;
+ struct v4l2_subdev *flite;
+ struct v4l2_subdev *csis;
+ struct v4l2_subdev *sensor;
+};
+
+/**
+ * struct gsc_dev - abstraction for G-Scaler entity
+ * @slock: the spinlock protecting this data structure
+ * @lock: the mutex protecting this data structure
+ * @pdev: pointer to the G-Scaler platform device
+ * @variant: the IP variant information
+ * @id: g_scaler device index (0..GSC_MAX_DEVS)
+ * @regs: the mapped hardware registers
+ * @regs_res: the resource claimed for IO registers
+ * @irq: G-scaler interrupt number
+ * @irq_queue: interrupt handler waitqueue
+ * @m2m: memory-to-memory V4L2 device information
+ * @out: memory-to-local V4L2 output device information
+ * @state: flags used to synchronize m2m and capture mode operation
+ * @alloc_ctx: videobuf2 memory allocator context
+ * @vb2: videobuf2 memory allocator call-back functions
+ * @mdev: pointer to exynos media device
+ * @pipeline: pointer to subdevs that are connected with gscaler
+ */
+struct gsc_dev {
+ spinlock_t slock;
+ struct mutex lock;
+ struct platform_device *pdev;
+ struct gsc_variant *variant;
+ u16 id;
+ struct clk *clock;
+ void __iomem *regs;
+ struct resource *regs_res;
+ int irq;
+ wait_queue_head_t irq_queue;
+ struct work_struct work_struct;
+ struct workqueue_struct *irq_workqueue;
+ struct gsc_m2m_device m2m;
+ struct gsc_output_device out;
+ struct gsc_capture_device cap;
+ struct exynos_platform_gscaler *pdata;
+ unsigned long state;
+ struct vb2_alloc_ctx *alloc_ctx;
+ const struct gsc_vb2 *vb2;
+ struct exynos_md *mdev[2];
+ struct gsc_pipeline pipeline;
+ struct exynos_entity_data md_data;
+ bool protected_content;
+ struct exynos5_bus_int_handle *int_poll_hd;
+ struct exynos5_bus_int_handle *int_min_hd;
+ struct exynos5_bus_mif_handle *mif_min_hd;
+
+};
+
+/**
+ * gsc_ctx - the device context data
+ * @slock: spinlock protecting this data structure
+ * @s_frame: source frame properties
+ * @d_frame: destination frame properties
+ * @in_path: input mode (DMA or camera)
+ * @out_path: output mode (DMA or FIFO)
+ * @scaler: image scaler properties
+ * @flags: additional flags for image conversion
+ * @state: flags to keep track of user configuration
+ * @gsc_dev: the g-scaler device this context applies to
+ * @m2m_ctx: memory-to-memory device context
+ * @fh: v4l2 file handle
+ * @ctrl_handler: v4l2 controls handler
+ * @ctrls_rdy: true if the control handler is initialized
+ * @gsc_ctrls G-Scaler control set
+ * @m2m_ctx: memory-to-memory device context
+ */
+struct gsc_ctx {
+ spinlock_t slock;
+ struct gsc_frame s_frame;
+ struct gsc_frame d_frame;
+ enum gsc_datapath in_path;
+ enum gsc_datapath out_path;
+ struct gsc_scaler scaler;
+ u32 flags;
+ u32 state;
+ struct gsc_dev *gsc_dev;
+ struct v4l2_m2m_ctx *m2m_ctx;
+ struct v4l2_fh fh;
+ struct v4l2_ctrl_handler ctrl_handler;
+ struct gsc_ctrls gsc_ctrls;
+ bool ctrls_rdy;
+ struct work_struct fence_work;
+ struct list_head fence_wait_list;
+};
+
+#if defined(CONFIG_VIDEOBUF2_CMA_PHYS)
+extern const struct gsc_vb2 gsc_vb2_cma;
+#elif defined(CONFIG_VIDEOBUF2_ION)
+extern const struct gsc_vb2 gsc_vb2_ion;
+#endif
+
+void gsc_set_prefbuf(struct gsc_dev *gsc, struct gsc_frame frm);
+void gsc_clk_release(struct gsc_dev *gsc);
+int gsc_register_m2m_device(struct gsc_dev *gsc);
+void gsc_unregister_m2m_device(struct gsc_dev *gsc);
+int gsc_register_output_device(struct gsc_dev *gsc);
+void gsc_unregister_output_device(struct gsc_dev *gsc);
+int gsc_register_capture_device(struct gsc_dev *gsc);
+void gsc_unregister_capture_device(struct gsc_dev *gsc);
+
+u32 get_plane_size(struct gsc_frame *fr, unsigned int plane);
+char gsc_total_fmts(void);
+struct gsc_fmt *get_format(int index);
+struct gsc_fmt *find_format(u32 *pixelformat, u32 *mbus_code, int index);
+int gsc_enum_fmt_mplane(struct v4l2_fmtdesc *f);
+int gsc_try_fmt_mplane(struct gsc_ctx *ctx, struct v4l2_format *f);
+void gsc_set_frame_size(struct gsc_frame *frame, int width, int height);
+int gsc_g_fmt_mplane(struct gsc_ctx *ctx, struct v4l2_format *f);
+void gsc_check_crop_change(u32 tmp_w, u32 tmp_h, u32 *w, u32 *h);
+int gsc_g_crop(struct gsc_ctx *ctx, struct v4l2_crop *cr);
+int gsc_try_crop(struct gsc_ctx *ctx, struct v4l2_crop *cr);
+int gsc_cal_prescaler_ratio(struct gsc_variant *var, u32 src, u32 dst, u32 *ratio);
+void gsc_get_prescaler_shfactor(u32 hratio, u32 vratio, u32 *sh);
+void gsc_check_src_scale_info(struct gsc_variant *var, struct gsc_frame *s_frame,
+ u32 *wratio, u32 tx, u32 ty, u32 *hratio, int rot);
+int gsc_check_scaler_ratio(struct gsc_variant *var, int sw, int sh, int dw,
+ int dh, int rot, int out_path);
+int gsc_set_scaler_info(struct gsc_ctx *ctx);
+int gsc_ctrls_create(struct gsc_ctx *ctx);
+void gsc_ctrls_delete(struct gsc_ctx *ctx);
+int gsc_out_hw_set(struct gsc_ctx *ctx);
+int gsc_out_set_in_addr(struct gsc_dev *gsc, struct gsc_ctx *ctx,
+ struct gsc_input_buf *buf, int index);
+int gsc_prepare_addr(struct gsc_ctx *ctx, struct vb2_buffer *vb,
+ struct gsc_frame *frame, struct gsc_addr *addr);
+int gsc_out_link_validate(const struct media_pad *source,
+ const struct media_pad *sink);
+int gsc_pipeline_s_stream(struct gsc_dev *gsc, bool on);
+
+static inline void gsc_ctx_state_lock_set(u32 state, struct gsc_ctx *ctx)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ctx->slock, flags);
+ ctx->state |= state;
+ spin_unlock_irqrestore(&ctx->slock, flags);
+}
+
+static inline void gsc_ctx_state_lock_clear(u32 state, struct gsc_ctx *ctx)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ctx->slock, flags);
+ ctx->state &= ~state;
+ spin_unlock_irqrestore(&ctx->slock, flags);
+}
+
+static inline int get_win_num(struct gsc_dev *dev)
+{
+ return (dev->id == 3) ? 2 : dev->id;
+}
+
+static inline int is_tiled(struct gsc_fmt *fmt)
+{
+ return fmt->pixelformat == V4L2_PIX_FMT_NV12MT_16X16;
+}
+
+static inline int is_output(enum v4l2_buf_type type)
+{
+ return (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ||
+ type == V4L2_BUF_TYPE_VIDEO_OUTPUT) ? 1 : 0;
+}
+
+static inline void gsc_hw_enable_control(struct gsc_dev *dev, bool on)
+{
+ u32 cfg = readl(dev->regs + GSC_ENABLE);
+
+ if (on)
+ cfg |= GSC_ENABLE_ON;
+ else
+ cfg &= ~GSC_ENABLE_ON;
+
+ writel(cfg, dev->regs + GSC_ENABLE);
+}
+
+static inline int gsc_hw_get_irq_status(struct gsc_dev *dev)
+{
+ u32 cfg = readl(dev->regs + GSC_IRQ);
+ if (cfg & (1 << GSC_OR_IRQ))
+ return GSC_OR_IRQ;
+ else
+ return GSC_DONE_IRQ;
+
+}
+
+static inline void gsc_hw_clear_irq(struct gsc_dev *dev, int irq)
+{
+ u32 cfg = readl(dev->regs + GSC_IRQ);
+ if (irq == GSC_OR_IRQ)
+ cfg |= GSC_IRQ_STATUS_OR_IRQ;
+ else if (irq == GSC_DONE_IRQ)
+ cfg |= GSC_IRQ_STATUS_OR_FRM_DONE;
+ writel(cfg, dev->regs + GSC_IRQ);
+}
+
+static inline void gsc_lock(struct vb2_queue *vq)
+{
+ struct gsc_ctx *ctx = vb2_get_drv_priv(vq);
+ mutex_lock(&ctx->gsc_dev->lock);
+}
+
+static inline void gsc_unlock(struct vb2_queue *vq)
+{
+ struct gsc_ctx *ctx = vb2_get_drv_priv(vq);
+ mutex_unlock(&ctx->gsc_dev->lock);
+}
+
+static inline bool gsc_ctx_state_is_set(u32 mask, struct gsc_ctx *ctx)
+{
+ unsigned long flags;
+ bool ret;
+
+ spin_lock_irqsave(&ctx->slock, flags);
+ ret = (ctx->state & mask) == mask;
+ spin_unlock_irqrestore(&ctx->slock, flags);
+ return ret;
+}
+
+static inline struct gsc_frame *ctx_get_frame(struct gsc_ctx *ctx,
+ enum v4l2_buf_type type)
+{
+ struct gsc_frame *frame;
+
+ if (V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE == type) {
+ frame = &ctx->s_frame;
+ } else if (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == type) {
+ frame = &ctx->d_frame;
+ } else {
+ gsc_err("Wrong buffer/video queue type (%d)", type);
+ return ERR_PTR(-EINVAL);
+ }
+
+ return frame;
+}
+
+static inline struct gsc_input_buf *
+active_queue_pop(struct gsc_output_device *vid_out, struct gsc_dev *dev)
+{
+ struct gsc_input_buf *buf;
+
+ buf = list_entry(vid_out->active_buf_q.next, struct gsc_input_buf, list);
+ return buf;
+}
+
+static inline void active_queue_push(struct gsc_output_device *vid_out,
+ struct gsc_input_buf *buf, struct gsc_dev *dev)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&dev->slock, flags);
+ list_add_tail(&buf->list, &vid_out->active_buf_q);
+ spin_unlock_irqrestore(&dev->slock, flags);
+}
+
+static inline struct gsc_dev *entity_to_gsc(struct media_entity *me)
+{
+ struct v4l2_subdev *sd;
+
+ sd = container_of(me, struct v4l2_subdev, entity);
+ return entity_data_to_gsc(v4l2_get_subdevdata(sd));
+}
+
+static inline void update_ctrl_value(struct v4l2_ctrl *ctrl, s32 value)
+{
+ ctrl->cur.val = ctrl->val = value;
+}
+
+void gsc_hw_set_sw_reset(struct gsc_dev *dev);
+void gsc_hw_set_one_frm_mode(struct gsc_dev *dev, bool mask);
+void gsc_hw_set_frm_done_irq_mask(struct gsc_dev *dev, bool mask);
+void gsc_hw_set_overflow_irq_mask(struct gsc_dev *dev, bool mask);
+void gsc_hw_set_gsc_irq_enable(struct gsc_dev *dev, bool mask);
+void gsc_hw_set_input_buf_mask_all(struct gsc_dev *dev);
+void gsc_hw_set_output_buf_mask_all(struct gsc_dev *dev);
+void gsc_hw_set_input_buf_masking(struct gsc_dev *dev, u32 shift, bool enable);
+void gsc_hw_set_output_buf_masking(struct gsc_dev *dev, u32 shift, bool enable);
+void gsc_hw_set_input_addr(struct gsc_dev *dev, struct gsc_addr *addr, int index);
+void gsc_hw_set_output_addr(struct gsc_dev *dev, struct gsc_addr *addr, int index);
+void gsc_hw_set_freerun_clock_mode(struct gsc_dev *dev, bool mask);
+void gsc_hw_set_input_path(struct gsc_ctx *ctx);
+void gsc_hw_set_in_size(struct gsc_ctx *ctx);
+void gsc_hw_set_in_image_rgb(struct gsc_ctx *ctx);
+void gsc_hw_set_in_image_format(struct gsc_ctx *ctx);
+void gsc_hw_set_output_path(struct gsc_ctx *ctx);
+void gsc_hw_set_out_size(struct gsc_ctx *ctx);
+void gsc_hw_set_out_image_rgb(struct gsc_ctx *ctx);
+void gsc_hw_set_out_image_format(struct gsc_ctx *ctx);
+void gsc_hw_set_prescaler(struct gsc_ctx *ctx);
+void gsc_hw_set_mainscaler(struct gsc_ctx *ctx);
+void gsc_hw_set_rotation(struct gsc_ctx *ctx);
+void gsc_hw_set_global_alpha(struct gsc_ctx *ctx);
+void gsc_hw_set_sfr_update(struct gsc_ctx *ctx);
+void gsc_hw_set_local_dst(int id, int out, bool on);
+void gsc_hw_set_sysreg_writeback(struct gsc_ctx *ctx);
+void gsc_hw_set_pxlasync_camif_lo_mask(struct gsc_dev *dev, bool on);
+void gsc_hw_set_h_coef(struct gsc_ctx *ctx);
+void gsc_hw_set_v_coef(struct gsc_ctx *ctx);
+void gsc_hw_set_in_pingpong_update(struct gsc_dev *dev);
+void gsc_hw_set_in_chrom_stride(struct gsc_ctx *ctx);
+void gsc_hw_set_out_chrom_stride(struct gsc_ctx *ctx);
+void gsc_hw_set_fire_bit_sync_mode(struct gsc_dev *dev, bool mask);
+
+int gsc_hw_get_input_buf_mask_status(struct gsc_dev *dev);
+int gsc_hw_get_done_input_buf_index(struct gsc_dev *dev);
+int gsc_hw_get_done_output_buf_index(struct gsc_dev *dev);
+int gsc_hw_get_nr_unmask_bits(struct gsc_dev *dev);
+int gsc_hw_get_mxr_path_status(void);
+int gsc_wait_reset(struct gsc_dev *dev);
+int gsc_wait_operating(struct gsc_dev *dev);
+int gsc_wait_stop(struct gsc_dev *dev);
+
+void gsc_disp_fifo_sw_reset(struct gsc_dev *dev);
+void gsc_pixelasync_sw_reset(struct gsc_dev *dev);
+
+int gsc_bus_request_get(struct gsc_dev *gsc);
+void gsc_bus_request_put(struct gsc_dev *gsc);
+
+int gsc_set_protected_content(struct gsc_dev *gsc, bool enable);
+
+#endif /* GSC_CORE_H_ */
diff --git a/drivers/media/video/exynos/gsc/gsc-m2m.c b/drivers/media/video/exynos/gsc/gsc-m2m.c
new file mode 100644
index 0000000..a3f622e
--- /dev/null
+++ b/drivers/media/video/exynos/gsc/gsc-m2m.c
@@ -0,0 +1,800 @@
+/* linux/drivers/media/video/exynos/gsc/gsc-m2m.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Samsung EXYNOS5 SoC series G-scaler driver
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/bug.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/list.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <media/v4l2-ioctl.h>
+
+#include "gsc-core.h"
+
+static int gsc_ctx_stop_req(struct gsc_ctx *ctx)
+{
+ struct gsc_ctx *curr_ctx;
+ struct gsc_dev *gsc = ctx->gsc_dev;
+ int ret = 0;
+ unsigned long flags;
+
+ curr_ctx = v4l2_m2m_get_curr_priv(gsc->m2m.m2m_dev);
+ if (!gsc_m2m_run(gsc) || (curr_ctx != ctx))
+ return 0;
+ spin_lock_irqsave(&ctx->slock, flags);
+ ctx->state |= GSC_CTX_STOP_REQ;
+ spin_unlock_irqrestore(&ctx->slock, flags);
+ ret = wait_event_timeout(gsc->irq_queue,
+ !gsc_ctx_state_is_set(GSC_CTX_STOP_REQ, ctx),
+ GSC_SHUTDOWN_TIMEOUT);
+ if (!ret)
+ ret = -EBUSY;
+
+ return ret;
+}
+
+static int gsc_m2m_stop_streaming(struct vb2_queue *q)
+{
+ struct gsc_ctx *ctx = q->drv_priv;
+ struct gsc_dev *gsc = ctx->gsc_dev;
+ int ret;
+
+ vb2_wait_for_all_buffers(q);
+ ret = gsc_ctx_stop_req(ctx);
+ /* FIXME: need to add v4l2_m2m_job_finish(fail) if ret is timeout */
+ if (ret < 0)
+ dev_err(&gsc->pdev->dev, "wait timeout : %s\n", __func__);
+
+ v4l2_m2m_get_next_job(gsc->m2m.m2m_dev, ctx->m2m_ctx);
+
+ return 0;
+}
+
+static void gsc_m2m_job_abort(void *priv)
+{
+ struct gsc_ctx *ctx = priv;
+ struct gsc_dev *gsc = ctx->gsc_dev;
+ int ret;
+
+ vb2_wait_for_all_buffers(v4l2_m2m_get_src_vq(ctx->m2m_ctx));
+ vb2_wait_for_all_buffers(v4l2_m2m_get_dst_vq(ctx->m2m_ctx));
+ ret = gsc_ctx_stop_req(ctx);
+ /* FIXME: need to add v4l2_m2m_job_finish(fail) if ret is timeout */
+ if (ret < 0)
+ dev_err(&gsc->pdev->dev, "wait timeout : %s\n", __func__);
+
+ v4l2_m2m_get_next_job(gsc->m2m.m2m_dev, ctx->m2m_ctx);
+}
+
+int gsc_fill_addr(struct gsc_ctx *ctx)
+{
+ struct gsc_frame *s_frame, *d_frame;
+ struct vb2_buffer *vb = NULL;
+ int ret = 0;
+
+ s_frame = &ctx->s_frame;
+ d_frame = &ctx->d_frame;
+
+ vb = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
+ if (vb->num_planes != s_frame->fmt->num_planes) {
+ gsc_err("gsc(%s): vb(%p) planes=%d s_frame(%p) planes=%d\n",
+ v4l2_m2m_get_src_vq(ctx->m2m_ctx)->name,
+ vb, vb->num_planes, s_frame, s_frame->fmt->num_planes);
+ return -EINVAL;
+ }
+ ret = gsc_prepare_addr(ctx, vb, s_frame, &s_frame->addr);
+ if (ret)
+ return ret;
+
+ vb = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+ if (vb->num_planes != d_frame->fmt->num_planes) {
+ gsc_err("gsc(%s): vb(%p) planes=%d d_frame(%p) planes=%d\n",
+ v4l2_m2m_get_dst_vq(ctx->m2m_ctx)->name,
+ vb, vb->num_planes, d_frame, d_frame->fmt->num_planes);
+ return -EINVAL;
+ }
+ ret = gsc_prepare_addr(ctx, vb, d_frame, &d_frame->addr);
+
+ return ret;
+}
+
+static void gsc_m2m_device_run(void *priv)
+{
+ struct gsc_ctx *ctx = priv;
+ struct gsc_dev *gsc;
+ unsigned long flags;
+ u32 ret;
+ bool is_set = false;
+
+ if (WARN(!ctx, "null hardware context\n"))
+ return;
+
+ gsc = ctx->gsc_dev;
+ pm_runtime_get_sync(&gsc->pdev->dev);
+
+ spin_lock_irqsave(&ctx->slock, flags);
+ /* Reconfigure hardware if the context has changed. */
+ if (gsc->m2m.ctx != ctx) {
+ gsc_dbg("gsc->m2m.ctx = 0x%p, current_ctx = 0x%p",
+ gsc->m2m.ctx, ctx);
+ ctx->state |= GSC_PARAMS;
+ gsc->m2m.ctx = ctx;
+ }
+
+ is_set = (ctx->state & GSC_CTX_STOP_REQ) ? 1 : 0;
+ ctx->state &= ~GSC_CTX_STOP_REQ;
+ if (is_set) {
+ wake_up(&gsc->irq_queue);
+ goto put_device;
+ }
+
+ ret = gsc_fill_addr(ctx);
+ if (ret) {
+ gsc_err("Wrong address");
+ goto put_device;
+ }
+
+ if (!gsc->protected_content)
+ gsc_set_prefbuf(gsc, ctx->s_frame);
+
+ if (ctx->state & GSC_PARAMS) {
+ gsc_hw_set_sw_reset(gsc);
+ ret = gsc_wait_reset(gsc);
+ if (ret < 0) {
+ gsc_err("gscaler s/w reset timeout");
+ goto put_device;
+ }
+ gsc_hw_set_input_buf_masking(gsc, GSC_M2M_BUF_NUM, false);
+ gsc_hw_set_output_buf_masking(gsc, GSC_M2M_BUF_NUM, false);
+ gsc_hw_set_frm_done_irq_mask(gsc, false);
+ gsc_hw_set_gsc_irq_enable(gsc, true);
+ gsc_hw_set_one_frm_mode(gsc, true);
+ gsc_hw_set_freerun_clock_mode(gsc, false);
+
+ if (gsc_set_scaler_info(ctx)) {
+ gsc_err("Scaler setup error");
+ goto put_device;
+ }
+
+ gsc_hw_set_input_path(ctx);
+ gsc_hw_set_in_size(ctx);
+ gsc_hw_set_in_image_format(ctx);
+
+ gsc_hw_set_output_path(ctx);
+ gsc_hw_set_out_size(ctx);
+ gsc_hw_set_out_image_format(ctx);
+
+ gsc_hw_set_prescaler(ctx);
+ gsc_hw_set_mainscaler(ctx);
+ gsc_hw_set_h_coef(ctx);
+ gsc_hw_set_v_coef(ctx);
+ gsc_hw_set_rotation(ctx);
+ gsc_hw_set_global_alpha(ctx);
+ }
+ /* When you update SFRs in the middle of operating
+ gsc_hw_set_sfr_update(ctx);
+ */
+ gsc_hw_set_input_addr(gsc, &ctx->s_frame.addr, GSC_M2M_BUF_NUM);
+ gsc_hw_set_output_addr(gsc, &ctx->d_frame.addr, GSC_M2M_BUF_NUM);
+
+ ctx->state &= ~GSC_PARAMS;
+
+ if (!test_and_set_bit(ST_M2M_RUN, &gsc->state)) {
+ /* One frame mode sequence
+ GSCALER_ON on -> GSCALER_OP_STATUS is operating ->
+ GSCALER_ON off */
+ gsc_hw_enable_control(gsc, true);
+ ret = gsc_wait_operating(gsc);
+ if (ret < 0) {
+ gsc_err("gscaler wait operating timeout");
+ goto put_device;
+ }
+ }
+
+ spin_unlock_irqrestore(&ctx->slock, flags);
+ return;
+
+put_device:
+ ctx->state &= ~GSC_PARAMS;
+ spin_unlock_irqrestore(&ctx->slock, flags);
+ pm_runtime_put_sync(&gsc->pdev->dev);
+}
+
+static int gsc_m2m_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
+ unsigned int *num_buffers, unsigned int *num_planes,
+ unsigned int sizes[], void *allocators[])
+{
+ struct gsc_ctx *ctx = vb2_get_drv_priv(vq);
+ struct gsc_frame *frame;
+ int i;
+
+ frame = ctx_get_frame(ctx, vq->type);
+ if (IS_ERR(frame))
+ return PTR_ERR(frame);
+
+ if (!frame->fmt)
+ return -EINVAL;
+
+ *num_planes = frame->fmt->num_planes;
+ for (i = 0; i < frame->fmt->num_planes; i++) {
+ sizes[i] = get_plane_size(frame, i);
+ allocators[i] = ctx->gsc_dev->alloc_ctx;
+ }
+ return 0;
+}
+
+static int gsc_m2m_buf_prepare(struct vb2_buffer *vb)
+{
+ struct gsc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+ struct gsc_dev *gsc = ctx->gsc_dev;
+ struct gsc_frame *frame;
+ int i;
+
+ frame = ctx_get_frame(ctx, vb->vb2_queue->type);
+ if (IS_ERR(frame))
+ return PTR_ERR(frame);
+
+ if (!V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) {
+ for (i = 0; i < frame->fmt->num_planes; i++)
+ vb2_set_plane_payload(vb, i, frame->payload[i]);
+ }
+
+ if (frame->cacheable)
+ gsc->vb2->cache_flush(vb, frame->fmt->num_planes);
+
+ return 0;
+}
+
+static void gsc_m2m_fence_work(struct work_struct *work)
+{
+ struct gsc_ctx *ctx = container_of(work, struct gsc_ctx, fence_work);
+ struct v4l2_m2m_buffer *buffer;
+ struct sync_fence *fence;
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&ctx->slock, flags);
+
+ while (!list_empty(&ctx->fence_wait_list)) {
+ buffer = list_first_entry(&ctx->fence_wait_list,
+ struct v4l2_m2m_buffer, wait);
+ list_del(&buffer->wait);
+ spin_unlock_irqrestore(&ctx->slock, flags);
+
+ fence = buffer->vb.acquire_fence;
+ if (fence) {
+ buffer->vb.acquire_fence = NULL;
+ ret = sync_fence_wait(fence, 1000);
+ if (ret == -ETIME) {
+ gsc_warn("sync_fence_wait() timeout");
+ ret = sync_fence_wait(fence, 10 * MSEC_PER_SEC);
+ }
+ if (ret)
+ gsc_warn("sync_fence_wait() error");
+ sync_fence_put(fence);
+ }
+
+ if (ctx->m2m_ctx) {
+ v4l2_m2m_buf_queue(ctx->m2m_ctx, &buffer->vb);
+ v4l2_m2m_try_schedule(ctx->m2m_ctx);
+ }
+
+ spin_lock_irqsave(&ctx->slock, flags);
+ }
+
+ spin_unlock_irqrestore(&ctx->slock, flags);
+}
+
+static void gsc_m2m_buf_queue(struct vb2_buffer *vb)
+{
+ struct gsc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+ struct v4l2_m2m_buffer *b = container_of(vb, struct v4l2_m2m_buffer, vb);
+ unsigned long flags;
+
+ gsc_dbg("ctx: %p, ctx->state: 0x%x", ctx, ctx->state);
+
+ spin_lock_irqsave(&ctx->slock, flags);
+ list_add_tail(&b->wait, &ctx->fence_wait_list);
+ spin_unlock_irqrestore(&ctx->slock, flags);
+
+ queue_work(ctx->gsc_dev->irq_workqueue, &ctx->fence_work);
+}
+
+struct vb2_ops gsc_m2m_qops = {
+ .queue_setup = gsc_m2m_queue_setup,
+ .buf_prepare = gsc_m2m_buf_prepare,
+ .buf_queue = gsc_m2m_buf_queue,
+ .wait_prepare = gsc_unlock,
+ .wait_finish = gsc_lock,
+ .stop_streaming = gsc_m2m_stop_streaming,
+};
+
+static int gsc_m2m_querycap(struct file *file, void *fh,
+ struct v4l2_capability *cap)
+{
+ struct gsc_ctx *ctx = fh_to_ctx(fh);
+ struct gsc_dev *gsc = ctx->gsc_dev;
+
+ strncpy(cap->driver, gsc->pdev->name, sizeof(cap->driver) - 1);
+ strncpy(cap->card, gsc->pdev->name, sizeof(cap->card) - 1);
+ cap->bus_info[0] = 0;
+ cap->capabilities = V4L2_CAP_STREAMING |
+ V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT |
+ V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE;
+
+ return 0;
+}
+
+static int gsc_m2m_enum_fmt_mplane(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ return gsc_enum_fmt_mplane(f);
+}
+
+static int gsc_m2m_g_fmt_mplane(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct gsc_ctx *ctx = fh_to_ctx(fh);
+
+ if ((f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) &&
+ (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE))
+ return -EINVAL;
+
+ return gsc_g_fmt_mplane(ctx, f);
+}
+
+static int gsc_m2m_try_fmt_mplane(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct gsc_ctx *ctx = fh_to_ctx(fh);
+
+ if ((f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) &&
+ (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE))
+ return -EINVAL;
+
+ return gsc_try_fmt_mplane(ctx, f);
+}
+
+static int gsc_m2m_s_fmt_mplane(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct gsc_ctx *ctx = fh_to_ctx(fh);
+ struct vb2_queue *vq;
+ struct gsc_frame *frame;
+ struct v4l2_pix_format_mplane *pix;
+ int i, ret = 0;
+
+ ret = gsc_m2m_try_fmt_mplane(file, fh, f);
+ if (ret)
+ return ret;
+
+ vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+
+ if (vb2_is_streaming(vq)) {
+ gsc_err("queue (%d) busy", f->type);
+ return -EBUSY;
+ }
+
+ if (V4L2_TYPE_IS_OUTPUT(f->type)) {
+ frame = &ctx->s_frame;
+ } else {
+ frame = &ctx->d_frame;
+ }
+
+ pix = &f->fmt.pix_mp;
+ frame->fmt = find_format(&pix->pixelformat, NULL, 0);
+ if (!frame->fmt)
+ return -EINVAL;
+
+ for (i = 0; i < frame->fmt->num_planes; i++)
+ frame->payload[i] = pix->plane_fmt[i].sizeimage;
+
+ gsc_set_frame_size(frame, pix->width, pix->height);
+
+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ gsc_ctx_state_lock_set(GSC_PARAMS | GSC_DST_FMT, ctx);
+ else
+ gsc_ctx_state_lock_set(GSC_PARAMS | GSC_SRC_FMT, ctx);
+
+ gsc_dbg("f_w: %d, f_h: %d", frame->f_width, frame->f_height);
+
+ return 0;
+}
+
+static int gsc_m2m_reqbufs(struct file *file, void *fh,
+ struct v4l2_requestbuffers *reqbufs)
+{
+ struct gsc_ctx *ctx = fh_to_ctx(fh);
+ struct gsc_dev *gsc = ctx->gsc_dev;
+ struct gsc_frame *frame;
+ u32 max_cnt;
+
+ max_cnt = (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ?
+ gsc->variant->in_buf_cnt : gsc->variant->out_buf_cnt;
+
+ if (reqbufs->count > max_cnt)
+ return -EINVAL;
+ else if (reqbufs->count == 0) {
+ if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ gsc_ctx_state_lock_clear(GSC_SRC_FMT, ctx);
+ else
+ gsc_ctx_state_lock_clear(GSC_DST_FMT, ctx);
+ }
+
+ gsc_set_protected_content(gsc, ctx->gsc_ctrls.drm_en->cur.val);
+
+ frame = ctx_get_frame(ctx, reqbufs->type);
+ frame->cacheable = ctx->gsc_ctrls.cacheable->val;
+ gsc->vb2->set_cacheable(gsc->alloc_ctx, frame->cacheable);
+
+ return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
+}
+
+static int gsc_m2m_querybuf(struct file *file, void *fh,
+ struct v4l2_buffer *buf)
+{
+ struct gsc_ctx *ctx = fh_to_ctx(fh);
+ return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
+}
+
+static int gsc_m2m_qbuf(struct file *file, void *fh,
+ struct v4l2_buffer *buf)
+{
+ struct gsc_ctx *ctx = fh_to_ctx(fh);
+ return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int gsc_m2m_dqbuf(struct file *file, void *fh,
+ struct v4l2_buffer *buf)
+{
+ struct gsc_ctx *ctx = fh_to_ctx(fh);
+ return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int gsc_m2m_streamon(struct file *file, void *fh,
+ enum v4l2_buf_type type)
+{
+ struct gsc_ctx *ctx = fh_to_ctx(fh);
+
+ /* The source and target color format need to be set */
+ if (V4L2_TYPE_IS_OUTPUT(type)) {
+ if (!gsc_ctx_state_is_set(GSC_SRC_FMT, ctx))
+ return -EINVAL;
+ } else if (!gsc_ctx_state_is_set(GSC_DST_FMT, ctx)) {
+ return -EINVAL;
+ }
+
+ return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
+}
+
+static int gsc_m2m_streamoff(struct file *file, void *fh,
+ enum v4l2_buf_type type)
+{
+ struct gsc_ctx *ctx = fh_to_ctx(fh);
+ return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
+}
+
+static int gsc_m2m_cropcap(struct file *file, void *fh,
+ struct v4l2_cropcap *cr)
+{
+ struct gsc_frame *frame;
+ struct gsc_ctx *ctx = fh_to_ctx(fh);
+
+ frame = ctx_get_frame(ctx, cr->type);
+ if (IS_ERR(frame))
+ return PTR_ERR(frame);
+
+ cr->bounds.left = 0;
+ cr->bounds.top = 0;
+ cr->bounds.width = frame->f_width;
+ cr->bounds.height = frame->f_height;
+ cr->defrect = cr->bounds;
+
+ return 0;
+}
+
+static int gsc_m2m_g_crop(struct file *file, void *fh, struct v4l2_crop *cr)
+{
+ struct gsc_ctx *ctx = fh_to_ctx(fh);
+
+ return gsc_g_crop(ctx, cr);
+}
+
+static int gsc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr)
+{
+ struct gsc_ctx *ctx = fh_to_ctx(fh);
+ struct gsc_variant *variant = ctx->gsc_dev->variant;
+ struct gsc_frame *f;
+ int ret;
+
+ ret = gsc_try_crop(ctx, cr);
+ if (ret)
+ return ret;
+
+ f = (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ?
+ &ctx->s_frame : &ctx->d_frame;
+
+ /* Check to see if scaling ratio is within supported range */
+ if (gsc_ctx_state_is_set(GSC_DST_FMT | GSC_SRC_FMT, ctx)) {
+ if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ ret = gsc_check_scaler_ratio(variant, cr->c.width,
+ cr->c.height, ctx->d_frame.crop.width,
+ ctx->d_frame.crop.height,
+ ctx->gsc_ctrls.rotate->val, ctx->out_path);
+ } else {
+ ret = gsc_check_scaler_ratio(variant, ctx->s_frame.crop.width,
+ ctx->s_frame.crop.height, cr->c.width,
+ cr->c.height, ctx->gsc_ctrls.rotate->val,
+ ctx->out_path);
+ }
+ if (ret) {
+ gsc_err("Out of scaler range");
+ return -EINVAL;
+ }
+ }
+
+ f->crop.left = cr->c.left;
+ f->crop.top = cr->c.top;
+ f->crop.width = cr->c.width;
+ f->crop.height = cr->c.height;
+
+ gsc_ctx_state_lock_set(GSC_PARAMS, ctx);
+
+ return 0;
+}
+
+static const struct v4l2_ioctl_ops gsc_m2m_ioctl_ops = {
+ .vidioc_querycap = gsc_m2m_querycap,
+
+ .vidioc_enum_fmt_vid_cap_mplane = gsc_m2m_enum_fmt_mplane,
+ .vidioc_enum_fmt_vid_out_mplane = gsc_m2m_enum_fmt_mplane,
+
+ .vidioc_g_fmt_vid_cap_mplane = gsc_m2m_g_fmt_mplane,
+ .vidioc_g_fmt_vid_out_mplane = gsc_m2m_g_fmt_mplane,
+
+ .vidioc_try_fmt_vid_cap_mplane = gsc_m2m_try_fmt_mplane,
+ .vidioc_try_fmt_vid_out_mplane = gsc_m2m_try_fmt_mplane,
+
+ .vidioc_s_fmt_vid_cap_mplane = gsc_m2m_s_fmt_mplane,
+ .vidioc_s_fmt_vid_out_mplane = gsc_m2m_s_fmt_mplane,
+
+ .vidioc_reqbufs = gsc_m2m_reqbufs,
+ .vidioc_querybuf = gsc_m2m_querybuf,
+
+ .vidioc_qbuf = gsc_m2m_qbuf,
+ .vidioc_dqbuf = gsc_m2m_dqbuf,
+
+ .vidioc_streamon = gsc_m2m_streamon,
+ .vidioc_streamoff = gsc_m2m_streamoff,
+
+ .vidioc_g_crop = gsc_m2m_g_crop,
+ .vidioc_s_crop = gsc_m2m_s_crop,
+ .vidioc_cropcap = gsc_m2m_cropcap
+
+};
+
+static int queue_init(void *priv, struct vb2_queue *src_vq,
+ struct vb2_queue *dst_vq)
+{
+ struct gsc_ctx *ctx = priv;
+ int ret;
+
+ memset(src_vq, 0, sizeof(*src_vq));
+ src_vq->name = kasprintf(GFP_KERNEL, "%s-src", dev_name(&ctx->gsc_dev->pdev->dev));
+ src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
+ src_vq->drv_priv = ctx;
+ src_vq->ops = &gsc_m2m_qops;
+ src_vq->mem_ops = ctx->gsc_dev->vb2->ops;
+ src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+
+ ret = vb2_queue_init(src_vq);
+ if (ret)
+ return ret;
+
+ memset(dst_vq, 0, sizeof(*dst_vq));
+ dst_vq->name = kasprintf(GFP_KERNEL, "%s-dst", dev_name(&ctx->gsc_dev->pdev->dev));
+ dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
+ dst_vq->drv_priv = ctx;
+ dst_vq->ops = &gsc_m2m_qops;
+ dst_vq->mem_ops = ctx->gsc_dev->vb2->ops;
+ dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+
+ return vb2_queue_init(dst_vq);
+}
+
+static int gsc_m2m_open(struct file *file)
+{
+ struct gsc_dev *gsc = video_drvdata(file);
+ struct gsc_ctx *ctx = NULL;
+ int ret;
+
+ gsc_dbg("pid: %d, state: 0x%lx", task_pid_nr(current), gsc->state);
+
+ if (gsc_m2m_opened(gsc) || gsc_out_opened(gsc) || gsc_cap_opened(gsc))
+ return -EBUSY;
+
+ ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ v4l2_fh_init(&ctx->fh, gsc->m2m.vfd);
+ ret = gsc_ctrls_create(ctx);
+ if (ret)
+ goto error_fh;
+
+ /* Use separate control handler per file handle */
+ ctx->fh.ctrl_handler = &ctx->ctrl_handler;
+ file->private_data = &ctx->fh;
+ v4l2_fh_add(&ctx->fh);
+
+ ctx->gsc_dev = gsc;
+ /* Default color format */
+ ctx->s_frame.fmt = get_format(0);
+ ctx->d_frame.fmt = get_format(0);
+ /* Setup the device context for mem2mem mode. */
+ ctx->state |= GSC_CTX_M2M;
+ ctx->flags = 0;
+ ctx->in_path = GSC_DMA;
+ ctx->out_path = GSC_DMA;
+ spin_lock_init(&ctx->slock);
+ INIT_LIST_HEAD(&ctx->fence_wait_list);
+ INIT_WORK(&ctx->fence_work, gsc_m2m_fence_work);
+
+ ctx->m2m_ctx = v4l2_m2m_ctx_init(gsc->m2m.m2m_dev, ctx, queue_init);
+ if (IS_ERR(ctx->m2m_ctx)) {
+ gsc_err("Failed to initialize m2m context");
+ ret = PTR_ERR(ctx->m2m_ctx);
+ goto error_fh;
+ }
+
+ if (gsc->m2m.refcnt++ == 0)
+ set_bit(ST_M2M_OPEN, &gsc->state);
+
+ gsc_bus_request_get(gsc);
+
+ gsc_dbg("gsc m2m driver is opened, ctx(0x%p)", ctx);
+ return 0;
+
+error_fh:
+ v4l2_fh_del(&ctx->fh);
+ v4l2_fh_exit(&ctx->fh);
+ kfree(ctx);
+ return ret;
+}
+
+static int gsc_m2m_release(struct file *file)
+{
+ struct gsc_ctx *ctx = fh_to_ctx(file->private_data);
+ struct gsc_dev *gsc = ctx->gsc_dev;
+
+ gsc_dbg("pid: %d, state: 0x%lx, refcnt= %d",
+ task_pid_nr(current), gsc->state, gsc->m2m.refcnt);
+
+ /* if we didn't properly sequence with the secure side to turn off
+ * content protection, we may be left in a very bad state and the
+ * only way to recover this reliably is to reboot.
+ */
+ BUG_ON(gsc->protected_content);
+
+ gsc_bus_request_put(gsc);
+
+ kfree(ctx->m2m_ctx->cap_q_ctx.q.name);
+ kfree(ctx->m2m_ctx->out_q_ctx.q.name);
+ v4l2_m2m_ctx_release(ctx->m2m_ctx);
+ gsc_ctrls_delete(ctx);
+ v4l2_fh_del(&ctx->fh);
+ v4l2_fh_exit(&ctx->fh);
+
+ if (--gsc->m2m.refcnt <= 0)
+ clear_bit(ST_M2M_OPEN, &gsc->state);
+ kfree(ctx);
+ return 0;
+}
+
+static unsigned int gsc_m2m_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct gsc_ctx *ctx = fh_to_ctx(file->private_data);
+
+ return v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
+}
+
+
+static int gsc_m2m_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct gsc_ctx *ctx = fh_to_ctx(file->private_data);
+
+ return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
+}
+static const struct v4l2_file_operations gsc_m2m_fops = {
+ .owner = THIS_MODULE,
+ .open = gsc_m2m_open,
+ .release = gsc_m2m_release,
+ .poll = gsc_m2m_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = gsc_m2m_mmap,
+};
+
+static struct v4l2_m2m_ops gsc_m2m_ops = {
+ .device_run = gsc_m2m_device_run,
+ .job_abort = gsc_m2m_job_abort,
+};
+
+int gsc_register_m2m_device(struct gsc_dev *gsc)
+{
+ struct video_device *vfd;
+ struct platform_device *pdev;
+ int ret = 0;
+
+ if (!gsc)
+ return -ENODEV;
+
+ pdev = gsc->pdev;
+
+ vfd = video_device_alloc();
+ if (!vfd) {
+ dev_err(&pdev->dev, "Failed to allocate video device\n");
+ return -ENOMEM;
+ }
+
+ vfd->fops = &gsc_m2m_fops;
+ vfd->ioctl_ops = &gsc_m2m_ioctl_ops;
+ vfd->release = video_device_release;
+ vfd->lock = &gsc->lock;
+ snprintf(vfd->name, sizeof(vfd->name), "%s:m2m", dev_name(&pdev->dev));
+
+ video_set_drvdata(vfd, gsc);
+
+ gsc->m2m.vfd = vfd;
+ gsc->m2m.m2m_dev = v4l2_m2m_init(&gsc_m2m_ops);
+ if (IS_ERR(gsc->m2m.m2m_dev)) {
+ dev_err(&pdev->dev, "failed to initialize v4l2-m2m device\n");
+ ret = PTR_ERR(gsc->m2m.m2m_dev);
+ goto err_m2m_r1;
+ }
+
+ ret = video_register_device(vfd, VFL_TYPE_GRABBER,
+ EXYNOS_VIDEONODE_GSC_M2M(gsc->id));
+ if (ret) {
+ dev_err(&pdev->dev,
+ "%s(): failed to register video device\n", __func__);
+ goto err_m2m_r2;
+ }
+
+ gsc_dbg("gsc m2m driver registered as /dev/video%d", vfd->num);
+
+ return 0;
+
+err_m2m_r2:
+ v4l2_m2m_release(gsc->m2m.m2m_dev);
+err_m2m_r1:
+ video_device_release(gsc->m2m.vfd);
+
+ return ret;
+}
+
+void gsc_unregister_m2m_device(struct gsc_dev *gsc)
+{
+ if (gsc)
+ v4l2_m2m_release(gsc->m2m.m2m_dev);
+}
diff --git a/drivers/media/video/exynos/gsc/gsc-output.c b/drivers/media/video/exynos/gsc/gsc-output.c
new file mode 100644
index 0000000..47f11b0
--- /dev/null
+++ b/drivers/media/video/exynos/gsc/gsc-output.c
@@ -0,0 +1,1097 @@
+/* linux/drivers/media/video/exynos/gsc/gsc-output.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Samsung EXYNOS5 SoC series G-scaler driver
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/bug.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/list.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <media/v4l2-ioctl.h>
+#include <plat/bts.h>
+
+#include "gsc-core.h"
+
+int gsc_out_hw_reset_off (struct gsc_dev *gsc)
+{
+ int ret;
+
+ gsc_hw_enable_control(gsc, false);
+ ret = gsc_wait_stop(gsc);
+ if (ret < 0) {
+ gsc_err("gscaler stop timeout");
+ return ret;
+ }
+
+ return 0;
+}
+
+int gsc_out_hw_set(struct gsc_ctx *ctx)
+{
+ struct gsc_dev *gsc = ctx->gsc_dev;
+ int ret = 0;
+
+ ret = gsc_set_scaler_info(ctx);
+ if (ret) {
+ gsc_err("Scaler setup error");
+ return ret;
+ }
+
+ if (gsc_hw_get_mxr_path_status())
+ gsc_hw_set_fire_bit_sync_mode(gsc, true);
+ else
+ gsc_hw_set_fire_bit_sync_mode(gsc, false);
+ gsc_hw_set_frm_done_irq_mask(gsc, false);
+ gsc_hw_set_gsc_irq_enable(gsc, true);
+ gsc_hw_set_one_frm_mode(gsc, false);
+ gsc_hw_set_freerun_clock_mode(gsc, true);
+
+ gsc_hw_set_input_path(ctx);
+ gsc_hw_set_in_size(ctx);
+ gsc_hw_set_in_image_format(ctx);
+
+ gsc_hw_set_output_path(ctx);
+ gsc_hw_set_out_size(ctx);
+ gsc_hw_set_out_image_format(ctx);
+
+ gsc_hw_set_prescaler(ctx);
+ gsc_hw_set_mainscaler(ctx);
+ gsc_hw_set_h_coef(ctx);
+ gsc_hw_set_v_coef(ctx);
+ gsc_hw_set_rotation(ctx);
+ gsc_hw_set_global_alpha(ctx);
+ gsc_hw_set_input_buf_mask_all(gsc);
+
+ gsc_hw_enable_control(gsc, true);
+ ret = gsc_wait_operating(gsc);
+ if (ret < 0) {
+ gsc_err("wait operation timeout");
+ return -EINVAL;
+ }
+ gsc_pipeline_s_stream(gsc, true);
+
+ return 0;
+}
+
+static void gsc_subdev_try_crop(struct gsc_dev *gsc, struct v4l2_rect *cr)
+{
+ struct gsc_variant *variant = gsc->variant;
+ u32 max_w, max_h, min_w, min_h;
+ u32 tmp_w, tmp_h;
+
+ if (gsc->out.ctx->gsc_ctrls.rotate->val == 90 ||
+ gsc->out.ctx->gsc_ctrls.rotate->val == 270) {
+ max_w = variant->pix_max->target_rot_en_w;
+ max_h = variant->pix_max->target_rot_en_h;
+ min_w = variant->pix_min->target_rot_en_w;
+ min_h = variant->pix_min->target_rot_en_h;
+ tmp_w = cr->height;
+ tmp_h = cr->width;
+ } else {
+ max_w = variant->pix_max->target_rot_dis_w;
+ max_h = variant->pix_max->target_rot_dis_h;
+ min_w = variant->pix_min->target_rot_dis_w;
+ min_h = variant->pix_min->target_rot_dis_h;
+ tmp_w = cr->width;
+ tmp_h = cr->height;
+ }
+
+ gsc_dbg("min_w: %d, min_h: %d, max_w: %d, max_h = %d",
+ min_w, min_h, max_w, max_h);
+
+ v4l_bound_align_image(&tmp_w, min_w, max_w, 0,
+ &tmp_h, min_h, max_h, 0, 0);
+
+ if (gsc->out.ctx->gsc_ctrls.rotate->val == 90 ||
+ gsc->out.ctx->gsc_ctrls.rotate->val == 270)
+ gsc_check_crop_change(tmp_h, tmp_w, &cr->width, &cr->height);
+ else
+ gsc_check_crop_change(tmp_w, tmp_h, &cr->width, &cr->height);
+
+ gsc_dbg("Aligned l:%d, t:%d, w:%d, h:%d", cr->left, cr->top,
+ cr->width, cr->height);
+}
+
+static int gsc_subdev_get_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ struct gsc_dev *gsc = entity_data_to_gsc(v4l2_get_subdevdata(sd));
+ struct gsc_ctx *ctx = gsc->out.ctx;
+ struct v4l2_mbus_framefmt *mf = &fmt->format;
+ struct gsc_frame *f;
+
+ if (fmt->pad == GSC_PAD_SINK) {
+ gsc_err("Sink pad get_fmt is not supported");
+ return 0;
+ }
+
+ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+ fmt->format = *v4l2_subdev_get_try_format(fh, fmt->pad);
+ return 0;
+ }
+
+ f = &ctx->d_frame;
+ mf->code = f->fmt->mbus_code;
+ mf->width = f->f_width;
+ mf->height = f->f_height;
+ mf->colorspace = V4L2_COLORSPACE_JPEG;
+
+ return 0;
+}
+
+static int gsc_subdev_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ struct gsc_dev *gsc = entity_data_to_gsc(v4l2_get_subdevdata(sd));
+ struct v4l2_mbus_framefmt *mf;
+ struct gsc_ctx *ctx = gsc->out.ctx;
+ struct gsc_frame *f;
+
+ gsc_dbg("pad%d: code: 0x%x, %dx%d",
+ fmt->pad, fmt->format.code, fmt->format.width, fmt->format.height);
+
+ if (fmt->pad == GSC_PAD_SINK) {
+ gsc_err("Sink pad set_fmt is not supported");
+ return 0;
+ }
+
+ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+ mf = v4l2_subdev_get_try_format(fh, fmt->pad);
+ mf->width = fmt->format.width;
+ mf->height = fmt->format.height;
+ mf->code = fmt->format.code;
+ mf->colorspace = V4L2_COLORSPACE_JPEG;
+ } else {
+ f = &ctx->d_frame;
+ gsc_set_frame_size(f, fmt->format.width, fmt->format.height);
+ f->fmt = find_format(NULL, &fmt->format.code, 0);
+ ctx->state |= GSC_DST_FMT;
+ }
+
+ return 0;
+}
+
+static int gsc_subdev_get_crop(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_crop *crop)
+{
+ struct gsc_dev *gsc = entity_data_to_gsc(v4l2_get_subdevdata(sd));
+ struct gsc_ctx *ctx = gsc->out.ctx;
+ struct v4l2_rect *r = &crop->rect;
+ struct gsc_frame *f;
+
+ if (crop->pad == GSC_PAD_SINK) {
+ gsc_err("Sink pad get_crop is not supported");
+ return 0;
+ }
+
+ if (crop->which == V4L2_SUBDEV_FORMAT_TRY) {
+ crop->rect = *v4l2_subdev_get_try_crop(fh, crop->pad);
+ return 0;
+ }
+
+ f = &ctx->d_frame;
+ r->left = f->crop.left;
+ r->top = f->crop.top;
+ r->width = f->crop.width;
+ r->height = f->crop.height;
+
+ gsc_dbg("f:%p, pad%d: l:%d, t:%d, %dx%d, f_w: %d, f_h: %d",
+ f, crop->pad, r->left, r->top, r->width, r->height,
+ f->f_width, f->f_height);
+
+ return 0;
+}
+
+static int gsc_subdev_set_crop(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_crop *crop)
+{
+ struct gsc_dev *gsc = entity_data_to_gsc(v4l2_get_subdevdata(sd));
+ struct gsc_ctx *ctx = gsc->out.ctx;
+ struct v4l2_rect *r;
+ struct gsc_frame *f;
+
+ gsc_dbg("(%d,%d)/%dx%d", crop->rect.left, crop->rect.top, crop->rect.width, crop->rect.height);
+
+ if (crop->pad == GSC_PAD_SINK) {
+ gsc_err("Sink pad set_fmt is not supported\n");
+ return 0;
+ }
+
+ if (crop->which == V4L2_SUBDEV_FORMAT_TRY) {
+ r = v4l2_subdev_get_try_crop(fh, crop->pad);
+ r->left = crop->rect.left;
+ r->top = crop->rect.top;
+ r->width = crop->rect.width;
+ r->height = crop->rect.height;
+ } else {
+ f = &ctx->d_frame;
+ f->crop.left = crop->rect.left;
+ f->crop.top = crop->rect.top;
+ f->crop.width = crop->rect.width;
+ f->crop.height = crop->rect.height;
+ if (f->crop.width % 2)
+ f->crop.width -= 1;
+ }
+
+ gsc_dbg("pad%d: (%d,%d)/%dx%d", crop->pad, crop->rect.left, crop->rect.top,
+ crop->rect.width, crop->rect.height);
+
+ return 0;
+}
+
+static int gsc_subdev_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct gsc_dev *gsc = entity_data_to_gsc(v4l2_get_subdevdata(sd));
+ int ret;
+
+ if (enable) {
+ ret = gsc_out_hw_set(gsc->out.ctx);
+ if (ret) {
+ gsc_err("GSC H/W setting is failed");
+ return -EINVAL;
+ }
+ } else {
+ INIT_LIST_HEAD(&gsc->out.active_buf_q);
+ clear_bit(ST_OUTPUT_STREAMON, &gsc->state);
+ bts_change_bus_traffic(&gsc->pdev->dev, BTS_DECREASE_BW);
+ pm_runtime_put_sync(&gsc->pdev->dev);
+ if (gsc->int_poll_hd) {
+ exynos5_bus_int_put(gsc->int_poll_hd);
+ gsc->int_poll_hd = NULL;
+ }
+ }
+
+ return 0;
+}
+
+static struct v4l2_subdev_pad_ops gsc_subdev_pad_ops = {
+ .get_fmt = gsc_subdev_get_fmt,
+ .set_fmt = gsc_subdev_set_fmt,
+ .get_crop = gsc_subdev_get_crop,
+ .set_crop = gsc_subdev_set_crop,
+};
+
+static struct v4l2_subdev_video_ops gsc_subdev_video_ops = {
+ .s_stream = gsc_subdev_s_stream,
+};
+
+static struct v4l2_subdev_ops gsc_subdev_ops = {
+ .pad = &gsc_subdev_pad_ops,
+ .video = &gsc_subdev_video_ops,
+};
+
+static int gsc_out_power_off(struct v4l2_subdev *sd)
+{
+ struct gsc_dev *gsc = entity_data_to_gsc(v4l2_get_subdevdata(sd));
+ int ret;
+
+ ret = gsc_out_hw_reset_off(gsc);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static struct exynos_media_ops gsc_out_link_callback = {
+ .power_off = gsc_out_power_off,
+};
+
+/*
+ * The video node ioctl operations
+ */
+static int gsc_output_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct gsc_dev *gsc = video_drvdata(file);
+
+ strncpy(cap->driver, gsc->pdev->name, sizeof(cap->driver) - 1);
+ strncpy(cap->card, gsc->pdev->name, sizeof(cap->card) - 1);
+ cap->bus_info[0] = 0;
+ cap->capabilities = V4L2_CAP_STREAMING |
+ V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VIDEO_OUTPUT_MPLANE;
+
+ return 0;
+}
+
+static int gsc_output_enum_fmt_mplane(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ return gsc_enum_fmt_mplane(f);
+}
+
+static int gsc_output_try_fmt_mplane(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct gsc_dev *gsc = video_drvdata(file);
+
+ if (!is_output(f->type)) {
+ gsc_err("Not supported buffer type");
+ return -EINVAL;
+ }
+
+ return gsc_try_fmt_mplane(gsc->out.ctx, f);
+}
+
+static int gsc_output_s_fmt_mplane(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct gsc_dev *gsc = video_drvdata(file);
+ struct gsc_ctx *ctx = gsc->out.ctx;
+ struct gsc_frame *frame;
+ struct v4l2_pix_format_mplane *pix;
+ int i, ret = 0;
+
+ ret = gsc_output_try_fmt_mplane(file, fh, f);
+ if (ret) {
+ gsc_err("Invalid argument");
+ return ret;
+ }
+
+ if (vb2_is_streaming(&gsc->out.vbq)) {
+ gsc_err("queue (%d) busy", f->type);
+ return -EBUSY;
+ }
+
+ frame = &ctx->s_frame;
+
+ pix = &f->fmt.pix_mp;
+ frame->fmt = find_format(&pix->pixelformat, NULL, 0);
+ if (!frame->fmt) {
+ gsc_err("Not supported pixel format");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < frame->fmt->num_planes; i++)
+ frame->payload[i] = pix->plane_fmt[i].sizeimage;
+
+ gsc_set_frame_size(frame, pix->width, pix->height);
+
+ ctx->state |= GSC_SRC_FMT;
+
+ gsc_dbg("f_w: %d, f_h: %d", frame->f_width, frame->f_height);
+
+ return 0;
+}
+
+static int gsc_output_g_fmt_mplane(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct gsc_dev *gsc = video_drvdata(file);
+ struct gsc_ctx *ctx = gsc->out.ctx;
+
+ if (!is_output(f->type)) {
+ gsc_err("Not supported buffer type");
+ return -EINVAL;
+ }
+
+ return gsc_g_fmt_mplane(ctx, f);
+}
+
+static int gsc_output_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *reqbufs)
+{
+ struct gsc_dev *gsc = video_drvdata(file);
+ struct gsc_output_device *out = &gsc->out;
+ struct gsc_frame *frame;
+ int ret;
+
+ if (reqbufs->count > gsc->variant->in_buf_cnt) {
+ gsc_err("Requested count exceeds maximun count of input buffer");
+ return -EINVAL;
+ } else if (reqbufs->count == 0)
+ gsc_ctx_state_lock_clear(GSC_SRC_FMT | GSC_DST_FMT,
+ out->ctx);
+
+ gsc_set_protected_content(gsc, out->ctx->gsc_ctrls.drm_en->cur.val);
+
+ frame = ctx_get_frame(out->ctx, reqbufs->type);
+ frame->cacheable = out->ctx->gsc_ctrls.cacheable->val;
+ gsc->vb2->set_cacheable(gsc->alloc_ctx, frame->cacheable);
+ ret = vb2_reqbufs(&out->vbq, reqbufs);
+ if (ret)
+ return ret;
+ out->req_cnt = reqbufs->count;
+
+ return ret;
+}
+
+static int gsc_output_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct gsc_dev *gsc = video_drvdata(file);
+ struct gsc_output_device *out = &gsc->out;
+
+ return vb2_querybuf(&out->vbq, buf);
+}
+
+static int gsc_output_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct gsc_dev *gsc = video_drvdata(file);
+ struct gsc_output_device *out = &gsc->out;
+ struct media_pad *sink_pad;
+ int ret;
+
+ sink_pad = media_entity_remote_source(&out->sd_pads[GSC_PAD_SOURCE]);
+ if (IS_ERR(sink_pad)) {
+ gsc_err("No sink pad conncted with a gscaler source pad");
+ return PTR_ERR(sink_pad);
+ }
+
+ ret = gsc_out_link_validate(&out->sd_pads[GSC_PAD_SOURCE], sink_pad);
+ if (ret) {
+ gsc_err("Output link validation is failed");
+ return ret;
+ }
+
+ media_entity_pipeline_start(&out->vfd->entity, gsc->pipeline.pipe);
+
+ return vb2_streamon(&gsc->out.vbq, type);
+}
+
+static int gsc_output_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct gsc_dev *gsc = video_drvdata(file);
+
+ return vb2_streamoff(&gsc->out.vbq, type);
+}
+
+static int gsc_output_qbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct gsc_dev *gsc = video_drvdata(file);
+ struct gsc_output_device *out = &gsc->out;
+
+ return vb2_qbuf(&out->vbq, buf);
+}
+
+static int gsc_output_dqbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct gsc_dev *gsc = video_drvdata(file);
+
+ return vb2_dqbuf(&gsc->out.vbq, buf,
+ file->f_flags & O_NONBLOCK);
+}
+
+static int gsc_output_cropcap(struct file *file, void *fh,
+ struct v4l2_cropcap *cr)
+{
+ struct gsc_dev *gsc = video_drvdata(file);
+ struct gsc_ctx *ctx = gsc->out.ctx;
+
+ if (!is_output(cr->type)) {
+ gsc_err("Not supported buffer type");
+ return -EINVAL;
+ }
+
+ cr->bounds.left = 0;
+ cr->bounds.top = 0;
+ cr->bounds.width = ctx->s_frame.f_width;
+ cr->bounds.height = ctx->s_frame.f_height;
+ cr->defrect = cr->bounds;
+
+ return 0;
+
+}
+
+static int gsc_output_g_crop(struct file *file, void *fh,
+ struct v4l2_crop *cr)
+{
+ struct gsc_dev *gsc = video_drvdata(file);
+
+ if (!is_output(cr->type)) {
+ gsc_err("Not supported buffer type");
+ return -EINVAL;
+ }
+
+ return gsc_g_crop(gsc->out.ctx, cr);
+}
+
+static int gsc_output_s_crop(struct file *file, void *fh, struct v4l2_crop *cr)
+{
+ struct gsc_dev *gsc = video_drvdata(file);
+ struct gsc_ctx *ctx = gsc->out.ctx;
+ struct gsc_variant *variant = gsc->variant;
+ struct gsc_frame *f;
+ unsigned int mask = GSC_DST_FMT | GSC_SRC_FMT;
+ int ret;
+
+ if (!is_output(cr->type)) {
+ gsc_err("Not supported buffer type");
+ return -EINVAL;
+ }
+
+ ret = gsc_try_crop(ctx, cr);
+ if (ret)
+ return ret;
+
+ f = &ctx->s_frame;
+
+ /* Check to see if scaling ratio is within supported range */
+ if ((ctx->state & (GSC_DST_FMT | GSC_SRC_FMT)) == mask) {
+ ret = gsc_check_scaler_ratio(variant, f->crop.width,
+ f->crop.height, ctx->d_frame.crop.width,
+ ctx->d_frame.crop.height,
+ ctx->gsc_ctrls.rotate->val, ctx->out_path);
+ if (ret) {
+ gsc_err("Out of scaler range");
+ return -EINVAL;
+ }
+ gsc_subdev_try_crop(gsc, &ctx->d_frame.crop);
+ }
+
+ f->crop.left = cr->c.left;
+ f->crop.top = cr->c.top;
+ f->crop.width = cr->c.width;
+ f->crop.height = cr->c.height;
+
+ return 0;
+}
+
+static const struct v4l2_ioctl_ops gsc_output_ioctl_ops = {
+ .vidioc_querycap = gsc_output_querycap,
+ .vidioc_enum_fmt_vid_out_mplane = gsc_output_enum_fmt_mplane,
+
+ .vidioc_try_fmt_vid_out_mplane = gsc_output_try_fmt_mplane,
+ .vidioc_s_fmt_vid_out_mplane = gsc_output_s_fmt_mplane,
+ .vidioc_g_fmt_vid_out_mplane = gsc_output_g_fmt_mplane,
+
+ .vidioc_reqbufs = gsc_output_reqbufs,
+ .vidioc_querybuf = gsc_output_querybuf,
+
+ .vidioc_qbuf = gsc_output_qbuf,
+ .vidioc_dqbuf = gsc_output_dqbuf,
+
+ .vidioc_streamon = gsc_output_streamon,
+ .vidioc_streamoff = gsc_output_streamoff,
+
+ .vidioc_g_crop = gsc_output_g_crop,
+ .vidioc_s_crop = gsc_output_s_crop,
+ .vidioc_cropcap = gsc_output_cropcap,
+};
+
+static int gsc_out_video_s_stream(struct gsc_dev *gsc, int enable)
+{
+ struct gsc_output_device *out = &gsc->out;
+ struct media_pad *sink_pad;
+ struct v4l2_subdev *sd;
+ int ret = 0;
+
+ sink_pad = media_entity_remote_source(&out->vd_pad);
+ if (IS_ERR(sink_pad)) {
+ gsc_err("No sink pad conncted with a gscaler video source pad");
+ return PTR_ERR(sink_pad);
+ }
+ sd = media_entity_to_v4l2_subdev(sink_pad->entity);
+ ret = v4l2_subdev_call(sd, video, s_stream, enable);
+ if (ret)
+ gsc_err("G-Scaler subdev s_stream[%d] failed", enable);
+
+ return ret;
+}
+
+static int gsc_out_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+ struct gsc_ctx *ctx = q->drv_priv;
+ struct gsc_dev *gsc = ctx->gsc_dev;
+
+ return gsc_out_video_s_stream(gsc, 1);
+}
+
+static int gsc_out_stop_streaming(struct vb2_queue *q)
+{
+ struct gsc_ctx *ctx = q->drv_priv;
+ struct gsc_dev *gsc = ctx->gsc_dev;
+ int ret = 0;
+
+ ret = gsc_pipeline_s_stream(gsc, false);
+ if (ret)
+ return ret;
+
+ if (ctx->out_path == GSC_FIMD) {
+ gsc_hw_enable_control(gsc, false);
+ ret = gsc_wait_stop(gsc);
+ if (ret < 0)
+ return ret;
+ }
+ gsc_hw_set_input_buf_mask_all(gsc);
+
+ /* TODO: Add gscaler clock off function */
+ ret = gsc_out_video_s_stream(gsc, 0);
+ if (ret) {
+ gsc_err("G-Scaler video s_stream off failed");
+ return ret;
+ }
+ media_entity_pipeline_stop(&gsc->out.vfd->entity);
+
+ return ret;
+}
+
+static int gsc_out_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
+ unsigned int *num_buffers, unsigned int *num_planes,
+ unsigned int sizes[], void *allocators[])
+{
+ struct gsc_ctx *ctx = vq->drv_priv;
+ struct gsc_fmt *ffmt = ctx->s_frame.fmt;
+ int i;
+
+ if (IS_ERR(ffmt)) {
+ gsc_err("Invalid source format");
+ return PTR_ERR(ffmt);
+ }
+
+ *num_planes = ffmt->num_planes;
+
+ for (i = 0; i < ffmt->num_planes; i++) {
+ sizes[i] = get_plane_size(&ctx->s_frame, i);
+ allocators[i] = ctx->gsc_dev->alloc_ctx;
+ }
+ vb2_queue_init(vq);
+
+ return 0;
+}
+
+static int gsc_out_buffer_prepare(struct vb2_buffer *vb)
+{
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct gsc_ctx *ctx = vq->drv_priv;
+ struct gsc_dev *gsc = ctx->gsc_dev;
+ struct gsc_frame *frame = &ctx->s_frame;
+
+ if (!ctx->s_frame.fmt || !is_output(vq->type)) {
+ gsc_err("Invalid argument");
+ return -EINVAL;
+ }
+
+ if (ctx->s_frame.cacheable)
+ gsc->vb2->cache_flush(vb, frame->fmt->num_planes);
+
+ return 0;
+}
+
+int gsc_out_set_in_addr(struct gsc_dev *gsc, struct gsc_ctx *ctx,
+ struct gsc_input_buf *buf, int index)
+{
+ int ret;
+
+ ret = gsc_prepare_addr(ctx, &buf->vb, &ctx->s_frame, &ctx->s_frame.addr);
+ if (ret) {
+ gsc_err("Fail to prepare G-Scaler address");
+ return -EINVAL;
+ }
+ gsc_hw_set_input_addr(gsc, &ctx->s_frame.addr, index);
+ active_queue_push(&gsc->out, buf, gsc);
+ buf->idx = index;
+
+ return 0;
+}
+
+static void gsc_out_buffer_queue(struct vb2_buffer *vb)
+{
+ struct gsc_input_buf *buf
+ = container_of(vb, struct gsc_input_buf, vb);
+ struct vb2_queue *q = vb->vb2_queue;
+ struct gsc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+ struct gsc_dev *gsc = ctx->gsc_dev;
+ unsigned long flags;
+ int ret;
+
+ if (vb->acquire_fence) {
+ ret = sync_fence_wait(vb->acquire_fence, 100);
+ sync_fence_put(vb->acquire_fence);
+ vb->acquire_fence = NULL;
+ if (ret < 0) {
+ gsc_err("synce_fence_wait() timeout");
+ return;
+ }
+ }
+
+ if (!test_and_set_bit(ST_OUTPUT_STREAMON, &gsc->state)) {
+ if (!gsc->int_poll_hd) {
+ gsc->int_poll_hd = exynos5_bus_int_poll();
+ if (!gsc->int_poll_hd)
+ gsc_err("failed to request busfreq poll");
+ }
+ ret = pm_runtime_get_sync(&gsc->pdev->dev);
+ if (ret < 0) {
+ gsc_err("fail to pm_runtime_get_sync()");
+ return;
+ }
+ gsc_hw_set_sw_reset(gsc);
+ ret = gsc_wait_reset(gsc);
+ if (ret < 0) {
+ gsc_err("gscaler s/w reset timeout");
+ return;
+ }
+ bts_change_bus_traffic(&gsc->pdev->dev, BTS_INCREASE_BW);
+ }
+
+ if (gsc->out.req_cnt >= atomic_read(&q->queued_count)) {
+ ret = gsc_out_set_in_addr(gsc, ctx, buf, vb->v4l2_buf.index);
+ if (ret) {
+ gsc_err("Failed to prepare G-Scaler address");
+ return;
+ }
+ spin_lock_irqsave(&gsc->slock, flags);
+ gsc_hw_set_input_buf_masking(gsc, vb->v4l2_buf.index, false);
+ gsc_hw_set_in_pingpong_update(gsc);
+ spin_unlock_irqrestore(&gsc->slock, flags);
+ } else {
+ gsc_err("All requested buffers have been queued already");
+ return;
+ }
+}
+
+static struct vb2_ops gsc_output_qops = {
+ .queue_setup = gsc_out_queue_setup,
+ .buf_prepare = gsc_out_buffer_prepare,
+ .buf_queue = gsc_out_buffer_queue,
+ .wait_prepare = gsc_unlock,
+ .wait_finish = gsc_lock,
+ .start_streaming = gsc_out_start_streaming,
+ .stop_streaming = gsc_out_stop_streaming,
+};
+
+static int gsc_out_link_setup(struct media_entity *entity,
+ const struct media_pad *local,
+ const struct media_pad *remote, u32 flags)
+{
+ if (media_entity_type(entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+ return 0;
+
+ if (local->flags == MEDIA_PAD_FL_SOURCE) {
+ struct gsc_dev *gsc = entity_to_gsc(entity);
+ struct v4l2_subdev *sd;
+ if (flags & MEDIA_LNK_FL_ENABLED) {
+ if (gsc->pipeline.disp == NULL) {
+ /* Gscaler 0 --> Winwow 0, Gscaler 1 --> Window 1,
+ Gscaler 2 --> Window 2, Gscaler 3 --> Window 2 */
+ char name[FIMD_NAME_SIZE];
+ sprintf(name, "%s%d", FIMD_ENTITY_NAME, get_win_num(gsc));
+ sd = media_entity_to_v4l2_subdev(remote->entity);
+ gsc->pipeline.disp = sd;
+ if (!strcmp(sd->name, name)) {
+ gsc->out.ctx->out_path = GSC_FIMD;
+ gsc_hw_set_local_dst(gsc->id,
+ GSC_FIMD, true);
+ } else {
+ gsc->out.ctx->out_path = GSC_MIXER;
+ gsc_hw_set_local_dst(gsc->id,
+ GSC_MIXER, true);
+ }
+ } else
+ gsc_err("G-Scaler source pad was linked already");
+ } else if (!(flags & ~MEDIA_LNK_FL_ENABLED)) {
+ if (gsc->pipeline.disp != NULL) {
+ if (gsc->out.ctx->out_path == GSC_FIMD) {
+ gsc_hw_set_local_dst(gsc->id,
+ GSC_FIMD, false);
+ } else {
+ gsc_hw_set_local_dst(gsc->id,
+ GSC_MIXER, false);
+ }
+ gsc->pipeline.disp = NULL;
+ gsc->out.ctx->out_path = 0;
+ } else
+ gsc_err("G-Scaler source pad was unlinked already");
+ }
+ }
+
+ return 0;
+}
+
+static const struct media_entity_operations gsc_out_media_ops = {
+ .link_setup = gsc_out_link_setup,
+};
+
+int gsc_output_ctrls_create(struct gsc_dev *gsc)
+{
+ int ret;
+
+ ret = gsc_ctrls_create(gsc->out.ctx);
+ if (ret) {
+ gsc_err("Failed to create controls of G-Scaler");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int gsc_output_open(struct file *file)
+{
+ struct gsc_dev *gsc = video_drvdata(file);
+ int ret = v4l2_fh_open(file);
+
+ if (ret)
+ return ret;
+
+ gsc_dbg("pid: %d, state: 0x%lx", task_pid_nr(current), gsc->state);
+
+ /* Return if the corresponding mem2mem/output/capture video node
+ is already opened. */
+ if (gsc_m2m_opened(gsc) || gsc_cap_opened(gsc) || gsc_out_opened(gsc)) {
+ gsc_err("G-Scaler%d has been opened already", gsc->id);
+ return -EBUSY;
+ }
+
+ if (WARN_ON(gsc->out.ctx == NULL)) {
+ gsc_err("G-Scaler output context is NULL");
+ return -ENXIO;
+ }
+
+ set_bit(ST_OUTPUT_OPEN, &gsc->state);
+
+ ret = gsc_ctrls_create(gsc->out.ctx);
+ if (ret < 0) {
+ v4l2_fh_release(file);
+ clear_bit(ST_OUTPUT_OPEN, &gsc->state);
+ return ret;
+ }
+
+ return ret;
+}
+
+static int gsc_output_close(struct file *file)
+{
+ struct gsc_dev *gsc = video_drvdata(file);
+
+ gsc_dbg("pid: %d, state: 0x%lx", task_pid_nr(current), gsc->state);
+
+ /* if we didn't properly sequence with the secure side to turn off
+ * content protection, we may be left in a very bad state and the
+ * only way to recover this reliably is to reboot.
+ */
+ BUG_ON(gsc->protected_content);
+
+ clear_bit(ST_OUTPUT_OPEN, &gsc->state);
+ vb2_queue_release(&gsc->out.vbq);
+ gsc_ctrls_delete(gsc->out.ctx);
+ v4l2_fh_release(file);
+
+ return 0;
+}
+
+static unsigned int gsc_output_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct gsc_dev *gsc = video_drvdata(file);
+
+ return vb2_poll(&gsc->out.vbq, file, wait);
+}
+
+static int gsc_output_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct gsc_dev *gsc = video_drvdata(file);
+
+ return vb2_mmap(&gsc->out.vbq, vma);
+}
+
+static const struct v4l2_file_operations gsc_output_fops = {
+ .owner = THIS_MODULE,
+ .open = gsc_output_open,
+ .release = gsc_output_close,
+ .poll = gsc_output_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = gsc_output_mmap,
+};
+
+static int gsc_create_link(struct gsc_dev *gsc)
+{
+ struct media_entity *source, *sink;
+ int ret;
+
+ source = &gsc->out.vfd->entity;
+ sink = &gsc->out.sd->entity;
+ ret = media_entity_create_link(source, 0, sink, GSC_PAD_SINK,
+ MEDIA_LNK_FL_IMMUTABLE |
+ MEDIA_LNK_FL_ENABLED);
+ if (ret) {
+ gsc_err("Failed to create link between G-Scaler vfd and subdev");
+ return ret;
+ }
+
+ return 0;
+}
+
+
+static int gsc_create_subdev(struct gsc_dev *gsc)
+{
+ struct v4l2_subdev *sd;
+ int ret;
+
+ sd = kzalloc(sizeof(*sd), GFP_KERNEL);
+ if (!sd)
+ return -ENOMEM;
+
+ v4l2_subdev_init(sd, &gsc_subdev_ops);
+ sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
+ snprintf(sd->name, sizeof(sd->name), "%s.%d", GSC_SUBDEV_NAME, gsc->id);
+
+ gsc->out.sd_pads[GSC_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+ gsc->out.sd_pads[GSC_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+ ret = media_entity_init(&sd->entity, GSC_PADS_NUM,
+ gsc->out.sd_pads, 0);
+ if (ret) {
+ gsc_err("Failed to initialize the G-Scaler media entity");
+ goto error;
+ }
+
+ sd->entity.ops = &gsc_out_media_ops;
+ ret = v4l2_device_register_subdev(&gsc->mdev[MDEV_OUTPUT]->v4l2_dev, sd);
+ if (ret) {
+ media_entity_cleanup(&sd->entity);
+ goto error;
+ }
+ gsc->mdev[MDEV_OUTPUT]->gsc_sd[gsc->id] = sd;
+ gsc_dbg("gsc_sd[%d] = 0x%08x\n", gsc->id,
+ (u32)gsc->mdev[MDEV_OUTPUT]->gsc_sd[gsc->id]);
+ gsc->out.sd = sd;
+ gsc->md_data.media_ops = &gsc_out_link_callback;
+ v4l2_set_subdevdata(sd, &gsc->md_data);
+
+ return 0;
+error:
+ kfree(sd);
+ return ret;
+}
+
+int gsc_register_output_device(struct gsc_dev *gsc)
+{
+ struct video_device *vfd;
+ struct gsc_output_device *gsc_out;
+ struct gsc_ctx *ctx;
+ struct vb2_queue *q;
+ int ret = -ENOMEM;
+
+ ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ ctx->gsc_dev = gsc;
+ ctx->s_frame.fmt = get_format(GSC_OUT_DEF_SRC);
+ ctx->d_frame.fmt = get_format(GSC_OUT_DEF_DST);
+ ctx->in_path = GSC_DMA;
+ ctx->state = GSC_CTX_OUTPUT;
+
+ vfd = video_device_alloc();
+ if (!vfd) {
+ gsc_err("Failed to allocate video device");
+ goto err_ctx_alloc;
+ }
+
+ snprintf(vfd->name, sizeof(vfd->name), "%s.output",
+ dev_name(&gsc->pdev->dev));
+
+
+ vfd->fops = &gsc_output_fops;
+ vfd->ioctl_ops = &gsc_output_ioctl_ops;
+ vfd->v4l2_dev = &gsc->mdev[MDEV_OUTPUT]->v4l2_dev;
+ vfd->release = video_device_release;
+ vfd->lock = &gsc->lock;
+ video_set_drvdata(vfd, gsc);
+
+ gsc_out = &gsc->out;
+ gsc_out->vfd = vfd;
+
+ INIT_LIST_HEAD(&gsc_out->active_buf_q);
+ spin_lock_init(&ctx->slock);
+ gsc_out->ctx = ctx;
+
+ q = &gsc->out.vbq;
+ memset(q, 0, sizeof(*q));
+ q->name = vfd->name;
+ q->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ q->io_modes = VB2_MMAP | VB2_DMABUF;
+ q->drv_priv = gsc->out.ctx;
+ q->ops = &gsc_output_qops;
+ q->mem_ops = gsc->vb2->ops;
+ q->buf_struct_size = sizeof(struct gsc_input_buf);
+
+ vb2_queue_init(q);
+
+ ret = video_register_device(vfd, VFL_TYPE_GRABBER,
+ EXYNOS_VIDEONODE_GSC_OUT(gsc->id));
+ if (ret) {
+ gsc_err("Failed to register video device");
+ goto err_ent;
+ }
+
+ gsc->out.vd_pad.flags = MEDIA_PAD_FL_SOURCE;
+ ret = media_entity_init(&vfd->entity, 1, &gsc->out.vd_pad, 0);
+ if (ret)
+ goto err_ent;
+
+ ret = gsc_create_subdev(gsc);
+ if (ret)
+ goto err_sd_reg;
+
+ ret = gsc_create_link(gsc);
+ if (ret)
+ goto err_sd_reg;
+
+ vfd->ctrl_handler = &ctx->ctrl_handler;
+ gsc_dbg("gsc output driver registered as /dev/video%d, ctx(0x%08x)",
+ vfd->num, (u32)ctx);
+ return 0;
+
+err_sd_reg:
+ media_entity_cleanup(&vfd->entity);
+err_ent:
+ video_device_release(vfd);
+err_ctx_alloc:
+ kfree(ctx);
+ return ret;
+}
+
+static void gsc_destroy_subdev(struct gsc_dev *gsc)
+{
+ struct v4l2_subdev *sd = gsc->out.sd;
+
+ if (!sd)
+ return;
+ media_entity_cleanup(&sd->entity);
+ v4l2_device_unregister_subdev(sd);
+ kfree(sd);
+ sd = NULL;
+}
+
+void gsc_unregister_output_device(struct gsc_dev *gsc)
+{
+ struct video_device *vfd = gsc->out.vfd;
+
+ if (vfd) {
+ media_entity_cleanup(&vfd->entity);
+ /* Can also be called if video device was
+ not registered */
+ video_unregister_device(vfd);
+ }
+ gsc_destroy_subdev(gsc);
+ kfree(gsc->out.ctx);
+ gsc->out.ctx = NULL;
+}
diff --git a/drivers/media/video/exynos/gsc/gsc-regs.c b/drivers/media/video/exynos/gsc/gsc-regs.c
new file mode 100644
index 0000000..30cfb91
--- /dev/null
+++ b/drivers/media/video/exynos/gsc/gsc-regs.c
@@ -0,0 +1,832 @@
+/* linux/drivers/media/video/exynos/gsc/gsc-regs.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Samsung EXYNOS5 SoC series G-scaler driver
+ *
+ * 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.
+ */
+
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <mach/map.h>
+#include "gsc-core.h"
+
+void gsc_hw_set_sw_reset(struct gsc_dev *dev)
+{
+ u32 cfg = 0;
+
+ cfg |= GSC_SW_RESET_SRESET;
+ writel(cfg, dev->regs + GSC_SW_RESET);
+}
+
+void gsc_disp_fifo_sw_reset(struct gsc_dev *dev)
+{
+ u32 cfg = readl(SYSREG_DISP1BLK_CFG);
+ /* DISPBLK1 FIFO S/W reset sequence
+ set FIFORST_DISP1 as 0 then, set FIFORST_DISP1 as 1 again */
+ cfg &= ~FIFORST_DISP1;
+ writel(cfg, SYSREG_DISP1BLK_CFG);
+ cfg |= FIFORST_DISP1;
+ writel(cfg, SYSREG_DISP1BLK_CFG);
+}
+
+void gsc_pixelasync_sw_reset(struct gsc_dev *dev)
+{
+ u32 cfg = readl(SYSREG_GSCBLK_CFG0);
+ /* GSCBLK Pixel asyncy FIFO S/W reset sequence
+ set PXLASYNC_SW_RESET as 0 then, set PXLASYNC_SW_RESET as 1 again */
+ cfg &= ~GSC_PXLASYNC_RST(dev->id);
+ writel(cfg, SYSREG_GSCBLK_CFG0);
+ cfg |= GSC_PXLASYNC_RST(dev->id);
+ writel(cfg, SYSREG_GSCBLK_CFG0);
+}
+
+int gsc_wait_reset(struct gsc_dev *dev)
+{
+ u32 cfg;
+ u32 cnt = 10 * USEC_PER_MSEC;
+
+ do {
+ cfg = readl(dev->regs + GSC_SW_RESET);
+ if (!cfg)
+ return 0;
+ udelay(1);
+ } while (--cnt);
+
+ return -EINVAL;
+}
+
+int gsc_wait_operating(struct gsc_dev *dev)
+{
+ u32 cfg;
+ u32 cnt = 10 * USEC_PER_MSEC;
+
+ do {
+ cfg = readl(dev->regs + GSC_ENABLE);
+ if (cfg & GSC_ENABLE_OP_STATUS)
+ return 0;
+ udelay(1);
+ } while (--cnt);
+
+ return -EBUSY;
+}
+
+int gsc_wait_stop(struct gsc_dev *dev)
+{
+ unsigned long timeo = jiffies + 10; /* timeout of 50ms */
+ u32 cfg;
+
+ while (time_before(jiffies, timeo)) {
+ cfg = readl(dev->regs + GSC_ENABLE);
+ if (!(cfg & GSC_ENABLE_OP_STATUS))
+ return 0;
+ usleep_range(10, 20);
+ }
+ gsc_dbg("wait time : %d ms", jiffies_to_msecs(jiffies - timeo + 20));
+
+ return -EBUSY;
+}
+
+void gsc_hw_set_in_chrom_stride(struct gsc_ctx *ctx)
+{
+ struct gsc_dev *dev = ctx->gsc_dev;
+ struct gsc_frame *frame = &ctx->s_frame;
+ u32 chrom_size, cfg;
+
+ cfg = readl(dev->regs + GSC_IN_CON);
+ cfg |= GSC_IN_CHROM_STRIDE_SEPAR;
+ writel(cfg, dev->regs + GSC_IN_CON);
+
+ cfg &= ~GSC_IN_CHROM_STRIDE_MASK;
+ chrom_size = ALIGN(frame->f_width / 2, 16) * 2;
+ cfg = GSC_IN_CHROM_STRIDE_VALUE(chrom_size);
+ writel(cfg, dev->regs + GSC_IN_CHROM_STRIDE);
+}
+
+void gsc_hw_set_out_chrom_stride(struct gsc_ctx *ctx)
+{
+ struct gsc_dev *dev = ctx->gsc_dev;
+ struct gsc_frame *frame = &ctx->d_frame;
+ u32 chrom_size, cfg;
+
+ cfg = readl(dev->regs + GSC_OUT_CON);
+ cfg |= GSC_OUT_CHROM_STRIDE_SEPAR;
+ writel(cfg, dev->regs + GSC_OUT_CON);
+
+ cfg &= ~GSC_OUT_CHROM_STRIDE_MASK;
+ chrom_size = ALIGN(frame->f_width / 2, 16) * 2;
+ cfg = GSC_OUT_CHROM_STRIDE_VALUE(chrom_size);
+ writel(cfg, dev->regs + GSC_OUT_CHROM_STRIDE);
+}
+
+void gsc_hw_set_in_pingpong_update(struct gsc_dev *dev)
+{
+ u32 cfg = readl(dev->regs + GSC_ENABLE);
+ cfg |= GSC_ENABLE_IN_PP_UPDATE;
+ writel(cfg, dev->regs + GSC_ENABLE);
+}
+
+void gsc_hw_set_one_frm_mode(struct gsc_dev *dev, bool mask)
+{
+ u32 cfg;
+
+ cfg = readl(dev->regs + GSC_ENABLE);
+ cfg &= ~(GSC_ENABLE_ON_CLEAR_MASK);
+ if (mask)
+ cfg |= GSC_ENABLE_ON_CLEAR_ONESHOT;
+ writel(cfg, dev->regs + GSC_ENABLE);
+}
+
+void gsc_hw_set_fire_bit_sync_mode(struct gsc_dev *dev, bool mask)
+{
+ u32 cfg;
+
+ cfg = readl(dev->regs + GSC_ENABLE);
+ cfg &= ~(GSC_ENABLE_PP_UPDATE_MODE_MASK);
+ if (mask)
+ cfg |= GSC_ENABLE_PP_UPDATE_FIRE_MODE;
+ writel(cfg, dev->regs + GSC_ENABLE);
+}
+
+int gsc_hw_get_mxr_path_status(void)
+{
+ int i, cnt = 0;
+
+ u32 cfg = readl(SYSREG_GSCBLK_CFG0);
+ for (i = 0; i < GSC_MAX_DEVS; i++) {
+ if (cfg & GSC_OUT_DST_MXR_SEL(i))
+ cnt++;
+ }
+ return (cnt > 2) ? 1 : 0;
+}
+
+int gsc_hw_get_input_buf_mask_status(struct gsc_dev *dev)
+{
+ u32 cfg, status, bits = 0;
+
+ cfg = readl(dev->regs + GSC_IN_BASE_ADDR_Y_MASK);
+ status = cfg & GSC_IN_BASE_ADDR_MASK;
+ while (status) {
+ status = status & (status - 1);
+ bits++;
+ }
+ return bits;
+}
+
+int gsc_hw_get_done_input_buf_index(struct gsc_dev *dev)
+{
+ u32 cfg, curr_index, i;
+
+ cfg = readl(dev->regs + GSC_IN_BASE_ADDR_Y_MASK);
+ curr_index = GSC_IN_CURR_GET_INDEX(cfg);
+ for (i = curr_index; i > 1; i--) {
+ if (cfg ^ (1 << (i - 2)))
+ return i - 2;
+ }
+
+ for (i = dev->variant->in_buf_cnt; i > curr_index; i--) {
+ if (cfg ^ (1 << (i - 1)))
+ return i - 1;
+ }
+
+ return curr_index - 1;
+}
+
+int gsc_hw_get_done_output_buf_index(struct gsc_dev *dev)
+{
+ u32 cfg, curr_index, done_buf_index;
+ unsigned long state_mask;
+ u32 reqbufs_cnt = dev->cap.reqbufs_cnt;
+
+ cfg = readl(dev->regs + GSC_OUT_BASE_ADDR_Y_MASK);
+ curr_index = GSC_OUT_CURR_GET_INDEX(cfg);
+ gsc_dbg("curr_index : %d", curr_index);
+ state_mask = cfg & GSC_OUT_BASE_ADDR_MASK;
+
+ done_buf_index = (curr_index == 0) ? reqbufs_cnt - 1 : curr_index - 1;
+
+ do {
+ /* Test done_buf_index whether masking or not */
+ if (test_bit(done_buf_index, &state_mask))
+ done_buf_index = (done_buf_index == 0) ?
+ reqbufs_cnt - 1 : done_buf_index - 1;
+ else
+ return done_buf_index;
+ } while (done_buf_index != curr_index);
+
+ return -EBUSY;
+}
+
+void gsc_hw_set_frm_done_irq_mask(struct gsc_dev *dev, bool mask)
+{
+ u32 cfg;
+
+ cfg = readl(dev->regs + GSC_IRQ);
+ if (mask)
+ cfg |= GSC_IRQ_FRMDONE_MASK;
+ else
+ cfg &= ~GSC_IRQ_FRMDONE_MASK;
+ writel(cfg, dev->regs + GSC_IRQ);
+}
+
+void gsc_hw_set_overflow_irq_mask(struct gsc_dev *dev, bool mask)
+{
+ u32 cfg;
+
+ cfg = readl(dev->regs + GSC_IRQ);
+ if (mask)
+ cfg |= GSC_IRQ_OR_MASK;
+ else
+ cfg &= ~GSC_IRQ_OR_MASK;
+ writel(cfg, dev->regs + GSC_IRQ);
+}
+
+void gsc_hw_set_gsc_irq_enable(struct gsc_dev *dev, bool mask)
+{
+ u32 cfg;
+
+ cfg = readl(dev->regs + GSC_IRQ);
+ if (mask)
+ cfg |= GSC_IRQ_ENABLE;
+ else
+ cfg &= ~GSC_IRQ_ENABLE;
+ writel(cfg, dev->regs + GSC_IRQ);
+}
+
+void gsc_hw_set_input_buf_mask_all(struct gsc_dev *dev)
+{
+ u32 cfg;
+
+ cfg = readl(dev->regs + GSC_IN_BASE_ADDR_Y_MASK);
+ cfg |= GSC_IN_BASE_ADDR_MASK;
+ cfg |= GSC_IN_BASE_ADDR_PINGPONG(dev->variant->in_buf_cnt);
+
+ writel(cfg, dev->regs + GSC_IN_BASE_ADDR_Y_MASK);
+ writel(cfg, dev->regs + GSC_IN_BASE_ADDR_CB_MASK);
+ writel(cfg, dev->regs + GSC_IN_BASE_ADDR_CR_MASK);
+}
+
+void gsc_hw_set_output_buf_mask_all(struct gsc_dev *dev)
+{
+ u32 cfg;
+
+ cfg = readl(dev->regs + GSC_OUT_BASE_ADDR_Y_MASK);
+ cfg |= GSC_OUT_BASE_ADDR_MASK;
+ cfg |= GSC_OUT_BASE_ADDR_PINGPONG(dev->variant->out_buf_cnt);
+
+ writel(cfg, dev->regs + GSC_OUT_BASE_ADDR_Y_MASK);
+ writel(cfg, dev->regs + GSC_OUT_BASE_ADDR_CB_MASK);
+ writel(cfg, dev->regs + GSC_OUT_BASE_ADDR_CR_MASK);
+}
+
+void gsc_hw_set_input_buf_masking(struct gsc_dev *dev, u32 shift,
+ bool enable)
+{
+ u32 cfg = readl(dev->regs + GSC_IN_BASE_ADDR_Y_MASK);
+ u32 mask = 1 << shift;
+
+ cfg &= (~mask);
+ cfg |= enable << shift;
+
+ writel(cfg, dev->regs + GSC_IN_BASE_ADDR_Y_MASK);
+ writel(cfg, dev->regs + GSC_IN_BASE_ADDR_CB_MASK);
+ writel(cfg, dev->regs + GSC_IN_BASE_ADDR_CR_MASK);
+}
+
+void gsc_hw_set_output_buf_masking(struct gsc_dev *dev, u32 shift,
+ bool enable)
+{
+ u32 cfg = readl(dev->regs + GSC_OUT_BASE_ADDR_Y_MASK);
+ u32 mask = 1 << shift;
+
+ cfg &= (~mask);
+ cfg |= enable << shift;
+
+ writel(cfg, dev->regs + GSC_OUT_BASE_ADDR_Y_MASK);
+ writel(cfg, dev->regs + GSC_OUT_BASE_ADDR_CB_MASK);
+ writel(cfg, dev->regs + GSC_OUT_BASE_ADDR_CR_MASK);
+}
+
+int gsc_hw_get_nr_unmask_bits(struct gsc_dev *dev)
+{
+ u32 bits = 0;
+ u32 mask_bits = readl(dev->regs + GSC_OUT_BASE_ADDR_Y_MASK);
+ mask_bits &= GSC_OUT_BASE_ADDR_MASK;
+
+ while (mask_bits) {
+ mask_bits = mask_bits & (mask_bits - 1);
+ bits++;
+ }
+ bits = 16 - bits;
+
+ return bits;
+}
+
+void gsc_hw_set_input_addr(struct gsc_dev *dev, struct gsc_addr *addr,
+ int index)
+{
+ gsc_dbg("src_buf[%d]: 0x%X, cb: 0x%X, cr: 0x%X", index,
+ addr->y, addr->cb, addr->cr);
+ writel(addr->y, dev->regs + GSC_IN_BASE_ADDR_Y(index));
+ writel(addr->cb, dev->regs + GSC_IN_BASE_ADDR_CB(index));
+ writel(addr->cr, dev->regs + GSC_IN_BASE_ADDR_CR(index));
+
+}
+
+void gsc_hw_set_output_addr(struct gsc_dev *dev,
+ struct gsc_addr *addr, int index)
+{
+ gsc_dbg("dst_buf[%d]: 0x%X, cb: 0x%X, cr: 0x%X",
+ index, addr->y, addr->cb, addr->cr);
+ writel(addr->y, dev->regs + GSC_OUT_BASE_ADDR_Y(index));
+ writel(addr->cb, dev->regs + GSC_OUT_BASE_ADDR_CB(index));
+ writel(addr->cr, dev->regs + GSC_OUT_BASE_ADDR_CR(index));
+}
+
+void gsc_hw_set_freerun_clock_mode(struct gsc_dev *dev, bool mask)
+{
+ u32 cfg = readl(dev->regs + GSC_ENABLE);
+
+ cfg &= ~(GSC_ENABLE_CLK_GATE_MODE_MASK);
+ if (mask)
+ cfg |= GSC_ENABLE_CLK_GATE_MODE_FREE;
+ writel(cfg, dev->regs + GSC_ENABLE);
+}
+
+void gsc_hw_set_input_path(struct gsc_ctx *ctx)
+{
+ struct gsc_dev *dev = ctx->gsc_dev;
+
+ u32 cfg = readl(dev->regs + GSC_IN_CON);
+ cfg &= ~(GSC_IN_PATH_MASK | GSC_IN_LOCAL_SEL_MASK);
+
+ if (ctx->in_path == GSC_DMA) {
+ cfg |= GSC_IN_PATH_MEMORY;
+ } else {
+ cfg |= GSC_IN_PATH_LOCAL;
+ if (ctx->in_path == GSC_WRITEBACK) {
+ cfg |= GSC_IN_LOCAL_FIMD_WB;
+ } else {
+ struct v4l2_subdev *sd = dev->pipeline.sensor;
+ struct gsc_sensor_info *s_info =
+ v4l2_get_subdev_hostdata(sd);
+ if (s_info->pdata->cam_port == CAM_PORT_A)
+ cfg |= GSC_IN_LOCAL_CAM0;
+ else
+ cfg |= GSC_IN_LOCAL_CAM1;
+ }
+ }
+
+ writel(cfg, dev->regs + GSC_IN_CON);
+}
+
+void gsc_hw_set_in_size(struct gsc_ctx *ctx)
+{
+ struct gsc_dev *dev = ctx->gsc_dev;
+ struct gsc_frame *frame = &ctx->s_frame;
+ u32 cfg;
+
+ /* Set input pixel offset */
+ cfg = GSC_SRCIMG_OFFSET_X(frame->crop.left);
+ cfg |= GSC_SRCIMG_OFFSET_Y(frame->crop.top);
+ writel(cfg, dev->regs + GSC_SRCIMG_OFFSET);
+
+ /* Set input original size */
+ cfg = GSC_SRCIMG_WIDTH(frame->f_width);
+ cfg |= GSC_SRCIMG_HEIGHT(frame->f_height);
+ writel(cfg, dev->regs + GSC_SRCIMG_SIZE);
+
+ /* Set input cropped size */
+ cfg = GSC_CROPPED_WIDTH(frame->crop.width);
+ cfg |= GSC_CROPPED_HEIGHT(frame->crop.height);
+ writel(cfg, dev->regs + GSC_CROPPED_SIZE);
+}
+
+void gsc_hw_set_in_image_rgb(struct gsc_ctx *ctx)
+{
+ struct gsc_dev *dev = ctx->gsc_dev;
+ struct gsc_frame *frame = &ctx->s_frame;
+ u32 cfg;
+
+ cfg = readl(dev->regs + GSC_IN_CON);
+ if (ctx->gsc_ctrls.csc_eq->val) {
+ if (ctx->gsc_ctrls.csc_range->val)
+ cfg |= GSC_IN_RGB_HD_WIDE;
+ else
+ cfg |= GSC_IN_RGB_HD_NARROW;
+ } else {
+ if (ctx->gsc_ctrls.csc_range->val)
+ cfg |= GSC_IN_RGB_SD_WIDE;
+ else
+ cfg |= GSC_IN_RGB_SD_NARROW;
+ }
+
+ if (frame->fmt->pixelformat == V4L2_PIX_FMT_RGB565X)
+ cfg |= GSC_IN_RGB565;
+ else if (frame->fmt->pixelformat == V4L2_PIX_FMT_RGB32)
+ cfg |= GSC_IN_XRGB8888;
+ else if (frame->fmt->pixelformat == V4L2_PIX_FMT_BGR32)
+ cfg |= GSC_IN_XRGB8888 | GSC_IN_RB_SWAP;
+
+ writel(cfg, dev->regs + GSC_IN_CON);
+}
+
+void gsc_hw_set_in_image_format(struct gsc_ctx *ctx)
+{
+ struct gsc_dev *dev = ctx->gsc_dev;
+ struct gsc_frame *frame = &ctx->s_frame;
+ u32 i, depth = 0;
+ u32 cfg;
+
+ cfg = readl(dev->regs + GSC_IN_CON);
+ cfg &= ~(GSC_IN_RGB_TYPE_MASK | GSC_IN_YUV422_1P_ORDER_MASK |
+ GSC_IN_CHROMA_ORDER_MASK | GSC_IN_FORMAT_MASK |
+ GSC_IN_TILE_TYPE_MASK | GSC_IN_TILE_MODE |
+ GSC_IN_CHROM_STRIDE_SEL_MASK | GSC_IN_RB_SWAP_MASK);
+ writel(cfg, dev->regs + GSC_IN_CON);
+
+ if (is_rgb(frame->fmt->pixelformat)) {
+ gsc_hw_set_in_image_rgb(ctx);
+ return;
+ }
+ for (i = 0; i < frame->fmt->num_planes; i++)
+ depth += frame->fmt->depth[i];
+
+ switch (frame->fmt->nr_comp) {
+ case 1:
+ cfg |= GSC_IN_YUV422_1P;
+ if (frame->fmt->yorder == GSC_LSB_Y)
+ cfg |= GSC_IN_YUV422_1P_ORDER_LSB_Y;
+ else
+ cfg |= GSC_IN_YUV422_1P_OEDER_LSB_C;
+ if (frame->fmt->corder == GSC_CBCR)
+ cfg |= GSC_IN_CHROMA_ORDER_CBCR;
+ else
+ cfg |= GSC_IN_CHROMA_ORDER_CRCB;
+ break;
+ case 2:
+ if (depth == 12)
+ cfg |= GSC_IN_YUV420_2P;
+ else
+ cfg |= GSC_IN_YUV422_2P;
+ if (frame->fmt->corder == GSC_CBCR)
+ cfg |= GSC_IN_CHROMA_ORDER_CBCR;
+ else
+ cfg |= GSC_IN_CHROMA_ORDER_CRCB;
+ break;
+ case 3:
+ if (depth == 12)
+ cfg |= GSC_IN_YUV420_3P;
+ else
+ cfg |= GSC_IN_YUV422_3P;
+ break;
+ };
+
+ if (is_AYV12(frame->fmt->pixelformat))
+ gsc_hw_set_in_chrom_stride(ctx);
+
+ if (is_tiled(frame->fmt))
+ cfg |= GSC_IN_TILE_C_16x8 | GSC_IN_TILE_MODE;
+
+ writel(cfg, dev->regs + GSC_IN_CON);
+}
+
+void gsc_hw_set_output_path(struct gsc_ctx *ctx)
+{
+ struct gsc_dev *dev = ctx->gsc_dev;
+
+ u32 cfg = readl(dev->regs + GSC_OUT_CON);
+ cfg &= ~GSC_OUT_PATH_MASK;
+
+ if (ctx->out_path == GSC_DMA)
+ cfg |= GSC_OUT_PATH_MEMORY;
+ else
+ cfg |= GSC_OUT_PATH_LOCAL;
+
+ writel(cfg, dev->regs + GSC_OUT_CON);
+}
+
+void gsc_hw_set_out_size(struct gsc_ctx *ctx)
+{
+ struct gsc_dev *dev = ctx->gsc_dev;
+ struct gsc_frame *frame = &ctx->d_frame;
+ u32 cfg;
+
+ /* Set output original size */
+ if (ctx->out_path == GSC_DMA) {
+ cfg = GSC_DSTIMG_OFFSET_X(frame->crop.left);
+ cfg |= GSC_DSTIMG_OFFSET_Y(frame->crop.top);
+ writel(cfg, dev->regs + GSC_DSTIMG_OFFSET);
+
+ cfg = GSC_DSTIMG_WIDTH(frame->f_width);
+ cfg |= GSC_DSTIMG_HEIGHT(frame->f_height);
+ writel(cfg, dev->regs + GSC_DSTIMG_SIZE);
+ }
+
+ /* Set output scaled size */
+ if (ctx->gsc_ctrls.rotate->val == 90 ||
+ ctx->gsc_ctrls.rotate->val == 270) {
+ cfg = GSC_SCALED_WIDTH(frame->crop.height);
+ cfg |= GSC_SCALED_HEIGHT(frame->crop.width);
+ } else {
+ cfg = GSC_SCALED_WIDTH(frame->crop.width);
+ cfg |= GSC_SCALED_HEIGHT(frame->crop.height);
+ }
+ writel(cfg, dev->regs + GSC_SCALED_SIZE);
+}
+
+void gsc_hw_set_out_image_rgb(struct gsc_ctx *ctx)
+{
+ struct gsc_dev *dev = ctx->gsc_dev;
+ struct gsc_frame *frame = &ctx->d_frame;
+ u32 cfg;
+
+ cfg = readl(dev->regs + GSC_OUT_CON);
+ if (ctx->gsc_ctrls.csc_eq->val) {
+ if (ctx->gsc_ctrls.csc_range->val)
+ cfg |= GSC_OUT_RGB_HD_WIDE;
+ else
+ cfg |= GSC_OUT_RGB_HD_NARROW;
+ } else {
+ if (ctx->gsc_ctrls.csc_range->val)
+ cfg |= GSC_OUT_RGB_SD_WIDE;
+ else
+ cfg |= GSC_OUT_RGB_SD_NARROW;
+ }
+
+ if (frame->fmt->pixelformat == V4L2_PIX_FMT_RGB565X)
+ cfg |= GSC_OUT_RGB565;
+ else if (frame->fmt->pixelformat == V4L2_PIX_FMT_RGB32)
+ cfg |= GSC_OUT_XRGB8888;
+ else if (frame->fmt->pixelformat == V4L2_PIX_FMT_BGR32)
+ cfg |= GSC_OUT_XRGB8888 | GSC_OUT_RB_SWAP;
+
+ writel(cfg, dev->regs + GSC_OUT_CON);
+}
+
+void gsc_hw_set_out_image_format(struct gsc_ctx *ctx)
+{
+ struct gsc_dev *dev = ctx->gsc_dev;
+ struct gsc_frame *frame = &ctx->d_frame;
+ u32 i, depth = 0;
+ u32 cfg;
+
+ cfg = readl(dev->regs + GSC_OUT_CON);
+ cfg &= ~(GSC_OUT_RGB_TYPE_MASK | GSC_OUT_YUV422_1P_ORDER_MASK |
+ GSC_OUT_CHROMA_ORDER_MASK | GSC_OUT_FORMAT_MASK |
+ GSC_OUT_CHROM_STRIDE_SEL_MASK | GSC_OUT_RB_SWAP_MASK);
+ writel(cfg, dev->regs + GSC_OUT_CON);
+
+ if (is_rgb(frame->fmt->pixelformat)) {
+ gsc_hw_set_out_image_rgb(ctx);
+ return;
+ }
+
+ if (ctx->out_path != GSC_DMA) {
+ cfg |= GSC_OUT_YUV444;
+ goto end_set;
+ }
+
+ for (i = 0; i < frame->fmt->num_planes; i++)
+ depth += frame->fmt->depth[i];
+
+ switch (frame->fmt->nr_comp) {
+ case 1:
+ cfg |= GSC_OUT_YUV422_1P;
+ if (frame->fmt->yorder == GSC_LSB_Y)
+ cfg |= GSC_OUT_YUV422_1P_ORDER_LSB_Y;
+ else
+ cfg |= GSC_OUT_YUV422_1P_OEDER_LSB_C;
+ if (frame->fmt->corder == GSC_CBCR)
+ cfg |= GSC_OUT_CHROMA_ORDER_CBCR;
+ else
+ cfg |= GSC_OUT_CHROMA_ORDER_CRCB;
+ break;
+ case 2:
+ if (depth == 12)
+ cfg |= GSC_OUT_YUV420_2P;
+ else
+ cfg |= GSC_OUT_YUV422_2P;
+ if (frame->fmt->corder == GSC_CBCR)
+ cfg |= GSC_OUT_CHROMA_ORDER_CBCR;
+ else
+ cfg |= GSC_OUT_CHROMA_ORDER_CRCB;
+ break;
+ case 3:
+ cfg |= GSC_OUT_YUV420_3P;
+ break;
+ };
+
+ if (is_AYV12(frame->fmt->pixelformat))
+ gsc_hw_set_out_chrom_stride(ctx);
+end_set:
+ writel(cfg, dev->regs + GSC_OUT_CON);
+}
+
+void gsc_hw_set_prescaler(struct gsc_ctx *ctx)
+{
+ struct gsc_dev *dev = ctx->gsc_dev;
+ struct gsc_scaler *sc = &ctx->scaler;
+ u32 cfg;
+
+ cfg = GSC_PRESC_SHFACTOR(sc->pre_shfactor);
+ cfg |= GSC_PRESC_H_RATIO(sc->pre_hratio);
+ cfg |= GSC_PRESC_V_RATIO(sc->pre_vratio);
+ writel(cfg, dev->regs + GSC_PRE_SCALE_RATIO);
+}
+
+void gsc_hw_set_mainscaler(struct gsc_ctx *ctx)
+{
+ struct gsc_dev *dev = ctx->gsc_dev;
+ struct gsc_scaler *sc = &ctx->scaler;
+ u32 cfg;
+
+ cfg = GSC_MAIN_H_RATIO_VALUE(sc->main_hratio);
+ writel(cfg, dev->regs + GSC_MAIN_H_RATIO);
+
+ cfg = GSC_MAIN_V_RATIO_VALUE(sc->main_vratio);
+ writel(cfg, dev->regs + GSC_MAIN_V_RATIO);
+}
+
+void gsc_hw_set_rotation(struct gsc_ctx *ctx)
+{
+ struct gsc_dev *dev = ctx->gsc_dev;
+ u32 cfg;
+
+ cfg = readl(dev->regs + GSC_IN_CON);
+ cfg &= ~GSC_IN_ROT_MASK;
+
+ switch (ctx->gsc_ctrls.rotate->val) {
+ case 270:
+ cfg |= GSC_IN_ROT_270;
+ break;
+ case 180:
+ cfg |= GSC_IN_ROT_180;
+ break;
+ case 90:
+ if (ctx->gsc_ctrls.hflip->val)
+ cfg |= GSC_IN_ROT_90_XFLIP;
+ else if (ctx->gsc_ctrls.vflip->val)
+ cfg |= GSC_IN_ROT_90_YFLIP;
+ else
+ cfg |= GSC_IN_ROT_90;
+ break;
+ case 0:
+ if (ctx->gsc_ctrls.hflip->val)
+ cfg |= GSC_IN_ROT_XFLIP;
+ else if (ctx->gsc_ctrls.vflip->val)
+ cfg |= GSC_IN_ROT_YFLIP;
+ }
+
+ writel(cfg, dev->regs + GSC_IN_CON);
+}
+
+void gsc_hw_set_global_alpha(struct gsc_ctx *ctx)
+{
+ struct gsc_dev *dev = ctx->gsc_dev;
+ struct gsc_frame *frame = &ctx->d_frame;
+ u32 cfg;
+
+ cfg = readl(dev->regs + GSC_OUT_CON);
+ cfg &= ~GSC_OUT_GLOBAL_ALPHA_MASK;
+
+ if (!is_rgb(frame->fmt->pixelformat)) {
+ gsc_dbg("Not a RGB format");
+ return;
+ }
+
+ cfg |= GSC_OUT_GLOBAL_ALPHA(ctx->gsc_ctrls.global_alpha->val);
+ writel(cfg, dev->regs + GSC_OUT_CON);
+}
+
+void gsc_hw_set_sfr_update(struct gsc_ctx *ctx)
+{
+ struct gsc_dev *dev = ctx->gsc_dev;
+ u32 cfg;
+
+ cfg = readl(dev->regs + GSC_ENABLE);
+ cfg |= GSC_ENABLE_SFR_UPDATE;
+ writel(cfg, dev->regs + GSC_ENABLE);
+}
+
+void gsc_hw_set_local_dst(int id, int out, bool on)
+{
+ u32 cfg = readl(SYSREG_GSCBLK_CFG0);
+
+ if (out == GSC_FIMD) {
+ if (on)
+ cfg |= GSC_OUT_DST_FIMD_SEL(id);
+ else
+ cfg &= ~(GSC_OUT_DST_FIMD_SEL(id));
+ } else if (out == GSC_MIXER) {
+ if (on)
+ cfg |= GSC_OUT_DST_MXR_SEL(id);
+ else
+ cfg &= ~(GSC_OUT_DST_MXR_SEL(id));
+ }
+ writel(cfg, SYSREG_GSCBLK_CFG0);
+}
+
+void gsc_hw_set_sysreg_writeback(struct gsc_ctx *ctx)
+{
+ struct gsc_dev *dev = ctx->gsc_dev;
+
+ u32 cfg = readl(SYSREG_GSCBLK_CFG1);
+
+ cfg &= ~GSC_BLK_SW_RESET_WB_DEST(dev->id);
+ writel(cfg, SYSREG_GSCBLK_CFG1);
+
+ cfg |= GSC_BLK_DISP1WB_DEST(dev->id);
+ cfg |= GSC_BLK_GSCL_WB_IN_SRC_SEL(dev->id);
+ cfg |= GSC_BLK_SW_RESET_WB_DEST(dev->id);
+
+ writel(cfg, SYSREG_GSCBLK_CFG1);
+}
+
+void gsc_hw_set_pxlasync_camif_lo_mask(struct gsc_dev *dev, bool on)
+{
+ u32 cfg = 0;
+
+ if (dev->id == 3) {
+ cfg = readl(SYSREG_GSCBLK_CFG0);
+ if (on)
+ cfg |= PXLASYNC_LO_MASK_CAMIF_TOP;
+ else
+ cfg &= ~(PXLASYNC_LO_MASK_CAMIF_TOP);
+ writel(cfg, SYSREG_GSCBLK_CFG0);
+ } else {
+ cfg = readl(SYSREG_GSCBLK_CFG2);
+ if (on)
+ cfg |= PXLASYNC_LO_MASK_CAMIF_GSCL(dev->id);
+ else
+ cfg &= ~PXLASYNC_LO_MASK_CAMIF_GSCL(dev->id);
+ writel(cfg, SYSREG_GSCBLK_CFG2);
+ }
+}
+
+void gsc_hw_set_h_coef(struct gsc_ctx *ctx)
+{
+ struct gsc_scaler *sc = &ctx->scaler;
+ struct gsc_dev *dev = ctx->gsc_dev;
+ int i, j, k, sc_ratio = 0;
+
+ if (sc->main_hratio <= GSC_SC_UP_MAX_RATIO)
+ sc_ratio = 0;
+ else if (sc->main_hratio <= GSC_SC_DOWN_RATIO_7_8)
+ sc_ratio = 1;
+ else if (sc->main_hratio <= GSC_SC_DOWN_RATIO_6_8)
+ sc_ratio = 2;
+ else if (sc->main_hratio <= GSC_SC_DOWN_RATIO_5_8)
+ sc_ratio = 3;
+ else if (sc->main_hratio <= GSC_SC_DOWN_RATIO_4_8)
+ sc_ratio = 4;
+ else if (sc->main_hratio <= GSC_SC_DOWN_RATIO_3_8)
+ sc_ratio = 5;
+ else
+ sc_ratio = 6;
+
+ for (i = 0; i < 9; i++) {
+ for (j = 0; j < 8; j++) {
+ for (k = 0; k < 3; k++) {
+ writel(h_coef_8t[sc_ratio][i][j],
+ dev->regs + GSC_HCOEF(i, j, k));
+ }
+ }
+ }
+}
+
+void gsc_hw_set_v_coef(struct gsc_ctx *ctx)
+{
+ struct gsc_scaler *sc = &ctx->scaler;
+ struct gsc_dev *dev = ctx->gsc_dev;
+ int i, j, k, sc_ratio = 0;
+
+ if (sc->main_vratio <= GSC_SC_UP_MAX_RATIO)
+ sc_ratio = 0;
+ else if (sc->main_vratio <= GSC_SC_DOWN_RATIO_7_8)
+ sc_ratio = 1;
+ else if (sc->main_vratio <= GSC_SC_DOWN_RATIO_6_8)
+ sc_ratio = 2;
+ else if (sc->main_vratio <= GSC_SC_DOWN_RATIO_5_8)
+ sc_ratio = 3;
+ else if (sc->main_vratio <= GSC_SC_DOWN_RATIO_4_8)
+ sc_ratio = 4;
+ else if (sc->main_vratio <= GSC_SC_DOWN_RATIO_3_8)
+ sc_ratio = 5;
+ else
+ sc_ratio = 6;
+
+ for (i = 0; i < 9; i++) {
+ for (j = 0; j < 4; j++) {
+ for (k = 0; k < 3; k++) {
+ writel(v_coef_4t[sc_ratio][i][j],
+ dev->regs + GSC_VCOEF(i, j, k));
+ }
+ }
+ }
+}
diff --git a/drivers/media/video/exynos/gsc/gsc-vb2.c b/drivers/media/video/exynos/gsc/gsc-vb2.c
new file mode 100644
index 0000000..cf31390
--- /dev/null
+++ b/drivers/media/video/exynos/gsc/gsc-vb2.c
@@ -0,0 +1,68 @@
+/* linux/drivers/media/video/exynos/gsc-vb2.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Videobuf2 allocator operations file
+ *
+ * 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.
+*/
+
+#include <linux/platform_device.h>
+#include "gsc-core.h"
+
+#if defined(CONFIG_VIDEOBUF2_CMA_PHYS)
+void *gsc_cma_init(struct gsc_dev *gsc)
+{
+ return vb2_cma_phys_init(&gsc->pdev->dev, NULL, 0, false);
+}
+
+int gsc_cma_resume(void *alloc_ctx) {}
+void gsc_cma_suspend(void *alloc_ctx) {}
+void gsc_cma_set_cacheable(void *alloc_ctx, bool cacheable) {}
+
+int gsc_cma_cache_flush(struct vb2_buffer *vb, u32 plane_no)
+{
+ return 0;
+}
+
+const struct gsc_vb2 gsc_vb2_cma = {
+ .ops = &vb2_cma_phys_memops,
+ .init = gsc_cma_init,
+ .cleanup = vb2_cma_phys_cleanup,
+ .plane_addr = vb2_cma_phys_plane_paddr,
+ .resume = gsc_cma_resume,
+ .suspend = gsc_cma_suspend,
+ .cache_flush = gsc_cma_cache_flush,
+ .set_cacheable = gsc_cma_set_cacheable,
+};
+#elif defined(CONFIG_VIDEOBUF2_ION)
+void *gsc_ion_init(struct gsc_dev *gsc)
+{
+ return vb2_ion_create_context(&gsc->pdev->dev, SZ_4K,
+ VB2ION_CTX_VMCONTIG | VB2ION_CTX_IOMMU | VB2ION_CTX_UNCACHED);
+}
+
+static unsigned long gsc_vb2_plane_addr(struct vb2_buffer *vb, u32 plane_no)
+{
+ void *cookie = vb2_plane_cookie(vb, plane_no);
+ dma_addr_t dva = 0;
+
+ WARN_ON(vb2_ion_dma_address(cookie, &dva) != 0);
+
+ return dva;
+}
+const struct gsc_vb2 gsc_vb2_ion = {
+ .ops = &vb2_ion_memops,
+ .init = gsc_ion_init,
+ .cleanup = vb2_ion_destroy_context,
+ .plane_addr = gsc_vb2_plane_addr,
+ .resume = vb2_ion_attach_iommu,
+ .suspend = vb2_ion_detach_iommu,
+ .cache_flush = vb2_ion_cache_flush,
+ .set_cacheable = vb2_ion_set_cached,
+ .set_protected = vb2_ion_set_protected,
+};
+#endif
diff --git a/drivers/media/video/exynos/gsc/regs-gsc.h b/drivers/media/video/exynos/gsc/regs-gsc.h
new file mode 100644
index 0000000..84bf35b
--- /dev/null
+++ b/drivers/media/video/exynos/gsc/regs-gsc.h
@@ -0,0 +1,288 @@
+/* linux/drivers/media/video/exynos/gsc/regs-gsc.h
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Register definition file for Samsung G-Scaler driver
+ *
+ * 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.
+ */
+
+#ifndef REGS_GSC_H_
+#define REGS_GSC_H_
+
+/* SYSCON. GSCBLK_CFG */
+#include <plat/map-base.h>
+
+#define SYSREG_DISP1BLK_CFG (S3C_VA_SYS + 0x0214)
+#define FIFORST_DISP1 (1 << 23)
+#define SYSREG_GSCBLK_CFG0 (S3C_VA_SYS + 0x0220)
+#define GSC_OUT_DST_FIMD_SEL(x) (1 << (8 + 2 * (x)))
+#define GSC_OUT_DST_MXR_SEL(x) (2 << (8 + 2 * (x)))
+#define GSC_PXLASYNC_RST(x) (1 << (x))
+#define PXLASYNC_LO_MASK_CAMIF_TOP (1 << 20)
+#define SYSREG_GSCBLK_CFG1 (S3C_VA_SYS + 0x0224)
+#define GSC_BLK_DISP1WB_DEST(x) (x << 10)
+#define GSC_BLK_SW_RESET_WB_DEST(x) (1 << (18 + x))
+#define GSC_BLK_GSCL_WB_IN_SRC_SEL(x) (1 << (2 * x))
+#define SYSREG_GSCBLK_CFG2 (S3C_VA_SYS + 0x2000)
+#define PXLASYNC_LO_MASK_CAMIF_GSCL(x) (1 << (x))
+
+/* G-Scaler enable */
+#define GSC_ENABLE 0x00
+#define GSC_ENABLE_PP_UPDATE_TIME_MASK (1 << 9)
+#define GSC_ENABLE_PP_UPDATE_TIME_CURR (0 << 9)
+#define GSC_ENABLE_PP_UPDATE_TIME_EOPAS (1 << 9)
+#define GSC_ENABLE_CLK_GATE_MODE_MASK (1 << 8)
+#define GSC_ENABLE_CLK_GATE_MODE_FREE (1 << 8)
+#define GSC_ENABLE_IPC_MODE_MASK (1 << 7)
+#define GSC_ENABLE_NORM_MODE (0 << 7)
+#define GSC_ENABLE_IPC_MODE (1 << 7)
+#define GSC_ENABLE_PP_UPDATE_MODE_MASK (1 << 6)
+#define GSC_ENABLE_PP_UPDATE_FIRE_MODE (1 << 6)
+#define GSC_ENABLE_IN_PP_UPDATE (1 << 5)
+#define GSC_ENABLE_ON_CLEAR_MASK (1 << 4)
+#define GSC_ENABLE_ON_CLEAR_ONESHOT (1 << 4)
+#define GSC_ENABLE_QOS_ENABLE (1 << 3)
+#define GSC_ENABLE_OP_STATUS (1 << 2)
+#define GSC_ENABLE_SFR_UPDATE (1 << 1)
+#define GSC_ENABLE_ON (1 << 0)
+
+/* G-Scaler S/W reset */
+#define GSC_SW_RESET 0x04
+#define GSC_SW_RESET_SRESET (1 << 0)
+
+/* G-Scaler IRQ */
+#define GSC_IRQ 0x08
+#define GSC_IRQ_STATUS_OR_IRQ (1 << 17)
+#define GSC_IRQ_STATUS_OR_FRM_DONE (1 << 16)
+#define GSC_IRQ_OR_MASK (1 << 2)
+#define GSC_IRQ_FRMDONE_MASK (1 << 1)
+#define GSC_IRQ_ENABLE (1 << 0)
+
+/* G-Scaler input control */
+#define GSC_IN_CON 0x10
+#define GSC_IN_CHROM_STRIDE_SEL_MASK (1 << 20)
+#define GSC_IN_CHROM_STRIDE_SEPAR (1 << 20)
+#define GSC_IN_RB_SWAP_MASK (1 << 19)
+#define GSC_IN_RB_SWAP (1 << 19)
+#define GSC_IN_ROT_MASK (7 << 16)
+#define GSC_IN_ROT_270 (7 << 16)
+#define GSC_IN_ROT_90_YFLIP (6 << 16)
+#define GSC_IN_ROT_90_XFLIP (5 << 16)
+#define GSC_IN_ROT_90 (4 << 16)
+#define GSC_IN_ROT_180 (3 << 16)
+#define GSC_IN_ROT_YFLIP (2 << 16)
+#define GSC_IN_ROT_XFLIP (1 << 16)
+#define GSC_IN_RGB_TYPE_MASK (3 << 14)
+#define GSC_IN_RGB_HD_WIDE (3 << 14)
+#define GSC_IN_RGB_HD_NARROW (2 << 14)
+#define GSC_IN_RGB_SD_WIDE (1 << 14)
+#define GSC_IN_RGB_SD_NARROW (0 << 14)
+#define GSC_IN_YUV422_1P_ORDER_MASK (1 << 13)
+#define GSC_IN_YUV422_1P_ORDER_LSB_Y (0 << 13)
+#define GSC_IN_YUV422_1P_OEDER_LSB_C (1 << 13)
+#define GSC_IN_CHROMA_ORDER_MASK (1 << 12)
+#define GSC_IN_CHROMA_ORDER_CBCR (0 << 12)
+#define GSC_IN_CHROMA_ORDER_CRCB (1 << 12)
+#define GSC_IN_FORMAT_MASK (7 << 8)
+#define GSC_IN_XRGB8888 (0 << 8)
+#define GSC_IN_RGB565 (1 << 8)
+#define GSC_IN_YUV420_2P (2 << 8)
+#define GSC_IN_YUV420_3P (3 << 8)
+#define GSC_IN_YUV422_1P (4 << 8)
+#define GSC_IN_YUV422_2P (5 << 8)
+#define GSC_IN_YUV422_3P (6 << 8)
+#define GSC_IN_TILE_TYPE_MASK (1 << 4)
+#define GSC_IN_TILE_C_16x8 (0 << 4)
+#define GSC_IN_TILE_C_16x16 (1 << 4)
+#define GSC_IN_TILE_MODE (1 << 3)
+#define GSC_IN_LOCAL_SEL_MASK (3 << 1)
+#define GSC_IN_LOCAL_CAM3 (3 << 1)
+#define GSC_IN_LOCAL_FIMD_WB (2 << 1)
+#define GSC_IN_LOCAL_CAM1 (1 << 1)
+#define GSC_IN_LOCAL_CAM0 (0 << 1)
+#define GSC_IN_PATH_MASK (1 << 0)
+#define GSC_IN_PATH_LOCAL (1 << 0)
+#define GSC_IN_PATH_MEMORY (0 << 0)
+
+/* G-Scaler source image size */
+#define GSC_SRCIMG_SIZE 0x14
+#define GSC_SRCIMG_HEIGHT_MASK (0x1fff << 16)
+#define GSC_SRCIMG_HEIGHT(x) ((x) << 16)
+#define GSC_SRCIMG_WIDTH_MASK (0x3fff << 0)
+#define GSC_SRCIMG_WIDTH(x) ((x) << 0)
+
+/* G-Scaler source image offset */
+#define GSC_SRCIMG_OFFSET 0x18
+#define GSC_SRCIMG_OFFSET_Y_MASK (0x1fff << 16)
+#define GSC_SRCIMG_OFFSET_Y(x) ((x) << 16)
+#define GSC_SRCIMG_OFFSET_X_MASK (0x1fff << 0)
+#define GSC_SRCIMG_OFFSET_X(x) ((x) << 0)
+
+/* G-Scaler cropped source image size */
+#define GSC_CROPPED_SIZE 0x1C
+#define GSC_CROPPED_HEIGHT_MASK (0x1fff << 16)
+#define GSC_CROPPED_HEIGHT(x) ((x) << 16)
+#define GSC_CROPPED_WIDTH_MASK (0x1fff << 0)
+#define GSC_CROPPED_WIDTH(x) ((x) << 0)
+
+/* G-Scaler output control */
+#define GSC_OUT_CON 0x20
+#define GSC_OUT_GLOBAL_ALPHA_MASK (0xff << 24)
+#define GSC_OUT_GLOBAL_ALPHA(x) ((x) << 24)
+#define GSC_OUT_CHROM_STRIDE_SEL_MASK (1 << 13)
+#define GSC_OUT_CHROM_STRIDE_SEPAR (1 << 13)
+#define GSC_OUT_RB_SWAP_MASK (1 << 12)
+#define GSC_OUT_RB_SWAP (1 << 12)
+#define GSC_OUT_RGB_TYPE_MASK (3 << 10)
+#define GSC_OUT_RGB_HD_NARROW (3 << 10)
+#define GSC_OUT_RGB_HD_WIDE (2 << 10)
+#define GSC_OUT_RGB_SD_NARROW (1 << 10)
+#define GSC_OUT_RGB_SD_WIDE (0 << 10)
+#define GSC_OUT_YUV422_1P_ORDER_MASK (1 << 9)
+#define GSC_OUT_YUV422_1P_ORDER_LSB_Y (0 << 9)
+#define GSC_OUT_YUV422_1P_OEDER_LSB_C (1 << 9)
+#define GSC_OUT_CHROMA_ORDER_MASK (1 << 8)
+#define GSC_OUT_CHROMA_ORDER_CBCR (0 << 8)
+#define GSC_OUT_CHROMA_ORDER_CRCB (1 << 8)
+#define GSC_OUT_FORMAT_MASK (7 << 4)
+#define GSC_OUT_XRGB8888 (0 << 4)
+#define GSC_OUT_RGB565 (1 << 4)
+#define GSC_OUT_YUV420_2P (2 << 4)
+#define GSC_OUT_YUV420_3P (3 << 4)
+#define GSC_OUT_YUV422_1P (4 << 4)
+#define GSC_OUT_YUV422_2P (5 << 4)
+#define GSC_OUT_YUV444 (7 << 4)
+#define GSC_OUT_PATH_MASK (1 << 0)
+#define GSC_OUT_PATH_LOCAL (1 << 0)
+#define GSC_OUT_PATH_MEMORY (0 << 0)
+
+/* G-Scaler scaled destination image size */
+#define GSC_SCALED_SIZE 0x24
+#define GSC_SCALED_HEIGHT_MASK (0x1fff << 16)
+#define GSC_SCALED_HEIGHT(x) ((x) << 16)
+#define GSC_SCALED_WIDTH_MASK (0x1fff << 0)
+#define GSC_SCALED_WIDTH(x) ((x) << 0)
+
+/* G-Scaler pre scale ratio */
+#define GSC_PRE_SCALE_RATIO 0x28
+#define GSC_PRESC_SHFACTOR_MASK (7 << 28)
+#define GSC_PRESC_SHFACTOR(x) ((x) << 28)
+#define GSC_PRESC_V_RATIO_MASK (7 << 16)
+#define GSC_PRESC_V_RATIO(x) ((x) << 16)
+#define GSC_PRESC_H_RATIO_MASK (7 << 0)
+#define GSC_PRESC_H_RATIO(x) ((x) << 0)
+
+/* G-Scaler main scale horizontal ratio */
+#define GSC_MAIN_H_RATIO 0x2C
+#define GSC_MAIN_H_RATIO_MASK (0xfffff << 0)
+#define GSC_MAIN_H_RATIO_VALUE(x) ((x) << 0)
+
+/* G-Scaler main scale vertical ratio */
+#define GSC_MAIN_V_RATIO 0x30
+#define GSC_MAIN_V_RATIO_MASK (0xfffff << 0)
+#define GSC_MAIN_V_RATIO_VALUE(x) ((x) << 0)
+
+/* G-Scaler input chrominance stride */
+#define GSC_IN_CHROM_STRIDE 0x3C
+#define GSC_IN_CHROM_STRIDE_MASK (0x3fff << 0)
+#define GSC_IN_CHROM_STRIDE_VALUE(x) ((x) << 0)
+
+/* G-Scaler destination image size */
+#define GSC_DSTIMG_SIZE 0x40
+#define GSC_DSTIMG_HEIGHT_MASK (0x1fff << 16)
+#define GSC_DSTIMG_HEIGHT(x) ((x) << 16)
+#define GSC_DSTIMG_WIDTH_MASK (0x1fff << 0)
+#define GSC_DSTIMG_WIDTH(x) ((x) << 0)
+
+/* G-Scaler destination image offset */
+#define GSC_DSTIMG_OFFSET 0x44
+#define GSC_DSTIMG_OFFSET_Y_MASK (0x1fff << 16)
+#define GSC_DSTIMG_OFFSET_Y(x) ((x) << 16)
+#define GSC_DSTIMG_OFFSET_X_MASK (0x1fff << 0)
+#define GSC_DSTIMG_OFFSET_X(x) ((x) << 0)
+
+/* G-Scaler output chrominance stride */
+#define GSC_OUT_CHROM_STRIDE 0x48
+#define GSC_OUT_CHROM_STRIDE_MASK (0x3fff << 0)
+#define GSC_OUT_CHROM_STRIDE_VALUE(x) ((x) << 0)
+
+/* G-Scaler input y address mask */
+#define GSC_IN_BASE_ADDR_Y_MASK 0x4C
+/* G-Scaler input y base address */
+#define GSC_IN_BASE_ADDR_Y(n) (0x50 + (n) * 0x4)
+/* G-Scaler input y base current address */
+#define GSC_IN_BASE_ADDR_Y_CUR(n) (0x60 + (n) * 0x4)
+
+/* G-Scaler input cb address mask */
+#define GSC_IN_BASE_ADDR_CB_MASK 0x7C
+/* G-Scaler input cb base address */
+#define GSC_IN_BASE_ADDR_CB(n) (0x80 + (n) * 0x4)
+/* G-Scaler input cb base current address */
+#define GSC_IN_BASE_ADDR_CB_CUR(n) (0x90 + (n) * 0x4)
+
+/* G-Scaler input cr address mask */
+#define GSC_IN_BASE_ADDR_CR_MASK 0xAC
+/* G-Scaler input cr base address */
+#define GSC_IN_BASE_ADDR_CR(n) (0xB0 + (n) * 0x4)
+/* G-Scaler input cr base current address */
+#define GSC_IN_BASE_ADDR_CR_CUR(n) (0xC0 + (n) * 0x4)
+
+/* G-Scaler input address mask */
+#define GSC_IN_CURR_ADDR_INDEX (0xf << 24)
+#define GSC_IN_CURR_GET_INDEX(x) ((x) >> 24)
+#define GSC_IN_BASE_ADDR_PINGPONG(x) ((x) << 16)
+#define GSC_IN_BASE_ADDR_MASK (0xff << 0)
+
+/* G-Scaler output y address mask */
+#define GSC_OUT_BASE_ADDR_Y_MASK 0x10C
+/* G-Scaler output y base address */
+#define GSC_OUT_BASE_ADDR_Y(n) (0x110 + (n) * 0x4)
+
+/* G-Scaler output cb address mask */
+#define GSC_OUT_BASE_ADDR_CB_MASK 0x15C
+/* G-Scaler output cb base address */
+#define GSC_OUT_BASE_ADDR_CB(n) (0x160 + (n) * 0x4)
+
+/* G-Scaler output cr address mask */
+#define GSC_OUT_BASE_ADDR_CR_MASK 0x1AC
+/* G-Scaler output cr base address */
+#define GSC_OUT_BASE_ADDR_CR(n) (0x1B0 + (n) * 0x4)
+
+/* G-Scaler output address mask */
+#define GSC_OUT_CURR_ADDR_INDEX (0xf << 24)
+#define GSC_OUT_CURR_GET_INDEX(x) ((x) >> 24)
+#define GSC_OUT_BASE_ADDR_PINGPONG(x) ((x) << 16)
+#define GSC_OUT_BASE_ADDR_MASK (0xffff << 0)
+
+/* G-Scaler horizontal scaling filter */
+#define GSC_HCOEF(n, s, x) (0x300 + (n) * 0x4 + (s) * 0x30 + (x) * 0x300)
+
+/* G-Scaler vertical scaling filter */
+#define GSC_VCOEF(n, s, x) (0x200 + (n) * 0x4 + (s) * 0x30 + (x) * 0x300)
+
+/* G-Scaler BUS control */
+#define GSC_BUSCON 0xA78
+#define GSC_BUSCON_INT_TIME_MASK (1 << 8)
+#define GSC_BUSCON_INT_DATA_TRANS (0 << 8)
+#define GSC_BUSCON_INT_AXI_RESPONSE (1 << 8)
+#define GSC_BUSCON_AWCACHE(x) ((x) << 4)
+#define GSC_BUSCON_ARCACHE(x) ((x) << 0)
+
+/* G-Scaler V position */
+#define GSC_VPOSITION 0xA7C
+#define GSC_VPOS_F(x) ((x) << 0)
+
+
+/* G-Scaler clock initial count */
+#define GSC_CLK_INIT_COUNT 0xC00
+#define GSC_CLK_GATE_MODE_INIT_CNT(x) ((x) << 0)
+
+/* G-Scaler clock snoop count */
+#define GSC_CLK_SNOOP_COUNT 0xC04
+#define GSC_CLK_GATE_MODE_SNOOP_CNT(x) ((x) << 0)
+
+#endif /* REGS_GSC_H_ */
diff --git a/drivers/media/video/exynos/jpeg/Kconfig b/drivers/media/video/exynos/jpeg/Kconfig
new file mode 100644
index 0000000..8298f57
--- /dev/null
+++ b/drivers/media/video/exynos/jpeg/Kconfig
@@ -0,0 +1,12 @@
+#
+# Configuration for JPEG
+#
+
+config VIDEO_EXYNOS_JPEG
+ bool "Samsung JPEG_v2.x driver"
+ depends on VIDEO_EXYNOS
+ default n
+ depends on VIDEO_DEV && VIDEO_V4L2
+ select V4L2_MEM2MEM_DEV
+ ---help---
+ This is a Samsung JPEG H/W driver for V2.x
diff --git a/drivers/media/video/exynos/jpeg/Makefile b/drivers/media/video/exynos/jpeg/Makefile
new file mode 100644
index 0000000..4d7fd1f
--- /dev/null
+++ b/drivers/media/video/exynos/jpeg/Makefile
@@ -0,0 +1,8 @@
+#################################################
+# Makefile for JPEG
+# 2009 (C) Samsung Electronics
+#################################################
+
+jpeg-objs := jpeg_dev.o jpeg_dec.o jpeg_enc.o jpeg_regs.o jpeg_mem.o
+obj-$(CONFIG_VIDEO_EXYNOS_JPEG) += jpeg.o
+
diff --git a/drivers/media/video/exynos/jpeg/jpeg_conf.h b/drivers/media/video/exynos/jpeg/jpeg_conf.h
new file mode 100644
index 0000000..21fcb19
--- /dev/null
+++ b/drivers/media/video/exynos/jpeg/jpeg_conf.h
@@ -0,0 +1,113 @@
+/* linux/drivers/media/video/exynos/jpeg/jpeg_conf.h
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Definition Quantization Table for Jpeg encoder/docoder
+ *
+ * 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.
+*/
+
+#ifndef __JPEG_CONF_H__
+#define __JPEG_CONF_H__
+
+/* Q-table for JPEG */
+/* ITU standard Q-table */
+const unsigned int ITU_Q_tbl[8][16] = {
+ {
+ 0x06030303, 0x07070706, 0x03030303, 0x08080804, /* Y QF:97 */
+ 0x01010101, 0x03040303, 0x03010101, 0x04050503,
+ 0x03030101, 0x05060704, 0x04030301, 0x06070605,
+ 0x05050403, 0x06070706, 0x06060604, 0x06070707
+ }, {
+ 0x06030303, 0x07070706, 0x04030303, 0x08080806, /* CbCr QF:97 */
+ 0x06030301, 0x06060606, 0x06060403, 0x06060606,
+ 0x06060606, 0x06060606, 0x06060606, 0x06060606,
+ 0x06060606, 0x06060606, 0x06060606, 0x06060606
+ }, {
+ 0x06030303, 0x0a080706, 0x03030303, 0x090a0904, /* Y QF:92 */
+ 0x04030303, 0x090b0906, 0x05040303, 0x0a0d0e08,
+ 0x09060403, 0x0c10110d, 0x0a090604, 0x0f12110d,
+ 0x0e0c0a08, 0x10131310, 0x100f0f0c, 0x10101012
+ }, {
+ 0x08040303, 0x10101010, 0x0b040303, 0x10101010, /* CbCr QF:92 */
+ 0x10090404, 0x10101010, 0x10100b08, 0x10101010,
+ 0x10101010, 0x10101010, 0x10101010, 0x10101010,
+ 0x10101010, 0x10101010, 0x10101010, 0x10101010
+ }, {
+ 0x06030304, 0x0e0c0a06, 0x05030303, 0x0d0e0e06, /* Y QF:88 */
+ 0x06040303, 0x0d110e0a, 0x07050403, 0x0f13150c,
+ 0x0d090504, 0x12191a10, 0x0f0d0806, 0x161b1913,
+ 0x15130f0c, 0x181d1d19, 0x18171611, 0x1819181b
+ }, {
+ 0x0b060404, 0x18181818, 0x10060504, 0x18181818, /* CbCr QF:88 */
+ 0x180d0606, 0x18181818, 0x1818100b, 0x18181818,
+ 0x18181818, 0x18181818, 0x18181818, 0x18181818,
+ 0x18181818, 0x18181818, 0x18181818, 0x18181818
+ }, {
+ 0x06040406, 0x16120e09, 0x07050404, 0x14161509, /* Y QF:82 */
+ 0x09060505, 0x1419150e, 0x0a080605, 0x161d1f12,
+ 0x140d0806, 0x1c252718, 0x17140d09, 0x2129251d,
+ 0x1f1c1712, 0x242b2c25, 0x2322211a, 0x24252428
+ }, {
+ 0x11090606, 0x24242424, 0x18090806, 0x24242424, /* CbCr QF:82 */
+ 0x24140909, 0x24242424, 0x24241811, 0x24242424,
+ 0x24242424, 0x24242424, 0x24242424, 0x24242424,
+ 0x24242424, 0x24242424, 0x24242424, 0x24242424
+ },
+
+};
+
+/* ITU Luminace Huffman Table */
+static unsigned int ITU_H_tbl_len_DC_luminance[4] = {
+ 0x01050100, 0x01010101, 0x00000001, 0x00000000
+};
+static unsigned int ITU_H_tbl_val_DC_luminance[3] = {
+ 0x03020100, 0x07060504, 0x0b0a0908
+};
+
+/* ITU Chrominace Huffman Table */
+static unsigned int ITU_H_tbl_len_DC_chrominance[4] = {
+ 0x01010300, 0x01010101, 0x00010101, 0x00000000
+};
+static unsigned int ITU_H_tbl_val_DC_chrominance[3] = {
+ 0x03020100, 0x07060504, 0x0b0a0908
+};
+
+static unsigned int ITU_H_tbl_len_AC_luminance[4] = {
+ 0x03010200, 0x03040203, 0x04040505, 0x7d010000
+};
+
+static unsigned int ITU_H_tbl_val_AC_luminance[41] = {
+ 0x00030201, 0x12051104, 0x06413121, 0x07615113,
+ 0x32147122, 0x08a19181, 0xc1b14223, 0xf0d15215,
+ 0x72623324, 0x160a0982, 0x1a191817, 0x28272625,
+ 0x35342a29, 0x39383736, 0x4544433a, 0x49484746,
+ 0x5554534a, 0x59585756, 0x6564635a, 0x69686766,
+ 0x7574736a, 0x79787776, 0x8584837a, 0x89888786,
+ 0x9493928a, 0x98979695, 0xa3a29a99, 0xa7a6a5a4,
+ 0xb2aaa9a8, 0xb6b5b4b3, 0xbab9b8b7, 0xc5c4c3c2,
+ 0xc9c8c7c6, 0xd4d3d2ca, 0xd8d7d6d5, 0xe2e1dad9,
+ 0xe6e5e4e3, 0xeae9e8e7, 0xf4f3f2f1, 0xf8f7f6f5,
+ 0x0000faf9
+};
+
+static u32 ITU_H_tbl_len_AC_chrominance[4] = {
+ 0x02010200, 0x04030404, 0x04040507, 0x77020100
+};
+static u32 ITU_H_tbl_val_AC_chrominance[41] = {
+ 0x03020100, 0x21050411, 0x41120631, 0x71610751,
+ 0x81322213, 0x91421408, 0x09c1b1a1, 0xf0523323,
+ 0xd1726215, 0x3424160a, 0x17f125e1, 0x261a1918,
+ 0x2a292827, 0x38373635, 0x44433a39, 0x48474645,
+ 0x54534a49, 0x58575655, 0x64635a59, 0x68676665,
+ 0x74736a69, 0x78777675, 0x83827a79, 0x87868584,
+ 0x928a8988, 0x96959493, 0x9a999897, 0xa5a4a3a2,
+ 0xa9a8a7a6, 0xb4b3b2aa, 0xb8b7b6b5, 0xc3c2bab9,
+ 0xc7c6c5c4, 0xd2cac9c8, 0xd6d5d4d3, 0xdad9d8d7,
+ 0xe5e4e3e2, 0xe9e8e7e6, 0xf4f3f2ea, 0xf8f7f6f5,
+ 0x0000faf9
+};
+#endif /* __JPEG_CONF_H__ */
diff --git a/drivers/media/video/exynos/jpeg/jpeg_core.h b/drivers/media/video/exynos/jpeg/jpeg_core.h
new file mode 100644
index 0000000..4944ab6
--- /dev/null
+++ b/drivers/media/video/exynos/jpeg/jpeg_core.h
@@ -0,0 +1,274 @@
+/* linux/drivers/media/video/samsung/jpeg_v2x/jpeg_core.h
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Definition for core file of the jpeg operation.
+ *
+ * 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.
+*/
+
+#ifndef __JPEG_CORE_H__
+#define __JPEG_CORE_H__
+
+#include <linux/mutex.h>
+#include <linux/types.h>
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/sched.h>
+
+#include <linux/videodev2.h>
+#include <linux/videodev2_exynos_media.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/v4l2-mediabus.h>
+#include <media/v4l2-ioctl.h>
+
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-ion.h>
+#include "jpeg_mem.h"
+
+#define INT_TIMEOUT 1000
+
+#define JPEG_NUM_INST 4
+#define JPEG_MAX_PLANE 3
+
+enum jpeg_state {
+ JPEG_IDLE,
+ JPEG_SRC_ADDR,
+ JPEG_DST_ADDR,
+ JPEG_ISR,
+ JPEG_STREAM,
+};
+
+enum jpeg_mode {
+ ENCODING,
+ DECODING,
+};
+
+enum jpeg_result {
+ OK_ENC_OR_DEC,
+ ERR_PROT,
+ ERR_DEC_INVALID_FORMAT,
+ ERR_MULTI_SCAN,
+ ERR_FRAME,
+ ERR_TIME_OUT,
+ ERR_UNKNOWN,
+};
+
+enum jpeg_img_quality_level {
+ QUALITY_LEVEL_1 = 0, /* high */
+ QUALITY_LEVEL_2,
+ QUALITY_LEVEL_3,
+ QUALITY_LEVEL_4, /* low */
+};
+
+/* raw data image format */
+enum jpeg_frame_format {
+ YCRCB_444_2P,
+ YCBCR_444_2P,
+ YCBCR_444_3P,
+ YCBYCR_422_1P,
+ YCRYCB_422_1P,
+ CBYCRY_422_1P,
+ CRYCBY_422_1P,
+ YCBCR_422_2P,
+ YCRCB_422_2P,
+ YCBYCR_422_3P,
+ YCBCR_420_3P,
+ YCRCB_420_3P,
+ YCBCR_420_2P,
+ YCRCB_420_2P,
+ YCBCR_420_2P_M,
+ YCRCB_420_2P_M,
+ RGB_565,
+ RGB_888,
+ BGR_888,
+ GRAY,
+};
+
+/* jpeg data format */
+enum jpeg_stream_format {
+ JPEG_422, /* decode input, encode output */
+ JPEG_420, /* decode input, encode output */
+ JPEG_444, /* decode input*/
+ JPEG_GRAY, /* decode input*/
+ JPEG_RESERVED,
+};
+
+enum jpeg_scale_value {
+ JPEG_SCALE_NORMAL,
+ JPEG_SCALE_2,
+ JPEG_SCALE_4,
+};
+
+enum jpeg_interface {
+ M2M_OUTPUT,
+ M2M_CAPTURE,
+};
+
+enum jpeg_node_type {
+ JPEG_NODE_INVALID = -1,
+ JPEG_NODE_DECODER = 11,
+ JPEG_NODE_ENCODER = 12,
+};
+
+struct jpeg_fmt {
+ char *name;
+ unsigned int fourcc;
+ int depth[JPEG_MAX_PLANE];
+ int color;
+ int memplanes;
+ int colplanes;
+ enum jpeg_interface types;
+};
+
+struct jpeg_dec_param {
+ unsigned int in_width;
+ unsigned int in_height;
+ unsigned int out_width;
+ unsigned int out_height;
+ unsigned int size;
+ unsigned int mem_size;
+ unsigned int in_plane;
+ unsigned int out_plane;
+ unsigned int in_depth;
+ unsigned int out_depth[JPEG_MAX_PLANE];
+
+ enum jpeg_stream_format in_fmt;
+ enum jpeg_frame_format out_fmt;
+};
+
+struct jpeg_enc_param {
+ unsigned int in_width;
+ unsigned int in_height;
+ unsigned int out_width;
+ unsigned int out_height;
+ unsigned int size;
+ unsigned int in_plane;
+ unsigned int out_plane;
+ unsigned int in_depth[JPEG_MAX_PLANE];
+ unsigned int out_depth;
+
+ enum jpeg_frame_format in_fmt;
+ enum jpeg_stream_format out_fmt;
+ enum jpeg_img_quality_level quality;
+};
+
+struct jpeg_ctx {
+ spinlock_t slock;
+ struct jpeg_dev *dev;
+ struct v4l2_m2m_ctx *m2m_ctx;
+
+ union {
+ struct jpeg_dec_param dec_param;
+ struct jpeg_enc_param enc_param;
+ } param;
+
+ int index;
+ unsigned long payload[VIDEO_MAX_PLANES];
+ bool input_cacheable;
+ bool output_cacheable;
+};
+
+struct jpeg_vb2 {
+ const struct vb2_mem_ops *ops;
+ void *(*init)(struct jpeg_dev *dev);
+ void (*cleanup)(void *alloc_ctx);
+
+ unsigned long (*plane_addr)(struct vb2_buffer *vb, u32 plane_no);
+
+ int (*resume)(void *alloc_ctx);
+ void (*suspend)(void *alloc_ctx);
+
+ int (*cache_flush)(struct vb2_buffer *vb, u32 num_planes);
+ void (*set_cacheable)(void *alloc_ctx, bool cacheable);
+};
+
+struct jpeg_dev {
+ spinlock_t slock;
+ struct v4l2_device v4l2_dev;
+ struct video_device *vfd_enc;
+ struct video_device *vfd_dec;
+ struct v4l2_m2m_dev *m2m_dev_enc;
+ struct v4l2_m2m_dev *m2m_dev_dec;
+ struct jpeg_ctx *ctx;
+ struct vb2_alloc_ctx *alloc_ctx;
+
+ struct platform_device *plat_dev;
+
+ struct clk *clk;
+
+ struct mutex lock;
+
+ int irq_no;
+ enum jpeg_result irq_ret;
+ wait_queue_head_t wq;
+ void __iomem *reg_base; /* register i/o */
+ enum jpeg_mode mode;
+ const struct jpeg_vb2 *vb2;
+
+ unsigned long hw_run;
+ atomic_t watchdog_cnt;
+ struct timer_list watchdog_timer;
+ struct workqueue_struct *watchdog_workqueue;
+ struct work_struct watchdog_work;
+ struct device *bus_dev;
+};
+
+enum jpeg_log {
+ JPEG_LOG_DEBUG = 0x1000,
+ JPEG_LOG_INFO = 0x0100,
+ JPEG_LOG_WARN = 0x0010,
+ JPEG_LOG_ERR = 0x0001,
+};
+
+/* debug macro */
+#define JPEG_LOG_DEFAULT (JPEG_LOG_WARN | JPEG_LOG_ERR)
+
+#define JPEG_DEBUG(fmt, ...) \
+ do { \
+ if (JPEG_LOG_DEFAULT & JPEG_LOG_DEBUG) \
+ printk(KERN_DEBUG "%s: " \
+ fmt, __func__, ##__VA_ARGS__); \
+ } while (0)
+
+#define JPEG_INFO(fmt, ...) \
+ do { \
+ if (JPEG_LOG_DEFAULT & JPEG_LOG_INFO) \
+ printk(KERN_INFO "%s: " \
+ fmt, __func__, ##__VA_ARGS__); \
+ } while (0)
+
+#define JPEG_WARN(fmt, ...) \
+ do { \
+ if (JPEG_LOG_DEFAULT & JPEG_LOG_WARN) \
+ printk(KERN_WARNING "%s: " \
+ fmt, __func__, ##__VA_ARGS__); \
+ } while (0)
+
+
+#define JPEG_ERROR(fmt, ...) \
+ do { \
+ if (JPEG_LOG_DEFAULT & JPEG_LOG_ERR) \
+ printk(KERN_ERR "%s: " \
+ fmt, __func__, ##__VA_ARGS__); \
+ } while (0)
+
+
+#define jpeg_dbg(fmt, ...) JPEG_DEBUG(fmt, ##__VA_ARGS__)
+#define jpeg_info(fmt, ...) JPEG_INFO(fmt, ##__VA_ARGS__)
+#define jpeg_warn(fmt, ...) JPEG_WARN(fmt, ##__VA_ARGS__)
+#define jpeg_err(fmt, ...) JPEG_ERROR(fmt, ##__VA_ARGS__)
+
+/*=====================================================================*/
+const struct v4l2_ioctl_ops *get_jpeg_dec_v4l2_ioctl_ops(void);
+const struct v4l2_ioctl_ops *get_jpeg_enc_v4l2_ioctl_ops(void);
+
+int jpeg_int_pending(struct jpeg_dev *ctrl);
+
+#endif /*__JPEG_CORE_H__*/
+
diff --git a/drivers/media/video/exynos/jpeg/jpeg_dec.c b/drivers/media/video/exynos/jpeg/jpeg_dec.c
new file mode 100644
index 0000000..8035644
--- /dev/null
+++ b/drivers/media/video/exynos/jpeg/jpeg_dec.c
@@ -0,0 +1,553 @@
+/* linux/drivers/media/video/exynos/jpeg/jpeg_dec.c
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Core file for Samsung Jpeg v2.x Interface driver
+ *
+ * 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.
+*/
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/miscdevice.h>
+#include <linux/platform_device.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/signal.h>
+#include <linux/ioport.h>
+#include <linux/kmod.h>
+#include <linux/vmalloc.h>
+#include <linux/time.h>
+#include <linux/clk.h>
+#include <linux/semaphore.h>
+#include <linux/vmalloc.h>
+#include <linux/workqueue.h>
+
+#include <asm/page.h>
+
+#include <mach/irqs.h>
+
+#include <media/v4l2-ioctl.h>
+
+#include "jpeg_core.h"
+#include "jpeg_dev.h"
+
+#include "jpeg_mem.h"
+#include "jpeg_regs.h"
+#include "regs_jpeg_v2_x.h"
+
+static struct jpeg_fmt formats[] = {
+ {
+ .name = "JPEG compressed format",
+ .fourcc = V4L2_PIX_FMT_JPEG_444,
+ .depth = {8},
+ .color = JPEG_444,
+ .memplanes = 1,
+ .types = M2M_OUTPUT,
+ }, {
+ .name = "JPEG compressed format",
+ .fourcc = V4L2_PIX_FMT_JPEG_422,
+ .depth = {8},
+ .color = JPEG_422,
+ .memplanes = 1,
+ .types = M2M_OUTPUT,
+ }, {
+ .name = "JPEG compressed format",
+ .fourcc = V4L2_PIX_FMT_JPEG_420,
+ .depth = {8},
+ .color = JPEG_420,
+ .memplanes = 1,
+ .types = M2M_OUTPUT,
+ }, {
+ .name = "JPEG compressed format",
+ .fourcc = V4L2_PIX_FMT_JPEG_GRAY,
+ .depth = {8},
+ .color = JPEG_GRAY,
+ .memplanes = 1,
+ .types = M2M_OUTPUT,
+ }, {
+ .name = "RGB565",
+ .fourcc = V4L2_PIX_FMT_RGB565X,
+ .depth = {16},
+ .color = RGB_565,
+ .memplanes = 1,
+ .types = M2M_CAPTURE,
+ }, {
+ .name = "XRGB-8-8-8-8, 32 bpp",
+ .fourcc = V4L2_PIX_FMT_RGB32,
+ .depth = {32},
+ .color = RGB_888,
+ .memplanes = 1,
+ .types = M2M_CAPTURE,
+ }, {
+ .name = "YUV 4:4:4 packed, Y/CbCr",
+ .fourcc = V4L2_PIX_FMT_YUV444_2P,
+ .depth = {24},
+ .color = YCBCR_444_2P,
+ .memplanes = 1,
+ .types = M2M_CAPTURE,
+ }, {
+ .name = "YUV 4:4:4 packed, Y/CrCb",
+ .fourcc = V4L2_PIX_FMT_YVU444_2P,
+ .depth = {24},
+ .color = YCRCB_444_2P,
+ .memplanes = 1,
+ .types = M2M_CAPTURE,
+ }, {
+ .name = "YUV 4:4:4 packed, Y/Cb/Cr",
+ .fourcc = V4L2_PIX_FMT_YUV444_3P,
+ .depth = {24},
+ .color = YCBCR_444_3P,
+ .memplanes = 1,
+ .types = M2M_CAPTURE,
+ }, {
+ .name = "YUV 4:2:2 packed, YCrYCb",
+ .fourcc = V4L2_PIX_FMT_YVYU,
+ .depth = {16},
+ .color = YCRYCB_422_1P,
+ .memplanes = 1,
+ .types = M2M_CAPTURE,
+ }, {
+ .name = "YUV 4:2:2 packed, CrYCbY",
+ .fourcc = V4L2_PIX_FMT_VYUY,
+ .depth = {16},
+ .color = CRYCBY_422_1P,
+ .memplanes = 1,
+ .types = M2M_CAPTURE,
+ }, {
+ .name = "YUV 4:2:2 packed, CbYCrY",
+ .fourcc = V4L2_PIX_FMT_UYVY,
+ .depth = {16},
+ .color = CBYCRY_422_1P,
+ .memplanes = 1,
+ .types = M2M_CAPTURE,
+ }, {
+ .name = "YUV 4:2:2 packed, YCbYCr",
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .depth = {16},
+ .color = YCBYCR_422_1P,
+ .memplanes = 1,
+ .types = M2M_CAPTURE,
+ }, {
+ .name = "YUV 4:2:2 planar, Y/CrCb",
+ .fourcc = V4L2_PIX_FMT_NV61,
+ .depth = {16},
+ .color = YCRCB_422_2P,
+ .memplanes = 1,
+ .types = M2M_CAPTURE,
+ }, {
+ .name = "YUV 4:2:2 planar, Y/CbCr",
+ .fourcc = V4L2_PIX_FMT_NV16,
+ .depth = {16},
+ .color = YCBCR_422_2P,
+ .memplanes = 1,
+ .types = M2M_CAPTURE,
+ }, {
+ .name = "YUV 4:2:0 planar, Y/CbCr",
+ .fourcc = V4L2_PIX_FMT_NV12,
+ .depth = {12},
+ .color = YCBCR_420_2P,
+ .memplanes = 1,
+ .types = M2M_CAPTURE,
+ }, {
+ .name = "YUV 4:2:0 planar, Y/CrCb",
+ .fourcc = V4L2_PIX_FMT_NV21,
+ .depth = {12},
+ .color = YCRCB_420_2P,
+ .memplanes = 1,
+ .types = M2M_CAPTURE,
+ }, {
+ .name = "YUV 4:2:0 contiguous 3-planar, Y/Cb/Cr",
+ .fourcc = V4L2_PIX_FMT_YUV420,
+ .depth = {12},
+ .color = YCBCR_420_3P,
+ .memplanes = 1,
+ .types = M2M_CAPTURE,
+ }, {
+ .name = "YUV 4:2:0 contiguous 3-planar, Y/Cr/Cb",
+ .fourcc = V4L2_PIX_FMT_YVU420,
+ .depth = {12},
+ .color = YCRCB_420_3P,
+ .memplanes = 1,
+ .types = M2M_CAPTURE,
+ }, {
+ .name = "Gray",
+ .fourcc = V4L2_PIX_FMT_GREY,
+ .depth = {8},
+ .color = GRAY,
+ .memplanes = 1,
+ .types = M2M_CAPTURE,
+ }, {
+ .name = "YUV 4:2:2 packed, CrYCbY",
+ .fourcc = V4L2_PIX_FMT_VYUY,
+ .depth = {16},
+ .color = CRYCBY_422_1P,
+ .memplanes = 1,
+ .types = M2M_CAPTURE,
+ }, {
+ .name = "YUV 4:2:2 packed, CbYCrY",
+ .fourcc = V4L2_PIX_FMT_UYVY,
+ .depth = {16},
+ .color = CRYCBY_422_1P,
+ .memplanes = 1,
+ .types = M2M_CAPTURE,
+ }, {
+ .name = "XBGR-8-8-8-8, 32 bpp",
+ .fourcc = V4L2_PIX_FMT_BGR32,
+ .depth = {32},
+ .color = BGR_888,
+ .memplanes = 1,
+ .types = M2M_CAPTURE,
+ },
+};
+
+static struct jpeg_fmt *find_format(struct v4l2_format *f)
+{
+ struct jpeg_fmt *fmt;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(formats); ++i) {
+ fmt = &formats[i];
+ if (fmt->fourcc == f->fmt.pix_mp.pixelformat)
+ break;
+ }
+
+ return (i == ARRAY_SIZE(formats)) ? NULL : fmt;
+}
+
+static int jpeg_dec_vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct jpeg_ctx *ctx = file->private_data;
+ struct jpeg_dev *dev = ctx->dev;
+
+ strncpy(cap->driver, dev->plat_dev->name, sizeof(cap->driver) - 1);
+ strncpy(cap->card, dev->plat_dev->name, sizeof(cap->card) - 1);
+ cap->bus_info[0] = 0;
+ cap->version = KERNEL_VERSION(1, 0, 0);
+ cap->capabilities = V4L2_CAP_STREAMING |
+ V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT |
+ V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE;
+ return 0;
+}
+
+int jpeg_dec_vidioc_enum_fmt(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ struct jpeg_fmt *fmt;
+
+ if (f->index >= ARRAY_SIZE(formats))
+ return -EINVAL;
+
+ fmt = &formats[f->index];
+ strncpy(f->description, fmt->name, sizeof(f->description) - 1);
+ f->pixelformat = fmt->color;
+
+ return 0;
+}
+
+int jpeg_dec_vidioc_g_fmt(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct jpeg_ctx *ctx = priv;
+ struct v4l2_pix_format_mplane *pixm;
+ struct jpeg_dec_param *dec_param = &ctx->param.dec_param;
+ unsigned int width, height;
+
+ pixm = &f->fmt.pix_mp;
+
+ pixm->field = V4L2_FIELD_NONE;
+
+ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ pixm->pixelformat = dec_param->in_fmt;
+ pixm->num_planes = dec_param->in_plane;
+ pixm->width = dec_param->in_width;
+ pixm->height = dec_param->in_height;
+ } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ jpeg_get_frame_size(ctx->dev->reg_base, &width, &height);
+ pixm->pixelformat =
+ dec_param->out_fmt;
+ pixm->num_planes = dec_param->out_plane;
+ pixm->width = width;
+ pixm->height = height;
+ } else {
+ v4l2_err(&ctx->dev->v4l2_dev,
+ "Wrong buffer/video queue type (%d)\n", f->type);
+ }
+
+ return 0;
+}
+
+static int jpeg_dec_vidioc_try_fmt(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct jpeg_fmt *fmt;
+ struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
+ struct jpeg_ctx *ctx = priv;
+ int i;
+
+ if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE &&
+ f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ return -EINVAL;
+
+ fmt = find_format(f);
+
+ if (!fmt) {
+ v4l2_err(&ctx->dev->v4l2_dev,
+ "Fourcc format (0x%08x) invalid.\n",
+ f->fmt.pix.pixelformat);
+ return -EINVAL;
+ }
+
+ if (pix->field == V4L2_FIELD_ANY)
+ pix->field = V4L2_FIELD_NONE;
+ else if (V4L2_FIELD_NONE != pix->field)
+ return -EINVAL;
+
+ pix->num_planes = fmt->memplanes;
+
+ for (i = 0; i < pix->num_planes; ++i) {
+ int bpl = pix->plane_fmt[i].bytesperline;
+
+ jpeg_dbg("[%d] bpl: %d, depth: %d, w: %d, h: %d",
+ i, bpl, fmt->depth[i], pix->width, pix->height);
+ if (!bpl || (bpl * 8 / fmt->depth[i]) > pix->width)
+ bpl = (pix->width * fmt->depth[i]) >> 3;
+
+ if (!pix->plane_fmt[i].sizeimage)
+ pix->plane_fmt[i].sizeimage = pix->height * bpl;
+
+ pix->plane_fmt[i].bytesperline = bpl;
+
+ jpeg_dbg("[%d]: bpl: %d, sizeimage: %d",
+ i, pix->plane_fmt[i].bytesperline,
+ pix->plane_fmt[i].sizeimage);
+ }
+
+ if (f->fmt.pix.height > MAX_JPEG_HEIGHT)
+ f->fmt.pix.height = MAX_JPEG_HEIGHT;
+
+ if (f->fmt.pix.width > MAX_JPEG_WIDTH)
+ f->fmt.pix.width = MAX_JPEG_WIDTH;
+
+ return 0;
+}
+
+static int jpeg_dec_vidioc_s_fmt_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct jpeg_ctx *ctx = priv;
+ struct vb2_queue *vq;
+ struct v4l2_pix_format_mplane *pix;
+ struct jpeg_fmt *fmt;
+ int ret;
+ int i;
+
+ ret = jpeg_dec_vidioc_try_fmt(file, priv, f);
+ if (ret)
+ return ret;
+
+ vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+ if (!vq)
+ return -EINVAL;
+
+ if (vb2_is_busy(vq)) {
+ v4l2_err(&ctx->dev->v4l2_dev, "queue (%d) busy\n", f->type);
+ return -EBUSY;
+ }
+
+ /* TODO: width & height has to be multiple of two */
+ pix = &f->fmt.pix_mp;
+ fmt = find_format(f);
+
+ for (i = 0; i < fmt->memplanes; i++) {
+ ctx->payload[i] =
+ pix->plane_fmt[i].bytesperline * pix->height;
+ ctx->param.dec_param.out_depth[i] = fmt->depth[i];
+ }
+ ctx->param.dec_param.out_width = pix->width;
+ ctx->param.dec_param.out_height = pix->height;
+ ctx->param.dec_param.out_plane = fmt->memplanes;
+ ctx->param.dec_param.out_fmt = fmt->color;
+
+ return 0;
+}
+
+static int jpeg_dec_vidioc_s_fmt_out(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct jpeg_ctx *ctx = priv;
+ struct vb2_queue *vq;
+ struct v4l2_pix_format_mplane *pix;
+ struct jpeg_fmt *fmt;
+ int ret;
+ int i;
+
+ ret = jpeg_dec_vidioc_try_fmt(file, priv, f);
+ if (ret)
+ return ret;
+
+ vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+ if (!vq)
+ return -EINVAL;
+
+ if (vb2_is_busy(vq)) {
+ v4l2_err(&ctx->dev->v4l2_dev, "queue (%d) busy\n", f->type);
+ return -EBUSY;
+ }
+
+ /* TODO: width & height has to be multiple of two */
+ pix = &f->fmt.pix_mp;
+ fmt = find_format(f);
+
+ for (i = 0; i < fmt->memplanes; i++)
+ ctx->payload[i] =
+ pix->plane_fmt[i].bytesperline * pix->height;
+
+ ctx->param.dec_param.in_width = pix->width;
+ ctx->param.dec_param.in_height = pix->height;
+ ctx->param.dec_param.in_plane = fmt->memplanes;
+ ctx->param.dec_param.in_depth = fmt->depth[0];
+ ctx->param.dec_param.in_fmt = fmt->color;
+ if((pix->plane_fmt[0].sizeimage % 32) == 0)
+ ctx->param.dec_param.size = (pix->plane_fmt[0].sizeimage / 32);
+ else
+ ctx->param.dec_param.size = (pix->plane_fmt[0].sizeimage / 32) + 1;
+ ctx->param.dec_param.mem_size = pix->plane_fmt[0].sizeimage;
+
+ return 0;
+}
+
+static int jpeg_dec_m2m_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *reqbufs)
+{
+ struct jpeg_ctx *ctx = priv;
+ struct vb2_queue *vq;
+
+ vq = v4l2_m2m_get_vq(ctx->m2m_ctx, reqbufs->type);
+ if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ ctx->dev->vb2->set_cacheable(ctx->dev->alloc_ctx, ctx->input_cacheable);
+ else if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ ctx->dev->vb2->set_cacheable(ctx->dev->alloc_ctx, ctx->output_cacheable);
+
+ return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
+}
+
+static int jpeg_dec_m2m_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct jpeg_ctx *ctx = priv;
+ return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
+}
+
+static int jpeg_dec_m2m_qbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct jpeg_ctx *ctx = priv;
+ return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int jpeg_dec_m2m_dqbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct jpeg_ctx *ctx = priv;
+ return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int jpeg_dec_m2m_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct jpeg_ctx *ctx = priv;
+ return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
+}
+
+static int jpeg_dec_m2m_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct jpeg_ctx *ctx = priv;
+ return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
+}
+
+static int vidioc_dec_s_jpegcomp(struct file *file, void *priv,
+ struct v4l2_jpegcompression *jpegcomp)
+{
+ struct jpeg_ctx *ctx = priv;
+ ctx->param.enc_param.quality = jpegcomp->quality;
+ return 0;
+}
+
+static int jpeg_dec_vidioc_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct jpeg_ctx *ctx = priv;
+/*
+* 0 : input/output noncacheable
+* 1 : input/output cacheable
+* 2 : input cacheable / output noncacheable
+* 3 : input noncacheable / output cacheable
+*/
+ switch (ctrl->id) {
+ case V4L2_CID_CACHEABLE:
+ if (ctrl->value == 0) {
+ ctx->input_cacheable = 0;
+ ctx->output_cacheable = 0;
+ } else if (ctrl->value == 1) {
+ ctx->input_cacheable = 1;
+ ctx->output_cacheable = 1;
+ } else if (ctrl->value == 2) {
+ ctx->input_cacheable = 1;
+ ctx->output_cacheable = 0;
+ } else if (ctrl->value == 3) {
+ ctx->input_cacheable = 0;
+ ctx->output_cacheable = 1;
+ } else {
+ ctx->input_cacheable = 0;
+ ctx->output_cacheable = 0;
+ }
+ break;
+ default:
+ v4l2_err(&ctx->dev->v4l2_dev, "Invalid control\n");
+ break;
+ }
+
+ return 0;
+}
+
+static const struct v4l2_ioctl_ops jpeg_dec_ioctl_ops = {
+ .vidioc_querycap = jpeg_dec_vidioc_querycap,
+
+ .vidioc_enum_fmt_vid_cap_mplane = jpeg_dec_vidioc_enum_fmt,
+ .vidioc_enum_fmt_vid_out_mplane = jpeg_dec_vidioc_enum_fmt,
+
+ .vidioc_g_fmt_vid_cap_mplane = jpeg_dec_vidioc_g_fmt,
+ .vidioc_g_fmt_vid_out_mplane = jpeg_dec_vidioc_g_fmt,
+
+ .vidioc_try_fmt_vid_cap_mplane = jpeg_dec_vidioc_try_fmt,
+ .vidioc_try_fmt_vid_out_mplane = jpeg_dec_vidioc_try_fmt,
+ .vidioc_s_fmt_vid_cap_mplane = jpeg_dec_vidioc_s_fmt_cap,
+ .vidioc_s_fmt_vid_out_mplane = jpeg_dec_vidioc_s_fmt_out,
+
+ .vidioc_reqbufs = jpeg_dec_m2m_reqbufs,
+ .vidioc_querybuf = jpeg_dec_m2m_querybuf,
+ .vidioc_qbuf = jpeg_dec_m2m_qbuf,
+ .vidioc_dqbuf = jpeg_dec_m2m_dqbuf,
+ .vidioc_streamon = jpeg_dec_m2m_streamon,
+ .vidioc_streamoff = jpeg_dec_m2m_streamoff,
+ .vidioc_s_jpegcomp = vidioc_dec_s_jpegcomp,
+ .vidioc_s_ctrl = jpeg_dec_vidioc_s_ctrl,
+};
+const struct v4l2_ioctl_ops *get_jpeg_dec_v4l2_ioctl_ops(void)
+{
+ return &jpeg_dec_ioctl_ops;
+}
diff --git a/drivers/media/video/exynos/jpeg/jpeg_dev.c b/drivers/media/video/exynos/jpeg/jpeg_dev.c
new file mode 100644
index 0000000..a03d9ea
--- /dev/null
+++ b/drivers/media/video/exynos/jpeg/jpeg_dev.c
@@ -0,0 +1,1056 @@
+/* linux/drivers/media/video/exynos/jpeg/jpeg_dev.c
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Core file for Samsung Jpeg v2.x Interface driver
+ *
+ * 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.
+*/
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/miscdevice.h>
+#include <linux/platform_device.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/signal.h>
+#include <linux/ioport.h>
+#include <linux/kmod.h>
+#include <linux/vmalloc.h>
+#include <linux/time.h>
+#include <linux/clk.h>
+#include <linux/semaphore.h>
+#include <linux/vmalloc.h>
+#include <linux/workqueue.h>
+
+#include <asm/page.h>
+
+#include <mach/irqs.h>
+
+#ifdef CONFIG_PM_RUNTIME
+#include <linux/pm_runtime.h>
+#endif
+
+#include <media/v4l2-ioctl.h>
+
+#include "jpeg_core.h"
+#include "jpeg_dev.h"
+
+#include "jpeg_mem.h"
+#include "jpeg_regs.h"
+#include "regs_jpeg_v2_x.h"
+
+static int jpeg_dec_queue_setup(struct vb2_queue *vq,
+ const struct v4l2_format *fmt, unsigned int *num_buffers,
+ unsigned int *num_planes, unsigned int sizes[],
+ void *allocators[])
+{
+ struct jpeg_ctx *ctx = vb2_get_drv_priv(vq);
+
+ int i;
+
+ if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ *num_planes = ctx->param.dec_param.in_plane;
+ for (i = 0; i < ctx->param.dec_param.in_plane; i++) {
+ sizes[i] = ctx->param.dec_param.mem_size;
+ allocators[i] = ctx->dev->alloc_ctx;
+ }
+ } else if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ *num_planes = ctx->param.dec_param.out_plane;
+ for (i = 0; i < ctx->param.dec_param.out_plane; i++) {
+ sizes[i] = (ctx->param.dec_param.out_width *
+ ctx->param.dec_param.out_height *
+ ctx->param.dec_param.out_depth[i]) / 8;
+ allocators[i] = ctx->dev->alloc_ctx;
+ }
+ }
+
+ return 0;
+}
+
+static int jpeg_dec_buf_prepare(struct vb2_buffer *vb)
+{
+ int i;
+ int num_plane = 0;
+
+ struct jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+
+ if (vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ num_plane = ctx->param.dec_param.in_plane;
+ if (ctx->input_cacheable == 1)
+ ctx->dev->vb2->cache_flush(vb, num_plane);
+ } else if (vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ num_plane = ctx->param.dec_param.out_plane;
+ if (ctx->output_cacheable == 1)
+ ctx->dev->vb2->cache_flush(vb, num_plane);
+ }
+
+ for (i = 0; i < num_plane; i++)
+ vb2_set_plane_payload(vb, i, ctx->payload[i]);
+
+ return 0;
+}
+
+static void jpeg_dec_buf_queue(struct vb2_buffer *vb)
+{
+ struct jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+
+ if (ctx->m2m_ctx)
+ v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
+}
+
+static void jpeg_dec_lock(struct vb2_queue *vq)
+{
+ struct jpeg_ctx *ctx = vb2_get_drv_priv(vq);
+ mutex_lock(&ctx->dev->lock);
+}
+
+static void jpeg_dec_unlock(struct vb2_queue *vq)
+{
+ struct jpeg_ctx *ctx = vb2_get_drv_priv(vq);
+ mutex_unlock(&ctx->dev->lock);
+}
+
+static int jpeg_dec_stop_streaming(struct vb2_queue *q)
+{
+ struct jpeg_ctx *ctx = q->drv_priv;
+ struct jpeg_dev *dev = ctx->dev;
+
+ v4l2_m2m_get_next_job(dev->m2m_dev_dec, ctx->m2m_ctx);
+
+ return 0;
+}
+
+static int jpeg_enc_queue_setup(struct vb2_queue *vq,
+ const struct v4l2_format *fmt, unsigned int *num_buffers,
+ unsigned int *num_planes, unsigned int sizes[],
+ void *allocators[])
+{
+ struct jpeg_ctx *ctx = vb2_get_drv_priv(vq);
+
+ int i;
+ if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ *num_planes = ctx->param.enc_param.in_plane;
+ for (i = 0; i < ctx->param.enc_param.in_plane; i++) {
+ sizes[i] = (ctx->param.enc_param.in_width *
+ ctx->param.enc_param.in_height *
+ ctx->param.enc_param.in_depth[i]) / 8;
+ allocators[i] = ctx->dev->alloc_ctx;
+ }
+
+ } else if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ *num_planes = ctx->param.enc_param.out_plane;
+ for (i = 0; i < ctx->param.enc_param.in_plane; i++) {
+ sizes[i] = (ctx->param.enc_param.out_width *
+ ctx->param.enc_param.out_height *
+ ctx->param.enc_param.out_depth * 2) / 8;
+ allocators[i] = ctx->dev->alloc_ctx;
+ }
+ }
+
+ return 0;
+}
+
+static int jpeg_enc_buf_prepare(struct vb2_buffer *vb)
+{
+ int i;
+ int num_plane = 0;
+
+ struct jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+
+ if (vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ num_plane = ctx->param.enc_param.in_plane;
+ if (ctx->input_cacheable == 1)
+ ctx->dev->vb2->cache_flush(vb, num_plane);
+ } else if (vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ num_plane = ctx->param.enc_param.out_plane;
+ if (ctx->output_cacheable == 1)
+ ctx->dev->vb2->cache_flush(vb, num_plane);
+ }
+
+ for (i = 0; i < num_plane; i++)
+ vb2_set_plane_payload(vb, i, ctx->payload[i]);
+
+ return 0;
+}
+
+static void jpeg_enc_buf_queue(struct vb2_buffer *vb)
+{
+ struct jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+
+ if (ctx->m2m_ctx)
+ v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
+}
+
+static void jpeg_enc_lock(struct vb2_queue *vq)
+{
+ struct jpeg_ctx *ctx = vb2_get_drv_priv(vq);
+ mutex_lock(&ctx->dev->lock);
+}
+
+static void jpeg_enc_unlock(struct vb2_queue *vq)
+{
+ struct jpeg_ctx *ctx = vb2_get_drv_priv(vq);
+ mutex_unlock(&ctx->dev->lock);
+}
+
+static int jpeg_enc_stop_streaming(struct vb2_queue *q)
+{
+ struct jpeg_ctx *ctx = q->drv_priv;
+ struct jpeg_dev *dev = ctx->dev;
+
+ v4l2_m2m_get_next_job(dev->m2m_dev_enc, ctx->m2m_ctx);
+
+ return 0;
+}
+
+static struct vb2_ops jpeg_enc_vb2_qops = {
+ .queue_setup = jpeg_enc_queue_setup,
+ .buf_prepare = jpeg_enc_buf_prepare,
+ .buf_queue = jpeg_enc_buf_queue,
+ .wait_prepare = jpeg_enc_lock,
+ .wait_finish = jpeg_enc_unlock,
+ .stop_streaming = jpeg_enc_stop_streaming,
+};
+
+static struct vb2_ops jpeg_dec_vb2_qops = {
+ .queue_setup = jpeg_dec_queue_setup,
+ .buf_prepare = jpeg_dec_buf_prepare,
+ .buf_queue = jpeg_dec_buf_queue,
+ .wait_prepare = jpeg_dec_lock,
+ .wait_finish = jpeg_dec_unlock,
+ .stop_streaming = jpeg_dec_stop_streaming,
+};
+
+static inline enum jpeg_node_type jpeg_get_node_type(struct file *file)
+{
+ struct video_device *vdev = video_devdata(file);
+
+ if (!vdev) {
+ jpeg_err("failed to get video_device\n");
+ return JPEG_NODE_INVALID;
+ }
+
+ jpeg_dbg("video_device index: %d\n", vdev->num);
+
+ if (vdev->num == JPEG_NODE_DECODER)
+ return JPEG_NODE_DECODER;
+ else if (vdev->num == JPEG_NODE_ENCODER)
+ return JPEG_NODE_ENCODER;
+ else
+ return JPEG_NODE_INVALID;
+}
+
+static int queue_init_dec(void *priv, struct vb2_queue *src_vq,
+ struct vb2_queue *dst_vq)
+{
+ struct jpeg_ctx *ctx = priv;
+ int ret;
+
+ memset(src_vq, 0, sizeof(*src_vq));
+ src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
+ src_vq->drv_priv = ctx;
+ src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+ src_vq->ops = &jpeg_dec_vb2_qops;
+ src_vq->mem_ops = ctx->dev->vb2->ops;
+
+ ret = vb2_queue_init(src_vq);
+ if (ret)
+ return ret;
+
+ memset(dst_vq, 0, sizeof(*dst_vq));
+ dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
+ dst_vq->drv_priv = ctx;
+ dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+ dst_vq->ops = &jpeg_dec_vb2_qops;
+ dst_vq->mem_ops = ctx->dev->vb2->ops;
+
+ return vb2_queue_init(dst_vq);
+}
+
+static int queue_init_enc(void *priv, struct vb2_queue *src_vq,
+ struct vb2_queue *dst_vq)
+{
+ struct jpeg_ctx *ctx = priv;
+ int ret;
+
+ memset(src_vq, 0, sizeof(*src_vq));
+ src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
+ src_vq->drv_priv = ctx;
+ src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+ src_vq->ops = &jpeg_enc_vb2_qops;
+ src_vq->mem_ops = ctx->dev->vb2->ops;
+
+ ret = vb2_queue_init(src_vq);
+ if (ret)
+ return ret;
+
+ memset(dst_vq, 0, sizeof(*dst_vq));
+ dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
+ dst_vq->drv_priv = ctx;
+ dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+ dst_vq->ops = &jpeg_enc_vb2_qops;
+ dst_vq->mem_ops = ctx->dev->vb2->ops;
+
+ return vb2_queue_init(dst_vq);
+}
+static int jpeg_m2m_open(struct file *file)
+{
+ struct jpeg_dev *dev = video_drvdata(file);
+ struct jpeg_ctx *ctx = NULL;
+ int ret = 0;
+ enum jpeg_node_type node;
+
+ node = jpeg_get_node_type(file);
+
+ if (node == JPEG_NODE_INVALID) {
+ jpeg_err("cannot specify node type\n");
+ ret = -ENOENT;
+ goto err_node_type;
+ }
+
+ ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ file->private_data = ctx;
+ ctx->dev = dev;
+
+ spin_lock_init(&ctx->slock);
+
+ if (node == JPEG_NODE_DECODER)
+ ctx->m2m_ctx =
+ v4l2_m2m_ctx_init(dev->m2m_dev_dec, ctx,
+ queue_init_dec);
+ else
+ ctx->m2m_ctx =
+ v4l2_m2m_ctx_init(dev->m2m_dev_enc, ctx,
+ queue_init_enc);
+
+ if (IS_ERR(ctx->m2m_ctx)) {
+ int err = PTR_ERR(ctx->m2m_ctx);
+ kfree(ctx);
+ return err;
+ }
+
+ clk_enable(dev->clk);
+
+#ifdef CONFIG_PM_RUNTIME
+#if defined (CONFIG_CPU_EXYNOS5250)
+ dev->vb2->resume(dev->alloc_ctx);
+#ifdef CONFIG_BUSFREQ_OPP
+ /* lock bus frequency */
+ dev_lock(dev->bus_dev, &dev->plat_dev->dev, BUSFREQ_400MHZ);
+#endif
+#else
+ pm_runtime_get_sync(&dev->plat_dev->dev);
+#endif
+#else
+ dev->vb2->resume(dev->alloc_ctx);
+#ifdef CONFIG_BUSFREQ_OPP
+ /* lock bus frequency */
+ dev_lock(dev->bus_dev, &dev->plat_dev->dev, BUSFREQ_400MHZ);
+#endif
+#endif
+
+ return 0;
+
+err_node_type:
+ kfree(ctx);
+ return ret;
+}
+
+static int jpeg_m2m_release(struct file *file)
+{
+ struct jpeg_ctx *ctx = file->private_data;
+
+ v4l2_m2m_ctx_release(ctx->m2m_ctx);
+
+#ifdef CONFIG_PM_RUNTIME
+#if defined (CONFIG_CPU_EXYNOS5250)
+ ctx->dev->vb2->suspend(ctx->dev->alloc_ctx);
+#ifdef CONFIG_BUSFREQ_OPP
+ /* Unlock bus frequency */
+ dev_unlock(ctx->dev->bus_dev, &ctx->dev->plat_dev->dev);
+#endif
+#else
+ pm_runtime_put_sync(&ctx->dev->plat_dev->dev);
+#endif
+#else
+ ctx->dev->vb2->suspend(ctx->dev->alloc_ctx);
+#ifdef CONFIG_BUSFREQ_OPP
+ /* Unlock bus frequency */
+ dev_unlock(ctx->dev->bus_dev, &ctx->dev->plat_dev->dev);
+#endif
+#endif
+ clk_disable(ctx->dev->clk);
+ kfree(ctx);
+
+ return 0;
+}
+
+static unsigned int jpeg_m2m_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct jpeg_ctx *ctx = file->private_data;
+
+ return v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
+}
+
+
+static int jpeg_m2m_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct jpeg_ctx *ctx = file->private_data;
+
+ return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
+}
+
+static const struct v4l2_file_operations jpeg_fops = {
+ .owner = THIS_MODULE,
+ .open = jpeg_m2m_open,
+ .release = jpeg_m2m_release,
+ .poll = jpeg_m2m_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = jpeg_m2m_mmap,
+};
+
+static struct video_device jpeg_enc_videodev = {
+ .name = JPEG_ENC_NAME,
+ .fops = &jpeg_fops,
+ .minor = 12,
+ .release = video_device_release,
+};
+
+static struct video_device jpeg_dec_videodev = {
+ .name = JPEG_DEC_NAME,
+ .fops = &jpeg_fops,
+ .minor = 11,
+ .release = video_device_release,
+};
+
+static void jpeg_device_enc_run(void *priv)
+{
+ struct jpeg_ctx *ctx = priv;
+ struct jpeg_dev *dev = ctx->dev;
+ struct jpeg_enc_param enc_param;
+ struct vb2_buffer *vb = NULL;
+ unsigned long flags;
+
+ dev = ctx->dev;
+ spin_lock_irqsave(&ctx->slock, flags);
+
+ dev->mode = ENCODING;
+ enc_param = ctx->param.enc_param;
+
+ jpeg_sw_reset(dev->reg_base);
+ jpeg_set_interrupt(dev->reg_base);
+ jpeg_set_huf_table_enable(dev->reg_base, 1);
+ jpeg_set_enc_tbl(dev->reg_base, enc_param.quality);
+ jpeg_set_encode_tbl_select(dev->reg_base, enc_param.quality);
+ jpeg_set_stream_size(dev->reg_base,
+ enc_param.in_width, enc_param.in_height);
+ jpeg_set_enc_out_fmt(dev->reg_base, enc_param.out_fmt);
+ jpeg_set_enc_in_fmt(dev->reg_base, enc_param.in_fmt);
+ vb = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+ jpeg_set_stream_buf_address(dev->reg_base, dev->vb2->plane_addr(vb, 0));
+
+ vb = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
+ jpeg_set_frame_buf_address(dev->reg_base,
+ enc_param.in_fmt, dev->vb2->plane_addr(vb, 0), enc_param.in_width, enc_param.in_height);
+
+ jpeg_set_encode_hoff_cnt(dev->reg_base, enc_param.out_fmt);
+
+ jpeg_set_timer_count(dev->reg_base, enc_param.in_width * enc_param.in_height * 32 + 0xff);
+ jpeg_set_enc_dec_mode(dev->reg_base, ENCODING);
+
+ spin_unlock_irqrestore(&ctx->slock, flags);
+}
+
+static void jpeg_device_dec_run(void *priv)
+{
+ struct jpeg_ctx *ctx = priv;
+ struct jpeg_dev *dev = ctx->dev;
+ struct jpeg_dec_param dec_param;
+ struct vb2_buffer *vb = NULL;
+ unsigned long flags;
+
+ dev = ctx->dev;
+
+ spin_lock_irqsave(&ctx->slock, flags);
+
+ dev->mode = DECODING;
+ dec_param = ctx->param.dec_param;
+
+ jpeg_sw_reset(dev->reg_base);
+ jpeg_set_interrupt(dev->reg_base);
+
+ jpeg_set_encode_tbl_select(dev->reg_base, 0);
+
+ vb = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
+ jpeg_set_stream_buf_address(dev->reg_base, dev->vb2->plane_addr(vb, 0));
+
+ vb = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+ jpeg_set_frame_buf_address(dev->reg_base,
+ dec_param.out_fmt, dev->vb2->plane_addr(vb, 0), dec_param.in_width, dec_param.in_height);
+
+ if (dec_param.out_width > 0 && dec_param.out_height > 0) {
+ if ((dec_param.out_width * 2 == dec_param.in_width) &&
+ (dec_param.out_height * 2 == dec_param.in_height))
+ jpeg_set_dec_scaling(dev->reg_base, JPEG_SCALE_2, JPEG_SCALE_2);
+ else if ((dec_param.out_width * 4 == dec_param.in_width) &&
+ (dec_param.out_height * 4 == dec_param.in_height))
+ jpeg_set_dec_scaling(dev->reg_base, JPEG_SCALE_4, JPEG_SCALE_4);
+ else
+ jpeg_set_dec_scaling(dev->reg_base, JPEG_SCALE_NORMAL, JPEG_SCALE_NORMAL);
+ }
+
+ jpeg_set_dec_out_fmt(dev->reg_base, dec_param.out_fmt);
+ jpeg_set_dec_bitstream_size(dev->reg_base, dec_param.size);
+ jpeg_set_timer_count(dev->reg_base, dec_param.in_width * dec_param.in_height * 8 + 0xff);
+ jpeg_set_enc_dec_mode(dev->reg_base, DECODING);
+
+ spin_unlock_irqrestore(&ctx->slock, flags);
+}
+
+static void jpeg_job_enc_abort(void *priv)
+{
+ struct jpeg_ctx *ctx = priv;
+ struct jpeg_dev *dev = ctx->dev;
+ v4l2_m2m_get_next_job(dev->m2m_dev_enc, ctx->m2m_ctx);
+}
+
+static void jpeg_job_dec_abort(void *priv)
+{
+ struct jpeg_ctx *ctx = priv;
+ struct jpeg_dev *dev = ctx->dev;
+ v4l2_m2m_get_next_job(dev->m2m_dev_dec, ctx->m2m_ctx);
+}
+
+static struct v4l2_m2m_ops jpeg_m2m_enc_ops = {
+ .device_run = jpeg_device_enc_run,
+ .job_abort = jpeg_job_enc_abort,
+};
+
+static struct v4l2_m2m_ops jpeg_m2m_dec_ops = {
+ .device_run = jpeg_device_dec_run,
+ .job_abort = jpeg_job_dec_abort,
+};
+
+int jpeg_int_pending(struct jpeg_dev *ctrl)
+{
+ unsigned int int_status;
+
+ int_status = jpeg_get_int_status(ctrl->reg_base);
+ jpeg_dbg("state(%d)\n", int_status);
+
+ return int_status;
+}
+
+static irqreturn_t jpeg_irq(int irq, void *priv)
+{
+ unsigned int int_status;
+ struct vb2_buffer *src_vb, *dst_vb;
+ struct jpeg_dev *ctrl = priv;
+ struct jpeg_ctx *ctx;
+ unsigned long payload_size = 0;
+
+ jpeg_clean_interrupt(ctrl->reg_base);
+
+ if (ctrl->mode == ENCODING)
+ ctx = v4l2_m2m_get_curr_priv(ctrl->m2m_dev_enc);
+ else
+ ctx = v4l2_m2m_get_curr_priv(ctrl->m2m_dev_dec);
+
+ if (ctx == 0) {
+ printk(KERN_ERR "ctx is null.\n");
+ jpeg_sw_reset(ctrl->reg_base);
+ goto ctx_err;
+ }
+
+ spin_lock(&ctx->slock);
+
+ src_vb = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
+ dst_vb = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
+
+ int_status = jpeg_int_pending(ctrl);
+
+ if (int_status) {
+ switch (int_status & 0x1ff) {
+ case 0x1:
+ ctrl->irq_ret = ERR_PROT;
+ break;
+ case 0x2:
+ ctrl->irq_ret = OK_ENC_OR_DEC;
+ break;
+ case 0x4:
+ ctrl->irq_ret = ERR_DEC_INVALID_FORMAT;
+ break;
+ case 0x8:
+ ctrl->irq_ret = ERR_MULTI_SCAN;
+ break;
+ case 0x10:
+ ctrl->irq_ret = ERR_FRAME;
+ break;
+ case 0x20:
+ ctrl->irq_ret = ERR_TIME_OUT;
+ break;
+ default:
+ ctrl->irq_ret = ERR_UNKNOWN;
+ break;
+ }
+ } else {
+ ctrl->irq_ret = ERR_UNKNOWN;
+ }
+
+ if (ctrl->irq_ret == OK_ENC_OR_DEC) {
+ if (ctrl->mode == ENCODING) {
+ payload_size = jpeg_get_stream_size(ctrl->reg_base);
+ vb2_set_plane_payload(dst_vb, 0, payload_size);
+ }
+ v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
+ v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE);
+ } else {
+ v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_ERROR);
+ v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_ERROR);
+ }
+
+ if (ctrl->mode == ENCODING)
+ v4l2_m2m_job_finish(ctrl->m2m_dev_enc, ctx->m2m_ctx);
+ else
+ v4l2_m2m_job_finish(ctrl->m2m_dev_dec, ctx->m2m_ctx);
+
+ spin_unlock(&ctx->slock);
+ctx_err:
+ return IRQ_HANDLED;
+}
+
+static int jpeg_setup_controller(struct jpeg_dev *ctrl)
+{
+ mutex_init(&ctrl->lock);
+ init_waitqueue_head(&ctrl->wq);
+
+ return 0;
+}
+
+static int jpeg_probe(struct platform_device *pdev)
+{
+ struct jpeg_dev *dev;
+ struct video_device *vfd;
+ struct resource *res;
+ int ret;
+
+ /* global structure */
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev) {
+ dev_err(&pdev->dev, "%s: not enough memory\n",
+ __func__);
+ ret = -ENOMEM;
+ goto err_alloc;
+ }
+
+ dev->plat_dev = pdev;
+
+ /* setup jpeg control */
+ ret = jpeg_setup_controller(dev);
+ if (ret) {
+ jpeg_err("failed to setup controller\n");
+ goto err_setup;
+ }
+
+ /* memory region */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ jpeg_err("failed to get jpeg memory region resource\n");
+ ret = -ENOENT;
+ goto err_res;
+ }
+
+ res = request_mem_region(res->start, resource_size(res),
+ pdev->name);
+ if (!res) {
+ jpeg_err("failed to request jpeg io memory region\n");
+ ret = -ENOMEM;
+ goto err_region;
+ }
+
+ /* ioremap */
+ dev->reg_base = ioremap(res->start, resource_size(res));
+ if (!dev->reg_base) {
+ jpeg_err("failed to remap jpeg io region\n");
+ ret = -ENOENT;
+ goto err_map;
+ }
+
+ /* irq */
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res) {
+ jpeg_err("failed to request jpeg irq resource\n");
+ ret = -ENOENT;
+ goto err_irq;
+ }
+
+ dev->irq_no = res->start;
+ ret = request_irq(dev->irq_no, (void *)jpeg_irq,
+ IRQF_DISABLED, pdev->name, dev);
+ if (ret != 0) {
+ jpeg_err("failed to jpeg request irq\n");
+ ret = -ENOENT;
+ goto err_irq;
+ }
+
+ /* clock */
+ dev->clk = clk_get(&pdev->dev, "jpeg");
+ if (IS_ERR(dev->clk)) {
+ jpeg_err("failed to find jpeg clock source\n");
+ ret = -ENOENT;
+ goto err_clk;
+ }
+
+#ifdef CONFIG_PM_RUNTIME
+#ifndef CONFIG_CPU_EXYNOS5250
+ pm_runtime_enable(&pdev->dev);
+#endif
+#endif
+
+ /* clock enable */
+ clk_enable(dev->clk);
+
+ ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
+ if (ret) {
+ v4l2_err(&dev->v4l2_dev, "Failed to register v4l2 device\n");
+ goto err_v4l2;
+ }
+
+ /* encoder */
+ vfd = video_device_alloc();
+ if (!vfd) {
+ v4l2_err(&dev->v4l2_dev, "Failed to allocate video device\n");
+ ret = -ENOMEM;
+ goto err_vd_alloc_enc;
+ }
+
+ *vfd = jpeg_enc_videodev;
+ vfd->ioctl_ops = get_jpeg_enc_v4l2_ioctl_ops();
+ ret = video_register_device(vfd, VFL_TYPE_GRABBER, 12);
+ if (ret) {
+ v4l2_err(&dev->v4l2_dev,
+ "%s(): failed to register video device\n", __func__);
+ video_device_release(vfd);
+ goto err_vd_alloc_enc;
+ }
+ v4l2_info(&dev->v4l2_dev,
+ "JPEG driver is registered to /dev/video%d\n", vfd->num);
+
+ dev->vfd_enc = vfd;
+ dev->m2m_dev_enc = v4l2_m2m_init(&jpeg_m2m_enc_ops);
+ if (IS_ERR(dev->m2m_dev_enc)) {
+ v4l2_err(&dev->v4l2_dev,
+ "failed to initialize v4l2-m2m device\n");
+ ret = PTR_ERR(dev->m2m_dev_enc);
+ goto err_m2m_init_enc;
+ }
+ video_set_drvdata(vfd, dev);
+
+ /* decoder */
+ vfd = video_device_alloc();
+ if (!vfd) {
+ v4l2_err(&dev->v4l2_dev, "Failed to allocate video device\n");
+ ret = -ENOMEM;
+ goto err_vd_alloc_dec;
+ }
+
+ *vfd = jpeg_dec_videodev;
+ vfd->ioctl_ops = get_jpeg_dec_v4l2_ioctl_ops();
+ ret = video_register_device(vfd, VFL_TYPE_GRABBER, 11);
+ if (ret) {
+ v4l2_err(&dev->v4l2_dev,
+ "%s(): failed to register video device\n", __func__);
+ video_device_release(vfd);
+ goto err_vd_alloc_dec;
+ }
+ v4l2_info(&dev->v4l2_dev,
+ "JPEG driver is registered to /dev/video%d\n", vfd->num);
+
+ dev->vfd_dec = vfd;
+ dev->m2m_dev_dec = v4l2_m2m_init(&jpeg_m2m_dec_ops);
+ if (IS_ERR(dev->m2m_dev_dec)) {
+ v4l2_err(&dev->v4l2_dev,
+ "failed to initialize v4l2-m2m device\n");
+ ret = PTR_ERR(dev->m2m_dev_dec);
+ goto err_m2m_init_dec;
+ }
+ video_set_drvdata(vfd, dev);
+
+ platform_set_drvdata(pdev, dev);
+
+#ifdef CONFIG_VIDEOBUF2_CMA_PHYS
+ dev->vb2 = &jpeg_vb2_cma;
+#elif defined(CONFIG_VIDEOBUF2_ION)
+ dev->vb2 = &jpeg_vb2_ion;
+#endif
+ dev->alloc_ctx = dev->vb2->init(dev);
+
+ if (IS_ERR(dev->alloc_ctx)) {
+ ret = PTR_ERR(dev->alloc_ctx);
+ goto err_video_reg;
+ }
+
+#ifdef CONFIG_BUSFREQ_OPP
+ /* To lock bus frequency in OPP mode */
+ dev->bus_dev = dev_get("exynos-busfreq");
+#endif
+
+ /* clock disable */
+ clk_disable(dev->clk);
+
+ return 0;
+
+err_video_reg:
+ v4l2_m2m_release(dev->m2m_dev_dec);
+err_m2m_init_dec:
+ video_unregister_device(dev->vfd_dec);
+ video_device_release(dev->vfd_dec);
+err_vd_alloc_dec:
+ v4l2_m2m_release(dev->m2m_dev_enc);
+err_m2m_init_enc:
+ video_unregister_device(dev->vfd_enc);
+ video_device_release(dev->vfd_enc);
+err_vd_alloc_enc:
+ v4l2_device_unregister(&dev->v4l2_dev);
+err_v4l2:
+ clk_disable(dev->clk);
+ clk_put(dev->clk);
+err_clk:
+ free_irq(dev->irq_no, NULL);
+err_irq:
+ iounmap(dev->reg_base);
+err_map:
+err_region:
+ kfree(res);
+err_res:
+ mutex_destroy(&dev->lock);
+err_setup:
+ kfree(dev);
+err_alloc:
+ return ret;
+
+}
+
+static int jpeg_remove(struct platform_device *pdev)
+{
+ struct jpeg_dev *dev = platform_get_drvdata(pdev);
+
+ v4l2_m2m_release(dev->m2m_dev_enc);
+ video_unregister_device(dev->vfd_enc);
+
+ v4l2_m2m_release(dev->m2m_dev_dec);
+ video_unregister_device(dev->vfd_dec);
+
+ v4l2_device_unregister(&dev->v4l2_dev);
+
+ dev->vb2->cleanup(dev->alloc_ctx);
+
+ free_irq(dev->irq_no, pdev);
+ mutex_destroy(&dev->lock);
+ iounmap(dev->reg_base);
+
+ clk_put(dev->clk);
+#ifdef CONFIG_PM_RUNTIME
+#if defined (CONFIG_CPU_EXYNOS5250)
+#ifdef CONFIG_BUSFREQ_OPP
+ /* lock bus frequency */
+ dev_unlock(dev->bus_dev, &pdev->dev);
+#endif
+#else
+ pm_runtime_put_sync(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+#endif
+#else
+#ifdef CONFIG_BUSFREQ_OPP
+ /* lock bus frequency */
+ dev_unlock(dev->bus_dev, &pdev->dev);
+#endif
+#endif
+ kfree(dev);
+ return 0;
+}
+
+static int jpeg_suspend(struct platform_device *pdev, pm_message_t state)
+{
+#ifdef CONFIG_PM_RUNTIME
+#if defined (CONFIG_CPU_EXYNOS5250)
+ struct jpeg_dev *dev = platform_get_drvdata(pdev);
+
+ if (dev->ctx) {
+ dev->vb2->suspend(dev->alloc_ctx);
+ clk_disable(dev->clk);
+ }
+#ifdef CONFIG_BUSFREQ_OPP
+ /* lock bus frequency */
+ dev_unlock(dev->bus_dev, &pdev->dev);
+#endif
+#else
+ pm_runtime_put_sync(&pdev->dev);
+#endif
+#else
+ struct jpeg_dev *dev = platform_get_drvdata(pdev);
+
+ if (dev->ctx) {
+ dev->vb2->suspend(dev->alloc_ctx);
+ clk_disable(dev->clk);
+ }
+#ifdef CONFIG_BUSFREQ_OPP
+ /* lock bus frequency */
+ dev_unlock(dev->bus_dev, &pdev->dev);
+#endif
+#endif
+ return 0;
+}
+
+static int jpeg_resume(struct platform_device *pdev)
+{
+#ifdef CONFIG_PM_RUNTIME
+#if defined (CONFIG_CPU_EXYNOS5250)
+ struct jpeg_dev *dev = platform_get_drvdata(pdev);
+
+ if (dev->ctx) {
+ clk_enable(dev->clk);
+ dev->vb2->resume(dev->alloc_ctx);
+ }
+#else
+ pm_runtime_get_sync(&pdev->dev);
+#endif
+#else
+ struct jpeg_dev *dev = platform_get_drvdata(pdev);
+
+ if (dev->ctx) {
+ clk_enable(dev->clk);
+ dev->vb2->resume(dev->alloc_ctx);
+ }
+#endif
+ return 0;
+}
+
+int jpeg_suspend_pd(struct device *dev)
+{
+ struct platform_device *pdev;
+ int ret;
+ pm_message_t state;
+
+ state.event = 0;
+ pdev = to_platform_device(dev);
+ ret = jpeg_suspend(pdev, state);
+
+ return 0;
+}
+
+int jpeg_resume_pd(struct device *dev)
+{
+ struct platform_device *pdev;
+ int ret;
+
+ pdev = to_platform_device(dev);
+ ret = jpeg_resume(pdev);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_RUNTIME
+static int jpeg_runtime_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct jpeg_dev *jpeg_drv = platform_get_drvdata(pdev);
+#ifdef CONFIG_BUSFREQ_OPP
+ /* lock bus frequency */
+ dev_unlock(jpeg_drv->bus_dev, dev);
+#endif
+ jpeg_drv->vb2->suspend(jpeg_drv->alloc_ctx);
+ /* clock disable */
+ clk_disable(jpeg_drv->clk);
+ return 0;
+}
+
+static int jpeg_runtime_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct jpeg_dev *jpeg_drv = platform_get_drvdata(pdev);
+#ifdef CONFIG_BUSFREQ_OPP
+ /* lock bus frequency */
+ dev_lock(jpeg_drv->bus_dev, &jpeg_drv->plat_dev->dev, BUSFREQ_400MHZ);
+#endif
+ clk_enable(jpeg_drv->clk);
+ jpeg_drv->vb2->resume(jpeg_drv->alloc_ctx);
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops jpeg_pm_ops = {
+ .suspend = jpeg_suspend_pd,
+ .resume = jpeg_resume_pd,
+#ifdef CONFIG_PM_RUNTIME
+ .runtime_suspend = jpeg_runtime_suspend,
+ .runtime_resume = jpeg_runtime_resume,
+#endif
+};
+static struct platform_driver jpeg_driver = {
+ .probe = jpeg_probe,
+ .remove = jpeg_remove,
+#if defined (CONFIG_CPU_EXYNOS5250)
+ .suspend = jpeg_suspend,
+ .resume = jpeg_resume,
+#else
+#ifndef CONFIG_PM_RUNTIME
+ .suspend = jpeg_suspend,
+ .resume = jpeg_resume,
+#endif
+#endif
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = JPEG_NAME,
+#ifdef CONFIG_PM_RUNTIME
+#if defined (CONFIG_CPU_EXYNOS5250)
+ .pm = NULL,
+#else
+ .pm = &jpeg_pm_ops,
+#endif
+#else
+ .pm = NULL,
+#endif
+ },
+};
+
+static int __init jpeg_init(void)
+{
+ printk(KERN_CRIT "Initialize JPEG driver\n");
+
+ platform_driver_register(&jpeg_driver);
+
+ return 0;
+}
+
+static void __exit jpeg_exit(void)
+{
+ platform_driver_unregister(&jpeg_driver);
+}
+
+module_init(jpeg_init);
+module_exit(jpeg_exit);
+
+MODULE_AUTHOR("ym.song@samsung.com>");
+MODULE_DESCRIPTION("JPEG v2.x H/W Device Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/exynos/jpeg/jpeg_dev.h b/drivers/media/video/exynos/jpeg/jpeg_dev.h
new file mode 100644
index 0000000..197e085
--- /dev/null
+++ b/drivers/media/video/exynos/jpeg/jpeg_dev.h
@@ -0,0 +1,24 @@
+/* linux/drivers/media/video/exynos/jpeg/jpeg_dev.h
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Header file for Samsung Jpeg v2.x Interface driver
+ *
+ * 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.
+ */
+
+#ifndef __JPEG_DEV_H__
+#define __JPEG_DEV_H__
+
+#define JPEG_NAME "s5p-jpeg"
+#define JPEG_ENC_NAME "video12"
+#define JPEG_DEC_NAME "video11"
+
+#if defined(CONFIG_BUSFREQ_OPP)
+#define BUSFREQ_400MHZ 400266
+#endif
+
+#endif /*__JPEG_DEV_H__*/
diff --git a/drivers/media/video/exynos/jpeg/jpeg_enc.c b/drivers/media/video/exynos/jpeg/jpeg_enc.c
new file mode 100644
index 0000000..a6e7745
--- /dev/null
+++ b/drivers/media/video/exynos/jpeg/jpeg_enc.c
@@ -0,0 +1,566 @@
+/* linux/drivers/media/video/exynos/jpeg/jpeg_dev.c
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Core file for Samsung Jpeg v2.x Interface driver
+ *
+ * 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.
+*/
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/miscdevice.h>
+#include <linux/platform_device.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/signal.h>
+#include <linux/ioport.h>
+#include <linux/kmod.h>
+#include <linux/vmalloc.h>
+#include <linux/time.h>
+#include <linux/clk.h>
+#include <linux/semaphore.h>
+#include <linux/vmalloc.h>
+#include <linux/workqueue.h>
+
+#include <asm/page.h>
+
+#include <mach/irqs.h>
+
+#include <media/v4l2-ioctl.h>
+
+#include "jpeg_core.h"
+#include "jpeg_dev.h"
+
+#include "jpeg_mem.h"
+#include "jpeg_regs.h"
+#include "regs_jpeg_v2_x.h"
+
+static struct jpeg_fmt formats[] = {
+ {
+ .name = "JPEG compressed format",
+ .fourcc = V4L2_PIX_FMT_JPEG_444,
+ .depth = {8},
+ .color = JPEG_444,
+ .memplanes = 1,
+ .types = M2M_CAPTURE,
+ }, {
+ .name = "JPEG compressed format",
+ .fourcc = V4L2_PIX_FMT_JPEG_422,
+ .depth = {8},
+ .color = JPEG_422,
+ .memplanes = 1,
+ .types = M2M_CAPTURE,
+ }, {
+ .name = "JPEG compressed format",
+ .fourcc = V4L2_PIX_FMT_JPEG_420,
+ .depth = {8},
+ .color = JPEG_420,
+ .memplanes = 1,
+ .types = M2M_CAPTURE,
+ }, {
+ .name = "JPEG compressed format",
+ .fourcc = V4L2_PIX_FMT_JPEG_GRAY,
+ .depth = {8},
+ .color = JPEG_GRAY,
+ .memplanes = 1,
+ .types = M2M_CAPTURE,
+ }, {
+ .name = "RGB565",
+ .fourcc = V4L2_PIX_FMT_RGB565X,
+ .depth = {16},
+ .color = RGB_565,
+ .memplanes = 1,
+ .types = M2M_OUTPUT,
+ }, {
+ .name = "YUV 4:4:4 packed, Y/CbCr",
+ .fourcc = V4L2_PIX_FMT_YUV444_2P,
+ .depth = {24},
+ .color = YCBCR_444_2P,
+ .memplanes = 1,
+ .types = M2M_OUTPUT,
+ }, {
+ .name = "YUV 4:4:4 packed, Y/CrCb",
+ .fourcc = V4L2_PIX_FMT_YVU444_2P,
+ .depth = {24},
+ .color = YCRCB_444_2P,
+ .memplanes = 1,
+ .types = M2M_OUTPUT,
+ }, {
+ .name = "YUV 4:4:4 packed, Y/Cb/Cr",
+ .fourcc = V4L2_PIX_FMT_YUV444_3P,
+ .depth = {24},
+ .color = YCBCR_444_3P,
+ .memplanes = 1,
+ .types = M2M_OUTPUT,
+ }, {
+ .name = "XRGB-8-8-8-8, 32 bpp",
+ .fourcc = V4L2_PIX_FMT_RGB32,
+ .depth = {32},
+ .color = RGB_888,
+ .memplanes = 1,
+ .types = M2M_OUTPUT,
+ }, {
+ .name = "YUV 4:2:2 packed, YCrYCb",
+ .fourcc = V4L2_PIX_FMT_YVYU,
+ .depth = {16},
+ .color = YCRYCB_422_1P,
+ .memplanes = 1,
+ .types = M2M_OUTPUT,
+ }, {
+ .name = "YUV 4:2:2 packed, CrYCbY",
+ .fourcc = V4L2_PIX_FMT_VYUY,
+ .depth = {16},
+ .color = CRYCBY_422_1P,
+ .memplanes = 1,
+ .types = M2M_OUTPUT,
+ }, {
+ .name = "YUV 4:2:2 packed, CbYCrY",
+ .fourcc = V4L2_PIX_FMT_UYVY,
+ .depth = {16},
+ .color = CBYCRY_422_1P,
+ .memplanes = 1,
+ .types = M2M_OUTPUT,
+ }, {
+ .name = "YUV 4:2:2 packed, YCbYCr",
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .depth = {16},
+ .color = YCBYCR_422_1P,
+ .memplanes = 1,
+ .types = M2M_OUTPUT,
+ }, {
+ .name = "YUV 4:2:2 planar, Y/CrCb",
+ .fourcc = V4L2_PIX_FMT_NV61,
+ .depth = {16},
+ .color = YCRCB_422_2P,
+ .memplanes = 1,
+ .types = M2M_OUTPUT,
+ }, {
+ .name = "YUV 4:2:2 planar, Y/CbCr",
+ .fourcc = V4L2_PIX_FMT_NV16,
+ .depth = {16},
+ .color = YCBCR_422_2P,
+ .memplanes = 1,
+ .types = M2M_OUTPUT,
+ }, {
+ .name = "YUV 4:2:0 planar, Y/CbCr",
+ .fourcc = V4L2_PIX_FMT_NV12,
+ .depth = {12},
+ .color = YCBCR_420_2P,
+ .memplanes = 1,
+ .types = M2M_OUTPUT,
+ }, {
+ .name = "YUV 4:2:0 planar, Y/CrCb",
+ .fourcc = V4L2_PIX_FMT_NV21,
+ .depth = {12},
+ .color = YCRCB_420_2P,
+ .memplanes = 1,
+ .types = M2M_OUTPUT,
+ }, {
+ .name = "YUV 4:2:0 contiguous 3-planar, Y/Cb/Cr",
+ .fourcc = V4L2_PIX_FMT_YUV420,
+ .depth = {12},
+ .color = YCBCR_420_3P,
+ .memplanes = 1,
+ .types = M2M_OUTPUT,
+ }, {
+ .name = "YUV 4:2:0 contiguous 3-planar, Y/Cr/Cb",
+ .fourcc = V4L2_PIX_FMT_YVU420,
+ .depth = {12},
+ .color = YCRCB_420_3P,
+ .memplanes = 1,
+ .types = M2M_OUTPUT,
+ }, {
+ .name = "Gray",
+ .fourcc = V4L2_PIX_FMT_GREY,
+ .depth = {8},
+ .color = GRAY,
+ .memplanes = 1,
+ .types = M2M_OUTPUT,
+ }, {
+ .name = "YUV 4:2:2 packed, CrYCbY",
+ .fourcc = V4L2_PIX_FMT_VYUY,
+ .depth = {16},
+ .color = CRYCBY_422_1P,
+ .memplanes = 1,
+ .types = M2M_OUTPUT,
+ }, {
+ .name = "YUV 4:2:2 packed, CbYCrY",
+ .fourcc = V4L2_PIX_FMT_UYVY,
+ .depth = {16},
+ .color = CRYCBY_422_1P,
+ .memplanes = 1,
+ .types = M2M_OUTPUT,
+ }, {
+ .name = "XBGR-8-8-8-8, 32 bpp",
+ .fourcc = V4L2_PIX_FMT_BGR32,
+ .depth = {32},
+ .color = BGR_888,
+ .memplanes = 1,
+ .types = M2M_OUTPUT,
+ },
+};
+
+static struct jpeg_fmt *find_format(struct v4l2_format *f)
+{
+ struct jpeg_fmt *fmt;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(formats); ++i) {
+ fmt = &formats[i];
+ if (fmt->fourcc == f->fmt.pix_mp.pixelformat)
+ break;
+ }
+
+ return (i == ARRAY_SIZE(formats)) ? NULL : fmt;
+}
+
+static int jpeg_enc_vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct jpeg_ctx *ctx = file->private_data;
+ struct jpeg_dev *dev = ctx->dev;
+
+ strncpy(cap->driver, dev->plat_dev->name, sizeof(cap->driver) - 1);
+ strncpy(cap->card, dev->plat_dev->name, sizeof(cap->card) - 1);
+ cap->bus_info[0] = 0;
+ cap->version = KERNEL_VERSION(1, 0, 0);
+ cap->capabilities = V4L2_CAP_STREAMING |
+ V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT |
+ V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE;
+ return 0;
+}
+
+int jpeg_enc_vidioc_enum_fmt(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ struct jpeg_fmt *fmt;
+
+ if (f->index >= ARRAY_SIZE(formats))
+ return -EINVAL;
+
+ fmt = &formats[f->index];
+ strncpy(f->description, fmt->name, sizeof(f->description) - 1);
+ f->pixelformat = fmt->fourcc;
+
+ return 0;
+}
+
+int jpeg_enc_vidioc_g_fmt(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct jpeg_ctx *ctx = priv;
+ struct v4l2_pix_format_mplane *pixm;
+ struct jpeg_enc_param *enc_param = &ctx->param.enc_param;
+
+ pixm = &f->fmt.pix_mp;
+
+ pixm->field = V4L2_FIELD_NONE;
+
+ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+ pixm->pixelformat =
+ enc_param->in_fmt;
+ pixm->num_planes =
+ enc_param->in_plane;
+ pixm->width =
+ enc_param->in_width;
+ pixm->height =
+ enc_param->in_height;
+ } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ pixm->pixelformat =
+ enc_param->out_fmt;
+ pixm->num_planes =
+ enc_param->out_plane;
+ pixm->width =
+ enc_param->out_width;
+ pixm->height =
+ enc_param->out_height;
+ } else {
+ v4l2_err(&ctx->dev->v4l2_dev,
+ "Wrong buffer/video queue type (%d)\n", f->type);
+ }
+
+ return 0;
+}
+
+static int jpeg_enc_vidioc_try_fmt(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct jpeg_fmt *fmt;
+ struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
+ struct jpeg_ctx *ctx = priv;
+ int i;
+
+ if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE &&
+ f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ return -EINVAL;
+
+ fmt = find_format(f);
+
+ if (!fmt) {
+ v4l2_err(&ctx->dev->v4l2_dev,
+ "Fourcc format (0x%08x) invalid.\n",
+ f->fmt.pix.pixelformat);
+ return -EINVAL;
+ }
+
+ if (pix->field == V4L2_FIELD_ANY)
+ pix->field = V4L2_FIELD_NONE;
+ else if (V4L2_FIELD_NONE != pix->field)
+ return -EINVAL;
+
+
+ pix->num_planes = fmt->memplanes;
+
+ for (i = 0; i < pix->num_planes; ++i) {
+ int bpl = pix->plane_fmt[i].bytesperline;
+
+ jpeg_dbg("[%d] bpl: %d, depth: %d, w: %d, h: %d",
+ i, bpl, fmt->depth[i], pix->width, pix->height);
+
+ if (!bpl || (bpl * 8 / fmt->depth[i]) > pix->width)
+ bpl = (pix->width * fmt->depth[i]) >> 3;
+
+ if (!pix->plane_fmt[i].sizeimage)
+ pix->plane_fmt[i].sizeimage = pix->height * bpl;
+
+ pix->plane_fmt[i].bytesperline = bpl;
+
+ jpeg_dbg("[%d]: bpl: %d, sizeimage: %d",
+ i, pix->plane_fmt[i].bytesperline,
+ pix->plane_fmt[i].sizeimage);
+ }
+
+ if (f->fmt.pix.height > MAX_JPEG_HEIGHT)
+ f->fmt.pix.height = MAX_JPEG_HEIGHT;
+
+ if (f->fmt.pix.width > MAX_JPEG_WIDTH)
+ f->fmt.pix.width = MAX_JPEG_WIDTH;
+
+ return 0;
+}
+
+static int jpeg_enc_vidioc_s_fmt_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct jpeg_ctx *ctx = priv;
+ struct vb2_queue *vq;
+ struct v4l2_pix_format_mplane *pix;
+ struct jpeg_fmt *fmt;
+ int ret;
+ int i;
+
+ ret = jpeg_enc_vidioc_try_fmt(file, priv, f);
+ if (ret)
+ return ret;
+
+ vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+ if (!vq)
+ return -EINVAL;
+
+ if (vb2_is_busy(vq)) {
+ v4l2_err(&ctx->dev->v4l2_dev, "queue (%d) busy\n", f->type);
+ return -EBUSY;
+ }
+
+ pix = &f->fmt.pix_mp;
+ fmt = find_format(f);
+
+ for (i = 0; i < fmt->memplanes; i++)
+ ctx->payload[i] =
+ pix->plane_fmt[i].bytesperline * pix->height;
+
+ ctx->param.enc_param.out_width = pix->height;
+ ctx->param.enc_param.out_height = pix->width;
+ ctx->param.enc_param.out_plane = fmt->memplanes;
+ ctx->param.enc_param.out_depth = fmt->depth[0];
+ ctx->param.enc_param.out_fmt = fmt->color;
+
+ return 0;
+}
+
+static int jpeg_enc_vidioc_s_fmt_out(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct jpeg_ctx *ctx = priv;
+ struct vb2_queue *vq;
+ struct v4l2_pix_format_mplane *pix;
+ struct jpeg_fmt *fmt;
+ int ret;
+ int i;
+
+ ret = jpeg_enc_vidioc_try_fmt(file, priv, f);
+ if (ret)
+ return ret;
+
+ vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+ if (!vq)
+ return -EINVAL;
+
+ if (vb2_is_busy(vq)) {
+ v4l2_err(&ctx->dev->v4l2_dev, "queue (%d) busy\n", f->type);
+ return -EBUSY;
+ }
+
+ /* TODO: width & height has to be multiple of two */
+ pix = &f->fmt.pix_mp;
+ fmt = find_format(f);
+
+ for (i = 0; i < fmt->memplanes; i++) {
+ ctx->payload[i] =
+ pix->plane_fmt[i].bytesperline * pix->height;
+ ctx->param.enc_param.in_depth[i] = fmt->depth[i];
+ }
+ ctx->param.enc_param.in_width = pix->width;
+ ctx->param.enc_param.in_height = pix->height;
+ ctx->param.enc_param.in_plane = fmt->memplanes;
+ ctx->param.enc_param.in_fmt = fmt->color;
+
+ return 0;
+}
+
+static int jpeg_enc_m2m_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *reqbufs)
+{
+ struct jpeg_ctx *ctx = priv;
+ struct vb2_queue *vq;
+
+ vq = v4l2_m2m_get_vq(ctx->m2m_ctx, reqbufs->type);
+ if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ ctx->dev->vb2->set_cacheable(ctx->dev->alloc_ctx, ctx->input_cacheable);
+ else if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ ctx->dev->vb2->set_cacheable(ctx->dev->alloc_ctx, ctx->output_cacheable);
+
+ return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
+}
+
+static int jpeg_enc_m2m_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct jpeg_ctx *ctx = priv;
+ return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
+}
+
+static int jpeg_enc_m2m_qbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct jpeg_ctx *ctx = priv;
+
+ return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int jpeg_enc_m2m_dqbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct jpeg_ctx *ctx = priv;
+ return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int jpeg_enc_m2m_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct jpeg_ctx *ctx = priv;
+ return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
+}
+
+static int jpeg_enc_m2m_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct jpeg_ctx *ctx = priv;
+ return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
+}
+
+static int vidioc_enc_s_jpegcomp(struct file *file, void *priv,
+ struct v4l2_jpegcompression *jpegcomp)
+{
+ struct jpeg_ctx *ctx = priv;
+
+ ctx->param.enc_param.quality = jpegcomp->quality;
+ return 0;
+}
+
+static int vidioc_enc_g_jpegcomp(struct file *file, void *priv,
+ struct v4l2_jpegcompression *jpegcomp)
+{
+ struct jpeg_ctx *ctx = priv;
+
+ jpegcomp->quality = ctx->param.enc_param.quality;
+ return 0;
+}
+
+static int jpeg_enc_vidioc_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct jpeg_ctx *ctx = priv;
+/*
+* 0 : input/output noncacheable
+* 1 : input/output cacheable
+* 2 : input cacheable / output noncacheable
+* 3 : input noncacheable / output cacheable
+*/
+ switch (ctrl->id) {
+ case V4L2_CID_CACHEABLE:
+ if (ctrl->value == 0) {
+ ctx->input_cacheable = 0;
+ ctx->output_cacheable = 0;
+ } else if (ctrl->value == 1) {
+ ctx->input_cacheable = 1;
+ ctx->output_cacheable = 1;
+ } else if (ctrl->value == 2) {
+ ctx->input_cacheable = 1;
+ ctx->output_cacheable = 0;
+ } else if (ctrl->value == 3) {
+ ctx->input_cacheable = 0;
+ ctx->output_cacheable = 1;
+ } else {
+ ctx->input_cacheable = 0;
+ ctx->output_cacheable = 0;
+ }
+ break;
+ default:
+ v4l2_err(&ctx->dev->v4l2_dev, "Invalid control\n");
+ break;
+ }
+
+ return 0;
+}
+
+static const struct v4l2_ioctl_ops jpeg_enc_ioctl_ops = {
+ .vidioc_querycap = jpeg_enc_vidioc_querycap,
+
+ .vidioc_enum_fmt_vid_cap_mplane = jpeg_enc_vidioc_enum_fmt,
+ .vidioc_enum_fmt_vid_out_mplane = jpeg_enc_vidioc_enum_fmt,
+
+ .vidioc_g_fmt_vid_cap_mplane = jpeg_enc_vidioc_g_fmt,
+ .vidioc_g_fmt_vid_out_mplane = jpeg_enc_vidioc_g_fmt,
+
+ .vidioc_try_fmt_vid_cap_mplane = jpeg_enc_vidioc_try_fmt,
+ .vidioc_try_fmt_vid_out_mplane = jpeg_enc_vidioc_try_fmt,
+ .vidioc_s_fmt_vid_cap_mplane = jpeg_enc_vidioc_s_fmt_cap,
+ .vidioc_s_fmt_vid_out_mplane = jpeg_enc_vidioc_s_fmt_out,
+
+ .vidioc_reqbufs = jpeg_enc_m2m_reqbufs,
+ .vidioc_querybuf = jpeg_enc_m2m_querybuf,
+ .vidioc_qbuf = jpeg_enc_m2m_qbuf,
+ .vidioc_dqbuf = jpeg_enc_m2m_dqbuf,
+ .vidioc_streamon = jpeg_enc_m2m_streamon,
+ .vidioc_streamoff = jpeg_enc_m2m_streamoff,
+ .vidioc_g_jpegcomp = vidioc_enc_g_jpegcomp,
+ .vidioc_s_jpegcomp = vidioc_enc_s_jpegcomp,
+ .vidioc_s_ctrl = jpeg_enc_vidioc_s_ctrl,
+};
+const struct v4l2_ioctl_ops *get_jpeg_enc_v4l2_ioctl_ops(void)
+{
+ return &jpeg_enc_ioctl_ops;
+}
diff --git a/drivers/media/video/exynos/jpeg/jpeg_mem.c b/drivers/media/video/exynos/jpeg/jpeg_mem.c
new file mode 100644
index 0000000..2911eca
--- /dev/null
+++ b/drivers/media/video/exynos/jpeg/jpeg_mem.c
@@ -0,0 +1,51 @@
+/* linux/drivers/media/video/exynos/jpeg/jpeg_mem.c
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Managent memory of the jpeg driver for encoder/docoder.
+ *
+ * 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.
+*/
+
+#include <linux/errno.h>
+#include <linux/vmalloc.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#include <asm/page.h>
+
+#include "jpeg_mem.h"
+#include "jpeg_core.h"
+
+#if defined(CONFIG_VIDEOBUF2_ION)
+void *jpeg_ion_init(struct jpeg_dev *dev)
+{
+ return vb2_ion_create_context(&dev->plat_dev->dev, SZ_8K,
+ VB2ION_CTX_VMCONTIG | VB2ION_CTX_IOMMU);
+}
+
+static unsigned long jpeg_vb2_plane_addr(struct vb2_buffer *vb, u32 plane_no)
+{
+ void *cookie = vb2_plane_cookie(vb, plane_no);
+ dma_addr_t dva = 0;
+
+ WARN_ON(vb2_ion_dma_address(cookie, &dva) != 0);
+
+ return dva;
+}
+
+const struct jpeg_vb2 jpeg_vb2_ion = {
+ .ops = &vb2_ion_memops,
+ .init = jpeg_ion_init,
+ .cleanup = vb2_ion_destroy_context,
+ .plane_addr = jpeg_vb2_plane_addr,
+ .resume = vb2_ion_attach_iommu,
+ .suspend = vb2_ion_detach_iommu,
+ .cache_flush = vb2_ion_cache_flush,
+ .set_cacheable = vb2_ion_set_cached,
+};
+#endif
diff --git a/drivers/media/video/exynos/jpeg/jpeg_mem.h b/drivers/media/video/exynos/jpeg/jpeg_mem.h
new file mode 100644
index 0000000..df26b2e
--- /dev/null
+++ b/drivers/media/video/exynos/jpeg/jpeg_mem.h
@@ -0,0 +1,39 @@
+/* linux/drivers/media/video/exynos/jpeg/jpeg_mem.h
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Definition for Operation of Jpeg encoder/docoder with memory
+ *
+ * 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.
+*/
+
+#ifndef __JPEG_MEM_H__
+#define __JPEG_MEM_H__
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/cma.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/file.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-memops.h>
+
+#include <asm/cacheflush.h>
+
+#if defined(CONFIG_VIDEOBUF2_CMA_PHYS)
+extern const struct jpeg_vb2 jpeg_vb2_cma;
+#elif defined(CONFIG_VIDEOBUF2_ION)
+extern const struct jpeg_vb2 jpeg_vb2_ion;
+#endif
+
+#define MAX_JPEG_WIDTH 3264
+#define MAX_JPEG_HEIGHT 2448
+
+#endif /* __JPEG_MEM_H__ */
diff --git a/drivers/media/video/exynos/jpeg/jpeg_regs.c b/drivers/media/video/exynos/jpeg/jpeg_regs.c
new file mode 100644
index 0000000..52f37e9
--- /dev/null
+++ b/drivers/media/video/exynos/jpeg/jpeg_regs.c
@@ -0,0 +1,702 @@
+/* linux/drivers/media/video/exynos/jpeg/jpeg_regs.c
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Register interface file for jpeg v2.x driver
+ *
+ * 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.
+*/
+#include <linux/io.h>
+#include <linux/delay.h>
+
+#include "jpeg_regs.h"
+#include "jpeg_conf.h"
+#include "jpeg_core.h"
+#include "regs_jpeg_v2_x.h"
+
+void jpeg_sw_reset(void __iomem *base)
+{
+ unsigned int reg;
+
+ reg = readl(base + S5P_JPEG_CNTL_REG);
+ writel((reg & S5P_JPEG_ENC_DEC_MODE_MASK),
+ base + S5P_JPEG_CNTL_REG);
+
+ reg = readl(base + S5P_JPEG_CNTL_REG);
+ writel(reg & ~S5P_JPEG_SOFT_RESET_HI,
+ base + S5P_JPEG_CNTL_REG);
+
+ ndelay(100000);
+
+ writel(reg | S5P_JPEG_SOFT_RESET_HI,
+ base + S5P_JPEG_CNTL_REG);
+}
+
+void jpeg_set_enc_dec_mode(void __iomem *base, enum jpeg_mode mode)
+{
+ unsigned int reg;
+
+ reg = readl(base + S5P_JPEG_CNTL_REG);
+ /* set jpeg mod register */
+ if (mode == DECODING) {
+ writel((reg & S5P_JPEG_ENC_DEC_MODE_MASK) | S5P_JPEG_DEC_MODE,
+ base + S5P_JPEG_CNTL_REG);
+ } else {/* encode */
+ writel((reg & S5P_JPEG_ENC_DEC_MODE_MASK) | S5P_JPEG_ENC_MODE,
+ base + S5P_JPEG_CNTL_REG);
+ }
+}
+
+void jpeg_set_dec_out_fmt(void __iomem *base,
+ enum jpeg_frame_format out_fmt)
+{
+ unsigned int reg = 0;
+
+ writel(0, base + S5P_JPEG_IMG_FMT_REG); /* clear */
+
+ /* set jpeg deocde ouput format register */
+ switch (out_fmt) {
+ case GRAY:
+ reg = S5P_JPEG_DEC_GRAY_IMG |
+ S5P_JPEG_GRAY_IMG_IP;
+ break;
+
+ case RGB_888:
+ reg = S5P_JPEG_DEC_RGB_IMG |
+ S5P_JPEG_RGB_IP_RGB_32BIT_IMG
+ | S5P_JPEG_ENC_FMT_RGB;
+ break;
+
+ case RGB_565:
+ reg = S5P_JPEG_DEC_RGB_IMG |
+ S5P_JPEG_RGB_IP_RGB_16BIT_IMG;
+ break;
+
+ case YCRCB_444_2P:
+ reg = S5P_JPEG_DEC_YUV_444_IMG |
+ S5P_JPEG_YUV_444_IP_YUV_444_2P_IMG |
+ S5P_JPEG_SWAP_CHROMA_CrCb;
+ break;
+
+ case YCBCR_444_2P:
+ reg = S5P_JPEG_DEC_YUV_444_IMG |
+ S5P_JPEG_YUV_444_IP_YUV_444_2P_IMG |
+ S5P_JPEG_SWAP_CHROMA_CbCr;
+ break;
+
+ case YCBCR_444_3P:
+ reg = S5P_JPEG_DEC_YUV_444_IMG |
+ S5P_JPEG_YUV_444_IP_YUV_444_3P_IMG;
+ break;
+
+ case BGR_888:
+ reg = S5P_JPEG_DEC_RGB_IMG |
+ S5P_JPEG_RGB_IP_RGB_32BIT_IMG
+ |S5P_JPEG_ENC_FMT_BGR;
+ break;
+
+ case CRYCBY_422_1P:
+ reg = S5P_JPEG_DEC_YUV_422_IMG |
+ S5P_JPEG_YUV_422_IP_YUV_422_1P_IMG |
+ S5P_JPEG_ENC_FMT_VYUY;
+ break;
+
+ case CBYCRY_422_1P:
+ reg = S5P_JPEG_DEC_YUV_422_IMG |
+ S5P_JPEG_YUV_422_IP_YUV_422_1P_IMG |
+ S5P_JPEG_ENC_FMT_UYVY;
+ break;
+ case YCRYCB_422_1P:
+ reg = S5P_JPEG_DEC_YUV_422_IMG |
+ S5P_JPEG_YUV_422_IP_YUV_422_1P_IMG |
+ S5P_JPEG_ENC_FMT_YVYU;
+ break;
+ case YCBYCR_422_1P:
+ reg = S5P_JPEG_DEC_YUV_422_IMG |
+ S5P_JPEG_YUV_422_IP_YUV_422_1P_IMG |
+ S5P_JPEG_ENC_FMT_YUYV;
+ break;
+
+ case YCRCB_422_2P:
+ reg = S5P_JPEG_DEC_YUV_422_IMG |
+ S5P_JPEG_YUV_422_IP_YUV_422_2P_IMG |
+ S5P_JPEG_SWAP_CHROMA_CrCb;
+ break;
+
+ case YCBCR_422_2P:
+ reg = S5P_JPEG_DEC_YUV_422_IMG |
+ S5P_JPEG_YUV_422_IP_YUV_422_2P_IMG |
+ S5P_JPEG_SWAP_CHROMA_CbCr;
+ break;
+
+ case YCBYCR_422_3P:
+ reg = S5P_JPEG_DEC_YUV_422_IMG |
+ S5P_JPEG_YUV_422_IP_YUV_422_3P_IMG;
+ break;
+
+ case YCRCB_420_2P:
+ reg = S5P_JPEG_DEC_YUV_420_IMG |
+ S5P_JPEG_YUV_420_IP_YUV_420_2P_IMG |
+ S5P_JPEG_SWAP_CHROMA_CrCb;
+ break;
+
+ case YCBCR_420_2P:
+ reg = S5P_JPEG_DEC_YUV_420_IMG |
+ S5P_JPEG_YUV_420_IP_YUV_420_2P_IMG |
+ S5P_JPEG_SWAP_CHROMA_CbCr;
+ break;
+
+ case YCBCR_420_3P:
+ case YCRCB_420_3P:
+ reg = S5P_JPEG_DEC_YUV_420_IMG |
+ S5P_JPEG_YUV_420_IP_YUV_420_3P_IMG;
+ break;
+
+ default:
+ break;
+ }
+
+ writel(reg, base + S5P_JPEG_IMG_FMT_REG);
+}
+
+void jpeg_set_enc_in_fmt(void __iomem *base,
+ enum jpeg_frame_format in_fmt)
+{
+ unsigned int reg;
+
+ reg = readl(base + S5P_JPEG_IMG_FMT_REG) &
+ S5P_JPEG_ENC_IN_FMT_MASK; /* clear except enc format */
+
+ switch (in_fmt) {
+ case GRAY:
+ reg = reg | S5P_JPEG_ENC_GRAY_IMG | S5P_JPEG_GRAY_IMG_IP;
+ break;
+
+ case RGB_565:
+ reg = reg | S5P_JPEG_ENC_RGB_IMG |
+ S5P_JPEG_RGB_IP_RGB_16BIT_IMG;
+ break;
+
+ case YCRCB_444_2P:
+ reg = reg | S5P_JPEG_ENC_YUV_444_IMG |
+ S5P_JPEG_YUV_444_IP_YUV_444_2P_IMG |
+ S5P_JPEG_SWAP_CHROMA_CrCb;
+ break;
+
+ case YCBCR_444_2P:
+ reg = reg | S5P_JPEG_ENC_YUV_444_IMG |
+ S5P_JPEG_YUV_444_IP_YUV_444_2P_IMG |
+ S5P_JPEG_SWAP_CHROMA_CbCr;
+ break;
+
+ case YCBCR_444_3P:
+ reg = reg | S5P_JPEG_ENC_YUV_444_IMG |
+ S5P_JPEG_YUV_444_IP_YUV_444_3P_IMG;
+ break;
+
+ case RGB_888:
+ reg = reg | S5P_JPEG_DEC_RGB_IMG |
+ S5P_JPEG_RGB_IP_RGB_32BIT_IMG
+ |S5P_JPEG_ENC_FMT_RGB;
+ break;
+ case BGR_888:
+ reg = reg | S5P_JPEG_DEC_RGB_IMG |
+ S5P_JPEG_RGB_IP_RGB_32BIT_IMG
+ |S5P_JPEG_ENC_FMT_BGR;
+ break;
+ case CRYCBY_422_1P:
+ reg = reg | S5P_JPEG_DEC_YUV_422_IMG |
+ S5P_JPEG_YUV_422_IP_YUV_422_1P_IMG |
+ S5P_JPEG_ENC_FMT_VYUY;
+ break;
+ case CBYCRY_422_1P:
+ reg = reg | S5P_JPEG_DEC_YUV_422_IMG |
+ S5P_JPEG_YUV_422_IP_YUV_422_1P_IMG |
+ S5P_JPEG_ENC_FMT_UYVY;
+ break;
+
+ case YCRYCB_422_1P:
+ reg = reg | S5P_JPEG_DEC_YUV_422_IMG |
+ S5P_JPEG_YUV_422_IP_YUV_422_1P_IMG |
+ S5P_JPEG_ENC_FMT_YVYU;
+ break;
+ case YCBYCR_422_1P:
+ reg = reg | S5P_JPEG_DEC_YUV_422_IMG |
+ S5P_JPEG_YUV_422_IP_YUV_422_1P_IMG |
+ S5P_JPEG_ENC_FMT_YUYV;
+ break;
+
+ case YCRCB_422_2P:
+ reg = reg | S5P_JPEG_DEC_YUV_422_IMG |
+ S5P_JPEG_YUV_422_IP_YUV_422_2P_IMG |
+ S5P_JPEG_SWAP_CHROMA_CrCb;
+ break;
+
+ case YCBCR_422_2P:
+ reg = reg | S5P_JPEG_DEC_YUV_422_IMG |
+ S5P_JPEG_YUV_422_IP_YUV_422_2P_IMG |
+ S5P_JPEG_SWAP_CHROMA_CbCr;
+ break;
+
+ case YCBYCR_422_3P:
+ reg = reg | S5P_JPEG_DEC_YUV_422_IMG |
+ S5P_JPEG_YUV_422_IP_YUV_422_3P_IMG;
+ break;
+
+ case YCRCB_420_2P:
+ reg = reg | S5P_JPEG_DEC_YUV_420_IMG |
+ S5P_JPEG_YUV_420_IP_YUV_420_2P_IMG |
+ S5P_JPEG_SWAP_CHROMA_CrCb;
+ break;
+
+ case YCBCR_420_2P:
+ reg = reg | S5P_JPEG_DEC_YUV_420_IMG |
+ S5P_JPEG_YUV_420_IP_YUV_420_2P_IMG |
+ S5P_JPEG_SWAP_CHROMA_CbCr;
+ break;
+
+ case YCBCR_420_3P:
+ case YCRCB_420_3P:
+ reg = reg | S5P_JPEG_DEC_YUV_420_IMG |
+ S5P_JPEG_YUV_420_IP_YUV_420_3P_IMG;
+ break;
+
+ default:
+ break;
+
+ }
+
+ writel(reg, base + S5P_JPEG_IMG_FMT_REG);
+
+}
+
+void jpeg_set_enc_out_fmt(void __iomem *base,
+ enum jpeg_stream_format out_fmt)
+{
+ unsigned int reg;
+
+ reg = readl(base + S5P_JPEG_IMG_FMT_REG) &
+ ~S5P_JPEG_ENC_FMT_MASK; /* clear enc format */
+
+ switch (out_fmt) {
+ case JPEG_GRAY:
+ reg = reg | S5P_JPEG_ENC_FMT_GRAY;
+ break;
+
+ case JPEG_444:
+ reg = reg | S5P_JPEG_ENC_FMT_YUV_444;
+ break;
+
+ case JPEG_422:
+ reg = reg | S5P_JPEG_ENC_FMT_YUV_422;
+ break;
+
+ case JPEG_420:
+ reg = reg | S5P_JPEG_ENC_FMT_YUV_420;
+ break;
+
+ default:
+ break;
+ }
+
+ writel(reg, base + S5P_JPEG_IMG_FMT_REG);
+}
+
+void jpeg_set_enc_tbl(void __iomem *base,
+ enum jpeg_img_quality_level level)
+{
+ int i;
+
+ switch (level) {
+ case QUALITY_LEVEL_1:
+ for (i = 0; i < 16; i++) {
+ writel((unsigned int)ITU_Q_tbl[0][i],
+ base + S5P_JPEG_QUAN_TBL_ENTRY_REG
+ + (i*0x04));
+ }
+
+ for (i = 0; i < 16; i++) {
+ writel((unsigned int)ITU_Q_tbl[1][i],
+ base + S5P_JPEG_QUAN_TBL_ENTRY_REG
+ + 0x40 + (i*0x04));
+ }
+
+ for (i = 0; i < 16; i++) {
+ writel((unsigned int)ITU_Q_tbl[0][i],
+ base + S5P_JPEG_QUAN_TBL_ENTRY_REG
+ + 0x80 + (i*0x04));
+ }
+
+ for (i = 0; i < 16; i++) {
+ writel((unsigned int)ITU_Q_tbl[1][i],
+ base + S5P_JPEG_QUAN_TBL_ENTRY_REG
+ + 0xc0 + (i*0x04));
+ }
+ break;
+
+ case QUALITY_LEVEL_2:
+ for (i = 0; i < 16; i++) {
+ writel((unsigned int)ITU_Q_tbl[2][i],
+ base + S5P_JPEG_QUAN_TBL_ENTRY_REG
+ + (i*0x04));
+ }
+
+ for (i = 0; i < 16; i++) {
+ writel((unsigned int)ITU_Q_tbl[3][i],
+ base + S5P_JPEG_QUAN_TBL_ENTRY_REG
+ + 0x40 + (i*0x04));
+ }
+
+ for (i = 0; i < 16; i++) {
+ writel((unsigned int)ITU_Q_tbl[2][i],
+ base + S5P_JPEG_QUAN_TBL_ENTRY_REG
+ + 0x80 + (i*0x04));
+ }
+
+ for (i = 0; i < 16; i++) {
+ writel((unsigned int)ITU_Q_tbl[3][i],
+ base + S5P_JPEG_QUAN_TBL_ENTRY_REG
+ + 0xc0 + (i*0x04));
+ }
+ break;
+
+ case QUALITY_LEVEL_3:
+ for (i = 0; i < 16; i++) {
+ writel((unsigned int)ITU_Q_tbl[4][i],
+ base + S5P_JPEG_QUAN_TBL_ENTRY_REG
+ + (i*0x04));
+ }
+
+ for (i = 0; i < 16; i++) {
+ writel((unsigned int)ITU_Q_tbl[5][i],
+ base + S5P_JPEG_QUAN_TBL_ENTRY_REG
+ + 0x40 + (i*0x04));
+ }
+
+ for (i = 0; i < 16; i++) {
+ writel((unsigned int)ITU_Q_tbl[4][i],
+ base + S5P_JPEG_QUAN_TBL_ENTRY_REG
+ + 0x80 + (i*0x04));
+ }
+
+ for (i = 0; i < 16; i++) {
+ writel((unsigned int)ITU_Q_tbl[5][i],
+ base + S5P_JPEG_QUAN_TBL_ENTRY_REG
+ + 0xc0 + (i*0x04));
+ }
+ break;
+
+ case QUALITY_LEVEL_4:
+ for (i = 0; i < 16; i++) {
+ writel((unsigned int)ITU_Q_tbl[6][i],
+ base + S5P_JPEG_QUAN_TBL_ENTRY_REG
+ + (i*0x04));
+ }
+
+ for (i = 0; i < 16; i++) {
+ writel((unsigned int)ITU_Q_tbl[7][i],
+ base + S5P_JPEG_QUAN_TBL_ENTRY_REG
+ + 0x40 + (i*0x04));
+ }
+
+ for (i = 0; i < 16; i++) {
+ writel((unsigned int)ITU_Q_tbl[6][i],
+ base + S5P_JPEG_QUAN_TBL_ENTRY_REG
+ + 0x80 + (i*0x04));
+ }
+
+ for (i = 0; i < 16; i++) {
+ writel((unsigned int)ITU_Q_tbl[7][i],
+ base + S5P_JPEG_QUAN_TBL_ENTRY_REG
+ + 0xc0 + (i*0x04));
+ }
+ break;
+
+ default:
+ for (i = 0; i < 16; i++) {
+ writel((unsigned int)ITU_Q_tbl[0][i],
+ base + S5P_JPEG_QUAN_TBL_ENTRY_REG
+ + (i*0x04));
+ }
+
+ for (i = 0; i < 16; i++) {
+ writel((unsigned int)ITU_Q_tbl[1][i],
+ base + S5P_JPEG_QUAN_TBL_ENTRY_REG
+ + 0x40 + (i*0x04));
+ }
+
+ for (i = 0; i < 16; i++) {
+ writel((unsigned int)ITU_Q_tbl[0][i],
+ base + S5P_JPEG_QUAN_TBL_ENTRY_REG
+ + 0x80 + (i*0x04));
+ }
+
+ for (i = 0; i < 16; i++) {
+ writel((unsigned int)ITU_Q_tbl[1][i],
+ base + S5P_JPEG_QUAN_TBL_ENTRY_REG
+ + 0xc0 + (i*0x04));
+ }
+ break;
+ }
+ for (i = 0; i < 4; i++) {
+ writel((unsigned int)ITU_H_tbl_len_DC_luminance[i],
+ base + S5P_JPEG_HUFF_TBL_ENTRY_REG + (i*0x04));
+ }
+
+ for (i = 0; i < 3; i++) {
+ writel((unsigned int)ITU_H_tbl_val_DC_luminance[i],
+ base + S5P_JPEG_HUFF_TBL_ENTRY_REG + 0x10 + (i*0x04));
+ }
+
+ for (i = 0; i < 4; i++) {
+ writel((unsigned int)ITU_H_tbl_len_DC_chrominance[i],
+ base + S5P_JPEG_HUFF_TBL_ENTRY_REG + 0x20 + (i*0x04));
+ }
+
+ for (i = 0; i < 3; i++) {
+ writel((unsigned int)ITU_H_tbl_val_DC_chrominance[i],
+ base + S5P_JPEG_HUFF_TBL_ENTRY_REG + 0x30 + (i*0x04));
+ }
+
+ for (i = 0; i < 4; i++) {
+ writel((unsigned int)ITU_H_tbl_len_AC_luminance[i],
+ base + S5P_JPEG_HUFF_TBL_ENTRY_REG + 0x40 + (i*0x04));
+ }
+
+ for (i = 0; i < 41; i++) {
+ writel((unsigned int)ITU_H_tbl_val_AC_luminance[i],
+ base + S5P_JPEG_HUFF_TBL_ENTRY_REG + 0x50 + (i*0x04));
+ }
+
+ for (i = 0; i < 4; i++) {
+ writel((unsigned int)ITU_H_tbl_len_AC_chrominance[i],
+ base + S5P_JPEG_HUFF_TBL_ENTRY_REG + 0x100 + (i*0x04));
+ }
+
+ for (i = 0; i < 41; i++) {
+ writel((unsigned int)ITU_H_tbl_val_AC_chrominance[i],
+ base + S5P_JPEG_HUFF_TBL_ENTRY_REG + 0x110 + (i*0x04));
+ }
+}
+
+void jpeg_set_interrupt(void __iomem *base)
+{
+ unsigned int reg;
+
+ reg = readl(base + S5P_JPEG_INT_EN_REG) & ~S5P_JPEG_INT_EN_MASK;
+ writel(S5P_JPEG_INT_EN_ALL, base + S5P_JPEG_INT_EN_REG);
+}
+
+void jpeg_clean_interrupt(void __iomem *base)
+{
+ writel(0, base + S5P_JPEG_INT_EN_REG);
+}
+
+unsigned int jpeg_get_int_status(void __iomem *base)
+{
+ unsigned int int_status;
+
+ int_status = readl(base + S5P_JPEG_INT_STATUS_REG);
+
+ return int_status;
+}
+
+void jpeg_set_huf_table_enable(void __iomem *base, int value)
+{
+ unsigned int reg;
+
+ reg = readl(base + S5P_JPEG_CNTL_REG) & ~S5P_JPEG_HUF_TBL_EN;
+
+ if (value == 1)
+ writel(reg | S5P_JPEG_HUF_TBL_EN, base + S5P_JPEG_CNTL_REG);
+ else
+ writel(reg | ~S5P_JPEG_HUF_TBL_EN, base + S5P_JPEG_CNTL_REG);
+}
+
+void jpeg_set_dec_scaling(void __iomem *base,
+ enum jpeg_scale_value x_value, enum jpeg_scale_value y_value)
+{
+ unsigned int reg;
+
+ reg = readl(base + S5P_JPEG_CNTL_REG) &
+ ~(S5P_JPEG_HOR_SCALING_MASK |
+ S5P_JPEG_VER_SCALING_MASK);
+
+ writel(reg | S5P_JPEG_HOR_SCALING(x_value) |
+ S5P_JPEG_VER_SCALING(y_value),
+ base + S5P_JPEG_CNTL_REG);
+}
+
+void jpeg_set_sys_int_enable(void __iomem *base, int value)
+{
+ unsigned int reg;
+
+ reg = readl(base + S5P_JPEG_CNTL_REG) & ~(S5P_JPEG_SYS_INT_EN);
+
+ if (value == 1)
+ writel(S5P_JPEG_SYS_INT_EN, base + S5P_JPEG_CNTL_REG);
+ else
+ writel(~S5P_JPEG_SYS_INT_EN, base + S5P_JPEG_CNTL_REG);
+}
+
+void jpeg_set_stream_buf_address(void __iomem *base, unsigned int address)
+{
+ writel(address, base + S5P_JPEG_OUT_MEM_BASE_REG);
+}
+
+void jpeg_set_stream_size(void __iomem *base,
+ unsigned int x_value, unsigned int y_value)
+{
+ writel(0x0, base + S5P_JPEG_IMG_SIZE_REG); /* clear */
+ writel(S5P_JPEG_X_SIZE(x_value) | S5P_JPEG_Y_SIZE(y_value),
+ base + S5P_JPEG_IMG_SIZE_REG);
+}
+
+void jpeg_set_frame_buf_address(void __iomem *base,
+ enum jpeg_frame_format fmt, unsigned int address, unsigned int width, unsigned int height)
+{
+ switch (fmt) {
+ case GRAY:
+ case RGB_565:
+ case RGB_888:
+ case YCRYCB_422_1P:
+ case YCBYCR_422_1P:
+ case BGR_888:
+ case CBYCRY_422_1P:
+ case CRYCBY_422_1P:
+ writel(address, base + S5P_JPEG_IMG_BA_PLANE_1_REG);
+ writel(0, base + S5P_JPEG_IMG_BA_PLANE_2_REG);
+ writel(0, base + S5P_JPEG_IMG_BA_PLANE_3_REG);
+ break;
+ case YCBCR_444_2P:
+ case YCRCB_444_2P:
+ case YCRCB_422_2P:
+ case YCBCR_422_2P:
+ case YCBCR_420_2P:
+ case YCRCB_420_2P:
+ writel(address, base + S5P_JPEG_IMG_BA_PLANE_1_REG);
+ writel(address + (width * height), base + S5P_JPEG_IMG_BA_PLANE_2_REG);
+ writel(0, base + S5P_JPEG_IMG_BA_PLANE_3_REG);
+ break;
+ case YCBCR_444_3P:
+ writel(address, base + S5P_JPEG_IMG_BA_PLANE_1_REG);
+ writel(address + (width * height), base + S5P_JPEG_IMG_BA_PLANE_2_REG);
+ writel(address + (width * height * 2), base + S5P_JPEG_IMG_BA_PLANE_3_REG);
+ break;
+ case YCBYCR_422_3P:
+ writel(address, base + S5P_JPEG_IMG_BA_PLANE_1_REG);
+ writel(address + (width * height), base + S5P_JPEG_IMG_BA_PLANE_2_REG);
+ writel(address + (width * height + (width * height / 2)), base + S5P_JPEG_IMG_BA_PLANE_3_REG);
+ break;
+ case YCBCR_420_3P:
+ writel(address, base + S5P_JPEG_IMG_BA_PLANE_1_REG);
+ writel(address + (width * height), base + S5P_JPEG_IMG_BA_PLANE_2_REG);
+ writel(address + (width * height + (width * height / 4)), base + S5P_JPEG_IMG_BA_PLANE_3_REG);
+ break;
+ case YCRCB_420_3P:
+ writel(address, base + S5P_JPEG_IMG_BA_PLANE_1_REG);
+ writel(address + (width * height + (width * height / 4)), base + S5P_JPEG_IMG_BA_PLANE_2_REG);
+ writel(address + (width * height), base + S5P_JPEG_IMG_BA_PLANE_3_REG);
+ break;
+ default:
+ break;
+ }
+}
+void jpeg_set_encode_tbl_select(void __iomem *base,
+ enum jpeg_img_quality_level level)
+{
+ unsigned int reg;
+
+ switch (level) {
+ case QUALITY_LEVEL_1:
+ reg = S5P_JPEG_Q_TBL_COMP1_0 | S5P_JPEG_Q_TBL_COMP2_1 |
+ S5P_JPEG_Q_TBL_COMP3_1 |
+ S5P_JPEG_HUFF_TBL_COMP1_AC_0_DC_0 |
+ S5P_JPEG_HUFF_TBL_COMP2_AC_1_DC_1 |
+ S5P_JPEG_HUFF_TBL_COMP3_AC_1_DC_1;
+ break;
+ case QUALITY_LEVEL_2:
+ reg = S5P_JPEG_Q_TBL_COMP1_0 | S5P_JPEG_Q_TBL_COMP2_3 |
+ S5P_JPEG_Q_TBL_COMP3_3 |
+ S5P_JPEG_HUFF_TBL_COMP1_AC_0_DC_0 |
+ S5P_JPEG_HUFF_TBL_COMP2_AC_1_DC_1 |
+ S5P_JPEG_HUFF_TBL_COMP3_AC_1_DC_1;
+ break;
+ case QUALITY_LEVEL_3:
+ reg = S5P_JPEG_Q_TBL_COMP1_2 | S5P_JPEG_Q_TBL_COMP2_1 |
+ S5P_JPEG_Q_TBL_COMP3_1 |
+ S5P_JPEG_HUFF_TBL_COMP1_AC_0_DC_0 |
+ S5P_JPEG_HUFF_TBL_COMP2_AC_1_DC_1 |
+ S5P_JPEG_HUFF_TBL_COMP3_AC_1_DC_1;
+ break;
+ case QUALITY_LEVEL_4:
+ reg = S5P_JPEG_Q_TBL_COMP1_2 | S5P_JPEG_Q_TBL_COMP2_3 |
+ S5P_JPEG_Q_TBL_COMP3_3 |
+ S5P_JPEG_HUFF_TBL_COMP1_AC_0_DC_0 |
+ S5P_JPEG_HUFF_TBL_COMP2_AC_1_DC_1 |
+ S5P_JPEG_HUFF_TBL_COMP3_AC_1_DC_1;
+ break;
+ default:
+ reg = S5P_JPEG_Q_TBL_COMP1_0 | S5P_JPEG_Q_TBL_COMP2_1 |
+ S5P_JPEG_Q_TBL_COMP3_1 |
+ S5P_JPEG_HUFF_TBL_COMP1_AC_0_DC_0 |
+ S5P_JPEG_HUFF_TBL_COMP2_AC_1_DC_1 |
+ S5P_JPEG_HUFF_TBL_COMP3_AC_1_DC_1;
+ break;
+ }
+ writel(reg, base + S5P_JPEG_TBL_SEL_REG);
+}
+
+void jpeg_set_encode_hoff_cnt(void __iomem *base, enum jpeg_stream_format fmt)
+{
+ if (fmt == JPEG_GRAY)
+ writel(0xd2, base + S5P_JPEG_HUFF_CNT_REG);
+ else
+ writel(0x1a2, base + S5P_JPEG_HUFF_CNT_REG);
+}
+
+unsigned int jpeg_get_stream_size(void __iomem *base)
+{
+ unsigned int size;
+
+ size = readl(base + S5P_JPEG_BITSTREAM_SIZE_REG);
+ return size;
+}
+
+void jpeg_set_dec_bitstream_size(void __iomem *base, unsigned int size)
+{
+ writel(size, base + S5P_JPEG_BITSTREAM_SIZE_REG);
+}
+
+void jpeg_set_timer_count(void __iomem *base, unsigned int size)
+{
+ writel(size, base + S5P_JPEG_INT_TIMER_COUNT_REG);
+}
+
+void jpeg_get_frame_size(void __iomem *base,
+ unsigned int *width, unsigned int *height)
+{
+ *width = (readl(base + S5P_JPEG_DECODE_XY_SIZE_REG) &
+ S5P_JPEG_DECODED_SIZE_MASK);
+ *height = (readl(base + S5P_JPEG_DECODE_XY_SIZE_REG) >> 16) &
+ S5P_JPEG_DECODED_SIZE_MASK ;
+}
+
+enum jpeg_stream_format jpeg_get_frame_fmt(void __iomem *base)
+{
+ unsigned int reg;
+ enum jpeg_stream_format out_format;
+
+ reg = readl(base + S5P_JPEG_DECODE_IMG_FMT_REG);
+
+ out_format =
+ ((reg & 0x03) == 0x01) ? JPEG_444 :
+ ((reg & 0x03) == 0x02) ? JPEG_422 :
+ ((reg & 0x03) == 0x03) ? JPEG_420 :
+ ((reg & 0x03) == 0x00) ? JPEG_GRAY : JPEG_RESERVED;
+
+ return out_format;
+}
diff --git a/drivers/media/video/exynos/jpeg/jpeg_regs.h b/drivers/media/video/exynos/jpeg/jpeg_regs.h
new file mode 100644
index 0000000..77e8e81
--- /dev/null
+++ b/drivers/media/video/exynos/jpeg/jpeg_regs.h
@@ -0,0 +1,50 @@
+/* linux/drivers/media/video/exynos/jpeg/jpeg_regs.h
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Header file of the register interface for jpeg v2.x driver
+ *
+ * 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.
+*/
+
+#ifndef __JPEG_REGS_H__
+#define __JPEG_REGS_H__
+
+#include "jpeg_core.h"
+
+void jpeg_sw_reset(void __iomem *base);
+void jpeg_set_enc_dec_mode(void __iomem *base, enum jpeg_mode mode);
+void jpeg_set_dec_out_fmt(void __iomem *base,
+ enum jpeg_frame_format out_fmt);
+void jpeg_set_enc_in_fmt(void __iomem *base,
+ enum jpeg_frame_format in_fmt);
+void jpeg_set_enc_out_fmt(void __iomem *base,
+ enum jpeg_stream_format out_fmt);
+void jpeg_set_enc_tbl(void __iomem *base,
+ enum jpeg_img_quality_level level);
+void jpeg_set_interrupt(void __iomem *base);
+void jpeg_clean_interrupt(void __iomem *base);
+unsigned int jpeg_get_int_status(void __iomem *base);
+void jpeg_set_huf_table_enable(void __iomem *base, int value);
+void jpeg_set_dec_scaling(void __iomem *base,
+ enum jpeg_scale_value x_value, enum jpeg_scale_value y_value);
+void jpeg_set_sys_int_enable(void __iomem *base, int value);
+void jpeg_set_stream_buf_address(void __iomem *base, unsigned int address);
+void jpeg_set_stream_size(void __iomem *base,
+ unsigned int x_value, unsigned int y_value);
+void jpeg_set_frame_buf_address(void __iomem *base, enum jpeg_frame_format fmt, unsigned int address, unsigned int width, unsigned int height);
+void jpeg_set_encode_tbl_select(void __iomem *base,
+ enum jpeg_img_quality_level level);
+void jpeg_set_encode_hoff_cnt(void __iomem *base, enum jpeg_stream_format fmt);
+void jpeg_set_dec_bitstream_size(void __iomem *base, unsigned int size);
+void jpeg_set_timer_count(void __iomem *base, unsigned int size);
+unsigned int jpeg_get_stream_size(void __iomem *base);
+void jpeg_get_frame_size(void __iomem *base,
+ unsigned int *width, unsigned int *height);
+
+enum jpeg_stream_format jpeg_get_frame_fmt(void __iomem *base);
+
+#endif /* __JPEG_REGS_H__ */
diff --git a/drivers/media/video/exynos/jpeg/regs_jpeg_v2_x.h b/drivers/media/video/exynos/jpeg/regs_jpeg_v2_x.h
new file mode 100644
index 0000000..879cc01
--- /dev/null
+++ b/drivers/media/video/exynos/jpeg/regs_jpeg_v2_x.h
@@ -0,0 +1,215 @@
+/* linux/drivers/media/video/exynos/jpeg/regs-jpeg_v2_x.h
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Register definition file for Samsung JPEG v.2 Encoder/Decoder
+ *
+ * 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.
+*/
+
+#ifndef __ASM_ARM_REGS_S5P_JPEG_H
+#define __ASM_ARM_REGS_S5P_JPEG_H
+
+/* JPEG Registers part */
+
+/* JPEG Codec Control Registers */
+#define S5P_JPEG_CNTL_REG 0x00
+#define S5P_JPEG_INT_EN_REG 0x04
+#define S5P_JPEG_INT_TIMER_COUNT_REG 0x08
+#define S5P_JPEG_INT_STATUS_REG 0x0c
+#define S5P_JPEG_OUT_MEM_BASE_REG 0x10
+#define S5P_JPEG_IMG_SIZE_REG 0x14
+#define S5P_JPEG_IMG_BA_PLANE_1_REG 0x18
+#define S5P_JPEG_IMG_SO_PLANE_1_REG 0x1c
+#define S5P_JPEG_IMG_PO_PLANE_1_REG 0x20
+#define S5P_JPEG_IMG_BA_PLANE_2_REG 0x24
+#define S5P_JPEG_IMG_SO_PLANE_2_REG 0x28
+#define S5P_JPEG_IMG_PO_PLANE_2_REG 0x2c
+#define S5P_JPEG_IMG_BA_PLANE_3_REG 0x30
+#define S5P_JPEG_IMG_SO_PLANE_3_REG 0x34
+#define S5P_JPEG_IMG_PO_PLANE_3_REG 0x38
+
+#define S5P_JPEG_TBL_SEL_REG 0x3c
+
+#define S5P_JPEG_IMG_FMT_REG 0x40
+
+#define S5P_JPEG_BITSTREAM_SIZE_REG 0x44
+#define S5P_JPEG_PADDING_REG 0x48
+#define S5P_JPEG_HUFF_CNT_REG 0x4c
+#define S5P_JPEG_FIFO_STATUS_REG 0x50
+#define S5P_JPEG_DECODE_XY_SIZE_REG 0x54
+#define S5P_JPEG_DECODE_IMG_FMT_REG 0x58
+
+#define S5P_JPEG_QUAN_TBL_ENTRY_REG 0x100
+#define S5P_JPEG_HUFF_TBL_ENTRY_REG 0x200
+
+
+/****************************************************************/
+/* Bit definition part */
+/****************************************************************/
+
+/* JPEG CNTL Register bit */
+#define S5P_JPEG_ENC_DEC_MODE_MASK (0xfffffffc << 0)
+#define S5P_JPEG_DEC_MODE (1 << 0)
+#define S5P_JPEG_ENC_MODE (1 << 1)
+#define S5P_JPEG_AUTO_RST_MARKER (1 << 2)
+#define S5P_JPEG_RST_INTERVAL_SHIFT 3
+#define S5P_JPEG_RST_INTERVAL(x) (((x) & 0xffff) << S5P_JPEG_RST_INTERVAL_SHIFT)
+#define S5P_JPEG_HUF_TBL_EN (1 << 19)
+#define S5P_JPEG_HOR_SCALING_SHIFT 20
+#define S5P_JPEG_HOR_SCALING_MASK (3 << S5P_JPEG_HOR_SCALING_SHIFT)
+#define S5P_JPEG_HOR_SCALING(x) (((x) & 0x3) << S5P_JPEG_HOR_SCALING_SHIFT)
+#define S5P_JPEG_VER_SCALING_SHIFT 22
+#define S5P_JPEG_VER_SCALING_MASK (3 << S5P_JPEG_VER_SCALING_SHIFT)
+#define S5P_JPEG_VER_SCALING(x) (((x) & 0x3) << S5P_JPEG_VER_SCALING_SHIFT)
+#define S5P_JPEG_PADDING (1 << 27)
+#define S5P_JPEG_SYS_INT_EN (1 << 28)
+#define S5P_JPEG_SOFT_RESET_HI (1 << 29)
+
+/* JPEG INT Register bit */
+#define S5P_JPEG_INT_EN_MASK (0x1ff << 0)
+#define S5P_JPEG_INT_EN_ALL (0x1ff << 0)
+
+#define S5P_JPEG_PROT_ERR_INT_EN (1 << 0)
+#define S5P_JPEG_IMG_COMPLETION_INT_EN (1 << 1)
+#define S5P_JPEG_DEC_INVALID_FORMAT_EN (1 << 2)
+#define S5P_JPEG_MULTI_SCAN_ERROR_EN (1 << 3)
+#define S5P_JPEG_FRAME_ERR_EN (1 << 4)
+#define S5P_JPEG_TIMER_INT_EN (1 << 5)
+#define S5P_JPEG_DEC_UPSAMPLING_ERR_EN (1 << 6)
+#define S5P_JPEG_ENC_WRONG_CONFIG_ERR_EN (1 << 7)
+#define S5P_JPEG_WRONG_IP_CONFIG_ERR_EN (1 << 8)
+
+#define S5P_JPEG_MOD_REG_PROC_ENC (0 << 3)
+#define S5P_JPEG_MOD_REG_PROC_DEC (1 << 3)
+
+#define S5P_JPEG_MOD_REG_SUBSAMPLE_444 (0 << 0)
+#define S5P_JPEG_MOD_REG_SUBSAMPLE_422 (1 << 0)
+#define S5P_JPEG_MOD_REG_SUBSAMPLE_420 (2 << 0)
+#define S5P_JPEG_MOD_REG_SUBSAMPLE_GRAY (3 << 0)
+
+
+/* JPEG IMAGE SIZE Register bit */
+#define S5P_JPEG_X_SIZE_SHIFT 0
+#define S5P_JPEG_X_SIZE_MASK (0xffff << S5P_JPEG_X_SIZE_SHIFT)
+#define S5P_JPEG_X_SIZE(x) (((x) & 0xffff) << S5P_JPEG_X_SIZE_SHIFT)
+#define S5P_JPEG_Y_SIZE_SHIFT 16
+#define S5P_JPEG_Y_SIZE_MASK (0xffff << S5P_JPEG_Y_SIZE_SHIFT)
+#define S5P_JPEG_Y_SIZE(x) (((x) & 0xffff) << S5P_JPEG_Y_SIZE_SHIFT)
+
+/* JPEG IMAGE FORMAT Register bit */
+#define S5P_JPEG_ENC_IN_FMT_MASK 0xffff0000
+#define S5P_JPEG_ENC_GRAY_IMG (0 << 0)
+#define S5P_JPEG_ENC_RGB_IMG (1 << 0)
+#define S5P_JPEG_ENC_YUV_444_IMG (2 << 0)
+#define S5P_JPEG_ENC_YUV_422_IMG (3 << 0)
+#define S5P_JPEG_ENC_YUV_440_IMG (4 << 0)
+
+#define S5P_JPEG_DEC_GRAY_IMG (0 << 0)
+#define S5P_JPEG_DEC_RGB_IMG (1 << 0)
+#define S5P_JPEG_DEC_YUV_444_IMG (2 << 0)
+#define S5P_JPEG_DEC_YUV_422_IMG (3 << 0)
+#define S5P_JPEG_DEC_YUV_420_IMG (4 << 0)
+
+#define S5P_JPEG_GRAY_IMG_IP_SHIFT 3
+#define S5P_JPEG_GRAY_IMG_IP_MASK (7 << S5P_JPEG_GRAY_IMG_IP_SHIFT)
+#define S5P_JPEG_GRAY_IMG_IP (4 << S5P_JPEG_GRAY_IMG_IP_SHIFT)
+
+#define S5P_JPEG_RGB_IP_SHIFT 6
+#define S5P_JPEG_RGB_IP_MASK (7 << S5P_JPEG_RGB_IP_SHIFT)
+#define S5P_JPEG_RGB_IP_RGB_16BIT_IMG (4 << S5P_JPEG_RGB_IP_SHIFT)
+#define S5P_JPEG_RGB_IP_RGB_32BIT_IMG (5 << S5P_JPEG_RGB_IP_SHIFT)
+
+#define S5P_JPEG_YUV_444_IP_SHIFT 9
+#define S5P_JPEG_YUV_444_IP_MASK (7 << S5P_JPEG_YUV_444_IP_SHIFT)
+#define S5P_JPEG_YUV_444_IP_YUV_444_2P_IMG (4 << S5P_JPEG_YUV_444_IP_SHIFT)
+#define S5P_JPEG_YUV_444_IP_YUV_444_3P_IMG (5 << S5P_JPEG_YUV_444_IP_SHIFT)
+
+#define S5P_JPEG_YUV_422_IP_SHIFT 12
+#define S5P_JPEG_YUV_422_IP_MASK (7 << S5P_JPEG_YUV_422_IP_SHIFT)
+#define S5P_JPEG_YUV_422_IP_YUV_422_1P_IMG (4 << S5P_JPEG_YUV_422_IP_SHIFT)
+#define S5P_JPEG_YUV_422_IP_YUV_422_2P_IMG (5 << S5P_JPEG_YUV_422_IP_SHIFT)
+#define S5P_JPEG_YUV_422_IP_YUV_422_3P_IMG (6 << S5P_JPEG_YUV_422_IP_SHIFT)
+
+#define S5P_JPEG_YUV_420_IP_SHIFT 15
+#define S5P_JPEG_YUV_420_IP_MASK (7 << S5P_JPEG_YUV_420_IP_SHIFT)
+#define S5P_JPEG_YUV_420_IP_YUV_420_2P_IMG (4 << S5P_JPEG_YUV_420_IP_SHIFT)
+#define S5P_JPEG_YUV_420_IP_YUV_420_3P_IMG (5 << S5P_JPEG_YUV_420_IP_SHIFT)
+
+#define S5P_JPEG_ENC_FMT_SHIFT 24
+#define S5P_JPEG_ENC_FMT_MASK (3 << S5P_JPEG_ENC_FMT_SHIFT)
+#define S5P_JPEG_ENC_FMT_GRAY (0 << S5P_JPEG_ENC_FMT_SHIFT)
+#define S5P_JPEG_ENC_FMT_YUV_444 (1 << S5P_JPEG_ENC_FMT_SHIFT)
+#define S5P_JPEG_ENC_FMT_YUV_422 (2 << S5P_JPEG_ENC_FMT_SHIFT)
+#define S5P_JPEG_ENC_FMT_YUV_420 (3 << S5P_JPEG_ENC_FMT_SHIFT)
+
+#define S5P_JPEG_SWAP_CHROMA_CrCb (1 << 26)
+#define S5P_JPEG_SWAP_CHROMA_CbCr (0 << 26)
+
+#define S5P_JPEG_SWAP_RGB_SHIFT 29
+#define S5P_JPEG_SWAP_RGB_MASK (1 << S5P_JPEG_SWAP_RGB_SHIFT)
+#define S5P_JPEG_ENC_FMT_BGR (1 << S5P_JPEG_SWAP_RGB_SHIFT)
+#define S5P_JPEG_ENC_FMT_RGB (0 << S5P_JPEG_SWAP_RGB_SHIFT)
+
+#define S5P_JPEG_RE_ORDER_YUV_422_1P_SHIFT 27
+#define S5P_JPEG_RE_ORDER_YUV_422_1P_MASK (3 << S5P_JPEG_RE_ORDER_YUV_422_1P_SHIFT)
+#define S5P_JPEG_ENC_FMT_YUYV (0 << S5P_JPEG_RE_ORDER_YUV_422_1P_SHIFT)
+#define S5P_JPEG_ENC_FMT_YVYU (1 << S5P_JPEG_RE_ORDER_YUV_422_1P_SHIFT)
+#define S5P_JPEG_ENC_FMT_UYVY (2 << S5P_JPEG_RE_ORDER_YUV_422_1P_SHIFT)
+#define S5P_JPEG_ENC_FMT_VYUY (3 << S5P_JPEG_RE_ORDER_YUV_422_1P_SHIFT)
+
+/* JPEG HUFF count Register bit */
+#define S5P_JPEG_HUFF_COUNT_MASK 0xffff
+
+/* JPEG Decoded_img_x_y_size Register bit */
+#define S5P_JPEG_DECODED_SIZE_MASK 0x0000ffff
+
+/* JPEG Decoded image format Register bit */
+#define S5P_JPEG_DECODED_IMG_FMT_MASK 0x3
+
+/* JPEG TBL SEL Register bit */
+#define S5P_JPEG_Q_TBL_COMP1_SHIFT 0
+#define S5P_JPEG_Q_TBL_COMP1_0 (0 << S5P_JPEG_Q_TBL_COMP1_SHIFT)
+#define S5P_JPEG_Q_TBL_COMP1_1 (1 << S5P_JPEG_Q_TBL_COMP1_SHIFT)
+#define S5P_JPEG_Q_TBL_COMP1_2 (2 << S5P_JPEG_Q_TBL_COMP1_SHIFT)
+#define S5P_JPEG_Q_TBL_COMP1_3 (3 << S5P_JPEG_Q_TBL_COMP1_SHIFT)
+
+#define S5P_JPEG_Q_TBL_COMP2_SHIFT 2
+#define S5P_JPEG_Q_TBL_COMP2_0 (0 << S5P_JPEG_Q_TBL_COMP2_SHIFT)
+#define S5P_JPEG_Q_TBL_COMP2_1 (1 << S5P_JPEG_Q_TBL_COMP2_SHIFT)
+#define S5P_JPEG_Q_TBL_COMP2_2 (2 << S5P_JPEG_Q_TBL_COMP2_SHIFT)
+#define S5P_JPEG_Q_TBL_COMP2_3 (3 << S5P_JPEG_Q_TBL_COMP2_SHIFT)
+
+#define S5P_JPEG_Q_TBL_COMP3_SHIFT 4
+#define S5P_JPEG_Q_TBL_COMP3_0 \
+ (0 << S5P_JPEG_Q_TBL_COMP3_SHIFT)
+#define S5P_JPEG_Q_TBL_COMP3_1 \
+ (1 << S5P_JPEG_Q_TBL_COMP3_SHIFT)
+#define S5P_JPEG_Q_TBL_COMP3_2 \
+ (2 << S5P_JPEG_Q_TBL_COMP3_SHIFT)
+#define S5P_JPEG_Q_TBL_COMP3_3 \
+ (3 << S5P_JPEG_Q_TBL_COMP3_SHIFT)
+
+#define S5P_JPEG_HUFF_TBL_COMP1_SHIFT 6
+#define S5P_JPEG_HUFF_TBL_COMP1_AC_0_DC_0 (0 << S5P_JPEG_HUFF_TBL_COMP1_SHIFT)
+#define S5P_JPEG_HUFF_TBL_COMP1_AC_0_DC_1 (1 << S5P_JPEG_HUFF_TBL_COMP1_SHIFT)
+#define S5P_JPEG_HUFF_TBL_COMP1_AC_1_DC_0 (2 << S5P_JPEG_HUFF_TBL_COMP1_SHIFT)
+#define S5P_JPEG_HUFF_TBL_COMP1_AC_1_DC_1 (3 << S5P_JPEG_HUFF_TBL_COMP1_SHIFT)
+
+#define S5P_JPEG_HUFF_TBL_COMP2_SHIFT 8
+#define S5P_JPEG_HUFF_TBL_COMP2_AC_0_DC_0 (0 << S5P_JPEG_HUFF_TBL_COMP2_SHIFT)
+#define S5P_JPEG_HUFF_TBL_COMP2_AC_0_DC_1 (1 << S5P_JPEG_HUFF_TBL_COMP2_SHIFT)
+#define S5P_JPEG_HUFF_TBL_COMP2_AC_1_DC_0 (2 << S5P_JPEG_HUFF_TBL_COMP2_SHIFT)
+#define S5P_JPEG_HUFF_TBL_COMP2_AC_1_DC_1 (3 << S5P_JPEG_HUFF_TBL_COMP2_SHIFT)
+
+#define S5P_JPEG_HUFF_TBL_COMP3_SHIFT 10
+#define S5P_JPEG_HUFF_TBL_COMP3_AC_0_DC_0 (0 << S5P_JPEG_HUFF_TBL_COMP3_SHIFT)
+#define S5P_JPEG_HUFF_TBL_COMP3_AC_0_DC_1 (1 << S5P_JPEG_HUFF_TBL_COMP3_SHIFT)
+#define S5P_JPEG_HUFF_TBL_COMP3_AC_1_DC_0 (2 << S5P_JPEG_HUFF_TBL_COMP3_SHIFT)
+#define S5P_JPEG_HUFF_TBL_COMP3_AC_1_DC_1 (3 << S5P_JPEG_HUFF_TBL_COMP3_SHIFT)
+
+#endif /* __ASM_ARM_REGS_S5P_JPEG_H */
+
diff --git a/drivers/media/video/exynos/mdev/Kconfig b/drivers/media/video/exynos/mdev/Kconfig
new file mode 100644
index 0000000..15134b0
--- /dev/null
+++ b/drivers/media/video/exynos/mdev/Kconfig
@@ -0,0 +1,8 @@
+config EXYNOS_MEDIA_DEVICE
+ bool
+ depends on MEDIA_EXYNOS
+ select MEDIA_CONTROLLER
+ select VIDEO_V4L2_SUBDEV_API
+ default y
+ help
+ This is a v4l2 driver for exynos media device.
diff --git a/drivers/media/video/exynos/mdev/Makefile b/drivers/media/video/exynos/mdev/Makefile
new file mode 100644
index 0000000..175a4bc
--- /dev/null
+++ b/drivers/media/video/exynos/mdev/Makefile
@@ -0,0 +1,2 @@
+mdev-objs := exynos-mdev.o
+obj-$(CONFIG_EXYNOS_MEDIA_DEVICE) += mdev.o
diff --git a/drivers/media/video/exynos/mdev/exynos-mdev.c b/drivers/media/video/exynos/mdev/exynos-mdev.c
new file mode 100644
index 0000000..a76e7c3
--- /dev/null
+++ b/drivers/media/video/exynos/mdev/exynos-mdev.c
@@ -0,0 +1,115 @@
+/* drviers/media/video/exynos/mdev/exynos-mdev.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * EXYNOS5 SoC series media device driver
+ *
+ * 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.
+*/
+
+#include <linux/bug.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/version.h>
+#include <media/v4l2-ctrls.h>
+#include <media/media-device.h>
+#include <media/exynos_mc.h>
+
+static int __devinit mdev_probe(struct platform_device *pdev)
+{
+ struct v4l2_device *v4l2_dev;
+ struct exynos_md *mdev;
+ int ret;
+
+ mdev = kzalloc(sizeof(struct exynos_md), GFP_KERNEL);
+ if (!mdev)
+ return -ENOMEM;
+
+ mdev->id = pdev->id;
+ mdev->pdev = pdev;
+ spin_lock_init(&mdev->slock);
+
+ snprintf(mdev->media_dev.model, sizeof(mdev->media_dev.model), "%s%d",
+ dev_name(&pdev->dev), mdev->id);
+
+ mdev->media_dev.dev = &pdev->dev;
+
+ v4l2_dev = &mdev->v4l2_dev;
+ v4l2_dev->mdev = &mdev->media_dev;
+ snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), "%s",
+ dev_name(&pdev->dev));
+
+ ret = v4l2_device_register(&pdev->dev, &mdev->v4l2_dev);
+ if (ret < 0) {
+ v4l2_err(v4l2_dev, "Failed to register v4l2_device: %d\n", ret);
+ goto err_v4l2_reg;
+ }
+ ret = media_device_register(&mdev->media_dev);
+ if (ret < 0) {
+ v4l2_err(v4l2_dev, "Failed to register media device: %d\n", ret);
+ goto err_mdev_reg;
+ }
+
+ platform_set_drvdata(pdev, mdev);
+ v4l2_info(v4l2_dev, "Media%d[0x%08x] was registered successfully\n",
+ mdev->id, (unsigned int)mdev);
+ return 0;
+
+err_mdev_reg:
+ v4l2_device_unregister(&mdev->v4l2_dev);
+err_v4l2_reg:
+ kfree(mdev);
+ return ret;
+}
+
+static int __devexit mdev_remove(struct platform_device *pdev)
+{
+ struct exynos_md *mdev = platform_get_drvdata(pdev);
+
+ if (!mdev)
+ return 0;
+ media_device_unregister(&mdev->media_dev);
+ v4l2_device_unregister(&mdev->v4l2_dev);
+ kfree(mdev);
+ return 0;
+}
+
+static struct platform_driver mdev_driver = {
+ .probe = mdev_probe,
+ .remove = __devexit_p(mdev_remove),
+ .driver = {
+ .name = MDEV_MODULE_NAME,
+ .owner = THIS_MODULE,
+ }
+};
+
+int __init mdev_init(void)
+{
+ int ret = platform_driver_register(&mdev_driver);
+ if (ret)
+ err("platform_driver_register failed: %d\n", ret);
+ return ret;
+}
+
+void __exit mdev_exit(void)
+{
+ platform_driver_unregister(&mdev_driver);
+}
+
+module_init(mdev_init);
+module_exit(mdev_exit);
+
+MODULE_AUTHOR("Hyunwoong Kim <khw0178.kim@samsung.com>");
+MODULE_DESCRIPTION("EXYNOS5 SoC series media device driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/exynos/mfc/Kconfig b/drivers/media/video/exynos/mfc/Kconfig
new file mode 100644
index 0000000..cc921d0
--- /dev/null
+++ b/drivers/media/video/exynos/mfc/Kconfig
@@ -0,0 +1,10 @@
+config EXYNOS_MFC_V6
+ bool
+
+config VIDEO_EXYNOS_MFC
+ bool "Exynos MFC 6.x Driver"
+ depends on VIDEO_EXYNOS
+ select VIDEOBUF2_CORE
+ select EXYNOS_MFC_V6
+ ---help---
+ MFC driver for V4L2.
diff --git a/drivers/media/video/exynos/mfc/Makefile b/drivers/media/video/exynos/mfc/Makefile
new file mode 100644
index 0000000..900bfc4
--- /dev/null
+++ b/drivers/media/video/exynos/mfc/Makefile
@@ -0,0 +1,7 @@
+obj-$(CONFIG_VIDEO_EXYNOS_MFC) := s5p-mfc.o
+s5p-mfc-y += s5p_mfc.o s5p_mfc_intr.o
+s5p-mfc-y += s5p_mfc_dec.o s5p_mfc_enc.o
+s5p-mfc-y += s5p_mfc_ctrl.o s5p_mfc_inst.o
+s5p-mfc-y += s5p_mfc_mem.o s5p_mfc_reg.o s5p_mfc_pm.o
+obj-$(CONFIG_EXYNOS_MFC_V5) += s5p_mfc_opr_v5.o s5p_mfc_cmd_v5.o s5p_mfc_shm.o
+obj-$(CONFIG_EXYNOS_MFC_V6) += s5p_mfc_opr_v6.o s5p_mfc_cmd_v6.o
diff --git a/drivers/media/video/exynos/mfc/regs-mfc-v5.h b/drivers/media/video/exynos/mfc/regs-mfc-v5.h
new file mode 100644
index 0000000..be89a92
--- /dev/null
+++ b/drivers/media/video/exynos/mfc/regs-mfc-v5.h
@@ -0,0 +1,442 @@
+/*
+ * Register definition file for Samsung MFC V5/V6 Interface (FIMV) driver
+ *
+ * Kamil Debski, Copyright (c) 2010 Samsung Electronics
+ * http://www.samsung.com/
+ *
+ * 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.
+*/
+
+#ifndef _REGS_FIMV_V5_H
+#define _REGS_FIMV_V5_H
+
+#define S5P_FIMV_REG_SIZE (S5P_FIMV_END_ADDR - S5P_FIMV_START_ADDR)
+#define S5P_FIMV_REG_COUNT ((S5P_FIMV_END_ADDR - S5P_FIMV_START_ADDR) / 4)
+
+/* Number of bits that the buffer address should be shifted for particular
+ * MFC buffers. */
+#define S5P_FIMV_MEM_OFFSET 11
+
+#define S5P_FIMV_START_ADDR 0x0000
+#define S5P_FIMV_END_ADDR 0xe008
+
+#define S5P_FIMV_SW_RESET 0x0000
+#define S5P_FIMV_RISC_HOST_INT 0x0008
+
+/* Command from HOST to RISC */
+#define S5P_FIMV_HOST2RISC_CMD 0x0030
+#define S5P_FIMV_HOST2RISC_ARG1 0x0034
+#define S5P_FIMV_HOST2RISC_ARG2 0x0038
+#define S5P_FIMV_HOST2RISC_ARG3 0x003c
+#define S5P_FIMV_HOST2RISC_ARG4 0x0040
+
+/* Command from RISC to HOST */
+#define S5P_FIMV_RISC2HOST_CMD 0x0044
+#define S5P_FIMV_RISC2HOST_CMD_MASK 0x1FFFF
+#define S5P_FIMV_RISC2HOST_ARG1 0x0048
+#define S5P_FIMV_RISC2HOST_ARG2 0x004c
+#define S5P_FIMV_RISC2HOST_ARG3 0x0050
+#define S5P_FIMV_RISC2HOST_ARG4 0x0054
+
+#define S5P_FIMV_FW_VERSION 0x0058
+#define S5P_FIMV_FW_Y_SHIFT 16
+#define S5P_FIMV_FW_M_SHIFT 8
+#define S5P_FIMV_FW_D_SHIFT 0
+#define S5P_FIMV_FW_MASK 0xff
+
+#define S5P_FIMV_SYS_MEM_SZ 0x005c
+#define S5P_FIMV_FW_STATUS 0x0080
+/* Memory controller register */
+#define S5P_FIMV_MC_DRAMBASE_ADR_A 0x0508
+#define S5P_FIMV_MC_DRAMBASE_ADR_B 0x050c
+#define S5P_FIMV_MC_STATUS 0x0510
+
+/* Common register */
+#define S5P_FIMV_COMMON_BASE_A 0x0600
+#define S5P_FIMV_COMMON_BASE_B 0x0700
+
+/* Decoder */
+#define S5P_FIMV_DEC_CHROMA_ADR (S5P_FIMV_COMMON_BASE_A)
+#define S5P_FIMV_DEC_LUMA_ADR (S5P_FIMV_COMMON_BASE_B)
+
+/* H.264 decoding */
+#define S5P_FIMV_H264_VERT_NB_MV_ADR (S5P_FIMV_COMMON_BASE_A + 0x8c) /* vertical neighbor motion vector */
+#define S5P_FIMV_H264_NB_IP_ADR (S5P_FIMV_COMMON_BASE_A + 0x90) /* neighbor pixels for intra pred */
+#define S5P_FIMV_H264_MV_ADR (S5P_FIMV_COMMON_BASE_B + 0x80) /* H264 motion vector */
+
+/* MPEG4 decoding */
+#define S5P_FIMV_MPEG4_NB_DCAC_ADR (S5P_FIMV_COMMON_BASE_A + 0x8c) /* neighbor AC/DC coeff. */
+#define S5P_FIMV_MPEG4_UP_NB_MV_ADR (S5P_FIMV_COMMON_BASE_A + 0x90) /* upper neighbor motion vector */
+#define S5P_FIMV_MPEG4_SA_MV_ADR (S5P_FIMV_COMMON_BASE_A + 0x94) /* subseq. anchor motion vector */
+#define S5P_FIMV_MPEG4_OT_LINE_ADR (S5P_FIMV_COMMON_BASE_A + 0x98) /* overlap transform line */
+#define S5P_FIMV_MPEG4_SP_ADR (S5P_FIMV_COMMON_BASE_A + 0xa8) /* syntax parser */
+
+/* H.263 decoding */
+#define S5P_FIMV_H263_NB_DCAC_ADR (S5P_FIMV_COMMON_BASE_A + 0x8c)
+#define S5P_FIMV_H263_UP_NB_MV_ADR (S5P_FIMV_COMMON_BASE_A + 0x90)
+#define S5P_FIMV_H263_SA_MV_ADR (S5P_FIMV_COMMON_BASE_A + 0x94)
+#define S5P_FIMV_H263_OT_LINE_ADR (S5P_FIMV_COMMON_BASE_A + 0x98)
+
+/* VC-1 decoding */
+#define S5P_FIMV_VC1_NB_DCAC_ADR (S5P_FIMV_COMMON_BASE_A + 0x8c)
+#define S5P_FIMV_VC1_UP_NB_MV_ADR (S5P_FIMV_COMMON_BASE_A + 0x90)
+#define S5P_FIMV_VC1_SA_MV_ADR (S5P_FIMV_COMMON_BASE_A + 0x94)
+#define S5P_FIMV_VC1_OT_LINE_ADR (S5P_FIMV_COMMON_BASE_A + 0x98)
+#define S5P_FIMV_VC1_BITPLANE3_ADR (S5P_FIMV_COMMON_BASE_A + 0x9c) /* bitplane3 */
+#define S5P_FIMV_VC1_BITPLANE2_ADR (S5P_FIMV_COMMON_BASE_A + 0xa0) /* bitplane2 */
+#define S5P_FIMV_VC1_BITPLANE1_ADR (S5P_FIMV_COMMON_BASE_A + 0xa4) /* bitplane1 */
+
+/* Encoder */
+#define S5P_FIMV_ENC_REF0_LUMA_ADR (S5P_FIMV_COMMON_BASE_A + 0x1c) /* reconstructed luma */
+#define S5P_FIMV_ENC_REF1_LUMA_ADR (S5P_FIMV_COMMON_BASE_A + 0x20)
+#define S5P_FIMV_ENC_REF0_CHROMA_ADR (S5P_FIMV_COMMON_BASE_B) /* reconstructed chroma */
+#define S5P_FIMV_ENC_REF1_CHROMA_ADR (S5P_FIMV_COMMON_BASE_B + 0x04)
+#define S5P_FIMV_ENC_REF2_LUMA_ADR (S5P_FIMV_COMMON_BASE_B + 0x10)
+#define S5P_FIMV_ENC_REF2_CHROMA_ADR (S5P_FIMV_COMMON_BASE_B + 0x08)
+#define S5P_FIMV_ENC_REF3_LUMA_ADR (S5P_FIMV_COMMON_BASE_B + 0x14)
+#define S5P_FIMV_ENC_REF3_CHROMA_ADR (S5P_FIMV_COMMON_BASE_B + 0x0c)
+
+/* H.264 encoding */
+#define S5P_FIMV_H264_UP_MV_ADR (S5P_FIMV_COMMON_BASE_A) /* upper motion vector */
+#define S5P_FIMV_H264_NBOR_INFO_ADR (S5P_FIMV_COMMON_BASE_A + 0x04) /* entropy engine's neighbor info. */
+#define S5P_FIMV_H264_UP_INTRA_MD_ADR (S5P_FIMV_COMMON_BASE_A + 0x08) /* upper intra MD */
+#define S5P_FIMV_H264_COZERO_FLAG_ADR (S5P_FIMV_COMMON_BASE_A + 0x10) /* direct cozero flag */
+#define S5P_FIMV_H264_UP_INTRA_PRED_ADR (S5P_FIMV_COMMON_BASE_B + 0x40) /* upper intra PRED */
+
+/* H.263 encoding */
+#define S5P_FIMV_H263_UP_MV_ADR (S5P_FIMV_COMMON_BASE_A) /* upper motion vector */
+#define S5P_FIMV_H263_ACDC_COEF_ADR (S5P_FIMV_COMMON_BASE_A + 0x04) /* upper Q coeff. */
+
+/* MPEG4 encoding */
+#define S5P_FIMV_MPEG4_UP_MV_ADR (S5P_FIMV_COMMON_BASE_A) /* upper motion vector */
+#define S5P_FIMV_MPEG4_ACDC_COEF_ADR (S5P_FIMV_COMMON_BASE_A + 0x04) /* upper Q coeff. */
+#define S5P_FIMV_MPEG4_COZERO_FLAG_ADR (S5P_FIMV_COMMON_BASE_A + 0x10) /* direct cozero flag */
+
+#define S5P_FIMV_ENC_REF_B_LUMA_ADR 0x062c /* ref B Luma addr */
+#define S5P_FIMV_ENC_REF_B_CHROMA_ADR 0x0630 /* ref B Chroma addr */
+
+#define S5P_FIMV_ENC_CUR_LUMA_ADR 0x0718 /* current Luma addr */
+#define S5P_FIMV_ENC_CUR_CHROMA_ADR 0x071C /* current Chroma addr */
+
+/* Codec common register */
+#define S5P_FIMV_ENC_HSIZE_PX 0x0818 /* frame width at encoder */
+#define S5P_FIMV_ENC_VSIZE_PX 0x081c /* frame height at encoder */
+#define S5P_FIMV_ENC_PROFILE 0x0830 /* profile register */
+#define S5P_FIMV_ENC_PROFILE_H264_MAIN 0
+#define S5P_FIMV_ENC_PROFILE_H264_HIGH 1
+#define S5P_FIMV_ENC_PROFILE_H264_BASELINE 2
+#define S5P_FIMV_ENC_PROFILE_H264_CONSTRAINED_BASELINE 3
+#define S5P_FIMV_ENC_PROFILE_MPEG4_SIMPLE 0
+#define S5P_FIMV_ENC_PROFILE_MPEG4_ADVANCED_SIMPLE 1
+#define S5P_FIMV_ENC_PIC_STRUCT 0x083c /* picture field/frame flag */
+#define S5P_FIMV_ENC_LF_CTRL 0x0848 /* loop filter control */
+#define S5P_FIMV_ENC_ALPHA_OFF 0x084c /* loop filter alpha offset */
+#define S5P_FIMV_ENC_BETA_OFF 0x0850 /* loop filter beta offset */
+#define S5P_FIMV_MR_BUSIF_CTRL 0x0854 /* hidden, bus interface ctrl */
+#define S5P_FIMV_ENC_PXL_CACHE_CTRL 0x0a00 /* pixel cache control */
+
+/* Channel & stream interface register */
+#define S5P_FIMV_SI_RTN_CHID 0x2000 /* Return CH instance ID register */
+#define S5P_FIMV_SI_CH0_INST_ID 0x2040 /* codec instance ID */
+#define S5P_FIMV_SI_CH1_INST_ID 0x2080 /* codec instance ID */
+/* Decoder */
+#define S5P_FIMV_SI_VRESOL 0x2004 /* vertical resolution of decoder */
+#define S5P_FIMV_SI_HRESOL 0x2008 /* horizontal resolution of decoder */
+#define S5P_FIMV_SI_BUF_NUMBER 0x200c /* number of frames in the decoded pic */
+#define S5P_FIMV_SI_DISPLAY_Y_ADR 0x2010 /* luma address of displayed pic */
+#define S5P_FIMV_SI_DISPLAY_C_ADR 0x2014 /* chroma address of displayed pic */
+#define S5P_FIMV_SI_CONSUMED_BYTES 0x2018 /* Consumed number of bytes to decode
+ a frame */
+#define S5P_FIMV_SI_DISPLAY_STATUS 0x201c /* status of decoded picture */
+#define S5P_FIMV_SI_FRAME_TYPE 0x2020 /* frame type such as skip/I/P/B */
+#define S5P_FIMV_SI_DECODED_STATUS 0x202c /* status of decoded picture */
+#define S5P_FIMV_DEC_CRC_GEN_MASK 0x3
+#define S5P_FIMV_DEC_CRC_GEN_SHIFT 4
+
+#define S5P_FIMV_SI_CH0_SB_ST_ADR 0x2044 /* start addr of stream buf */
+#define S5P_FIMV_SI_CH0_SB_FRM_SIZE 0x2048 /* size of stream buf */
+#define S5P_FIMV_SI_CH0_DESC_ADR 0x204c /* addr of descriptor buf */
+#define S5P_FIMV_SI_CH0_CPB_SIZE 0x2058 /* max size of coded pic. buf */
+#define S5P_FIMV_SI_CH0_DESC_SIZE 0x205c /* max size of descriptor buf */
+
+#define S5P_FIMV_SI_CH1_SB_ST_ADR 0x2084 /* start addr of stream buf */
+#define S5P_FIMV_SI_CH1_SB_FRM_SIZE 0x2088 /* size of stream buf */
+#define S5P_FIMV_SI_CH1_DESC_ADR 0x208c /* addr of descriptor buf */
+#define S5P_FIMV_SI_CH1_CPB_SIZE 0x2098 /* max size of coded pic. buf */
+#define S5P_FIMV_SI_CH1_DESC_SIZE 0x209c /* max size of descriptor buf */
+
+#define S5P_FIMV_SI_FIMV1_HRESOL 0x2054 /* horizontal resolution */
+#define S5P_FIMV_SI_FIMV1_VRESOL 0x2050 /* vertical resolution */
+#define S5P_FIMV_CRC_LUMA0 0x2030 /* luma crc data per frame(top field)*/
+#define S5P_FIMV_CRC_CHROMA0 0x2034 /* chroma crc data per frame(top field)*/
+#define S5P_FIMV_CRC_LUMA1 0x2038 /* luma crc data per bottom field */
+#define S5P_FIMV_CRC_CHROMA1 0x203c /* chroma crc data per bottom field */
+
+/* Display status */
+#define S5P_FIMV_DEC_STATUS_DECODING_ONLY 0
+#define S5P_FIMV_DEC_STATUS_DECODING_DISPLAY 1
+#define S5P_FIMV_DEC_STATUS_DISPLAY_ONLY 2
+#define S5P_FIMV_DEC_STATUS_DECODING_EMPTY 3
+#define S5P_FIMV_DEC_STATUS_DECODING_STATUS_MASK 7
+#define S5P_FIMV_DEC_STATUS_PROGRESSIVE (0<<3)
+#define S5P_FIMV_DEC_STATUS_INTERLACE (1<<3)
+#define S5P_FIMV_DEC_STATUS_INTERLACE_MASK (1<<3)
+#define S5P_FIMV_DEC_STATUS_CRC_NUMBER_TWO (0<<4)
+#define S5P_FIMV_DEC_STATUS_CRC_NUMBER_FOUR (1<<4)
+#define S5P_FIMV_DEC_STATUS_CRC_NUMBER_MASK (1<<4)
+#define S5P_FIMV_DEC_STATUS_CRC_GENERATED (1<<5)
+#define S5P_FIMV_DEC_STATUS_CRC_NOT_GENERATED (0<<5)
+#define S5P_FIMV_DEC_STATUS_CRC_MASK (1<<5)
+
+#define S5P_FIMV_DEC_STATUS_RESOLUTION_MASK (3<<4)
+#define S5P_FIMV_DEC_STATUS_RESOLUTION_INC (1<<4)
+#define S5P_FIMV_DEC_STATUS_RESOLUTION_DEC (2<<4)
+#define S5P_FIMV_DEC_STATUS_RESOLUTION_SHIFT 4
+
+/* Decode frame address */
+#define S5P_FIMV_DECODE_Y_ADR 0x2024
+#define S5P_FIMV_DECODE_C_ADR 0x2028
+
+/* Decoded frame tpe */
+#define S5P_FIMV_DECODED_FRAME_TYPE 0x2020
+#define S5P_FIMV_DECODED_FRAME_MASK 7
+
+#define S5P_FIMV_DECODED_FRAME_NOT_CODED 0
+#define S5P_FIMV_DECODED_FRAME_I 1
+#define S5P_FIMV_DECODED_FRAME_P 2
+#define S5P_FIMV_DECODED_FRAME_B 3
+#define S5P_FIMV_DECODED_FRAME_OTHER 4
+
+/* Sizes of buffers required for decoding */
+#define S5P_FIMV_DEC_NB_IP_SIZE (32 * 1024)
+#define S5P_FIMV_DEC_VERT_NB_MV_SIZE (16 * 1024)
+#define S5P_FIMV_DEC_NB_DCAC_SIZE (16 * 1024)
+#define S5P_FIMV_DEC_UPNB_MV_SIZE (68 * 1024)
+#define S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE (136 * 1024)
+#define S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE (32 * 1024)
+#define S5P_FIMV_DEC_VC1_BITPLANE_SIZE (2 * 1024)
+#define S5P_FIMV_DEC_STX_PARSER_SIZE (68 * 1024)
+
+#define S5P_FIMV_DEC_BUF_ALIGN (8 * 1024)
+#define S5P_FIMV_ENC_BUF_ALIGN (8 * 1024)
+#define S5P_FIMV_NV12M_HALIGN 16
+#define S5P_FIMV_NV12M_LVALIGN 16
+#define S5P_FIMV_NV12M_CVALIGN 8
+#define S5P_FIMV_NV12MT_HALIGN 128
+#define S5P_FIMV_NV12MT_VALIGN 32
+#define S5P_FIMV_NV12M_SALIGN 2048
+#define S5P_FIMV_NV12MT_SALIGN 8192
+
+/* Sizes of buffers required for encoding */
+#define S5P_FIMV_ENC_UPMV_SIZE (0x10000)
+#define S5P_FIMV_ENC_COLFLG_SIZE (0x10000)
+#define S5P_FIMV_ENC_INTRAMD_SIZE (0x10000)
+#define S5P_FIMV_ENC_INTRAPRED_SIZE (0x4000)
+#define S5P_FIMV_ENC_NBORINFO_SIZE (0x10000)
+#define S5P_FIMV_ENC_ACDCCOEF_SIZE (0x10000)
+
+/* Encoder */
+#define S5P_FIMV_ENC_SI_STRM_SIZE 0x2004 /* stream size */
+#define S5P_FIMV_ENC_SI_PIC_CNT 0x2008 /* picture count */
+#define S5P_FIMV_ENC_SI_WRITE_PTR 0x200c /* write pointer */
+#define S5P_FIMV_ENC_SI_SLICE_TYPE 0x2010 /* slice type(I/P/B/IDR) */
+#define S5P_FIMV_ENCODED_TYPE_NOT_CODED 0
+#define S5P_FIMV_ENCODED_TYPE_I 1
+#define S5P_FIMV_ENCODED_TYPE_P 2
+#define S5P_FIMV_ENCODED_TYPE_B 3
+#define S5P_FIMV_ENCODED_TYPE_SKIPPED 4
+#define S5P_FIMV_ENCODED_Y_ADDR 0x2014 /* the addr of the encoded luma pic */
+#define S5P_FIMV_ENCODED_C_ADDR 0x2018 /* the addr of the encoded chroma pic */
+
+#define S5P_FIMV_ENC_SI_CH0_SB_ADR 0x2044 /* addr of stream buf */
+#define S5P_FIMV_ENC_SI_CH0_SB_SIZE 0x204c /* size of stream buf */
+#define S5P_FIMV_ENC_SI_CH0_CUR_Y_ADR 0x2050 /* current Luma addr */
+#define S5P_FIMV_ENC_SI_CH0_CUR_C_ADR 0x2054 /* current Chroma addr */
+#define S5P_FIMV_ENC_SI_CH0_FRAME_INS 0x2058 /* frame insertion */
+
+#define S5P_FIMV_ENC_SI_CH1_SB_ADR 0x2084 /* addr of stream buf */
+#define S5P_FIMV_ENC_SI_CH1_SB_SIZE 0x208c /* size of stream buf */
+#define S5P_FIMV_ENC_SI_CH1_CUR_Y_ADR 0x2090 /* current Luma addr */
+#define S5P_FIMV_ENC_SI_CH1_CUR_C_ADR 0x2094 /* current Chroma addr */
+#define S5P_FIMV_ENC_SI_CH1_FRAME_INS 0x2098 /* frame insertion */
+
+#define S5P_FIMV_ENC_PIC_TYPE_CTRL 0xc504 /* pic type level control */
+#define S5P_FIMV_ENC_B_RECON_WRITE_ON 0xc508 /* B frame recon write ctrl */
+#define S5P_FIMV_ENC_MSLICE_CTRL 0xc50c /* multi slice control */
+#define S5P_FIMV_ENC_MSLICE_MB 0xc510 /* MB number in the one slice */
+#define S5P_FIMV_ENC_MSLICE_BIT 0xc514 /* bit count for one slice */
+#define S5P_FIMV_ENC_CIR_CTRL 0xc518 /* number of intra refresh MB */
+#define S5P_FIMV_ENC_MAP_FOR_CUR 0xc51c /* linear or 64x32 tiled mode */
+#define S5P_FIMV_ENC_PADDING_CTRL 0xc520 /* padding control */
+
+#define S5P_FIMV_ENC_RC_CONFIG 0xc5a0 /* RC config */
+#define S5P_FIMV_ENC_RC_BIT_RATE 0xc5a8 /* bit rate */
+#define S5P_FIMV_ENC_RC_QBOUND 0xc5ac /* max/min QP */
+#define S5P_FIMV_ENC_RC_RPARA 0xc5b0 /* rate control reaction coeff */
+#define S5P_FIMV_ENC_RC_MB_CTRL 0xc5b4 /* MB adaptive scaling */
+
+/* Encoder for H264 only */
+#define S5P_FIMV_ENC_H264_ENTRP_MODE 0xd004 /* CAVLC or CABAC */
+#define S5P_FIMV_ENC_H264_ALPHA_OFF 0xd008 /* loop filter alpha offset */
+#define S5P_FIMV_ENC_H264_BETA_OFF 0xd00c /* loop filter beta offset */
+#define S5P_FIMV_ENC_H264_NUM_OF_REF 0xd010 /* number of reference for P/B */
+#define S5P_FIMV_ENC_H264_TRANS_FLAG 0xd034 /* 8x8 transform flag in PPS & high profile */
+
+#define S5P_FIMV_ENC_RC_FRAME_RATE 0xd0d0 /* frame rate */
+
+/* Encoder for MPEG4 only */
+#define S5P_FIMV_ENC_MPEG4_QUART_PXL 0xe008 /* qpel interpolation ctrl */
+
+/* Additional */
+#define S5P_FIMV_SI_CH0_DPB_CONF_CTRL 0x2068 /* DPB Config Control Register */
+#define S5P_FIMV_SLICE_INT_MASK 1
+#define S5P_FIMV_SLICE_INT_SHIFT 31
+#define S5P_FIMV_DDELAY_ENA_SHIFT 30
+#define S5P_FIMV_DDELAY_VAL_MASK 0xff
+#define S5P_FIMV_DDELAY_VAL_SHIFT 16
+#define S5P_FIMV_DPB_COUNT_MASK 0xffff
+
+#define S5P_FIMV_SI_CH0_RELEASE_BUF 0x2060 /* DPB release buffer register */
+#define S5P_FIMV_SI_CH0_HOST_WR_ADR 0x2064 /* address of shared memory */
+
+/* Codec numbers */
+#define MFC_FORMATS_NO_CODEC -1
+
+#define S5P_FIMV_CODEC_H264_DEC 0
+#define S5P_FIMV_CODEC_VC1_DEC 1
+#define S5P_FIMV_CODEC_MPEG4_DEC 2
+#define S5P_FIMV_CODEC_MPEG2_DEC 3
+#define S5P_FIMV_CODEC_H263_DEC 4
+#define S5P_FIMV_CODEC_VC1RCV_DEC 5
+#define S5P_FIMV_CODEC_FIMV1_DEC 6
+#define S5P_FIMV_CODEC_FIMV2_DEC 7
+#define S5P_FIMV_CODEC_FIMV3_DEC 8
+#define S5P_FIMV_CODEC_FIMV4_DEC 9
+
+#define S5P_FIMV_CODEC_H264_ENC 16
+#define S5P_FIMV_CODEC_MPEG4_ENC 17
+#define S5P_FIMV_CODEC_H263_ENC 18
+
+/* Channel Control Register */
+#define S5P_FIMV_CH_SEQ_HEADER 1
+#define S5P_FIMV_CH_FRAME_START 2
+#define S5P_FIMV_CH_LAST_FRAME 3
+#define S5P_FIMV_CH_INIT_BUFS 4
+#define S5P_FIMV_CH_FRAME_START_REALLOC 5
+
+#define S5P_FIMV_CH_MASK 7
+#define S5P_FIMV_CH_SHIFT 16
+
+/* Host to RISC command */
+#define S5P_FIMV_H2R_CMD_EMPTY 0
+#define S5P_FIMV_H2R_CMD_OPEN_INSTANCE 1
+#define S5P_FIMV_H2R_CMD_CLOSE_INSTANCE 2
+#define S5P_FIMV_H2R_CMD_SYS_INIT 3
+#define S5P_FIMV_H2R_CMD_FLUSH 4
+#define S5P_FIMV_H2R_CMD_SLEEP 5
+#define S5P_FIMV_H2R_CMD_WAKEUP 6
+
+#define S5P_FIMV_R2H_CMD_EMPTY 0
+#define S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET 1
+#define S5P_FIMV_R2H_CMD_CLOSE_INSTANCE_RET 2
+#define S5P_FIMV_R2H_CMD_RSV_RET 3
+#define S5P_FIMV_R2H_CMD_SEQ_DONE_RET 4
+#define S5P_FIMV_R2H_CMD_FRAME_DONE_RET 5
+#define S5P_FIMV_R2H_CMD_SLICE_DONE_RET 6
+#define S5P_FIMV_R2H_CMD_ENC_COMPLETE_RET 7
+#define S5P_FIMV_R2H_CMD_SYS_INIT_RET 8
+#define S5P_FIMV_R2H_CMD_FW_STATUS_RET 9
+#define S5P_FIMV_R2H_CMD_SLEEP_RET 10
+#define S5P_FIMV_R2H_CMD_WAKEUP_RET 11
+#define S5P_FIMV_R2H_CMD_FLUSH_RET 12
+#define S5P_FIMV_R2H_CMD_INIT_BUFFERS_RET 15
+#define S5P_FIMV_R2H_CMD_EDFU_INIT_RET 16
+#define S5P_FIMV_R2H_CMD_ERR_RET 32
+
+/* Dummy definition for MFCv6 compatibilty */
+#define S5P_FIMV_CODEC_H264_MVC_DEC -1
+#define S5P_FIMV_R2H_CMD_FIELD_DONE_RET -1
+#define S5P_FIMV_MFC_RESET -1
+#define S5P_FIMV_RISC_ON -1
+#define S5P_FIMV_RISC_BASE_ADDRESS -1
+#define S5P_FIMV_CODEC_VP8_DEC -1
+#define S5P_FIMV_REG_CLEAR_BEGIN 0
+#define S5P_FIMV_REG_CLEAR_COUNT 0
+#define S5P_FIMV_CRC_DISP_LUMA0 S5P_FIMV_CRC_LUMA0
+#define S5P_FIMV_CRC_DISP_CHROMA0 S5P_FIMV_CRC_CHROMA0
+#define S5P_FIMV_CRC_DISP_STATUS S5P_FIMV_SI_DECODED_STATUS
+#define S5P_FIMV_D_MVC_VIEW_ID 0
+#define S5P_FIMV_MFC_BUS_RESET_CTRL -1
+#define S5P_FIMV_D_MIN_NUM_MV -1
+#define S5P_FIMV_D_NUM_MV -1
+#define S5P_FIMV_MFC_VERSION 0
+#define S5P_FIMV_ERR_FRAME_CONCEAL -1
+
+/* Error handling defines */
+#define S5P_FIMV_ERR_WARNINGS_START 145
+#define S5P_FIMV_ERR_DEC_MASK 0xFFFF
+#define S5P_FIMV_ERR_DEC_SHIFT 0
+#define S5P_FIMV_ERR_DSPL_MASK 0xFFFF0000
+#define S5P_FIMV_ERR_DSPL_SHIFT 16
+
+/* Shared memory registers' offsets */
+
+/* An offset of the start position in the stream when
+ * the start position is not aligned */
+#define S5P_FIMV_SHARED_CROP_INFO_H 0x0020
+#define S5P_FIMV_SHARED_CROP_LEFT_MASK 0xFFFF
+#define S5P_FIMV_SHARED_CROP_LEFT_SHIFT 0
+#define S5P_FIMV_SHARED_CROP_RIGHT_MASK 0xFFFF0000
+#define S5P_FIMV_SHARED_CROP_RIGHT_SHIFT 16
+#define S5P_FIMV_SHARED_CROP_INFO_V 0x0024
+#define S5P_FIMV_SHARED_CROP_TOP_MASK 0xFFFF
+#define S5P_FIMV_SHARED_CROP_TOP_SHIFT 0
+#define S5P_FIMV_SHARED_CROP_BOTTOM_MASK 0xFFFF0000
+#define S5P_FIMV_SHARED_CROP_BOTTOM_SHIFT 16
+#define S5P_FIMV_SHARED_SET_FRAME_TAG 0x0004
+#define S5P_FIMV_SHARED_GET_FRAME_TAG_TOP 0x0008
+#define S5P_FIMV_SHARED_GET_FRAME_TAG_BOT 0x000C
+#define S5P_FIMV_SHARED_START_BYTE_NUM 0x0018
+#define S5P_FIMV_SHARED_PARAM_CHANGE 0x002c
+#define S5P_FIMV_SHARED_RC_VOP_TIMING 0x0030
+#define S5P_FIMV_SHARED_LUMA_DPB_SIZE 0x0064
+#define S5P_FIMV_SHARED_CHROMA_DPB_SIZE 0x0068
+#define S5P_FIMV_SHARED_MV_SIZE 0x006C
+#define S5P_FIMV_SHARED_PIC_TIME_TOP 0x0010
+#define S5P_FIMV_SHARED_PIC_TIME_BOTTOM 0x0014
+#define S5P_FIMV_SHARED_EXT_ENC_CONTROL 0x0028
+#define S5P_FIMV_SHARED_P_B_FRAME_QP 0x0070
+#define S5P_FIMV_SHARED_ASPECT_RATIO_IDC 0x0074
+#define S5P_FIMV_SHARED_EXTENDED_SAR 0x0078
+#define S5P_FIMV_SHARED_NEW_RC_BIT_RATE 0x0090
+#define S5P_FIMV_SHARED_NEW_RC_FRAME_RATE 0x0094
+#define S5P_FIMV_SHARED_NEW_I_PERIOD 0x0098
+#define S5P_FIMV_SHARED_H264_I_PERIOD 0x009C
+#define S5P_FIMV_SHARED_RC_CONTROL_CONFIG 0x00A0
+#define S5P_FIMV_SHARED_DISP_FRAME_TYPE_SHIFT 2
+
+#define S5P_FIMV_SHARED_FRAME_PACK_SEI_AVAIL 0x16C
+#define S5P_FIMV_SHARED_FRAME_PACK_ARRGMENT_ID 0x170
+#define S5P_FIMV_SHARED_FRAME_PACK_SEI_INFO 0x174
+#define S5P_FIMV_SHARED_FRAME_PACK_GRID_POS 0x178
+
+/* SEI related information */
+#define S5P_FIMV_FRAME_PACK_SEI_AVAIL S5P_FIMV_SHARED_FRAME_PACK_SEI_AVAIL
+#define S5P_FIMV_FRAME_PACK_ARRGMENT_ID S5P_FIMV_SHARED_FRAME_PACK_ARRGMENT_ID
+#define S5P_FIMV_FRAME_PACK_SEI_INFO S5P_FIMV_SHARED_FRAME_PACK_SEI_INFO
+#define S5P_FIMV_FRAME_PACK_GRID_POS S5P_FIMV_SHARED_FRAME_PACK_GRID_POS
+
+#define S5P_FIMV_SHARED_SET_E_FRAME_TAG S5P_FIMV_SHARED_SET_FRAME_TAG
+#define S5P_FIMV_SHARED_GET_E_FRAME_TAG S5P_FIMV_SHARED_GET_FRAME_TAG_TOP
+#define S5P_FIMV_ENCODED_LUMA_ADDR S5P_FIMV_ENCODED_Y_ADDR
+#define S5P_FIMV_ENCODED_CHROMA_ADDR S5P_FIMV_ENCODED_C_ADDR
+#define S5P_FIMV_FRAME_INSERTION S5P_FIMV_ENC_SI_CH0_FRAME_INS
+
+#define S5P_FIMV_PARAM_CHANGE_FLAG S5P_FIMV_SHARED_PARAM_CHANGE /* flag */
+#define S5P_FIMV_NEW_I_PERIOD S5P_FIMV_SHARED_NEW_I_PERIOD
+#define S5P_FIMV_NEW_RC_FRAME_RATE S5P_FIMV_SHARED_NEW_RC_FRAME_RATE
+#define S5P_FIMV_NEW_RC_BIT_RATE S5P_FIMV_SHARED_NEW_RC_BIT_RATE
+
+#endif /* _REGS_FIMV_V5_H */
diff --git a/drivers/media/video/exynos/mfc/regs-mfc-v6.h b/drivers/media/video/exynos/mfc/regs-mfc-v6.h
new file mode 100644
index 0000000..e9286ce
--- /dev/null
+++ b/drivers/media/video/exynos/mfc/regs-mfc-v6.h
@@ -0,0 +1,687 @@
+/*
+ * Register definition file for Samsung MFC V5/V6 Interface (FIMV) driver
+ *
+ * Kamil Debski, Copyright (c) 2010 Samsung Electronics
+ * http://www.samsung.com/
+ *
+ * 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.
+*/
+
+#ifndef _REGS_FIMV_V6_H
+#define _REGS_FIMV_V6_H
+
+#define S5P_FIMV_REG_SIZE (S5P_FIMV_END_ADDR - S5P_FIMV_START_ADDR)
+#define S5P_FIMV_REG_COUNT ((S5P_FIMV_END_ADDR - S5P_FIMV_START_ADDR) / 4)
+
+/* Number of bits that the buffer address should be shifted for particular
+ * MFC buffers. */
+#define S5P_FIMV_MEM_OFFSET 0
+
+#define S5P_FIMV_START_ADDR 0x0000
+#define S5P_FIMV_END_ADDR 0xfd80
+
+#define S5P_FIMV_REG_CLEAR_BEGIN 0xf000
+#define S5P_FIMV_REG_CLEAR_COUNT 1024
+
+/* Codec Common Registers */
+#define S5P_FIMV_RISC_ON 0x0000
+#define S5P_FIMV_RISC2HOST_INT 0x003C
+#define S5P_FIMV_HOST2RISC_INT 0x0044
+#define S5P_FIMV_RISC_BASE_ADDRESS 0x0054
+
+#define S5P_FIMV_MFC_RESET 0x1070
+
+#define S5P_FIMV_HOST2RISC_CMD 0x1100
+#define S5P_FIMV_H2R_CMD_EMPTY 0
+#define S5P_FIMV_H2R_CMD_SYS_INIT 1
+#define S5P_FIMV_H2R_CMD_OPEN_INSTANCE 2
+#define S5P_FIMV_CH_SEQ_HEADER 3
+#define S5P_FIMV_CH_INIT_BUFS 4
+#define S5P_FIMV_CH_FRAME_START 5
+#define S5P_FIMV_H2R_CMD_CLOSE_INSTANCE 6
+#define S5P_FIMV_H2R_CMD_SLEEP 7
+#define S5P_FIMV_H2R_CMD_WAKEUP 8
+#define S5P_FIMV_CH_LAST_FRAME 9
+#define S5P_FIMV_H2R_CMD_FLUSH 10
+/* RMVME: REALLOC used? */
+#define S5P_FIMV_CH_FRAME_START_REALLOC 5
+
+#define S5P_FIMV_RISC2HOST_CMD 0x1104
+#define S5P_FIMV_R2H_CMD_EMPTY 0
+#define S5P_FIMV_R2H_CMD_SYS_INIT_RET 1
+#define S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET 2
+#define S5P_FIMV_R2H_CMD_SEQ_DONE_RET 3
+#define S5P_FIMV_R2H_CMD_INIT_BUFFERS_RET 4
+
+#define S5P_FIMV_R2H_CMD_CLOSE_INSTANCE_RET 6
+#define S5P_FIMV_R2H_CMD_SLEEP_RET 7
+#define S5P_FIMV_R2H_CMD_WAKEUP_RET 8
+#define S5P_FIMV_R2H_CMD_COMPLETE_SEQ_RET 9
+#define S5P_FIMV_R2H_CMD_DPB_FLUSH_RET 10
+#define S5P_FIMV_R2H_CMD_NAL_ABORT_RET 11
+#define S5P_FIMV_R2H_CMD_FW_STATUS_RET 12
+#define S5P_FIMV_R2H_CMD_FRAME_DONE_RET 13
+#define S5P_FIMV_R2H_CMD_FIELD_DONE_RET 14
+#define S5P_FIMV_R2H_CMD_SLICE_DONE_RET 15
+#define S5P_FIMV_R2H_CMD_ENC_BUFFER_FUL_RET 16
+#define S5P_FIMV_R2H_CMD_ERR_RET 32
+
+#define S5P_FIMV_MFC_BUS_RESET_CTRL 0x7110
+#define S5P_FIMV_FW_VERSION 0xF000
+
+#define S5P_FIMV_INSTANCE_ID 0xF008
+#define S5P_FIMV_CODEC_TYPE 0xF00C
+#define S5P_FIMV_CONTEXT_MEM_ADDR 0xF014
+#define S5P_FIMV_CONTEXT_MEM_SIZE 0xF018
+#define S5P_FIMV_PIXEL_FORMAT 0xF020
+
+#define S5P_FIMV_METADATA_ENABLE 0xF024
+#define S5P_FIMV_MFC_VERSION 0xF028
+#define S5P_FIMV_DBG_BUFFER_ADDR 0xF030
+#define S5P_FIMV_DBG_BUFFER_SIZE 0xF034
+#define S5P_FIMV_RET_INSTANCE_ID 0xF070
+
+#define S5P_FIMV_ERROR_CODE 0xF074
+#define S5P_FIMV_ERR_WARNINGS_START 160
+#define S5P_FIMV_ERR_DEC_MASK 0xFFFF
+#define S5P_FIMV_ERR_DEC_SHIFT 0
+#define S5P_FIMV_ERR_DSPL_MASK 0xFFFF0000
+#define S5P_FIMV_ERR_DSPL_SHIFT 16
+
+#define S5P_FIMV_DBG_BUFFER_OUTPUT_SIZE 0xF078
+#define S5P_FIMV_METADATA_STATUS 0xF07C
+#define S5P_FIMV_METADATA_ADDR_MB_INFO 0xF080
+#define S5P_FIMV_METADATA_SIZE_MB_INFO 0xF084
+
+/* Decoder Registers */
+#define S5P_FIMV_D_CRC_CTRL 0xF0B0
+#define S5P_FIMV_D_DEC_OPTIONS 0xF0B4
+#define S5P_FIMV_D_OPT_FMO_ASO_CTRL_MASK 4
+#define S5P_FIMV_D_OPT_DDELAY_EN_SHIFT 3
+#define S5P_FIMV_D_OPT_LF_CTRL_SHIFT 1
+#define S5P_FIMV_D_OPT_LF_CTRL_MASK 0x3
+#define S5P_FIMV_D_OPT_TILE_MODE_SHIFT 0
+
+#define S5P_FIMV_D_DISPLAY_DELAY 0xF0B8
+
+#define S5P_FIMV_D_SET_FRAME_WIDTH 0xF0BC
+#define S5P_FIMV_D_SET_FRAME_HEIGHT 0xF0C0
+
+#define S5P_FIMV_D_SEI_ENABLE 0xF0C4
+
+/* Buffer setting registers */
+#define S5P_FIMV_D_MIN_NUM_DPB 0xF0F0
+#define S5P_FIMV_D_MIN_LUMA_DPB_SIZE 0xF0F4
+#define S5P_FIMV_D_MIN_CHROMA_DPB_SIZE 0xF0F8
+#define S5P_FIMV_D_MVC_NUM_VIEWS 0xF0FC
+#define S5P_FIMV_D_MIN_NUM_MV 0xF100
+#define S5P_FIMV_D_NUM_DPB 0xF130
+#define S5P_FIMV_D_LUMA_DPB_SIZE 0xF134
+#define S5P_FIMV_D_CHROMA_DPB_SIZE 0xF138
+#define S5P_FIMV_D_MV_BUFFER_SIZE 0xF13C
+
+#define S5P_FIMV_D_LUMA_DPB 0xF140
+#define S5P_FIMV_D_CHROMA_DPB 0xF240
+#define S5P_FIMV_D_MV_BUFFER 0xF340
+
+#define S5P_FIMV_D_SCRATCH_BUFFER_ADDR 0xF440
+#define S5P_FIMV_D_SCRATCH_BUFFER_SIZE 0xF444
+#define S5P_FIMV_D_METADATA_BUFFER_ADDR 0xF448
+#define S5P_FIMV_D_METADATA_BUFFER_SIZE 0xF44C
+#define S5P_FIMV_D_NUM_MV 0xF478
+#define S5P_FIMV_D_CPB_BUFFER_ADDR 0xF4B0
+#define S5P_FIMV_D_CPB_BUFFER_SIZE 0xF4B4
+
+#define S5P_FIMV_D_AVAILABLE_DPB_FLAG_UPPER 0xF4B8
+#define S5P_FIMV_D_AVAILABLE_DPB_FLAG_LOWER 0xF4BC
+#define S5P_FIMV_D_CPB_BUFFER_OFFSET 0xF4C0
+#define S5P_FIMV_D_SLICE_IF_ENABLE 0xF4C4
+#define S5P_FIMV_D_PICTURE_TAG 0xF4C8
+#define S5P_FIMV_D_STREAM_DATA_SIZE 0xF4D0
+
+/* Display information register */
+#define S5P_FIMV_D_DISPLAY_FRAME_WIDTH 0xF500
+#define S5P_FIMV_D_DISPLAY_FRAME_HEIGHT 0xF504
+
+/* Display status */
+#define S5P_FIMV_D_DISPLAY_STATUS 0xF508
+#define S5P_FIMV_DEC_STATUS_DECODING_ONLY 0
+#define S5P_FIMV_DEC_STATUS_DECODING_DISPLAY 1
+#define S5P_FIMV_DEC_STATUS_DISPLAY_ONLY 2
+#define S5P_FIMV_DEC_STATUS_DECODING_EMPTY 3
+#define S5P_FIMV_DEC_STATUS_DECODING_STATUS_MASK 7
+#define S5P_FIMV_DEC_STATUS_PROGRESSIVE (0<<3)
+#define S5P_FIMV_DEC_STATUS_INTERLACE (1<<3)
+#define S5P_FIMV_DEC_STATUS_INTERLACE_MASK (1<<3)
+#define S5P_FIMV_DEC_STATUS_RESOLUTION_MASK (3<<4)
+#define S5P_FIMV_DEC_STATUS_RESOLUTION_INC (1<<4)
+#define S5P_FIMV_DEC_STATUS_RESOLUTION_DEC (2<<4)
+#define S5P_FIMV_DEC_STATUS_RESOLUTION_SHIFT 4
+#define S5P_FIMV_DEC_STATUS_CRC_GENERATED (1<<5)
+#define S5P_FIMV_DEC_STATUS_CRC_NOT_GENERATED (0<<5)
+#define S5P_FIMV_DEC_STATUS_CRC_MASK (1<<5)
+
+#define S5P_FIMV_D_DISPLAY_LUMA_ADDR 0xF50C
+#define S5P_FIMV_D_DISPLAY_CHROMA_ADDR 0xF510
+
+#define S5P_FIMV_D_DISPLAY_FRAME_TYPE 0xF514
+#define S5P_FIMV_DISPLAY_FRAME_MASK 7
+#define S5P_FIMV_DISPLAY_FRAME_NOT_CODED 0
+#define S5P_FIMV_DISPLAY_FRAME_I 1
+#define S5P_FIMV_DISPLAY_FRAME_P 2
+#define S5P_FIMV_DISPLAY_FRAME_B 3
+#define S5P_FIMV_DISPLAY_FRAME_S_VOP 4 /* MPEG4 */
+#define S5P_FIMV_SHARED_CROP_INFO_H 0x0020
+#define S5P_FIMV_SHARED_CROP_LEFT_MASK 0xFFFF
+#define S5P_FIMV_SHARED_CROP_LEFT_SHIFT 0
+#define S5P_FIMV_SHARED_CROP_RIGHT_MASK 0xFFFF0000
+#define S5P_FIMV_SHARED_CROP_RIGHT_SHIFT 16
+#define S5P_FIMV_SHARED_CROP_INFO_V 0x0024
+#define S5P_FIMV_SHARED_CROP_TOP_MASK 0xFFFF
+#define S5P_FIMV_SHARED_CROP_TOP_SHIFT 0
+#define S5P_FIMV_SHARED_CROP_BOTTOM_MASK 0xFFFF0000
+#define S5P_FIMV_SHARED_CROP_BOTTOM_SHIFT 16
+
+#define S5P_FIMV_D_DISPLAY_CROP_INFO1 0xF518
+#define S5P_FIMV_D_DISPLAY_CROP_INFO2 0xF51C
+#define S5P_FIMV_D_DISPLAY_PICTURE_PROFILE 0xF520
+#define S5P_FIMV_D_DISPLAY_LUMA_CRC_TOP 0xF524
+#define S5P_FIMV_D_DISPLAY_CHROMA_CRC_TOP 0xF528
+#define S5P_FIMV_D_DISPLAY_LUMA_CRC_BOT 0xF52C
+#define S5P_FIMV_D_DISPLAY_CHROMA_CRC_BOT 0xF530
+#define S5P_FIMV_D_DISPLAY_ASPECT_RATIO 0xF534
+#define S5P_FIMV_D_DISPLAY_EXTENDED_AR 0xF538
+
+/* Decoded picture information register */
+#define S5P_FIMV_D_DECODED_FRAME_WIDTH 0xF53C
+#define S5P_FIMV_D_DECODED_FRAME_HEIGHT 0xF540
+#define S5P_FIMV_D_DECODED_STATUS 0xF544
+#define S5P_FIMV_DEC_CRC_GEN_MASK 0x1
+#define S5P_FIMV_DEC_CRC_GEN_SHIFT 6
+
+#define S5P_FIMV_D_DECODED_LUMA_ADDR 0xF548
+#define S5P_FIMV_D_DECODED_CHROMA_ADDR 0xF54C
+
+#define S5P_FIMV_D_DECODED_FRAME_TYPE 0xF550
+#define S5P_FIMV_DECODED_FRAME_MASK 7
+#define S5P_FIMV_DECODED_FRAME_NOT_CODED 0
+#define S5P_FIMV_DECODED_FRAME_I 1
+#define S5P_FIMV_DECODED_FRAME_P 2
+#define S5P_FIMV_DECODED_FRAME_B 3
+#define S5P_FIMV_DECODED_FRAME_S_VOP 4 /* MPEG4 */
+#define S5P_FIMV_DECODED_FRAME_NON_DISPLAY 5 /* VP8 */
+
+#define S5P_FIMV_D_DECODED_CROP_INFO1 0xF554
+#define S5P_FIMV_D_DECODED_CROP_INFO2 0xF558
+#define S5P_FIMV_D_DECODED_PICTURE_PROFILE 0xF55C
+#define S5P_FIMV_D_DECODED_NAL_SIZE 0xF560
+#define S5P_FIMV_D_DECODED_LUMA_CRC_TOP 0xF564
+#define S5P_FIMV_D_DECODED_CHROMA_CRC_TOP 0xF568
+#define S5P_FIMV_D_DECODED_LUMA_CRC_BOT 0xF56C
+#define S5P_FIMV_D_DECODED_CHROMA_CRC_BOT 0xF570
+
+/* Returned value register for specific setting */
+#define S5P_FIMV_D_RET_PICTURE_TAG_TOP 0xF574
+#define S5P_FIMV_D_RET_PICTURE_TAG_BOT 0xF578
+#define S5P_FIMV_D_RET_PICTURE_TIME_TOP 0xF57C
+#define S5P_FIMV_D_RET_PICTURE_TIME_BOT 0xF580
+#define S5P_FIMV_D_CHROMA_FORMAT 0xF588
+#define S5P_FIMV_D_MPEG4_INFO 0xF58C
+#define S5P_FIMV_D_H264_INFO 0xF590
+
+#define S5P_FIMV_D_METADATA_ADDR_CONCEALED_MB 0xF594
+#define S5P_FIMV_D_METADATA_SIZE_CONCEALED_MB 0xF598
+#define S5P_FIMV_D_METADATA_ADDR_VC1_PARAM 0xF59C
+#define S5P_FIMV_D_METADATA_SIZE_VC1_PARAM 0xF5A0
+#define S5P_FIMV_D_METADATA_ADDR_SEI_NAL 0xF5A4
+#define S5P_FIMV_D_METADATA_SIZE_SEI_NAL 0xF5A8
+#define S5P_FIMV_D_METADATA_ADDR_VUI 0xF5AC
+#define S5P_FIMV_D_METADATA_SIZE_VUI 0xF5B0
+
+#define S5P_FIMV_D_MVC_VIEW_ID 0xF5B4
+#define S5P_FIMV_D_MVC_VIEW_ID_DISP_MASK 0xFFFF
+
+/* SEI related information */
+#define S5P_FIMV_D_FRAME_PACK_SEI_AVAIL 0xF5F0
+#define S5P_FIMV_D_FRAME_PACK_ARRGMENT_ID 0xF5F4
+#define S5P_FIMV_D_FRAME_PACK_SEI_INFO 0xF5F8
+#define S5P_FIMV_D_FRAME_PACK_GRID_POS 0xF5FC
+
+/* Encoder Registers */
+#define S5P_FIMV_E_FRAME_WIDTH 0xF770
+#define S5P_FIMV_E_FRAME_HEIGHT 0xF774
+#define S5P_FIMV_E_CROPPED_FRAME_WIDTH 0xF778
+#define S5P_FIMV_E_CROPPED_FRAME_HEIGHT 0xF77C
+#define S5P_FIMV_E_FRAME_CROP_OFFSET 0xF780
+#define S5P_FIMV_E_ENC_OPTIONS 0xF784
+#define S5P_FIMV_E_PICTURE_PROFILE 0xF788
+#define S5P_FIMV_ENC_PROFILE_H264_BASELINE 0
+#define S5P_FIMV_ENC_PROFILE_H264_MAIN 1
+#define S5P_FIMV_ENC_PROFILE_H264_HIGH 2
+#define S5P_FIMV_ENC_PROFILE_H264_CONSTRAINED_BASELINE 3
+#define S5P_FIMV_ENC_PROFILE_MPEG4_SIMPLE 0
+#define S5P_FIMV_ENC_PROFILE_MPEG4_ADVANCED_SIMPLE 1
+#define S5P_FIMV_E_FIXED_PICTURE_QP 0xF790
+
+#define S5P_FIMV_E_RC_CONFIG 0xF794
+#define S5P_FIMV_E_RC_QP_BOUND 0xF798
+#define S5P_FIMV_E_RC_RPARAM 0xF79C
+#define S5P_FIMV_E_MB_RC_CONFIG 0xF7A0
+#define S5P_FIMV_E_PADDING_CTRL 0xF7A4
+#define S5P_FIMV_E_MV_HOR_RANGE 0xF7AC
+#define S5P_FIMV_E_MV_VER_RANGE 0xF7B0
+
+#define S5P_FIMV_E_VBV_BUFFER_SIZE 0xF84C
+#define S5P_FIMV_E_VBV_INIT_DELAY 0xF850
+#define S5P_FIMV_E_NUM_DPB 0xF890
+#define S5P_FIMV_E_LUMA_DPB 0xF8C0
+#define S5P_FIMV_E_CHROMA_DPB 0xF904
+#define S5P_FIMV_E_ME_BUFFER 0xF948
+
+#define S5P_FIMV_E_SCRATCH_BUFFER_ADDR 0xF98C
+#define S5P_FIMV_E_SCRATCH_BUFFER_SIZE 0xF990
+#define S5P_FIMV_E_TMV_BUFFER0 0xF994
+#define S5P_FIMV_E_TMV_BUFFER1 0xF998
+#define S5P_FIMV_E_SOURCE_LUMA_ADDR 0xF9F0
+#define S5P_FIMV_E_SOURCE_CHROMA_ADDR 0xF9F4
+#define S5P_FIMV_E_STREAM_BUFFER_ADDR 0xF9F8
+#define S5P_FIMV_E_STREAM_BUFFER_SIZE 0xF9FC
+#define S5P_FIMV_E_ROI_BUFFER_ADDR 0xFA00
+
+#define S5P_FIMV_E_PARAM_CHANGE 0xFA04
+#define S5P_FIMV_E_IR_SIZE 0xFA08
+#define S5P_FIMV_E_GOP_CONFIG 0xFA0C
+#define S5P_FIMV_E_MSLICE_MODE 0xFA10
+#define S5P_FIMV_E_MSLICE_SIZE_MB 0xFA14
+#define S5P_FIMV_E_MSLICE_SIZE_BITS 0xFA18
+#define S5P_FIMV_E_FRAME_INSERTION 0xFA1C
+
+#define S5P_FIMV_E_RC_FRAME_RATE 0xFA20
+#define S5P_FIMV_E_RC_BIT_RATE 0xFA24
+#define S5P_FIMV_E_RC_QP_OFFSET 0xFA28
+#define S5P_FIMV_E_RC_ROI_CTRL 0xFA2C
+#define S5P_FIMV_E_PICTURE_TAG 0xFA30
+#define S5P_FIMV_E_BIT_COUNT_ENABLE 0xFA34
+#define S5P_FIMV_E_MAX_BIT_COUNT 0xFA38
+#define S5P_FIMV_E_MIN_BIT_COUNT 0xFA3C
+
+#define S5P_FIMV_E_METADATA_BUFFER_ADDR 0xFA40
+#define S5P_FIMV_E_METADATA_BUFFER_SIZE 0xFA44
+#define S5P_FIMV_E_STREAM_SIZE 0xFA80
+#define S5P_FIMV_E_SLICE_TYPE 0xFA84
+#define S5P_FIMV_ENCODED_TYPE_NOT_CODED 0
+#define S5P_FIMV_ENCODED_TYPE_I 1
+#define S5P_FIMV_ENCODED_TYPE_P 2
+#define S5P_FIMV_ENCODED_TYPE_B 3
+#define S5P_FIMV_ENCODED_TYPE_SKIPPED 4
+#define S5P_FIMV_E_PICTURE_COUNT 0xFA88
+#define S5P_FIMV_E_RET_PICTURE_TAG 0xFA8C
+#define S5P_FIMV_E_STREAM_BUFFER_WRITE_POINTER 0xFA90
+
+#define S5P_FIMV_E_ENCODED_SOURCE_LUMA_ADDR 0xFA94
+#define S5P_FIMV_E_ENCODED_SOURCE_CHROMA_ADDR 0xFA98
+#define S5P_FIMV_E_RECON_LUMA_DPB_ADDR 0xFA9C
+#define S5P_FIMV_E_RECON_CHROMA_DPB_ADDR 0xFAA0
+#define S5P_FIMV_E_METADATA_ADDR_ENC_SLICE 0xFAA4
+#define S5P_FIMV_E_METADATA_SIZE_ENC_SLICE 0xFAA8
+
+#define S5P_FIMV_E_MPEG4_OPTIONS 0xFB10
+#define S5P_FIMV_E_MPEG4_HEC_PERIOD 0xFB14
+#define S5P_FIMV_E_ASPECT_RATIO 0xFB50
+#define S5P_FIMV_E_EXTENDED_SAR 0xFB54
+
+#define S5P_FIMV_E_H264_OPTIONS 0xFB58
+#define S5P_FIMV_E_H264_LF_ALPHA_OFFSET 0xFB5C
+#define S5P_FIMV_E_H264_LF_BETA_OFFSET 0xFB60
+#define S5P_FIMV_E_H264_I_PERIOD 0xFB64
+
+#define S5P_FIMV_E_H264_FMO_SLICE_GRP_MAP_TYPE 0xFB68
+#define S5P_FIMV_E_H264_FMO_NUM_SLICE_GRP_MINUS1 0xFB6C
+#define S5P_FIMV_E_H264_FMO_SLICE_GRP_CHANGE_DIR 0xFB70
+#define S5P_FIMV_E_H264_FMO_SLICE_GRP_CHANGE_RATE_MINUS1 0xFB74
+#define S5P_FIMV_E_H264_FMO_RUN_LENGTH_MINUS1_0 0xFB78
+#define S5P_FIMV_E_H264_FMO_RUN_LENGTH_MINUS1_1 0xFB7C
+#define S5P_FIMV_E_H264_FMO_RUN_LENGTH_MINUS1_2 0xFB80
+#define S5P_FIMV_E_H264_FMO_RUN_LENGTH_MINUS1_3 0xFB84
+
+#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_0 0xFB88
+#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_1 0xFB8C
+#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_2 0xFB90
+#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_3 0xFB94
+#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_4 0xFB98
+#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_5 0xFB9C
+#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_6 0xFBA0
+#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_7 0xFBA4
+
+#define S5P_FIMV_E_H264_CHROMA_QP_OFFSET 0xFBA8
+#define S5P_FIMV_E_H264_NUM_T_LAYER 0xFBAC
+
+#define S5P_FIMV_E_H264_HIERARCHICAL_QP_LAYER0 0xFBB0
+#define S5P_FIMV_E_H264_HIERARCHICAL_QP_LAYER1 0xFBB4
+#define S5P_FIMV_E_H264_HIERARCHICAL_QP_LAYER2 0xFBB8
+#define S5P_FIMV_E_H264_HIERARCHICAL_QP_LAYER3 0xFBBC
+#define S5P_FIMV_E_H264_HIERARCHICAL_QP_LAYER4 0xFBC0
+#define S5P_FIMV_E_H264_HIERARCHICAL_QP_LAYER5 0xFBC4
+#define S5P_FIMV_E_H264_HIERARCHICAL_QP_LAYER6 0xFBC8
+
+#define S5P_FIMV_E_H264_FRAME_PACKING_SEI_INFO 0xFC4C
+
+#define S5P_FIMV_E_MVC_FRAME_QP_VIEW1 0xFD40
+#define S5P_FIMV_E_MVC_RC_FRAME_RATE_VIEW1 0xFD44
+#define S5P_FIMV_E_MVC_RC_BIT_RATE_VIEW1 0xFD48
+#define S5P_FIMV_E_MVC_RC_QBOUND_VIEW1 0xFD4C
+#define S5P_FIMV_E_MVC_RC_RPARA_VIEW1 0xFD50
+#define S5P_FIMV_E_MVC_INTER_VIEW_PREDICTION_ON 0xFD80
+
+/* Codec numbers */
+#define MFC_FORMATS_NO_CODEC -1
+
+#define S5P_FIMV_CODEC_H264_DEC 0
+#define S5P_FIMV_CODEC_H264_MVC_DEC 1
+
+#define S5P_FIMV_CODEC_MPEG4_DEC 3
+#define S5P_FIMV_CODEC_FIMV1_DEC 4
+#define S5P_FIMV_CODEC_FIMV2_DEC 5
+#define S5P_FIMV_CODEC_FIMV3_DEC 6
+#define S5P_FIMV_CODEC_FIMV4_DEC 7
+#define S5P_FIMV_CODEC_H263_DEC 8
+#define S5P_FIMV_CODEC_VC1RCV_DEC 9
+#define S5P_FIMV_CODEC_VC1_DEC 10
+
+#define S5P_FIMV_CODEC_MPEG2_DEC 13
+#define S5P_FIMV_CODEC_VP8_DEC 14
+
+#define S5P_FIMV_CODEC_H264_ENC 20
+#define S5P_FIMV_CODEC_H264_MVC_ENC 21
+
+#define S5P_FIMV_CODEC_MPEG4_ENC 23
+#define S5P_FIMV_CODEC_H263_ENC 24
+
+/*** Definitions for MFCv5 compatibility ***/
+#define S5P_FIMV_SI_DISPLAY_Y_ADR S5P_FIMV_D_DISPLAY_LUMA_ADDR
+#define S5P_FIMV_SI_DISPLAY_C_ADR S5P_FIMV_D_DISPLAY_CHROMA_ADDR
+
+#define S5P_FIMV_CRC_LUMA0 S5P_FIMV_D_DECODED_LUMA_CRC_TOP
+#define S5P_FIMV_CRC_CHROMA0 S5P_FIMV_D_DECODED_CHROMA_CRC_TOP
+#define S5P_FIMV_CRC_LUMA1 S5P_FIMV_D_DECODED_LUMA_CRC_BOT
+#define S5P_FIMV_CRC_CHROMA1 S5P_FIMV_D_DECODED_CHROMA_CRC_BOT
+#define S5P_FIMV_CRC_DISP_LUMA0 S5P_FIMV_D_DISPLAY_LUMA_CRC_TOP
+#define S5P_FIMV_CRC_DISP_CHROMA0 S5P_FIMV_D_DISPLAY_CHROMA_CRC_TOP
+
+#define S5P_FIMV_SI_DECODED_STATUS S5P_FIMV_D_DECODED_STATUS
+#define S5P_FIMV_SI_DISPLAY_STATUS S5P_FIMV_D_DISPLAY_STATUS
+#define S5P_FIMV_SHARED_SET_FRAME_TAG S5P_FIMV_D_PICTURE_TAG
+#define S5P_FIMV_SHARED_GET_FRAME_TAG_TOP S5P_FIMV_D_RET_PICTURE_TAG_TOP
+#define S5P_FIMV_CRC_DISP_STATUS S5P_FIMV_D_DISPLAY_STATUS
+
+/* SEI related information */
+#define S5P_FIMV_FRAME_PACK_SEI_AVAIL S5P_FIMV_D_FRAME_PACK_SEI_AVAIL
+#define S5P_FIMV_FRAME_PACK_ARRGMENT_ID S5P_FIMV_D_FRAME_PACK_ARRGMENT_ID
+#define S5P_FIMV_FRAME_PACK_SEI_INFO S5P_FIMV_D_FRAME_PACK_SEI_INFO
+#define S5P_FIMV_FRAME_PACK_GRID_POS S5P_FIMV_D_FRAME_PACK_GRID_POS
+
+#define S5P_FIMV_SHARED_SET_E_FRAME_TAG S5P_FIMV_E_PICTURE_TAG
+#define S5P_FIMV_SHARED_GET_E_FRAME_TAG S5P_FIMV_E_RET_PICTURE_TAG
+#define S5P_FIMV_ENCODED_LUMA_ADDR S5P_FIMV_E_ENCODED_SOURCE_LUMA_ADDR
+#define S5P_FIMV_ENCODED_CHROMA_ADDR S5P_FIMV_E_ENCODED_SOURCE_CHROMA_ADDR
+#define S5P_FIMV_FRAME_INSERTION S5P_FIMV_E_FRAME_INSERTION
+
+#define S5P_FIMV_PARAM_CHANGE_FLAG S5P_FIMV_E_PARAM_CHANGE /* flag */
+#define S5P_FIMV_NEW_I_PERIOD S5P_FIMV_E_GOP_CONFIG
+#define S5P_FIMV_NEW_RC_FRAME_RATE S5P_FIMV_E_RC_FRAME_RATE
+#define S5P_FIMV_NEW_RC_BIT_RATE S5P_FIMV_E_RC_BIT_RATE
+
+#define S5P_FIMV_ERR_FRAME_CONCEAL 150
+/*** End of MFCv5 compatibility definitions ***/
+
+/*** old definitions ***/
+#if 1
+
+#define S5P_FIMV_SW_RESET 0x0000
+#define S5P_FIMV_RISC_HOST_INT 0x0008
+
+/* Command from HOST to RISC */
+#define S5P_FIMV_HOST2RISC_ARG1 0x0034
+#define S5P_FIMV_HOST2RISC_ARG2 0x0038
+#define S5P_FIMV_HOST2RISC_ARG3 0x003c
+#define S5P_FIMV_HOST2RISC_ARG4 0x0040
+
+/* Command from RISC to HOST */
+#define S5P_FIMV_RISC2HOST_CMD_MASK 0x1FFFF
+#define S5P_FIMV_RISC2HOST_ARG1 0x0048
+#define S5P_FIMV_RISC2HOST_ARG2 0x004c
+#define S5P_FIMV_RISC2HOST_ARG3 0x0050
+#define S5P_FIMV_RISC2HOST_ARG4 0x0054
+
+#define S5P_FIMV_SYS_MEM_SZ 0x005c
+#define S5P_FIMV_FW_STATUS 0x0080
+
+/* Memory controller register */
+#define S5P_FIMV_MC_DRAMBASE_ADR_A 0x0508
+#define S5P_FIMV_MC_DRAMBASE_ADR_B 0x050c
+#define S5P_FIMV_MC_STATUS 0x0510
+
+/* Common register */
+#define S5P_FIMV_COMMON_BASE_A 0x0600
+#define S5P_FIMV_COMMON_BASE_B 0x0700
+
+/* Decoder */
+#define S5P_FIMV_DEC_CHROMA_ADR (S5P_FIMV_COMMON_BASE_A)
+#define S5P_FIMV_DEC_LUMA_ADR (S5P_FIMV_COMMON_BASE_B)
+
+/* H.264 decoding */
+#define S5P_FIMV_H264_VERT_NB_MV_ADR (S5P_FIMV_COMMON_BASE_A + 0x8c) /* vertical neighbor motion vector */
+#define S5P_FIMV_H264_NB_IP_ADR (S5P_FIMV_COMMON_BASE_A + 0x90) /* neighbor pixels for intra pred */
+#define S5P_FIMV_H264_MV_ADR (S5P_FIMV_COMMON_BASE_B + 0x80) /* H264 motion vector */
+
+/* MPEG4 decoding */
+#define S5P_FIMV_MPEG4_NB_DCAC_ADR (S5P_FIMV_COMMON_BASE_A + 0x8c) /* neighbor AC/DC coeff. */
+#define S5P_FIMV_MPEG4_UP_NB_MV_ADR (S5P_FIMV_COMMON_BASE_A + 0x90) /* upper neighbor motion vector */
+#define S5P_FIMV_MPEG4_SA_MV_ADR (S5P_FIMV_COMMON_BASE_A + 0x94) /* subseq. anchor motion vector */
+#define S5P_FIMV_MPEG4_OT_LINE_ADR (S5P_FIMV_COMMON_BASE_A + 0x98) /* overlap transform line */
+#define S5P_FIMV_MPEG4_SP_ADR (S5P_FIMV_COMMON_BASE_A + 0xa8) /* syntax parser */
+
+/* H.263 decoding */
+#define S5P_FIMV_H263_NB_DCAC_ADR (S5P_FIMV_COMMON_BASE_A + 0x8c)
+#define S5P_FIMV_H263_UP_NB_MV_ADR (S5P_FIMV_COMMON_BASE_A + 0x90)
+#define S5P_FIMV_H263_SA_MV_ADR (S5P_FIMV_COMMON_BASE_A + 0x94)
+#define S5P_FIMV_H263_OT_LINE_ADR (S5P_FIMV_COMMON_BASE_A + 0x98)
+
+/* VC-1 decoding */
+#define S5P_FIMV_VC1_NB_DCAC_ADR (S5P_FIMV_COMMON_BASE_A + 0x8c)
+#define S5P_FIMV_VC1_UP_NB_MV_ADR (S5P_FIMV_COMMON_BASE_A + 0x90)
+#define S5P_FIMV_VC1_SA_MV_ADR (S5P_FIMV_COMMON_BASE_A + 0x94)
+#define S5P_FIMV_VC1_OT_LINE_ADR (S5P_FIMV_COMMON_BASE_A + 0x98)
+#define S5P_FIMV_VC1_BITPLANE3_ADR (S5P_FIMV_COMMON_BASE_A + 0x9c) /* bitplane3 */
+#define S5P_FIMV_VC1_BITPLANE2_ADR (S5P_FIMV_COMMON_BASE_A + 0xa0) /* bitplane2 */
+#define S5P_FIMV_VC1_BITPLANE1_ADR (S5P_FIMV_COMMON_BASE_A + 0xa4) /* bitplane1 */
+
+/* Encoder */
+#define S5P_FIMV_ENC_REF0_LUMA_ADR (S5P_FIMV_COMMON_BASE_A + 0x1c) /* reconstructed luma */
+#define S5P_FIMV_ENC_REF1_LUMA_ADR (S5P_FIMV_COMMON_BASE_A + 0x20)
+#define S5P_FIMV_ENC_REF0_CHROMA_ADR (S5P_FIMV_COMMON_BASE_B) /* reconstructed chroma */
+#define S5P_FIMV_ENC_REF1_CHROMA_ADR (S5P_FIMV_COMMON_BASE_B + 0x04)
+#define S5P_FIMV_ENC_REF2_LUMA_ADR (S5P_FIMV_COMMON_BASE_B + 0x10)
+#define S5P_FIMV_ENC_REF2_CHROMA_ADR (S5P_FIMV_COMMON_BASE_B + 0x08)
+#define S5P_FIMV_ENC_REF3_LUMA_ADR (S5P_FIMV_COMMON_BASE_B + 0x14)
+#define S5P_FIMV_ENC_REF3_CHROMA_ADR (S5P_FIMV_COMMON_BASE_B + 0x0c)
+
+/* H.264 encoding */
+#define S5P_FIMV_H264_UP_MV_ADR (S5P_FIMV_COMMON_BASE_A) /* upper motion vector */
+#define S5P_FIMV_H264_NBOR_INFO_ADR (S5P_FIMV_COMMON_BASE_A + 0x04) /* entropy engine's neighbor info. */
+#define S5P_FIMV_H264_UP_INTRA_MD_ADR (S5P_FIMV_COMMON_BASE_A + 0x08) /* upper intra MD */
+#define S5P_FIMV_H264_COZERO_FLAG_ADR (S5P_FIMV_COMMON_BASE_A + 0x10) /* direct cozero flag */
+#define S5P_FIMV_H264_UP_INTRA_PRED_ADR (S5P_FIMV_COMMON_BASE_B + 0x40) /* upper intra PRED */
+
+/* H.263 encoding */
+#define S5P_FIMV_H263_UP_MV_ADR (S5P_FIMV_COMMON_BASE_A) /* upper motion vector */
+#define S5P_FIMV_H263_ACDC_COEF_ADR (S5P_FIMV_COMMON_BASE_A + 0x04) /* upper Q coeff. */
+
+/* MPEG4 encoding */
+#define S5P_FIMV_MPEG4_UP_MV_ADR (S5P_FIMV_COMMON_BASE_A) /* upper motion vector */
+#define S5P_FIMV_MPEG4_ACDC_COEF_ADR (S5P_FIMV_COMMON_BASE_A + 0x04) /* upper Q coeff. */
+#define S5P_FIMV_MPEG4_COZERO_FLAG_ADR (S5P_FIMV_COMMON_BASE_A + 0x10) /* direct cozero flag */
+
+#define S5P_FIMV_ENC_REF_B_LUMA_ADR 0x062c /* ref B Luma addr */
+#define S5P_FIMV_ENC_REF_B_CHROMA_ADR 0x0630 /* ref B Chroma addr */
+
+#define S5P_FIMV_ENC_CUR_LUMA_ADR 0x0718 /* current Luma addr */
+#define S5P_FIMV_ENC_CUR_CHROMA_ADR 0x071C /* current Chroma addr */
+
+/* Codec common register */
+#define S5P_FIMV_ENC_HSIZE_PX 0x0818 /* frame width at encoder */
+#define S5P_FIMV_ENC_VSIZE_PX 0x081c /* frame height at encoder */
+#define S5P_FIMV_ENC_PROFILE 0x0830 /* profile register */
+#define S5P_FIMV_ENC_PIC_STRUCT 0x083c /* picture field/frame flag */
+#define S5P_FIMV_ENC_LF_CTRL 0x0848 /* loop filter control */
+#define S5P_FIMV_ENC_ALPHA_OFF 0x084c /* loop filter alpha offset */
+#define S5P_FIMV_ENC_BETA_OFF 0x0850 /* loop filter beta offset */
+#define S5P_FIMV_MR_BUSIF_CTRL 0x0854 /* hidden, bus interface ctrl */
+#define S5P_FIMV_ENC_PXL_CACHE_CTRL 0x0a00 /* pixel cache control */
+
+/* Channel & stream interface register */
+#define S5P_FIMV_SI_RTN_CHID 0x2000 /* Return CH instance ID register */
+#define S5P_FIMV_SI_CH0_INST_ID 0x2040 /* codec instance ID */
+#define S5P_FIMV_SI_CH1_INST_ID 0x2080 /* codec instance ID */
+/* Decoder */
+#define S5P_FIMV_SI_VRESOL 0x2004 /* vertical resolution of decoder */
+#define S5P_FIMV_SI_HRESOL 0x2008 /* horizontal resolution of decoder */
+#define S5P_FIMV_SI_BUF_NUMBER 0x200c /* number of frames in the decoded pic */
+#define S5P_FIMV_SI_CONSUMED_BYTES 0x2018 /* Consumed number of bytes to decode
+ a frame */
+#define S5P_FIMV_SI_FRAME_TYPE 0x2020 /* frame type such as skip/I/P/B */
+
+#define S5P_FIMV_SI_CH0_SB_ST_ADR 0x2044 /* start addr of stream buf */
+#define S5P_FIMV_SI_CH0_SB_FRM_SIZE 0x2048 /* size of stream buf */
+#define S5P_FIMV_SI_CH0_DESC_ADR 0x204c /* addr of descriptor buf */
+#define S5P_FIMV_SI_CH0_CPB_SIZE 0x2058 /* max size of coded pic. buf */
+#define S5P_FIMV_SI_CH0_DESC_SIZE 0x205c /* max size of descriptor buf */
+
+#define S5P_FIMV_SI_CH1_SB_ST_ADR 0x2084 /* start addr of stream buf */
+#define S5P_FIMV_SI_CH1_SB_FRM_SIZE 0x2088 /* size of stream buf */
+#define S5P_FIMV_SI_CH1_DESC_ADR 0x208c /* addr of descriptor buf */
+#define S5P_FIMV_SI_CH1_CPB_SIZE 0x2098 /* max size of coded pic. buf */
+#define S5P_FIMV_SI_CH1_DESC_SIZE 0x209c /* max size of descriptor buf */
+
+#define S5P_FIMV_SI_FIMV1_HRESOL 0x2054 /* horizontal resolution */
+#define S5P_FIMV_SI_FIMV1_VRESOL 0x2050 /* vertical resolution */
+
+/* Decode frame address */
+#define S5P_FIMV_DECODE_Y_ADR 0x2024
+#define S5P_FIMV_DECODE_C_ADR 0x2028
+
+/* Decoded frame type */
+#define S5P_FIMV_DECODED_FRAME_TYPE 0x2020
+
+/* Sizes of buffers required for decoding */
+#define S5P_FIMV_DEC_NB_IP_SIZE (32 * 1024)
+#define S5P_FIMV_DEC_VERT_NB_MV_SIZE (16 * 1024)
+#define S5P_FIMV_DEC_NB_DCAC_SIZE (16 * 1024)
+#define S5P_FIMV_DEC_UPNB_MV_SIZE (68 * 1024)
+#define S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE (136 * 1024)
+#define S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE (32 * 1024)
+#define S5P_FIMV_DEC_VC1_BITPLANE_SIZE (2 * 1024)
+#define S5P_FIMV_DEC_STX_PARSER_SIZE (68 * 1024)
+
+#define S5P_FIMV_NV12M_HALIGN 16
+#define S5P_FIMV_NV12MT_HALIGN 16
+#define S5P_FIMV_NV12MT_VALIGN 16
+
+/* Sizes of buffers required for encoding */
+#define S5P_FIMV_ENC_UPMV_SIZE (0x10000)
+#define S5P_FIMV_ENC_COLFLG_SIZE (0x10000)
+#define S5P_FIMV_ENC_INTRAMD_SIZE (0x10000)
+#define S5P_FIMV_ENC_INTRAPRED_SIZE (0x4000)
+#define S5P_FIMV_ENC_NBORINFO_SIZE (0x10000)
+#define S5P_FIMV_ENC_ACDCCOEF_SIZE (0x10000)
+
+/* Encoder */
+#define S5P_FIMV_ENC_SI_STRM_SIZE 0x2004 /* stream size */
+#define S5P_FIMV_ENC_SI_PIC_CNT 0x2008 /* picture count */
+#define S5P_FIMV_ENC_SI_WRITE_PTR 0x200c /* write pointer */
+#define S5P_FIMV_ENC_SI_SLICE_TYPE 0x2010 /* slice type(I/P/B/IDR) */
+#define S5P_FIMV_ENCODED_Y_ADDR 0x2014 /* the addr of the encoded luma pic */
+#define S5P_FIMV_ENCODED_C_ADDR 0x2018 /* the addr of the encoded chroma pic */
+
+#define S5P_FIMV_ENC_SI_CH0_SB_ADR 0x2044 /* addr of stream buf */
+#define S5P_FIMV_ENC_SI_CH0_SB_SIZE 0x204c /* size of stream buf */
+#define S5P_FIMV_ENC_SI_CH0_CUR_Y_ADR 0x2050 /* current Luma addr */
+#define S5P_FIMV_ENC_SI_CH0_CUR_C_ADR 0x2054 /* current Chroma addr */
+#define S5P_FIMV_ENC_SI_CH0_FRAME_INS 0x2058 /* frame insertion */
+
+#define S5P_FIMV_ENC_SI_CH1_SB_ADR 0x2084 /* addr of stream buf */
+#define S5P_FIMV_ENC_SI_CH1_SB_SIZE 0x208c /* size of stream buf */
+#define S5P_FIMV_ENC_SI_CH1_CUR_Y_ADR 0x2090 /* current Luma addr */
+#define S5P_FIMV_ENC_SI_CH1_CUR_C_ADR 0x2094 /* current Chroma addr */
+#define S5P_FIMV_ENC_SI_CH1_FRAME_INS 0x2098 /* frame insertion */
+
+#define S5P_FIMV_ENC_PIC_TYPE_CTRL 0xc504 /* pic type level control */
+#define S5P_FIMV_ENC_B_RECON_WRITE_ON 0xc508 /* B frame recon write ctrl */
+#define S5P_FIMV_ENC_MSLICE_CTRL 0xc50c /* multi slice control */
+#define S5P_FIMV_ENC_MSLICE_MB 0xc510 /* MB number in the one slice */
+#define S5P_FIMV_ENC_MSLICE_BIT 0xc514 /* bit count for one slice */
+#define S5P_FIMV_ENC_CIR_CTRL 0xc518 /* number of intra refresh MB */
+#define S5P_FIMV_ENC_MAP_FOR_CUR 0xc51c /* linear or 64x32 tiled mode */
+#define S5P_FIMV_ENC_PADDING_CTRL 0xc520 /* padding control */
+
+#define S5P_FIMV_ENC_RC_CONFIG 0xc5a0 /* RC config */
+#define S5P_FIMV_ENC_RC_BIT_RATE 0xc5a8 /* bit rate */
+#define S5P_FIMV_ENC_RC_QBOUND 0xc5ac /* max/min QP */
+#define S5P_FIMV_ENC_RC_RPARA 0xc5b0 /* rate control reaction coeff */
+#define S5P_FIMV_ENC_RC_MB_CTRL 0xc5b4 /* MB adaptive scaling */
+
+/* Encoder for H264 only */
+#define S5P_FIMV_ENC_H264_ENTRP_MODE 0xd004 /* CAVLC or CABAC */
+#define S5P_FIMV_ENC_H264_ALPHA_OFF 0xd008 /* loop filter alpha offset */
+#define S5P_FIMV_ENC_H264_BETA_OFF 0xd00c /* loop filter beta offset */
+#define S5P_FIMV_ENC_H264_NUM_OF_REF 0xd010 /* number of reference for P/B */
+#define S5P_FIMV_ENC_H264_TRANS_FLAG 0xd034 /* 8x8 transform flag in PPS & high profile */
+
+#define S5P_FIMV_ENC_RC_FRAME_RATE 0xd0d0 /* frame rate */
+
+/* Encoder for MPEG4 only */
+#define S5P_FIMV_ENC_MPEG4_QUART_PXL 0xe008 /* qpel interpolation ctrl */
+
+/* Additional */
+#define S5P_FIMV_SI_CH0_DPB_CONF_CTRL 0x2068 /* DPB Config Control Register */
+#define S5P_FIMV_DPB_COUNT_MASK 0xffff
+
+#define S5P_FIMV_SI_CH0_RELEASE_BUF 0x2060 /* DPB release buffer register */
+#define S5P_FIMV_SI_CH0_HOST_WR_ADR 0x2064 /* address of shared memory */
+
+/* Channel Control Register */
+#define S5P_FIMV_CH_FRAME_START_REALLOC 5
+
+#define S5P_FIMV_CH_MASK 7
+#define S5P_FIMV_CH_SHIFT 16
+
+/* Host to RISC command */
+#define S5P_FIMV_R2H_CMD_RSV_RET 3
+#define S5P_FIMV_R2H_CMD_ENC_COMPLETE_RET 7
+#define S5P_FIMV_R2H_CMD_FLUSH_RET 12
+#define S5P_FIMV_R2H_CMD_EDFU_INIT_RET 16
+
+/* Shared memory registers' offsets */
+
+/* An offset of the start position in the stream when
+ * the start position is not aligned */
+#define S5P_FIMV_SHARED_GET_FRAME_TAG_BOT 0x000C
+#define S5P_FIMV_SHARED_START_BYTE_NUM 0x0018
+#define S5P_FIMV_SHARED_RC_VOP_TIMING 0x0030
+#define S5P_FIMV_SHARED_LUMA_DPB_SIZE 0x0064
+#define S5P_FIMV_SHARED_CHROMA_DPB_SIZE 0x0068
+#define S5P_FIMV_SHARED_MV_SIZE 0x006C
+#define S5P_FIMV_SHARED_PIC_TIME_TOP 0x0010
+#define S5P_FIMV_SHARED_PIC_TIME_BOTTOM 0x0014
+#define S5P_FIMV_SHARED_EXT_ENC_CONTROL 0x0028
+#define S5P_FIMV_SHARED_P_B_FRAME_QP 0x0070
+#define S5P_FIMV_SHARED_ASPECT_RATIO_IDC 0x0074
+#define S5P_FIMV_SHARED_EXTENDED_SAR 0x0078
+#define S5P_FIMV_SHARED_H264_I_PERIOD 0x009C
+#define S5P_FIMV_SHARED_RC_CONTROL_CONFIG 0x00A0
+
+#endif /* End of old definitions */
+
+#endif /* _REGS_FIMV_V6_H */
diff --git a/drivers/media/video/exynos/mfc/s5p_mfc.c b/drivers/media/video/exynos/mfc/s5p_mfc.c
new file mode 100644
index 0000000..c185487
--- /dev/null
+++ b/drivers/media/video/exynos/mfc/s5p_mfc.c
@@ -0,0 +1,1755 @@
+/*
+ * Samsung S5P Multi Format Codec V5/V6
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * Kamil Debski, <k.debski@samsung.com>
+ *
+ * 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.
+ */
+
+#define DEBUG
+
+#include <linux/io.h>
+#include <linux/sched.h>
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/version.h>
+#include <linux/workqueue.h>
+#include <linux/videodev2.h>
+#include <linux/videodev2_exynos_media.h>
+#include <linux/proc_fs.h>
+#include <linux/pm_wakeup.h>
+#include <mach/videonode.h>
+#include <media/videobuf2-core.h>
+
+#include "s5p_mfc_common.h"
+
+#include "s5p_mfc_intr.h"
+#include "s5p_mfc_mem.h"
+#include "s5p_mfc_debug.h"
+#include "s5p_mfc_reg.h"
+#include "s5p_mfc_ctrl.h"
+#include "s5p_mfc_dec.h"
+#include "s5p_mfc_enc.h"
+#include "s5p_mfc_pm.h"
+
+#define S5P_MFC_NAME "s5p-mfc"
+#define S5P_MFC_DEC_NAME "s5p-mfc-dec"
+#define S5P_MFC_ENC_NAME "s5p-mfc-enc"
+
+#define DISABLE_SLEEP
+
+int debug;
+module_param(debug, int, S_IRUGO | S_IWUSR);
+
+#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
+static struct proc_dir_entry *mfc_proc_entry;
+
+#define MFC_PROC_ROOT "mfc"
+#define MFC_PROC_INSTANCE_NUMBER "instance_number"
+#define MFC_PROC_DRM_INSTANCE_NUMBER "drm_instance_number"
+#define MFC_PROC_FW_STATUS "fw_status"
+
+#define MFC_DRM_MAGIC_SIZE 0x10
+#define MFC_DRM_MAGIC_CHUNK0 0x13cdbf16
+#define MFC_DRM_MAGIC_CHUNK1 0x8b803342
+#define MFC_DRM_MAGIC_CHUNK2 0x5e87f4f5
+#define MFC_DRM_MAGIC_CHUNK3 0x3bd05317
+
+static bool check_magic(unsigned char *addr)
+{
+ if (((u32)*(u32 *)(addr) == MFC_DRM_MAGIC_CHUNK0) &&
+ ((u32)*(u32 *)(addr + 0x4) == MFC_DRM_MAGIC_CHUNK1) &&
+ ((u32)*(u32 *)(addr + 0x8) == MFC_DRM_MAGIC_CHUNK2) &&
+ ((u32)*(u32 *)(addr + 0xC) == MFC_DRM_MAGIC_CHUNK3))
+ return true;
+ else
+ return false;
+}
+
+static inline void clear_magic(unsigned char *addr)
+{
+ memset((void *)addr, 0x00, MFC_DRM_MAGIC_SIZE);
+}
+#endif
+
+void mfc_workqueue_try_run(struct work_struct *work)
+{
+ struct s5p_mfc_dev *dev = container_of(work, struct s5p_mfc_dev,
+ work_struct);
+
+ s5p_mfc_try_run(dev);
+}
+
+/* Helper functions for interrupt processing */
+/* Remove from hw execution round robin */
+inline void clear_work_bit(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+
+ spin_lock(&dev->condlock);
+ clear_bit(ctx->num, &dev->ctx_work_bits);
+ spin_unlock(&dev->condlock);
+}
+
+/* Wake up context wait_queue */
+static inline void wake_up_ctx(struct s5p_mfc_ctx *ctx, unsigned int reason,
+ unsigned int err)
+{
+ ctx->int_cond = 1;
+ ctx->int_type = reason;
+ ctx->int_err = err;
+ wake_up(&ctx->queue);
+}
+
+/* Wake up device wait_queue */
+static inline void wake_up_dev(struct s5p_mfc_dev *dev, unsigned int reason,
+ unsigned int err)
+{
+ dev->int_cond = 1;
+ dev->int_type = reason;
+ dev->int_err = err;
+ wake_up_interruptible(&dev->queue);
+}
+
+void s5p_mfc_watchdog(unsigned long arg)
+{
+ struct s5p_mfc_dev *dev = (struct s5p_mfc_dev *)arg;
+
+ if (dev->hw_lock)
+ atomic_inc(&dev->watchdog_cnt);
+ if (atomic_read(&dev->watchdog_cnt) >= MFC_WATCHDOG_CNT) {
+ /* This means that hw is busy and no interrupts were
+ * generated by hw for the Nth time of running this
+ * watchdog timer. This usually means a serious hw
+ * error. Now it is time to kill all instances and
+ * reset the MFC. */
+ mfc_err("Time out during waiting for HW.\n");
+ queue_work(dev->watchdog_workqueue, &dev->watchdog_work);
+ }
+ dev->watchdog_timer.expires = jiffies +
+ msecs_to_jiffies(MFC_WATCHDOG_INTERVAL);
+ add_timer(&dev->watchdog_timer);
+}
+
+static void s5p_mfc_watchdog_worker(struct work_struct *work)
+{
+ struct s5p_mfc_dev *dev;
+ struct s5p_mfc_ctx *ctx;
+ int i, ret;
+ int mutex_locked;
+ unsigned long flags;
+
+ dev = container_of(work, struct s5p_mfc_dev, watchdog_work);
+
+ mfc_err("Driver timeout error handling.\n");
+ /* Lock the mutex that protects open and release.
+ * This is necessary as they may load and unload firmware. */
+ mutex_locked = mutex_trylock(&dev->mfc_mutex);
+ if (!mutex_locked)
+ mfc_err("This is not good. Some instance may be "
+ "closing/opening.\n");
+
+ s5p_mfc_clock_off();
+
+ spin_lock_irqsave(&dev->irqlock, flags);
+
+ for (i = 0; i < MFC_NUM_CONTEXTS; i++) {
+ ctx = dev->ctx[i];
+ if (ctx) {
+ ctx->state = MFCINST_ERROR;
+ s5p_mfc_cleanup_queue(&ctx->dst_queue,
+ &ctx->vq_dst);
+ s5p_mfc_cleanup_queue(&ctx->src_queue,
+ &ctx->vq_src);
+ clear_work_bit(ctx);
+ wake_up_ctx(ctx, S5P_FIMV_R2H_CMD_ERR_RET, 0);
+ }
+ }
+ dev->hw_lock = 0;
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+ /* Double check if there is at least one instance running.
+ * If no instance is in memory than no firmware should be present */
+ if (dev->num_inst > 0) {
+ ret = s5p_mfc_load_firmware(dev);
+ if (ret != 0) {
+ mfc_err("Failed to reload FW.\n");
+ if (mutex_locked)
+ mutex_unlock(&dev->mfc_mutex);
+ return;
+ }
+
+ ret = s5p_mfc_init_hw(dev);
+ if (ret != 0) {
+ mfc_err("Failed to reinit FW.\n");
+ if (mutex_locked)
+ mutex_unlock(&dev->mfc_mutex);
+ return;
+ }
+ }
+ if (mutex_locked)
+ mutex_unlock(&dev->mfc_mutex);
+}
+
+static inline enum s5p_mfc_node_type s5p_mfc_get_node_type(struct file *file)
+{
+ struct video_device *vdev = video_devdata(file);
+
+ if (!vdev) {
+ mfc_err("failed to get video_device");
+ return MFCNODE_INVALID;
+ }
+
+ mfc_debug(2, "video_device index: %d\n", vdev->index);
+
+ if (vdev->index == 0)
+ return MFCNODE_DECODER;
+ else if (vdev->index == 1)
+ return MFCNODE_ENCODER;
+ else
+ return MFCNODE_INVALID;
+}
+
+static void s5p_mfc_handle_frame_all_extracted(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+ struct s5p_mfc_buf *dst_buf;
+ int index, is_first = 1;
+
+ mfc_debug(2, "Decided to finish\n");
+ ctx->sequence++;
+ while (!list_empty(&ctx->dst_queue)) {
+ dst_buf = list_entry(ctx->dst_queue.next,
+ struct s5p_mfc_buf, list);
+ mfc_debug(2, "Cleaning up buffer: %d\n",
+ dst_buf->vb.v4l2_buf.index);
+ vb2_set_plane_payload(&dst_buf->vb, 0, 0);
+ vb2_set_plane_payload(&dst_buf->vb, 1, 0);
+ list_del(&dst_buf->list);
+ ctx->dst_queue_cnt--;
+ dst_buf->vb.v4l2_buf.sequence = (ctx->sequence++);
+
+ if (s5p_mfc_read_info(ctx, PIC_TIME_TOP) ==
+ s5p_mfc_read_info(ctx, PIC_TIME_BOT))
+ dst_buf->vb.v4l2_buf.field = V4L2_FIELD_NONE;
+ else
+ dst_buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED;
+
+ clear_bit(dst_buf->vb.v4l2_buf.index, &dec->dpb_status);
+
+ index = dst_buf->vb.v4l2_buf.index;
+ if (call_cop(ctx, get_buf_ctrls_val, ctx, &ctx->dst_ctrls[index]) < 0)
+ mfc_err("failed in get_buf_ctrls_val\n");
+
+ if (is_first) {
+ call_cop(ctx, get_buf_update_val, ctx,
+ &ctx->dst_ctrls[index],
+ V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG,
+ dec->eos_tag);
+ is_first = 0;
+ } else {
+ call_cop(ctx, get_buf_update_val, ctx,
+ &ctx->dst_ctrls[index],
+ V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG,
+ DEFAULT_TAG);
+ }
+
+ vb2_buffer_done(&dst_buf->vb, VB2_BUF_STATE_DONE);
+ mfc_debug(2, "Cleaned up buffer: %d\n",
+ dst_buf->vb.v4l2_buf.index);
+ }
+ if (ctx->state != MFCINST_ABORT)
+ ctx->state = MFCINST_RUNNING;
+ mfc_debug(2, "After cleanup\n");
+}
+
+static void s5p_mfc_handle_frame_new(struct s5p_mfc_ctx *ctx, unsigned int err)
+{
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_buf *dst_buf;
+ dma_addr_t dspl_y_addr = MFC_GET_ADR(DEC_DISPLAY_Y);
+ unsigned int index;
+ unsigned int frame_type = s5p_mfc_get_disp_frame_type();
+ int mvc_view_id = s5p_mfc_get_mvc_disp_view_id();
+
+ if (ctx->codec_mode == S5P_FIMV_CODEC_H264_MVC_DEC) {
+ if (mvc_view_id == 0)
+ ctx->sequence++;
+ } else {
+ ctx->sequence++;
+ }
+
+ /* If frame is same as previous then skip and do not dequeue */
+ if (frame_type == S5P_FIMV_DISPLAY_FRAME_NOT_CODED)
+ return;
+ /* The MFC returns address of the buffer, now we have to
+ * check which videobuf does it correspond to */
+ list_for_each_entry(dst_buf, &ctx->dst_queue, list) {
+ mfc_debug(2, "Listing: %d\n", dst_buf->vb.v4l2_buf.index);
+ /* Check if this is the buffer we're looking for */
+ mfc_debug(2, "0x%08lx, 0x%08x",
+ (unsigned long)s5p_mfc_mem_plane_addr(
+ ctx, &dst_buf->vb, 0),
+ dspl_y_addr);
+ if (s5p_mfc_mem_plane_addr(ctx, &dst_buf->vb, 0)
+ == dspl_y_addr) {
+ list_del(&dst_buf->list);
+ ctx->dst_queue_cnt--;
+ dst_buf->vb.v4l2_buf.sequence = ctx->sequence;
+
+ if (s5p_mfc_read_info(ctx, PIC_TIME_TOP) ==
+ s5p_mfc_read_info(ctx, PIC_TIME_BOT))
+ dst_buf->vb.v4l2_buf.field = V4L2_FIELD_NONE;
+ else
+ dst_buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED;
+
+ vb2_set_plane_payload(&dst_buf->vb, 0, ctx->luma_size);
+ vb2_set_plane_payload(&dst_buf->vb, 1, ctx->chroma_size);
+ clear_bit(dst_buf->vb.v4l2_buf.index, &dec->dpb_status);
+
+ dst_buf->vb.v4l2_buf.flags &=
+ ~(V4L2_BUF_FLAG_KEYFRAME |
+ V4L2_BUF_FLAG_PFRAME |
+ V4L2_BUF_FLAG_BFRAME);
+
+ switch (frame_type) {
+ case S5P_FIMV_DISPLAY_FRAME_I:
+ dst_buf->vb.v4l2_buf.flags |=
+ V4L2_BUF_FLAG_KEYFRAME;
+ break;
+ case S5P_FIMV_DISPLAY_FRAME_P:
+ dst_buf->vb.v4l2_buf.flags |=
+ V4L2_BUF_FLAG_PFRAME;
+ break;
+ case S5P_FIMV_DISPLAY_FRAME_B:
+ dst_buf->vb.v4l2_buf.flags |=
+ V4L2_BUF_FLAG_BFRAME;
+ break;
+ default:
+ break;
+ }
+
+ if (s5p_mfc_err_dspl(err))
+ mfc_err("Warning for displayed frame: %d\n",
+ s5p_mfc_err_dspl(err));
+
+ index = dst_buf->vb.v4l2_buf.index;
+ if (call_cop(ctx, get_buf_ctrls_val, ctx, &ctx->dst_ctrls[index]) < 0)
+ mfc_err("failed in get_buf_ctrls_val\n");
+
+ vb2_buffer_done(&dst_buf->vb,
+ s5p_mfc_err_dspl(err) ?
+ VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
+
+ break;
+ }
+ }
+}
+
+static int s5p_mfc_find_start_code(unsigned char *src_mem, unsigned int remainSize)
+{
+ unsigned int index = 0;
+
+ for (index = 0; index < remainSize - 3; index++) {
+ if ((src_mem[index] == 0x00) && (src_mem[index+1] == 0x00) &&
+ (src_mem[index+2] == 0x01))
+ return index;
+ }
+
+ return -1;
+}
+
+static void s5p_mfc_handle_frame_error(struct s5p_mfc_ctx *ctx,
+ unsigned int reason, unsigned int err)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+ struct s5p_mfc_buf *src_buf;
+ unsigned long flags;
+ unsigned int index;
+
+ mfc_err("Interrupt Error: %d\n", err);
+
+ dec->dpb_flush = 0;
+ dec->remained = 0;
+
+ spin_lock_irqsave(&dev->irqlock, flags);
+ if (!list_empty(&ctx->src_queue)) {
+ src_buf = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
+ index = src_buf->vb.v4l2_buf.index;
+ if (call_cop(ctx, recover_buf_ctrls_val, ctx, &ctx->src_ctrls[index]) < 0)
+ mfc_err("failed in recover_buf_ctrls_val\n");
+
+ mfc_debug(2, "MFC needs next buffer.\n");
+ dec->consumed = 0;
+ list_del(&src_buf->list);
+ ctx->src_queue_cnt--;
+
+ if (call_cop(ctx, get_buf_ctrls_val, ctx, &ctx->src_ctrls[index]) < 0)
+ mfc_err("failed in get_buf_ctrls_val\n");
+
+ vb2_buffer_done(&src_buf->vb, VB2_BUF_STATE_ERROR);
+ }
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+
+ mfc_debug(2, "Assesing whether this context should be run again.\n");
+ /* This context state is always RUNNING */
+ if (ctx->src_queue_cnt == 0 || ctx->dst_queue_cnt < ctx->dpb_count) {
+ mfc_err("No need to run again.\n");
+ clear_work_bit(ctx);
+ }
+ mfc_debug(2, "After assesing whether this context should be run again. %d\n", ctx->src_queue_cnt);
+
+ s5p_mfc_clear_int_flags();
+ wake_up_ctx(ctx, reason, err);
+ if (test_and_clear_bit(ctx->num, &dev->hw_lock) == 0)
+ BUG();
+
+ s5p_mfc_clock_off();
+
+ queue_work(dev->irq_workqueue, &dev->work_struct);
+}
+
+/* Handle frame decoding interrupt */
+static void s5p_mfc_handle_frame(struct s5p_mfc_ctx *ctx,
+ unsigned int reason, unsigned int err)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+ unsigned int dst_frame_status;
+ struct s5p_mfc_buf *src_buf;
+ unsigned long flags;
+ unsigned int res_change;
+ unsigned int index, remained;
+
+ dst_frame_status = s5p_mfc_get_dspl_status()
+ & S5P_FIMV_DEC_STATUS_DECODING_STATUS_MASK;
+ res_change = (s5p_mfc_get_dspl_status()
+ & S5P_FIMV_DEC_STATUS_RESOLUTION_MASK)
+ >> S5P_FIMV_DEC_STATUS_RESOLUTION_SHIFT;
+ mfc_debug(2, "Frame Status: %x\n", dst_frame_status);
+ mfc_debug(2, "frame packing sei available status: %x\n", s5p_mfc_get_sei_avail_status());
+
+ if (ctx->state == MFCINST_RES_CHANGE_INIT)
+ ctx->state = MFCINST_RES_CHANGE_FLUSH;
+
+ if (res_change) {
+ if (res_change == 1) {
+ mfc_err("Resolution change set to %d\n", res_change);
+ ctx->state = MFCINST_RES_CHANGE_INIT;
+
+ s5p_mfc_clear_int_flags();
+ wake_up_ctx(ctx, reason, err);
+ if (test_and_clear_bit(ctx->num, &dev->hw_lock) == 0)
+ BUG();
+
+ s5p_mfc_clock_off();
+
+ queue_work(dev->irq_workqueue, &dev->work_struct);
+ return;
+ } else if (res_change == 2) {
+ /* Resolution decrease is ignored */
+ goto leave_handle_frame;
+ }
+ }
+ if (dec->dpb_flush)
+ dec->dpb_flush = 0;
+ if (dec->remained)
+ dec->remained = 0;
+
+ spin_lock_irqsave(&dev->irqlock, flags);
+ /* All frames remaining in the buffer have been extracted */
+ if (dst_frame_status == S5P_FIMV_DEC_STATUS_DECODING_EMPTY) {
+ if (ctx->state == MFCINST_RES_CHANGE_FLUSH) {
+ mfc_debug(2, "Last frame received after resolution change.\n");
+ s5p_mfc_handle_frame_all_extracted(ctx);
+ ctx->state = MFCINST_RES_CHANGE_END;
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+ goto leave_handle_frame;
+ } else {
+ s5p_mfc_handle_frame_all_extracted(ctx);
+ }
+ }
+
+ /* A frame has been decoded and is in the buffer */
+ if (dst_frame_status == S5P_FIMV_DEC_STATUS_DISPLAY_ONLY ||
+ dst_frame_status == S5P_FIMV_DEC_STATUS_DECODING_DISPLAY) {
+ s5p_mfc_handle_frame_new(ctx, err);
+ } else {
+ mfc_debug(2, "No frame decode.\n");
+ }
+ /* Mark source buffer as complete */
+ if (dst_frame_status != S5P_FIMV_DEC_STATUS_DISPLAY_ONLY
+ && !list_empty(&ctx->src_queue)) {
+ src_buf = list_entry(ctx->src_queue.next, struct s5p_mfc_buf,
+ list);
+ mfc_debug(2, "Packed PB test. Size:%d, prev offset: %ld, this run:"
+ " %d\n", src_buf->vb.v4l2_planes[0].bytesused,
+ dec->consumed, s5p_mfc_get_consumed_stream());
+ dec->consumed += s5p_mfc_get_consumed_stream();
+ remained = src_buf->vb.v4l2_planes[0].bytesused - dec->consumed;
+
+ if (dec->is_packedpb && remained > STUFF_BYTE &&
+ s5p_mfc_get_dec_frame_type() ==
+ S5P_FIMV_DECODED_FRAME_P) {
+ unsigned char *stream_vir;
+ int offset = 0;
+
+ /* Run MFC again on the same buffer */
+ mfc_debug(2, "Running again the same buffer.\n");
+
+ stream_vir = vb2_plane_vaddr(&src_buf->vb, 0);
+ s5p_mfc_cache_inv(&src_buf->vb, 0);
+
+ offset = s5p_mfc_find_start_code(
+ stream_vir + dec->consumed, remained);
+
+ if (offset > STUFF_BYTE)
+ dec->consumed += offset;
+
+ s5p_mfc_set_dec_stream_buffer(ctx,
+ src_buf->planes.stream, dec->consumed,
+ src_buf->vb.v4l2_planes[0].bytesused -
+ dec->consumed);
+ dev->curr_ctx = ctx->num;
+ dev->curr_ctx_drm = ctx->is_drm;
+ s5p_mfc_clean_ctx_int_flags(ctx);
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+ s5p_mfc_clear_int_flags();
+ wake_up_ctx(ctx, reason, err);
+ s5p_mfc_decode_one_frame(ctx, 0);
+ return;
+ } else {
+ index = src_buf->vb.v4l2_buf.index;
+ if (call_cop(ctx, recover_buf_ctrls_val, ctx, &ctx->src_ctrls[index]) < 0)
+ mfc_err("failed in recover_buf_ctrls_val\n");
+
+ mfc_debug(2, "MFC needs next buffer.\n");
+ dec->consumed = 0;
+ list_del(&src_buf->list);
+ ctx->src_queue_cnt--;
+
+ if (call_cop(ctx, get_buf_ctrls_val, ctx, &ctx->src_ctrls[index]) < 0)
+ mfc_err("failed in get_buf_ctrls_val\n");
+
+ vb2_buffer_done(&src_buf->vb, VB2_BUF_STATE_DONE);
+ }
+ }
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+leave_handle_frame:
+ mfc_debug(2, "Assesing whether this context should be run again.\n");
+ /* if (!s5p_mfc_ctx_ready(ctx)) { */
+ if ((ctx->src_queue_cnt == 0 && ctx->state != MFCINST_FINISHING)
+ || ctx->dst_queue_cnt < ctx->dpb_count) {
+ mfc_debug(2, "No need to run again.\n");
+ clear_work_bit(ctx);
+ }
+ mfc_debug(2, "After assesing whether this context should be run again.\n");
+ s5p_mfc_clear_int_flags();
+ wake_up_ctx(ctx, reason, err);
+ if (test_and_clear_bit(ctx->num, &dev->hw_lock) == 0)
+ BUG();
+
+ s5p_mfc_clock_off();
+
+ queue_work(dev->irq_workqueue, &dev->work_struct);
+}
+
+/* Error handling for interrupt */
+static inline void s5p_mfc_handle_error(struct s5p_mfc_ctx *ctx,
+ unsigned int reason, unsigned int err)
+{
+ struct s5p_mfc_dev *dev;
+ unsigned long flags;
+
+ if (ctx == 0)
+ return;
+
+ dev = ctx->dev;
+ mfc_err("Interrupt Error: %d\n", err);
+ s5p_mfc_clear_int_flags();
+ wake_up_dev(dev, reason, err);
+
+ /* Error recovery is dependent on the state of context */
+ switch (ctx->state) {
+ case MFCINST_INIT:
+ /* This error had to happen while acquireing instance */
+ case MFCINST_GOT_INST:
+ /* This error had to happen while parsing the header */
+ case MFCINST_HEAD_PARSED:
+ /* This error had to happen while setting dst buffers */
+ case MFCINST_RETURN_INST:
+ /* This error had to happen while releasing instance */
+ clear_work_bit(ctx);
+ wake_up_ctx(ctx, reason, err);
+ if (test_and_clear_bit(ctx->num, &dev->hw_lock) == 0)
+ BUG();
+
+ s5p_mfc_clock_off();
+
+ break;
+ case MFCINST_FINISHING:
+ case MFCINST_FINISHED:
+ /* It is higly probable that an error occured
+ * while decoding a frame */
+ clear_work_bit(ctx);
+ ctx->state = MFCINST_ERROR;
+ /* Mark all dst buffers as having an error */
+ spin_lock_irqsave(&dev->irqlock, flags);
+ s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst);
+ /* Mark all src buffers as having an error */
+ s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src);
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+ if (test_and_clear_bit(ctx->num, &dev->hw_lock) == 0)
+ BUG();
+
+ s5p_mfc_clock_off();
+
+ break;
+ default:
+ mfc_err("Encountered an error interrupt which had not been handled.\n");
+ break;
+ }
+ return;
+}
+
+/* Interrupt processing */
+static irqreturn_t s5p_mfc_irq(int irq, void *priv)
+{
+ struct s5p_mfc_dev *dev = priv;
+ struct s5p_mfc_buf *src_buf;
+ struct s5p_mfc_ctx *ctx;
+ struct s5p_mfc_dec *dec = NULL;
+ unsigned int reason;
+ unsigned int err;
+ unsigned long flags;
+
+ mfc_debug_enter();
+ /* Reset the timeout watchdog */
+ atomic_set(&dev->watchdog_cnt, 0);
+
+ /* Get the reason of interrupt and the error code */
+ reason = s5p_mfc_get_int_reason();
+ err = s5p_mfc_get_int_err();
+ mfc_debug(2, "Int reason: %d (err: %d)\n", reason, err);
+
+ /* don't try to lookup current context for these operations */
+ switch (reason) {
+ case S5P_FIMV_R2H_CMD_SYS_INIT_RET:
+ case S5P_FIMV_R2H_CMD_FW_STATUS_RET:
+ case S5P_FIMV_R2H_CMD_SLEEP_RET:
+ case S5P_FIMV_R2H_CMD_WAKEUP_RET:
+ s5p_mfc_clear_int_flags();
+ wake_up_dev(dev, reason, err);
+ /* Initialize hw_lock */
+ dev->hw_lock = 0;
+ goto done;
+ }
+
+ ctx = dev->ctx[dev->curr_ctx];
+ if (!ctx) {
+ unsigned long r2h_int;
+
+ mfc_err("Invalid context %d: num_insts=%d work_bits=%lx hw_lock=%lx\n",
+ dev->curr_ctx, dev->num_inst, dev->ctx_work_bits,
+ dev->hw_lock);
+ r2h_int = readl(dev->regs_base + S5P_FIMV_RISC2HOST_INT);
+ mfc_err(" reason=%d err=%d r2h_int=%lx\n",
+ reason, err, r2h_int);
+ BUG();
+ }
+
+ if (ctx->type == MFCINST_DECODER)
+ dec = ctx->dec_priv;
+
+ switch (reason) {
+ case S5P_FIMV_R2H_CMD_ERR_RET:
+ /* An error has occured */
+ if (ctx->state == MFCINST_RUNNING) {
+ if (s5p_mfc_err_dec(err) >= S5P_FIMV_ERR_WARNINGS_START)
+ s5p_mfc_handle_frame(ctx, reason, err);
+ else
+ s5p_mfc_handle_frame_error(ctx, reason, err);
+ } else {
+ s5p_mfc_handle_error(ctx, reason, err);
+ }
+ break;
+ case S5P_FIMV_R2H_CMD_SLICE_DONE_RET:
+ case S5P_FIMV_R2H_CMD_FIELD_DONE_RET:
+ case S5P_FIMV_R2H_CMD_FRAME_DONE_RET:
+ if (ctx->c_ops->post_frame_start) {
+ if (ctx->c_ops->post_frame_start(ctx))
+ mfc_err("post_frame_start() failed\n");
+
+ s5p_mfc_clear_int_flags();
+ wake_up_ctx(ctx, reason, err);
+ if (test_and_clear_bit(ctx->num, &dev->hw_lock) == 0)
+ BUG();
+
+ s5p_mfc_clock_off();
+
+ queue_work(dev->irq_workqueue, &dev->work_struct);
+ } else {
+ s5p_mfc_handle_frame(ctx, reason, err);
+ }
+ break;
+ case S5P_FIMV_R2H_CMD_SEQ_DONE_RET:
+ if (ctx->type == MFCINST_ENCODER) {
+ if (ctx->c_ops->post_seq_start(ctx))
+ mfc_err("post_seq_start() failed\n");
+ } else if (ctx->type == MFCINST_DECODER) {
+ if (ctx->src_fmt->fourcc != V4L2_PIX_FMT_FIMV1) {
+ ctx->img_width = s5p_mfc_get_img_width();
+ ctx->img_height = s5p_mfc_get_img_height();
+ }
+
+ s5p_mfc_dec_calc_dpb_size(ctx);
+
+ ctx->dpb_count = s5p_mfc_get_dpb_count();
+ if (dev->fw.date >= 0x120206)
+ dec->mv_count = s5p_mfc_get_mv_count();
+ if (ctx->img_width == 0 || ctx->img_height == 0)
+ ctx->state = MFCINST_ERROR;
+ else
+ ctx->state = MFCINST_HEAD_PARSED;
+
+ if ((ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC ||
+ ctx->codec_mode == S5P_FIMV_CODEC_H264_MVC_DEC) &&
+ !list_empty(&ctx->src_queue)) {
+ struct s5p_mfc_buf *src_buf;
+ src_buf = list_entry(ctx->src_queue.next,
+ struct s5p_mfc_buf, list);
+ mfc_debug(2, "Check consumed size of header. ");
+ mfc_debug(2, "source : %d, consumed : %d\n",
+ s5p_mfc_get_consumed_stream(),
+ src_buf->vb.v4l2_planes[0].bytesused);
+ if (s5p_mfc_get_consumed_stream() <
+ src_buf->vb.v4l2_planes[0].bytesused)
+ dec->remained = 1;
+ }
+ }
+
+ s5p_mfc_clear_int_flags();
+ clear_work_bit(ctx);
+ if (test_and_clear_bit(ctx->num, &dev->hw_lock) == 0)
+ BUG();
+
+ s5p_mfc_clock_off();
+
+ queue_work(dev->irq_workqueue, &dev->work_struct);
+
+ wake_up_ctx(ctx, reason, err);
+ break;
+ case S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET:
+ ctx->inst_no = s5p_mfc_get_inst_no();
+ ctx->state = MFCINST_GOT_INST;
+ clear_work_bit(ctx);
+ wake_up_ctx(ctx, reason, err);
+ goto irq_cleanup_hw;
+ break;
+ case S5P_FIMV_R2H_CMD_CLOSE_INSTANCE_RET:
+ clear_work_bit(ctx);
+ ctx->state = MFCINST_FREE;
+ wake_up_ctx(ctx, reason, err);
+ goto irq_cleanup_hw;
+ break;
+ case S5P_FIMV_R2H_CMD_INIT_BUFFERS_RET:
+ s5p_mfc_clear_int_flags();
+ ctx->int_type = reason;
+ ctx->int_err = err;
+ ctx->int_cond = 1;
+ spin_lock(&dev->condlock);
+ clear_bit(ctx->num, &dev->ctx_work_bits);
+ spin_unlock(&dev->condlock);
+ if (err == 0) {
+ ctx->state = MFCINST_RUNNING;
+ if (ctx->type == MFCINST_DECODER &&
+ dec->dst_memtype == V4L2_MEMORY_MMAP) {
+ if (!dec->dpb_flush && !dec->remained) {
+ mfc_debug(2, "INIT_BUFFERS with dpb_flush - leaving image in src queue.\n");
+ spin_lock_irqsave(&dev->irqlock, flags);
+ if (!list_empty(&ctx->src_queue)) {
+ src_buf = list_entry(ctx->src_queue.next,
+ struct s5p_mfc_buf, list);
+ list_del(&src_buf->list);
+ ctx->src_queue_cnt--;
+ vb2_buffer_done(&src_buf->vb, VB2_BUF_STATE_DONE);
+ }
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+ } else {
+ if (dec->dpb_flush)
+ dec->dpb_flush = 0;
+ }
+ } else if (ctx->type == MFCINST_ENCODER) {
+ if (s5p_mfc_enc_ctx_ready(ctx)) {
+ spin_lock_irqsave(&dev->condlock,
+ flags);
+ set_bit(ctx->num, &dev->ctx_work_bits);
+ spin_unlock_irqrestore(&dev->condlock,
+ flags);
+ }
+ }
+
+ if (test_and_clear_bit(ctx->num, &dev->hw_lock) == 0)
+ BUG();
+
+ s5p_mfc_clock_off();
+
+ wake_up(&ctx->queue);
+
+ queue_work(dev->irq_workqueue, &dev->work_struct);
+ } else {
+ if (test_and_clear_bit(ctx->num, &dev->hw_lock) == 0)
+ BUG();
+
+ s5p_mfc_clock_off();
+
+ wake_up(&ctx->queue);
+ }
+ break;
+ default:
+ mfc_debug(2, "Unknown int reason.\n");
+ s5p_mfc_clear_int_flags();
+ }
+
+done:
+ mfc_debug_leave();
+ return IRQ_HANDLED;
+
+irq_cleanup_hw:
+ s5p_mfc_clear_int_flags();
+ if (test_and_clear_bit(ctx->num, &dev->hw_lock) == 0)
+ mfc_err("Failed to unlock hw.\n");
+
+ s5p_mfc_clock_off();
+
+ queue_work(dev->irq_workqueue, &dev->work_struct);
+ mfc_debug(2, "%s-- (via irq_cleanup_hw)\n", __func__);
+ return IRQ_HANDLED;
+}
+
+/* Open an MFC node */
+static int s5p_mfc_open(struct file *file)
+{
+ struct s5p_mfc_ctx *ctx = NULL;
+ struct s5p_mfc_dev *dev = video_drvdata(file);
+ unsigned long flags;
+ int ret = 0;
+ enum s5p_mfc_node_type node;
+
+ mfc_debug_enter();
+
+ node = s5p_mfc_get_node_type(file);
+ if (node == MFCNODE_INVALID) {
+ mfc_err("cannot specify node type\n");
+ ret = -ENOENT;
+ goto err_node_type;
+ }
+
+#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
+ if (dev->num_drm_inst > 0) {
+ mfc_err("DRM instance was activated, cannot open no more instance\n");
+ ret = -EINVAL;
+ goto err_drm_playback;
+ }
+#endif
+ dev->num_inst++; /* It is guarded by mfc_mutex in vfd */
+ if (dev->num_inst == 1)
+ __pm_stay_awake(&dev->mfc_ws);
+
+ /* Allocate memory for context */
+ ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
+ if (!ctx) {
+ mfc_err("Not enough memory.\n");
+ ret = -ENOMEM;
+ goto err_ctx_alloc;
+ }
+
+ v4l2_fh_init(&ctx->fh, (node == MFCNODE_DECODER) ? dev->vfd_dec : dev->vfd_enc);
+ file->private_data = &ctx->fh;
+ v4l2_fh_add(&ctx->fh);
+
+ ctx->dev = dev;
+
+ /* Get context number */
+ ctx->num = 0;
+ while (dev->ctx[ctx->num]) {
+ ctx->num++;
+ if (ctx->num >= MFC_NUM_CONTEXTS) {
+ mfc_err("Too many open contexts.\n");
+ ret = -EBUSY;
+ goto err_ctx_num;
+ }
+ }
+
+ /* Mark context as idle */
+ spin_lock_irqsave(&dev->condlock, flags);
+ clear_bit(ctx->num, &dev->ctx_work_bits);
+ spin_unlock_irqrestore(&dev->condlock, flags);
+ dev->ctx[ctx->num] = ctx;
+
+ init_waitqueue_head(&ctx->queue);
+
+ if (node == MFCNODE_DECODER)
+ ret = s5p_mfc_init_dec_ctx(ctx);
+ else
+ ret = s5p_mfc_init_enc_ctx(ctx);
+ if (ret)
+ goto err_ctx_init;
+
+ ret = call_cop(ctx, init_ctx_ctrls, ctx);
+ if (ret) {
+ mfc_err("failed int init_buf_ctrls\n");
+ goto err_ctx_ctrls;
+ }
+
+#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
+ if (check_magic(dev->drm_info.virt)) {
+ if (dev->num_inst == 1) {
+ mfc_debug(1, "DRM instance opened\n");
+
+ dev->num_drm_inst++;
+ ctx->is_drm = 1;
+
+ s5p_mfc_alloc_instance_buffer(ctx);
+ } else {
+ clear_magic(dev->drm_info.virt);
+ mfc_err("MFC instances are not cleared before DRM instance!\n");
+ ret = -EINVAL;
+ goto err_drm_start;
+ }
+ }
+#endif
+
+ /* Load firmware if this is the first instance */
+ if (dev->num_inst == 1) {
+ dev->watchdog_timer.expires = jiffies +
+ msecs_to_jiffies(MFC_WATCHDOG_INTERVAL);
+ add_timer(&dev->watchdog_timer);
+#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
+ if (check_magic(dev->drm_info.virt)) {
+ clear_magic(dev->drm_info.virt);
+
+ if (!dev->fw_status) {
+ ret = s5p_mfc_alloc_firmware(dev);
+ if (ret)
+ goto err_fw_alloc;
+ }
+
+ dev->fw_status = 1;
+ } else {
+ if (!dev->fw_status) {
+ ret = s5p_mfc_alloc_firmware(dev);
+ if (ret)
+ goto err_fw_alloc;
+
+ ret = s5p_mfc_load_firmware(dev);
+ if (ret)
+ goto err_fw_load;
+
+ dev->fw_status = 1;
+ }
+ }
+
+ s5p_mfc_alloc_dev_context_buffer(dev);
+#else
+ /* Load the FW */
+ ret = s5p_mfc_alloc_firmware(dev);
+ if (ret)
+ goto err_fw_alloc;
+
+ ret = s5p_mfc_load_firmware(dev);
+ if (ret)
+ goto err_fw_load;
+#endif
+ mfc_debug(2, "power on\n");
+ ret = s5p_mfc_power_on();
+ if (ret < 0) {
+ mfc_err("power on failed\n");
+ goto err_pwr_enable;
+ }
+
+ dev->curr_ctx = ctx->num;
+ dev->curr_ctx_drm = ctx->is_drm;
+
+ /* Init the FW */
+ ret = s5p_mfc_init_hw(dev);
+ if (ret)
+ goto err_hw_init;
+ }
+
+ return ret;
+
+ /* Deinit when failure occured */
+err_hw_init:
+ s5p_mfc_power_off();
+
+err_pwr_enable:
+#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
+ s5p_mfc_release_dev_context_buffer(dev);
+#endif
+err_fw_load:
+#ifndef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
+ /* only release the firmware buffers when DRM is not possible */
+ s5p_mfc_release_firmware(dev);
+#endif
+
+err_fw_alloc:
+ del_timer_sync(&dev->watchdog_timer);
+ if (ctx->is_drm) {
+ s5p_mfc_release_instance_buffer(ctx);
+ dev->num_drm_inst--;
+ }
+
+#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
+err_drm_start:
+#endif
+ call_cop(ctx, cleanup_ctx_ctrls, ctx);
+
+err_ctx_ctrls:
+ if (node == MFCNODE_DECODER)
+ kfree(ctx->dec_priv);
+ else if (ctx->type == MFCINST_ENCODER)
+ kfree(ctx->enc_priv);
+
+err_ctx_init:
+ dev->ctx[ctx->num] = 0;
+
+err_ctx_num:
+ v4l2_fh_del(&ctx->fh);
+ v4l2_fh_exit(&ctx->fh);
+ kfree(ctx);
+
+err_ctx_alloc:
+ dev->num_inst--;
+ if (dev->num_inst == 0)
+ __pm_relax(&dev->mfc_ws);
+
+#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
+err_drm_playback:
+#endif
+err_node_type:
+ mfc_debug_leave();
+
+ return ret;
+}
+
+/* Release MFC context */
+static int s5p_mfc_release(struct file *file)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ struct s5p_mfc_dev *dev = ctx->dev;
+ unsigned long flags;
+
+ mfc_debug_enter();
+
+ if (call_cop(ctx, cleanup_ctx_ctrls, ctx) < 0)
+ mfc_err("failed in init_buf_ctrls\n");
+
+ v4l2_fh_del(&ctx->fh);
+ v4l2_fh_exit(&ctx->fh);
+
+ vb2_queue_release(&ctx->vq_src);
+ vb2_queue_release(&ctx->vq_dst);
+
+ /* Mark context as idle */
+ spin_lock_irqsave(&dev->condlock, flags);
+ clear_bit(ctx->num, &dev->ctx_work_bits);
+ spin_unlock_irqrestore(&dev->condlock, flags);
+ /* If instance was initialised then
+ * return instance and free reosurces */
+ if (ctx->inst_no != MFC_NO_INSTANCE_SET) {
+ ctx->state = MFCINST_RETURN_INST;
+ spin_lock_irqsave(&dev->condlock, flags);
+ set_bit(ctx->num, &dev->ctx_work_bits);
+ spin_unlock_irqrestore(&dev->condlock, flags);
+ s5p_mfc_try_run(dev);
+ /* Wait until instance is returned or timeout occured */
+ if (s5p_mfc_wait_for_done_ctx
+ (ctx, S5P_FIMV_R2H_CMD_CLOSE_INSTANCE_RET)) {
+ mfc_err("Err returning instance.\n");
+ }
+ /* Free resources */
+ s5p_mfc_release_codec_buffers(ctx);
+ if (!ctx->is_drm)
+ s5p_mfc_release_instance_buffer(ctx);
+ if (ctx->type == MFCINST_DECODER)
+ s5p_mfc_release_dec_desc_buffer(ctx);
+
+ ctx->inst_no = -1;
+ }
+ /* hardware locking scheme */
+ if (dev->curr_ctx == ctx->num)
+ clear_bit(ctx->num, &dev->hw_lock);
+
+ if (ctx->is_drm) {
+ dev->num_drm_inst--;
+ if (dev->num_drm_inst == 0)
+ s5p_mfc_release_instance_buffer(ctx);
+ }
+ dev->num_inst--;
+
+ if (dev->num_inst == 0) {
+ s5p_mfc_deinit_hw(dev);
+
+ /* reset <-> F/W release */
+#ifndef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
+ s5p_mfc_release_firmware(dev);
+#endif
+ del_timer_sync(&dev->watchdog_timer);
+
+ mfc_debug(2, "power off\n");
+ s5p_mfc_power_off();
+ __pm_relax(&dev->mfc_ws);
+
+ }
+
+ if (ctx->type == MFCINST_DECODER)
+ kfree(ctx->dec_priv);
+ else if (ctx->type == MFCINST_ENCODER)
+ kfree(ctx->enc_priv);
+ dev->ctx[ctx->num] = 0;
+ kfree(ctx);
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+/* Poll */
+static unsigned int s5p_mfc_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ unsigned int ret = 0;
+
+ if (s5p_mfc_get_node_type(file) == MFCNODE_DECODER)
+ ret = vb2_poll(&ctx->vq_src, file, wait);
+ else if (s5p_mfc_get_node_type(file) == MFCNODE_ENCODER)
+ ret = vb2_poll(&ctx->vq_dst, file, wait);
+
+ return ret;
+}
+
+/* Mmap */
+static int s5p_mfc_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+ int ret;
+
+ mfc_debug_enter();
+ if (offset < DST_QUEUE_OFF_BASE) {
+ mfc_debug(2, "mmaping source.\n");
+ ret = vb2_mmap(&ctx->vq_src, vma);
+ } else { /* capture */
+ mfc_debug(2, "mmaping destination.\n");
+ vma->vm_pgoff -= (DST_QUEUE_OFF_BASE >> PAGE_SHIFT);
+ ret = vb2_mmap(&ctx->vq_dst, vma);
+ }
+ mfc_debug_leave();
+ return ret;
+}
+
+/* v4l2 ops */
+static const struct v4l2_file_operations s5p_mfc_fops = {
+ .owner = THIS_MODULE,
+ .open = s5p_mfc_open,
+ .release = s5p_mfc_release,
+ .poll = s5p_mfc_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = s5p_mfc_mmap,
+};
+
+/* videodec structure */
+static struct video_device s5p_mfc_dec_videodev = {
+ .name = S5P_MFC_DEC_NAME,
+ .fops = &s5p_mfc_fops,
+ /*
+ .ioctl_ops = &s5p_mfc_ioctl_ops,
+ */
+ .minor = -1,
+ .release = video_device_release,
+};
+
+static struct video_device s5p_mfc_enc_videodev = {
+ .name = S5P_MFC_ENC_NAME,
+ .fops = &s5p_mfc_fops,
+ /*
+ .ioctl_ops = &s5p_mfc_enc_ioctl_ops,
+ */
+ .minor = -1,
+ .release = video_device_release,
+};
+
+#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
+static int proc_read_inst_number(char *buf, char **start,
+ off_t off, int count, int *eof, void *data)
+{
+ struct s5p_mfc_dev *dev = (struct s5p_mfc_dev *)data;
+ int len = 0;
+
+ len += sprintf(buf + len, "%d\n", dev->num_inst);
+
+ return len;
+}
+
+static int proc_read_drm_inst_number(char *buf, char **start,
+ off_t off, int count, int *eof, void *data)
+{
+ struct s5p_mfc_dev *dev = (struct s5p_mfc_dev *)data;
+ int len = 0;
+
+ len += sprintf(buf + len, "%d\n", dev->num_drm_inst);
+
+ return len;
+}
+
+static int proc_read_fw_status(char *buf, char **start,
+ off_t off, int count, int *eof, void *data)
+{
+ struct s5p_mfc_dev *dev = (struct s5p_mfc_dev *)data;
+ int len = 0;
+
+ len += sprintf(buf + len, "%d\n", dev->fw_status);
+
+ return len;
+}
+#endif
+
+/* MFC probe function */
+static int __devinit s5p_mfc_probe(struct platform_device *pdev)
+{
+ struct s5p_mfc_dev *dev;
+ struct video_device *vfd;
+ struct resource *res;
+ int ret = -ENOENT;
+ unsigned int alloc_ctx_num;
+ size_t size;
+ char workqueue_name[MFC_WORKQUEUE_LEN];
+
+ pr_debug("%s++\n", __func__);
+ dev = kzalloc(sizeof *dev, GFP_KERNEL);
+ if (!dev) {
+ dev_err(&pdev->dev, "Not enough memory for MFC device.\n");
+ return -ENOMEM;
+ }
+
+ spin_lock_init(&dev->irqlock);
+ spin_lock_init(&dev->condlock);
+ dev_dbg(&pdev->dev, "Initialised spin lock\n");
+ dev->plat_dev = pdev;
+ if (!dev->plat_dev) {
+ dev_err(&pdev->dev, "No platform data specified\n");
+ ret = -ENODEV;
+ goto free_dev;
+ }
+
+ dev->platdata = (&pdev->dev)->platform_data;
+ dev_dbg(&pdev->dev, "Getting clocks\n");
+ ret = s5p_mfc_init_pm(dev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to get mfc clock source\n");
+ goto free_clk;
+ }
+
+ wakeup_source_init(&dev->mfc_ws, "mfc");
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "failed to get memory region resource.\n");
+ ret = -ENOENT;
+ goto probe_out1;
+ }
+ size = (res->end - res->start) + 1;
+ dev->mfc_mem = request_mem_region(res->start, size, pdev->name);
+ if (dev->mfc_mem == NULL) {
+ dev_err(&pdev->dev, "failed to get memory region.\n");
+ ret = -ENOENT;
+ goto probe_out2;
+ }
+ dev->regs_base = ioremap(dev->mfc_mem->start,
+ dev->mfc_mem->end - dev->mfc_mem->start + 1);
+ if (dev->regs_base == NULL) {
+ dev_err(&pdev->dev, "failed to ioremap address region.\n");
+ ret = -ENOENT;
+ goto probe_out3;
+ }
+
+ s5p_mfc_init_reg(dev->regs_base);
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "failed to get irq resource.\n");
+ ret = -ENOENT;
+ goto probe_out4;
+ }
+ dev->irq = res->start;
+ ret = request_threaded_irq(dev->irq, NULL, s5p_mfc_irq, IRQF_ONESHOT, pdev->name,
+ dev);
+ if (ret != 0) {
+ dev_err(&pdev->dev, "Failed to install irq (%d)\n", ret);
+ goto probe_out5;
+ }
+
+ mutex_init(&dev->mfc_mutex);
+
+ ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
+ if (ret)
+ goto probe_out6;
+ init_waitqueue_head(&dev->queue);
+
+ /* decoder */
+ vfd = video_device_alloc();
+ if (!vfd) {
+ v4l2_err(&dev->v4l2_dev, "Failed to allocate video device\n");
+ ret = -ENOMEM;
+ goto alloc_vdev_dec;
+ }
+ *vfd = s5p_mfc_dec_videodev;
+
+ vfd->ioctl_ops = get_dec_v4l2_ioctl_ops();
+
+ vfd->lock = &dev->mfc_mutex;
+ vfd->v4l2_dev = &dev->v4l2_dev;
+ snprintf(vfd->name, sizeof(vfd->name), "%s", s5p_mfc_dec_videodev.name);
+
+ ret = video_register_device(vfd, VFL_TYPE_GRABBER, S5P_VIDEONODE_MFC_DEC);
+ if (ret) {
+ v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
+ video_device_release(vfd);
+ goto reg_vdev_dec;
+ }
+ v4l2_info(&dev->v4l2_dev, "decoder registered as /dev/video%d\n",
+ vfd->num);
+ dev->vfd_dec = vfd;
+
+ video_set_drvdata(vfd, dev);
+
+ /* encoder */
+ vfd = video_device_alloc();
+ if (!vfd) {
+ v4l2_err(&dev->v4l2_dev, "Failed to allocate video device\n");
+ ret = -ENOMEM;
+ goto alloc_vdev_enc;
+ }
+ *vfd = s5p_mfc_enc_videodev;
+
+ vfd->ioctl_ops = get_enc_v4l2_ioctl_ops();
+
+ vfd->lock = &dev->mfc_mutex;
+ vfd->v4l2_dev = &dev->v4l2_dev;
+ snprintf(vfd->name, sizeof(vfd->name), "%s", s5p_mfc_enc_videodev.name);
+
+ ret = video_register_device(vfd, VFL_TYPE_GRABBER, S5P_VIDEONODE_MFC_ENC);
+ if (ret) {
+ v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
+ video_device_release(vfd);
+ goto reg_vdev_enc;
+ }
+ v4l2_info(&dev->v4l2_dev, "encoder registered as /dev/video%d\n",
+ vfd->num);
+ dev->vfd_enc = vfd;
+
+ video_set_drvdata(vfd, dev);
+
+ platform_set_drvdata(pdev, dev);
+
+ dev->hw_lock = 0;
+ dev->watchdog_workqueue = create_singlethread_workqueue(S5P_MFC_NAME);
+ INIT_WORK(&dev->watchdog_work, s5p_mfc_watchdog_worker);
+ atomic_set(&dev->watchdog_cnt, 0);
+ init_timer(&dev->watchdog_timer);
+ dev->watchdog_timer.data = (unsigned long)dev;
+ dev->watchdog_timer.function = s5p_mfc_watchdog;
+
+ dev->fw.ver = 0x65;
+ dev->variant = (struct s5p_mfc_variant *)
+ platform_get_device_id(pdev)->driver_data;
+
+ /* default FW alloc is added */
+ alloc_ctx_num = dev->variant->port_num + 1;
+ dev->alloc_ctx = (struct vb2_alloc_ctx **)
+ s5p_mfc_mem_init_multi(&pdev->dev, alloc_ctx_num);
+
+ if (IS_ERR(dev->alloc_ctx)) {
+ mfc_err("Couldn't prepare allocator ctx.\n");
+ ret = PTR_ERR(dev->alloc_ctx);
+ goto alloc_ctx_fail;
+ }
+
+ sprintf(workqueue_name, "mfc_workqueue");
+ dev->irq_workqueue = alloc_workqueue((workqueue_name), WQ_UNBOUND
+ | WQ_MEM_RECLAIM | WQ_HIGHPRI, 1);
+ if (dev->irq_workqueue == NULL) {
+ dev_err(&pdev->dev, "failed to create workqueue for mfc\n");
+ goto workqueue_fail;
+ }
+ INIT_WORK(&dev->work_struct, mfc_workqueue_try_run);
+
+#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
+ dev->alloc_ctx_fw = (struct vb2_alloc_ctx *)
+ vb2_ion_create_context(&pdev->dev,
+ IS_MFCV6(dev) ? SZ_4K : SZ_128K,
+ VB2ION_CTX_DRM_MFCFW);
+ if (IS_ERR(dev->alloc_ctx_fw)) {
+ mfc_err("failed to prepare F/W allocation context\n");
+ ret = PTR_ERR(dev->alloc_ctx_fw);
+ goto alloc_ctx_fw_fail;
+ }
+
+ dev->alloc_ctx_sh = (struct vb2_alloc_ctx *)
+ vb2_ion_create_context(&pdev->dev,
+ SZ_4K,
+ VB2ION_CTX_DRM_MFCSH);
+ if (IS_ERR(dev->alloc_ctx_sh)) {
+ mfc_err("failed to prepare shared allocation context\n");
+ ret = PTR_ERR(dev->alloc_ctx_sh);
+ goto alloc_ctx_sh_fail;
+ }
+
+ dev->drm_info.alloc = s5p_mfc_mem_alloc(dev->alloc_ctx_sh, PAGE_SIZE);
+ if (IS_ERR(dev->drm_info.alloc)) {
+ mfc_err("failed to allocate shared region\n");
+ ret = PTR_ERR(dev->drm_info.alloc);
+ goto shared_alloc_fail;
+ }
+ dev->drm_info.virt = s5p_mfc_mem_vaddr(dev->drm_info.alloc);
+ if (!dev->drm_info.virt) {
+ mfc_err("failed to get vaddr for shared region\n");
+ ret = -ENOMEM;
+ goto shared_vaddr_fail;
+ }
+
+ dev->alloc_ctx_drm = (struct vb2_alloc_ctx *)
+ vb2_ion_create_context(&pdev->dev,
+ SZ_4K,
+ VB2ION_CTX_DRM_VIDEO);
+ if (IS_ERR(dev->alloc_ctx_drm)) {
+ mfc_err("failed to prepare DRM allocation context\n");
+ ret = PTR_ERR(dev->alloc_ctx_drm);
+ goto alloc_ctx_drm_fail;
+ }
+
+ mfc_proc_entry = proc_mkdir(MFC_PROC_ROOT, NULL);
+ if (!mfc_proc_entry) {
+ dev_err(&pdev->dev, "unable to create /proc/%s\n",
+ MFC_PROC_ROOT);
+ ret = -ENOMEM;
+ goto err_proc_entry;
+ }
+
+ if (!create_proc_read_entry(MFC_PROC_INSTANCE_NUMBER,
+ 0,
+ mfc_proc_entry,
+ proc_read_inst_number,
+ dev)) {
+ dev_err(&pdev->dev, "unable to create /proc/%s/%s\n",
+ MFC_PROC_ROOT, MFC_PROC_INSTANCE_NUMBER);
+ ret = -ENOMEM;
+ goto err_proc_number;
+ }
+
+ if (!create_proc_read_entry(MFC_PROC_DRM_INSTANCE_NUMBER,
+ 0,
+ mfc_proc_entry,
+ proc_read_drm_inst_number,
+ dev)) {
+ dev_err(&pdev->dev, "unable to create /proc/%s/%s\n",
+ MFC_PROC_ROOT, MFC_PROC_DRM_INSTANCE_NUMBER);
+ ret = -ENOMEM;
+ goto err_proc_drm;
+ }
+
+ if (!create_proc_read_entry(MFC_PROC_FW_STATUS,
+ 0,
+ mfc_proc_entry,
+ proc_read_fw_status,
+ dev)) {
+ dev_err(&pdev->dev, "unable to create /proc/%s/%s\n",
+ MFC_PROC_ROOT, MFC_PROC_FW_STATUS);
+ ret = -ENOMEM;
+ goto err_proc_fw;
+ }
+#endif
+ pr_debug("%s--\n", __func__);
+ return 0;
+
+/* Deinit MFC if probe had failed */
+#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
+err_proc_fw:
+ remove_proc_entry(MFC_PROC_DRM_INSTANCE_NUMBER, mfc_proc_entry);
+err_proc_drm:
+ remove_proc_entry(MFC_PROC_INSTANCE_NUMBER, mfc_proc_entry);
+err_proc_number:
+ remove_proc_entry(MFC_PROC_ROOT, NULL);
+err_proc_entry:
+ vb2_ion_destroy_context(dev->alloc_ctx_drm);
+shared_vaddr_fail:
+ s5p_mfc_mem_free(dev->drm_info.alloc);
+shared_alloc_fail:
+alloc_ctx_drm_fail:
+ vb2_ion_destroy_context(dev->alloc_ctx_sh);
+alloc_ctx_sh_fail:
+ vb2_ion_destroy_context(dev->alloc_ctx_fw);
+alloc_ctx_fw_fail:
+ destroy_workqueue(dev->irq_workqueue);
+#endif
+workqueue_fail:
+ s5p_mfc_mem_cleanup_multi((void **)dev->alloc_ctx,
+ alloc_ctx_num);
+alloc_ctx_fail:
+ video_unregister_device(dev->vfd_enc);
+reg_vdev_enc:
+alloc_vdev_enc:
+ video_unregister_device(dev->vfd_dec);
+reg_vdev_dec:
+alloc_vdev_dec:
+ v4l2_device_unregister(&dev->v4l2_dev);
+probe_out6:
+ free_irq(dev->irq, dev);
+probe_out5:
+probe_out4:
+ iounmap(dev->regs_base);
+ dev->regs_base = NULL;
+probe_out3:
+ release_resource(dev->mfc_mem);
+ kfree(dev->mfc_mem);
+probe_out2:
+probe_out1:
+ wakeup_source_trash(&dev->mfc_ws);
+ s5p_mfc_final_pm(dev);
+free_clk:
+
+free_dev:
+ kfree(dev);
+ pr_debug("%s-- with error\n", __func__);
+ return ret;
+}
+
+/* Remove the driver */
+static int __devexit s5p_mfc_remove(struct platform_device *pdev)
+{
+ struct s5p_mfc_dev *dev = platform_get_drvdata(pdev);
+
+ dev_dbg(&pdev->dev, "%s++\n", __func__);
+ v4l2_info(&dev->v4l2_dev, "Removing %s\n", pdev->name);
+ del_timer_sync(&dev->watchdog_timer);
+ flush_workqueue(dev->watchdog_workqueue);
+ destroy_workqueue(dev->watchdog_workqueue);
+ video_unregister_device(dev->vfd_enc);
+ video_unregister_device(dev->vfd_dec);
+ v4l2_device_unregister(&dev->v4l2_dev);
+#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
+ remove_proc_entry(MFC_PROC_FW_STATUS, mfc_proc_entry);
+ remove_proc_entry(MFC_PROC_DRM_INSTANCE_NUMBER, mfc_proc_entry);
+ remove_proc_entry(MFC_PROC_INSTANCE_NUMBER, mfc_proc_entry);
+ remove_proc_entry(MFC_PROC_ROOT, NULL);
+ vb2_ion_destroy_context(dev->alloc_ctx_drm);
+ s5p_mfc_mem_free(dev->drm_info.alloc);
+ vb2_ion_destroy_context(dev->alloc_ctx_sh);
+ vb2_ion_destroy_context(dev->alloc_ctx_fw);
+#endif
+ s5p_mfc_mem_cleanup_multi((void **)dev->alloc_ctx,
+ dev->variant->port_num + 1);
+ mfc_debug(2, "Will now deinit HW\n");
+ s5p_mfc_deinit_hw(dev);
+ free_irq(dev->irq, dev);
+ iounmap(dev->regs_base);
+ if (dev->mfc_mem != NULL) {
+ release_resource(dev->mfc_mem);
+ kfree(dev->mfc_mem);
+ dev->mfc_mem = NULL;
+ }
+ wakeup_source_trash(&dev->mfc_ws);
+ s5p_mfc_final_pm(dev);
+ kfree(dev);
+ dev_dbg(&pdev->dev, "%s--\n", __func__);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int s5p_mfc_suspend(struct device *dev)
+{
+ struct s5p_mfc_dev *m_dev = platform_get_drvdata(to_platform_device(dev));
+ int ret;
+
+ if (m_dev->num_inst == 0)
+ return 0;
+
+#ifndef DISABLE_SLEEP
+ ret = s5p_mfc_sleep(m_dev);
+#else
+ ret = -EBUSY;
+#endif
+
+ return ret;
+}
+
+static int s5p_mfc_resume(struct device *dev)
+{
+ struct s5p_mfc_dev *m_dev = platform_get_drvdata(to_platform_device(dev));
+ int ret;
+
+ if (m_dev->num_inst == 0)
+ return 0;
+
+#ifndef DISABLE_SLEEP
+ ret = s5p_mfc_wakeup(m_dev);
+#else
+ /* cannot be here without sleep enabled since suspend would return
+ * an error */
+ BUG();
+#endif
+
+ return ret;
+}
+#endif
+
+#ifdef CONFIG_PM_RUNTIME
+static int s5p_mfc_runtime_suspend(struct device *dev)
+{
+ struct s5p_mfc_dev *m_dev = platform_get_drvdata(to_platform_device(dev));
+ int pre_power;
+
+ pre_power = atomic_read(&m_dev->pm.power);
+ atomic_set(&m_dev->pm.power, 0);
+
+ return 0;
+}
+
+static int s5p_mfc_runtime_idle(struct device *dev)
+{
+ return 0;
+}
+
+static int s5p_mfc_runtime_resume(struct device *dev)
+{
+ struct s5p_mfc_dev *m_dev = platform_get_drvdata(to_platform_device(dev));
+ int pre_power;
+
+ if (!m_dev->alloc_ctx)
+ return 0;
+
+ pre_power = atomic_read(&m_dev->pm.power);
+ atomic_set(&m_dev->pm.power, 1);
+
+ return 0;
+}
+#endif
+
+/* Power management */
+static const struct dev_pm_ops s5p_mfc_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(s5p_mfc_suspend, s5p_mfc_resume)
+ SET_RUNTIME_PM_OPS(
+ s5p_mfc_runtime_suspend,
+ s5p_mfc_runtime_resume,
+ s5p_mfc_runtime_idle
+ )
+};
+
+struct s5p_mfc_buf_size_v5 mfc_buf_size_v5 = {
+ .h264_ctx_buf = PAGE_ALIGN(0x96000), /* 600KB */
+ .non_h264_ctx_buf = PAGE_ALIGN(0x2800), /* 10KB */
+ .desc_buf = PAGE_ALIGN(0x20000), /* 128KB */
+ .shared_buf = PAGE_ALIGN(0x1000), /* 4KB */
+};
+
+struct s5p_mfc_buf_size_v6 mfc_buf_size_v6 = {
+ .dev_ctx = PAGE_ALIGN(0x6400), /* 25KB */
+ .h264_dec_ctx = PAGE_ALIGN(0x200000), /* 1.6MB */
+ .other_dec_ctx = PAGE_ALIGN(0x5000), /* 20KB */
+ .h264_enc_ctx = PAGE_ALIGN(0x19000), /* 100KB */
+ .other_enc_ctx = PAGE_ALIGN(0x2800), /* 10KB */
+};
+
+struct s5p_mfc_buf_size buf_size_v5 = {
+ .firmware_code = PAGE_ALIGN(0x60000), /* 384KB */
+ .cpb_buf = PAGE_ALIGN(0x400000), /* 4MB */
+ .buf = &mfc_buf_size_v5,
+};
+
+struct s5p_mfc_buf_size buf_size_v6 = {
+ .firmware_code = PAGE_ALIGN(0x100000), /* 1MB */
+ .cpb_buf = PAGE_ALIGN(0x300000), /* 3MB */
+ .buf = &mfc_buf_size_v6,
+};
+
+struct s5p_mfc_buf_align mfc_buf_align_v5 = {
+ .mfc_base_align = 17,
+};
+
+struct s5p_mfc_buf_align mfc_buf_align_v6 = {
+ .mfc_base_align = 0,
+};
+
+static struct s5p_mfc_variant mfc_drvdata_v5 = {
+ .version = 0x51,
+ .port_num = 2,
+ .buf_size = &buf_size_v5,
+ .buf_align = &mfc_buf_align_v5,
+};
+
+static struct s5p_mfc_variant mfc_drvdata_v6 = {
+ .version = 0x61,
+ .port_num = 1,
+ .buf_size = &buf_size_v6,
+ .buf_align = &mfc_buf_align_v6,
+};
+
+static struct platform_device_id mfc_driver_ids[] = {
+ {
+ .name = "s5p-mfc",
+ .driver_data = (unsigned long)&mfc_drvdata_v6,
+ }, {
+ .name = "s5p-mfc-v5",
+ .driver_data = (unsigned long)&mfc_drvdata_v5,
+ }, {
+ .name = "s5p-mfc-v6",
+ .driver_data = (unsigned long)&mfc_drvdata_v6,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(platform, mfc_driver_ids);
+
+static struct platform_driver s5p_mfc_driver = {
+ .probe = s5p_mfc_probe,
+ .remove = __devexit_p(s5p_mfc_remove),
+ .id_table = mfc_driver_ids,
+ .driver = {
+ .name = S5P_MFC_NAME,
+ .owner = THIS_MODULE,
+ .pm = &s5p_mfc_pm_ops
+ },
+};
+
+static char banner[] __initdata =
+ "EXYNOS MFC V4L2 Driver, (c) 2010 Samsung Electronics\n";
+
+static int __init s5p_mfc_init(void)
+{
+ pr_info("%s", banner);
+ if (platform_driver_register(&s5p_mfc_driver) != 0) {
+ pr_err("Platform device registration failed..\n");
+ return -1;
+ }
+ return 0;
+}
+
+static void __devexit s5p_mfc_exit(void)
+{
+ platform_driver_unregister(&s5p_mfc_driver);
+}
+
+module_init(s5p_mfc_init);
+module_exit(s5p_mfc_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Kamil Debski <k.debski@samsung.com>");
+
diff --git a/drivers/media/video/exynos/mfc/s5p_mfc_cmd.h b/drivers/media/video/exynos/mfc/s5p_mfc_cmd.h
new file mode 100644
index 0000000..37bd668
--- /dev/null
+++ b/drivers/media/video/exynos/mfc/s5p_mfc_cmd.h
@@ -0,0 +1,29 @@
+/*
+ * linux/drivers/media/video/exynos/mfc/s5p_mfc_cmd.h
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * 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.
+ */
+
+#ifndef __S5P_MFC_CMD_H
+#define __S5P_MFC_CMD_H __FILE__
+
+#define MAX_H2R_ARG 4
+
+struct s5p_mfc_cmd_args {
+ unsigned int arg[MAX_H2R_ARG];
+};
+
+int s5p_mfc_cmd_host2risc(int cmd, struct s5p_mfc_cmd_args *args);
+int s5p_mfc_sys_init_cmd(struct s5p_mfc_dev *dev);
+int s5p_mfc_sleep_cmd(struct s5p_mfc_dev *dev);
+int s5p_mfc_wakeup_cmd(struct s5p_mfc_dev *dev);
+int s5p_mfc_open_inst_cmd(struct s5p_mfc_ctx *ctx);
+int s5p_mfc_close_inst_cmd(struct s5p_mfc_ctx *ctx);
+
+#endif /* __S5P_MFC_CMD_H */
diff --git a/drivers/media/video/exynos/mfc/s5p_mfc_cmd_v5.c b/drivers/media/video/exynos/mfc/s5p_mfc_cmd_v5.c
new file mode 100644
index 0000000..b9d4552
--- /dev/null
+++ b/drivers/media/video/exynos/mfc/s5p_mfc_cmd_v5.c
@@ -0,0 +1,147 @@
+/*
+ * linux/drivers/media/video/exynos/mfc/s5p_mfc_cmd_v5.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * 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.
+ */
+
+#include "s5p_mfc_common.h"
+
+#include "s5p_mfc_debug.h"
+#include "s5p_mfc_reg.h"
+#include "s5p_mfc_cmd.h"
+#include "s5p_mfc_mem.h"
+
+int s5p_mfc_cmd_host2risc(int cmd, struct s5p_mfc_cmd_args *args)
+{
+ int cur_cmd;
+ unsigned long timeout;
+
+ timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT);
+
+ /* wait until host to risc command register becomes 'H2R_CMD_EMPTY' */
+ do {
+ if (time_after(jiffies, timeout)) {
+ mfc_err("Timeout while waiting for hardware.\n");
+ return -EIO;
+ }
+
+ cur_cmd = s5p_mfc_read_reg(S5P_FIMV_HOST2RISC_CMD);
+ } while (cur_cmd != S5P_FIMV_H2R_CMD_EMPTY);
+
+ s5p_mfc_write_reg(args->arg[0], S5P_FIMV_HOST2RISC_ARG1);
+ s5p_mfc_write_reg(args->arg[1], S5P_FIMV_HOST2RISC_ARG2);
+ s5p_mfc_write_reg(args->arg[2], S5P_FIMV_HOST2RISC_ARG3);
+ s5p_mfc_write_reg(args->arg[3], S5P_FIMV_HOST2RISC_ARG4);
+
+ /* Issue the command */
+ s5p_mfc_write_reg(cmd, S5P_FIMV_HOST2RISC_CMD);
+
+ return 0;
+}
+
+int s5p_mfc_sys_init_cmd(struct s5p_mfc_dev *dev)
+{
+ struct s5p_mfc_cmd_args h2r_args;
+ struct s5p_mfc_buf_size *buf_size = dev->variant->buf_size;
+ int ret;
+
+ mfc_debug_enter();
+
+ memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args));
+ h2r_args.arg[0] = buf_size->firmware_code;
+
+ ret = s5p_mfc_cmd_host2risc(S5P_FIMV_H2R_CMD_SYS_INIT, &h2r_args);
+
+ mfc_debug_leave();
+
+ return ret;
+}
+
+int s5p_mfc_sleep_cmd(struct s5p_mfc_dev *dev)
+{
+ struct s5p_mfc_cmd_args h2r_args;
+ int ret;
+
+ mfc_debug_enter();
+
+ memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args));
+
+ ret = s5p_mfc_cmd_host2risc(S5P_FIMV_H2R_CMD_SLEEP, &h2r_args);
+
+ mfc_debug_leave();
+
+ return ret;
+}
+
+int s5p_mfc_wakeup_cmd(struct s5p_mfc_dev *dev)
+{
+ struct s5p_mfc_cmd_args h2r_args;
+ int ret;
+
+ mfc_debug_enter();
+
+ memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args));
+
+ ret = s5p_mfc_cmd_host2risc(S5P_FIMV_H2R_CMD_WAKEUP, &h2r_args);
+
+ mfc_debug_leave();
+
+ return ret;
+}
+
+/* Open a new instance and get its number */
+int s5p_mfc_open_inst_cmd(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_cmd_args h2r_args;
+ unsigned int crc = 0;
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+ int ret;
+
+ mfc_debug_enter();
+
+ mfc_debug(2, "Requested codec mode: %d\n", ctx->codec_mode);
+
+ if (ctx->type == MFCINST_DECODER)
+ crc = dec->crc_enable;
+
+ memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args));
+ h2r_args.arg[0] = ctx->codec_mode;
+ h2r_args.arg[1] = crc << 31; /* no pixelcache */
+ h2r_args.arg[2] = ctx->ctx.ofs;
+ h2r_args.arg[3] = ctx->ctx_buf_size;
+
+ ret = s5p_mfc_cmd_host2risc(S5P_FIMV_H2R_CMD_OPEN_INSTANCE, &h2r_args);
+
+ mfc_debug_leave();
+
+ return ret;
+}
+
+/* Close instance */
+int s5p_mfc_close_inst_cmd(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_cmd_args h2r_args;
+ int ret = 0;
+
+ mfc_debug_enter();
+
+ if (ctx->state != MFCINST_FREE) {
+ memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args));
+ h2r_args.arg[0] = ctx->inst_no;
+
+ ret = s5p_mfc_cmd_host2risc(S5P_FIMV_H2R_CMD_CLOSE_INSTANCE,
+ &h2r_args);
+ } else {
+ ret = -EINVAL;
+ }
+
+ mfc_debug_leave();
+
+ return ret;
+}
diff --git a/drivers/media/video/exynos/mfc/s5p_mfc_cmd_v6.c b/drivers/media/video/exynos/mfc/s5p_mfc_cmd_v6.c
new file mode 100644
index 0000000..d2dbe24
--- /dev/null
+++ b/drivers/media/video/exynos/mfc/s5p_mfc_cmd_v6.c
@@ -0,0 +1,132 @@
+/*
+ * linux/drivers/media/video/exynos/mfc/s5p_mfc_cmd_v6.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * 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.
+ */
+
+#include "s5p_mfc_common.h"
+
+#include "s5p_mfc_debug.h"
+#include "s5p_mfc_reg.h"
+#include "s5p_mfc_cmd.h"
+#include "s5p_mfc_mem.h"
+
+int s5p_mfc_cmd_host2risc(int cmd, struct s5p_mfc_cmd_args *args)
+{
+ mfc_debug(2, "Issue the command: %d\n", cmd);
+
+ /* Reset RISC2HOST command */
+ s5p_mfc_write_reg(0x0, S5P_FIMV_RISC2HOST_CMD);
+
+ /* Issue the command */
+ s5p_mfc_write_reg(cmd, S5P_FIMV_HOST2RISC_CMD);
+ s5p_mfc_write_reg(0x1, S5P_FIMV_HOST2RISC_INT);
+
+ return 0;
+}
+
+int s5p_mfc_sys_init_cmd(struct s5p_mfc_dev *dev)
+{
+ struct s5p_mfc_cmd_args h2r_args;
+ struct s5p_mfc_buf_size_v6 *buf_size = dev->variant->buf_size->buf;
+ int ret;
+
+ mfc_debug_enter();
+
+#ifndef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
+ s5p_mfc_alloc_dev_context_buffer(dev);
+#endif
+
+ s5p_mfc_write_reg(dev->ctx_buf.ofs, S5P_FIMV_CONTEXT_MEM_ADDR);
+ s5p_mfc_write_reg(buf_size->dev_ctx, S5P_FIMV_CONTEXT_MEM_SIZE);
+
+ ret = s5p_mfc_cmd_host2risc(S5P_FIMV_H2R_CMD_SYS_INIT, &h2r_args);
+
+ mfc_debug_leave();
+
+ return ret;
+}
+
+int s5p_mfc_sleep_cmd(struct s5p_mfc_dev *dev)
+{
+ struct s5p_mfc_cmd_args h2r_args;
+ int ret;
+
+ mfc_debug_enter();
+
+ memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args));
+
+ ret = s5p_mfc_cmd_host2risc(S5P_FIMV_H2R_CMD_SLEEP, &h2r_args);
+
+ mfc_debug_leave();
+
+ return ret;
+}
+
+int s5p_mfc_wakeup_cmd(struct s5p_mfc_dev *dev)
+{
+ struct s5p_mfc_cmd_args h2r_args;
+ int ret;
+
+ mfc_debug_enter();
+
+ memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args));
+
+ ret = s5p_mfc_cmd_host2risc(S5P_FIMV_H2R_CMD_WAKEUP, &h2r_args);
+
+ mfc_debug_leave();
+
+ return ret;
+}
+
+/* Open a new instance and get its number */
+int s5p_mfc_open_inst_cmd(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_cmd_args h2r_args;
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+ int ret;
+
+ mfc_debug_enter();
+
+ mfc_debug(2, "Requested codec mode: %d\n", ctx->codec_mode);
+
+ s5p_mfc_write_reg(ctx->codec_mode, S5P_FIMV_CODEC_TYPE);
+ s5p_mfc_write_reg(ctx->ctx.ofs, S5P_FIMV_CONTEXT_MEM_ADDR);
+ s5p_mfc_write_reg(ctx->ctx_buf_size, S5P_FIMV_CONTEXT_MEM_SIZE);
+ if (ctx->type == MFCINST_DECODER)
+ s5p_mfc_write_reg(dec->crc_enable, S5P_FIMV_D_CRC_CTRL);
+
+ ret = s5p_mfc_cmd_host2risc(S5P_FIMV_H2R_CMD_OPEN_INSTANCE, &h2r_args);
+
+ mfc_debug_leave();
+
+ return ret;
+}
+
+/* Close instance */
+int s5p_mfc_close_inst_cmd(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_cmd_args h2r_args;
+ int ret = 0;
+
+ mfc_debug_enter();
+
+ if (ctx->state != MFCINST_FREE) {
+ s5p_mfc_write_reg(ctx->inst_no, S5P_FIMV_INSTANCE_ID);
+
+ ret = s5p_mfc_cmd_host2risc(S5P_FIMV_H2R_CMD_CLOSE_INSTANCE,
+ &h2r_args);
+ } else {
+ ret = -EINVAL;
+ }
+
+ mfc_debug_leave();
+
+ return ret;
+}
diff --git a/drivers/media/video/exynos/mfc/s5p_mfc_common.h b/drivers/media/video/exynos/mfc/s5p_mfc_common.h
new file mode 100644
index 0000000..c19be3b
--- /dev/null
+++ b/drivers/media/video/exynos/mfc/s5p_mfc_common.h
@@ -0,0 +1,661 @@
+/*
+ * Samsung S5P Multi Format Codec V5/V6
+ *
+ * This file contains definitions of enums and structs used by the codec
+ * driver.
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * Kamil Debski, <k.debski@samsung.com>
+ *
+ * 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
+ */
+
+#ifndef S5P_MFC_COMMON_H_
+#define S5P_MFC_COMMON_H_
+
+#include <linux/videodev2.h>
+#include <linux/videodev2_exynos_media.h>
+#include <linux/workqueue.h>
+#include <linux/slab.h>
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-fh.h>
+
+#include <media/videobuf2-core.h>
+
+#include <mach/exynos5_bus.h>
+
+#define MFC_MAX_EXTRA_DPB 5
+#define MFC_MAX_BUFFERS 32
+#define MFC_MAX_REF_BUFS 2
+#define MFC_FRAME_PLANES 2
+
+#define MFC_NUM_CONTEXTS 4
+/* Interrupt timeout */
+#define MFC_INT_TIMEOUT 2000
+/* Busy wait timeout */
+#define MFC_BW_TIMEOUT 500
+/* Watchdog interval */
+#define MFC_WATCHDOG_INTERVAL 1000
+/* After how many executions watchdog should assume lock up */
+#define MFC_WATCHDOG_CNT 10
+
+#define MFC_NO_INSTANCE_SET -1
+
+#define MFC_ENC_CAP_PLANE_COUNT 1
+#define MFC_ENC_OUT_PLANE_COUNT 2
+
+#define MFC_NAME_LEN 16
+#define MFC_FW_NAME "mfc_fw.bin"
+
+#define STUFF_BYTE 4
+#define MFC_WORKQUEUE_LEN 32
+
+#define MFC_BASE_MASK ((1 << 17) - 1)
+#define MFC_VER_MAJOR(ver) ((ver >> 4) & 0xF)
+#define MFC_VER_MINOR(ver) (ver & 0xF)
+
+/**
+ * enum s5p_mfc_inst_type - The type of an MFC device node.
+ */
+enum s5p_mfc_node_type {
+ MFCNODE_INVALID = -1,
+ MFCNODE_DECODER = 0,
+ MFCNODE_ENCODER = 1,
+};
+
+/**
+ * enum s5p_mfc_inst_type - The type of an MFC instance.
+ */
+enum s5p_mfc_inst_type {
+ MFCINST_INVALID = 0,
+ MFCINST_DECODER = 1,
+ MFCINST_ENCODER = 2,
+};
+
+/**
+ * enum s5p_mfc_inst_state - The state of an MFC instance.
+ */
+enum s5p_mfc_inst_state {
+ MFCINST_FREE = 0,
+ MFCINST_INIT = 100,
+ MFCINST_GOT_INST,
+ MFCINST_HEAD_PARSED,
+ MFCINST_BUFS_SET,
+ MFCINST_RUNNING,
+ MFCINST_FINISHING,
+ MFCINST_FINISHED,
+ MFCINST_RETURN_INST,
+ MFCINST_ERROR,
+ MFCINST_ABORT,
+ MFCINST_RES_CHANGE_INIT,
+ MFCINST_RES_CHANGE_FLUSH,
+ MFCINST_RES_CHANGE_END,
+ MFCINST_RUNNING_NO_OUTPUT,
+};
+
+/**
+ * enum s5p_mfc_queue_state - The state of buffer queue.
+ */
+enum s5p_mfc_queue_state {
+ QUEUE_FREE = 0,
+ QUEUE_BUFS_REQUESTED,
+ QUEUE_BUFS_QUERIED,
+ QUEUE_BUFS_MMAPED,
+};
+
+/**
+ * enum s5p_mfc_check_state - The state for user notification
+ */
+enum s5p_mfc_check_state {
+ MFCSTATE_PROCESSING = 0,
+ MFCSTATE_DEC_RES_DETECT,
+ MFCSTATE_DEC_TERMINATING,
+ MFCSTATE_ENC_NO_OUTPUT,
+};
+
+/**
+ * enum s5p_mfc_buf_cacheable_mask - The mask for cacheble setting
+ */
+enum s5p_mfc_buf_cacheable_mask {
+ MFCMASK_DST_CACHE = (1 << 0),
+ MFCMASK_SRC_CACHE = (1 << 1),
+};
+
+struct s5p_mfc_ctx;
+struct s5p_mfc_extra_buf;
+
+/**
+ * struct s5p_mfc_buf - MFC buffer
+ *
+ */
+struct s5p_mfc_buf {
+ struct vb2_buffer vb;
+ struct list_head list;
+ union {
+ struct {
+ dma_addr_t luma;
+ dma_addr_t chroma;
+ } raw;
+ dma_addr_t stream;
+ } planes;
+ int used;
+};
+
+#define vb_to_mfc_buf(x) \
+ container_of(x, struct s5p_mfc_buf, vb)
+
+struct s5p_mfc_pm {
+ struct clk *clock;
+ atomic_t power;
+ struct device *device;
+ spinlock_t clklock;
+};
+
+struct s5p_mfc_fw {
+ const struct firmware *info;
+ int state;
+ int ver;
+ int date;
+};
+
+struct s5p_mfc_buf_align {
+ unsigned int mfc_base_align;
+};
+
+struct s5p_mfc_buf_size_v5 {
+ unsigned int h264_ctx_buf;
+ unsigned int non_h264_ctx_buf;
+ unsigned int desc_buf;
+ unsigned int shared_buf;
+};
+
+struct s5p_mfc_buf_size_v6 {
+ unsigned int dev_ctx;
+ unsigned int h264_dec_ctx;
+ unsigned int other_dec_ctx;
+ unsigned int h264_enc_ctx;
+ unsigned int other_enc_ctx;
+};
+
+struct s5p_mfc_buf_size {
+ unsigned int firmware_code;
+ unsigned int cpb_buf;
+ void *buf;
+};
+
+struct s5p_mfc_variant {
+ unsigned int version;
+ unsigned int port_num;
+ struct s5p_mfc_buf_size *buf_size;
+ struct s5p_mfc_buf_align *buf_align;
+};
+
+/**
+ * struct s5p_mfc_extra_buf - represents internal used buffer
+ * @alloc: allocation-specific contexts for each buffer
+ * (videobuf2 allocator)
+ * @ofs: offset of each buffer, will be used for MFC
+ * @virt: kernel virtual address, only valid when the
+ * buffer accessed by driver
+ * @dma: DMA address, only valid when kernel DMA API used
+ */
+struct s5p_mfc_extra_buf {
+ void *alloc;
+ unsigned long ofs;
+ void *virt;
+ dma_addr_t dma;
+};
+
+/**
+ * struct s5p_mfc_dev - The struct containing driver internal parameters.
+ */
+struct s5p_mfc_dev {
+ struct v4l2_device v4l2_dev;
+ struct video_device *vfd_dec;
+ struct video_device *vfd_enc;
+ struct platform_device *plat_dev;
+
+ void __iomem *regs_base;
+ int irq;
+ struct resource *mfc_mem;
+
+ struct s5p_mfc_pm pm;
+ struct s5p_mfc_fw fw;
+ struct s5p_mfc_variant *variant;
+ struct s5p_mfc_platdata *platdata;
+
+ int num_inst;
+ spinlock_t irqlock;
+ spinlock_t condlock;
+
+ struct mutex mfc_mutex;
+
+ int int_cond;
+ int int_type;
+ unsigned int int_err;
+ wait_queue_head_t queue;
+
+ size_t port_a;
+ size_t port_b;
+
+ unsigned long hw_lock;
+
+ /*
+ struct clk *clock1;
+ struct clk *clock2;
+ */
+
+ /* For 6.x, Added for SYS_INIT context buffer */
+ struct s5p_mfc_extra_buf ctx_buf;
+
+ struct s5p_mfc_ctx *ctx[MFC_NUM_CONTEXTS];
+ int curr_ctx;
+ unsigned long ctx_work_bits;
+
+ atomic_t watchdog_cnt;
+ struct timer_list watchdog_timer;
+ struct workqueue_struct *watchdog_workqueue;
+ struct work_struct watchdog_work;
+
+ struct vb2_alloc_ctx **alloc_ctx;
+
+ unsigned long clk_state;
+
+ /* for DRM */
+ int curr_ctx_drm;
+ int fw_status;
+ int num_drm_inst;
+ struct s5p_mfc_extra_buf drm_info;
+ struct vb2_alloc_ctx *alloc_ctx_fw;
+ struct vb2_alloc_ctx *alloc_ctx_sh;
+ struct vb2_alloc_ctx *alloc_ctx_drm;
+
+ struct work_struct work_struct;
+ struct workqueue_struct *irq_workqueue;
+
+ /* to prevent suspend */
+ struct wakeup_source mfc_ws;
+};
+
+/**
+ *
+ */
+struct s5p_mfc_h264_enc_params {
+ enum v4l2_mpeg_video_h264_profile profile;
+ u8 level;
+ u8 interlace;
+ enum v4l2_mpeg_video_h264_loop_filter_mode loop_filter_mode;
+ s8 loop_filter_alpha;
+ s8 loop_filter_beta;
+ enum v4l2_mpeg_video_h264_entropy_mode entropy_mode;
+ u8 num_ref_pic_4p;
+ u8 _8x8_transform;
+ u32 rc_framerate;
+ u8 rc_frame_qp;
+ u8 rc_min_qp;
+ u8 rc_max_qp;
+ u8 rc_mb_dark;
+ u8 rc_mb_smooth;
+ u8 rc_mb_static;
+ u8 rc_mb_activity;
+ u8 rc_p_frame_qp;
+ u8 rc_b_frame_qp;
+ u8 ar_vui;
+ enum v4l2_mpeg_video_h264_vui_sar_idc ar_vui_idc;
+ u16 ext_sar_width;
+ u16 ext_sar_height;
+ u8 open_gop;
+ u16 open_gop_size;
+ u8 hier_qp;
+ enum v4l2_mpeg_video_h264_hierarchical_coding_type hier_qp_type;
+ u8 hier_qp_layer;
+ u8 hier_qp_layer_qp[7];
+ u8 sei_gen_enable;
+ u8 sei_fp_curr_frame_0;
+ enum v4l2_mpeg_video_h264_sei_fp_arrangement_type \
+ sei_fp_arrangement_type;
+ u32 fmo_enable;
+ u32 fmo_slice_map_type;
+ u32 fmo_slice_num_grp;
+ u32 fmo_run_length[4];
+ u32 fmo_sg_dir;
+ u32 fmo_sg_rate;
+ u32 aso_enable;
+ u32 aso_slice_order[8];
+};
+
+/**
+ *
+ */
+struct s5p_mfc_mpeg4_enc_params {
+ /* MPEG4 Only */
+ enum v4l2_mpeg_video_mpeg4_profile profile;
+ u8 level;
+ u8 quarter_pixel; /* MFC5.x */
+ u16 vop_time_res;
+ u16 vop_frm_delta;
+ u8 rc_b_frame_qp;
+ /* Common for MPEG4, H263 */
+ u32 rc_framerate;
+ u8 rc_frame_qp;
+ u8 rc_min_qp;
+ u8 rc_max_qp;
+ u8 rc_p_frame_qp;
+};
+
+/**
+ *
+ */
+struct s5p_mfc_enc_params {
+ u16 width;
+ u16 height;
+
+ u16 gop_size;
+ enum v4l2_mpeg_video_multi_slice_mode slice_mode;
+ u16 slice_mb;
+ u32 slice_bit;
+ u16 intra_refresh_mb;
+ u8 pad;
+ u8 pad_luma;
+ u8 pad_cb;
+ u8 pad_cr;
+ u8 rc_frame;
+ u32 rc_bitrate;
+ u16 rc_reaction_coeff;
+ u8 frame_tag;
+
+ u8 num_b_frame; /* H.264/MPEG4 */
+ u8 rc_mb; /* H.264: MFCv5, MPEG4/H.263: MFCv6 */
+ u16 vbv_buf_size;
+ enum v4l2_mpeg_video_header_mode seq_hdr_mode;
+ enum v4l2_mpeg_mfc51_video_frame_skip_mode frame_skip_mode;
+ u8 fixed_target_bit;
+
+ u16 rc_frame_delta; /* MFC6.1 Only */
+
+ union {
+ struct s5p_mfc_h264_enc_params h264;
+ struct s5p_mfc_mpeg4_enc_params mpeg4;
+ } codec;
+};
+
+enum s5p_mfc_ctrl_type {
+ MFC_CTRL_TYPE_GET_SRC = 0x1,
+ MFC_CTRL_TYPE_GET_DST = 0x2,
+ MFC_CTRL_TYPE_SET = 0x4,
+};
+
+#define MFC_CTRL_TYPE_GET (MFC_CTRL_TYPE_GET_SRC | MFC_CTRL_TYPE_GET_DST)
+#define MFC_CTRL_TYPE_SRC (MFC_CTRL_TYPE_SET | MFC_CTRL_TYPE_GET_SRC)
+#define MFC_CTRL_TYPE_DST (MFC_CTRL_TYPE_GET_DST)
+
+enum s5p_mfc_ctrl_mode {
+ MFC_CTRL_MODE_NONE = 0x0,
+ MFC_CTRL_MODE_SFR = 0x1,
+ MFC_CTRL_MODE_SHM = 0x2,
+ MFC_CTRL_MODE_CST = 0x4,
+};
+
+struct s5p_mfc_ctrl_cfg {
+ enum s5p_mfc_ctrl_type type;
+ unsigned int id;
+ unsigned int is_volatile; /* only for MFC_CTRL_TYPE_SET */
+ unsigned int mode;
+ unsigned int addr;
+ unsigned int mask;
+ unsigned int shft;
+ unsigned int flag_mode; /* only for MFC_CTRL_TYPE_SET */
+ unsigned int flag_addr; /* only for MFC_CTRL_TYPE_SET */
+ unsigned int flag_shft; /* only for MFC_CTRL_TYPE_SET */
+};
+
+struct s5p_mfc_ctx_ctrl {
+ struct list_head list;
+ enum s5p_mfc_ctrl_type type;
+ unsigned int id;
+ unsigned int addr;
+ int has_new;
+ int val;
+};
+
+struct s5p_mfc_buf_ctrl {
+ struct list_head list;
+ unsigned int id;
+ enum s5p_mfc_ctrl_type type;
+ int has_new;
+ int val;
+ unsigned int old_val; /* only for MFC_CTRL_TYPE_SET */
+ unsigned int is_volatile; /* only for MFC_CTRL_TYPE_SET */
+ unsigned int updated;
+ unsigned int mode;
+ unsigned int addr;
+ unsigned int mask;
+ unsigned int shft;
+ unsigned int flag_mode; /* only for MFC_CTRL_TYPE_SET */
+ unsigned int flag_addr; /* only for MFC_CTRL_TYPE_SET */
+ unsigned int flag_shft; /* only for MFC_CTRL_TYPE_SET */
+};
+
+struct s5p_mfc_codec_ops {
+ /* initialization routines */
+ int (*alloc_ctx_buf) (struct s5p_mfc_ctx *ctx);
+ int (*alloc_desc_buf) (struct s5p_mfc_ctx *ctx);
+ int (*get_init_arg) (struct s5p_mfc_ctx *ctx, void *arg);
+ int (*pre_seq_start) (struct s5p_mfc_ctx *ctx);
+ int (*post_seq_start) (struct s5p_mfc_ctx *ctx);
+ int (*set_init_arg) (struct s5p_mfc_ctx *ctx, void *arg);
+ int (*set_codec_bufs) (struct s5p_mfc_ctx *ctx);
+ int (*set_dpbs) (struct s5p_mfc_ctx *ctx); /* decoder */
+ /* execution routines */
+ int (*get_exe_arg) (struct s5p_mfc_ctx *ctx, void *arg);
+ int (*pre_frame_start) (struct s5p_mfc_ctx *ctx);
+ int (*post_frame_start) (struct s5p_mfc_ctx *ctx);
+ int (*multi_data_frame) (struct s5p_mfc_ctx *ctx);
+ int (*set_exe_arg) (struct s5p_mfc_ctx *ctx, void *arg);
+ /* configuration routines */
+ int (*get_codec_cfg) (struct s5p_mfc_ctx *ctx, unsigned int type,
+ int *value);
+ int (*set_codec_cfg) (struct s5p_mfc_ctx *ctx, unsigned int type,
+ int *value);
+ /* controls per buffer */
+ int (*init_ctx_ctrls) (struct s5p_mfc_ctx *ctx);
+ int (*cleanup_ctx_ctrls) (struct s5p_mfc_ctx *ctx);
+ int (*init_buf_ctrls) (struct s5p_mfc_ctx *ctx,
+ enum s5p_mfc_ctrl_type type, unsigned int index);
+ int (*cleanup_buf_ctrls) (struct s5p_mfc_ctx *ctx,
+ enum s5p_mfc_ctrl_type type, unsigned int index);
+ int (*to_buf_ctrls) (struct s5p_mfc_ctx *ctx, struct list_head *head);
+ int (*to_ctx_ctrls) (struct s5p_mfc_ctx *ctx, struct list_head *head);
+ int (*set_buf_ctrls_val) (struct s5p_mfc_ctx *ctx,
+ struct list_head *head);
+ int (*get_buf_ctrls_val) (struct s5p_mfc_ctx *ctx,
+ struct list_head *head);
+ int (*recover_buf_ctrls_val) (struct s5p_mfc_ctx *ctx,
+ struct list_head *head);
+ int (*get_buf_update_val) (struct s5p_mfc_ctx *ctx,
+ struct list_head *head, unsigned int id, int value);
+};
+
+#define call_cop(c, op, args...) \
+ (((c)->c_ops->op) ? \
+ ((c)->c_ops->op(args)) : 0)
+
+struct s5p_mfc_dec {
+ int total_dpb_count;
+
+ struct list_head dpb_queue;
+ unsigned int dpb_queue_cnt;
+
+ size_t src_buf_size;
+
+ int loop_filter_mpeg4;
+ int display_delay;
+ int is_packedpb;
+ int slice_enable;
+ int mv_count;
+
+ int crc_enable;
+ int crc_luma0;
+ int crc_chroma0;
+ int crc_luma1;
+ int crc_chroma1;
+
+ struct s5p_mfc_extra_buf dsc;
+ unsigned long consumed;
+ unsigned long dpb_status;
+ unsigned int dpb_flush;
+
+ enum v4l2_memory dst_memtype;
+ int sei_parse;
+ int eos_tag;
+
+ /* For 6.x */
+ int remained;
+};
+
+struct s5p_mfc_enc {
+ struct s5p_mfc_enc_params params;
+
+ size_t dst_buf_size;
+
+ int frame_count;
+ enum v4l2_mpeg_mfc51_video_frame_type frame_type;
+ enum v4l2_mpeg_mfc51_video_force_frame_type force_frame_type;
+
+ struct list_head ref_queue;
+ unsigned int ref_queue_cnt;
+
+ /* For 6.x */
+ size_t luma_dpb_size;
+ size_t chroma_dpb_size;
+ size_t me_buffer_size;
+ size_t tmv_buffer_size;
+
+ unsigned int slice_mode;
+ union {
+ unsigned int mb;
+ unsigned int bits;
+ } slice_size;
+};
+
+/**
+ * struct s5p_mfc_ctx - This struct contains the instance context
+ */
+struct s5p_mfc_ctx {
+ struct s5p_mfc_dev *dev;
+ struct v4l2_fh fh;
+ int num;
+
+ int int_cond;
+ int int_type;
+ unsigned int int_err;
+ wait_queue_head_t queue;
+
+ struct s5p_mfc_fmt *src_fmt;
+ struct s5p_mfc_fmt *dst_fmt;
+
+ struct vb2_queue vq_src;
+ struct vb2_queue vq_dst;
+
+ struct list_head src_queue;
+ struct list_head dst_queue;
+
+ unsigned int src_queue_cnt;
+ unsigned int dst_queue_cnt;
+
+ enum s5p_mfc_inst_type type;
+ enum s5p_mfc_inst_state state;
+ int inst_no;
+
+ int img_width;
+ int img_height;
+ int buf_width;
+ int buf_height;
+ int dpb_count;
+
+ int luma_size;
+ int chroma_size;
+ int mv_size;
+
+ /* Buffers */
+ void *port_a_buf;
+ size_t port_a_phys;
+ size_t port_a_size;
+
+ void *port_b_buf;
+ size_t port_b_phys;
+ size_t port_b_size;
+
+ enum s5p_mfc_queue_state capture_state;
+ enum s5p_mfc_queue_state output_state;
+
+ struct list_head ctrls;
+
+ struct list_head src_ctrls[MFC_MAX_BUFFERS];
+ struct list_head dst_ctrls[MFC_MAX_BUFFERS];
+
+ unsigned long src_ctrls_avail;
+ unsigned long dst_ctrls_avail;
+
+ unsigned int sequence;
+
+ /* Control values */
+ int codec_mode;
+ __u32 pix_format;
+ int cacheable;
+
+ /* Extra Buffers */
+ unsigned int ctx_buf_size;
+ struct s5p_mfc_extra_buf ctx;
+ struct s5p_mfc_extra_buf shm;
+
+ struct s5p_mfc_dec *dec_priv;
+ struct s5p_mfc_enc *enc_priv;
+
+ struct s5p_mfc_codec_ops *c_ops;
+
+ /* For 6.x */
+ size_t scratch_buf_size;
+
+ /* for DRM */
+ int is_drm;
+
+ /* for PPMU monitoring */
+ struct exynos5_bus_int_handle *mfc_int_handle_poll;
+};
+
+#define fh_to_mfc_ctx(x) \
+ container_of(x, struct s5p_mfc_ctx, fh)
+
+#define MFC_FMT_DEC 0
+#define MFC_FMT_ENC 1
+#define MFC_FMT_RAW 2
+
+#define HAS_PORTNUM(dev) (dev ? (dev->variant ? \
+ (dev->variant->port_num ? 1 : 0) : 0) : 0)
+#define IS_TWOPORT(dev) (dev->variant->port_num == 2 ? 1 : 0)
+#define IS_MFCV6(dev) (dev->variant->version >= 0x60 ? 1 : 0)
+
+struct s5p_mfc_fmt {
+ char *name;
+ u32 fourcc;
+ u32 codec_mode;
+ u32 type;
+ u32 num_planes;
+};
+
+#if defined(CONFIG_EXYNOS_MFC_V5)
+#include "regs-mfc-v5.h"
+#include "s5p_mfc_opr_v5.h"
+#include "s5p_mfc_shm.h"
+#elif defined(CONFIG_EXYNOS_MFC_V6)
+#include "regs-mfc-v6.h"
+#include "s5p_mfc_opr_v6.h"
+#endif
+
+#endif /* S5P_MFC_COMMON_H_ */
diff --git a/drivers/media/video/exynos/mfc/s5p_mfc_ctrl.c b/drivers/media/video/exynos/mfc/s5p_mfc_ctrl.c
new file mode 100644
index 0000000..fb61d6f
--- /dev/null
+++ b/drivers/media/video/exynos/mfc/s5p_mfc_ctrl.c
@@ -0,0 +1,552 @@
+/*
+ * linux/drivers/media/video/exynos/mfc/s5p_mfc_ctrl.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * 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.
+ */
+
+#include <linux/delay.h>
+#include <linux/jiffies.h>
+
+#include <linux/firmware.h>
+#include <linux/err.h>
+#include <linux/sched.h>
+#include <linux/cma.h>
+
+#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
+#include <plat/iovmm.h>
+#endif
+
+#include "s5p_mfc_common.h"
+
+#include "s5p_mfc_mem.h"
+#include "s5p_mfc_intr.h"
+#include "s5p_mfc_debug.h"
+#include "s5p_mfc_reg.h"
+#include "s5p_mfc_cmd.h"
+#include "s5p_mfc_pm.h"
+
+static void *s5p_mfc_bitproc_buf;
+static dma_addr_t s5p_mfc_bitproc_phys;
+static unsigned char *s5p_mfc_bitproc_virt;
+
+/* Allocate firmware */
+int s5p_mfc_alloc_firmware(struct s5p_mfc_dev *dev)
+{
+#if defined(CONFIG_VIDEOBUF2_CMA_PHYS)
+ int err;
+ struct cma_info mem_info_f, mem_info_a, mem_info_b;
+#endif
+ unsigned int base_align = dev->variant->buf_align->mfc_base_align;
+ unsigned int firmware_size = dev->variant->buf_size->firmware_code;
+ void *alloc_ctx = dev->alloc_ctx[MFC_CMA_FW_ALLOC_CTX];
+
+ mfc_debug_enter();
+
+#if !defined(CONFIG_VIDEOBUF2_ION)
+ if (s5p_mfc_bitproc_buf) {
+ mfc_err("Attempting to allocate firmware when it seems that it is already loaded.\n");
+ return -ENOMEM;
+ }
+#else
+ if (s5p_mfc_bitproc_buf)
+ return 0;
+#endif
+
+ /* Get memory region information and check if it is correct */
+#if defined(CONFIG_VIDEOBUF2_CMA_PHYS)
+ err = cma_info(&mem_info_f, dev->v4l2_dev.dev, MFC_CMA_FW);
+ mfc_debug(3, "Area \"%s\" is from %08x to %08x and has size %08x", "f",
+ mem_info_f.lower_bound, mem_info_f.upper_bound,
+ mem_info_f.total_size);
+ if (err) {
+ mfc_err("Couldn't get memory information from CMA.\n");
+ return -EINVAL;
+ }
+ err = cma_info(&mem_info_a, dev->v4l2_dev.dev, MFC_CMA_BANK1);
+ mfc_debug(3, "Area \"%s\" is from %08x to %08x and has size %08x", "a",
+ mem_info_a.lower_bound, mem_info_a.upper_bound,
+ mem_info_a.total_size);
+ if (err) {
+ mfc_err("Couldn't get memory information from CMA.\n");
+ return -EINVAL;
+ }
+
+ if (mem_info_f.upper_bound > mem_info_a.lower_bound) {
+ mfc_err("Firmware has to be "
+ "allocated before memory for buffers (bank A).\n");
+ return -EINVAL;
+ }
+#endif
+ mfc_debug(2, "Allocating memory for firmware.\n");
+
+#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
+ alloc_ctx = dev->alloc_ctx_fw;
+#endif
+
+ s5p_mfc_bitproc_buf = s5p_mfc_mem_alloc(alloc_ctx, firmware_size);
+ if (IS_ERR(s5p_mfc_bitproc_buf)) {
+ s5p_mfc_bitproc_buf = 0;
+ printk(KERN_ERR "Allocating bitprocessor buffer failed\n");
+ return -ENOMEM;
+ }
+
+ s5p_mfc_bitproc_phys = s5p_mfc_mem_daddr(s5p_mfc_bitproc_buf);
+ if (s5p_mfc_bitproc_phys & ((1 << base_align) - 1)) {
+ mfc_err("The base memory is not aligned to %dBytes.\n",
+ (1 << base_align));
+ s5p_mfc_mem_free(s5p_mfc_bitproc_buf);
+ s5p_mfc_bitproc_phys = 0;
+ s5p_mfc_bitproc_buf = 0;
+ return -EIO;
+ }
+
+#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
+ iovmm_map_oto(&dev->plat_dev->dev, s5p_mfc_bitproc_phys,
+ firmware_size);
+#endif
+ if (!dev->num_drm_inst) {
+ s5p_mfc_bitproc_virt = s5p_mfc_mem_vaddr(s5p_mfc_bitproc_buf);
+ mfc_debug(2, "Virtual address for FW: %08lx\n",
+ (long unsigned int)s5p_mfc_bitproc_virt);
+ if (!s5p_mfc_bitproc_virt) {
+ mfc_err("Bitprocessor memory remap failed\n");
+ s5p_mfc_mem_free(s5p_mfc_bitproc_buf);
+ s5p_mfc_bitproc_phys = 0;
+ s5p_mfc_bitproc_buf = 0;
+ return -EIO;
+ }
+ }
+
+ dev->port_a = s5p_mfc_bitproc_phys;
+
+ s5p_mfc_bitproc_virt = s5p_mfc_mem_vaddr(s5p_mfc_bitproc_buf);
+ mfc_debug(2, "Virtual address for FW: %08lx\n",
+ (long unsigned int)s5p_mfc_bitproc_virt);
+ if (!s5p_mfc_bitproc_virt) {
+ mfc_err("Bitprocessor memory remap failed\n");
+ s5p_mfc_mem_free(s5p_mfc_bitproc_buf);
+ s5p_mfc_bitproc_phys = 0;
+ s5p_mfc_bitproc_buf = 0;
+ return -EIO;
+ }
+
+#if defined(CONFIG_VIDEOBUF2_CMA_PHYS)
+ if (HAS_PORTNUM(dev) && IS_TWOPORT(dev)) {
+ err = cma_info(&mem_info_b, dev->v4l2_dev.dev, MFC_CMA_BANK2);
+ mfc_debug(3, "Area \"%s\" is from %08x to %08x and has size %08x", "b",
+ mem_info_b.lower_bound, mem_info_b.upper_bound,
+ mem_info_b.total_size);
+ if (err) {
+ mfc_err("Couldn't get memory information from CMA.\n");
+ return -EINVAL;
+ }
+ dev->port_b = mem_info_b.lower_bound;
+ mfc_debug(2, "Port A: %08x Port B: %08x (FW: %08x size: %08x)\n",
+ dev->port_a, dev->port_b, s5p_mfc_bitproc_phys,
+ firmware_size);
+ } else {
+ mfc_debug(2, "Port : %08x (FW: %08x size: %08x)\n",
+ dev->port_a, s5p_mfc_bitproc_phys,
+ firmware_size);
+ }
+#elif defined(CONFIG_VIDEOBUF2_ION)
+ dev->port_b = s5p_mfc_bitproc_phys;
+
+ mfc_debug(2, "Port A: %08x Port B: %08x (FW: %08x size: %08x)\n",
+ dev->port_a, dev->port_b,
+ s5p_mfc_bitproc_phys,
+ firmware_size);
+#endif
+ mfc_debug_leave();
+
+ return 0;
+}
+
+/* Load firmware to MFC */
+int s5p_mfc_load_firmware(struct s5p_mfc_dev *dev)
+{
+ struct firmware *fw_blob;
+ unsigned int firmware_size = dev->variant->buf_size->firmware_code;
+ int err;
+
+ /* Firmare has to be present as a separate file or compiled
+ * into kernel. */
+ mfc_debug_enter();
+ mfc_debug(2, "Requesting fw\n");
+ err = request_firmware((const struct firmware **)&fw_blob,
+ MFC_FW_NAME, dev->v4l2_dev.dev);
+
+ if (err != 0) {
+ mfc_err("Firmware is not present in the /lib/firmware directory nor compiled in kernel.\n");
+ return -EINVAL;
+ }
+
+ mfc_debug(2, "Ret of request_firmware: %d Size: %d\n", err, fw_blob->size);
+
+ if (fw_blob->size > firmware_size) {
+ mfc_err("MFC firmware is too big to be loaded.\n");
+ release_firmware(fw_blob);
+ return -ENOMEM;
+ }
+ if (s5p_mfc_bitproc_buf == 0 || s5p_mfc_bitproc_phys == 0) {
+ mfc_err("MFC firmware is not allocated or was not mapped correctly.\n");
+ release_firmware(fw_blob);
+ return -EINVAL;
+ }
+ memcpy(s5p_mfc_bitproc_virt, fw_blob->data, fw_blob->size);
+ /*
+ s5p_mfc_bitproc_dma = dma_map_single(dev->v4l2_dev.dev,
+ s5p_mfc_bitproc_virt,
+ FIRMWARE_CODE_SIZE,
+ DMA_TO_DEVICE);
+ */
+ s5p_mfc_cache_clean_priv(s5p_mfc_bitproc_buf);
+ release_firmware(fw_blob);
+ mfc_debug_leave();
+ return 0;
+}
+
+/* Release firmware memory */
+int s5p_mfc_release_firmware(struct s5p_mfc_dev *dev)
+{
+ /* Before calling this function one has to make sure
+ * that MFC is no longer processing */
+ if (!s5p_mfc_bitproc_buf)
+ return -EINVAL;
+ /*
+ if (s5p_mfc_bitproc_dma)
+ dma_unmap_single(dev->v4l2_dev.dev, s5p_mfc_bitproc_dma,
+ FIRMWARE_CODE_SIZE, DMA_TO_DEVICE);
+ */
+#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
+ iovmm_unmap_oto(&dev->plat_dev->dev, s5p_mfc_bitproc_phys);
+#endif
+ s5p_mfc_mem_free(s5p_mfc_bitproc_buf);
+
+ s5p_mfc_bitproc_virt = 0;
+ s5p_mfc_bitproc_phys = 0;
+ s5p_mfc_bitproc_buf = 0;
+ /*
+ s5p_mfc_bitproc_dma = 0;
+ */
+ return 0;
+}
+
+/* Reset the device */
+static int s5p_mfc_reset(struct s5p_mfc_dev *dev)
+{
+ int i;
+ unsigned int status;
+ unsigned long timeout;
+
+ mfc_debug_enter();
+
+ /* Stop procedure */
+ /* Reset VI */
+ /*
+ s5p_mfc_write_reg(0x3f7, S5P_FIMV_SW_RESET);
+ */
+
+ if (IS_MFCV6(dev)) {
+ /* Reset IP */
+ s5p_mfc_write_reg(0xFEE, S5P_FIMV_MFC_RESET); /* except RISC, reset */
+ s5p_mfc_write_reg(0x0, S5P_FIMV_MFC_RESET); /* reset release */
+
+ /* Zero Initialization of MFC registers */
+ s5p_mfc_write_reg(0, S5P_FIMV_RISC2HOST_CMD);
+ s5p_mfc_write_reg(0, S5P_FIMV_HOST2RISC_CMD);
+ s5p_mfc_write_reg(0, S5P_FIMV_FW_VERSION);
+
+ for (i = 0; i < S5P_FIMV_REG_CLEAR_COUNT; i++)
+ s5p_mfc_write_reg(0, S5P_FIMV_REG_CLEAR_BEGIN + (i*4));
+
+ /* Reset */
+ s5p_mfc_write_reg(0x1, S5P_FIMV_MFC_BUS_RESET_CTRL);
+
+ timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT);
+ /* Check bus status */
+ do {
+ if (time_after(jiffies, timeout)) {
+ mfc_err("Timeout while resetting MFC.\n");
+ return -EIO;
+ }
+ status = s5p_mfc_read_reg(S5P_FIMV_MFC_BUS_RESET_CTRL);
+ } while ((status & 0x2) == 0);
+ s5p_mfc_write_reg(0, S5P_FIMV_RISC_ON);
+ s5p_mfc_write_reg(0x1FFF, S5P_FIMV_MFC_RESET);
+ s5p_mfc_write_reg(0, S5P_FIMV_MFC_RESET);
+ } else {
+ s5p_mfc_write_reg(0x3f6, S5P_FIMV_SW_RESET); /* reset RISC */
+ s5p_mfc_write_reg(0x3e2, S5P_FIMV_SW_RESET); /* All reset except for MC */
+ mdelay(10);
+
+ timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT);
+
+ /* Check MC status */
+ do {
+ if (time_after(jiffies, timeout)) {
+ mfc_err("Timeout while resetting MFC.\n");
+ return -EIO;
+ }
+
+ status = s5p_mfc_read_reg(S5P_FIMV_MC_STATUS);
+
+ } while (status & 0x3);
+
+ s5p_mfc_write_reg(0x0, S5P_FIMV_SW_RESET);
+ s5p_mfc_write_reg(0x3fe, S5P_FIMV_SW_RESET);
+ }
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+static inline void s5p_mfc_init_memctrl(struct s5p_mfc_dev *dev)
+{
+ if (IS_MFCV6(dev)) {
+ s5p_mfc_write_reg(dev->port_a, S5P_FIMV_RISC_BASE_ADDRESS);
+ mfc_debug(2, "Base Address : %08x\n", dev->port_a);
+ } else {
+ /* channelA, port0 */
+ s5p_mfc_write_reg(dev->port_a, S5P_FIMV_MC_DRAMBASE_ADR_A);
+ /* channelB, port1 */
+ s5p_mfc_write_reg(dev->port_b, S5P_FIMV_MC_DRAMBASE_ADR_B);
+
+ mfc_debug(2, "Port A: %08x, Port B: %08x\n", dev->port_a, dev->port_b);
+ }
+}
+
+static inline void s5p_mfc_clear_cmds(struct s5p_mfc_dev *dev)
+{
+ if (IS_MFCV6(dev)) {
+ /* Zero initialization should be done before RESET.
+ * Nothing to do here. */
+ } else {
+ s5p_mfc_write_reg(0xffffffff, S5P_FIMV_SI_CH0_INST_ID);
+ s5p_mfc_write_reg(0xffffffff, S5P_FIMV_SI_CH1_INST_ID);
+
+ s5p_mfc_write_reg(0, S5P_FIMV_RISC2HOST_CMD);
+ s5p_mfc_write_reg(0, S5P_FIMV_HOST2RISC_CMD);
+ }
+}
+
+/* Initialize hardware */
+int s5p_mfc_init_hw(struct s5p_mfc_dev *dev)
+{
+ char fimv_info;
+ int mfc_info;
+ int ret = 0;
+
+ mfc_debug_enter();
+
+ /* RMVME: */
+ if (!s5p_mfc_bitproc_buf)
+ return -EINVAL;
+
+ /* 0. MFC reset */
+ mfc_debug(2, "MFC reset...\n");
+
+ s5p_mfc_clock_on();
+
+ ret = s5p_mfc_reset(dev);
+ if (ret) {
+ mfc_err("Failed to reset MFC - timeout.\n");
+ goto err_init_hw;
+ }
+ mfc_debug(2, "Done MFC reset...\n");
+
+ /* 1. Set DRAM base Addr */
+ s5p_mfc_init_memctrl(dev);
+
+ /* 2. Initialize registers of channel I/F */
+ s5p_mfc_clear_cmds(dev);
+ s5p_mfc_clean_dev_int_flags(dev);
+
+ /* 3. Release reset signal to the RISC */
+ if (IS_MFCV6(dev))
+ s5p_mfc_write_reg(0x1, S5P_FIMV_RISC_ON);
+ else
+ s5p_mfc_write_reg(0x3ff, S5P_FIMV_SW_RESET);
+
+ mfc_debug(2, "Will now wait for completion of firmware transfer.\n");
+ if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_FW_STATUS_RET)) {
+ mfc_err("Failed to load firmware.\n");
+ s5p_mfc_clean_dev_int_flags(dev);
+ ret = -EIO;
+ goto err_init_hw;
+ }
+
+ s5p_mfc_clean_dev_int_flags(dev);
+ /* 4. Initialize firmware */
+ ret = s5p_mfc_sys_init_cmd(dev);
+ if (ret) {
+ mfc_err("Failed to send command to MFC - timeout.\n");
+ goto err_init_hw;
+ }
+ mfc_debug(2, "Ok, now will write a command to init the system\n");
+ if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_SYS_INIT_RET)) {
+ mfc_err("Failed to load firmware\n");
+ ret = -EIO;
+ goto err_init_hw;
+ }
+
+ dev->int_cond = 0;
+ if (dev->int_err != 0 || dev->int_type !=
+ S5P_FIMV_R2H_CMD_SYS_INIT_RET) {
+ /* Failure. */
+ mfc_err("Failed to init firmware - error: %d"
+ " int: %d.\n", dev->int_err, dev->int_type);
+ ret = -EIO;
+ goto err_init_hw;
+ }
+
+ fimv_info = MFC_GET_REG(SYS_FW_FIMV_INFO);
+ if (fimv_info != 'D' && fimv_info != 'E')
+ fimv_info = 'N';
+
+ mfc_info("MFC v%x.%x, F/W : (%c) %02xyy, %02xmm, %02xdd\n",
+ MFC_VER_MAJOR(dev->fw.ver),
+ MFC_VER_MINOR(dev->fw.ver),
+ fimv_info,
+ MFC_GET_REG(SYS_FW_VER_YEAR),
+ MFC_GET_REG(SYS_FW_VER_MONTH),
+ MFC_GET_REG(SYS_FW_VER_DATE));
+
+ dev->fw.date = MFC_GET_REG(SYS_FW_VER_ALL);
+ /* Check MFC version and F/W version */
+ if (dev->fw.date >= 0x120328) {
+ mfc_info = MFC_GET_REG(SYS_MFC_VER);
+ if (mfc_info != dev->fw.ver) {
+ mfc_err("Invalid F/W version(0x%x) for MFC H/W(0x%x)\n",
+ mfc_info, dev->fw.ver);
+ ret = -EIO;
+ goto err_init_hw;
+ }
+ }
+
+err_init_hw:
+ s5p_mfc_clock_off();
+ mfc_debug_leave();
+
+ return ret;
+}
+
+
+/* Deinitialize hardware */
+void s5p_mfc_deinit_hw(struct s5p_mfc_dev *dev)
+{
+ s5p_mfc_clock_on();
+
+ s5p_mfc_reset(dev);
+ if (IS_MFCV6(dev))
+ s5p_mfc_release_dev_context_buffer(dev);
+
+ s5p_mfc_clock_off();
+}
+
+int s5p_mfc_sleep(struct s5p_mfc_dev *dev)
+{
+ int ret;
+
+ mfc_debug_enter();
+
+ s5p_mfc_clock_on();
+
+ s5p_mfc_clean_dev_int_flags(dev);
+ ret = s5p_mfc_sleep_cmd(dev);
+ if (ret) {
+ mfc_err("Failed to send command to MFC - timeout.\n");
+ goto err_mfc_sleep;
+ }
+ if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_SLEEP_RET)) {
+ mfc_err("Failed to sleep\n");
+ ret = -EIO;
+ goto err_mfc_sleep;
+ }
+
+ dev->int_cond = 0;
+ if (dev->int_err != 0 || dev->int_type !=
+ S5P_FIMV_R2H_CMD_SLEEP_RET) {
+ /* Failure. */
+ mfc_err("Failed to sleep - error: %d"
+ " int: %d.\n", dev->int_err, dev->int_type);
+ ret = -EIO;
+ goto err_mfc_sleep;
+ }
+
+err_mfc_sleep:
+ s5p_mfc_clock_off();
+ mfc_debug_leave();
+
+ return ret;
+}
+
+int s5p_mfc_wakeup(struct s5p_mfc_dev *dev)
+{
+ int ret;
+
+ mfc_debug_enter();
+
+ /* 0. MFC reset */
+ mfc_debug(2, "MFC reset...\n");
+
+ s5p_mfc_clock_on();
+
+ ret = s5p_mfc_reset(dev);
+ if (ret) {
+ mfc_err("Failed to reset MFC - timeout.\n");
+ goto err_mfc_wakeup;
+ }
+ mfc_debug(2, "Done MFC reset...\n");
+
+ /* 1. Set DRAM base Addr */
+ s5p_mfc_init_memctrl(dev);
+
+ /* 2. Initialize registers of channel I/F */
+ s5p_mfc_clear_cmds(dev);
+
+ s5p_mfc_clean_dev_int_flags(dev);
+ /* 3. Initialize firmware */
+ ret = s5p_mfc_wakeup_cmd(dev);
+ if (ret) {
+ mfc_err("Failed to send command to MFC - timeout.\n");
+ goto err_mfc_wakeup;
+ }
+
+ /* 4. Release reset signal to the RISC */
+ if (IS_MFCV6(dev))
+ s5p_mfc_write_reg(0x1, S5P_FIMV_RISC_ON);
+ else
+ s5p_mfc_write_reg(0x3ff, S5P_FIMV_SW_RESET);
+
+ mfc_debug(2, "Ok, now will write a command to wakeup the system\n");
+ if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_WAKEUP_RET)) {
+ mfc_err("Failed to load firmware\n");
+ ret = -EIO;
+ goto err_mfc_wakeup;
+ }
+
+ dev->int_cond = 0;
+ if (dev->int_err != 0 || dev->int_type !=
+ S5P_FIMV_R2H_CMD_WAKEUP_RET) {
+ /* Failure. */
+ mfc_err("Failed to wakeup - error: %d"
+ " int: %d.\n", dev->int_err, dev->int_type);
+ ret = -EIO;
+ goto err_mfc_wakeup;
+ }
+
+err_mfc_wakeup:
+ s5p_mfc_clock_off();
+ mfc_debug_leave();
+
+ return 0;
+}
+
diff --git a/drivers/media/video/exynos/mfc/s5p_mfc_ctrl.h b/drivers/media/video/exynos/mfc/s5p_mfc_ctrl.h
new file mode 100644
index 0000000..b780f15
--- /dev/null
+++ b/drivers/media/video/exynos/mfc/s5p_mfc_ctrl.h
@@ -0,0 +1,26 @@
+/*
+ * linux/drivers/media/video/exynos/mfc/s5p_mfc_ctrl.h
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * 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.
+ */
+
+#ifndef __S5P_MFC_CTRL_H
+#define __S5P_MFC_CTRL_H __FILE__
+
+int s5p_mfc_release_firmware(struct s5p_mfc_dev *dev);
+int s5p_mfc_alloc_firmware(struct s5p_mfc_dev *dev);
+int s5p_mfc_load_firmware(struct s5p_mfc_dev *dev);
+
+int s5p_mfc_init_hw(struct s5p_mfc_dev *dev);
+void s5p_mfc_deinit_hw(struct s5p_mfc_dev *dev);
+
+int s5p_mfc_sleep(struct s5p_mfc_dev *dev);
+int s5p_mfc_wakeup(struct s5p_mfc_dev *dev);
+
+#endif /* __S5P_MFC_CTRL_H */
diff --git a/drivers/media/video/exynos/mfc/s5p_mfc_debug.h b/drivers/media/video/exynos/mfc/s5p_mfc_debug.h
new file mode 100644
index 0000000..990a3784
--- /dev/null
+++ b/drivers/media/video/exynos/mfc/s5p_mfc_debug.h
@@ -0,0 +1,47 @@
+/*
+ * drivers/media/video/exynos/mfc/s5p_mfc_debug.h
+ *
+ * Header file for Samsung MFC (Multi Function Codec - FIMV) driver
+ * This file contains debug macros
+ *
+ * Kamil Debski, Copyright (c) 2010 Samsung Electronics
+ * http://www.samsung.com/
+ *
+ * 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.
+ */
+
+#ifndef S5P_MFC_DEBUG_H_
+#define S5P_MFC_DEBUG_H_
+
+#define DEBUG
+
+#ifdef DEBUG
+extern int debug;
+
+#define mfc_debug(level, fmt, args...) \
+ do { \
+ if (debug >= level) \
+ printk(KERN_DEBUG "%s:%d: " fmt, \
+ __func__, __LINE__, ##args); \
+ } while (0)
+#else
+#define mfc_debug(fmt, args...)
+#endif
+
+#define mfc_debug_enter() mfc_debug(5, "enter")
+#define mfc_debug_leave() mfc_debug(5, "leave")
+
+#define mfc_err(fmt, args...) \
+ do { \
+ printk(KERN_ERR "%s:%d: " fmt, \
+ __func__, __LINE__, ##args); \
+ } while (0)
+
+#define mfc_info(fmt, args...) \
+ do { \
+ printk(KERN_INFO fmt, ##args); \
+ } while (0)
+
+#endif /* S5P_MFC_DEBUG_H_ */
diff --git a/drivers/media/video/exynos/mfc/s5p_mfc_dec.c b/drivers/media/video/exynos/mfc/s5p_mfc_dec.c
new file mode 100644
index 0000000..0fea05d
--- /dev/null
+++ b/drivers/media/video/exynos/mfc/s5p_mfc_dec.c
@@ -0,0 +1,2367 @@
+/*
+ * linux/drivers/media/video/exynos/mfc/s5p_mfc_dec.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ * Kamil Debski, <k.debski@samsung.com>
+ *
+ * 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.
+ */
+
+#include <linux/io.h>
+#include <linux/sched.h>
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/version.h>
+#include <linux/workqueue.h>
+#include <linux/videodev2.h>
+#include <linux/videodev2_exynos_media.h>
+#include <media/videobuf2-core.h>
+
+#include "s5p_mfc_common.h"
+
+#include "s5p_mfc_intr.h"
+#include "s5p_mfc_mem.h"
+#include "s5p_mfc_debug.h"
+#include "s5p_mfc_reg.h"
+#include "s5p_mfc_dec.h"
+#include "s5p_mfc_pm.h"
+
+#define DEF_SRC_FMT 2
+#define DEF_DST_FMT 0
+
+static struct s5p_mfc_fmt formats[] = {
+ {
+ .name = "4:2:0 2 Planes 16x16 Tiles",
+ .fourcc = V4L2_PIX_FMT_NV12MT_16X16,
+ .codec_mode = MFC_FORMATS_NO_CODEC,
+ .type = MFC_FMT_RAW,
+ .num_planes = 2,
+ },
+ {
+ .name = "4:2:0 2 Planes 64x32 Tiles",
+ .fourcc = V4L2_PIX_FMT_NV12MT,
+ .codec_mode = MFC_FORMATS_NO_CODEC,
+ .type = MFC_FMT_RAW,
+ .num_planes = 2,
+ },
+ {
+ .name = "4:2:0 2 Planes Y/CbCr",
+ .fourcc = V4L2_PIX_FMT_NV12M,
+ .codec_mode = MFC_FORMATS_NO_CODEC,
+ .type = MFC_FMT_RAW,
+ .num_planes = 2,
+ },
+ {
+ .name = "4:2:0 2 Planes Y/CrCb",
+ .fourcc = V4L2_PIX_FMT_NV21M,
+ .codec_mode = MFC_FORMATS_NO_CODEC,
+ .type = MFC_FMT_RAW,
+ .num_planes = 2,
+ },
+ {
+ .name = "H264 Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_H264,
+ .codec_mode = S5P_FIMV_CODEC_H264_DEC,
+ .type = MFC_FMT_DEC,
+ .num_planes = 1,
+ },
+ /* MFC 6.x only */
+ {
+ .name = "H264/MVC Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_H264_MVC,
+ .codec_mode = S5P_FIMV_CODEC_H264_MVC_DEC,
+ .type = MFC_FMT_DEC,
+ .num_planes = 1,
+ },
+ {
+ .name = "H263 Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_H263,
+ .codec_mode = S5P_FIMV_CODEC_H263_DEC,
+ .type = MFC_FMT_DEC,
+ .num_planes = 1,
+ },
+ {
+ .name = "MPEG1 Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_MPEG1,
+ .codec_mode = S5P_FIMV_CODEC_MPEG2_DEC,
+ .type = MFC_FMT_DEC,
+ .num_planes = 1,
+ },
+ {
+ .name = "MPEG2 Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_MPEG2,
+ .codec_mode = S5P_FIMV_CODEC_MPEG2_DEC,
+ .type = MFC_FMT_DEC,
+ .num_planes = 1,
+ },
+ {
+ .name = "MPEG4 Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_MPEG4,
+ .codec_mode = S5P_FIMV_CODEC_MPEG4_DEC,
+ .type = MFC_FMT_DEC,
+ .num_planes = 1,
+ },
+ {
+ .name = "FIMV Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_FIMV,
+ .codec_mode = S5P_FIMV_CODEC_MPEG4_DEC,
+ .type = MFC_FMT_DEC,
+ .num_planes = 1,
+ },
+ {
+ .name = "FIMV1 Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_FIMV1,
+ .codec_mode = S5P_FIMV_CODEC_FIMV1_DEC,
+ .type = MFC_FMT_DEC,
+ .num_planes = 1,
+ },
+ {
+ .name = "FIMV2 Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_FIMV2,
+ .codec_mode = S5P_FIMV_CODEC_FIMV2_DEC,
+ .type = MFC_FMT_DEC,
+ .num_planes = 1,
+ },
+ {
+ .name = "FIMV3 Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_FIMV3,
+ .codec_mode = S5P_FIMV_CODEC_FIMV3_DEC,
+ .type = MFC_FMT_DEC,
+ .num_planes = 1,
+ },
+ {
+ .name = "FIMV4 Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_FIMV4,
+ .codec_mode = S5P_FIMV_CODEC_FIMV4_DEC,
+ .type = MFC_FMT_DEC,
+ .num_planes = 1,
+ },
+ {
+ .name = "XviD Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_XVID,
+ .codec_mode = S5P_FIMV_CODEC_MPEG4_DEC,
+ .type = MFC_FMT_DEC,
+ .num_planes = 1,
+ },
+ {
+ .name = "VC1 Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_VC1_ANNEX_G,
+ .codec_mode = S5P_FIMV_CODEC_VC1_DEC,
+ .type = MFC_FMT_DEC,
+ .num_planes = 1,
+ },
+ {
+ .name = "VC1 RCV Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_VC1_ANNEX_L,
+ .codec_mode = S5P_FIMV_CODEC_VC1RCV_DEC,
+ .type = MFC_FMT_DEC,
+ .num_planes = 1,
+ },
+ {
+ .name = "VP8 Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_VP8,
+ .codec_mode = S5P_FIMV_CODEC_VP8_DEC,
+ .type = MFC_FMT_DEC,
+ .num_planes = 1,
+ },
+};
+
+#define NUM_FORMATS ARRAY_SIZE(formats)
+
+/* Find selected format description */
+static struct s5p_mfc_fmt *find_format(struct v4l2_format *f, unsigned int t)
+{
+ unsigned int i;
+
+ for (i = 0; i < NUM_FORMATS; i++) {
+ if (formats[i].fourcc == f->fmt.pix_mp.pixelformat &&
+ formats[i].type == t)
+ return (struct s5p_mfc_fmt *)&formats[i];
+ }
+
+ return NULL;
+}
+
+static struct v4l2_queryctrl controls[] = {
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "H.264 Display Delay",
+ .minimum = -1,
+ .maximum = 32,
+ .step = 1,
+ .default_value = -1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Mpeg4 Loop Filter Enable",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Slice Interface Enable",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_PACKED_PB,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Packed PB Enable",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Frame Tag",
+ .minimum = 0,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_CACHEABLE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Cacheable flag",
+ .minimum = 0,
+ .maximum = 3,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_CRC_ENABLE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "CRC enable",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_CRC_DATA_LUMA,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "CRC data",
+ .minimum = 0,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_CRC_DATA_CHROMA,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "CRC data",
+ .minimum = 0,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_DISPLAY_STATUS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Display status",
+ .minimum = 0,
+ .maximum = 3,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TYPE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Frame type",
+ .minimum = 0,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_SEI_FRAME_PACKING,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Frame pack sei parse flag",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+};
+
+#define NUM_CTRLS ARRAY_SIZE(controls)
+
+static struct v4l2_queryctrl *get_ctrl(int id)
+{
+ int i;
+
+ for (i = 0; i < NUM_CTRLS; ++i)
+ if (id == controls[i].id)
+ return &controls[i];
+ return NULL;
+}
+
+/* Check whether a ctrl value if correct */
+static int check_ctrl_val(struct s5p_mfc_ctx *ctx, struct v4l2_control *ctrl)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct v4l2_queryctrl *c;
+
+ c = get_ctrl(ctrl->id);
+ if (!c)
+ return -EINVAL;
+
+ if (ctrl->value < c->minimum || ctrl->value > c->maximum
+ || (c->step != 0 && ctrl->value % c->step != 0)) {
+ v4l2_err(&dev->v4l2_dev, "invalid control value\n");
+ return -ERANGE;
+ }
+
+ return 0;
+}
+
+static struct s5p_mfc_ctrl_cfg mfc_ctrl_list[] = {
+ {
+ .type = MFC_CTRL_TYPE_SET,
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_CUSTOM,
+ .addr = S5P_FIMV_SHARED_SET_FRAME_TAG,
+ .mask = 0xFFFFFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_CUSTOM,
+ .addr = S5P_FIMV_SHARED_GET_FRAME_TAG_TOP,
+ .mask = 0xFFFFFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_DISPLAY_STATUS,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_SI_DISPLAY_STATUS,
+ .mask = 0x7,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ /* CRC related definitions are based on non-H.264 type */
+ {
+ .type = MFC_CTRL_TYPE_GET_SRC,
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_CRC_DATA_LUMA,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_CRC_LUMA0,
+ .mask = 0xFFFFFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_SRC,
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_CRC_DATA_CHROMA,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_CRC_CHROMA0,
+ .mask = 0xFFFFFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_SRC,
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_CRC_DATA_LUMA_BOT,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_CRC_LUMA1,
+ .mask = 0xFFFFFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_SRC,
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_CRC_DATA_CHROMA_BOT,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_CRC_CHROMA1,
+ .mask = 0xFFFFFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_SRC,
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_CRC_GENERATED,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_SI_DECODED_STATUS,
+ .mask = S5P_FIMV_DEC_CRC_GEN_MASK,
+ .shft = S5P_FIMV_DEC_CRC_GEN_SHIFT,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_VIDEO_H264_SEI_FP_AVAIL,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_CUSTOM,
+ .addr = S5P_FIMV_FRAME_PACK_SEI_AVAIL,
+ .mask = 0x1,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRGMENT_ID,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_CUSTOM,
+ .addr = S5P_FIMV_FRAME_PACK_ARRGMENT_ID,
+ .mask = 0xFFFFFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_VIDEO_H264_SEI_FP_INFO,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_CUSTOM,
+ .addr = S5P_FIMV_FRAME_PACK_SEI_INFO,
+ .mask = 0x3FFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_VIDEO_H264_SEI_FP_GRID_POS,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_CUSTOM,
+ .addr = S5P_FIMV_FRAME_PACK_GRID_POS,
+ .mask = 0xFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ {
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_VIDEO_H264_MVC_VIEW_ID,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_CUSTOM,
+ .addr = S5P_FIMV_D_MVC_VIEW_ID,
+ .mask = 0xFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+};
+
+#define NUM_CTRL_CFGS ARRAY_SIZE(mfc_ctrl_list)
+
+/* Check whether a context should be run on hardware */
+int s5p_mfc_dec_ctx_ready(struct s5p_mfc_ctx *ctx)
+{
+ mfc_debug(2, "src=%d, dst=%d, state=%d capstat=%d\n",
+ ctx->src_queue_cnt, ctx->dst_queue_cnt,
+ ctx->state, ctx->capture_state);
+
+ /* Context is to parse header */
+ if (ctx->src_queue_cnt >= 1 && ctx->state == MFCINST_GOT_INST)
+ return 1;
+ /* Context is to decode a frame */
+ if (ctx->src_queue_cnt >= 1 &&
+ ctx->state == MFCINST_RUNNING &&
+ ctx->dst_queue_cnt >= ctx->dpb_count)
+ return 1;
+ /* Context is to return last frame */
+ if (ctx->state == MFCINST_FINISHING &&
+ ctx->dst_queue_cnt >= ctx->dpb_count)
+ return 1;
+ /* Context is to set buffers */
+ if (ctx->state == MFCINST_HEAD_PARSED &&
+ ctx->capture_state == QUEUE_BUFS_MMAPED)
+ return 1;
+ /* Resolution change */
+ if ((ctx->state == MFCINST_RES_CHANGE_INIT ||
+ ctx->state == MFCINST_RES_CHANGE_FLUSH) &&
+ ctx->dst_queue_cnt >= ctx->dpb_count)
+ return 1;
+ if (ctx->state == MFCINST_RES_CHANGE_END &&
+ ctx->src_queue_cnt >= 1)
+ return 1;
+
+ mfc_debug(2, "s5p_mfc_dec_ctx_ready: ctx is not ready.\n");
+
+ return 0;
+}
+
+static int dec_cleanup_ctx_ctrls(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_ctx_ctrl *ctx_ctrl;
+
+ while (!list_empty(&ctx->ctrls)) {
+ ctx_ctrl = list_entry((&ctx->ctrls)->next,
+ struct s5p_mfc_ctx_ctrl, list);
+
+ mfc_debug(7, "Cleanup context control "\
+ "id: 0x%08x, type: %d\n",
+ ctx_ctrl->id, ctx_ctrl->type);
+
+ list_del(&ctx_ctrl->list);
+ kfree(ctx_ctrl);
+ }
+
+ INIT_LIST_HEAD(&ctx->ctrls);
+
+ return 0;
+}
+static int dec_init_ctx_ctrls(struct s5p_mfc_ctx *ctx)
+{
+ int i;
+ struct s5p_mfc_ctx_ctrl *ctx_ctrl;
+
+ INIT_LIST_HEAD(&ctx->ctrls);
+
+ for (i = 0; i < NUM_CTRL_CFGS; i++) {
+ ctx_ctrl = kzalloc(sizeof(struct s5p_mfc_ctx_ctrl), GFP_KERNEL);
+ if (ctx_ctrl == NULL) {
+ mfc_err("Failed to allocate context control "\
+ "id: 0x%08x, type: %d\n",
+ mfc_ctrl_list[i].id,
+ mfc_ctrl_list[i].type);
+
+ dec_cleanup_ctx_ctrls(ctx);
+
+ return -ENOMEM;
+ }
+
+ ctx_ctrl->type = mfc_ctrl_list[i].type;
+ ctx_ctrl->id = mfc_ctrl_list[i].id;
+ ctx_ctrl->addr = mfc_ctrl_list[i].addr;
+ ctx_ctrl->has_new = 0;
+ ctx_ctrl->val = 0;
+
+ list_add_tail(&ctx_ctrl->list, &ctx->ctrls);
+
+ mfc_debug(7, "Add context control id: 0x%08x, type : %d\n",
+ ctx_ctrl->id, ctx_ctrl->type);
+ }
+
+ return 0;
+}
+
+static void __dec_reset_buf_ctrls(struct list_head *head)
+{
+ struct s5p_mfc_buf_ctrl *buf_ctrl;
+
+ list_for_each_entry(buf_ctrl, head, list) {
+ mfc_debug(8, "Reset buffer control value "\
+ "id: 0x%08x, type: %d\n",
+ buf_ctrl->id, buf_ctrl->type);
+
+ buf_ctrl->has_new = 0;
+ buf_ctrl->val = 0;
+ buf_ctrl->old_val = 0;
+ buf_ctrl->updated = 0;
+ }
+}
+
+static void __dec_cleanup_buf_ctrls(struct list_head *head)
+{
+ struct s5p_mfc_buf_ctrl *buf_ctrl;
+
+ while (!list_empty(head)) {
+ buf_ctrl = list_entry(head->next,
+ struct s5p_mfc_buf_ctrl, list);
+
+ mfc_debug(7, "Cleanup buffer control "\
+ "id: 0x%08x, type: %d\n",
+ buf_ctrl->id, buf_ctrl->type);
+
+ list_del(&buf_ctrl->list);
+ kfree(buf_ctrl);
+ }
+
+ INIT_LIST_HEAD(head);
+}
+
+static int dec_init_buf_ctrls(struct s5p_mfc_ctx *ctx,
+ enum s5p_mfc_ctrl_type type, unsigned int index)
+{
+ int i;
+ struct s5p_mfc_ctx_ctrl *ctx_ctrl;
+ struct s5p_mfc_buf_ctrl *buf_ctrl;
+ struct list_head *head;
+
+ if (index >= MFC_MAX_BUFFERS) {
+ mfc_err("Per-buffer control index is out of range\n");
+ return -EINVAL;
+ }
+
+ if (type & MFC_CTRL_TYPE_SRC) {
+ if (test_bit(index, &ctx->src_ctrls_avail)) {
+ mfc_debug(7, "Source per-buffer control is already "\
+ "initialized [%d]\n", index);
+
+ __dec_reset_buf_ctrls(&ctx->src_ctrls[index]);
+
+ return 0;
+ }
+
+ head = &ctx->src_ctrls[index];
+ } else if (type & MFC_CTRL_TYPE_DST) {
+ if (test_bit(index, &ctx->dst_ctrls_avail)) {
+ mfc_debug(7, "Dest. per-buffer control is already "\
+ "initialized [%d]\n", index);
+
+ __dec_reset_buf_ctrls(&ctx->dst_ctrls[index]);
+
+ return 0;
+ }
+
+ head = &ctx->dst_ctrls[index];
+ } else {
+ mfc_err("Control type mismatch. type : %d\n", type);
+ return -EINVAL;
+ }
+
+ INIT_LIST_HEAD(head);
+
+ list_for_each_entry(ctx_ctrl, &ctx->ctrls, list) {
+ if (!(type & ctx_ctrl->type))
+ continue;
+
+ /* find matched control configuration index */
+ for (i = 0; i < NUM_CTRL_CFGS; i++) {
+ if (ctx_ctrl->id == mfc_ctrl_list[i].id)
+ break;
+ }
+
+ if (i == NUM_CTRL_CFGS) {
+ mfc_err("Failed to find buffer control "\
+ "id: 0x%08x, type: %d\n",
+ ctx_ctrl->id, ctx_ctrl->type);
+ continue;
+ }
+
+ buf_ctrl = kzalloc(sizeof(struct s5p_mfc_buf_ctrl), GFP_KERNEL);
+ if (buf_ctrl == NULL) {
+ mfc_err("Failed to allocate buffer control "\
+ "id: 0x%08x, type: %d\n",
+ mfc_ctrl_list[i].id,
+ mfc_ctrl_list[i].type);
+
+ __dec_cleanup_buf_ctrls(head);
+
+ return -ENOMEM;
+ }
+
+ buf_ctrl->id = ctx_ctrl->id;
+ buf_ctrl->type = ctx_ctrl->type;
+ buf_ctrl->addr = ctx_ctrl->addr;
+
+ buf_ctrl->is_volatile = mfc_ctrl_list[i].is_volatile;
+ buf_ctrl->mode = mfc_ctrl_list[i].mode;
+ buf_ctrl->mask = mfc_ctrl_list[i].mask;
+ buf_ctrl->shft = mfc_ctrl_list[i].shft;
+ buf_ctrl->flag_mode = mfc_ctrl_list[i].flag_mode;
+ buf_ctrl->flag_addr = mfc_ctrl_list[i].flag_addr;
+ buf_ctrl->flag_shft = mfc_ctrl_list[i].flag_shft;
+
+ list_add_tail(&buf_ctrl->list, head);
+
+ mfc_debug(7, "Add buffer control id: 0x%08x, type : %d\n",\
+ buf_ctrl->id, buf_ctrl->type);
+ }
+
+ __dec_reset_buf_ctrls(head);
+
+ if (type & MFC_CTRL_TYPE_SRC)
+ set_bit(index, &ctx->src_ctrls_avail);
+ else
+ set_bit(index, &ctx->dst_ctrls_avail);
+
+ return 0;
+}
+
+static int dec_cleanup_buf_ctrls(struct s5p_mfc_ctx *ctx,
+ enum s5p_mfc_ctrl_type type, unsigned int index)
+{
+ struct list_head *head;
+
+ if (index >= MFC_MAX_BUFFERS) {
+ mfc_err("Per-buffer control index is out of range\n");
+ return -EINVAL;
+ }
+
+ if (type & MFC_CTRL_TYPE_SRC) {
+ if (!(test_and_clear_bit(index, &ctx->src_ctrls_avail))) {
+ mfc_debug(7, "Source per-buffer control is "\
+ "not available [%d]\n", index);
+ return 0;
+ }
+
+ head = &ctx->src_ctrls[index];
+ } else if (type & MFC_CTRL_TYPE_DST) {
+ if (!(test_and_clear_bit(index, &ctx->dst_ctrls_avail))) {
+ mfc_debug(7, "Dest. per-buffer Control is "\
+ "not available [%d]\n", index);
+ return 0;
+ }
+
+ head = &ctx->dst_ctrls[index];
+ } else {
+ mfc_err("Control type mismatch. type : %d\n", type);
+ return -EINVAL;
+ }
+
+ __dec_cleanup_buf_ctrls(head);
+
+ return 0;
+}
+
+static int dec_to_buf_ctrls(struct s5p_mfc_ctx *ctx, struct list_head *head)
+{
+ struct s5p_mfc_ctx_ctrl *ctx_ctrl;
+ struct s5p_mfc_buf_ctrl *buf_ctrl;
+
+ list_for_each_entry(ctx_ctrl, &ctx->ctrls, list) {
+ if (!(ctx_ctrl->type & MFC_CTRL_TYPE_SET) || !ctx_ctrl->has_new)
+ continue;
+
+ list_for_each_entry(buf_ctrl, head, list) {
+ if (!(buf_ctrl->type & MFC_CTRL_TYPE_SET))
+ continue;
+
+ if (buf_ctrl->id == ctx_ctrl->id) {
+ buf_ctrl->has_new = 1;
+ buf_ctrl->val = ctx_ctrl->val;
+ if (buf_ctrl->is_volatile)
+ buf_ctrl->updated = 0;
+
+ ctx_ctrl->has_new = 0;
+ break;
+ }
+ }
+ }
+
+ list_for_each_entry(buf_ctrl, head, list) {
+ if (buf_ctrl->has_new)
+ mfc_debug(8, "Updated buffer control "\
+ "id: 0x%08x val: %d\n",
+ buf_ctrl->id, buf_ctrl->val);
+ }
+
+ return 0;
+}
+
+static int dec_to_ctx_ctrls(struct s5p_mfc_ctx *ctx, struct list_head *head)
+{
+ struct s5p_mfc_ctx_ctrl *ctx_ctrl;
+ struct s5p_mfc_buf_ctrl *buf_ctrl;
+
+ list_for_each_entry(buf_ctrl, head, list) {
+ if (!(buf_ctrl->type & MFC_CTRL_TYPE_GET) || !buf_ctrl->has_new)
+ continue;
+
+ list_for_each_entry(ctx_ctrl, &ctx->ctrls, list) {
+ if (!(ctx_ctrl->type & MFC_CTRL_TYPE_GET))
+ continue;
+
+ if (ctx_ctrl->id == buf_ctrl->id) {
+ if (ctx_ctrl->has_new)
+ mfc_debug(8,
+ "Overwrite context control "\
+ "value id: 0x%08x, val: %d\n",
+ ctx_ctrl->id, ctx_ctrl->val);
+
+ ctx_ctrl->has_new = 1;
+ ctx_ctrl->val = buf_ctrl->val;
+
+ buf_ctrl->has_new = 0;
+ }
+ }
+ }
+
+ list_for_each_entry(ctx_ctrl, &ctx->ctrls, list) {
+ if (ctx_ctrl->has_new)
+ mfc_debug(8, "Updated context control "\
+ "id: 0x%08x val: %d\n",
+ ctx_ctrl->id, ctx_ctrl->val);
+ }
+
+ return 0;
+}
+
+static int dec_set_buf_ctrls_val(struct s5p_mfc_ctx *ctx, struct list_head *head)
+{
+ struct s5p_mfc_buf_ctrl *buf_ctrl;
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+ unsigned int value = 0;
+
+ list_for_each_entry(buf_ctrl, head, list) {
+ if (!(buf_ctrl->type & MFC_CTRL_TYPE_SET) || !buf_ctrl->has_new)
+ continue;
+
+ /* read old vlaue */
+ if (buf_ctrl->mode == MFC_CTRL_MODE_SFR)
+ value = s5p_mfc_read_reg(buf_ctrl->addr);
+ else if (buf_ctrl->mode == MFC_CTRL_MODE_SHM)
+ value = s5p_mfc_read_info(ctx, buf_ctrl->addr);
+
+ /* save old vlaue for recovery */
+ if (buf_ctrl->is_volatile)
+ buf_ctrl->old_val = (value >> buf_ctrl->shft) & buf_ctrl->mask;
+
+ /* write new value */
+ value &= ~(buf_ctrl->mask << buf_ctrl->shft);
+ value |= ((buf_ctrl->val & buf_ctrl->mask) << buf_ctrl->shft);
+
+ if (buf_ctrl->mode == MFC_CTRL_MODE_SFR)
+ s5p_mfc_write_reg(value, buf_ctrl->addr);
+ else if (buf_ctrl->mode == MFC_CTRL_MODE_SHM)
+ s5p_mfc_write_info(ctx, value, buf_ctrl->addr);
+
+ /* set change flag bit */
+ if (buf_ctrl->flag_mode == MFC_CTRL_MODE_SFR) {
+ value = s5p_mfc_read_reg(buf_ctrl->flag_addr);
+ value |= (1 << buf_ctrl->flag_shft);
+ s5p_mfc_write_reg(value, buf_ctrl->flag_addr);
+ } else if (buf_ctrl->flag_mode == MFC_CTRL_MODE_SHM) {
+ value = s5p_mfc_read_info(ctx, buf_ctrl->flag_addr);
+ value |= (1 << buf_ctrl->flag_shft);
+ s5p_mfc_write_info(ctx, value, buf_ctrl->flag_addr);
+ }
+
+ buf_ctrl->has_new = 0;
+ buf_ctrl->updated = 1;
+
+ if (buf_ctrl->id == V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG)
+ dec->eos_tag = buf_ctrl->val;
+
+ mfc_debug(8, "Set buffer control "\
+ "id: 0x%08x val: %d\n",
+ buf_ctrl->id, buf_ctrl->val);
+ }
+
+ return 0;
+}
+
+static int dec_get_buf_ctrls_val(struct s5p_mfc_ctx *ctx, struct list_head *head)
+{
+ struct s5p_mfc_buf_ctrl *buf_ctrl;
+ unsigned int value = 0;
+
+ list_for_each_entry(buf_ctrl, head, list) {
+ if (!(buf_ctrl->type & MFC_CTRL_TYPE_GET))
+ continue;
+
+ if (buf_ctrl->mode == MFC_CTRL_MODE_SFR)
+ value = s5p_mfc_read_reg(buf_ctrl->addr);
+ else if (buf_ctrl->mode == MFC_CTRL_MODE_SHM)
+ value = s5p_mfc_read_info(ctx, buf_ctrl->addr);
+
+ value = (value >> buf_ctrl->shft) & buf_ctrl->mask;
+
+ buf_ctrl->val = value;
+ buf_ctrl->has_new = 1;
+
+ mfc_debug(8, "Get buffer control "\
+ "id: 0x%08x val: %d\n",
+ buf_ctrl->id, buf_ctrl->val);
+ }
+
+ return 0;
+}
+
+static int dec_recover_buf_ctrls_val(struct s5p_mfc_ctx *ctx, struct list_head *head)
+{
+ struct s5p_mfc_buf_ctrl *buf_ctrl;
+ unsigned int value = 0;
+
+ list_for_each_entry(buf_ctrl, head, list) {
+ if (!(buf_ctrl->type & MFC_CTRL_TYPE_SET)
+ || !buf_ctrl->is_volatile
+ || !buf_ctrl->updated)
+ continue;
+
+ if (buf_ctrl->mode == MFC_CTRL_MODE_SFR)
+ value = s5p_mfc_read_reg(buf_ctrl->addr);
+ else if (buf_ctrl->mode == MFC_CTRL_MODE_SHM)
+ value = s5p_mfc_read_info(ctx, buf_ctrl->addr);
+
+ value &= ~(buf_ctrl->mask << buf_ctrl->shft);
+ value |= ((buf_ctrl->old_val & buf_ctrl->mask) << buf_ctrl->shft);
+
+ if (buf_ctrl->mode == MFC_CTRL_MODE_SFR)
+ s5p_mfc_write_reg(value, buf_ctrl->addr);
+ else if (buf_ctrl->mode == MFC_CTRL_MODE_SHM)
+ s5p_mfc_write_info(ctx, value, buf_ctrl->addr);
+
+ /* clear change flag bit */
+ if (buf_ctrl->flag_mode == MFC_CTRL_MODE_SFR) {
+ value = s5p_mfc_read_reg(buf_ctrl->flag_addr);
+ value &= ~(1 << buf_ctrl->flag_shft);
+ s5p_mfc_write_reg(value, buf_ctrl->flag_addr);
+ } else if (buf_ctrl->flag_mode == MFC_CTRL_MODE_SHM) {
+ value = s5p_mfc_read_info(ctx, buf_ctrl->flag_addr);
+ value &= ~(1 << buf_ctrl->flag_shft);
+ s5p_mfc_write_info(ctx, value, buf_ctrl->flag_addr);
+ }
+
+ mfc_debug(8, "Recover buffer control "\
+ "id: 0x%08x old val: %d\n",
+ buf_ctrl->id, buf_ctrl->old_val);
+ }
+
+ return 0;
+}
+
+static int dec_get_buf_update_val(struct s5p_mfc_ctx *ctx,
+ struct list_head *head, unsigned int id, int value)
+{
+ struct s5p_mfc_buf_ctrl *buf_ctrl;
+
+ list_for_each_entry(buf_ctrl, head, list) {
+ if ((buf_ctrl->id == id)) {
+ buf_ctrl->val = value;
+ mfc_debug(5, "++id: 0x%08x val: %d\n",
+ buf_ctrl->id, buf_ctrl->val);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static struct s5p_mfc_codec_ops decoder_codec_ops = {
+ .pre_seq_start = NULL,
+ .post_seq_start = NULL,
+ .pre_frame_start = NULL,
+ .post_frame_start = NULL,
+ .init_ctx_ctrls = dec_init_ctx_ctrls,
+ .cleanup_ctx_ctrls = dec_cleanup_ctx_ctrls,
+ .init_buf_ctrls = dec_init_buf_ctrls,
+ .cleanup_buf_ctrls = dec_cleanup_buf_ctrls,
+ .to_buf_ctrls = dec_to_buf_ctrls,
+ .to_ctx_ctrls = dec_to_ctx_ctrls,
+ .set_buf_ctrls_val = dec_set_buf_ctrls_val,
+ .get_buf_ctrls_val = dec_get_buf_ctrls_val,
+ .recover_buf_ctrls_val = dec_recover_buf_ctrls_val,
+ .get_buf_update_val = dec_get_buf_update_val,
+};
+
+/* Query capabilities of the device */
+static int vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct s5p_mfc_dev *dev = video_drvdata(file);
+
+ strncpy(cap->driver, dev->plat_dev->name, sizeof(cap->driver) - 1);
+ strncpy(cap->card, dev->plat_dev->name, sizeof(cap->card) - 1);
+ cap->bus_info[0] = 0;
+ cap->version = KERNEL_VERSION(1, 0, 0);
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT
+ | V4L2_CAP_STREAMING;
+ return 0;
+}
+
+/* Enumerate format */
+static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool mplane, bool out)
+{
+ struct s5p_mfc_fmt *fmt;
+ int i, j = 0;
+
+ for (i = 0; i < ARRAY_SIZE(formats); ++i) {
+ if (mplane && formats[i].num_planes == 1)
+ continue;
+ else if (!mplane && formats[i].num_planes > 1)
+ continue;
+ if (out && formats[i].type != MFC_FMT_DEC)
+ continue;
+ else if (!out && formats[i].type != MFC_FMT_RAW)
+ continue;
+
+ if (j == f->index)
+ break;
+ ++j;
+ }
+ if (i == ARRAY_SIZE(formats))
+ return -EINVAL;
+ fmt = &formats[i];
+ strlcpy(f->description, fmt->name, sizeof(f->description));
+ f->pixelformat = fmt->fourcc;
+ return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *pirv,
+ struct v4l2_fmtdesc *f)
+{
+ return vidioc_enum_fmt(f, false, false);
+}
+
+static int vidioc_enum_fmt_vid_cap_mplane(struct file *file, void *pirv,
+ struct v4l2_fmtdesc *f)
+{
+ return vidioc_enum_fmt(f, true, false);
+}
+
+static int vidioc_enum_fmt_vid_out(struct file *file, void *prov,
+ struct v4l2_fmtdesc *f)
+{
+ return vidioc_enum_fmt(f, false, true);
+}
+
+static int vidioc_enum_fmt_vid_out_mplane(struct file *file, void *prov,
+ struct v4l2_fmtdesc *f)
+{
+ return vidioc_enum_fmt(f, true, true);
+}
+
+/* Get format */
+static int vidioc_g_fmt_vid_cap_mplane(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+
+ mfc_debug_enter();
+ mfc_debug(2, "f->type = %d ctx->state = %d\n", f->type, ctx->state);
+
+ if (ctx->state == MFCINST_GOT_INST ||
+ ctx->state == MFCINST_RES_CHANGE_END) {
+ /* If the MFC is parsing the header,
+ * so wait until it is finished */
+ s5p_mfc_wait_for_done_ctx(ctx, S5P_FIMV_R2H_CMD_SEQ_DONE_RET);
+ }
+
+ if (ctx->state >= MFCINST_HEAD_PARSED &&
+ ctx->state < MFCINST_ABORT) {
+ /* This is run on CAPTURE (deocde output) */
+ /* Width and height are set to the dimensions
+ of the movie, the buffer is bigger and
+ further processing stages should crop to this
+ rectangle. */
+ pix_mp->width = ctx->img_width;
+ pix_mp->height = ctx->img_height;
+ pix_mp->field = V4L2_FIELD_NONE;
+ pix_mp->num_planes = 2;
+ /* Set pixelformat to the format in which MFC
+ outputs the decoded frame */
+ pix_mp->pixelformat = V4L2_PIX_FMT_NV12MT;
+ pix_mp->plane_fmt[0].bytesperline = ctx->buf_width;
+ pix_mp->plane_fmt[0].sizeimage =
+ ctx->buf_width * ctx->buf_height;
+ pix_mp->plane_fmt[1].bytesperline = ctx->buf_width;
+ pix_mp->plane_fmt[1].sizeimage =
+ ctx->buf_width * (ctx->buf_height >> 1);
+ }
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+static int vidioc_g_fmt_vid_out_mplane(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+ struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+
+ mfc_debug_enter();
+ mfc_debug(2, "f->type = %d ctx->state = %d\n", f->type, ctx->state);
+
+ /* This is run on OUTPUT
+ The buffer contains compressed image
+ so width and height have no meaning */
+ pix_mp->width = 0;
+ pix_mp->height = 0;
+ pix_mp->field = V4L2_FIELD_NONE;
+ pix_mp->plane_fmt[0].bytesperline = dec->src_buf_size;
+ pix_mp->plane_fmt[0].sizeimage = dec->src_buf_size;
+ pix_mp->pixelformat = ctx->src_fmt->fourcc;
+ pix_mp->num_planes = ctx->src_fmt->num_planes;
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+/* Try format */
+static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
+{
+ struct s5p_mfc_dev *dev = video_drvdata(file);
+ struct s5p_mfc_fmt *fmt;
+
+ mfc_debug(2, "Type is %d\n", f->type);
+ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ fmt = find_format(f, MFC_FMT_DEC);
+ if (!fmt) {
+ mfc_err("Unsupported format for source.\n");
+ return -EINVAL;
+ }
+ if (!IS_MFCV6(dev)) {
+ if (fmt->fourcc == V4L2_PIX_FMT_VP8) {
+ mfc_err("Not supported format.\n");
+ return -EINVAL;
+ }
+ }
+ } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ fmt = find_format(f, MFC_FMT_RAW);
+ if (!fmt) {
+ mfc_err("Unsupported format for destination.\n");
+ return -EINVAL;
+ }
+ if (IS_MFCV6(dev)) {
+ if (fmt->fourcc == V4L2_PIX_FMT_NV12MT) {
+ mfc_err("Not supported format.\n");
+ return -EINVAL;
+ }
+ } else {
+ if (fmt->fourcc != V4L2_PIX_FMT_NV12MT) {
+ mfc_err("Not supported format.\n");
+ return -EINVAL;
+ }
+ }
+ }
+ /* Width and height are left intact as they may be relevant for
+ * FIMV1 decoding. */
+
+ return 0;
+}
+
+/* Set format */
+static int vidioc_s_fmt_vid_cap_mplane(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct s5p_mfc_dev *dev = video_drvdata(file);
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ int ret = 0;
+
+ mfc_debug_enter();
+
+ if (ctx->vq_dst.streaming) {
+ v4l2_err(&dev->v4l2_dev, "%s queue busy\n", __func__);
+ return -EBUSY;
+ }
+
+ ret = vidioc_try_fmt(file, priv, f);
+ if (ret)
+ return ret;
+
+ ctx->dst_fmt = find_format(f, MFC_FMT_RAW);
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+static int vidioc_s_fmt_vid_out_mplane(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct s5p_mfc_dev *dev = video_drvdata(file);
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+ unsigned long flags;
+ int ret = 0;
+ struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+ int i;
+ struct s5p_mfc_ctx_ctrl *ctx_ctrl;
+
+ mfc_debug_enter();
+
+ if (ctx->vq_src.streaming) {
+ v4l2_err(&dev->v4l2_dev, "%s queue busy\n", __func__);
+ return -EBUSY;
+ }
+
+ ret = vidioc_try_fmt(file, priv, f);
+ if (ret)
+ return ret;
+
+ ctx->src_fmt = find_format(f, MFC_FMT_DEC);
+ ctx->codec_mode = ctx->src_fmt->codec_mode;
+ mfc_debug(2, "The codec number is: %d\n", ctx->codec_mode);
+ ctx->pix_format = pix_mp->pixelformat;
+ if ((pix_mp->width > 0) && (pix_mp->height > 0)) {
+ ctx->img_height = pix_mp->height;
+ ctx->img_width = pix_mp->width;
+ }
+ /* As this buffer will contain compressed data, the size is set
+ * to the maximum size. */
+ if (pix_mp->plane_fmt[0].sizeimage)
+ dec->src_buf_size = pix_mp->plane_fmt[0].sizeimage;
+ else
+ dec->src_buf_size = MAX_FRAME_SIZE;
+ mfc_debug(2, "s_fmt w/h: %dx%d, ctx: %dx%d\n", pix_mp->width,
+ pix_mp->height, ctx->img_width, ctx->img_height);
+ mfc_debug(2, "sizeimage: %d\n", pix_mp->plane_fmt[0].sizeimage);
+ pix_mp->plane_fmt[0].bytesperline = 0;
+
+ /* In case of calling s_fmt twice or more */
+ if (ctx->inst_no != MFC_NO_INSTANCE_SET) {
+ ctx->state = MFCINST_RETURN_INST;
+ spin_lock_irqsave(&dev->condlock, flags);
+ set_bit(ctx->num, &dev->ctx_work_bits);
+ spin_unlock_irqrestore(&dev->condlock, flags);
+ s5p_mfc_try_run(dev);
+ /* Wait until instance is returned or timeout occured */
+ if (s5p_mfc_wait_for_done_ctx
+ (ctx, S5P_FIMV_R2H_CMD_CLOSE_INSTANCE_RET)) {
+ mfc_err("Err returning instance.\n");
+ }
+ /* Free resources */
+ if (!ctx->is_drm)
+ s5p_mfc_release_instance_buffer(ctx);
+ s5p_mfc_release_dec_desc_buffer(ctx);
+
+ ctx->state = MFCINST_INIT;
+ }
+
+ if (dec->crc_enable && (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC ||
+ ctx->codec_mode == S5P_FIMV_CODEC_H264_MVC_DEC)) {
+ /* CRC related control types should be changed by the codec mode. */
+ mfc_debug(5, "ctx_ctrl is changed for H.264\n");
+ list_for_each_entry(ctx_ctrl, &ctx->ctrls, list) {
+ switch (ctx_ctrl->id) {
+ case V4L2_CID_MPEG_MFC51_VIDEO_CRC_DATA_LUMA:
+ ctx_ctrl->type = MFC_CTRL_TYPE_GET_DST;
+ ctx_ctrl->addr = S5P_FIMV_CRC_DISP_LUMA0;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_CRC_DATA_CHROMA:
+ ctx_ctrl->type = MFC_CTRL_TYPE_GET_DST;
+ ctx_ctrl->addr = S5P_FIMV_CRC_DISP_CHROMA0;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_CRC_GENERATED:
+ ctx_ctrl->type = MFC_CTRL_TYPE_GET_DST;
+ ctx_ctrl->addr = S5P_FIMV_CRC_DISP_STATUS;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_CRC_DATA_LUMA_BOT:
+ case V4L2_CID_MPEG_MFC51_VIDEO_CRC_DATA_CHROMA_BOT:
+ ctx_ctrl->type = MFC_CTRL_TYPE_GET_DST;
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* Reinitialize controls for source buffers */
+ for (i = 0; i < MFC_MAX_BUFFERS; i++) {
+ if (test_bit(i, &ctx->src_ctrls_avail)) {
+ if (call_cop(ctx, cleanup_buf_ctrls, ctx,
+ MFC_CTRL_TYPE_SRC, i) < 0)
+ mfc_err("failed in cleanup_buf_ctrls\n");
+ if (call_cop(ctx, init_buf_ctrls, ctx,
+ MFC_CTRL_TYPE_SRC, i) < 0)
+ mfc_err("failed in init_buf_ctrls\n");
+ }
+ }
+ }
+
+ if (!ctx->is_drm)
+ s5p_mfc_alloc_instance_buffer(ctx);
+ s5p_mfc_alloc_dec_temp_buffers(ctx);
+
+ spin_lock_irqsave(&dev->condlock, flags);
+ set_bit(ctx->num, &dev->ctx_work_bits);
+ spin_unlock_irqrestore(&dev->condlock, flags);
+ s5p_mfc_try_run(dev);
+ if (s5p_mfc_wait_for_done_ctx(ctx,
+ S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET)) {
+ /* Error or timeout */
+ mfc_err("Error getting instance from hardware.\n");
+ s5p_mfc_release_instance_buffer(ctx);
+ s5p_mfc_release_dec_desc_buffer(ctx);
+ return -EIO;
+ }
+ mfc_debug(2, "Got instance number: %d\n", ctx->inst_no);
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+/* Reqeust buffers */
+static int vidioc_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *reqbufs)
+{
+ struct s5p_mfc_dev *dev = video_drvdata(file);
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+ int ret = 0;
+ unsigned long flags;
+ int cacheable;
+ void *alloc_ctx1 = ctx->dev->alloc_ctx[MFC_CMA_BANK1_ALLOC_CTX];
+ void *alloc_ctx2 = ctx->dev->alloc_ctx[MFC_CMA_BANK2_ALLOC_CTX];
+
+ mfc_debug_enter();
+ mfc_debug(2, "Memory type: %d\n", reqbufs->memory);
+
+ if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ cacheable = (ctx->cacheable & MFCMASK_SRC_CACHE) ? 1 : 0;
+ if (ctx->is_drm)
+ s5p_mfc_mem_set_cacheable(ctx->dev->alloc_ctx_drm,
+ cacheable);
+ else
+ s5p_mfc_mem_set_cacheable(alloc_ctx1, cacheable);
+ /* Can only request buffers after
+ an instance has been opened.*/
+ if (ctx->state == MFCINST_GOT_INST) {
+ if (reqbufs->count == 0) {
+ mfc_debug(2, "Freeing buffers.\n");
+ ret = vb2_reqbufs(&ctx->vq_src, reqbufs);
+ return ret;
+ }
+ /* Decoding */
+ if (ctx->output_state != QUEUE_FREE) {
+ mfc_err("Bufs have already been requested.\n");
+ return -EINVAL;
+ }
+ ret = vb2_reqbufs(&ctx->vq_src, reqbufs);
+ if (ret) {
+ mfc_err("vb2_reqbufs on output failed.\n");
+ return ret;
+ }
+ mfc_debug(2, "vb2_reqbufs: %d\n", ret);
+ ctx->output_state = QUEUE_BUFS_REQUESTED;
+ }
+ } else if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ dec->dst_memtype = reqbufs->memory;
+
+ /* cacheable setting */
+ cacheable = (ctx->cacheable & MFCMASK_DST_CACHE) ? 1 : 0;
+ if (ctx->is_drm) {
+ s5p_mfc_mem_set_cacheable(ctx->dev->alloc_ctx_drm,
+ cacheable);
+ } else {
+ if (!IS_MFCV6(dev))
+ s5p_mfc_mem_set_cacheable(alloc_ctx2,
+ cacheable);
+
+ s5p_mfc_mem_set_cacheable(alloc_ctx1, cacheable);
+ }
+
+ if (reqbufs->count == 0) {
+ mfc_debug(2, "Freeing buffers.\n");
+ ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
+ dec->dpb_queue_cnt = 0;
+ return ret;
+ }
+
+ if (ctx->capture_state != QUEUE_FREE) {
+ mfc_err("Bufs have already been requested.\n");
+ return -EINVAL;
+ }
+
+ ctx->capture_state = QUEUE_BUFS_REQUESTED;
+
+ ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
+ if (ret) {
+ mfc_err("vb2_reqbufs on capture failed.\n");
+ return ret;
+ }
+
+ if (reqbufs->count < ctx->dpb_count) {
+ mfc_err("Not enough buffers allocated.\n");
+ reqbufs->count = 0;
+ ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
+ return -ENOMEM;
+ }
+
+ dec->total_dpb_count = reqbufs->count;
+
+ ret = s5p_mfc_alloc_codec_buffers(ctx);
+ if (ret) {
+ mfc_err("Failed to allocate decoding buffers.\n");
+ reqbufs->count = 0;
+ ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
+ return -ENOMEM;
+ }
+
+ if (dec->dst_memtype == V4L2_MEMORY_MMAP) {
+ if (dec->dpb_queue_cnt == dec->total_dpb_count) {
+ ctx->capture_state = QUEUE_BUFS_MMAPED;
+ } else {
+ mfc_err("Not all buffers passed to buf_init.\n");
+ reqbufs->count = 0;
+ ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
+ s5p_mfc_release_codec_buffers(ctx);
+ return -ENOMEM;
+ }
+ }
+
+ if (s5p_mfc_dec_ctx_ready(ctx)) {
+ spin_lock_irqsave(&dev->condlock, flags);
+ set_bit(ctx->num, &dev->ctx_work_bits);
+ spin_unlock_irqrestore(&dev->condlock, flags);
+ }
+
+ s5p_mfc_try_run(dev);
+
+ if (dec->dst_memtype == V4L2_MEMORY_MMAP) {
+ s5p_mfc_wait_for_done_ctx(ctx,
+ S5P_FIMV_R2H_CMD_INIT_BUFFERS_RET);
+ }
+ }
+
+ mfc_debug_leave();
+
+ return ret;
+}
+
+/* Query buffer */
+static int vidioc_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ int ret;
+ int i;
+
+ mfc_debug_enter();
+
+ if (buf->memory != V4L2_MEMORY_MMAP) {
+ mfc_err("Only mmaped buffers can be used.\n");
+ return -EINVAL;
+ }
+
+ mfc_debug(2, "State: %d, buf->type: %d\n", ctx->state, buf->type);
+ if (ctx->state == MFCINST_GOT_INST &&
+ buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ ret = vb2_querybuf(&ctx->vq_src, buf);
+ } else if (ctx->state == MFCINST_RUNNING &&
+ buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ ret = vb2_querybuf(&ctx->vq_dst, buf);
+ for (i = 0; i < buf->length; i++)
+ buf->m.planes[i].m.mem_offset += DST_QUEUE_OFF_BASE;
+ } else {
+ mfc_err("vidioc_querybuf called in an inappropriate state.\n");
+ ret = -EINVAL;
+ }
+ mfc_debug_leave();
+ return ret;
+}
+
+/* Queue a buffer */
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+
+ mfc_debug_enter();
+
+ mfc_debug(2, "Enqueued buf: %d, (type = %d)\n", buf->index, buf->type);
+ if (ctx->state == MFCINST_ERROR) {
+ mfc_err("Call on QBUF after unrecoverable error.\n");
+ return -EIO;
+ }
+
+ if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ return vb2_qbuf(&ctx->vq_src, buf);
+ else
+ return vb2_qbuf(&ctx->vq_dst, buf);
+
+ mfc_debug_leave();
+ return -EINVAL;
+}
+
+/* Dequeue a buffer */
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ int ret;
+
+ mfc_debug_enter();
+ mfc_debug(2, "Addr: %p %p %p Type: %d\n", &ctx->vq_src, buf, buf->m.planes,
+ buf->type);
+ if (ctx->state == MFCINST_ERROR) {
+ mfc_err("Call on DQBUF after unrecoverable error.\n");
+ return -EIO;
+ }
+ if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ ret = vb2_dqbuf(&ctx->vq_src, buf, file->f_flags & O_NONBLOCK);
+ else
+ ret = vb2_dqbuf(&ctx->vq_dst, buf, file->f_flags & O_NONBLOCK);
+ mfc_debug_leave();
+ return ret;
+}
+
+/* Stream on */
+static int vidioc_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ int ret = -EINVAL;
+
+ mfc_debug_enter();
+ if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ ret = vb2_streamon(&ctx->vq_src, type);
+ } else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ ret = vb2_streamon(&ctx->vq_dst, type);
+
+ if (!ret) {
+ ctx->mfc_int_handle_poll = exynos5_bus_int_poll();
+ if (!ctx->mfc_int_handle_poll)
+ mfc_err("Failed to request INT poll()\n");
+ }
+ }
+ mfc_debug(2, "ctx->src_queue_cnt = %d ctx->state = %d "
+ "ctx->dst_queue_cnt = %d ctx->dpb_count = %d\n",
+ ctx->src_queue_cnt, ctx->state, ctx->dst_queue_cnt,
+ ctx->dpb_count);
+ mfc_debug_leave();
+ return ret;
+}
+
+/* Stream off, which equals to a pause */
+static int vidioc_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ int ret;
+
+ mfc_debug_enter();
+ ret = -EINVAL;
+ if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ ret = vb2_streamoff(&ctx->vq_src, type);
+ } else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ ret = vb2_streamoff(&ctx->vq_dst, type);
+ if (!ret) {
+ if (ctx->mfc_int_handle_poll) {
+ exynos5_bus_int_put(ctx->mfc_int_handle_poll);
+ ctx->mfc_int_handle_poll = NULL;
+ }
+ }
+ }
+ mfc_debug_leave();
+ return ret;
+}
+
+/* Query a ctrl */
+static int vidioc_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *qc)
+{
+ struct v4l2_queryctrl *c;
+
+ c = get_ctrl(qc->id);
+ if (!c)
+ return -EINVAL;
+ *qc = *c;
+ return 0;
+}
+
+/* Get ctrl */
+static int get_ctrl_val(struct s5p_mfc_ctx *ctx, struct v4l2_control *ctrl)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+ struct s5p_mfc_ctx_ctrl *ctx_ctrl;
+ int found = 0;
+
+ mfc_debug_enter();
+
+ switch (ctrl->id) {
+ case V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER:
+ ctrl->value = dec->loop_filter_mpeg4;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY:
+ ctrl->value = dec->display_delay;
+ break;
+ case V4L2_CID_CACHEABLE:
+ ctrl->value = ctx->cacheable;
+ break;
+ case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:
+ if (ctx->state >= MFCINST_HEAD_PARSED &&
+ ctx->state < MFCINST_ABORT) {
+ ctrl->value = ctx->dpb_count;
+ break;
+ } else if (ctx->state != MFCINST_INIT) {
+ v4l2_err(&dev->v4l2_dev, "Decoding not initialised.\n");
+ return -EINVAL;
+ }
+
+ /* Should wait for the header to be parsed */
+ s5p_mfc_wait_for_done_ctx(ctx,
+ S5P_FIMV_R2H_CMD_SEQ_DONE_RET);
+ if (ctx->state >= MFCINST_HEAD_PARSED &&
+ ctx->state < MFCINST_ABORT) {
+ ctrl->value = ctx->dpb_count;
+ } else {
+ v4l2_err(&dev->v4l2_dev,
+ "Decoding not initialised.\n");
+ return -EINVAL;
+ }
+ break;
+ case V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE:
+ ctrl->value = dec->slice_enable;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_PACKED_PB:
+ ctrl->value = dec->is_packedpb;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_CRC_ENABLE:
+ ctrl->value = dec->crc_enable;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_CHECK_STATE:
+ if (ctx->state == MFCINST_RES_CHANGE_FLUSH
+ || ctx->state == MFCINST_RES_CHANGE_END
+ || ctx->state == MFCINST_HEAD_PARSED)
+ ctrl->value = MFCSTATE_DEC_RES_DETECT;
+ else if (ctx->state == MFCINST_FINISHING)
+ ctrl->value = MFCSTATE_DEC_TERMINATING;
+ else
+ ctrl->value = MFCSTATE_PROCESSING;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_SEI_FRAME_PACKING:
+ ctrl->value = dec->sei_parse;
+ break;
+ default:
+ list_for_each_entry(ctx_ctrl, &ctx->ctrls, list) {
+ if (!(ctx_ctrl->type & MFC_CTRL_TYPE_GET))
+ continue;
+
+ if (ctx_ctrl->id == ctrl->id) {
+ if (ctx_ctrl->has_new) {
+ ctx_ctrl->has_new = 0;
+ ctrl->value = ctx_ctrl->val;
+ } else {
+ mfc_debug(8, "Control value "\
+ "is not up to date: "\
+ "0x%08x\n", ctrl->id);
+ return -EINVAL;
+ }
+
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ v4l2_err(&dev->v4l2_dev, "Invalid control 0x%08x\n",
+ ctrl->id);
+ return -EINVAL;
+ }
+ break;
+ }
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+/* Get a ctrl */
+static int vidioc_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ int ret = 0;
+
+ mfc_debug_enter();
+ ret = get_ctrl_val(ctx, ctrl);
+ mfc_debug_leave();
+
+ return ret;
+}
+
+/* Set a ctrl */
+static int vidioc_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct s5p_mfc_dev *dev = video_drvdata(file);
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+ struct s5p_mfc_ctx_ctrl *ctx_ctrl;
+ int ret = 0;
+ int stream_on;
+ int found = 0;
+
+ mfc_debug_enter();
+
+ stream_on = ctx->vq_src.streaming || ctx->vq_dst.streaming;
+
+ ret = check_ctrl_val(ctx, ctrl);
+ if (ret)
+ return ret;
+
+ switch (ctrl->id) {
+ case V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER:
+ if (stream_on)
+ return -EBUSY;
+ dec->loop_filter_mpeg4 = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY:
+ if (stream_on)
+ return -EBUSY;
+ dec->display_delay = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE:
+ if (stream_on)
+ return -EBUSY;
+ dec->slice_enable = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_PACKED_PB:
+ if (stream_on)
+ return -EBUSY;
+ if (ctx->codec_mode != S5P_FIMV_CODEC_MPEG4_DEC &&
+ ctx->codec_mode != S5P_FIMV_CODEC_FIMV1_DEC &&
+ ctx->codec_mode != S5P_FIMV_CODEC_FIMV2_DEC &&
+ ctx->codec_mode != S5P_FIMV_CODEC_FIMV3_DEC &&
+ ctx->codec_mode != S5P_FIMV_CODEC_FIMV4_DEC)
+ return -EINVAL;
+ dec->is_packedpb = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_CRC_ENABLE:
+ if (ctrl->value == 1 || ctrl->value == 0)
+ dec->crc_enable = ctrl->value;
+ else
+ dec->crc_enable = 0;
+ break;
+ case V4L2_CID_CACHEABLE:
+ /*if (stream_on)
+ return -EBUSY; */
+ ctx->cacheable |= ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_SEI_FRAME_PACKING:
+ /*if (stream_on)
+ return -EBUSY; */
+ if (ctrl->value == 0 || ctrl->value == 1)
+ dec->sei_parse = ctrl->value;
+ else
+ dec->sei_parse = 0;
+ break;
+ default:
+ list_for_each_entry(ctx_ctrl, &ctx->ctrls, list) {
+ if (!(ctx_ctrl->type & MFC_CTRL_TYPE_SET))
+ continue;
+
+ if (ctx_ctrl->id == ctrl->id) {
+ ctx_ctrl->has_new = 1;
+ ctx_ctrl->val = ctrl->value;
+
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ v4l2_err(&dev->v4l2_dev, "Invalid control 0x%08x\n",
+ ctrl->id);
+ return -EINVAL;
+ }
+ break;
+ }
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+/* Get cropping information */
+static int vidioc_g_crop(struct file *file, void *priv,
+ struct v4l2_crop *cr)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ u32 left, right, top, bottom;
+
+ mfc_debug_enter();
+ if (ctx->state != MFCINST_HEAD_PARSED &&
+ ctx->state != MFCINST_RUNNING && ctx->state != MFCINST_FINISHING
+ && ctx->state != MFCINST_FINISHED) {
+ mfc_debug(2, "%s-- with error\n", __func__);
+ return -EINVAL;
+ }
+ if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_H264) {
+ s5p_mfc_clock_on();
+ left = s5p_mfc_read_info(ctx, CROP_INFO_H);
+ right = left >> S5P_FIMV_SHARED_CROP_RIGHT_SHIFT;
+ left = left & S5P_FIMV_SHARED_CROP_LEFT_MASK;
+ top = s5p_mfc_read_info(ctx, CROP_INFO_V);
+ s5p_mfc_clock_off();
+ bottom = top >> S5P_FIMV_SHARED_CROP_BOTTOM_SHIFT;
+ top = top & S5P_FIMV_SHARED_CROP_TOP_MASK;
+ cr->c.left = left;
+ cr->c.top = top;
+ cr->c.width = ctx->img_width - left - right;
+ cr->c.height = ctx->img_height - top - bottom;
+ mfc_debug(2, "Cropping info [h264]: l=%d t=%d "
+ "w=%d h=%d (r=%d b=%d fw=%d fh=%d\n", left, top,
+ cr->c.width, cr->c.height, right, bottom,
+ ctx->buf_width, ctx->buf_height);
+ } else {
+ cr->c.left = 0;
+ cr->c.top = 0;
+ cr->c.width = ctx->img_width;
+ cr->c.height = ctx->img_height;
+ mfc_debug(2, "Cropping info: w=%d h=%d fw=%d "
+ "fh=%d\n", cr->c.width, cr->c.height, ctx->buf_width,
+ ctx->buf_height);
+ }
+ mfc_debug_leave();
+ return 0;
+}
+
+static int vidioc_g_ext_ctrls(struct file *file, void *priv,
+ struct v4l2_ext_controls *f)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ struct v4l2_ext_control *ext_ctrl;
+ struct v4l2_control ctrl;
+ int i;
+ int ret = 0;
+
+ if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+ return -EINVAL;
+
+ for (i = 0; i < f->count; i++) {
+ ext_ctrl = (f->controls + i);
+
+ ctrl.id = ext_ctrl->id;
+
+ ret = get_ctrl_val(ctx, &ctrl);
+ if (ret == 0) {
+ ext_ctrl->value = ctrl.value;
+ } else {
+ f->error_idx = i;
+ break;
+ }
+
+ mfc_debug(2, "[%d] id: 0x%08x, value: %d", i, ext_ctrl->id, ext_ctrl->value);
+ }
+
+ return ret;
+}
+
+/* v4l2_ioctl_ops */
+static const struct v4l2_ioctl_ops s5p_mfc_dec_ioctl_ops = {
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+ .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap_mplane,
+ .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
+ .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out_mplane,
+ .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt_vid_cap_mplane,
+ .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt_vid_out_mplane,
+ .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt,
+ .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt,
+ .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt_vid_cap_mplane,
+ .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt_vid_out_mplane,
+ .vidioc_reqbufs = vidioc_reqbufs,
+ .vidioc_querybuf = vidioc_querybuf,
+ .vidioc_qbuf = vidioc_qbuf,
+ .vidioc_dqbuf = vidioc_dqbuf,
+ .vidioc_streamon = vidioc_streamon,
+ .vidioc_streamoff = vidioc_streamoff,
+ .vidioc_queryctrl = vidioc_queryctrl,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ .vidioc_g_crop = vidioc_g_crop,
+ .vidioc_g_ext_ctrls = vidioc_g_ext_ctrls,
+};
+
+static int s5p_mfc_queue_setup(struct vb2_queue *vq,
+ const struct v4l2_format *fmt,
+ unsigned int *buf_count, unsigned int *plane_count,
+ unsigned int psize[], void *allocators[])
+{
+ struct s5p_mfc_ctx *ctx = vq->drv_priv;
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+ void *alloc_ctx1 = ctx->dev->alloc_ctx[MFC_CMA_BANK1_ALLOC_CTX];
+ void *alloc_ctx2 = ctx->dev->alloc_ctx[MFC_CMA_BANK2_ALLOC_CTX];
+
+ mfc_debug_enter();
+
+ /* Video output for decoding (source)
+ * this can be set after getting an instance */
+ if (ctx->state == MFCINST_GOT_INST &&
+ vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ mfc_debug(2, "setting for VIDEO output\n");
+ /* A single plane is required for input */
+ *plane_count = 1;
+ if (*buf_count < 1)
+ *buf_count = 1;
+ if (*buf_count > MFC_MAX_BUFFERS)
+ *buf_count = MFC_MAX_BUFFERS;
+ /* Video capture for decoding (destination)
+ * this can be set after the header was parsed */
+ } else if (ctx->state == MFCINST_HEAD_PARSED &&
+ vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ mfc_debug(2, "setting for VIDEO capture\n");
+ /* Output plane count is 2 - one for Y and one for CbCr */
+ *plane_count = 2;
+ /* Setup buffer count */
+ if (*buf_count < ctx->dpb_count)
+ *buf_count = ctx->dpb_count;
+ if (*buf_count > ctx->dpb_count + MFC_MAX_EXTRA_DPB)
+ *buf_count = ctx->dpb_count + MFC_MAX_EXTRA_DPB;
+ if (*buf_count > MFC_MAX_BUFFERS)
+ *buf_count = MFC_MAX_BUFFERS;
+ } else {
+ mfc_err("State seems invalid. State = %d, vq->type = %d\n",
+ ctx->state, vq->type);
+ return -EINVAL;
+ }
+ mfc_debug(2, "%s, buffer count=%d, plane count=%d type=0x%x\n", __func__,
+ *buf_count, *plane_count, vq->type);
+
+ if (ctx->state == MFCINST_HEAD_PARSED &&
+ vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ psize[0] = ctx->luma_size;
+ psize[1] = ctx->chroma_size;
+
+ if (ctx->is_drm) {
+ allocators[0] = ctx->dev->alloc_ctx_drm;
+ allocators[1] = ctx->dev->alloc_ctx_drm;
+ } else {
+ if (IS_MFCV6(dev))
+ allocators[0] = alloc_ctx1;
+ else
+ allocators[0] = alloc_ctx2;
+ allocators[1] = alloc_ctx1;
+ }
+ } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE &&
+ ctx->state == MFCINST_GOT_INST) {
+ psize[0] = dec->src_buf_size;
+
+ if (ctx->is_drm)
+ allocators[0] = ctx->dev->alloc_ctx_drm;
+ else
+ allocators[0] = alloc_ctx1;
+
+ } else {
+ mfc_err("Currently only decoding is supported. Decoding not initalised.\n");
+ return -EINVAL;
+ }
+
+ mfc_debug(2, "%s, plane=0, size=%d\n", __func__, psize[0]);
+ mfc_debug(2, "%s, plane=1, size=%d\n", __func__, psize[1]);
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+static void s5p_mfc_unlock(struct vb2_queue *q)
+{
+ struct s5p_mfc_ctx *ctx = q->drv_priv;
+ struct s5p_mfc_dev *dev = ctx->dev;
+
+ mutex_unlock(&dev->mfc_mutex);
+}
+
+static void s5p_mfc_lock(struct vb2_queue *q)
+{
+ struct s5p_mfc_ctx *ctx = q->drv_priv;
+ struct s5p_mfc_dev *dev = ctx->dev;
+
+ mutex_lock(&dev->mfc_mutex);
+}
+
+static int s5p_mfc_buf_init(struct vb2_buffer *vb)
+{
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct s5p_mfc_ctx *ctx = vq->drv_priv;
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+ struct s5p_mfc_buf *buf = vb_to_mfc_buf(vb);
+ int i;
+ unsigned long flags;
+
+ mfc_debug_enter();
+
+ if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ if (ctx->capture_state == QUEUE_BUFS_MMAPED) {
+ mfc_debug_leave();
+ return 0;
+ }
+ for (i = 0; i <= ctx->src_fmt->num_planes ; i++) {
+ if (s5p_mfc_mem_plane_addr(ctx, vb, i) == 0) {
+ mfc_err("Plane mem not allocated.\n");
+ return -EINVAL;
+ }
+ }
+
+ buf->planes.raw.luma = s5p_mfc_mem_plane_addr(ctx, vb, 0);
+ buf->planes.raw.chroma = s5p_mfc_mem_plane_addr(ctx, vb, 1);
+
+ spin_lock_irqsave(&dev->irqlock, flags);
+ list_add_tail(&buf->list, &dec->dpb_queue);
+ dec->dpb_queue_cnt++;
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+
+ if (call_cop(ctx, init_buf_ctrls, ctx, MFC_CTRL_TYPE_DST,
+ vb->v4l2_buf.index) < 0)
+ mfc_err("failed in init_buf_ctrls\n");
+ } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ if (s5p_mfc_mem_plane_addr(ctx, vb, 0) == 0) {
+ mfc_err("Plane memory not allocated.\n");
+ return -EINVAL;
+ }
+ buf->planes.stream = s5p_mfc_mem_plane_addr(ctx, vb, 0);
+
+ if (call_cop(ctx, init_buf_ctrls, ctx, MFC_CTRL_TYPE_SRC,
+ vb->v4l2_buf.index) < 0)
+ mfc_err("failed in init_buf_ctrls\n");
+ } else {
+ mfc_err("s5p_mfc_buf_init: unknown queue type.\n");
+ return -EINVAL;
+ }
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+static int s5p_mfc_buf_prepare(struct vb2_buffer *vb)
+{
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct s5p_mfc_ctx *ctx = vq->drv_priv;
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+ unsigned int index = vb->v4l2_buf.index;
+
+ if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ if (vb2_plane_size(vb, 0) < ctx->luma_size ||
+ vb2_plane_size(vb, 1) < ctx->chroma_size) {
+ mfc_err("Plane buffer (CAPTURE) is too small.\n");
+ return -EINVAL;
+ }
+ mfc_debug(2, "Size: 0=%lu 2=%lu\n", vb2_plane_size(vb, 0),
+ vb2_plane_size(vb, 1));
+ if (ctx->cacheable & MFCMASK_DST_CACHE)
+ s5p_mfc_mem_cache_flush(vb, 2);
+ } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ if (ctx->cacheable & MFCMASK_SRC_CACHE)
+ s5p_mfc_mem_cache_flush(vb, 1);
+ mfc_debug(2, "Plane size: %ld, ctx->dec_src_buf_size: %d\n",
+ vb2_plane_size(vb, 0), dec->src_buf_size);
+ if (vb2_plane_size(vb, 0) < dec->src_buf_size) {
+ mfc_err("Plane buffer (OUTPUT) is too small.\n");
+ return -EINVAL;
+ }
+
+ if (call_cop(ctx, to_buf_ctrls, ctx, &ctx->src_ctrls[index]) < 0)
+ mfc_err("failed in to_buf_ctrls\n");
+ }
+ return 0;
+}
+
+static int s5p_mfc_buf_finish(struct vb2_buffer *vb)
+{
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct s5p_mfc_ctx *ctx = vq->drv_priv;
+ unsigned int index = vb->v4l2_buf.index;
+
+ if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ if (ctx->cacheable & MFCMASK_DST_CACHE)
+ s5p_mfc_mem_cache_flush(vb, 2);
+ if (call_cop(ctx, to_ctx_ctrls, ctx, &ctx->dst_ctrls[index]) < 0)
+ mfc_err("failed in to_ctx_ctrls\n");
+ } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ if (call_cop(ctx, to_ctx_ctrls, ctx, &ctx->src_ctrls[index]) < 0)
+ mfc_err("failed in to_ctx_ctrls\n");
+ }
+
+ return 0;
+}
+
+static void s5p_mfc_buf_cleanup(struct vb2_buffer *vb)
+{
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct s5p_mfc_ctx *ctx = vq->drv_priv;
+ unsigned int index = vb->v4l2_buf.index;
+
+ mfc_debug_enter();
+
+ if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ if (call_cop(ctx, cleanup_buf_ctrls, ctx,
+ MFC_CTRL_TYPE_DST, index) < 0)
+ mfc_err("failed in cleanup_buf_ctrls\n");
+ } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ if (call_cop(ctx, cleanup_buf_ctrls, ctx,
+ MFC_CTRL_TYPE_SRC, index) < 0)
+ mfc_err("failed in cleanup_buf_ctrls\n");
+ } else {
+ mfc_err("s5p_mfc_buf_cleanup: unknown queue type.\n");
+ }
+
+ mfc_debug_leave();
+}
+
+static int s5p_mfc_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+ struct s5p_mfc_ctx *ctx = q->drv_priv;
+ struct s5p_mfc_dev *dev = ctx->dev;
+ unsigned long flags;
+
+ if (ctx->state == MFCINST_FINISHING || ctx->state == MFCINST_FINISHED)
+ ctx->state = MFCINST_RUNNING;
+
+ /* If context is ready then dev = work->data;schedule it to run */
+ if (s5p_mfc_dec_ctx_ready(ctx)) {
+ spin_lock_irqsave(&dev->condlock, flags);
+ set_bit(ctx->num, &dev->ctx_work_bits);
+ spin_unlock_irqrestore(&dev->condlock, flags);
+ }
+
+ s5p_mfc_try_run(dev);
+
+ return 0;
+}
+
+static int s5p_mfc_stop_streaming(struct vb2_queue *q)
+{
+ unsigned long flags;
+ struct s5p_mfc_ctx *ctx = q->drv_priv;
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+ struct s5p_mfc_dev *dev = ctx->dev;
+ int aborted = 0;
+ int index = 0;
+
+ if ((ctx->state == MFCINST_FINISHING ||
+ ctx->state == MFCINST_RUNNING) &&
+ test_bit(ctx->num, &dev->hw_lock)) {
+ ctx->state = MFCINST_ABORT;
+ s5p_mfc_wait_for_done_ctx(ctx, S5P_FIMV_R2H_CMD_FRAME_DONE_RET);
+ aborted = 1;
+ }
+
+ spin_lock_irqsave(&dev->irqlock, flags);
+
+ if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst);
+ INIT_LIST_HEAD(&ctx->dst_queue);
+ ctx->dst_queue_cnt = 0;
+ dec->dpb_flush = 1;
+ dec->dpb_status = 0;
+
+ INIT_LIST_HEAD(&dec->dpb_queue);
+ dec->dpb_queue_cnt = 0;
+
+ while (index < MFC_MAX_BUFFERS) {
+ index = find_next_bit(&ctx->dst_ctrls_avail,
+ MFC_MAX_BUFFERS, index);
+ if (index < MFC_MAX_BUFFERS)
+ __dec_reset_buf_ctrls(&ctx->dst_ctrls[index]);
+ index++;
+ }
+ } else if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src);
+ INIT_LIST_HEAD(&ctx->src_queue);
+ ctx->src_queue_cnt = 0;
+
+ while (index < MFC_MAX_BUFFERS) {
+ index = find_next_bit(&ctx->src_ctrls_avail,
+ MFC_MAX_BUFFERS, index);
+ if (index < MFC_MAX_BUFFERS)
+ __dec_reset_buf_ctrls(&ctx->src_ctrls[index]);
+ index++;
+ }
+ }
+
+ if (aborted)
+ ctx->state = MFCINST_RUNNING;
+
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+
+ return 0;
+}
+
+
+static void s5p_mfc_buf_queue(struct vb2_buffer *vb)
+{
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct s5p_mfc_ctx *ctx = vq->drv_priv;
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+ unsigned long flags;
+ struct s5p_mfc_buf *buf = vb_to_mfc_buf(vb);
+ struct s5p_mfc_buf *dpb_buf, *tmp_buf;
+ int wait_flag = 0;
+ int remove_flag = 0;
+
+ mfc_debug_enter();
+
+ if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ buf->used = 0;
+ mfc_debug(2, "Src queue: %p\n", &ctx->src_queue);
+ mfc_debug(2, "Adding to src: %p (0x%08lx, 0x%08lx)\n", vb,
+ (unsigned long)s5p_mfc_mem_plane_addr(ctx, vb, 0),
+ (unsigned long)buf->planes.stream);
+ spin_lock_irqsave(&dev->irqlock, flags);
+ list_add_tail(&buf->list, &ctx->src_queue);
+ ctx->src_queue_cnt++;
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+ } else if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ buf->used = 0;
+ mfc_debug(2, "Dst queue: %p\n", &ctx->dst_queue);
+ mfc_debug(2, "Adding to dst: %p (0x%08lx)\n", vb,
+ (unsigned long)s5p_mfc_mem_plane_addr(ctx, vb, 0));
+ mfc_debug(2, "ADDING Flag before: %lx (%d)\n",
+ dec->dpb_status, vb->v4l2_buf.index);
+ /* Mark destination as available for use by MFC */
+ spin_lock_irqsave(&dev->irqlock, flags);
+ if (!list_empty(&dec->dpb_queue)) {
+ remove_flag = 0;
+ list_for_each_entry_safe(dpb_buf, tmp_buf, &dec->dpb_queue, list) {
+ if (dpb_buf == buf) {
+ list_del(&dpb_buf->list);
+ remove_flag = 1;
+ break;
+ }
+ }
+ if (remove_flag == 0) {
+ mfc_err("Can't find buf(0x%08lx)\n",
+ (unsigned long)buf->planes.raw.luma);
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+ return;
+ }
+ }
+ set_bit(vb->v4l2_buf.index, &dec->dpb_status);
+ mfc_debug(2, "ADDING Flag after: %lx\n", dec->dpb_status);
+ list_add_tail(&buf->list, &ctx->dst_queue);
+ ctx->dst_queue_cnt++;
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+ if ((dec->dst_memtype == V4L2_MEMORY_USERPTR || dec->dst_memtype == V4L2_MEMORY_DMABUF) &&
+ ctx->dst_queue_cnt == dec->total_dpb_count)
+ ctx->capture_state = QUEUE_BUFS_MMAPED;
+ } else {
+ mfc_err("Unsupported buffer type (%d)\n", vq->type);
+ }
+
+ if (s5p_mfc_dec_ctx_ready(ctx)) {
+ spin_lock_irqsave(&dev->condlock, flags);
+ set_bit(ctx->num, &dev->ctx_work_bits);
+ spin_unlock_irqrestore(&dev->condlock, flags);
+ if (ctx->state == MFCINST_HEAD_PARSED)
+ wait_flag = 1;
+ }
+ s5p_mfc_try_run(dev);
+ if (wait_flag) {
+ s5p_mfc_wait_for_done_ctx(ctx,
+ S5P_FIMV_R2H_CMD_INIT_BUFFERS_RET);
+ }
+
+ mfc_debug_leave();
+}
+
+static struct vb2_ops s5p_mfc_dec_qops = {
+ .queue_setup = s5p_mfc_queue_setup,
+ .wait_prepare = s5p_mfc_unlock,
+ .wait_finish = s5p_mfc_lock,
+ .buf_init = s5p_mfc_buf_init,
+ .buf_prepare = s5p_mfc_buf_prepare,
+ .buf_finish = s5p_mfc_buf_finish,
+ .buf_cleanup = s5p_mfc_buf_cleanup,
+ .start_streaming = s5p_mfc_start_streaming,
+ .stop_streaming = s5p_mfc_stop_streaming,
+ .buf_queue = s5p_mfc_buf_queue,
+};
+
+const struct v4l2_ioctl_ops *get_dec_v4l2_ioctl_ops(void)
+{
+ return &s5p_mfc_dec_ioctl_ops;
+}
+
+int s5p_mfc_init_dec_ctx(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dec *dec;
+ int ret = 0;
+ int i;
+
+ dec = kzalloc(sizeof(struct s5p_mfc_dec), GFP_KERNEL);
+ if (!dec) {
+ mfc_err("failed to allocate decoder private data\n");
+ return -ENOMEM;
+ }
+ ctx->dec_priv = dec;
+
+ ctx->inst_no = MFC_NO_INSTANCE_SET;
+
+ INIT_LIST_HEAD(&ctx->src_queue);
+ INIT_LIST_HEAD(&ctx->dst_queue);
+ ctx->src_queue_cnt = 0;
+ ctx->dst_queue_cnt = 0;
+
+ for (i = 0; i < MFC_MAX_BUFFERS; i++) {
+ INIT_LIST_HEAD(&ctx->src_ctrls[i]);
+ INIT_LIST_HEAD(&ctx->dst_ctrls[i]);
+ }
+ ctx->src_ctrls_avail = 0;
+ ctx->dst_ctrls_avail = 0;
+
+ ctx->capture_state = QUEUE_FREE;
+ ctx->output_state = QUEUE_FREE;
+
+ ctx->state = MFCINST_INIT;
+ ctx->type = MFCINST_DECODER;
+ ctx->c_ops = &decoder_codec_ops;
+ ctx->src_fmt = &formats[DEF_SRC_FMT];
+ ctx->dst_fmt = &formats[DEF_DST_FMT];
+
+ INIT_LIST_HEAD(&dec->dpb_queue);
+ dec->dpb_queue_cnt = 0;
+
+ dec->display_delay = -1;
+ dec->is_packedpb = 0;
+
+ /* Init videobuf2 queue for OUTPUT */
+ ctx->vq_src.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ ctx->vq_src.drv_priv = ctx;
+ ctx->vq_src.buf_struct_size = sizeof(struct s5p_mfc_buf);
+ ctx->vq_src.io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
+ ctx->vq_src.ops = &s5p_mfc_dec_qops;
+ ctx->vq_src.mem_ops = s5p_mfc_mem_ops();
+ ret = vb2_queue_init(&ctx->vq_src);
+ if (ret) {
+ mfc_err("Failed to initialize videobuf2 queue(output)\n");
+ return ret;
+ }
+ /* Init videobuf2 queue for CAPTURE */
+ ctx->vq_dst.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ ctx->vq_dst.drv_priv = ctx;
+ ctx->vq_dst.buf_struct_size = sizeof(struct s5p_mfc_buf);
+ ctx->vq_dst.io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
+ ctx->vq_dst.ops = &s5p_mfc_dec_qops;
+ ctx->vq_dst.mem_ops = s5p_mfc_mem_ops();
+ ret = vb2_queue_init(&ctx->vq_dst);
+ if (ret) {
+ mfc_err("Failed to initialize videobuf2 queue(capture)\n");
+ return ret;
+ }
+
+ /* For MFC 6.x */
+ dec->remained = 0;
+
+ return ret;
+}
diff --git a/drivers/media/video/exynos/mfc/s5p_mfc_dec.h b/drivers/media/video/exynos/mfc/s5p_mfc_dec.h
new file mode 100644
index 0000000..00f35d3
--- /dev/null
+++ b/drivers/media/video/exynos/mfc/s5p_mfc_dec.h
@@ -0,0 +1,23 @@
+/*
+ * linux/drivers/media/video/exynos/mfc/s5p_mfc_dec.h
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * 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.
+ */
+
+#ifndef __S5P_MFC_DEC_H_
+#define __S5P_MFC_DEC_H_ __FILE__
+
+#define MAX_FRAME_SIZE (2*1024*1024)
+#define DEFAULT_TAG (-1)
+
+const struct v4l2_ioctl_ops *get_dec_v4l2_ioctl_ops(void);
+int s5p_mfc_init_dec_ctx(struct s5p_mfc_ctx *ctx);
+int s5p_mfc_dec_ctx_ready(struct s5p_mfc_ctx *ctx);
+
+#endif /* __S5P_MFC_DEC_H_ */
diff --git a/drivers/media/video/exynos/mfc/s5p_mfc_enc.c b/drivers/media/video/exynos/mfc/s5p_mfc_enc.c
new file mode 100644
index 0000000..c2fc812
--- /dev/null
+++ b/drivers/media/video/exynos/mfc/s5p_mfc_enc.c
@@ -0,0 +1,3287 @@
+/*
+ * linux/drivers/media/video/exynos/mfc/s5p_mfc_enc.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * 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.
+ */
+
+#include <linux/io.h>
+#include <linux/sched.h>
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/version.h>
+#include <linux/workqueue.h>
+#include <linux/videodev2.h>
+#include <linux/videodev2_exynos_media.h>
+#include <media/videobuf2-core.h>
+
+#include "s5p_mfc_common.h"
+
+#include "s5p_mfc_intr.h"
+#include "s5p_mfc_mem.h"
+#include "s5p_mfc_debug.h"
+#include "s5p_mfc_reg.h"
+#include "s5p_mfc_enc.h"
+#include "s5p_mfc_pm.h"
+
+#define DEF_SRC_FMT 1
+#define DEF_DST_FMT 2
+
+static struct s5p_mfc_fmt formats[] = {
+ {
+ .name = "4:2:0 2 Planes 16x16 Tiles",
+ .fourcc = V4L2_PIX_FMT_NV12MT_16X16,
+ .codec_mode = MFC_FORMATS_NO_CODEC,
+ .type = MFC_FMT_RAW,
+ .num_planes = 2,
+ },
+ {
+ .name = "4:2:0 2 Planes 64x32 Tiles",
+ .fourcc = V4L2_PIX_FMT_NV12MT,
+ .codec_mode = MFC_FORMATS_NO_CODEC,
+ .type = MFC_FMT_RAW,
+ .num_planes = 2,
+ },
+ {
+ .name = "4:2:0 2 Planes",
+ .fourcc = V4L2_PIX_FMT_NV12M,
+ .codec_mode = MFC_FORMATS_NO_CODEC,
+ .type = MFC_FMT_RAW,
+ .num_planes = 2,
+ },
+ {
+ .name = "4:2:0 2 Planes Y/CrCb",
+ .fourcc = V4L2_PIX_FMT_NV21M,
+ .codec_mode = MFC_FORMATS_NO_CODEC,
+ .type = MFC_FMT_RAW,
+ .num_planes = 2,
+ },
+ {
+ .name = "H264 Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_H264,
+ .codec_mode = S5P_FIMV_CODEC_H264_ENC,
+ .type = MFC_FMT_ENC,
+ .num_planes = 1,
+ },
+ {
+ .name = "MPEG4 Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_MPEG4,
+ .codec_mode = S5P_FIMV_CODEC_MPEG4_ENC,
+ .type = MFC_FMT_ENC,
+ .num_planes = 1,
+ },
+ {
+ .name = "H263 Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_H263,
+ .codec_mode = S5P_FIMV_CODEC_H263_ENC,
+ .type = MFC_FMT_ENC,
+ .num_planes = 1,
+ },
+};
+
+#define NUM_FORMATS ARRAY_SIZE(formats)
+
+static struct s5p_mfc_fmt *find_format(struct v4l2_format *f, unsigned int t)
+{
+ unsigned int i;
+
+ for (i = 0; i < NUM_FORMATS; i++) {
+ if (formats[i].fourcc == f->fmt.pix_mp.pixelformat &&
+ formats[i].type == t)
+ return (struct s5p_mfc_fmt *)&formats[i];
+ }
+
+ return NULL;
+}
+
+static struct v4l2_queryctrl controls[] = {
+ {
+ .id = V4L2_CID_CACHEABLE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Cacheable flag",
+ .minimum = 0,
+ .maximum = 3,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_GOP_SIZE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "The period of intra frame",
+ .minimum = 0,
+ .maximum = (1 << 16) - 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "The slice partitioning method",
+ .minimum = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE,
+ .maximum = V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES,
+ .step = 1,
+ .default_value = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "The number of MB in a slice",
+ .minimum = 1,
+ .maximum = ENC_MULTI_SLICE_MB_MAX,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "The maximum bits per slices",
+ .minimum = ENC_MULTI_SLICE_BYTE_MIN,
+ .maximum = (1 << 30) - 1,
+ .step = 1,
+ .default_value = ENC_MULTI_SLICE_BYTE_MIN,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "The number of intra refresh MBs",
+ .minimum = 0,
+ .maximum = ENC_INTRA_REFRESH_MB_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_PADDING,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Padding control enable",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_PADDING_YUV,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Padding Color YUV Value",
+ .minimum = 0,
+ .maximum = (1 << 25) - 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Frame level rate control enable",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_BITRATE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Target bit rate rate-control",
+ .minimum = 1,
+ .maximum = (1 << 30) - 1,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Rate control reaction coeff.",
+ .minimum = 1,
+ .maximum = (1 << 16) - 1,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_STREAM_SIZE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Encoded stream size",
+ .minimum = 0,
+ .maximum = (1 << 30) - 1,
+ .step = 1,
+ .default_value = 0,
+ .flags = V4L2_CTRL_FLAG_READ_ONLY,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_FRAME_COUNT,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Encoded frame count",
+ .minimum = 0,
+ .maximum = (1 << 30) - 1,
+ .step = 1,
+ .default_value = 0,
+ .flags = V4L2_CTRL_FLAG_READ_ONLY,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TYPE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Encoded frame type",
+ .minimum = 0,
+ .maximum = 5,
+ .step = 1,
+ .default_value = 0,
+ .flags = V4L2_CTRL_FLAG_READ_ONLY,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Force frame type",
+ .minimum = V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_DISABLED,
+ .maximum = V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_NOT_CODED,
+ .step = 1,
+ .default_value = \
+ V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_DISABLED,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_VBV_SIZE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "VBV buffer size (1Kbits)",
+ .minimum = 0,
+ .maximum = ENC_VBV_BUF_SIZE_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_HEADER_MODE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Sequence header mode",
+ .minimum = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE,
+ .maximum = V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME,
+ .step = 1,
+ .default_value = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Frame skip enable",
+ .minimum = V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_DISABLED,
+ .maximum = V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT,
+ .step = 1,
+ .default_value = V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_DISABLED,
+ },
+ { /* MFC5.x Only */
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Fixed target bit enable",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ { /* MFC6.x Only for H.264 & H.263 */
+ .id = V4L2_CID_MPEG_MFC6X_VIDEO_FRAME_DELTA,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "MPEG4 frame delta",
+ .minimum = 1,
+ .maximum = (1 << 16) - 1,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_B_FRAMES,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "The number of B frames",
+ .minimum = 0,
+ .maximum = 2,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_PROFILE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "H264 profile",
+ .minimum = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE,
+ .maximum = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH,
+ .step = 1,
+ .default_value = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_LEVEL,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "H264 level",
+ .minimum = V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
+ .maximum = V4L2_MPEG_VIDEO_H264_LEVEL_4_2,
+ .step = 1,
+ .default_value = V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_H264_INTERLACE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "H264 interlace mode",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "H264 loop filter mode",
+ .minimum = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED,
+ .maximum = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_S_B,
+ .step = 1,
+ .default_value = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "H264 loop filter alpha offset",
+ .minimum = ENC_H264_LOOP_FILTER_AB_MIN,
+ .maximum = ENC_H264_LOOP_FILTER_AB_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "H264 loop filter beta offset",
+ .minimum = ENC_H264_LOOP_FILTER_AB_MIN,
+ .maximum = ENC_H264_LOOP_FILTER_AB_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "H264 entorpy mode",
+ .minimum = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC,
+ .maximum = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC,
+ .step = 1,
+ .default_value = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_H264_NUM_REF_PIC_FOR_P,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "The number of ref. picture of P",
+ .minimum = 1,
+ .maximum = 2,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "H264 8x8 transform enable",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "MB level rate control",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_H264_RC_FRAME_RATE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "H264 Frame rate",
+ .minimum = 1,
+ .maximum = ENC_H264_RC_FRAME_RATE_MAX,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "H264 Frame QP value",
+ .minimum = 0,
+ .maximum = 51,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_MIN_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "H264 Minimum QP value",
+ .minimum = 0,
+ .maximum = 51,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ /* MAX_QP must be greater than or equal to MIN_QP */
+ .id = V4L2_CID_MPEG_VIDEO_H264_MAX_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "H264 Maximum QP value",
+ .minimum = 0,
+ .maximum = 51,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_DARK,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "H264 dark region adaptive",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_SMOOTH,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "H264 smooth region adaptive",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_STATIC,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "H264 static region adaptive",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_ACTIVITY,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "H264 MB activity adaptive",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "H264 P frame QP value",
+ .minimum = 0,
+ .maximum = 51,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "H264 B frame QP value",
+ .minimum = 0,
+ .maximum = 51,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Aspect ratio VUI enable",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "VUI aspect ratio IDC",
+ .minimum = V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_UNSPECIFIED,
+ .maximum = V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Horizontal size of SAR",
+ .minimum = 0,
+ .maximum = (1 << 16) - 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Vertical size of SAR",
+ .minimum = 0,
+ .maximum = (1 << 16) - 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_GOP_CLOSURE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "GOP closure",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_I_PERIOD,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "H264 I period",
+ .minimum = 0,
+ .maximum = (1 << 16) - 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Hierarchical Coding",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hierarchical Coding Type",
+ .minimum = V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_B,
+ .maximum = V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P,
+ .step = 1,
+ .default_value = V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_B,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hierarchical Coding Layer",
+ .minimum = 0,
+ .maximum = 7,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hierarchical Coding Layer QP",
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_SEI_FRAME_PACKING,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "frame pack sei generation flag",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_SEI_FP_CURRENT_FRAME_0,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Current frame is frame 0 flag",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Frame packing arrangement type",
+ .minimum = V4L2_MPEG_VIDEO_H264_SEI_FP_TYPE_SIDE_BY_SIDE,
+ .maximum = V4L2_MPEG_VIDEO_H264_SEI_FP_TYPE_TEMPORAL,
+ .step = 1,
+ .default_value = V4L2_MPEG_VIDEO_H264_SEI_FP_TYPE_SIDE_BY_SIDE,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_FMO,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Flexible Macroblock Order",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_FMO_MAP_TYPE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Map type for FMO",
+ .minimum = V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_INTERLEAVED_SLICES,
+ .maximum = V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_WIPE_SCAN,
+ .step = 1,
+ .default_value = \
+ V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_INTERLEAVED_SLICES,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_FMO_SLICE_GROUP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Number of slice groups for FMO",
+ .minimum = 1,
+ .maximum = 4,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_FMO_RUN_LENGTH,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "FMO Run Length",
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_DIRECTION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Direction of the slice group",
+ .minimum = V4L2_MPEG_VIDEO_H264_FMO_CHANGE_DIR_RIGHT,
+ .maximum = V4L2_MPEG_VIDEO_H264_FMO_CHANGE_DIR_LEFT,
+ .step = 1,
+ .default_value = V4L2_MPEG_VIDEO_H264_FMO_CHANGE_DIR_RIGHT,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_RATE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Size of the first slice group",
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_ASO,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Arbitrary Slice Order",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H264_ASO_SLICE_ORDER,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "ASO Slice order",
+ .minimum = INT_MIN,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "MPEG4 profile",
+ .minimum = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE,
+ .maximum = V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE,
+ .step = 1,
+ .default_value = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "MPEG4 level",
+ .minimum = V4L2_MPEG_VIDEO_MPEG4_LEVEL_0,
+ .maximum = V4L2_MPEG_VIDEO_MPEG4_LEVEL_6,
+ .step = 1,
+ .default_value = V4L2_MPEG_VIDEO_MPEG4_LEVEL_0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "MPEG4 Frame QP value",
+ .minimum = 1,
+ .maximum = 31,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "MPEG4 Minimum QP value",
+ .minimum = 1,
+ .maximum = 31,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "MPEG4 Maximum QP value",
+ .minimum = 1,
+ .maximum = 31,
+ .step = 1,
+ .default_value = 1,
+ },
+ { /* MFC5.x Only */
+ .id = V4L2_CID_MPEG_VIDEO_MPEG4_QPEL,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Quarter pixel search enable",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "MPEG4 P frame QP value",
+ .minimum = 1,
+ .maximum = 31,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "MPEG4 B frame QP value",
+ .minimum = 1,
+ .maximum = 31,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_MPEG4_VOP_TIME_RES,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "MPEG4 vop time resolution",
+ .minimum = 0,
+ .maximum = ENC_MPEG4_VOP_TIME_RES_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_MPEG4_VOP_FRM_DELTA,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "MPEG4 frame delta",
+ .minimum = 1,
+ .maximum = (1 << 16) - 1,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_H263_RC_FRAME_RATE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "H263 Frame rate",
+ .minimum = 1,
+ .maximum = ENC_H263_RC_FRAME_RATE_MAX,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "H263 Frame QP value",
+ .minimum = 1,
+ .maximum = 31,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H263_MIN_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "H263 Minimum QP value",
+ .minimum = 1,
+ .maximum = 31,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H263_MAX_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "H263 Maximum QP value",
+ .minimum = 1,
+ .maximum = 31,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "H263 P frame QP value",
+ .minimum = 1,
+ .maximum = 31,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Frame Tag",
+ .minimum = 0,
+ .maximum = INT_MAX,
+ .step = 1,
+ .default_value = 0,
+ },
+};
+
+#define NUM_CTRLS ARRAY_SIZE(controls)
+
+static struct v4l2_queryctrl *get_ctrl(int id)
+{
+ int i;
+
+ for (i = 0; i < NUM_CTRLS; ++i)
+ if (id == controls[i].id)
+ return &controls[i];
+ return NULL;
+}
+
+static int check_ctrl_val(struct s5p_mfc_ctx *ctx, struct v4l2_control *ctrl)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct v4l2_queryctrl *c;
+
+ c = get_ctrl(ctrl->id);
+ if (!c)
+ return -EINVAL;
+ if (ctrl->value < c->minimum || ctrl->value > c->maximum
+ || (c->step != 0 && ctrl->value % c->step != 0)) {
+ v4l2_err(&dev->v4l2_dev, "Invalid control value\n");
+ return -ERANGE;
+ }
+ return 0;
+}
+
+static struct s5p_mfc_ctrl_cfg mfc_ctrl_list[] = {
+ { /* set frame tag */
+ .type = MFC_CTRL_TYPE_SET,
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_CUSTOM,
+ .addr = S5P_FIMV_SHARED_SET_E_FRAME_TAG,
+ .mask = 0xFFFFFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ { /* get frame tag */
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_CUSTOM,
+ .addr = S5P_FIMV_SHARED_GET_E_FRAME_TAG,
+ .mask = 0xFFFFFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ { /* encoded y physical addr */
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_LUMA_ADDR,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_ENCODED_LUMA_ADDR,
+ .mask = 0xFFFFFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ { /* encoded c physical addr */
+ .type = MFC_CTRL_TYPE_GET_DST,
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_CHROMA_ADDR,
+ .is_volatile = 0,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_ENCODED_CHROMA_ADDR,
+ .mask = 0xFFFFFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ { /* I, not coded frame insertion */
+ .type = MFC_CTRL_TYPE_SET,
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_SFR,
+ .addr = S5P_FIMV_FRAME_INSERTION,
+ .mask = 0x3,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_NONE,
+ .flag_addr = 0,
+ .flag_shft = 0,
+ },
+ { /* I period change */
+ .type = MFC_CTRL_TYPE_SET,
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_I_PERIOD_CH,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_CUSTOM,
+ .addr = S5P_FIMV_NEW_I_PERIOD,
+ .mask = 0xFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_CUSTOM,
+ .flag_addr = S5P_FIMV_PARAM_CHANGE_FLAG,
+ .flag_shft = 0,
+ },
+ { /* frame rate change */
+ .type = MFC_CTRL_TYPE_SET,
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_FRAME_RATE_CH,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_CUSTOM,
+ .addr = S5P_FIMV_NEW_RC_FRAME_RATE,
+ .mask = 0xFFFF,
+ .shft = 16,
+ .flag_mode = MFC_CTRL_MODE_CUSTOM,
+ .flag_addr = S5P_FIMV_PARAM_CHANGE_FLAG,
+ .flag_shft = 1,
+ },
+ { /* bit rate change */
+ .type = MFC_CTRL_TYPE_SET,
+ .id = V4L2_CID_MPEG_MFC51_VIDEO_BIT_RATE_CH,
+ .is_volatile = 1,
+ .mode = MFC_CTRL_MODE_CUSTOM,
+ .addr = S5P_FIMV_NEW_RC_BIT_RATE,
+ .mask = 0xFFFFFFFF,
+ .shft = 0,
+ .flag_mode = MFC_CTRL_MODE_CUSTOM,
+ .flag_addr = S5P_FIMV_PARAM_CHANGE_FLAG,
+ .flag_shft = 2,
+ },
+};
+
+#define NUM_CTRL_CFGS ARRAY_SIZE(mfc_ctrl_list)
+
+int s5p_mfc_enc_ctx_ready(struct s5p_mfc_ctx *ctx)
+{
+ mfc_debug(2, "src=%d, dst=%d, state=%d\n",
+ ctx->src_queue_cnt, ctx->dst_queue_cnt, ctx->state);
+
+ /* context is ready to make header */
+ if (ctx->state == MFCINST_GOT_INST && ctx->dst_queue_cnt >= 1)
+ return 1;
+ /* context is ready to allocate DPB */
+ if (ctx->dst_queue_cnt >= 1 && ctx->state == MFCINST_HEAD_PARSED)
+ return 1;
+ /* context is ready to encode a frame */
+ if (ctx->state == MFCINST_RUNNING &&
+ ctx->src_queue_cnt >= 1 && ctx->dst_queue_cnt >= 1)
+ return 1;
+ /* context is ready to encode a frame in case of B frame */
+ if (ctx->state == MFCINST_RUNNING_NO_OUTPUT &&
+ ctx->src_queue_cnt >= 1 && ctx->dst_queue_cnt >= 1)
+ return 1;
+ /* context is ready to encode remain frames */
+ if (ctx->state == MFCINST_FINISHING &&
+ ctx->src_queue_cnt >= 1 && ctx->dst_queue_cnt >= 1)
+ return 1;
+
+ mfc_debug(2, "ctx is not ready.\n");
+
+ return 0;
+}
+
+static int enc_cleanup_ctx_ctrls(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_ctx_ctrl *ctx_ctrl;
+
+ while (!list_empty(&ctx->ctrls)) {
+ ctx_ctrl = list_entry((&ctx->ctrls)->next,
+ struct s5p_mfc_ctx_ctrl, list);
+
+ mfc_debug(7, "Cleanup context control "\
+ "id: 0x%08x, type: %d\n",
+ ctx_ctrl->id, ctx_ctrl->type);
+
+ list_del(&ctx_ctrl->list);
+ kfree(ctx_ctrl);
+ }
+
+ INIT_LIST_HEAD(&ctx->ctrls);
+
+ return 0;
+}
+
+static int enc_init_ctx_ctrls(struct s5p_mfc_ctx *ctx)
+{
+ int i;
+ struct s5p_mfc_ctx_ctrl *ctx_ctrl;
+
+ INIT_LIST_HEAD(&ctx->ctrls);
+
+ for (i = 0; i < NUM_CTRL_CFGS; i++) {
+ ctx_ctrl = kzalloc(sizeof(struct s5p_mfc_ctx_ctrl), GFP_KERNEL);
+ if (ctx_ctrl == NULL) {
+ mfc_err("Failed to allocate context control "\
+ "id: 0x%08x, type: %d\n",
+ mfc_ctrl_list[i].id,
+ mfc_ctrl_list[i].type);
+
+ enc_cleanup_ctx_ctrls(ctx);
+
+ return -ENOMEM;
+ }
+
+ ctx_ctrl->type = mfc_ctrl_list[i].type;
+ ctx_ctrl->id = mfc_ctrl_list[i].id;
+ ctx_ctrl->has_new = 0;
+ ctx_ctrl->val = 0;
+
+ list_add_tail(&ctx_ctrl->list, &ctx->ctrls);
+
+ mfc_debug(7, "Add context control id: 0x%08x, type : %d\n",
+ ctx_ctrl->id, ctx_ctrl->type);
+ }
+
+ return 0;
+}
+
+static void __enc_reset_buf_ctrls(struct list_head *head)
+{
+ struct s5p_mfc_buf_ctrl *buf_ctrl;
+
+ list_for_each_entry(buf_ctrl, head, list) {
+ mfc_debug(8, "Reset buffer control value "\
+ "id: 0x%08x, type: %d\n",
+ buf_ctrl->id, buf_ctrl->type);
+
+ buf_ctrl->has_new = 0;
+ buf_ctrl->val = 0;
+ buf_ctrl->old_val = 0;
+ buf_ctrl->updated = 0;
+ }
+}
+
+static void __enc_cleanup_buf_ctrls(struct list_head *head)
+{
+ struct s5p_mfc_buf_ctrl *buf_ctrl;
+
+ while (!list_empty(head)) {
+ buf_ctrl = list_entry(head->next,
+ struct s5p_mfc_buf_ctrl, list);
+
+ mfc_debug(7, "Cleanup buffer control "\
+ "id: 0x%08x, type: %d\n",
+ buf_ctrl->id, buf_ctrl->type);
+
+ list_del(&buf_ctrl->list);
+ kfree(buf_ctrl);
+ }
+
+ INIT_LIST_HEAD(head);
+}
+
+static int enc_init_buf_ctrls(struct s5p_mfc_ctx *ctx,
+ enum s5p_mfc_ctrl_type type, unsigned int index)
+{
+ int i;
+ struct s5p_mfc_buf_ctrl *buf_ctrl;
+ struct list_head *head;
+
+ if (index >= MFC_MAX_BUFFERS) {
+ mfc_err("Per-buffer control index is out of range\n");
+ return -EINVAL;
+ }
+
+ if (type & MFC_CTRL_TYPE_SRC) {
+ if (test_bit(index, &ctx->src_ctrls_avail)) {
+ mfc_debug(7, "Source per-buffer control is already "\
+ "initialized [%d]\n", index);
+
+ __enc_reset_buf_ctrls(&ctx->src_ctrls[index]);
+
+ return 0;
+ }
+
+ head = &ctx->src_ctrls[index];
+ } else if (type & MFC_CTRL_TYPE_DST) {
+ if (test_bit(index, &ctx->dst_ctrls_avail)) {
+ mfc_debug(7, "Dest. per-buffer control is already "\
+ "initialized [%d]\n", index);
+
+ __enc_reset_buf_ctrls(&ctx->dst_ctrls[index]);
+
+ return 0;
+ }
+
+ head = &ctx->dst_ctrls[index];
+ } else {
+ mfc_err("Control type mismatch. type : %d\n", type);
+ return -EINVAL;
+ }
+
+ INIT_LIST_HEAD(head);
+
+ for (i = 0; i < NUM_CTRL_CFGS; i++) {
+ if (!(type & mfc_ctrl_list[i].type))
+ continue;
+
+ buf_ctrl = kzalloc(sizeof(struct s5p_mfc_buf_ctrl), GFP_KERNEL);
+ if (buf_ctrl == NULL) {
+ mfc_err("Failed to allocate buffer control "\
+ "id: 0x%08x, type: %d\n",
+ mfc_ctrl_list[i].id,
+ mfc_ctrl_list[i].type);
+
+ __enc_cleanup_buf_ctrls(head);
+
+ return -ENOMEM;
+ }
+
+ buf_ctrl->type = mfc_ctrl_list[i].type;
+ buf_ctrl->id = mfc_ctrl_list[i].id;
+ buf_ctrl->is_volatile = mfc_ctrl_list[i].is_volatile;
+ buf_ctrl->mode = mfc_ctrl_list[i].mode;
+ buf_ctrl->addr = mfc_ctrl_list[i].addr;
+ buf_ctrl->mask = mfc_ctrl_list[i].mask;
+ buf_ctrl->shft = mfc_ctrl_list[i].shft;
+ buf_ctrl->flag_mode = mfc_ctrl_list[i].flag_mode;
+ buf_ctrl->flag_addr = mfc_ctrl_list[i].flag_addr;
+ buf_ctrl->flag_shft = mfc_ctrl_list[i].flag_shft;
+
+ list_add_tail(&buf_ctrl->list, head);
+
+ mfc_debug(7, "Add buffer control id: 0x%08x, type : %d\n",
+ buf_ctrl->id, buf_ctrl->type);
+ }
+
+ __enc_reset_buf_ctrls(head);
+
+ if (type & MFC_CTRL_TYPE_SRC)
+ set_bit(index, &ctx->src_ctrls_avail);
+ else
+ set_bit(index, &ctx->dst_ctrls_avail);
+
+ return 0;
+}
+
+static int enc_cleanup_buf_ctrls(struct s5p_mfc_ctx *ctx,
+ enum s5p_mfc_ctrl_type type, unsigned int index)
+{
+ struct list_head *head;
+
+ if (index >= MFC_MAX_BUFFERS) {
+ mfc_err("Per-buffer control index is out of range\n");
+ return -EINVAL;
+ }
+
+ if (type & MFC_CTRL_TYPE_SRC) {
+ if (!(test_and_clear_bit(index, &ctx->src_ctrls_avail))) {
+ mfc_debug(7, "Source per-buffer control is "\
+ "not available [%d]\n", index);
+ return 0;
+ }
+
+ head = &ctx->src_ctrls[index];
+ } else if (type & MFC_CTRL_TYPE_DST) {
+ if (!(test_and_clear_bit(index, &ctx->dst_ctrls_avail))) {
+ mfc_debug(7, "Dest. per-buffer Control is "\
+ "not available [%d]\n", index);
+ return 0;
+ }
+
+ head = &ctx->dst_ctrls[index];
+ } else {
+ mfc_err("Control type mismatch. type : %d\n", type);
+ return -EINVAL;
+ }
+
+ __enc_cleanup_buf_ctrls(head);
+
+ return 0;
+}
+
+static int enc_to_buf_ctrls(struct s5p_mfc_ctx *ctx, struct list_head *head)
+{
+ struct s5p_mfc_ctx_ctrl *ctx_ctrl;
+ struct s5p_mfc_buf_ctrl *buf_ctrl;
+
+ list_for_each_entry(ctx_ctrl, &ctx->ctrls, list) {
+ if (!(ctx_ctrl->type & MFC_CTRL_TYPE_SET) || !ctx_ctrl->has_new)
+ continue;
+
+ list_for_each_entry(buf_ctrl, head, list) {
+ if (!(buf_ctrl->type & MFC_CTRL_TYPE_SET))
+ continue;
+
+ if (buf_ctrl->id == ctx_ctrl->id) {
+ buf_ctrl->has_new = 1;
+ buf_ctrl->val = ctx_ctrl->val;
+ if (buf_ctrl->is_volatile)
+ buf_ctrl->updated = 0;
+
+ ctx_ctrl->has_new = 0;
+ break;
+ }
+ }
+ }
+
+ list_for_each_entry(buf_ctrl, head, list) {
+ if (buf_ctrl->has_new)
+ mfc_debug(8, "Updated buffer control "\
+ "id: 0x%08x val: %d\n",
+ buf_ctrl->id, buf_ctrl->val);
+ }
+
+ return 0;
+}
+
+static int enc_to_ctx_ctrls(struct s5p_mfc_ctx *ctx, struct list_head *head)
+{
+ struct s5p_mfc_ctx_ctrl *ctx_ctrl;
+ struct s5p_mfc_buf_ctrl *buf_ctrl;
+
+ list_for_each_entry(buf_ctrl, head, list) {
+ if (!(buf_ctrl->type & MFC_CTRL_TYPE_GET) || !buf_ctrl->has_new)
+ continue;
+
+ list_for_each_entry(ctx_ctrl, &ctx->ctrls, list) {
+ if (!(ctx_ctrl->type & MFC_CTRL_TYPE_GET))
+ continue;
+
+ if (ctx_ctrl->id == buf_ctrl->id) {
+ if (ctx_ctrl->has_new)
+ mfc_debug(8,
+ "Overwrite context control "\
+ "value id: 0x%08x, val: %d\n",
+ ctx_ctrl->id, ctx_ctrl->val);
+
+ ctx_ctrl->has_new = 1;
+ ctx_ctrl->val = buf_ctrl->val;
+
+ buf_ctrl->has_new = 0;
+ }
+ }
+ }
+
+ list_for_each_entry(ctx_ctrl, &ctx->ctrls, list) {
+ if (ctx_ctrl->has_new)
+ mfc_debug(8, "Updated context control "\
+ "id: 0x%08x val: %d\n",
+ ctx_ctrl->id, ctx_ctrl->val);
+ }
+
+ return 0;
+}
+
+static int enc_set_buf_ctrls_val(struct s5p_mfc_ctx *ctx, struct list_head *head)
+{
+ struct s5p_mfc_buf_ctrl *buf_ctrl;
+ unsigned int value = 0;
+
+ list_for_each_entry(buf_ctrl, head, list) {
+ if (!(buf_ctrl->type & MFC_CTRL_TYPE_SET) || !buf_ctrl->has_new)
+ continue;
+
+ /* read old vlaue */
+ if (buf_ctrl->mode == MFC_CTRL_MODE_SFR)
+ value = s5p_mfc_read_reg(buf_ctrl->addr);
+ else if (buf_ctrl->mode == MFC_CTRL_MODE_SHM)
+ value = s5p_mfc_read_info(ctx, buf_ctrl->addr);
+
+ /* save old value for recovery */
+ if (buf_ctrl->is_volatile)
+ buf_ctrl->old_val = (value >> buf_ctrl->shft) & buf_ctrl->mask;
+
+ /* write new value */
+ value &= ~(buf_ctrl->mask << buf_ctrl->shft);
+ value |= ((buf_ctrl->val & buf_ctrl->mask) << buf_ctrl->shft);
+
+ if (buf_ctrl->mode == MFC_CTRL_MODE_SFR)
+ s5p_mfc_write_reg(value, buf_ctrl->addr);
+ else if (buf_ctrl->mode == MFC_CTRL_MODE_SHM)
+ s5p_mfc_write_info(ctx, value, buf_ctrl->addr);
+
+ /* set change flag bit */
+ if (buf_ctrl->flag_mode == MFC_CTRL_MODE_SFR) {
+ value = s5p_mfc_read_reg(buf_ctrl->flag_addr);
+ value |= (1 << buf_ctrl->flag_shft);
+ s5p_mfc_write_reg(value, buf_ctrl->flag_addr);
+ } else if (buf_ctrl->flag_mode == MFC_CTRL_MODE_SHM) {
+ value = s5p_mfc_read_info(ctx, buf_ctrl->flag_addr);
+ value |= (1 << buf_ctrl->flag_shft);
+ s5p_mfc_write_info(ctx, value, buf_ctrl->flag_addr);
+ }
+
+ buf_ctrl->has_new = 0;
+ buf_ctrl->updated = 1;
+
+ mfc_debug(8, "Set buffer control "\
+ "id: 0x%08x val: %d\n",
+ buf_ctrl->id, buf_ctrl->val);
+ }
+
+ return 0;
+}
+
+static int enc_get_buf_ctrls_val(struct s5p_mfc_ctx *ctx, struct list_head *head)
+{
+ struct s5p_mfc_buf_ctrl *buf_ctrl;
+ unsigned int value = 0;
+
+ list_for_each_entry(buf_ctrl, head, list) {
+ if (!(buf_ctrl->type & MFC_CTRL_TYPE_GET))
+ continue;
+
+ if (buf_ctrl->mode == MFC_CTRL_MODE_SFR)
+ value = s5p_mfc_read_reg(buf_ctrl->addr);
+ else if (buf_ctrl->mode == MFC_CTRL_MODE_SHM)
+ value = s5p_mfc_read_info(ctx, buf_ctrl->addr);
+
+ value = (value >> buf_ctrl->shft) & buf_ctrl->mask;
+
+ buf_ctrl->val = value;
+ buf_ctrl->has_new = 1;
+
+ mfc_debug(8, "Get buffer control "\
+ "id: 0x%08x val: %d\n",
+ buf_ctrl->id, buf_ctrl->val);
+ }
+
+ return 0;
+}
+
+static int enc_recover_buf_ctrls_val(struct s5p_mfc_ctx *ctx,
+ struct list_head *head)
+{
+ struct s5p_mfc_buf_ctrl *buf_ctrl;
+ unsigned int value = 0;
+
+ list_for_each_entry(buf_ctrl, head, list) {
+ if (!(buf_ctrl->type & MFC_CTRL_TYPE_SET)
+ || !buf_ctrl->is_volatile
+ || !buf_ctrl->updated)
+ continue;
+
+ if (buf_ctrl->mode == MFC_CTRL_MODE_SFR)
+ value = s5p_mfc_read_reg(buf_ctrl->addr);
+ else if (buf_ctrl->mode == MFC_CTRL_MODE_SHM)
+ value = s5p_mfc_read_info(ctx, buf_ctrl->addr);
+
+ value &= ~(buf_ctrl->mask << buf_ctrl->shft);
+ value |= ((buf_ctrl->old_val & buf_ctrl->mask)
+ << buf_ctrl->shft);
+
+ if (buf_ctrl->mode == MFC_CTRL_MODE_SFR)
+ s5p_mfc_write_reg(value, buf_ctrl->addr);
+ else if (buf_ctrl->mode == MFC_CTRL_MODE_SHM)
+ s5p_mfc_write_info(ctx, value, buf_ctrl->addr);
+
+ /* clear change flag bit */
+ if (buf_ctrl->flag_mode == MFC_CTRL_MODE_SFR) {
+ value = s5p_mfc_read_reg(buf_ctrl->flag_addr);
+ value &= ~(1 << buf_ctrl->flag_shft);
+ s5p_mfc_write_reg(value, buf_ctrl->flag_addr);
+ } else if (buf_ctrl->flag_mode == MFC_CTRL_MODE_SHM) {
+ value = s5p_mfc_read_info(ctx, buf_ctrl->flag_addr);
+ value &= ~(1 << buf_ctrl->flag_shft);
+ s5p_mfc_write_info(ctx, value, buf_ctrl->flag_addr);
+ }
+
+ mfc_debug(8, "Recover buffer control "\
+ "id: 0x%08x old val: %d\n",
+ buf_ctrl->id, buf_ctrl->old_val);
+ }
+
+ return 0;
+}
+
+static void cleanup_ref_queue(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+ struct s5p_mfc_buf *mb_entry;
+ dma_addr_t mb_y_addr, mb_c_addr;
+
+ /* move buffers in ref queue to src queue */
+ while (!list_empty(&enc->ref_queue)) {
+ mb_entry = list_entry((&enc->ref_queue)->next, struct s5p_mfc_buf, list);
+
+ mb_y_addr = s5p_mfc_mem_plane_addr(ctx, &mb_entry->vb, 0);
+ mb_c_addr = s5p_mfc_mem_plane_addr(ctx, &mb_entry->vb, 1);
+
+ mfc_debug(2, "enc ref y addr: 0x%08lx",
+ (unsigned long)mb_y_addr);
+ mfc_debug(2, "enc ref c addr: 0x%08lx",
+ (unsigned long)mb_c_addr);
+
+ list_del(&mb_entry->list);
+ enc->ref_queue_cnt--;
+
+ list_add_tail(&mb_entry->list, &ctx->src_queue);
+ ctx->src_queue_cnt++;
+ }
+
+ mfc_debug(2, "enc src count: %d, enc ref count: %d\n",
+ ctx->src_queue_cnt, enc->ref_queue_cnt);
+
+ INIT_LIST_HEAD(&enc->ref_queue);
+ enc->ref_queue_cnt = 0;
+}
+
+static int enc_pre_seq_start(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_buf *dst_mb;
+ dma_addr_t dst_addr;
+ unsigned int dst_size;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->irqlock, flags);
+
+ dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list);
+ dst_addr = s5p_mfc_mem_plane_addr(ctx, &dst_mb->vb, 0);
+ dst_size = vb2_plane_size(&dst_mb->vb, 0);
+ s5p_mfc_set_enc_stream_buffer(ctx, dst_addr, dst_size);
+
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+
+ return 0;
+}
+
+static int enc_post_seq_start(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+ struct s5p_mfc_enc_params *p = &enc->params;
+ struct s5p_mfc_buf *dst_mb;
+ unsigned long flags;
+
+ mfc_debug(2, "seq header size: %d", s5p_mfc_get_enc_strm_size());
+
+ if (p->seq_hdr_mode == V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) {
+ spin_lock_irqsave(&dev->irqlock, flags);
+
+ dst_mb = list_entry(ctx->dst_queue.next,
+ struct s5p_mfc_buf, list);
+ list_del(&dst_mb->list);
+ ctx->dst_queue_cnt--;
+
+ vb2_set_plane_payload(&dst_mb->vb, 0, s5p_mfc_get_enc_strm_size());
+ vb2_buffer_done(&dst_mb->vb, VB2_BUF_STATE_DONE);
+
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+ }
+
+ if (IS_MFCV6(dev))
+ ctx->state = MFCINST_HEAD_PARSED; /* for INIT_BUFFER cmd */
+ else {
+ ctx->state = MFCINST_RUNNING;
+
+ if (s5p_mfc_enc_ctx_ready(ctx)) {
+ spin_lock_irqsave(&dev->condlock, flags);
+ set_bit(ctx->num, &dev->ctx_work_bits);
+ spin_unlock_irqrestore(&dev->condlock, flags);
+ }
+ queue_work(dev->irq_workqueue, &dev->work_struct);
+ }
+ if (IS_MFCV6(dev))
+ ctx->dpb_count = s5p_mfc_get_enc_dpb_count();
+
+ return 0;
+}
+
+static int enc_pre_frame_start(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_buf *dst_mb;
+ struct s5p_mfc_buf *src_mb;
+ unsigned long flags;
+ dma_addr_t src_y_addr, src_c_addr, dst_addr;
+ unsigned int dst_size;
+
+ spin_lock_irqsave(&dev->irqlock, flags);
+
+ src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
+ src_y_addr = s5p_mfc_mem_plane_addr(ctx, &src_mb->vb, 0);
+ src_c_addr = s5p_mfc_mem_plane_addr(ctx, &src_mb->vb, 1);
+ s5p_mfc_set_enc_frame_buffer(ctx, src_y_addr, src_c_addr);
+
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+
+ mfc_debug(2, "enc src y addr: 0x%08lx", (unsigned long)src_y_addr);
+ mfc_debug(2, "enc src c addr: 0x%08lx", (unsigned long)src_c_addr);
+
+ spin_lock_irqsave(&dev->irqlock, flags);
+
+ dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list);
+ dst_addr = s5p_mfc_mem_plane_addr(ctx, &dst_mb->vb, 0);
+ dst_size = vb2_plane_size(&dst_mb->vb, 0);
+ s5p_mfc_set_enc_stream_buffer(ctx, dst_addr, dst_size);
+
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+
+ mfc_debug(2, "enc dst addr: 0x%08lx", (unsigned long)dst_addr);
+
+ return 0;
+}
+
+static int enc_post_frame_start(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+ struct s5p_mfc_buf *mb_entry;
+ dma_addr_t enc_y_addr, enc_c_addr;
+ dma_addr_t mb_y_addr, mb_c_addr;
+ int slice_type;
+ unsigned int strm_size;
+ unsigned int pic_count;
+ unsigned long flags;
+ unsigned int index;
+
+ slice_type = s5p_mfc_get_enc_slice_type();
+ strm_size = s5p_mfc_get_enc_strm_size();
+ pic_count = s5p_mfc_get_enc_pic_count();
+
+ mfc_debug(2, "encoded slice type: %d", slice_type);
+ mfc_debug(2, "encoded stream size: %d", strm_size);
+ mfc_debug(2, "display order: %d", pic_count);
+
+ /* set encoded frame type */
+ enc->frame_type = slice_type;
+
+ spin_lock_irqsave(&dev->irqlock, flags);
+
+ if (slice_type >= 0) {
+ if (ctx->state == MFCINST_RUNNING_NO_OUTPUT)
+ ctx->state = MFCINST_RUNNING;
+
+ s5p_mfc_get_enc_frame_buffer(ctx, &enc_y_addr, &enc_c_addr);
+
+ mfc_debug(2, "encoded y addr: 0x%08lx",
+ (unsigned long)enc_y_addr);
+ mfc_debug(2, "encoded c addr: 0x%08lx",
+ (unsigned long)enc_c_addr);
+
+ list_for_each_entry(mb_entry, &ctx->src_queue, list) {
+ mb_y_addr = s5p_mfc_mem_plane_addr(ctx,
+ &mb_entry->vb, 0);
+ mb_c_addr = s5p_mfc_mem_plane_addr(ctx,
+ &mb_entry->vb, 1);
+
+ mfc_debug(2, "enc src y addr: 0x%08lx",
+ (unsigned long)mb_y_addr);
+ mfc_debug(2, "enc src c addr: 0x%08lx",
+ (unsigned long)mb_c_addr);
+
+ mb_entry = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
+ index = mb_entry->vb.v4l2_buf.index;
+ if (call_cop(ctx, recover_buf_ctrls_val, ctx, &ctx->src_ctrls[index]) < 0)
+ mfc_err("failed in recover_buf_ctrls_val\n");
+
+ if ((enc_y_addr == mb_y_addr) && (enc_c_addr == mb_c_addr)) {
+ list_del(&mb_entry->list);
+ ctx->src_queue_cnt--;
+
+ vb2_buffer_done(&mb_entry->vb, VB2_BUF_STATE_DONE);
+ break;
+ }
+ }
+
+ list_for_each_entry(mb_entry, &enc->ref_queue, list) {
+ mb_y_addr = s5p_mfc_mem_plane_addr(ctx,
+ &mb_entry->vb, 0);
+ mb_c_addr = s5p_mfc_mem_plane_addr(ctx,
+ &mb_entry->vb, 1);
+
+ mfc_debug(2, "enc ref y addr: 0x%08lx",
+ (unsigned long)mb_y_addr);
+ mfc_debug(2, "enc ref c addr: 0x%08lx",
+ (unsigned long)mb_c_addr);
+
+ if ((enc_y_addr == mb_y_addr) && (enc_c_addr == mb_c_addr)) {
+ list_del(&mb_entry->list);
+ enc->ref_queue_cnt--;
+
+ vb2_buffer_done(&mb_entry->vb, VB2_BUF_STATE_DONE);
+ break;
+ }
+ }
+ }
+
+ if ((ctx->src_queue_cnt > 0) &&
+ ((ctx->state == MFCINST_RUNNING) ||
+ (ctx->state == MFCINST_RUNNING_NO_OUTPUT))) {
+ mb_entry = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
+
+ if (mb_entry->used) {
+ list_del(&mb_entry->list);
+ ctx->src_queue_cnt--;
+
+ list_add_tail(&mb_entry->list, &enc->ref_queue);
+ enc->ref_queue_cnt++;
+ }
+ /* slice_type = 4 && strm_size = 0, skipped enable
+ should be considered */
+ if ((slice_type == -1) && (strm_size == 0))
+ ctx->state = MFCINST_RUNNING_NO_OUTPUT;
+
+ mfc_debug(2, "slice_type: %d, ctx->state: %d\n", slice_type, ctx->state);
+ mfc_debug(2, "enc src count: %d, enc ref count: %d\n",
+ ctx->src_queue_cnt, enc->ref_queue_cnt);
+ }
+
+ if (strm_size > 0) {
+ /* at least one more dest. buffers exist always */
+ mb_entry = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list);
+
+ mb_entry->vb.v4l2_buf.flags &=
+ ~(V4L2_BUF_FLAG_KEYFRAME |
+ V4L2_BUF_FLAG_PFRAME |
+ V4L2_BUF_FLAG_BFRAME);
+
+ switch (slice_type) {
+ case S5P_FIMV_ENCODED_TYPE_I:
+ mb_entry->vb.v4l2_buf.flags |=
+ V4L2_BUF_FLAG_KEYFRAME;
+ break;
+ case S5P_FIMV_ENCODED_TYPE_P:
+ mb_entry->vb.v4l2_buf.flags |=
+ V4L2_BUF_FLAG_PFRAME;
+ break;
+ case S5P_FIMV_ENCODED_TYPE_B:
+ mb_entry->vb.v4l2_buf.flags |=
+ V4L2_BUF_FLAG_BFRAME;
+ break;
+ default:
+ mb_entry->vb.v4l2_buf.flags |=
+ V4L2_BUF_FLAG_KEYFRAME;
+ break;
+ }
+ mfc_debug(2, "Slice type : %d\n", mb_entry->vb.v4l2_buf.flags);
+
+ list_del(&mb_entry->list);
+ ctx->dst_queue_cnt--;
+ vb2_set_plane_payload(&mb_entry->vb, 0, strm_size);
+
+ index = mb_entry->vb.v4l2_buf.index;
+ if (call_cop(ctx, get_buf_ctrls_val, ctx, &ctx->dst_ctrls[index]) < 0)
+ mfc_err("failed in get_buf_ctrls_val\n");
+
+ vb2_buffer_done(&mb_entry->vb, VB2_BUF_STATE_DONE);
+ }
+
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+
+ if ((ctx->src_queue_cnt == 0) || (ctx->dst_queue_cnt == 0)) {
+ spin_lock(&dev->condlock);
+ clear_bit(ctx->num, &dev->ctx_work_bits);
+ spin_unlock(&dev->condlock);
+ }
+
+ return 0;
+}
+
+static struct s5p_mfc_codec_ops encoder_codec_ops = {
+ .get_buf_update_val = NULL,
+ .init_ctx_ctrls = enc_init_ctx_ctrls,
+ .cleanup_ctx_ctrls = enc_cleanup_ctx_ctrls,
+ .init_buf_ctrls = enc_init_buf_ctrls,
+ .cleanup_buf_ctrls = enc_cleanup_buf_ctrls,
+ .to_buf_ctrls = enc_to_buf_ctrls,
+ .to_ctx_ctrls = enc_to_ctx_ctrls,
+ .set_buf_ctrls_val = enc_set_buf_ctrls_val,
+ .get_buf_ctrls_val = enc_get_buf_ctrls_val,
+ .recover_buf_ctrls_val = enc_recover_buf_ctrls_val,
+ .pre_seq_start = enc_pre_seq_start,
+ .post_seq_start = enc_post_seq_start,
+ .pre_frame_start = enc_pre_frame_start,
+ .post_frame_start = enc_post_frame_start,
+};
+
+/* Query capabilities of the device */
+static int vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct s5p_mfc_dev *dev = video_drvdata(file);
+
+ strncpy(cap->driver, dev->plat_dev->name, sizeof(cap->driver) - 1);
+ strncpy(cap->card, dev->plat_dev->name, sizeof(cap->card) - 1);
+ cap->bus_info[0] = 0;
+ cap->version = KERNEL_VERSION(1, 0, 0);
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE
+ | V4L2_CAP_VIDEO_OUTPUT
+ | V4L2_CAP_STREAMING;
+
+ return 0;
+}
+
+static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool mplane, bool out)
+{
+ struct s5p_mfc_fmt *fmt;
+ int i, j = 0;
+
+ for (i = 0; i < ARRAY_SIZE(formats); ++i) {
+ if (mplane && formats[i].num_planes == 1)
+ continue;
+ else if (!mplane && formats[i].num_planes > 1)
+ continue;
+ if (out && formats[i].type != MFC_FMT_RAW)
+ continue;
+ else if (!out && formats[i].type != MFC_FMT_ENC)
+ continue;
+
+ if (j == f->index) {
+ fmt = &formats[i];
+ strlcpy(f->description, fmt->name,
+ sizeof(f->description));
+ f->pixelformat = fmt->fourcc;
+
+ return 0;
+ }
+
+ ++j;
+ }
+
+ return -EINVAL;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *pirv,
+ struct v4l2_fmtdesc *f)
+{
+ return vidioc_enum_fmt(f, false, false);
+}
+
+static int vidioc_enum_fmt_vid_cap_mplane(struct file *file, void *pirv,
+ struct v4l2_fmtdesc *f)
+{
+ return vidioc_enum_fmt(f, true, false);
+}
+
+static int vidioc_enum_fmt_vid_out(struct file *file, void *prov,
+ struct v4l2_fmtdesc *f)
+{
+ return vidioc_enum_fmt(f, false, true);
+}
+
+static int vidioc_enum_fmt_vid_out_mplane(struct file *file, void *prov,
+ struct v4l2_fmtdesc *f)
+{
+ return vidioc_enum_fmt(f, true, true);
+}
+
+static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+ struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
+
+ mfc_debug_enter();
+
+ mfc_debug(2, "f->type = %d ctx->state = %d\n", f->type, ctx->state);
+
+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ /* This is run on output (encoder dest) */
+ pix_fmt_mp->width = 0;
+ pix_fmt_mp->height = 0;
+ pix_fmt_mp->field = V4L2_FIELD_NONE;
+ pix_fmt_mp->pixelformat = ctx->dst_fmt->fourcc;
+ pix_fmt_mp->num_planes = ctx->dst_fmt->num_planes;
+
+ pix_fmt_mp->plane_fmt[0].bytesperline = enc->dst_buf_size;
+ pix_fmt_mp->plane_fmt[0].sizeimage = enc->dst_buf_size;
+ } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ /* This is run on capture (encoder src) */
+ pix_fmt_mp->width = ctx->img_width;
+ pix_fmt_mp->height = ctx->img_height;
+ pix_fmt_mp->field = V4L2_FIELD_NONE;
+ pix_fmt_mp->pixelformat = ctx->src_fmt->fourcc;
+ pix_fmt_mp->num_planes = ctx->src_fmt->num_planes;
+
+ pix_fmt_mp->plane_fmt[0].bytesperline = ctx->buf_width;
+ pix_fmt_mp->plane_fmt[0].sizeimage = ctx->luma_size;
+ pix_fmt_mp->plane_fmt[1].bytesperline = ctx->buf_width;
+ pix_fmt_mp->plane_fmt[1].sizeimage = ctx->chroma_size;
+ } else {
+ mfc_err("invalid buf type\n");
+ return -EINVAL;
+ }
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
+{
+ struct s5p_mfc_fmt *fmt;
+ struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
+
+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ fmt = find_format(f, MFC_FMT_ENC);
+ if (!fmt) {
+ mfc_err("failed to try output format\n");
+ return -EINVAL;
+ }
+
+ if (pix_fmt_mp->plane_fmt[0].sizeimage == 0) {
+ mfc_err("must be set encoding output size\n");
+ return -EINVAL;
+ }
+
+ pix_fmt_mp->plane_fmt[0].bytesperline =
+ pix_fmt_mp->plane_fmt[0].sizeimage;
+ } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ fmt = find_format(f, MFC_FMT_RAW);
+ if (!fmt) {
+ mfc_err("failed to try output format\n");
+ return -EINVAL;
+ }
+
+ if (fmt->num_planes != pix_fmt_mp->num_planes) {
+ mfc_err("failed to try output format\n");
+ return -EINVAL;
+ }
+
+ /*
+ pix_fmt_mp->height;
+ pix_fmt_mp->width;
+
+ pix_fmt_mp->plane_fmt[0].bytesperline; - buf_width
+ pix_fmt_mp->plane_fmt[0].sizeimage; - luma
+ pix_fmt_mp->plane_fmt[1].bytesperline; - buf_width
+ pix_fmt_mp->plane_fmt[1].sizeimage; - chroma
+ */
+ } else {
+ mfc_err("invalid buf type\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
+{
+ struct s5p_mfc_dev *dev = video_drvdata(file);
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+ struct s5p_mfc_fmt *fmt;
+ struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
+ unsigned long flags;
+ int ret = 0;
+
+ mfc_debug_enter();
+
+ ret = vidioc_try_fmt(file, priv, f);
+ if (ret)
+ return ret;
+
+ if (ctx->vq_src.streaming || ctx->vq_dst.streaming) {
+ v4l2_err(&dev->v4l2_dev, "%s queue busy\n", __func__);
+ ret = -EBUSY;
+ goto out;
+ }
+
+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ fmt = find_format(f, MFC_FMT_ENC);
+ if (!fmt) {
+ mfc_err("failed to set capture format\n");
+ return -EINVAL;
+ }
+ ctx->state = MFCINST_INIT;
+
+ ctx->dst_fmt = fmt;
+ ctx->codec_mode = ctx->dst_fmt->codec_mode;
+ mfc_debug(2, "codec number: %d\n", ctx->dst_fmt->codec_mode);
+
+ /* CHKME: 2KB aligned, multiple of 4KB - it may be ok with SDVMM */
+ enc->dst_buf_size = pix_fmt_mp->plane_fmt[0].sizeimage;
+ pix_fmt_mp->plane_fmt[0].bytesperline = 0;
+
+ ctx->capture_state = QUEUE_FREE;
+
+ if (!ctx->is_drm)
+ s5p_mfc_alloc_instance_buffer(ctx);
+
+ spin_lock_irqsave(&dev->condlock, flags);
+ set_bit(ctx->num, &dev->ctx_work_bits);
+ spin_unlock_irqrestore(&dev->condlock, flags);
+
+ s5p_mfc_clean_ctx_int_flags(ctx);
+ s5p_mfc_try_run(dev);
+ if (s5p_mfc_wait_for_done_ctx(ctx, \
+ S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET)) {
+ /* Error or timeout */
+ mfc_err("Error getting instance from hardware.\n");
+ s5p_mfc_release_instance_buffer(ctx);
+ ret = -EIO;
+ goto out;
+ }
+ mfc_debug(2, "Got instance number: %d\n", ctx->inst_no);
+ } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ fmt = find_format(f, MFC_FMT_RAW);
+ if (!fmt) {
+ mfc_err("failed to set output format\n");
+ return -EINVAL;
+ }
+ if (!IS_MFCV6(dev)) {
+ if (fmt->fourcc == V4L2_PIX_FMT_NV12MT_16X16) {
+ mfc_err("Not supported format.\n");
+ return -EINVAL;
+ }
+ } else if (IS_MFCV6(dev)) {
+ if (fmt->fourcc == V4L2_PIX_FMT_NV12MT) {
+ mfc_err("Not supported format.\n");
+ return -EINVAL;
+ }
+ }
+
+ if (fmt->num_planes != pix_fmt_mp->num_planes) {
+ mfc_err("failed to set output format\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ctx->src_fmt = fmt;
+ ctx->img_width = pix_fmt_mp->width;
+ ctx->img_height = pix_fmt_mp->height;
+
+ mfc_debug(2, "codec number: %d\n", ctx->src_fmt->codec_mode);
+ mfc_debug(2, "fmt - w: %d, h: %d, ctx - w: %d, h: %d\n",
+ pix_fmt_mp->width, pix_fmt_mp->height,
+ ctx->img_width, ctx->img_height);
+
+ s5p_mfc_enc_calc_src_size(ctx);
+
+ ctx->output_state = QUEUE_FREE;
+
+ pix_fmt_mp->plane_fmt[0].bytesperline = ctx->buf_width;
+ pix_fmt_mp->plane_fmt[0].sizeimage = ctx->luma_size;
+ pix_fmt_mp->plane_fmt[1].bytesperline = ctx->buf_width;
+ pix_fmt_mp->plane_fmt[1].sizeimage = ctx->chroma_size;
+ } else {
+ mfc_err("invalid buf type\n");
+ return -EINVAL;
+ }
+out:
+ mfc_debug_leave();
+ return ret;
+}
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *reqbufs)
+{
+ struct s5p_mfc_dev *dev = video_drvdata(file);
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ int ret = 0;
+ int cacheable;
+ void *alloc_ctx1 = ctx->dev->alloc_ctx[MFC_CMA_BANK1_ALLOC_CTX];
+ void *alloc_ctx2 = ctx->dev->alloc_ctx[MFC_CMA_BANK2_ALLOC_CTX];
+
+ mfc_debug_enter();
+
+ mfc_debug(2, "type: %d\n", reqbufs->memory);
+
+ /* if memory is not mmp or userptr return error */
+ if ((reqbufs->memory != V4L2_MEMORY_MMAP) &&
+ (reqbufs->memory != V4L2_MEMORY_USERPTR) &&
+ (reqbufs->memory != V4L2_MEMORY_DMABUF))
+ return -EINVAL;
+
+ if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ /* RMVME: s5p_mfc_buf_negotiate() ctx state checked */
+ /*
+ if (ctx->state != MFCINST_GOT_INST) {
+ mfc_err("invalid context state: %d\n", ctx->state);
+ return -EINVAL;
+ }
+ */
+ cacheable = (ctx->cacheable & MFCMASK_DST_CACHE) ? 1 : 0;
+ if (ctx->is_drm)
+ s5p_mfc_mem_set_cacheable(
+ ctx->dev->alloc_ctx_drm, cacheable);
+ else
+ s5p_mfc_mem_set_cacheable(alloc_ctx1, cacheable);
+
+ if (ctx->capture_state != QUEUE_FREE) {
+ mfc_err("invalid capture state: %d\n", ctx->capture_state);
+ return -EINVAL;
+ }
+
+ ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
+ if (ret != 0) {
+ mfc_err("error in vb2_reqbufs() for E(D)\n");
+ return ret;
+ }
+ ctx->capture_state = QUEUE_BUFS_REQUESTED;
+
+ if (!IS_MFCV6(dev)) {
+ ret = s5p_mfc_alloc_codec_buffers(ctx);
+ if (ret) {
+ mfc_err("Failed to allocate encoding buffers.\n");
+ reqbufs->count = 0;
+ ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
+ return -ENOMEM;
+ }
+ }
+ } else if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ /* cacheable setting */
+ cacheable = (ctx->cacheable & MFCMASK_SRC_CACHE) ? 1 : 0;
+ if (ctx->is_drm) {
+ s5p_mfc_mem_set_cacheable(
+ ctx->dev->alloc_ctx_drm, cacheable);
+ } else {
+ if (!IS_MFCV6(dev))
+ s5p_mfc_mem_set_cacheable(
+ alloc_ctx2, cacheable);
+ else
+ s5p_mfc_mem_set_cacheable(
+ alloc_ctx1, cacheable);
+ }
+
+ if (ctx->output_state != QUEUE_FREE) {
+ mfc_err("invalid output state: %d\n", ctx->output_state);
+ return -EINVAL;
+ }
+
+ ret = vb2_reqbufs(&ctx->vq_src, reqbufs);
+ if (ret != 0) {
+ mfc_err("error in vb2_reqbufs() for E(S)\n");
+ return ret;
+ }
+ ctx->output_state = QUEUE_BUFS_REQUESTED;
+ } else {
+ mfc_err("invalid buf type\n");
+ return -EINVAL;
+ }
+
+ mfc_debug(2, "--\n");
+
+ return ret;
+}
+
+static int vidioc_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ int ret = 0;
+
+ mfc_debug_enter();
+
+ mfc_debug(2, "type: %d\n", buf->memory);
+
+ /* if memory is not mmp or userptr return error */
+ if ((buf->memory != V4L2_MEMORY_MMAP) &&
+ (buf->memory != V4L2_MEMORY_USERPTR) &&
+ (buf->memory != V4L2_MEMORY_DMABUF))
+ return -EINVAL;
+
+ mfc_debug(2, "state: %d, buf->type: %d\n", ctx->state, buf->type);
+
+ if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ if (ctx->state != MFCINST_GOT_INST) {
+ mfc_err("invalid context state: %d\n", ctx->state);
+ return -EINVAL;
+ }
+
+ ret = vb2_querybuf(&ctx->vq_dst, buf);
+ if (ret != 0) {
+ mfc_err("error in vb2_querybuf() for E(D)\n");
+ return ret;
+ }
+ buf->m.planes[0].m.mem_offset += DST_QUEUE_OFF_BASE;
+
+ } else if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ ret = vb2_querybuf(&ctx->vq_src, buf);
+ if (ret != 0) {
+ mfc_err("error in vb2_querybuf() for E(S)\n");
+ return ret;
+ }
+ } else {
+ mfc_err("invalid buf type\n");
+ return -EINVAL;
+ }
+
+ mfc_debug_leave();
+
+ return ret;
+}
+
+/* Queue a buffer */
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+
+ mfc_debug_enter();
+ mfc_debug(2, "Enqueued buf: %d (type = %d)\n", buf->index, buf->type);
+ if (ctx->state == MFCINST_ERROR) {
+ mfc_err("Call on QBUF after unrecoverable error.\n");
+ return -EIO;
+ }
+ if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ return vb2_qbuf(&ctx->vq_src, buf);
+ else
+ return vb2_qbuf(&ctx->vq_dst, buf);
+ mfc_debug_leave();
+ return -EINVAL;
+}
+
+/* Dequeue a buffer */
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ int ret;
+
+ mfc_debug_enter();
+ mfc_debug(2, "Addr: %p %p %p Type: %d\n", &ctx->vq_src, buf, buf->m.planes,
+ buf->type);
+ if (ctx->state == MFCINST_ERROR) {
+ mfc_err("Call on DQBUF after unrecoverable error.\n");
+ return -EIO;
+ }
+ if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ ret = vb2_dqbuf(&ctx->vq_src, buf, file->f_flags & O_NONBLOCK);
+ else
+ ret = vb2_dqbuf(&ctx->vq_dst, buf, file->f_flags & O_NONBLOCK);
+ mfc_debug_leave();
+ return ret;
+}
+
+/* Stream on */
+static int vidioc_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ int ret = -EINVAL;
+
+ mfc_debug_enter();
+ if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ ret = vb2_streamon(&ctx->vq_src, type);
+ } else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ ret = vb2_streamon(&ctx->vq_dst, type);
+
+ if (!ret) {
+ ctx->mfc_int_handle_poll = exynos5_bus_int_poll();
+ if (!ctx->mfc_int_handle_poll)
+ mfc_err("Failed to request INT poll()\n");
+ }
+ }
+ mfc_debug(2, "ctx->src_queue_cnt = %d ctx->state = %d "
+ "ctx->dst_queue_cnt = %d ctx->dpb_count = %d\n",
+ ctx->src_queue_cnt, ctx->state, ctx->dst_queue_cnt,
+ ctx->dpb_count);
+ mfc_debug_leave();
+ return ret;
+}
+
+/* Stream off, which equals to a pause */
+static int vidioc_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ int ret;
+
+ mfc_debug_enter();
+ ret = -EINVAL;
+ if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ ret = vb2_streamoff(&ctx->vq_src, type);
+ } else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ ret = vb2_streamoff(&ctx->vq_dst, type);
+
+ if (!ret) {
+ if (ctx->mfc_int_handle_poll) {
+ exynos5_bus_int_put(ctx->mfc_int_handle_poll);
+ ctx->mfc_int_handle_poll = NULL;
+ }
+ }
+ }
+ mfc_debug_leave();
+ return ret;
+}
+
+/* Query a ctrl */
+static int vidioc_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *qc)
+{
+ struct v4l2_queryctrl *c;
+
+ c = get_ctrl(qc->id);
+ if (!c)
+ return -EINVAL;
+ *qc = *c;
+ return 0;
+}
+
+static int get_ctrl_val(struct s5p_mfc_ctx *ctx, struct v4l2_control *ctrl)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+ struct s5p_mfc_ctx_ctrl *ctx_ctrl;
+ int ret = 0;
+ int found = 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_CACHEABLE:
+ ctrl->value = ctx->cacheable;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_STREAM_SIZE:
+ ctrl->value = enc->dst_buf_size;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_COUNT:
+ ctrl->value = enc->frame_count;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TYPE:
+ ctrl->value = enc->frame_type;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_CHECK_STATE:
+ if (ctx->state == MFCINST_RUNNING_NO_OUTPUT)
+ ctrl->value = MFCSTATE_ENC_NO_OUTPUT;
+ else
+ ctrl->value = MFCSTATE_PROCESSING;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG:
+ case V4L2_CID_MPEG_MFC51_VIDEO_LUMA_ADDR:
+ case V4L2_CID_MPEG_MFC51_VIDEO_CHROMA_ADDR:
+ list_for_each_entry(ctx_ctrl, &ctx->ctrls, list) {
+ if (!(ctx_ctrl->type & MFC_CTRL_TYPE_GET))
+ continue;
+
+ if (ctx_ctrl->id == ctrl->id) {
+ if (ctx_ctrl->has_new) {
+ ctx_ctrl->has_new = 0;
+ ctrl->value = ctx_ctrl->val;
+ } else {
+ mfc_debug(8, "Control value "\
+ "is not up to date: "\
+ "0x%08x\n", ctrl->id);
+ return -EINVAL;
+ }
+
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ v4l2_err(&dev->v4l2_dev, "Invalid control: 0x%08x\n",
+ ctrl->id);
+ return -EINVAL;
+ }
+ break;
+ default:
+ v4l2_err(&dev->v4l2_dev, "Invalid control: 0x%08x\n", ctrl->id);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ int ret = 0;
+
+ mfc_debug_enter();
+ ret = get_ctrl_val(ctx, ctrl);
+ mfc_debug_leave();
+
+ return ret;
+}
+
+static inline int h264_level(enum v4l2_mpeg_video_h264_level lvl)
+{
+ static unsigned int t[V4L2_MPEG_VIDEO_H264_LEVEL_4_2 + 1] = {
+ /* V4L2_MPEG_VIDEO_H264_LEVEL_1_0 */ 10,
+ /* V4L2_MPEG_VIDEO_H264_LEVEL_1B */ 9,
+ /* V4L2_MPEG_VIDEO_H264_LEVEL_1_1 */ 11,
+ /* V4L2_MPEG_VIDEO_H264_LEVEL_1_2 */ 12,
+ /* V4L2_MPEG_VIDEO_H264_LEVEL_1_3 */ 13,
+ /* V4L2_MPEG_VIDEO_H264_LEVEL_2_0 */ 20,
+ /* V4L2_MPEG_VIDEO_H264_LEVEL_2_1 */ 21,
+ /* V4L2_MPEG_VIDEO_H264_LEVEL_2_2 */ 22,
+ /* V4L2_MPEG_VIDEO_H264_LEVEL_3_0 */ 30,
+ /* V4L2_MPEG_VIDEO_H264_LEVEL_3_1 */ 31,
+ /* V4L2_MPEG_VIDEO_H264_LEVEL_3_2 */ 32,
+ /* V4L2_MPEG_VIDEO_H264_LEVEL_4_0 */ 40,
+ /* V4L2_MPEG_VIDEO_H264_LEVEL_4_1 */ 41,
+ /* V4L2_MPEG_VIDEO_H264_LEVEL_4_2 */ 42,
+ };
+ return t[lvl];
+}
+
+static inline int mpeg4_level(enum v4l2_mpeg_video_mpeg4_level lvl)
+{
+ static unsigned int t[V4L2_MPEG_VIDEO_MPEG4_LEVEL_6 + 1] = {
+ /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_0 */ 0,
+ /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_0B, Simple */ 9,
+ /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_1 */ 1,
+ /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_2 */ 2,
+ /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_3 */ 3,
+ /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_3B, Advanced */ 7,
+ /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_4 */ 4,
+ /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_5 */ 5,
+ /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_6, Simple */ 6,
+ };
+ return t[lvl];
+}
+
+static inline int vui_sar_idc(enum v4l2_mpeg_video_h264_vui_sar_idc sar)
+{
+ static unsigned int t[V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED + 1] = {
+ /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_UNSPECIFIED */ 0,
+ /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_1x1 */ 1,
+ /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_12x11 */ 2,
+ /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_10x11 */ 3,
+ /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_16x11 */ 4,
+ /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_40x33 */ 5,
+ /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_24x11 */ 6,
+ /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_20x11 */ 7,
+ /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_32x11 */ 8,
+ /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_80x33 */ 9,
+ /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_18x11 */ 10,
+ /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_15x11 */ 11,
+ /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_64x33 */ 12,
+ /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_160x99 */ 13,
+ /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_4x3 */ 14,
+ /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_3x2 */ 15,
+ /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_2x1 */ 16,
+ /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED */ 255,
+ };
+ return t[sar];
+}
+
+static int set_enc_param(struct s5p_mfc_ctx *ctx, struct v4l2_control *ctrl)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+ struct s5p_mfc_enc_params *p = &enc->params;
+ int ret = 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+ p->gop_size = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:
+ p->slice_mode = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB:
+ p->slice_mb = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES:
+ p->slice_bit = ctrl->value * 8;
+ break;
+ case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB:
+ p->intra_refresh_mb = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_PADDING:
+ p->pad = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_PADDING_YUV:
+ p->pad_luma = (ctrl->value >> 16) & 0xff;
+ p->pad_cb = (ctrl->value >> 8) & 0xff;
+ p->pad_cr = (ctrl->value >> 0) & 0xff;
+ break;
+ case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE:
+ p->rc_frame = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE:
+ p->rc_bitrate = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF:
+ p->rc_reaction_coeff = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE:
+ enc->force_frame_type = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_VBV_SIZE:
+ p->vbv_buf_size = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEADER_MODE:
+ p->seq_hdr_mode = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE:
+ p->frame_skip_mode = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT: /* MFC5.x Only */
+ p->fixed_target_bit = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+ p->num_b_frame = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+ switch (ctrl->value) {
+ case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN:
+ p->codec.h264.profile =
+ S5P_FIMV_ENC_PROFILE_H264_MAIN;
+ break;
+ case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH:
+ p->codec.h264.profile =
+ S5P_FIMV_ENC_PROFILE_H264_HIGH;
+ break;
+ case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE:
+ p->codec.h264.profile =
+ S5P_FIMV_ENC_PROFILE_H264_BASELINE;
+ break;
+ case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE:
+ if (IS_MFCV6(dev))
+ p->codec.h264.profile =
+ S5P_FIMV_ENC_PROFILE_H264_CONSTRAINED_BASELINE;
+ else
+ ret = -EINVAL;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+ p->codec.h264.level = h264_level(ctrl->value);
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_H264_INTERLACE:
+ p->codec.h264.interlace = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
+ p->codec.h264.loop_filter_mode = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA:
+ p->codec.h264.loop_filter_alpha = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA:
+ p->codec.h264.loop_filter_beta = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
+ p->codec.h264.entropy_mode = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_H264_NUM_REF_PIC_FOR_P:
+ p->codec.h264.num_ref_pic_4p = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM:
+ p->codec.h264._8x8_transform = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE:
+ p->rc_mb = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_H264_RC_FRAME_RATE:
+ p->codec.h264.rc_framerate = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP:
+ p->codec.h264.rc_frame_qp = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_MIN_QP:
+ p->codec.h264.rc_min_qp = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_MAX_QP:
+ p->codec.h264.rc_max_qp = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_DARK:
+ p->codec.h264.rc_mb_dark = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_SMOOTH:
+ p->codec.h264.rc_mb_smooth = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_STATIC:
+ p->codec.h264.rc_mb_static = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_ACTIVITY:
+ p->codec.h264.rc_mb_activity = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP:
+ p->codec.h264.rc_p_frame_qp = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP:
+ p->codec.h264.rc_b_frame_qp = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE:
+ p->codec.h264.ar_vui = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC:
+ p->codec.h264.ar_vui_idc = vui_sar_idc(ctrl->value);
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH:
+ p->codec.h264.ext_sar_width = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT:
+ p->codec.h264.ext_sar_height = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
+ p->codec.h264.open_gop = ctrl->value ? 0 : 1;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD:
+ p->codec.h264.open_gop_size = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING:
+ p->codec.h264.hier_qp = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE:
+ p->codec.h264.hier_qp_type = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER:
+ p->codec.h264.hier_qp_layer = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_QP:
+ p->codec.h264.hier_qp_layer_qp[(ctrl->value >> 16) & 0x7]
+ = ctrl->value & 0xFF;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_SEI_FRAME_PACKING:
+ p->codec.h264.sei_gen_enable = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_SEI_FP_CURRENT_FRAME_0:
+ p->codec.h264.sei_fp_curr_frame_0 = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE:
+ p->codec.h264.sei_fp_arrangement_type = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_FMO:
+ p->codec.h264.fmo_enable = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_FMO_MAP_TYPE:
+ switch (ctrl->value) {
+ case V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_INTERLEAVED_SLICES:
+ case V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_SCATTERED_SLICES:
+ case V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_RASTER_SCAN:
+ case V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_WIPE_SCAN:
+ p->codec.h264.fmo_slice_map_type = ctrl->value;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_FMO_SLICE_GROUP:
+ p->codec.h264.fmo_slice_num_grp = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_FMO_RUN_LENGTH:
+ p->codec.h264.fmo_run_length[ctrl->value >> 30]
+ = ctrl->value & 0x3FFFFFFF;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_DIRECTION:
+ p->codec.h264.fmo_sg_dir = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_RATE:
+ p->codec.h264.fmo_sg_rate = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_ASO:
+ p->codec.h264.aso_enable = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_ASO_SLICE_ORDER:
+ p->codec.h264.aso_slice_order[(ctrl->value >> 18) & 0x7]
+ &= ~(0xFF << (((ctrl->value >> 16) & 0x3) << 3));
+ p->codec.h264.aso_slice_order[(ctrl->value >> 18) & 0x7]
+ |= (ctrl->value & 0xFF) << \
+ (((ctrl->value >> 16) & 0x3) << 3);
+ break;
+ case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
+ switch (ctrl->value) {
+ case V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE:
+ p->codec.mpeg4.profile =
+ S5P_FIMV_ENC_PROFILE_MPEG4_SIMPLE;
+ break;
+ case V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE:
+ p->codec.mpeg4.profile =
+ S5P_FIMV_ENC_PROFILE_MPEG4_ADVANCED_SIMPLE;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ break;
+ case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
+ p->codec.mpeg4.level = mpeg4_level(ctrl->value);
+ break;
+ case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP:
+ p->codec.mpeg4.rc_frame_qp = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP:
+ p->codec.mpeg4.rc_min_qp = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP:
+ p->codec.mpeg4.rc_max_qp = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_MPEG4_QPEL:
+ p->codec.mpeg4.quarter_pixel = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP:
+ p->codec.mpeg4.rc_p_frame_qp = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP:
+ p->codec.mpeg4.rc_b_frame_qp = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_MPEG4_VOP_TIME_RES:
+ p->codec.mpeg4.vop_time_res = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_MPEG4_VOP_FRM_DELTA:
+ p->codec.mpeg4.vop_frm_delta = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_H263_RC_FRAME_RATE:
+ p->codec.mpeg4.rc_framerate = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP:
+ p->codec.mpeg4.rc_frame_qp = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H263_MIN_QP:
+ p->codec.mpeg4.rc_min_qp = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H263_MAX_QP:
+ p->codec.mpeg4.rc_max_qp = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP:
+ p->codec.mpeg4.rc_p_frame_qp = ctrl->value;
+ break;
+ default:
+ v4l2_err(&dev->v4l2_dev, "Invalid control\n");
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int set_ctrl_val(struct s5p_mfc_ctx *ctx, struct v4l2_control *ctrl)
+{
+
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_ctx_ctrl *ctx_ctrl;
+ int ret = 0;
+ int found = 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_CACHEABLE:
+ ctx->cacheable |= ctrl->value;
+ break;
+ case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG:
+ case V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE:
+ case V4L2_CID_MPEG_MFC51_VIDEO_I_PERIOD_CH:
+ case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_RATE_CH:
+ case V4L2_CID_MPEG_MFC51_VIDEO_BIT_RATE_CH:
+ list_for_each_entry(ctx_ctrl, &ctx->ctrls, list) {
+ if (!(ctx_ctrl->type & MFC_CTRL_TYPE_SET))
+ continue;
+
+ if (ctx_ctrl->id == ctrl->id) {
+ ctx_ctrl->has_new = 1;
+ ctx_ctrl->val = ctrl->value;
+ if (ctx_ctrl->id == \
+ V4L2_CID_MPEG_MFC51_VIDEO_FRAME_RATE_CH)
+ ctx_ctrl->val *= 1000;
+
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ v4l2_err(&dev->v4l2_dev, "Invalid control 0x%08x\n",
+ ctrl->id);
+ return -EINVAL;
+ }
+ break;
+ default:
+ ret = set_enc_param(ctx, ctrl);
+ break;
+ }
+
+ return ret;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ int ret = 0;
+
+ mfc_debug_enter();
+
+ ret = check_ctrl_val(ctx, ctrl);
+ if (ret != 0)
+ return ret;
+
+ ret = set_ctrl_val(ctx, ctrl);
+
+ mfc_debug_leave();
+
+ return ret;
+}
+
+static int vidioc_g_ext_ctrls(struct file *file, void *priv,
+ struct v4l2_ext_controls *f)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ struct v4l2_ext_control *ext_ctrl;
+ struct v4l2_control ctrl;
+ int i;
+ int ret = 0;
+
+ /*
+ if (s5p_mfc_get_node_type(file) != MFCNODE_ENCODER)
+ return -EINVAL;
+ */
+
+ if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+ return -EINVAL;
+
+ for (i = 0; i < f->count; i++) {
+ ext_ctrl = (f->controls + i);
+
+ ctrl.id = ext_ctrl->id;
+
+ ret = get_ctrl_val(ctx, &ctrl);
+ if (ret == 0) {
+ ext_ctrl->value = ctrl.value;
+ } else {
+ f->error_idx = i;
+ break;
+ }
+
+ mfc_debug(2, "[%d] id: 0x%08x, value: %d", i, ext_ctrl->id, ext_ctrl->value);
+ }
+
+ return ret;
+}
+
+static int vidioc_s_ext_ctrls(struct file *file, void *priv,
+ struct v4l2_ext_controls *f)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ struct v4l2_ext_control *ext_ctrl;
+ struct v4l2_control ctrl;
+ int i;
+ int ret = 0;
+
+ /*
+ if (s5p_mfc_get_node_type(file) != MFCNODE_ENCODER)
+ return -EINVAL;
+ */
+
+ if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+ return -EINVAL;
+
+ for (i = 0; i < f->count; i++) {
+ ext_ctrl = (f->controls + i);
+
+ ctrl.id = ext_ctrl->id;
+ ctrl.value = ext_ctrl->value;
+
+ ret = check_ctrl_val(ctx, &ctrl);
+ if (ret != 0) {
+ f->error_idx = i;
+ break;
+ }
+
+ ret = set_enc_param(ctx, &ctrl);
+ if (ret != 0) {
+ f->error_idx = i;
+ break;
+ }
+
+ mfc_debug(2, "[%d] id: 0x%08x, value: %d", i, ext_ctrl->id, ext_ctrl->value);
+ }
+
+ return ret;
+}
+
+static int vidioc_try_ext_ctrls(struct file *file, void *priv,
+ struct v4l2_ext_controls *f)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data);
+ struct v4l2_ext_control *ext_ctrl;
+ struct v4l2_control ctrl;
+ int i;
+ int ret = 0;
+
+ /*
+ if (s5p_mfc_get_node_type(file) != MFCNODE_ENCODER)
+ return -EINVAL;
+ */
+
+ if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+ return -EINVAL;
+
+ for (i = 0; i < f->count; i++) {
+ ext_ctrl = (f->controls + i);
+
+ ctrl.id = ext_ctrl->id;
+ ctrl.value = ext_ctrl->value;
+
+ ret = check_ctrl_val(ctx, &ctrl);
+ if (ret != 0) {
+ f->error_idx = i;
+ break;
+ }
+
+ mfc_debug(2, "[%d] id: 0x%08x, value: %d", i, ext_ctrl->id, ext_ctrl->value);
+ }
+
+ return ret;
+}
+
+static const struct v4l2_ioctl_ops s5p_mfc_enc_ioctl_ops = {
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+ .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap_mplane,
+ .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
+ .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out_mplane,
+ .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt,
+ .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt,
+ .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt,
+ .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt,
+ .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt,
+ .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt,
+ .vidioc_reqbufs = vidioc_reqbufs,
+ .vidioc_querybuf = vidioc_querybuf,
+ .vidioc_qbuf = vidioc_qbuf,
+ .vidioc_dqbuf = vidioc_dqbuf,
+ .vidioc_streamon = vidioc_streamon,
+ .vidioc_streamoff = vidioc_streamoff,
+ .vidioc_queryctrl = vidioc_queryctrl,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ .vidioc_g_ext_ctrls = vidioc_g_ext_ctrls,
+ .vidioc_s_ext_ctrls = vidioc_s_ext_ctrls,
+ .vidioc_try_ext_ctrls = vidioc_try_ext_ctrls,
+};
+
+static int check_vb_with_fmt(struct s5p_mfc_fmt *fmt, struct vb2_buffer *vb)
+{
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct s5p_mfc_ctx *ctx = vq->drv_priv;
+ int i;
+
+ if (!fmt)
+ return -EINVAL;
+
+ if (fmt->num_planes != vb->num_planes) {
+ mfc_err("invalid plane number for the format\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < fmt->num_planes; i++) {
+ if (!s5p_mfc_mem_plane_addr(ctx, vb, i)) {
+ mfc_err("failed to get plane cookie\n");
+ return -EINVAL;
+ }
+
+ mfc_debug(2, "index: %d, plane[%d] cookie: 0x%08lx",
+ vb->v4l2_buf.index, i,
+ (unsigned long)s5p_mfc_mem_plane_addr(ctx, vb, i));
+ }
+
+ return 0;
+}
+
+static int s5p_mfc_queue_setup(struct vb2_queue *vq,
+ const struct v4l2_format *fmt,
+ unsigned int *buf_count, unsigned int *plane_count,
+ unsigned int psize[], void *allocators[])
+{
+ struct s5p_mfc_ctx *ctx = vq->drv_priv;
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+ struct s5p_mfc_dev *dev = ctx->dev;
+ int i;
+ void *alloc_ctx1 = ctx->dev->alloc_ctx[MFC_CMA_BANK1_ALLOC_CTX];
+ void *alloc_ctx2 = ctx->dev->alloc_ctx[MFC_CMA_BANK2_ALLOC_CTX];
+
+ mfc_debug_enter();
+
+ if (ctx->state != MFCINST_GOT_INST &&
+ vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ mfc_err("invalid state: %d\n", ctx->state);
+ return -EINVAL;
+ }
+ if (ctx->state >= MFCINST_FINISHING &&
+ vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ mfc_err("invalid state: %d\n", ctx->state);
+ return -EINVAL;
+ }
+
+ if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ if (ctx->dst_fmt)
+ *plane_count = ctx->dst_fmt->num_planes;
+ else
+ *plane_count = MFC_ENC_CAP_PLANE_COUNT;
+
+ if (*buf_count < 1)
+ *buf_count = 1;
+ if (*buf_count > MFC_MAX_BUFFERS)
+ *buf_count = MFC_MAX_BUFFERS;
+
+ psize[0] = enc->dst_buf_size;
+ if (ctx->is_drm)
+ allocators[0] = ctx->dev->alloc_ctx_drm;
+ else
+ allocators[0] = alloc_ctx1;
+ } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ if (ctx->src_fmt)
+ *plane_count = ctx->src_fmt->num_planes;
+ else
+ *plane_count = MFC_ENC_OUT_PLANE_COUNT;
+
+ if (*buf_count < 1)
+ *buf_count = 1;
+ if (*buf_count > MFC_MAX_BUFFERS)
+ *buf_count = MFC_MAX_BUFFERS;
+
+ psize[0] = ctx->luma_size;
+ psize[1] = ctx->chroma_size;
+ if (ctx->is_drm) {
+ allocators[0] = ctx->dev->alloc_ctx_drm;
+ allocators[1] = ctx->dev->alloc_ctx_drm;
+ } else {
+ if (IS_MFCV6(dev)) {
+ allocators[0] = alloc_ctx1;
+ allocators[1] = alloc_ctx1;
+ } else {
+ allocators[0] = alloc_ctx2;
+ allocators[1] = alloc_ctx2;
+ }
+ }
+ } else {
+ mfc_err("invalid queue type: %d\n", vq->type);
+ return -EINVAL;
+ }
+
+ mfc_debug(2, "buf_count: %d, plane_count: %d\n", *buf_count, *plane_count);
+ for (i = 0; i < *plane_count; i++)
+ mfc_debug(2, "plane[%d] size=%d\n", i, psize[i]);
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+static void s5p_mfc_unlock(struct vb2_queue *q)
+{
+ struct s5p_mfc_ctx *ctx = q->drv_priv;
+ struct s5p_mfc_dev *dev = ctx->dev;
+
+ mutex_unlock(&dev->mfc_mutex);
+}
+
+static void s5p_mfc_lock(struct vb2_queue *q)
+{
+ struct s5p_mfc_ctx *ctx = q->drv_priv;
+ struct s5p_mfc_dev *dev = ctx->dev;
+
+ mutex_lock(&dev->mfc_mutex);
+}
+
+static int s5p_mfc_buf_init(struct vb2_buffer *vb)
+{
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct s5p_mfc_ctx *ctx = vq->drv_priv;
+ struct s5p_mfc_buf *buf = vb_to_mfc_buf(vb);
+ int ret;
+
+ mfc_debug_enter();
+
+ if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ ret = check_vb_with_fmt(ctx->dst_fmt, vb);
+ if (ret < 0)
+ return ret;
+
+ buf->planes.stream = s5p_mfc_mem_plane_addr(ctx, vb, 0);
+
+ if (call_cop(ctx, init_buf_ctrls, ctx, MFC_CTRL_TYPE_DST,
+ vb->v4l2_buf.index) < 0)
+ mfc_err("failed in init_buf_ctrls\n");
+
+ } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ ret = check_vb_with_fmt(ctx->src_fmt, vb);
+ if (ret < 0)
+ return ret;
+
+ buf->planes.raw.luma = s5p_mfc_mem_plane_addr(ctx, vb, 0);
+ buf->planes.raw.chroma = s5p_mfc_mem_plane_addr(ctx, vb, 1);
+
+ if (call_cop(ctx, init_buf_ctrls, ctx, MFC_CTRL_TYPE_SRC,
+ vb->v4l2_buf.index) < 0)
+ mfc_err("failed in init_buf_ctrls\n");
+
+ } else {
+ mfc_err("inavlid queue type: %d\n", vq->type);
+ return -EINVAL;
+ }
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+static int s5p_mfc_buf_prepare(struct vb2_buffer *vb)
+{
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct s5p_mfc_ctx *ctx = vq->drv_priv;
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+ unsigned int index = vb->v4l2_buf.index;
+ int ret;
+
+ mfc_debug_enter();
+
+ if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ ret = check_vb_with_fmt(ctx->dst_fmt, vb);
+ if (ret < 0)
+ return ret;
+
+ mfc_debug(2, "plane size: %ld, dst size: %d\n",
+ vb2_plane_size(vb, 0), enc->dst_buf_size);
+
+ if (vb2_plane_size(vb, 0) < enc->dst_buf_size) {
+ mfc_err("plane size is too small for capture\n");
+ return -EINVAL;
+ }
+ if (ctx->cacheable & MFCMASK_DST_CACHE)
+ s5p_mfc_mem_cache_flush(vb, 1);
+ } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ ret = check_vb_with_fmt(ctx->src_fmt, vb);
+ if (ret < 0)
+ return ret;
+
+ mfc_debug(2, "plane size: %ld, luma size: %d\n",
+ vb2_plane_size(vb, 0), ctx->luma_size);
+ mfc_debug(2, "plane size: %ld, chroma size: %d\n",
+ vb2_plane_size(vb, 1), ctx->chroma_size);
+
+ if (vb2_plane_size(vb, 0) < ctx->luma_size ||
+ vb2_plane_size(vb, 1) < ctx->chroma_size) {
+ mfc_err("plane size is too small for output\n");
+ return -EINVAL;
+ }
+ if (ctx->cacheable & MFCMASK_SRC_CACHE)
+ s5p_mfc_mem_cache_flush(vb, 2);
+
+ if (call_cop(ctx, to_buf_ctrls, ctx, &ctx->src_ctrls[index]) < 0)
+ mfc_err("failed in to_buf_ctrls\n");
+
+ } else {
+ mfc_err("inavlid queue type: %d\n", vq->type);
+ return -EINVAL;
+ }
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+static int s5p_mfc_buf_finish(struct vb2_buffer *vb)
+{
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct s5p_mfc_ctx *ctx = vq->drv_priv;
+ unsigned int index = vb->v4l2_buf.index;
+
+ if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ if (call_cop(ctx, to_ctx_ctrls, ctx, &ctx->dst_ctrls[index]) < 0)
+ mfc_err("failed in to_ctx_ctrls\n");
+ } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ if (call_cop(ctx, to_ctx_ctrls, ctx, &ctx->src_ctrls[index]) < 0)
+ mfc_err("failed in to_ctx_ctrls\n");
+ }
+
+ return 0;
+}
+
+static void s5p_mfc_buf_cleanup(struct vb2_buffer *vb)
+{
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct s5p_mfc_ctx *ctx = vq->drv_priv;
+ unsigned int index = vb->v4l2_buf.index;
+
+ mfc_debug_enter();
+
+ if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ if (call_cop(ctx, cleanup_buf_ctrls, ctx,
+ MFC_CTRL_TYPE_DST, index) < 0)
+ mfc_err("failed in cleanup_buf_ctrls\n");
+ } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ if (call_cop(ctx, cleanup_buf_ctrls, ctx,
+ MFC_CTRL_TYPE_SRC, index) < 0)
+ mfc_err("failed in cleanup_buf_ctrls\n");
+ } else {
+ mfc_err("s5p_mfc_buf_cleanup: unknown queue type.\n");
+ }
+
+ mfc_debug_leave();
+}
+
+static int s5p_mfc_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+ struct s5p_mfc_ctx *ctx = q->drv_priv;
+ struct s5p_mfc_dev *dev = ctx->dev;
+ unsigned long flags;
+
+ /* If context is ready then dev = work->data;schedule it to run */
+ if (s5p_mfc_enc_ctx_ready(ctx)) {
+ spin_lock_irqsave(&dev->condlock, flags);
+ set_bit(ctx->num, &dev->ctx_work_bits);
+ spin_unlock_irqrestore(&dev->condlock, flags);
+ }
+
+ s5p_mfc_try_run(dev);
+
+ return 0;
+}
+
+static int s5p_mfc_stop_streaming(struct vb2_queue *q)
+{
+ unsigned long flags;
+ struct s5p_mfc_ctx *ctx = q->drv_priv;
+ struct s5p_mfc_dev *dev = ctx->dev;
+ int index = 0;
+
+ if ((ctx->state == MFCINST_FINISHING ||
+ ctx->state == MFCINST_RUNNING) &&
+ test_bit(ctx->num, &dev->hw_lock)) {
+ ctx->state = MFCINST_ABORT;
+ s5p_mfc_wait_for_done_ctx(ctx, S5P_FIMV_R2H_CMD_FRAME_DONE_RET);
+ }
+
+ spin_lock_irqsave(&dev->irqlock, flags);
+
+ if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst);
+ INIT_LIST_HEAD(&ctx->dst_queue);
+ ctx->dst_queue_cnt = 0;
+
+ while (index < MFC_MAX_BUFFERS) {
+ index = find_next_bit(&ctx->dst_ctrls_avail,
+ MFC_MAX_BUFFERS, index);
+ if (index < MFC_MAX_BUFFERS)
+ __enc_reset_buf_ctrls(&ctx->dst_ctrls[index]);
+ index++;
+ }
+ } else if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ cleanup_ref_queue(ctx);
+
+ s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src);
+ INIT_LIST_HEAD(&ctx->src_queue);
+ ctx->src_queue_cnt = 0;
+
+ while (index < MFC_MAX_BUFFERS) {
+ index = find_next_bit(&ctx->src_ctrls_avail,
+ MFC_MAX_BUFFERS, index);
+ if (index < MFC_MAX_BUFFERS)
+ __enc_reset_buf_ctrls(&ctx->src_ctrls[index]);
+ index++;
+ }
+ }
+
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+
+ return 0;
+}
+
+static void s5p_mfc_buf_queue(struct vb2_buffer *vb)
+{
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct s5p_mfc_ctx *ctx = vq->drv_priv;
+ struct s5p_mfc_dev *dev = ctx->dev;
+ unsigned long flags;
+ struct s5p_mfc_buf *buf = vb_to_mfc_buf(vb);
+
+ mfc_debug_enter();
+
+ if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ buf->used = 0;
+ mfc_debug(2, "dst queue: %p\n", &ctx->dst_queue);
+ mfc_debug(2, "adding to dst: %p (%08lx, %08x)\n", vb,
+ (unsigned long)s5p_mfc_mem_plane_addr(ctx, vb, 0),
+ buf->planes.stream);
+
+ /* Mark destination as available for use by MFC */
+ spin_lock_irqsave(&dev->irqlock, flags);
+ list_add_tail(&buf->list, &ctx->dst_queue);
+ ctx->dst_queue_cnt++;
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+ } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ buf->used = 0;
+ mfc_debug(2, "src queue: %p\n", &ctx->src_queue);
+ mfc_debug(2, "adding to src: %p (%08lx, %08lx, %08x, %08x)\n", vb,
+ (unsigned long)s5p_mfc_mem_plane_addr(ctx, vb, 0),
+ (unsigned long)s5p_mfc_mem_plane_addr(ctx, vb, 1),
+ buf->planes.raw.luma,
+ buf->planes.raw.chroma);
+
+ spin_lock_irqsave(&dev->irqlock, flags);
+
+ if (vb->v4l2_planes[0].bytesused == 0) {
+ mfc_debug(1, "change state to FINISHING\n");
+ ctx->state = MFCINST_FINISHING;
+
+ vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+
+ cleanup_ref_queue(ctx);
+ } else {
+ list_add_tail(&buf->list, &ctx->src_queue);
+ ctx->src_queue_cnt++;
+ }
+
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+ } else {
+ mfc_err("unsupported buffer type (%d)\n", vq->type);
+ }
+
+ if (s5p_mfc_enc_ctx_ready(ctx)) {
+ spin_lock_irqsave(&dev->condlock, flags);
+ set_bit(ctx->num, &dev->ctx_work_bits);
+ spin_unlock_irqrestore(&dev->condlock, flags);
+ }
+ s5p_mfc_try_run(dev);
+
+ mfc_debug_leave();
+}
+
+static struct vb2_ops s5p_mfc_enc_qops = {
+ .queue_setup = s5p_mfc_queue_setup,
+ .wait_prepare = s5p_mfc_unlock,
+ .wait_finish = s5p_mfc_lock,
+ .buf_init = s5p_mfc_buf_init,
+ .buf_prepare = s5p_mfc_buf_prepare,
+ .buf_finish = s5p_mfc_buf_finish,
+ .buf_cleanup = s5p_mfc_buf_cleanup,
+ .start_streaming = s5p_mfc_start_streaming,
+ .stop_streaming = s5p_mfc_stop_streaming,
+ .buf_queue = s5p_mfc_buf_queue,
+};
+
+const struct v4l2_ioctl_ops *get_enc_v4l2_ioctl_ops(void)
+{
+ return &s5p_mfc_enc_ioctl_ops;
+}
+
+int s5p_mfc_init_enc_ctx(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_enc *enc;
+ int ret = 0;
+ int i;
+
+ enc = kzalloc(sizeof(struct s5p_mfc_enc), GFP_KERNEL);
+ if (!enc) {
+ mfc_err("failed to allocate encoder private data\n");
+ return -ENOMEM;
+ }
+ ctx->enc_priv = enc;
+
+ ctx->inst_no = MFC_NO_INSTANCE_SET;
+
+ INIT_LIST_HEAD(&ctx->src_queue);
+ INIT_LIST_HEAD(&ctx->dst_queue);
+ ctx->src_queue_cnt = 0;
+ ctx->dst_queue_cnt = 0;
+
+ for (i = 0; i < MFC_MAX_BUFFERS; i++) {
+ INIT_LIST_HEAD(&ctx->src_ctrls[i]);
+ INIT_LIST_HEAD(&ctx->dst_ctrls[i]);
+ }
+ ctx->src_ctrls_avail = 0;
+ ctx->dst_ctrls_avail = 0;
+
+ ctx->type = MFCINST_ENCODER;
+ ctx->c_ops = &encoder_codec_ops;
+ ctx->src_fmt = &formats[DEF_SRC_FMT];
+ ctx->dst_fmt = &formats[DEF_DST_FMT];
+
+ INIT_LIST_HEAD(&enc->ref_queue);
+ enc->ref_queue_cnt = 0;
+
+ /* Init videobuf2 queue for OUTPUT */
+ ctx->vq_src.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ ctx->vq_src.drv_priv = ctx;
+ ctx->vq_src.buf_struct_size = sizeof(struct s5p_mfc_buf);
+ ctx->vq_src.io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
+ ctx->vq_src.ops = &s5p_mfc_enc_qops;
+ ctx->vq_src.mem_ops = s5p_mfc_mem_ops();
+ ret = vb2_queue_init(&ctx->vq_src);
+ if (ret) {
+ mfc_err("Failed to initialize videobuf2 queue(output)\n");
+ return ret;
+ }
+
+ /* Init videobuf2 queue for CAPTURE */
+ ctx->vq_dst.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ ctx->vq_dst.drv_priv = ctx;
+ ctx->vq_dst.buf_struct_size = sizeof(struct s5p_mfc_buf);
+ ctx->vq_dst.io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
+ ctx->vq_dst.ops = &s5p_mfc_enc_qops;
+ ctx->vq_dst.mem_ops = s5p_mfc_mem_ops();
+ ret = vb2_queue_init(&ctx->vq_dst);
+ if (ret) {
+ mfc_err("Failed to initialize videobuf2 queue(capture)\n");
+ return ret;
+ }
+
+ return 0;
+}
diff --git a/drivers/media/video/exynos/mfc/s5p_mfc_enc.h b/drivers/media/video/exynos/mfc/s5p_mfc_enc.h
new file mode 100644
index 0000000..077d285
--- /dev/null
+++ b/drivers/media/video/exynos/mfc/s5p_mfc_enc.h
@@ -0,0 +1,20 @@
+/*
+ * linux/drivers/media/video/exynos/mfc/s5p_mfc_enc.h
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * 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.
+ */
+
+#ifndef __S5P_MFC_ENC_H_
+#define __S5P_MFC_ENC_H_ __FILE__
+
+const struct v4l2_ioctl_ops *get_enc_v4l2_ioctl_ops(void);
+int s5p_mfc_init_enc_ctx(struct s5p_mfc_ctx *ctx);
+int s5p_mfc_enc_ctx_ready(struct s5p_mfc_ctx *ctx);
+
+#endif /* __S5P_MFC_ENC_H_ */
diff --git a/drivers/media/video/exynos/mfc/s5p_mfc_inst.c b/drivers/media/video/exynos/mfc/s5p_mfc_inst.c
new file mode 100644
index 0000000..813309a
--- /dev/null
+++ b/drivers/media/video/exynos/mfc/s5p_mfc_inst.c
@@ -0,0 +1,52 @@
+/*
+ * linux/drivers/media/video/exynos/mfc/s5p_mfc_inst.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * 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.
+ */
+
+#include "s5p_mfc_common.h"
+#include "s5p_mfc_cmd.h"
+#include "s5p_mfc_debug.h"
+#include "s5p_mfc_intr.h"
+
+int s5p_mfc_open_inst(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ int ret;
+
+ /* Preparing decoding - getting instance number */
+ mfc_debug(2, "Getting instance number\n");
+ dev->curr_ctx = ctx->num;
+ s5p_mfc_clean_ctx_int_flags(ctx);
+ ret = s5p_mfc_open_inst_cmd(ctx);
+ if (ret) {
+ mfc_err("Failed to create a new instance.\n");
+ ctx->state = MFCINST_ERROR;
+ }
+ return ret;
+}
+
+int s5p_mfc_close_inst(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ int ret;
+
+ /* Closing decoding instance */
+ mfc_debug(2, "Returning instance number\n");
+ dev->curr_ctx = ctx->num;
+ s5p_mfc_clean_ctx_int_flags(ctx);
+ ret = s5p_mfc_close_inst_cmd(ctx);
+ if (ret) {
+ mfc_err("Failed to return an instance.\n");
+ ctx->state = MFCINST_ERROR;
+ return ret;
+ }
+ return ret;
+}
+
diff --git a/drivers/media/video/exynos/mfc/s5p_mfc_inst.h b/drivers/media/video/exynos/mfc/s5p_mfc_inst.h
new file mode 100644
index 0000000..3976ace
--- /dev/null
+++ b/drivers/media/video/exynos/mfc/s5p_mfc_inst.h
@@ -0,0 +1,19 @@
+/*
+ * linux/drivers/media/video/exynos/mfc/s5p_mfc_inst.h
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * 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.
+ */
+
+#ifndef __S5P_MFC_INST_H_
+#define __S5P_MFC_INST_H_ __FILE__
+
+int s5p_mfc_open_inst(struct s5p_mfc_ctx *ctx);
+int s5p_mfc_close_inst(struct s5p_mfc_ctx *ctx);
+
+#endif /* __S5P_MFC_INST_H_ */
diff --git a/drivers/media/video/exynos/mfc/s5p_mfc_intr.c b/drivers/media/video/exynos/mfc/s5p_mfc_intr.c
new file mode 100644
index 0000000..b37f924
--- /dev/null
+++ b/drivers/media/video/exynos/mfc/s5p_mfc_intr.c
@@ -0,0 +1,84 @@
+/*
+ * drivers/media/video/exynos/mfc/s5p_mfc_intr.c
+ *
+ * C file for Samsung MFC (Multi Function Codec - FIMV) driver
+ * This file contains functions used to wait for command completion.
+ *
+ * Kamil Debski, Copyright (c) 2010 Samsung Electronics
+ * http://www.samsung.com/
+ *
+ * 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.
+ */
+
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/io.h>
+
+#include "s5p_mfc_common.h"
+
+#include "s5p_mfc_intr.h"
+#include "s5p_mfc_debug.h"
+
+int s5p_mfc_wait_for_done_dev(struct s5p_mfc_dev *dev, int command)
+{
+ int ret;
+
+ ret = wait_event_interruptible_timeout(dev->queue,
+ (dev->int_cond && (dev->int_type == command
+ || dev->int_type == S5P_FIMV_R2H_CMD_ERR_RET)),
+ msecs_to_jiffies(MFC_INT_TIMEOUT));
+ if (ret == 0) {
+ mfc_err("Interrupt (dev->int_type:%d, command:%d) timed out.\n",
+ dev->int_type, command);
+ return 1;
+ } else if (ret == -ERESTARTSYS) {
+ mfc_err("Interrupted by a signal.\n");
+ return 1;
+ }
+ mfc_debug(1, "Finished waiting (dev->int_type:%d, command: %d).\n",
+ dev->int_type, command);
+ /* RMVME: */
+ if (dev->int_type == S5P_FIMV_R2H_CMD_RSV_RET)
+ return 1;
+ return 0;
+}
+
+void s5p_mfc_clean_dev_int_flags(struct s5p_mfc_dev *dev)
+{
+ dev->int_cond = 0;
+ dev->int_type = 0;
+ dev->int_err = 0;
+}
+
+int s5p_mfc_wait_for_done_ctx(struct s5p_mfc_ctx *ctx, int command)
+{
+ int ret;
+
+ ret = wait_event_timeout(ctx->queue,
+ (ctx->int_cond && (ctx->int_type == command
+ || ctx->int_type == S5P_FIMV_R2H_CMD_ERR_RET)),
+ msecs_to_jiffies(MFC_INT_TIMEOUT));
+ if (ret == 0) {
+ mfc_err("Interrupt (ctx->int_type:%d, command:%d) timed out.\n",
+ ctx->int_type, command);
+ return 1;
+ }
+ mfc_debug(1, "Finished waiting (ctx->int_type:%d, command: %d).\n",
+ ctx->int_type, command);
+ /* RMVME: */
+ if (ctx->int_type == S5P_FIMV_R2H_CMD_RSV_RET)
+ return 1;
+ return 0;
+}
+
+void s5p_mfc_clean_ctx_int_flags(struct s5p_mfc_ctx *ctx)
+{
+ ctx->int_cond = 0;
+ ctx->int_type = 0;
+ ctx->int_err = 0;
+}
+
diff --git a/drivers/media/video/exynos/mfc/s5p_mfc_intr.h b/drivers/media/video/exynos/mfc/s5p_mfc_intr.h
new file mode 100644
index 0000000..9364b74
--- /dev/null
+++ b/drivers/media/video/exynos/mfc/s5p_mfc_intr.h
@@ -0,0 +1,25 @@
+/*
+ * drivers/media/video/exynos/mfc/s5p_mfc_intr.h
+ *
+ * Header file for Samsung MFC (Multi Function Codec - FIMV) driver
+ * It contains waiting functions declarations.
+ *
+ * Kamil Debski, Copyright (c) 2010 Samsung Electronics
+ * http://www.samsung.com/
+ *
+ * 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.
+ */
+
+#ifndef _S5P_MFC_INTR_H_
+#define _S5P_MFC_INTR_H_
+
+#include "s5p_mfc_common.h"
+
+int s5p_mfc_wait_for_done_ctx(struct s5p_mfc_ctx *ctx, int command);
+int s5p_mfc_wait_for_done_dev(struct s5p_mfc_dev *dev, int command);
+void s5p_mfc_clean_ctx_int_flags(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_clean_dev_int_flags(struct s5p_mfc_dev *dev);
+
+#endif /* _S5P_MFC_INTR_H_ */
diff --git a/drivers/media/video/exynos/mfc/s5p_mfc_mem.c b/drivers/media/video/exynos/mfc/s5p_mfc_mem.c
new file mode 100644
index 0000000..0acd75a
--- /dev/null
+++ b/drivers/media/video/exynos/mfc/s5p_mfc_mem.c
@@ -0,0 +1,230 @@
+/*
+ * linux/drivers/media/video/exynos/mfc/s5p_mfc_mem.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * 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.
+ */
+
+#include <linux/dma-mapping.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-memops.h>
+#include <asm/cacheflush.h>
+
+#include "s5p_mfc_common.h"
+#include "s5p_mfc_mem.h"
+#include "s5p_mfc_pm.h"
+#include "s5p_mfc_debug.h"
+
+#if defined(CONFIG_VIDEOBUF2_CMA_PHYS)
+static const char * const s5p_mem_types[] = {
+ MFC_CMA_FW,
+ MFC_CMA_BANK1,
+ MFC_CMA_BANK2,
+};
+
+static unsigned long s5p_mem_alignments[] = {
+ MFC_CMA_FW_ALIGN,
+ MFC_CMA_BANK1_ALIGN,
+ MFC_CMA_BANK2_ALIGN,
+};
+
+struct vb2_mem_ops *s5p_mfc_mem_ops(void)
+{
+ return (struct vb2_mem_ops *)&vb2_cma_phys_memops;
+}
+
+void **s5p_mfc_mem_init_multi(struct device *dev, unsigned int ctx_num)
+{
+/* TODO Cachable should be set */
+ return (void **)vb2_cma_phys_init_multi(dev, ctx_num,
+ s5p_mem_types,
+ s5p_mem_alignments, 0);
+}
+
+void s5p_mfc_mem_cleanup_multi(void **alloc_ctxes)
+{
+ vb2_cma_phys_cleanup_multi(alloc_ctxes);
+}
+#elif defined(CONFIG_VIDEOBUF2_ION)
+struct vb2_mem_ops *s5p_mfc_mem_ops(void)
+{
+ return (struct vb2_mem_ops *)&vb2_ion_memops;
+}
+
+void **s5p_mfc_mem_init_multi(struct device *dev, unsigned int ctx_num)
+{
+
+ struct s5p_mfc_dev *m_dev = platform_get_drvdata(to_platform_device(dev));
+ void **alloc_ctxes;
+ unsigned int i;
+
+ alloc_ctxes = kmalloc(sizeof(*alloc_ctxes) * ctx_num, GFP_KERNEL);
+ if (!alloc_ctxes)
+ return NULL;
+
+ for (i = 0; i < ctx_num; i++) {
+ alloc_ctxes[i] = vb2_ion_create_context(dev,
+ IS_MFCV6(m_dev) ? SZ_4K : SZ_128K,
+ VB2ION_CTX_VMCONTIG | VB2ION_CTX_IOMMU);
+ if (IS_ERR(alloc_ctxes[i]))
+ break;
+ }
+
+ if (i < ctx_num) {
+ while (i-- > 0)
+ vb2_ion_destroy_context(alloc_ctxes[i]);
+
+ kfree(alloc_ctxes);
+ alloc_ctxes = NULL;
+ }
+
+ return alloc_ctxes;
+}
+
+void s5p_mfc_mem_cleanup_multi(void **alloc_ctxes, unsigned int ctx_num)
+{
+ while (ctx_num-- > 0)
+ vb2_ion_destroy_context(alloc_ctxes[ctx_num]);
+
+ kfree(alloc_ctxes);
+}
+#endif
+
+#if defined(CONFIG_VIDEOBUF2_CMA_PHYS)
+struct vb2_cma_phys_conf {
+ struct device *dev;
+ const char *type;
+ unsigned long alignment;
+ bool cacheable;
+};
+
+struct vb2_cma_phys_buf {
+ struct vb2_cma_phys_conf *conf;
+ dma_addr_t paddr;
+ unsigned long size;
+ struct vm_area_struct *vma;
+ atomic_t refcount;
+ struct vb2_vmarea_handler handler;
+ bool cacheable;
+};
+void s5p_mfc_cache_clean(void *alloc_ctx)
+{
+ struct vb2_cma_phys_buf *buf = (struct vb2_cma_phys_buf *)alloc_ctx;
+ void *start_addr;
+ unsigned long size;
+ unsigned long paddr = (dma_addr_t)buf->paddr;
+
+ start_addr = (dma_addr_t *)phys_to_virt(buf->paddr);
+ size = buf->size;
+
+ dmac_map_area(start_addr, size, DMA_TO_DEVICE);
+ outer_clean_range(paddr, paddr + size);
+}
+
+void s5p_mfc_cache_inv(void *alloc_ctx)
+{
+ struct vb2_cma_phys_buf *buf = (struct vb2_cma_phys_buf *)alloc_ctx;
+ void *start_addr;
+ unsigned long size;
+ unsigned long paddr = (dma_addr_t)buf->paddr;
+
+ start_addr = (dma_addr_t *)phys_to_virt(buf->paddr);
+ size = buf->size;
+
+ outer_inv_range(paddr, paddr + size);
+ dmac_unmap_area(start_addr, size, DMA_FROM_DEVICE);
+}
+
+void s5p_mfc_mem_suspend(void *alloc_ctx)
+{
+ /* NOP */
+}
+
+void s5p_mfc_mem_resume(void *alloc_ctx)
+{
+ /* NOP */
+}
+
+void s5p_mfc_mem_set_cacheable(void *alloc_ctx, bool cacheable)
+{
+ vb2_cma_phys_set_cacheable(alloc_ctx, cacheable);
+}
+
+void s5p_mfc_mem_get_cacheable(void *alloc_ctx)
+{
+ /* NOP */
+}
+
+int s5p_mfc_mem_cache_flush(struct vb2_buffer *vb, u32 plane_no)
+{
+ vb2_cma_phys_cache_flush(vb, plane_no);
+ return 0;
+}
+#elif defined(CONFIG_VIDEOBUF2_ION)
+void s5p_mfc_cache_clean_priv(void *cookie)
+{
+ int nents = 0;
+ struct scatterlist *sg;
+
+ sg = vb2_ion_get_sg(cookie, &nents);
+
+ dma_sync_sg_for_device(NULL, sg, nents, DMA_TO_DEVICE);
+}
+
+void s5p_mfc_cache_inv_priv(void *cookie)
+{
+ int nents = 0;
+ struct scatterlist *sg;
+
+ sg = vb2_ion_get_sg(cookie, &nents);
+
+ dma_sync_sg_for_device(NULL, sg, nents, DMA_FROM_DEVICE);
+}
+
+void s5p_mfc_cache_clean(struct vb2_buffer *vb, int plane_no)
+{
+ void *cookie = vb2_plane_cookie(vb, plane_no);
+ int nents = 0;
+ struct scatterlist *sg;
+
+ sg = vb2_ion_get_sg(cookie, &nents);
+
+ dma_sync_sg_for_device(NULL, sg, nents, DMA_TO_DEVICE);
+}
+
+void s5p_mfc_cache_inv(struct vb2_buffer *vb, int plane_no)
+{
+ void *cookie = vb2_plane_cookie(vb, plane_no);
+ int nents = 0;
+ struct scatterlist *sg;
+
+ sg = vb2_ion_get_sg(cookie, &nents);
+
+ dma_sync_sg_for_device(NULL, sg, nents, DMA_FROM_DEVICE);
+}
+
+void s5p_mfc_mem_suspend(void *alloc_ctx)
+{
+ vb2_ion_detach_iommu(alloc_ctx);
+}
+
+int s5p_mfc_mem_resume(void *alloc_ctx)
+{
+ return vb2_ion_attach_iommu(alloc_ctx);
+}
+
+void s5p_mfc_mem_set_cacheable(void *alloc_ctx, bool cacheable)
+{
+ vb2_ion_set_cached(alloc_ctx, cacheable);
+}
+
+int s5p_mfc_mem_cache_flush(struct vb2_buffer *vb, u32 plane_no)
+{
+ return vb2_ion_cache_flush(vb, plane_no);
+}
+#endif
diff --git a/drivers/media/video/exynos/mfc/s5p_mfc_mem.h b/drivers/media/video/exynos/mfc/s5p_mfc_mem.h
new file mode 100644
index 0000000..69ab214
--- /dev/null
+++ b/drivers/media/video/exynos/mfc/s5p_mfc_mem.h
@@ -0,0 +1,137 @@
+/*
+ * linux/drivers/media/video/exynos/mfc/s5p_mfc_mem.h
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * 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.
+ */
+
+#ifndef __S5P_MFC_MEM_H_
+#define __S5P_MFC_MEM_H_ __FILE__
+
+#include <linux/platform_device.h>
+
+#if defined(CONFIG_VIDEOBUF2_CMA_PHYS)
+#include <media/videobuf2-cma-phys.h>
+#elif defined(CONFIG_VIDEOBUF2_ION)
+#include <media/videobuf2-ion.h>
+#endif
+
+/* Offset base used to differentiate between CAPTURE and OUTPUT
+* while mmaping */
+#define DST_QUEUE_OFF_BASE (TASK_SIZE / 2)
+
+#if defined(CONFIG_VIDEOBUF2_CMA_PHYS)
+/* Define names for CMA memory kinds used by MFC */
+#define MFC_CMA_BANK1 "a"
+#define MFC_CMA_BANK2 "b"
+#define MFC_CMA_FW "f"
+
+#define MFC_CMA_FW_ALLOC_CTX 0
+#define MFC_CMA_BANK1_ALLOC_CTX 1
+#define MFC_CMA_BANK2_ALLOC_CTX 2
+
+#define MFC_CMA_BANK1_ALIGN 0x2000 /* 8KB */
+#define MFC_CMA_BANK2_ALIGN 0x2000 /* 8KB */
+#define MFC_CMA_FW_ALIGN 0x20000 /* 128KB */
+
+#define s5p_mfc_mem_plane_addr(c, v, n) \
+ do { \
+ (dma_addr_t)vb2_cma_phys_plane_paddr(v, n) \
+ } while (0)
+
+static inline void *s5p_mfc_mem_alloc(void *alloc_ctx, unsigned long size)
+{
+ return vb2_cma_phys_memops.alloc(alloc_ctx, size);
+}
+
+static inline void s5p_mfc_mem_free(void *vb_priv)
+{
+ vb2_cma_phys_memops.put(vb_priv);
+}
+
+static inline dma_addr_t s5p_mfc_mem_daddr(void *vb_priv)
+{
+ return (dma_addr_t)vb2_cma_phys_memops.cookie(vb_priv);
+}
+
+static inline void *s5p_mfc_mem_vaddr(void *vb_priv)
+{
+ return vb2_cma_phys_memops.vaddr(vb_priv);
+}
+#elif defined(CONFIG_VIDEOBUF2_ION)
+#define MFC_ALLOC_CTX_NUM 2
+
+#define MFC_BANK_A_ALLOC_CTX 0
+#define MFC_BANK_B_ALLOC_CTX 1
+
+#define MFC_BANK_A_ALIGN_ORDER 11
+#define MFC_BANK_B_ALIGN_ORDER 11
+
+#define MFC_CMA_BANK1_ALLOC_CTX MFC_BANK_A_ALLOC_CTX
+#define MFC_CMA_BANK2_ALLOC_CTX MFC_BANK_B_ALLOC_CTX
+#define MFC_CMA_FW_ALLOC_CTX MFC_BANK_A_ALLOC_CTX
+
+static inline dma_addr_t s5p_mfc_mem_plane_addr(
+ struct s5p_mfc_ctx *c, struct vb2_buffer *v, unsigned int n)
+{
+ void *cookie = vb2_plane_cookie(v, n);
+ dma_addr_t addr = 0;
+
+#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
+ if (c->is_drm)
+ WARN_ON(vb2_ion_phys_address(cookie,
+ (phys_addr_t *)&addr) != 0);
+ else
+ WARN_ON(vb2_ion_dma_address(cookie, &addr) != 0);
+#else
+ WARN_ON(vb2_ion_dma_address(cookie, &addr) != 0);
+#endif
+
+ return (unsigned long)addr;
+}
+
+static inline void *s5p_mfc_mem_alloc(void *alloc_ctx, unsigned int size)
+{
+ return vb2_ion_private_alloc(alloc_ctx, size);
+}
+
+static inline void s5p_mfc_mem_free(void *cookie)
+{
+ vb2_ion_private_free(cookie);
+}
+
+static inline dma_addr_t s5p_mfc_mem_daddr(void *cookie)
+{
+ dma_addr_t addr = 0;
+
+ WARN_ON(vb2_ion_dma_address(cookie, &addr) != 0);
+
+ return addr;
+}
+
+static inline void *s5p_mfc_mem_vaddr(void *cookie)
+{
+ return vb2_ion_private_vaddr(cookie);
+}
+#endif
+
+struct vb2_mem_ops *s5p_mfc_mem_ops(void);
+void **s5p_mfc_mem_init_multi(struct device *dev, unsigned int ctx_num);
+void s5p_mfc_mem_cleanup_multi(void **alloc_ctxes, unsigned int ctx_num);
+
+void s5p_mfc_cache_clean_priv(void *cookie);
+void s5p_mfc_cache_inv_priv(void *cookie);
+void s5p_mfc_cache_clean(struct vb2_buffer *vb, int plane_no);
+void s5p_mfc_cache_inv(struct vb2_buffer *vb, int plane_no);
+
+void s5p_mfc_mem_suspend(void *alloc_ctx);
+int s5p_mfc_mem_resume(void *alloc_ctx);
+
+void s5p_mfc_mem_set_cacheable(void *alloc_ctx, bool cacheable);
+int s5p_mfc_mem_cache_flush(struct vb2_buffer *vb, u32 plane_no);
+#endif /* __S5P_MFC_MEM_H_ */
diff --git a/drivers/media/video/exynos/mfc/s5p_mfc_opr_v5.c b/drivers/media/video/exynos/mfc/s5p_mfc_opr_v5.c
new file mode 100644
index 0000000..6d0e1b3
--- /dev/null
+++ b/drivers/media/video/exynos/mfc/s5p_mfc_opr_v5.c
@@ -0,0 +1,1770 @@
+/*
+ * drivers/media/video/exynos/mfc/s5p_mfc_opr_v5.c
+ *
+ * Samsung MFC (Multi Function Codec - FIMV) driver
+ * This file contains hw related functions.
+ *
+ * Kamil Debski, Copyright (c) 2010 Samsung Electronics
+ * http://www.samsung.com/
+ *
+ * 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.
+ */
+
+#define DEBUG
+
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/io.h>
+#include <linux/jiffies.h>
+
+#include <linux/firmware.h>
+#include <linux/err.h>
+#include <linux/sched.h>
+#include <linux/cma.h>
+
+#include <linux/dma-mapping.h>
+#include <asm/cacheflush.h>
+
+#include "s5p_mfc_common.h"
+
+#include "s5p_mfc_mem.h"
+#include "s5p_mfc_intr.h"
+#include "s5p_mfc_inst.h"
+#include "s5p_mfc_pm.h"
+#include "s5p_mfc_debug.h"
+
+/* #define S5P_MFC_DEBUG_REGWRITE */
+#ifdef S5P_MFC_DEBUG_REGWRITE
+#undef writel
+#define writel(v, r) \
+ do { \
+ printk(KERN_ERR "MFCWRITE(%p): %08x\n", r, (unsigned int)v); \
+ __raw_writel(v, r); \
+ } while (0)
+#endif /* S5P_MFC_DEBUG_REGWRITE */
+
+#define READL(offset) readl(dev->regs_base + (offset))
+#define WRITEL(data, offset) writel((data), dev->regs_base + (offset))
+#define OFFSETA(x) (((x) - dev->port_a) >> S5P_FIMV_MEM_OFFSET)
+#define OFFSETB(x) (((x) - dev->port_b) >> S5P_FIMV_MEM_OFFSET)
+
+/* Allocate temporary buffers for decoding */
+int s5p_mfc_alloc_dec_temp_buffers(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+ struct s5p_mfc_buf_size_v5 *buf_size = dev->variant->buf_size->buf;
+
+ mfc_debug_enter();
+
+ dec->dsc.alloc = s5p_mfc_mem_alloc(
+ dev->alloc_ctx[MFC_CMA_BANK1_ALLOC_CTX], buf_size->desc_buf);
+ if (IS_ERR(dec->dsc.alloc)) {
+ mfc_err("Allocating DESC buffer failed.\n");
+ return PTR_ERR(dec->dsc.alloc);
+ }
+
+ dec->dsc.ofs = OFFSETA(s5p_mfc_mem_daddr(dec->dsc.alloc));
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+/* Release temproary buffers for decoding */
+void s5p_mfc_release_dec_desc_buffer(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+
+ if (dec->dsc.alloc) {
+ s5p_mfc_mem_free(dec->dsc.alloc);
+ dec->dsc.alloc = NULL;
+ dec->dsc.ofs = 0;
+ dec->dsc.virt = NULL;
+ }
+}
+
+/* Allocate codec buffers */
+int s5p_mfc_alloc_codec_buffers(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+ unsigned int enc_ref_y_size = 0;
+ unsigned int enc_ref_c_size = 0;
+ unsigned int guard_width, guard_height;
+
+ mfc_debug_enter();
+
+ if (ctx->type == MFCINST_DECODER) {
+ mfc_debug(2, "Luma size:%d Chroma size:%d MV size:%d\n",
+ ctx->luma_size, ctx->chroma_size, ctx->mv_size);
+ mfc_debug(2, "Totals bufs: %d\n", dec->total_dpb_count);
+ } else if (ctx->type == MFCINST_ENCODER) {
+ enc_ref_y_size = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN)
+ * ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN);
+ enc_ref_y_size = ALIGN(enc_ref_y_size, S5P_FIMV_NV12MT_SALIGN);
+
+ if (ctx->codec_mode == S5P_FIMV_CODEC_H264_ENC) {
+ enc_ref_c_size = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN)
+ * ALIGN((ctx->img_height >> 1), S5P_FIMV_NV12MT_VALIGN);
+ enc_ref_c_size = ALIGN(enc_ref_c_size, S5P_FIMV_NV12MT_SALIGN);
+ } else {
+ guard_width = ALIGN(ctx->img_width + 16, S5P_FIMV_NV12MT_HALIGN);
+ guard_height = ALIGN((ctx->img_height >> 1) + 4, S5P_FIMV_NV12MT_VALIGN);
+ enc_ref_c_size = ALIGN(guard_width * guard_height,
+ S5P_FIMV_NV12MT_SALIGN);
+ }
+
+ mfc_debug(2, "recon luma size: %d chroma size: %d\n",
+ enc_ref_y_size, enc_ref_c_size);
+ } else {
+ return -EINVAL;
+ }
+
+ /* Codecs have different memory requirements */
+ switch (ctx->codec_mode) {
+ case S5P_FIMV_CODEC_H264_DEC:
+ ctx->port_a_size =
+ ALIGN(S5P_FIMV_DEC_NB_IP_SIZE +
+ S5P_FIMV_DEC_VERT_NB_MV_SIZE,
+ S5P_FIMV_DEC_BUF_ALIGN);
+ /* TODO, when merged with FIMC then test will it work without
+ * alignment to 8192. For all codecs. */
+ ctx->port_b_size = dec->total_dpb_count * ctx->mv_size;
+ break;
+ case S5P_FIMV_CODEC_MPEG4_DEC:
+ case S5P_FIMV_CODEC_FIMV1_DEC:
+ case S5P_FIMV_CODEC_FIMV2_DEC:
+ case S5P_FIMV_CODEC_FIMV3_DEC:
+ case S5P_FIMV_CODEC_FIMV4_DEC:
+ ctx->port_a_size =
+ ALIGN(S5P_FIMV_DEC_NB_DCAC_SIZE +
+ S5P_FIMV_DEC_UPNB_MV_SIZE +
+ S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE +
+ S5P_FIMV_DEC_STX_PARSER_SIZE +
+ S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE,
+ S5P_FIMV_DEC_BUF_ALIGN);
+ ctx->port_b_size = 0;
+ break;
+
+ case S5P_FIMV_CODEC_VC1RCV_DEC:
+ case S5P_FIMV_CODEC_VC1_DEC:
+ ctx->port_a_size =
+ ALIGN(S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE +
+ S5P_FIMV_DEC_UPNB_MV_SIZE +
+ S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE +
+ S5P_FIMV_DEC_NB_DCAC_SIZE +
+ 3 * S5P_FIMV_DEC_VC1_BITPLANE_SIZE,
+ S5P_FIMV_DEC_BUF_ALIGN);
+ ctx->port_b_size = 0;
+ break;
+
+ case S5P_FIMV_CODEC_MPEG2_DEC:
+ ctx->port_a_size = 0;
+ ctx->port_b_size = 0;
+ break;
+ case S5P_FIMV_CODEC_H263_DEC:
+ ctx->port_a_size =
+ ALIGN(S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE +
+ S5P_FIMV_DEC_UPNB_MV_SIZE +
+ S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE +
+ S5P_FIMV_DEC_NB_DCAC_SIZE,
+ S5P_FIMV_DEC_BUF_ALIGN);
+ ctx->port_b_size = 0;
+ break;
+
+ case S5P_FIMV_CODEC_H264_ENC:
+ ctx->port_a_size = (enc_ref_y_size * 2) +
+ S5P_FIMV_ENC_UPMV_SIZE +
+ S5P_FIMV_ENC_COLFLG_SIZE +
+ S5P_FIMV_ENC_INTRAMD_SIZE +
+ S5P_FIMV_ENC_NBORINFO_SIZE;
+ ctx->port_b_size = (enc_ref_y_size * 2) +
+ (enc_ref_c_size * 4) +
+ S5P_FIMV_ENC_INTRAPRED_SIZE;
+ break;
+ case S5P_FIMV_CODEC_MPEG4_ENC:
+ ctx->port_a_size = (enc_ref_y_size * 2) +
+ S5P_FIMV_ENC_UPMV_SIZE +
+ S5P_FIMV_ENC_COLFLG_SIZE +
+ S5P_FIMV_ENC_ACDCCOEF_SIZE;
+ ctx->port_b_size = (enc_ref_y_size * 2) +
+ (enc_ref_c_size * 4);
+ break;
+ case S5P_FIMV_CODEC_H263_ENC:
+ ctx->port_a_size = (enc_ref_y_size * 2) +
+ S5P_FIMV_ENC_UPMV_SIZE +
+ S5P_FIMV_ENC_ACDCCOEF_SIZE;
+ ctx->port_b_size = (enc_ref_y_size * 2) +
+ (enc_ref_c_size * 4);
+ break;
+ default:
+ break;
+ }
+
+ /* Allocate only if memory from bank 1 is necessary */
+ if (ctx->port_a_size > 0) {
+ ctx->port_a_buf = s5p_mfc_mem_alloc(
+ dev->alloc_ctx[MFC_CMA_BANK1_ALLOC_CTX], ctx->port_a_size);
+ if (IS_ERR(ctx->port_a_buf)) {
+ ctx->port_a_buf = 0;
+ printk(KERN_ERR
+ "Buf alloc for decoding failed (port A).\n");
+ return -ENOMEM;
+ }
+ ctx->port_a_phys = s5p_mfc_mem_daddr(ctx->port_a_buf);
+ }
+
+ /* Allocate only if memory from bank 2 is necessary */
+ if (ctx->port_b_size > 0) {
+ ctx->port_b_buf = s5p_mfc_mem_alloc(
+ dev->alloc_ctx[MFC_CMA_BANK2_ALLOC_CTX], ctx->port_b_size);
+ if (IS_ERR(ctx->port_b_buf)) {
+ ctx->port_b_buf = 0;
+ mfc_err("Buf alloc for decoding failed (port B).\n");
+ return -ENOMEM;
+ }
+ ctx->port_b_phys = s5p_mfc_mem_daddr(ctx->port_b_buf);
+ }
+ mfc_debug_leave();
+
+ return 0;
+}
+
+/* Release buffers allocated for codec */
+void s5p_mfc_release_codec_buffers(struct s5p_mfc_ctx *ctx)
+{
+ if (ctx->port_a_buf) {
+ s5p_mfc_mem_free(ctx->port_a_buf);
+ ctx->port_a_buf = 0;
+ ctx->port_a_phys = 0;
+ ctx->port_a_size = 0;
+ }
+ if (ctx->port_b_buf) {
+ s5p_mfc_mem_free(ctx->port_b_buf);
+ ctx->port_b_buf = 0;
+ ctx->port_b_phys = 0;
+ ctx->port_b_size = 0;
+ }
+}
+
+/* Allocate memory for instance data buffer */
+int s5p_mfc_alloc_instance_buffer(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_buf_size_v5 *buf_size = dev->variant->buf_size->buf;
+
+ mfc_debug_enter();
+
+ if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC)
+ ctx->ctx_buf_size = buf_size->h264_ctx_buf;
+ else
+ ctx->ctx_buf_size = buf_size->non_h264_ctx_buf;
+
+ ctx->ctx.alloc = s5p_mfc_mem_alloc(
+ dev->alloc_ctx[MFC_CMA_BANK1_ALLOC_CTX], ctx->ctx_buf_size);
+ if (IS_ERR(ctx->ctx.alloc)) {
+ mfc_err("Allocating context buffer failed.\n");
+ return PTR_ERR(ctx->ctx.alloc);
+ }
+
+ ctx->ctx.ofs = OFFSETA(s5p_mfc_mem_daddr(ctx->ctx.alloc));
+
+ ctx->ctx.virt = s5p_mfc_mem_vaddr(ctx->ctx.alloc);
+ if (!ctx->ctx.virt) {
+ s5p_mfc_mem_free(ctx->ctx.alloc);
+ ctx->ctx.alloc = NULL;
+ ctx->ctx.ofs = 0;
+ ctx->ctx.virt = NULL;
+
+ mfc_err("Remapping context buffer failed.\n");
+ return -ENOMEM;
+ }
+
+ memset(ctx->ctx.virt, 0, ctx->ctx_buf_size);
+ s5p_mfc_cache_clean_priv(ctx->ctx.alloc);
+ /*
+ ctx->ctx.dma = dma_map_single(ctx->dev->v4l2_dev.dev,
+ ctx->ctx.virt, ctx->ctx_buf_size,
+ DMA_TO_DEVICE);
+ */
+
+ if (s5p_mfc_init_shm(ctx) < 0) {
+ s5p_mfc_mem_free(ctx->ctx.alloc);
+ ctx->ctx.alloc = NULL;
+ ctx->ctx.ofs = 0;
+ ctx->ctx.virt = NULL;
+
+ mfc_err("Remapping shared mem buffer failed.\n");
+ return -ENOMEM;
+ }
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+/* Release instance buffer */
+void s5p_mfc_release_instance_buffer(struct s5p_mfc_ctx *ctx)
+{
+ mfc_debug_enter();
+
+ if (ctx->ctx.alloc) {
+ /*
+ dma_unmap_single(ctx->dev->v4l2_dev.dev,
+ ctx->ctx.dma, ctx->ctx_buf_size,
+ DMA_TO_DEVICE);
+ */
+ s5p_mfc_mem_free(ctx->ctx.alloc);
+ ctx->ctx.alloc = NULL;
+ ctx->ctx.ofs = 0;
+ ctx->ctx.virt = NULL;
+ }
+ if (ctx->shm.alloc) {
+ s5p_mfc_mem_free(ctx->shm.alloc);
+ ctx->shm.alloc = NULL;
+ ctx->shm.ofs = 0;
+ ctx->shm.virt = NULL;
+ }
+
+ mfc_debug_leave();
+}
+
+int s5p_mfc_alloc_dev_context_buffer(struct s5p_mfc_dev *dev)
+{
+ /* NOP */
+
+ return 0;
+}
+
+void s5p_mfc_release_dev_context_buffer(struct s5p_mfc_dev *dev)
+{
+ /* NOP */
+}
+
+void s5p_mfc_dec_calc_dpb_size(struct s5p_mfc_ctx *ctx)
+{
+ unsigned int guard_width, guard_height;
+
+ ctx->buf_width = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN);
+ ctx->buf_height = ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN);
+ mfc_debug(2, "SEQ Done: Movie dimensions %dx%d, "
+ "buffer dimensions: %dx%d\n", ctx->img_width,
+ ctx->img_height, ctx->buf_width, ctx->buf_height);
+
+ if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC) {
+ ctx->luma_size = ALIGN(ctx->buf_width * ctx->buf_height,
+ S5P_FIMV_DEC_BUF_ALIGN);
+ ctx->chroma_size = ALIGN(ctx->buf_width *
+ ALIGN((ctx->img_height >> 1),
+ S5P_FIMV_NV12MT_VALIGN),
+ S5P_FIMV_DEC_BUF_ALIGN);
+ ctx->mv_size = ALIGN(ctx->buf_width *
+ ALIGN((ctx->buf_height >> 2),
+ S5P_FIMV_NV12MT_VALIGN),
+ S5P_FIMV_DEC_BUF_ALIGN);
+ } else {
+ guard_width = ALIGN(ctx->img_width + 24, S5P_FIMV_NV12MT_HALIGN);
+ guard_height = ALIGN(ctx->img_height + 16, S5P_FIMV_NV12MT_VALIGN);
+ ctx->luma_size = ALIGN(guard_width * guard_height,
+ S5P_FIMV_DEC_BUF_ALIGN);
+
+ guard_width = ALIGN(ctx->img_width + 16, S5P_FIMV_NV12MT_HALIGN);
+ guard_height = ALIGN((ctx->img_height >> 1) + 4, S5P_FIMV_NV12MT_VALIGN);
+ ctx->chroma_size = ALIGN(guard_width * guard_height,
+ S5P_FIMV_DEC_BUF_ALIGN);
+
+ ctx->mv_size = 0;
+ }
+}
+
+void s5p_mfc_enc_calc_src_size(struct s5p_mfc_ctx *ctx)
+{
+ if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M) {
+ ctx->buf_width = ALIGN(ctx->img_width, S5P_FIMV_NV12M_HALIGN);
+
+ ctx->luma_size = ALIGN(ctx->img_width, S5P_FIMV_NV12M_HALIGN)
+ * ALIGN(ctx->img_height, S5P_FIMV_NV12M_LVALIGN);
+ ctx->chroma_size = ALIGN(ctx->img_width, S5P_FIMV_NV12M_HALIGN)
+ * ALIGN((ctx->img_height >> 1), S5P_FIMV_NV12M_CVALIGN);
+
+ ctx->luma_size = ALIGN(ctx->luma_size, S5P_FIMV_NV12M_SALIGN);
+ ctx->chroma_size = ALIGN(ctx->chroma_size, S5P_FIMV_NV12M_SALIGN);
+ } else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT) {
+ ctx->buf_width = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN);
+
+ ctx->luma_size = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN)
+ * ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN);
+ ctx->chroma_size = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN)
+ * ALIGN((ctx->img_height >> 1), S5P_FIMV_NV12MT_VALIGN);
+
+ ctx->luma_size = ALIGN(ctx->luma_size, S5P_FIMV_NV12MT_SALIGN);
+ ctx->chroma_size = ALIGN(ctx->chroma_size, S5P_FIMV_NV12MT_SALIGN);
+ }
+}
+
+/* Set registers for decoding temporary buffers */
+void s5p_mfc_set_dec_desc_buffer(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+ struct s5p_mfc_buf_size_v5 *buf_size = dev->variant->buf_size->buf;
+
+ WRITEL(dec->dsc.ofs, S5P_FIMV_SI_CH0_DESC_ADR);
+ WRITEL(buf_size->desc_buf, S5P_FIMV_SI_CH0_DESC_SIZE);
+}
+
+/* Set registers for shared buffer */
+void s5p_mfc_set_shared_buffer(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+
+ WRITEL(ctx->shm.ofs, S5P_FIMV_SI_CH0_HOST_WR_ADR);
+}
+
+/* Set registers for decoding stream buffer */
+int s5p_mfc_set_dec_stream_buffer(struct s5p_mfc_ctx *ctx, dma_addr_t buf_addr,
+ unsigned int start_num_byte, unsigned int buf_size)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_buf_size *variant_buf_size = dev->variant->buf_size;
+
+ mfc_debug_enter();
+ mfc_debug(2, "inst_no: %d, buf_addr: 0x%08lx, buf_size: 0x"\
+ "%08x (%d)\n", ctx->inst_no, (unsigned long)buf_addr,
+ buf_size, buf_size);
+ WRITEL(OFFSETA(buf_addr), S5P_FIMV_SI_CH0_SB_ST_ADR);
+ WRITEL(variant_buf_size->cpb_buf, S5P_FIMV_SI_CH0_CPB_SIZE);
+ WRITEL(buf_size, S5P_FIMV_SI_CH0_SB_FRM_SIZE);
+ mfc_debug(2, "Shared_virt: %p (start offset: %d)\n",
+ ctx->shm.virt, start_num_byte);
+ s5p_mfc_write_info(ctx, start_num_byte, START_BYTE_NUM);
+ mfc_debug_leave();
+ return 0;
+}
+
+/* Set decoding frame buffer */
+int s5p_mfc_set_dec_frame_buffer(struct s5p_mfc_ctx *ctx)
+{
+ unsigned int frame_size, i;
+ unsigned int frame_size_ch, frame_size_mv;
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+ unsigned int dpb;
+ dma_addr_t buf_addr1, buf_addr2;
+ int buf_size1, buf_size2;
+ struct s5p_mfc_buf *buf;
+ struct list_head *buf_queue;
+
+ buf_addr1 = ctx->port_a_phys;
+ buf_size1 = ctx->port_a_size;
+ buf_addr2 = ctx->port_b_phys;
+ buf_size2 = ctx->port_b_size;
+
+ mfc_debug(2, "Buf1: %p (%d) Buf2: %p (%d)\n",
+ (void *)buf_addr1, buf_size1,
+ (void *)buf_addr2, buf_size2);
+ mfc_debug(2, "Total DPB COUNT: %d\n", dec->total_dpb_count);
+ mfc_debug(2, "Setting display delay to %d\n", dec->display_delay);
+
+ dpb = READL(S5P_FIMV_SI_CH0_DPB_CONF_CTRL) & ~S5P_FIMV_DPB_COUNT_MASK;
+ WRITEL(dec->total_dpb_count | dpb, S5P_FIMV_SI_CH0_DPB_CONF_CTRL);
+
+ s5p_mfc_set_shared_buffer(ctx);
+
+ switch (ctx->codec_mode) {
+ case S5P_FIMV_CODEC_H264_DEC:
+ WRITEL(OFFSETA(buf_addr1), S5P_FIMV_H264_VERT_NB_MV_ADR);
+ buf_addr1 += S5P_FIMV_DEC_VERT_NB_MV_SIZE;
+ buf_size1 -= S5P_FIMV_DEC_VERT_NB_MV_SIZE;
+ WRITEL(OFFSETA(buf_addr1), S5P_FIMV_H264_NB_IP_ADR);
+ buf_addr1 += S5P_FIMV_DEC_NB_IP_SIZE;
+ buf_size1 -= S5P_FIMV_DEC_NB_IP_SIZE;
+ break;
+ case S5P_FIMV_CODEC_MPEG4_DEC:
+ case S5P_FIMV_CODEC_FIMV1_DEC:
+ case S5P_FIMV_CODEC_FIMV2_DEC:
+ case S5P_FIMV_CODEC_FIMV3_DEC:
+ case S5P_FIMV_CODEC_FIMV4_DEC:
+ WRITEL(OFFSETA(buf_addr1), S5P_FIMV_MPEG4_NB_DCAC_ADR);
+ buf_addr1 += S5P_FIMV_DEC_NB_DCAC_SIZE;
+ buf_size1 -= S5P_FIMV_DEC_NB_DCAC_SIZE;
+ WRITEL(OFFSETA(buf_addr1), S5P_FIMV_MPEG4_UP_NB_MV_ADR);
+ buf_addr1 += S5P_FIMV_DEC_UPNB_MV_SIZE;
+ buf_size1 -= S5P_FIMV_DEC_UPNB_MV_SIZE;
+ WRITEL(OFFSETA(buf_addr1), S5P_FIMV_MPEG4_SA_MV_ADR);
+ buf_addr1 += S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE;
+ buf_size1 -= S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE;
+ WRITEL(OFFSETA(buf_addr1), S5P_FIMV_MPEG4_SP_ADR);
+ buf_addr1 += S5P_FIMV_DEC_STX_PARSER_SIZE;
+ buf_size1 -= S5P_FIMV_DEC_STX_PARSER_SIZE;
+ WRITEL(OFFSETA(buf_addr1), S5P_FIMV_MPEG4_OT_LINE_ADR);
+ buf_addr1 += S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE;
+ buf_size1 -= S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE;
+ break;
+ case S5P_FIMV_CODEC_H263_DEC:
+ WRITEL(OFFSETA(buf_addr1), S5P_FIMV_H263_OT_LINE_ADR);
+ buf_addr1 += S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE;
+ buf_size1 -= S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE;
+ WRITEL(OFFSETA(buf_addr1), S5P_FIMV_H263_UP_NB_MV_ADR);
+ buf_addr1 += S5P_FIMV_DEC_UPNB_MV_SIZE;
+ buf_size1 -= S5P_FIMV_DEC_UPNB_MV_SIZE;
+ WRITEL(OFFSETA(buf_addr1), S5P_FIMV_H263_SA_MV_ADR);
+ buf_addr1 += S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE;
+ buf_size1 -= S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE;
+ WRITEL(OFFSETA(buf_addr1), S5P_FIMV_H263_NB_DCAC_ADR);
+ buf_addr1 += S5P_FIMV_DEC_NB_DCAC_SIZE;
+ buf_size1 -= S5P_FIMV_DEC_NB_DCAC_SIZE;
+ break;
+ case S5P_FIMV_CODEC_VC1_DEC:
+ case S5P_FIMV_CODEC_VC1RCV_DEC:
+ WRITEL(OFFSETA(buf_addr1), S5P_FIMV_VC1_NB_DCAC_ADR);
+ buf_addr1 += S5P_FIMV_DEC_NB_DCAC_SIZE;
+ buf_size1 -= S5P_FIMV_DEC_NB_DCAC_SIZE;
+ WRITEL(OFFSETA(buf_addr1), S5P_FIMV_VC1_OT_LINE_ADR);
+ buf_addr1 += S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE;
+ buf_size1 -= S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE;
+ WRITEL(OFFSETA(buf_addr1), S5P_FIMV_VC1_UP_NB_MV_ADR);
+ buf_addr1 += S5P_FIMV_DEC_UPNB_MV_SIZE;
+ buf_size1 -= S5P_FIMV_DEC_UPNB_MV_SIZE;
+ WRITEL(OFFSETA(buf_addr1), S5P_FIMV_VC1_SA_MV_ADR);
+ buf_addr1 += S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE;
+ buf_size1 -= S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE;
+ WRITEL(OFFSETA(buf_addr1), S5P_FIMV_VC1_BITPLANE3_ADR);
+ buf_addr1 += S5P_FIMV_DEC_VC1_BITPLANE_SIZE;
+ buf_size1 -= S5P_FIMV_DEC_VC1_BITPLANE_SIZE;
+ WRITEL(OFFSETA(buf_addr1), S5P_FIMV_VC1_BITPLANE2_ADR);
+ buf_addr1 += S5P_FIMV_DEC_VC1_BITPLANE_SIZE;
+ buf_size1 -= S5P_FIMV_DEC_VC1_BITPLANE_SIZE;
+ WRITEL(OFFSETA(buf_addr1), S5P_FIMV_VC1_BITPLANE1_ADR);
+ buf_addr1 += S5P_FIMV_DEC_VC1_BITPLANE_SIZE;
+ buf_size1 -= S5P_FIMV_DEC_VC1_BITPLANE_SIZE;
+ break;
+ case S5P_FIMV_CODEC_MPEG2_DEC:
+ break;
+ default:
+ mfc_err("Unknown codec for decoding (%x).\n",
+ ctx->codec_mode);
+ return -EINVAL;
+ break;
+ }
+ frame_size = ctx->luma_size;
+ frame_size_ch = ctx->chroma_size;
+ frame_size_mv = ctx->mv_size;
+ mfc_debug(2, "Frame size: %d ch: %d mv: %d\n", frame_size, frame_size_ch,
+ frame_size_mv);
+
+ i = 0;
+ if (dec->dst_memtype == V4L2_MEMORY_USERPTR)
+ buf_queue = &ctx->dst_queue;
+ else
+ buf_queue = &dec->dpb_queue;
+ list_for_each_entry(buf, buf_queue, list) {
+ mfc_debug(2, "Luma 0x%08lx\n",
+ (unsigned long)buf->planes.raw.luma);
+ WRITEL(OFFSETB(buf->planes.raw.luma),
+ S5P_FIMV_DEC_LUMA_ADR + i * 4);
+ mfc_debug(2, "\tChroma 0x%08lx\n",
+ (unsigned long)buf->planes.raw.chroma);
+ WRITEL(OFFSETA(buf->planes.raw.chroma),
+ S5P_FIMV_DEC_CHROMA_ADR + i * 4);
+
+ if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC) {
+ mfc_debug(2, "\tBuf2: 0x%08lx, size: %d\n",
+ (unsigned long)buf_addr2, buf_size2);
+ WRITEL(OFFSETB(buf_addr2), S5P_FIMV_H264_MV_ADR + i * 4);
+ buf_addr2 += frame_size_mv;
+ buf_size2 -= frame_size_mv;
+ }
+
+ i++;
+ }
+
+ mfc_debug(2, "Buf1: 0x%08lx, buf_size1: %d\n",
+ (unsigned long)buf_addr1, buf_size1);
+ mfc_debug(2, "Buf 1/2 size after: %d/%d (frames %d)\n",
+ buf_size1, buf_size2, dec->total_dpb_count);
+ if (buf_size1 < 0 || buf_size2 < 0) {
+ mfc_debug(2, "Not enough memory has been allocated.\n");
+ return -ENOMEM;
+ }
+
+ s5p_mfc_write_info(ctx, frame_size, ALLOC_LUMA_DPB_SIZE);
+ s5p_mfc_write_info(ctx, frame_size_ch, ALLOC_CHROMA_DPB_SIZE);
+
+ if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC)
+ s5p_mfc_write_info(ctx, frame_size_mv, ALLOC_MV_SIZE);
+
+ WRITEL(((S5P_FIMV_CH_INIT_BUFS & S5P_FIMV_CH_MASK) << S5P_FIMV_CH_SHIFT)
+ | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID);
+
+ mfc_debug(2, "After setting buffers.\n");
+ return 0;
+}
+
+/* Set registers for encoding stream buffer */
+int s5p_mfc_set_enc_stream_buffer(struct s5p_mfc_ctx *ctx,
+ dma_addr_t addr, unsigned int size)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+
+ WRITEL(OFFSETA(addr), S5P_FIMV_ENC_SI_CH0_SB_ADR);
+ WRITEL(size, S5P_FIMV_ENC_SI_CH0_SB_SIZE);
+
+ return 0;
+}
+
+void s5p_mfc_set_enc_frame_buffer(struct s5p_mfc_ctx *ctx,
+ dma_addr_t y_addr, dma_addr_t c_addr)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+
+ WRITEL(OFFSETB(y_addr), S5P_FIMV_ENC_SI_CH0_CUR_Y_ADR);
+ WRITEL(OFFSETB(c_addr), S5P_FIMV_ENC_SI_CH0_CUR_C_ADR);
+}
+
+void s5p_mfc_get_enc_frame_buffer(struct s5p_mfc_ctx *ctx,
+ dma_addr_t *y_addr, dma_addr_t *c_addr)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+
+ *y_addr = dev->port_b + (READL(S5P_FIMV_ENCODED_Y_ADDR) << 11);
+ *c_addr = dev->port_b + (READL(S5P_FIMV_ENCODED_C_ADDR) << 11);
+}
+
+/* Set encoding ref & codec buffer */
+int s5p_mfc_set_enc_ref_buffer(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ size_t buf_addr1, buf_addr2;
+ size_t buf_size1, buf_size2;
+ unsigned int enc_ref_y_size, enc_ref_c_size;
+ unsigned int guard_width, guard_height;
+ int i;
+
+ mfc_debug_enter();
+
+ buf_addr1 = ctx->port_a_phys;
+ buf_size1 = ctx->port_a_size;
+ buf_addr2 = ctx->port_b_phys;
+ buf_size2 = ctx->port_b_size;
+
+ enc_ref_y_size = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN)
+ * ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN);
+ enc_ref_y_size = ALIGN(enc_ref_y_size, S5P_FIMV_NV12MT_SALIGN);
+
+ if (ctx->codec_mode == S5P_FIMV_CODEC_H264_ENC) {
+ enc_ref_c_size = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN)
+ * ALIGN((ctx->img_height >> 1), S5P_FIMV_NV12MT_VALIGN);
+ enc_ref_c_size = ALIGN(enc_ref_c_size, S5P_FIMV_NV12MT_SALIGN);
+ } else {
+ guard_width = ALIGN(ctx->img_width + 16, S5P_FIMV_NV12MT_HALIGN);
+ guard_height = ALIGN((ctx->img_height >> 1) + 4, S5P_FIMV_NV12MT_VALIGN);
+ enc_ref_c_size = ALIGN(guard_width * guard_height,
+ S5P_FIMV_NV12MT_SALIGN);
+ }
+
+ mfc_debug(2, "buf_size1: %d, buf_size2: %d\n", buf_size1, buf_size2);
+
+ switch (ctx->codec_mode) {
+ case S5P_FIMV_CODEC_H264_ENC:
+ for (i = 0; i < 2; i++) {
+ WRITEL(OFFSETA(buf_addr1),
+ S5P_FIMV_ENC_REF0_LUMA_ADR + (4 * i));
+ buf_addr1 += enc_ref_y_size;
+ buf_size1 -= enc_ref_y_size;
+
+ WRITEL(OFFSETB(buf_addr2),
+ S5P_FIMV_ENC_REF2_LUMA_ADR + (4 * i));
+ buf_addr2 += enc_ref_y_size;
+ buf_size2 -= enc_ref_y_size;
+ }
+
+ for (i = 0; i < 4; i++) {
+ WRITEL(OFFSETB(buf_addr2),
+ S5P_FIMV_ENC_REF0_CHROMA_ADR + (4 * i));
+ buf_addr2 += enc_ref_c_size;
+ buf_size2 -= enc_ref_c_size;
+ }
+
+ WRITEL(OFFSETA(buf_addr1), S5P_FIMV_H264_UP_MV_ADR);
+ buf_addr1 += S5P_FIMV_ENC_UPMV_SIZE;
+ buf_size1 -= S5P_FIMV_ENC_UPMV_SIZE;
+
+ WRITEL(OFFSETA(buf_addr1), S5P_FIMV_H264_COZERO_FLAG_ADR);
+ buf_addr1 += S5P_FIMV_ENC_COLFLG_SIZE;
+ buf_size1 -= S5P_FIMV_ENC_COLFLG_SIZE;
+
+ WRITEL(OFFSETA(buf_addr1), S5P_FIMV_H264_UP_INTRA_MD_ADR);
+ buf_addr1 += S5P_FIMV_ENC_INTRAMD_SIZE;
+ buf_size1 -= S5P_FIMV_ENC_INTRAMD_SIZE;
+
+ WRITEL(OFFSETB(buf_addr2), S5P_FIMV_H264_UP_INTRA_PRED_ADR);
+ buf_addr2 += S5P_FIMV_ENC_INTRAPRED_SIZE;
+ buf_size2 -= S5P_FIMV_ENC_INTRAPRED_SIZE;
+
+ WRITEL(OFFSETA(buf_addr1), S5P_FIMV_H264_NBOR_INFO_ADR);
+ buf_addr1 += S5P_FIMV_ENC_NBORINFO_SIZE;
+ buf_size1 -= S5P_FIMV_ENC_NBORINFO_SIZE;
+
+ mfc_debug(2, "buf_size1: %d, buf_size2: %d\n",
+ buf_size1, buf_size2);
+ break;
+
+ case S5P_FIMV_CODEC_MPEG4_ENC:
+ for (i = 0; i < 2; i++) {
+ WRITEL(OFFSETA(buf_addr1),
+ S5P_FIMV_ENC_REF0_LUMA_ADR + (4 * i));
+ buf_addr1 += enc_ref_y_size;
+ buf_size1 -= enc_ref_y_size;
+
+ WRITEL(OFFSETB(buf_addr2),
+ S5P_FIMV_ENC_REF2_LUMA_ADR + (4 * i));
+ buf_addr2 += enc_ref_y_size;
+ buf_size2 -= enc_ref_y_size;
+ }
+
+ for (i = 0; i < 4; i++) {
+ WRITEL(OFFSETB(buf_addr2),
+ S5P_FIMV_ENC_REF0_CHROMA_ADR + (4 * i));
+ buf_addr2 += enc_ref_c_size;
+ buf_size2 -= enc_ref_c_size;
+ }
+
+ WRITEL(OFFSETA(buf_addr1), S5P_FIMV_MPEG4_UP_MV_ADR);
+ buf_addr1 += S5P_FIMV_ENC_UPMV_SIZE;
+ buf_size1 -= S5P_FIMV_ENC_UPMV_SIZE;
+
+ WRITEL(OFFSETA(buf_addr1), S5P_FIMV_MPEG4_COZERO_FLAG_ADR);
+ buf_addr1 += S5P_FIMV_ENC_COLFLG_SIZE;
+ buf_size1 -= S5P_FIMV_ENC_COLFLG_SIZE;
+
+ WRITEL(OFFSETA(buf_addr1), S5P_FIMV_MPEG4_ACDC_COEF_ADR);
+ buf_addr1 += S5P_FIMV_ENC_ACDCCOEF_SIZE;
+ buf_size1 -= S5P_FIMV_ENC_ACDCCOEF_SIZE;
+
+ mfc_debug(2, "buf_size1: %d, buf_size2: %d\n",
+ buf_size1, buf_size2);
+ break;
+
+ case S5P_FIMV_CODEC_H263_ENC:
+ for (i = 0; i < 2; i++) {
+ WRITEL(OFFSETA(buf_addr1),
+ S5P_FIMV_ENC_REF0_LUMA_ADR + (4 * i));
+ buf_addr1 += enc_ref_y_size;
+ buf_size1 -= enc_ref_y_size;
+
+ WRITEL(OFFSETB(buf_addr2),
+ S5P_FIMV_ENC_REF2_LUMA_ADR + (4 * i));
+ buf_addr2 += enc_ref_y_size;
+ buf_size2 -= enc_ref_y_size;
+ }
+
+ for (i = 0; i < 4; i++) {
+ WRITEL(OFFSETB(buf_addr2),
+ S5P_FIMV_ENC_REF0_CHROMA_ADR + (4 * i));
+ buf_addr2 += enc_ref_c_size;
+ buf_size2 -= enc_ref_c_size;
+ }
+
+ WRITEL(OFFSETA(buf_addr1), S5P_FIMV_H263_UP_MV_ADR);
+ buf_addr1 += S5P_FIMV_ENC_UPMV_SIZE;
+ buf_size1 -= S5P_FIMV_ENC_UPMV_SIZE;
+
+ WRITEL(OFFSETA(buf_addr1), S5P_FIMV_H263_ACDC_COEF_ADR);
+ buf_addr1 += S5P_FIMV_ENC_ACDCCOEF_SIZE;
+ buf_size1 -= S5P_FIMV_ENC_ACDCCOEF_SIZE;
+
+ mfc_debug(2, "buf_size1: %d, buf_size2: %d\n",
+ buf_size1, buf_size2);
+ break;
+
+ default:
+ mfc_err("Unknown codec set for encoding: %d\n",
+ ctx->codec_mode);
+ return -EINVAL;
+ }
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+ struct s5p_mfc_enc_params *p = &enc->params;
+ unsigned int reg;
+ unsigned int shm;
+
+ mfc_debug_enter();
+
+ /* width */
+ WRITEL(ctx->img_width, S5P_FIMV_ENC_HSIZE_PX);
+ /* height */
+ WRITEL(ctx->img_height, S5P_FIMV_ENC_VSIZE_PX);
+
+ /* pictype : enable, IDR period */
+ reg = READL(S5P_FIMV_ENC_PIC_TYPE_CTRL);
+ reg |= (1 << 18);
+ reg &= ~(0xFFFF);
+ reg |= p->gop_size;
+ WRITEL(reg, S5P_FIMV_ENC_PIC_TYPE_CTRL);
+
+ WRITEL(0, S5P_FIMV_ENC_B_RECON_WRITE_ON);
+
+ /* multi-slice control */
+ /* multi-slice MB number or bit size */
+ WRITEL(p->slice_mode, S5P_FIMV_ENC_MSLICE_CTRL);
+ if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) {
+ WRITEL(p->slice_mb, S5P_FIMV_ENC_MSLICE_MB);
+ } else if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) {
+ WRITEL(p->slice_bit, S5P_FIMV_ENC_MSLICE_BIT);
+ } else {
+ WRITEL(0, S5P_FIMV_ENC_MSLICE_MB);
+ WRITEL(0, S5P_FIMV_ENC_MSLICE_BIT);
+ }
+
+ /* cyclic intra refresh */
+ WRITEL(p->intra_refresh_mb, S5P_FIMV_ENC_CIR_CTRL);
+
+ /* memory structure cur. frame */
+ if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M)
+ WRITEL(0, S5P_FIMV_ENC_MAP_FOR_CUR);
+ else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT)
+ WRITEL(3, S5P_FIMV_ENC_MAP_FOR_CUR);
+
+ /* padding control & value */
+ reg = READL(S5P_FIMV_ENC_PADDING_CTRL);
+ if (p->pad) {
+ /** enable */
+ reg |= (1 << 31);
+ /** cr value */
+ reg &= ~(0xFF << 16);
+ reg |= (p->pad_cr << 16);
+ /** cb value */
+ reg &= ~(0xFF << 8);
+ reg |= (p->pad_cb << 8);
+ /** y value */
+ reg &= ~(0xFF);
+ reg |= (p->pad_luma);
+ } else {
+ /** disable & all value clear */
+ reg = 0;
+ }
+ WRITEL(reg, S5P_FIMV_ENC_PADDING_CTRL);
+
+ /* rate control config. */
+ reg = READL(S5P_FIMV_ENC_RC_CONFIG);
+ /** frame-level rate control */
+ reg &= ~(0x1 << 9);
+ reg |= (p->rc_frame << 9);
+ WRITEL(reg, S5P_FIMV_ENC_RC_CONFIG);
+
+ /* bit rate */
+ if (p->rc_frame)
+ WRITEL(p->rc_bitrate,
+ S5P_FIMV_ENC_RC_BIT_RATE);
+ else
+ WRITEL(0, S5P_FIMV_ENC_RC_BIT_RATE);
+
+ /* reaction coefficient */
+ if (p->rc_frame)
+ WRITEL(p->rc_reaction_coeff, S5P_FIMV_ENC_RC_RPARA);
+
+ /* extended encoder ctrl */
+ shm = s5p_mfc_read_info(ctx, EXT_ENC_CONTROL);
+ /** vbv buffer size */
+ if (p->frame_skip_mode == V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) {
+ shm &= ~(0xFFFF << 16);
+ shm |= (p->vbv_buf_size << 16);
+ }
+ /** seq header ctrl */
+ shm &= ~(0x1 << 3);
+ shm |= (p->seq_hdr_mode << 3);
+ /** frame skip mode */
+ shm &= ~(0x3 << 1);
+ shm |= (p->frame_skip_mode << 1);
+ s5p_mfc_write_info(ctx, shm, EXT_ENC_CONTROL);
+
+ /* fixed target bit */
+ s5p_mfc_write_info(ctx, p->fixed_target_bit, RC_CONTROL_CONFIG);
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+ struct s5p_mfc_enc_params *p = &enc->params;
+ struct s5p_mfc_h264_enc_params *p_264 = &p->codec.h264;
+ unsigned int reg;
+ unsigned int shm;
+
+ mfc_debug_enter();
+
+ s5p_mfc_set_enc_params(ctx);
+
+ /* pictype : number of B */
+ reg = READL(S5P_FIMV_ENC_PIC_TYPE_CTRL);
+ /** num_b_frame - 0 ~ 2 */
+ reg &= ~(0x3 << 16);
+ reg |= (p->num_b_frame << 16);
+ WRITEL(reg, S5P_FIMV_ENC_PIC_TYPE_CTRL);
+
+ /* profile & level */
+ reg = READL(S5P_FIMV_ENC_PROFILE);
+ /** level */
+ reg &= ~(0xFF << 8);
+ reg |= (p_264->level << 8);
+ /** profile - 0 ~ 2 */
+ reg &= ~(0x3F);
+ reg |= p_264->profile;
+ WRITEL(reg, S5P_FIMV_ENC_PROFILE);
+
+ /* interlace */
+ WRITEL(p_264->interlace, S5P_FIMV_ENC_PIC_STRUCT);
+ /** height */
+ if (p_264->interlace)
+ WRITEL(ctx->img_height >> 1, S5P_FIMV_ENC_VSIZE_PX);
+
+ /* loopfilter ctrl */
+ WRITEL(p_264->loop_filter_mode, S5P_FIMV_ENC_LF_CTRL);
+
+ /* loopfilter alpha offset */
+ if (p_264->loop_filter_alpha < 0) {
+ reg = 0x10;
+ reg |= (0xFF - p_264->loop_filter_alpha) + 1;
+ } else {
+ reg = 0x00;
+ reg |= (p_264->loop_filter_alpha & 0xF);
+ }
+ WRITEL(reg, S5P_FIMV_ENC_ALPHA_OFF);
+
+ /* loopfilter beta offset */
+ if (p_264->loop_filter_beta < 0) {
+ reg = 0x10;
+ reg |= (0xFF - p_264->loop_filter_beta) + 1;
+ } else {
+ reg = 0x00;
+ reg |= (p_264->loop_filter_beta & 0xF);
+ }
+ WRITEL(reg, S5P_FIMV_ENC_BETA_OFF);
+
+ /* entropy coding mode */
+ WRITEL(p_264->entropy_mode, S5P_FIMV_ENC_H264_ENTRP_MODE);
+
+ /* number of ref. picture */
+ reg = READL(S5P_FIMV_ENC_H264_NUM_OF_REF);
+ /** num of ref. pictures of P */
+ reg &= ~(0x3 << 5);
+ reg |= (p_264->num_ref_pic_4p << 5);
+ WRITEL(reg, S5P_FIMV_ENC_H264_NUM_OF_REF);
+
+ /* 8x8 transform enable */
+ WRITEL(p_264->_8x8_transform, S5P_FIMV_ENC_H264_TRANS_FLAG);
+
+ /* rate control config. */
+ reg = READL(S5P_FIMV_ENC_RC_CONFIG);
+ /** macroblock level rate control */
+ reg &= ~(0x1 << 8);
+ reg |= (p->rc_mb << 8);
+ /** frame QP */
+ reg &= ~(0x3F);
+ reg |= p_264->rc_frame_qp;
+ WRITEL(reg, S5P_FIMV_ENC_RC_CONFIG);
+
+ /* frame rate */
+ if (p->rc_frame)
+ WRITEL(p_264->rc_framerate * 1000,
+ S5P_FIMV_ENC_RC_FRAME_RATE);
+ else
+ WRITEL(0, S5P_FIMV_ENC_RC_FRAME_RATE);
+
+ /* max & min value of QP */
+ reg = READL(S5P_FIMV_ENC_RC_QBOUND);
+ /** max QP */
+ reg &= ~(0x3F << 8);
+ reg |= (p_264->rc_max_qp << 8);
+ /** min QP */
+ reg &= ~(0x3F);
+ reg |= p_264->rc_min_qp;
+ WRITEL(reg, S5P_FIMV_ENC_RC_QBOUND);
+
+ /* macroblock adaptive scaling features */
+ if (p->rc_mb) {
+ reg = READL(S5P_FIMV_ENC_RC_MB_CTRL);
+ /** dark region */
+ reg &= ~(0x1 << 3);
+ reg |= (p_264->rc_mb_dark << 3);
+ /** smooth region */
+ reg &= ~(0x1 << 2);
+ reg |= (p_264->rc_mb_smooth << 2);
+ /** static region */
+ reg &= ~(0x1 << 1);
+ reg |= (p_264->rc_mb_static << 1);
+ /** high activity region */
+ reg &= ~(0x1);
+ reg |= p_264->rc_mb_activity;
+ WRITEL(reg, S5P_FIMV_ENC_RC_MB_CTRL);
+ }
+
+ if (!p->rc_frame && !p->rc_mb) {
+ shm = s5p_mfc_read_info(ctx, P_B_FRAME_QP);
+ shm &= ~(0xFFF);
+ shm |= ((p_264->rc_b_frame_qp & 0x3F) << 6);
+ shm |= (p_264->rc_p_frame_qp & 0x3F);
+ s5p_mfc_write_info(ctx, shm, P_B_FRAME_QP);
+ }
+
+ /* extended encoder ctrl */
+ shm = s5p_mfc_read_info(ctx, EXT_ENC_CONTROL);
+ /** AR VUI control */
+ shm &= ~(0x1 << 15);
+ shm |= (p_264->ar_vui << 1);
+ s5p_mfc_write_info(ctx, shm, EXT_ENC_CONTROL);
+
+ if (p_264->ar_vui) {
+ /* aspect ration IDC */
+ shm = s5p_mfc_read_info(ctx, ASPECT_RATIO_IDC);
+ shm &= ~(0xFF);
+ shm |= p_264->ar_vui_idc;
+ s5p_mfc_write_info(ctx, shm, ASPECT_RATIO_IDC);
+
+ if (p_264->ar_vui_idc == 0xFF) {
+ /* sample AR info */
+ shm = s5p_mfc_read_info(ctx, EXTENDED_SAR);
+ shm &= ~(0xFFFFFFFF);
+ shm |= p_264->ext_sar_width << 16;
+ shm |= p_264->ext_sar_height;
+ s5p_mfc_write_info(ctx, shm, EXTENDED_SAR);
+ }
+ }
+
+ /* intra picture period for H.264 */
+ shm = s5p_mfc_read_info(ctx, H264_I_PERIOD);
+ /** control */
+ shm &= ~(0x1 << 16);
+ shm |= (p_264->open_gop << 16);
+ /** value */
+ if (p_264->open_gop) {
+ shm &= ~(0xFFFF);
+ shm |= p_264->open_gop_size;
+ }
+ s5p_mfc_write_info(ctx, shm, H264_I_PERIOD);
+
+ /* set frame pack sei generation */
+ if (p_264->sei_gen_enable) {
+ /* frame packing enable */
+ shm = s5p_mfc_read_info(ctx, FRAME_PACK_SEI_ENABLE);
+ shm |= (1 << 1);
+ s5p_mfc_write_info(ctx, shm, FRAME_PACK_SEI_ENABLE);
+
+ /* set current frame0 flag & arrangement type */
+ shm = 0;
+ /** current frame0 flag */
+ shm |= ((p_264->sei_fp_curr_frame_0 & 0x1) << 2);
+ /** arrangement type
+ *(spec. Table D-8. Definition of frame_packing_arrangement_type)
+ */
+ shm |= (p_264->sei_fp_arrangement_type - 3) & 0x3;
+ s5p_mfc_write_info(ctx, shm, FRAME_PACK_SEI_INFO);
+ }
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+static int s5p_mfc_set_enc_params_mpeg4(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+ struct s5p_mfc_enc_params *p = &enc->params;
+ struct s5p_mfc_mpeg4_enc_params *p_mpeg4 = &p->codec.mpeg4;
+ unsigned int reg;
+ unsigned int shm;
+
+ mfc_debug_enter();
+
+ s5p_mfc_set_enc_params(ctx);
+
+ /* pictype : number of B */
+ reg = READL(S5P_FIMV_ENC_PIC_TYPE_CTRL);
+ /** num_b_frame - 0 ~ 2 */
+ reg &= ~(0x3 << 16);
+ reg |= (p->num_b_frame << 16);
+ WRITEL(reg, S5P_FIMV_ENC_PIC_TYPE_CTRL);
+
+ /* profile & level */
+ reg = READL(S5P_FIMV_ENC_PROFILE);
+ /** level */
+ reg &= ~(0xFF << 8);
+ reg |= (p_mpeg4->level << 8);
+ /** profile - 0 ~ 2 */
+ reg &= ~(0x3F);
+ reg |= p_mpeg4->profile;
+ WRITEL(reg, S5P_FIMV_ENC_PROFILE);
+
+ /* quarter_pixel */
+ WRITEL(p_mpeg4->quarter_pixel, S5P_FIMV_ENC_MPEG4_QUART_PXL);
+
+ /* qp */
+ if (p->rc_frame) {
+ shm = s5p_mfc_read_info(ctx, P_B_FRAME_QP);
+ shm &= ~(0xFFF);
+ shm |= ((p_mpeg4->rc_b_frame_qp & 0x3F) << 6);
+ shm |= (p_mpeg4->rc_p_frame_qp & 0x3F);
+ s5p_mfc_write_info(ctx, shm, P_B_FRAME_QP);
+ }
+
+ /* frame rate */
+ if (p->rc_frame) {
+ if (p_mpeg4->vop_frm_delta > 0) {
+ p_mpeg4->rc_framerate = p_mpeg4->vop_time_res /
+ p_mpeg4->vop_frm_delta;
+ WRITEL(p_mpeg4->rc_framerate * 1000,
+ S5P_FIMV_ENC_RC_FRAME_RATE);
+ shm = s5p_mfc_read_info(ctx, RC_VOP_TIMING);
+ shm &= ~(0xFFFFFFFF);
+ shm |= (1 << 31);
+ shm |= ((p_mpeg4->vop_time_res & 0x7FFF) << 16);
+ shm |= (p_mpeg4->vop_frm_delta & 0xFFFF);
+ s5p_mfc_write_info(ctx, shm, RC_VOP_TIMING);
+ }
+ } else {
+ WRITEL(0, S5P_FIMV_ENC_RC_FRAME_RATE);
+ }
+
+ /* rate control config. */
+ reg = READL(S5P_FIMV_ENC_RC_CONFIG);
+ /** frame QP */
+ reg &= ~(0x3F);
+ reg |= p_mpeg4->rc_frame_qp;
+ WRITEL(reg, S5P_FIMV_ENC_RC_CONFIG);
+
+ /* max & min value of QP */
+ reg = READL(S5P_FIMV_ENC_RC_QBOUND);
+ /** max QP */
+ reg &= ~(0x3F << 8);
+ reg |= (p_mpeg4->rc_max_qp << 8);
+ /** min QP */
+ reg &= ~(0x3F);
+ reg |= p_mpeg4->rc_min_qp;
+ WRITEL(reg, S5P_FIMV_ENC_RC_QBOUND);
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+static int s5p_mfc_set_enc_params_h263(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+ struct s5p_mfc_enc_params *p = &enc->params;
+ struct s5p_mfc_mpeg4_enc_params *p_mpeg4 = &p->codec.mpeg4;
+ unsigned int reg;
+ unsigned int shm;
+
+ mfc_debug_enter();
+
+ s5p_mfc_set_enc_params(ctx);
+
+ /* qp */
+ if (!p->rc_frame) {
+ shm = s5p_mfc_read_info(ctx, P_B_FRAME_QP);
+ shm &= ~(0xFFF);
+ shm |= (p_mpeg4->rc_p_frame_qp & 0x3F);
+ s5p_mfc_write_info(ctx, shm, P_B_FRAME_QP);
+ }
+
+ /* frame rate */
+ if (p->rc_frame)
+ WRITEL(p_mpeg4->rc_framerate * 1000,
+ S5P_FIMV_ENC_RC_FRAME_RATE);
+ else
+ WRITEL(0, S5P_FIMV_ENC_RC_FRAME_RATE);
+
+ /* rate control config. */
+ reg = READL(S5P_FIMV_ENC_RC_CONFIG);
+ /** frame QP */
+ reg &= ~(0x3F);
+ reg |= p_mpeg4->rc_frame_qp;
+ WRITEL(reg, S5P_FIMV_ENC_RC_CONFIG);
+
+ /* max & min value of QP */
+ reg = READL(S5P_FIMV_ENC_RC_QBOUND);
+ /** max QP */
+ reg &= ~(0x3F << 8);
+ reg |= (p_mpeg4->rc_max_qp << 8);
+ /** min QP */
+ reg &= ~(0x3F);
+ reg |= p_mpeg4->rc_min_qp;
+ WRITEL(reg, S5P_FIMV_ENC_RC_QBOUND);
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+#if 0
+/* Open a new instance and get its number */
+int s5p_mfc_open_inst(struct s5p_mfc_ctx *ctx)
+{
+ int ret;
+
+ mfc_debug_enter();
+ mfc_debug(2, "Requested codec mode: %d\n", ctx->codec_mode);
+ ret = s5p_mfc_cmd_host2risc(ctx->dev, ctx, \
+ S5P_FIMV_H2R_CMD_OPEN_INSTANCE, ctx->codec_mode);
+ mfc_debug_leave();
+ return ret;
+}
+
+/* Close instance */
+int s5p_mfc_close_inst(struct s5p_mfc_ctx *ctx)
+{
+ int ret = 0;
+ struct s5p_mfc_dev *dev = ctx->dev;
+
+ mfc_debug_enter();
+ if (ctx->state != MFCINST_FREE) {
+ ret = s5p_mfc_cmd_host2risc(dev, ctx,
+ S5P_FIMV_H2R_CMD_CLOSE_INSTANCE, ctx->inst_no);
+ } else {
+ ret = -EINVAL;
+ }
+ mfc_debug_leave();
+ return ret;
+}
+#endif
+
+/* Initialize decoding */
+int s5p_mfc_init_decode(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+
+ mfc_debug_enter();
+ mfc_debug(2, "InstNo: %d/%d\n", ctx->inst_no, S5P_FIMV_CH_SEQ_HEADER);
+ s5p_mfc_set_shared_buffer(ctx);
+ mfc_debug(2, "BUFs: %08x %08x %08x %08x %08x\n",
+ READL(S5P_FIMV_SI_CH0_DESC_ADR),
+ READL(S5P_FIMV_SI_CH0_CPB_SIZE),
+ READL(S5P_FIMV_SI_CH0_DESC_SIZE),
+ READL(S5P_FIMV_SI_CH0_SB_ST_ADR),
+ READL(S5P_FIMV_SI_CH0_SB_FRM_SIZE));
+ /* Setup loop filter, for decoding this is only valid for MPEG4 */
+ if (ctx->codec_mode == S5P_FIMV_CODEC_MPEG4_DEC) {
+ mfc_debug(2, "Set loop filter to: %d\n", dec->loop_filter_mpeg4);
+ WRITEL(dec->loop_filter_mpeg4, S5P_FIMV_ENC_LF_CTRL);
+ } else {
+ WRITEL(0, S5P_FIMV_ENC_LF_CTRL);
+ }
+ /* When user sets desplay_delay to 0,
+ * It works as "display_delay enable" and delay set to 0.
+ * If user wants display_delay disable, It should be
+ * set to negative value. */
+ WRITEL(((dec->slice_enable & S5P_FIMV_SLICE_INT_MASK) <<
+ S5P_FIMV_SLICE_INT_SHIFT) |
+ ((dec->display_delay < 0 ? 0 : 1) <<
+ S5P_FIMV_DDELAY_ENA_SHIFT) |
+ (((dec->display_delay >= 0 ? dec->display_delay : 0) &
+ S5P_FIMV_DDELAY_VAL_MASK) << S5P_FIMV_DDELAY_VAL_SHIFT),
+ S5P_FIMV_SI_CH0_DPB_CONF_CTRL);
+ if (ctx->codec_mode == S5P_FIMV_CODEC_FIMV1_DEC) {
+ mfc_debug(2, "Setting FIMV1 resolution to %dx%d\n",
+ ctx->img_width, ctx->img_height);
+ WRITEL(ctx->img_width, S5P_FIMV_SI_FIMV1_HRESOL);
+ WRITEL(ctx->img_height, S5P_FIMV_SI_FIMV1_VRESOL);
+ }
+
+ /* sei parse */
+ s5p_mfc_write_info(ctx, dec->sei_parse, FRAME_PACK_SEI_ENABLE);
+
+ WRITEL(((S5P_FIMV_CH_SEQ_HEADER & S5P_FIMV_CH_MASK)
+ << S5P_FIMV_CH_SHIFT)
+ | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID);
+
+ /* Enable CRC data */
+ WRITEL(dec->crc_enable << 31, S5P_FIMV_HOST2RISC_ARG2);
+
+ mfc_debug(2, "DELAY : %x\n", READL(S5P_FIMV_SI_CH0_DPB_CONF_CTRL));
+
+ mfc_debug_leave();
+ return 0;
+}
+
+static inline void s5p_mfc_set_flush(struct s5p_mfc_ctx *ctx, int flush)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ unsigned int dpb;
+ if (flush)
+ dpb = READL(S5P_FIMV_SI_CH0_DPB_CONF_CTRL) | (1 << 14);
+ else
+ dpb = READL(S5P_FIMV_SI_CH0_DPB_CONF_CTRL) & ~(1 << 14);
+ WRITEL(dpb, S5P_FIMV_SI_CH0_DPB_CONF_CTRL);
+}
+
+/* Decode a single frame */
+int s5p_mfc_decode_one_frame(struct s5p_mfc_ctx *ctx, int last_frame)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+
+ mfc_debug(2, "Setting flags to %08lx (free:%d WTF:%d)\n",
+ dec->dpb_status, ctx->dst_queue_cnt, dec->dpb_queue_cnt);
+
+ WRITEL(dec->dpb_status, S5P_FIMV_SI_CH0_RELEASE_BUF);
+ s5p_mfc_set_shared_buffer(ctx);
+ s5p_mfc_set_flush(ctx, dec->dpb_flush);
+ /* Issue different commands to instance basing on whether it
+ * is the last frame or not. */
+ switch (last_frame) {
+ case 0:
+ WRITEL(((S5P_FIMV_CH_FRAME_START & S5P_FIMV_CH_MASK) <<
+ S5P_FIMV_CH_SHIFT) | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID);
+ break;
+ case 1:
+ WRITEL(((S5P_FIMV_CH_LAST_FRAME & S5P_FIMV_CH_MASK) <<
+ S5P_FIMV_CH_SHIFT) | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID);
+ break;
+ case 2:
+ WRITEL(((S5P_FIMV_CH_FRAME_START_REALLOC & S5P_FIMV_CH_MASK) <<
+ S5P_FIMV_CH_SHIFT) | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID);
+ break;
+ }
+ mfc_debug(2, "Decoding a usual frame.\n");
+ return 0;
+}
+
+int s5p_mfc_init_encode(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+
+ mfc_debug(2, "++\n");
+
+ if (ctx->codec_mode == S5P_FIMV_CODEC_H264_ENC)
+ s5p_mfc_set_enc_params_h264(ctx);
+ else if (ctx->codec_mode == S5P_FIMV_CODEC_MPEG4_ENC)
+ s5p_mfc_set_enc_params_mpeg4(ctx);
+ else if (ctx->codec_mode == S5P_FIMV_CODEC_H263_ENC)
+ s5p_mfc_set_enc_params_h263(ctx);
+ else {
+ mfc_err("Unknown codec for encoding (%x).\n",
+ ctx->codec_mode);
+ return -EINVAL;
+ }
+
+ s5p_mfc_set_shared_buffer(ctx);
+
+ WRITEL(((S5P_FIMV_CH_SEQ_HEADER << 16) & 0x70000) | (ctx->inst_no),
+ S5P_FIMV_SI_CH0_INST_ID);
+
+ mfc_debug(2, "--\n");
+
+ return 0;
+}
+
+/* Encode a single frame */
+int s5p_mfc_encode_one_frame(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+
+ mfc_debug(2, "++\n");
+
+ /* memory structure cur. frame */
+ if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M)
+ WRITEL(0, S5P_FIMV_ENC_MAP_FOR_CUR);
+ else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT)
+ WRITEL(3, S5P_FIMV_ENC_MAP_FOR_CUR);
+
+ s5p_mfc_set_shared_buffer(ctx);
+
+ WRITEL((S5P_FIMV_CH_FRAME_START << 16 & 0x70000) | (ctx->inst_no),
+ S5P_FIMV_SI_CH0_INST_ID);
+
+ mfc_debug(2, "--\n");
+
+ return 0;
+}
+
+static inline int s5p_mfc_get_new_ctx(struct s5p_mfc_dev *dev)
+{
+ unsigned long flags;
+ int new_ctx;
+ int cnt;
+
+ spin_lock_irqsave(&dev->condlock, flags);
+ mfc_debug(2, "Previos context: %d (bits %08lx)\n", dev->curr_ctx,
+ dev->ctx_work_bits);
+ new_ctx = (dev->curr_ctx + 1) % MFC_NUM_CONTEXTS;
+ cnt = 0;
+ while (!test_bit(new_ctx, &dev->ctx_work_bits)) {
+ new_ctx = (new_ctx + 1) % MFC_NUM_CONTEXTS;
+ cnt++;
+ if (cnt > MFC_NUM_CONTEXTS) {
+ /* No contexts to run */
+ spin_unlock_irqrestore(&dev->condlock, flags);
+ return -EAGAIN;
+ }
+ }
+ spin_unlock_irqrestore(&dev->condlock, flags);
+ return new_ctx;
+}
+
+static inline void s5p_mfc_run_res_change(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+
+ s5p_mfc_set_dec_desc_buffer(ctx);
+ s5p_mfc_set_dec_stream_buffer(ctx, 0, 0, 0);
+ dev->curr_ctx = ctx->num;
+ s5p_mfc_clean_ctx_int_flags(ctx);
+ s5p_mfc_decode_one_frame(ctx, 2);
+}
+
+static inline void s5p_mfc_run_dec_last_frames(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+
+ s5p_mfc_set_dec_desc_buffer(ctx);
+ s5p_mfc_set_dec_stream_buffer(ctx, 0, 0, 0);
+ dev->curr_ctx = ctx->num;
+ s5p_mfc_clean_ctx_int_flags(ctx);
+ s5p_mfc_decode_one_frame(ctx, 1);
+}
+
+static inline int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_buf *temp_vb;
+ unsigned long flags;
+ int last_frame = 0;
+ unsigned int index;
+
+ spin_lock_irqsave(&dev->irqlock, flags);
+
+ /* Frames are being decoded */
+ if (list_empty(&ctx->src_queue)) {
+ mfc_debug(2, "No src buffers.\n");
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+ return -EAGAIN;
+ }
+ /* Get the next source buffer */
+ temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
+ temp_vb->used = 1;
+ mfc_debug(2, "Temp vb: %p\n", temp_vb);
+ mfc_debug(2, "Src Addr: 0x%08lx\n",
+ (unsigned long)s5p_mfc_mem_plane_addr(ctx, &temp_vb->vb, 0));
+ s5p_mfc_set_dec_desc_buffer(ctx);
+ s5p_mfc_set_dec_stream_buffer(ctx,
+ s5p_mfc_mem_plane_addr(ctx, &temp_vb->vb, 0),
+ 0, temp_vb->vb.v4l2_planes[0].bytesused);
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+
+ index = temp_vb->vb.v4l2_buf.index;
+ if (call_cop(ctx, set_buf_ctrls_val, ctx, &ctx->src_ctrls[index]) < 0)
+ mfc_err("failed in set_buf_ctrls_val\n");
+
+ dev->curr_ctx = ctx->num;
+ s5p_mfc_clean_ctx_int_flags(ctx);
+ if (temp_vb->vb.v4l2_planes[0].bytesused == 0) {
+ last_frame = 1;
+ mfc_debug(2, "Setting ctx->state to FINISHING\n");
+ ctx->state = MFCINST_FINISHING;
+ }
+ s5p_mfc_decode_one_frame(ctx, last_frame);
+
+ return 0;
+}
+
+static inline int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ unsigned long flags;
+ struct s5p_mfc_buf *dst_mb;
+ struct s5p_mfc_buf *src_mb;
+ dma_addr_t src_y_addr, src_c_addr, dst_addr;
+ /*
+ unsigned int src_y_size, src_c_size;
+ */
+ unsigned int dst_size;
+ unsigned int index;
+
+ spin_lock_irqsave(&dev->irqlock, flags);
+
+ if (list_empty(&ctx->src_queue)) {
+ mfc_debug(2, "no src buffers.\n");
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+ return -EAGAIN;
+ }
+
+ if (list_empty(&ctx->dst_queue)) {
+ mfc_debug(2, "no dst buffers.\n");
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+ return -EAGAIN;
+ }
+
+ src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
+ src_mb->used = 1;
+ src_y_addr = s5p_mfc_mem_plane_addr(ctx, &src_mb->vb, 0);
+ src_c_addr = s5p_mfc_mem_plane_addr(ctx, &src_mb->vb, 1);
+
+ mfc_debug(2, "enc src y addr: 0x%08lx", (unsigned long)src_y_addr);
+ mfc_debug(2, "enc src c addr: 0x%08lx", (unsigned long)src_c_addr);
+
+ s5p_mfc_set_enc_frame_buffer(ctx, src_y_addr, src_c_addr);
+
+ dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list);
+ dst_mb->used = 1;
+ dst_addr = s5p_mfc_mem_plane_addr(ctx, &dst_mb->vb, 0);
+ dst_size = vb2_plane_size(&dst_mb->vb, 0);
+
+ s5p_mfc_set_enc_stream_buffer(ctx, dst_addr, dst_size);
+
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+
+ index = src_mb->vb.v4l2_buf.index;
+ if (call_cop(ctx, set_buf_ctrls_val, ctx, &ctx->src_ctrls[index]) < 0)
+ mfc_err("failed in set_buf_ctrls_val\n");
+
+ dev->curr_ctx = ctx->num;
+ s5p_mfc_clean_ctx_int_flags(ctx);
+ s5p_mfc_encode_one_frame(ctx);
+
+ return 0;
+}
+
+static inline void s5p_mfc_run_init_dec(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ unsigned long flags;
+ struct s5p_mfc_buf *temp_vb;
+
+ /* Initializing decoding - parsing header */
+ spin_lock_irqsave(&dev->irqlock, flags);
+ mfc_debug(2, "Preparing to init decoding.\n");
+ temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
+ s5p_mfc_set_dec_desc_buffer(ctx);
+ mfc_debug(2, "Header size: %d\n", temp_vb->vb.v4l2_planes[0].bytesused);
+ s5p_mfc_set_dec_stream_buffer(ctx,
+ s5p_mfc_mem_plane_addr(ctx, &temp_vb->vb, 0),
+ 0, temp_vb->vb.v4l2_planes[0].bytesused);
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+ dev->curr_ctx = ctx->num;
+ mfc_debug(2, "Header addr: 0x%08lx\n",
+ (unsigned long)s5p_mfc_mem_plane_addr(ctx, &temp_vb->vb, 0));
+ s5p_mfc_clean_ctx_int_flags(ctx);
+ s5p_mfc_init_decode(ctx);
+}
+
+static inline void s5p_mfc_run_init_enc(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ unsigned long flags;
+ struct s5p_mfc_buf *dst_mb;
+ dma_addr_t dst_addr;
+ unsigned int dst_size;
+
+ s5p_mfc_set_enc_ref_buffer(ctx);
+
+ spin_lock_irqsave(&dev->irqlock, flags);
+
+ dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list);
+ dst_addr = s5p_mfc_mem_plane_addr(ctx, &dst_mb->vb, 0);
+ dst_size = vb2_plane_size(&dst_mb->vb, 0);
+ s5p_mfc_set_enc_stream_buffer(ctx, dst_addr, dst_size);
+
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+
+ dev->curr_ctx = ctx->num;
+ mfc_debug(2, "Header addr: 0x%08lx\n",
+ (unsigned long)s5p_mfc_mem_plane_addr(ctx, &dst_mb->vb, 0));
+ s5p_mfc_clean_ctx_int_flags(ctx);
+ s5p_mfc_init_encode(ctx);
+}
+
+static inline int s5p_mfc_run_init_dec_buffers(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ unsigned long flags;
+ struct s5p_mfc_buf *temp_vb;
+ int ret;
+ /* Header was parsed now starting processing
+ * First set the output frame buffers
+ * s5p_mfc_alloc_dec_buffers(ctx); */
+
+ if (ctx->capture_state != QUEUE_BUFS_MMAPED) {
+ mfc_err("It seems that not all destionation buffers were "
+ "mmaped.\nMFC requires that all destination are mmaped "
+ "before starting processing.\n");
+ return -EAGAIN;
+ }
+
+ spin_lock_irqsave(&dev->irqlock, flags);
+
+ if (list_empty(&ctx->src_queue)) {
+ mfc_err("Header has been deallocated in the middle of "
+ "initialization.\n");
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+ return -EIO;
+ }
+
+ temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
+ s5p_mfc_set_dec_desc_buffer(ctx);
+ mfc_debug(2, "Header size: %d\n", temp_vb->vb.v4l2_planes[0].bytesused);
+ s5p_mfc_set_dec_stream_buffer(ctx,
+ s5p_mfc_mem_plane_addr(ctx, &temp_vb->vb, 0),
+ 0, temp_vb->vb.v4l2_planes[0].bytesused);
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+ dev->curr_ctx = ctx->num;
+ s5p_mfc_clean_ctx_int_flags(ctx);
+ ret = s5p_mfc_set_dec_frame_buffer(ctx);
+ if (ret) {
+ mfc_err("Failed to alloc frame mem.\n");
+ ctx->state = MFCINST_ERROR;
+ }
+ return ret;
+}
+
+/* Try running an operation on hardware */
+void s5p_mfc_try_run(struct s5p_mfc_dev *dev)
+{
+ struct s5p_mfc_ctx *ctx;
+ int new_ctx;
+ unsigned int ret = 0;
+
+ mfc_debug(1, "Try run dev: %p\n", dev);
+
+ /* Check whether hardware is not running */
+ if (test_and_set_bit(0, &dev->hw_lock) != 0) {
+ /* This is perfectly ok, the scheduled ctx should wait */
+ mfc_debug(1, "Couldn't lock HW.\n");
+ return;
+ }
+
+ /* Choose the context to run */
+ new_ctx = s5p_mfc_get_new_ctx(dev);
+ if (new_ctx < 0) {
+ /* No contexts to run */
+ if (test_and_clear_bit(0, &dev->hw_lock) == 0) {
+ mfc_err("Failed to unlock hardware.\n");
+ return;
+ }
+
+ mfc_debug(1, "No ctx is scheduled to be run.\n");
+ return;
+ }
+
+ mfc_debug(1, "New context: %d\n", new_ctx);
+ ctx = dev->ctx[new_ctx];
+ mfc_debug(1, "Seting new context to %p\n", ctx);
+ /* Got context to run in ctx */
+ mfc_debug(1, "ctx->dst_queue_cnt=%d ctx->dpb_count=%d ctx->src_queue_cnt=%d\n",
+ ctx->dst_queue_cnt, ctx->dpb_count, ctx->src_queue_cnt);
+ mfc_debug(1, "ctx->state=%d\n", ctx->state);
+ /* Last frame has already been sent to MFC
+ * Now obtaining frames from MFC buffer */
+
+ s5p_mfc_clock_on();
+
+ if (ctx->type == MFCINST_DECODER) {
+ switch (ctx->state) {
+ case MFCINST_FINISHING:
+ s5p_mfc_run_dec_last_frames(ctx);
+ break;
+ case MFCINST_RUNNING:
+ ret = s5p_mfc_run_dec_frame(ctx);
+ break;
+ case MFCINST_INIT:
+ ret = s5p_mfc_open_inst(ctx);
+ break;
+ case MFCINST_RETURN_INST:
+ ret = s5p_mfc_close_inst(ctx);
+ break;
+ case MFCINST_GOT_INST:
+ s5p_mfc_run_init_dec(ctx);
+ break;
+ case MFCINST_HEAD_PARSED:
+ ret = s5p_mfc_run_init_dec_buffers(ctx);
+ break;
+ case MFCINST_RES_CHANGE_INIT:
+ s5p_mfc_run_res_change(ctx);
+ break;
+ case MFCINST_RES_CHANGE_FLUSH:
+ s5p_mfc_run_dec_frame(ctx);
+ break;
+ case MFCINST_RES_CHANGE_END:
+ mfc_debug(2, "Finished remaining frames after resolution change.\n");
+ ctx->capture_state = QUEUE_FREE;
+ mfc_debug(2, "Will re-init the codec`.\n");
+ s5p_mfc_run_init_dec(ctx);
+ break;
+ default:
+ ret = -EAGAIN;
+ }
+ } else if (ctx->type == MFCINST_ENCODER) {
+ switch (ctx->state) {
+ case MFCINST_FINISHING:
+ case MFCINST_RUNNING:
+ ret = s5p_mfc_run_enc_frame(ctx);
+ break;
+ case MFCINST_INIT:
+ ret = s5p_mfc_open_inst(ctx);
+ break;
+ case MFCINST_RETURN_INST:
+ ret = s5p_mfc_close_inst(ctx);
+ break;
+ case MFCINST_GOT_INST:
+ s5p_mfc_run_init_enc(ctx);
+ break;
+ default:
+ ret = -EAGAIN;
+ }
+ } else {
+ mfc_err("invalid context type: %d\n", ctx->type);
+ ret = -EAGAIN;
+ }
+
+ if (ret) {
+ /* Free hardware lock */
+ if (test_and_clear_bit(0, &dev->hw_lock) == 0)
+ mfc_err("Failed to unlock hardware.\n");
+ s5p_mfc_clock_off();
+ }
+}
+
+
+void s5p_mfc_cleanup_queue(struct list_head *lh, struct vb2_queue *vq)
+{
+ struct s5p_mfc_buf *b;
+ int i;
+
+ while (!list_empty(lh)) {
+ b = list_entry(lh->next, struct s5p_mfc_buf, list);
+ for (i = 0; i < b->vb.num_planes; i++)
+ vb2_set_plane_payload(&b->vb, i, 0);
+ vb2_buffer_done(&b->vb, VB2_BUF_STATE_ERROR);
+ list_del(&b->list);
+ }
+}
+
+void s5p_mfc_write_info(struct s5p_mfc_ctx *ctx, unsigned int data, unsigned int ofs)
+{
+ /* MFC 5.x uses shared memory for information */
+ s5p_mfc_write_shm(ctx, data, ofs);
+}
+
+unsigned int s5p_mfc_read_info(struct s5p_mfc_ctx *ctx, unsigned int ofs)
+{
+ /* MFC 5.x uses shared memory for information */
+ return s5p_mfc_read_shm(ctx, ofs);
+}
diff --git a/drivers/media/video/exynos/mfc/s5p_mfc_opr_v5.h b/drivers/media/video/exynos/mfc/s5p_mfc_opr_v5.h
new file mode 100644
index 0000000..72f913b
--- /dev/null
+++ b/drivers/media/video/exynos/mfc/s5p_mfc_opr_v5.h
@@ -0,0 +1,145 @@
+/*
+ * drivers/media/video/exynos/mfc/s5p_mfc_opr_v5.h
+ *
+ * Header file for Samsung MFC (Multi Function Codec - FIMV) driver
+ * Contains declarations of hw related functions.
+ *
+ * Kamil Debski, Copyright (c) 2010 Samsung Electronics
+ * http://www.samsung.com/
+ *
+ * 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.
+ */
+
+#ifndef S5P_MFC_OPR_V5_H_
+#define S5P_MFC_OPR_V5_H_
+
+#include "s5p_mfc_common.h"
+#include "s5p_mfc_mem.h"
+
+#define MFC_CTRL_MODE_CUSTOM MFC_CTRL_MODE_SHM
+
+/*
+int s5p_mfc_release_firmware(struct s5p_mfc_dev *dev);
+int s5p_mfc_alloc_firmware(struct s5p_mfc_dev *dev);
+int s5p_mfc_load_firmware(struct s5p_mfc_dev *dev);
+int s5p_mfc_init_hw(struct s5p_mfc_dev *dev);
+*/
+
+int s5p_mfc_init_decode(struct s5p_mfc_ctx *ctx);
+int s5p_mfc_init_encode(struct s5p_mfc_ctx *mfc_ctx);
+/*
+void s5p_mfc_deinit_hw(struct s5p_mfc_dev *dev);
+int s5p_mfc_set_sleep(struct s5p_mfc_ctx *ctx);
+int s5p_mfc_set_wakeup(struct s5p_mfc_ctx *ctx);
+*/
+
+int s5p_mfc_set_dec_frame_buffer(struct s5p_mfc_ctx *ctx);
+int s5p_mfc_set_dec_stream_buffer(struct s5p_mfc_ctx *ctx, dma_addr_t buf_addr,
+ unsigned int start_num_byte,
+ unsigned int buf_size);
+
+void s5p_mfc_set_enc_frame_buffer(struct s5p_mfc_ctx *ctx,
+ dma_addr_t y_addr, dma_addr_t c_addr);
+int s5p_mfc_set_enc_stream_buffer(struct s5p_mfc_ctx *ctx,
+ dma_addr_t addr, unsigned int size);
+void s5p_mfc_get_enc_frame_buffer(struct s5p_mfc_ctx *ctx,
+ dma_addr_t *y_addr, dma_addr_t *c_addr);
+int s5p_mfc_set_enc_ref_buffer(struct s5p_mfc_ctx *mfc_ctx);
+
+int s5p_mfc_decode_one_frame(struct s5p_mfc_ctx *ctx, int last_frame);
+int s5p_mfc_encode_one_frame(struct s5p_mfc_ctx *mfc_ctx);
+
+/* Instance handling */
+/*
+int s5p_mfc_open_inst(struct s5p_mfc_ctx *ctx);
+int s5p_mfc_return_inst_no(struct s5p_mfc_ctx *ctx);
+*/
+
+/* Memory allocation */
+int s5p_mfc_alloc_dec_temp_buffers(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_set_dec_desc_buffer(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_release_dec_desc_buffer(struct s5p_mfc_ctx *ctx);
+
+int s5p_mfc_alloc_codec_buffers(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_release_codec_buffers(struct s5p_mfc_ctx *ctx);
+
+int s5p_mfc_alloc_instance_buffer(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_release_instance_buffer(struct s5p_mfc_ctx *ctx);
+int s5p_mfc_alloc_dev_context_buffer(struct s5p_mfc_dev *dev);
+void s5p_mfc_release_dev_context_buffer(struct s5p_mfc_dev *dev);
+
+void s5p_mfc_dec_calc_dpb_size(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_enc_calc_src_size(struct s5p_mfc_ctx *ctx);
+
+#define s5p_mfc_get_dspl_y_adr() (readl(dev->regs_base + \
+ S5P_FIMV_SI_DISPLAY_Y_ADR) << 11)
+#define s5p_mfc_get_dspl_status() readl(dev->regs_base + \
+ S5P_FIMV_SI_DISPLAY_STATUS)
+#define s5p_mfc_get_dec_frame_type() (readl(dev->regs_base + \
+ S5P_FIMV_DECODED_FRAME_TYPE) \
+ & S5P_FIMV_DECODED_FRAME_MASK)
+#define s5p_mfc_get_disp_frame_type() ((s5p_mfc_read_shm(ctx, DISP_PIC_FRAME_TYPE) \
+ >> S5P_FIMV_SHARED_DISP_FRAME_TYPE_SHIFT) \
+ & S5P_FIMV_DECODED_FRAME_MASK)
+#define s5p_mfc_get_consumed_stream() readl(dev->regs_base + \
+ S5P_FIMV_SI_CONSUMED_BYTES)
+#define s5p_mfc_get_int_reason() (readl(dev->regs_base + \
+ S5P_FIMV_RISC2HOST_CMD) & \
+ S5P_FIMV_RISC2HOST_CMD_MASK)
+#define s5p_mfc_get_int_err() readl(dev->regs_base + \
+ S5P_FIMV_RISC2HOST_ARG2)
+#define s5p_mfc_err_dec(x) (((x) & S5P_FIMV_ERR_DEC_MASK) >> \
+ S5P_FIMV_ERR_DEC_SHIFT)
+#define s5p_mfc_err_dspl(x) (((x) & S5P_FIMV_ERR_DSPL_MASK) >> \
+ S5P_FIMV_ERR_DSPL_SHIFT)
+#define s5p_mfc_get_img_width() readl(dev->regs_base + \
+ S5P_FIMV_SI_HRESOL)
+#define s5p_mfc_get_img_height() readl(dev->regs_base + \
+ S5P_FIMV_SI_VRESOL)
+#define s5p_mfc_get_dpb_count() readl(dev->regs_base + \
+ S5P_FIMV_SI_BUF_NUMBER)
+#define s5p_mfc_get_inst_no() readl(dev->regs_base + \
+ S5P_FIMV_RISC2HOST_ARG1)
+#define s5p_mfc_get_mv_count() 0
+#define s5p_mfc_get_mvc_num_views() -1
+#define s5p_mfc_get_mvc_disp_view_id() -1
+#define s5p_mfc_get_enc_dpb_count() -1
+#define s5p_mfc_get_enc_strm_size() readl(dev->regs_base + \
+ S5P_FIMV_ENC_SI_STRM_SIZE)
+#define s5p_mfc_get_enc_slice_type() readl(dev->regs_base + \
+ S5P_FIMV_ENC_SI_SLICE_TYPE)
+#define s5p_mfc_get_enc_pic_count() readl(dev->regs_base + \
+ S5P_FIMV_ENC_SI_PIC_CNT)
+#define s5p_mfc_get_sei_avail_status() s5p_mfc_read_shm(ctx, FRAME_PACK_SEI_AVAIL)
+
+#define s5p_mfc_clear_int_flags() \
+ do { \
+ s5p_mfc_write_reg(0, S5P_FIMV_RISC_HOST_INT); \
+ s5p_mfc_write_reg(0, S5P_FIMV_RISC2HOST_CMD); \
+ s5p_mfc_write_reg(0xffff, S5P_FIMV_SI_RTN_CHID);\
+ } while (0)
+
+/* Definition */
+#define ENC_MULTI_SLICE_MB_MAX ((1 << 16) - 1)
+#define ENC_MULTI_SLICE_BIT_MIN 1900
+#define ENC_MULTI_SLICE_BYTE_MIN 238
+#define ENC_INTRA_REFRESH_MB_MAX ((1 << 16) - 1)
+#define ENC_VBV_BUF_SIZE_MAX ((1 << 16) - 1)
+#define ENC_H264_LOOP_FILTER_AB_MIN -6
+#define ENC_H264_LOOP_FILTER_AB_MAX 6
+#define ENC_H264_RC_FRAME_RATE_MAX ((1 << 30) - 1)
+#define ENC_H263_RC_FRAME_RATE_MAX ((1 << 30) - 1)
+#define ENC_H264_PROFILE_MAX 2
+#define ENC_H264_LEVEL_MAX 40
+#define ENC_MPEG4_VOP_TIME_RES_MAX ((1 << 15) - 1)
+
+void s5p_mfc_try_run(struct s5p_mfc_dev *dev);
+
+void s5p_mfc_cleanup_queue(struct list_head *lh, struct vb2_queue *vq);
+
+void s5p_mfc_write_info(struct s5p_mfc_ctx *ctx, unsigned int data, unsigned int ofs);
+unsigned int s5p_mfc_read_info(struct s5p_mfc_ctx *ctx, unsigned int ofs);
+
+#endif /* S5P_MFC_OPR_V5_H_ */
diff --git a/drivers/media/video/exynos/mfc/s5p_mfc_opr_v6.c b/drivers/media/video/exynos/mfc/s5p_mfc_opr_v6.c
new file mode 100644
index 0000000..11d7529
--- /dev/null
+++ b/drivers/media/video/exynos/mfc/s5p_mfc_opr_v6.c
@@ -0,0 +1,1893 @@
+/*
+ * drivers/media/video/exynos/mfc/s5p_mfc_opr_v6.c
+ *
+ * Samsung MFC (Multi Function Codec - FIMV) driver
+ * This file contains hw related functions.
+ *
+ * Kamil Debski, Copyright (c) 2010 Samsung Electronics
+ * http://www.samsung.com/
+ *
+ * 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.
+ */
+
+#define DEBUG
+
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/io.h>
+#include <linux/jiffies.h>
+
+#include <linux/firmware.h>
+#include <linux/err.h>
+#include <linux/sched.h>
+#include <linux/cma.h>
+
+#include <linux/dma-mapping.h>
+#include <asm/cacheflush.h>
+
+#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
+#include <plat/iovmm.h>
+#endif
+
+#include "s5p_mfc_common.h"
+
+#include "s5p_mfc_cmd.h"
+#include "s5p_mfc_mem.h"
+#include "s5p_mfc_intr.h"
+#include "s5p_mfc_inst.h"
+#include "s5p_mfc_pm.h"
+#include "s5p_mfc_debug.h"
+#include "s5p_mfc_dec.h"
+#include "s5p_mfc_enc.h"
+
+/* #define S5P_MFC_DEBUG_REGWRITE */
+#ifdef S5P_MFC_DEBUG_REGWRITE
+#undef writel
+#define writel(v, r) \
+ do { \
+ printk(KERN_ERR "MFCWRITE(%p): %08x\n", r, (unsigned int)v); \
+ __raw_writel(v, r); \
+ } while (0)
+#endif /* S5P_MFC_DEBUG_REGWRITE */
+
+#define READL(offset) readl(dev->regs_base + (offset))
+#define WRITEL(data, offset) writel((data), dev->regs_base + (offset))
+#define OFFSETA(x) (((x) - dev->port_a) >> S5P_FIMV_MEM_OFFSET)
+#define OFFSETB(x) (((x) - dev->port_b) >> S5P_FIMV_MEM_OFFSET)
+
+/* Allocate temporary buffers for decoding */
+int s5p_mfc_alloc_dec_temp_buffers(struct s5p_mfc_ctx *ctx)
+{
+ /* NOP */
+
+ return 0;
+}
+
+/* Release temproary buffers for decoding */
+void s5p_mfc_release_dec_desc_buffer(struct s5p_mfc_ctx *ctx)
+{
+ /* NOP */
+}
+
+/* Allocate codec buffers */
+int s5p_mfc_alloc_codec_buffers(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+ unsigned int mb_width, mb_height;
+ void *alloc_ctx = dev->alloc_ctx[MFC_CMA_BANK1_ALLOC_CTX];
+
+ mfc_debug_enter();
+
+ mb_width = mb_width(ctx->img_width);
+ mb_height = mb_height(ctx->img_height);
+
+ if (ctx->type == MFCINST_DECODER) {
+ mfc_debug(2, "Luma size:%d Chroma size:%d MV size:%d\n",
+ ctx->luma_size, ctx->chroma_size, ctx->mv_size);
+ mfc_debug(2, "Totals bufs: %d\n", dec->total_dpb_count);
+ } else if (ctx->type == MFCINST_ENCODER) {
+ enc->tmv_buffer_size = ENC_TMV_SIZE(mb_width, mb_height);
+ enc->tmv_buffer_size = ALIGN(enc->tmv_buffer_size, 32) * 2;
+ enc->luma_dpb_size = ALIGN((mb_width * mb_height) * 256, 256);
+ enc->chroma_dpb_size = ALIGN((mb_width * mb_height) * 128, 256);
+ enc->me_buffer_size =
+ (ENC_ME_SIZE(ctx->img_width, ctx->img_height,
+ mb_width, mb_height));
+ enc->me_buffer_size = ALIGN(enc->me_buffer_size, 256);
+
+ mfc_debug(2, "recon luma size: %d chroma size: %d\n",
+ enc->luma_dpb_size, enc->chroma_dpb_size);
+ } else {
+ return -EINVAL;
+ }
+
+ /* Codecs have different memory requirements */
+ switch (ctx->codec_mode) {
+ case S5P_FIMV_CODEC_H264_DEC:
+ case S5P_FIMV_CODEC_H264_MVC_DEC:
+ if (dev->fw.date < 0x120206)
+ dec->mv_count = dec->total_dpb_count;
+ if (dev->fw.ver == 0x61)
+ ctx->scratch_buf_size =
+ DEC_V61_H264_SCRATCH_SIZE(mb_width, mb_height);
+ else
+ ctx->scratch_buf_size =
+ DEC_V65_H264_SCRATCH_SIZE(mb_width, mb_height);
+ ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, 256);
+ ctx->port_a_size =
+ ctx->scratch_buf_size +
+ (dec->mv_count * ctx->mv_size);
+ break;
+ case S5P_FIMV_CODEC_MPEG4_DEC:
+ case S5P_FIMV_CODEC_FIMV1_DEC:
+ case S5P_FIMV_CODEC_FIMV2_DEC:
+ case S5P_FIMV_CODEC_FIMV3_DEC:
+ case S5P_FIMV_CODEC_FIMV4_DEC:
+ if (dev->fw.ver == 0x61)
+ ctx->scratch_buf_size =
+ DEC_V61_MPEG4_SCRATCH_SIZE(mb_width, mb_height);
+ else
+ ctx->scratch_buf_size =
+ DEC_V65_MPEG4_SCRATCH_SIZE(mb_width, mb_height);
+ ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, 256);
+ ctx->port_a_size = ctx->scratch_buf_size;
+ break;
+ case S5P_FIMV_CODEC_VC1RCV_DEC:
+ case S5P_FIMV_CODEC_VC1_DEC:
+ if (dev->fw.ver == 0x61)
+ ctx->scratch_buf_size =
+ DEC_V61_VC1_SCRATCH_SIZE(mb_width, mb_height);
+ else
+ ctx->scratch_buf_size =
+ DEC_V65_VC1_SCRATCH_SIZE(mb_width, mb_height);
+ ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, 256);
+ ctx->port_a_size = ctx->scratch_buf_size;
+ break;
+ case S5P_FIMV_CODEC_MPEG2_DEC:
+ if (dev->fw.ver == 0x61)
+ ctx->scratch_buf_size =
+ DEC_V61_MPEG2_SCRATCH_SIZE(mb_width, mb_height);
+ else
+ ctx->scratch_buf_size =
+ DEC_V65_MPEG2_SCRATCH_SIZE(mb_width, mb_height);
+ ctx->port_a_size = 0;
+ ctx->port_b_size = 0;
+ break;
+ case S5P_FIMV_CODEC_H263_DEC:
+ if (dev->fw.ver == 0x61)
+ ctx->scratch_buf_size =
+ DEC_V61_MPEG4_SCRATCH_SIZE(mb_width, mb_height);
+ else
+ ctx->scratch_buf_size =
+ DEC_V65_MPEG4_SCRATCH_SIZE(mb_width, mb_height);
+ ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, 256);
+ ctx->port_a_size = ctx->scratch_buf_size;
+ break;
+ case S5P_FIMV_CODEC_VP8_DEC:
+ if (dev->fw.ver == 0x61)
+ ctx->scratch_buf_size =
+ DEC_V61_VP8_SCRATCH_SIZE(mb_width, mb_height);
+ else
+ ctx->scratch_buf_size =
+ DEC_V65_VP8_SCRATCH_SIZE(mb_width, mb_height);
+ ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, 256);
+ ctx->port_a_size = ctx->scratch_buf_size;
+ break;
+ case S5P_FIMV_CODEC_H264_ENC:
+ if (dev->fw.ver == 0x61)
+ ctx->scratch_buf_size =
+ ENC_V61_H264_SCRATCH_SIZE(mb_width, mb_height);
+ else
+ ctx->scratch_buf_size =
+ ENC_V65_H264_SCRATCH_SIZE(mb_width, mb_height);
+ ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, 256);
+ ctx->port_a_size =
+ ctx->scratch_buf_size + enc->tmv_buffer_size +
+ (ctx->dpb_count * (enc->luma_dpb_size +
+ enc->chroma_dpb_size + enc->me_buffer_size));
+ ctx->port_b_size = 0;
+ break;
+ case S5P_FIMV_CODEC_MPEG4_ENC:
+ case S5P_FIMV_CODEC_H263_ENC:
+ if (dev->fw.ver == 0x61)
+ ctx->scratch_buf_size =
+ ENC_V61_MPEG4_SCRATCH_SIZE(mb_width, mb_height);
+ else
+ ctx->scratch_buf_size =
+ ENC_V65_MPEG4_SCRATCH_SIZE(mb_width, mb_height);
+ ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, 256);
+ ctx->port_a_size =
+ ctx->scratch_buf_size + enc->tmv_buffer_size +
+ (ctx->dpb_count * (enc->luma_dpb_size +
+ enc->chroma_dpb_size + enc->me_buffer_size));
+ ctx->port_b_size = 0;
+ break;
+ default:
+ break;
+ }
+
+ if (ctx->is_drm)
+ alloc_ctx = dev->alloc_ctx_drm;
+
+ /* Allocate only if memory from bank 1 is necessary */
+ if (ctx->port_a_size > 0) {
+ ctx->port_a_buf = s5p_mfc_mem_alloc(
+ alloc_ctx, ctx->port_a_size);
+ if (IS_ERR(ctx->port_a_buf)) {
+ ctx->port_a_buf = 0;
+ printk(KERN_ERR
+ "Buf alloc for decoding failed (port A).\n");
+ return -ENOMEM;
+ }
+ ctx->port_a_phys = s5p_mfc_mem_daddr(ctx->port_a_buf);
+ }
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+/* Release buffers allocated for codec */
+void s5p_mfc_release_codec_buffers(struct s5p_mfc_ctx *ctx)
+{
+ if (ctx->port_a_buf) {
+ s5p_mfc_mem_free(ctx->port_a_buf);
+ ctx->port_a_buf = 0;
+ ctx->port_a_phys = 0;
+ ctx->port_a_size = 0;
+ }
+}
+
+/* Allocate memory for instance data buffer */
+int s5p_mfc_alloc_instance_buffer(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_buf_size_v6 *buf_size = dev->variant->buf_size->buf;
+ void *alloc_ctx = dev->alloc_ctx[MFC_CMA_BANK1_ALLOC_CTX];
+
+ mfc_debug_enter();
+
+ switch (ctx->codec_mode) {
+ case S5P_FIMV_CODEC_H264_DEC:
+ case S5P_FIMV_CODEC_H264_MVC_DEC:
+ ctx->ctx_buf_size = buf_size->h264_dec_ctx;
+ break;
+ case S5P_FIMV_CODEC_MPEG4_DEC:
+ case S5P_FIMV_CODEC_H263_DEC:
+ case S5P_FIMV_CODEC_VC1RCV_DEC:
+ case S5P_FIMV_CODEC_VC1_DEC:
+ case S5P_FIMV_CODEC_MPEG2_DEC:
+ case S5P_FIMV_CODEC_VP8_DEC:
+ case S5P_FIMV_CODEC_FIMV1_DEC:
+ case S5P_FIMV_CODEC_FIMV2_DEC:
+ case S5P_FIMV_CODEC_FIMV3_DEC:
+ case S5P_FIMV_CODEC_FIMV4_DEC:
+ ctx->ctx_buf_size = buf_size->other_dec_ctx;
+ break;
+ case S5P_FIMV_CODEC_H264_ENC:
+ ctx->ctx_buf_size = buf_size->h264_enc_ctx;
+ break;
+ case S5P_FIMV_CODEC_MPEG4_ENC:
+ case S5P_FIMV_CODEC_H263_ENC:
+ ctx->ctx_buf_size = buf_size->other_enc_ctx;
+ break;
+ default:
+ ctx->ctx_buf_size = 0;
+ mfc_err("Codec type(%d) should be checked!\n", ctx->codec_mode);
+ break;
+ }
+
+ if (ctx->is_drm) {
+ ctx->ctx_buf_size = buf_size->h264_dec_ctx;
+ alloc_ctx = dev->alloc_ctx_drm;
+ }
+
+ ctx->ctx.alloc = s5p_mfc_mem_alloc(alloc_ctx, ctx->ctx_buf_size);
+ if (IS_ERR(ctx->ctx.alloc)) {
+ mfc_err("Allocating context buffer failed.\n");
+ return PTR_ERR(ctx->ctx.alloc);
+ }
+
+ ctx->ctx.ofs = s5p_mfc_mem_daddr(ctx->ctx.alloc);
+ ctx->ctx.virt = s5p_mfc_mem_vaddr(ctx->ctx.alloc);
+ if (!ctx->ctx.virt) {
+ s5p_mfc_mem_free(ctx->ctx.alloc);
+ ctx->ctx.alloc = NULL;
+ ctx->ctx.ofs = 0;
+ ctx->ctx.virt = NULL;
+
+ mfc_err("Remapping context buffer failed.\n");
+ return -ENOMEM;
+ }
+
+ s5p_mfc_cache_inv_priv(ctx->ctx.alloc);
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+/* Release instance buffer */
+void s5p_mfc_release_instance_buffer(struct s5p_mfc_ctx *ctx)
+{
+ mfc_debug_enter();
+
+ if (ctx->ctx.alloc) {
+ /*
+ dma_unmap_single(ctx->dev->v4l2_dev.dev,
+ ctx->ctx.dma, ctx->ctx_buf_size,
+ DMA_TO_DEVICE);
+ */
+ s5p_mfc_mem_free(ctx->ctx.alloc);
+ ctx->ctx.alloc = NULL;
+ ctx->ctx.ofs = 0;
+ ctx->ctx.virt = NULL;
+ }
+
+ mfc_debug_leave();
+}
+
+/* Allocate context buffers for SYS_INIT */
+int s5p_mfc_alloc_dev_context_buffer(struct s5p_mfc_dev *dev)
+{
+ struct s5p_mfc_buf_size_v6 *buf_size = dev->variant->buf_size->buf;
+ void *alloc_ctx = dev->alloc_ctx[MFC_CMA_BANK1_ALLOC_CTX];
+
+ mfc_debug_enter();
+
+#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
+ alloc_ctx = dev->alloc_ctx_drm;
+#endif
+ dev->ctx_buf.alloc = s5p_mfc_mem_alloc(alloc_ctx, buf_size->dev_ctx);
+ if (IS_ERR(dev->ctx_buf.alloc)) {
+ mfc_err("Allocating DESC buffer failed.\n");
+ return PTR_ERR(dev->ctx_buf.alloc);
+ }
+
+ dev->ctx_buf.ofs = s5p_mfc_mem_daddr(dev->ctx_buf.alloc);
+#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
+ iovmm_map_oto(&dev->plat_dev->dev, dev->ctx_buf.ofs,
+ buf_size->dev_ctx);
+#endif
+ dev->ctx_buf.virt = s5p_mfc_mem_vaddr(dev->ctx_buf.alloc);
+ if (!dev->ctx_buf.virt) {
+ s5p_mfc_mem_free(dev->ctx_buf.alloc);
+ dev->ctx_buf.alloc = NULL;
+ dev->ctx_buf.ofs = 0;
+
+ mfc_err("Remapping DESC buffer failed.\n");
+ return -ENOMEM;
+ }
+
+ s5p_mfc_cache_inv_priv(dev->ctx_buf.alloc);
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+/* Release context buffers for SYS_INIT */
+void s5p_mfc_release_dev_context_buffer(struct s5p_mfc_dev *dev)
+{
+ if (dev->ctx_buf.alloc) {
+#ifdef CONFIG_EXYNOS_CONTENT_PATH_PROTECTION
+ iovmm_unmap_oto(&dev->plat_dev->dev, dev->ctx_buf.ofs);
+#endif
+ s5p_mfc_mem_free(dev->ctx_buf.alloc);
+ dev->ctx_buf.alloc = NULL;
+ dev->ctx_buf.ofs = 0;
+ dev->ctx_buf.virt = NULL;
+ }
+}
+
+static int calc_plane(int width, int height)
+{
+ int mbX, mbY;
+
+ mbX = (width + 15)/16;
+ mbY = (height + 15)/16;
+
+ /* Alignment for interlaced processing */
+ mbY = (mbY + 1) / 2 * 2;
+
+ return (mbX * 16) * (mbY * 16);
+}
+
+void s5p_mfc_dec_calc_dpb_size(struct s5p_mfc_ctx *ctx)
+{
+ ctx->buf_width = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN);
+ ctx->buf_height = ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN);
+ mfc_debug(2, "SEQ Done: Movie dimensions %dx%d, "
+ "buffer dimensions: %dx%d\n", ctx->img_width,
+ ctx->img_height, ctx->buf_width, ctx->buf_height);
+
+ ctx->luma_size = calc_plane(ctx->img_width, ctx->img_height);
+ ctx->chroma_size = calc_plane(ctx->img_width, (ctx->img_height >> 1));
+ if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC ||
+ ctx->codec_mode == S5P_FIMV_CODEC_H264_MVC_DEC) {
+ ctx->mv_size = s5p_mfc_dec_mv_size(ctx->img_width,
+ ctx->img_height);
+ ctx->mv_size = ALIGN(ctx->mv_size, 16);
+ } else {
+ ctx->mv_size = 0;
+ }
+}
+
+void s5p_mfc_enc_calc_src_size(struct s5p_mfc_ctx *ctx)
+{
+ unsigned int mb_width, mb_height;
+
+ mb_width = mb_width(ctx->img_width);
+ mb_height = mb_height(ctx->img_height);
+
+ ctx->buf_width = ALIGN(ctx->img_width, S5P_FIMV_NV12M_HALIGN);
+ ctx->luma_size = ALIGN((mb_width * mb_height) * 256, 256);
+ ctx->chroma_size = ALIGN((mb_width * mb_height) * 128, 256);
+}
+
+/* Set registers for decoding stream buffer */
+int s5p_mfc_set_dec_stream_buffer(struct s5p_mfc_ctx *ctx, dma_addr_t buf_addr,
+ unsigned int start_num_byte, unsigned int strm_size)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_buf_size *buf_size = dev->variant->buf_size;
+
+ mfc_debug_enter();
+ mfc_debug(2, "inst_no: %d, buf_addr: 0x%08x, buf_size: 0x"
+ "%08x (%d)\n", ctx->inst_no, buf_addr, strm_size, strm_size);
+ WRITEL(strm_size, S5P_FIMV_D_STREAM_DATA_SIZE);
+ WRITEL(buf_addr, S5P_FIMV_D_CPB_BUFFER_ADDR);
+ WRITEL(buf_size->cpb_buf, S5P_FIMV_D_CPB_BUFFER_SIZE);
+ WRITEL(start_num_byte, S5P_FIMV_D_CPB_BUFFER_OFFSET);
+
+ mfc_debug_leave();
+ return 0;
+}
+
+/* Set decoding frame buffer */
+int s5p_mfc_set_dec_frame_buffer(struct s5p_mfc_ctx *ctx)
+{
+ unsigned int frame_size, i;
+ unsigned int frame_size_ch, frame_size_mv;
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+ size_t buf_addr1;
+ int buf_size1;
+ int align_gap;
+ struct s5p_mfc_buf *buf;
+ struct list_head *buf_queue;
+ unsigned char *dpb_vir;
+
+ buf_addr1 = ctx->port_a_phys;
+ buf_size1 = ctx->port_a_size;
+
+ mfc_debug(2, "Buf1: %p (%d)\n", (void *)buf_addr1, buf_size1);
+ mfc_debug(2, "Total DPB COUNT: %d\n", dec->total_dpb_count);
+ mfc_debug(2, "Setting display delay to %d\n", dec->display_delay);
+
+ WRITEL(dec->total_dpb_count, S5P_FIMV_D_NUM_DPB);
+ WRITEL(ctx->luma_size, S5P_FIMV_D_LUMA_DPB_SIZE);
+ WRITEL(ctx->chroma_size, S5P_FIMV_D_CHROMA_DPB_SIZE);
+
+ WRITEL(buf_addr1, S5P_FIMV_D_SCRATCH_BUFFER_ADDR);
+ WRITEL(ctx->scratch_buf_size, S5P_FIMV_D_SCRATCH_BUFFER_SIZE);
+ buf_addr1 += ctx->scratch_buf_size;
+ buf_size1 -= ctx->scratch_buf_size;
+
+ if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC ||
+ ctx->codec_mode == S5P_FIMV_CODEC_H264_MVC_DEC)
+ WRITEL(ctx->mv_size, S5P_FIMV_D_MV_BUFFER_SIZE);
+
+ frame_size = ctx->luma_size;
+ frame_size_ch = ctx->chroma_size;
+ frame_size_mv = ctx->mv_size;
+ mfc_debug(2, "Frame size: %d ch: %d mv: %d\n", frame_size, frame_size_ch,
+ frame_size_mv);
+
+ if (dec->dst_memtype == V4L2_MEMORY_USERPTR || dec->dst_memtype == V4L2_MEMORY_DMABUF)
+ buf_queue = &ctx->dst_queue;
+ else
+ buf_queue = &dec->dpb_queue;
+ i = 0;
+ list_for_each_entry(buf, buf_queue, list) {
+ mfc_debug(2, "Luma %x\n", buf->planes.raw.luma);
+ WRITEL(buf->planes.raw.luma, S5P_FIMV_D_LUMA_DPB + i * 4);
+ mfc_debug(2, "\tChroma %x\n", buf->planes.raw.chroma);
+ WRITEL(buf->planes.raw.chroma, S5P_FIMV_D_CHROMA_DPB + i * 4);
+
+ if ((i == 0) && (!ctx->is_drm)) {
+ dpb_vir = vb2_plane_vaddr(&buf->vb, 0);
+ if (dpb_vir) {
+ memset(dpb_vir, 0x0, ctx->luma_size);
+ s5p_mfc_cache_inv(&buf->vb, 0);
+ }
+
+ dpb_vir = vb2_plane_vaddr(&buf->vb, 1);
+ if (dpb_vir) {
+ memset(dpb_vir, 0x80, ctx->chroma_size);
+ s5p_mfc_cache_inv(&buf->vb, 1);
+ }
+ }
+ i++;
+ }
+
+ WRITEL(dec->mv_count, S5P_FIMV_D_NUM_MV);
+ if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC ||
+ ctx->codec_mode == S5P_FIMV_CODEC_H264_MVC_DEC) {
+ for (i = 0; i < dec->mv_count; i++) {
+ /* To test alignment */
+ align_gap = buf_addr1;
+ buf_addr1 = ALIGN(buf_addr1, 16);
+ align_gap = buf_addr1 - align_gap;
+ buf_size1 -= align_gap;
+
+ mfc_debug(2, "\tBuf1: %x, size: %d\n", buf_addr1, buf_size1);
+ WRITEL(buf_addr1, S5P_FIMV_D_MV_BUFFER + i * 4);
+ buf_addr1 += frame_size_mv;
+ buf_size1 -= frame_size_mv;
+ }
+ }
+
+ mfc_debug(2, "Buf1: %u, buf_size1: %d (frames %d)\n",
+ buf_addr1, buf_size1, dec->total_dpb_count);
+ if (buf_size1 < 0) {
+ mfc_debug(2, "Not enough memory has been allocated.\n");
+ return -ENOMEM;
+ }
+
+ WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID);
+ s5p_mfc_cmd_host2risc(S5P_FIMV_CH_INIT_BUFS, NULL);
+
+ mfc_debug(2, "After setting buffers.\n");
+ return 0;
+}
+
+/* Set registers for encoding stream buffer */
+int s5p_mfc_set_enc_stream_buffer(struct s5p_mfc_ctx *ctx,
+ dma_addr_t addr, unsigned int size)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+
+ WRITEL(addr, S5P_FIMV_E_STREAM_BUFFER_ADDR); /* 16B align */
+ WRITEL(size, S5P_FIMV_E_STREAM_BUFFER_SIZE);
+
+ mfc_debug(2, "stream buf addr: 0x%08lx, size: 0x%08x(%d)",
+ (unsigned long)addr, size, size);
+
+ return 0;
+}
+
+void s5p_mfc_set_enc_frame_buffer(struct s5p_mfc_ctx *ctx,
+ dma_addr_t y_addr, dma_addr_t c_addr)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+
+ WRITEL(y_addr, S5P_FIMV_E_SOURCE_LUMA_ADDR); /* 256B align */
+ WRITEL(c_addr, S5P_FIMV_E_SOURCE_CHROMA_ADDR);
+
+ mfc_debug(2, "enc src y buf addr: 0x%08lx", (unsigned long)y_addr);
+ mfc_debug(2, "enc src c buf addr: 0x%08lx", (unsigned long)c_addr);
+}
+
+void s5p_mfc_get_enc_frame_buffer(struct s5p_mfc_ctx *ctx,
+ dma_addr_t *y_addr, dma_addr_t *c_addr)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ unsigned long enc_recon_y_addr, enc_recon_c_addr;
+
+ *y_addr = READL(S5P_FIMV_E_ENCODED_SOURCE_LUMA_ADDR);
+ *c_addr = READL(S5P_FIMV_E_ENCODED_SOURCE_CHROMA_ADDR);
+
+ enc_recon_y_addr = READL(S5P_FIMV_E_RECON_LUMA_DPB_ADDR);
+ enc_recon_c_addr = READL(S5P_FIMV_E_RECON_CHROMA_DPB_ADDR);
+
+ mfc_debug(2, "recon y addr: 0x%08lx", enc_recon_y_addr);
+ mfc_debug(2, "recon c addr: 0x%08lx", enc_recon_c_addr);
+}
+
+/* Set encoding ref & codec buffer */
+int s5p_mfc_set_enc_ref_buffer(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+ size_t buf_addr1;
+ int buf_size1;
+ int i;
+
+ mfc_debug_enter();
+
+ buf_addr1 = ctx->port_a_phys;
+ buf_size1 = ctx->port_a_size;
+
+ mfc_debug(2, "Buf1: %p (%d)\n", (void *)buf_addr1, buf_size1);
+
+ for (i = 0; i < ctx->dpb_count; i++) {
+ WRITEL(buf_addr1, S5P_FIMV_E_LUMA_DPB + (4 * i));
+ buf_addr1 += enc->luma_dpb_size;
+ WRITEL(buf_addr1, S5P_FIMV_E_CHROMA_DPB + (4 * i));
+ buf_addr1 += enc->chroma_dpb_size;
+ WRITEL(buf_addr1, S5P_FIMV_E_ME_BUFFER + (4 * i));
+ buf_addr1 += enc->me_buffer_size;
+ buf_size1 -= (enc->luma_dpb_size + enc->chroma_dpb_size +
+ enc->me_buffer_size);
+ }
+
+ WRITEL(buf_addr1, S5P_FIMV_E_SCRATCH_BUFFER_ADDR);
+ WRITEL(ctx->scratch_buf_size, S5P_FIMV_E_SCRATCH_BUFFER_SIZE);
+ buf_addr1 += ctx->scratch_buf_size;
+ buf_size1 -= ctx->scratch_buf_size;
+
+ WRITEL(buf_addr1, S5P_FIMV_E_TMV_BUFFER0);
+ buf_addr1 += enc->tmv_buffer_size >> 1;
+ WRITEL(buf_addr1, S5P_FIMV_E_TMV_BUFFER1);
+ buf_addr1 += enc->tmv_buffer_size >> 1;
+ buf_size1 -= enc->tmv_buffer_size;
+
+ mfc_debug(2, "Buf1: %u, buf_size1: %d (ref frames %d)\n",
+ buf_addr1, buf_size1, ctx->dpb_count);
+ if (buf_size1 < 0) {
+ mfc_debug(2, "Not enough memory has been allocated.\n");
+ return -ENOMEM;
+ }
+
+ WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID);
+ s5p_mfc_cmd_host2risc(S5P_FIMV_CH_INIT_BUFS, NULL);
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+static int s5p_mfc_set_slice_mode(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+
+ /* multi-slice control */
+ WRITEL(enc->slice_mode, S5P_FIMV_E_MSLICE_MODE);
+ /* multi-slice MB number or bit size */
+ if (enc->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) {
+ WRITEL(enc->slice_size.mb, S5P_FIMV_E_MSLICE_SIZE_MB);
+ } else if (enc->slice_mode == \
+ V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) {
+ WRITEL(enc->slice_size.bits, S5P_FIMV_E_MSLICE_SIZE_BITS);
+ } else {
+ WRITEL(0x0, S5P_FIMV_E_MSLICE_SIZE_MB);
+ WRITEL(0x0, S5P_FIMV_E_MSLICE_SIZE_BITS);
+ }
+
+ return 0;
+
+}
+
+static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+ struct s5p_mfc_enc_params *p = &enc->params;
+ unsigned int reg = 0;
+
+ mfc_debug_enter();
+
+ /* width */
+ WRITEL(ctx->img_width, S5P_FIMV_E_FRAME_WIDTH); /* 16 align */
+ /* height */
+ WRITEL(ctx->img_height, S5P_FIMV_E_FRAME_HEIGHT); /* 16 align */
+
+ /** cropped width */
+ WRITEL(ctx->img_width, S5P_FIMV_E_CROPPED_FRAME_WIDTH);
+ /** cropped height */
+ WRITEL(ctx->img_height, S5P_FIMV_E_CROPPED_FRAME_HEIGHT);
+ /** cropped offset */
+ WRITEL(0x0, S5P_FIMV_E_FRAME_CROP_OFFSET);
+
+ /* pictype : IDR period */
+ reg = 0;
+ reg &= ~(0xffff);
+ reg |= p->gop_size;
+ WRITEL(reg, S5P_FIMV_E_GOP_CONFIG);
+
+ /* multi-slice control */
+ /* multi-slice MB number or bit size */
+ reg = 0;
+ enc->slice_mode = p->slice_mode;
+
+ if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) {
+ /* reg |= (0x1 << 3); */
+ WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS);
+ enc->slice_size.mb = p->slice_mb;
+ } else if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) {
+ /* reg |= (0x1 << 3); */
+ WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS);
+ enc->slice_size.bits = p->slice_bit;
+ } else {
+ reg &= ~(0x1 << 3);
+ WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS);
+ }
+
+ s5p_mfc_set_slice_mode(ctx);
+
+ /* cyclic intra refresh */
+ WRITEL(p->intra_refresh_mb, S5P_FIMV_E_IR_SIZE);
+ reg = READL(S5P_FIMV_E_ENC_OPTIONS);
+ if (p->intra_refresh_mb == 0)
+ reg &= ~(0x1 << 4);
+ else
+ reg |= (0x1 << 4);
+ WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS);
+
+ /* 'NON_REFERENCE_STORE_ENABLE' for debugging */
+ reg = READL(S5P_FIMV_E_ENC_OPTIONS);
+ reg &= ~(0x1 << 9);
+ WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS);
+
+ /* memory structure cur. frame */
+ if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M) {
+ /* 0: Linear, 1: 2D tiled*/
+ reg = READL(S5P_FIMV_E_ENC_OPTIONS);
+ reg &= ~(0x1 << 7);
+ WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS);
+ /* 0: NV12(CbCr), 1: NV21(CrCb) */
+ WRITEL(0x0, S5P_FIMV_PIXEL_FORMAT);
+ } else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV21M) {
+ /* 0: Linear, 1: 2D tiled*/
+ reg = READL(S5P_FIMV_E_ENC_OPTIONS);
+ reg &= ~(0x1 << 7);
+ WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS);
+ /* 0: NV12(CbCr), 1: NV21(CrCb) */
+ WRITEL(0x1, S5P_FIMV_PIXEL_FORMAT);
+ } else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT_16X16) {
+ /* 0: Linear, 1: 2D tiled*/
+ reg = READL(S5P_FIMV_E_ENC_OPTIONS);
+ reg |= (0x1 << 7);
+ WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS);
+ /* 0: NV12(CbCr), 1: NV21(CrCb) */
+ WRITEL(0x0, S5P_FIMV_PIXEL_FORMAT);
+ }
+
+ /* memory structure recon. frame */
+ /* 0: Linear, 1: 2D tiled */
+ reg = READL(S5P_FIMV_E_ENC_OPTIONS);
+ reg |= (0x1 << 8);
+ WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS);
+
+ /* padding control & value */
+ WRITEL(0x0, S5P_FIMV_E_PADDING_CTRL);
+ if (p->pad) {
+ reg = 0;
+ /** enable */
+ reg |= (1 << 31);
+ /** cr value */
+ reg &= ~(0xFF << 16);
+ reg |= (p->pad_cr << 16);
+ /** cb value */
+ reg &= ~(0xFF << 8);
+ reg |= (p->pad_cb << 8);
+ /** y value */
+ reg &= ~(0xFF);
+ reg |= (p->pad_luma);
+ WRITEL(reg, S5P_FIMV_E_PADDING_CTRL);
+ }
+
+ /* rate control config. */
+ reg = 0;
+ /** frame-level rate control */
+ reg &= ~(0x1 << 9);
+ reg |= (p->rc_frame << 9);
+ WRITEL(reg, S5P_FIMV_E_RC_CONFIG);
+
+ /* bit rate */
+ if (p->rc_frame)
+ WRITEL(p->rc_bitrate,
+ S5P_FIMV_E_RC_BIT_RATE);
+ else
+ WRITEL(1, S5P_FIMV_E_RC_BIT_RATE);
+
+ /* reaction coefficient, fixed value set from FW_111021*/
+ if (p->rc_frame) {
+ if (p->rc_reaction_coeff < TIGHT_CBR_MAX) /* tight CBR */
+ WRITEL(1, S5P_FIMV_E_RC_RPARAM);
+ else /* loose CBR */
+ WRITEL(2, S5P_FIMV_E_RC_RPARAM);
+ }
+
+ /* extended encoder ctrl */
+ /** vbv buffer size */
+ if (p->frame_skip_mode == V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT)
+ WRITEL(p->vbv_buf_size, S5P_FIMV_E_VBV_BUFFER_SIZE);
+
+ /** seq header ctrl */
+ reg = READL(S5P_FIMV_E_ENC_OPTIONS);
+ reg &= ~(0x1 << 2);
+ reg |= (p->seq_hdr_mode << 2);
+ /** frame skip mode */
+ reg &= ~(0x3);
+ reg |= (p->frame_skip_mode);
+ WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS);
+
+ /* fixed target bit */
+ /* s5p_mfc_write_info(ctx, p->fixed_target_bit, RC_CONTROL_CONFIG); */
+
+ /* 'DROP_CONTROL_ENABLE', disable */
+ reg = READL(S5P_FIMV_E_RC_CONFIG);
+ reg &= ~(0x1 << 10);
+ WRITEL(reg, S5P_FIMV_E_RC_CONFIG);
+
+ /* setting for MV range [16, 256] */
+ if (dev->fw.ver == 0x61)
+ reg = ENC_V61_MV_RANGE;
+ else
+ reg = ENC_V65_MV_RANGE;
+ WRITEL(reg, S5P_FIMV_E_MV_HOR_RANGE);
+ WRITEL(reg, S5P_FIMV_E_MV_VER_RANGE);
+
+ WRITEL(0x0, S5P_FIMV_E_VBV_INIT_DELAY); /* SEQ_start Only */
+
+ /* initialize for '0' only setting */
+ WRITEL(0x0, S5P_FIMV_E_FRAME_INSERTION); /* NAL_start Only */
+ WRITEL(0x0, S5P_FIMV_E_ROI_BUFFER_ADDR); /* NAL_start Only */
+ WRITEL(0x0, S5P_FIMV_E_PARAM_CHANGE); /* NAL_start Only */
+ WRITEL(0x0, S5P_FIMV_E_RC_ROI_CTRL); /* NAL_start Only */
+ WRITEL(0x0, S5P_FIMV_E_PICTURE_TAG); /* NAL_start Only */
+
+ WRITEL(0x0, S5P_FIMV_E_BIT_COUNT_ENABLE); /* NAL_start Only */
+ WRITEL(0x0, S5P_FIMV_E_MAX_BIT_COUNT); /* NAL_start Only */
+ WRITEL(0x0, S5P_FIMV_E_MIN_BIT_COUNT); /* NAL_start Only */
+
+ WRITEL(0x0, S5P_FIMV_E_METADATA_BUFFER_ADDR); /* NAL_start Only */
+ WRITEL(0x0, S5P_FIMV_E_METADATA_BUFFER_SIZE); /* NAL_start Only */
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+ struct s5p_mfc_enc_params *p = &enc->params;
+ struct s5p_mfc_h264_enc_params *p_264 = &p->codec.h264;
+ unsigned int reg = 0;
+ int i;
+
+ mfc_debug_enter();
+
+ s5p_mfc_set_enc_params(ctx);
+
+ /* pictype : number of B */
+ reg = READL(S5P_FIMV_E_GOP_CONFIG);
+ /** num_b_frame - 0 ~ 2 */
+ reg &= ~(0x3 << 16);
+ reg |= (p->num_b_frame << 16);
+ WRITEL(reg, S5P_FIMV_E_GOP_CONFIG);
+
+ /* profile & level */
+ reg = 0;
+ /** level */
+ reg &= ~(0xFF << 8);
+ reg |= (p_264->level << 8);
+ /** profile - 0 ~ 3 */
+ reg &= ~(0x3F);
+ reg |= p_264->profile;
+ WRITEL(reg, S5P_FIMV_E_PICTURE_PROFILE);
+
+ /* interlace */
+ reg = 0;
+ reg &= ~(0x1 << 3);
+ reg |= (p_264->interlace << 3);
+ WRITEL(reg, S5P_FIMV_E_H264_OPTIONS);
+
+ /** height */
+ if (p_264->interlace) {
+ WRITEL(ctx->img_height >> 1, S5P_FIMV_E_FRAME_HEIGHT); /* 32 align */
+ /** cropped height */
+ WRITEL(ctx->img_height >> 1, S5P_FIMV_E_CROPPED_FRAME_HEIGHT);
+ }
+
+ /* loop filter ctrl */
+ reg = READL(S5P_FIMV_E_H264_OPTIONS);
+ reg &= ~(0x3 << 1);
+ reg |= (p_264->loop_filter_mode << 1);
+ WRITEL(reg, S5P_FIMV_E_H264_OPTIONS);
+
+ /* loopfilter alpha offset */
+ if (p_264->loop_filter_alpha < 0) {
+ reg = 0x10;
+ reg |= (0xFF - p_264->loop_filter_alpha) + 1;
+ } else {
+ reg = 0x00;
+ reg |= (p_264->loop_filter_alpha & 0xF);
+ }
+ WRITEL(reg, S5P_FIMV_E_H264_LF_ALPHA_OFFSET);
+
+ /* loopfilter beta offset */
+ if (p_264->loop_filter_beta < 0) {
+ reg = 0x10;
+ reg |= (0xFF - p_264->loop_filter_beta) + 1;
+ } else {
+ reg = 0x00;
+ reg |= (p_264->loop_filter_beta & 0xF);
+ }
+ WRITEL(reg, S5P_FIMV_E_H264_LF_BETA_OFFSET);
+
+ /* entropy coding mode */
+ reg = READL(S5P_FIMV_E_H264_OPTIONS);
+ reg &= ~(0x1);
+ reg |= (p_264->entropy_mode);
+ WRITEL(reg, S5P_FIMV_E_H264_OPTIONS);
+
+ /* number of ref. picture */
+ reg = READL(S5P_FIMV_E_H264_OPTIONS);
+ reg &= ~(0x1 << 7);
+ reg |= ((p_264->num_ref_pic_4p-1) << 7);
+ WRITEL(reg, S5P_FIMV_E_H264_OPTIONS);
+
+ /* 8x8 transform enable */
+ reg = READL(S5P_FIMV_E_H264_OPTIONS);
+ reg &= ~(0x3 << 12);
+ reg |= (p_264->_8x8_transform << 12);
+ WRITEL(reg, S5P_FIMV_E_H264_OPTIONS);
+
+ /* rate control config. */
+ reg = READL(S5P_FIMV_E_RC_CONFIG);
+ /** macroblock level rate control */
+ reg &= ~(0x1 << 8);
+ reg |= (p->rc_mb << 8);
+ WRITEL(reg, S5P_FIMV_E_RC_CONFIG);
+ /** frame QP */
+ reg &= ~(0x3F);
+ reg |= p_264->rc_frame_qp;
+ WRITEL(reg, S5P_FIMV_E_RC_CONFIG);
+
+ /* frame rate */
+ /* Fix value for H.264, H.263 in the driver */
+ p->rc_frame_delta = FRAME_DELTA_H264_H263;
+ if (p->rc_frame) {
+ reg = 0;
+ reg &= ~(0xffff << 16);
+ reg |= ((p_264->rc_framerate * p->rc_frame_delta) << 16);
+ reg &= ~(0xffff);
+ reg |= p->rc_frame_delta;
+ WRITEL(reg, S5P_FIMV_E_RC_FRAME_RATE);
+ }
+
+ /* max & min value of QP */
+ reg = 0;
+ /** max QP */
+ reg &= ~(0x3F << 8);
+ reg |= (p_264->rc_max_qp << 8);
+ /** min QP */
+ reg &= ~(0x3F);
+ reg |= p_264->rc_min_qp;
+ WRITEL(reg, S5P_FIMV_E_RC_QP_BOUND);
+
+ /* macroblock adaptive scaling features */
+ WRITEL(0x0, S5P_FIMV_E_MB_RC_CONFIG);
+ if (p->rc_mb) {
+ reg = 0;
+ /** dark region */
+ reg &= ~(0x1 << 3);
+ reg |= (p_264->rc_mb_dark << 3);
+ /** smooth region */
+ reg &= ~(0x1 << 2);
+ reg |= (p_264->rc_mb_smooth << 2);
+ /** static region */
+ reg &= ~(0x1 << 1);
+ reg |= (p_264->rc_mb_static << 1);
+ /** high activity region */
+ reg &= ~(0x1);
+ reg |= p_264->rc_mb_activity;
+ WRITEL(reg, S5P_FIMV_E_MB_RC_CONFIG);
+ }
+
+ WRITEL(0x0, S5P_FIMV_E_FIXED_PICTURE_QP);
+ if (!p->rc_frame && !p->rc_mb) {
+ reg = 0;
+ reg &= ~(0x3f << 16);
+ reg |= (p_264->rc_b_frame_qp << 16);
+ reg &= ~(0x3f << 8);
+ reg |= (p_264->rc_p_frame_qp << 8);
+ reg &= ~(0x3f);
+ reg |= p_264->rc_frame_qp;
+ WRITEL(reg, S5P_FIMV_E_FIXED_PICTURE_QP);
+ }
+
+ /* extended encoder ctrl */
+ reg = READL(S5P_FIMV_E_H264_OPTIONS);
+ reg &= ~(0x1 << 5);
+ reg |= (p_264->ar_vui << 5);
+ WRITEL(reg, S5P_FIMV_E_H264_OPTIONS);
+
+ WRITEL(0x0, S5P_FIMV_E_ASPECT_RATIO);
+ WRITEL(0x0, S5P_FIMV_E_EXTENDED_SAR);
+ if (p_264->ar_vui) {
+ /* aspect ration IDC */
+ reg = 0;
+ reg &= ~(0xff);
+ reg |= p_264->ar_vui_idc;
+ WRITEL(reg, S5P_FIMV_E_ASPECT_RATIO);
+ if (p_264->ar_vui_idc == 0xFF) {
+ /* sample AR info. */
+ reg = 0;
+ reg &= ~(0xffffffff);
+ reg |= p_264->ext_sar_width << 16;
+ reg |= p_264->ext_sar_height;
+ WRITEL(reg, S5P_FIMV_E_EXTENDED_SAR);
+ }
+ }
+
+ /* intra picture period for H.264 open GOP */
+ /** control */
+ reg = READL(S5P_FIMV_E_H264_OPTIONS);
+ reg &= ~(0x1 << 4);
+ reg |= (p_264->open_gop << 4);
+ WRITEL(reg, S5P_FIMV_E_H264_OPTIONS);
+ /** value */
+ WRITEL(0x0, S5P_FIMV_E_H264_I_PERIOD);
+ if (p_264->open_gop) {
+ reg = 0;
+ reg &= ~(0xffff);
+ reg |= p_264->open_gop_size;
+ WRITEL(reg, S5P_FIMV_E_H264_I_PERIOD);
+ }
+
+ /* 'WEIGHTED_BI_PREDICTION' for B is disable */
+ reg = READL(S5P_FIMV_E_H264_OPTIONS);
+ reg &= ~(0x3 << 9);
+ WRITEL(reg, S5P_FIMV_E_H264_OPTIONS);
+
+ /* 'CONSTRAINED_INTRA_PRED_ENABLE' is disable */
+ reg = READL(S5P_FIMV_E_H264_OPTIONS);
+ reg &= ~(0x1 << 14);
+ WRITEL(reg, S5P_FIMV_E_H264_OPTIONS);
+
+ /* ASO enable */
+ reg = READL(S5P_FIMV_E_H264_OPTIONS);
+ if (p_264->aso_enable)
+ reg |= (0x1 << 6);
+ else
+ reg &= ~(0x1 << 6);
+ WRITEL(reg, S5P_FIMV_E_H264_OPTIONS);
+
+ /* hier qp enable */
+ reg = READL(S5P_FIMV_E_H264_OPTIONS);
+ reg &= ~(0x1 << 8);
+ reg |= ((p_264->open_gop & 0x1) << 8);
+ WRITEL(reg, S5P_FIMV_E_H264_OPTIONS);
+ reg = 0;
+ if (p_264->hier_qp && p_264->hier_qp_layer) {
+ reg |= (p_264->hier_qp_type & 0x1) << 0x3;
+ reg |= p_264->hier_qp_layer & 0x7;
+ WRITEL(reg, S5P_FIMV_E_H264_NUM_T_LAYER);
+ /* QP value for each layer */
+ for (i = 0; i < (p_264->hier_qp_layer & 0x7); i++)
+ WRITEL(p_264->hier_qp_layer_qp[i],
+ S5P_FIMV_E_H264_HIERARCHICAL_QP_LAYER0 + i * 4);
+ }
+ /* number of coding layer should be zero when hierarchical is disable */
+ WRITEL(reg, S5P_FIMV_E_H264_NUM_T_LAYER);
+
+ /* set frame pack sei generation */
+ if (p_264->sei_gen_enable) {
+ /* frame packing enable */
+ reg = READL(S5P_FIMV_E_H264_OPTIONS);
+ reg |= (1 << 25);
+ WRITEL(reg, S5P_FIMV_E_H264_OPTIONS);
+
+ /* set current frame0 flag & arrangement type */
+ reg = 0;
+ /** current frame0 flag */
+ reg |= ((p_264->sei_fp_curr_frame_0 & 0x1) << 2);
+ /** arrangement type */
+ reg |= (p_264->sei_fp_arrangement_type - 3) & 0x3;
+ WRITEL(reg, S5P_FIMV_E_H264_FRAME_PACKING_SEI_INFO);
+ }
+
+ if (p_264->fmo_enable) {
+ switch (p_264->fmo_slice_map_type) {
+ case V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_INTERLEAVED_SLICES:
+ if (p_264->fmo_slice_num_grp > 4)
+ p_264->fmo_slice_num_grp = 4;
+ for (i = 0; i < (p_264->fmo_slice_num_grp & 0xF); i++)
+ WRITEL(p_264->fmo_run_length[i] - 1,
+ S5P_FIMV_E_H264_FMO_RUN_LENGTH_MINUS1_0 + i*4);
+ break;
+ case V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_SCATTERED_SLICES:
+ if (p_264->fmo_slice_num_grp > 4)
+ p_264->fmo_slice_num_grp = 4;
+ break;
+ case V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_RASTER_SCAN:
+ case V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_WIPE_SCAN:
+ if (p_264->fmo_slice_num_grp > 2)
+ p_264->fmo_slice_num_grp = 2;
+ WRITEL(p_264->fmo_sg_dir & 0x1,
+ S5P_FIMV_E_H264_FMO_SLICE_GRP_CHANGE_DIR);
+ /* the valid range is 0 ~ number of macroblocks -1 */
+ WRITEL(p_264->fmo_sg_rate, S5P_FIMV_E_H264_FMO_SLICE_GRP_CHANGE_RATE_MINUS1);
+ break;
+ default:
+ mfc_err("Unsupported map type for FMO: %d\n",
+ p_264->fmo_slice_map_type);
+ p_264->fmo_slice_map_type = 0;
+ p_264->fmo_slice_num_grp = 1;
+ break;
+ }
+
+ WRITEL(p_264->fmo_slice_map_type, S5P_FIMV_E_H264_FMO_SLICE_GRP_MAP_TYPE);
+ WRITEL(p_264->fmo_slice_num_grp - 1, S5P_FIMV_E_H264_FMO_NUM_SLICE_GRP_MINUS1);
+ } else {
+ WRITEL(0, S5P_FIMV_E_H264_FMO_NUM_SLICE_GRP_MINUS1);
+ }
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+static int s5p_mfc_set_enc_params_mpeg4(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+ struct s5p_mfc_enc_params *p = &enc->params;
+ struct s5p_mfc_mpeg4_enc_params *p_mpeg4 = &p->codec.mpeg4;
+ unsigned int reg = 0;
+
+ mfc_debug_enter();
+
+ s5p_mfc_set_enc_params(ctx);
+
+ /* pictype : number of B */
+ reg = READL(S5P_FIMV_E_GOP_CONFIG);
+ /** num_b_frame - 0 ~ 2 */
+ reg &= ~(0x3 << 16);
+ reg |= (p->num_b_frame << 16);
+ WRITEL(reg, S5P_FIMV_E_GOP_CONFIG);
+
+ /* profile & level */
+ reg = 0;
+ /** level */
+ reg &= ~(0xFF << 8);
+ reg |= (p_mpeg4->level << 8);
+ /** profile - 0 ~ 1 */
+ reg &= ~(0x3F);
+ reg |= p_mpeg4->profile;
+ WRITEL(reg, S5P_FIMV_E_PICTURE_PROFILE);
+
+ /* quarter_pixel */
+ /* WRITEL(p_mpeg4->quarter_pixel, S5P_FIMV_ENC_MPEG4_QUART_PXL); */
+
+ /* qp */
+ WRITEL(0x0, S5P_FIMV_E_FIXED_PICTURE_QP);
+ if (!p->rc_frame && !p->rc_mb) {
+ reg = 0;
+ reg &= ~(0x3f << 16);
+ reg |= (p_mpeg4->rc_b_frame_qp << 16);
+ reg &= ~(0x3f << 8);
+ reg |= (p_mpeg4->rc_p_frame_qp << 8);
+ reg &= ~(0x3f);
+ reg |= p_mpeg4->rc_frame_qp;
+ WRITEL(reg, S5P_FIMV_E_FIXED_PICTURE_QP);
+ }
+
+ /* frame rate */
+ if (p->rc_frame) {
+ reg = 0;
+ reg &= ~(0xffff << 16);
+ reg |= (p_mpeg4->vop_time_res << 16);
+ reg &= ~(0xffff);
+ reg |= p_mpeg4->vop_frm_delta;
+ WRITEL(reg, S5P_FIMV_E_RC_FRAME_RATE);
+ }
+
+ /* rate control config. */
+ reg = READL(S5P_FIMV_E_RC_CONFIG);
+ /** macroblock level rate control */
+ reg &= ~(0x1 << 8);
+ reg |= (p->rc_mb << 8);
+ WRITEL(reg, S5P_FIMV_E_RC_CONFIG);
+ /** frame QP */
+ reg &= ~(0x3F);
+ reg |= p_mpeg4->rc_frame_qp;
+ WRITEL(reg, S5P_FIMV_E_RC_CONFIG);
+
+ /* max & min value of QP */
+ reg = 0;
+ /** max QP */
+ reg &= ~(0x3F << 8);
+ reg |= (p_mpeg4->rc_max_qp << 8);
+ /** min QP */
+ reg &= ~(0x3F);
+ reg |= p_mpeg4->rc_min_qp;
+ WRITEL(reg, S5P_FIMV_E_RC_QP_BOUND);
+
+ /* initialize for '0' only setting*/
+ WRITEL(0x0, S5P_FIMV_E_MPEG4_OPTIONS); /* SEQ_start only */
+ WRITEL(0x0, S5P_FIMV_E_MPEG4_HEC_PERIOD); /* SEQ_start only */
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+static int s5p_mfc_set_enc_params_h263(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+ struct s5p_mfc_enc_params *p = &enc->params;
+ struct s5p_mfc_mpeg4_enc_params *p_mpeg4 = &p->codec.mpeg4;
+ unsigned int reg = 0;
+
+ mfc_debug_enter();
+
+ s5p_mfc_set_enc_params(ctx);
+
+ /* profile & level */
+ reg = 0;
+ /** profile */
+ reg |= (0x1 << 4);
+ WRITEL(reg, S5P_FIMV_E_PICTURE_PROFILE);
+
+ /* qp */
+ WRITEL(0x0, S5P_FIMV_E_FIXED_PICTURE_QP);
+ if (!p->rc_frame && !p->rc_mb) {
+ reg = 0;
+ reg &= ~(0x3f << 8);
+ reg |= (p_mpeg4->rc_p_frame_qp << 8);
+ reg &= ~(0x3f);
+ reg |= p_mpeg4->rc_frame_qp;
+ WRITEL(reg, S5P_FIMV_E_FIXED_PICTURE_QP);
+ }
+
+ /* frame rate */
+ /* Fix value for H.264, H.263 in the driver */
+ p->rc_frame_delta = FRAME_DELTA_H264_H263;
+ if (p->rc_frame) {
+ reg = 0;
+ reg &= ~(0xffff << 16);
+ reg |= ((p_mpeg4->rc_framerate * p->rc_frame_delta) << 16);
+ reg &= ~(0xffff);
+ reg |= p->rc_frame_delta;
+ WRITEL(reg, S5P_FIMV_E_RC_FRAME_RATE);
+ }
+
+ /* rate control config. */
+ reg = READL(S5P_FIMV_E_RC_CONFIG);
+ /** macroblock level rate control */
+ reg &= ~(0x1 << 8);
+ reg |= (p->rc_mb << 8);
+ WRITEL(reg, S5P_FIMV_E_RC_CONFIG);
+ /** frame QP */
+ reg &= ~(0x3F);
+ reg |= p_mpeg4->rc_frame_qp;
+ WRITEL(reg, S5P_FIMV_E_RC_CONFIG);
+
+ /* max & min value of QP */
+ reg = 0;
+ /** max QP */
+ reg &= ~(0x3F << 8);
+ reg |= (p_mpeg4->rc_max_qp << 8);
+ /** min QP */
+ reg &= ~(0x3F);
+ reg |= p_mpeg4->rc_min_qp;
+ WRITEL(reg, S5P_FIMV_E_RC_QP_BOUND);
+
+ mfc_debug_leave();
+
+ return 0;
+}
+
+/* Initialize decoding */
+int s5p_mfc_init_decode(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+ unsigned int reg = 0;
+ int fmo_aso_ctrl = 0;
+
+ mfc_debug_enter();
+ mfc_debug(2, "InstNo: %d/%d\n", ctx->inst_no, S5P_FIMV_CH_SEQ_HEADER);
+ mfc_debug(2, "BUFs: %08x %08x %08x\n",
+ READL(S5P_FIMV_D_CPB_BUFFER_ADDR),
+ READL(S5P_FIMV_D_CPB_BUFFER_ADDR),
+ READL(S5P_FIMV_D_CPB_BUFFER_ADDR));
+
+ /* FMO_ASO_CTRL - 0: Enable, 1: Disable */
+ reg |= (fmo_aso_ctrl << S5P_FIMV_D_OPT_FMO_ASO_CTRL_MASK);
+
+ /* When user sets desplay_delay to 0,
+ * It works as "display_delay enable" and delay set to 0.
+ * If user wants display_delay disable, It should be
+ * set to negative value. */
+ if (dec->display_delay >= 0) {
+ reg |= (0x1 << S5P_FIMV_D_OPT_DDELAY_EN_SHIFT);
+ WRITEL(dec->display_delay, S5P_FIMV_D_DISPLAY_DELAY);
+ }
+ /* Setup loop filter, for decoding this is only valid for MPEG4 */
+ if (ctx->codec_mode == S5P_FIMV_CODEC_MPEG4_DEC) {
+ mfc_debug(2, "Set loop filter to: %d\n", dec->loop_filter_mpeg4);
+ reg |= (dec->loop_filter_mpeg4 << S5P_FIMV_D_OPT_LF_CTRL_SHIFT);
+ }
+ if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_NV12MT_16X16)
+ reg |= (0x1 << S5P_FIMV_D_OPT_TILE_MODE_SHIFT);
+
+ WRITEL(reg, S5P_FIMV_D_DEC_OPTIONS);
+
+ if (ctx->codec_mode == S5P_FIMV_CODEC_FIMV1_DEC) {
+ mfc_debug(2, "Setting FIMV1 resolution to %dx%d\n",
+ ctx->img_width, ctx->img_height);
+ WRITEL(ctx->img_width, S5P_FIMV_D_SET_FRAME_WIDTH);
+ WRITEL(ctx->img_height, S5P_FIMV_D_SET_FRAME_HEIGHT);
+ }
+
+ /* 0: NV12(CbCr), 1: NV21(CrCb) */
+ if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_NV21M)
+ WRITEL(0x1, S5P_FIMV_PIXEL_FORMAT);
+ else
+ WRITEL(0x0, S5P_FIMV_PIXEL_FORMAT);
+
+ /* sei parse */
+ WRITEL(dec->sei_parse, S5P_FIMV_D_SEI_ENABLE);
+
+ WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID);
+ s5p_mfc_cmd_host2risc(S5P_FIMV_CH_SEQ_HEADER, NULL);
+
+ mfc_debug_leave();
+ return 0;
+}
+
+static inline void s5p_mfc_set_flush(struct s5p_mfc_ctx *ctx, int flush)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ unsigned int dpb;
+ if (flush)
+ dpb = READL(S5P_FIMV_SI_CH0_DPB_CONF_CTRL) | (1 << 14);
+ else
+ dpb = READL(S5P_FIMV_SI_CH0_DPB_CONF_CTRL) & ~(1 << 14);
+ WRITEL(dpb, S5P_FIMV_SI_CH0_DPB_CONF_CTRL);
+}
+
+/* Decode a single frame */
+int s5p_mfc_decode_one_frame(struct s5p_mfc_ctx *ctx, int last_frame)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_dec *dec = ctx->dec_priv;
+
+ mfc_debug(2, "Setting flags to %08lx (free:%d WTF:%d)\n",
+ dec->dpb_status, ctx->dst_queue_cnt,
+ dec->dpb_queue_cnt);
+ WRITEL(dec->dpb_status, S5P_FIMV_D_AVAILABLE_DPB_FLAG_LOWER);
+ WRITEL(0x0, S5P_FIMV_D_AVAILABLE_DPB_FLAG_UPPER);
+ WRITEL(dec->slice_enable, S5P_FIMV_D_SLICE_IF_ENABLE);
+
+ WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID);
+ /* Issue different commands to instance basing on whether it
+ * is the last frame or not. */
+ switch (last_frame) {
+ case 0:
+ s5p_mfc_cmd_host2risc(S5P_FIMV_CH_FRAME_START, NULL);
+ break;
+ case 1:
+ s5p_mfc_cmd_host2risc(S5P_FIMV_CH_LAST_FRAME, NULL);
+ break;
+ }
+
+ mfc_debug(2, "Decoding a usual frame.\n");
+ return 0;
+}
+
+int s5p_mfc_init_encode(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+
+ mfc_debug(2, "++\n");
+
+ if (ctx->codec_mode == S5P_FIMV_CODEC_H264_ENC)
+ s5p_mfc_set_enc_params_h264(ctx);
+ else if (ctx->codec_mode == S5P_FIMV_CODEC_MPEG4_ENC)
+ s5p_mfc_set_enc_params_mpeg4(ctx);
+ else if (ctx->codec_mode == S5P_FIMV_CODEC_H263_ENC)
+ s5p_mfc_set_enc_params_h263(ctx);
+ else {
+ mfc_err("Unknown codec for encoding (%x).\n",
+ ctx->codec_mode);
+ return -EINVAL;
+ }
+
+ WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID);
+ s5p_mfc_cmd_host2risc(S5P_FIMV_CH_SEQ_HEADER, NULL);
+
+ mfc_debug(2, "--\n");
+
+ return 0;
+}
+
+int s5p_mfc_h264_set_aso_slice_order(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_enc *enc = ctx->enc_priv;
+ struct s5p_mfc_enc_params *p = &enc->params;
+ struct s5p_mfc_h264_enc_params *p_264 = &p->codec.h264;
+ int i;
+
+ if (p_264->aso_enable) {
+ for (i = 0; i < 8; i++)
+ WRITEL(p_264->aso_slice_order[i],
+ S5P_FIMV_E_H264_ASO_SLICE_ORDER_0 + i * 4);
+ }
+ return 0;
+}
+
+/* Encode a single frame */
+int s5p_mfc_encode_one_frame(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+
+ mfc_debug(2, "++\n");
+
+ /* memory structure cur. frame */
+ /*
+ if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M)
+ WRITEL(0, S5P_FIMV_ENC_MAP_FOR_CUR);
+ else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT)
+ WRITEL(3, S5P_FIMV_ENC_MAP_FOR_CUR);
+ */
+ if (ctx->codec_mode == S5P_FIMV_CODEC_H264_ENC)
+ s5p_mfc_h264_set_aso_slice_order(ctx);
+
+ s5p_mfc_set_slice_mode(ctx);
+
+ WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID);
+ s5p_mfc_cmd_host2risc(S5P_FIMV_CH_FRAME_START, NULL);
+
+ mfc_debug(2, "--\n");
+
+ return 0;
+}
+
+static inline int s5p_mfc_get_new_ctx(struct s5p_mfc_dev *dev)
+{
+ int new_ctx;
+ int cnt;
+
+ mfc_debug(2, "Previos context: %d (bits %08lx)\n", dev->curr_ctx,
+ dev->ctx_work_bits);
+ new_ctx = (dev->curr_ctx + 1) % MFC_NUM_CONTEXTS;
+ cnt = 0;
+ while (!test_bit(new_ctx, &dev->ctx_work_bits)) {
+ new_ctx = (new_ctx + 1) % MFC_NUM_CONTEXTS;
+ cnt++;
+ if (cnt > MFC_NUM_CONTEXTS) {
+ /* No contexts to run */
+ return -EAGAIN;
+ }
+ }
+ return new_ctx;
+}
+
+static inline int s5p_mfc_run_dec_last_frames(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_buf *temp_vb;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->irqlock, flags);
+
+ /* Frames are being decoded */
+ if (list_empty(&ctx->src_queue)) {
+ mfc_debug(2, "No src buffers.\n");
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+ return -EAGAIN;
+ }
+ /* Get the next source buffer */
+ temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
+ temp_vb->used = 1;
+ s5p_mfc_set_dec_stream_buffer(ctx,
+ s5p_mfc_mem_plane_addr(ctx, &temp_vb->vb, 0), 0, 0);
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+
+ dev->curr_ctx = ctx->num;
+ s5p_mfc_clean_ctx_int_flags(ctx);
+ s5p_mfc_decode_one_frame(ctx, 1);
+
+ return 0;
+}
+
+static inline int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_buf *temp_vb;
+ unsigned long flags;
+ int last_frame = 0;
+ unsigned int index;
+
+ spin_lock_irqsave(&dev->irqlock, flags);
+
+ /* Frames are being decoded */
+ if (list_empty(&ctx->src_queue)) {
+ mfc_debug(2, "No src buffers.\n");
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+ return -EAGAIN;
+ }
+ if (ctx->dst_queue_cnt < ctx->dpb_count) {
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+ return -EAGAIN;
+ }
+ /* Get the next source buffer */
+ temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
+ temp_vb->used = 1;
+ mfc_debug(2, "Temp vb: %p\n", temp_vb);
+ mfc_debug(2, "Src Addr: 0x%08lx\n",
+ (unsigned long)s5p_mfc_mem_plane_addr(ctx, &temp_vb->vb, 0));
+ s5p_mfc_set_dec_stream_buffer(ctx,
+ s5p_mfc_mem_plane_addr(ctx, &temp_vb->vb, 0),
+ 0, temp_vb->vb.v4l2_planes[0].bytesused);
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+
+ index = temp_vb->vb.v4l2_buf.index;
+ if (call_cop(ctx, set_buf_ctrls_val, ctx, &ctx->src_ctrls[index]) < 0)
+ mfc_err("failed in set_buf_ctrls_val\n");
+
+ dev->curr_ctx = ctx->num;
+ s5p_mfc_clean_ctx_int_flags(ctx);
+ if (temp_vb->vb.v4l2_planes[0].bytesused == 0) {
+ last_frame = 1;
+ mfc_debug(2, "Setting ctx->state to FINISHING\n");
+ ctx->state = MFCINST_FINISHING;
+ }
+ s5p_mfc_decode_one_frame(ctx, last_frame);
+
+ return 0;
+}
+
+static inline int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ unsigned long flags;
+ struct s5p_mfc_buf *dst_mb;
+ struct s5p_mfc_buf *src_mb;
+ dma_addr_t src_y_addr, src_c_addr, dst_addr;
+ /*
+ unsigned int src_y_size, src_c_size;
+ */
+ unsigned int dst_size;
+ unsigned int index;
+
+ spin_lock_irqsave(&dev->irqlock, flags);
+
+ if (list_empty(&ctx->src_queue)) {
+ mfc_debug(2, "no src buffers.\n");
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+ return -EAGAIN;
+ }
+
+ if (list_empty(&ctx->dst_queue)) {
+ mfc_debug(2, "no dst buffers.\n");
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+ return -EAGAIN;
+ }
+
+ src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
+ src_mb->used = 1;
+ src_y_addr = s5p_mfc_mem_plane_addr(ctx, &src_mb->vb, 0);
+ src_c_addr = s5p_mfc_mem_plane_addr(ctx, &src_mb->vb, 1);
+
+ mfc_debug(2, "enc src y addr: 0x%08lx", (unsigned long)src_y_addr);
+ mfc_debug(2, "enc src c addr: 0x%08lx", (unsigned long)src_c_addr);
+
+ s5p_mfc_set_enc_frame_buffer(ctx, src_y_addr, src_c_addr);
+
+ dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list);
+ dst_mb->used = 1;
+ dst_addr = s5p_mfc_mem_plane_addr(ctx, &dst_mb->vb, 0);
+ dst_size = vb2_plane_size(&dst_mb->vb, 0);
+
+ s5p_mfc_set_enc_stream_buffer(ctx, dst_addr, dst_size);
+
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+
+ index = src_mb->vb.v4l2_buf.index;
+ if (call_cop(ctx, set_buf_ctrls_val, ctx, &ctx->src_ctrls[index]) < 0)
+ mfc_err("failed in set_buf_ctrls_val\n");
+
+ dev->curr_ctx = ctx->num;
+ s5p_mfc_clean_ctx_int_flags(ctx);
+ s5p_mfc_encode_one_frame(ctx);
+
+ return 0;
+}
+
+static inline void s5p_mfc_run_init_dec(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ unsigned long flags;
+ struct s5p_mfc_buf *temp_vb;
+
+ /* Initializing decoding - parsing header */
+ spin_lock_irqsave(&dev->irqlock, flags);
+ mfc_debug(2, "Preparing to init decoding.\n");
+ temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
+ mfc_debug(2, "Header size: %d\n", temp_vb->vb.v4l2_planes[0].bytesused);
+ s5p_mfc_set_dec_stream_buffer(ctx,
+ s5p_mfc_mem_plane_addr(ctx, &temp_vb->vb, 0),
+ 0, temp_vb->vb.v4l2_planes[0].bytesused);
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+ dev->curr_ctx = ctx->num;
+ mfc_debug(2, "Header addr: 0x%08lx\n",
+ (unsigned long)s5p_mfc_mem_plane_addr(ctx, &temp_vb->vb, 0));
+ s5p_mfc_clean_ctx_int_flags(ctx);
+ s5p_mfc_init_decode(ctx);
+}
+
+static inline int s5p_mfc_run_init_enc(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ unsigned long flags;
+ struct s5p_mfc_buf *dst_mb;
+ dma_addr_t dst_addr;
+ unsigned int dst_size;
+ int ret;
+
+ spin_lock_irqsave(&dev->irqlock, flags);
+
+ dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list);
+ dst_addr = s5p_mfc_mem_plane_addr(ctx, &dst_mb->vb, 0);
+ dst_size = vb2_plane_size(&dst_mb->vb, 0);
+ s5p_mfc_set_enc_stream_buffer(ctx, dst_addr, dst_size);
+
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+
+ dev->curr_ctx = ctx->num;
+ mfc_debug(2, "Header addr: 0x%08lx\n",
+ (unsigned long)s5p_mfc_mem_plane_addr(ctx, &dst_mb->vb, 0));
+ s5p_mfc_clean_ctx_int_flags(ctx);
+
+ ret = s5p_mfc_init_encode(ctx);
+ return ret;
+}
+
+static inline int s5p_mfc_run_init_dec_buffers(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ int ret;
+ /* Header was parsed now starting processing
+ * First set the output frame buffers
+ * s5p_mfc_alloc_dec_buffers(ctx); */
+
+ if (ctx->capture_state != QUEUE_BUFS_MMAPED) {
+ mfc_err("It seems that not all destionation buffers were "
+ "mmaped.\nMFC requires that all destination are mmaped "
+ "before starting processing.\n");
+ return -EAGAIN;
+ }
+
+ dev->curr_ctx = ctx->num;
+ s5p_mfc_clean_ctx_int_flags(ctx);
+ ret = s5p_mfc_set_dec_frame_buffer(ctx);
+ if (ret) {
+ mfc_err("Failed to alloc frame mem.\n");
+ ctx->state = MFCINST_ERROR;
+ }
+ return ret;
+}
+
+static inline int s5p_mfc_run_init_enc_buffers(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ int ret;
+
+ ret = s5p_mfc_alloc_codec_buffers(ctx);
+ if (ret) {
+ mfc_err("Failed to allocate encoding buffers.\n");
+ return -ENOMEM;
+ }
+
+ /* Header was generated now starting processing
+ * First set the reference frame buffers
+ */
+ if (ctx->capture_state != QUEUE_BUFS_REQUESTED) {
+ mfc_err("It seems that destionation buffers were not "
+ "requested.\nMFC requires that header should be generated "
+ "before allocating codec buffer.\n");
+ return -EAGAIN;
+ }
+
+ dev->curr_ctx = ctx->num;
+ s5p_mfc_clean_ctx_int_flags(ctx);
+ ret = s5p_mfc_set_enc_ref_buffer(ctx);
+ if (ret) {
+ mfc_err("Failed to alloc frame mem.\n");
+ ctx->state = MFCINST_ERROR;
+ }
+ return ret;
+}
+
+static inline int s5p_mfc_ctx_ready(struct s5p_mfc_ctx *ctx)
+{
+ if (ctx->type == MFCINST_DECODER)
+ return s5p_mfc_dec_ctx_ready(ctx);
+ else if (ctx->type == MFCINST_ENCODER)
+ return s5p_mfc_enc_ctx_ready(ctx);
+
+ return 0;
+}
+
+/* Try running an operation on hardware */
+void s5p_mfc_try_run(struct s5p_mfc_dev *dev)
+{
+ struct s5p_mfc_ctx *ctx;
+ int new_ctx;
+ unsigned int ret = 0;
+ unsigned long flags;
+
+ mfc_debug(1, "Try run dev: %p\n", dev);
+
+ spin_lock_irqsave(&dev->condlock, flags);
+ /* Check whether hardware is not running */
+ if (dev->hw_lock != 0) {
+ spin_unlock_irqrestore(&dev->condlock, flags);
+ /* This is perfectly ok, the scheduled ctx should wait */
+ mfc_debug(1, "Couldn't lock HW.\n");
+ return;
+ }
+
+ /* Choose the context to run */
+ new_ctx = s5p_mfc_get_new_ctx(dev);
+ if (new_ctx < 0) {
+ /* No contexts to run */
+ spin_unlock_irqrestore(&dev->condlock, flags);
+ mfc_debug(1, "No ctx is scheduled to be run.\n");
+ return;
+ }
+
+ ctx = dev->ctx[new_ctx];
+ if (test_and_set_bit(ctx->num, &dev->hw_lock) != 0) {
+ spin_unlock_irqrestore(&dev->condlock, flags);
+ mfc_err("Failed to lock hardware.\n");
+ return;
+ }
+ spin_unlock_irqrestore(&dev->condlock, flags);
+
+ mfc_debug(1, "New context: %d\n", new_ctx);
+ mfc_debug(1, "Seting new context to %p\n", ctx);
+ /* Got context to run in ctx */
+ mfc_debug(1, "ctx->dst_queue_cnt=%d ctx->dpb_count=%d ctx->src_queue_cnt=%d\n",
+ ctx->dst_queue_cnt, ctx->dpb_count, ctx->src_queue_cnt);
+ mfc_debug(1, "ctx->state=%d\n", ctx->state);
+ /* Last frame has already been sent to MFC
+ * Now obtaining frames from MFC buffer */
+
+ dev->curr_ctx_drm = ctx->is_drm;
+
+ s5p_mfc_clock_on();
+
+ if (ctx->type == MFCINST_DECODER) {
+ switch (ctx->state) {
+ case MFCINST_FINISHING:
+ ret = s5p_mfc_run_dec_last_frames(ctx);
+ break;
+ case MFCINST_RUNNING:
+ ret = s5p_mfc_run_dec_frame(ctx);
+ break;
+ case MFCINST_INIT:
+ ret = s5p_mfc_open_inst(ctx);
+ break;
+ case MFCINST_RETURN_INST:
+ ret = s5p_mfc_close_inst(ctx);
+ break;
+ case MFCINST_GOT_INST:
+ s5p_mfc_run_init_dec(ctx);
+ break;
+ case MFCINST_HEAD_PARSED:
+ ret = s5p_mfc_run_init_dec_buffers(ctx);
+ break;
+ case MFCINST_RES_CHANGE_INIT:
+ ret = s5p_mfc_run_dec_last_frames(ctx);
+ break;
+ case MFCINST_RES_CHANGE_FLUSH:
+ ret = s5p_mfc_run_dec_last_frames(ctx);
+ break;
+ case MFCINST_RES_CHANGE_END:
+ mfc_debug(2, "Finished remaining frames after resolution change.\n");
+ ctx->capture_state = QUEUE_FREE;
+ mfc_debug(2, "Will re-init the codec`.\n");
+ s5p_mfc_run_init_dec(ctx);
+ break;
+ default:
+ ret = -EAGAIN;
+ }
+ } else if (ctx->type == MFCINST_ENCODER) {
+ switch (ctx->state) {
+ case MFCINST_FINISHING:
+ case MFCINST_RUNNING:
+ case MFCINST_RUNNING_NO_OUTPUT:
+ ret = s5p_mfc_run_enc_frame(ctx);
+ break;
+ case MFCINST_INIT:
+ ret = s5p_mfc_open_inst(ctx);
+ break;
+ case MFCINST_RETURN_INST:
+ ret = s5p_mfc_close_inst(ctx);
+ break;
+ case MFCINST_GOT_INST:
+ ret = s5p_mfc_run_init_enc(ctx);
+ break;
+ case MFCINST_HEAD_PARSED: /* Only for MFC6.x */
+ ret = s5p_mfc_run_init_enc_buffers(ctx);
+ break;
+ default:
+ ret = -EAGAIN;
+ }
+ } else {
+ mfc_err("invalid context type: %d\n", ctx->type);
+ ret = -EAGAIN;
+ }
+
+ if (ret) {
+ /* Check again the ctx condition and clear work bits
+ * if ctx is not available. */
+ if (s5p_mfc_ctx_ready(ctx) == 0) {
+ spin_lock_irqsave(&dev->condlock, flags);
+ clear_bit(ctx->num, &dev->ctx_work_bits);
+ spin_unlock_irqrestore(&dev->condlock, flags);
+ }
+ /* Free hardware lock */
+ if (test_and_clear_bit(ctx->num, &dev->hw_lock) == 0)
+ mfc_err("Failed to unlock hardware.\n");
+ s5p_mfc_clock_off();
+
+ /* Trigger again if other instance's work is waiting */
+ if (dev->ctx_work_bits)
+ queue_work(dev->irq_workqueue, &dev->work_struct);
+ }
+}
+
+
+void s5p_mfc_cleanup_queue(struct list_head *lh, struct vb2_queue *vq)
+{
+ struct s5p_mfc_buf *b;
+ int i;
+
+ while (!list_empty(lh)) {
+ b = list_entry(lh->next, struct s5p_mfc_buf, list);
+ for (i = 0; i < b->vb.num_planes; i++)
+ vb2_set_plane_payload(&b->vb, i, 0);
+ vb2_buffer_done(&b->vb, VB2_BUF_STATE_ERROR);
+ list_del(&b->list);
+ }
+}
+
+void s5p_mfc_write_info(struct s5p_mfc_ctx *ctx, unsigned int data, unsigned int ofs)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+
+ /* MFC 6.x uses SFR for information */
+ if (dev->hw_lock) {
+ WRITEL(data, ofs);
+ } else {
+ s5p_mfc_clock_on();
+ WRITEL(data, ofs);
+ s5p_mfc_clock_off();
+ }
+}
+
+unsigned int s5p_mfc_read_info(struct s5p_mfc_ctx *ctx, unsigned int ofs)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ int ret;
+
+ /* MFC 6.x uses SFR for information */
+ if (dev->hw_lock) {
+ ret = READL(ofs);
+ } else {
+ s5p_mfc_clock_on();
+ ret = READL(ofs);
+ s5p_mfc_clock_off();
+ }
+
+ return ret;
+}
diff --git a/drivers/media/video/exynos/mfc/s5p_mfc_opr_v6.h b/drivers/media/video/exynos/mfc/s5p_mfc_opr_v6.h
new file mode 100644
index 0000000..a39e357
--- /dev/null
+++ b/drivers/media/video/exynos/mfc/s5p_mfc_opr_v6.h
@@ -0,0 +1,197 @@
+/*
+ * drivers/media/video/exynos/mfc/s5p_mfc_opr_v6.h
+ *
+ * Header file for Samsung MFC (Multi Function Codec - FIMV) driver
+ * Contains declarations of hw related functions.
+ *
+ * Kamil Debski, Copyright (c) 2010 Samsung Electronics
+ * http://www.samsung.com/
+ *
+ * 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.
+ */
+
+#ifndef S5P_MFC_OPR_V6_H_
+#define S5P_MFC_OPR_V6_H_
+
+#include "s5p_mfc_common.h"
+#include "s5p_mfc_mem.h"
+
+#define MFC_CTRL_MODE_CUSTOM MFC_CTRL_MODE_SFR
+
+int s5p_mfc_init_decode(struct s5p_mfc_ctx *ctx);
+int s5p_mfc_init_encode(struct s5p_mfc_ctx *mfc_ctx);
+
+int s5p_mfc_set_dec_frame_buffer(struct s5p_mfc_ctx *ctx);
+int s5p_mfc_set_dec_stream_buffer(struct s5p_mfc_ctx *ctx,
+ dma_addr_t buf_addr,
+ unsigned int start_num_byte,
+ unsigned int buf_size);
+
+void s5p_mfc_set_enc_frame_buffer(struct s5p_mfc_ctx *ctx,
+ dma_addr_t y_addr, dma_addr_t c_addr);
+int s5p_mfc_set_enc_stream_buffer(struct s5p_mfc_ctx *ctx,
+ dma_addr_t addr, unsigned int size);
+void s5p_mfc_get_enc_frame_buffer(struct s5p_mfc_ctx *ctx,
+ dma_addr_t *y_addr, dma_addr_t *c_addr);
+int s5p_mfc_set_enc_ref_buffer(struct s5p_mfc_ctx *mfc_ctx);
+
+int s5p_mfc_decode_one_frame(struct s5p_mfc_ctx *ctx, int last_frame);
+int s5p_mfc_encode_one_frame(struct s5p_mfc_ctx *mfc_ctx);
+
+/* Memory allocation */
+int s5p_mfc_alloc_dec_temp_buffers(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_set_dec_desc_buffer(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_release_dec_desc_buffer(struct s5p_mfc_ctx *ctx);
+
+int s5p_mfc_alloc_codec_buffers(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_release_codec_buffers(struct s5p_mfc_ctx *ctx);
+
+int s5p_mfc_alloc_instance_buffer(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_release_instance_buffer(struct s5p_mfc_ctx *ctx);
+int s5p_mfc_alloc_dev_context_buffer(struct s5p_mfc_dev *dev);
+void s5p_mfc_release_dev_context_buffer(struct s5p_mfc_dev *dev);
+
+void s5p_mfc_dec_calc_dpb_size(struct s5p_mfc_ctx *ctx);
+void s5p_mfc_enc_calc_src_size(struct s5p_mfc_ctx *ctx);
+
+#define s5p_mfc_get_dspl_y_adr() (readl(dev->regs_base + \
+ S5P_FIMV_SI_DISPLAY_Y_ADR) << 11)
+#define s5p_mfc_get_dspl_status() readl(dev->regs_base + \
+ S5P_FIMV_D_DISPLAY_STATUS)
+#define s5p_mfc_get_decoded_status() readl(dev->regs_base + \
+ S5P_FIMV_D_DECODED_STATUS)
+#define s5p_mfc_get_dec_frame_type() (readl(dev->regs_base + \
+ S5P_FIMV_D_DECODED_FRAME_TYPE) \
+ & S5P_FIMV_DECODED_FRAME_MASK)
+#define s5p_mfc_get_disp_frame_type() (readl(ctx->dev->regs_base + \
+ S5P_FIMV_D_DISPLAY_FRAME_TYPE) \
+ & S5P_FIMV_DISPLAY_FRAME_MASK)
+#define s5p_mfc_get_consumed_stream() readl(dev->regs_base + \
+ S5P_FIMV_D_DECODED_NAL_SIZE)
+#define s5p_mfc_get_int_reason() (readl(dev->regs_base + \
+ S5P_FIMV_RISC2HOST_CMD) & \
+ S5P_FIMV_RISC2HOST_CMD_MASK)
+#define s5p_mfc_get_int_err() readl(dev->regs_base + \
+ S5P_FIMV_ERROR_CODE)
+#define s5p_mfc_err_dec(x) (((x) & S5P_FIMV_ERR_DEC_MASK) >> \
+ S5P_FIMV_ERR_DEC_SHIFT)
+#define s5p_mfc_err_dspl(x) (((x) & S5P_FIMV_ERR_DSPL_MASK) >> \
+ S5P_FIMV_ERR_DSPL_SHIFT)
+#define s5p_mfc_get_img_width() readl(dev->regs_base + \
+ S5P_FIMV_D_DISPLAY_FRAME_WIDTH)
+#define s5p_mfc_get_img_height() readl(dev->regs_base + \
+ S5P_FIMV_D_DISPLAY_FRAME_HEIGHT)
+#define s5p_mfc_get_dpb_count() readl(dev->regs_base + \
+ S5P_FIMV_D_MIN_NUM_DPB)
+#define s5p_mfc_get_mv_count() readl(dev->regs_base + \
+ S5P_FIMV_D_MIN_NUM_MV)
+#define s5p_mfc_get_inst_no() readl(dev->regs_base + \
+ S5P_FIMV_RET_INSTANCE_ID)
+#define s5p_mfc_get_enc_dpb_count() readl(dev->regs_base + \
+ S5P_FIMV_E_NUM_DPB)
+#define s5p_mfc_get_enc_strm_size() readl(dev->regs_base + \
+ S5P_FIMV_E_STREAM_SIZE)
+#define s5p_mfc_get_enc_slice_type() readl(dev->regs_base + \
+ S5P_FIMV_E_SLICE_TYPE)
+#define s5p_mfc_get_enc_pic_count() readl(dev->regs_base + \
+ S5P_FIMV_E_PICTURE_COUNT)
+#define s5p_mfc_get_sei_avail_status() readl(dev->regs_base + \
+ S5P_FIMV_D_FRAME_PACK_SEI_AVAIL)
+#define s5p_mfc_get_mvc_num_views() readl(dev->regs_base + \
+ S5P_FIMV_D_MVC_NUM_VIEWS)
+#define s5p_mfc_get_mvc_disp_view_id() (readl(dev->regs_base + \
+ S5P_FIMV_D_MVC_VIEW_ID) \
+ & S5P_FIMV_D_MVC_VIEW_ID_DISP_MASK)
+
+#define mb_width(x_size) ((x_size + 15) / 16)
+#define mb_height(y_size) ((y_size + 15) / 16)
+#define s5p_mfc_dec_mv_size(x, y) (mb_width(x) * (((mb_height(y)+1)/2)*2) * 64 + 128)
+
+#define s5p_mfc_clear_int_flags() \
+ do { \
+ s5p_mfc_write_reg(0, S5P_FIMV_RISC2HOST_CMD); \
+ s5p_mfc_write_reg(0, S5P_FIMV_RISC2HOST_INT); \
+ } while (0)
+
+/* Definition */
+#define ENC_MULTI_SLICE_MB_MAX ((1 << 30) - 1)
+#define ENC_MULTI_SLICE_BIT_MIN 2800
+#define ENC_MULTI_SLICE_BYTE_MIN 350
+#define ENC_INTRA_REFRESH_MB_MAX ((1 << 18) - 1)
+#define ENC_VBV_BUF_SIZE_MAX ((1 << 30) - 1)
+#define ENC_H264_LOOP_FILTER_AB_MIN -12
+#define ENC_H264_LOOP_FILTER_AB_MAX 12
+#define ENC_H264_RC_FRAME_RATE_MAX ((1 << 16) - 1)
+#define ENC_H263_RC_FRAME_RATE_MAX ((1 << 16) - 1)
+#define ENC_H264_PROFILE_MAX 3
+#define ENC_H264_LEVEL_MAX 42
+#define ENC_MPEG4_VOP_TIME_RES_MAX ((1 << 16) - 1)
+#define FRAME_DELTA_H264_H263 1
+#define TIGHT_CBR_MAX 10
+
+/* Definitions for shared memory compatibility */
+#define PIC_TIME_TOP S5P_FIMV_D_RET_PICTURE_TAG_TOP
+#define PIC_TIME_BOT S5P_FIMV_D_RET_PICTURE_TAG_BOT
+#define CROP_INFO_H S5P_FIMV_D_DISPLAY_CROP_INFO1
+#define CROP_INFO_V S5P_FIMV_D_DISPLAY_CROP_INFO2
+
+/* Scratch buffer size for MFC v6.1 */
+#define DEC_V61_H264_SCRATCH_SIZE(x, y) \
+ ((x * 128) + 65536)
+#define DEC_V61_MPEG4_SCRATCH_SIZE(x, y) \
+ ((x) * ((y) * 64 + 144) + \
+ ((2048 + 15) / 16 * (y) * 64) + \
+ ((2048 + 15) / 16 * 256 + 8320))
+#define DEC_V61_VC1_SCRATCH_SIZE(x, y) \
+ (2096 * ((x) + (y) + 1))
+#define DEC_V61_MPEG2_SCRATCH_SIZE(x, y) 0
+#define DEC_V61_H263_SCRATCH_SIZE(x, y) \
+ ((x) * 400)
+#define DEC_V61_VP8_SCRATCH_SIZE(x, y) \
+ ((x) * 32 + (y) * 128 + 34816)
+#define ENC_V61_H264_SCRATCH_SIZE(x, y) \
+ (((x) * 64) + (((x) + 1) * 16) + (4096 * 16))
+#define ENC_V61_MPEG4_SCRATCH_SIZE(x, y) \
+ (((x) * 16) + (((x) + 1) * 16))
+
+/* Scratch buffer size for MFC v6.5 */
+#define DEC_V65_H264_SCRATCH_SIZE(x, y) \
+ ((x * 192) + 64)
+#define DEC_V65_MPEG4_SCRATCH_SIZE(x, y) \
+ ((x) * ((y) * 64 + 144) + \
+ ((2048 + 15) / 16 * (y) * 64) + \
+ ((2048 + 15) / 16 * 256 + 8320))
+#define DEC_V65_VC1_SCRATCH_SIZE(x, y) \
+ (2096 * ((x) + (y) + 1))
+#define DEC_V65_MPEG2_SCRATCH_SIZE(x, y) 0
+#define DEC_V65_H263_SCRATCH_SIZE(x, y) \
+ ((x) * 400)
+#define DEC_V65_VP8_SCRATCH_SIZE(x, y) \
+ ((x) * 32 + (y) * 128 + \
+ (((x) + 1) / 2) * 64 + 2112)
+#define ENC_V65_H264_SCRATCH_SIZE(x, y) \
+ (((x) * 48) + (((x) + 1) / 2 * 128) + 144)
+#define ENC_V65_MPEG4_SCRATCH_SIZE(x, y) \
+ (((x) * 32) + 16)
+
+/* Encoder buffer size for common */
+#define ENC_TMV_SIZE(x, y) \
+ (((x) + 1) * ((y) + 3) * 8)
+#define ENC_ME_SIZE(f_x, f_y, mb_x, mb_y) \
+ ((((((f_x) + 127) / 64) * 16) * \
+ ((((f_y) + 63) / 64) * 16)) + \
+ ((((mb_x) * (mb_y) + 31) / 32) * 16))
+
+/* MV range is [16,256] for v6.1, [16,128] for v6.5 */
+#define ENC_V61_MV_RANGE 256
+#define ENC_V65_MV_RANGE 128
+void s5p_mfc_try_run(struct s5p_mfc_dev *dev);
+
+void s5p_mfc_cleanup_queue(struct list_head *lh, struct vb2_queue *vq);
+
+void s5p_mfc_write_info(struct s5p_mfc_ctx *ctx, unsigned int data, unsigned int ofs);
+unsigned int s5p_mfc_read_info(struct s5p_mfc_ctx *ctx, unsigned int ofs);
+
+#endif /* S5P_MFC_OPR_V6_H_ */
diff --git a/drivers/media/video/exynos/mfc/s5p_mfc_pm.c b/drivers/media/video/exynos/mfc/s5p_mfc_pm.c
new file mode 100644
index 0000000..5d91970
--- /dev/null
+++ b/drivers/media/video/exynos/mfc/s5p_mfc_pm.c
@@ -0,0 +1,230 @@
+/*
+ * linux/drivers/media/video/exynos/mfc/s5p_mfc_pm.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * 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.
+ */
+
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/jiffies.h>
+#include <linux/pm_runtime.h>
+#include <linux/platform_device.h>
+
+#include <mach/exynos-mfc.h>
+
+#include "s5p_mfc_common.h"
+#include "s5p_mfc_debug.h"
+#include "s5p_mfc_pm.h"
+#include "s5p_mfc_reg.h"
+
+#define CLK_DEBUG
+
+static struct s5p_mfc_pm *pm;
+atomic_t clk_ref;
+
+#if defined(CONFIG_ARCH_EXYNOS4)
+
+#define MFC_PARENT_CLK_NAME "mout_mfc0"
+#define MFC_CLKNAME "sclk_mfc"
+#define MFC_GATE_CLK_NAME "mfc"
+
+int s5p_mfc_init_pm(struct s5p_mfc_dev *dev)
+{
+ struct clk *parent, *sclk;
+ int ret = 0;
+
+ pm = &dev->pm;
+
+ parent = clk_get(&dev->plat_dev->dev, MFC_PARENT_CLK_NAME);
+ if (IS_ERR(parent)) {
+ printk(KERN_ERR "failed to get parent clock\n");
+ ret = -ENOENT;
+ goto err_p_clk;
+ }
+
+ sclk = clk_get(&dev->plat_dev->dev, MFC_CLKNAME);
+ if (IS_ERR(sclk)) {
+ printk(KERN_ERR "failed to get source clock\n");
+ ret = -ENOENT;
+ goto err_s_clk;
+ }
+
+ clk_set_parent(sclk, parent);
+ clk_set_rate(sclk, 200 * 1000000);
+
+ /* clock for gating */
+ pm->clock = clk_get(&dev->plat_dev->dev, MFC_GATE_CLK_NAME);
+ if (IS_ERR(pm->clock)) {
+ printk(KERN_ERR "failed to get clock-gating control\n");
+ ret = -ENOENT;
+ goto err_g_clk;
+ }
+
+ atomic_set(&pm->power, 0);
+ atomic_set(&clk_ref, 0);
+
+ pm->device = &dev->plat_dev->dev;
+ pm_runtime_enable(pm->device);
+
+ return 0;
+
+err_g_clk:
+ clk_put(sclk);
+err_s_clk:
+ clk_put(parent);
+err_p_clk:
+ return ret;
+}
+
+#elif defined(CONFIG_ARCH_EXYNOS5)
+
+#define MFC_PARENT_CLK_NAME "dout_aclk_333"
+#define MFC_CLKNAME "aclk_333"
+#define MFC_GATE_CLK_NAME "mfc"
+
+int s5p_mfc_init_pm(struct s5p_mfc_dev *dev)
+{
+ struct clk *parent_clk, *sclk;
+ int ret = 0;
+ struct s5p_mfc_platdata *pdata;
+
+ pm = &dev->pm;
+
+ /* clock for gating */
+ pm->clock = clk_get(&dev->plat_dev->dev, MFC_GATE_CLK_NAME);
+ if (IS_ERR(pm->clock)) {
+ printk(KERN_ERR "failed to get clock-gating control\n");
+ ret = PTR_ERR(pm->clock);
+ goto err_g_clk;
+ }
+
+ parent_clk = clk_get(&dev->plat_dev->dev, MFC_PARENT_CLK_NAME);
+ if (IS_ERR(parent_clk)) {
+ printk(KERN_ERR "failed to get parent clock %s.\n", MFC_PARENT_CLK_NAME);
+ ret = PTR_ERR(parent_clk);
+ goto err_p_clk;
+ }
+
+ sclk = clk_get(&dev->plat_dev->dev, MFC_CLKNAME);
+ if (IS_ERR(sclk)) {
+ printk(KERN_ERR "failed to get source clock\n");
+ ret = -ENOENT;
+ goto err_s_clk;
+ }
+
+ clk_set_parent(sclk, parent_clk);
+ pdata = dev->platdata;
+ clk_set_rate(parent_clk, pdata->clock_rate);
+
+ spin_lock_init(&pm->clklock);
+ atomic_set(&pm->power, 0);
+ atomic_set(&clk_ref, 0);
+
+ pm->device = &dev->plat_dev->dev;
+ pm_runtime_enable(pm->device);
+
+ clk_put(sclk);
+ clk_put(parent_clk);
+
+ return 0;
+
+err_s_clk:
+ clk_put(parent_clk);
+err_p_clk:
+ clk_put(pm->clock);
+err_g_clk:
+ return ret;
+}
+
+#endif
+
+void s5p_mfc_final_pm(struct s5p_mfc_dev *dev)
+{
+ clk_put(pm->clock);
+
+ pm_runtime_disable(pm->device);
+}
+
+int s5p_mfc_clock_on(void)
+{
+ int ret = 0;
+ int state, val;
+ struct s5p_mfc_dev *dev = platform_get_drvdata(to_platform_device(pm->device));
+ unsigned long flags;
+
+ ret = clk_enable(pm->clock);
+ if (ret < 0)
+ return ret;
+
+ if (!dev->curr_ctx_drm) {
+ ret = s5p_mfc_mem_resume(dev->alloc_ctx[0]);
+ if (ret < 0) {
+ clk_disable(pm->clock);
+ return ret;
+ }
+ }
+
+ spin_lock_irqsave(&pm->clklock, flags);
+ if ((atomic_inc_return(&clk_ref) == 1) && (dev->fw.date >= 0x120206)) {
+ val = s5p_mfc_read_reg(S5P_FIMV_MFC_BUS_RESET_CTRL);
+ val &= ~(0x1);
+ s5p_mfc_write_reg(val, S5P_FIMV_MFC_BUS_RESET_CTRL);
+ }
+ spin_unlock_irqrestore(&pm->clklock, flags);
+
+ state = atomic_read(&clk_ref);
+ mfc_debug(3, "+ %d", state);
+
+ return 0;
+}
+
+void s5p_mfc_clock_off(void)
+{
+ int state, val;
+ unsigned long timeout, flags;
+ struct s5p_mfc_dev *dev = platform_get_drvdata(to_platform_device(pm->device));
+
+ spin_lock_irqsave(&pm->clklock, flags);
+ if ((atomic_dec_return(&clk_ref) == 0) && (dev->fw.date >= 0x120206)) {
+ s5p_mfc_write_reg(0x1, S5P_FIMV_MFC_BUS_RESET_CTRL);
+
+ timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT);
+ /* Check bus status */
+ do {
+ if (time_after(jiffies, timeout)) {
+ mfc_err("Timeout while resetting MFC.\n");
+ break;
+ }
+ val = s5p_mfc_read_reg(S5P_FIMV_MFC_BUS_RESET_CTRL);
+ } while ((val & 0x2) == 0);
+ }
+ spin_unlock_irqrestore(&pm->clklock, flags);
+
+ state = atomic_read(&clk_ref);
+ if (state < 0)
+ mfc_err("Clock state is wrong(%d)\n", state);
+
+ if (!dev->curr_ctx_drm)
+ s5p_mfc_mem_suspend(dev->alloc_ctx[0]);
+ clk_disable(pm->clock);
+}
+
+int s5p_mfc_power_on(void)
+{
+ atomic_set(&pm->power, 1);
+
+ return pm_runtime_get_sync(pm->device);
+}
+
+int s5p_mfc_power_off(void)
+{
+ atomic_set(&pm->power, 0);
+
+ return pm_runtime_put_sync(pm->device);
+}
diff --git a/drivers/media/video/exynos/mfc/s5p_mfc_pm.h b/drivers/media/video/exynos/mfc/s5p_mfc_pm.h
new file mode 100644
index 0000000..b0cf094
--- /dev/null
+++ b/drivers/media/video/exynos/mfc/s5p_mfc_pm.h
@@ -0,0 +1,24 @@
+/*
+ * linux/drivers/media/video/exynos/mfc/s5p_mfc_pm.h
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * 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.
+ */
+
+#ifndef __S5P_MFC_PM_H
+#define __S5P_MFC_PM_H __FILE__
+
+int s5p_mfc_init_pm(struct s5p_mfc_dev *dev);
+void s5p_mfc_final_pm(struct s5p_mfc_dev *dev);
+
+int s5p_mfc_clock_on(void);
+void s5p_mfc_clock_off(void);
+int s5p_mfc_power_on(void);
+int s5p_mfc_power_off(void);
+
+#endif /* __S5P_MFC_PM_H */
diff --git a/drivers/media/video/exynos/mfc/s5p_mfc_reg.c b/drivers/media/video/exynos/mfc/s5p_mfc_reg.c
new file mode 100644
index 0000000..5ed3cb30
--- /dev/null
+++ b/drivers/media/video/exynos/mfc/s5p_mfc_reg.c
@@ -0,0 +1,30 @@
+/*
+ * linux/drivers/media/video/exynos/mfc/s5p_mfc_reg.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * 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.
+ */
+
+ #include <linux/io.h>
+
+static void __iomem *regs;
+
+void s5p_mfc_init_reg(void __iomem *base)
+{
+ regs = base;
+}
+
+void s5p_mfc_write_reg(unsigned int data, unsigned int offset)
+{
+ writel(data, regs + offset);
+}
+
+unsigned int s5p_mfc_read_reg(unsigned int offset)
+{
+ return readl(regs + offset);
+}
diff --git a/drivers/media/video/exynos/mfc/s5p_mfc_reg.h b/drivers/media/video/exynos/mfc/s5p_mfc_reg.h
new file mode 100644
index 0000000..acede15
--- /dev/null
+++ b/drivers/media/video/exynos/mfc/s5p_mfc_reg.h
@@ -0,0 +1,122 @@
+/*
+ * linux/drivers/media/video/exynos/mfc/s5p_mfc_reg.h
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * 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.
+ */
+
+#ifndef __S5P_MFC_REG_H_
+#define __S5P_MFC_REG_H_ __FILE__
+
+#define MFC_SYS_SW_RESET_ADDR S5P_FIMV_SW_RESET
+#define MFC_SYS_SW_RESET_MASK 0x3FF
+#define MFC_SYS_SW_RESET_SHFT 0x0
+#define MFC_SYS_R2H_INT_ADDR S5P_FIMV_RISC_HOST_INT
+#define MFC_SYS_R2H_INT_MASK 0x1
+#define MFC_SYS_R2H_INT_SHFT 0x0
+#define MFC_SYS_H2R_CMD_ADDR S5P_FIMV_HOST2RISC_CMD
+#define MFC_SYS_H2R_ARG1_ADDR S5P_FIMV_HOST2RISC_ARG1
+#define MFC_SYS_CODEC_TYPE_ADDR S5P_FIMV_HOST2RISC_ARG1
+#define MFC_SYS_INST_ID_ADDR S5P_FIMV_HOST2RISC_ARG1
+#define MFC_SYS_FW_MEM_SIZE_ADDR S5P_FIMV_HOST2RISC_ARG1
+#define MFC_SYS_H2R_ARG2_ADDR S5P_FIMV_HOST2RISC_ARG2
+#define MFC_SYS_CRC_GEN_EN_ADDR S5P_FIMV_HOST2RISC_ARG2
+#define MFC_SYS_CRC_GEN_EN_MASK 0x1
+#define MFC_SYS_CRC_GEN_EN_SHFT 0x1F
+#define MFC_SYS_ENC_PIXEL_CACHE_ADDR S5P_FIMV_HOST2RISC_ARG2
+#define MFC_SYS_ENC_PIXEL_CACHE_MASK 0x2
+#define MFC_SYS_ENC_PIXEL_CACHE_SHFT 0x0
+#define MFC_SYS_DEC_PIXEL_CACHE_ADDR S5P_FIMV_HOST2RISC_ARG2
+#define MFC_SYS_DEC_PIXEL_CACHE_MASK 0x2
+#define MFC_SYS_DEC_PIXEL_CACHE_SHFT 0x0
+#define MFC_SYS_H2R_ARG3_ADDR S5P_FIMV_HOST2RISC_ARG3
+
+#define MFC_SYS_H2R_ARG4_ADDR S5P_FIMV_HOST2RISC_ARG4
+
+#define MFC_SYS_FW_FIMV_INFO_ADDR S5P_FIMV_FW_VERSION
+#define MFC_SYS_FW_FIMV_INFO_MASK 0xFF
+#define MFC_SYS_FW_FIMV_INFO_SHFT 24
+#define MFC_SYS_FW_VER_YEAR_ADDR S5P_FIMV_FW_VERSION
+#define MFC_SYS_FW_VER_YEAR_MASK 0xFF
+#define MFC_SYS_FW_VER_YEAR_SHFT 16
+#define MFC_SYS_FW_VER_MONTH_ADDR S5P_FIMV_FW_VERSION
+#define MFC_SYS_FW_VER_MONTH_MASK 0xFF
+#define MFC_SYS_FW_VER_MONTH_SHFT 8
+#define MFC_SYS_FW_VER_DATE_ADDR S5P_FIMV_FW_VERSION
+#define MFC_SYS_FW_VER_DATE_MASK 0xFF
+#define MFC_SYS_FW_VER_DATE_SHFT 0
+#define MFC_SYS_FW_VER_ALL_ADDR S5P_FIMV_FW_VERSION
+#define MFC_SYS_FW_VER_ALL_MASK 0xFFFFFF
+#define MFC_SYS_FW_VER_ALL_SHFT 0
+
+#define MFC_DEC_DISPLAY_Y_ADR_ADDR S5P_FIMV_SI_DISPLAY_Y_ADR
+#define MFC_DEC_DISPLAY_Y_ADR_MASK 0xFFFFFFFF
+#define MFC_DEC_DISPLAY_Y_ADR_SHFT S5P_FIMV_MEM_OFFSET
+#define MFC_DEC_DISPLAY_C_ADR_ADDR S5P_FIMV_SI_DISPLAY_C_ADR
+#define MFC_DEC_DISPLAY_C_ADR_MASK 0xFFFFFFFF
+#define MFC_DEC_DISPLAY_C_ADR_SHFT S5P_FIMV_MEM_OFFSET
+
+#define MFC_DEC_DISPLAY_STATUS_ADDR MFC_SI_DISPLAY_STATUS
+#define MFC_DEC_DISPLAY_STATUS_MASK 0x7
+#define MFC_DEC_DISPLAY_STATUS_SHFT 0x0
+#define MFC_DEC_DISPLAY_INTERACE_ADDR MFC_SI_DISPLAY_STATUS
+#define MFC_DEC_DISPLAY_INTERACE_MASK 0x1
+#define MFC_DEC_DISPLAY_INTERACE_SHFT 0x3
+#define MFC_DEC_DISPLAY_RES_CHG_ADDR MFC_SI_DISPLAY_STATUS
+#define MFC_DEC_DISPLAY_RES_CHG_MASK 0x3
+#define MFC_DEC_DISPLAY_RES_CHG_SHFT 0x4
+
+#define MFC_DEC_DECODE_FRAME_TYPE_ADDR S5P_FIMV_DECODE_FRAME_TYPE
+#define MFC_DEC_DECODE_FRAME_TYPE_MASK 0x7
+#define MFC_DEC_DECODE_FRAME_TYPE_SHFT 0
+
+#define MFC_DEC_DECODE_STATUS_ADDR MFC_SI_DECODE_STATUS
+#define MFC_DEC_DECODE_STATUS_MASK 0x7
+#define MFC_DEC_DECODE_STATUS_SHFT 0x0
+#define MFC_DEC_DECODE_INTERACE_ADDR MFC_SI_DECODE_STATUS
+#define MFC_DEC_DECODE_INTERACE_MASK 0x1
+#define MFC_DEC_DECODE_INTERACE_SHFT 0x3
+#define MFC_DEC_DECODE_NUM_CRC_ADDR MFC_SI_DECODE_STATUS
+#define MFC_DEC_DECODE_NUM_CRC_MASK 0x1
+#define MFC_DEC_DECODE_NUM_CRC_SHFT 0x4
+#define MFC_DEC_DECODE_GEN_CRC_ADDR MFC_SI_DECODE_STATUS
+#define MFC_DEC_DECODE_GEN_CRC_MASK 0x1
+#define MFC_DEC_DECODE_GEN_CRC_SHFT 0x5
+
+#define MFC_SYS_MFC_VER_ADDR S5P_FIMV_MFC_VERSION
+#define MFC_SYS_MFC_VER_MASK 0xFFFFFFFF
+#define MFC_SYS_MFC_VER_SHFT 0x0
+
+#define MFC_ENC_LEVEL_ADDR MFC_ENC_PROFILE
+#define MFC_ENC_LEVEL_MASK 0xFF
+#define MFC_ENC_LEVEL_SHFT 0x8
+#define MFC_ENC_PROFILE_ADDR MFC_ENC_PROFILE
+#define MFC_ENC_PROFILE_MASK 0x3
+#define MFC_ENC_PROFILE_SHFT 0x0
+
+#define _MFC_SET_REG(target, val) s5p_mfc_write_reg(val, MFC_##target##_ADDR)
+#define MFC_SET_REG(target, val, shadow) \
+ do { \
+ shadow = s5p_mfc_read_reg(MFC_##target##_ADDR); \
+ shadow &= ~(MFC_##target##_MASK << MFC_##target##_SHFT); \
+ shadow |= ((val & MFC_##target##_MASK) << MFC_##target##_SHFT); \
+ s5p_mfc_write_reg(shadow, MFC_##target##_ADDR); \
+ } while (0)
+
+#define _MFC_GET_REG(target) s5p_mfc_read_reg(MFC_##target##_ADDR)
+#define MFC_GET_REG(target) \
+ ((s5p_mfc_read_reg(MFC_##target##_ADDR) >> MFC_##target##_SHFT) \
+ & MFC_##target##_MASK)
+
+#define MFC_GET_ADR(target) \
+ (s5p_mfc_read_reg(MFC_##target##_ADR_ADDR) << MFC_##target##_ADR_SHFT)
+
+void s5p_mfc_init_reg(void __iomem *base);
+void s5p_mfc_write_reg(unsigned int data, unsigned int offset);
+unsigned int s5p_mfc_read_reg(unsigned int offset);
+#endif /* __S5P_MFC_REG_H_ */
diff --git a/drivers/media/video/exynos/mfc/s5p_mfc_shm.c b/drivers/media/video/exynos/mfc/s5p_mfc_shm.c
new file mode 100644
index 0000000..e05381d
--- /dev/null
+++ b/drivers/media/video/exynos/mfc/s5p_mfc_shm.c
@@ -0,0 +1,52 @@
+/*
+ * linux/drivers/media/video/exynos/mfc/s5p_mfc_shm.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * 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.
+ */
+
+#include <linux/io.h>
+
+#include "s5p_mfc_common.h"
+
+#include "s5p_mfc_mem.h"
+#include "s5p_mfc_debug.h"
+
+int s5p_mfc_init_shm(struct s5p_mfc_ctx *ctx)
+{
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_buf_size_v5 *buf_size = dev->variant->buf_size->buf;
+ void *shm_alloc_ctx = dev->alloc_ctx[MFC_CMA_BANK1_ALLOC_CTX];
+
+ ctx->shm.alloc = s5p_mfc_mem_alloc(shm_alloc_ctx, buf_size->shared_buf);
+ if (IS_ERR(ctx->shm.alloc)) {
+ mfc_err("failed to allocate shared memory\n");
+ return PTR_ERR(ctx->shm.alloc);
+ }
+
+ /* shm_ofs only keeps the offset from base (port a) */
+ ctx->shm.ofs = s5p_mfc_mem_daddr(ctx->shm.alloc) - dev->port_a;
+ ctx->shm.virt = s5p_mfc_mem_vaddr(ctx->shm.alloc);
+ if (!ctx->shm.virt) {
+ s5p_mfc_mem_free(ctx->shm.alloc);
+ ctx->shm.ofs = 0;
+ ctx->shm.alloc = NULL;
+
+ mfc_err("failed to virt addr of shared memory\n");
+ return -ENOMEM;
+ }
+
+ memset((void *)ctx->shm.virt, 0, buf_size->shared_buf);
+ s5p_mfc_cache_clean_priv(ctx->shm.alloc);
+
+ mfc_debug(2, "shm info addr: 0x%08x, phys: 0x%08lx\n",
+ (unsigned int)ctx->shm.virt, ctx->shm.ofs);
+
+ return 0;
+}
+
diff --git a/drivers/media/video/exynos/mfc/s5p_mfc_shm.h b/drivers/media/video/exynos/mfc/s5p_mfc_shm.h
new file mode 100644
index 0000000..3e28eaa
--- /dev/null
+++ b/drivers/media/video/exynos/mfc/s5p_mfc_shm.h
@@ -0,0 +1,95 @@
+/*
+ * linux/drivers/media/video/exynos/mfc/s5p_mfc_shm.h
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * 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.
+ */
+
+#ifndef __S5P_MFC_SHM_H_
+#define __S5P_MFC_SHM_H_ __FILE__
+
+#include <linux/io.h>
+
+enum MFC_SHM_OFS {
+ EXTENEDED_DECODE_STATUS = 0x00, /* D */
+ SET_FRAME_TAG = 0x04, /* D */
+ GET_FRAME_TAG_TOP = 0x08, /* D */
+ GET_FRAME_TAG_BOT = 0x0C, /* D */
+ PIC_TIME_TOP = 0x10, /* D */
+ PIC_TIME_BOT = 0x14, /* D */
+ START_BYTE_NUM = 0x18, /* D */
+
+ CROP_INFO_H = 0x20, /* D */
+ CROP_INFO_V = 0x24, /* D */
+ EXT_ENC_CONTROL = 0x28, /* E */
+ ENC_PARAM_CHANGE = 0x2C, /* E */
+ RC_VOP_TIMING = 0x30, /* E, MPEG4 */
+ HEC_PERIOD = 0x34, /* E, MPEG4 */
+ METADATA_ENABLE = 0x38, /* C */
+ METADATA_STATUS = 0x3C, /* C */
+ METADATA_DISPLAY_INDEX = 0x40, /* C */
+ EXT_METADATA_START_ADDR = 0x44, /* C */
+ PUT_EXTRADATA = 0x48, /* C */
+ EXTRADATA_ADDR = 0x4C, /* C */
+
+ ALLOC_LUMA_DPB_SIZE = 0x64, /* D */
+ ALLOC_CHROMA_DPB_SIZE = 0x68, /* D */
+ ALLOC_MV_SIZE = 0x6C, /* D */
+ P_B_FRAME_QP = 0x70, /* E */
+ ASPECT_RATIO_IDC = 0x74, /* E, H.264, depend on ASPECT_RATIO_VUI_ENABLE in EXT_ENC_CONTROL */
+ EXTENDED_SAR = 0x78, /* E, H.264, depned on ASPECT_RATIO_VUI_ENABLE in EXT_ENC_CONTROL */
+ DISP_PIC_PROFILE = 0x7C, /* D */
+ FLUSH_CMD_TYPE = 0x80, /* C */
+ FLUSH_CMD_INBUF1 = 0x84, /* C */
+ FLUSH_CMD_INBUF2 = 0x88, /* C */
+ FLUSH_CMD_OUTBUF = 0x8C, /* E */
+ NEW_RC_BIT_RATE = 0x90, /* E, format as RC_BIT_RATE(0xC5A8) depend on RC_BIT_RATE_CHANGE in ENC_PARAM_CHANGE */
+ NEW_RC_FRAME_RATE = 0x94, /* E, format as RC_FRAME_RATE(0xD0D0) depend on RC_FRAME_RATE_CHANGE in ENC_PARAM_CHANGE */
+ NEW_I_PERIOD = 0x98, /* E, format as I_FRM_CTRL(0xC504) depend on I_PERIOD_CHANGE in ENC_PARAM_CHANGE */
+ H264_I_PERIOD = 0x9C, /* E, H.264, open GOP */
+ RC_CONTROL_CONFIG = 0xA0, /* E */
+ BATCH_INPUT_ADDR = 0xA4, /* E */
+ BATCH_OUTPUT_ADDR = 0xA8, /* E */
+ BATCH_OUTPUT_SIZE = 0xAC, /* E */
+ MIN_LUMA_DPB_SIZE = 0xB0, /* D */
+ DEVICE_FORMAT_ID = 0xB4, /* C */
+ H264_POC_TYPE = 0xB8, /* D */
+ MIN_CHROMA_DPB_SIZE = 0xBC, /* D */
+ DISP_PIC_FRAME_TYPE = 0xC0, /* D */
+ FREE_LUMA_DPB = 0xC4, /* D, VC1 MPEG4 */
+ ASPECT_RATIO_INFO = 0xC8, /* D, MPEG4 */
+ EXTENDED_PAR = 0xCC, /* D, MPEG4 */
+ DBG_HISTORY_INPUT0 = 0xD0, /* C */
+ DBG_HISTORY_INPUT1 = 0xD4, /* C */
+ DBG_HISTORY_OUTPUT = 0xD8, /* C */
+ HIERARCHICAL_P_QP = 0xE0, /* E, H.264 */
+ FRAME_PACK_SEI_ENABLE = 0x168, /* C */
+ FRAME_PACK_SEI_AVAIL = 0x16c, /* D */
+ FRAME_PACK_SEI_INFO = 0x17c, /* E */
+};
+
+#define S5P_FIMV_DISPLAY_FRAME_NOT_CODED 0
+#define S5P_FIMV_DISPLAY_FRAME_I 1
+#define S5P_FIMV_DISPLAY_FRAME_P 2
+#define S5P_FIMV_DISPLAY_FRAME_B 3
+
+int s5p_mfc_init_shm(struct s5p_mfc_ctx *ctx);
+
+static inline void s5p_mfc_write_shm(struct s5p_mfc_ctx *ctx, unsigned int data, unsigned int ofs)
+{
+ writel(data, (ctx->shm.virt + ofs));
+ s5p_mfc_cache_clean_priv(ctx->shm.alloc);
+}
+
+static inline u32 s5p_mfc_read_shm(struct s5p_mfc_ctx *ctx, unsigned int ofs)
+{
+ s5p_mfc_cache_inv_priv(ctx->shm.alloc);
+ return readl(ctx->shm.virt + ofs);
+}
+
+#endif /* __S5P_MFC_SHM_H_ */
diff --git a/drivers/media/video/exynos/mipi-csis/Kconfig b/drivers/media/video/exynos/mipi-csis/Kconfig
new file mode 100644
index 0000000..9dd0e74
--- /dev/null
+++ b/drivers/media/video/exynos/mipi-csis/Kconfig
@@ -0,0 +1,8 @@
+config VIDEO_EXYNOS_MIPI_CSIS
+ bool "Exynos MIPI-CSIS driver"
+ depends on VIDEO_EXYNOS && VIDEO_EXYNOS_FIMC_LITE &&\
+ (ARCH_EXYNOS4 || ARCH_EXYNOS5)
+ select MEDIA_EXYNOS
+ default n
+ help
+ This is a v4l2 driver for exynos mipi-csis interface device.
diff --git a/drivers/media/video/exynos/mipi-csis/Makefile b/drivers/media/video/exynos/mipi-csis/Makefile
new file mode 100644
index 0000000..1e64df7
--- /dev/null
+++ b/drivers/media/video/exynos/mipi-csis/Makefile
@@ -0,0 +1,2 @@
+exynos-mipi-csis-objs := mipi-csis.o
+obj-$(CONFIG_VIDEO_EXYNOS_MIPI_CSIS) += mipi-csis.o
diff --git a/drivers/media/video/exynos/mipi-csis/mipi-csis.c b/drivers/media/video/exynos/mipi-csis/mipi-csis.c
new file mode 100644
index 0000000..2842c09
--- /dev/null
+++ b/drivers/media/video/exynos/mipi-csis/mipi-csis.c
@@ -0,0 +1,890 @@
+/*
+ * Samsung S5P/EXYNOS4 SoC series MIPI-CSI receiver driver
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ * Contact: Sylwester Nawrocki, <s.nawrocki@samsung.com>
+ *
+ * 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.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/memory.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/videodev2.h>
+#include <linux/videodev2_exynos_media.h>
+#include <media/v4l2-subdev.h>
+#include <media/exynos_mc.h>
+#include <plat/mipi_csis.h>
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+#define MODULE_NAME "s5p-mipi-csis"
+#define DEFAULT_CSIS_SINK_WIDTH 800
+#define DEFAULT_CSIS_SINK_HEIGHT 480
+#define CLK_NAME_SIZE 20
+
+enum csis_input_entity {
+ CSIS_INPUT_NONE,
+ CSIS_INPUT_SENSOR,
+};
+
+enum csis_output_entity {
+ CSIS_OUTPUT_NONE,
+ CSIS_OUTPUT_FLITE,
+};
+
+#define CSIS0_MAX_LANES 4
+#define CSIS1_MAX_LANES 2
+/* Register map definition */
+
+/* CSIS global control */
+#define S5PCSIS_CTRL 0x00
+#define S5PCSIS_CTRL_DPDN_DEFAULT (0 << 31)
+#define S5PCSIS_CTRL_DPDN_SWAP (1 << 31)
+#define S5PCSIS_CTRL_ALIGN_32BIT (1 << 20)
+#define S5PCSIS_CTRL_UPDATE_SHADOW (1 << 16)
+#define S5PCSIS_CTRL_WCLK_EXTCLK (1 << 8)
+#define S5PCSIS_CTRL_RESET (1 << 4)
+#define S5PCSIS_CTRL_ENABLE (1 << 0)
+
+/* D-PHY control */
+#define S5PCSIS_DPHYCTRL 0x04
+#define S5PCSIS_DPHYCTRL_HSS_MASK (0x1f << 27)
+#define S5PCSIS_DPHYCTRL_ENABLE (0x1f << 0)
+
+#define S5PCSIS_CONFIG 0x08
+#define S5PCSIS_CFG_FMT_YCBCR422_8BIT (0x1e << 2)
+#define S5PCSIS_CFG_FMT_RAW8 (0x2a << 2)
+#define S5PCSIS_CFG_FMT_RAW10 (0x2b << 2)
+#define S5PCSIS_CFG_FMT_RAW12 (0x2c << 2)
+/* User defined formats, x = 1...4 */
+#define S5PCSIS_CFG_FMT_USER(x) ((0x30 + x - 1) << 2)
+#define S5PCSIS_CFG_FMT_MASK (0x3f << 2)
+#define S5PCSIS_CFG_NR_LANE_MASK 3
+
+/* Interrupt mask. */
+#define S5PCSIS_INTMSK 0x10
+#define S5PCSIS_INTMSK_EN_ALL 0xf000103f
+#define S5PCSIS_INTSRC 0x14
+
+/* Pixel resolution */
+#define S5PCSIS_RESOL 0x2c
+#define CSIS_MAX_PIX_WIDTH 0xffff
+#define CSIS_MAX_PIX_HEIGHT 0xffff
+#define CSIS_SRC_CLK "mout_mpll_user"
+
+enum {
+ CSIS_CLK_MUX,
+ CSIS_CLK_GATE,
+};
+
+static char *csi_clock_name[] = {
+ [CSIS_CLK_MUX] = "sclk_gscl_wrap",
+ [CSIS_CLK_GATE] = "gscl_wrap",
+};
+#define NUM_CSIS_CLOCKS ARRAY_SIZE(csi_clock_name)
+
+enum {
+ ST_POWERED = 1,
+ ST_STREAMING = 2,
+ ST_SUSPENDED = 4,
+};
+
+/**
+ * struct csis_state - the driver's internal state data structure
+ * @lock: mutex serializing the subdev and power management operations,
+ * protecting @format and @flags members
+ * @pads: CSIS pads array
+ * @sd: v4l2_subdev associated with CSIS device instance
+ * @pdev: CSIS platform device
+ * @regs_res: requested I/O register memory resource
+ * @regs: mmaped I/O registers memory
+ * @clock: CSIS clocks
+ * @irq: requested s5p-mipi-csis irq number
+ * @flags: the state variable for power and streaming control
+ * @csis_fmt: current CSIS pixel format
+ * @format: common media bus format for the source and sink pad
+ */
+struct csis_state {
+ struct mutex lock;
+ struct media_pad pads[CSIS_PADS_NUM];
+ struct exynos_md *mdev;
+ struct v4l2_subdev sd;
+ struct platform_device *pdev;
+ struct resource *regs_res;
+ void __iomem *regs;
+ struct clk *clock[NUM_CSIS_CLOCKS];
+ int irq;
+ struct regulator *supply;
+ u32 flags;
+ const struct csis_pix_format *csis_fmt;
+ struct v4l2_mbus_framefmt format;
+ enum csis_input_entity input;
+ enum csis_output_entity output;
+};
+
+/**
+ * struct csis_pix_format - CSIS pixel format description
+ * @pix_width_alignment: horizontal pixel alignment, width will be
+ * multiple of 2^pix_width_alignment
+ * @code: corresponding media bus code
+ * @fmt_reg: S5PCSIS_CONFIG register value
+ */
+struct csis_pix_format {
+ unsigned int pix_width_alignment;
+ enum v4l2_mbus_pixelcode code;
+ u32 fmt_reg;
+};
+
+static const struct csis_pix_format s5pcsis_formats[] = {
+ {
+ .code = V4L2_MBUS_FMT_YUYV8_2X8,
+ .fmt_reg = S5PCSIS_CFG_FMT_YCBCR422_8BIT,
+ }, {
+ .code = V4L2_MBUS_FMT_JPEG_1X8,
+ .fmt_reg = S5PCSIS_CFG_FMT_USER(1),
+ },
+};
+
+#define s5pcsis_write(__csis, __r, __v) writel(__v, __csis->regs + __r)
+#define s5pcsis_read(__csis, __r) readl(__csis->regs + __r)
+
+static struct csis_state *sd_to_csis_state(struct v4l2_subdev *sdev)
+{
+ return container_of(sdev, struct csis_state, sd);
+}
+
+static const struct csis_pix_format *find_csis_format(
+ struct v4l2_mbus_framefmt *mf)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(s5pcsis_formats); i++)
+ if (mf->code == s5pcsis_formats[i].code)
+ return &s5pcsis_formats[i];
+ return NULL;
+}
+
+static void s5pcsis_enable_interrupts(struct csis_state *state, bool on)
+{
+ u32 val = s5pcsis_read(state, S5PCSIS_INTMSK);
+
+ val = on ? val | S5PCSIS_INTMSK_EN_ALL :
+ val & ~S5PCSIS_INTMSK_EN_ALL;
+ s5pcsis_write(state, S5PCSIS_INTMSK, val);
+}
+
+static void s5pcsis_reset(struct csis_state *state)
+{
+ u32 val = s5pcsis_read(state, S5PCSIS_CTRL);
+
+ s5pcsis_write(state, S5PCSIS_CTRL, val | S5PCSIS_CTRL_RESET);
+ udelay(10);
+}
+
+static void s5pcsis_system_enable(struct csis_state *state, int on)
+{
+ u32 val;
+
+ val = s5pcsis_read(state, S5PCSIS_CTRL);
+ if (on)
+ val |= S5PCSIS_CTRL_ENABLE;
+ else
+ val &= ~S5PCSIS_CTRL_ENABLE;
+ s5pcsis_write(state, S5PCSIS_CTRL, val);
+
+ val = s5pcsis_read(state, S5PCSIS_DPHYCTRL);
+ if (on)
+ val |= S5PCSIS_DPHYCTRL_ENABLE;
+ else
+ val &= ~S5PCSIS_DPHYCTRL_ENABLE;
+ s5pcsis_write(state, S5PCSIS_DPHYCTRL, val);
+}
+
+/* Called with the state.lock mutex held */
+static void __s5pcsis_set_format(struct csis_state *state)
+{
+ struct v4l2_mbus_framefmt *mf = &state->format;
+ u32 val;
+
+ v4l2_dbg(1, debug, &state->sd, "fmt: %d, %d x %d\n",
+ mf->code, mf->width, mf->height);
+
+ /* Color format */
+ val = s5pcsis_read(state, S5PCSIS_CONFIG);
+ val = (val & ~S5PCSIS_CFG_FMT_MASK) | state->csis_fmt->fmt_reg;
+ s5pcsis_write(state, S5PCSIS_CONFIG, val);
+
+ /* Pixel resolution */
+ val = (mf->width << 16) | mf->height;
+ s5pcsis_write(state, S5PCSIS_RESOL, val);
+}
+
+static void s5pcsis_set_hsync_settle(struct csis_state *state, int settle)
+{
+ u32 val = s5pcsis_read(state, S5PCSIS_DPHYCTRL);
+
+ val = (val & ~S5PCSIS_DPHYCTRL_HSS_MASK) | (settle << 27);
+ s5pcsis_write(state, S5PCSIS_DPHYCTRL, val);
+}
+
+static void s5pcsis_set_params(struct csis_state *state)
+{
+ struct s5p_platform_mipi_csis *pdata = state->pdev->dev.platform_data;
+ u32 val;
+
+ val = s5pcsis_read(state, S5PCSIS_CONFIG);
+ val = (val & ~S5PCSIS_CFG_NR_LANE_MASK) | (pdata->lanes - 1);
+ s5pcsis_write(state, S5PCSIS_CONFIG, val);
+
+ __s5pcsis_set_format(state);
+ s5pcsis_set_hsync_settle(state, pdata->hs_settle);
+
+ val = s5pcsis_read(state, S5PCSIS_CTRL);
+ if (pdata->alignment == 32)
+ val |= S5PCSIS_CTRL_ALIGN_32BIT;
+ else /* 24-bits */
+ val &= ~S5PCSIS_CTRL_ALIGN_32BIT;
+ /* using external clock. */
+ val |= S5PCSIS_CTRL_WCLK_EXTCLK;
+ s5pcsis_write(state, S5PCSIS_CTRL, val);
+
+ /* Update the shadow register. */
+ val = s5pcsis_read(state, S5PCSIS_CTRL);
+ s5pcsis_write(state, S5PCSIS_CTRL, val | S5PCSIS_CTRL_UPDATE_SHADOW);
+}
+
+static void s5pcsis_clk_put(struct csis_state *state)
+{
+ int i;
+
+ for (i = 0; i < NUM_CSIS_CLOCKS; i++)
+ if (!IS_ERR_OR_NULL(state->clock[i]))
+ clk_put(state->clock[i]);
+}
+
+static int s5pcsis_clk_get(struct csis_state *state)
+{
+ struct device *dev = &state->pdev->dev;
+ int i;
+ char clk_name[CLK_NAME_SIZE];
+
+ for (i = 0; i < NUM_CSIS_CLOCKS; i++) {
+ snprintf(clk_name, sizeof(clk_name), "%s%d",
+ csi_clock_name[i], state->pdev->id);
+ state->clock[i] = clk_get(dev, clk_name);
+ if (IS_ERR(state->clock[i])) {
+ s5pcsis_clk_put(state);
+ dev_err(dev, "failed to get clock: %s\n",
+ csi_clock_name[i]);
+ return -ENXIO;
+ }
+ }
+ return 0;
+}
+
+static int s5pcsis_resume(struct device *dev);
+static int s5pcsis_s_power(struct v4l2_subdev *sd, int on)
+{
+ struct csis_state *state = sd_to_csis_state(sd);
+ struct device *dev = &state->pdev->dev;
+
+ if (on) {
+#ifndef CONFIG_PM_RUNTIME
+ return s5pcsis_resume(dev);
+#else
+ return pm_runtime_get_sync(dev);
+#endif
+ }
+
+ return pm_runtime_put_sync(dev);
+}
+
+static void s5pcsis_start_stream(struct csis_state *state)
+{
+ s5pcsis_reset(state);
+ s5pcsis_set_params(state);
+ s5pcsis_system_enable(state, true);
+ s5pcsis_enable_interrupts(state, true);
+}
+
+static void s5pcsis_stop_stream(struct csis_state *state)
+{
+ s5pcsis_enable_interrupts(state, false);
+ s5pcsis_system_enable(state, false);
+}
+
+/* v4l2_subdev operations */
+static int s5pcsis_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct csis_state *state = sd_to_csis_state(sd);
+ int ret = 0;
+
+ v4l2_dbg(1, debug, sd, "%s: %d, state: 0x%x\n",
+ __func__, enable, state->flags);
+
+ if (enable) {
+ ret = pm_runtime_get_sync(&state->pdev->dev);
+ if (ret && ret != 1)
+ return ret;
+ }
+ mutex_lock(&state->lock);
+ if (enable) {
+ if (state->flags & ST_SUSPENDED) {
+ ret = -EBUSY;
+ goto unlock;
+ }
+ s5pcsis_start_stream(state);
+ state->flags |= ST_STREAMING;
+ } else {
+ s5pcsis_stop_stream(state);
+ state->flags &= ~ST_STREAMING;
+ }
+unlock:
+ mutex_unlock(&state->lock);
+ if (!enable)
+ pm_runtime_put(&state->pdev->dev);
+
+ return ret == 1 ? 0 : ret;
+}
+
+static int s5pcsis_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ if (code->index >= ARRAY_SIZE(s5pcsis_formats))
+ return -EINVAL;
+
+ code->code = s5pcsis_formats[code->index].code;
+ return 0;
+}
+
+static struct csis_pix_format const *s5pcsis_try_format(
+ struct v4l2_mbus_framefmt *mf)
+{
+ struct csis_pix_format const *csis_fmt;
+
+ csis_fmt = find_csis_format(mf);
+ if (csis_fmt == NULL)
+ csis_fmt = &s5pcsis_formats[0];
+
+ mf->code = csis_fmt->code;
+ v4l_bound_align_image(&mf->width, 1, CSIS_MAX_PIX_WIDTH,
+ csis_fmt->pix_width_alignment,
+ &mf->height, 1, CSIS_MAX_PIX_HEIGHT, 1,
+ 0);
+ return csis_fmt;
+}
+
+static struct v4l2_mbus_framefmt *__s5pcsis_get_format(
+ struct csis_state *state, struct v4l2_subdev_fh *fh,
+ u32 pad, enum v4l2_subdev_format_whence which)
+{
+ if (which == V4L2_SUBDEV_FORMAT_TRY)
+ return fh ? v4l2_subdev_get_try_format(fh, pad) : NULL;
+
+ return &state->format;
+}
+
+static int s5pcsis_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ struct csis_state *state = sd_to_csis_state(sd);
+ struct csis_pix_format const *csis_fmt;
+ struct v4l2_mbus_framefmt *mf;
+
+ mf = __s5pcsis_get_format(state, fh, fmt->pad, fmt->which);
+
+ if (fmt->pad == CSIS_PAD_SOURCE) {
+ if (mf) {
+ mutex_lock(&state->lock);
+ fmt->format = *mf;
+ mutex_unlock(&state->lock);
+ }
+ return 0;
+ }
+ csis_fmt = s5pcsis_try_format(&fmt->format);
+ if (mf) {
+ mutex_lock(&state->lock);
+ *mf = fmt->format;
+ if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+ state->csis_fmt = csis_fmt;
+ mutex_unlock(&state->lock);
+ }
+ return 0;
+}
+
+static int s5pcsis_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ struct csis_state *state = sd_to_csis_state(sd);
+ struct v4l2_mbus_framefmt *mf;
+
+ if (fmt->pad != CSIS_PAD_SOURCE && fmt->pad != CSIS_PAD_SINK)
+ return -EINVAL;
+
+ mf = __s5pcsis_get_format(state, fh, fmt->pad, fmt->which);
+ if (!mf)
+ return -EINVAL;
+
+ mutex_lock(&state->lock);
+ fmt->format = *mf;
+ mutex_unlock(&state->lock);
+
+ return 0;
+}
+
+static struct v4l2_subdev_core_ops s5pcsis_core_ops = {
+ .s_power = s5pcsis_s_power,
+};
+
+static struct v4l2_subdev_pad_ops s5pcsis_pad_ops = {
+ .enum_mbus_code = s5pcsis_enum_mbus_code,
+ .get_fmt = s5pcsis_get_fmt,
+ .set_fmt = s5pcsis_set_fmt,
+};
+
+static struct v4l2_subdev_video_ops s5pcsis_video_ops = {
+ .s_stream = s5pcsis_s_stream,
+};
+
+static struct v4l2_subdev_ops s5pcsis_subdev_ops = {
+ .core = &s5pcsis_core_ops,
+ .pad = &s5pcsis_pad_ops,
+ .video = &s5pcsis_video_ops,
+};
+
+static int s5pcsis_init_formats(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh)
+{
+ struct v4l2_subdev_format format;
+
+ memset(&format, 0, sizeof(format));
+ format.pad = CSIS_PAD_SINK;
+ format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
+ format.format.code = s5pcsis_formats[0].code;
+ format.format.width = DEFAULT_CSIS_SINK_WIDTH;
+ format.format.height = DEFAULT_CSIS_SINK_HEIGHT;
+ s5pcsis_set_fmt(sd, fh, &format);
+
+ return 0;
+}
+
+static int s5pcsis_subdev_close(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh)
+{
+ v4l2_info(sd, "%s\n", __func__);
+ return 0;
+}
+
+static int s5pcsis_subdev_registered(struct v4l2_subdev *sd)
+{
+ v4l2_dbg(1, debug, sd, "%s\n", __func__);
+ return 0;
+}
+
+static void s5pcsis_subdev_unregistered(struct v4l2_subdev *sd)
+{
+ v4l2_dbg(1, debug, sd, "%s\n", __func__);
+}
+
+static const struct v4l2_subdev_internal_ops s5pcsis_v4l2_internal_ops = {
+ .open = s5pcsis_init_formats,
+ .close = s5pcsis_subdev_close,
+ .registered = s5pcsis_subdev_registered,
+ .unregistered = s5pcsis_subdev_unregistered,
+};
+
+static int s5pcsis_link_setup(struct media_entity *entity,
+ const struct media_pad *local,
+ const struct media_pad *remote, u32 flags)
+{
+ struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
+ struct csis_state *state = sd_to_csis_state(sd);
+
+ switch (local->index | media_entity_type(remote->entity)) {
+ case CSIS_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
+ if (flags & MEDIA_LNK_FL_ENABLED) {
+ v4l2_info(sd, "%s : sink link enabled\n", __func__);
+ state->input = CSIS_INPUT_SENSOR;
+ } else {
+ v4l2_info(sd, "%s : sink link disabled\n", __func__);
+ state->input = CSIS_INPUT_NONE;
+ }
+ break;
+
+ case CSIS_PAD_SOURCE | MEDIA_ENT_T_V4L2_SUBDEV:
+ if (flags & MEDIA_LNK_FL_ENABLED) {
+ v4l2_info(sd, "%s : source link enabled\n", __func__);
+ state->output = CSIS_OUTPUT_FLITE;
+ } else {
+ v4l2_info(sd, "%s : source link disabled\n", __func__);
+ state->output = CSIS_OUTPUT_NONE;
+ }
+ break;
+
+ default:
+ v4l2_err(sd, "%s : ERR link\n", __func__);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct media_entity_operations s5pcsis_media_ops = {
+ .link_setup = s5pcsis_link_setup,
+};
+
+static irqreturn_t s5pcsis_irq_handler(int irq, void *dev_id)
+{
+ struct csis_state *state = dev_id;
+ u32 val;
+
+ /* Just clear the interrupt pending bits. */
+ val = s5pcsis_read(state, S5PCSIS_INTSRC);
+ s5pcsis_write(state, S5PCSIS_INTSRC, val);
+
+ v4l2_info(&state->sd, "%s : error : 0x%x\n", __func__, val);
+
+ return IRQ_HANDLED;
+}
+
+static int csis_get_md_callback(struct device *dev, void *p)
+{
+ struct exynos_md **md_list = p;
+ struct exynos_md *md = NULL;
+
+ md = dev_get_drvdata(dev);
+
+ if (md)
+ *(md_list + md->id) = md;
+
+ return 0; /* non-zero value stops iteration */
+}
+
+static struct exynos_md *csis_get_capture_md(enum mdev_node node)
+{
+ struct device_driver *drv;
+ struct exynos_md *md[MDEV_MAX_NUM] = {NULL,};
+ int ret;
+
+ drv = driver_find(MDEV_MODULE_NAME, &platform_bus_type);
+ if (!drv)
+ return ERR_PTR(-ENODEV);
+
+ ret = driver_for_each_device(drv, NULL, &md[0],
+ csis_get_md_callback);
+
+ return ret ? NULL : md[node];
+
+}
+
+static int __devinit s5pcsis_probe(struct platform_device *pdev)
+{
+ struct s5p_platform_mipi_csis *pdata;
+ struct resource *mem_res;
+ struct resource *regs_res;
+ struct csis_state *state;
+ int ret = -ENOMEM;
+
+ state = kzalloc(sizeof(*state), GFP_KERNEL);
+ if (!state)
+ return -ENOMEM;
+
+ mutex_init(&state->lock);
+ state->pdev = pdev;
+
+ pdata = pdev->dev.platform_data;
+ if (pdata == NULL || pdata->phy_enable == NULL) {
+ dev_err(&pdev->dev, "Platform data not fully specified\n");
+ goto e_free;
+ }
+
+ if ((pdev->id == 1 && pdata->lanes > CSIS1_MAX_LANES) ||
+ pdata->lanes > CSIS0_MAX_LANES) {
+ ret = -EINVAL;
+ dev_err(&pdev->dev, "Unsupported number of data lanes: %d\n",
+ pdata->lanes);
+ goto e_free;
+ }
+
+ mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem_res) {
+ dev_err(&pdev->dev, "Failed to get IO memory region\n");
+ goto e_free;
+ }
+
+ regs_res = request_mem_region(mem_res->start, resource_size(mem_res),
+ pdev->name);
+ if (!regs_res) {
+ dev_err(&pdev->dev, "Failed to request IO memory region\n");
+ goto e_free;
+ }
+ state->regs_res = regs_res;
+
+ state->regs = ioremap(mem_res->start, resource_size(mem_res));
+ if (!state->regs) {
+ dev_err(&pdev->dev, "Failed to remap IO region\n");
+ goto e_reqmem;
+ }
+
+ ret = s5pcsis_clk_get(state);
+ if (ret)
+ goto e_unmap;
+
+ clk_enable(state->clock[CSIS_CLK_MUX]);
+ if (pdata->clk_rate) {
+ struct clk *srclk;
+ srclk = clk_get(&state->pdev->dev, CSIS_SRC_CLK);
+ if (IS_ERR_OR_NULL(srclk)) {
+ dev_err(&state->pdev->dev, "failed to get csis src clk\n");
+ goto e_unmap;
+ }
+ clk_set_parent(state->clock[CSIS_CLK_MUX], srclk);
+ clk_put(srclk);
+ clk_set_rate(state->clock[CSIS_CLK_MUX], pdata->clk_rate);
+ } else {
+ dev_WARN(&pdev->dev, "No clock frequency specified!\n");
+ }
+
+ state->irq = platform_get_irq(pdev, 0);
+ if (state->irq < 0) {
+ ret = state->irq;
+ dev_err(&pdev->dev, "Failed to get irq\n");
+ goto e_clkput;
+ }
+
+ if (!pdata->fixed_phy_vdd) {
+ state->supply = regulator_get(&pdev->dev, "mipi_csi");
+ if (IS_ERR(state->supply)) {
+ ret = PTR_ERR(state->supply);
+ state->supply = NULL;
+ goto e_clkput;
+ }
+ }
+
+ ret = request_irq(state->irq, s5pcsis_irq_handler, 0,
+ dev_name(&pdev->dev), state);
+ if (ret) {
+ dev_err(&pdev->dev, "request_irq failed\n");
+ goto e_regput;
+ }
+
+ v4l2_subdev_init(&state->sd, &s5pcsis_subdev_ops);
+ state->sd.owner = THIS_MODULE;
+ state->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
+ snprintf(state->sd.name, sizeof(state->sd.name), "%s.%d\n",
+ MODULE_NAME, pdev->id);
+
+ state->pads[CSIS_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+ state->pads[CSIS_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+ ret = media_entity_init(&state->sd.entity,
+ CSIS_PADS_NUM, state->pads, 0);
+ if (ret < 0)
+ goto e_irqfree;
+
+ s5pcsis_init_formats(&state->sd, NULL);
+
+ state->sd.internal_ops = &s5pcsis_v4l2_internal_ops;
+ state->sd.entity.ops = &s5pcsis_media_ops;
+
+ state->mdev = csis_get_capture_md(MDEV_CAPTURE);
+ if (IS_ERR_OR_NULL(state->mdev))
+ goto e_irqfree;
+
+ state->mdev->csis_sd[pdev->id] = &state->sd;
+ state->sd.grp_id = CSIS_GRP_ID;
+ ret = v4l2_device_register_subdev(&state->mdev->v4l2_dev, &state->sd);
+ if (ret)
+ goto e_irqfree;
+ /* This allows to retrieve the platform device id by the host driver */
+ v4l2_set_subdevdata(&state->sd, pdev);
+
+ /* .. and a pointer to the subdev. */
+ platform_set_drvdata(pdev, &state->sd);
+
+ state->flags = ST_SUSPENDED;
+ pm_runtime_enable(&pdev->dev);
+
+ v4l2_info(&state->sd, "%s : csis%d probe success\n", __func__, pdev->id);
+ return 0;
+
+e_irqfree:
+ free_irq(state->irq, state);
+e_regput:
+ if (state->supply)
+ regulator_put(state->supply);
+e_clkput:
+ clk_disable(state->clock[CSIS_CLK_MUX]);
+ s5pcsis_clk_put(state);
+e_unmap:
+ iounmap(state->regs);
+e_reqmem:
+ release_mem_region(regs_res->start, resource_size(regs_res));
+e_free:
+ kfree(state);
+ return ret;
+}
+
+static int s5pcsis_suspend(struct device *dev)
+{
+ struct s5p_platform_mipi_csis *pdata = dev->platform_data;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct v4l2_subdev *sd = platform_get_drvdata(pdev);
+ struct csis_state *state = sd_to_csis_state(sd);
+ int ret = 0;
+
+ v4l2_dbg(1, debug, sd, "%s: flags: 0x%x\n",
+ __func__, state->flags);
+
+ mutex_lock(&state->lock);
+ if (state->flags & ST_POWERED) {
+ s5pcsis_stop_stream(state);
+ ret = pdata->phy_enable(state->pdev, false);
+ if (ret)
+ goto unlock;
+ if (state->supply) {
+ ret = regulator_disable(state->supply);
+ if (ret)
+ goto unlock;
+ }
+ clk_disable(state->clock[CSIS_CLK_GATE]);
+ state->flags &= ~ST_POWERED;
+ }
+ state->flags |= ST_SUSPENDED;
+ unlock:
+ mutex_unlock(&state->lock);
+ return ret ? -EAGAIN : 0;
+}
+
+static int s5pcsis_resume(struct device *dev)
+{
+ struct s5p_platform_mipi_csis *pdata = dev->platform_data;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct v4l2_subdev *sd = platform_get_drvdata(pdev);
+ struct csis_state *state = sd_to_csis_state(sd);
+ int ret = 0;
+
+ v4l2_info(sd, "%s: flags: 0x%x\n", __func__, state->flags);
+
+ mutex_lock(&state->lock);
+ if (!(state->flags & ST_SUSPENDED))
+ goto unlock;
+
+ if (!(state->flags & ST_POWERED)) {
+ if (state->supply)
+ ret = regulator_enable(state->supply);
+ if (ret)
+ goto unlock;
+
+ ret = pdata->phy_enable(state->pdev, true);
+ if (!ret) {
+ state->flags |= ST_POWERED;
+ } else if (state->supply) {
+ regulator_disable(state->supply);
+ goto unlock;
+ }
+ clk_enable(state->clock[CSIS_CLK_GATE]);
+ }
+ if (state->flags & ST_STREAMING)
+ s5pcsis_start_stream(state);
+
+ state->flags &= ~ST_SUSPENDED;
+ unlock:
+ mutex_unlock(&state->lock);
+ return ret ? -EAGAIN : 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int s5pcsis_pm_suspend(struct device *dev)
+{
+ return s5pcsis_suspend(dev);
+}
+
+static int s5pcsis_pm_resume(struct device *dev)
+{
+ int ret;
+
+ ret = s5pcsis_resume(dev);
+
+ if (!ret) {
+ pm_runtime_disable(dev);
+ ret = pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+ }
+
+ return ret;
+}
+#endif
+
+static int __devexit s5pcsis_remove(struct platform_device *pdev)
+{
+ struct v4l2_subdev *sd = platform_get_drvdata(pdev);
+ struct csis_state *state = sd_to_csis_state(sd);
+ struct resource *res = state->regs_res;
+
+ pm_runtime_disable(&pdev->dev);
+ s5pcsis_suspend(&pdev->dev);
+ clk_disable(state->clock[CSIS_CLK_MUX]);
+ pm_runtime_set_suspended(&pdev->dev);
+
+ s5pcsis_clk_put(state);
+ if (state->supply)
+ regulator_put(state->supply);
+
+ media_entity_cleanup(&state->sd.entity);
+ free_irq(state->irq, state);
+ iounmap(state->regs);
+ release_mem_region(res->start, resource_size(res));
+ kfree(state);
+
+ return 0;
+}
+
+static const struct dev_pm_ops s5pcsis_pm_ops = {
+ SET_RUNTIME_PM_OPS(s5pcsis_suspend, s5pcsis_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(s5pcsis_pm_suspend, s5pcsis_pm_resume)
+};
+
+static struct platform_driver s5pcsis_driver = {
+ .probe = s5pcsis_probe,
+ .remove = __devexit_p(s5pcsis_remove),
+ .driver = {
+ .name = MODULE_NAME,
+ .owner = THIS_MODULE,
+ .pm = &s5pcsis_pm_ops,
+ },
+};
+
+static int __init s5pcsis_init(void)
+{
+ return platform_driver_probe(&s5pcsis_driver, s5pcsis_probe);
+}
+
+static void __exit s5pcsis_exit(void)
+{
+ platform_driver_unregister(&s5pcsis_driver);
+}
+
+module_init(s5pcsis_init);
+module_exit(s5pcsis_exit);
+
+MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
+MODULE_DESCRIPTION("S5P/EXYNOS4 MIPI CSI receiver driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/exynos/rotator/Kconfig b/drivers/media/video/exynos/rotator/Kconfig
new file mode 100644
index 0000000..60ed0de
--- /dev/null
+++ b/drivers/media/video/exynos/rotator/Kconfig
@@ -0,0 +1,7 @@
+config VIDEO_EXYNOS_ROTATOR
+ bool "Exynos image rotator driver"
+ depends on VIDEO_EXYNOS && (ARCH_EXYNOS4 || ARCH_EXYNOS5)
+ select V4L2_MEM2MEM_DEV
+ default n
+ help
+ This is a v4l2 driver for EXYNOS Image Rotator device.
diff --git a/drivers/media/video/exynos/rotator/Makefile b/drivers/media/video/exynos/rotator/Makefile
new file mode 100644
index 0000000..62ccceb
--- /dev/null
+++ b/drivers/media/video/exynos/rotator/Makefile
@@ -0,0 +1,9 @@
+#
+# Copyright (c) 2012 Samsung Electronics Co., Ltd.
+# http://www.samsung.com
+#
+# Licensed under GPLv2
+#
+
+rotator-objs := rotator-core.o rotator-regs.o rotator-vb2.o
+obj-$(CONFIG_VIDEO_EXYNOS_ROTATOR) += rotator.o
diff --git a/drivers/media/video/exynos/rotator/rotator-core.c b/drivers/media/video/exynos/rotator/rotator-core.c
new file mode 100644
index 0000000..8b093dd
--- /dev/null
+++ b/drivers/media/video/exynos/rotator/rotator-core.c
@@ -0,0 +1,1332 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Core file for Samsung EXYNOS Image Rotator driver
+ *
+ * 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.
+*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <linux/pm_runtime.h>
+
+#include <media/v4l2-ioctl.h>
+#include <mach/videonode.h>
+
+#include "rotator.h"
+
+int log_level;
+module_param_named(log_level, log_level, uint, 0644);
+
+static struct rot_fmt rot_formats[] = {
+ {
+ .name = "RGB565",
+ .pixelformat = V4L2_PIX_FMT_RGB565,
+ .num_planes = 1,
+ .num_comp = 1,
+ .bitperpixel = { 16 },
+ }, {
+ .name = "XRGB-8888, 32 bpp",
+ .pixelformat = V4L2_PIX_FMT_RGB32,
+ .num_planes = 1,
+ .num_comp = 1,
+ .bitperpixel = { 32 },
+ }, {
+ .name = "YUV 4:2:2 packed, YCbYCr",
+ .pixelformat = V4L2_PIX_FMT_YUYV,
+ .num_planes = 1,
+ .num_comp = 1,
+ .bitperpixel = { 16 },
+ }, {
+ .name = "YUV 4:2:0 non-contiguous 2-planar, Y/CbCr",
+ .pixelformat = V4L2_PIX_FMT_NV12M,
+ .num_planes = 2,
+ .num_comp = 2,
+ .bitperpixel = { 8, 4 },
+ }, {
+ .name = "YUV 4:2:0 non-contiguous 3-planar, Y/Cb/Cr",
+ .pixelformat = V4L2_PIX_FMT_YUV420M,
+ .num_planes = 3,
+ .num_comp = 3,
+ .bitperpixel = { 8, 2, 2 },
+ },
+};
+
+/* Find the matches format */
+static struct rot_fmt *rot_find_format(struct v4l2_format *f)
+{
+ struct rot_fmt *rot_fmt;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(rot_formats); ++i) {
+ rot_fmt = &rot_formats[i];
+ if (rot_fmt->pixelformat == f->fmt.pix_mp.pixelformat)
+ return &rot_formats[i];
+ }
+
+ return NULL;
+}
+
+static void rot_bound_align_image(struct rot_ctx *ctx, struct rot_fmt *rot_fmt,
+ u32 *width, u32 *height)
+{
+ struct exynos_rot_variant *variant = ctx->rot_dev->variant;
+ struct exynos_rot_size_limit *limit = NULL;
+
+ switch (rot_fmt->pixelformat) {
+ case V4L2_PIX_FMT_YUV420M:
+ limit = &variant->limit_yuv420_3p;
+ break;
+ case V4L2_PIX_FMT_NV12M:
+ limit = &variant->limit_yuv420_2p;
+ break;
+ case V4L2_PIX_FMT_YUYV:
+ limit = &variant->limit_yuv422;
+ break;
+ case V4L2_PIX_FMT_RGB565:
+ limit = &variant->limit_rgb565;
+ break;
+ case V4L2_PIX_FMT_RGB32:
+ limit = &variant->limit_rgb888;
+ break;
+ default:
+ v4l2_err(&ctx->rot_dev->m2m.v4l2_dev,
+ "not supported format values\n");
+ return;
+ }
+
+ /* Bound an image to have width and height in limit */
+ v4l_bound_align_image(width, limit->min_x, limit->max_x,
+ limit->align, height, limit->min_y,
+ limit->max_y, limit->align, 0);
+}
+
+static void rot_adjust_pixminfo(struct rot_ctx *ctx, struct rot_frame *frame,
+ struct v4l2_pix_format_mplane *pixm)
+{
+ struct rot_frame *rot_frame;
+
+ if (frame == &ctx->s_frame) {
+ if (test_bit(CTX_DST, &ctx->flags)) {
+ rot_frame = &ctx->d_frame;
+ pixm->pixelformat = rot_frame->rot_fmt->pixelformat;
+ }
+ set_bit(CTX_SRC, &ctx->flags);
+ } else if (frame == &ctx->d_frame) {
+ if (test_bit(CTX_SRC, &ctx->flags)) {
+ rot_frame = &ctx->s_frame;
+ pixm->pixelformat = rot_frame->rot_fmt->pixelformat;
+ }
+ set_bit(CTX_DST, &ctx->flags);
+ }
+}
+
+static int rot_v4l2_querycap(struct file *file, void *fh,
+ struct v4l2_capability *cap)
+{
+ strncpy(cap->driver, MODULE_NAME, sizeof(cap->driver) - 1);
+ strncpy(cap->card, MODULE_NAME, sizeof(cap->card) - 1);
+
+ cap->bus_info[0] = 0;
+ cap->capabilities = V4L2_CAP_STREAMING |
+ V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE;
+
+ return 0;
+}
+
+static int rot_v4l2_enum_fmt_mplane(struct file *file, void *fh,
+ struct v4l2_fmtdesc *f)
+{
+ struct rot_fmt *rot_fmt;
+
+ if (f->index >= ARRAY_SIZE(rot_formats))
+ return -EINVAL;
+
+ rot_fmt = &rot_formats[f->index];
+ strncpy(f->description, rot_fmt->name, sizeof(f->description) - 1);
+ f->pixelformat = rot_fmt->pixelformat;
+
+ return 0;
+}
+
+static int rot_v4l2_g_fmt_mplane(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct rot_ctx *ctx = fh_to_rot_ctx(fh);
+ struct rot_fmt *rot_fmt;
+ struct rot_frame *frame;
+ struct v4l2_pix_format_mplane *pixm = &f->fmt.pix_mp;
+ int i;
+
+ frame = ctx_get_frame(ctx, f->type);
+ if (IS_ERR(frame))
+ return PTR_ERR(frame);
+
+ rot_fmt = frame->rot_fmt;
+
+ pixm->width = frame->pix_mp.width;
+ pixm->height = frame->pix_mp.height;
+ pixm->pixelformat = frame->pix_mp.pixelformat;
+ pixm->field = V4L2_FIELD_NONE;
+ pixm->num_planes = frame->rot_fmt->num_planes;
+ pixm->colorspace = 0;
+
+ for (i = 0; i < pixm->num_planes; ++i) {
+ pixm->plane_fmt[i].bytesperline = (pixm->width *
+ rot_fmt->bitperpixel[i]) >> 3;
+ pixm->plane_fmt[i].sizeimage = pixm->plane_fmt[i].bytesperline
+ * pixm->height;
+
+ v4l2_dbg(1, log_level, &ctx->rot_dev->m2m.v4l2_dev,
+ "[%d] plane: bytesperline %d, sizeimage %d\n",
+ i, pixm->plane_fmt[i].bytesperline,
+ pixm->plane_fmt[i].sizeimage);
+ }
+
+ return 0;
+}
+
+static int rot_v4l2_try_fmt_mplane(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct rot_ctx *ctx = fh_to_rot_ctx(fh);
+ struct rot_fmt *rot_fmt;
+ struct v4l2_pix_format_mplane *pixm = &f->fmt.pix_mp;
+ int i;
+
+ if (!V4L2_TYPE_IS_MULTIPLANAR(f->type)) {
+ v4l2_err(&ctx->rot_dev->m2m.v4l2_dev,
+ "not supported v4l2 type\n");
+ return -EINVAL;
+ }
+
+ rot_fmt = rot_find_format(f);
+ if (!rot_fmt) {
+ v4l2_err(&ctx->rot_dev->m2m.v4l2_dev,
+ "not supported format type\n");
+ return -EINVAL;
+ }
+
+ rot_bound_align_image(ctx, rot_fmt, &pixm->width, &pixm->height);
+
+ pixm->num_planes = rot_fmt->num_planes;
+ pixm->colorspace = 0;
+
+ for (i = 0; i < pixm->num_planes; ++i) {
+ pixm->plane_fmt[i].bytesperline = (pixm->width *
+ rot_fmt->bitperpixel[i]) >> 3;
+ pixm->plane_fmt[i].sizeimage = pixm->plane_fmt[i].bytesperline
+ * pixm->height;
+
+ v4l2_dbg(1, log_level, &ctx->rot_dev->m2m.v4l2_dev,
+ "[%d] plane: bytesperline %d, sizeimage %d\n",
+ i, pixm->plane_fmt[i].bytesperline,
+ pixm->plane_fmt[i].sizeimage);
+ }
+
+ return 0;
+}
+
+static int rot_v4l2_s_fmt_mplane(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct rot_ctx *ctx = fh_to_rot_ctx(fh);
+ struct vb2_queue *vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+ struct rot_frame *frame;
+ struct v4l2_pix_format_mplane *pixm = &f->fmt.pix_mp;
+ int i, ret = 0;
+
+ if (vb2_is_streaming(vq)) {
+ v4l2_err(&ctx->rot_dev->m2m.v4l2_dev, "device is busy\n");
+ return -EBUSY;
+ }
+
+ ret = rot_v4l2_try_fmt_mplane(file, fh, f);
+ if (ret < 0)
+ return ret;
+
+ frame = ctx_get_frame(ctx, f->type);
+ if (IS_ERR(frame))
+ return PTR_ERR(frame);
+
+ set_bit(CTX_PARAMS, &ctx->flags);
+
+ frame->rot_fmt = rot_find_format(f);
+ if (!frame->rot_fmt) {
+ v4l2_err(&ctx->rot_dev->m2m.v4l2_dev,
+ "not supported format values\n");
+ return -EINVAL;
+ }
+
+ rot_adjust_pixminfo(ctx, frame, pixm);
+
+ frame->pix_mp.pixelformat = pixm->pixelformat;
+ frame->pix_mp.width = pixm->width;
+ frame->pix_mp.height = pixm->height;
+
+ /*
+ * Shouldn't call s_crop or g_crop before called g_fmt or s_fmt.
+ * Let's assume that we can keep the order.
+ */
+ frame->crop.width = pixm->width;
+ frame->crop.height = pixm->height;
+
+ for (i = 0; i < frame->rot_fmt->num_planes; ++i)
+ frame->bytesused[i] = (pixm->width * pixm->height *
+ frame->rot_fmt->bitperpixel[i]) >> 3;
+
+ return 0;
+}
+
+static int rot_v4l2_reqbufs(struct file *file, void *fh,
+ struct v4l2_requestbuffers *reqbufs)
+{
+ struct rot_ctx *ctx = fh_to_rot_ctx(fh);
+ struct rot_dev *rot = ctx->rot_dev;
+ struct rot_frame *frame;
+
+ frame = ctx_get_frame(ctx, reqbufs->type);
+ if (IS_ERR(frame))
+ return PTR_ERR(frame);
+
+ if (frame == &ctx->s_frame)
+ clear_bit(CTX_SRC, &ctx->flags);
+ else if (frame == &ctx->d_frame)
+ clear_bit(CTX_DST, &ctx->flags);
+
+ rot->vb2->set_cacheable(rot->alloc_ctx, ctx->cacheable);
+
+ return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
+}
+
+static int rot_v4l2_querybuf(struct file *file, void *fh,
+ struct v4l2_buffer *buf)
+{
+ struct rot_ctx *ctx = fh_to_rot_ctx(fh);
+ return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
+}
+
+static int rot_v4l2_qbuf(struct file *file, void *fh,
+ struct v4l2_buffer *buf)
+{
+ struct rot_ctx *ctx = fh_to_rot_ctx(fh);
+ return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int rot_v4l2_dqbuf(struct file *file, void *fh,
+ struct v4l2_buffer *buf)
+{
+ struct rot_ctx *ctx = fh_to_rot_ctx(fh);
+ return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int rot_v4l2_streamon(struct file *file, void *fh,
+ enum v4l2_buf_type type)
+{
+ struct rot_ctx *ctx = fh_to_rot_ctx(fh);
+ return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
+}
+
+static int rot_v4l2_streamoff(struct file *file, void *fh,
+ enum v4l2_buf_type type)
+{
+ struct rot_ctx *ctx = fh_to_rot_ctx(fh);
+ return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
+}
+
+static int rot_v4l2_cropcap(struct file *file, void *fh,
+ struct v4l2_cropcap *cr)
+{
+ struct rot_ctx *ctx = fh_to_rot_ctx(fh);
+ struct rot_frame *frame;
+
+ frame = ctx_get_frame(ctx, cr->type);
+ if (IS_ERR(frame))
+ return PTR_ERR(frame);
+
+ cr->bounds.left = 0;
+ cr->bounds.top = 0;
+ cr->bounds.width = frame->pix_mp.width;
+ cr->bounds.height = frame->pix_mp.height;
+ cr->defrect = cr->bounds;
+
+ return 0;
+}
+
+static int rot_v4l2_g_crop(struct file *file, void *fh, struct v4l2_crop *cr)
+{
+ struct rot_ctx *ctx = fh_to_rot_ctx(fh);
+ struct rot_frame *frame;
+
+ frame = ctx_get_frame(ctx, cr->type);
+ if (IS_ERR(frame))
+ return PTR_ERR(frame);
+
+ cr->c = frame->crop;
+
+ return 0;
+}
+
+static int rot_v4l2_s_crop(struct file *file, void *fh, struct v4l2_crop *cr)
+{
+ struct rot_ctx *ctx = fh_to_rot_ctx(fh);
+ struct rot_frame *frame;
+ struct v4l2_pix_format_mplane *pixm;
+ int i;
+
+ frame = ctx_get_frame(ctx, cr->type);
+ if (IS_ERR(frame))
+ return PTR_ERR(frame);
+
+ if (!test_bit(CTX_PARAMS, &ctx->flags)) {
+ v4l2_err(&ctx->rot_dev->m2m.v4l2_dev,
+ "color format is not set\n");
+ return -EINVAL;
+ }
+
+ if (cr->c.left < 0 || cr->c.top < 0 ||
+ cr->c.width < 0 || cr->c.height < 0) {
+ v4l2_err(&ctx->rot_dev->m2m.v4l2_dev,
+ "crop value is negative\n");
+ return -EINVAL;
+ }
+
+ pixm = &frame->pix_mp;
+ rot_bound_align_image(ctx, frame->rot_fmt, &cr->c.width, &cr->c.height);
+
+ /* Adjust left/top if cropping rectangle is out of bounds */
+ if (cr->c.left + cr->c.width > pixm->width) {
+ dev_warn(ctx->rot_dev->dev,
+ "out of bound left cropping size:left %d, width %d\n",
+ cr->c.left, cr->c.width);
+ cr->c.left = pixm->width - cr->c.width;
+ }
+ if (cr->c.top + cr->c.height > pixm->height) {
+ dev_warn(ctx->rot_dev->dev,
+ "out of bound top cropping size:top %d, height %d\n",
+ cr->c.top, cr->c.height);
+ cr->c.top = pixm->height - cr->c.height;
+ }
+
+ frame->crop = cr->c;
+
+ for (i = 0; i < frame->rot_fmt->num_planes; ++i)
+ frame->bytesused[i] = (cr->c.width * cr->c.height *
+ frame->rot_fmt->bitperpixel[i]) >> 3;
+
+ return 0;
+}
+
+static const struct v4l2_ioctl_ops rot_v4l2_ioctl_ops = {
+ .vidioc_querycap = rot_v4l2_querycap,
+
+ .vidioc_enum_fmt_vid_cap_mplane = rot_v4l2_enum_fmt_mplane,
+ .vidioc_enum_fmt_vid_out_mplane = rot_v4l2_enum_fmt_mplane,
+
+ .vidioc_g_fmt_vid_cap_mplane = rot_v4l2_g_fmt_mplane,
+ .vidioc_g_fmt_vid_out_mplane = rot_v4l2_g_fmt_mplane,
+
+ .vidioc_try_fmt_vid_cap_mplane = rot_v4l2_try_fmt_mplane,
+ .vidioc_try_fmt_vid_out_mplane = rot_v4l2_try_fmt_mplane,
+
+ .vidioc_s_fmt_vid_cap_mplane = rot_v4l2_s_fmt_mplane,
+ .vidioc_s_fmt_vid_out_mplane = rot_v4l2_s_fmt_mplane,
+
+ .vidioc_reqbufs = rot_v4l2_reqbufs,
+ .vidioc_querybuf = rot_v4l2_querybuf,
+
+ .vidioc_qbuf = rot_v4l2_qbuf,
+ .vidioc_dqbuf = rot_v4l2_dqbuf,
+
+ .vidioc_streamon = rot_v4l2_streamon,
+ .vidioc_streamoff = rot_v4l2_streamoff,
+
+ .vidioc_g_crop = rot_v4l2_g_crop,
+ .vidioc_s_crop = rot_v4l2_s_crop,
+ .vidioc_cropcap = rot_v4l2_cropcap
+};
+
+static int rot_ctx_stop_req(struct rot_ctx *ctx)
+{
+ struct rot_ctx *curr_ctx;
+ struct rot_dev *rot = ctx->rot_dev;
+ int ret = 0;
+
+ curr_ctx = v4l2_m2m_get_curr_priv(rot->m2m.m2m_dev);
+ if (!test_bit(CTX_RUN, &ctx->flags) || (curr_ctx != ctx))
+ return 0;
+
+ set_bit(CTX_ABORT, &ctx->flags);
+
+ ret = wait_event_timeout(rot->wait,
+ !test_bit(CTX_RUN, &ctx->flags), ROT_TIMEOUT);
+
+ /* TODO: How to handle case of timeout event */
+ if (ret == 0) {
+ dev_err(rot->dev, "device failed to stop request\n");
+ ret = -EBUSY;
+ }
+
+ return ret;
+}
+
+static int rot_vb2_queue_setup(struct vb2_queue *vq,
+ const struct v4l2_format *fmt, unsigned int *num_buffers,
+ unsigned int *num_planes, unsigned int sizes[],
+ void *allocators[])
+{
+ struct rot_ctx *ctx = vb2_get_drv_priv(vq);
+ struct rot_frame *frame;
+ int i;
+
+ frame = ctx_get_frame(ctx, vq->type);
+ if (IS_ERR(frame))
+ return PTR_ERR(frame);
+
+ /* Get number of planes from format_list in driver */
+ *num_planes = frame->rot_fmt->num_planes;
+ for (i = 0; i < frame->rot_fmt->num_planes; i++) {
+ sizes[i] = (frame->pix_mp.width * frame->pix_mp.height *
+ frame->rot_fmt->bitperpixel[i]) >> 3;
+ allocators[i] = ctx->rot_dev->alloc_ctx;
+ }
+
+ return 0;
+}
+
+static int rot_vb2_buf_prepare(struct vb2_buffer *vb)
+{
+ struct rot_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+ struct rot_frame *frame;
+ int i;
+
+ frame = ctx_get_frame(ctx, vb->vb2_queue->type);
+ if (IS_ERR(frame))
+ return PTR_ERR(frame);
+
+ if (!V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) {
+ for (i = 0; i < frame->rot_fmt->num_planes; i++)
+ vb2_set_plane_payload(vb, i, frame->bytesused[i]);
+ }
+
+ if (ctx->cacheable)
+ ctx->rot_dev->vb2->cache_flush(vb, frame->rot_fmt->num_planes);
+
+ return 0;
+}
+
+static void rot_vb2_buf_queue(struct vb2_buffer *vb)
+{
+ struct rot_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+
+ if (ctx->m2m_ctx)
+ v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
+}
+
+static void rot_vb2_lock(struct vb2_queue *vq)
+{
+ struct rot_ctx *ctx = vb2_get_drv_priv(vq);
+ mutex_lock(&ctx->rot_dev->lock);
+}
+
+static void rot_vb2_unlock(struct vb2_queue *vq)
+{
+ struct rot_ctx *ctx = vb2_get_drv_priv(vq);
+ mutex_unlock(&ctx->rot_dev->lock);
+}
+
+static int rot_vb2_start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+ struct rot_ctx *ctx = vb2_get_drv_priv(vq);
+ set_bit(CTX_STREAMING, &ctx->flags);
+
+ return 0;
+}
+
+static int rot_vb2_stop_streaming(struct vb2_queue *vq)
+{
+ struct rot_ctx *ctx = vb2_get_drv_priv(vq);
+ struct rot_dev *rot = ctx->rot_dev;
+ int ret;
+
+ ret = rot_ctx_stop_req(ctx);
+ if (ret < 0)
+ dev_err(ctx->rot_dev->dev, "wait timeout\n");
+
+ clear_bit(CTX_STREAMING, &ctx->flags);
+ v4l2_m2m_get_next_job(rot->m2m.m2m_dev, ctx->m2m_ctx);
+
+ return ret;
+}
+
+static struct vb2_ops rot_vb2_ops = {
+ .queue_setup = rot_vb2_queue_setup,
+ .buf_prepare = rot_vb2_buf_prepare,
+ .buf_queue = rot_vb2_buf_queue,
+ .wait_finish = rot_vb2_lock,
+ .wait_prepare = rot_vb2_unlock,
+ .start_streaming = rot_vb2_start_streaming,
+ .stop_streaming = rot_vb2_stop_streaming,
+};
+
+static int queue_init(void *priv, struct vb2_queue *src_vq,
+ struct vb2_queue *dst_vq)
+{
+ struct rot_ctx *ctx = priv;
+ int ret;
+
+ memset(src_vq, 0, sizeof(*src_vq));
+ src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ src_vq->io_modes = VB2_MMAP | VB2_USERPTR;
+ src_vq->ops = &rot_vb2_ops;
+ src_vq->mem_ops = ctx->rot_dev->vb2->ops;
+ src_vq->drv_priv = ctx;
+ src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+
+ ret = vb2_queue_init(src_vq);
+ if (ret)
+ return ret;
+
+ memset(dst_vq, 0, sizeof(*dst_vq));
+ dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ dst_vq->io_modes = VB2_MMAP | VB2_USERPTR;
+ dst_vq->ops = &rot_vb2_ops;
+ dst_vq->mem_ops = ctx->rot_dev->vb2->ops;
+ dst_vq->drv_priv = ctx;
+ dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+
+ return vb2_queue_init(dst_vq);
+}
+
+static int rot_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct rot_ctx *ctx;
+
+ rot_dbg("ctrl ID:%d, value:%d\n", ctrl->id, ctrl->val);
+ ctx = container_of(ctrl->handler, struct rot_ctx, ctrl_handler);
+
+ switch (ctrl->id) {
+ case V4L2_CID_VFLIP:
+ if (ctrl->val)
+ ctx->flip |= ROT_VFLIP;
+ else
+ ctx->flip &= ~ROT_VFLIP;
+ break;
+ case V4L2_CID_HFLIP:
+ if (ctrl->val)
+ ctx->flip |= ROT_HFLIP;
+ else
+ ctx->flip &= ~ROT_HFLIP;
+ break;
+ case V4L2_CID_ROTATE:
+ ctx->rotation = ctrl->val;
+ break;
+ case V4L2_CID_CACHEABLE:
+ ctx->cacheable = (bool)ctrl->val;
+ break;
+ }
+
+ return 0;
+}
+
+static const struct v4l2_ctrl_ops rot_ctrl_ops = {
+ .s_ctrl = rot_s_ctrl,
+};
+
+static const struct v4l2_ctrl_config rot_custom_ctrl[] = {
+ {
+ .ops = &rot_ctrl_ops,
+ .id = V4L2_CID_CACHEABLE,
+ .name = "set cacheable",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .flags = V4L2_CTRL_FLAG_SLIDER,
+ .max = 1,
+ .def = true,
+ }
+};
+
+static int rot_add_ctrls(struct rot_ctx *ctx)
+{
+ v4l2_ctrl_handler_init(&ctx->ctrl_handler, 4);
+ v4l2_ctrl_new_std(&ctx->ctrl_handler, &rot_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
+ v4l2_ctrl_new_std(&ctx->ctrl_handler, &rot_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+ v4l2_ctrl_new_std(&ctx->ctrl_handler, &rot_ctrl_ops,
+ V4L2_CID_ROTATE, 0, 270, 90, 0);
+ v4l2_ctrl_new_custom(&ctx->ctrl_handler, &rot_custom_ctrl[0], NULL);
+
+ if (ctx->ctrl_handler.error) {
+ int err = ctx->ctrl_handler.error;
+ v4l2_err(&ctx->rot_dev->m2m.v4l2_dev,
+ "v4l2_ctrl_handler_init failed\n");
+ v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+ return err;
+ }
+
+ v4l2_ctrl_handler_setup(&ctx->ctrl_handler);
+
+ return 0;
+}
+
+static int rot_open(struct file *file)
+{
+ struct rot_dev *rot = video_drvdata(file);
+ struct rot_ctx *ctx;
+ int ret;
+
+ ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
+ if (!ctx) {
+ dev_err(rot->dev, "no memory for open context\n");
+ return -ENOMEM;
+ }
+
+ atomic_inc(&rot->m2m.in_use);
+ ctx->rot_dev = rot;
+
+ v4l2_fh_init(&ctx->fh, rot->m2m.vfd);
+ ret = rot_add_ctrls(ctx);
+ if (ret)
+ goto err_fh;
+
+ ctx->fh.ctrl_handler = &ctx->ctrl_handler;
+ file->private_data = &ctx->fh;
+ v4l2_fh_add(&ctx->fh);
+
+ /* Default color format */
+ ctx->s_frame.rot_fmt = &rot_formats[0];
+ ctx->d_frame.rot_fmt = &rot_formats[0];
+ init_waitqueue_head(&rot->wait);
+ spin_lock_init(&ctx->slock);
+
+ /* Setup the device context for mem2mem mode. */
+ ctx->m2m_ctx = v4l2_m2m_ctx_init(rot->m2m.m2m_dev, ctx, queue_init);
+ if (IS_ERR(ctx->m2m_ctx)) {
+ ret = -EINVAL;
+ goto err_ctx;
+ }
+
+ return 0;
+
+err_ctx:
+ v4l2_fh_del(&ctx->fh);
+err_fh:
+ v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+ v4l2_fh_exit(&ctx->fh);
+ atomic_dec(&rot->m2m.in_use);
+ kfree(ctx);
+
+ return ret;
+}
+
+static int rot_release(struct file *file)
+{
+ struct rot_ctx *ctx = fh_to_rot_ctx(file->private_data);
+ struct rot_dev *rot = ctx->rot_dev;
+
+ rot_dbg("refcnt= %d", atomic_read(&rot->m2m.in_use));
+
+ v4l2_m2m_ctx_release(ctx->m2m_ctx);
+ v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+ v4l2_fh_del(&ctx->fh);
+ v4l2_fh_exit(&ctx->fh);
+ atomic_dec(&rot->m2m.in_use);
+ kfree(ctx);
+
+ return 0;
+}
+
+static unsigned int rot_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct rot_ctx *ctx = fh_to_rot_ctx(file->private_data);
+
+ return v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
+}
+
+static int rot_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct rot_ctx *ctx = fh_to_rot_ctx(file->private_data);
+
+ return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
+}
+
+static const struct v4l2_file_operations rot_v4l2_fops = {
+ .owner = THIS_MODULE,
+ .open = rot_open,
+ .release = rot_release,
+ .poll = rot_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = rot_mmap,
+};
+
+static void rot_watchdog(unsigned long arg)
+{
+ struct rot_dev *rot = (struct rot_dev *)arg;
+ struct rot_ctx *ctx;
+ unsigned long flags;
+ struct vb2_buffer *src_vb, *dst_vb;
+
+ rot_dbg("timeout watchdog\n");
+ if (atomic_read(&rot->wdt.cnt) >= ROT_WDT_CNT) {
+ pm_runtime_put(rot->dev);
+
+ rot_dbg("wakeup blocked process\n");
+ atomic_set(&rot->wdt.cnt, 0);
+ clear_bit(DEV_RUN, &rot->state);
+
+ ctx = v4l2_m2m_get_curr_priv(rot->m2m.m2m_dev);
+ if (!ctx || !ctx->m2m_ctx) {
+ dev_err(rot->dev, "current ctx is NULL\n");
+ return;
+ }
+ spin_lock_irqsave(&rot->slock, flags);
+ clear_bit(CTX_RUN, &ctx->flags);
+ src_vb = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
+ dst_vb = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
+
+ if (src_vb && dst_vb) {
+ v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_ERROR);
+ v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_ERROR);
+
+ v4l2_m2m_job_finish(rot->m2m.m2m_dev, ctx->m2m_ctx);
+ }
+ spin_unlock_irqrestore(&rot->slock, flags);
+ return;
+ }
+
+ if (test_bit(DEV_RUN, &rot->state)) {
+ atomic_inc(&rot->wdt.cnt);
+ dev_err(rot->dev, "rotator is still running\n");
+ rot->wdt.timer.expires = jiffies + ROT_TIMEOUT;
+ add_timer(&rot->wdt.timer);
+ } else {
+ rot_dbg("rotator finished job\n");
+ }
+}
+
+static irqreturn_t rot_irq_handler(int irq, void *priv)
+{
+ struct rot_dev *rot = priv;
+ struct rot_ctx *ctx;
+ struct vb2_buffer *src_vb, *dst_vb;
+ unsigned int irq_src;
+
+ spin_lock(&rot->slock);
+
+ clear_bit(DEV_RUN, &rot->state);
+ if (timer_pending(&rot->wdt.timer))
+ del_timer(&rot->wdt.timer);
+
+ rot_hwget_irq_src(rot, &irq_src);
+ rot_hwset_irq_clear(rot, &irq_src);
+
+ if (irq_src != ISR_PEND_DONE) {
+ dev_err(rot->dev, "####################\n");
+ dev_err(rot->dev, "Illegal SFR configuration\n");
+ dev_err(rot->dev, "The result might be wrong\n");
+ dev_err(rot->dev, "####################\n");
+ rot_dump_registers(rot);
+ }
+
+ ctx = v4l2_m2m_get_curr_priv(rot->m2m.m2m_dev);
+ if (!ctx || !ctx->m2m_ctx) {
+ dev_err(rot->dev, "current ctx is NULL\n");
+ goto isr_unlock;
+ }
+
+ clear_bit(CTX_RUN, &ctx->flags);
+
+ src_vb = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
+ dst_vb = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
+
+ if (src_vb && dst_vb) {
+ v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
+ v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE);
+
+ if (test_bit(DEV_SUSPEND, &rot->state)) {
+ rot_dbg("wake up blocked process by suspend\n");
+ wake_up(&rot->wait);
+ } else {
+ v4l2_m2m_job_finish(rot->m2m.m2m_dev, ctx->m2m_ctx);
+ }
+
+ /* Wake up from CTX_ABORT state */
+ if (test_and_clear_bit(CTX_ABORT, &ctx->flags))
+ wake_up(&rot->wait);
+
+ pm_runtime_put(rot->dev);
+ } else {
+ dev_err(rot->dev, "failed to get the buffer done\n");
+ }
+
+isr_unlock:
+ spin_unlock(&rot->slock);
+
+ return IRQ_HANDLED;
+}
+
+static void rot_get_bufaddr(struct rot_dev *rot, struct vb2_buffer *vb,
+ struct rot_frame *frame, struct rot_addr *addr)
+{
+ unsigned int pix_size;
+
+ pix_size = frame->pix_mp.width * frame->pix_mp.height;
+
+ addr->y = rot->vb2->plane_addr(vb, 0);
+ addr->cb = 0;
+ addr->cr = 0;
+
+ switch (frame->rot_fmt->num_comp) {
+ case 2:
+ if (frame->rot_fmt->num_planes == 1)
+ addr->cb = addr->y + pix_size;
+ else if (frame->rot_fmt->num_planes == 2)
+ addr->cb = rot->vb2->plane_addr(vb, 1);
+ break;
+ case 3:
+ if (frame->rot_fmt->num_planes == 3) {
+ addr->cb = rot->vb2->plane_addr(vb, 1);
+ addr->cr = rot->vb2->plane_addr(vb, 2);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static void rot_set_frame_addr(struct rot_ctx *ctx)
+{
+ struct vb2_buffer *vb;
+ struct rot_frame *s_frame, *d_frame;
+ struct rot_dev *rot = ctx->rot_dev;
+
+ s_frame = &ctx->s_frame;
+ d_frame = &ctx->d_frame;
+
+ /* set source buffer address */
+ vb = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
+ rot_get_bufaddr(rot, vb, s_frame, &s_frame->addr);
+
+ rot_hwset_src_addr(rot, s_frame->addr.y, ROT_ADDR_Y);
+ rot_hwset_src_addr(rot, s_frame->addr.cb, ROT_ADDR_CB);
+ rot_hwset_src_addr(rot, s_frame->addr.cr, ROT_ADDR_CR);
+
+ /* set destination buffer address */
+ vb = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+ rot_get_bufaddr(rot, vb, d_frame, &d_frame->addr);
+
+ rot_hwset_dst_addr(rot, d_frame->addr.y, ROT_ADDR_Y);
+ rot_hwset_dst_addr(rot, d_frame->addr.cb, ROT_ADDR_CB);
+ rot_hwset_dst_addr(rot, d_frame->addr.cr, ROT_ADDR_CR);
+}
+
+static void rot_mapping_flip(struct rot_ctx *ctx, u32 *degree, u32 *flip)
+{
+ *degree = ctx->rotation;
+ *flip = ctx->flip;
+
+ if (ctx->flip == (ROT_VFLIP | ROT_HFLIP)) {
+ *flip = ROT_NOFLIP;
+ switch (ctx->rotation) {
+ case 0:
+ *degree = 180;
+ break;
+ case 90:
+ *degree = 270;
+ break;
+ case 180:
+ *degree = 0;
+ break;
+ case 270:
+ *degree = 90;
+ break;
+ }
+ }
+}
+
+static void rot_m2m_device_run(void *priv)
+{
+ struct rot_ctx *ctx = priv;
+ struct rot_frame *s_frame, *d_frame;
+ struct rot_dev *rot;
+ unsigned long flags;
+ u32 degree = 0, flip = 0;
+
+ spin_lock_irqsave(&ctx->slock, flags);
+
+ rot = ctx->rot_dev;
+
+ if (test_bit(DEV_RUN, &rot->state)) {
+ dev_err(rot->dev, "Rotator is already in progress\n");
+ goto run_unlock;
+ }
+
+ if (test_bit(DEV_SUSPEND, &rot->state)) {
+ dev_err(rot->dev, "Rotator is in suspend state\n");
+ goto run_unlock;
+ }
+
+ if (test_bit(CTX_ABORT, &ctx->flags)) {
+ rot_dbg("aborted rot device run\n");
+ goto run_unlock;
+ }
+
+ pm_runtime_get_sync(ctx->rot_dev->dev);
+
+ s_frame = &ctx->s_frame;
+ d_frame = &ctx->d_frame;
+
+ /* Configuration rotator registers */
+ rot_hwset_image_format(rot, s_frame->rot_fmt->pixelformat);
+ rot_mapping_flip(ctx, °ree, &flip);
+ rot_hwset_flip(rot, flip);
+ rot_hwset_rotation(rot, degree);
+
+ rot_hwset_src_imgsize(rot, s_frame);
+ rot_hwset_dst_imgsize(rot, d_frame);
+
+ rot_hwset_src_crop(rot, &s_frame->crop);
+ rot_hwset_dst_crop(rot, &d_frame->crop);
+
+ rot_set_frame_addr(ctx);
+
+ /* Enable rotator interrupt */
+ rot_hwset_irq_frame_done(rot, 1);
+ rot_hwset_irq_illegal_config(rot, 1);
+
+ set_bit(DEV_RUN, &rot->state);
+ set_bit(CTX_RUN, &ctx->flags);
+
+ /* Start rotate operation */
+ rot_hwset_start(rot);
+
+ /* Start watchdog timer */
+ rot->wdt.timer.expires = jiffies + ROT_TIMEOUT;
+ if (timer_pending(&rot->wdt.timer) == 0)
+ add_timer(&rot->wdt.timer);
+ else
+ mod_timer(&rot->wdt.timer, rot->wdt.timer.expires);
+
+run_unlock:
+ spin_unlock_irqrestore(&ctx->slock, flags);
+}
+
+static void rot_m2m_job_abort(void *priv)
+{
+ struct rot_ctx *ctx = priv;
+ struct rot_dev *rot = ctx->rot_dev;
+ int ret;
+
+ ret = rot_ctx_stop_req(ctx);
+ if (ret < 0)
+ dev_err(ctx->rot_dev->dev, "wait timeout\n");
+
+ v4l2_m2m_get_next_job(rot->m2m.m2m_dev, ctx->m2m_ctx);
+}
+
+static struct v4l2_m2m_ops rot_m2m_ops = {
+ .device_run = rot_m2m_device_run,
+ .job_abort = rot_m2m_job_abort,
+};
+
+static int rot_register_m2m_device(struct rot_dev *rot)
+{
+ struct v4l2_device *v4l2_dev;
+ struct device *dev;
+ struct video_device *vfd;
+ int ret = 0;
+
+ if (!rot)
+ return -ENODEV;
+
+ dev = rot->dev;
+ v4l2_dev = &rot->m2m.v4l2_dev;
+
+ snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), "%s.m2m",
+ MODULE_NAME);
+
+ ret = v4l2_device_register(dev, v4l2_dev);
+ if (ret) {
+ dev_err(rot->dev, "failed to register v4l2 device\n");
+ return ret;
+ }
+
+ vfd = video_device_alloc();
+ if (!vfd) {
+ dev_err(rot->dev, "failed to allocate video device\n");
+ goto err_v4l2_dev;
+ }
+
+ vfd->fops = &rot_v4l2_fops;
+ vfd->ioctl_ops = &rot_v4l2_ioctl_ops;
+ vfd->release = video_device_release;
+ snprintf(vfd->name, sizeof(vfd->name), "%s:m2m", MODULE_NAME);
+
+ video_set_drvdata(vfd, rot);
+
+ rot->m2m.vfd = vfd;
+ rot->m2m.m2m_dev = v4l2_m2m_init(&rot_m2m_ops);
+ if (IS_ERR(rot->m2m.m2m_dev)) {
+ dev_err(rot->dev, "failed to initialize v4l2-m2m device\n");
+ ret = PTR_ERR(rot->m2m.m2m_dev);
+ goto err_dev_alloc;
+ }
+
+ ret = video_register_device(vfd, VFL_TYPE_GRABBER,
+ EXYNOS_VIDEONODE_ROTATOR);
+ if (ret) {
+ dev_err(rot->dev, "failed to register video device\n");
+ goto err_m2m_dev;
+ }
+
+ return 0;
+
+err_m2m_dev:
+ v4l2_m2m_release(rot->m2m.m2m_dev);
+err_dev_alloc:
+ video_device_release(rot->m2m.vfd);
+err_v4l2_dev:
+ v4l2_device_unregister(v4l2_dev);
+
+ return ret;
+}
+
+static int rot_suspend(struct device *dev)
+{
+ struct rot_dev *rot = dev_get_drvdata(dev);
+ int ret;
+
+ set_bit(DEV_SUSPEND, &rot->state);
+
+ ret = wait_event_timeout(rot->wait,
+ !test_bit(DEV_RUN, &rot->state), ROT_TIMEOUT);
+ if (ret == 0)
+ dev_err(rot->dev, "wait timeout\n");
+
+ return 0;
+}
+
+static int rot_resume(struct device *dev)
+{
+ struct rot_dev *rot = dev_get_drvdata(dev);
+
+ clear_bit(DEV_SUSPEND, &rot->state);
+
+ return 0;
+}
+
+static int rot_runtime_suspend(struct device *dev)
+{
+ struct rot_dev *rot = dev_get_drvdata(dev);
+
+ rot->vb2->suspend(rot->alloc_ctx);
+
+ clk_disable(rot->clock);
+
+ return 0;
+}
+
+static int rot_runtime_resume(struct device *dev)
+{
+ struct rot_dev *rot = dev_get_drvdata(dev);
+
+ clk_enable(rot->clock);
+
+ rot->vb2->resume(rot->alloc_ctx);
+
+ return 0;
+}
+
+static const struct dev_pm_ops rot_pm_ops = {
+ .suspend = rot_suspend,
+ .resume = rot_resume,
+ .runtime_suspend = rot_runtime_suspend,
+ .runtime_resume = rot_runtime_resume,
+};
+
+static int rot_probe(struct platform_device *pdev)
+{
+ struct exynos_rot_driverdata *drv_data;
+ struct rot_dev *rot;
+ struct resource *res;
+ int variant_num, ret = 0;
+
+ dev_info(&pdev->dev, "++%s\n", __func__);
+ drv_data = (struct exynos_rot_driverdata *)
+ platform_get_device_id(pdev)->driver_data;
+
+ if (pdev->id >= drv_data->nr_dev) {
+ dev_err(&pdev->dev, "Invalid platform device id\n");
+ return -EINVAL;
+ }
+
+ rot = devm_kzalloc(&pdev->dev, sizeof(struct rot_dev), GFP_KERNEL);
+ if (!rot) {
+ dev_err(&pdev->dev, "no memory for rotator device\n");
+ return -ENOMEM;
+ }
+
+ rot->dev = &pdev->dev;
+ rot->id = pdev->id;
+ variant_num = (rot->id < 0) ? 0 : rot->id;
+ rot->variant = drv_data->variant[variant_num];
+
+ spin_lock_init(&rot->slock);
+
+ /* Get memory resource and map SFR region. */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ rot->regs = devm_request_and_ioremap(&pdev->dev, res);
+ if (rot->regs == NULL) {
+ dev_err(&pdev->dev, "failed to claim register region\n");
+ return -ENOENT;
+ }
+
+ /* Get IRQ resource and register IRQ handler. */
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "failed to get IRQ resource\n");
+ return -ENXIO;
+ }
+
+ ret = devm_request_irq(&pdev->dev, res->start, rot_irq_handler, 0,
+ pdev->name, rot);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to install irq\n");
+ return ret;
+ }
+
+ atomic_set(&rot->wdt.cnt, 0);
+ setup_timer(&rot->wdt.timer, rot_watchdog, (unsigned long)rot);
+
+ rot->clock = clk_get(rot->dev, "rotator");
+ if (IS_ERR(rot->clock)) {
+ dev_err(&pdev->dev, "failed to get clock for rotator\n");
+ return -ENXIO;
+ }
+
+#if defined(CONFIG_VIDEOBUF2_ION)
+ rot->vb2 = &rot_vb2_ion;
+#endif
+
+ rot->alloc_ctx = rot->vb2->init(rot);
+ platform_set_drvdata(pdev, rot);
+
+ ret = rot_register_m2m_device(rot);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register m2m device\n");
+ ret = -EPERM;
+ goto err;
+ }
+
+ pm_runtime_enable(&pdev->dev);
+
+#ifndef CONFIG_PM_RUNTIME
+ rot_runtime_resume(&pdev->dev);
+#endif
+
+ dev_info(&pdev->dev, "rotator registered successfully\n");
+
+ return 0;
+
+err:
+ clk_put(rot->clock);
+ return ret;
+}
+
+static int rot_remove(struct platform_device *pdev)
+{
+ struct rot_dev *rot = platform_get_drvdata(pdev);
+
+ clk_put(rot->clock);
+
+ pm_runtime_disable(&pdev->dev);
+
+#ifndef CONFIG_PM_RUNTIME
+ rot_runtime_suspend(&pdev->dev);
+#endif
+
+ if (timer_pending(&rot->wdt.timer))
+ del_timer(&rot->wdt.timer);
+
+ return 0;
+}
+
+static struct exynos_rot_variant rot_variant_exynos = {
+ .limit_rgb565 = {
+ .min_x = 16,
+ .min_y = 16,
+ .max_x = SZ_16K,
+ .max_y = SZ_16K,
+ .align = 2,
+ },
+ .limit_rgb888 = {
+ .min_x = 8,
+ .min_y = 8,
+ .max_x = SZ_8K,
+ .max_y = SZ_8K,
+ .align = 2,
+ },
+ .limit_yuv422 = {
+ .min_x = 16,
+ .min_y = 16,
+ .max_x = SZ_16K,
+ .max_y = SZ_16K,
+ .align = 2,
+ },
+ .limit_yuv420_2p = {
+ .min_x = 32,
+ .min_y = 32,
+ .max_x = SZ_32K,
+ .max_y = SZ_32K,
+ .align = 3,
+ },
+ .limit_yuv420_3p = {
+ .min_x = 64,
+ .min_y = 32,
+ .max_x = SZ_32K,
+ .max_y = SZ_32K,
+ .align = 4,
+ },
+};
+
+static struct exynos_rot_driverdata rot_drvdata_exynos = {
+ .variant = {
+ [0] = &rot_variant_exynos,
+ },
+ .nr_dev = 1,
+};
+
+static struct platform_device_id rot_driver_ids[] = {
+ {
+ .name = MODULE_NAME,
+ .driver_data = (unsigned long)&rot_drvdata_exynos,
+ },
+ {},
+};
+
+static struct platform_driver rot_driver = {
+ .probe = rot_probe,
+ .remove = rot_remove,
+ .id_table = rot_driver_ids,
+ .driver = {
+ .name = MODULE_NAME,
+ .owner = THIS_MODULE,
+ .pm = &rot_pm_ops,
+ }
+};
+
+module_platform_driver(rot_driver);
+
+MODULE_AUTHOR("Sunyoung, Kang <sy0816.kang@samsung.com>");
+MODULE_AUTHOR("Ayoung, Sim <a.sim@samsung.com>");
+MODULE_DESCRIPTION("Exynos Image Rotator driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/exynos/rotator/rotator-regs.c b/drivers/media/video/exynos/rotator/rotator-regs.c
new file mode 100644
index 0000000..9f983bf
--- /dev/null
+++ b/drivers/media/video/exynos/rotator/rotator-regs.c
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Register interface file for Exynos Rotator driver
+ *
+ * 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.
+*/
+
+#include "rotator.h"
+
+void rot_hwset_irq_frame_done(struct rot_dev *rot, u32 enable)
+{
+ unsigned long cfg = readl(rot->regs + ROTATOR_CONFIG);
+
+ if (enable)
+ cfg |= ROTATOR_CONFIG_IRQ_DONE;
+ else
+ cfg &= ~ROTATOR_CONFIG_IRQ_DONE;
+
+ writel(cfg, rot->regs + ROTATOR_CONFIG);
+}
+
+void rot_hwset_irq_illegal_config(struct rot_dev *rot, u32 enable)
+{
+ unsigned long cfg = readl(rot->regs + ROTATOR_CONFIG);
+
+ if (enable)
+ cfg |= ROTATOR_CONFIG_IRQ_ILLEGAL;
+ else
+ cfg &= ~ROTATOR_CONFIG_IRQ_ILLEGAL;
+
+ writel(cfg, rot->regs + ROTATOR_CONFIG);
+}
+
+int rot_hwset_image_format(struct rot_dev *rot, u32 pixelformat)
+{
+ unsigned long cfg = readl(rot->regs + ROTATOR_CONTROL);
+ cfg &= ~ROTATOR_CONTROL_FMT_MASK;
+
+ switch (pixelformat) {
+ case V4L2_PIX_FMT_YUV420M:
+ cfg |= ROTATOR_CONTROL_FMT_YCBCR420_3P;
+ break;
+ case V4L2_PIX_FMT_NV12M:
+ cfg |= ROTATOR_CONTROL_FMT_YCBCR420_2P;
+ break;
+ case V4L2_PIX_FMT_YUYV:
+ cfg |= ROTATOR_CONTROL_FMT_YCBCR422;
+ break;
+ case V4L2_PIX_FMT_RGB565:
+ cfg |= ROTATOR_CONTROL_FMT_RGB565;
+ break;
+ case V4L2_PIX_FMT_RGB32:
+ cfg |= ROTATOR_CONTROL_FMT_RGB888;
+ break;
+ default:
+ dev_err(rot->dev, "invalid pixelformat type\n");
+ return -EINVAL;
+ }
+ writel(cfg, rot->regs + ROTATOR_CONTROL);
+ return 0;
+}
+
+void rot_hwset_flip(struct rot_dev *rot, u32 direction)
+{
+ unsigned long cfg = readl(rot->regs + ROTATOR_CONTROL);
+ cfg &= ~ROTATOR_CONTROL_FLIP_MASK;
+
+ if (direction == ROT_VFLIP)
+ cfg |= ROTATOR_CONTROL_FLIP_V;
+ else if (direction == ROT_HFLIP)
+ cfg |= ROTATOR_CONTROL_FLIP_H;
+
+ writel(cfg, rot->regs + ROTATOR_CONTROL);
+}
+
+void rot_hwset_rotation(struct rot_dev *rot, int degree)
+{
+ unsigned long cfg = readl(rot->regs + ROTATOR_CONTROL);
+ cfg &= ~ROTATOR_CONTROL_ROT_MASK;
+
+ if (degree == 90)
+ cfg |= ROTATOR_CONTROL_ROT_90;
+ else if (degree == 180)
+ cfg |= ROTATOR_CONTROL_ROT_180;
+ else if (degree == 270)
+ cfg |= ROTATOR_CONTROL_ROT_270;
+
+ writel(cfg, rot->regs + ROTATOR_CONTROL);
+}
+
+void rot_hwset_start(struct rot_dev *rot)
+{
+ unsigned long cfg = readl(rot->regs + ROTATOR_CONTROL);
+
+ cfg |= ROTATOR_CONTROL_START;
+
+ writel(cfg, rot->regs + ROTATOR_CONTROL);
+}
+
+void rot_hwset_src_addr(struct rot_dev *rot, dma_addr_t addr, u32 comp)
+{
+ writel(addr, rot->regs + ROTATOR_SRC_IMG_ADDR(comp));
+}
+
+void rot_hwset_dst_addr(struct rot_dev *rot, dma_addr_t addr, u32 comp)
+{
+ writel(addr, rot->regs + ROTATOR_DST_IMG_ADDR(comp));
+}
+
+void rot_hwset_src_imgsize(struct rot_dev *rot, struct rot_frame *frame)
+{
+ unsigned long cfg;
+
+ cfg = ROTATOR_SRCIMG_YSIZE(frame->pix_mp.height) |
+ ROTATOR_SRCIMG_XSIZE(frame->pix_mp.width);
+
+ writel(cfg, rot->regs + ROTATOR_SRCIMG);
+
+ cfg = ROTATOR_SRCROT_YSIZE(frame->pix_mp.height) |
+ ROTATOR_SRCROT_XSIZE(frame->pix_mp.width);
+
+ writel(cfg, rot->regs + ROTATOR_SRCROT);
+}
+
+void rot_hwset_src_crop(struct rot_dev *rot, struct v4l2_rect *rect)
+{
+ unsigned long cfg;
+
+ cfg = ROTATOR_SRC_Y(rect->top) |
+ ROTATOR_SRC_X(rect->left);
+
+ writel(cfg, rot->regs + ROTATOR_SRC);
+
+ cfg = ROTATOR_SRCROT_YSIZE(rect->height) |
+ ROTATOR_SRCROT_XSIZE(rect->width);
+
+ writel(cfg, rot->regs + ROTATOR_SRCROT);
+}
+
+void rot_hwset_dst_imgsize(struct rot_dev *rot, struct rot_frame *frame)
+{
+ unsigned long cfg;
+
+ cfg = ROTATOR_DSTIMG_YSIZE(frame->pix_mp.height) |
+ ROTATOR_DSTIMG_XSIZE(frame->pix_mp.width);
+
+ writel(cfg, rot->regs + ROTATOR_DSTIMG);
+}
+
+void rot_hwset_dst_crop(struct rot_dev *rot, struct v4l2_rect *rect)
+{
+ unsigned long cfg;
+
+ cfg = ROTATOR_DST_Y(rect->top) |
+ ROTATOR_DST_X(rect->left);
+
+ writel(cfg, rot->regs + ROTATOR_DST);
+}
+
+void rot_hwget_irq_src(struct rot_dev *rot, enum rot_irq_src *irq)
+{
+ unsigned long cfg = readl(rot->regs + ROTATOR_STATUS);
+ cfg = ROTATOR_STATUS_IRQ(cfg);
+
+ if (cfg == 1)
+ *irq = ISR_PEND_DONE;
+ else if (cfg == 2)
+ *irq = ISR_PEND_ILLEGAL;
+}
+
+void rot_hwset_irq_clear(struct rot_dev *rot, enum rot_irq_src *irq)
+{
+ unsigned long cfg = readl(rot->regs + ROTATOR_STATUS);
+ cfg |= ROTATOR_STATUS_IRQ_PENDING((u32)irq);
+
+ writel(cfg, rot->regs + ROTATOR_STATUS);
+}
+
+void rot_hwget_status(struct rot_dev *rot, enum rot_status *state)
+{
+ unsigned long cfg;
+
+ cfg = readl(rot->regs + ROTATOR_STATUS);
+ cfg &= ROTATOR_STATUS_MASK;
+
+ switch (cfg) {
+ case 0:
+ *state = ROT_IDLE;
+ break;
+ case 1:
+ *state = ROT_RESERVED;
+ break;
+ case 2:
+ *state = ROT_RUNNING;
+ break;
+ case 3:
+ *state = ROT_RUNNING_REMAIN;
+ break;
+ };
+}
+
+void rot_dump_registers(struct rot_dev *rot)
+{
+ unsigned int tmp, i;
+
+ rot_dbg("dump rotator registers\n");
+ for (i = 0; i <= ROTATOR_DST; i += 0x4) {
+ tmp = readl(rot->regs + i);
+ rot_dbg("0x%08x: 0x%08x", i, tmp);
+ }
+}
diff --git a/drivers/media/video/exynos/rotator/rotator-regs.h b/drivers/media/video/exynos/rotator/rotator-regs.h
new file mode 100644
index 0000000..a603417
--- /dev/null
+++ b/drivers/media/video/exynos/rotator/rotator-regs.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Register header file for Exynos Rotator driver
+ *
+ * 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.
+*/
+
+/* Configuration */
+#define ROTATOR_CONFIG 0x00
+#define ROTATOR_CONFIG_IRQ_ILLEGAL (1 << 9)
+#define ROTATOR_CONFIG_IRQ_DONE (1 << 8)
+
+/* Image0 Control */
+#define ROTATOR_CONTROL 0x10
+#define ROTATOR_CONTROL_PATTERN_WRITE (1 << 16)
+#define ROTATOR_CONTROL_FMT_YCBCR420_3P (0 << 8)
+#define ROTATOR_CONTROL_FMT_YCBCR420_2P (1 << 8)
+#define ROTATOR_CONTROL_FMT_YCBCR422 (3 << 8)
+#define ROTATOR_CONTROL_FMT_RGB565 (4 << 8)
+#define ROTATOR_CONTROL_FMT_RGB888 (6 << 8)
+#define ROTATOR_CONTROL_FMT_MASK (7 << 8)
+#define ROTATOR_CONTROL_FLIP_V (2 << 6)
+#define ROTATOR_CONTROL_FLIP_H (3 << 6)
+#define ROTATOR_CONTROL_FLIP_MASK (3 << 6)
+#define ROTATOR_CONTROL_ROT_90 (1 << 4)
+#define ROTATOR_CONTROL_ROT_180 (2 << 4)
+#define ROTATOR_CONTROL_ROT_270 (3 << 4)
+#define ROTATOR_CONTROL_ROT_MASK (3 << 4)
+#define ROTATOR_CONTROL_START (1 << 0)
+
+/* Status */
+#define ROTATOR_STATUS 0x20
+#define ROTATOR_STATUS_IRQ_PENDING(x) (1 << (x))
+#define ROTATOR_STATUS_IRQ(x) (((x) >> 8) & 0x3)
+#define ROTATOR_STATUS_MASK (3 << 0)
+
+/* Sourc Image Base Address */
+#define ROTATOR_SRC_IMG_ADDR(n) (0x30 + ((n) << 2))
+
+/* Source Image X,Y Size */
+#define ROTATOR_SRCIMG 0x3c
+#define ROTATOR_SRCIMG_YSIZE(x) ((x) << 16)
+#define ROTATOR_SRCIMG_XSIZE(x) ((x) << 0)
+
+/* Source Image X,Y Coordinates */
+#define ROTATOR_SRC 0x40
+#define ROTATOR_SRC_Y(x) ((x) << 16)
+#define ROTATOR_SRC_X(x) ((x) << 0)
+
+/* Source Image Rotation Size */
+#define ROTATOR_SRCROT 0x44
+#define ROTATOR_SRCROT_YSIZE(x) ((x) << 16)
+#define ROTATOR_SRCROT_XSIZE(x) ((x) << 0)
+
+/* Destination Image Base Address */
+#define ROTATOR_DST_IMG_ADDR(n) (0x50 + ((n) << 2))
+
+/* Destination Image X,Y Size */
+#define ROTATOR_DSTIMG 0x5c
+#define ROTATOR_DSTIMG_YSIZE(x) ((x) << 16)
+#define ROTATOR_DSTIMG_XSIZE(x) ((x) << 0)
+
+/* Destination Image X,Y Coordinates */
+#define ROTATOR_DST 0x60
+#define ROTATOR_DST_Y(x) ((x) << 16)
+#define ROTATOR_DST_X(x) ((x) << 0)
diff --git a/drivers/media/video/exynos/rotator/rotator-vb2.c b/drivers/media/video/exynos/rotator/rotator-vb2.c
new file mode 100644
index 0000000..75cf134
--- /dev/null
+++ b/drivers/media/video/exynos/rotator/rotator-vb2.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Videobuf2 bridge driver file for EXYNOS Image Rotator driver
+ *
+ * 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.
+*/
+
+#include <linux/platform_device.h>
+#include "rotator.h"
+
+#if defined(CONFIG_VIDEOBUF2_ION)
+void *rot_ion_init(struct rot_dev *rot)
+{
+ return vb2_ion_create_context(rot->dev, SZ_1M,
+ VB2ION_CTX_PHCONTIG | VB2ION_CTX_IOMMU | VB2ION_CTX_UNCACHED);
+}
+
+static unsigned long rot_vb2_plane_addr(struct vb2_buffer *vb, u32 plane_no)
+{
+ void *cookie = vb2_plane_cookie(vb, plane_no);
+ dma_addr_t dma_addr = 0;
+
+ WARN_ON(vb2_ion_dma_address(cookie, &dma_addr) != 0);
+
+ return (unsigned long)dma_addr;
+}
+
+const struct rot_vb2 rot_vb2_ion = {
+ .ops = &vb2_ion_memops,
+ .init = rot_ion_init,
+ .cleanup = vb2_ion_destroy_context,
+ .plane_addr = rot_vb2_plane_addr,
+ .resume = vb2_ion_attach_iommu,
+ .suspend = vb2_ion_detach_iommu,
+ .cache_flush = vb2_ion_cache_flush,
+ .set_cacheable = vb2_ion_set_cached,
+};
+#endif
diff --git a/drivers/media/video/exynos/rotator/rotator.h b/drivers/media/video/exynos/rotator/rotator.h
new file mode 100644
index 0000000..60d93e2
--- /dev/null
+++ b/drivers/media/video/exynos/rotator/rotator.h
@@ -0,0 +1,295 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Header file for Exynos Rotator driver
+ *
+ * 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.
+*/
+
+#ifndef ROTATOR__H_
+#define ROTATOR__H_
+
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+#include <linux/videodev2_exynos_media.h>
+#include <linux/io.h>
+#include <media/videobuf2-core.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-mem2mem.h>
+
+#include "rotator-regs.h"
+
+#if defined(CONFIG_VIDEOBUF2_ION)
+#include <media/videobuf2-ion.h>
+#endif
+
+extern int log_level;
+
+#define rot_dbg(fmt, args...) \
+ do { \
+ if (log_level) \
+ printk(KERN_DEBUG "[%s:%d] " \
+ fmt, __func__, __LINE__, ##args); \
+ } while (0)
+
+/* Time to wait for frame done interrupt */
+#define ROT_TIMEOUT (2 * HZ)
+#define ROT_WDT_CNT 5
+#define MODULE_NAME "exynos-rot"
+#define ROT_MAX_DEVS 1
+
+/* Address index */
+#define ROT_ADDR_RGB 0
+#define ROT_ADDR_Y 0
+#define ROT_ADDR_CB 1
+#define ROT_ADDR_CBCR 1
+#define ROT_ADDR_CR 2
+
+/* Rotator flip direction */
+#define ROT_NOFLIP (1 << 0)
+#define ROT_VFLIP (1 << 1)
+#define ROT_HFLIP (1 << 2)
+
+/* Rotator hardware device state */
+#define DEV_RUN (1 << 0)
+#define DEV_SUSPEND (1 << 1)
+
+/* Rotator m2m context state */
+#define CTX_PARAMS (1 << 0)
+#define CTX_STREAMING (1 << 1)
+#define CTX_RUN (1 << 2)
+#define CTX_ABORT (1 << 3)
+#define CTX_SRC (1 << 4)
+#define CTX_DST (1 << 5)
+
+enum rot_irq_src {
+ ISR_PEND_DONE = 8,
+ ISR_PEND_ILLEGAL = 9,
+};
+
+enum rot_status {
+ ROT_IDLE,
+ ROT_RESERVED,
+ ROT_RUNNING,
+ ROT_RUNNING_REMAIN,
+};
+
+/*
+ * struct exynos_rot_size_limit - Rotator variant size information
+ *
+ * @min_x: minimum pixel x size
+ * @min_y: minimum pixel y size
+ * @max_x: maximum pixel x size
+ * @max_y: maximum pixel y size
+ */
+struct exynos_rot_size_limit {
+ u32 min_x;
+ u32 min_y;
+ u32 max_x;
+ u32 max_y;
+ u32 align;
+};
+
+struct exynos_rot_variant {
+ struct exynos_rot_size_limit limit_rgb565;
+ struct exynos_rot_size_limit limit_rgb888;
+ struct exynos_rot_size_limit limit_yuv422;
+ struct exynos_rot_size_limit limit_yuv420_2p;
+ struct exynos_rot_size_limit limit_yuv420_3p;
+};
+
+/*
+ * struct exynos_rot_driverdata - per device type driver data for init time.
+ *
+ * @variant: the variant information for this driver.
+ * @nr_dev: number of devices available in SoC
+ */
+struct exynos_rot_driverdata {
+ struct exynos_rot_variant *variant[ROT_MAX_DEVS];
+ int nr_dev;
+};
+
+/**
+ * struct rot_fmt - the driver's internal color format data
+ * @name: format description
+ * @pixelformat: the fourcc code for this format, 0 if not applicable
+ * @num_planes: number of physically non-contiguous data planes
+ * @num_comp: number of color components(ex. RGB, Y, Cb, Cr)
+ * @bitperpixel: bits per pixel
+ */
+struct rot_fmt {
+ char *name;
+ u32 pixelformat;
+ u16 num_planes;
+ u16 num_comp;
+ u32 bitperpixel[VIDEO_MAX_PLANES];
+};
+
+struct rot_addr {
+ dma_addr_t y;
+ dma_addr_t cb;
+ dma_addr_t cr;
+};
+
+/*
+ * struct rot_frame - source/target frame properties
+ * @fmt: buffer format(like virtual screen)
+ * @crop: image size / position
+ * @addr: buffer start address(access using ROT_ADDR_XXX)
+ * @bytesused: image size in bytes (w x h x bpp)
+ */
+struct rot_frame {
+ struct rot_fmt *rot_fmt;
+ struct v4l2_pix_format_mplane pix_mp;
+ struct v4l2_rect crop;
+ struct rot_addr addr;
+ unsigned long bytesused[VIDEO_MAX_PLANES];
+};
+
+/*
+ * struct rot_m2m_device - v4l2 memory-to-memory device data
+ * @v4l2_dev: v4l2 device
+ * @vfd: the video device node
+ * @m2m_dev: v4l2 memory-to-memory device data
+ * @in_use: the open count
+ */
+struct rot_m2m_device {
+ struct v4l2_device v4l2_dev;
+ struct video_device *vfd;
+ struct v4l2_m2m_dev *m2m_dev;
+ atomic_t in_use;
+};
+
+struct rot_wdt {
+ struct timer_list timer;
+ atomic_t cnt;
+};
+
+struct rot_ctx;
+struct rot_vb2;
+
+/*
+ * struct rot_dev - the abstraction for Rotator device
+ * @dev: pointer to the Rotator device
+ * @pdata: pointer to the device platform data
+ * @variant: the IP variant information
+ * @m2m: memory-to-memory V4L2 device information
+ * @id: Rotator device index (0..ROT_MAX_DEVS)
+ * @clock: clock required for Rotator operation
+ * @regs: the mapped hardware registers
+ * @wait: interrupt handler waitqueue
+ * @ws: work struct
+ * @state: device state flags
+ * @alloc_ctx: videobuf2 memory allocator context
+ * @rot_vb2: videobuf2 memory allocator callbacks
+ * @slock: the spinlock protecting this data structure
+ * @lock: the mutex protecting this data structure
+ * @wdt: watchdog timer information
+ */
+struct rot_dev {
+ struct device *dev;
+ struct exynos_platform_rot *pdata;
+ struct exynos_rot_variant *variant;
+ struct rot_m2m_device m2m;
+ int id;
+ struct clk *clock;
+ void __iomem *regs;
+ wait_queue_head_t wait;
+ unsigned long state;
+ struct vb2_alloc_ctx *alloc_ctx;
+ const struct rot_vb2 *vb2;
+ spinlock_t slock;
+ struct mutex lock;
+ struct rot_wdt wdt;
+};
+
+/*
+ * rot_ctx - the abstration for Rotator open context
+ * @rot_dev: the Rotator device this context applies to
+ * @m2m_ctx: memory-to-memory device context
+ * @frame: source frame properties
+ * @ctrl_handler: v4l2 controls handler
+ * @fh: v4l2 file handle
+ * @rotation: image clockwise rotation in degrees
+ * @flip: image flip mode
+ * @state: context state flags
+ * @slock: spinlock protecting this data structure
+ */
+struct rot_ctx {
+ struct rot_dev *rot_dev;
+ struct v4l2_m2m_ctx *m2m_ctx;
+ struct rot_frame s_frame;
+ struct rot_frame d_frame;
+ struct v4l2_ctrl_handler ctrl_handler;
+ struct v4l2_fh fh;
+ int rotation;
+ u32 flip;
+ unsigned long flags;
+ spinlock_t slock;
+ bool cacheable;
+};
+
+struct rot_vb2 {
+ const struct vb2_mem_ops *ops;
+ void *(*init)(struct rot_dev *rot);
+ void (*cleanup)(void *alloc_ctx);
+
+ unsigned long (*plane_addr)(struct vb2_buffer *vb, u32 plane_no);
+
+ int (*resume)(void *alloc_ctx);
+ void (*suspend)(void *alloc_ctx);
+
+ int (*cache_flush)(struct vb2_buffer *vb, u32 num_planes);
+ void (*set_cacheable)(void *alloc_ctx, bool cacheable);
+};
+
+static inline struct rot_frame *ctx_get_frame(struct rot_ctx *ctx,
+ enum v4l2_buf_type type)
+{
+ struct rot_frame *frame;
+
+ if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
+ if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ frame = &ctx->s_frame;
+ else
+ frame = &ctx->d_frame;
+ } else {
+ dev_err(ctx->rot_dev->dev,
+ "Wrong V4L2 buffer type %d\n", type);
+ return ERR_PTR(-EINVAL);
+ }
+
+ return frame;
+}
+
+#define fh_to_rot_ctx(__fh) container_of(__fh, struct rot_ctx, fh)
+
+void rot_hwset_irq_frame_done(struct rot_dev *rot, u32 enable);
+void rot_hwset_irq_illegal_config(struct rot_dev *rot, u32 enable);
+int rot_hwset_image_format(struct rot_dev *rot, u32 pixelformat);
+void rot_hwset_flip(struct rot_dev *rot, u32 direction);
+void rot_hwset_rotation(struct rot_dev *rot, int degree);
+void rot_hwset_start(struct rot_dev *rot);
+void rot_hwset_src_addr(struct rot_dev *rot, dma_addr_t addr, u32 comp);
+void rot_hwset_dst_addr(struct rot_dev *rot, dma_addr_t addr, u32 comp);
+void rot_hwset_src_imgsize(struct rot_dev *rot, struct rot_frame *frame);
+void rot_hwset_src_crop(struct rot_dev *rot, struct v4l2_rect *rect);
+void rot_hwset_dst_imgsize(struct rot_dev *rot, struct rot_frame *frame);
+void rot_hwset_dst_crop(struct rot_dev *rot, struct v4l2_rect *rect);
+void rot_hwget_irq_src(struct rot_dev *rot, enum rot_irq_src *irq);
+void rot_hwset_irq_clear(struct rot_dev *rot, enum rot_irq_src *irq);
+void rot_hwget_status(struct rot_dev *rot, enum rot_status *state);
+void rot_dump_registers(struct rot_dev *rot);
+
+#if defined(CONFIG_VIDEOBUF2_ION)
+extern const struct rot_vb2 rot_vb2_ion;
+#endif
+
+#endif /* ROTATOR__H_ */
diff --git a/drivers/media/video/exynos/tv/Kconfig b/drivers/media/video/exynos/tv/Kconfig
new file mode 100644
index 0000000..aed965b
--- /dev/null
+++ b/drivers/media/video/exynos/tv/Kconfig
@@ -0,0 +1,122 @@
+# drivers/media/video/s5p-tv/Kconfig
+#
+# Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+# http://www.samsung.com/
+# Tomasz Stanislawski <t.stanislaws@samsung.com>
+#
+# Licensed under GPL
+
+comment "Exynos TV support"
+
+config VIDEO_EXYNOS_TV
+ bool "Samsung TV driver for S5P platform (experimental)"
+ depends on PLAT_S5P
+ depends on EXPERIMENTAL
+ select MEDIA_EXYNOS
+ select VIDEO_EXYNOS_HDMI
+ select VIDEO_EXYNOS_MIXER
+ default n
+ ---help---
+ Say Y here to enable selecting the TV output devices for
+ Samsung S5P platform.
+
+if VIDEO_EXYNOS_TV
+
+config VIDEO_EXYNOS_HDMI
+ tristate "Samsung HDMI Driver"
+ depends on VIDEO_V4L2
+ depends on VIDEO_EXYNOS_TV
+ depends on SWITCH
+ select VIDEO_EXYNOS_HDMIPHY
+ help
+ Say Y here if you want support for the HDMI output
+ interface in S5P Samsung SoC. The driver can be compiled
+ as module. It is an auxiliary driver, that exposes a V4L2
+ subdev for use by other drivers. This driver requires
+ hdmiphy driver to work correctly.
+
+config VIDEO_EXYNOS_HDMI_AUDIO_I2S
+ bool "Enable HDMI audio using I2S path"
+ depends on VIDEO_EXYNOS_HDMI
+ depends on SND_SOC_SAMSUNG_SMDK_WM8994
+ default y
+ help
+ Enables HDMI audio through I2S path.
+
+config VIDEO_EXYNOS_HDMI_AUDIO_SPDIF
+ bool "Enable HDMI audio using SPDIF path"
+ depends on VIDEO_EXYNOS_HDMI
+ depends on SND_SOC_SAMSUNG_SMDK_SPDIF
+ default n
+ help
+ Enables HDMI audio through SPDIF path.
+
+config VIDEO_EXYNOS_HDCP
+ bool "Enable HDCP"
+ depends on VIDEO_EXYNOS_HDMI
+ depends on I2C
+ default n
+ help
+ Enables HDCP feature. However if you want to use HDCP,
+ device private key must be e-fused in SoC.
+
+config VIDEO_EXYNOS_HDMI_DEBUG
+ bool "Enable debug for HDMI Driver"
+ depends on VIDEO_EXYNOS_HDMI
+ default n
+ help
+ Enables debugging for HDMI driver.
+
+config VIDEO_EXYNOS_HDMIPHY
+ tristate "Samsung HDMIPHY Driver"
+ depends on VIDEO_DEV && VIDEO_V4L2 && I2C
+ depends on VIDEO_EXYNOS_TV
+ help
+ Say Y here if you want support for the physical HDMI
+ interface in S5P Samsung SoC. The driver can be compiled
+ as module. It is an I2C driver, that exposes a V4L2
+ subdev for use by other drivers.
+
+config VIDEO_EXYNOS_SDO
+ tristate "Samsung Analog TV Driver"
+ depends on VIDEO_DEV && VIDEO_V4L2
+ depends on VIDEO_EXYNOS_TV
+ depends on CPU_EXYNOS4210
+ help
+ Say Y here if you want support for the analog TV output
+ interface in S5P Samsung SoC. The driver can be compiled
+ as module. It is an auxiliary driver, that exposes a V4L2
+ subdev for use by other drivers. This driver requires
+ hdmiphy driver to work correctly.
+
+config VIDEO_EXYNOS_MIXER
+ tristate "Samsung Mixer and Video Processor Driver"
+ depends on VIDEO_DEV && VIDEO_V4L2
+ depends on VIDEO_EXYNOS_TV
+ select VIDEOBUF2_DMA_CONTIG
+ help
+ Say Y here if you want support for the Mixer in Samsung S5P SoCs.
+ This device produce image data to one of output interfaces.
+
+config VIDEO_EXYNOS_HDMI_CEC
+ tristate "Samsung HDMI CEC Driver"
+ depends on VIDEO_DEV && VIDEO_V4L2 && I2C
+ depends on VIDEO_EXYNOS_TV
+ help
+ Say Y here if you want support for the HDMI CEC
+ interface in S5P Samsung SoC. The driver can be compiled
+ as module.
+
+config VIDEO_SAMSUNG_MEMSIZE_TV
+ int "Memory size in kbytes for TV"
+ depends on VIDEO_EXYNOS_MIXER && VIDEOBUF2_CMA_PHYS
+ default "16200"
+
+config VIDEO_EXYNOS_MIXER_DEBUG
+ bool "Enable debug for Mixer Driver"
+ depends on VIDEO_EXYNOS_MIXER
+ default n
+ help
+ Enables debugging for Mixer driver.
+
+endif # VIDEO_EXYNOS_TV
diff --git a/drivers/media/video/exynos/tv/Makefile b/drivers/media/video/exynos/tv/Makefile
new file mode 100644
index 0000000..29cef3f
--- /dev/null
+++ b/drivers/media/video/exynos/tv/Makefile
@@ -0,0 +1,31 @@
+# drivers/media/video/samsung/tvout/Makefile
+#
+# Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+# http://www.samsung.com/
+# Tomasz Stanislawski <t.stanislaws@samsung.com>
+#
+# Licensed under GPL
+obj-$(CONFIG_VIDEO_EXYNOS_HDMIPHY) += s5p-hdmiphy.o
+s5p-hdmiphy-y += hdmiphy_drv.o
+obj-$(CONFIG_VIDEO_EXYNOS_HDMI) += s5p-hdmi.o
+s5p-hdmi-y += hdcp_drv.o hdmi_drv.o
+obj-$(CONFIG_VIDEO_EXYNOS_SDO) += s5p-sdo.o
+s5p-sdo-y += sdo_drv.o
+obj-$(CONFIG_VIDEO_EXYNOS_MIXER) += s5p-mixer.o
+s5p-mixer-y += mixer_vb2.o mixer_drv.o mixer_video.o mixer_reg.o mixer_grp_layer.o
+obj-$(CONFIG_VIDEO_EXYNOS_HDMI_CEC) += s5p-hdmi_cec.o
+s5p-hdmi_cec-y += hdmi_cec.o hdmi_cec_ctrl.o
+
+ifeq ($(CONFIG_ARCH_EXYNOS4), y)
+ s5p-mixer-y += mixer_vp_layer.o
+else
+ s5p-mixer-y += mixer_video_layer.o
+endif
+
+ifeq ($(CONFIG_VIDEO_EXYNOS_HDMI),y)
+ ifeq ($(CONFIG_CPU_EXYNOS4210), y)
+ s5p-hdmi-y += hdmi_reg_4210.o hdmiphy_conf_4210.o
+ else
+ s5p-hdmi-y += hdmi_reg_5250.o hdmiphy_conf_5250.o
+ endif
+endif
diff --git a/drivers/media/video/exynos/tv/cec.h b/drivers/media/video/exynos/tv/cec.h
new file mode 100644
index 0000000..f33a619
--- /dev/null
+++ b/drivers/media/video/exynos/tv/cec.h
@@ -0,0 +1,84 @@
+/* linux/drivers/media/video/samsung/tvout/hw_if/hw_if.h
+ *
+ * Copyright (c) 2010 Samsung Electronics
+ * http://www.samsung.com/
+ *
+ * Header file for interface of Samsung TVOUT-related hardware
+ *
+ * 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.
+ */
+
+#ifndef _SAMSUNG_TVOUT_CEC_H_
+#define _SAMSUNG_TVOUT_CEC_H_ __FILE__
+
+/*****************************************************************************
+ * This file includes declarations for external functions of
+ * Samsung TVOUT-related hardware. So only external functions
+ * to be used by higher layer must exist in this file.
+ *
+ * Higher layer must use only the declarations included in this file.
+ ****************************************************************************/
+
+#define to_tvout_plat(d) (to_platform_device(d)->dev.platform_data)
+
+#ifndef tvout_dbg
+#ifdef CONFIG_TV_DEBUG
+#define tvout_dbg(fmt, ...) \
+ printk(KERN_INFO "[%s] %s(): " fmt, \
+ DRV_NAME, __func__, ##__VA_ARGS__)
+#else
+#define tvout_dbg(fmt, ...)
+#endif
+#endif
+
+enum s5p_tvout_endian {
+ TVOUT_LITTLE_ENDIAN = 0,
+ TVOUT_BIG_ENDIAN = 1
+};
+
+enum cec_state {
+ STATE_RX,
+ STATE_TX,
+ STATE_DONE,
+ STATE_ERROR
+};
+
+struct cec_rx_struct {
+ spinlock_t lock;
+ wait_queue_head_t waitq;
+ atomic_t state;
+ u8 *buffer;
+ unsigned int size;
+};
+
+struct cec_tx_struct {
+ wait_queue_head_t waitq;
+ atomic_t state;
+};
+
+extern struct cec_rx_struct cec_rx_struct;
+extern struct cec_tx_struct cec_tx_struct;
+
+void s5p_cec_set_divider(void);
+void s5p_cec_enable_rx(void);
+void s5p_cec_mask_rx_interrupts(void);
+void s5p_cec_unmask_rx_interrupts(void);
+void s5p_cec_mask_tx_interrupts(void);
+void s5p_cec_unmask_tx_interrupts(void);
+void s5p_cec_reset(void);
+void s5p_cec_tx_reset(void);
+void s5p_cec_rx_reset(void);
+void s5p_cec_threshold(void);
+void s5p_cec_set_tx_state(enum cec_state state);
+void s5p_cec_set_rx_state(enum cec_state state);
+void s5p_cec_copy_packet(char *data, size_t count);
+void s5p_cec_set_addr(u32 addr);
+u32 s5p_cec_get_status(void);
+void s5p_clr_pending_tx(void);
+void s5p_clr_pending_rx(void);
+void s5p_cec_get_rx_buf(u32 size, u8 *buffer);
+int __init s5p_cec_mem_probe(struct platform_device *pdev);
+
+#endif /* _SAMSUNG_TVOUT_CEC_H_ */
diff --git a/drivers/media/video/exynos/tv/hdcp_drv.c b/drivers/media/video/exynos/tv/hdcp_drv.c
new file mode 100644
index 0000000..00cd209
--- /dev/null
+++ b/drivers/media/video/exynos/tv/hdcp_drv.c
@@ -0,0 +1,996 @@
+/* linux/drivers/media/video/exynos/tv/hdcp_drv.c
+ *
+ * Copyright (c) 2011 Samsung Electronics
+ * http://www.samsung.com/
+ *
+ * HDCP function for Samsung TV driver
+ *
+ * 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.
+ */
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/workqueue.h>
+#include <linux/export.h>
+#include <linux/module.h>
+
+#include "hdmi.h"
+#include "regs-hdmi-5250.h"
+
+#define AN_SIZE 8
+#define AKSV_SIZE 5
+#define BKSV_SIZE 5
+#define MAX_KEY_SIZE 16
+
+#define BKSV_RETRY_CNT 14
+#define BKSV_DELAY 100
+
+#define DDC_RETRY_CNT 400000
+#define DDC_DELAY 25
+
+#define KEY_LOAD_RETRY_CNT 1000
+#define ENCRYPT_CHECK_CNT 10
+
+#define KSV_FIFO_RETRY_CNT 50
+#define KSV_FIFO_CHK_DELAY 100 /* ms */
+#define KSV_LIST_RETRY_CNT 10000
+
+#define BCAPS_SIZE 1
+#define BSTATUS_SIZE 2
+#define SHA_1_HASH_SIZE 20
+#define HDCP_MAX_DEVS 128
+#define HDCP_KSV_SIZE 5
+
+/* offset of HDCP port */
+#define HDCP_BKSV 0x00
+#define HDCP_RI 0x08
+#define HDCP_AKSV 0x10
+#define HDCP_AN 0x18
+#define HDCP_SHA1 0x20
+#define HDCP_BCAPS 0x40
+#define HDCP_BSTATUS 0x41
+#define HDCP_KSVFIFO 0x43
+
+#define KSV_FIFO_READY (0x1 << 5)
+
+#define MAX_CASCADE_EXCEEDED_ERROR (-2)
+#define MAX_DEVS_EXCEEDED_ERROR (-3)
+#define REPEATER_ILLEGAL_DEVICE_ERROR (-4)
+#define REPEATER_TIMEOUT_ERROR (-5)
+
+#define MAX_CASCADE_EXCEEDED (0x1 << 3)
+#define MAX_DEVS_EXCEEDED (0x1 << 7)
+
+struct i2c_client *hdcp_client;
+
+int hdcp_i2c_read(struct hdmi_device *hdev, u8 offset, int bytes, u8 *buf)
+{
+ struct device *dev = hdev->dev;
+ struct i2c_client *i2c = hdcp_client;
+ int ret, cnt = 0;
+
+ struct i2c_msg msg[] = {
+ [0] = {
+ .addr = i2c->addr,
+ .flags = 0,
+ .len = 1,
+ .buf = &offset
+ },
+ [1] = {
+ .addr = i2c->addr,
+ .flags = I2C_M_RD,
+ .len = bytes,
+ .buf = buf
+ }
+ };
+
+ do {
+ if (!is_hdmi_streaming(hdev))
+ goto ddc_read_err;
+
+ ret = i2c_transfer(i2c->adapter, msg, 2);
+
+ if (ret < 0 || ret != 2)
+ dev_dbg(dev, "%s: can't read data, retry %d\n",
+ __func__, cnt);
+ else
+ break;
+
+ if (hdev->hdcp_info.auth_status == FIRST_AUTHENTICATION_DONE
+ || hdev->hdcp_info.auth_status
+ == SECOND_AUTHENTICATION_DONE)
+ goto ddc_read_err;
+
+ msleep(DDC_DELAY);
+ cnt++;
+ } while (cnt < DDC_RETRY_CNT);
+
+ if (cnt == DDC_RETRY_CNT)
+ goto ddc_read_err;
+
+ dev_dbg(dev, "%s: read data ok\n", __func__);
+
+ return 0;
+
+ddc_read_err:
+ dev_err(dev, "%s: can't read data, timeout\n", __func__);
+ return -ETIME;
+}
+
+int hdcp_i2c_write(struct hdmi_device *hdev, u8 offset, int bytes, u8 *buf)
+{
+ struct device *dev = hdev->dev;
+ struct i2c_client *i2c = hdcp_client;
+ u8 msg[bytes + 1];
+ int ret, cnt = 0;
+
+ msg[0] = offset;
+ memcpy(&msg[1], buf, bytes);
+
+ do {
+ if (!is_hdmi_streaming(hdev))
+ goto ddc_write_err;
+
+ ret = i2c_master_send(i2c, msg, bytes + 1);
+
+ if (ret < 0 || ret < bytes + 1)
+ dev_dbg(dev, "%s: can't write data, retry %d\n",
+ __func__, cnt);
+ else
+ break;
+
+ msleep(DDC_DELAY);
+ cnt++;
+ } while (cnt < DDC_RETRY_CNT);
+
+ if (cnt == DDC_RETRY_CNT)
+ goto ddc_write_err;
+
+ dev_dbg(dev, "%s: write data ok\n", __func__);
+ return 0;
+
+ddc_write_err:
+ dev_err(dev, "%s: can't write data, timeout\n", __func__);
+ return -ETIME;
+}
+
+static int __devinit hdcp_probe(struct i2c_client *client,
+ const struct i2c_device_id *dev_id)
+{
+ int ret = 0;
+
+ hdcp_client = client;
+
+ dev_info(&client->adapter->dev, "attached exynos hdcp "
+ "into i2c adapter successfully\n");
+
+ return ret;
+}
+
+static int hdcp_remove(struct i2c_client *client)
+{
+ dev_info(&client->adapter->dev, "detached exynos hdcp "
+ "from i2c adapter successfully\n");
+
+ return 0;
+}
+
+static int hdcp_suspend(struct i2c_client *cl, pm_message_t mesg)
+{
+ return 0;
+};
+
+static int hdcp_resume(struct i2c_client *cl)
+{
+ return 0;
+};
+
+static struct i2c_device_id hdcp_idtable[] = {
+ {"exynos_hdcp", 0},
+};
+MODULE_DEVICE_TABLE(i2c, hdcp_idtable);
+
+static struct i2c_driver hdcp_driver = {
+ .driver = {
+ .name = "exynos_hdcp",
+ .owner = THIS_MODULE,
+ },
+ .id_table = hdcp_idtable,
+ .probe = hdcp_probe,
+ .remove = __devexit_p(hdcp_remove),
+ .suspend = hdcp_suspend,
+ .resume = hdcp_resume,
+};
+
+static int __init hdcp_init(void)
+{
+ return i2c_add_driver(&hdcp_driver);
+}
+
+static void __exit hdcp_exit(void)
+{
+ i2c_del_driver(&hdcp_driver);
+}
+
+module_init(hdcp_init);
+module_exit(hdcp_exit);
+
+/* internal functions of HDCP */
+static void hdcp_encryption(struct hdmi_device *hdev, bool on)
+{
+ if (on)
+ hdmi_write_mask(hdev, HDMI_ENC_EN, ~0, HDMI_HDCP_ENC_ENABLE);
+ else
+ hdmi_write_mask(hdev, HDMI_ENC_EN, 0, HDMI_HDCP_ENC_ENABLE);
+
+ hdmi_reg_mute(hdev, !on);
+}
+
+static int hdcp_write_key(struct hdmi_device *hdev, int size,
+ int reg, int offset)
+{
+ struct device *dev = hdev->dev;
+ u8 buf[MAX_KEY_SIZE];
+ int cnt, zero = 0;
+ int i;
+
+ memset(buf, 0, sizeof(buf));
+ hdmi_read_bytes(hdev, reg, buf, size);
+
+ for (cnt = 0; cnt < size; cnt++)
+ if (buf[cnt] == 0)
+ zero++;
+
+ if (zero == size) {
+ dev_dbg(dev, "%s: %s is null\n", __func__,
+ offset == HDCP_AN ? "An" : "Aksv");
+ goto write_key_err;
+ }
+
+ if (hdcp_i2c_write(hdev, offset, size, buf) < 0)
+ goto write_key_err;
+
+ for (i = 1; i < size + 1; i++)
+ dev_dbg(dev, "%s: %s[%d] : 0x%02x\n", __func__,
+ offset == HDCP_AN ? "An" : "Aksv", i, buf[i]);
+
+ return 0;
+
+write_key_err:
+ dev_dbg(dev, "%s: write %s is failed\n", __func__,
+ offset == HDCP_AN ? "An" : "Aksv");
+ return -1;
+}
+
+static int hdcp_read_bcaps(struct hdmi_device *hdev)
+{
+ struct device *dev = hdev->dev;
+ u8 bcaps = 0;
+
+ if (hdcp_i2c_read(hdev, HDCP_BCAPS, BCAPS_SIZE, &bcaps) < 0)
+ goto bcaps_read_err;
+
+ if (!is_hdmi_streaming(hdev))
+ goto bcaps_read_err;
+
+ hdmi_writeb(hdev, HDMI_HDCP_BCAPS, bcaps);
+
+ if (bcaps & HDMI_HDCP_BCAPS_REPEATER)
+ hdev->hdcp_info.is_repeater = 1;
+ else
+ hdev->hdcp_info.is_repeater = 0;
+
+ dev_dbg(dev, "%s: device is %s\n", __func__,
+ hdev->hdcp_info.is_repeater ? "REPEAT" : "SINK");
+ dev_dbg(dev, "%s: [i2c] bcaps : 0x%02x\n", __func__, bcaps);
+
+ return 0;
+
+bcaps_read_err:
+ dev_err(dev, "can't read bcaps : timeout\n");
+ return -ETIME;
+}
+
+static int hdcp_read_bksv(struct hdmi_device *hdev)
+{
+ struct device *dev = hdev->dev;
+ u8 bksv[BKSV_SIZE];
+ int i, j;
+ u32 one = 0, zero = 0, result = 0;
+ u32 cnt = 0;
+
+ memset(bksv, 0, sizeof(bksv));
+
+ do {
+ if (hdcp_i2c_read(hdev, HDCP_BKSV, BKSV_SIZE, bksv) < 0)
+ goto bksv_read_err;
+
+ for (i = 0; i < BKSV_SIZE; i++)
+ dev_dbg(dev, "%s: i2c read : bksv[%d]: 0x%x\n",
+ __func__, i, bksv[i]);
+
+ for (i = 0; i < BKSV_SIZE; i++) {
+
+ for (j = 0; j < 8; j++) {
+ result = bksv[i] & (0x1 << j);
+
+ if (result == 0)
+ zero++;
+ else
+ one++;
+ }
+
+ }
+
+ if (!is_hdmi_streaming(hdev))
+ goto bksv_read_err;
+
+ if ((zero == 20) && (one == 20)) {
+ hdmi_write_bytes(hdev, HDMI_HDCP_BKSV_(0),
+ bksv, BKSV_SIZE);
+ break;
+ }
+ dev_dbg(dev, "%s: invalid bksv, retry : %d\n", __func__, cnt);
+
+ msleep(BKSV_DELAY);
+ cnt++;
+ } while (cnt < BKSV_RETRY_CNT);
+
+ if (cnt == BKSV_RETRY_CNT)
+ goto bksv_read_err;
+
+ dev_dbg(dev, "%s: bksv read OK, retry : %d\n", __func__, cnt);
+ return 0;
+
+bksv_read_err:
+ dev_err(dev, "%s: can't read bksv : timeout\n", __func__);
+ return -ETIME;
+}
+
+static int hdcp_read_ri(struct hdmi_device *hdev)
+{
+ struct device *dev = hdev->dev;
+ u8 ri[2] = {0, 0};
+ u8 rj[2] = {0, 0};
+
+
+ ri[0] = hdmi_readb(hdev, HDMI_HDCP_RI_0);
+ ri[1] = hdmi_readb(hdev, HDMI_HDCP_RI_1);
+
+ if (hdcp_i2c_read(hdev, HDCP_RI, 2, rj) < 0)
+ goto compare_err;
+
+ dev_dbg(dev, "%s: Rx -> rj[0]: 0x%02x, rj[1]: 0x%02x\n", __func__,
+ rj[0], rj[1]);
+ dev_dbg(dev, "%s: Tx -> ri[0]: 0x%02x, ri[1]: 0x%02x\n", __func__,
+ ri[0], ri[1]);
+
+ if ((ri[0] == rj[0]) && (ri[1] == rj[1]) && (ri[0] | ri[1]))
+ hdmi_writeb(hdev, HDMI_HDCP_CHECK_RESULT,
+ HDMI_HDCP_RI_MATCH_RESULT_Y);
+ else {
+ hdmi_writeb(hdev, HDMI_HDCP_CHECK_RESULT,
+ HDMI_HDCP_RI_MATCH_RESULT_N);
+ goto compare_err;
+ }
+
+ memset(ri, 0, sizeof(ri));
+ memset(rj, 0, sizeof(rj));
+
+ dev_dbg(dev, "%s: ri and ri' are matched\n", __func__);
+
+ return 0;
+
+compare_err:
+ hdev->hdcp_info.event = HDCP_EVENT_STOP;
+ hdev->hdcp_info.auth_status = NOT_AUTHENTICATED;
+ dev_err(dev, "%s: ri and ri' are mismatched\n", __func__);
+ msleep(10);
+ return -1;
+}
+
+static void hdcp_sw_reset(struct hdmi_device *hdev)
+{
+ u8 val;
+
+ val = hdmi_get_int_mask(hdev);
+
+ hdmi_set_int_mask(hdev, HDMI_INTC_EN_HPD_PLUG, 0);
+ hdmi_set_int_mask(hdev, HDMI_INTC_EN_HPD_UNPLUG, 0);
+
+ hdmi_sw_hpd_enable(hdev, 1);
+ hdmi_sw_hpd_plug(hdev, 0);
+ hdmi_sw_hpd_plug(hdev, 1);
+ hdmi_sw_hpd_enable(hdev, 0);
+
+ if (val & HDMI_INTC_EN_HPD_PLUG)
+ hdmi_set_int_mask(hdev, HDMI_INTC_EN_HPD_PLUG, 1);
+ if (val & HDMI_INTC_EN_HPD_UNPLUG)
+ hdmi_set_int_mask(hdev, HDMI_INTC_EN_HPD_UNPLUG, 1);
+}
+
+static int hdcp_reset_auth(struct hdmi_device *hdev)
+{
+ struct device *dev = hdev->dev;
+ u8 val;
+ unsigned long spin_flags;
+
+ if (!is_hdmi_streaming(hdev))
+ return -ENODEV;
+
+ spin_lock_irqsave(&hdev->hdcp_info.reset_lock, spin_flags);
+
+ hdev->hdcp_info.event = HDCP_EVENT_STOP;
+ hdev->hdcp_info.auth_status = NOT_AUTHENTICATED;
+
+ hdmi_write(hdev, HDMI_HDCP_CTRL1, 0x0);
+ hdmi_write(hdev, HDMI_HDCP_CTRL2, 0x0);
+ hdmi_reg_mute(hdev, 1);
+
+ hdcp_encryption(hdev, 0);
+
+ dev_dbg(dev, "%s: reset authentication\n", __func__);
+
+ val = HDMI_UPDATE_RI_INT_EN | HDMI_WRITE_INT_EN |
+ HDMI_WATCHDOG_INT_EN | HDMI_WTFORACTIVERX_INT_EN;
+ hdmi_write_mask(hdev, HDMI_STATUS_EN, 0, val);
+
+ hdmi_writeb(hdev, HDMI_HDCP_CHECK_RESULT, HDMI_HDCP_CLR_ALL_RESULTS);
+
+ /* need some delay (at least 1 frame) */
+ mdelay(16);
+
+ hdcp_sw_reset(hdev);
+
+ val = HDMI_UPDATE_RI_INT_EN | HDMI_WRITE_INT_EN |
+ HDMI_WATCHDOG_INT_EN | HDMI_WTFORACTIVERX_INT_EN;
+ hdmi_write_mask(hdev, HDMI_STATUS_EN, ~0, val);
+ hdmi_write_mask(hdev, HDMI_HDCP_CTRL1, ~0, HDMI_HDCP_CP_DESIRED_EN);
+ spin_unlock_irqrestore(&hdev->hdcp_info.reset_lock, spin_flags);
+
+ return 0;
+}
+
+static int hdcp_loadkey(struct hdmi_device *hdev)
+{
+ struct device *dev = hdev->dev;
+ u8 val;
+ int cnt = 0;
+
+ hdmi_write_mask(hdev, HDMI_EFUSE_CTRL, ~0,
+ HDMI_EFUSE_CTRL_HDCP_KEY_READ);
+
+ do {
+ val = hdmi_readb(hdev, HDMI_EFUSE_STATUS);
+ if (val & HDMI_EFUSE_ECC_DONE)
+ break;
+ cnt++;
+ mdelay(1);
+ } while (cnt < KEY_LOAD_RETRY_CNT);
+
+ if (cnt == KEY_LOAD_RETRY_CNT)
+ goto key_load_err;
+
+ val = hdmi_readb(hdev, HDMI_EFUSE_STATUS);
+
+ if (val & HDMI_EFUSE_ECC_FAIL)
+ goto key_load_err;
+
+ dev_dbg(dev, "%s: load key is ok\n", __func__);
+ return 0;
+
+key_load_err:
+ dev_err(dev, "%s: can't load key\n", __func__);
+ return -1;
+}
+
+static int hdmi_start_encryption(struct hdmi_device *hdev)
+{
+ struct device *dev = hdev->dev;
+ u8 val;
+ u32 cnt = 0;
+
+ do {
+ val = hdmi_readb(hdev, HDMI_STATUS);
+
+ if (val & HDMI_AUTHEN_ACK_AUTH) {
+ hdcp_encryption(hdev, 1);
+ break;
+ }
+
+ mdelay(1);
+
+ cnt++;
+ } while (cnt < ENCRYPT_CHECK_CNT);
+
+ if (cnt == ENCRYPT_CHECK_CNT)
+ goto encrypt_err;
+
+
+ dev_dbg(dev, "%s: encryption is start\n", __func__);
+ return 0;
+
+encrypt_err:
+ hdcp_encryption(hdev, 0);
+ dev_err(dev, "%s: encryption is failed\n", __func__);
+ return -1;
+}
+
+static int hdmi_check_repeater(struct hdmi_device *hdev)
+{
+ struct device *dev = hdev->dev;
+ int val, i;
+ int cnt = 0, cnt2 = 0;
+
+ u8 bcaps = 0;
+ u8 status[BSTATUS_SIZE];
+ u8 rx_v[SHA_1_HASH_SIZE];
+ u8 ksv_list[HDCP_MAX_DEVS * HDCP_KSV_SIZE];
+
+ u32 dev_cnt;
+
+ memset(status, 0, sizeof(status));
+ memset(rx_v, 0, sizeof(rx_v));
+ memset(ksv_list, 0, sizeof(ksv_list));
+
+ do {
+ if (hdcp_read_bcaps(hdev) < 0)
+ goto check_repeater_err;
+
+ bcaps = hdmi_readb(hdev, HDMI_HDCP_BCAPS);
+
+ if (bcaps & KSV_FIFO_READY) {
+ dev_dbg(dev, "%s: repeater : ksv fifo not ready\n",
+ __func__);
+ dev_dbg(dev, "%s: retries = %d\n", __func__, cnt);
+ break;
+ }
+
+ msleep(KSV_FIFO_CHK_DELAY);
+
+ cnt++;
+ } while (cnt < KSV_FIFO_RETRY_CNT);
+
+ if (cnt == KSV_FIFO_RETRY_CNT)
+ return REPEATER_TIMEOUT_ERROR;
+
+ dev_dbg(dev, "%s: repeater : ksv fifo ready\n", __func__);
+
+ if (hdcp_i2c_read(hdev, HDCP_BSTATUS, BSTATUS_SIZE, status) < 0)
+ goto check_repeater_err;
+
+ if (status[1] & MAX_CASCADE_EXCEEDED)
+ return MAX_CASCADE_EXCEEDED_ERROR;
+ else if (status[0] & MAX_DEVS_EXCEEDED)
+ return MAX_DEVS_EXCEEDED_ERROR;
+
+ hdmi_writeb(hdev, HDMI_HDCP_BSTATUS_0, status[0]);
+ hdmi_writeb(hdev, HDMI_HDCP_BSTATUS_1, status[1]);
+
+ dev_dbg(dev, "%s: status[0] :0x%02x\n", __func__, status[0]);
+ dev_dbg(dev, "%s: status[1] :0x%02x\n", __func__, status[1]);
+
+ dev_cnt = status[0] & 0x7f;
+
+ dev_dbg(dev, "%s: repeater : dev cnt = %d\n", __func__, dev_cnt);
+
+ if (dev_cnt) {
+
+ if (hdcp_i2c_read(hdev, HDCP_KSVFIFO, dev_cnt * HDCP_KSV_SIZE,
+ ksv_list) < 0)
+ goto check_repeater_err;
+
+ cnt = 0;
+
+ do {
+ hdmi_write_bytes(hdev, HDMI_HDCP_KSV_LIST_(0),
+ &ksv_list[cnt * 5], HDCP_KSV_SIZE);
+
+ val = HDMI_HDCP_KSV_WRITE_DONE;
+
+ if (cnt == dev_cnt - 1)
+ val |= HDMI_HDCP_KSV_END;
+
+ hdmi_write(hdev, HDMI_HDCP_KSV_LIST_CON, val);
+
+ if (cnt < dev_cnt - 1) {
+ cnt2 = 0;
+ do {
+ val = hdmi_readb(hdev,
+ HDMI_HDCP_KSV_LIST_CON);
+ if (val & HDMI_HDCP_KSV_READ)
+ break;
+ cnt2++;
+ } while (cnt2 < KSV_LIST_RETRY_CNT);
+
+ if (cnt2 == KSV_LIST_RETRY_CNT)
+ dev_dbg(dev, "%s: ksv list not readed\n",
+ __func__);
+ }
+ cnt++;
+ } while (cnt < dev_cnt);
+ } else
+ hdmi_writeb(hdev, HDMI_HDCP_KSV_LIST_CON,
+ HDMI_HDCP_KSV_LIST_EMPTY);
+
+ if (hdcp_i2c_read(hdev, HDCP_SHA1, SHA_1_HASH_SIZE, rx_v) < 0)
+ goto check_repeater_err;
+
+ for (i = 0; i < SHA_1_HASH_SIZE; i++)
+ dev_dbg(dev, "%s: [i2c] SHA-1 rx :: %02x\n", __func__, rx_v[i]);
+
+ hdmi_write_bytes(hdev, HDMI_HDCP_SHA1_(0), rx_v, SHA_1_HASH_SIZE);
+
+ val = hdmi_readb(hdev, HDMI_HDCP_SHA_RESULT);
+ if (val & HDMI_HDCP_SHA_VALID_RD) {
+ if (val & HDMI_HDCP_SHA_VALID) {
+ dev_dbg(dev, "%s: SHA-1 result is ok\n", __func__);
+ hdmi_writeb(hdev, HDMI_HDCP_SHA_RESULT, 0x0);
+ } else {
+ dev_dbg(dev, "%s: SHA-1 result is not vaild\n",
+ __func__);
+ hdmi_writeb(hdev, HDMI_HDCP_SHA_RESULT, 0x0);
+ goto check_repeater_err;
+ }
+ } else {
+ dev_dbg(dev, "%s: SHA-1 result is not ready\n", __func__);
+ hdmi_writeb(hdev, HDMI_HDCP_SHA_RESULT, 0x0);
+ goto check_repeater_err;
+ }
+
+ dev_dbg(dev, "%s: check repeater is ok\n", __func__);
+ return 0;
+
+check_repeater_err:
+ dev_err(dev, "%s: check repeater is failed\n", __func__);
+ return -1;
+}
+
+static int hdcp_bksv(struct hdmi_device *hdev)
+{
+ struct device *dev = hdev->dev;
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ hdev->hdcp_info.auth_status = RECEIVER_READ_READY;
+
+ if (hdcp_read_bcaps(hdev) < 0)
+ goto bksv_start_err;
+
+ hdev->hdcp_info.auth_status = BCAPS_READ_DONE;
+
+ if (hdcp_read_bksv(hdev) < 0)
+ goto bksv_start_err;
+
+ hdev->hdcp_info.auth_status = BKSV_READ_DONE;
+
+ dev_dbg(dev, "%s: bksv start is ok\n", __func__);
+
+ return 0;
+
+bksv_start_err:
+ dev_err(dev, "%s: failed to start bksv\n", __func__);
+ msleep(100);
+ return -1;
+}
+
+static int hdcp_second_auth(struct hdmi_device *hdev)
+{
+ struct device *dev = hdev->dev;
+ int ret = 0;
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ if (!hdev->hdcp_info.hdcp_start)
+ goto second_auth_err;
+
+ if (!is_hdmi_streaming(hdev))
+ goto second_auth_err;
+
+ ret = hdmi_check_repeater(hdev);
+
+ if (!ret) {
+ hdev->hdcp_info.auth_status = SECOND_AUTHENTICATION_DONE;
+ hdmi_start_encryption(hdev);
+ } else {
+ switch (ret) {
+
+ case REPEATER_ILLEGAL_DEVICE_ERROR:
+ hdmi_writeb(hdev, HDMI_HDCP_CTRL2, 0x1);
+ mdelay(1);
+ hdmi_writeb(hdev, HDMI_HDCP_CTRL2, 0x0);
+
+ dev_dbg(dev, "%s: repeater : illegal device\n",
+ __func__);
+ break;
+ case REPEATER_TIMEOUT_ERROR:
+ hdmi_write_mask(hdev, HDMI_HDCP_CTRL1, ~0,
+ HDMI_HDCP_SET_REPEATER_TIMEOUT);
+ hdmi_write_mask(hdev, HDMI_HDCP_CTRL1, 0,
+ HDMI_HDCP_SET_REPEATER_TIMEOUT);
+
+ dev_dbg(dev, "%s: repeater : timeout\n", __func__);
+ break;
+ case MAX_CASCADE_EXCEEDED_ERROR:
+
+ dev_dbg(dev, "%s: repeater : exceeded MAX_CASCADE\n",
+ __func__);
+ break;
+ case MAX_DEVS_EXCEEDED_ERROR:
+
+ dev_dbg(dev, "%s: repeater : exceeded MAX_DEVS\n",
+ __func__);
+ break;
+ default:
+ break;
+ }
+
+ hdev->hdcp_info.auth_status = NOT_AUTHENTICATED;
+
+ goto second_auth_err;
+ }
+
+ dev_dbg(dev, "%s: second authentication is OK\n", __func__);
+ return 0;
+
+second_auth_err:
+ dev_dbg(dev, "%s: second authentication is failed\n", __func__);
+ return -1;
+}
+
+static int hdcp_write_aksv(struct hdmi_device *hdev)
+{
+ struct device *dev = hdev->dev;
+ dev_dbg(dev, "%s\n", __func__);
+
+ if (hdev->hdcp_info.auth_status != BKSV_READ_DONE) {
+ dev_err(dev, "%s: bksv is not ready\n", __func__);
+ goto aksv_write_err;
+ }
+ if (!is_hdmi_streaming(hdev))
+ goto aksv_write_err;
+
+ if (hdcp_write_key(hdev, AN_SIZE, HDMI_HDCP_AN_(0), HDCP_AN) < 0)
+ goto aksv_write_err;
+
+ hdev->hdcp_info.auth_status = AN_WRITE_DONE;
+
+ dev_dbg(dev, "%s: write An is done\n", __func__);
+
+ if (hdcp_write_key(hdev, AKSV_SIZE, HDMI_HDCP_AKSV_(0), HDCP_AKSV) < 0)
+ goto aksv_write_err;
+
+ msleep(100);
+
+ hdev->hdcp_info.auth_status = AKSV_WRITE_DONE;
+
+ dev_dbg(dev, "%s: write aksv is done\n", __func__);
+ dev_dbg(dev, "%s: aksv start is OK\n", __func__);
+ return 0;
+
+aksv_write_err:
+ dev_err(dev, "%s: aksv start is failed\n", __func__);
+ return -1;
+}
+
+static int hdcp_check_ri(struct hdmi_device *hdev)
+{
+ struct device *dev = hdev->dev;
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ if (hdev->hdcp_info.auth_status < AKSV_WRITE_DONE) {
+ dev_dbg(dev, "%s: ri check is not ready\n", __func__);
+ goto check_ri_err;
+ }
+
+ if (!is_hdmi_streaming(hdev))
+ goto check_ri_err;
+
+ if (hdcp_read_ri(hdev) < 0)
+ goto check_ri_err;
+
+ if (hdev->hdcp_info.is_repeater)
+ hdev->hdcp_info.auth_status
+ = SECOND_AUTHENTICATION_RDY;
+ else {
+ hdev->hdcp_info.auth_status
+ = FIRST_AUTHENTICATION_DONE;
+ hdmi_start_encryption(hdev);
+ }
+
+ dev_dbg(dev, "%s: ri check is OK\n", __func__);
+ return 0;
+
+check_ri_err:
+ dev_err(dev, "%s: ri check is failed\n", __func__);
+ return -1;
+}
+
+static void hdcp_work(struct work_struct *work)
+{
+ struct hdmi_device *hdev = container_of(work, struct hdmi_device, work);
+
+ if (!hdev->hdcp_info.hdcp_start)
+ return;
+
+ if (!is_hdmi_streaming(hdev))
+ return;
+
+ if (hdev->hdcp_info.event & HDCP_EVENT_READ_BKSV_START) {
+ if (hdcp_bksv(hdev) < 0)
+ goto work_err;
+ else
+ hdev->hdcp_info.event &= ~HDCP_EVENT_READ_BKSV_START;
+ }
+
+ if (hdev->hdcp_info.event & HDCP_EVENT_SECOND_AUTH_START) {
+ if (hdcp_second_auth(hdev) < 0)
+ goto work_err;
+ else
+ hdev->hdcp_info.event &= ~HDCP_EVENT_SECOND_AUTH_START;
+ }
+
+ if (hdev->hdcp_info.event & HDCP_EVENT_WRITE_AKSV_START) {
+ if (hdcp_write_aksv(hdev) < 0)
+ goto work_err;
+ else
+ hdev->hdcp_info.event &= ~HDCP_EVENT_WRITE_AKSV_START;
+ }
+
+ if (hdev->hdcp_info.event & HDCP_EVENT_CHECK_RI_START) {
+ if (hdcp_check_ri(hdev) < 0)
+ goto work_err;
+ else
+ hdev->hdcp_info.event &= ~HDCP_EVENT_CHECK_RI_START;
+ }
+ return;
+work_err:
+ if (!hdev->hdcp_info.hdcp_start)
+ return;
+ if (!is_hdmi_streaming(hdev))
+ return;
+
+ hdcp_reset_auth(hdev);
+}
+
+/* HDCP APIs for hdmi driver */
+irqreturn_t hdcp_irq_handler(struct hdmi_device *hdev)
+{
+ struct device *dev = hdev->dev;
+ u32 event = 0;
+ u8 flag;
+ event = 0;
+
+ if (!hdev->streaming) {
+ hdev->hdcp_info.event = HDCP_EVENT_STOP;
+ hdev->hdcp_info.auth_status = NOT_AUTHENTICATED;
+ return IRQ_HANDLED;
+ }
+
+ flag = hdmi_readb(hdev, HDMI_STATUS);
+
+ if (flag & HDMI_WTFORACTIVERX_INT_OCC) {
+ event |= HDCP_EVENT_READ_BKSV_START;
+ hdmi_write_mask(hdev, HDMI_STATUS, ~0,
+ HDMI_WTFORACTIVERX_INT_OCC);
+ hdmi_write(hdev, HDMI_HDCP_I2C_INT, 0x0);
+ }
+
+ if (flag & HDMI_WRITE_INT_OCC) {
+ event |= HDCP_EVENT_WRITE_AKSV_START;
+ hdmi_write_mask(hdev, HDMI_STATUS, ~0, HDMI_WRITE_INT_OCC);
+ hdmi_write(hdev, HDMI_HDCP_AN_INT, 0x0);
+ }
+
+ if (flag & HDMI_UPDATE_RI_INT_OCC) {
+ event |= HDCP_EVENT_CHECK_RI_START;
+ hdmi_write_mask(hdev, HDMI_STATUS, ~0, HDMI_UPDATE_RI_INT_OCC);
+ hdmi_write(hdev, HDMI_HDCP_RI_INT, 0x0);
+ }
+
+ if (flag & HDMI_WATCHDOG_INT_OCC) {
+ event |= HDCP_EVENT_SECOND_AUTH_START;
+ hdmi_write_mask(hdev, HDMI_STATUS, ~0, HDMI_WATCHDOG_INT_OCC);
+ hdmi_write(hdev, HDMI_HDCP_WDT_INT, 0x0);
+ }
+
+ if (!event) {
+ dev_dbg(dev, "%s: unknown irq\n", __func__);
+ return IRQ_HANDLED;
+ }
+
+ if (is_hdmi_streaming(hdev)) {
+ hdev->hdcp_info.event |= event;
+ queue_work(hdev->hdcp_wq, &hdev->work);
+ } else {
+ hdev->hdcp_info.event = HDCP_EVENT_STOP;
+ hdev->hdcp_info.auth_status = NOT_AUTHENTICATED;
+ }
+
+ return IRQ_HANDLED;
+}
+
+int hdcp_prepare(struct hdmi_device *hdev)
+{
+ hdev->hdcp_wq = create_workqueue("khdcpd");
+ if (hdev->hdcp_wq == NULL)
+ return -ENOMEM;
+
+ INIT_WORK(&hdev->work, hdcp_work);
+
+ spin_lock_init(&hdev->hdcp_info.reset_lock);
+
+#if defined(CONFIG_VIDEO_EXYNOS_HDCP)
+ hdev->hdcp_info.hdcp_enable = 1;
+#else
+ hdev->hdcp_info.hdcp_enable = 0;
+#endif
+ return 0;
+}
+
+int hdcp_start(struct hdmi_device *hdev)
+{
+ struct device *dev = hdev->dev;
+
+ hdev->hdcp_info.event = HDCP_EVENT_STOP;
+ hdev->hdcp_info.auth_status = NOT_AUTHENTICATED;
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ hdcp_sw_reset(hdev);
+
+ dev_dbg(dev, "%s: stop encryption\n", __func__);
+
+ hdcp_encryption(hdev, 0);
+
+ msleep(120);
+ if (hdcp_loadkey(hdev) < 0)
+ return -1;
+
+ hdmi_write(hdev, HDMI_GCP_CON, HDMI_GCP_CON_NO_TRAN);
+ hdmi_write(hdev, HDMI_STATUS_EN, HDMI_INT_EN_ALL);
+
+ hdmi_write(hdev, HDMI_HDCP_CTRL1, HDMI_HDCP_CP_DESIRED_EN);
+
+ hdev->hdcp_info.hdcp_start = 1;
+
+ hdmi_set_int_mask(hdev, HDMI_INTC_EN_HDCP, 1);
+
+ return 0;
+}
+
+int hdcp_stop(struct hdmi_device *hdev)
+{
+ struct device *dev = hdev->dev;
+ u8 val;
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ hdmi_set_int_mask(hdev, HDMI_INTC_EN_HDCP, 0);
+
+ hdev->hdcp_info.event = HDCP_EVENT_STOP;
+ hdev->hdcp_info.auth_status = NOT_AUTHENTICATED;
+ hdev->hdcp_info.hdcp_start = false;
+
+ hdmi_writeb(hdev, HDMI_HDCP_CTRL1, 0x0);
+
+ hdmi_sw_hpd_enable(hdev, 0);
+
+ val = HDMI_UPDATE_RI_INT_EN | HDMI_WRITE_INT_EN |
+ HDMI_WATCHDOG_INT_EN | HDMI_WTFORACTIVERX_INT_EN;
+ hdmi_write_mask(hdev, HDMI_STATUS_EN, 0, val);
+ hdmi_write_mask(hdev, HDMI_STATUS_EN, ~0, val);
+
+ hdmi_write_mask(hdev, HDMI_STATUS, ~0, HDMI_INT_EN_ALL);
+
+ dev_dbg(dev, "%s: stop encryption\n", __func__);
+ hdcp_encryption(hdev, 0);
+
+ hdmi_writeb(hdev, HDMI_HDCP_CHECK_RESULT, HDMI_HDCP_CLR_ALL_RESULTS);
+
+ return 0;
+}
diff --git a/drivers/media/video/exynos/tv/hdmi.h b/drivers/media/video/exynos/tv/hdmi.h
new file mode 100644
index 0000000..1858ecc
--- /dev/null
+++ b/drivers/media/video/exynos/tv/hdmi.h
@@ -0,0 +1,422 @@
+/*
+ * Samsung HDMI interface driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * Jiun Yu, <jiun.yu@samsung.com>
+ *
+ * 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 Foundiation. either version 2 of the License,
+ * or (at your option) any later version
+ */
+
+#ifndef SAMSUMG_HDMI_H
+#define SAMSUNG_HDMI_H
+
+#ifdef CONFIG_VIDEO_EXYNOS_HDMI_DEBUG
+#define DEBUG
+#endif
+
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/regulator/consumer.h>
+#include <linux/switch.h>
+
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-device.h>
+
+#define INFOFRAME_CNT 2
+
+#define HDMI_VSI_VERSION 0x01
+#define HDMI_AVI_VERSION 0x02
+#define HDMI_AUI_VERSION 0x01
+#define HDMI_VSI_LENGTH 0x05
+#define HDMI_AVI_LENGTH 0x0d
+#define HDMI_AUI_LENGTH 0x0a
+
+#define AVI_ACTIVE_FORMAT_VALID (1 << 4)
+#define AVI_PIC_ASPECT_RATIO_4_3 (1 << 4)
+#define AVI_PIC_ASPECT_RATIO_16_9 (2 << 4)
+#define AVI_SAME_AS_PIC_ASPECT_RATIO 8
+
+/* HDMI audio configuration value */
+#define DEFAULT_SAMPLE_RATE 44100
+#define DEFAULT_BITS_PER_SAMPLE 16
+
+/* HDMI pad definitions */
+#define HDMI_PAD_SINK 0
+#define HDMI_PADS_NUM 1
+
+/* HPD state definitions */
+#define HPD_LOW 0
+#define HPD_HIGH 1
+
+enum HDMI_VIDEO_FORMAT {
+ HDMI_VIDEO_FORMAT_2D = 0x0,
+ /** refer to Table 8-12 HDMI_Video_Format in HDMI specification v1.4a */
+ HDMI_VIDEO_FORMAT_3D = 0x2
+};
+
+enum HDMI_3D_FORMAT {
+ /** refer to Table 8-13 3D_Structure in HDMI specification v1.4a */
+
+ /** Frame Packing */
+ HDMI_3D_FORMAT_FP = 0x0,
+ /** Top-and-Bottom */
+ HDMI_3D_FORMAT_TB = 0x6,
+ /** Side-by-Side Half */
+ HDMI_3D_FORMAT_SB_HALF = 0x8
+};
+
+enum HDMI_3D_EXT_DATA {
+ /* refer to Table H-3 3D_Ext_Data - Additional video format
+ * information for Side-by-side(half) 3D structure */
+
+ /** Horizontal sub-sampleing */
+ HDMI_H_SUB_SAMPLE = 0x1
+};
+
+enum HDMI_OUTPUT_FMT {
+ HDMI_OUTPUT_RGB888 = 0x0,
+ HDMI_OUTPUT_YUV444 = 0x2
+};
+
+enum HDMI_PACKET_TYPE {
+ /** refer to Table 5-8 Packet Type in HDMI specification v1.4a */
+
+ /** InfoFrame packet type */
+ HDMI_PACKET_TYPE_INFOFRAME = 0X80,
+ /** Vendor-Specific InfoFrame */
+ HDMI_PACKET_TYPE_VSI = HDMI_PACKET_TYPE_INFOFRAME + 1,
+ /** Auxiliary Video information InfoFrame */
+ HDMI_PACKET_TYPE_AVI = HDMI_PACKET_TYPE_INFOFRAME + 2,
+ /** Audio information InfoFrame */
+ HDMI_PACKET_TYPE_AUI = HDMI_PACKET_TYPE_INFOFRAME + 4
+};
+
+enum HDMI_AUDIO_CODEC {
+ HDMI_AUDIO_PCM,
+ HDMI_AUDIO_AC3,
+ HDMI_AUDIO_MP3
+};
+
+enum HDMI_ASPECT_RATIO {
+ HDMI_ASPECT_RATIO_16_9,
+ HDMI_ASPECT_RATIO_4_3
+};
+
+enum HDCP_EVENT {
+ HDCP_EVENT_STOP = 1 << 0,
+ HDCP_EVENT_START = 1 << 1,
+ HDCP_EVENT_READ_BKSV_START = 1 << 2,
+ HDCP_EVENT_WRITE_AKSV_START = 1 << 4,
+ HDCP_EVENT_CHECK_RI_START = 1 << 8,
+ HDCP_EVENT_SECOND_AUTH_START = 1 << 16
+};
+
+enum HDCP_STATE {
+ NOT_AUTHENTICATED,
+ RECEIVER_READ_READY,
+ BCAPS_READ_DONE,
+ BKSV_READ_DONE,
+ AN_WRITE_DONE,
+ AKSV_WRITE_DONE,
+ FIRST_AUTHENTICATION_DONE,
+ SECOND_AUTHENTICATION_RDY,
+ SECOND_AUTHENTICATION_DONE,
+};
+
+#define DEFAULT_AUDIO_CODEC HDMI_AUDIO_PCM
+
+struct hdmi_resources {
+ struct clk *hdmi;
+ struct clk *sclk_hdmi;
+ struct clk *sclk_pixel;
+ struct clk *sclk_hdmiphy;
+ struct regulator_bulk_data *regul_bulk;
+ int regul_count;
+};
+
+struct hdmi_tg_regs {
+ u8 cmd;
+ u8 h_fsz_l;
+ u8 h_fsz_h;
+ u8 hact_st_l;
+ u8 hact_st_h;
+ u8 hact_sz_l;
+ u8 hact_sz_h;
+ u8 v_fsz_l;
+ u8 v_fsz_h;
+ u8 vsync_l;
+ u8 vsync_h;
+ u8 vsync2_l;
+ u8 vsync2_h;
+ u8 vact_st_l;
+ u8 vact_st_h;
+ u8 vact_sz_l;
+ u8 vact_sz_h;
+ u8 field_chg_l;
+ u8 field_chg_h;
+ u8 vact_st2_l;
+ u8 vact_st2_h;
+#ifndef CONFIG_CPU_EXYNOS4210
+ u8 vact_st3_l;
+ u8 vact_st3_h;
+ u8 vact_st4_l;
+ u8 vact_st4_h;
+#endif
+ u8 vsync_top_hdmi_l;
+ u8 vsync_top_hdmi_h;
+ u8 vsync_bot_hdmi_l;
+ u8 vsync_bot_hdmi_h;
+ u8 field_top_hdmi_l;
+ u8 field_top_hdmi_h;
+ u8 field_bot_hdmi_l;
+ u8 field_bot_hdmi_h;
+#ifndef CONFIG_CPU_EXYNOS4210
+ u8 tg_3d;
+#endif
+};
+
+struct hdmi_core_regs {
+#ifndef CONFIG_CPU_EXYNOS4210
+ u8 h_blank[2];
+ u8 v2_blank[2];
+ u8 v1_blank[2];
+ u8 v_line[2];
+ u8 h_line[2];
+ u8 hsync_pol[1];
+ u8 vsync_pol[1];
+ u8 int_pro_mode[1];
+ u8 v_blank_f0[2];
+ u8 v_blank_f1[2];
+ u8 h_sync_start[2];
+ u8 h_sync_end[2];
+ u8 v_sync_line_bef_2[2];
+ u8 v_sync_line_bef_1[2];
+ u8 v_sync_line_aft_2[2];
+ u8 v_sync_line_aft_1[2];
+ u8 v_sync_line_aft_pxl_2[2];
+ u8 v_sync_line_aft_pxl_1[2];
+ u8 v_blank_f2[2]; /* for 3D mode */
+ u8 v_blank_f3[2]; /* for 3D mode */
+ u8 v_blank_f4[2]; /* for 3D mode */
+ u8 v_blank_f5[2]; /* for 3D mode */
+ u8 v_sync_line_aft_3[2];
+ u8 v_sync_line_aft_4[2];
+ u8 v_sync_line_aft_5[2];
+ u8 v_sync_line_aft_6[2];
+ u8 v_sync_line_aft_pxl_3[2];
+ u8 v_sync_line_aft_pxl_4[2];
+ u8 v_sync_line_aft_pxl_5[2];
+ u8 v_sync_line_aft_pxl_6[2];
+ u8 vact_space_1[2];
+ u8 vact_space_2[2];
+ u8 vact_space_3[2];
+ u8 vact_space_4[2];
+ u8 vact_space_5[2];
+ u8 vact_space_6[2];
+#else
+ u8 h_blank[2];
+ u8 v_blank[3];
+ u8 h_v_line[3];
+ u8 vsync_pol[1];
+ u8 int_pro_mode[1];
+ u8 v_blank_f[3];
+ u8 h_sync_gen[3];
+ u8 v_sync_gen1[3];
+ u8 v_sync_gen2[3];
+ u8 v_sync_gen3[3];
+#endif
+};
+
+struct hdmi_3d_info {
+ enum HDMI_VIDEO_FORMAT is_3d;
+ enum HDMI_3D_FORMAT fmt_3d;
+};
+
+struct hdmi_preset_conf {
+ struct hdmi_core_regs core;
+ struct hdmi_tg_regs tg;
+ struct v4l2_mbus_framefmt mbus_fmt;
+ u8 vic;
+};
+
+struct hdmi_driver_data {
+ int hdmiphy_bus;
+};
+
+struct hdmi_infoframe {
+ enum HDMI_PACKET_TYPE type;
+ u8 ver;
+ u8 len;
+};
+
+struct hdcp_info {
+ u8 is_repeater;
+ u32 hdcp_start;
+ int hdcp_enable;
+ spinlock_t reset_lock;
+
+ enum HDCP_EVENT event;
+ enum HDCP_STATE auth_status;
+};
+
+struct hdmi_device {
+ /** base address of HDMI registers */
+ void __iomem *regs;
+
+ /** HDMI interrupt */
+ unsigned int int_irq;
+ unsigned int ext_irq;
+
+ /** pointer to device parent */
+ struct device *dev;
+ /** subdev generated by HDMI device */
+ struct v4l2_subdev sd;
+ /** sink pad connected to mixer */
+ struct media_pad pad;
+ /** V4L2 device structure */
+ struct v4l2_device v4l2_dev;
+ /** subdev of HDMIPHY interface */
+ struct v4l2_subdev *phy_sd;
+ /** configuration of current graphic mode */
+ const struct hdmi_preset_conf *cur_conf;
+ /** current preset */
+ u32 cur_preset;
+ /** other resources */
+ struct hdmi_resources res;
+ /** HDMI is streaming or not */
+ int streaming;
+ /** supported HDMI InfoFrame */
+ struct hdmi_infoframe infoframe[INFOFRAME_CNT];
+ /** audio on/off control flag */
+ int audio_enable;
+ /** audio sample rate */
+ int sample_rate;
+ /** audio bits per sample */
+ int bits_per_sample;
+ /** current audio codec type */
+ enum HDMI_AUDIO_CODEC audio_codec;
+ /** HDMI output format */
+ enum HDMI_OUTPUT_FMT output_fmt;
+ /** Aspect ratio information */
+ enum HDMI_ASPECT_RATIO aspect;
+
+ /** HDCP information */
+ struct hdcp_info hdcp_info;
+ struct work_struct work;
+ struct workqueue_struct *hdcp_wq;
+
+ /* HPD releated */
+ struct work_struct hpd_work;
+ struct work_struct hpd_work_ext;
+ struct switch_dev hpd_switch;
+
+ /* choose DVI or HDMI mode */
+ int dvi_mode;
+};
+
+struct hdmi_conf {
+ u32 preset;
+ const struct hdmi_preset_conf *conf;
+ const struct hdmi_3d_info *info;
+};
+extern const struct hdmi_conf hdmi_conf[];
+
+struct hdmiphy_conf {
+ u32 preset;
+ const u8 *data;
+};
+extern const struct hdmiphy_conf hdmiphy_conf[];
+extern const int hdmi_pre_cnt;
+extern const int hdmiphy_conf_cnt;
+
+const struct hdmi_3d_info *hdmi_preset2info(u32 preset);
+
+irqreturn_t hdmi_irq_handler(int irq, void *dev_data);
+int hdmi_conf_apply(struct hdmi_device *hdmi_dev);
+int is_hdmiphy_ready(struct hdmi_device *hdev);
+void hdmi_enable(struct hdmi_device *hdev, int on);
+void hdmi_hpd_enable(struct hdmi_device *hdev, int on);
+void hdmi_tg_enable(struct hdmi_device *hdev, int on);
+void hdmi_reg_stop_vsi(struct hdmi_device *hdev);
+void hdmi_reg_infoframe(struct hdmi_device *hdev,
+ struct hdmi_infoframe *infoframe);
+void hdmi_reg_set_acr(struct hdmi_device *hdev);
+void hdmi_reg_spdif_audio_init(struct hdmi_device *hdev);
+void hdmi_reg_i2s_audio_init(struct hdmi_device *hdev);
+void hdmi_audio_enable(struct hdmi_device *hdev, int on);
+void hdmi_bluescreen_enable(struct hdmi_device *hdev, int on);
+void hdmi_reg_mute(struct hdmi_device *hdev, int on);
+int hdmi_hpd_status(struct hdmi_device *hdev);
+int is_hdmi_streaming(struct hdmi_device *hdev);
+u8 hdmi_get_int_mask(struct hdmi_device *hdev);
+void hdmi_set_int_mask(struct hdmi_device *hdev, u8 mask, int en);
+void hdmi_sw_hpd_enable(struct hdmi_device *hdev, int en);
+void hdmi_sw_hpd_plug(struct hdmi_device *hdev, int en);
+void hdmi_phy_sw_reset(struct hdmi_device *hdev);
+void hdmi_sw_reset(struct hdmi_device *hdev);
+void hdmi_dumpregs(struct hdmi_device *hdev, char *prefix);
+void hdmi_set_3d_info(struct hdmi_device *hdev);
+void hdmi_set_dvi_mode(struct hdmi_device *hdev);
+
+/** HDCP functions */
+irqreturn_t hdcp_irq_handler(struct hdmi_device *hdev);
+int hdcp_stop(struct hdmi_device *hdev);
+int hdcp_start(struct hdmi_device *hdev);
+int hdcp_prepare(struct hdmi_device *hdev);
+int hdcp_i2c_read(struct hdmi_device *hdev, u8 offset, int bytes, u8 *buf);
+int hdcp_i2c_write(struct hdmi_device *hdev, u8 offset, int bytes, u8 *buf);
+
+static inline
+void hdmi_write(struct hdmi_device *hdev, u32 reg_id, u32 value)
+{
+ writel(value, hdev->regs + reg_id);
+}
+
+static inline
+void hdmi_write_mask(struct hdmi_device *hdev, u32 reg_id, u32 value, u32 mask)
+{
+ u32 old = readl(hdev->regs + reg_id);
+ value = (value & mask) | (old & ~mask);
+ writel(value, hdev->regs + reg_id);
+}
+
+static inline
+void hdmi_writeb(struct hdmi_device *hdev, u32 reg_id, u8 value)
+{
+ writeb(value, hdev->regs + reg_id);
+}
+
+static inline void hdmi_write_bytes(struct hdmi_device *hdev, u32 reg_id,
+ u8 *buf, int bytes)
+{
+ int i;
+
+ for (i = 0; i < bytes; ++i)
+ writeb(buf[i], hdev->regs + reg_id + i * 4);
+}
+
+static inline u32 hdmi_read(struct hdmi_device *hdev, u32 reg_id)
+{
+ return readl(hdev->regs + reg_id);
+}
+
+static inline u8 hdmi_readb(struct hdmi_device *hdev, u32 reg_id)
+{
+ return readb(hdev->regs + reg_id);
+}
+
+static inline void hdmi_read_bytes(struct hdmi_device *hdev, u32 reg_id,
+ u8 *buf, int bytes)
+{
+ int i;
+
+ for (i = 0; i < bytes; ++i)
+ buf[i] = readb(hdev->regs + reg_id + i * 4);
+}
+
+#endif /* SAMSUNG_HDMI_H */
diff --git a/drivers/media/video/exynos/tv/hdmi_cec.c b/drivers/media/video/exynos/tv/hdmi_cec.c
new file mode 100644
index 0000000..8b058b11
--- /dev/null
+++ b/drivers/media/video/exynos/tv/hdmi_cec.c
@@ -0,0 +1,437 @@
+/* linux/drivers/media/video/samsung/tvout/s5p_cec_ctrl.c
+ *
+ * Copyright (c) 2009 Samsung Electronics
+ * http://www.samsung.com/
+ *
+ * cec interface file for Samsung TVOut driver
+ *
+ * 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.
+*/
+
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/poll.h>
+#include <linux/miscdevice.h>
+#include <linux/clk.h>
+#include <linux/sched.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/export.h>
+#include <linux/module.h>
+#include <plat/devs.h>
+#include <plat/tv-core.h>
+
+#include "cec.h"
+
+MODULE_AUTHOR("SangPil Moon");
+MODULE_DESCRIPTION("S5P CEC driver");
+MODULE_LICENSE("GPL");
+
+#define CEC_IOC_MAGIC 'c'
+#define CEC_IOC_SETLADDR _IOW(CEC_IOC_MAGIC, 0, unsigned int)
+
+#define VERSION "1.0" /* Driver version number */
+#define CEC_MINOR 243 /* Major 10, Minor 242, /dev/cec */
+
+
+#define CEC_STATUS_TX_RUNNING (1<<0)
+#define CEC_STATUS_TX_TRANSFERRING (1<<1)
+#define CEC_STATUS_TX_DONE (1<<2)
+#define CEC_STATUS_TX_ERROR (1<<3)
+#define CEC_STATUS_TX_BYTES (0xFF<<8)
+#define CEC_STATUS_RX_RUNNING (1<<16)
+#define CEC_STATUS_RX_RECEIVING (1<<17)
+#define CEC_STATUS_RX_DONE (1<<18)
+#define CEC_STATUS_RX_ERROR (1<<19)
+#define CEC_STATUS_RX_BCAST (1<<20)
+#define CEC_STATUS_RX_BYTES (0xFF<<24)
+
+
+/* CEC Rx buffer size */
+#define CEC_RX_BUFF_SIZE 16
+/* CEC Tx buffer size */
+#define CEC_TX_BUFF_SIZE 16
+
+#define TV_CLK_GET_WITH_ERR_CHECK(clk, pdev, clk_name) \
+ do { \
+ clk = clk_get(&pdev->dev, clk_name); \
+ if (IS_ERR(clk)) { \
+ printk(KERN_ERR \
+ "failed to find clock %s\n", clk_name); \
+ return -ENOENT; \
+ } \
+ } while (0);
+
+static atomic_t hdmi_on = ATOMIC_INIT(0);
+static DEFINE_MUTEX(cec_lock);
+struct clk *hdmi_cec_clk;
+
+static int s5p_cec_open(struct inode *inode, struct file *file)
+{
+ int ret = 0;
+
+ mutex_lock(&cec_lock);
+ clk_enable(hdmi_cec_clk);
+
+ if (atomic_read(&hdmi_on)) {
+ tvout_dbg("do not allow multiple open for tvout cec\n");
+ ret = -EBUSY;
+ goto err_multi_open;
+ } else
+ atomic_inc(&hdmi_on);
+
+ s5p_cec_reset();
+
+ s5p_cec_set_divider();
+
+ s5p_cec_threshold();
+
+ s5p_cec_unmask_tx_interrupts();
+
+ s5p_cec_set_rx_state(STATE_RX);
+ s5p_cec_unmask_rx_interrupts();
+ s5p_cec_enable_rx();
+
+err_multi_open:
+ mutex_unlock(&cec_lock);
+
+ return ret;
+}
+
+static int s5p_cec_release(struct inode *inode, struct file *file)
+{
+ atomic_dec(&hdmi_on);
+
+ s5p_cec_mask_tx_interrupts();
+ s5p_cec_mask_rx_interrupts();
+
+ clk_disable(hdmi_cec_clk);
+ clk_put(hdmi_cec_clk);
+
+ return 0;
+}
+
+static ssize_t s5p_cec_read(struct file *file, char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ ssize_t retval;
+ unsigned long spin_flags;
+
+ if (wait_event_interruptible(cec_rx_struct.waitq,
+ atomic_read(&cec_rx_struct.state) == STATE_DONE)) {
+ return -ERESTARTSYS;
+ }
+ spin_lock_irqsave(&cec_rx_struct.lock, spin_flags);
+
+ if (cec_rx_struct.size > count) {
+ spin_unlock_irqrestore(&cec_rx_struct.lock, spin_flags);
+
+ return -1;
+ }
+
+ if (copy_to_user(buffer, cec_rx_struct.buffer, cec_rx_struct.size)) {
+ spin_unlock_irqrestore(&cec_rx_struct.lock, spin_flags);
+ printk(KERN_ERR " copy_to_user() failed!\n");
+
+ return -EFAULT;
+ }
+
+ retval = cec_rx_struct.size;
+
+ s5p_cec_set_rx_state(STATE_RX);
+ spin_unlock_irqrestore(&cec_rx_struct.lock, spin_flags);
+
+ return retval;
+}
+
+static ssize_t s5p_cec_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ char *data;
+
+ /* check data size */
+
+ if (count > CEC_TX_BUFF_SIZE || count == 0)
+ return -1;
+
+ data = kmalloc(count, GFP_KERNEL);
+
+ if (!data) {
+ printk(KERN_ERR " kmalloc() failed!\n");
+
+ return -1;
+ }
+
+ if (copy_from_user(data, buffer, count)) {
+ printk(KERN_ERR " copy_from_user() failed!\n");
+ kfree(data);
+
+ return -EFAULT;
+ }
+
+ s5p_cec_copy_packet(data, count);
+
+ kfree(data);
+
+ /* wait for interrupt */
+ if (wait_event_interruptible(cec_tx_struct.waitq,
+ atomic_read(&cec_tx_struct.state)
+ != STATE_TX)) {
+
+ return -ERESTARTSYS;
+ }
+
+ if (atomic_read(&cec_tx_struct.state) == STATE_ERROR)
+ return -1;
+
+ return count;
+}
+
+#if 0
+static int s5p_cec_ioctl(struct inode *inode, struct file *file, u32 cmd,
+ unsigned long arg)
+#else
+static long s5p_cec_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+#endif
+{
+ u32 laddr;
+
+ switch (cmd) {
+ case CEC_IOC_SETLADDR:
+ if (get_user(laddr, (u32 __user *) arg))
+ return -EFAULT;
+
+ tvout_dbg("logical address = 0x%02x\n", laddr);
+
+ s5p_cec_set_addr(laddr);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static u32 s5p_cec_poll(struct file *file, poll_table *wait)
+{
+ poll_wait(file, &cec_rx_struct.waitq, wait);
+
+ if (atomic_read(&cec_rx_struct.state) == STATE_DONE)
+ return POLLIN | POLLRDNORM;
+
+ return 0;
+}
+
+static const struct file_operations cec_fops = {
+ .owner = THIS_MODULE,
+ .open = s5p_cec_open,
+ .release = s5p_cec_release,
+ .read = s5p_cec_read,
+ .write = s5p_cec_write,
+#if 1
+ .unlocked_ioctl = s5p_cec_ioctl,
+#else
+ .ioctl = s5p_cec_ioctl,
+#endif
+ .poll = s5p_cec_poll,
+};
+
+static struct miscdevice cec_misc_device = {
+ .minor = CEC_MINOR,
+ .name = "CEC",
+ .fops = &cec_fops,
+};
+
+static irqreturn_t s5p_cec_irq_handler(int irq, void *dev_id)
+{
+
+ u32 status = 0;
+
+ status = s5p_cec_get_status();
+
+ if (status & CEC_STATUS_TX_DONE) {
+ if (status & CEC_STATUS_TX_ERROR) {
+ tvout_dbg(" CEC_STATUS_TX_ERROR!\n");
+ s5p_cec_set_tx_state(STATE_ERROR);
+ } else {
+ tvout_dbg(" CEC_STATUS_TX_DONE!\n");
+ s5p_cec_set_tx_state(STATE_DONE);
+ }
+
+ s5p_clr_pending_tx();
+
+ wake_up_interruptible(&cec_tx_struct.waitq);
+ }
+
+ if (status & CEC_STATUS_RX_DONE) {
+ if (status & CEC_STATUS_RX_ERROR) {
+ tvout_dbg(" CEC_STATUS_RX_ERROR!\n");
+ s5p_cec_rx_reset();
+
+ } else {
+ u32 size;
+
+ tvout_dbg(" CEC_STATUS_RX_DONE!\n");
+
+ /* copy data from internal buffer */
+ size = status >> 24;
+
+ spin_lock(&cec_rx_struct.lock);
+
+ s5p_cec_get_rx_buf(size, cec_rx_struct.buffer);
+
+ cec_rx_struct.size = size;
+
+ s5p_cec_set_rx_state(STATE_DONE);
+
+ spin_unlock(&cec_rx_struct.lock);
+
+ s5p_cec_enable_rx();
+ }
+
+ /* clear interrupt pending bit */
+ s5p_clr_pending_rx();
+
+ wake_up_interruptible(&cec_rx_struct.waitq);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int __devinit s5p_cec_probe(struct platform_device *pdev)
+{
+ struct s5p_platform_cec *pdata;
+ u8 *buffer;
+ int ret;
+ struct resource *res;
+
+ pdata = to_tvout_plat(&pdev->dev);
+
+ if (pdata->cfg_gpio)
+ pdata->cfg_gpio(pdev);
+
+
+ s5p_cec_mem_probe(pdev);
+
+ if (misc_register(&cec_misc_device)) {
+ printk(KERN_WARNING " Couldn't register device 10, %d.\n",
+ CEC_MINOR);
+
+ return -EBUSY;
+ }
+
+#if 0
+ irq_num = platform_get_irq(pdev, 0);
+
+ if (irq_num < 0) {
+ printk(KERN_ERR "failed to get %s irq resource\n", "cec");
+ ret = -ENOENT;
+
+ return ret;
+ }
+#endif
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "failed to get irq resource.\n");
+ ret = -ENOENT;
+ return ret;
+ }
+
+ ret = request_irq(res->start, s5p_cec_irq_handler, IRQF_DISABLED,
+ pdev->name, &pdev->id);
+
+ if (ret != 0) {
+ printk(KERN_ERR "failed to install %s irq (%d)\n", "cec", ret);
+
+ return ret;
+ }
+
+ init_waitqueue_head(&cec_rx_struct.waitq);
+ spin_lock_init(&cec_rx_struct.lock);
+ init_waitqueue_head(&cec_tx_struct.waitq);
+
+ buffer = kmalloc(CEC_TX_BUFF_SIZE, GFP_KERNEL);
+
+ if (!buffer) {
+ printk(KERN_ERR " kmalloc() failed!\n");
+ misc_deregister(&cec_misc_device);
+
+ return -EIO;
+ }
+
+ cec_rx_struct.buffer = buffer;
+
+ cec_rx_struct.size = 0;
+ TV_CLK_GET_WITH_ERR_CHECK(hdmi_cec_clk, pdev, "sclk_cec");
+
+ dev_info(&pdev->dev, "probe successful\n");
+
+ return 0;
+}
+
+static int __devexit s5p_cec_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int s5p_cec_suspend(struct platform_device *dev, pm_message_t state)
+{
+ return 0;
+}
+
+static int s5p_cec_resume(struct platform_device *dev)
+{
+ return 0;
+}
+#else
+#define s5p_cec_suspend NULL
+#define s5p_cec_resume NULL
+#endif
+
+static struct platform_driver s5p_cec_driver = {
+ .probe = s5p_cec_probe,
+ .remove = __devexit_p(s5p_cec_remove),
+ .suspend = s5p_cec_suspend,
+ .resume = s5p_cec_resume,
+ .driver = {
+ .name = "s5p-tvout-cec",
+ .owner = THIS_MODULE,
+ },
+};
+
+static char banner[] __initdata =
+ "S5P CEC for Exynos4 Driver, (c) 2009 Samsung Electronics\n";
+
+static int __init s5p_cec_init(void)
+{
+ int ret;
+
+ printk(banner);
+
+ ret = platform_driver_register(&s5p_cec_driver);
+
+ if (ret) {
+ printk(KERN_ERR "Platform Device Register Failed %d\n", ret);
+
+ return -1;
+ }
+
+ return 0;
+}
+
+static void __exit s5p_cec_exit(void)
+{
+ kfree(cec_rx_struct.buffer);
+
+ platform_driver_unregister(&s5p_cec_driver);
+}
+
+module_init(s5p_cec_init);
+module_exit(s5p_cec_exit);
+
diff --git a/drivers/media/video/exynos/tv/hdmi_cec_ctrl.c b/drivers/media/video/exynos/tv/hdmi_cec_ctrl.c
new file mode 100644
index 0000000..67834d4
--- /dev/null
+++ b/drivers/media/video/exynos/tv/hdmi_cec_ctrl.c
@@ -0,0 +1,266 @@
+/* linux/drivers/media/video/samsung/tvout/hw_if/cec.c
+ *
+ * Copyright (c) 2009 Samsung Electronics
+ * http://www.samsung.com/
+ *
+ * cec ftn file for Samsung TVOUT driver
+ *
+ * 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.
+ */
+
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/videodev2.h>
+#include <linux/videodev2_exynos_media.h>
+#include <linux/irqreturn.h>
+#include <linux/stddef.h>
+
+#include <mach/regs-clock.h>
+#include <mach/regs-clock.h>
+#include <mach/regs-cec.h>
+
+#include "cec.h"
+
+#undef tvout_dbg
+
+#ifdef CONFIG_CEC_DEBUG
+#define tvout_dbg(fmt, ...) \
+ printk(KERN_INFO "\t\t[CEC] %s(): " fmt, \
+ __func__, ##__VA_ARGS__)
+#else
+#define tvout_dbg(fmt, ...)
+#endif
+
+#define S5P_HDMI_FIN 24000000
+#define CEC_DIV_RATIO 320000
+
+#define CEC_MESSAGE_BROADCAST_MASK 0x0F
+#define CEC_MESSAGE_BROADCAST 0x0F
+#define CEC_FILTER_THRESHOLD 0x15
+
+static struct resource *cec_mem;
+void __iomem *cec_base;
+
+struct cec_rx_struct cec_rx_struct;
+struct cec_tx_struct cec_tx_struct;
+
+void s5p_cec_set_divider(void)
+{
+ u32 div_ratio, reg, div_val;
+
+ div_ratio = S5P_HDMI_FIN / CEC_DIV_RATIO - 1;
+
+ reg = readl(EXYNOS_HDMI_PHY_CONTROL);
+ reg = (reg & ~(0x3FF << 16)) | (div_ratio << 16);
+
+ writel(reg, EXYNOS_HDMI_PHY_CONTROL);
+
+ div_val = CEC_DIV_RATIO * 0.00005 - 1;
+
+ writeb(0x0, cec_base + S5P_CES_DIVISOR_3);
+ writeb(0x0, cec_base + S5P_CES_DIVISOR_2);
+ writeb(0x0, cec_base + S5P_CES_DIVISOR_1);
+ writeb(div_val, cec_base + S5P_CES_DIVISOR_0);
+}
+
+void s5p_cec_enable_rx(void)
+{
+ u8 reg;
+
+ reg = readb(cec_base + S5P_CES_RX_CTRL);
+ reg |= S5P_CES_RX_CTRL_ENABLE;
+ writeb(reg, cec_base + S5P_CES_RX_CTRL);
+}
+
+void s5p_cec_mask_rx_interrupts(void)
+{
+ u8 reg;
+
+ reg = readb(cec_base + S5P_CES_IRQ_MASK);
+ reg |= S5P_CES_IRQ_RX_DONE;
+ reg |= S5P_CES_IRQ_RX_ERROR;
+ writeb(reg, cec_base + S5P_CES_IRQ_MASK);
+}
+
+void s5p_cec_unmask_rx_interrupts(void)
+{
+ u8 reg;
+
+ reg = readb(cec_base + S5P_CES_IRQ_MASK);
+ reg &= ~S5P_CES_IRQ_RX_DONE;
+ reg &= ~S5P_CES_IRQ_RX_ERROR;
+ writeb(reg, cec_base + S5P_CES_IRQ_MASK);
+}
+
+void s5p_cec_mask_tx_interrupts(void)
+{
+ u8 reg;
+ reg = readb(cec_base + S5P_CES_IRQ_MASK);
+ reg |= S5P_CES_IRQ_TX_DONE;
+ reg |= S5P_CES_IRQ_TX_ERROR;
+ writeb(reg, cec_base + S5P_CES_IRQ_MASK);
+
+}
+
+void s5p_cec_unmask_tx_interrupts(void)
+{
+ u8 reg;
+
+ reg = readb(cec_base + S5P_CES_IRQ_MASK);
+ reg &= ~S5P_CES_IRQ_TX_DONE;
+ reg &= ~S5P_CES_IRQ_TX_ERROR;
+ writeb(reg, cec_base + S5P_CES_IRQ_MASK);
+}
+
+void s5p_cec_reset(void)
+{
+ writeb(S5P_CES_RX_CTRL_RESET, cec_base + S5P_CES_RX_CTRL);
+ writeb(S5P_CES_TX_CTRL_RESET, cec_base + S5P_CES_TX_CTRL);
+}
+
+void s5p_cec_tx_reset(void)
+{
+ writeb(S5P_CES_TX_CTRL_RESET, cec_base + S5P_CES_TX_CTRL);
+}
+
+void s5p_cec_rx_reset(void)
+{
+ writeb(S5P_CES_RX_CTRL_RESET, cec_base + S5P_CES_RX_CTRL);
+}
+
+void s5p_cec_threshold(void)
+{
+ writeb(CEC_FILTER_THRESHOLD, cec_base + S5P_CES_RX_FILTER_TH);
+ writeb(0, cec_base + S5P_CES_RX_FILTER_CTRL);
+}
+
+void s5p_cec_set_tx_state(enum cec_state state)
+{
+ atomic_set(&cec_tx_struct.state, state);
+}
+
+void s5p_cec_set_rx_state(enum cec_state state)
+{
+ atomic_set(&cec_rx_struct.state, state);
+}
+
+void s5p_cec_copy_packet(char *data, size_t count)
+{
+ int i = 0;
+ u8 reg;
+
+ while (i < count) {
+ writeb(data[i], cec_base + (S5P_CES_TX_BUFF0 + (i * 4)));
+ i++;
+ }
+
+ writeb(count, cec_base + S5P_CES_TX_BYTES);
+ s5p_cec_set_tx_state(STATE_TX);
+ reg = readb(cec_base + S5P_CES_TX_CTRL);
+ reg |= S5P_CES_TX_CTRL_START;
+
+ if ((data[0] & CEC_MESSAGE_BROADCAST_MASK) == CEC_MESSAGE_BROADCAST)
+ reg |= S5P_CES_TX_CTRL_BCAST;
+ else
+ reg &= ~S5P_CES_TX_CTRL_BCAST;
+
+ reg |= 0x50;
+ writeb(reg, cec_base + S5P_CES_TX_CTRL);
+}
+
+void s5p_cec_set_addr(u32 addr)
+{
+ writeb(addr & 0x0F, cec_base + S5P_CES_LOGIC_ADDR);
+}
+
+u32 s5p_cec_get_status(void)
+{
+ u32 status = 0;
+
+ status = readb(cec_base + S5P_CES_STATUS_0);
+ status |= readb(cec_base + S5P_CES_STATUS_1) << 8;
+ status |= readb(cec_base + S5P_CES_STATUS_2) << 16;
+ status |= readb(cec_base + S5P_CES_STATUS_3) << 24;
+
+ tvout_dbg("status = 0x%x!\n", status);
+
+ return status;
+}
+
+void s5p_clr_pending_tx(void)
+{
+ writeb(S5P_CES_IRQ_TX_DONE | S5P_CES_IRQ_TX_ERROR,
+ cec_base + S5P_CES_IRQ_CLEAR);
+}
+
+void s5p_clr_pending_rx(void)
+{
+ writeb(S5P_CES_IRQ_RX_DONE | S5P_CES_IRQ_RX_ERROR,
+ cec_base + S5P_CES_IRQ_CLEAR);
+}
+
+void s5p_cec_get_rx_buf(u32 size, u8 *buffer)
+{
+ u32 i = 0;
+
+ while (i < size) {
+ buffer[i] = readb(cec_base + S5P_CES_RX_BUFF0 + (i * 4));
+ i++;
+ }
+}
+
+int __init s5p_cec_mem_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ size_t size;
+ int ret;
+
+ dev_dbg(&pdev->dev, "%s\n", __func__);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ if (res == NULL) {
+ dev_err(&pdev->dev,
+ "failed to get memory region resource for cec\n");
+ return -ENOENT;
+ }
+
+ size = (res->end - res->start) + 1;
+ cec_mem = request_mem_region(res->start, size, pdev->name);
+
+ if (cec_mem == NULL) {
+ dev_err(&pdev->dev,
+ "failed to get memory region for cec\n");
+ return -ENOENT;
+ }
+
+ cec_base = ioremap(res->start, size);
+
+ if (cec_base == NULL) {
+ dev_err(&pdev->dev,
+ "failed to ioremap address region for cec\n");
+ return -ENOENT;
+ }
+
+ return ret;
+}
+
+int __init s5p_cec_mem_release(struct platform_device *pdev)
+{
+ iounmap(cec_base);
+
+ if (cec_mem != NULL) {
+ if (release_resource(cec_mem))
+ dev_err(&pdev->dev,
+ "Can't remove tvout drv !!\n");
+
+ kfree(cec_mem);
+
+ cec_mem = NULL;
+ }
+
+ return 0;
+}
diff --git a/drivers/media/video/exynos/tv/hdmi_drv.c b/drivers/media/video/exynos/tv/hdmi_drv.c
new file mode 100644
index 0000000..edc8e33
--- /dev/null
+++ b/drivers/media/video/exynos/tv/hdmi_drv.c
@@ -0,0 +1,961 @@
+/*
+ * Samsung HDMI interface driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * Tomasz Stanislawski, <t.stanislaws@samsung.com>
+ *
+ * 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 Foundiation. either version 2 of the License,
+ * or (at your option) any later version
+ */
+#include "hdmi.h"
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <media/v4l2-subdev.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <linux/bug.h>
+#include <linux/pm_domain.h>
+#include <linux/pm_runtime.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/videodev2_exynos_media.h>
+#include <linux/sched.h>
+#include <plat/devs.h>
+#include <plat/tv-core.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-device.h>
+#include <media/exynos_mc.h>
+#include "regs-hdmi-5250.h"
+
+MODULE_AUTHOR("Tomasz Stanislawski, <t.stanislaws@samsung.com>");
+MODULE_DESCRIPTION("Samsung HDMI");
+MODULE_LICENSE("GPL");
+
+/* default preset configured on probe */
+#define HDMI_DEFAULT_PRESET V4L2_DV_1080P60
+
+/* I2C module and id for HDMIPHY */
+static struct i2c_board_info hdmiphy_info = {
+ I2C_BOARD_INFO("hdmiphy", 0x38),
+};
+
+static struct hdmi_driver_data hdmi_driver_data[] = {
+ { .hdmiphy_bus = 3 },
+ { .hdmiphy_bus = 8 },
+ { .hdmiphy_bus = 8 },
+};
+
+static struct platform_device_id hdmi_driver_types[] = {
+ {
+ .name = "s5pv210-hdmi",
+ .driver_data = (unsigned long)&hdmi_driver_data[0],
+ }, {
+ .name = "exynos4-hdmi",
+ .driver_data = (unsigned long)&hdmi_driver_data[1],
+ }, {
+ .name = "exynos5-hdmi",
+ .driver_data = (unsigned long)&hdmi_driver_data[2],
+ }, {
+ /* end node */
+ }
+};
+
+static const struct v4l2_subdev_ops hdmi_sd_ops;
+
+static struct hdmi_device *sd_to_hdmi_dev(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct hdmi_device, sd);
+}
+
+static const struct hdmi_preset_conf *hdmi_preset2conf(u32 preset)
+{
+ int i;
+
+ for (i = 0; i < hdmi_pre_cnt; ++i)
+ if (hdmi_conf[i].preset == preset)
+ return hdmi_conf[i].conf;
+ return NULL;
+}
+
+const struct hdmi_3d_info *hdmi_preset2info(u32 preset)
+{
+ int i;
+
+ for (i = 0; i < hdmi_pre_cnt; ++i)
+ if (hdmi_conf[i].preset == preset)
+ return hdmi_conf[i].info;
+ return NULL;
+}
+
+static int hdmi_set_infoframe(struct hdmi_device *hdev)
+{
+ struct hdmi_infoframe infoframe;
+ const struct hdmi_3d_info *info;
+
+ info = hdmi_preset2info(hdev->cur_preset);
+
+ if (info->is_3d == HDMI_VIDEO_FORMAT_3D) {
+ infoframe.type = HDMI_PACKET_TYPE_VSI;
+ infoframe.ver = HDMI_VSI_VERSION;
+ infoframe.len = HDMI_VSI_LENGTH;
+ hdmi_reg_infoframe(hdev, &infoframe);
+ } else
+ hdmi_reg_stop_vsi(hdev);
+
+ infoframe.type = HDMI_PACKET_TYPE_AVI;
+ infoframe.ver = HDMI_AVI_VERSION;
+ infoframe.len = HDMI_AVI_LENGTH;
+ hdmi_reg_infoframe(hdev, &infoframe);
+
+ if (hdev->audio_enable) {
+ infoframe.type = HDMI_PACKET_TYPE_AUI;
+ infoframe.ver = HDMI_AUI_VERSION;
+ infoframe.len = HDMI_AUI_LENGTH;
+ hdmi_reg_infoframe(hdev, &infoframe);
+ }
+
+ return 0;
+}
+
+static int hdmi_set_packets(struct hdmi_device *hdev)
+{
+ hdmi_reg_set_acr(hdev);
+ return 0;
+}
+
+static int hdmi_streamon(struct hdmi_device *hdev)
+{
+ struct device *dev = hdev->dev;
+ struct hdmi_resources *res = &hdev->res;
+ int ret, tries;
+ u32 val0, val1, val2;
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ hdev->streaming = 1;
+ ret = v4l2_subdev_call(hdev->phy_sd, video, s_stream, 1);
+ if (ret)
+ return ret;
+
+ /* waiting for HDMIPHY's PLL to get to steady state */
+ for (tries = 100; tries; --tries) {
+ if (is_hdmiphy_ready(hdev))
+ break;
+
+ mdelay(1);
+ }
+ /* steady state not achieved */
+ if (tries == 0) {
+ dev_err(dev, "hdmiphy's pll could not reach steady state.\n");
+ v4l2_subdev_call(hdev->phy_sd, video, s_stream, 0);
+ hdmi_dumpregs(hdev, "s_stream");
+ return -EIO;
+ }
+
+ /* hdmiphy clock is used for HDMI in streaming mode */
+ clk_disable(res->sclk_hdmi);
+ clk_set_parent(res->sclk_hdmi, res->sclk_hdmiphy);
+ clk_enable(res->sclk_hdmi);
+
+ /* 3D test */
+ hdmi_set_infoframe(hdev);
+
+ /* set packets for audio */
+ hdmi_set_packets(hdev);
+
+ /* init audio */
+#if defined(CONFIG_VIDEO_EXYNOS_HDMI_AUDIO_I2S)
+ hdmi_reg_i2s_audio_init(hdev);
+#elif defined(CONFIG_VIDEO_EXYNOS_HDMI_AUDIO_SPDIF)
+ hdmi_reg_spdif_audio_init(hdev);
+#endif
+ /* enbale HDMI audio */
+ if (hdev->audio_enable)
+ hdmi_audio_enable(hdev, 1);
+
+ hdmi_set_dvi_mode(hdev);
+
+ /* enable HDMI and timing generator */
+ hdmi_enable(hdev, 1);
+ hdmi_tg_enable(hdev, 1);
+
+ mdelay(5);
+ val0 = hdmi_read(hdev, HDMI_ACR_MCTS0);
+ val1 = hdmi_read(hdev, HDMI_ACR_MCTS1);
+ val2 = hdmi_read(hdev, HDMI_ACR_MCTS2);
+ dev_dbg(dev, "HDMI_ACR_MCTS0 : 0x%08x\n", val0);
+ dev_dbg(dev, "HDMI_ACR_MCTS1 : 0x%08x\n", val1);
+ dev_dbg(dev, "HDMI_ACR_MCTS2 : 0x%08x\n", val2);
+
+ /* start HDCP if enabled */
+ if (hdev->hdcp_info.hdcp_enable) {
+ ret = hdcp_start(hdev);
+ if (ret)
+ return ret;
+ }
+
+ hdmi_dumpregs(hdev, "streamon");
+ return 0;
+}
+
+static int hdmi_streamoff(struct hdmi_device *hdev)
+{
+ struct device *dev = hdev->dev;
+ struct hdmi_resources *res = &hdev->res;
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ if (hdev->hdcp_info.hdcp_enable)
+ hdcp_stop(hdev);
+
+ hdmi_audio_enable(hdev, 0);
+ hdmi_enable(hdev, 0);
+ hdmi_tg_enable(hdev, 0);
+
+ /* pixel(vpll) clock is used for HDMI in config mode */
+ clk_disable(res->sclk_hdmi);
+ clk_set_parent(res->sclk_hdmi, res->sclk_pixel);
+ clk_enable(res->sclk_hdmi);
+
+ v4l2_subdev_call(hdev->phy_sd, video, s_stream, 0);
+
+ hdev->streaming = 0;
+ hdmi_dumpregs(hdev, "streamoff");
+ return 0;
+}
+
+static int hdmi_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
+ struct device *dev = hdev->dev;
+
+ dev_dbg(dev, "%s(%d)\n", __func__, enable);
+ if (enable)
+ return hdmi_streamon(hdev);
+ return hdmi_streamoff(hdev);
+}
+
+static void hdmi_resource_poweron(struct hdmi_resources *res)
+{
+ /* use VPP as parent clock; HDMIPHY is not working yet */
+ clk_set_parent(res->sclk_hdmi, res->sclk_pixel);
+ /* turn clocks on */
+ clk_enable(res->sclk_hdmi);
+}
+
+static int hdmi_runtime_resume(struct device *dev);
+static int hdmi_runtime_suspend(struct device *dev);
+
+static int hdmi_s_power(struct v4l2_subdev *sd, int on)
+{
+ struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
+ int ret = 0;
+
+ /* If runtime PM is not implemented, hdmi_runtime_resume
+ * and hdmi_runtime_suspend functions are directly called.
+ */
+
+ if (on) {
+ clk_enable(hdev->res.hdmi);
+
+#ifdef CONFIG_PM_RUNTIME
+ ret = pm_runtime_get_sync(hdev->dev);
+#else
+ hdmi_runtime_resume(hdev->dev);
+#endif
+
+ disable_irq(hdev->ext_irq);
+ cancel_work_sync(&hdev->hpd_work_ext);
+
+ s5p_v4l2_int_src_hdmi_hpd();
+ hdmi_hpd_enable(hdev, 1);
+ enable_irq(hdev->int_irq);
+
+ dev_info(hdev->dev, "HDMI interrupt changed to internal\n");
+ } else {
+ hdmi_hpd_enable(hdev, 0);
+ disable_irq(hdev->int_irq);
+ cancel_work_sync(&hdev->hpd_work);
+
+ s5p_v4l2_int_src_ext_hpd();
+ enable_irq(hdev->ext_irq);
+ dev_info(hdev->dev, "HDMI interrupt changed to external\n");
+
+#ifdef CONFIG_PM_RUNTIME
+ ret = pm_runtime_put_sync(hdev->dev);
+#else
+ hdmi_runtime_suspend(hdev->dev);
+#endif
+
+ clk_disable(hdev->res.hdmi);
+ }
+
+ /* only values < 0 indicate errors */
+ return IS_ERR_VALUE(ret) ? ret : 0;
+}
+
+int hdmi_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+ struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
+ struct device *dev = hdev->dev;
+ int ret = 0;
+
+ dev_dbg(dev, "%s start\n", __func__);
+
+ switch (ctrl->id) {
+ case V4L2_CID_TV_SET_DVI_MODE:
+ hdev->dvi_mode = ctrl->value;
+ break;
+ case V4L2_CID_TV_SET_ASPECT_RATIO:
+ hdev->aspect = ctrl->value;
+ break;
+ default:
+ dev_err(dev, "invalid control id\n");
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+int hdmi_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+ struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
+ struct device *dev = hdev->dev;
+
+ ctrl->value = switch_get_state(&hdev->hpd_switch);
+ dev_dbg(dev, "HDMI cable is %s\n", ctrl->value ?
+ "connected" : "disconnected");
+
+ return 0;
+}
+
+static int hdmi_s_dv_preset(struct v4l2_subdev *sd,
+ struct v4l2_dv_preset *preset)
+{
+ struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
+ struct device *dev = hdev->dev;
+ const struct hdmi_preset_conf *conf;
+
+ conf = hdmi_preset2conf(preset->preset);
+ if (conf == NULL) {
+ dev_err(dev, "preset (%u) not supported\n", preset->preset);
+ return -EINVAL;
+ }
+ hdev->cur_conf = conf;
+ hdev->cur_preset = preset->preset;
+ return 0;
+}
+
+static int hdmi_g_dv_preset(struct v4l2_subdev *sd,
+ struct v4l2_dv_preset *preset)
+{
+ memset(preset, 0, sizeof(*preset));
+ preset->preset = sd_to_hdmi_dev(sd)->cur_preset;
+ return 0;
+}
+
+static int hdmi_g_mbus_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *fmt)
+{
+ struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
+ struct device *dev = hdev->dev;
+
+ dev_dbg(dev, "%s\n", __func__);
+ if (!hdev->cur_conf)
+ return -EINVAL;
+ *fmt = hdev->cur_conf->mbus_fmt;
+ return 0;
+}
+
+static int hdmi_s_mbus_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *fmt)
+{
+ struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
+ struct device *dev = hdev->dev;
+
+ dev_dbg(dev, "%s\n", __func__);
+ if (fmt->code == V4L2_MBUS_FMT_YUV8_1X24)
+ hdev->output_fmt = HDMI_OUTPUT_YUV444;
+ else
+ hdev->output_fmt = HDMI_OUTPUT_RGB888;
+
+ return 0;
+}
+
+static int hdmi_enum_dv_presets(struct v4l2_subdev *sd,
+ struct v4l2_dv_enum_preset *preset)
+{
+ if (preset->index >= hdmi_pre_cnt)
+ return -EINVAL;
+ return v4l_fill_dv_preset_info(hdmi_conf[preset->index].preset, preset);
+}
+
+static const struct v4l2_subdev_core_ops hdmi_sd_core_ops = {
+ .s_power = hdmi_s_power,
+ .s_ctrl = hdmi_s_ctrl,
+ .g_ctrl = hdmi_g_ctrl,
+};
+
+static const struct v4l2_subdev_video_ops hdmi_sd_video_ops = {
+ .s_dv_preset = hdmi_s_dv_preset,
+ .g_dv_preset = hdmi_g_dv_preset,
+ .enum_dv_presets = hdmi_enum_dv_presets,
+ .g_mbus_fmt = hdmi_g_mbus_fmt,
+ .s_mbus_fmt = hdmi_s_mbus_fmt,
+ .s_stream = hdmi_s_stream,
+};
+
+static const struct v4l2_subdev_ops hdmi_sd_ops = {
+ .core = &hdmi_sd_core_ops,
+ .video = &hdmi_sd_video_ops,
+};
+
+static int hdmi_runtime_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct s5p_hdmi_platdata *pdata = pdev->dev.platform_data;
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
+ struct hdmi_resources *res = &hdev->res;
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ /* HDMI PHY off sequence
+ * LINK off -> PHY off -> HDMI_PHY_CONTROL disable */
+
+ /* turn clocks off */
+ clk_disable(res->sclk_hdmi);
+
+ v4l2_subdev_call(hdev->phy_sd, core, s_power, 0);
+
+ /* power-off hdmiphy */
+ if (pdata->hdmiphy_enable)
+ pdata->hdmiphy_enable(pdev, 0);
+
+ return 0;
+}
+
+static int hdmi_runtime_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct s5p_hdmi_platdata *pdata = pdev->dev.platform_data;
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
+ struct hdmi_resources *res = &hdev->res;
+ int ret = 0;
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ /* power-on hdmiphy */
+ if (pdata->hdmiphy_enable)
+ pdata->hdmiphy_enable(pdev, 1);
+ hdmi_resource_poweron(&hdev->res);
+ hdmi_sw_reset(hdev);
+ hdmi_phy_sw_reset(hdev);
+
+ ret = v4l2_subdev_call(hdev->phy_sd, core, s_power, 1);
+ if (ret) {
+ dev_err(dev, "failed to turn on hdmiphy\n");
+ goto fail;
+ }
+
+ ret = hdmi_conf_apply(hdev);
+ if (ret)
+ goto fail;
+
+ dev_dbg(dev, "poweron succeed\n");
+
+ return 0;
+
+fail:
+ clk_disable(res->sclk_hdmi);
+ v4l2_subdev_call(hdev->phy_sd, core, s_power, 0);
+ if (pdata->hdmiphy_enable)
+ pdata->hdmiphy_enable(pdev, 0);
+ dev_err(dev, "poweron failed\n");
+
+ return ret;
+}
+
+static int hdmi_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct s5p_hdmi_platdata *pdata = pdev->dev.platform_data;
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
+ int ret = 0;
+
+ dev_dbg(dev, "%s start\n", __func__);
+
+ /* HDMI PHY power off
+ * HDMI PHY is on as default configuration
+ * So, HDMI PHY must be turned off if it's not used */
+ if (pdata->hdmiphy_enable)
+ pdata->hdmiphy_enable(pdev, 1);
+
+ ret = v4l2_subdev_call(hdev->phy_sd, core, s_power, 0);
+ if (ret)
+ dev_err(dev, "failed to turn off hdmiphy\n");
+
+ if (pdata->hdmiphy_enable)
+ pdata->hdmiphy_enable(pdev, 0);
+
+ return ret;
+}
+
+static int hdmi_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct s5p_hdmi_platdata *pdata = pdev->dev.platform_data;
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
+ int ret = 0;
+
+ dev_dbg(dev, "%s start\n", __func__);
+
+ /* HDMI PHY power off
+ * HDMI PHY is on as default configuration
+ * So, HDMI PHY must be turned off if it's not used */
+ if (pdata->hdmiphy_enable)
+ pdata->hdmiphy_enable(pdev, 1);
+
+ ret = v4l2_subdev_call(hdev->phy_sd, core, s_power, 0);
+ if (ret)
+ dev_err(dev, "failed to turn off hdmiphy\n");
+
+ if (pdata->hdmiphy_enable)
+ pdata->hdmiphy_enable(pdev, 0);
+
+ return ret;
+}
+
+static const struct dev_pm_ops hdmi_pm_ops = {
+#ifndef CONFIG_PM_GENERIC_DOMAINS
+ .suspend = hdmi_suspend,
+ .resume = hdmi_resume,
+#endif
+ .runtime_suspend = hdmi_runtime_suspend,
+ .runtime_resume = hdmi_runtime_resume,
+};
+
+static void hdmi_resources_cleanup(struct hdmi_device *hdev)
+{
+ struct hdmi_resources *res = &hdev->res;
+
+ dev_dbg(hdev->dev, "HDMI resource cleanup\n");
+ /* put clocks */
+ if (!IS_ERR_OR_NULL(res->sclk_hdmiphy))
+ clk_put(res->sclk_hdmiphy);
+ if (!IS_ERR_OR_NULL(res->sclk_pixel))
+ clk_put(res->sclk_pixel);
+ if (!IS_ERR_OR_NULL(res->sclk_hdmi))
+ clk_put(res->sclk_hdmi);
+ if (!IS_ERR_OR_NULL(res->hdmi))
+ clk_put(res->hdmi);
+ memset(res, 0, sizeof *res);
+}
+
+static int hdmi_resources_init(struct hdmi_device *hdev)
+{
+ struct device *dev = hdev->dev;
+ struct hdmi_resources *res = &hdev->res;
+
+ dev_dbg(dev, "HDMI resource init\n");
+
+ memset(res, 0, sizeof *res);
+ /* get clocks, power */
+
+ res->hdmi = clk_get(dev, "hdmi");
+ if (IS_ERR_OR_NULL(res->hdmi)) {
+ dev_err(dev, "failed to get clock 'hdmi'\n");
+ goto fail;
+ }
+ res->sclk_hdmi = clk_get(dev, "sclk_hdmi");
+ if (IS_ERR_OR_NULL(res->sclk_hdmi)) {
+ dev_err(dev, "failed to get clock 'sclk_hdmi'\n");
+ goto fail;
+ }
+ res->sclk_pixel = clk_get(dev, "sclk_pixel");
+ if (IS_ERR_OR_NULL(res->sclk_pixel)) {
+ dev_err(dev, "failed to get clock 'sclk_pixel'\n");
+ goto fail;
+ }
+ res->sclk_hdmiphy = clk_get(dev, "sclk_hdmiphy");
+ if (IS_ERR_OR_NULL(res->sclk_hdmiphy)) {
+ dev_err(dev, "failed to get clock 'sclk_hdmiphy'\n");
+ goto fail;
+ }
+
+ return 0;
+fail:
+ dev_err(dev, "HDMI resource init - failed\n");
+ hdmi_resources_cleanup(hdev);
+ return -ENODEV;
+}
+
+static int hdmi_link_setup(struct media_entity *entity,
+ const struct media_pad *local,
+ const struct media_pad *remote, u32 flags)
+{
+ return 0;
+}
+
+/* hdmi entity operations */
+static const struct media_entity_operations hdmi_entity_ops = {
+ .link_setup = hdmi_link_setup,
+};
+
+static int hdmi_register_entity(struct hdmi_device *hdev)
+{
+ struct v4l2_subdev *sd = &hdev->sd;
+ struct v4l2_device *v4l2_dev;
+ struct media_pad *pads = &hdev->pad;
+ struct media_entity *me = &sd->entity;
+ struct device *dev = hdev->dev;
+ struct exynos_md *md;
+ int ret;
+
+ dev_dbg(dev, "HDMI entity init\n");
+
+ /* init hdmi subdev */
+ v4l2_subdev_init(sd, &hdmi_sd_ops);
+ sd->owner = THIS_MODULE;
+ strlcpy(sd->name, "s5p-hdmi", sizeof(sd->name));
+
+ dev_set_drvdata(dev, sd);
+
+ /* init hdmi sub-device as entity */
+ pads[HDMI_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+ me->ops = &hdmi_entity_ops;
+ ret = media_entity_init(me, HDMI_PADS_NUM, pads, 0);
+ if (ret) {
+ dev_err(dev, "failed to initialize media entity\n");
+ return ret;
+ }
+
+ /* get output media ptr for registering hdmi's sd */
+ md = (struct exynos_md *)module_name_to_driver_data(MDEV_MODULE_NAME);
+ if (!md) {
+ dev_err(dev, "failed to get output media device\n");
+ return -ENODEV;
+ }
+
+ v4l2_dev = &md->v4l2_dev;
+
+ /* regiser HDMI subdev as entity to v4l2_dev pointer of
+ * output media device
+ */
+ ret = v4l2_device_register_subdev(v4l2_dev, sd);
+ if (ret) {
+ dev_err(dev, "failed to register HDMI subdev\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static void hdmi_entity_info_print(struct hdmi_device *hdev)
+{
+ struct v4l2_subdev *sd = &hdev->sd;
+ struct media_entity *me = &sd->entity;
+
+ dev_dbg(hdev->dev, "\n************* HDMI entity info **************\n");
+ dev_dbg(hdev->dev, "[SUB DEVICE INFO]\n");
+ entity_info_print(me, hdev->dev);
+ dev_dbg(hdev->dev, "*********************************************\n\n");
+}
+
+irqreturn_t hdmi_irq_handler_ext(int irq, void *dev_data)
+{
+ struct hdmi_device *hdev = dev_data;
+ queue_work(system_nrt_wq, &hdev->hpd_work_ext);
+
+ return IRQ_HANDLED;
+}
+
+static void hdmi_hpd_work_ext(struct work_struct *work)
+{
+ int state;
+ struct hdmi_device *hdev = container_of(work, struct hdmi_device,
+ hpd_work_ext);
+
+ state = s5p_v4l2_hpd_read_gpio();
+ switch_set_state(&hdev->hpd_switch, state);
+
+ dev_info(hdev->dev, "%s (ext)\n", state ? "plugged" : "unplugged");
+}
+
+static void hdmi_hpd_work(struct work_struct *work)
+{
+ int state;
+ struct hdmi_device *hdev = container_of(work, struct hdmi_device,
+ hpd_work);
+
+ state = hdmi_hpd_status(hdev);
+ switch_set_state(&hdev->hpd_switch, state);
+
+ dev_info(hdev->dev, "%s (int)\n", state ? "plugged" : "unplugged");
+}
+
+static int __devinit hdmi_probe(struct platform_device *pdev)
+{
+ struct s5p_hdmi_platdata *pdata;
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+ struct i2c_adapter *phy_adapter;
+ struct hdmi_device *hdmi_dev = NULL;
+ struct hdmi_driver_data *drv_data;
+ struct generic_pm_domain *genpd;
+ int ret;
+
+ dev_dbg(dev, "probe start\n");
+
+ hdmi_dev = kzalloc(sizeof(*hdmi_dev), GFP_KERNEL);
+ if (!hdmi_dev) {
+ dev_err(dev, "out of memory\n");
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ hdmi_dev->dev = dev;
+
+ ret = hdmi_resources_init(hdmi_dev);
+ if (ret)
+ goto fail_hdev;
+
+ /* mapping HDMI registers */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(dev, "get memory resource failed.\n");
+ ret = -ENXIO;
+ goto fail_init;
+ }
+
+ hdmi_dev->regs = ioremap(res->start, resource_size(res));
+ if (hdmi_dev->regs == NULL) {
+ dev_err(dev, "register mapping failed.\n");
+ ret = -ENXIO;
+ goto fail_hdev;
+ }
+
+ /* External hpd */
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (res == NULL) {
+ dev_err(dev, "get external interrupt resource failed.\n");
+ ret = -ENXIO;
+ goto fail_regs;
+ }
+ hdmi_dev->ext_irq = res->start;
+
+ /* Internal hpd */
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
+ if (res == NULL) {
+ dev_err(dev, "get internal interrupt resource failed.\n");
+ ret = -ENXIO;
+ goto fail_regs;
+ }
+ hdmi_dev->int_irq = res->start;
+
+ INIT_WORK(&hdmi_dev->hpd_work, hdmi_hpd_work);
+ INIT_WORK(&hdmi_dev->hpd_work_ext, hdmi_hpd_work_ext);
+
+ /* setting v4l2 name to prevent WARN_ON in v4l2_device_register */
+ strlcpy(hdmi_dev->v4l2_dev.name, dev_name(dev),
+ sizeof(hdmi_dev->v4l2_dev.name));
+ /* passing NULL owner prevents driver from erasing drvdata */
+ ret = v4l2_device_register(NULL, &hdmi_dev->v4l2_dev);
+ if (ret) {
+ dev_err(dev, "could not register v4l2 device.\n");
+ goto fail_regs;
+ }
+
+ drv_data = (struct hdmi_driver_data *)
+ platform_get_device_id(pdev)->driver_data;
+ dev_info(dev, "hdmiphy i2c bus number = %d\n", drv_data->hdmiphy_bus);
+
+ phy_adapter = i2c_get_adapter(drv_data->hdmiphy_bus);
+ if (phy_adapter == NULL) {
+ dev_err(dev, "adapter request failed\n");
+ ret = -ENXIO;
+ goto fail_vdev;
+ }
+
+ hdmi_dev->phy_sd = v4l2_i2c_new_subdev_board(&hdmi_dev->v4l2_dev,
+ phy_adapter, &hdmiphy_info, NULL);
+ /* on failure or not adapter is no longer useful */
+ i2c_put_adapter(phy_adapter);
+ if (hdmi_dev->phy_sd == NULL) {
+ dev_err(dev, "missing subdev for hdmiphy\n");
+ ret = -ENODEV;
+ goto fail_vdev;
+ }
+
+ pdata = pdev->dev.platform_data;
+
+ /* HDMI PHY power off
+ * HDMI PHY is on as default configuration
+ * So, HDMI PHY must be turned off if it's not used */
+ if (pdata->hdmiphy_enable)
+ pdata->hdmiphy_enable(pdev, 1);
+ v4l2_subdev_call(hdmi_dev->phy_sd, core, s_power, 0);
+ if (pdata->hdmiphy_enable)
+ pdata->hdmiphy_enable(pdev, 0);
+
+#ifdef CONFIG_PM_GENERIC_DOMAINS
+ genpd = dev_to_genpd(hdmi_dev->dev);
+ if (IS_ERR(genpd)) {
+ dev_err(dev, "failed get genpd\n");
+ goto fail_vdev;
+ }
+ genpd->domain.ops.suspend = hdmi_suspend;
+ genpd->domain.ops.resume = hdmi_resume;
+#endif
+
+ pm_runtime_enable(dev);
+
+ hdmi_dev->hpd_switch.name = "hdmi";
+ switch_dev_register(&hdmi_dev->hpd_switch);
+
+ ret = request_irq(hdmi_dev->int_irq, hdmi_irq_handler,
+ 0, "hdmi-int", hdmi_dev);
+ if (ret) {
+ dev_err(dev, "request int interrupt failed.\n");
+ goto fail_vdev;
+ }
+ disable_irq(hdmi_dev->int_irq);
+
+ s5p_v4l2_int_src_ext_hpd();
+ ret = request_irq(hdmi_dev->ext_irq, hdmi_irq_handler_ext,
+ IRQ_TYPE_EDGE_BOTH, "hdmi-ext", hdmi_dev);
+ if (ret) {
+ dev_err(dev, "request ext interrupt failed.\n");
+ goto fail_ext;
+ }
+
+ if (s5p_v4l2_hpd_read_gpio())
+ switch_set_state(&hdmi_dev->hpd_switch, 1);
+ else
+ switch_set_state(&hdmi_dev->hpd_switch, 0);
+
+ hdmi_dev->cur_preset = HDMI_DEFAULT_PRESET;
+ /* FIXME: missing fail preset is not supported */
+ hdmi_dev->cur_conf = hdmi_preset2conf(hdmi_dev->cur_preset);
+
+ /* default audio configuration : enable audio */
+ hdmi_dev->audio_enable = 1;
+ hdmi_dev->sample_rate = DEFAULT_SAMPLE_RATE;
+ hdmi_dev->bits_per_sample = DEFAULT_BITS_PER_SAMPLE;
+ hdmi_dev->audio_codec = DEFAULT_AUDIO_CODEC;
+
+ /* default aspect ratio is 16:9 */
+ hdmi_dev->aspect = HDMI_ASPECT_RATIO_16_9;
+
+ /* register hdmi subdev as entity */
+ ret = hdmi_register_entity(hdmi_dev);
+ if (ret)
+ goto fail_irq;
+
+ hdmi_entity_info_print(hdmi_dev);
+
+ /* initialize hdcp resource */
+ ret = hdcp_prepare(hdmi_dev);
+ if (ret)
+ goto fail_irq;
+
+ dev_info(dev, "probe sucessful\n");
+
+ return 0;
+
+fail_irq:
+ free_irq(hdmi_dev->ext_irq, hdmi_dev);
+
+fail_ext:
+ free_irq(hdmi_dev->int_irq, hdmi_dev);
+
+fail_vdev:
+ v4l2_device_unregister(&hdmi_dev->v4l2_dev);
+
+fail_regs:
+ iounmap(hdmi_dev->regs);
+
+fail_init:
+ hdmi_resources_cleanup(hdmi_dev);
+
+fail_hdev:
+ kfree(hdmi_dev);
+
+fail:
+ dev_err(dev, "probe failed\n");
+ return ret;
+}
+
+static int __devexit hdmi_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct hdmi_device *hdmi_dev = sd_to_hdmi_dev(sd);
+
+ pm_runtime_disable(dev);
+ clk_disable(hdmi_dev->res.hdmi);
+ v4l2_device_unregister(&hdmi_dev->v4l2_dev);
+ free_irq(hdmi_dev->ext_irq, hdmi_dev);
+ free_irq(hdmi_dev->int_irq, hdmi_dev);
+ switch_dev_unregister(&hdmi_dev->hpd_switch);
+ iounmap(hdmi_dev->regs);
+ hdmi_resources_cleanup(hdmi_dev);
+ flush_workqueue(hdmi_dev->hdcp_wq);
+ destroy_workqueue(hdmi_dev->hdcp_wq);
+ kfree(hdmi_dev);
+ dev_info(dev, "remove sucessful\n");
+
+ return 0;
+}
+
+static struct platform_driver hdmi_driver __refdata = {
+ .probe = hdmi_probe,
+ .remove = __devexit_p(hdmi_remove),
+ .id_table = hdmi_driver_types,
+ .driver = {
+ .name = "s5p-hdmi",
+ .owner = THIS_MODULE,
+ .pm = &hdmi_pm_ops,
+ }
+};
+
+/* D R I V E R I N I T I A L I Z A T I O N */
+
+static int __init hdmi_init(void)
+{
+ int ret;
+ static const char banner[] __initdata = KERN_INFO \
+ "Samsung HDMI output driver, "
+ "(c) 2010-2011 Samsung Electronics Co., Ltd.\n";
+ printk(banner);
+
+ ret = platform_driver_register(&hdmi_driver);
+ if (ret)
+ printk(KERN_ERR "HDMI platform driver register failed\n");
+
+ return ret;
+}
+module_init(hdmi_init);
+
+static void __exit hdmi_exit(void)
+{
+ platform_driver_unregister(&hdmi_driver);
+}
+module_exit(hdmi_exit);
+
+
diff --git a/drivers/media/video/exynos/tv/hdmi_reg_4210.c b/drivers/media/video/exynos/tv/hdmi_reg_4210.c
new file mode 100644
index 0000000..51a37c8
--- /dev/null
+++ b/drivers/media/video/exynos/tv/hdmi_reg_4210.c
@@ -0,0 +1,450 @@
+/*
+ * Samsung HDMI driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * Jiun Yu <jiun.yu@samsung.com>
+ *
+ * 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 Foundiation. either version 2 of the License,
+ * or (at your option) any later version
+ */
+
+#include <linux/delay.h>
+
+#include "hdmi.h"
+#include "regs-hdmi-4210.h"
+
+static const struct hdmi_preset_conf hdmi_conf_480p = {
+ .core = {
+ .h_blank = {0x8a, 0x00},
+ .v_blank = {0x0d, 0x6a, 0x01},
+ .h_v_line = {0x0d, 0xa2, 0x35},
+ .vsync_pol = {0x01},
+ .int_pro_mode = {0x00},
+ .v_blank_f = {0x00, 0x00, 0x00},
+ .h_sync_gen = {0x0e, 0x30, 0x11},
+ .v_sync_gen1 = {0x0f, 0x90, 0x00},
+ /* other don't care */
+ },
+ .tg = {
+ 0x00, /* cmd */
+ 0x5a, 0x03, /* h_fsz */
+ 0x8a, 0x00, 0xd0, 0x02, /* hact */
+ 0x0d, 0x02, /* v_fsz */
+ 0x01, 0x00, 0x33, 0x02, /* vsync */
+ 0x2d, 0x00, 0xe0, 0x01, /* vact */
+ 0x33, 0x02, /* field_chg */
+ 0x49, 0x02, /* vact_st2 */
+ 0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
+ 0x01, 0x00, 0x33, 0x02, /* field top/bot */
+ },
+ .mbus_fmt = {
+ .width = 720,
+ .height = 480,
+ .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+ .field = V4L2_FIELD_NONE,
+ },
+};
+
+static const struct hdmi_preset_conf hdmi_conf_720p60 = {
+ .core = {
+ .h_blank = {0x72, 0x01},
+ .v_blank = {0xee, 0xf2, 0x00},
+ .h_v_line = {0xee, 0x22, 0x67},
+ .vsync_pol = {0x00},
+ .int_pro_mode = {0x00},
+ .v_blank_f = {0x00, 0x00, 0x00}, /* don't care */
+ .h_sync_gen = {0x6c, 0x50, 0x02},
+ .v_sync_gen1 = {0x0a, 0x50, 0x00},
+ /* other don't care */
+ },
+ .tg = {
+ 0x00, /* cmd */
+ 0x72, 0x06, /* h_fsz */
+ 0x72, 0x01, 0x00, 0x05, /* hact */
+ 0xee, 0x02, /* v_fsz */
+ 0x01, 0x00, 0x33, 0x02, /* vsync */
+ 0x1e, 0x00, 0xd0, 0x02, /* vact */
+ 0x33, 0x02, /* field_chg */
+ 0x49, 0x02, /* vact_st2 */
+ 0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
+ 0x01, 0x00, 0x33, 0x02, /* field top/bot */
+ },
+ .mbus_fmt = {
+ .width = 1280,
+ .height = 720,
+ .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+ .field = V4L2_FIELD_NONE,
+ },
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080p50 = {
+ .core = {
+ .h_blank = {0xd0, 0x02},
+ .v_blank = {0x65, 0x6c, 0x01},
+ .h_v_line = {0x65, 0x04, 0xa5},
+ .vsync_pol = {0x00},
+ .int_pro_mode = {0x00},
+ .v_blank_f = {0x00, 0x00, 0x00}, /* don't care */
+ .h_sync_gen = {0x0e, 0xea, 0x08},
+ .v_sync_gen1 = {0x09, 0x40, 0x00},
+ /* other don't care */
+ },
+ .tg = {
+ 0x00, /* cmd */
+ 0x98, 0x08, /* h_fsz */
+ 0x18, 0x01, 0x80, 0x07, /* hact */
+ 0x65, 0x04, /* v_fsz */
+ 0x01, 0x00, 0x33, 0x02, /* vsync */
+ 0x2d, 0x00, 0x38, 0x04, /* vact */
+ 0x33, 0x02, /* field_chg */
+ 0x49, 0x02, /* vact_st2 */
+ 0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
+ 0x01, 0x00, 0x33, 0x02, /* field top/bot */
+ },
+ .mbus_fmt = {
+ .width = 1920,
+ .height = 1080,
+ .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+ .field = V4L2_FIELD_NONE,
+ },
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080p60 = {
+ .core = {
+ .h_blank = {0x18, 0x01},
+ .v_blank = {0x65, 0x6c, 0x01},
+ .h_v_line = {0x65, 0x84, 0x89},
+ .vsync_pol = {0x00},
+ .int_pro_mode = {0x00},
+ .v_blank_f = {0x00, 0x00, 0x00}, /* don't care */
+ .h_sync_gen = {0x56, 0x08, 0x02},
+ .v_sync_gen1 = {0x09, 0x40, 0x00},
+ /* other don't care */
+ },
+ .tg = {
+ 0x00, /* cmd */
+ 0x98, 0x08, /* h_fsz */
+ 0x18, 0x01, 0x80, 0x07, /* hact */
+ 0x65, 0x04, /* v_fsz */
+ 0x01, 0x00, 0x33, 0x02, /* vsync */
+ 0x2d, 0x00, 0x38, 0x04, /* vact */
+ 0x33, 0x02, /* field_chg */
+ 0x48, 0x02, /* vact_st2 */
+ 0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+ 0x01, 0x00, 0x33, 0x02, /* field top/bot */
+ },
+ .mbus_fmt = {
+ .width = 1920,
+ .height = 1080,
+ .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+ .field = V4L2_FIELD_NONE,
+ },
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080i60 = {
+ .core = {
+ .h_blank = {0x18, 0x01},
+ .v_blank = {0x32, 0xb2, 0x00},
+ .h_v_line = {0x65, 0x84, 0x89},
+ .vsync_pol = {0x00},
+ .int_pro_mode = {0x01},
+ .v_blank_f = {0x49, 0x2a, 0x23},
+ .h_sync_gen = {0x56, 0x08, 0x02},
+ .v_sync_gen1 = {0x07, 0x20, 0x00},
+ .v_sync_gen2 = {0x39, 0x42, 0x23},
+ .v_sync_gen3 = {0xa4, 0x44, 0x4a},
+ },
+ .tg = {
+ 0x00, /* cmd */
+ 0x98, 0x08, /* h_fsz */
+ 0x17, 0x01, 0x81, 0x07, /* hact */
+ 0x65, 0x04, /* v_fsz */
+ 0x01, 0x00, 0x33, 0x02, /* vsync */
+ 0x16, 0x00, 0x1c, 0x02, /* vact */
+ 0x33, 0x02, /* field_chg */
+ 0x49, 0x02, /* vact_st2 */
+ 0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
+ 0x01, 0x00, 0x33, 0x02, /* field top/bot */
+ },
+ .mbus_fmt = {
+ .width = 1920,
+ .height = 1080,
+ .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+ .field = V4L2_FIELD_INTERLACED,
+ },
+};
+
+const struct hdmi_conf hdmi_conf[] = {
+ { V4L2_DV_480P59_94, &hdmi_conf_480p },
+ { V4L2_DV_720P59_94, &hdmi_conf_720p60 },
+ { V4L2_DV_1080P50, &hdmi_conf_1080p50 },
+ { V4L2_DV_1080P30, &hdmi_conf_1080p60 },
+ { V4L2_DV_1080P60, &hdmi_conf_1080p60 },
+ { V4L2_DV_1080I60, &hdmi_conf_1080i60 },
+};
+
+const int hdmi_pre_cnt = ARRAY_SIZE(hdmi_conf);
+
+irqreturn_t hdmi_irq_handler(int irq, void *dev_data)
+{
+ struct hdmi_device *hdev = dev_data;
+ u32 intc_flag;
+
+ (void)irq;
+ intc_flag = hdmi_read(hdev, HDMI_INTC_FLAG);
+ /* clearing flags for HPD plug/unplug */
+ if (intc_flag & HDMI_INTC_FLAG_HPD_UNPLUG) {
+ printk(KERN_INFO "unplugged\n");
+ hdmi_write_mask(hdev, HDMI_INTC_FLAG, ~0,
+ HDMI_INTC_FLAG_HPD_UNPLUG);
+ }
+ if (intc_flag & HDMI_INTC_FLAG_HPD_PLUG) {
+ printk(KERN_INFO "plugged\n");
+ hdmi_write_mask(hdev, HDMI_INTC_FLAG, ~0,
+ HDMI_INTC_FLAG_HPD_PLUG);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void hdmi_reg_init(struct hdmi_device *hdev)
+{
+ /* enable HPD interrupts */
+ hdmi_write_mask(hdev, HDMI_INTC_CON, ~0, HDMI_INTC_EN_GLOBAL |
+ HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG);
+ /* choose HDMI mode */
+ hdmi_write_mask(hdev, HDMI_MODE_SEL,
+ HDMI_MODE_HDMI_EN, HDMI_MODE_MASK);
+ /* disable bluescreen */
+ hdmi_write_mask(hdev, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN);
+ /* choose bluescreen (fecal) color */
+ hdmi_writeb(hdev, HDMI_BLUE_SCREEN_0, 0x12);
+ hdmi_writeb(hdev, HDMI_BLUE_SCREEN_1, 0x34);
+ hdmi_writeb(hdev, HDMI_BLUE_SCREEN_2, 0x56);
+ /* enable AVI packet every vsync, fixes purple line problem */
+ hdmi_writeb(hdev, HDMI_AVI_CON, 0x02);
+ /* force YUV444, look to CEA-861-D, table 7 for more detail */
+ hdmi_writeb(hdev, HDMI_AVI_BYTE(0), 2 << 5);
+ hdmi_write_mask(hdev, HDMI_CON_1, 2, 3 << 5);
+}
+
+static void hdmi_timing_apply(struct hdmi_device *hdev,
+ const struct hdmi_preset_conf *conf)
+{
+ const struct hdmi_core_regs *core = &conf->core;
+ const struct hdmi_tg_regs *tg = &conf->tg;
+
+ /* setting core registers */
+ hdmi_writeb(hdev, HDMI_H_BLANK_0, core->h_blank[0]);
+ hdmi_writeb(hdev, HDMI_H_BLANK_1, core->h_blank[1]);
+ hdmi_writeb(hdev, HDMI_V_BLANK_0, core->v_blank[0]);
+ hdmi_writeb(hdev, HDMI_V_BLANK_1, core->v_blank[1]);
+ hdmi_writeb(hdev, HDMI_V_BLANK_2, core->v_blank[2]);
+ hdmi_writeb(hdev, HDMI_H_V_LINE_0, core->h_v_line[0]);
+ hdmi_writeb(hdev, HDMI_H_V_LINE_1, core->h_v_line[1]);
+ hdmi_writeb(hdev, HDMI_H_V_LINE_2, core->h_v_line[2]);
+ hdmi_writeb(hdev, HDMI_VSYNC_POL, core->vsync_pol[0]);
+ hdmi_writeb(hdev, HDMI_INT_PRO_MODE, core->int_pro_mode[0]);
+ hdmi_writeb(hdev, HDMI_V_BLANK_F_0, core->v_blank_f[0]);
+ hdmi_writeb(hdev, HDMI_V_BLANK_F_1, core->v_blank_f[1]);
+ hdmi_writeb(hdev, HDMI_V_BLANK_F_2, core->v_blank_f[2]);
+ hdmi_writeb(hdev, HDMI_H_SYNC_GEN_0, core->h_sync_gen[0]);
+ hdmi_writeb(hdev, HDMI_H_SYNC_GEN_1, core->h_sync_gen[1]);
+ hdmi_writeb(hdev, HDMI_H_SYNC_GEN_2, core->h_sync_gen[2]);
+ hdmi_writeb(hdev, HDMI_V_SYNC_GEN_1_0, core->v_sync_gen1[0]);
+ hdmi_writeb(hdev, HDMI_V_SYNC_GEN_1_1, core->v_sync_gen1[1]);
+ hdmi_writeb(hdev, HDMI_V_SYNC_GEN_1_2, core->v_sync_gen1[2]);
+ hdmi_writeb(hdev, HDMI_V_SYNC_GEN_2_0, core->v_sync_gen2[0]);
+ hdmi_writeb(hdev, HDMI_V_SYNC_GEN_2_1, core->v_sync_gen2[1]);
+ hdmi_writeb(hdev, HDMI_V_SYNC_GEN_2_2, core->v_sync_gen2[2]);
+ hdmi_writeb(hdev, HDMI_V_SYNC_GEN_3_0, core->v_sync_gen3[0]);
+ hdmi_writeb(hdev, HDMI_V_SYNC_GEN_3_1, core->v_sync_gen3[1]);
+ hdmi_writeb(hdev, HDMI_V_SYNC_GEN_3_2, core->v_sync_gen3[2]);
+ /* Timing generator registers */
+ hdmi_writeb(hdev, HDMI_TG_H_FSZ_L, tg->h_fsz_l);
+ hdmi_writeb(hdev, HDMI_TG_H_FSZ_H, tg->h_fsz_h);
+ hdmi_writeb(hdev, HDMI_TG_HACT_ST_L, tg->hact_st_l);
+ hdmi_writeb(hdev, HDMI_TG_HACT_ST_H, tg->hact_st_h);
+ hdmi_writeb(hdev, HDMI_TG_HACT_SZ_L, tg->hact_sz_l);
+ hdmi_writeb(hdev, HDMI_TG_HACT_SZ_H, tg->hact_sz_h);
+ hdmi_writeb(hdev, HDMI_TG_V_FSZ_L, tg->v_fsz_l);
+ hdmi_writeb(hdev, HDMI_TG_V_FSZ_H, tg->v_fsz_h);
+ hdmi_writeb(hdev, HDMI_TG_VSYNC_L, tg->vsync_l);
+ hdmi_writeb(hdev, HDMI_TG_VSYNC_H, tg->vsync_h);
+ hdmi_writeb(hdev, HDMI_TG_VSYNC2_L, tg->vsync2_l);
+ hdmi_writeb(hdev, HDMI_TG_VSYNC2_H, tg->vsync2_h);
+ hdmi_writeb(hdev, HDMI_TG_VACT_ST_L, tg->vact_st_l);
+ hdmi_writeb(hdev, HDMI_TG_VACT_ST_H, tg->vact_st_h);
+ hdmi_writeb(hdev, HDMI_TG_VACT_SZ_L, tg->vact_sz_l);
+ hdmi_writeb(hdev, HDMI_TG_VACT_SZ_H, tg->vact_sz_h);
+ hdmi_writeb(hdev, HDMI_TG_FIELD_CHG_L, tg->field_chg_l);
+ hdmi_writeb(hdev, HDMI_TG_FIELD_CHG_H, tg->field_chg_h);
+ hdmi_writeb(hdev, HDMI_TG_VACT_ST2_L, tg->vact_st2_l);
+ hdmi_writeb(hdev, HDMI_TG_VACT_ST2_H, tg->vact_st2_h);
+ hdmi_writeb(hdev, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi_l);
+ hdmi_writeb(hdev, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi_h);
+ hdmi_writeb(hdev, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi_l);
+ hdmi_writeb(hdev, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi_h);
+ hdmi_writeb(hdev, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi_l);
+ hdmi_writeb(hdev, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi_h);
+ hdmi_writeb(hdev, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi_l);
+ hdmi_writeb(hdev, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi_h);
+}
+
+int hdmi_conf_apply(struct hdmi_device *hdmi_dev)
+{
+ struct device *dev = hdmi_dev->dev;
+ const struct hdmi_preset_conf *conf = hdmi_dev->cur_conf;
+ struct v4l2_dv_preset preset;
+ int ret;
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ /* reset hdmiphy */
+ hdmi_write_mask(hdmi_dev, HDMI_PHY_RSTOUT, ~0, HDMI_PHY_SW_RSTOUT);
+ mdelay(10);
+ hdmi_write_mask(hdmi_dev, HDMI_PHY_RSTOUT, 0, HDMI_PHY_SW_RSTOUT);
+ mdelay(10);
+
+ /* configure presets */
+ preset.preset = hdmi_dev->cur_preset;
+ ret = v4l2_subdev_call(hdmi_dev->phy_sd, video, s_dv_preset, &preset);
+ if (ret) {
+ dev_err(dev, "failed to set preset (%u)\n", preset.preset);
+ return ret;
+ }
+
+ /* resetting HDMI core */
+ hdmi_write_mask(hdmi_dev, HDMI_CORE_RSTOUT, 0, HDMI_CORE_SW_RSTOUT);
+ mdelay(10);
+ hdmi_write_mask(hdmi_dev, HDMI_CORE_RSTOUT, ~0, HDMI_CORE_SW_RSTOUT);
+ mdelay(10);
+
+ hdmi_reg_init(hdmi_dev);
+
+ /* setting core registers */
+ hdmi_timing_apply(hdmi_dev, conf);
+
+ return 0;
+}
+
+int is_hdmiphy_ready(struct hdmi_device *hdev)
+{
+ u32 val = hdmi_read(hdev, HDMI_PHY_STATUS);
+ if (val & HDMI_PHY_STATUS_READY)
+ return 1;
+
+ return 0;
+}
+
+void hdmi_enable(struct hdmi_device *hdev, int on)
+{
+ if (on)
+ hdmi_write_mask(hdev, HDMI_CON_0, ~0, HDMI_EN);
+ else
+ hdmi_write_mask(hdev, HDMI_CON_0, 0, HDMI_EN);
+}
+
+void hdmi_tg_enable(struct hdmi_device *hdev, int on)
+{
+ u32 mask;
+
+ mask = (hdev->cur_conf->mbus_fmt.field == V4L2_FIELD_INTERLACED) ?
+ HDMI_TG_EN | HDMI_FIELD_EN : HDMI_TG_EN;
+
+ if (on)
+ hdmi_write_mask(hdev, HDMI_TG_CMD, ~0, mask);
+ else
+ hdmi_write_mask(hdev, HDMI_TG_CMD, 0, mask);
+}
+
+void hdmi_dumpregs(struct hdmi_device *hdev, char *prefix)
+{
+#define DUMPREG(reg_id) \
+ dev_dbg(hdev->dev, "%s:" #reg_id " = %08x\n", prefix, \
+ readl(hdev->regs + reg_id))
+
+ dev_dbg(hdev->dev, "%s: ---- CONTROL REGISTERS ----\n", prefix);
+ DUMPREG(HDMI_INTC_FLAG);
+ DUMPREG(HDMI_INTC_CON);
+ DUMPREG(HDMI_HPD_STATUS);
+ DUMPREG(HDMI_PHY_RSTOUT);
+ DUMPREG(HDMI_PHY_VPLL);
+ DUMPREG(HDMI_PHY_CMU);
+ DUMPREG(HDMI_CORE_RSTOUT);
+
+ dev_dbg(hdev->dev, "%s: ---- CORE REGISTERS ----\n", prefix);
+ DUMPREG(HDMI_CON_0);
+ DUMPREG(HDMI_CON_1);
+ DUMPREG(HDMI_CON_2);
+ DUMPREG(HDMI_SYS_STATUS);
+ DUMPREG(HDMI_PHY_STATUS);
+ DUMPREG(HDMI_STATUS_EN);
+ DUMPREG(HDMI_HPD);
+ DUMPREG(HDMI_MODE_SEL);
+ DUMPREG(HDMI_HPD_GEN);
+ DUMPREG(HDMI_DC_CONTROL);
+ DUMPREG(HDMI_VIDEO_PATTERN_GEN);
+
+ dev_dbg(hdev->dev, "%s: ---- CORE SYNC REGISTERS ----\n", prefix);
+ DUMPREG(HDMI_H_BLANK_0);
+ DUMPREG(HDMI_H_BLANK_1);
+ DUMPREG(HDMI_V_BLANK_0);
+ DUMPREG(HDMI_V_BLANK_1);
+ DUMPREG(HDMI_V_BLANK_2);
+ DUMPREG(HDMI_H_V_LINE_0);
+ DUMPREG(HDMI_H_V_LINE_1);
+ DUMPREG(HDMI_H_V_LINE_2);
+ DUMPREG(HDMI_VSYNC_POL);
+ DUMPREG(HDMI_INT_PRO_MODE);
+ DUMPREG(HDMI_V_BLANK_F_0);
+ DUMPREG(HDMI_V_BLANK_F_1);
+ DUMPREG(HDMI_V_BLANK_F_2);
+ DUMPREG(HDMI_H_SYNC_GEN_0);
+ DUMPREG(HDMI_H_SYNC_GEN_1);
+ DUMPREG(HDMI_H_SYNC_GEN_2);
+ DUMPREG(HDMI_V_SYNC_GEN_1_0);
+ DUMPREG(HDMI_V_SYNC_GEN_1_1);
+ DUMPREG(HDMI_V_SYNC_GEN_1_2);
+ DUMPREG(HDMI_V_SYNC_GEN_2_0);
+ DUMPREG(HDMI_V_SYNC_GEN_2_1);
+ DUMPREG(HDMI_V_SYNC_GEN_2_2);
+ DUMPREG(HDMI_V_SYNC_GEN_3_0);
+ DUMPREG(HDMI_V_SYNC_GEN_3_1);
+ DUMPREG(HDMI_V_SYNC_GEN_3_2);
+
+ dev_dbg(hdev->dev, "%s: ---- TG REGISTERS ----\n", prefix);
+ DUMPREG(HDMI_TG_CMD);
+ DUMPREG(HDMI_TG_H_FSZ_L);
+ DUMPREG(HDMI_TG_H_FSZ_H);
+ DUMPREG(HDMI_TG_HACT_ST_L);
+ DUMPREG(HDMI_TG_HACT_ST_H);
+ DUMPREG(HDMI_TG_HACT_SZ_L);
+ DUMPREG(HDMI_TG_HACT_SZ_H);
+ DUMPREG(HDMI_TG_V_FSZ_L);
+ DUMPREG(HDMI_TG_V_FSZ_H);
+ DUMPREG(HDMI_TG_VSYNC_L);
+ DUMPREG(HDMI_TG_VSYNC_H);
+ DUMPREG(HDMI_TG_VSYNC2_L);
+ DUMPREG(HDMI_TG_VSYNC2_H);
+ DUMPREG(HDMI_TG_VACT_ST_L);
+ DUMPREG(HDMI_TG_VACT_ST_H);
+ DUMPREG(HDMI_TG_VACT_SZ_L);
+ DUMPREG(HDMI_TG_VACT_SZ_H);
+ DUMPREG(HDMI_TG_FIELD_CHG_L);
+ DUMPREG(HDMI_TG_FIELD_CHG_H);
+ DUMPREG(HDMI_TG_VACT_ST2_L);
+ DUMPREG(HDMI_TG_VACT_ST2_H);
+ DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
+ DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
+ DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
+ DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
+ DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
+ DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
+ DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
+ DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
+#undef DUMPREG
+}
diff --git a/drivers/media/video/exynos/tv/hdmi_reg_5250.c b/drivers/media/video/exynos/tv/hdmi_reg_5250.c
new file mode 100644
index 0000000..3120a7a
--- /dev/null
+++ b/drivers/media/video/exynos/tv/hdmi_reg_5250.c
@@ -0,0 +1,3029 @@
+/*
+ * Samsung HDMI driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * Jiun Yu <jiun.yu@samsung.com>
+ *
+ * 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 Foundiation. either version 2 of the License,
+ * or (at your option) any later version
+ */
+
+#include "hdmi.h"
+#include <linux/delay.h>
+#include <linux/pm_runtime.h>
+#include <plat/devs.h>
+#include <plat/tv-core.h>
+
+#include "regs-hdmi-5250.h"
+
+static const struct hdmi_preset_conf hdmi_conf_480p60 = {
+ .core = {
+ .h_blank = {0x8a, 0x00},
+ .v2_blank = {0x0d, 0x02},
+ .v1_blank = {0x2d, 0x00},
+ .v_line = {0x0d, 0x02},
+ .h_line = {0x5a, 0x03},
+ .hsync_pol = {0x01},
+ .vsync_pol = {0x01},
+ .int_pro_mode = {0x00},
+ .v_blank_f0 = {0xff, 0xff},
+ .v_blank_f1 = {0xff, 0xff},
+ .h_sync_start = {0x0e, 0x00},
+ .h_sync_end = {0x4c, 0x00},
+ .v_sync_line_bef_2 = {0x0f, 0x00},
+ .v_sync_line_bef_1 = {0x09, 0x00},
+ .v_sync_line_aft_2 = {0xff, 0xff},
+ .v_sync_line_aft_1 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_2 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_1 = {0xff, 0xff},
+ .v_blank_f2 = {0xff, 0xff},
+ .v_blank_f3 = {0xff, 0xff},
+ .v_blank_f4 = {0xff, 0xff},
+ .v_blank_f5 = {0xff, 0xff},
+ .v_sync_line_aft_3 = {0xff, 0xff},
+ .v_sync_line_aft_4 = {0xff, 0xff},
+ .v_sync_line_aft_5 = {0xff, 0xff},
+ .v_sync_line_aft_6 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+ .vact_space_1 = {0xff, 0xff},
+ .vact_space_2 = {0xff, 0xff},
+ .vact_space_3 = {0xff, 0xff},
+ .vact_space_4 = {0xff, 0xff},
+ .vact_space_5 = {0xff, 0xff},
+ .vact_space_6 = {0xff, 0xff},
+ /* other don't care */
+ },
+ .tg = {
+ 0x00, /* cmd */
+ 0x5a, 0x03, /* h_fsz */
+ 0x8a, 0x00, 0xd0, 0x02, /* hact */
+ 0x0d, 0x02, /* v_fsz */
+ 0x01, 0x00, 0x33, 0x02, /* vsync */
+ 0x2d, 0x00, 0xe0, 0x01, /* vact */
+ 0x33, 0x02, /* field_chg */
+ 0x48, 0x02, /* vact_st2 */
+ 0x00, 0x00, /* vact_st3 */
+ 0x00, 0x00, /* vact_st4 */
+ 0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+ 0x01, 0x00, 0x33, 0x02, /* field top/bot */
+ 0x00, /* 3d FP */
+ },
+ .mbus_fmt = {
+ .width = 720,
+ .height = 480,
+ .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+ .field = V4L2_FIELD_NONE,
+ },
+ .vic = 3,
+};
+
+static const struct hdmi_preset_conf hdmi_conf_720p60 = {
+ .core = {
+ .h_blank = {0x72, 0x01},
+ .v2_blank = {0xee, 0x02},
+ .v1_blank = {0x1e, 0x00},
+ .v_line = {0xee, 0x02},
+ .h_line = {0x72, 0x06},
+ .hsync_pol = {0x00},
+ .vsync_pol = {0x00},
+ .int_pro_mode = {0x00},
+ .v_blank_f0 = {0xff, 0xff},
+ .v_blank_f1 = {0xff, 0xff},
+ .h_sync_start = {0x6c, 0x00},
+ .h_sync_end = {0x94, 0x00},
+ .v_sync_line_bef_2 = {0x0a, 0x00},
+ .v_sync_line_bef_1 = {0x05, 0x00},
+ .v_sync_line_aft_2 = {0xff, 0xff},
+ .v_sync_line_aft_1 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_2 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_1 = {0xff, 0xff},
+ .v_blank_f2 = {0xff, 0xff},
+ .v_blank_f3 = {0xff, 0xff},
+ .v_blank_f4 = {0xff, 0xff},
+ .v_blank_f5 = {0xff, 0xff},
+ .v_sync_line_aft_3 = {0xff, 0xff},
+ .v_sync_line_aft_4 = {0xff, 0xff},
+ .v_sync_line_aft_5 = {0xff, 0xff},
+ .v_sync_line_aft_6 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+ .vact_space_1 = {0xff, 0xff},
+ .vact_space_2 = {0xff, 0xff},
+ .vact_space_3 = {0xff, 0xff},
+ .vact_space_4 = {0xff, 0xff},
+ .vact_space_5 = {0xff, 0xff},
+ .vact_space_6 = {0xff, 0xff},
+ /* other don't care */
+ },
+ .tg = {
+ 0x00, /* cmd */
+ 0x72, 0x06, /* h_fsz */
+ 0x72, 0x01, 0x00, 0x05, /* hact */
+ 0xee, 0x02, /* v_fsz */
+ 0x01, 0x00, 0x33, 0x02, /* vsync */
+ 0x1e, 0x00, 0xd0, 0x02, /* vact */
+ 0x33, 0x02, /* field_chg */
+ 0x48, 0x02, /* vact_st2 */
+ 0x00, 0x00, /* vact_st3 */
+ 0x00, 0x00, /* vact_st4 */
+ 0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+ 0x01, 0x00, 0x33, 0x02, /* field top/bot */
+ 0x00, /* 3d FP */
+ },
+ .mbus_fmt = {
+ .width = 1280,
+ .height = 720,
+ .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+ .field = V4L2_FIELD_NONE,
+ },
+ .vic = 4,
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080i60 = {
+ .core = {
+ .h_blank = {0x18, 0x01},
+ .v2_blank = {0x32, 0x02},
+ .v1_blank = {0x16, 0x00},
+ .v_line = {0x65, 0x04},
+ .h_line = {0x98, 0x08},
+ .hsync_pol = {0x00},
+ .vsync_pol = {0x00},
+ .int_pro_mode = {0x01},
+ .v_blank_f0 = {0x49, 0x02},
+ .v_blank_f1 = {0x65, 0x04},
+ .h_sync_start = {0x56, 0x00},
+ .h_sync_end = {0x82, 0x00},
+ .v_sync_line_bef_2 = {0x07, 0x00},
+ .v_sync_line_bef_1 = {0x02, 0x00},
+ .v_sync_line_aft_2 = {0x39, 0x02},
+ .v_sync_line_aft_1 = {0x34, 0x02},
+ .v_sync_line_aft_pxl_2 = {0xa4, 0x04},
+ .v_sync_line_aft_pxl_1 = {0xa4, 0x04},
+ .v_blank_f2 = {0xff, 0xff},
+ .v_blank_f3 = {0xff, 0xff},
+ .v_blank_f4 = {0xff, 0xff},
+ .v_blank_f5 = {0xff, 0xff},
+ .v_sync_line_aft_3 = {0xff, 0xff},
+ .v_sync_line_aft_4 = {0xff, 0xff},
+ .v_sync_line_aft_5 = {0xff, 0xff},
+ .v_sync_line_aft_6 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+ .vact_space_1 = {0xff, 0xff},
+ .vact_space_2 = {0xff, 0xff},
+ .vact_space_3 = {0xff, 0xff},
+ .vact_space_4 = {0xff, 0xff},
+ .vact_space_5 = {0xff, 0xff},
+ .vact_space_6 = {0xff, 0xff},
+ /* other don't care */
+ },
+ .tg = {
+ 0x00, /* cmd */
+ 0x98, 0x08, /* h_fsz */
+ 0x18, 0x01, 0x80, 0x07, /* hact */
+ 0x65, 0x04, /* v_fsz */
+ 0x01, 0x00, 0x33, 0x02, /* vsync */
+ 0x16, 0x00, 0x1c, 0x02, /* vact */
+ 0x33, 0x02, /* field_chg */
+ 0x49, 0x02, /* vact_st2 */
+ 0x00, 0x00, /* vact_st3 */
+ 0x00, 0x00, /* vact_st4 */
+ 0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
+ 0x01, 0x00, 0x33, 0x02, /* field top/bot */
+ 0x00, /* 3d FP */
+ },
+ .mbus_fmt = {
+ .width = 1920,
+ .height = 1080,
+ .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+ .field = V4L2_FIELD_INTERLACED,
+ },
+ .vic = 5,
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080p60 = {
+ .core = {
+ .h_blank = {0x18, 0x01},
+ .v2_blank = {0x65, 0x04},
+ .v1_blank = {0x2d, 0x00},
+ .v_line = {0x65, 0x04},
+ .h_line = {0x98, 0x08},
+ .hsync_pol = {0x00},
+ .vsync_pol = {0x00},
+ .int_pro_mode = {0x00},
+ .v_blank_f0 = {0xff, 0xff},
+ .v_blank_f1 = {0xff, 0xff},
+ .h_sync_start = {0x56, 0x00},
+ .h_sync_end = {0x82, 0x00},
+ .v_sync_line_bef_2 = {0x09, 0x00},
+ .v_sync_line_bef_1 = {0x04, 0x00},
+ .v_sync_line_aft_2 = {0xff, 0xff},
+ .v_sync_line_aft_1 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_2 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_1 = {0xff, 0xff},
+ .v_blank_f2 = {0xff, 0xff},
+ .v_blank_f3 = {0xff, 0xff},
+ .v_blank_f4 = {0xff, 0xff},
+ .v_blank_f5 = {0xff, 0xff},
+ .v_sync_line_aft_3 = {0xff, 0xff},
+ .v_sync_line_aft_4 = {0xff, 0xff},
+ .v_sync_line_aft_5 = {0xff, 0xff},
+ .v_sync_line_aft_6 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+ /* other don't care */
+ },
+ .tg = {
+ 0x00, /* cmd */
+ 0x98, 0x08, /* h_fsz */
+ 0x18, 0x01, 0x80, 0x07, /* hact */
+ 0x65, 0x04, /* v_fsz */
+ 0x01, 0x00, 0x33, 0x02, /* vsync */
+ 0x2d, 0x00, 0x38, 0x04, /* vact */
+ 0x33, 0x02, /* field_chg */
+ 0x48, 0x02, /* vact_st2 */
+ 0x00, 0x00, /* vact_st3 */
+ 0x00, 0x00, /* vact_st4 */
+ 0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+ 0x01, 0x00, 0x33, 0x02, /* field top/bot */
+ 0x00, /* 3d FP */
+ },
+ .mbus_fmt = {
+ .width = 1920,
+ .height = 1080,
+ .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+ .field = V4L2_FIELD_NONE,
+ },
+ .vic = 16,
+};
+
+static const struct hdmi_preset_conf hdmi_conf_576p50 = {
+ .core = {
+ .h_blank = {0x90, 0x00},
+ .v2_blank = {0x71, 0x02},
+ .v1_blank = {0x31, 0x00},
+ .v_line = {0x71, 0x02},
+ .h_line = {0x60, 0x03},
+ .hsync_pol = {0x01},
+ .vsync_pol = {0x01},
+ .int_pro_mode = {0x00},
+ .v_blank_f0 = {0xff, 0xff},
+ .v_blank_f1 = {0xff, 0xff},
+ .h_sync_start = {0x0a, 0x00},
+ .h_sync_end = {0x4a, 0x00},
+ .v_sync_line_bef_2 = {0x0a, 0x00},
+ .v_sync_line_bef_1 = {0x05, 0x00},
+ .v_sync_line_aft_2 = {0xff, 0xff},
+ .v_sync_line_aft_1 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_2 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_1 = {0xff, 0xff},
+ .v_blank_f2 = {0xff, 0xff},
+ .v_blank_f3 = {0xff, 0xff},
+ .v_blank_f4 = {0xff, 0xff},
+ .v_blank_f5 = {0xff, 0xff},
+ .v_sync_line_aft_3 = {0xff, 0xff},
+ .v_sync_line_aft_4 = {0xff, 0xff},
+ .v_sync_line_aft_5 = {0xff, 0xff},
+ .v_sync_line_aft_6 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+ /* other don't care */
+ },
+ .tg = {
+ 0x00, /* cmd */
+ 0x60, 0x03, /* h_fsz */
+ 0x90, 0x00, 0xd0, 0x02, /* hact */
+ 0x71, 0x02, /* v_fsz */
+ 0x01, 0x00, 0x33, 0x02, /* vsync */
+ 0x31, 0x00, 0x40, 0x02, /* vact */
+ 0x33, 0x02, /* field_chg */
+ 0x48, 0x02, /* vact_st2 */
+ 0x00, 0x00, /* vact_st3 */
+ 0x00, 0x00, /* vact_st4 */
+ 0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+ 0x01, 0x00, 0x33, 0x02, /* field top/bot */
+ 0x00, /* 3d FP */
+ },
+ .mbus_fmt = {
+ .width = 720,
+ .height = 576,
+ .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+ .field = V4L2_FIELD_NONE,
+ },
+ .vic = 18,
+};
+
+static const struct hdmi_preset_conf hdmi_conf_720p50 = {
+ .core = {
+ .h_blank = {0xbc, 0x02},
+ .v2_blank = {0xee, 0x02},
+ .v1_blank = {0x1e, 0x00},
+ .v_line = {0xee, 0x02},
+ .h_line = {0xbc, 0x07},
+ .hsync_pol = {0x00},
+ .vsync_pol = {0x00},
+ .int_pro_mode = {0x00},
+ .v_blank_f0 = {0xff, 0xff},
+ .v_blank_f1 = {0xff, 0xff},
+ .h_sync_start = {0xb6, 0x01},
+ .h_sync_end = {0xde, 0x01},
+ .v_sync_line_bef_2 = {0x0a, 0x00},
+ .v_sync_line_bef_1 = {0x05, 0x00},
+ .v_sync_line_aft_2 = {0xff, 0xff},
+ .v_sync_line_aft_1 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_2 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_1 = {0xff, 0xff},
+ .v_blank_f2 = {0xff, 0xff},
+ .v_blank_f3 = {0xff, 0xff},
+ .v_blank_f4 = {0xff, 0xff},
+ .v_blank_f5 = {0xff, 0xff},
+ .v_sync_line_aft_3 = {0xff, 0xff},
+ .v_sync_line_aft_4 = {0xff, 0xff},
+ .v_sync_line_aft_5 = {0xff, 0xff},
+ .v_sync_line_aft_6 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+ .vact_space_1 = {0xff, 0xff},
+ .vact_space_2 = {0xff, 0xff},
+ .vact_space_3 = {0xff, 0xff},
+ .vact_space_4 = {0xff, 0xff},
+ .vact_space_5 = {0xff, 0xff},
+ .vact_space_6 = {0xff, 0xff},
+ /* other don't care */
+ },
+ .tg = {
+ 0x00, /* cmd */
+ 0xbc, 0x07, /* h_fsz */
+ 0xbc, 0x02, 0x00, 0x05, /* hact */
+ 0xee, 0x02, /* v_fsz */
+ 0x01, 0x00, 0x33, 0x02, /* vsync */
+ 0x1e, 0x00, 0xd0, 0x02, /* vact */
+ 0x33, 0x02, /* field_chg */
+ 0x48, 0x02, /* vact_st2 */
+ 0x00, 0x00, /* vact_st3 */
+ 0x00, 0x00, /* vact_st4 */
+ 0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+ 0x01, 0x00, 0x33, 0x02, /* field top/bot */
+ 0x00, /* 3d FP */
+ },
+ .mbus_fmt = {
+ .width = 1280,
+ .height = 720,
+ .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+ .field = V4L2_FIELD_NONE,
+ },
+ .vic = 19,
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080i50 = {
+ .core = {
+ .h_blank = {0xd0, 0x02},
+ .v2_blank = {0x32, 0x02},
+ .v1_blank = {0x16, 0x00},
+ .v_line = {0x65, 0x04},
+ .h_line = {0x50, 0x0a},
+ .hsync_pol = {0x00},
+ .vsync_pol = {0x00},
+ .int_pro_mode = {0x01},
+ .v_blank_f0 = {0x49, 0x02},
+ .v_blank_f1 = {0x65, 0x04},
+ .h_sync_start = {0x0e, 0x02},
+ .h_sync_end = {0x3a, 0x02},
+ .v_sync_line_bef_2 = {0x07, 0x00},
+ .v_sync_line_bef_1 = {0x02, 0x00},
+ .v_sync_line_aft_2 = {0x39, 0x02},
+ .v_sync_line_aft_1 = {0x34, 0x02},
+ .v_sync_line_aft_pxl_2 = {0x38, 0x07},
+ .v_sync_line_aft_pxl_1 = {0x38, 0x07},
+ .v_blank_f2 = {0xff, 0xff},
+ .v_blank_f3 = {0xff, 0xff},
+ .v_blank_f4 = {0xff, 0xff},
+ .v_blank_f5 = {0xff, 0xff},
+ .v_sync_line_aft_3 = {0xff, 0xff},
+ .v_sync_line_aft_4 = {0xff, 0xff},
+ .v_sync_line_aft_5 = {0xff, 0xff},
+ .v_sync_line_aft_6 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+ .vact_space_1 = {0xff, 0xff},
+ .vact_space_2 = {0xff, 0xff},
+ .vact_space_3 = {0xff, 0xff},
+ .vact_space_4 = {0xff, 0xff},
+ .vact_space_5 = {0xff, 0xff},
+ .vact_space_6 = {0xff, 0xff},
+ /* other don't care */
+ },
+ .tg = {
+ 0x00, /* cmd */
+ 0x50, 0x0a, /* h_fsz */
+ 0xd0, 0x02, 0x80, 0x07, /* hact */
+ 0x65, 0x04, /* v_fsz */
+ 0x01, 0x00, 0x33, 0x02, /* vsync */
+ 0x16, 0x00, 0x1c, 0x02, /* vact */
+ 0x33, 0x02, /* field_chg */
+ 0x49, 0x02, /* vact_st2 */
+ 0x00, 0x00, /* vact_st3 */
+ 0x00, 0x00, /* vact_st4 */
+ 0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
+ 0x01, 0x00, 0x33, 0x02, /* field top/bot */
+ 0x00, /* 3d FP */
+ },
+ .mbus_fmt = {
+ .width = 1920,
+ .height = 1080,
+ .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+ .field = V4L2_FIELD_INTERLACED,
+ },
+ .vic = 20,
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080p50 = {
+ .core = {
+ .h_blank = {0xd0, 0x02},
+ .v2_blank = {0x65, 0x04},
+ .v1_blank = {0x2d, 0x00},
+ .v_line = {0x65, 0x04},
+ .h_line = {0x50, 0x0a},
+ .hsync_pol = {0x00},
+ .vsync_pol = {0x00},
+ .int_pro_mode = {0x00},
+ .v_blank_f0 = {0xff, 0xff},
+ .v_blank_f1 = {0xff, 0xff},
+ .h_sync_start = {0x0e, 0x02},
+ .h_sync_end = {0x3a, 0x02},
+ .v_sync_line_bef_2 = {0x09, 0x00},
+ .v_sync_line_bef_1 = {0x04, 0x00},
+ .v_sync_line_aft_2 = {0xff, 0xff},
+ .v_sync_line_aft_1 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_2 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_1 = {0xff, 0xff},
+ .v_blank_f2 = {0xff, 0xff},
+ .v_blank_f3 = {0xff, 0xff},
+ .v_blank_f4 = {0xff, 0xff},
+ .v_blank_f5 = {0xff, 0xff},
+ .v_sync_line_aft_3 = {0xff, 0xff},
+ .v_sync_line_aft_4 = {0xff, 0xff},
+ .v_sync_line_aft_5 = {0xff, 0xff},
+ .v_sync_line_aft_6 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+ .vact_space_1 = {0xff, 0xff},
+ .vact_space_2 = {0xff, 0xff},
+ .vact_space_3 = {0xff, 0xff},
+ .vact_space_4 = {0xff, 0xff},
+ .vact_space_5 = {0xff, 0xff},
+ .vact_space_6 = {0xff, 0xff},
+ /* other don't care */
+ },
+ .tg = {
+ 0x00, /* cmd */
+ 0x50, 0x0a, /* h_fsz */
+ 0xd0, 0x02, 0x80, 0x07, /* hact */
+ 0x65, 0x04, /* v_fsz */
+ 0x01, 0x00, 0x33, 0x02, /* vsync */
+ 0x2d, 0x00, 0x38, 0x04, /* vact */
+ 0x33, 0x02, /* field_chg */
+ 0x48, 0x02, /* vact_st2 */
+ 0x00, 0x00, /* vact_st3 */
+ 0x00, 0x00, /* vact_st4 */
+ 0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+ 0x01, 0x00, 0x33, 0x02, /* field top/bot */
+ 0x00, /* 3d FP */
+ },
+ .mbus_fmt = {
+ .width = 1920,
+ .height = 1080,
+ .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+ .field = V4L2_FIELD_NONE,
+ },
+ .vic = 31,
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080p30 = {
+ .core = {
+ .h_blank = {0x18, 0x01},
+ .v2_blank = {0x65, 0x04},
+ .v1_blank = {0x2d, 0x00},
+ .v_line = {0x65, 0x04},
+ .h_line = {0x98, 0x08},
+ .hsync_pol = {0x00},
+ .vsync_pol = {0x00},
+ .int_pro_mode = {0x00},
+ .v_blank_f0 = {0xff, 0xff},
+ .v_blank_f1 = {0xff, 0xff},
+ .h_sync_start = {0x56, 0x00},
+ .h_sync_end = {0x82, 0x00},
+ .v_sync_line_bef_2 = {0x09, 0x00},
+ .v_sync_line_bef_1 = {0x04, 0x00},
+ .v_sync_line_aft_2 = {0xff, 0xff},
+ .v_sync_line_aft_1 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_2 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_1 = {0xff, 0xff},
+ .v_blank_f2 = {0xff, 0xff},
+ .v_blank_f3 = {0xff, 0xff},
+ .v_blank_f4 = {0xff, 0xff},
+ .v_blank_f5 = {0xff, 0xff},
+ .v_sync_line_aft_3 = {0xff, 0xff},
+ .v_sync_line_aft_4 = {0xff, 0xff},
+ .v_sync_line_aft_5 = {0xff, 0xff},
+ .v_sync_line_aft_6 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+ .vact_space_1 = {0xff, 0xff},
+ .vact_space_2 = {0xff, 0xff},
+ .vact_space_3 = {0xff, 0xff},
+ .vact_space_4 = {0xff, 0xff},
+ .vact_space_5 = {0xff, 0xff},
+ .vact_space_6 = {0xff, 0xff},
+ /* other don't care */
+ },
+ .tg = {
+ 0x00, /* cmd */
+ 0x98, 0x08, /* h_fsz */
+ 0x18, 0x01, 0x80, 0x07, /* hact */
+ 0x65, 0x04, /* v_fsz */
+ 0x01, 0x00, 0x33, 0x02, /* vsync */
+ 0x2d, 0x00, 0x38, 0x04, /* vact */
+ 0x33, 0x02, /* field_chg */
+ 0x48, 0x02, /* vact_st2 */
+ 0x00, 0x00, /* vact_st3 */
+ 0x00, 0x00, /* vact_st4 */
+ 0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+ 0x01, 0x00, 0x33, 0x02, /* field top/bot */
+ 0x00, /* 3d FP */
+ },
+ .mbus_fmt = {
+ .width = 1920,
+ .height = 1080,
+ .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+ .field = V4L2_FIELD_NONE,
+ },
+ .vic = 34,
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080p24 = {
+ .core = {
+ .h_blank = {0x3e, 0x03},
+ .v2_blank = {0x65, 0x04},
+ .v1_blank = {0x2d, 0x00},
+ .v_line = {0x65, 0x04},
+ .h_line = {0xbe, 0x0a},
+ .hsync_pol = {0x00},
+ .vsync_pol = {0x00},
+ .int_pro_mode = {0x00},
+ .v_blank_f0 = {0xff, 0xff},
+ .v_blank_f1 = {0xff, 0xff},
+ .h_sync_start = {0x7c, 0x02},
+ .h_sync_end = {0xa8, 0x02},
+ .v_sync_line_bef_2 = {0x09, 0x00},
+ .v_sync_line_bef_1 = {0x04, 0x00},
+ .v_sync_line_aft_2 = {0xff, 0xff},
+ .v_sync_line_aft_1 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_2 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_1 = {0xff, 0xff},
+ .v_blank_f2 = {0xff, 0xff},
+ .v_blank_f3 = {0xff, 0xff},
+ .v_blank_f4 = {0xff, 0xff},
+ .v_blank_f5 = {0xff, 0xff},
+ .v_sync_line_aft_3 = {0xff, 0xff},
+ .v_sync_line_aft_4 = {0xff, 0xff},
+ .v_sync_line_aft_5 = {0xff, 0xff},
+ .v_sync_line_aft_6 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+ .vact_space_1 = {0xff, 0xff},
+ .vact_space_2 = {0xff, 0xff},
+ .vact_space_3 = {0xff, 0xff},
+ .vact_space_4 = {0xff, 0xff},
+ .vact_space_5 = {0xff, 0xff},
+ .vact_space_6 = {0xff, 0xff},
+ /* other don't care */
+ },
+ .tg = {
+ 0x00, /* cmd */
+ 0xbe, 0x0a, /* h_fsz */
+ 0x3e, 0x03, 0x80, 0x07, /* hact */
+ 0x65, 0x04, /* v_fsz */
+ 0x01, 0x00, 0x33, 0x02, /* vsync */
+ 0x2d, 0x00, 0x38, 0x04, /* vact */
+ 0x33, 0x02, /* field_chg */
+ 0x48, 0x02, /* vact_st2 */
+ 0x00, 0x00, /* vact_st3 */
+ 0x00, 0x00, /* vact_st4 */
+ 0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+ 0x01, 0x00, 0x33, 0x02, /* field top/bot */
+ 0x00, /* 3d FP */
+ },
+ .mbus_fmt = {
+ .width = 1920,
+ .height = 1080,
+ .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+ .field = V4L2_FIELD_NONE,
+ },
+ .vic = 32,
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080p25 = {
+ .core = {
+ .h_blank = {0xd0, 0x02},
+ .v2_blank = {0x65, 0x04},
+ .v1_blank = {0x2d, 0x00},
+ .v_line = {0x65, 0x04},
+ .h_line = {0x50, 0x0a},
+ .hsync_pol = {0x00},
+ .vsync_pol = {0x00},
+ .int_pro_mode = {0x00},
+ .v_blank_f0 = {0xff, 0xff},
+ .v_blank_f1 = {0xff, 0xff},
+ .h_sync_start = {0x0e, 0x02},
+ .h_sync_end = {0x3a, 0x02},
+ .v_sync_line_bef_2 = {0x09, 0x00},
+ .v_sync_line_bef_1 = {0x04, 0x00},
+ .v_sync_line_aft_2 = {0xff, 0xff},
+ .v_sync_line_aft_1 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_2 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_1 = {0xff, 0xff},
+ .v_blank_f2 = {0xff, 0xff},
+ .v_blank_f3 = {0xff, 0xff},
+ .v_blank_f4 = {0xff, 0xff},
+ .v_blank_f5 = {0xff, 0xff},
+ .v_sync_line_aft_3 = {0xff, 0xff},
+ .v_sync_line_aft_4 = {0xff, 0xff},
+ .v_sync_line_aft_5 = {0xff, 0xff},
+ .v_sync_line_aft_6 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+ .vact_space_1 = {0xff, 0xff},
+ .vact_space_2 = {0xff, 0xff},
+ .vact_space_3 = {0xff, 0xff},
+ .vact_space_4 = {0xff, 0xff},
+ .vact_space_5 = {0xff, 0xff},
+ .vact_space_6 = {0xff, 0xff},
+ /* other don't care */
+ },
+ .tg = {
+ 0x00, /* cmd */
+ 0x50, 0x0a, /* h_fsz */
+ 0xd0, 0x02, 0x80, 0x07, /* hact */
+ 0x65, 0x04, /* v_fsz */
+ 0x01, 0x00, 0x33, 0x02, /* vsync */
+ 0x2d, 0x00, 0x38, 0x04, /* vact */
+ 0x33, 0x02, /* field_chg */
+ 0x48, 0x02, /* vact_st2 */
+ 0x00, 0x00, /* vact_st3 */
+ 0x00, 0x00, /* vact_st4 */
+ 0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+ 0x01, 0x00, 0x33, 0x02, /* field top/bot */
+ 0x00, /* 3d FP */
+ },
+ .mbus_fmt = {
+ .width = 1920,
+ .height = 1080,
+ .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+ .field = V4L2_FIELD_NONE,
+ },
+ .vic = 33,
+};
+
+static const struct hdmi_preset_conf hdmi_conf_480p59_94 = {
+ .core = {
+ .h_blank = {0x8a, 0x00},
+ .v2_blank = {0x0d, 0x02},
+ .v1_blank = {0x2d, 0x00},
+ .v_line = {0x0d, 0x02},
+ .h_line = {0x5a, 0x03},
+ .hsync_pol = {0x01},
+ .vsync_pol = {0x01},
+ .int_pro_mode = {0x00},
+ .v_blank_f0 = {0xff, 0xff},
+ .v_blank_f1 = {0xff, 0xff},
+ .h_sync_start = {0x0e, 0x00},
+ .h_sync_end = {0x4c, 0x00},
+ .v_sync_line_bef_2 = {0x0f, 0x00},
+ .v_sync_line_bef_1 = {0x09, 0x00},
+ .v_sync_line_aft_2 = {0xff, 0xff},
+ .v_sync_line_aft_1 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_2 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_1 = {0xff, 0xff},
+ .v_blank_f2 = {0xff, 0xff},
+ .v_blank_f3 = {0xff, 0xff},
+ .v_blank_f4 = {0xff, 0xff},
+ .v_blank_f5 = {0xff, 0xff},
+ .v_sync_line_aft_3 = {0xff, 0xff},
+ .v_sync_line_aft_4 = {0xff, 0xff},
+ .v_sync_line_aft_5 = {0xff, 0xff},
+ .v_sync_line_aft_6 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+ .vact_space_1 = {0xff, 0xff},
+ .vact_space_2 = {0xff, 0xff},
+ .vact_space_3 = {0xff, 0xff},
+ .vact_space_4 = {0xff, 0xff},
+ .vact_space_5 = {0xff, 0xff},
+ .vact_space_6 = {0xff, 0xff},
+ /* other don't care */
+ },
+ .tg = {
+ 0x00, /* cmd */
+ 0x5a, 0x03, /* h_fsz */
+ 0x8a, 0x00, 0xd0, 0x02, /* hact */
+ 0x0d, 0x02, /* v_fsz */
+ 0x01, 0x00, 0x33, 0x02, /* vsync */
+ 0x2d, 0x00, 0xe0, 0x01, /* vact */
+ 0x33, 0x02, /* field_chg */
+ 0x48, 0x02, /* vact_st2 */
+ 0x00, 0x00, /* vact_st3 */
+ 0x00, 0x00, /* vact_st4 */
+ 0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+ 0x01, 0x00, 0x33, 0x02, /* field top/bot */
+ 0x00, /* 3d FP */
+ },
+ .mbus_fmt = {
+ .width = 720,
+ .height = 480,
+ .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+ .field = V4L2_FIELD_NONE,
+ },
+ .vic = 3,
+};
+
+static const struct hdmi_preset_conf hdmi_conf_720p59_94 = {
+ .core = {
+ .h_blank = {0x72, 0x01},
+ .v2_blank = {0xee, 0x02},
+ .v1_blank = {0x1e, 0x00},
+ .v_line = {0xee, 0x02},
+ .h_line = {0x72, 0x06},
+ .hsync_pol = {0x00},
+ .vsync_pol = {0x00},
+ .int_pro_mode = {0x00},
+ .v_blank_f0 = {0xff, 0xff},
+ .v_blank_f1 = {0xff, 0xff},
+ .h_sync_start = {0x6c, 0x00},
+ .h_sync_end = {0x94, 0x00},
+ .v_sync_line_bef_2 = {0x0a, 0x00},
+ .v_sync_line_bef_1 = {0x05, 0x00},
+ .v_sync_line_aft_2 = {0xff, 0xff},
+ .v_sync_line_aft_1 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_2 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_1 = {0xff, 0xff},
+ .v_blank_f2 = {0xff, 0xff},
+ .v_blank_f3 = {0xff, 0xff},
+ .v_blank_f4 = {0xff, 0xff},
+ .v_blank_f5 = {0xff, 0xff},
+ .v_sync_line_aft_3 = {0xff, 0xff},
+ .v_sync_line_aft_4 = {0xff, 0xff},
+ .v_sync_line_aft_5 = {0xff, 0xff},
+ .v_sync_line_aft_6 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+ .vact_space_1 = {0xff, 0xff},
+ .vact_space_2 = {0xff, 0xff},
+ .vact_space_3 = {0xff, 0xff},
+ .vact_space_4 = {0xff, 0xff},
+ .vact_space_5 = {0xff, 0xff},
+ .vact_space_6 = {0xff, 0xff},
+ /* other don't care */
+ },
+ .tg = {
+ 0x00, /* cmd */
+ 0x72, 0x06, /* h_fsz */
+ 0x72, 0x01, 0x00, 0x05, /* hact */
+ 0xee, 0x02, /* v_fsz */
+ 0x01, 0x00, 0x33, 0x02, /* vsync */
+ 0x1e, 0x00, 0xd0, 0x02, /* vact */
+ 0x33, 0x02, /* field_chg */
+ 0x48, 0x02, /* vact_st2 */
+ 0x00, 0x00, /* vact_st3 */
+ 0x00, 0x00, /* vact_st4 */
+ 0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+ 0x01, 0x00, 0x33, 0x02, /* field top/bot */
+ 0x00, /* 3d FP */
+ },
+ .mbus_fmt = {
+ .width = 1280,
+ .height = 720,
+ .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+ .field = V4L2_FIELD_NONE,
+ },
+ .vic = 4,
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080i59_94 = {
+ .core = {
+ .h_blank = {0x18, 0x01},
+ .v2_blank = {0x32, 0x02},
+ .v1_blank = {0x16, 0x00},
+ .v_line = {0x65, 0x04},
+ .h_line = {0x98, 0x08},
+ .hsync_pol = {0x00},
+ .vsync_pol = {0x00},
+ .int_pro_mode = {0x01},
+ .v_blank_f0 = {0x49, 0x02},
+ .v_blank_f1 = {0x65, 0x04},
+ .h_sync_start = {0x56, 0x00},
+ .h_sync_end = {0x82, 0x00},
+ .v_sync_line_bef_2 = {0x07, 0x00},
+ .v_sync_line_bef_1 = {0x02, 0x00},
+ .v_sync_line_aft_2 = {0x39, 0x02},
+ .v_sync_line_aft_1 = {0x34, 0x02},
+ .v_sync_line_aft_pxl_2 = {0xa4, 0x04},
+ .v_sync_line_aft_pxl_1 = {0xa4, 0x04},
+ .v_blank_f2 = {0xff, 0xff},
+ .v_blank_f3 = {0xff, 0xff},
+ .v_blank_f4 = {0xff, 0xff},
+ .v_blank_f5 = {0xff, 0xff},
+ .v_sync_line_aft_3 = {0xff, 0xff},
+ .v_sync_line_aft_4 = {0xff, 0xff},
+ .v_sync_line_aft_5 = {0xff, 0xff},
+ .v_sync_line_aft_6 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+ .vact_space_1 = {0xff, 0xff},
+ .vact_space_2 = {0xff, 0xff},
+ .vact_space_3 = {0xff, 0xff},
+ .vact_space_4 = {0xff, 0xff},
+ .vact_space_5 = {0xff, 0xff},
+ .vact_space_6 = {0xff, 0xff},
+ /* other don't care */
+ },
+ .tg = {
+ 0x00, /* cmd */
+ 0x98, 0x08, /* h_fsz */
+ 0x18, 0x01, 0x80, 0x07, /* hact */
+ 0x65, 0x04, /* v_fsz */
+ 0x01, 0x00, 0x33, 0x02, /* vsync */
+ 0x16, 0x00, 0x1c, 0x02, /* vact */
+ 0x33, 0x02, /* field_chg */
+ 0x49, 0x02, /* vact_st2 */
+ 0x00, 0x00, /* vact_st3 */
+ 0x00, 0x00, /* vact_st4 */
+ 0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
+ 0x01, 0x00, 0x33, 0x02, /* field top/bot */
+ 0x00, /* 3d FP */
+ },
+ .mbus_fmt = {
+ .width = 1920,
+ .height = 1080,
+ .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+ .field = V4L2_FIELD_INTERLACED,
+ },
+ .vic = 5,
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080p59_94 = {
+ .core = {
+ .h_blank = {0x18, 0x01},
+ .v2_blank = {0x65, 0x04},
+ .v1_blank = {0x2d, 0x00},
+ .v_line = {0x65, 0x04},
+ .h_line = {0x98, 0x08},
+ .hsync_pol = {0x00},
+ .vsync_pol = {0x00},
+ .int_pro_mode = {0x00},
+ .v_blank_f0 = {0xff, 0xff},
+ .v_blank_f1 = {0xff, 0xff},
+ .h_sync_start = {0x56, 0x00},
+ .h_sync_end = {0x82, 0x00},
+ .v_sync_line_bef_2 = {0x09, 0x00},
+ .v_sync_line_bef_1 = {0x04, 0x00},
+ .v_sync_line_aft_2 = {0xff, 0xff},
+ .v_sync_line_aft_1 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_2 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_1 = {0xff, 0xff},
+ .v_blank_f2 = {0xff, 0xff},
+ .v_blank_f3 = {0xff, 0xff},
+ .v_blank_f4 = {0xff, 0xff},
+ .v_blank_f5 = {0xff, 0xff},
+ .v_sync_line_aft_3 = {0xff, 0xff},
+ .v_sync_line_aft_4 = {0xff, 0xff},
+ .v_sync_line_aft_5 = {0xff, 0xff},
+ .v_sync_line_aft_6 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+ .vact_space_1 = {0xff, 0xff},
+ .vact_space_2 = {0xff, 0xff},
+ .vact_space_3 = {0xff, 0xff},
+ .vact_space_4 = {0xff, 0xff},
+ .vact_space_5 = {0xff, 0xff},
+ .vact_space_6 = {0xff, 0xff},
+ /* other don't care */
+ },
+ .tg = {
+ 0x00, /* cmd */
+ 0x98, 0x08, /* h_fsz */
+ 0x18, 0x01, 0x80, 0x07, /* hact */
+ 0x65, 0x04, /* v_fsz */
+ 0x01, 0x00, 0x33, 0x02, /* vsync */
+ 0x2d, 0x00, 0x38, 0x04, /* vact */
+ 0x33, 0x02, /* field_chg */
+ 0x48, 0x02, /* vact_st2 */
+ 0x00, 0x00, /* vact_st3 */
+ 0x00, 0x00, /* vact_st4 */
+ 0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+ 0x01, 0x00, 0x33, 0x02, /* field top/bot */
+ 0x00, /* 3d FP */
+ },
+ .mbus_fmt = {
+ .width = 1920,
+ .height = 1080,
+ .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+ .field = V4L2_FIELD_NONE,
+ },
+ .vic = 16,
+};
+
+static const struct hdmi_preset_conf hdmi_conf_720p60_sb_half = {
+ .core = {
+ .h_blank = {0x72, 0x01},
+ .v2_blank = {0xee, 0x02},
+ .v1_blank = {0x1e, 0x00},
+ .v_line = {0xee, 0x02},
+ .h_line = {0x72, 0x06},
+ .hsync_pol = {0x00},
+ .vsync_pol = {0x00},
+ .int_pro_mode = {0x00},
+ .v_blank_f0 = {0xff, 0xff},
+ .v_blank_f1 = {0xff, 0xff},
+ .h_sync_start = {0x6c, 0x00},
+ .h_sync_end = {0x94, 0x00},
+ .v_sync_line_bef_2 = {0x0a, 0x00},
+ .v_sync_line_bef_1 = {0x05, 0x00},
+ .v_sync_line_aft_2 = {0xff, 0xff},
+ .v_sync_line_aft_1 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_2 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_1 = {0xff, 0xff},
+ .v_blank_f2 = {0xff, 0xff},
+ .v_blank_f3 = {0xff, 0xff},
+ .v_blank_f4 = {0xff, 0xff},
+ .v_blank_f5 = {0xff, 0xff},
+ .v_sync_line_aft_3 = {0xff, 0xff},
+ .v_sync_line_aft_4 = {0xff, 0xff},
+ .v_sync_line_aft_5 = {0xff, 0xff},
+ .v_sync_line_aft_6 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+ .vact_space_1 = {0xff, 0xff},
+ .vact_space_2 = {0xff, 0xff},
+ .vact_space_3 = {0xff, 0xff},
+ .vact_space_4 = {0xff, 0xff},
+ .vact_space_5 = {0xff, 0xff},
+ .vact_space_6 = {0xff, 0xff},
+ /* other don't care */
+ },
+ .tg = {
+ 0x00, /* cmd */
+ 0x72, 0x06, /* h_fsz */
+ 0x72, 0x01, 0x00, 0x05, /* hact */
+ 0xee, 0x02, /* v_fsz */
+ 0x01, 0x00, 0x33, 0x02, /* vsync */
+ 0x1e, 0x00, 0xd0, 0x02, /* vact */
+ 0x33, 0x02, /* field_chg */
+ 0x0c, 0x03, /* vact_st2 */
+ 0x00, 0x00, /* vact_st3 */
+ 0x00, 0x00, /* vact_st4 */
+ 0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+ 0x01, 0x00, 0x33, 0x02, /* field top/bot */
+ 0x00, /* 3d FP */
+ },
+ .mbus_fmt = {
+ .width = 1280,
+ .height = 720,
+ .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+ .field = V4L2_FIELD_NONE,
+ },
+ .vic = 4,
+};
+
+static const struct hdmi_preset_conf hdmi_conf_720p60_tb = {
+ .core = {
+ .h_blank = {0x72, 0x01},
+ .v2_blank = {0xee, 0x02},
+ .v1_blank = {0x1e, 0x00},
+ .v_line = {0xee, 0x02},
+ .h_line = {0x72, 0x06},
+ .hsync_pol = {0x00},
+ .vsync_pol = {0x00},
+ .int_pro_mode = {0x00},
+ .v_blank_f0 = {0xff, 0xff},
+ .v_blank_f1 = {0xff, 0xff},
+ .h_sync_start = {0x6c, 0x00},
+ .h_sync_end = {0x94, 0x00},
+ .v_sync_line_bef_2 = {0x0a, 0x00},
+ .v_sync_line_bef_1 = {0x05, 0x00},
+ .v_sync_line_aft_2 = {0xff, 0xff},
+ .v_sync_line_aft_1 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_2 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_1 = {0xff, 0xff},
+ .v_blank_f2 = {0xff, 0xff},
+ .v_blank_f3 = {0xff, 0xff},
+ .v_blank_f4 = {0xff, 0xff},
+ .v_blank_f5 = {0xff, 0xff},
+ .v_sync_line_aft_3 = {0xff, 0xff},
+ .v_sync_line_aft_4 = {0xff, 0xff},
+ .v_sync_line_aft_5 = {0xff, 0xff},
+ .v_sync_line_aft_6 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+ .vact_space_1 = {0xff, 0xff},
+ .vact_space_2 = {0xff, 0xff},
+ .vact_space_3 = {0xff, 0xff},
+ .vact_space_4 = {0xff, 0xff},
+ .vact_space_5 = {0xff, 0xff},
+ .vact_space_6 = {0xff, 0xff},
+ /* other don't care */
+ },
+ .tg = {
+ 0x00, /* cmd */
+ 0x72, 0x06, /* h_fsz */
+ 0x72, 0x01, 0x00, 0x05, /* hact */
+ 0xee, 0x02, /* v_fsz */
+ 0x01, 0x00, 0x33, 0x02, /* vsync */
+ 0x1e, 0x00, 0xd0, 0x02, /* vact */
+ 0x33, 0x02, /* field_chg */
+ 0x0c, 0x03, /* vact_st2 */
+ 0x00, 0x00, /* vact_st3 */
+ 0x00, 0x00, /* vact_st4 */
+ 0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+ 0x01, 0x00, 0x33, 0x02, /* field top/bot */
+ 0x00, /* 3d FP */
+ },
+ .mbus_fmt = {
+ .width = 1280,
+ .height = 720,
+ .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+ .field = V4L2_FIELD_NONE,
+ },
+ .vic = 4,
+};
+
+static const struct hdmi_preset_conf hdmi_conf_720p59_94_sb_half = {
+ .core = {
+ .h_blank = {0x72, 0x01},
+ .v2_blank = {0xee, 0x02},
+ .v1_blank = {0x1e, 0x00},
+ .v_line = {0xee, 0x02},
+ .h_line = {0x72, 0x06},
+ .hsync_pol = {0x00},
+ .vsync_pol = {0x00},
+ .int_pro_mode = {0x00},
+ .v_blank_f0 = {0xff, 0xff},
+ .v_blank_f1 = {0xff, 0xff},
+ .h_sync_start = {0x6c, 0x00},
+ .h_sync_end = {0x94, 0x00},
+ .v_sync_line_bef_2 = {0x0a, 0x00},
+ .v_sync_line_bef_1 = {0x05, 0x00},
+ .v_sync_line_aft_2 = {0xff, 0xff},
+ .v_sync_line_aft_1 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_2 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_1 = {0xff, 0xff},
+ .v_blank_f2 = {0xff, 0xff},
+ .v_blank_f3 = {0xff, 0xff},
+ .v_blank_f4 = {0xff, 0xff},
+ .v_blank_f5 = {0xff, 0xff},
+ .v_sync_line_aft_3 = {0xff, 0xff},
+ .v_sync_line_aft_4 = {0xff, 0xff},
+ .v_sync_line_aft_5 = {0xff, 0xff},
+ .v_sync_line_aft_6 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+ .vact_space_1 = {0xff, 0xff},
+ .vact_space_2 = {0xff, 0xff},
+ .vact_space_3 = {0xff, 0xff},
+ .vact_space_4 = {0xff, 0xff},
+ .vact_space_5 = {0xff, 0xff},
+ .vact_space_6 = {0xff, 0xff},
+ /* other don't care */
+ },
+ .tg = {
+ 0x00, /* cmd */
+ 0x72, 0x06, /* h_fsz */
+ 0x72, 0x01, 0x00, 0x05, /* hact */
+ 0xee, 0x02, /* v_fsz */
+ 0x01, 0x00, 0x33, 0x02, /* vsync */
+ 0x1e, 0x00, 0xd0, 0x02, /* vact */
+ 0x00, 0x00, /* field_chg */
+ 0x0c, 0x03, /* vact_st2 */
+ 0x00, 0x00, /* vact_st3 */
+ 0x00, 0x00, /* vact_st4 */
+ 0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+ 0x01, 0x00, 0x33, 0x02, /* field top/bot */
+ 0x00, /* 3d FP */
+ },
+ .mbus_fmt = {
+ .width = 1280,
+ .height = 720,
+ .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+ .field = V4L2_FIELD_NONE,
+ },
+ .vic = 4,
+};
+
+static const struct hdmi_preset_conf hdmi_conf_720p59_94_tb = {
+ .core = {
+ .h_blank = {0x72, 0x01},
+ .v2_blank = {0xee, 0x02},
+ .v1_blank = {0x1e, 0x00},
+ .v_line = {0xee, 0x02},
+ .h_line = {0x72, 0x06},
+ .hsync_pol = {0x00},
+ .vsync_pol = {0x00},
+ .int_pro_mode = {0x00},
+ .v_blank_f0 = {0xff, 0xff},
+ .v_blank_f1 = {0xff, 0xff},
+ .h_sync_start = {0x6c, 0x00},
+ .h_sync_end = {0x94, 0x00},
+ .v_sync_line_bef_2 = {0x0a, 0x00},
+ .v_sync_line_bef_1 = {0x05, 0x00},
+ .v_sync_line_aft_2 = {0xff, 0xff},
+ .v_sync_line_aft_1 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_2 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_1 = {0xff, 0xff},
+ .v_blank_f2 = {0xff, 0xff},
+ .v_blank_f3 = {0xff, 0xff},
+ .v_blank_f4 = {0xff, 0xff},
+ .v_blank_f5 = {0xff, 0xff},
+ .v_sync_line_aft_3 = {0xff, 0xff},
+ .v_sync_line_aft_4 = {0xff, 0xff},
+ .v_sync_line_aft_5 = {0xff, 0xff},
+ .v_sync_line_aft_6 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+ .vact_space_1 = {0xff, 0xff},
+ .vact_space_2 = {0xff, 0xff},
+ .vact_space_3 = {0xff, 0xff},
+ .vact_space_4 = {0xff, 0xff},
+ .vact_space_5 = {0xff, 0xff},
+ .vact_space_6 = {0xff, 0xff},
+ /* other don't care */
+ },
+ .tg = {
+ 0x00, /* cmd */
+ 0x72, 0x06, /* h_fsz */
+ 0x72, 0x01, 0x00, 0x05, /* hact */
+ 0xee, 0x02, /* v_fsz */
+ 0x01, 0x00, 0x33, 0x02, /* vsync */
+ 0x1e, 0x00, 0xd0, 0x02, /* vact */
+ 0x00, 0x00, /* field_chg */
+ 0x0c, 0x03, /* vact_st2 */
+ 0x00, 0x00, /* vact_st3 */
+ 0x00, 0x00, /* vact_st4 */
+ 0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+ 0x01, 0x00, 0x33, 0x02, /* field top/bot */
+ 0x00, /* 3d FP */
+ },
+ .mbus_fmt = {
+ .width = 1280,
+ .height = 720,
+ .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+ .field = V4L2_FIELD_NONE,
+ },
+ .vic = 4,
+};
+
+static const struct hdmi_preset_conf hdmi_conf_720p50_sb_half = {
+ .core = {
+ .h_blank = {0xbc, 0x02},
+ .v2_blank = {0xdc, 0x05},
+ .v1_blank = {0x1e, 0x00},
+ .v_line = {0xdc, 0x05},
+ .h_line = {0xbc, 0x07},
+ .hsync_pol = {0x00},
+ .vsync_pol = {0x00},
+ .int_pro_mode = {0x00},
+ .v_blank_f0 = {0xff, 0xff},
+ .v_blank_f1 = {0xff, 0xff},
+ .h_sync_start = {0xb6, 0x01},
+ .h_sync_end = {0xde, 0x01},
+ .v_sync_line_bef_2 = {0x0a, 0x00},
+ .v_sync_line_bef_1 = {0x05, 0x00},
+ .v_sync_line_aft_2 = {0xff, 0xff},
+ .v_sync_line_aft_1 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_2 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_1 = {0xff, 0xff},
+ .v_blank_f2 = {0xff, 0xff},
+ .v_blank_f3 = {0xff, 0xff},
+ .v_blank_f4 = {0xff, 0xff},
+ .v_blank_f5 = {0xff, 0xff},
+ .v_sync_line_aft_3 = {0xff, 0xff},
+ .v_sync_line_aft_4 = {0xff, 0xff},
+ .v_sync_line_aft_5 = {0xff, 0xff},
+ .v_sync_line_aft_6 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+ .vact_space_1 = {0xee, 0x02},
+ .vact_space_2 = {0x0c, 0x03},
+ .vact_space_3 = {0xff, 0xff},
+ .vact_space_4 = {0xff, 0xff},
+ .vact_space_5 = {0xff, 0xff},
+ .vact_space_6 = {0xff, 0xff},
+ /* other don't care */
+ },
+ .tg = {
+ 0x00, /* cmd */
+ 0xbc, 0x07, /* h_fsz */
+ 0xbc, 0x02, 0x00, 0x05, /* hact */
+ 0xee, 0x02, /* v_fsz */
+ 0x01, 0x00, 0x33, 0x02, /* vsync */
+ 0x1e, 0x00, 0xd0, 0x02, /* vact */
+ 0x00, 0x00, /* field_chg */
+ 0x0c, 0x03, /* vact_st2 */
+ 0x00, 0x00, /* vact_st3 */
+ 0x00, 0x00, /* vact_st4 */
+ 0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+ 0x01, 0x00, 0x33, 0x02, /* field top/bot */
+ 0x00, /* 3d FP */
+ },
+ .mbus_fmt = {
+ .width = 1280,
+ .height = 720,
+ .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+ .field = V4L2_FIELD_NONE,
+ },
+ .vic = 19,
+};
+
+static const struct hdmi_preset_conf hdmi_conf_720p50_tb = {
+ .core = {
+ .h_blank = {0xbc, 0x02},
+ .v2_blank = {0xdc, 0x05},
+ .v1_blank = {0x1e, 0x00},
+ .v_line = {0xdc, 0x05},
+ .h_line = {0xbc, 0x07},
+ .hsync_pol = {0x00},
+ .vsync_pol = {0x00},
+ .int_pro_mode = {0x00},
+ .v_blank_f0 = {0xff, 0xff},
+ .v_blank_f1 = {0xff, 0xff},
+ .h_sync_start = {0xb6, 0x01},
+ .h_sync_end = {0xde, 0x01},
+ .v_sync_line_bef_2 = {0x0a, 0x00},
+ .v_sync_line_bef_1 = {0x05, 0x00},
+ .v_sync_line_aft_2 = {0xff, 0xff},
+ .v_sync_line_aft_1 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_2 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_1 = {0xff, 0xff},
+ .v_blank_f2 = {0xff, 0xff},
+ .v_blank_f3 = {0xff, 0xff},
+ .v_blank_f4 = {0xff, 0xff},
+ .v_blank_f5 = {0xff, 0xff},
+ .v_sync_line_aft_3 = {0xff, 0xff},
+ .v_sync_line_aft_4 = {0xff, 0xff},
+ .v_sync_line_aft_5 = {0xff, 0xff},
+ .v_sync_line_aft_6 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+ .vact_space_1 = {0xee, 0x02},
+ .vact_space_2 = {0x0c, 0x03},
+ .vact_space_3 = {0xff, 0xff},
+ .vact_space_4 = {0xff, 0xff},
+ .vact_space_5 = {0xff, 0xff},
+ .vact_space_6 = {0xff, 0xff},
+ /* other don't care */
+ },
+ .tg = {
+ 0x00, /* cmd */
+ 0xbc, 0x07, /* h_fsz */
+ 0xbc, 0x02, 0x00, 0x05, /* hact */
+ 0xee, 0x02, /* v_fsz */
+ 0x01, 0x00, 0x33, 0x02, /* vsync */
+ 0x1e, 0x00, 0xd0, 0x02, /* vact */
+ 0x00, 0x00, /* field_chg */
+ 0x0c, 0x03, /* vact_st2 */
+ 0x00, 0x00, /* vact_st3 */
+ 0x00, 0x00, /* vact_st4 */
+ 0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+ 0x01, 0x00, 0x33, 0x02, /* field top/bot */
+ 0x00, /* 3d FP */
+ },
+ .mbus_fmt = {
+ .width = 1280,
+ .height = 720,
+ .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+ .field = V4L2_FIELD_NONE,
+ },
+ .vic = 19,
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080p24_fp = {
+ .core = {
+ .h_blank = {0x3e, 0x03},
+ .v2_blank = {0xca, 0x08},
+ .v1_blank = {0x2d, 0x00},
+ .v_line = {0xca, 0x08},
+ .h_line = {0xbe, 0x0a},
+ .hsync_pol = {0x00},
+ .vsync_pol = {0x00},
+ .int_pro_mode = {0x00},
+ .v_blank_f0 = {0xff, 0xff},
+ .v_blank_f1 = {0xff, 0xff},
+ .h_sync_start = {0x7c, 0x02},
+ .h_sync_end = {0xa8, 0x02},
+ .v_sync_line_bef_2 = {0x09, 0x00},
+ .v_sync_line_bef_1 = {0x04, 0x00},
+ .v_sync_line_aft_2 = {0xff, 0xff},
+ .v_sync_line_aft_1 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_2 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_1 = {0xff, 0xff},
+ .v_blank_f2 = {0xff, 0xff},
+ .v_blank_f3 = {0xff, 0xff},
+ .v_blank_f4 = {0xff, 0xff},
+ .v_blank_f5 = {0xff, 0xff},
+ .v_sync_line_aft_3 = {0xff, 0xff},
+ .v_sync_line_aft_4 = {0xff, 0xff},
+ .v_sync_line_aft_5 = {0xff, 0xff},
+ .v_sync_line_aft_6 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+ .vact_space_1 = {0x65, 0x04},
+ .vact_space_2 = {0x92, 0x04},
+ .vact_space_3 = {0xff, 0xff},
+ .vact_space_4 = {0xff, 0xff},
+ .vact_space_5 = {0xff, 0xff},
+ .vact_space_6 = {0xff, 0xff},
+ /* other don't care */
+ },
+ .tg = {
+ 0x00, /* cmd */
+ 0xbe, 0x0a, /* h_fsz */
+ 0x3e, 0x03, 0x80, 0x07, /* hact */
+ 0xca, 0x08, /* v_fsz */
+ 0x01, 0x00, 0x33, 0x02, /* vsync */
+ 0x2d, 0x00, 0x38, 0x04, /* vact */
+ 0x33, 0x02, /* field_chg */
+ 0x92, 0x04, /* vact_st2 */
+ 0x00, 0x00, /* vact_st3 */
+ 0x00, 0x00, /* vact_st4 */
+ 0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+ 0x01, 0x00, 0x33, 0x02, /* field top/bot */
+ 0x01, /* 3d FP */
+ },
+ .mbus_fmt = {
+ .width = 1920,
+ .height = 1080,
+ .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+ .field = V4L2_FIELD_NONE,
+ },
+ .vic = 32,
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080p24_sb_half = {
+ .core = {
+ .h_blank = {0x3e, 0x03},
+ .v2_blank = {0x65, 0x04},
+ .v1_blank = {0x2d, 0x00},
+ .v_line = {0x65, 0x04},
+ .h_line = {0xbe, 0x0a},
+ .hsync_pol = {0x00},
+ .vsync_pol = {0x00},
+ .int_pro_mode = {0x00},
+ .v_blank_f0 = {0xff, 0xff},
+ .v_blank_f1 = {0xff, 0xff},
+ .h_sync_start = {0x7c, 0x02},
+ .h_sync_end = {0xa8, 0x02},
+ .v_sync_line_bef_2 = {0x09, 0x00},
+ .v_sync_line_bef_1 = {0x04, 0x00},
+ .v_sync_line_aft_2 = {0xff, 0xff},
+ .v_sync_line_aft_1 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_2 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_1 = {0xff, 0xff},
+ .v_blank_f2 = {0xff, 0xff},
+ .v_blank_f3 = {0xff, 0xff},
+ .v_blank_f4 = {0xff, 0xff},
+ .v_blank_f5 = {0xff, 0xff},
+ .v_sync_line_aft_3 = {0xff, 0xff},
+ .v_sync_line_aft_4 = {0xff, 0xff},
+ .v_sync_line_aft_5 = {0xff, 0xff},
+ .v_sync_line_aft_6 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+ .vact_space_1 = {0xff, 0xff},
+ .vact_space_2 = {0xff, 0xff},
+ .vact_space_3 = {0xff, 0xff},
+ .vact_space_4 = {0xff, 0xff},
+ .vact_space_5 = {0xff, 0xff},
+ .vact_space_6 = {0xff, 0xff},
+ /* other don't care */
+ },
+ .tg = {
+ 0x00, /* cmd */
+ 0xbe, 0x0a, /* h_fsz */
+ 0x3e, 0x03, 0x80, 0x07, /* hact */
+ 0x65, 0x04, /* v_fsz */
+ 0x01, 0x00, 0x33, 0x02, /* vsync */
+ 0x2d, 0x00, 0x38, 0x04, /* vact */
+ 0x33, 0x02, /* field_chg */
+ 0x48, 0x02, /* vact_st2 */
+ 0x00, 0x00, /* vact_st3 */
+ 0x00, 0x00, /* vact_st4 */
+ 0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+ 0x01, 0x00, 0x33, 0x02, /* field top/bot */
+ 0x00, /* 3d FP */
+ },
+ .mbus_fmt = {
+ .width = 1920,
+ .height = 1080,
+ .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+ .field = V4L2_FIELD_NONE,
+ },
+ .vic = 32,
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080p24_tb = {
+ .core = {
+ .h_blank = {0x3e, 0x03},
+ .v2_blank = {0x65, 0x04},
+ .v1_blank = {0x2d, 0x00},
+ .v_line = {0x65, 0x04},
+ .h_line = {0xbe, 0x0a},
+ .hsync_pol = {0x00},
+ .vsync_pol = {0x00},
+ .int_pro_mode = {0x00},
+ .v_blank_f0 = {0xff, 0xff},
+ .v_blank_f1 = {0xff, 0xff},
+ .h_sync_start = {0x7c, 0x02},
+ .h_sync_end = {0xa8, 0x02},
+ .v_sync_line_bef_2 = {0x09, 0x00},
+ .v_sync_line_bef_1 = {0x04, 0x00},
+ .v_sync_line_aft_2 = {0xff, 0xff},
+ .v_sync_line_aft_1 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_2 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_1 = {0xff, 0xff},
+ .v_blank_f2 = {0xff, 0xff},
+ .v_blank_f3 = {0xff, 0xff},
+ .v_blank_f4 = {0xff, 0xff},
+ .v_blank_f5 = {0xff, 0xff},
+ .v_sync_line_aft_3 = {0xff, 0xff},
+ .v_sync_line_aft_4 = {0xff, 0xff},
+ .v_sync_line_aft_5 = {0xff, 0xff},
+ .v_sync_line_aft_6 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+ .vact_space_1 = {0xff, 0xff},
+ .vact_space_2 = {0xff, 0xff},
+ .vact_space_3 = {0xff, 0xff},
+ .vact_space_4 = {0xff, 0xff},
+ .vact_space_5 = {0xff, 0xff},
+ .vact_space_6 = {0xff, 0xff},
+ /* other don't care */
+ },
+ .tg = {
+ 0x00, /* cmd */
+ 0xbe, 0x0a, /* h_fsz */
+ 0x3e, 0x03, 0x80, 0x07, /* hact */
+ 0x65, 0x04, /* v_fsz */
+ 0x01, 0x00, 0x33, 0x02, /* vsync */
+ 0x2d, 0x00, 0x38, 0x04, /* vact */
+ 0x33, 0x02, /* field_chg */
+ 0x48, 0x02, /* vact_st2 */
+ 0x00, 0x00, /* vact_st3 */
+ 0x00, 0x00, /* vact_st4 */
+ 0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+ 0x01, 0x00, 0x33, 0x02, /* field top/bot */
+ 0x00, /* 3d FP */
+ },
+ .mbus_fmt = {
+ .width = 1920,
+ .height = 1080,
+ .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+ .field = V4L2_FIELD_NONE,
+ },
+ .vic = 32,
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080p23_98_fp = {
+ .core = {
+ .h_blank = {0x3e, 0x03},
+ .v2_blank = {0xca, 0x08},
+ .v1_blank = {0x2d, 0x00},
+ .v_line = {0xca, 0x08},
+ .h_line = {0xbe, 0x0a},
+ .hsync_pol = {0x00},
+ .vsync_pol = {0x00},
+ .int_pro_mode = {0x00},
+ .v_blank_f0 = {0xff, 0xff},
+ .v_blank_f1 = {0xff, 0xff},
+ .h_sync_start = {0x7c, 0x02},
+ .h_sync_end = {0xa8, 0x02},
+ .v_sync_line_bef_2 = {0x09, 0x00},
+ .v_sync_line_bef_1 = {0x04, 0x00},
+ .v_sync_line_aft_2 = {0xff, 0xff},
+ .v_sync_line_aft_1 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_2 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_1 = {0xff, 0xff},
+ .v_blank_f2 = {0xff, 0xff},
+ .v_blank_f3 = {0xff, 0xff},
+ .v_blank_f4 = {0xff, 0xff},
+ .v_blank_f5 = {0xff, 0xff},
+ .v_sync_line_aft_3 = {0xff, 0xff},
+ .v_sync_line_aft_4 = {0xff, 0xff},
+ .v_sync_line_aft_5 = {0xff, 0xff},
+ .v_sync_line_aft_6 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+ .vact_space_1 = {0x65, 0x04},
+ .vact_space_2 = {0x92, 0x04},
+ .vact_space_3 = {0xff, 0xff},
+ .vact_space_4 = {0xff, 0xff},
+ .vact_space_5 = {0xff, 0xff},
+ .vact_space_6 = {0xff, 0xff},
+ /* other don't care */
+ },
+ .tg = {
+ 0x00, /* cmd */
+ 0xbe, 0x0a, /* h_fsz */
+ 0x3e, 0x03, 0x80, 0x07, /* hact */
+ 0xca, 0x08, /* v_fsz */
+ 0x01, 0x00, 0x33, 0x02, /* vsync */
+ 0x2d, 0x00, 0x38, 0x04, /* vact */
+ 0x33, 0x02, /* field_chg */
+ 0x92, 0x04, /* vact_st2 */
+ 0x00, 0x00, /* vact_st3 */
+ 0x00, 0x00, /* vact_st4 */
+ 0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+ 0x01, 0x00, 0x33, 0x02, /* field top/bot */
+ 0x01, /* 3d FP */
+ },
+ .mbus_fmt = {
+ .width = 1920,
+ .height = 1080,
+ .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+ .field = V4L2_FIELD_NONE,
+ },
+ .vic = 32,
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080p23_98_sb_half = {
+ .core = {
+ .h_blank = {0x3e, 0x03},
+ .v2_blank = {0x65, 0x04},
+ .v1_blank = {0x2d, 0x00},
+ .v_line = {0x65, 0x04},
+ .h_line = {0xbe, 0x0a},
+ .hsync_pol = {0x00},
+ .vsync_pol = {0x00},
+ .int_pro_mode = {0x00},
+ .v_blank_f0 = {0xff, 0xff},
+ .v_blank_f1 = {0xff, 0xff},
+ .h_sync_start = {0x7c, 0x02},
+ .h_sync_end = {0xa8, 0x02},
+ .v_sync_line_bef_2 = {0x09, 0x00},
+ .v_sync_line_bef_1 = {0x04, 0x00},
+ .v_sync_line_aft_2 = {0xff, 0xff},
+ .v_sync_line_aft_1 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_2 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_1 = {0xff, 0xff},
+ .v_blank_f2 = {0xff, 0xff},
+ .v_blank_f3 = {0xff, 0xff},
+ .v_blank_f4 = {0xff, 0xff},
+ .v_blank_f5 = {0xff, 0xff},
+ .v_sync_line_aft_3 = {0xff, 0xff},
+ .v_sync_line_aft_4 = {0xff, 0xff},
+ .v_sync_line_aft_5 = {0xff, 0xff},
+ .v_sync_line_aft_6 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+ .vact_space_1 = {0xff, 0xff},
+ .vact_space_2 = {0xff, 0xff},
+ .vact_space_3 = {0xff, 0xff},
+ .vact_space_4 = {0xff, 0xff},
+ .vact_space_5 = {0xff, 0xff},
+ .vact_space_6 = {0xff, 0xff},
+ /* other don't care */
+ },
+ .tg = {
+ 0x00, /* cmd */
+ 0xbe, 0x0a, /* h_fsz */
+ 0x3e, 0x03, 0x80, 0x07, /* hact */
+ 0x65, 0x04, /* v_fsz */
+ 0x01, 0x00, 0x33, 0x02, /* vsync */
+ 0x2d, 0x00, 0x38, 0x04, /* vact */
+ 0x33, 0x02, /* field_chg */
+ 0x48, 0x02, /* vact_st2 */
+ 0x00, 0x00, /* vact_st3 */
+ 0x00, 0x00, /* vact_st4 */
+ 0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+ 0x01, 0x00, 0x33, 0x02, /* field top/bot */
+ 0x00, /* 3d FP */
+ },
+ .mbus_fmt = {
+ .width = 1920,
+ .height = 1080,
+ .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+ .field = V4L2_FIELD_NONE,
+ },
+ .vic = 32,
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080p23_98_tb = {
+ .core = {
+ .h_blank = {0x3e, 0x03},
+ .v2_blank = {0x65, 0x04},
+ .v1_blank = {0x2d, 0x00},
+ .v_line = {0x65, 0x04},
+ .h_line = {0xbe, 0x0a},
+ .hsync_pol = {0x00},
+ .vsync_pol = {0x00},
+ .int_pro_mode = {0x00},
+ .v_blank_f0 = {0xff, 0xff},
+ .v_blank_f1 = {0xff, 0xff},
+ .h_sync_start = {0x7c, 0x02},
+ .h_sync_end = {0xa8, 0x02},
+ .v_sync_line_bef_2 = {0x09, 0x00},
+ .v_sync_line_bef_1 = {0x04, 0x00},
+ .v_sync_line_aft_2 = {0xff, 0xff},
+ .v_sync_line_aft_1 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_2 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_1 = {0xff, 0xff},
+ .v_blank_f2 = {0xff, 0xff},
+ .v_blank_f3 = {0xff, 0xff},
+ .v_blank_f4 = {0xff, 0xff},
+ .v_blank_f5 = {0xff, 0xff},
+ .v_sync_line_aft_3 = {0xff, 0xff},
+ .v_sync_line_aft_4 = {0xff, 0xff},
+ .v_sync_line_aft_5 = {0xff, 0xff},
+ .v_sync_line_aft_6 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+ .vact_space_1 = {0xff, 0xff},
+ .vact_space_2 = {0xff, 0xff},
+ .vact_space_3 = {0xff, 0xff},
+ .vact_space_4 = {0xff, 0xff},
+ .vact_space_5 = {0xff, 0xff},
+ .vact_space_6 = {0xff, 0xff},
+ /* other don't care */
+ },
+ .tg = {
+ 0x00, /* cmd */
+ 0xbe, 0x0a, /* h_fsz */
+ 0x3e, 0x03, 0x80, 0x07, /* hact */
+ 0x65, 0x04, /* v_fsz */
+ 0x01, 0x00, 0x33, 0x02, /* vsync */
+ 0x2d, 0x00, 0x38, 0x04, /* vact */
+ 0x33, 0x02, /* field_chg */
+ 0x48, 0x02, /* vact_st2 */
+ 0x00, 0x00, /* vact_st3 */
+ 0x00, 0x00, /* vact_st4 */
+ 0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+ 0x01, 0x00, 0x33, 0x02, /* field top/bot */
+ 0x00, /* 3d FP */
+ },
+ .mbus_fmt = {
+ .width = 1920,
+ .height = 1080,
+ .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+ .field = V4L2_FIELD_NONE,
+ },
+ .vic = 32,
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080i60_sb_half = {
+ .core = {
+ .h_blank = {0x18, 0x01},
+ .v2_blank = {0x32, 0x02},
+ .v1_blank = {0x16, 0x00},
+ .v_line = {0x65, 0x04},
+ .h_line = {0x98, 0x08},
+ .hsync_pol = {0x00},
+ .vsync_pol = {0x00},
+ .int_pro_mode = {0x01},
+ .v_blank_f0 = {0x49, 0x02},
+ .v_blank_f1 = {0x65, 0x04},
+ .h_sync_start = {0x56, 0x00},
+ .h_sync_end = {0x82, 0x00},
+ .v_sync_line_bef_2 = {0x07, 0x00},
+ .v_sync_line_bef_1 = {0x02, 0x00},
+ .v_sync_line_aft_2 = {0x39, 0x02},
+ .v_sync_line_aft_1 = {0x34, 0x02},
+ .v_sync_line_aft_pxl_2 = {0xa4, 0x04},
+ .v_sync_line_aft_pxl_1 = {0xa4, 0x04},
+ .v_blank_f2 = {0xff, 0xff},
+ .v_blank_f3 = {0xff, 0xff},
+ .v_blank_f4 = {0xff, 0xff},
+ .v_blank_f5 = {0xff, 0xff},
+ .v_sync_line_aft_3 = {0xff, 0xff},
+ .v_sync_line_aft_4 = {0xff, 0xff},
+ .v_sync_line_aft_5 = {0xff, 0xff},
+ .v_sync_line_aft_6 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+ .vact_space_1 = {0xff, 0xff},
+ .vact_space_2 = {0xff, 0xff},
+ .vact_space_3 = {0xff, 0xff},
+ .vact_space_4 = {0xff, 0xff},
+ .vact_space_5 = {0xff, 0xff},
+ .vact_space_6 = {0xff, 0xff},
+ /* other don't care */
+ },
+ .tg = {
+ 0x00, /* cmd */
+ 0x98, 0x08, /* h_fsz */
+ 0x18, 0x01, 0x80, 0x07, /* hact */
+ 0x64, 0x04, /* v_fsz */
+ 0x01, 0x00, 0x33, 0x02, /* vsync */
+ 0x16, 0x00, 0x1c, 0x02, /* vact */
+ 0x65, 0x04, /* field_chg */
+ 0x49, 0x02, /* vact_st2 */
+ 0x7b, 0x04, /* vact_st3 */
+ 0xae, 0x06, /* vact_st4 */
+ 0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
+ 0x01, 0x00, 0x33, 0x02, /* field top/bot */
+ 0x00, /* 3d FP */
+ },
+ .mbus_fmt = {
+ .width = 1920,
+ .height = 1080,
+ .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+ .field = V4L2_FIELD_INTERLACED,
+ },
+ .vic = 5,
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080i59_94_sb_half = {
+ .core = {
+ .h_blank = {0x18, 0x01},
+ .v2_blank = {0x32, 0x02},
+ .v1_blank = {0x16, 0x00},
+ .v_line = {0x65, 0x04},
+ .h_line = {0x98, 0x08},
+ .hsync_pol = {0x00},
+ .vsync_pol = {0x00},
+ .int_pro_mode = {0x01},
+ .v_blank_f0 = {0x49, 0x02},
+ .v_blank_f1 = {0x65, 0x04},
+ .h_sync_start = {0x56, 0x00},
+ .h_sync_end = {0x82, 0x00},
+ .v_sync_line_bef_2 = {0x07, 0x00},
+ .v_sync_line_bef_1 = {0x02, 0x00},
+ .v_sync_line_aft_2 = {0x39, 0x02},
+ .v_sync_line_aft_1 = {0x34, 0x02},
+ .v_sync_line_aft_pxl_2 = {0xa4, 0x04},
+ .v_sync_line_aft_pxl_1 = {0xa4, 0x04},
+ .v_blank_f2 = {0xff, 0xff},
+ .v_blank_f3 = {0xff, 0xff},
+ .v_blank_f4 = {0xff, 0xff},
+ .v_blank_f5 = {0xff, 0xff},
+ .v_sync_line_aft_3 = {0xff, 0xff},
+ .v_sync_line_aft_4 = {0xff, 0xff},
+ .v_sync_line_aft_5 = {0xff, 0xff},
+ .v_sync_line_aft_6 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+ .vact_space_1 = {0xff, 0xff},
+ .vact_space_2 = {0xff, 0xff},
+ .vact_space_3 = {0xff, 0xff},
+ .vact_space_4 = {0xff, 0xff},
+ .vact_space_5 = {0xff, 0xff},
+ .vact_space_6 = {0xff, 0xff},
+ /* other don't care */
+ },
+ .tg = {
+ 0x00, /* cmd */
+ 0x98, 0x08, /* h_fsz */
+ 0x18, 0x01, 0x80, 0x07, /* hact */
+ 0x64, 0x04, /* v_fsz */
+ 0x01, 0x00, 0x33, 0x02, /* vsync */
+ 0x16, 0x00, 0x1c, 0x02, /* vact */
+ 0x65, 0x04, /* field_chg */
+ 0x49, 0x02, /* vact_st2 */
+ 0x7b, 0x04, /* vact_st3 */
+ 0xae, 0x06, /* vact_st4 */
+ 0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
+ 0x01, 0x00, 0x33, 0x02, /* field top/bot */
+ 0x00, /* 3d FP */
+ },
+ .mbus_fmt = {
+ .width = 1920,
+ .height = 1080,
+ .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+ .field = V4L2_FIELD_INTERLACED,
+ },
+ .vic = 5,
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080i50_sb_half = {
+ .core = {
+ .h_blank = {0xd0, 0x02},
+ .v2_blank = {0x32, 0x02},
+ .v1_blank = {0x16, 0x00},
+ .v_line = {0x65, 0x04},
+ .h_line = {0x50, 0x0a},
+ .hsync_pol = {0x00},
+ .vsync_pol = {0x00},
+ .int_pro_mode = {0x01},
+ .v_blank_f0 = {0x49, 0x02},
+ .v_blank_f1 = {0x65, 0x04},
+ .h_sync_start = {0x0e, 0x02},
+ .h_sync_end = {0x3a, 0x02},
+ .v_sync_line_bef_2 = {0x07, 0x00},
+ .v_sync_line_bef_1 = {0x02, 0x00},
+ .v_sync_line_aft_2 = {0x39, 0x02},
+ .v_sync_line_aft_1 = {0x34, 0x02},
+ .v_sync_line_aft_pxl_2 = {0x38, 0x07},
+ .v_sync_line_aft_pxl_1 = {0x38, 0x07},
+ .v_blank_f2 = {0xff, 0xff},
+ .v_blank_f3 = {0xff, 0xff},
+ .v_blank_f4 = {0xff, 0xff},
+ .v_blank_f5 = {0xff, 0xff},
+ .v_sync_line_aft_3 = {0xff, 0xff},
+ .v_sync_line_aft_4 = {0xff, 0xff},
+ .v_sync_line_aft_5 = {0xff, 0xff},
+ .v_sync_line_aft_6 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+ .vact_space_1 = {0xff, 0xff},
+ .vact_space_2 = {0xff, 0xff},
+ .vact_space_3 = {0xff, 0xff},
+ .vact_space_4 = {0xff, 0xff},
+ .vact_space_5 = {0xff, 0xff},
+ .vact_space_6 = {0xff, 0xff},
+ /* other don't care */
+ },
+ .tg = {
+ 0x00, /* cmd */
+ 0x50, 0x0a, /* h_fsz */
+ 0xd0, 0x02, 0x80, 0x07, /* hact */
+ 0x64, 0x04, /* v_fsz */
+ 0x01, 0x00, 0x33, 0x02, /* vsync */
+ 0x16, 0x00, 0x1c, 0x02, /* vact */
+ 0x65, 0x04, /* field_chg */
+ 0x49, 0x02, /* vact_st2 */
+ 0x7b, 0x04, /* vact_st3 */
+ 0xae, 0x06, /* vact_st4 */
+ 0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
+ 0x01, 0x00, 0x33, 0x02, /* field top/bot */
+ 0x00, /* 3d FP */
+ },
+ .mbus_fmt = {
+ .width = 1920,
+ .height = 1080,
+ .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+ .field = V4L2_FIELD_INTERLACED,
+ },
+ .vic = 20,
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080p60_sb_half = {
+ .core = {
+ .h_blank = {0x18, 0x01},
+ .v2_blank = {0x65, 0x04},
+ .v1_blank = {0x2d, 0x00},
+ .v_line = {0x65, 0x04},
+ .h_line = {0x98, 0x08},
+ .hsync_pol = {0x00},
+ .vsync_pol = {0x00},
+ .int_pro_mode = {0x00},
+ .v_blank_f0 = {0xff, 0xff},
+ .v_blank_f1 = {0xff, 0xff},
+ .h_sync_start = {0x56, 0x00},
+ .h_sync_end = {0x82, 0x00},
+ .v_sync_line_bef_2 = {0x09, 0x00},
+ .v_sync_line_bef_1 = {0x04, 0x00},
+ .v_sync_line_aft_2 = {0xff, 0xff},
+ .v_sync_line_aft_1 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_2 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_1 = {0xff, 0xff},
+ .v_blank_f2 = {0xff, 0xff},
+ .v_blank_f3 = {0xff, 0xff},
+ .v_blank_f4 = {0xff, 0xff},
+ .v_blank_f5 = {0xff, 0xff},
+ .v_sync_line_aft_3 = {0xff, 0xff},
+ .v_sync_line_aft_4 = {0xff, 0xff},
+ .v_sync_line_aft_5 = {0xff, 0xff},
+ .v_sync_line_aft_6 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+ .vact_space_1 = {0xff, 0xff},
+ .vact_space_2 = {0xff, 0xff},
+ .vact_space_3 = {0xff, 0xff},
+ .vact_space_4 = {0xff, 0xff},
+ .vact_space_5 = {0xff, 0xff},
+ .vact_space_6 = {0xff, 0xff},
+ /* other don't care */
+ },
+ .tg = {
+ 0x00, /* cmd */
+ 0x98, 0x08, /* h_fsz */
+ 0x18, 0x01, 0x80, 0x07, /* hact */
+ 0x65, 0x04, /* v_fsz */
+ 0x01, 0x00, 0x33, 0x02, /* vsync */
+ 0x2d, 0x00, 0x38, 0x04, /* vact */
+ 0x33, 0x02, /* field_chg */
+ 0x48, 0x02, /* vact_st2 */
+ 0x00, 0x00, /* vact_st3 */
+ 0x00, 0x00, /* vact_st4 */
+ 0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+ 0x01, 0x00, 0x33, 0x02, /* field top/bot */
+ 0x00, /* 3d FP */
+ },
+ .mbus_fmt = {
+ .width = 1920,
+ .height = 1080,
+ .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+ .field = V4L2_FIELD_NONE,
+ },
+ .vic = 16,
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080p60_tb = {
+ .core = {
+ .h_blank = {0x18, 0x01},
+ .v2_blank = {0x65, 0x04},
+ .v1_blank = {0x2d, 0x00},
+ .v_line = {0x65, 0x04},
+ .h_line = {0x98, 0x08},
+ .hsync_pol = {0x00},
+ .vsync_pol = {0x00},
+ .int_pro_mode = {0x00},
+ .v_blank_f0 = {0xff, 0xff},
+ .v_blank_f1 = {0xff, 0xff},
+ .h_sync_start = {0x56, 0x00},
+ .h_sync_end = {0x82, 0x00},
+ .v_sync_line_bef_2 = {0x09, 0x00},
+ .v_sync_line_bef_1 = {0x04, 0x00},
+ .v_sync_line_aft_2 = {0xff, 0xff},
+ .v_sync_line_aft_1 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_2 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_1 = {0xff, 0xff},
+ .v_blank_f2 = {0xff, 0xff},
+ .v_blank_f3 = {0xff, 0xff},
+ .v_blank_f4 = {0xff, 0xff},
+ .v_blank_f5 = {0xff, 0xff},
+ .v_sync_line_aft_3 = {0xff, 0xff},
+ .v_sync_line_aft_4 = {0xff, 0xff},
+ .v_sync_line_aft_5 = {0xff, 0xff},
+ .v_sync_line_aft_6 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+ .vact_space_1 = {0xff, 0xff},
+ .vact_space_2 = {0xff, 0xff},
+ .vact_space_3 = {0xff, 0xff},
+ .vact_space_4 = {0xff, 0xff},
+ .vact_space_5 = {0xff, 0xff},
+ .vact_space_6 = {0xff, 0xff},
+ /* other don't care */
+ },
+ .tg = {
+ 0x00, /* cmd */
+ 0x98, 0x08, /* h_fsz */
+ 0x18, 0x01, 0x80, 0x07, /* hact */
+ 0x65, 0x04, /* v_fsz */
+ 0x01, 0x00, 0x33, 0x02, /* vsync */
+ 0x2d, 0x00, 0x38, 0x04, /* vact */
+ 0x33, 0x02, /* field_chg */
+ 0x48, 0x02, /* vact_st2 */
+ 0x00, 0x00, /* vact_st3 */
+ 0x00, 0x00, /* vact_st4 */
+ 0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+ 0x01, 0x00, 0x33, 0x02, /* field top/bot */
+ 0x00, /* 3d FP */
+ },
+ .mbus_fmt = {
+ .width = 1920,
+ .height = 1080,
+ .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+ .field = V4L2_FIELD_NONE,
+ },
+ .vic = 16,
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080p30_sb_half = {
+ .core = {
+ .h_blank = {0x18, 0x01},
+ .v2_blank = {0x65, 0x04},
+ .v1_blank = {0x2d, 0x00},
+ .v_line = {0x65, 0x04},
+ .h_line = {0x98, 0x08},
+ .hsync_pol = {0x00},
+ .vsync_pol = {0x00},
+ .int_pro_mode = {0x00},
+ .v_blank_f0 = {0xff, 0xff},
+ .v_blank_f1 = {0xff, 0xff},
+ .h_sync_start = {0x56, 0x00},
+ .h_sync_end = {0x82, 0x00},
+ .v_sync_line_bef_2 = {0x09, 0x00},
+ .v_sync_line_bef_1 = {0x04, 0x00},
+ .v_sync_line_aft_2 = {0xff, 0xff},
+ .v_sync_line_aft_1 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_2 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_1 = {0xff, 0xff},
+ .v_blank_f2 = {0xff, 0xff},
+ .v_blank_f3 = {0xff, 0xff},
+ .v_blank_f4 = {0xff, 0xff},
+ .v_blank_f5 = {0xff, 0xff},
+ .v_sync_line_aft_3 = {0xff, 0xff},
+ .v_sync_line_aft_4 = {0xff, 0xff},
+ .v_sync_line_aft_5 = {0xff, 0xff},
+ .v_sync_line_aft_6 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+ .vact_space_1 = {0xff, 0xff},
+ .vact_space_2 = {0xff, 0xff},
+ .vact_space_3 = {0xff, 0xff},
+ .vact_space_4 = {0xff, 0xff},
+ .vact_space_5 = {0xff, 0xff},
+ .vact_space_6 = {0xff, 0xff},
+ /* other don't care */
+ },
+ .tg = {
+ 0x00, /* cmd */
+ 0x98, 0x08, /* h_fsz */
+ 0x18, 0x01, 0x80, 0x07, /* hact */
+ 0x65, 0x04, /* v_fsz */
+ 0x01, 0x00, 0x33, 0x02, /* vsync */
+ 0x2d, 0x00, 0x38, 0x04, /* vact */
+ 0x33, 0x02, /* field_chg */
+ 0x48, 0x02, /* vact_st2 */
+ 0x00, 0x00, /* vact_st3 */
+ 0x00, 0x00, /* vact_st4 */
+ 0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+ 0x01, 0x00, 0x33, 0x02, /* field top/bot */
+ 0x00, /* 3d FP */
+ },
+ .mbus_fmt = {
+ .width = 1920,
+ .height = 1080,
+ .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+ .field = V4L2_FIELD_NONE,
+ },
+ .vic = 34,
+};
+
+static const struct hdmi_preset_conf hdmi_conf_1080p30_tb = {
+ .core = {
+ .h_blank = {0x18, 0x01},
+ .v2_blank = {0x65, 0x04},
+ .v1_blank = {0x2d, 0x00},
+ .v_line = {0x65, 0x04},
+ .h_line = {0x98, 0x08},
+ .hsync_pol = {0x00},
+ .vsync_pol = {0x00},
+ .int_pro_mode = {0x00},
+ .v_blank_f0 = {0xff, 0xff},
+ .v_blank_f1 = {0xff, 0xff},
+ .h_sync_start = {0x56, 0x00},
+ .h_sync_end = {0x82, 0x00},
+ .v_sync_line_bef_2 = {0x09, 0x00},
+ .v_sync_line_bef_1 = {0x04, 0x00},
+ .v_sync_line_aft_2 = {0xff, 0xff},
+ .v_sync_line_aft_1 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_2 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_1 = {0xff, 0xff},
+ .v_blank_f2 = {0xff, 0xff},
+ .v_blank_f3 = {0xff, 0xff},
+ .v_blank_f4 = {0xff, 0xff},
+ .v_blank_f5 = {0xff, 0xff},
+ .v_sync_line_aft_3 = {0xff, 0xff},
+ .v_sync_line_aft_4 = {0xff, 0xff},
+ .v_sync_line_aft_5 = {0xff, 0xff},
+ .v_sync_line_aft_6 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+ .vact_space_1 = {0xff, 0xff},
+ .vact_space_2 = {0xff, 0xff},
+ .vact_space_3 = {0xff, 0xff},
+ .vact_space_4 = {0xff, 0xff},
+ .vact_space_5 = {0xff, 0xff},
+ .vact_space_6 = {0xff, 0xff},
+ /* other don't care */
+ },
+ .tg = {
+ 0x00, /* cmd */
+ 0x98, 0x08, /* h_fsz */
+ 0x18, 0x01, 0x80, 0x07, /* hact */
+ 0x65, 0x04, /* v_fsz */
+ 0x01, 0x00, 0x33, 0x02, /* vsync */
+ 0x2d, 0x00, 0x38, 0x04, /* vact */
+ 0x33, 0x02, /* field_chg */
+ 0x48, 0x02, /* vact_st2 */
+ 0x00, 0x00, /* vact_st3 */
+ 0x00, 0x00, /* vact_st4 */
+ 0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+ 0x01, 0x00, 0x33, 0x02, /* field top/bot */
+ 0x00, /* 3d FP */
+ },
+ .mbus_fmt = {
+ .width = 1920,
+ .height = 1080,
+ .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
+ .field = V4L2_FIELD_NONE,
+ },
+ .vic = 34,
+};
+
+static const struct hdmi_3d_info info_2d = {
+ .is_3d = HDMI_VIDEO_FORMAT_2D,
+};
+
+static const struct hdmi_3d_info info_3d_sb_h = {
+ .is_3d = HDMI_VIDEO_FORMAT_3D,
+ .fmt_3d = HDMI_3D_FORMAT_SB_HALF,
+};
+
+static const struct hdmi_3d_info info_3d_tb = {
+ .is_3d = HDMI_VIDEO_FORMAT_3D,
+ .fmt_3d = HDMI_3D_FORMAT_TB,
+};
+
+static const struct hdmi_3d_info info_3d_fp = {
+ .is_3d = HDMI_VIDEO_FORMAT_3D,
+ .fmt_3d = HDMI_3D_FORMAT_FP,
+};
+
+const struct hdmi_conf hdmi_conf[] = {
+ { V4L2_DV_480P59_94, &hdmi_conf_480p59_94, &info_2d },
+ { V4L2_DV_480P60, &hdmi_conf_480p60, &info_2d },
+ { V4L2_DV_576P50, &hdmi_conf_576p50, &info_2d },
+ { V4L2_DV_720P50, &hdmi_conf_720p50, &info_2d },
+ { V4L2_DV_720P59_94, &hdmi_conf_720p59_94, &info_2d },
+ { V4L2_DV_720P60, &hdmi_conf_720p60, &info_2d },
+ { V4L2_DV_1080I50, &hdmi_conf_1080i50, &info_2d },
+ { V4L2_DV_1080I59_94, &hdmi_conf_1080i59_94, &info_2d },
+ { V4L2_DV_1080I60, &hdmi_conf_1080i60, &info_2d },
+ { V4L2_DV_1080P24, &hdmi_conf_1080p24, &info_2d },
+ { V4L2_DV_1080P25, &hdmi_conf_1080p25, &info_2d },
+ { V4L2_DV_1080P30, &hdmi_conf_1080p30, &info_2d },
+ { V4L2_DV_1080P50, &hdmi_conf_1080p50, &info_2d },
+ { V4L2_DV_1080P59_94, &hdmi_conf_1080p59_94, &info_2d },
+ { V4L2_DV_1080P60, &hdmi_conf_1080p60, &info_2d },
+ { V4L2_DV_720P60_SB_HALF, &hdmi_conf_720p60_sb_half, &info_3d_sb_h },
+ { V4L2_DV_720P60_TB, &hdmi_conf_720p60_tb, &info_3d_tb },
+ { V4L2_DV_720P59_94_SB_HALF, &hdmi_conf_720p59_94_sb_half,
+ &info_3d_sb_h },
+ { V4L2_DV_720P59_94_TB, &hdmi_conf_720p59_94_tb, &info_3d_tb },
+ { V4L2_DV_720P50_SB_HALF, &hdmi_conf_720p50_sb_half, &info_3d_sb_h },
+ { V4L2_DV_720P50_TB, &hdmi_conf_720p50_tb, &info_3d_tb },
+ { V4L2_DV_1080P24_FP, &hdmi_conf_1080p24_fp, &info_3d_fp },
+ { V4L2_DV_1080P24_SB_HALF, &hdmi_conf_1080p24_sb_half, &info_3d_sb_h },
+ { V4L2_DV_1080P24_TB, &hdmi_conf_1080p24_tb, &info_3d_tb },
+ { V4L2_DV_1080P23_98_FP, &hdmi_conf_1080p23_98_fp, &info_3d_fp },
+ { V4L2_DV_1080P23_98_SB_HALF, &hdmi_conf_1080p23_98_sb_half,
+ &info_3d_sb_h },
+ { V4L2_DV_1080P23_98_TB, &hdmi_conf_1080p23_98_tb, &info_3d_tb },
+ { V4L2_DV_1080I60_SB_HALF, &hdmi_conf_1080i60_sb_half, &info_3d_sb_h },
+ { V4L2_DV_1080I59_94_SB_HALF, &hdmi_conf_1080i59_94_sb_half,
+ &info_3d_sb_h },
+ { V4L2_DV_1080I50_SB_HALF, &hdmi_conf_1080i50_sb_half, &info_3d_sb_h },
+ { V4L2_DV_1080P60_SB_HALF, &hdmi_conf_1080p60_sb_half, &info_3d_sb_h },
+ { V4L2_DV_1080P60_TB, &hdmi_conf_1080p60_tb, &info_3d_tb },
+ { V4L2_DV_1080P30_SB_HALF, &hdmi_conf_1080p30_sb_half, &info_3d_sb_h },
+ { V4L2_DV_1080P30_TB, &hdmi_conf_1080p30_tb, &info_3d_tb },
+};
+
+const int hdmi_pre_cnt = ARRAY_SIZE(hdmi_conf);
+
+irqreturn_t hdmi_irq_handler(int irq, void *dev_data)
+{
+ struct hdmi_device *hdev = dev_data;
+ u32 intc_flag;
+
+ if (!pm_runtime_suspended(hdev->dev)) {
+ intc_flag = hdmi_read(hdev, HDMI_INTC_FLAG_0);
+ /* clearing flags for HPD plug/unplug */
+ if (intc_flag & HDMI_INTC_FLAG_HPD_UNPLUG) {
+ if (hdev->hdcp_info.hdcp_enable)
+ hdcp_stop(hdev);
+ hdmi_write_mask(hdev, HDMI_INTC_FLAG_0, ~0,
+ HDMI_INTC_FLAG_HPD_UNPLUG);
+ }
+ if (intc_flag & HDMI_INTC_FLAG_HPD_PLUG) {
+ hdmi_write_mask(hdev, HDMI_INTC_FLAG_0, ~0,
+ HDMI_INTC_FLAG_HPD_PLUG);
+ }
+ if (intc_flag & HDMI_INTC_FLAG_HDCP) {
+ pr_info("hdcp interrupt occur\n");
+ hdcp_irq_handler(hdev);
+ hdmi_write_mask(hdev, HDMI_INTC_FLAG_0, ~0,
+ HDMI_INTC_FLAG_HDCP);
+ }
+ }
+
+ queue_work(system_nrt_wq, &hdev->hpd_work);
+
+ return IRQ_HANDLED;
+}
+
+void hdmi_reg_init(struct hdmi_device *hdev)
+{
+ /* enable HPD interrupts */
+ hdmi_write_mask(hdev, HDMI_INTC_CON_0, ~0, HDMI_INTC_EN_GLOBAL |
+ HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG);
+ /* choose HDMI mode */
+ hdmi_write_mask(hdev, HDMI_MODE_SEL,
+ HDMI_MODE_HDMI_EN, HDMI_MODE_MASK);
+ /* disable bluescreen */
+ hdmi_write_mask(hdev, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN);
+ /* enable AVI packet every vsync, fixes purple line problem */
+ hdmi_writeb(hdev, HDMI_AVI_CON, HDMI_AVI_CON_EVERY_VSYNC);
+ /* RGB888 is default output format of HDMI,
+ * look to CEA-861-D, table 7 for more detail */
+ hdmi_writeb(hdev, HDMI_AVI_BYTE(1), 0 << 5);
+ hdmi_write_mask(hdev, HDMI_CON_1, 2, 3 << 5);
+}
+
+void hdmi_set_dvi_mode(struct hdmi_device *hdev)
+{
+ u32 val;
+
+ hdmi_write_mask(hdev, HDMI_MODE_SEL, hdev->dvi_mode ? HDMI_MODE_DVI_EN :
+ HDMI_MODE_HDMI_EN, HDMI_MODE_MASK);
+
+ if (hdev->dvi_mode)
+ val = HDMI_VID_PREAMBLE_DIS | HDMI_GUARD_BAND_DIS;
+ else
+ val = HDMI_VID_PREAMBLE_EN | HDMI_GUARD_BAND_EN;
+ hdmi_write(hdev, HDMI_CON_2, val);
+}
+
+void hdmi_timing_apply(struct hdmi_device *hdev,
+ const struct hdmi_preset_conf *conf)
+{
+ const struct hdmi_core_regs *core = &conf->core;
+ const struct hdmi_tg_regs *tg = &conf->tg;
+
+ /* setting core registers */
+ hdmi_writeb(hdev, HDMI_H_BLANK_0, core->h_blank[0]);
+ hdmi_writeb(hdev, HDMI_H_BLANK_1, core->h_blank[1]);
+ hdmi_writeb(hdev, HDMI_V2_BLANK_0, core->v2_blank[0]);
+ hdmi_writeb(hdev, HDMI_V2_BLANK_1, core->v2_blank[1]);
+ hdmi_writeb(hdev, HDMI_V1_BLANK_0, core->v1_blank[0]);
+ hdmi_writeb(hdev, HDMI_V1_BLANK_1, core->v1_blank[1]);
+ hdmi_writeb(hdev, HDMI_V_LINE_0, core->v_line[0]);
+ hdmi_writeb(hdev, HDMI_V_LINE_1, core->v_line[1]);
+ hdmi_writeb(hdev, HDMI_H_LINE_0, core->h_line[0]);
+ hdmi_writeb(hdev, HDMI_H_LINE_1, core->h_line[1]);
+ hdmi_writeb(hdev, HDMI_HSYNC_POL, core->hsync_pol[0]);
+ hdmi_writeb(hdev, HDMI_VSYNC_POL, core->vsync_pol[0]);
+ hdmi_writeb(hdev, HDMI_INT_PRO_MODE, core->int_pro_mode[0]);
+ hdmi_writeb(hdev, HDMI_V_BLANK_F0_0, core->v_blank_f0[0]);
+ hdmi_writeb(hdev, HDMI_V_BLANK_F0_1, core->v_blank_f0[1]);
+ hdmi_writeb(hdev, HDMI_V_BLANK_F1_0, core->v_blank_f1[0]);
+ hdmi_writeb(hdev, HDMI_V_BLANK_F1_1, core->v_blank_f1[1]);
+ hdmi_writeb(hdev, HDMI_H_SYNC_START_0, core->h_sync_start[0]);
+ hdmi_writeb(hdev, HDMI_H_SYNC_START_1, core->h_sync_start[1]);
+ hdmi_writeb(hdev, HDMI_H_SYNC_END_0, core->h_sync_end[0]);
+ hdmi_writeb(hdev, HDMI_H_SYNC_END_1, core->h_sync_end[1]);
+ hdmi_writeb(hdev, HDMI_V_SYNC_LINE_BEF_2_0, core->v_sync_line_bef_2[0]);
+ hdmi_writeb(hdev, HDMI_V_SYNC_LINE_BEF_2_1, core->v_sync_line_bef_2[1]);
+ hdmi_writeb(hdev, HDMI_V_SYNC_LINE_BEF_1_0, core->v_sync_line_bef_1[0]);
+ hdmi_writeb(hdev, HDMI_V_SYNC_LINE_BEF_1_1, core->v_sync_line_bef_1[1]);
+ hdmi_writeb(hdev, HDMI_V_SYNC_LINE_AFT_2_0, core->v_sync_line_aft_2[0]);
+ hdmi_writeb(hdev, HDMI_V_SYNC_LINE_AFT_2_1, core->v_sync_line_aft_2[1]);
+ hdmi_writeb(hdev, HDMI_V_SYNC_LINE_AFT_1_0, core->v_sync_line_aft_1[0]);
+ hdmi_writeb(hdev, HDMI_V_SYNC_LINE_AFT_1_1, core->v_sync_line_aft_1[1]);
+ hdmi_writeb(hdev, HDMI_V_SYNC_LINE_AFT_PXL_2_0,
+ core->v_sync_line_aft_pxl_2[0]);
+ hdmi_writeb(hdev, HDMI_V_SYNC_LINE_AFT_PXL_2_1,
+ core->v_sync_line_aft_pxl_2[1]);
+ hdmi_writeb(hdev, HDMI_V_SYNC_LINE_AFT_PXL_1_0,
+ core->v_sync_line_aft_pxl_1[0]);
+ hdmi_writeb(hdev, HDMI_V_SYNC_LINE_AFT_PXL_1_1,
+ core->v_sync_line_aft_pxl_1[1]);
+ hdmi_writeb(hdev, HDMI_V_BLANK_F2_0, core->v_blank_f2[0]);
+ hdmi_writeb(hdev, HDMI_V_BLANK_F2_1, core->v_blank_f2[1]);
+ hdmi_writeb(hdev, HDMI_V_BLANK_F3_0, core->v_blank_f3[0]);
+ hdmi_writeb(hdev, HDMI_V_BLANK_F3_1, core->v_blank_f3[1]);
+ hdmi_writeb(hdev, HDMI_V_BLANK_F4_0, core->v_blank_f4[0]);
+ hdmi_writeb(hdev, HDMI_V_BLANK_F4_1, core->v_blank_f4[1]);
+ hdmi_writeb(hdev, HDMI_V_BLANK_F5_0, core->v_blank_f5[0]);
+ hdmi_writeb(hdev, HDMI_V_BLANK_F5_1, core->v_blank_f5[1]);
+ hdmi_writeb(hdev, HDMI_V_SYNC_LINE_AFT_3_0, core->v_sync_line_aft_3[0]);
+ hdmi_writeb(hdev, HDMI_V_SYNC_LINE_AFT_3_1, core->v_sync_line_aft_3[1]);
+ hdmi_writeb(hdev, HDMI_V_SYNC_LINE_AFT_4_0, core->v_sync_line_aft_4[0]);
+ hdmi_writeb(hdev, HDMI_V_SYNC_LINE_AFT_4_1, core->v_sync_line_aft_4[1]);
+ hdmi_writeb(hdev, HDMI_V_SYNC_LINE_AFT_5_0, core->v_sync_line_aft_5[0]);
+ hdmi_writeb(hdev, HDMI_V_SYNC_LINE_AFT_5_1, core->v_sync_line_aft_5[1]);
+ hdmi_writeb(hdev, HDMI_V_SYNC_LINE_AFT_6_0, core->v_sync_line_aft_6[0]);
+ hdmi_writeb(hdev, HDMI_V_SYNC_LINE_AFT_6_1, core->v_sync_line_aft_6[1]);
+ hdmi_writeb(hdev, HDMI_V_SYNC_LINE_AFT_PXL_3_0,
+ core->v_sync_line_aft_pxl_3[0]);
+ hdmi_writeb(hdev, HDMI_V_SYNC_LINE_AFT_PXL_3_1,
+ core->v_sync_line_aft_pxl_3[1]);
+ hdmi_writeb(hdev, HDMI_V_SYNC_LINE_AFT_PXL_4_0,
+ core->v_sync_line_aft_pxl_4[0]);
+ hdmi_writeb(hdev, HDMI_V_SYNC_LINE_AFT_PXL_4_1,
+ core->v_sync_line_aft_pxl_4[1]);
+ hdmi_writeb(hdev, HDMI_V_SYNC_LINE_AFT_PXL_5_0,
+ core->v_sync_line_aft_pxl_5[0]);
+ hdmi_writeb(hdev, HDMI_V_SYNC_LINE_AFT_PXL_5_1,
+ core->v_sync_line_aft_pxl_5[1]);
+ hdmi_writeb(hdev, HDMI_V_SYNC_LINE_AFT_PXL_6_0,
+ core->v_sync_line_aft_pxl_6[0]);
+ hdmi_writeb(hdev, HDMI_V_SYNC_LINE_AFT_PXL_6_1,
+ core->v_sync_line_aft_pxl_6[1]);
+ hdmi_writeb(hdev, HDMI_VACT_SPACE_1_0, core->vact_space_1[0]);
+ hdmi_writeb(hdev, HDMI_VACT_SPACE_1_1, core->vact_space_1[1]);
+ hdmi_writeb(hdev, HDMI_VACT_SPACE_2_0, core->vact_space_2[0]);
+ hdmi_writeb(hdev, HDMI_VACT_SPACE_2_1, core->vact_space_2[1]);
+ hdmi_writeb(hdev, HDMI_VACT_SPACE_3_0, core->vact_space_3[0]);
+ hdmi_writeb(hdev, HDMI_VACT_SPACE_3_1, core->vact_space_3[1]);
+ hdmi_writeb(hdev, HDMI_VACT_SPACE_4_0, core->vact_space_4[0]);
+ hdmi_writeb(hdev, HDMI_VACT_SPACE_4_1, core->vact_space_4[1]);
+ hdmi_writeb(hdev, HDMI_VACT_SPACE_5_0, core->vact_space_5[0]);
+ hdmi_writeb(hdev, HDMI_VACT_SPACE_5_1, core->vact_space_5[1]);
+ hdmi_writeb(hdev, HDMI_VACT_SPACE_6_0, core->vact_space_6[0]);
+ hdmi_writeb(hdev, HDMI_VACT_SPACE_6_1, core->vact_space_6[1]);
+
+ /* Timing generator registers */
+ hdmi_writeb(hdev, HDMI_TG_H_FSZ_L, tg->h_fsz_l);
+ hdmi_writeb(hdev, HDMI_TG_H_FSZ_H, tg->h_fsz_h);
+ hdmi_writeb(hdev, HDMI_TG_HACT_ST_L, tg->hact_st_l);
+ hdmi_writeb(hdev, HDMI_TG_HACT_ST_H, tg->hact_st_h);
+ hdmi_writeb(hdev, HDMI_TG_HACT_SZ_L, tg->hact_sz_l);
+ hdmi_writeb(hdev, HDMI_TG_HACT_SZ_H, tg->hact_sz_h);
+ hdmi_writeb(hdev, HDMI_TG_V_FSZ_L, tg->v_fsz_l);
+ hdmi_writeb(hdev, HDMI_TG_V_FSZ_H, tg->v_fsz_h);
+ hdmi_writeb(hdev, HDMI_TG_VSYNC_L, tg->vsync_l);
+ hdmi_writeb(hdev, HDMI_TG_VSYNC_H, tg->vsync_h);
+ hdmi_writeb(hdev, HDMI_TG_VSYNC2_L, tg->vsync2_l);
+ hdmi_writeb(hdev, HDMI_TG_VSYNC2_H, tg->vsync2_h);
+ hdmi_writeb(hdev, HDMI_TG_VACT_ST_L, tg->vact_st_l);
+ hdmi_writeb(hdev, HDMI_TG_VACT_ST_H, tg->vact_st_h);
+ hdmi_writeb(hdev, HDMI_TG_VACT_SZ_L, tg->vact_sz_l);
+ hdmi_writeb(hdev, HDMI_TG_VACT_SZ_H, tg->vact_sz_h);
+ hdmi_writeb(hdev, HDMI_TG_FIELD_CHG_L, tg->field_chg_l);
+ hdmi_writeb(hdev, HDMI_TG_FIELD_CHG_H, tg->field_chg_h);
+ hdmi_writeb(hdev, HDMI_TG_VACT_ST2_L, tg->vact_st2_l);
+ hdmi_writeb(hdev, HDMI_TG_VACT_ST2_H, tg->vact_st2_h);
+ hdmi_writeb(hdev, HDMI_TG_VACT_ST3_L, tg->vact_st3_l);
+ hdmi_writeb(hdev, HDMI_TG_VACT_ST3_H, tg->vact_st3_h);
+ hdmi_writeb(hdev, HDMI_TG_VACT_ST4_L, tg->vact_st4_l);
+ hdmi_writeb(hdev, HDMI_TG_VACT_ST4_H, tg->vact_st4_h);
+ hdmi_writeb(hdev, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi_l);
+ hdmi_writeb(hdev, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi_h);
+ hdmi_writeb(hdev, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi_l);
+ hdmi_writeb(hdev, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi_h);
+ hdmi_writeb(hdev, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi_l);
+ hdmi_writeb(hdev, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi_h);
+ hdmi_writeb(hdev, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi_l);
+ hdmi_writeb(hdev, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi_h);
+ hdmi_writeb(hdev, HDMI_TG_3D, tg->tg_3d);
+}
+
+int hdmi_conf_apply(struct hdmi_device *hdmi_dev)
+{
+ struct device *dev = hdmi_dev->dev;
+ const struct hdmi_preset_conf *conf = hdmi_dev->cur_conf;
+ struct v4l2_dv_preset preset;
+ int ret;
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ /* configure presets */
+ preset.preset = hdmi_dev->cur_preset;
+ ret = v4l2_subdev_call(hdmi_dev->phy_sd, video, s_dv_preset, &preset);
+ if (ret) {
+ dev_err(dev, "failed to set preset (%u)\n", preset.preset);
+ return ret;
+ }
+
+ hdmi_reg_init(hdmi_dev);
+
+ /* setting core registers */
+ hdmi_timing_apply(hdmi_dev, conf);
+
+ return 0;
+}
+
+int is_hdmiphy_ready(struct hdmi_device *hdev)
+{
+ u32 val = hdmi_read(hdev, HDMI_PHY_STATUS);
+ if (val & HDMI_PHY_STATUS_READY)
+ return 1;
+
+ return 0;
+}
+
+void hdmi_enable(struct hdmi_device *hdev, int on)
+{
+ if (on)
+ hdmi_write_mask(hdev, HDMI_CON_0, ~0, HDMI_EN);
+ else
+ hdmi_write_mask(hdev, HDMI_CON_0, 0, HDMI_EN);
+}
+
+void hdmi_hpd_enable(struct hdmi_device *hdev, int on)
+{
+ /* enable HPD interrupts */
+ hdmi_write_mask(hdev, HDMI_INTC_CON_0, ~0, HDMI_INTC_EN_GLOBAL |
+ HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG);
+}
+
+void hdmi_tg_enable(struct hdmi_device *hdev, int on)
+{
+ u32 mask;
+
+ mask = (hdev->cur_conf->mbus_fmt.field == V4L2_FIELD_INTERLACED) ?
+ HDMI_TG_EN | HDMI_FIELD_EN : HDMI_TG_EN;
+
+ if (on)
+ hdmi_write_mask(hdev, HDMI_TG_CMD, ~0, mask);
+ else
+ hdmi_write_mask(hdev, HDMI_TG_CMD, 0, mask);
+}
+
+static u8 hdmi_chksum(struct hdmi_device *hdev, u32 start, u8 len, u32 hdr_sum)
+{
+ int i;
+
+ /* hdr_sum : header0 + header1 + header2
+ * start : start address of packet byte1
+ * len : packet bytes - 1 */
+ for (i = 0; i < len; ++i)
+ hdr_sum += hdmi_read(hdev, start + i * 4);
+
+ return (u8)(0x100 - (hdr_sum & 0xff));
+}
+
+void hdmi_reg_stop_vsi(struct hdmi_device *hdev)
+{
+ hdmi_writeb(hdev, HDMI_VSI_CON, HDMI_VSI_CON_DO_NOT_TRANSMIT);
+}
+
+void hdmi_reg_infoframe(struct hdmi_device *hdev,
+ struct hdmi_infoframe *infoframe)
+{
+ struct device *dev = hdev->dev;
+ const struct hdmi_3d_info *info = hdmi_preset2info(hdev->cur_preset);
+ u32 hdr_sum;
+ u8 chksum;
+ u32 aspect_ratio;
+ u32 vic;
+
+ dev_dbg(dev, "%s: InfoFrame type = 0x%x\n", __func__, infoframe->type);
+
+ /* Packets must NOT be transferred in case of DVI mode
+ * DVI mode doesn't allow Data Island Period. If any packet is tranferred,
+ * It makes Data Island Period */
+ if (hdev->dvi_mode) {
+ hdmi_writeb(hdev, HDMI_VSI_CON, HDMI_VSI_CON_DO_NOT_TRANSMIT);
+ hdmi_writeb(hdev, HDMI_AVI_CON, HDMI_AVI_CON_DO_NOT_TRANSMIT);
+ hdmi_write(hdev, HDMI_AUI_CON, HDMI_AUI_CON_NO_TRAN);
+ return;
+ }
+
+ switch (infoframe->type) {
+ case HDMI_PACKET_TYPE_VSI:
+ hdmi_writeb(hdev, HDMI_VSI_CON, HDMI_VSI_CON_EVERY_VSYNC);
+ hdmi_writeb(hdev, HDMI_VSI_HEADER0, infoframe->type);
+ hdmi_writeb(hdev, HDMI_VSI_HEADER1, infoframe->ver);
+ /* 0x000C03 : 24-bit IEEE Registration Identifier */
+ hdmi_writeb(hdev, HDMI_VSI_DATA(1), 0x03);
+ hdmi_writeb(hdev, HDMI_VSI_DATA(2), 0x0c);
+ hdmi_writeb(hdev, HDMI_VSI_DATA(3), 0x00);
+ hdmi_writeb(hdev, HDMI_VSI_DATA(4),
+ HDMI_VSI_DATA04_VIDEO_FORMAT(info->is_3d));
+ hdmi_writeb(hdev, HDMI_VSI_DATA(5),
+ HDMI_VSI_DATA05_3D_STRUCTURE(info->fmt_3d));
+ if (info->fmt_3d == HDMI_3D_FORMAT_SB_HALF) {
+ infoframe->len += 1;
+ hdmi_writeb(hdev, HDMI_VSI_DATA(6),
+ (u8)HDMI_VSI_DATA06_3D_EXT_DATA(HDMI_H_SUB_SAMPLE));
+ }
+ hdmi_writeb(hdev, HDMI_VSI_HEADER2, infoframe->len);
+ hdr_sum = infoframe->type + infoframe->ver + infoframe->len;
+ chksum = hdmi_chksum(hdev, HDMI_VSI_DATA(1), infoframe->len, hdr_sum);
+ dev_dbg(dev, "VSI checksum = 0x%x\n", chksum);
+ hdmi_writeb(hdev, HDMI_VSI_DATA(0), chksum);
+ break;
+ case HDMI_PACKET_TYPE_AVI:
+ hdmi_writeb(hdev, HDMI_AVI_CON, HDMI_AVI_CON_EVERY_VSYNC);
+ hdmi_writeb(hdev, HDMI_AVI_HEADER0, infoframe->type);
+ hdmi_writeb(hdev, HDMI_AVI_HEADER1, infoframe->ver);
+ hdmi_writeb(hdev, HDMI_AVI_HEADER2, infoframe->len);
+ hdr_sum = infoframe->type + infoframe->ver + infoframe->len;
+ hdmi_writeb(hdev, HDMI_AVI_BYTE(1), hdev->output_fmt << 5 |
+ AVI_ACTIVE_FORMAT_VALID);
+ if (hdev->aspect == HDMI_ASPECT_RATIO_4_3 &&
+ (hdev->cur_preset == V4L2_DV_480P59_94 ||
+ hdev->cur_preset == V4L2_DV_480P60)) {
+ aspect_ratio = AVI_PIC_ASPECT_RATIO_4_3;
+ /* 2 : 480P59.94/60Hz 4:3 aspect ratio */
+ vic = 2;
+ } else if (hdev->aspect == HDMI_ASPECT_RATIO_4_3 &&
+ hdev->cur_preset == V4L2_DV_576P50) {
+ aspect_ratio = AVI_PIC_ASPECT_RATIO_4_3;
+ /* 17 : 576P50Hz 4:3 aspect ratio */
+ vic = 17;
+ } else {
+ aspect_ratio = AVI_PIC_ASPECT_RATIO_16_9;
+ vic = hdev->cur_conf->vic;
+ }
+
+ hdmi_writeb(hdev, HDMI_AVI_BYTE(2), aspect_ratio |
+ AVI_SAME_AS_PIC_ASPECT_RATIO);
+ dev_dbg(dev, "VIC code = %d\n", vic);
+ hdmi_writeb(hdev, HDMI_AVI_BYTE(4), vic);
+ chksum = hdmi_chksum(hdev, HDMI_AVI_BYTE(1), infoframe->len, hdr_sum);
+ dev_dbg(dev, "AVI checksum = 0x%x\n", chksum);
+ hdmi_writeb(hdev, HDMI_AVI_CHECK_SUM, chksum);
+ break;
+ case HDMI_PACKET_TYPE_AUI:
+ hdmi_write(hdev, HDMI_AUI_CON, HDMI_AUI_CON_TRANS_EVERY_VSYNC);
+ hdmi_writeb(hdev, HDMI_AUI_HEADER0, infoframe->type);
+ hdmi_writeb(hdev, HDMI_AUI_HEADER1, infoframe->ver);
+ hdmi_writeb(hdev, HDMI_AUI_HEADER2, infoframe->len);
+ hdr_sum = infoframe->type + infoframe->ver + infoframe->len;
+ chksum = hdmi_chksum(hdev, HDMI_AUI_BYTE(1), infoframe->len, hdr_sum);
+ dev_dbg(dev, "AUI checksum = 0x%x\n", chksum);
+ hdmi_writeb(hdev, HDMI_AUI_CHECK_SUM, chksum);
+ break;
+ default:
+ break;
+ }
+}
+
+void hdmi_reg_set_acr(struct hdmi_device *hdev)
+{
+ u32 n, cts;
+ int sample_rate = hdev->sample_rate;
+
+ if (hdev->dvi_mode) {
+ hdmi_write(hdev, HDMI_ACR_CON, HDMI_ACR_CON_TX_MODE_NO_TX);
+ return;
+ }
+
+ if (sample_rate == 32000) {
+ n = 4096;
+ cts = 27000;
+ } else if (sample_rate == 44100) {
+ n = 6272;
+ cts = 30000;
+ } else if (sample_rate == 48000) {
+ n = 6144;
+ cts = 27000;
+ } else if (sample_rate == 88200) {
+ n = 12544;
+ cts = 30000;
+ } else if (sample_rate == 96000) {
+ n = 12288;
+ cts = 27000;
+ } else if (sample_rate == 176400) {
+ n = 25088;
+ cts = 30000;
+ } else if (sample_rate == 192000) {
+ n = 24576;
+ cts = 27000;
+ } else {
+ n = 0;
+ cts = 0;
+ }
+
+ hdmi_write(hdev, HDMI_ACR_N0, HDMI_ACR_N0_VAL(n));
+ hdmi_write(hdev, HDMI_ACR_N1, HDMI_ACR_N1_VAL(n));
+ hdmi_write(hdev, HDMI_ACR_N2, HDMI_ACR_N2_VAL(n));
+
+ /* transfer ACR packet */
+ hdmi_write(hdev, HDMI_ACR_CON, HDMI_ACR_CON_TX_MODE_MESURED_CTS);
+}
+
+void hdmi_reg_spdif_audio_init(struct hdmi_device *hdev)
+{
+ u32 val;
+ int bps, rep_time;
+
+ hdmi_write(hdev, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_ENABLE);
+
+ val = HDMI_SPDIFIN_CFG_NOISE_FILTER_2_SAMPLE |
+ HDMI_SPDIFIN_CFG_PCPD_MANUAL |
+ HDMI_SPDIFIN_CFG_WORD_LENGTH_MANUAL |
+ HDMI_SPDIFIN_CFG_UVCP_REPORT |
+ HDMI_SPDIFIN_CFG_HDMI_2_BURST |
+ HDMI_SPDIFIN_CFG_DATA_ALIGN_32;
+ hdmi_write(hdev, HDMI_SPDIFIN_CONFIG_1, val);
+ hdmi_write(hdev, HDMI_SPDIFIN_CONFIG_2, 0);
+
+ bps = hdev->audio_codec == HDMI_AUDIO_PCM ? hdev->bits_per_sample : 16;
+ rep_time = hdev->audio_codec == HDMI_AUDIO_AC3 ? 1536 * 2 - 1 : 0;
+ val = HDMI_SPDIFIN_USER_VAL_REPETITION_TIME_LOW(rep_time) |
+ HDMI_SPDIFIN_USER_VAL_WORD_LENGTH_24;
+ hdmi_write(hdev, HDMI_SPDIFIN_USER_VALUE_1, val);
+ val = HDMI_SPDIFIN_USER_VAL_REPETITION_TIME_HIGH(rep_time);
+ hdmi_write(hdev, HDMI_SPDIFIN_USER_VALUE_2, val);
+ hdmi_write(hdev, HDMI_SPDIFIN_USER_VALUE_3, 0);
+ hdmi_write(hdev, HDMI_SPDIFIN_USER_VALUE_4, 0);
+
+ val = HDMI_I2S_IN_ENABLE | HDMI_I2S_AUD_SPDIF | HDMI_I2S_MUX_ENABLE;
+ hdmi_write(hdev, HDMI_I2S_IN_MUX_CON, val);
+
+ hdmi_write(hdev, HDMI_I2S_MUX_CH, HDMI_I2S_CH_ALL_EN);
+ hdmi_write(hdev, HDMI_I2S_MUX_CUV, HDMI_I2S_CUV_RL_EN);
+
+ hdmi_write_mask(hdev, HDMI_SPDIFIN_CLK_CTRL, 0, HDMI_SPDIFIN_CLK_ON);
+ hdmi_write_mask(hdev, HDMI_SPDIFIN_CLK_CTRL, ~0, HDMI_SPDIFIN_CLK_ON);
+
+ hdmi_write(hdev, HDMI_SPDIFIN_OP_CTRL, HDMI_SPDIFIN_STATUS_CHECK_MODE);
+ hdmi_write(hdev, HDMI_SPDIFIN_OP_CTRL,
+ HDMI_SPDIFIN_STATUS_CHECK_MODE_HDMI);
+}
+
+void hdmi_reg_i2s_audio_init(struct hdmi_device *hdev)
+{
+ u32 data_num, bit_ch, sample_frq, val;
+ int sample_rate = hdev->sample_rate;
+ int bits_per_sample = hdev->bits_per_sample;
+
+ if (bits_per_sample == 16) {
+ data_num = 1;
+ bit_ch = 0;
+ } else if (bits_per_sample == 20) {
+ data_num = 2;
+ bit_ch = 1;
+ } else if (bits_per_sample == 24) {
+ data_num = 3;
+ bit_ch = 1;
+ } else if (bits_per_sample == 32) {
+ data_num = 1;
+ bit_ch = 2;
+ } else {
+ data_num = 1;
+ bit_ch = 0;
+ }
+
+ /* reset I2S */
+ hdmi_write(hdev, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_DISABLE);
+ hdmi_write(hdev, HDMI_I2S_CLK_CON, HDMI_I2S_CLK_ENABLE);
+
+ hdmi_write_mask(hdev, HDMI_I2S_DSD_CON, 0, HDMI_I2S_DSD_ENABLE);
+
+ /* Configuration I2S input ports. Configure I2S_PIN_SEL_0~4 */
+ val = HDMI_I2S_SEL_SCLK(5) | HDMI_I2S_SEL_LRCK(6);
+ hdmi_write(hdev, HDMI_I2S_PIN_SEL_0, val);
+ val = HDMI_I2S_SEL_SDATA1(3) | HDMI_I2S_SEL_SDATA0(4);
+ hdmi_write(hdev, HDMI_I2S_PIN_SEL_1, val);
+ val = HDMI_I2S_SEL_SDATA3(1) | HDMI_I2S_SEL_SDATA2(2);
+ hdmi_write(hdev, HDMI_I2S_PIN_SEL_2, val);
+ hdmi_write(hdev, HDMI_I2S_PIN_SEL_3, HDMI_I2S_SEL_DSD(0));
+
+ /* I2S_CON_1 & 2 */
+ val = HDMI_I2S_SCLK_FALLING_EDGE | HDMI_I2S_L_CH_LOW_POL;
+ hdmi_write(hdev, HDMI_I2S_CON_1, val);
+ val = HDMI_I2S_MSB_FIRST_MODE | HDMI_I2S_SET_BIT_CH(bit_ch) |
+ HDMI_I2S_SET_SDATA_BIT(data_num) | HDMI_I2S_BASIC_FORMAT;
+ hdmi_write(hdev, HDMI_I2S_CON_2, val);
+
+ if (sample_rate == 32000)
+ sample_frq = 0x3;
+ else if (sample_rate == 44100)
+ sample_frq = 0x0;
+ else if (sample_rate == 48000)
+ sample_frq = 0x2;
+ else if (sample_rate == 96000)
+ sample_frq = 0xa;
+ else
+ sample_frq = 0;
+
+ /* Configure register related to CUV information */
+ val = HDMI_I2S_CH_STATUS_MODE_0 | HDMI_I2S_2AUD_CH_WITHOUT_PREEMPH |
+ HDMI_I2S_COPYRIGHT | HDMI_I2S_LINEAR_PCM |
+ HDMI_I2S_CONSUMER_FORMAT;
+ hdmi_write(hdev, HDMI_I2S_CH_ST_0, val);
+ hdmi_write(hdev, HDMI_I2S_CH_ST_1, HDMI_I2S_CD_PLAYER);
+ hdmi_write(hdev, HDMI_I2S_CH_ST_2, HDMI_I2S_SET_SOURCE_NUM(0));
+ val = HDMI_I2S_CLK_ACCUR_LEVEL_1 |
+ HDMI_I2S_SET_SAMPLING_FREQ(sample_frq);
+ hdmi_write(hdev, HDMI_I2S_CH_ST_3, val);
+ val = HDMI_I2S_ORG_SAMPLING_FREQ_44_1 |
+ HDMI_I2S_WORD_LENGTH_MAX24_20BITS |
+ HDMI_I2S_WORD_LENGTH_MAX_20BITS;
+ hdmi_write(hdev, HDMI_I2S_CH_ST_4, val);
+
+ hdmi_write(hdev, HDMI_I2S_CH_ST_CON, HDMI_I2S_CH_STATUS_RELOAD);
+
+ val = HDMI_I2S_IN_ENABLE | HDMI_I2S_AUD_I2S | HDMI_I2S_CUV_I2S_ENABLE
+ | HDMI_I2S_MUX_ENABLE;
+ hdmi_write(hdev, HDMI_I2S_IN_MUX_CON, val);
+
+ val = HDMI_I2S_CH0_L_EN | HDMI_I2S_CH0_R_EN | HDMI_I2S_CH1_L_EN |
+ HDMI_I2S_CH1_R_EN | HDMI_I2S_CH2_L_EN | HDMI_I2S_CH2_R_EN |
+ HDMI_I2S_CH3_L_EN | HDMI_I2S_CH3_R_EN;
+ hdmi_write(hdev, HDMI_I2S_MUX_CH, val);
+
+ val = HDMI_I2S_CUV_L_EN | HDMI_I2S_CUV_R_EN;
+ hdmi_write(hdev, HDMI_I2S_MUX_CUV, val);
+}
+
+void hdmi_audio_enable(struct hdmi_device *hdev, int on)
+{
+ if (on) {
+ if (hdev->dvi_mode)
+ return;
+ hdmi_write_mask(hdev, HDMI_CON_0, ~0, HDMI_ASP_ENABLE);
+ } else
+ hdmi_write_mask(hdev, HDMI_CON_0, 0, HDMI_ASP_ENABLE);
+}
+
+void hdmi_bluescreen_enable(struct hdmi_device *hdev, int on)
+{
+ if (on)
+ hdmi_write_mask(hdev, HDMI_CON_0, ~0, HDMI_BLUE_SCR_EN);
+ else
+ hdmi_write_mask(hdev, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN);
+}
+
+void hdmi_reg_mute(struct hdmi_device *hdev, int on)
+{
+ hdmi_bluescreen_enable(hdev, on);
+ hdmi_audio_enable(hdev, !on);
+}
+
+int hdmi_hpd_status(struct hdmi_device *hdev)
+{
+ return hdmi_read(hdev, HDMI_HPD_STATUS);
+}
+
+int is_hdmi_streaming(struct hdmi_device *hdev)
+{
+ if (hdmi_hpd_status(hdev) && hdev->streaming)
+ return 1;
+ return 0;
+}
+
+u8 hdmi_get_int_mask(struct hdmi_device *hdev)
+{
+ return hdmi_readb(hdev, HDMI_INTC_CON_0);
+}
+
+void hdmi_set_int_mask(struct hdmi_device *hdev, u8 mask, int en)
+{
+ if (en) {
+ mask |= HDMI_INTC_EN_GLOBAL;
+ hdmi_write_mask(hdev, HDMI_INTC_CON_0, ~0, mask);
+ } else
+ hdmi_write_mask(hdev, HDMI_INTC_CON_0, 0,
+ HDMI_INTC_EN_GLOBAL);
+}
+
+void hdmi_sw_hpd_enable(struct hdmi_device *hdev, int en)
+{
+ if (en)
+ hdmi_write_mask(hdev, HDMI_HPD, ~0, HDMI_HPD_SEL_I_HPD);
+ else
+ hdmi_write_mask(hdev, HDMI_HPD, 0, HDMI_HPD_SEL_I_HPD);
+}
+
+void hdmi_sw_hpd_plug(struct hdmi_device *hdev, int en)
+{
+ if (en)
+ hdmi_write_mask(hdev, HDMI_HPD, ~0, HDMI_SW_HPD_PLUGGED);
+ else
+ hdmi_write_mask(hdev, HDMI_HPD, 0, HDMI_SW_HPD_PLUGGED);
+}
+
+void hdmi_phy_sw_reset(struct hdmi_device *hdev)
+{
+ hdmi_write_mask(hdev, HDMI_PHY_RSTOUT, ~0, HDMI_PHY_SW_RSTOUT);
+ mdelay(10);
+ hdmi_write_mask(hdev, HDMI_PHY_RSTOUT, 0, HDMI_PHY_SW_RSTOUT);
+}
+
+void hdmi_sw_reset(struct hdmi_device *hdev)
+{
+ hdmi_write_mask(hdev, HDMI_CORE_RSTOUT, 0, HDMI_CORE_SW_RSTOUT);
+ mdelay(10);
+ hdmi_write_mask(hdev, HDMI_CORE_RSTOUT, ~0, HDMI_CORE_SW_RSTOUT);
+}
+
+void hdmi_dumpregs(struct hdmi_device *hdev, char *prefix)
+{
+#define DUMPREG(reg_id) \
+ dev_dbg(hdev->dev, "%s:" #reg_id " = %08x\n", prefix, \
+ readl(hdev->regs + reg_id))
+
+ int i;
+
+ dev_dbg(hdev->dev, "%s: ---- CONTROL REGISTERS ----\n", prefix);
+ DUMPREG(HDMI_INTC_CON_0);
+ DUMPREG(HDMI_INTC_FLAG_0);
+ DUMPREG(HDMI_HPD_STATUS);
+ DUMPREG(HDMI_INTC_CON_1);
+ DUMPREG(HDMI_INTC_FLAG_1);
+ DUMPREG(HDMI_PHY_STATUS_0);
+ DUMPREG(HDMI_PHY_STATUS_PLL);
+ DUMPREG(HDMI_PHY_CON_0);
+ DUMPREG(HDMI_PHY_RSTOUT);
+ DUMPREG(HDMI_PHY_VPLL);
+ DUMPREG(HDMI_PHY_CMU);
+ DUMPREG(HDMI_CORE_RSTOUT);
+
+ dev_dbg(hdev->dev, "%s: ---- CORE REGISTERS ----\n", prefix);
+ DUMPREG(HDMI_CON_0);
+ DUMPREG(HDMI_CON_1);
+ DUMPREG(HDMI_CON_2);
+ DUMPREG(HDMI_STATUS);
+ DUMPREG(HDMI_PHY_STATUS);
+ DUMPREG(HDMI_STATUS_EN);
+ DUMPREG(HDMI_HPD);
+ DUMPREG(HDMI_MODE_SEL);
+ DUMPREG(HDMI_ENC_EN);
+ DUMPREG(HDMI_DC_CONTROL);
+ DUMPREG(HDMI_VIDEO_PATTERN_GEN);
+
+ dev_dbg(hdev->dev, "%s: ---- CORE SYNC REGISTERS ----\n", prefix);
+ DUMPREG(HDMI_H_BLANK_0);
+ DUMPREG(HDMI_H_BLANK_1);
+ DUMPREG(HDMI_V2_BLANK_0);
+ DUMPREG(HDMI_V2_BLANK_1);
+ DUMPREG(HDMI_V1_BLANK_0);
+ DUMPREG(HDMI_V1_BLANK_1);
+ DUMPREG(HDMI_V_LINE_0);
+ DUMPREG(HDMI_V_LINE_1);
+ DUMPREG(HDMI_H_LINE_0);
+ DUMPREG(HDMI_H_LINE_1);
+ DUMPREG(HDMI_HSYNC_POL);
+
+ DUMPREG(HDMI_VSYNC_POL);
+ DUMPREG(HDMI_INT_PRO_MODE);
+ DUMPREG(HDMI_V_BLANK_F0_0);
+ DUMPREG(HDMI_V_BLANK_F0_1);
+ DUMPREG(HDMI_V_BLANK_F1_0);
+ DUMPREG(HDMI_V_BLANK_F1_1);
+
+ DUMPREG(HDMI_H_SYNC_START_0);
+ DUMPREG(HDMI_H_SYNC_START_1);
+ DUMPREG(HDMI_H_SYNC_END_0);
+ DUMPREG(HDMI_H_SYNC_END_1);
+
+ DUMPREG(HDMI_V_SYNC_LINE_BEF_2_0);
+ DUMPREG(HDMI_V_SYNC_LINE_BEF_2_1);
+ DUMPREG(HDMI_V_SYNC_LINE_BEF_1_0);
+ DUMPREG(HDMI_V_SYNC_LINE_BEF_1_1);
+
+ DUMPREG(HDMI_V_SYNC_LINE_AFT_2_0);
+ DUMPREG(HDMI_V_SYNC_LINE_AFT_2_1);
+ DUMPREG(HDMI_V_SYNC_LINE_AFT_1_0);
+ DUMPREG(HDMI_V_SYNC_LINE_AFT_1_1);
+
+ DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_0);
+ DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_1);
+ DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_0);
+ DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_1);
+
+ DUMPREG(HDMI_V_BLANK_F2_0);
+ DUMPREG(HDMI_V_BLANK_F2_1);
+ DUMPREG(HDMI_V_BLANK_F3_0);
+ DUMPREG(HDMI_V_BLANK_F3_1);
+ DUMPREG(HDMI_V_BLANK_F4_0);
+ DUMPREG(HDMI_V_BLANK_F4_1);
+ DUMPREG(HDMI_V_BLANK_F5_0);
+ DUMPREG(HDMI_V_BLANK_F5_1);
+
+ DUMPREG(HDMI_V_SYNC_LINE_AFT_3_0);
+ DUMPREG(HDMI_V_SYNC_LINE_AFT_3_1);
+ DUMPREG(HDMI_V_SYNC_LINE_AFT_4_0);
+ DUMPREG(HDMI_V_SYNC_LINE_AFT_4_1);
+ DUMPREG(HDMI_V_SYNC_LINE_AFT_5_0);
+ DUMPREG(HDMI_V_SYNC_LINE_AFT_5_1);
+ DUMPREG(HDMI_V_SYNC_LINE_AFT_6_0);
+ DUMPREG(HDMI_V_SYNC_LINE_AFT_6_1);
+
+ DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_0);
+ DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_1);
+ DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_0);
+ DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_1);
+ DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_0);
+ DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_1);
+ DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_0);
+ DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_1);
+
+ DUMPREG(HDMI_VACT_SPACE_1_0);
+ DUMPREG(HDMI_VACT_SPACE_1_1);
+ DUMPREG(HDMI_VACT_SPACE_2_0);
+ DUMPREG(HDMI_VACT_SPACE_2_1);
+ DUMPREG(HDMI_VACT_SPACE_3_0);
+ DUMPREG(HDMI_VACT_SPACE_3_1);
+ DUMPREG(HDMI_VACT_SPACE_4_0);
+ DUMPREG(HDMI_VACT_SPACE_4_1);
+ DUMPREG(HDMI_VACT_SPACE_5_0);
+ DUMPREG(HDMI_VACT_SPACE_5_1);
+ DUMPREG(HDMI_VACT_SPACE_6_0);
+ DUMPREG(HDMI_VACT_SPACE_6_1);
+
+ dev_dbg(hdev->dev, "%s: ---- TG REGISTERS ----\n", prefix);
+ DUMPREG(HDMI_TG_CMD);
+ DUMPREG(HDMI_TG_H_FSZ_L);
+ DUMPREG(HDMI_TG_H_FSZ_H);
+ DUMPREG(HDMI_TG_HACT_ST_L);
+ DUMPREG(HDMI_TG_HACT_ST_H);
+ DUMPREG(HDMI_TG_HACT_SZ_L);
+ DUMPREG(HDMI_TG_HACT_SZ_H);
+ DUMPREG(HDMI_TG_V_FSZ_L);
+ DUMPREG(HDMI_TG_V_FSZ_H);
+ DUMPREG(HDMI_TG_VSYNC_L);
+ DUMPREG(HDMI_TG_VSYNC_H);
+ DUMPREG(HDMI_TG_VSYNC2_L);
+ DUMPREG(HDMI_TG_VSYNC2_H);
+ DUMPREG(HDMI_TG_VACT_ST_L);
+ DUMPREG(HDMI_TG_VACT_ST_H);
+ DUMPREG(HDMI_TG_VACT_SZ_L);
+ DUMPREG(HDMI_TG_VACT_SZ_H);
+ DUMPREG(HDMI_TG_FIELD_CHG_L);
+ DUMPREG(HDMI_TG_FIELD_CHG_H);
+ DUMPREG(HDMI_TG_VACT_ST2_L);
+ DUMPREG(HDMI_TG_VACT_ST2_H);
+ DUMPREG(HDMI_TG_VACT_ST3_L);
+ DUMPREG(HDMI_TG_VACT_ST3_H);
+ DUMPREG(HDMI_TG_VACT_ST4_L);
+ DUMPREG(HDMI_TG_VACT_ST4_H);
+ DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L);
+ DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H);
+ DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L);
+ DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H);
+ DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L);
+ DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H);
+ DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L);
+ DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H);
+ DUMPREG(HDMI_TG_3D);
+
+ dev_dbg(hdev->dev, "%s: ---- PACKET REGISTERS ----\n", prefix);
+ DUMPREG(HDMI_AVI_CON);
+ DUMPREG(HDMI_AVI_HEADER0);
+ DUMPREG(HDMI_AVI_HEADER1);
+ DUMPREG(HDMI_AVI_HEADER2);
+ DUMPREG(HDMI_AVI_CHECK_SUM);
+ for (i = 1; i < 6; ++i)
+ DUMPREG(HDMI_AVI_BYTE(i));
+
+ DUMPREG(HDMI_VSI_CON);
+ DUMPREG(HDMI_VSI_HEADER0);
+ DUMPREG(HDMI_VSI_HEADER1);
+ DUMPREG(HDMI_VSI_HEADER2);
+ for (i = 0; i < 7; ++i)
+ DUMPREG(HDMI_VSI_DATA(i));
+ DUMPREG(HDMI_AUI_CON);
+ DUMPREG(HDMI_ACR_CON);
+
+#undef DUMPREG
+}
diff --git a/drivers/media/video/exynos/tv/hdmiphy_conf_4210.c b/drivers/media/video/exynos/tv/hdmiphy_conf_4210.c
new file mode 100644
index 0000000..67033c5
--- /dev/null
+++ b/drivers/media/video/exynos/tv/hdmiphy_conf_4210.c
@@ -0,0 +1,53 @@
+/*
+ * Samsung HDMI Physical interface driver
+ *
+ * Copyright (C) 2010-2011 Samsung Electronics Co.Ltd
+ * Author: Jiun Yu <jiun.yu@samsung.com>
+ *
+ * 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.
+ */
+
+#include "hdmi.h"
+
+static const u8 hdmiphy_conf27[32] = {
+ 0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
+ 0x6B, 0x10, 0x02, 0x51, 0xDf, 0xF2, 0x54, 0x87,
+ 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
+ 0x22, 0x40, 0xe3, 0x26, 0x00, 0x00, 0x00, 0x80,
+};
+
+static const u8 hdmiphy_conf74_175[32] = {
+ 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B,
+ 0x6D, 0x10, 0x01, 0x51, 0xef, 0xF3, 0x54, 0xb9,
+ 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
+ 0x22, 0x40, 0xa5, 0x26, 0x01, 0x00, 0x00, 0x80,
+};
+
+static const u8 hdmiphy_conf74_25[32] = {
+ 0x01, 0x05, 0x00, 0xd8, 0x10, 0x9c, 0xf8, 0x40,
+ 0x6a, 0x10, 0x01, 0x51, 0xff, 0xf1, 0x54, 0xba,
+ 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xe0,
+ 0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x80,
+};
+
+static const u8 hdmiphy_conf148_5[32] = {
+ 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf8, 0x40,
+ 0x6A, 0x18, 0x00, 0x51, 0xff, 0xF1, 0x54, 0xba,
+ 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
+ 0x22, 0x40, 0xa4, 0x26, 0x02, 0x00, 0x00, 0x80,
+};
+
+const struct hdmiphy_conf hdmiphy_conf[] = {
+ { V4L2_DV_480P59_94, hdmiphy_conf27 },
+ { V4L2_DV_1080P30, hdmiphy_conf74_175 },
+ { V4L2_DV_720P59_94, hdmiphy_conf74_175 },
+ { V4L2_DV_720P60, hdmiphy_conf74_25 },
+ { V4L2_DV_1080P50, hdmiphy_conf148_5 },
+ { V4L2_DV_1080P60, hdmiphy_conf148_5 },
+ { V4L2_DV_1080I60, hdmiphy_conf74_25 },
+};
+
+const int hdmiphy_conf_cnt = ARRAY_SIZE(hdmiphy_conf);
diff --git a/drivers/media/video/exynos/tv/hdmiphy_conf_5250.c b/drivers/media/video/exynos/tv/hdmiphy_conf_5250.c
new file mode 100644
index 0000000..5cc0643
--- /dev/null
+++ b/drivers/media/video/exynos/tv/hdmiphy_conf_5250.c
@@ -0,0 +1,94 @@
+/*
+ * Samsung HDMI Physical interface driver
+ *
+ * Copyright (C) 2010-2011 Samsung Electronics Co.Ltd
+ * Author: Jiun Yu <jiun.yu@samsung.com>
+ *
+ * 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.
+ */
+
+#include "hdmi.h"
+
+static const u8 hdmiphy_conf27[32] = {
+ 0x01, 0x51, 0x2d, 0x75, 0x40, 0x01, 0x00, 0x08,
+ 0x82, 0xa0, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
+ 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
+ 0x54, 0xe3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00,
+};
+
+static const u8 hdmiphy_conf27_027[32] = {
+ 0x01, 0xd1, 0x2d, 0x72, 0x40, 0x64, 0x12, 0x08,
+ 0x43, 0xa0, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
+ 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
+ 0x54, 0xe3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00,
+};
+
+static const u8 hdmiphy_conf74_175[32] = {
+ 0x01, 0xd1, 0x1f, 0x10, 0x40, 0x5b, 0xef, 0x08,
+ 0x81, 0xa0, 0xb9, 0xd8, 0x45, 0xa0, 0xac, 0x80,
+ 0x5a, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
+ 0x54, 0xa6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x00,
+};
+
+static const u8 hdmiphy_conf74_25[32] = {
+ 0x01, 0xd1, 0x1f, 0x10, 0x40, 0x40, 0xf8, 0x08,
+ 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
+ 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
+ 0x54, 0xa5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x00,
+};
+
+static const u8 hdmiphy_conf148_352[32] = {
+ 0x01, 0xd2, 0x3e, 0x00, 0x40, 0x5b, 0xef, 0x08,
+ 0x81, 0xa0, 0xb9, 0xd8, 0x45, 0xa0, 0xac, 0x80,
+ 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
+ 0x54, 0x4b, 0x25, 0x03, 0x00, 0x00, 0x01, 0x00,
+};
+
+static const u8 hdmiphy_conf148_5[32] = {
+ 0x01, 0xd1, 0x1f, 0x00, 0x40, 0x40, 0xf8, 0x08,
+ 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
+ 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
+ 0x54, 0x4b, 0x25, 0x03, 0x00, 0x00, 0x01, 0x00,
+};
+
+const struct hdmiphy_conf hdmiphy_conf[] = {
+ { V4L2_DV_480P59_94, hdmiphy_conf27 },
+ { V4L2_DV_480P60, hdmiphy_conf27_027 },
+ { V4L2_DV_576P50, hdmiphy_conf27 },
+ { V4L2_DV_720P50, hdmiphy_conf74_25 },
+ { V4L2_DV_720P59_94, hdmiphy_conf74_175 },
+ { V4L2_DV_720P60, hdmiphy_conf74_25 },
+ { V4L2_DV_1080I50, hdmiphy_conf74_25 },
+ { V4L2_DV_1080I59_94, hdmiphy_conf74_175 },
+ { V4L2_DV_1080I60, hdmiphy_conf74_25 },
+ { V4L2_DV_1080P24, hdmiphy_conf74_25 },
+ { V4L2_DV_1080P25, hdmiphy_conf74_25 },
+ { V4L2_DV_1080P30, hdmiphy_conf74_175 },
+ { V4L2_DV_1080P50, hdmiphy_conf148_5 },
+ { V4L2_DV_1080P59_94, hdmiphy_conf148_352 },
+ { V4L2_DV_1080P60, hdmiphy_conf148_5 },
+ { V4L2_DV_720P60_SB_HALF, hdmiphy_conf74_25 },
+ { V4L2_DV_720P60_TB, hdmiphy_conf74_25 },
+ { V4L2_DV_720P59_94_SB_HALF, hdmiphy_conf74_25 },
+ { V4L2_DV_720P59_94_TB, hdmiphy_conf74_25 },
+ { V4L2_DV_720P50_SB_HALF, hdmiphy_conf74_25 },
+ { V4L2_DV_720P50_TB, hdmiphy_conf74_25 },
+ { V4L2_DV_1080P24_FP, hdmiphy_conf148_5 },
+ { V4L2_DV_1080P24_SB_HALF, hdmiphy_conf74_25 },
+ { V4L2_DV_1080P24_TB, hdmiphy_conf74_25 },
+ { V4L2_DV_1080P23_98_FP, hdmiphy_conf148_5 },
+ { V4L2_DV_1080P23_98_SB_HALF, hdmiphy_conf74_25 },
+ { V4L2_DV_1080P23_98_TB, hdmiphy_conf74_25 },
+ { V4L2_DV_1080I60_SB_HALF, hdmiphy_conf74_25 },
+ { V4L2_DV_1080I59_94_SB_HALF, hdmiphy_conf74_25 },
+ { V4L2_DV_1080I50_SB_HALF, hdmiphy_conf74_25 },
+ { V4L2_DV_1080P60_SB_HALF, hdmiphy_conf148_5 },
+ { V4L2_DV_1080P60_TB, hdmiphy_conf148_5 },
+ { V4L2_DV_1080P30_SB_HALF, hdmiphy_conf74_25 },
+ { V4L2_DV_1080P30_TB, hdmiphy_conf74_25 },
+};
+
+const int hdmiphy_conf_cnt = ARRAY_SIZE(hdmiphy_conf);
diff --git a/drivers/media/video/exynos/tv/hdmiphy_drv.c b/drivers/media/video/exynos/tv/hdmiphy_drv.c
new file mode 100644
index 0000000..01d28da
--- /dev/null
+++ b/drivers/media/video/exynos/tv/hdmiphy_drv.c
@@ -0,0 +1,259 @@
+/*
+ * Samsung HDMI Physical interface driver
+ *
+ * Copyright (C) 2010-2011 Samsung Electronics Co.Ltd
+ * Author: Tomasz Stanislawski <t.stanislaws@samsung.com>
+ *
+ * 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.
+ */
+#include "hdmi.h"
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/err.h>
+
+#include <media/v4l2-subdev.h>
+
+MODULE_AUTHOR("Tomasz Stanislawski <t.stanislaws@samsung.com>");
+MODULE_DESCRIPTION("Samsung HDMI Physical interface driver");
+MODULE_LICENSE("GPL");
+
+#ifdef DEBUG
+static void hdmiphy_print_reg(u8 *recv_buffer)
+{
+ int i;
+
+ for (i = 1; i <= 32; i++) {
+ printk("[%2x]", recv_buffer[i - 1]);
+ if (!(i % 8) && i)
+ printk("\n");
+ }
+ printk("\n");
+}
+#endif
+
+const u8 *hdmiphy_preset2conf(u32 preset)
+{
+ int i;
+ for (i = 0; i < hdmiphy_conf_cnt; ++i)
+ if (hdmiphy_conf[i].preset == preset)
+ return hdmiphy_conf[i].data;
+ return NULL;
+}
+
+static int hdmiphy_ctrl(struct i2c_client *client, u8 reg, u8 bit,
+ u8 *recv_buffer, int en)
+{
+ int ret;
+ u8 buffer[2];
+ struct device *dev = &client->dev;
+
+ buffer[0] = reg;
+ buffer[1] = en ? (recv_buffer[reg] & (~(1 << bit))) :
+ (recv_buffer[reg] | (1 << bit));
+ recv_buffer[reg] = buffer[1];
+
+ ret = i2c_master_send(client, buffer, 2);
+ if (ret != 2) {
+ dev_err(dev, "failed to turn %s HDMIPHY via I2C\n",
+ en ? "on" : "off");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int hdmiphy_enable_oscpad(struct i2c_client *client, int on,
+ u8 *recv_buffer)
+{
+ int ret;
+ u8 buffer[2];
+ struct device *dev = &client->dev;
+
+ buffer[0] = 0x0b;
+ if (on)
+ buffer[1] = 0xd8;
+ else
+ buffer[1] = 0x18;
+ recv_buffer[0x0b] = buffer[1];
+
+ ret = i2c_master_send(client, buffer, 2);
+ if (ret != 2) {
+ dev_err(dev, "failed to %s osc pad\n",
+ on ? "enable" : "disable");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int hdmiphy_s_power(struct v4l2_subdev *sd, int on)
+{
+ u8 recv_buffer[32];
+ u8 buffer[2];
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct device *dev = &client->dev;
+
+ memset(recv_buffer, 0, sizeof(recv_buffer));
+
+ dev_dbg(dev, "%s: hdmiphy is %s\n", __func__, on ? "on" : "off");
+
+ buffer[0] = 0x1;
+ i2c_master_send(client, buffer, 1);
+ i2c_master_recv(client, recv_buffer, 32);
+
+#ifdef DEBUG
+ hdmiphy_print_reg(recv_buffer);
+#endif
+
+ if (!on)
+ hdmiphy_enable_oscpad(client, 0, recv_buffer);
+
+ hdmiphy_ctrl(client, 0x1d, 0x7, recv_buffer, on);
+ hdmiphy_ctrl(client, 0x1d, 0x0, recv_buffer, on);
+ hdmiphy_ctrl(client, 0x1d, 0x1, recv_buffer, on);
+ hdmiphy_ctrl(client, 0x1d, 0x2, recv_buffer, on);
+ hdmiphy_ctrl(client, 0x1d, 0x4, recv_buffer, on);
+ hdmiphy_ctrl(client, 0x1d, 0x5, recv_buffer, on);
+ hdmiphy_ctrl(client, 0x1d, 0x6, recv_buffer, on);
+
+ if (!on)
+ hdmiphy_ctrl(client, 0x4, 0x3, recv_buffer, 0);
+
+#ifdef DEBUG
+ buffer[0] = 0x1;
+ i2c_master_send(client, buffer, 1);
+ i2c_master_recv(client, recv_buffer, 32);
+
+ hdmiphy_print_reg(recv_buffer);
+#endif
+ return 0;
+}
+
+static int hdmiphy_s_dv_preset(struct v4l2_subdev *sd,
+ struct v4l2_dv_preset *preset)
+{
+ const u8 *data;
+ u8 buffer[32];
+ u8 recv_buffer[32];
+ int ret;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct device *dev = &client->dev;
+
+ dev_dbg(dev, "s_dv_preset(preset = %d)\n", preset->preset);
+ data = hdmiphy_preset2conf(preset->preset);
+ if (!data) {
+ dev_err(dev, "format not supported\n");
+ return -EINVAL;
+ }
+
+ memset(recv_buffer, 0, 32);
+
+#ifdef DEBUG
+ i2c_master_recv(client, recv_buffer, 32);
+ hdmiphy_print_reg(recv_buffer);
+#endif
+
+ /* storing configuration to the device */
+ memcpy(buffer, data, 32);
+ ret = i2c_master_send(client, buffer, 32);
+ if (ret != 32) {
+ dev_err(dev, "failed to configure HDMIPHY via I2C\n");
+ return -EIO;
+ }
+
+#ifdef DEBUG
+ i2c_master_recv(client, recv_buffer, 32);
+ hdmiphy_print_reg(recv_buffer);
+#endif
+
+ return 0;
+}
+
+static int hdmiphy_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct device *dev = &client->dev;
+ u8 buffer[2];
+ int ret;
+
+ dev_dbg(dev, "s_stream(%d)\n", enable);
+ /* going to/from configuration from/to operation mode */
+ buffer[0] = 0x1f;
+ buffer[1] = enable ? 0x80 : 0x00;
+
+ ret = i2c_master_send(client, buffer, 2);
+ if (ret != 2) {
+ dev_err(dev, "stream (%d) failed\n", enable);
+ return -EIO;
+ }
+ return 0;
+}
+
+static const struct v4l2_subdev_core_ops hdmiphy_core_ops = {
+ .s_power = hdmiphy_s_power,
+};
+
+static const struct v4l2_subdev_video_ops hdmiphy_video_ops = {
+ .s_dv_preset = hdmiphy_s_dv_preset,
+ .s_stream = hdmiphy_s_stream,
+};
+
+static const struct v4l2_subdev_ops hdmiphy_ops = {
+ .core = &hdmiphy_core_ops,
+ .video = &hdmiphy_video_ops,
+};
+
+static int __devinit hdmiphy_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ static struct v4l2_subdev sd;
+
+ dev_info(&client->dev, "hdmiphy_probe start\n");
+
+ v4l2_i2c_subdev_init(&sd, client, &hdmiphy_ops);
+ dev_info(&client->dev, "probe successful\n");
+ return 0;
+}
+
+static int __devexit hdmiphy_remove(struct i2c_client *client)
+{
+ dev_info(&client->dev, "remove successful\n");
+ return 0;
+}
+
+static const struct i2c_device_id hdmiphy_id[] = {
+ { "hdmiphy", 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(i2c, hdmiphy_id);
+
+static struct i2c_driver hdmiphy_driver = {
+ .driver = {
+ .name = "s5p-hdmiphy",
+ .owner = THIS_MODULE,
+ },
+ .probe = hdmiphy_probe,
+ .remove = __devexit_p(hdmiphy_remove),
+ .id_table = hdmiphy_id,
+};
+
+static int __init hdmiphy_init(void)
+{
+ return i2c_add_driver(&hdmiphy_driver);
+}
+module_init(hdmiphy_init);
+
+static void __exit hdmiphy_exit(void)
+{
+ i2c_del_driver(&hdmiphy_driver);
+}
+module_exit(hdmiphy_exit);
diff --git a/drivers/media/video/exynos/tv/mixer.h b/drivers/media/video/exynos/tv/mixer.h
new file mode 100644
index 0000000..ad30225
--- /dev/null
+++ b/drivers/media/video/exynos/tv/mixer.h
@@ -0,0 +1,562 @@
+/*
+ * Samsung TV Mixer driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * Tomasz Stanislawski, <t.stanislaws@samsung.com>
+ *
+ * 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 Foundiation. either version 2 of the License,
+ * or (at your option) any later version
+ */
+
+#ifndef SAMSUNG_MIXER_H
+#define SAMSUNG_MIXER_H
+
+#ifdef CONFIG_VIDEO_EXYNOS_MIXER_DEBUG
+ #define DEBUG
+#endif
+
+#include <linux/fb.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+#include <linux/videodev2_exynos_media.h>
+#include <media/v4l2-device.h>
+#include <media/videobuf2-core.h>
+#include <media/exynos_mc.h>
+
+#include "regs-mixer.h"
+
+/** maximum number of output interfaces */
+#define MXR_MAX_OUTPUTS 2
+
+/** There are 2 mixers after EXYNOS5250 */
+#define MXR_SUB_MIXER0 0
+#define MXR_SUB_MIXER1 1
+/** maximum number of sub-mixers */
+#if defined(CONFIG_ARCH_EXYNOS4)
+#define MXR_MAX_SUB_MIXERS 1
+#else
+#define MXR_MAX_SUB_MIXERS 2
+#endif
+
+/** each sub-mixer supports 1 video layer and 2 graphic layers */
+#define MXR_LAYER_VIDEO 0
+#define MXR_LAYER_GRP0 1
+#define MXR_LAYER_GRP1 2
+
+/** maximum number of input interfaces (layers) */
+#define MXR_MAX_LAYERS 3
+#define MXR_DRIVER_NAME "s5p-mixer"
+/** maximal number of planes for every layer */
+#define MXR_MAX_PLANES 2
+
+#define MXR_ENABLE 1
+#define MXR_DISABLE 0
+
+/* mixer pad definitions */
+#define MXR_PAD_SINK_GSCALER 0
+#define MXR_PAD_SINK_GRP0 1
+#define MXR_PAD_SINK_GRP1 2
+#define MXR_PAD_SOURCE_GSCALER 3
+#define MXR_PAD_SOURCE_GRP0 4
+#define MXR_PAD_SOURCE_GRP1 5
+#define MXR_PADS_NUM 6
+/** description of a macroblock for packed formats */
+struct mxr_block {
+ /** vertical number of pixels in macroblock */
+ unsigned int width;
+ /** horizontal number of pixels in macroblock */
+ unsigned int height;
+ /** size of block in bytes */
+ unsigned int size;
+};
+
+/** description of supported format */
+struct mxr_format {
+ /** format name/mnemonic */
+ const char *name;
+ /** fourcc identifier */
+ u32 fourcc;
+ /** colorspace identifier */
+ enum v4l2_colorspace colorspace;
+ /** number of planes in image data */
+ int num_planes;
+ /** description of block for each plane */
+ struct mxr_block plane[MXR_MAX_PLANES];
+ /** number of subframes in image data */
+ int num_subframes;
+ /** specifies to which subframe belong given plane */
+ int plane2subframe[MXR_MAX_PLANES];
+ /** internal code, driver dependant */
+ unsigned long cookie;
+};
+
+/** description of crop configuration for image */
+struct mxr_crop {
+ /** width of layer in pixels */
+ unsigned int full_width;
+ /** height of layer in pixels */
+ unsigned int full_height;
+ /** horizontal offset of first pixel to be displayed */
+ unsigned int x_offset;
+ /** vertical offset of first pixel to be displayed */
+ unsigned int y_offset;
+ /** width of displayed data in pixels */
+ unsigned int width;
+ /** height of displayed data in pixels */
+ unsigned int height;
+ /** indicate which fields are present in buffer */
+ unsigned int field;
+};
+
+/** stages of geometry operations */
+enum mxr_geometry_stage {
+ MXR_GEOMETRY_SINK,
+ MXR_GEOMETRY_COMPOSE,
+ MXR_GEOMETRY_CROP,
+ MXR_GEOMETRY_SOURCE,
+};
+
+/** description of transformation from source to destination image */
+struct mxr_geometry {
+ /** cropping for source image */
+ struct mxr_crop src;
+ /** cropping for destination image */
+ struct mxr_crop dst;
+ /** layer-dependant description of horizontal scaling */
+ unsigned int x_ratio;
+ /** layer-dependant description of vertical scaling */
+ unsigned int y_ratio;
+};
+
+/** instance of a buffer */
+struct mxr_buffer {
+ /** common v4l buffer stuff -- must be first */
+ struct vb2_buffer vb;
+ /** node for layer's lists */
+ struct list_head list;
+ struct list_head wait;
+};
+
+/** TV graphic layer pipeline state */
+enum mxr_pipeline_state {
+ /** graphic layer is not shown */
+ MXR_PIPELINE_IDLE = 0,
+ /** state between STREAMON and hardware start */
+ MXR_PIPELINE_STREAMING_START,
+ /** graphic layer is shown */
+ MXR_PIPELINE_STREAMING,
+ /** state before STREAMOFF is finished */
+ MXR_PIPELINE_STREAMING_FINISH,
+};
+
+/** TV graphic layer pipeline structure for streaming media data */
+struct mxr_pipeline {
+ struct media_pipeline pipe;
+ enum mxr_pipeline_state state;
+
+ /** starting point on pipeline */
+ struct mxr_layer *layer;
+};
+
+/** forward declarations */
+struct mxr_device;
+struct mxr_layer;
+
+/** callback for layers operation */
+struct mxr_layer_ops {
+ /* TODO: try to port it to subdev API */
+ /** handler for resource release function */
+ void (*release)(struct mxr_layer *);
+ /** setting buffer to HW */
+ void (*buffer_set)(struct mxr_layer *, struct mxr_buffer *);
+ /** setting format and geometry in HW */
+ void (*format_set)(struct mxr_layer *);
+ /** streaming stop/start */
+ void (*stream_set)(struct mxr_layer *, int);
+ /** adjusting geometry */
+ void (*fix_geometry)(struct mxr_layer *);
+};
+
+enum mxr_layer_type {
+ MXR_LAYER_TYPE_VIDEO = 0,
+ MXR_LAYER_TYPE_GRP = 1,
+};
+
+struct mxr_layer_en {
+ int graph0;
+ int graph1;
+ int graph2;
+ int graph3;
+};
+
+/** layer instance, a single window and content displayed on output */
+struct mxr_layer {
+ /** parent mixer device */
+ struct mxr_device *mdev;
+ /** layer index (unique identifier) */
+ int idx;
+ /** layer type */
+ enum mxr_layer_type type;
+ /** minor number of mixer layer as video device */
+ int minor;
+ /** callbacks for layer methods */
+ struct mxr_layer_ops ops;
+ /** format array */
+ const struct mxr_format **fmt_array;
+ /** size of format array */
+ unsigned long fmt_array_size;
+
+ /** lock for protection of list and state fields */
+ spinlock_t enq_slock;
+ /** list for enqueued buffers */
+ struct list_head enq_list;
+
+ /** list for buffers waiting on a fence */
+ struct list_head fence_wait_list;
+ struct workqueue_struct *fence_wq;
+ struct work_struct fence_work;
+
+ /** buffer currently owned by hardware in temporary registers */
+ struct mxr_buffer *update_buf;
+ /** buffer currently owned by hardware in shadow registers */
+ struct mxr_buffer *shadow_buf;
+
+ /** mutex for protection of fields below */
+ struct mutex mutex;
+ /** handler for video node */
+ struct video_device vfd;
+ /** queue for output buffers */
+ struct vb2_queue vb_queue;
+ /** current image format */
+ const struct mxr_format *fmt;
+ /** current geometry of image */
+ struct mxr_geometry geo;
+
+ /** index of current mixer path : MXR_SUB_MIXERx*/
+ int cur_mxr;
+ /** source pad of mixer input */
+ struct media_pad pad;
+ /** pipeline structure for streaming TV graphic layer */
+ struct mxr_pipeline pipe;
+
+ /** enable per layer blending for each layer */
+ int layer_blend_en;
+ /** alpha value for per layer blending */
+ u32 layer_alpha;
+ /** enable per pixel blending */
+ int pixel_blend_en;
+ /** enable chromakey */
+ int chroma_en;
+ /** value for chromakey */
+ u32 chroma_val;
+ /** priority for each layer */
+ u8 prio;
+};
+
+/** description of mixers output interface */
+struct mxr_output {
+ /** name of output */
+ char name[32];
+ /** output subdev */
+ struct v4l2_subdev *sd;
+ /** cookie used for configuration of registers */
+ int cookie;
+};
+
+/** specify source of output subdevs */
+struct mxr_output_conf {
+ /** name of output (connector) */
+ char *output_name;
+ /** name of module that generates output subdev */
+ char *module_name;
+ /** cookie need for mixer HW */
+ int cookie;
+};
+
+struct clk;
+struct regulator;
+
+/** auxiliary resources used my mixer */
+struct mxr_resources {
+ /** interrupt index */
+ int irq;
+ /** pointer to Mixer registers */
+ void __iomem *mxr_regs;
+#if defined(CONFIG_ARCH_EXYNOS4)
+ /** pointer to Video Processor registers */
+ void __iomem *vp_regs;
+ /** other resources, should used under mxr_device.mutex */
+ struct clk *vp;
+#endif
+#if defined(CONFIG_CPU_EXYNOS4210)
+ struct clk *sclk_dac;
+#endif
+ struct clk *sclk_mixer;
+ struct clk *mixer;
+ struct clk *sclk_hdmi;
+};
+
+/* event flags used */
+enum mxr_devide_flags {
+ MXR_EVENT_VSYNC = 0,
+};
+
+/** videobuf2 context of mixer */
+struct mxr_vb2 {
+ const struct vb2_mem_ops *ops;
+ void *(*init)(struct mxr_device *mdev);
+ void (*cleanup)(void *alloc_ctx);
+
+ unsigned long (*plane_addr)(struct vb2_buffer *vb, u32 plane_no);
+
+ int (*resume)(void *alloc_ctx);
+ void (*suspend)(void *alloc_ctx);
+
+ int (*cache_flush)(struct vb2_buffer *vb, u32 num_planes);
+ void (*set_cacheable)(void *alloc_ctx, bool cacheable);
+};
+
+/** sub-mixer 0,1 drivers instance */
+struct sub_mxr_device {
+ /** state of each layer */
+ struct mxr_layer *layer[MXR_MAX_LAYERS];
+
+ /** use of each sub mixer */
+ int use;
+ /** use of local path gscaler to mixer */
+ int local;
+ /** for mixer as sub-device */
+ struct v4l2_subdev sd;
+ /** mixer's pads : 3 sink pad, 3 source pad */
+ struct media_pad pads[MXR_PADS_NUM];
+ /** format info of mixer's pads */
+ struct v4l2_mbus_framefmt mbus_fmt[MXR_PADS_NUM];
+ /** crop info of mixer's pads */
+ struct v4l2_rect crop[MXR_PADS_NUM];
+};
+
+/** drivers instance */
+struct mxr_device {
+ /** master device */
+ struct device *dev;
+ /** state of each output */
+ struct mxr_output *output[MXR_MAX_OUTPUTS];
+ /** number of registered outputs */
+ int output_cnt;
+
+ /* video resources */
+
+ /** videbuf2 context */
+ const struct mxr_vb2 *vb2;
+ /** context of allocator */
+ void *alloc_ctx;
+ /** event wait queue */
+ wait_queue_head_t event_queue;
+ /** state flags */
+ unsigned long event_flags;
+
+ /** spinlock for protection of registers */
+ spinlock_t reg_slock;
+
+ /** mutex for protection of fields below */
+ struct mutex mutex;
+ /** mutex for protection of streamer */
+ struct mutex s_mutex;
+
+ /** number of entities depndant on output configuration */
+ int n_output;
+ /** number of users that do streaming */
+ int n_streamer;
+ /** index of current output */
+ int current_output;
+ /** auxiliary resources used my mixer */
+ struct mxr_resources res;
+
+ /** number of G-Scaler linked to mixer0 */
+ int mxr0_gsc;
+ /** number of G-Scaler linked to mixer1 */
+ int mxr1_gsc;
+ /** media entity link setup flags */
+ unsigned long flags;
+
+ /** entity info which transfers media data to mixer subdev */
+ enum mxr_data_from mxr_data_from;
+
+ /** count of sub-mixers */
+ struct sub_mxr_device sub_mxr[MXR_MAX_SUB_MIXERS];
+
+ /** enabled layer number **/
+ struct mxr_layer_en layer_en;
+ /** frame packing flag **/
+ int frame_packing;
+
+ struct exynos5_bus_mif_handle *mif_handle;
+ struct exynos5_bus_int_handle *int_handle;
+};
+
+#if defined(CONFIG_VIDEOBUF2_CMA_PHYS)
+extern const struct mxr_vb2 mxr_vb2_cma;
+#elif defined(CONFIG_VIDEOBUF2_ION)
+extern const struct mxr_vb2 mxr_vb2_ion;
+#endif
+
+/** transform device structure into mixer device */
+static inline struct mxr_device *to_mdev(struct device *dev)
+{
+ return dev_get_drvdata(dev);
+}
+
+/** transform subdev structure into mixer device */
+static inline struct mxr_device *sd_to_mdev(struct v4l2_subdev *sd)
+{
+ struct sub_mxr_device *sub_mxr =
+ container_of(sd, struct sub_mxr_device, sd);
+ return sub_mxr->layer[MXR_LAYER_GRP0]->mdev;
+}
+
+/** transform subdev structure into sub mixer device */
+static inline struct sub_mxr_device *sd_to_sub_mxr(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct sub_mxr_device, sd);
+}
+
+/** transform entity structure into sub mixer device */
+static inline struct sub_mxr_device *entity_to_sub_mxr(struct media_entity *me)
+{
+ struct v4l2_subdev *sd;
+
+ sd = container_of(me, struct v4l2_subdev, entity);
+ return container_of(sd, struct sub_mxr_device, sd);
+}
+
+/** transform entity structure into sub mixer device */
+static inline struct mxr_device *sub_mxr_to_mdev(struct sub_mxr_device *sub_mxr)
+{
+ int idx;
+
+ if (!strcmp(sub_mxr->sd.name, "s5p-mixer0"))
+ idx = MXR_SUB_MIXER0;
+ else
+ idx = MXR_SUB_MIXER1;
+
+ return container_of(sub_mxr, struct mxr_device, sub_mxr[idx]);
+}
+
+/** get current output data, should be called under mdev's mutex */
+static inline struct mxr_output *to_output(struct mxr_device *mdev)
+{
+ return mdev->output[mdev->current_output];
+}
+
+/** get current output subdev, should be called under mdev's mutex */
+static inline struct v4l2_subdev *to_outsd(struct mxr_device *mdev)
+{
+ struct mxr_output *out = to_output(mdev);
+ return out ? out->sd : NULL;
+}
+
+/** forward declaration for mixer platform data */
+struct mxr_platform_data;
+
+/** acquiring common video resources */
+int __devinit mxr_acquire_video(struct mxr_device *mdev,
+ struct mxr_output_conf *output_cont, int output_count);
+
+/** releasing common video resources */
+void mxr_release_video(struct mxr_device *mdev);
+
+struct mxr_layer *mxr_graph_layer_create(struct mxr_device *mdev, int cur_mxr,
+ int idx, int nr);
+struct mxr_layer *mxr_vp_layer_create(struct mxr_device *mdev, int cur_mxr,
+ int idx, int nr);
+struct mxr_layer *mxr_video_layer_create(struct mxr_device *mdev, int cur_mxr,
+ int idx);
+struct mxr_layer *mxr_base_layer_create(struct mxr_device *mdev,
+ int idx, char *name, struct mxr_layer_ops *ops);
+
+const struct mxr_format *find_format_by_fourcc(
+ struct mxr_layer *layer, unsigned long fourcc);
+
+void mxr_base_layer_release(struct mxr_layer *layer);
+void mxr_layer_release(struct mxr_layer *layer);
+void mxr_layer_geo_fix(struct mxr_layer *layer);
+void mxr_layer_default_geo(struct mxr_layer *layer);
+
+int mxr_base_layer_register(struct mxr_layer *layer);
+void mxr_base_layer_unregister(struct mxr_layer *layer);
+
+unsigned long mxr_get_plane_size(const struct mxr_block *blk,
+ unsigned int width, unsigned int height);
+
+/** adds new consumer for mixer's power */
+int __must_check mxr_power_get(struct mxr_device *mdev);
+/** removes consumer for mixer's power */
+void mxr_power_put(struct mxr_device *mdev);
+/** add new client for output configuration */
+void mxr_output_get(struct mxr_device *mdev);
+/** removes new client for output configuration */
+void mxr_output_put(struct mxr_device *mdev);
+/** returns format of data delivared to current output */
+void mxr_get_mbus_fmt(struct mxr_device *mdev,
+ struct v4l2_mbus_framefmt *mbus_fmt);
+
+/* Debug */
+
+#define mxr_err(mdev, fmt, ...) dev_err(mdev->dev, fmt, ##__VA_ARGS__)
+#define mxr_warn(mdev, fmt, ...) dev_warn(mdev->dev, fmt, ##__VA_ARGS__)
+#define mxr_info(mdev, fmt, ...) dev_info(mdev->dev, fmt, ##__VA_ARGS__)
+
+#ifdef CONFIG_VIDEO_EXYNOS_MIXER_DEBUG
+ #define mxr_dbg(mdev, fmt, ...) dev_dbg(mdev->dev, fmt, ##__VA_ARGS__)
+#else
+ #define mxr_dbg(mdev, fmt, ...) do { (void) mdev; } while (0)
+#endif
+
+/* accessing Mixer's and Video Processor's registers */
+
+void mxr_layer_sync(struct mxr_device *mdev, int en);
+void mxr_vsync_set_update(struct mxr_device *mdev, int en);
+void mxr_reg_reset(struct mxr_device *mdev);
+void mxr_reg_set_layer_prio(struct mxr_device *mdev);
+void mxr_reg_set_layer_blend(struct mxr_device *mdev, int sub_mxr, int num,
+ int en);
+void mxr_reg_layer_alpha(struct mxr_device *mdev, int sub_mxr, int num, u32 a);
+void mxr_reg_set_pixel_blend(struct mxr_device *mdev, int sub_mxr, int num,
+ int en);
+void mxr_reg_set_colorkey(struct mxr_device *mdev, int sub_mxr,
+ int num, int en);
+void mxr_reg_colorkey_val(struct mxr_device *mdev, int sub_mxr, int num, u32 v);
+irqreturn_t mxr_irq_handler(int irq, void *dev_data);
+void mxr_reg_s_output(struct mxr_device *mdev, int cookie);
+void mxr_reg_streamon(struct mxr_device *mdev);
+void mxr_reg_streamoff(struct mxr_device *mdev);
+int mxr_reg_wait4vsync(struct mxr_device *mdev);
+void mxr_reg_set_mbus_fmt(struct mxr_device *mdev,
+ struct v4l2_mbus_framefmt *fmt, u32 dvi_mode);
+void mxr_reg_local_path_clear(struct mxr_device *mdev);
+void mxr_reg_local_path_set(struct mxr_device *mdev, int mxr0_gsc, int mxr1_gsc,
+ u32 flags);
+void mxr_reg_graph_layer_stream(struct mxr_device *mdev, int idx, int en);
+void mxr_reg_graph_buffer(struct mxr_device *mdev, int idx, dma_addr_t addr);
+void mxr_reg_graph_format(struct mxr_device *mdev, int idx,
+ const struct mxr_format *fmt, const struct mxr_geometry *geo);
+
+void mxr_reg_video_layer_stream(struct mxr_device *mdev, int idx, int en);
+void mxr_reg_video_geo(struct mxr_device *mdev, int cur_mxr, int idx,
+ const struct mxr_geometry *geo);
+
+#if defined(CONFIG_ARCH_EXYNOS4)
+void mxr_reg_vp_layer_stream(struct mxr_device *mdev, int en);
+void mxr_reg_vp_buffer(struct mxr_device *mdev,
+ dma_addr_t luma_addr[2], dma_addr_t chroma_addr[2]);
+void mxr_reg_vp_format(struct mxr_device *mdev,
+ const struct mxr_format *fmt, const struct mxr_geometry *geo);
+#endif
+void mxr_reg_dump(struct mxr_device *mdev);
+void mxr_debugfs_init(struct mxr_device *mdev);
+
+#endif /* SAMSUNG_MIXER_H */
diff --git a/drivers/media/video/exynos/tv/mixer_drv.c b/drivers/media/video/exynos/tv/mixer_drv.c
new file mode 100644
index 0000000..9c9e46e
--- /dev/null
+++ b/drivers/media/video/exynos/tv/mixer_drv.c
@@ -0,0 +1,1521 @@
+/*
+ * Samsung TV Mixer driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * Tomasz Stanislawski, <t.stanislaws@samsung.com>
+ *
+ * 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 Foundiation. either version 2 of the License,
+ * or (at your option) any later version
+ */
+#include "mixer.h"
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/fb.h>
+#include <linux/delay.h>
+#include <linux/pm_runtime.h>
+#include <linux/clk.h>
+#include <linux/kernel.h>
+
+#include <mach/exynos5_bus.h>
+#include <mach/videonode-exynos5.h>
+#include <media/exynos_mc.h>
+
+#include <plat/bts.h>
+
+MODULE_AUTHOR("Tomasz Stanislawski, <t.stanislaws@samsung.com>");
+MODULE_DESCRIPTION("Samsung MIXER");
+MODULE_LICENSE("GPL");
+
+/* --------- DRIVER PARAMETERS ---------- */
+
+static struct mxr_output_conf mxr_output_conf[] = {
+ {
+ .output_name = "S5P HDMI connector",
+ .module_name = "s5p-hdmi",
+ .cookie = 1,
+ },
+ {
+ .output_name = "S5P SDO connector",
+ .module_name = "s5p-sdo",
+ .cookie = 0,
+ },
+};
+
+void mxr_get_mbus_fmt(struct mxr_device *mdev,
+ struct v4l2_mbus_framefmt *mbus_fmt)
+{
+ struct v4l2_subdev *sd;
+ int ret;
+
+ mutex_lock(&mdev->mutex);
+ sd = to_outsd(mdev);
+ ret = v4l2_subdev_call(sd, video, g_mbus_fmt, mbus_fmt);
+ WARN(ret, "failed to get mbus_fmt for output %s\n", sd->name);
+ mutex_unlock(&mdev->mutex);
+}
+
+static void mxr_set_alpha_blend(struct mxr_device *mdev)
+{
+ int i, j;
+ int layer_en, pixel_en, chroma_en;
+ u32 a, v;
+
+ for (i = 0; i < MXR_MAX_SUB_MIXERS; ++i) {
+ for (j = 0; j < MXR_MAX_LAYERS; ++j) {
+ layer_en = mdev->sub_mxr[i].layer[j]->layer_blend_en;
+ a = mdev->sub_mxr[i].layer[j]->layer_alpha;
+ pixel_en = mdev->sub_mxr[i].layer[j]->pixel_blend_en;
+ chroma_en = mdev->sub_mxr[i].layer[j]->chroma_en;
+ v = mdev->sub_mxr[i].layer[j]->chroma_val;
+
+ mxr_dbg(mdev, "mixer%d: layer%d\n", i, j);
+ mxr_dbg(mdev, "layer blend is %s, alpha = %d\n",
+ layer_en ? "enabled" : "disabled", a);
+ mxr_dbg(mdev, "pixel blend is %s\n",
+ pixel_en ? "enabled" : "disabled");
+ mxr_dbg(mdev, "chromakey is %s, value = %d\n",
+ chroma_en ? "enabled" : "disabled", v);
+
+ mxr_reg_set_layer_blend(mdev, i, j, layer_en);
+ mxr_reg_layer_alpha(mdev, i, j, a);
+ mxr_reg_set_pixel_blend(mdev, i, j, pixel_en);
+ mxr_reg_set_colorkey(mdev, i, j, chroma_en);
+ mxr_reg_colorkey_val(mdev, i, j, v);
+ }
+ }
+}
+
+static int mxr_streamer_get(struct mxr_device *mdev, struct v4l2_subdev *sd)
+{
+ int i;
+ int ret = 0;
+ int local = 1;
+ struct sub_mxr_device *sub_mxr;
+ struct mxr_layer *layer;
+ struct media_pad *pad;
+ struct v4l2_mbus_framefmt mbus_fmt;
+#if defined(CONFIG_CPU_EXYNOS4210)
+ struct mxr_resources *res = &mdev->res;
+#endif
+ struct v4l2_control ctrl;
+
+ mutex_lock(&mdev->s_mutex);
+ ++mdev->n_streamer;
+ mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_streamer);
+ /* If pipeline is started from Gscaler input video device,
+ * TV basic configuration must be set before running mixer */
+ if (mdev->mxr_data_from == FROM_GSC_SD) {
+ mxr_dbg(mdev, "%s: from gscaler\n", __func__);
+ local = 0;
+ /* enable mixer clock */
+ ret = mxr_power_get(mdev);
+ if (ret) {
+ mxr_err(mdev, "power on failed\n");
+ ret = -ENODEV;
+ goto out;
+ }
+ /* turn on connected output device through link
+ * with mixer */
+ mxr_output_get(mdev);
+
+ for (i = 0; i < MXR_MAX_SUB_MIXERS; ++i) {
+ sub_mxr = &mdev->sub_mxr[i];
+ if (sub_mxr->local) {
+ layer = sub_mxr->layer[MXR_LAYER_VIDEO];
+ layer->pipe.state = MXR_PIPELINE_STREAMING;
+ mxr_layer_geo_fix(layer);
+ layer->ops.format_set(layer);
+ layer->ops.stream_set(layer, 1);
+ local += sub_mxr->local;
+ }
+ }
+ if (local == 2)
+ mxr_layer_sync(mdev, MXR_ENABLE);
+
+ /* Set the TVOUT register about gsc-mixer local path */
+ mxr_reg_local_path_set(mdev, mdev->mxr0_gsc, mdev->mxr1_gsc,
+ mdev->flags);
+ }
+
+ /* Alpha blending configuration always can be changed
+ * whenever streaming */
+ mxr_set_alpha_blend(mdev);
+ mxr_reg_set_layer_prio(mdev);
+
+ if ((mdev->n_streamer == 1 && local == 1) ||
+ (mdev->n_streamer == 2 && local == 2)) {
+ for (i = MXR_PAD_SOURCE_GSCALER; i < MXR_PADS_NUM; ++i) {
+ pad = &sd->entity.pads[i];
+
+ /* find sink pad of output via enabled link*/
+ pad = media_entity_remote_source(pad);
+ if (pad)
+ if (media_entity_type(pad->entity)
+ == MEDIA_ENT_T_V4L2_SUBDEV)
+ break;
+
+ if (i == MXR_PAD_SOURCE_GRP1) {
+ ret = -ENODEV;
+ goto out;
+ }
+ }
+
+ sd = media_entity_to_v4l2_subdev(pad->entity);
+
+ mxr_dbg(mdev, "cookie of current output = (%d)\n",
+ to_output(mdev)->cookie);
+
+#if defined(CONFIG_CPU_EXYNOS4210)
+ if (to_output(mdev)->cookie == 0)
+ clk_set_parent(res->sclk_mixer, res->sclk_dac);
+ else
+ clk_set_parent(res->sclk_mixer, res->sclk_hdmi);
+#endif
+ mxr_reg_s_output(mdev, to_output(mdev)->cookie);
+
+ ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mbus_fmt);
+ if (ret) {
+ mxr_err(mdev, "failed to get mbus_fmt for output %s\n",
+ sd->name);
+ goto out;
+ }
+ ctrl.id = V4L2_CID_TV_GET_DVI_MODE;
+ ret = v4l2_subdev_call(sd, core, g_ctrl, &ctrl);
+ if (ret) {
+ mxr_err(mdev, "failed to get DVI or HDMI mode %s\n",
+ sd->name);
+ goto out;
+ }
+
+ mxr_reg_set_mbus_fmt(mdev, &mbus_fmt, ctrl.value);
+ ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mbus_fmt);
+ if (ret) {
+ mxr_err(mdev, "failed to set mbus_fmt for output %s\n",
+ sd->name);
+ goto out;
+ }
+ mxr_reg_streamon(mdev);
+
+ ret = v4l2_subdev_call(sd, video, s_stream, 1);
+ if (ret) {
+ mxr_err(mdev, "starting stream failed for output %s\n",
+ sd->name);
+ goto out;
+ }
+
+ ret = mxr_reg_wait4vsync(mdev);
+ if (ret) {
+ mxr_err(mdev, "failed to get vsync (%d) from output\n",
+ ret);
+ goto out;
+ }
+ }
+
+out:
+ mutex_unlock(&mdev->s_mutex);
+ mxr_reg_dump(mdev);
+
+ return ret;
+}
+
+static int mxr_streamer_put(struct mxr_device *mdev, struct v4l2_subdev *sd)
+{
+ int i;
+ int ret = 0;
+ int local = 1;
+ struct media_pad *pad;
+ struct sub_mxr_device *sub_mxr;
+ struct mxr_layer *layer;
+ struct v4l2_subdev *hdmi_sd;
+ struct v4l2_subdev *gsc_sd;
+ struct exynos_entity_data *md_data;
+
+ mutex_lock(&mdev->s_mutex);
+ --mdev->n_streamer;
+ mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_streamer);
+
+ /* distinction number of local path */
+ if (mdev->mxr_data_from == FROM_GSC_SD) {
+ local = 0;
+ for (i = 0; i < MXR_MAX_SUB_MIXERS; ++i) {
+ sub_mxr = &mdev->sub_mxr[i];
+ if (sub_mxr->local)
+ local += sub_mxr->local;
+ }
+ if (local == 2)
+ mxr_layer_sync(mdev, MXR_DISABLE);
+ }
+
+ if ((mdev->n_streamer == 0 && local == 1) ||
+ (mdev->n_streamer == 1 && local == 2)) {
+ for (i = MXR_PAD_SOURCE_GSCALER; i < MXR_PADS_NUM; ++i) {
+ pad = &sd->entity.pads[i];
+
+ /* find sink pad of output via enabled link*/
+ pad = media_entity_remote_source(pad);
+ if (pad)
+ if (media_entity_type(pad->entity)
+ == MEDIA_ENT_T_V4L2_SUBDEV)
+ break;
+
+ if (i == MXR_PAD_SOURCE_GRP1) {
+ ret = -ENODEV;
+ goto out;
+ }
+ }
+
+ hdmi_sd = media_entity_to_v4l2_subdev(pad->entity);
+
+ mxr_reg_streamoff(mdev);
+ /* vsync applies Mixer setup */
+ ret = mxr_reg_wait4vsync(mdev);
+ if (ret) {
+ mxr_err(mdev, "failed to get vsync (%d) from output\n",
+ ret);
+ goto out;
+ }
+ }
+ /* When using local path between gscaler and mixer, below stop sequence
+ * must be processed */
+ if (mdev->mxr_data_from == FROM_GSC_SD) {
+ pad = &sd->entity.pads[MXR_PAD_SINK_GSCALER];
+ pad = media_entity_remote_source(pad);
+ if (pad) {
+ gsc_sd = media_entity_to_v4l2_subdev(
+ pad->entity);
+ mxr_dbg(mdev, "stop from %s\n", gsc_sd->name);
+ md_data = (struct exynos_entity_data *)
+ gsc_sd->dev_priv;
+ md_data->media_ops->power_off(gsc_sd);
+ }
+ }
+
+ if ((mdev->n_streamer == 0 && local == 1) ||
+ (mdev->n_streamer == 1 && local == 2)) {
+ ret = v4l2_subdev_call(hdmi_sd, video, s_stream, 0);
+ if (ret) {
+ mxr_err(mdev, "stopping stream failed for output %s\n",
+ hdmi_sd->name);
+ goto out;
+ }
+ }
+ /* turn off connected output device through link
+ * with mixer */
+ if (mdev->mxr_data_from == FROM_GSC_SD) {
+ for (i = 0; i < MXR_MAX_SUB_MIXERS; ++i) {
+ sub_mxr = &mdev->sub_mxr[i];
+ if (sub_mxr->local) {
+ layer = sub_mxr->layer[MXR_LAYER_VIDEO];
+ layer->ops.stream_set(layer, 0);
+ layer->pipe.state = MXR_PIPELINE_IDLE;
+ }
+ }
+ mxr_reg_local_path_clear(mdev);
+ mxr_output_put(mdev);
+
+ /* disable mixer clock */
+ mxr_power_put(mdev);
+ }
+ WARN(mdev->n_streamer < 0, "negative number of streamers (%d)\n",
+ mdev->n_streamer);
+
+out:
+ mutex_unlock(&mdev->s_mutex);
+ mxr_reg_dump(mdev);
+
+ return ret;
+}
+
+void mxr_output_get(struct mxr_device *mdev)
+{
+ mutex_lock(&mdev->mutex);
+ ++mdev->n_output;
+ mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_output);
+ /* turn on auxiliary driver */
+ if (mdev->n_output == 1)
+ v4l2_subdev_call(to_outsd(mdev), core, s_power, 1);
+ mutex_unlock(&mdev->mutex);
+}
+
+void mxr_output_put(struct mxr_device *mdev)
+{
+ mutex_lock(&mdev->mutex);
+ --mdev->n_output;
+ mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_output);
+ /* turn on auxiliary driver */
+ if (mdev->n_output == 0)
+ v4l2_subdev_call(to_outsd(mdev), core, s_power, 0);
+ WARN(mdev->n_output < 0, "negative number of output users (%d)\n",
+ mdev->n_output);
+ mutex_unlock(&mdev->mutex);
+}
+
+static int mxr_runtime_resume(struct device *dev);
+static int mxr_runtime_suspend(struct device *dev);
+
+int mxr_power_get(struct mxr_device *mdev)
+{
+ /* If runtime PM is not implemented, mxr_runtime_resume
+ * function is directly called.
+ */
+#ifdef CONFIG_PM_RUNTIME
+ int ret = pm_runtime_get_sync(mdev->dev);
+ /* returning 1 means that power is already enabled,
+ * so zero success be returned */
+ if (IS_ERR_VALUE(ret))
+ return ret;
+ return 0;
+#else
+ mxr_runtime_resume(mdev->dev);
+ return 0;
+#endif
+}
+
+void mxr_power_put(struct mxr_device *mdev)
+{
+ /* If runtime PM is not implemented, mxr_runtime_suspend
+ * function is directly called.
+ */
+#ifdef CONFIG_PM_RUNTIME
+ pm_runtime_put_sync(mdev->dev);
+#else
+ mxr_runtime_suspend(mdev->dev);
+#endif
+}
+
+/* --------- RESOURCE MANAGEMENT -------------*/
+
+static int __devinit mxr_acquire_plat_resources(struct mxr_device *mdev,
+ struct platform_device *pdev)
+{
+ struct resource *res;
+ int ret;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mxr");
+ if (res == NULL) {
+ mxr_err(mdev, "get memory resource failed.\n");
+ ret = -ENXIO;
+ goto fail;
+ }
+
+ mdev->res.mxr_regs = ioremap(res->start, resource_size(res));
+ if (mdev->res.mxr_regs == NULL) {
+ mxr_err(mdev, "register mapping failed.\n");
+ ret = -ENXIO;
+ goto fail;
+ }
+
+#if defined(CONFIG_ARCH_EXYNOS4)
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vp");
+ if (res == NULL) {
+ mxr_err(mdev, "get memory resource failed.\n");
+ ret = -ENXIO;
+ goto fail_mxr_regs;
+ }
+
+ mdev->res.vp_regs = ioremap(res->start, resource_size(res));
+ if (mdev->res.vp_regs == NULL) {
+ mxr_err(mdev, "register mapping failed.\n");
+ ret = -ENXIO;
+ goto fail_mxr_regs;
+ }
+#endif
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq");
+ if (res == NULL) {
+ mxr_err(mdev, "get interrupt resource failed.\n");
+ ret = -ENXIO;
+ goto fail_vp_regs;
+ }
+
+ ret = request_irq(res->start, mxr_irq_handler, 0, "s5p-mixer", mdev);
+ if (ret) {
+ mxr_err(mdev, "request interrupt failed.\n");
+ goto fail_vp_regs;
+ }
+ mdev->res.irq = res->start;
+
+ return 0;
+
+fail_vp_regs:
+#if defined(CONFIG_ARCH_EXYNOS4)
+ iounmap(mdev->res.vp_regs);
+
+fail_mxr_regs:
+#endif
+ iounmap(mdev->res.mxr_regs);
+
+fail:
+ return ret;
+}
+
+static void mxr_release_plat_resources(struct mxr_device *mdev)
+{
+ free_irq(mdev->res.irq, mdev);
+#if defined(CONFIG_ARCH_EXYNOS4)
+ iounmap(mdev->res.vp_regs);
+#endif
+ iounmap(mdev->res.mxr_regs);
+}
+
+static void mxr_release_clocks(struct mxr_device *mdev)
+{
+ struct mxr_resources *res = &mdev->res;
+
+#if defined(CONFIG_ARCH_EXYNOS4)
+ if (!IS_ERR_OR_NULL(res->vp))
+ clk_put(res->vp);
+#endif
+#if defined(CONFIG_CPU_EXYNOS4210)
+ if (!IS_ERR_OR_NULL(res->sclk_mixer))
+ clk_put(res->sclk_mixer);
+ if (!IS_ERR_OR_NULL(res->sclk_dac))
+ clk_put(res->sclk_dac);
+#endif
+ if (!IS_ERR_OR_NULL(res->mixer))
+ clk_put(res->mixer);
+ if (!IS_ERR_OR_NULL(res->sclk_hdmi))
+ clk_put(res->sclk_hdmi);
+}
+
+static int mxr_acquire_clocks(struct mxr_device *mdev)
+{
+ struct mxr_resources *res = &mdev->res;
+ struct device *dev = mdev->dev;
+
+#if defined(CONFIG_ARCH_EXYNOS4)
+ res->vp = clk_get(dev, "vp");
+ if (IS_ERR_OR_NULL(res->vp)) {
+ mxr_err(mdev, "failed to get clock 'vp'\n");
+ goto fail;
+ }
+ res->sclk_mixer = clk_get(dev, "sclk_mixer");
+ if (IS_ERR_OR_NULL(res->sclk_mixer)) {
+ mxr_err(mdev, "failed to get clock 'sclk_mixer'\n");
+ goto fail;
+ }
+#endif
+#if defined(CONFIG_CPU_EXYNOS4210)
+
+ res->sclk_dac = clk_get(dev, "sclk_dac");
+ if (IS_ERR_OR_NULL(res->sclk_dac)) {
+ mxr_err(mdev, "failed to get clock 'sclk_dac'\n");
+ goto fail;
+ }
+#endif
+ res->mixer = clk_get(dev, "mixer");
+ if (IS_ERR_OR_NULL(res->mixer)) {
+ mxr_err(mdev, "failed to get clock 'mixer'\n");
+ goto fail;
+ }
+ res->sclk_hdmi = clk_get(dev, "sclk_hdmi");
+ if (IS_ERR_OR_NULL(res->sclk_hdmi)) {
+ mxr_err(mdev, "failed to get clock 'sclk_hdmi'\n");
+ goto fail;
+ }
+
+ return 0;
+fail:
+ mxr_release_clocks(mdev);
+ return -ENODEV;
+}
+
+static int __devinit mxr_acquire_resources(struct mxr_device *mdev,
+ struct platform_device *pdev)
+{
+ int ret;
+ ret = mxr_acquire_plat_resources(mdev, pdev);
+
+ if (ret)
+ goto fail;
+
+ ret = mxr_acquire_clocks(mdev);
+ if (ret)
+ goto fail_plat;
+
+ mxr_info(mdev, "resources acquired\n");
+ return 0;
+
+fail_plat:
+ mxr_release_plat_resources(mdev);
+fail:
+ mxr_err(mdev, "resources acquire failed\n");
+ return ret;
+}
+
+static void mxr_release_resources(struct mxr_device *mdev)
+{
+ mxr_release_clocks(mdev);
+ mxr_release_plat_resources(mdev);
+ memset(&mdev->res, 0, sizeof mdev->res);
+}
+
+static void mxr_release_layers(struct mxr_device *mdev)
+{
+ int i, j;
+
+ for (i = 0; i < MXR_MAX_SUB_MIXERS; ++i) {
+ for (j = 0; j < MXR_MAX_LAYERS; ++j)
+ if (mdev->sub_mxr[i].layer[j])
+ mxr_layer_release(mdev->sub_mxr[i].layer[j]);
+ }
+}
+
+static int __devinit mxr_acquire_layers(struct mxr_device *mdev,
+ struct mxr_platform_data *pdata)
+{
+ struct sub_mxr_device *sub_mxr;
+
+ sub_mxr = &mdev->sub_mxr[MXR_SUB_MIXER0];
+#if defined(CONFIG_ARCH_EXYNOS4)
+ sub_mxr->layer[MXR_LAYER_VIDEO] = mxr_vp_layer_create(mdev,
+ MXR_SUB_MIXER0, 0, EXYNOS_VIDEONODE_MXR_VIDEO);
+#else
+ sub_mxr->layer[MXR_LAYER_VIDEO] =
+ mxr_video_layer_create(mdev, MXR_SUB_MIXER0, 0);
+#endif
+ sub_mxr->layer[MXR_LAYER_GRP0] = mxr_graph_layer_create(mdev,
+ MXR_SUB_MIXER0, 0, EXYNOS_VIDEONODE_MXR_GRP(0));
+ sub_mxr->layer[MXR_LAYER_GRP1] = mxr_graph_layer_create(mdev,
+ MXR_SUB_MIXER0, 1, EXYNOS_VIDEONODE_MXR_GRP(1));
+ if (!sub_mxr->layer[MXR_LAYER_VIDEO] || !sub_mxr->layer[MXR_LAYER_GRP0]
+ || !sub_mxr->layer[MXR_LAYER_GRP1]) {
+ mxr_err(mdev, "failed to acquire layers\n");
+ goto fail;
+ }
+
+ /* Exynos5250 supports 2 sub-mixers */
+ if (MXR_MAX_SUB_MIXERS == 2) {
+ sub_mxr = &mdev->sub_mxr[MXR_SUB_MIXER1];
+ sub_mxr->layer[MXR_LAYER_VIDEO] =
+ mxr_video_layer_create(mdev, MXR_SUB_MIXER1, 1);
+ sub_mxr->layer[MXR_LAYER_GRP0] = mxr_graph_layer_create(mdev,
+ MXR_SUB_MIXER1, 2, EXYNOS_VIDEONODE_MXR_GRP(2));
+ sub_mxr->layer[MXR_LAYER_GRP1] = mxr_graph_layer_create(mdev,
+ MXR_SUB_MIXER1, 3, EXYNOS_VIDEONODE_MXR_GRP(3));
+ if (!sub_mxr->layer[MXR_LAYER_VIDEO] ||
+ !sub_mxr->layer[MXR_LAYER_GRP0] ||
+ !sub_mxr->layer[MXR_LAYER_GRP1]) {
+ mxr_err(mdev, "failed to acquire layers\n");
+ goto fail;
+ }
+ }
+
+ return 0;
+
+fail:
+ mxr_release_layers(mdev);
+ return -ENODEV;
+}
+
+/* ---------- POWER MANAGEMENT ----------- */
+
+static int mxr_runtime_resume(struct device *dev)
+{
+ struct mxr_device *mdev = to_mdev(dev);
+ struct mxr_resources *res = &mdev->res;
+
+ mxr_dbg(mdev, "resume - start\n");
+ mutex_lock(&mdev->mutex);
+ /* turn clocks on */
+ clk_enable(res->mixer);
+#if defined(CONFIG_ARCH_EXYNOS4)
+ clk_enable(res->vp);
+#endif
+#if defined(CONFIG_CPU_EXYNOS4210)
+ clk_enable(res->sclk_mixer);
+#endif
+
+ mdev->mif_handle = exynos5_bus_mif_min(800000);
+ if (!mdev->mif_handle)
+ dev_err(dev, "failed to request min_freq for mif\n");
+
+ mdev->int_handle = exynos5_bus_int_min(266000);
+ if (!mdev->int_handle)
+ dev_err(dev, "failed to request min_freq for int\n");
+
+ bts_change_threshold(BTS_MIXER_BW);
+
+ /* enable system mmu for tv. It must be enabled after enabling
+ * mixer's clock. Because of system mmu limitation. */
+ mdev->vb2->resume(mdev->alloc_ctx);
+ /* apply default configuration */
+ mxr_reg_reset(mdev);
+ mxr_dbg(mdev, "resume - finished\n");
+
+ mutex_unlock(&mdev->mutex);
+ return 0;
+}
+
+static int mxr_runtime_suspend(struct device *dev)
+{
+ struct mxr_device *mdev = to_mdev(dev);
+ struct mxr_resources *res = &mdev->res;
+ mxr_dbg(mdev, "suspend - start\n");
+ mutex_lock(&mdev->mutex);
+ /* disable system mmu for tv. It must be disabled before disabling
+ * mixer's clock. Because of system mmu limitation. */
+ mdev->vb2->suspend(mdev->alloc_ctx);
+
+ bts_change_threshold(BTS_INCREASE_BW);
+
+ if (mdev->int_handle) {
+ exynos5_bus_int_put(mdev->int_handle);
+ mdev->int_handle = NULL;
+ }
+
+ if (mdev->mif_handle) {
+ exynos5_bus_mif_put(mdev->mif_handle);
+ mdev->mif_handle = NULL;
+ }
+
+ /* turn clocks off */
+#if defined(CONFIG_CPU_EXYNOS4210)
+ clk_disable(res->sclk_mixer);
+#endif
+#if defined(CONFIG_ARCH_EXYNOS4)
+ clk_disable(res->vp);
+#endif
+ clk_disable(res->mixer);
+ mutex_unlock(&mdev->mutex);
+ mxr_dbg(mdev, "suspend - finished\n");
+ return 0;
+}
+
+/* ---------- SUB-DEVICE CALLBACKS ----------- */
+
+static const struct dev_pm_ops mxr_pm_ops = {
+ .runtime_suspend = mxr_runtime_suspend,
+ .runtime_resume = mxr_runtime_resume,
+};
+
+static int mxr_s_power(struct v4l2_subdev *sd, int on)
+{
+ return 0;
+}
+
+/* When mixer is connected to gscaler through local path, only gscaler's
+ * video device can command alpha blending functionality for mixer */
+static int mxr_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+ struct mxr_device *mdev = sd_to_mdev(sd);
+ struct mxr_layer *layer;
+ int v = ctrl->value;
+ int num = 0;
+
+ mxr_dbg(mdev, "%s start\n", __func__);
+ mxr_dbg(mdev, "id = %d, value = %d\n", ctrl->id, ctrl->value);
+
+ if (!strcmp(sd->name, "s5p-mixer0"))
+ num = MXR_SUB_MIXER0;
+ else if (!strcmp(sd->name, "s5p-mixer1"))
+ num = MXR_SUB_MIXER1;
+
+ layer = mdev->sub_mxr[num].layer[MXR_LAYER_VIDEO];
+ switch (ctrl->id) {
+ case V4L2_CID_TV_LAYER_BLEND_ENABLE:
+ layer->layer_blend_en = v;
+ break;
+ case V4L2_CID_TV_LAYER_BLEND_ALPHA:
+ layer->layer_alpha = (u32)v;
+ break;
+ case V4L2_CID_TV_PIXEL_BLEND_ENABLE:
+ layer->pixel_blend_en = v;
+ break;
+ case V4L2_CID_TV_CHROMA_ENABLE:
+ layer->chroma_en = v;
+ break;
+ case V4L2_CID_TV_CHROMA_VALUE:
+ layer->chroma_val = (u32)v;
+ break;
+ case V4L2_CID_TV_LAYER_PRIO:
+ layer->prio = (u8)v;
+ if (layer->pipe.state == MXR_PIPELINE_STREAMING)
+ mxr_reg_set_layer_prio(mdev);
+ break;
+ default:
+ mxr_err(mdev, "invalid control id\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int mxr_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct mxr_device *mdev = sd_to_mdev(sd);
+ struct exynos_entity_data *md_data;
+ int ret;
+
+ /* It can be known which entity calls this function */
+ md_data = v4l2_get_subdevdata(sd);
+ mdev->mxr_data_from = md_data->mxr_data_from;
+
+ if (enable)
+ ret = mxr_streamer_get(mdev, sd);
+ else
+ ret = mxr_streamer_put(mdev, sd);
+
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static struct v4l2_mbus_framefmt *
+__mxr_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+ struct sub_mxr_device *sub_mxr = sd_to_sub_mxr(sd);
+
+ if (which == V4L2_SUBDEV_FORMAT_TRY)
+ return v4l2_subdev_get_try_format(fh, pad);
+ else
+ return &sub_mxr->mbus_fmt[pad];
+}
+
+static struct v4l2_rect *
+__mxr_get_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+ struct sub_mxr_device *sub_mxr = sd_to_sub_mxr(sd);
+
+ if (which == V4L2_SUBDEV_FORMAT_TRY)
+ return v4l2_subdev_get_try_crop(fh, pad);
+ else
+ return &sub_mxr->crop[pad];
+}
+
+static unsigned int mxr_adjust_graph_format(unsigned int code)
+{
+ switch (code) {
+ case V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE:
+ case V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE:
+ case V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE:
+ case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE:
+ case V4L2_MBUS_FMT_RGB565_2X8_BE:
+ case V4L2_MBUS_FMT_RGB565_2X8_LE:
+ case V4L2_MBUS_FMT_XRGB8888_4X8_LE:
+ return code;
+ default:
+ return V4L2_MBUS_FMT_XRGB8888_4X8_LE; /* default format */
+ }
+}
+
+/* This can be moved to graphic layer's callback function */
+static void mxr_set_layer_src_fmt(struct sub_mxr_device *sub_mxr, u32 pad)
+{
+ /* sink pad number and array index of layer are same */
+ struct mxr_layer *layer = sub_mxr->layer[pad];
+ struct v4l2_mbus_framefmt *fmt = &sub_mxr->mbus_fmt[pad];
+ u32 fourcc;
+
+ switch (fmt->code) {
+ case V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE:
+ case V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE:
+ fourcc = V4L2_PIX_FMT_RGB444;
+ break;
+ case V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE:
+ case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE:
+ fourcc = V4L2_PIX_FMT_RGB555;
+ break;
+ case V4L2_MBUS_FMT_RGB565_2X8_BE:
+ case V4L2_MBUS_FMT_RGB565_2X8_LE:
+ fourcc = V4L2_PIX_FMT_RGB565;
+ break;
+ case V4L2_MBUS_FMT_XRGB8888_4X8_LE:
+ fourcc = V4L2_PIX_FMT_BGR32;
+ break;
+ }
+ /* This will be applied to hardware right after streamon */
+ layer->fmt = find_format_by_fourcc(layer, fourcc);
+}
+
+static int mxr_try_format(struct mxr_device *mdev,
+ struct v4l2_subdev_fh *fh, u32 pad,
+ struct v4l2_mbus_framefmt *fmt,
+ enum v4l2_subdev_format_whence which)
+{
+ struct v4l2_mbus_framefmt mbus_fmt;
+
+ fmt->width = clamp_val(fmt->width, 1, 32767);
+ fmt->height = clamp_val(fmt->height, 1, 2047);
+
+ switch (pad) {
+ case MXR_PAD_SINK_GSCALER:
+ fmt->code = V4L2_MBUS_FMT_YUV8_1X24;
+ break;
+ case MXR_PAD_SINK_GRP0:
+ case MXR_PAD_SINK_GRP1:
+ fmt->code = mxr_adjust_graph_format(fmt->code);
+ break;
+ case MXR_PAD_SOURCE_GSCALER:
+ case MXR_PAD_SOURCE_GRP0:
+ case MXR_PAD_SOURCE_GRP1:
+ mxr_get_mbus_fmt(mdev, &mbus_fmt);
+ fmt->code = (fmt->code == V4L2_MBUS_FMT_YUV8_1X24) ?
+ V4L2_MBUS_FMT_YUV8_1X24 : V4L2_MBUS_FMT_XRGB8888_4X8_LE;
+ fmt->width = mbus_fmt.width;
+ fmt->height = mbus_fmt.height;
+ break;
+ }
+
+ return 0;
+}
+
+static void mxr_apply_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh, u32 pad,
+ struct v4l2_mbus_framefmt *fmt,
+ enum v4l2_subdev_format_whence which)
+{
+ struct sub_mxr_device *sub_mxr;
+ struct mxr_device *mdev;
+ int i, j;
+ sub_mxr = sd_to_sub_mxr(sd);
+ mdev = sd_to_mdev(sd);
+
+ if (which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+ if (pad == MXR_PAD_SINK_GRP0 || pad == MXR_PAD_SINK_GRP1) {
+ struct mxr_layer *layer = sub_mxr->layer[pad];
+
+ mxr_set_layer_src_fmt(sub_mxr, pad);
+ layer->geo.src.full_width = fmt->width;
+ layer->geo.src.full_height = fmt->height;
+ layer->ops.fix_geometry(layer);
+ } else if (pad == MXR_PAD_SOURCE_GSCALER
+ || pad == MXR_PAD_SOURCE_GRP0
+ || pad == MXR_PAD_SOURCE_GRP1) {
+ for (i = 0; i < MXR_MAX_LAYERS; ++i) {
+ struct mxr_layer *layer = sub_mxr->layer[i];
+ layer->geo.dst.full_width = fmt->width;
+ layer->geo.dst.full_height = fmt->height;
+ layer->ops.fix_geometry(layer);
+ }
+ for (i = 0; i < MXR_MAX_SUB_MIXERS; ++i) {
+ sub_mxr = &mdev->sub_mxr[i];
+ for (j = MXR_PAD_SOURCE_GSCALER;
+ j < MXR_PADS_NUM; ++j)
+ sub_mxr->mbus_fmt[j].code = fmt->code;
+ }
+ }
+ }
+}
+
+static int mxr_try_crop(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh, unsigned int pad,
+ struct v4l2_rect *r, enum v4l2_subdev_format_whence which)
+{
+ struct v4l2_mbus_framefmt *fmt;
+
+ fmt = __mxr_get_fmt(sd, fh, pad, which);
+ if (fmt == NULL)
+ return -EINVAL;
+
+ r->left = clamp_val(r->left, 0, fmt->width);
+ r->top = clamp_val(r->top, 0, fmt->height);
+ r->width = clamp_val(r->width, 1, fmt->width - r->left);
+ r->height = clamp_val(r->height, 1, fmt->height - r->top);
+
+ /* need to align size with G-Scaler */
+ if (pad == MXR_PAD_SINK_GSCALER || pad == MXR_PAD_SOURCE_GSCALER)
+ if (r->width % 2)
+ r->width -= 1;
+
+ return 0;
+}
+
+static void mxr_apply_crop(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh, unsigned int pad,
+ struct v4l2_rect *r, enum v4l2_subdev_format_whence which)
+{
+ struct sub_mxr_device *sub_mxr = sd_to_sub_mxr(sd);
+ struct mxr_layer *layer;
+
+ if (which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+ if (pad == MXR_PAD_SINK_GRP0 || pad == MXR_PAD_SINK_GRP1) {
+ layer = sub_mxr->layer[pad];
+
+ layer->geo.src.width = r->width;
+ layer->geo.src.height = r->height;
+ layer->geo.src.x_offset = r->left;
+ layer->geo.src.y_offset = r->top;
+ layer->ops.fix_geometry(layer);
+ } else if (pad == MXR_PAD_SOURCE_GSCALER
+ || pad == MXR_PAD_SOURCE_GRP0
+ || pad == MXR_PAD_SOURCE_GRP1) {
+ layer = sub_mxr->layer[pad - (MXR_PADS_NUM >> 1)];
+
+ layer->geo.dst.width = r->width;
+ layer->geo.dst.height = r->height;
+ layer->geo.dst.x_offset = r->left;
+ layer->geo.dst.y_offset = r->top;
+ layer->ops.fix_geometry(layer);
+ }
+ }
+}
+
+static int mxr_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *format)
+{
+ struct v4l2_mbus_framefmt *fmt;
+
+ fmt = __mxr_get_fmt(sd, fh, format->pad, format->which);
+ if (fmt == NULL)
+ return -EINVAL;
+
+ format->format = *fmt;
+
+ return 0;
+}
+
+static int mxr_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *format)
+{
+ struct mxr_device *mdev = sd_to_mdev(sd);
+ struct v4l2_mbus_framefmt *fmt;
+ int ret;
+ u32 pad;
+
+ fmt = __mxr_get_fmt(sd, fh, format->pad, format->which);
+ if (fmt == NULL)
+ return -EINVAL;
+
+ ret = mxr_try_format(mdev, fh, format->pad, &format->format,
+ format->which);
+ if (ret)
+ return ret;
+
+ *fmt = format->format;
+
+ mxr_apply_format(sd, fh, format->pad, &format->format, format->which);
+
+ if (format->pad == MXR_PAD_SINK_GSCALER ||
+ format->pad == MXR_PAD_SINK_GRP0 ||
+ format->pad == MXR_PAD_SINK_GRP1) {
+ pad = format->pad + (MXR_PADS_NUM >> 1);
+ fmt = __mxr_get_fmt(sd, fh, pad, format->which);
+ if (fmt == NULL)
+ return -EINVAL;
+
+ *fmt = format->format;
+
+ ret = mxr_try_format(mdev, fh, pad, fmt, format->which);
+ if (ret)
+ return ret;
+
+ mxr_apply_format(sd, fh, pad, fmt, format->which);
+ }
+
+ return 0;
+}
+
+static int mxr_set_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_crop *crop)
+{
+ struct v4l2_rect *r;
+ int ret;
+ u32 pad;
+
+ r = __mxr_get_crop(sd, fh, crop->pad, crop->which);
+ if (r == NULL)
+ return -EINVAL;
+
+ ret = mxr_try_crop(sd, fh, crop->pad, &crop->rect, crop->which);
+ if (ret)
+ return ret;
+
+ /* transfer adjusted crop information to user space */
+ *r = crop->rect;
+
+ /* reserved[0] is used for sink pad number temporally */
+ mxr_apply_crop(sd, fh, crop->pad, r, crop->which);
+
+ /* In case of sink pad, crop info will be propagated to source pad */
+ if (crop->pad == MXR_PAD_SINK_GSCALER ||
+ crop->pad == MXR_PAD_SINK_GRP0 ||
+ crop->pad == MXR_PAD_SINK_GRP1) {
+ pad = crop->pad + (MXR_PADS_NUM >> 1);
+ r = __mxr_get_crop(sd, fh, pad, crop->which);
+ if (r == NULL)
+ return -EINVAL;
+ /* store propagated crop info to source pad */
+ *r = crop->rect;
+
+ ret = mxr_try_crop(sd, fh, pad, r, crop->which);
+ if (ret)
+ return ret;
+
+ mxr_apply_crop(sd, fh, pad, r, crop->which);
+ }
+
+ return 0;
+}
+
+static int mxr_get_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_crop *crop)
+{
+ struct v4l2_rect *r;
+
+ r = __mxr_get_crop(sd, fh, crop->pad, crop->which);
+ if (r == NULL)
+ return -EINVAL;
+
+ crop->rect = *r;
+
+ return 0;
+}
+
+static const struct v4l2_subdev_core_ops mxr_sd_core_ops = {
+ .s_power = mxr_s_power,
+ .s_ctrl = mxr_s_ctrl,
+};
+
+static const struct v4l2_subdev_video_ops mxr_sd_video_ops = {
+ .s_stream = mxr_s_stream,
+};
+
+static const struct v4l2_subdev_pad_ops mxr_sd_pad_ops = {
+ .get_fmt = mxr_get_fmt,
+ .set_fmt = mxr_set_fmt,
+ .get_crop = mxr_get_crop,
+ .set_crop = mxr_set_crop
+};
+
+static const struct v4l2_subdev_ops mxr_sd_ops = {
+ .core = &mxr_sd_core_ops,
+ .video = &mxr_sd_video_ops,
+ .pad = &mxr_sd_pad_ops,
+};
+
+static int mxr_link_setup(struct media_entity *entity,
+ const struct media_pad *local,
+ const struct media_pad *remote, u32 flags)
+{
+ struct media_pad *pad;
+ struct sub_mxr_device *sub_mxr = entity_to_sub_mxr(entity);
+ struct mxr_device *mdev = sub_mxr_to_mdev(sub_mxr);
+ int i;
+ int gsc_num = 0;
+
+ /* difficult to get dev ptr */
+ printk(KERN_DEBUG "%s start\n", __func__);
+
+ if (flags & MEDIA_LNK_FL_ENABLED) {
+ sub_mxr->use = 1;
+ if (local->index == MXR_PAD_SINK_GSCALER)
+ sub_mxr->local = 1;
+ /* find a remote pad by interating over all links
+ * until enabled link is found.
+ * This will be remove. because Exynos5250 only supports
+ * HDMI output */
+ pad = media_entity_remote_source((struct media_pad *)local);
+ if (pad) {
+ printk(KERN_ERR "%s is already connected to %s\n",
+ entity->name, pad->entity->name);
+ return -EBUSY;
+ }
+ } else {
+ if (local->index == MXR_PAD_SINK_GSCALER)
+ sub_mxr->local = 0;
+ sub_mxr->use = 0;
+ for (i = 0; i < entity->num_links; ++i)
+ if (entity->links[i].flags & MEDIA_LNK_FL_ENABLED)
+ sub_mxr->use = 1;
+ }
+
+ if (!strcmp(remote->entity->name, "exynos-gsc-sd.0"))
+ gsc_num = 0;
+ else if (!strcmp(remote->entity->name, "exynos-gsc-sd.1"))
+ gsc_num = 1;
+ else if (!strcmp(remote->entity->name, "exynos-gsc-sd.2"))
+ gsc_num = 2;
+ else if (!strcmp(remote->entity->name, "exynos-gsc-sd.3"))
+ gsc_num = 3;
+
+ if (!strcmp(local->entity->name, "s5p-mixer0"))
+ mdev->mxr0_gsc = gsc_num;
+ else if (!strcmp(local->entity->name, "s5p-mixer1"))
+ mdev->mxr1_gsc = gsc_num;
+
+ /* deliver those variables to mxr_streamer_get() */
+ mdev->flags = flags;
+ return 0;
+}
+
+/* mixer entity operations */
+static const struct media_entity_operations mxr_entity_ops = {
+ .link_setup = mxr_link_setup,
+};
+
+/* ---------- MEDIA CONTROLLER MANAGEMENT ----------- */
+
+static int mxr_register_entity(struct mxr_device *mdev, int mxr_num)
+{
+ struct v4l2_subdev *sd = &mdev->sub_mxr[mxr_num].sd;
+ struct media_pad *pads = mdev->sub_mxr[mxr_num].pads;
+ struct media_entity *me = &sd->entity;
+ struct exynos_md *md;
+ int ret;
+
+ mxr_dbg(mdev, "mixer%d entity init\n", mxr_num);
+
+ /* init mixer sub-device */
+ v4l2_subdev_init(sd, &mxr_sd_ops);
+ sd->owner = THIS_MODULE;
+ sprintf(sd->name, "s5p-mixer%d", mxr_num);
+
+ /* mixer sub-device can be opened in user space */
+ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+ /* init mixer sub-device as entity */
+ pads[MXR_PAD_SINK_GSCALER].flags = MEDIA_PAD_FL_SINK;
+ pads[MXR_PAD_SINK_GRP0].flags = MEDIA_PAD_FL_SINK;
+ pads[MXR_PAD_SINK_GRP1].flags = MEDIA_PAD_FL_SINK;
+ pads[MXR_PAD_SOURCE_GSCALER].flags = MEDIA_PAD_FL_SOURCE;
+ pads[MXR_PAD_SOURCE_GRP0].flags = MEDIA_PAD_FL_SOURCE;
+ pads[MXR_PAD_SOURCE_GRP1].flags = MEDIA_PAD_FL_SOURCE;
+ me->ops = &mxr_entity_ops;
+ ret = media_entity_init(me, MXR_PADS_NUM, pads, 0);
+ if (ret) {
+ mxr_err(mdev, "failed to initialize media entity\n");
+ return ret;
+ }
+
+ md = (struct exynos_md *)module_name_to_driver_data(MDEV_MODULE_NAME);
+ if (!md) {
+ mxr_err(mdev, "failed to get output media device\n");
+ return -ENODEV;
+ }
+
+ ret = v4l2_device_register_subdev(&md->v4l2_dev, sd);
+ if (ret) {
+ mxr_err(mdev, "failed to register mixer subdev\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int mxr_register_entities(struct mxr_device *mdev)
+{
+ int ret, i;
+
+ for (i = 0; i < MXR_MAX_SUB_MIXERS; ++i) {
+ ret = mxr_register_entity(mdev, i);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static void mxr_unregister_entity(struct mxr_device *mdev, int mxr_num)
+{
+ v4l2_device_unregister_subdev(&mdev->sub_mxr[mxr_num].sd);
+}
+
+static void mxr_unregister_entities(struct mxr_device *mdev)
+{
+ int i;
+
+ for (i = 0; i < MXR_MAX_SUB_MIXERS; ++i)
+ mxr_unregister_entity(mdev, i);
+}
+
+static void mxr_entities_info_print(struct mxr_device *mdev)
+{
+ struct v4l2_subdev *sd;
+ struct media_entity *sd_me;
+ struct media_entity *vd_me;
+ int num_layers;
+ int i, j;
+
+#if defined(CONFIG_ARCH_EXYNOS4)
+ num_layers = 3;
+#else
+ num_layers = 2;
+#endif
+ mxr_dbg(mdev, "\n************ MIXER entities info ***********\n");
+
+ for (i = 0; i < MXR_MAX_SUB_MIXERS; ++i) {
+ mxr_dbg(mdev, "[SUB DEVICE INFO]\n");
+ sd = &mdev->sub_mxr[i].sd;
+ sd_me = &sd->entity;
+ entity_info_print(sd_me, mdev->dev);
+
+ for (j = 0; j < num_layers; ++j) {
+ vd_me = &mdev->sub_mxr[i].layer[j]->vfd.entity;
+
+ mxr_dbg(mdev, "\n[VIDEO DEVICE %d INFO]\n", j);
+ entity_info_print(vd_me, mdev->dev);
+ }
+ }
+
+ mxr_dbg(mdev, "**************************************************\n\n");
+}
+
+static int mxr_create_links_sub_mxr(struct mxr_device *mdev, int mxr_num,
+ int flags)
+{
+ struct exynos_md *md;
+ struct mxr_layer *layer;
+ int ret;
+ int i, j;
+ char err[80];
+
+ mxr_info(mdev, "mixer%d create links\n", mxr_num);
+
+ memset(err, 0, sizeof(err));
+
+ /* link creation : gscaler0~3[1] -> mixer[0] */
+ md = (struct exynos_md *)module_name_to_driver_data(MDEV_MODULE_NAME);
+ for (i = 0; i < MAX_GSC_SUBDEV; ++i) {
+ if (md->gsc_sd[i] != NULL) {
+ ret = media_entity_create_link(&md->gsc_sd[i]->entity,
+ GSC_OUT_PAD_SOURCE,
+ &mdev->sub_mxr[mxr_num].sd.entity,
+ MXR_PAD_SINK_GSCALER, 0);
+ if (ret) {
+ sprintf(err, "%s --> %s",
+ md->gsc_sd[i]->entity.name,
+ mdev->sub_mxr[mxr_num].sd.entity.name);
+ goto fail;
+ }
+ }
+ }
+
+ /* link creation : mixer input0[0] -> mixer[1] */
+ layer = mdev->sub_mxr[mxr_num].layer[MXR_LAYER_GRP0];
+ ret = media_entity_create_link(&layer->vfd.entity, 0,
+ &mdev->sub_mxr[mxr_num].sd.entity, MXR_PAD_SINK_GRP0, flags);
+ if (ret) {
+ sprintf(err, "%s --> %s", layer->vfd.entity.name,
+ mdev->sub_mxr[mxr_num].sd.entity.name);
+ goto fail;
+ }
+
+ /* link creation : mixer input1[0] -> mixer[2] */
+ layer = mdev->sub_mxr[mxr_num].layer[MXR_LAYER_GRP1];
+ ret = media_entity_create_link(&layer->vfd.entity, 0,
+ &mdev->sub_mxr[mxr_num].sd.entity, MXR_PAD_SINK_GRP1, flags);
+ if (ret) {
+ sprintf(err, "%s --> %s", layer->vfd.entity.name,
+ mdev->sub_mxr[mxr_num].sd.entity.name);
+ goto fail;
+ }
+
+ /* link creation : mixer[3,4,5] -> output device(hdmi or sdo)[0] */
+ mxr_dbg(mdev, "output device count = %d\n", mdev->output_cnt);
+ for (i = 0; i < mdev->output_cnt; ++i) { /* sink pad of hdmi/sdo is 0 */
+ flags = 0;
+ /* default output device link is HDMI */
+ if (!strcmp(mdev->output[i]->sd->name, "s5p-hdmi"))
+ flags = MEDIA_LNK_FL_ENABLED;
+
+ for (j = MXR_PAD_SOURCE_GSCALER; j < MXR_PADS_NUM; ++j) {
+ ret = media_entity_create_link(
+ &mdev->sub_mxr[mxr_num].sd.entity,
+ j, &mdev->output[i]->sd->entity,
+ 0, flags);
+ if (ret) {
+ sprintf(err, "%s --> %s",
+ mdev->sub_mxr[mxr_num].sd.entity.name,
+ mdev->output[i]->sd->entity.name);
+ goto fail;
+ }
+ }
+ }
+
+ return 0;
+
+fail:
+ mxr_err(mdev, "failed to create link : %s\n", err);
+ return ret;
+}
+
+static int mxr_create_links(struct mxr_device *mdev)
+{
+ int ret, i;
+ int flags;
+
+#if defined(CONFIG_ARCH_EXYNOS4)
+ struct mxr_layer *layer;
+ struct media_entity *source, *sink;
+
+ layer = mdev->sub_mxr[MXR_SUB_MIXER0].layer[MXR_LAYER_VIDEO];
+ source = &layer->vfd.entity;
+ sink = &mdev->sub_mxr[MXR_SUB_MIXER0].sd.entity;
+ ret = media_entity_create_link(source, 0, sink, MXR_PAD_SINK_GSCALER,
+ MEDIA_LNK_FL_ENABLED);
+#endif
+ for (i = 0; i < MXR_MAX_SUB_MIXERS; ++i) {
+ if (mdev->sub_mxr[i].use)
+ flags = MEDIA_LNK_FL_ENABLED;
+ else
+ flags = 0;
+
+ ret = mxr_create_links_sub_mxr(mdev, i, flags);
+ if (ret)
+ return ret;
+ }
+
+ mxr_info(mdev, "mixer links are created successfully\n");
+
+ return 0;
+}
+
+/* --------- DRIVER INITIALIZATION ---------- */
+
+static int __devinit mxr_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct mxr_platform_data *pdata = dev->platform_data;
+ struct mxr_device *mdev;
+ int ret;
+
+ /* mdev does not exist yet so no mxr_dbg is used */
+ dev_info(dev, "probe start\n");
+
+ mdev = kzalloc(sizeof *mdev, GFP_KERNEL);
+ if (!mdev) {
+ dev_err(dev, "not enough memory.\n");
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ /* setup pointer to master device */
+ mdev->dev = dev;
+
+ /* use only sub mixer0 as default */
+ mdev->sub_mxr[MXR_SUB_MIXER0].use = 1;
+ mdev->sub_mxr[MXR_SUB_MIXER1].use = 1;
+
+#if defined(CONFIG_VIDEOBUF2_CMA_PHYS)
+ mdev->vb2 = &mxr_vb2_cma;
+#elif defined(CONFIG_VIDEOBUF2_ION)
+ mdev->vb2 = &mxr_vb2_ion;
+#endif
+
+ mutex_init(&mdev->mutex);
+ mutex_init(&mdev->s_mutex);
+ spin_lock_init(&mdev->reg_slock);
+ init_waitqueue_head(&mdev->event_queue);
+
+ /* acquire resources: regs, irqs, clocks, regulators */
+ ret = mxr_acquire_resources(mdev, pdev);
+ if (ret)
+ goto fail_mem;
+
+ /* configure resources for video output */
+ ret = mxr_acquire_video(mdev, mxr_output_conf,
+ ARRAY_SIZE(mxr_output_conf));
+ if (ret)
+ goto fail_resources;
+
+ /* register mixer subdev as entity */
+ ret = mxr_register_entities(mdev);
+ if (ret)
+ goto fail_video;
+
+ /* configure layers */
+ ret = mxr_acquire_layers(mdev, pdata);
+ if (ret)
+ goto fail_entity;
+
+ /* create links connected to gscaler, mixer inputs and hdmi */
+ ret = mxr_create_links(mdev);
+ if (ret)
+ goto fail_entity;
+
+ dev_set_drvdata(dev, mdev);
+
+ pm_runtime_enable(dev);
+
+ mxr_entities_info_print(mdev);
+
+ mxr_debugfs_init(mdev);
+
+ mxr_info(mdev, "probe successful\n");
+ return 0;
+
+fail_entity:
+ mxr_unregister_entities(mdev);
+
+fail_video:
+ mxr_release_video(mdev);
+
+fail_resources:
+ mxr_release_resources(mdev);
+
+fail_mem:
+ kfree(mdev);
+
+fail:
+ dev_info(dev, "probe failed\n");
+ return ret;
+}
+
+static int __devexit mxr_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct mxr_device *mdev = to_mdev(dev);
+
+ pm_runtime_disable(dev);
+
+ mxr_release_layers(mdev);
+ mxr_release_video(mdev);
+ mxr_release_resources(mdev);
+
+ if (mdev->mif_handle)
+ exynos5_bus_mif_put(mdev->mif_handle);
+
+ kfree(mdev);
+
+ dev_info(dev, "remove sucessful\n");
+ return 0;
+}
+
+static struct platform_driver mxr_driver __refdata = {
+ .probe = mxr_probe,
+ .remove = __devexit_p(mxr_remove),
+ .driver = {
+ .name = MXR_DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .pm = &mxr_pm_ops,
+ }
+};
+
+static int __init mxr_init(void)
+{
+ int i, ret;
+ static const char banner[] __initdata = KERN_INFO
+ "Samsung TV Mixer driver, "
+ "(c) 2010-2011 Samsung Electronics Co., Ltd.\n";
+ printk(banner);
+
+ /* Loading auxiliary modules */
+ for (i = 0; i < ARRAY_SIZE(mxr_output_conf); ++i)
+ request_module(mxr_output_conf[i].module_name);
+
+ ret = platform_driver_register(&mxr_driver);
+ if (ret != 0) {
+ printk(KERN_ERR "registration of MIXER driver failed\n");
+ return -ENXIO;
+ }
+
+ return 0;
+}
+module_init(mxr_init);
+
+static void __exit mxr_exit(void)
+{
+ platform_driver_unregister(&mxr_driver);
+}
+module_exit(mxr_exit);
diff --git a/drivers/media/video/exynos/tv/mixer_grp_layer.c b/drivers/media/video/exynos/tv/mixer_grp_layer.c
new file mode 100644
index 0000000..447e0e3
--- /dev/null
+++ b/drivers/media/video/exynos/tv/mixer_grp_layer.c
@@ -0,0 +1,186 @@
+/*
+ * Samsung TV Mixer driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * Tomasz Stanislawski, <t.stanislaws@samsung.com>
+ *
+ * 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 Foundiation. either version 2 of the License,
+ * or (at your option) any later version
+ */
+
+#include "mixer.h"
+
+#if defined(CONFIG_VIDEOBUF2_CMA_PHYS)
+#include <media/videobuf2-cma-phys.h>
+#elif defined(CONFIG_VIDEOBUF2_ION)
+#include <media/videobuf2-ion.h>
+#endif
+
+/* FORMAT DEFINITIONS */
+
+static const struct mxr_format mxr_fb_fmt_rgb565 = {
+ .name = "RGB565",
+ .fourcc = V4L2_PIX_FMT_RGB565,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .num_planes = 1,
+ .plane = {
+ { .width = 1, .height = 1, .size = 2 },
+ },
+ .num_subframes = 1,
+ .cookie = 4,
+};
+
+static const struct mxr_format mxr_fb_fmt_argb1555 = {
+ .name = "ARGB1555",
+ .num_planes = 1,
+ .fourcc = V4L2_PIX_FMT_RGB555,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .plane = {
+ { .width = 1, .height = 1, .size = 2 },
+ },
+ .num_subframes = 1,
+ .cookie = 5,
+};
+
+static const struct mxr_format mxr_fb_fmt_argb4444 = {
+ .name = "ARGB4444",
+ .num_planes = 1,
+ .fourcc = V4L2_PIX_FMT_RGB444,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .plane = {
+ { .width = 1, .height = 1, .size = 2 },
+ },
+ .num_subframes = 1,
+ .cookie = 6,
+};
+
+static const struct mxr_format mxr_fb_fmt_argb8888 = {
+ .name = "ARGB8888",
+ .fourcc = V4L2_PIX_FMT_BGR32,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .num_planes = 1,
+ .plane = {
+ { .width = 1, .height = 1, .size = 4 },
+ },
+ .num_subframes = 1,
+ .cookie = 7,
+};
+
+static const struct mxr_format *mxr_graph_format[] = {
+ &mxr_fb_fmt_rgb565,
+ &mxr_fb_fmt_argb1555,
+ &mxr_fb_fmt_argb4444,
+ &mxr_fb_fmt_argb8888,
+};
+
+/* AUXILIARY CALLBACKS */
+
+static void mxr_graph_layer_release(struct mxr_layer *layer)
+{
+ mxr_base_layer_unregister(layer);
+ mxr_base_layer_release(layer);
+}
+
+static void mxr_graph_buffer_set(struct mxr_layer *layer,
+ struct mxr_buffer *buf)
+{
+ struct mxr_device *mdev = layer->mdev;
+ dma_addr_t addr = 0;
+
+ if (buf)
+ addr = mdev->vb2->plane_addr(&buf->vb, 0);
+ mxr_reg_graph_buffer(layer->mdev, layer->idx, addr);
+}
+
+static void mxr_graph_stream_set(struct mxr_layer *layer, int en)
+{
+ mxr_reg_graph_layer_stream(layer->mdev, layer->idx, en);
+}
+
+static void mxr_graph_format_set(struct mxr_layer *layer)
+{
+ mxr_reg_graph_format(layer->mdev, layer->idx,
+ layer->fmt, &layer->geo);
+}
+
+static void mxr_graph_fix_geometry(struct mxr_layer *layer)
+{
+ struct mxr_geometry *geo = &layer->geo;
+
+ mxr_dbg(layer->mdev, "%s start\n", __func__);
+ /* limit to boundary size */
+ geo->src.full_width = clamp_val(geo->src.full_width, 1, 32767);
+ geo->src.full_height = clamp_val(geo->src.full_height, 1, 2047);
+
+ /* limit to coordinate of source x, y */
+ geo->src.x_offset = clamp_val(geo->src.x_offset, 0,
+ geo->src.full_width - 1);
+ geo->src.y_offset = clamp_val(geo->src.y_offset, 0,
+ geo->src.full_height - 1);
+
+ /* limit to boundary size of crop width, height */
+ geo->src.width = clamp_val(geo->src.width, 1,
+ geo->src.full_width - geo->src.x_offset);
+ geo->src.height = clamp_val(geo->src.height, 1,
+ geo->src.full_height - geo->src.y_offset);
+
+ /* dst full resolution and TV display size are same */
+
+ geo->dst.x_offset = clamp_val(geo->dst.x_offset, 0,
+ geo->dst.full_width - 1);
+ geo->dst.y_offset = clamp_val(geo->dst.y_offset, 0,
+ geo->dst.full_height - 1);
+
+ /* mixer scale-up is unuseful. so no use it */
+ geo->dst.width = clamp_val(geo->src.width, 1,
+ geo->dst.full_width - geo->dst.x_offset);
+ geo->dst.height = clamp_val(geo->src.height, 1,
+ geo->dst.full_height - geo->dst.y_offset);
+}
+
+/* PUBLIC API */
+
+struct mxr_layer *mxr_graph_layer_create(struct mxr_device *mdev, int cur_mxr,
+ int idx, int nr)
+{
+ struct mxr_layer *layer;
+ int ret;
+ struct mxr_layer_ops ops = {
+ .release = mxr_graph_layer_release,
+ .buffer_set = mxr_graph_buffer_set,
+ .stream_set = mxr_graph_stream_set,
+ .format_set = mxr_graph_format_set,
+ .fix_geometry = mxr_graph_fix_geometry,
+ };
+ char name[32];
+
+ sprintf(name, "mxr%d_graph%d", cur_mxr, idx);
+
+ layer = mxr_base_layer_create(mdev, idx, name, &ops);
+ if (layer == NULL) {
+ mxr_err(mdev, "failed to initialize layer(%d) base\n", idx);
+ goto fail;
+ }
+
+ layer->fmt_array = mxr_graph_format;
+ layer->fmt_array_size = ARRAY_SIZE(mxr_graph_format);
+ layer->minor = nr;
+ layer->type = MXR_LAYER_TYPE_GRP;
+
+ ret = mxr_base_layer_register(layer);
+ if (ret)
+ goto fail_layer;
+
+ layer->cur_mxr = cur_mxr;
+ return layer;
+
+fail_layer:
+ mxr_base_layer_release(layer);
+
+fail:
+ return NULL;
+}
+
diff --git a/drivers/media/video/exynos/tv/mixer_reg.c b/drivers/media/video/exynos/tv/mixer_reg.c
new file mode 100644
index 0000000..37c10bd
--- /dev/null
+++ b/drivers/media/video/exynos/tv/mixer_reg.c
@@ -0,0 +1,1031 @@
+/*
+ * Samsung TV Mixer driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * Tomasz Stanislawski, <t.stanislaws@samsung.com>
+ *
+ * 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 Foundiation. either version 2 of the License,
+ * or (at your option) any later version
+ */
+
+#include "mixer.h"
+#include "regs-mixer.h"
+#include "regs-vp.h"
+
+#include <plat/cpu.h>
+#include <linux/delay.h>
+#include <linux/ratelimit.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+/* Register access subroutines */
+
+static inline u32 vp_read(struct mxr_device *mdev, u32 reg_id)
+{
+#if defined(CONFIG_ARCH_EXYNOS4)
+ return readl(mdev->res.vp_regs + reg_id);
+#else
+ return 0;
+#endif
+}
+
+static inline void vp_write(struct mxr_device *mdev, u32 reg_id, u32 val)
+{
+#if defined(CONFIG_ARCH_EXYNOS4)
+ writel(val, mdev->res.vp_regs + reg_id);
+#endif
+}
+
+static inline void vp_write_mask(struct mxr_device *mdev, u32 reg_id,
+ u32 val, u32 mask)
+{
+#if defined(CONFIG_ARCH_EXYNOS4)
+ u32 old = vp_read(mdev, reg_id);
+
+ val = (val & mask) | (old & ~mask);
+ writel(val, mdev->res.vp_regs + reg_id);
+#endif
+}
+
+static inline u32 mxr_read(struct mxr_device *mdev, u32 reg_id)
+{
+ return readl(mdev->res.mxr_regs + reg_id);
+}
+
+static inline void mxr_write(struct mxr_device *mdev, u32 reg_id, u32 val)
+{
+ writel(val, mdev->res.mxr_regs + reg_id);
+}
+
+static inline void mxr_write_mask(struct mxr_device *mdev, u32 reg_id,
+ u32 val, u32 mask)
+{
+ u32 old = mxr_read(mdev, reg_id);
+
+ val = (val & mask) | (old & ~mask);
+ writel(val, mdev->res.mxr_regs + reg_id);
+}
+
+void mxr_layer_sync(struct mxr_device *mdev, int en)
+{
+ mxr_write_mask(mdev, MXR_STATUS, en ? MXR_STATUS_LAYER_SYNC : 0,
+ MXR_STATUS_LAYER_SYNC);
+}
+
+void mxr_vsync_set_update(struct mxr_device *mdev, int en)
+{
+ /* block update on vsync */
+ mxr_write_mask(mdev, MXR_STATUS, en ? MXR_STATUS_SYNC_ENABLE : 0,
+ MXR_STATUS_SYNC_ENABLE);
+#if defined(CONFIG_ARCH_EXYNOS4)
+ vp_write(mdev, VP_SHADOW_UPDATE, en ? VP_SHADOW_UPDATE_ENABLE : 0);
+#endif
+}
+
+static void __mxr_reg_vp_reset(struct mxr_device *mdev)
+{
+#if defined(CONFIG_ARCH_EXYNOS4)
+ int tries = 100;
+
+ vp_write(mdev, VP_SRESET, VP_SRESET_PROCESSING);
+ for (tries = 100; tries; --tries) {
+ /* waiting until VP_SRESET_PROCESSING is 0 */
+ if (~vp_read(mdev, VP_SRESET) & VP_SRESET_PROCESSING)
+ break;
+ mdelay(10);
+ }
+ WARN(tries == 0, "failed to reset Video Processor\n");
+#endif
+}
+
+static void mxr_reg_sub_mxr_reset(struct mxr_device *mdev, int mxr_num)
+{
+ u32 val; /* value stored to register */
+
+ if (mxr_num == MXR_SUB_MIXER0) {
+ /* use dark gray background color */
+ mxr_write(mdev, MXR_BG_COLOR0, 0x008080);
+ mxr_write(mdev, MXR_BG_COLOR1, 0x008080);
+ mxr_write(mdev, MXR_BG_COLOR2, 0x008080);
+
+ /* setting graphical layers */
+
+ val = MXR_GRP_CFG_BLANK_KEY_OFF; /* no blank key */
+ val |= MXR_GRP_CFG_ALPHA_VAL(0xff); /* non-transparent alpha */
+
+ /* the same configuration for both layers */
+ mxr_write(mdev, MXR_GRAPHIC_CFG(0), val);
+ mxr_write(mdev, MXR_GRAPHIC_CFG(1), val);
+ } else if (mxr_num == MXR_SUB_MIXER1) {
+ val = MXR_LAYER_CFG_GRP1_VAL(3);
+ val |= MXR_LAYER_CFG_GRP0_VAL(2);
+ val |= MXR_LAYER_CFG_VP_VAL(1);
+ mxr_write(mdev, MXR1_LAYER_CFG, val);
+
+ /* use dark gray background color */
+ mxr_write(mdev, MXR1_BG_COLOR0, 0x008080);
+ mxr_write(mdev, MXR1_BG_COLOR1, 0x008080);
+ mxr_write(mdev, MXR1_BG_COLOR2, 0x008080);
+
+ /* setting graphical layers */
+
+ val = MXR_GRP_CFG_BLANK_KEY_OFF; /* no blank key */
+ val |= MXR_GRP_CFG_ALPHA_VAL(0xff); /* non-transparent alpha */
+
+ /* the same configuration for both layers */
+ mxr_write(mdev, MXR1_GRAPHIC_CFG(0), val);
+ mxr_write(mdev, MXR1_GRAPHIC_CFG(1), val);
+ }
+}
+
+static void mxr_reg_vp_default_filter(struct mxr_device *mdev);
+
+void mxr_reg_reset(struct mxr_device *mdev)
+{
+ int i;
+ unsigned long flags;
+
+ spin_lock_irqsave(&mdev->reg_slock, flags);
+
+ mxr_write_mask(mdev, MXR_STATUS, ~0, MXR_STATUS_SOFT_RESET);
+ mxr_vsync_set_update(mdev, MXR_DISABLE);
+
+ /* set output in RGB888 mode */
+ mxr_write(mdev, MXR_CFG, MXR_CFG_OUT_RGB888);
+
+ /* 16 beat burst in DMA */
+ mxr_write_mask(mdev, MXR_STATUS, MXR_STATUS_16_BURST,
+ MXR_STATUS_BURST_MASK);
+
+ for (i = 0; i < MXR_MAX_SUB_MIXERS; ++i)
+ mxr_reg_sub_mxr_reset(mdev, i);
+
+ /* configuration of Video Processor Registers */
+ __mxr_reg_vp_reset(mdev);
+ mxr_reg_vp_default_filter(mdev);
+
+ /* enable all interrupts */
+ mxr_write_mask(mdev, MXR_INT_EN, ~0, MXR_INT_EN_ALL);
+
+ mxr_vsync_set_update(mdev, MXR_ENABLE);
+ spin_unlock_irqrestore(&mdev->reg_slock, flags);
+}
+
+void mxr_reg_graph_format(struct mxr_device *mdev, int idx,
+ const struct mxr_format *fmt, const struct mxr_geometry *geo)
+{
+ u32 wh, sxy, dxy;
+ unsigned long flags;
+
+ spin_lock_irqsave(&mdev->reg_slock, flags);
+ mxr_vsync_set_update(mdev, MXR_DISABLE);
+
+ /* Mostly, src width, height and dst width, height are same.
+ * However, in case of doing src and dst cropping, those are different.
+ * So you have to write dst width and height to MXR_GRAPHIC_WH register.
+ */
+ wh = MXR_GRP_WH_WIDTH(geo->dst.width);
+ wh |= MXR_GRP_WH_HEIGHT(geo->dst.height);
+ wh |= MXR_GRP_WH_H_SCALE(geo->x_ratio);
+ wh |= MXR_GRP_WH_V_SCALE(geo->y_ratio);
+
+ /* setup offsets in source image */
+ sxy = MXR_GRP_SXY_SX(geo->src.x_offset);
+ sxy |= MXR_GRP_SXY_SY(geo->src.y_offset);
+
+ /* setup offsets in display image */
+ dxy = MXR_GRP_DXY_DX(geo->dst.x_offset);
+ dxy |= MXR_GRP_DXY_DY(geo->dst.y_offset);
+
+ if (idx == 0) {
+ mxr_write_mask(mdev, MXR_GRAPHIC_CFG(0),
+ MXR_GRP_CFG_FORMAT_VAL(fmt->cookie),
+ MXR_GRP_CFG_FORMAT_MASK);
+ mxr_write(mdev, MXR_GRAPHIC_SPAN(0), geo->src.full_width);
+ mxr_write(mdev, MXR_GRAPHIC_WH(0), wh);
+ mxr_write(mdev, MXR_GRAPHIC_SXY(0), sxy);
+ mxr_write(mdev, MXR_GRAPHIC_DXY(0), dxy);
+ } else if (idx == 1) {
+ mxr_write_mask(mdev, MXR_GRAPHIC_CFG(1),
+ MXR_GRP_CFG_FORMAT_VAL(fmt->cookie),
+ MXR_GRP_CFG_FORMAT_MASK);
+ mxr_write(mdev, MXR_GRAPHIC_SPAN(1), geo->src.full_width);
+ mxr_write(mdev, MXR_GRAPHIC_WH(1), wh);
+ mxr_write(mdev, MXR_GRAPHIC_SXY(1), sxy);
+ mxr_write(mdev, MXR_GRAPHIC_DXY(1), dxy);
+ } else if (idx == 2) {
+ mxr_write_mask(mdev, MXR1_GRAPHIC_CFG(0),
+ MXR_GRP_CFG_FORMAT_VAL(fmt->cookie),
+ MXR_GRP_CFG_FORMAT_MASK);
+ mxr_write(mdev, MXR1_GRAPHIC_SPAN(0), geo->src.full_width);
+ mxr_write(mdev, MXR1_GRAPHIC_WH(0), wh);
+ mxr_write(mdev, MXR1_GRAPHIC_SXY(0), sxy);
+ mxr_write(mdev, MXR1_GRAPHIC_DXY(0), dxy);
+ } else if (idx == 3) {
+ mxr_write_mask(mdev, MXR1_GRAPHIC_CFG(1),
+ MXR_GRP_CFG_FORMAT_VAL(fmt->cookie),
+ MXR_GRP_CFG_FORMAT_MASK);
+ mxr_write(mdev, MXR1_GRAPHIC_SPAN(1), geo->src.full_width);
+ mxr_write(mdev, MXR1_GRAPHIC_WH(1), wh);
+ mxr_write(mdev, MXR1_GRAPHIC_SXY(1), sxy);
+ mxr_write(mdev, MXR1_GRAPHIC_DXY(1), dxy);
+ }
+
+ mxr_vsync_set_update(mdev, MXR_ENABLE);
+ spin_unlock_irqrestore(&mdev->reg_slock, flags);
+}
+
+void mxr_reg_video_geo(struct mxr_device *mdev, int cur_mxr, int idx,
+ const struct mxr_geometry *geo)
+{
+ u32 lt, rb;
+ unsigned long flags;
+
+ mxr_dbg(mdev, "%s\n", __func__);
+
+ spin_lock_irqsave(&mdev->reg_slock, flags);
+ mxr_vsync_set_update(mdev, MXR_DISABLE);
+
+ lt = MXR_VIDEO_LT_LEFT_VAL(geo->dst.x_offset);
+ lt |= MXR_VIDEO_LT_TOP_VAL(geo->dst.y_offset);
+ rb = MXR_VIDEO_RB_RIGHT_VAL(geo->dst.x_offset + geo->dst.width - 1);
+ rb |= MXR_VIDEO_RB_BOTTOM_VAL(geo->dst.y_offset + geo->dst.height - 1);
+
+ if (cur_mxr == MXR_SUB_MIXER0) {
+ mxr_write(mdev, MXR_VIDEO_LT, lt);
+ mxr_write(mdev, MXR_VIDEO_RB, rb);
+ } else if (cur_mxr == MXR_SUB_MIXER1) {
+ mxr_write(mdev, MXR1_VIDEO_LT, lt);
+ mxr_write(mdev, MXR1_VIDEO_RB, rb);
+ }
+
+ mxr_vsync_set_update(mdev, MXR_ENABLE);
+ spin_unlock_irqrestore(&mdev->reg_slock, flags);
+
+ mxr_dbg(mdev, "destination x = %d, y = %d, width = %d, height = %d\n",
+ geo->dst.x_offset, geo->dst.y_offset,
+ geo->dst.width, geo->dst.height);
+}
+
+void mxr_reg_vp_format(struct mxr_device *mdev,
+ const struct mxr_format *fmt, const struct mxr_geometry *geo)
+{
+#if defined(CONFIG_ARCH_EXYNOS4)
+ unsigned long flags;
+
+ spin_lock_irqsave(&mdev->reg_slock, flags);
+ mxr_vsync_set_update(mdev, MXR_DISABLE);
+
+ vp_write_mask(mdev, VP_MODE, fmt->cookie, VP_MODE_FMT_MASK);
+
+ /* setting size of input image */
+ vp_write(mdev, VP_IMG_SIZE_Y, VP_IMG_HSIZE(geo->src.full_width) |
+ VP_IMG_VSIZE(geo->src.full_height));
+ /* chroma height has to reduced by 2 to avoid chroma distorions */
+ vp_write(mdev, VP_IMG_SIZE_C, VP_IMG_HSIZE(geo->src.full_width) |
+ VP_IMG_VSIZE(geo->src.full_height / 2));
+
+ vp_write(mdev, VP_SRC_WIDTH, geo->src.width);
+ vp_write(mdev, VP_SRC_HEIGHT, geo->src.height);
+ vp_write(mdev, VP_SRC_H_POSITION,
+ VP_SRC_H_POSITION_VAL(geo->src.x_offset));
+ vp_write(mdev, VP_SRC_V_POSITION, geo->src.y_offset);
+
+ vp_write(mdev, VP_DST_WIDTH, geo->dst.width);
+ vp_write(mdev, VP_DST_H_POSITION, geo->dst.x_offset);
+ if (geo->dst.field == V4L2_FIELD_INTERLACED) {
+ vp_write(mdev, VP_DST_HEIGHT, geo->dst.height / 2);
+ vp_write(mdev, VP_DST_V_POSITION, geo->dst.y_offset / 2);
+ } else {
+ vp_write(mdev, VP_DST_HEIGHT, geo->dst.height);
+ vp_write(mdev, VP_DST_V_POSITION, geo->dst.y_offset);
+ }
+
+ vp_write(mdev, VP_H_RATIO, geo->x_ratio);
+ vp_write(mdev, VP_V_RATIO, geo->y_ratio);
+
+ vp_write(mdev, VP_ENDIAN_MODE, VP_ENDIAN_MODE_LITTLE);
+
+ mxr_vsync_set_update(mdev, MXR_ENABLE);
+ spin_unlock_irqrestore(&mdev->reg_slock, flags);
+#endif
+}
+
+void mxr_reg_graph_buffer(struct mxr_device *mdev, int idx, dma_addr_t addr)
+{
+ u32 val = addr ? ~0 : 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&mdev->reg_slock, flags);
+ mxr_vsync_set_update(mdev, MXR_DISABLE);
+
+ if (idx == 0) {
+ mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_GRP0_ENABLE);
+ mxr_write(mdev, MXR_GRAPHIC_BASE(0), addr);
+ } else if (idx == 1) {
+ mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_GRP1_ENABLE);
+ mxr_write(mdev, MXR_GRAPHIC_BASE(1), addr);
+ } else if (idx == 2) {
+ mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_MX1_GRP0_ENABLE);
+ mxr_write(mdev, MXR1_GRAPHIC_BASE(0), addr);
+ } else if (idx == 3) {
+ mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_MX1_GRP1_ENABLE);
+ mxr_write(mdev, MXR1_GRAPHIC_BASE(1), addr);
+ }
+
+ mxr_vsync_set_update(mdev, MXR_ENABLE);
+ spin_unlock_irqrestore(&mdev->reg_slock, flags);
+}
+
+void mxr_reg_vp_buffer(struct mxr_device *mdev,
+ dma_addr_t luma_addr[2], dma_addr_t chroma_addr[2])
+{
+#if defined(CONFIG_ARCH_EXYNOS4)
+ u32 val = luma_addr[0] ? ~0 : 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&mdev->reg_slock, flags);
+ mxr_vsync_set_update(mdev, MXR_DISABLE);
+
+ mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_VIDEO_ENABLE);
+ vp_write_mask(mdev, VP_ENABLE, val, VP_ENABLE_ON);
+ /* TODO: fix tiled mode */
+ vp_write(mdev, VP_TOP_Y_PTR, luma_addr[0]);
+ vp_write(mdev, VP_TOP_C_PTR, chroma_addr[0]);
+ vp_write(mdev, VP_BOT_Y_PTR, luma_addr[1]);
+ vp_write(mdev, VP_BOT_C_PTR, chroma_addr[1]);
+
+ mxr_vsync_set_update(mdev, MXR_ENABLE);
+ spin_unlock_irqrestore(&mdev->reg_slock, flags);
+#endif
+}
+
+void mxr_reg_set_layer_prio(struct mxr_device *mdev)
+{
+ u8 p_g0, p_g1, p_v;
+ u32 val;
+
+ p_v = mdev->sub_mxr[MXR_SUB_MIXER0].layer[MXR_LAYER_VIDEO]->prio;
+ p_g0 = mdev->sub_mxr[MXR_SUB_MIXER0].layer[MXR_LAYER_GRP0]->prio;
+ p_g1 = mdev->sub_mxr[MXR_SUB_MIXER0].layer[MXR_LAYER_GRP1]->prio;
+ mxr_dbg(mdev, "video layer priority = %d\n", p_v);
+ mxr_dbg(mdev, "graphic0 layer priority = %d\n", p_g0);
+ mxr_dbg(mdev, "graphic1 layer priority = %d\n", p_g1);
+
+ val = MXR_LAYER_CFG_GRP1_VAL(p_g1);
+ val |= MXR_LAYER_CFG_GRP0_VAL(p_g0);
+ val |= MXR_LAYER_CFG_VP_VAL(p_v);
+ mxr_write(mdev, MXR_LAYER_CFG, val);
+}
+
+void mxr_reg_set_layer_blend(struct mxr_device *mdev, int sub_mxr, int num,
+ int en)
+{
+ u32 val = en ? ~0 : 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&mdev->reg_slock, flags);
+ mxr_vsync_set_update(mdev, MXR_DISABLE);
+
+ if (sub_mxr == MXR_SUB_MIXER0 && num == MXR_LAYER_VIDEO)
+ mxr_write_mask(mdev, MXR_VIDEO_CFG, val,
+ MXR_VIDEO_CFG_BLEND_EN);
+ else if (sub_mxr == MXR_SUB_MIXER0 && num == MXR_LAYER_GRP0)
+ mxr_write_mask(mdev, MXR_GRAPHIC_CFG(0), val,
+ MXR_GRP_CFG_LAYER_BLEND_EN);
+ else if (sub_mxr == MXR_SUB_MIXER0 && num == MXR_LAYER_GRP1)
+ mxr_write_mask(mdev, MXR_GRAPHIC_CFG(1), val,
+ MXR_GRP_CFG_LAYER_BLEND_EN);
+#if defined(CONFIG_ARCH_EXYNOS5)
+ else if (sub_mxr == MXR_SUB_MIXER1 && num == MXR_LAYER_VIDEO)
+ mxr_write_mask(mdev, MXR1_VIDEO_CFG, val,
+ MXR_VIDEO_CFG_BLEND_EN);
+ else if (sub_mxr == MXR_SUB_MIXER1 && num == MXR_LAYER_GRP0)
+ mxr_write_mask(mdev, MXR1_GRAPHIC_CFG(0), val,
+ MXR_GRP_CFG_LAYER_BLEND_EN);
+ else if (sub_mxr == MXR_SUB_MIXER1 && num == MXR_LAYER_GRP1)
+ mxr_write_mask(mdev, MXR1_GRAPHIC_CFG(1), val,
+ MXR_GRP_CFG_LAYER_BLEND_EN);
+#endif
+
+ mxr_vsync_set_update(mdev, MXR_ENABLE);
+ spin_unlock_irqrestore(&mdev->reg_slock, flags);
+}
+
+void mxr_reg_layer_alpha(struct mxr_device *mdev, int sub_mxr, int num, u32 a)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&mdev->reg_slock, flags);
+ mxr_vsync_set_update(mdev, MXR_DISABLE);
+
+ if (sub_mxr == MXR_SUB_MIXER0 && num == MXR_LAYER_VIDEO)
+ mxr_write_mask(mdev, MXR_VIDEO_CFG, MXR_VIDEO_CFG_ALPHA(a),
+ 0xff);
+ else if (sub_mxr == MXR_SUB_MIXER0 && num == MXR_LAYER_GRP0)
+ mxr_write_mask(mdev, MXR_GRAPHIC_CFG(0), MXR_GRP_CFG_ALPHA_VAL(a),
+ 0xff);
+ else if (sub_mxr == MXR_SUB_MIXER0 && num == MXR_LAYER_GRP1)
+ mxr_write_mask(mdev, MXR_GRAPHIC_CFG(1), MXR_GRP_CFG_ALPHA_VAL(a),
+ 0xff);
+#if defined(CONFIG_ARCH_EXYNOS5)
+ else if (sub_mxr == MXR_SUB_MIXER1 && num == MXR_LAYER_VIDEO)
+ mxr_write_mask(mdev, MXR1_VIDEO_CFG, MXR_VIDEO_CFG_ALPHA(a),
+ 0xff);
+ else if (sub_mxr == MXR_SUB_MIXER1 && num == MXR_LAYER_GRP0)
+ mxr_write_mask(mdev, MXR1_GRAPHIC_CFG(0), MXR_GRP_CFG_ALPHA_VAL(a),
+ 0xff);
+ else if (sub_mxr == MXR_SUB_MIXER1 && num == MXR_LAYER_GRP1)
+ mxr_write_mask(mdev, MXR1_GRAPHIC_CFG(1), MXR_GRP_CFG_ALPHA_VAL(a),
+ 0xff);
+#endif
+
+ mxr_vsync_set_update(mdev, MXR_ENABLE);
+ spin_unlock_irqrestore(&mdev->reg_slock, flags);
+}
+
+void mxr_reg_set_pixel_blend(struct mxr_device *mdev, int sub_mxr, int num,
+ int en)
+{
+ u32 val = en ? ~0 : 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&mdev->reg_slock, flags);
+ mxr_vsync_set_update(mdev, MXR_DISABLE);
+
+ if (sub_mxr == MXR_SUB_MIXER0 && num == MXR_LAYER_GRP0)
+ mxr_write_mask(mdev, MXR_GRAPHIC_CFG(0), val,
+ MXR_GRP_CFG_PIXEL_BLEND_EN);
+ else if (sub_mxr == MXR_SUB_MIXER0 && num == MXR_LAYER_GRP1)
+ mxr_write_mask(mdev, MXR_GRAPHIC_CFG(1), val,
+ MXR_GRP_CFG_PIXEL_BLEND_EN);
+#if defined(CONFIG_ARCH_EXYNOS5)
+ else if (sub_mxr == MXR_SUB_MIXER1 && num == MXR_LAYER_GRP0)
+ mxr_write_mask(mdev, MXR1_GRAPHIC_CFG(0), val,
+ MXR_GRP_CFG_PIXEL_BLEND_EN);
+ else if (sub_mxr == MXR_SUB_MIXER1 && num == MXR_LAYER_GRP1)
+ mxr_write_mask(mdev, MXR1_GRAPHIC_CFG(1), val,
+ MXR_GRP_CFG_PIXEL_BLEND_EN);
+#endif
+
+ mxr_vsync_set_update(mdev, MXR_ENABLE);
+ spin_unlock_irqrestore(&mdev->reg_slock, flags);
+}
+
+void mxr_reg_set_colorkey(struct mxr_device *mdev, int sub_mxr, int num, int en)
+{
+ u32 val = en ? ~0 : 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&mdev->reg_slock, flags);
+ mxr_vsync_set_update(mdev, MXR_DISABLE);
+
+ if (sub_mxr == MXR_SUB_MIXER0 && num == MXR_LAYER_GRP0)
+ mxr_write_mask(mdev, MXR_GRAPHIC_CFG(0), val,
+ MXR_GRP_CFG_BLANK_KEY_OFF);
+ else if (sub_mxr == MXR_SUB_MIXER0 && num == MXR_LAYER_GRP1)
+ mxr_write_mask(mdev, MXR_GRAPHIC_CFG(1), val,
+ MXR_GRP_CFG_BLANK_KEY_OFF);
+#if defined(CONFIG_ARCH_EXYNOS5)
+ else if (sub_mxr == MXR_SUB_MIXER1 && num == MXR_LAYER_GRP0)
+ mxr_write_mask(mdev, MXR1_GRAPHIC_CFG(0), val,
+ MXR_GRP_CFG_BLANK_KEY_OFF);
+ else if (sub_mxr == MXR_SUB_MIXER1 && num == MXR_LAYER_GRP1)
+ mxr_write_mask(mdev, MXR1_GRAPHIC_CFG(1), val,
+ MXR_GRP_CFG_BLANK_KEY_OFF);
+#endif
+
+ mxr_vsync_set_update(mdev, MXR_ENABLE);
+ spin_unlock_irqrestore(&mdev->reg_slock, flags);
+}
+
+void mxr_reg_colorkey_val(struct mxr_device *mdev, int sub_mxr, int num, u32 v)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&mdev->reg_slock, flags);
+ mxr_vsync_set_update(mdev, MXR_DISABLE);
+
+ if (sub_mxr == MXR_SUB_MIXER0 && num == MXR_LAYER_GRP0)
+ mxr_write(mdev, MXR_GRAPHIC_BLANK(0), v);
+ else if (sub_mxr == MXR_SUB_MIXER0 && num == MXR_LAYER_GRP1)
+ mxr_write(mdev, MXR_GRAPHIC_BLANK(1), v);
+#if defined(CONFIG_ARCH_EXYNOS5)
+ else if (sub_mxr == MXR_SUB_MIXER1 && num == MXR_LAYER_GRP0)
+ mxr_write(mdev, MXR1_GRAPHIC_BLANK(0), v);
+ else if (sub_mxr == MXR_SUB_MIXER1 && num == MXR_LAYER_GRP1)
+ mxr_write(mdev, MXR1_GRAPHIC_BLANK(1), v);
+#endif
+
+ mxr_vsync_set_update(mdev, MXR_ENABLE);
+ spin_unlock_irqrestore(&mdev->reg_slock, flags);
+}
+
+static void mxr_irq_layer_handle(struct mxr_layer *layer)
+{
+ struct list_head *head = &layer->enq_list;
+ struct mxr_pipeline *pipe = &layer->pipe;
+ struct mxr_buffer *done;
+
+ /* skip non-existing layer */
+ if (layer == NULL)
+ return;
+
+ spin_lock(&layer->enq_slock);
+ if (pipe->state == MXR_PIPELINE_IDLE)
+ goto done;
+
+ done = layer->shadow_buf;
+ layer->shadow_buf = layer->update_buf;
+
+ if (list_empty(head)) {
+ if (pipe->state != MXR_PIPELINE_STREAMING)
+ layer->update_buf = NULL;
+ } else {
+ struct mxr_buffer *next;
+ next = list_first_entry(head, struct mxr_buffer, list);
+ list_del(&next->list);
+ layer->update_buf = next;
+ }
+
+ layer->ops.buffer_set(layer, layer->update_buf);
+
+ if (done && done != layer->shadow_buf)
+ vb2_buffer_done(&done->vb, VB2_BUF_STATE_DONE);
+
+done:
+ spin_unlock(&layer->enq_slock);
+}
+
+u32 mxr_irq_underrun_handle(struct mxr_device *mdev, u32 val)
+{
+ if (val & MXR_INT_STATUS_MX0_VIDEO) {
+ printk_ratelimited("mixer0 video layer underrun occur\n");
+ val |= MXR_INT_STATUS_MX0_VIDEO;
+ } else if (val & MXR_INT_STATUS_MX0_GRP0) {
+ printk_ratelimited("mixer0 graphic0 layer underrun occur\n");
+ val |= MXR_INT_STATUS_MX0_GRP0;
+ } else if (val & MXR_INT_STATUS_MX0_GRP1) {
+ printk_ratelimited("mixer0 graphic1 layer underrun occur\n");
+ val |= MXR_INT_STATUS_MX0_GRP1;
+ } else if (val & MXR_INT_STATUS_MX1_VIDEO) {
+ printk_ratelimited("mixer1 video layer underrun occur\n");
+ val |= MXR_INT_STATUS_MX1_VIDEO;
+ } else if (val & MXR_INT_STATUS_MX1_GRP0) {
+ printk_ratelimited("mixer1 graphic0 layer underrun occur\n");
+ val |= MXR_INT_STATUS_MX1_GRP0;
+ } else if (val & MXR_INT_STATUS_MX1_GRP1) {
+ printk_ratelimited("mixer1 graphic1 layer underrun occur\n");
+ val |= MXR_INT_STATUS_MX1_GRP1;
+ }
+
+ return val;
+}
+
+irqreturn_t mxr_irq_handler(int irq, void *dev_data)
+{
+ struct mxr_device *mdev = dev_data;
+ u32 i, val;
+
+ spin_lock(&mdev->reg_slock);
+ val = mxr_read(mdev, MXR_INT_STATUS);
+
+ /* wake up process waiting for VSYNC */
+ if (val & MXR_INT_STATUS_VSYNC) {
+ set_bit(MXR_EVENT_VSYNC, &mdev->event_flags);
+ wake_up(&mdev->event_queue);
+ }
+
+ /* clear interrupts.
+ vsync is updated after write MXR_CFG_LAYER_UPDATE bit */
+ if (val & MXR_INT_CLEAR_VSYNC)
+ mxr_write_mask(mdev, MXR_INT_STATUS, ~0, MXR_INT_CLEAR_VSYNC);
+
+ val = mxr_irq_underrun_handle(mdev, val);
+ mxr_write(mdev, MXR_INT_STATUS, val);
+
+ spin_unlock(&mdev->reg_slock);
+ /* leave on non-vsync event */
+ if (~val & MXR_INT_CLEAR_VSYNC)
+ return IRQ_HANDLED;
+
+ for (i = 0; i < MXR_MAX_SUB_MIXERS; ++i) {
+#if defined(CONFIG_ARCH_EXYNOS4)
+ mxr_irq_layer_handle(mdev->sub_mxr[i].layer[MXR_LAYER_VIDEO]);
+#endif
+ mxr_irq_layer_handle(mdev->sub_mxr[i].layer[MXR_LAYER_GRP0]);
+ mxr_irq_layer_handle(mdev->sub_mxr[i].layer[MXR_LAYER_GRP1]);
+ }
+
+ if (test_bit(MXR_EVENT_VSYNC, &mdev->event_flags)) {
+ spin_lock(&mdev->reg_slock);
+ mxr_write_mask(mdev, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE);
+ spin_unlock(&mdev->reg_slock);
+ }
+
+ return IRQ_HANDLED;
+}
+
+void mxr_reg_s_output(struct mxr_device *mdev, int cookie)
+{
+ u32 val;
+
+ val = cookie == 0 ? MXR_CFG_DST_SDO : MXR_CFG_DST_HDMI;
+ mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_DST_MASK);
+}
+
+void mxr_reg_streamon(struct mxr_device *mdev)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&mdev->reg_slock, flags);
+ /* single write -> no need to block vsync update */
+
+ /* start MIXER */
+ mxr_write_mask(mdev, MXR_STATUS, ~0, MXR_STATUS_REG_RUN);
+
+ spin_unlock_irqrestore(&mdev->reg_slock, flags);
+}
+
+void mxr_reg_streamoff(struct mxr_device *mdev)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&mdev->reg_slock, flags);
+ /* single write -> no need to block vsync update */
+
+ /* stop MIXER */
+ mxr_write_mask(mdev, MXR_STATUS, 0, MXR_STATUS_REG_RUN);
+
+ spin_unlock_irqrestore(&mdev->reg_slock, flags);
+}
+
+int mxr_reg_wait4vsync(struct mxr_device *mdev)
+{
+ int ret;
+
+ clear_bit(MXR_EVENT_VSYNC, &mdev->event_flags);
+ /* TODO: consider adding interruptible */
+ ret = wait_event_timeout(mdev->event_queue,
+ test_bit(MXR_EVENT_VSYNC, &mdev->event_flags),
+ msecs_to_jiffies(1000));
+ if (ret > 0)
+ return 0;
+ if (ret < 0)
+ return ret;
+ mxr_warn(mdev, "no vsync detected - timeout\n");
+ return -ETIME;
+}
+
+void mxr_reg_set_mbus_fmt(struct mxr_device *mdev,
+ struct v4l2_mbus_framefmt *fmt, u32 dvi_mode)
+{
+ u32 val = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&mdev->reg_slock, flags);
+ mxr_vsync_set_update(mdev, MXR_DISABLE);
+
+ /* choosing between YUV444 and RGB888 as mixer output type */
+ if (mdev->sub_mxr[MXR_SUB_MIXER0].mbus_fmt[MXR_PAD_SOURCE_GRP0].code ==
+ V4L2_MBUS_FMT_YUV8_1X24) {
+ if (dvi_mode) {
+ val = MXR_CFG_OUT_RGB888;
+ fmt->code = V4L2_MBUS_FMT_XRGB8888_4X8_LE;
+ } else {
+ val = MXR_CFG_OUT_YUV444;
+ fmt->code = V4L2_MBUS_FMT_YUV8_1X24;
+ }
+ } else {
+ val = MXR_CFG_OUT_RGB888;
+ fmt->code = V4L2_MBUS_FMT_XRGB8888_4X8_LE;
+ }
+
+ /* choosing between interlace and progressive mode */
+ if (fmt->field == V4L2_FIELD_INTERLACED)
+ val |= MXR_CFG_SCAN_INTERLACE;
+ else
+ val |= MXR_CFG_SCAN_PROGRASSIVE;
+
+ /* choosing between porper HD and SD mode */
+ if (fmt->height == 480)
+ val |= MXR_CFG_SCAN_NTSC | MXR_CFG_SCAN_SD;
+ else if (fmt->height == 576)
+ val |= MXR_CFG_SCAN_PAL | MXR_CFG_SCAN_SD;
+ else if (fmt->height == 720)
+ val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
+ else if (fmt->height == 1080)
+ val |= MXR_CFG_SCAN_HD_1080 | MXR_CFG_SCAN_HD;
+ else
+ WARN(1, "unrecognized mbus height %u!\n", fmt->height);
+
+ mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_SCAN_MASK |
+ MXR_CFG_OUT_MASK);
+
+ val = (fmt->field == V4L2_FIELD_INTERLACED) ? ~0 : 0;
+ vp_write_mask(mdev, VP_MODE, val,
+ VP_MODE_LINE_SKIP | VP_MODE_FIELD_ID_AUTO_TOGGLING);
+
+ mxr_vsync_set_update(mdev, MXR_ENABLE);
+ spin_unlock_irqrestore(&mdev->reg_slock, flags);
+}
+
+void mxr_reg_local_path_clear(struct mxr_device *mdev)
+{
+ u32 val;
+
+ val = readl(SYSREG_DISP1BLK_CFG);
+ val &= ~(DISP1BLK_CFG_MIXER0_VALID | DISP1BLK_CFG_MIXER1_VALID);
+ writel(val, SYSREG_DISP1BLK_CFG);
+ mxr_dbg(mdev, "SYSREG_DISP1BLK_CFG = 0x%x\n",
+ readl(SYSREG_DISP1BLK_CFG));
+}
+
+void mxr_reg_local_path_set(struct mxr_device *mdev, int mxr0_gsc, int mxr1_gsc,
+ u32 flags)
+{
+ u32 val = 0;
+ int mxr0_local = mdev->sub_mxr[MXR_SUB_MIXER0].local;
+ int mxr1_local = mdev->sub_mxr[MXR_SUB_MIXER1].local;
+
+ if (mxr0_local && !mxr1_local) { /* 1-path : sub-mixer0 */
+ val = MXR_TVOUT_CFG_ONE_PATH;
+ val |= MXR_TVOUT_CFG_PATH_MIXER0;
+ } else if (!mxr0_local && mxr1_local) { /* 1-path : sub-mixer1 */
+ val = MXR_TVOUT_CFG_ONE_PATH;
+ val |= MXR_TVOUT_CFG_PATH_MIXER1;
+ } else if (mxr0_local && mxr1_local) { /* 2-path */
+ val = MXR_TVOUT_CFG_TWO_PATH;
+ val |= MXR_TVOUT_CFG_STEREO_SCOPIC;
+ }
+
+ mxr_write(mdev, MXR_TVOUT_CFG, val);
+
+ /* set local path gscaler to mixer */
+ val = readl(SYSREG_DISP1BLK_CFG);
+ val |= DISP1BLK_CFG_FIFORST_DISP1;
+ val &= ~DISP1BLK_CFG_MIXER_MASK;
+ if (flags & MEDIA_LNK_FL_ENABLED) {
+ if (mxr0_local) {
+ val |= DISP1BLK_CFG_MIXER0_VALID;
+ val |= DISP1BLK_CFG_MIXER0_SRC_GSC(mxr0_gsc);
+ }
+ if (mxr1_local) {
+ val |= DISP1BLK_CFG_MIXER1_VALID;
+ val |= DISP1BLK_CFG_MIXER1_SRC_GSC(mxr1_gsc);
+ }
+ }
+ mxr_dbg(mdev, "%s: SYSREG value = 0x%x\n", __func__, val);
+ writel(val, SYSREG_DISP1BLK_CFG);
+}
+
+void mxr_reg_graph_layer_stream(struct mxr_device *mdev, int idx, int en)
+{
+ u32 val = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&mdev->reg_slock, flags);
+ mxr_vsync_set_update(mdev, MXR_DISABLE);
+
+ if (mdev->frame_packing) {
+ val = MXR_TVOUT_CFG_TWO_PATH;
+ val |= MXR_TVOUT_CFG_STEREO_SCOPIC;
+ } else {
+ val = MXR_TVOUT_CFG_ONE_PATH;
+ val |= MXR_TVOUT_CFG_PATH_MIXER0;
+ }
+
+ mxr_write(mdev, MXR_TVOUT_CFG, val);
+
+ mxr_vsync_set_update(mdev, MXR_ENABLE);
+ spin_unlock_irqrestore(&mdev->reg_slock, flags);
+}
+
+void mxr_reg_vp_layer_stream(struct mxr_device *mdev, int en)
+{
+ /* no extra actions need to be done */
+}
+
+void mxr_reg_video_layer_stream(struct mxr_device *mdev, int idx, int en)
+{
+ u32 val = en ? ~0 : 0;
+
+ if (idx == 0)
+ mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_VIDEO_ENABLE);
+ else if (idx == 1)
+ mxr_write_mask(mdev, MXR_CFG, val, MXR_CFG_MX1_VIDEO_ENABLE);
+}
+
+static const u8 filter_y_horiz_tap8[] = {
+ 0, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 0, 0, 0,
+ 0, 2, 4, 5, 6, 6, 6, 6,
+ 6, 5, 5, 4, 3, 2, 1, 1,
+ 0, -6, -12, -16, -18, -20, -21, -20,
+ -20, -18, -16, -13, -10, -8, -5, -2,
+ 127, 126, 125, 121, 114, 107, 99, 89,
+ 79, 68, 57, 46, 35, 25, 16, 8,
+};
+
+static const u8 filter_y_vert_tap4[] = {
+ 0, -3, -6, -8, -8, -8, -8, -7,
+ -6, -5, -4, -3, -2, -1, -1, 0,
+ 127, 126, 124, 118, 111, 102, 92, 81,
+ 70, 59, 48, 37, 27, 19, 11, 5,
+ 0, 5, 11, 19, 27, 37, 48, 59,
+ 70, 81, 92, 102, 111, 118, 124, 126,
+ 0, 0, -1, -1, -2, -3, -4, -5,
+ -6, -7, -8, -8, -8, -8, -6, -3,
+};
+
+static const u8 filter_cr_horiz_tap4[] = {
+ 0, -3, -6, -8, -8, -8, -8, -7,
+ -6, -5, -4, -3, -2, -1, -1, 0,
+ 127, 126, 124, 118, 111, 102, 92, 81,
+ 70, 59, 48, 37, 27, 19, 11, 5,
+};
+
+static inline void mxr_reg_vp_filter_set(struct mxr_device *mdev,
+ int reg_id, const u8 *data, unsigned int size)
+{
+ /* assure 4-byte align */
+ BUG_ON(size & 3);
+ for (; size; size -= 4, reg_id += 4, data += 4) {
+ u32 val = (data[0] << 24) | (data[1] << 16) |
+ (data[2] << 8) | data[3];
+ vp_write(mdev, reg_id, val);
+ }
+}
+
+static void mxr_reg_vp_default_filter(struct mxr_device *mdev)
+{
+#if defined(CONFIG_ARCH_EXYNOS4)
+ mxr_reg_vp_filter_set(mdev, VP_POLY8_Y0_LL,
+ filter_y_horiz_tap8, sizeof filter_y_horiz_tap8);
+ mxr_reg_vp_filter_set(mdev, VP_POLY4_Y0_LL,
+ filter_y_vert_tap4, sizeof filter_y_vert_tap4);
+ mxr_reg_vp_filter_set(mdev, VP_POLY4_C0_LL,
+ filter_cr_horiz_tap4, sizeof filter_cr_horiz_tap4);
+#endif
+}
+
+static int mxr_debugfs_show(struct seq_file *s, void *unused)
+{
+ struct mxr_device *mdev = s->private;
+
+ mutex_lock(&mdev->s_mutex);
+
+ if (!mdev->n_streamer) {
+ seq_printf(s, "Not streaming\n");
+ mutex_unlock(&mdev->s_mutex);
+ return 0;
+ }
+
+#define DUMPREG(reg_id) \
+do { \
+ seq_printf(s, "%-17s %08x\n", #reg_id, \
+ (u32)readl(mdev->res.mxr_regs + reg_id)); \
+} while (0)
+
+ DUMPREG(MXR_STATUS);
+ DUMPREG(MXR_CFG);
+ DUMPREG(MXR_INT_EN);
+ DUMPREG(MXR_INT_STATUS);
+ DUMPREG(MXR_LAYER_CFG);
+ DUMPREG(MXR_VIDEO_CFG);
+ DUMPREG(MXR_GRAPHIC0_CFG);
+ DUMPREG(MXR_GRAPHIC0_BASE);
+ DUMPREG(MXR_GRAPHIC0_SPAN);
+ DUMPREG(MXR_GRAPHIC0_WH);
+ DUMPREG(MXR_GRAPHIC0_SXY);
+ DUMPREG(MXR_GRAPHIC0_DXY);
+ DUMPREG(MXR_GRAPHIC1_CFG);
+ DUMPREG(MXR_GRAPHIC1_BASE);
+ DUMPREG(MXR_GRAPHIC1_SPAN);
+ DUMPREG(MXR_GRAPHIC1_WH);
+ DUMPREG(MXR_GRAPHIC1_SXY);
+ DUMPREG(MXR_GRAPHIC1_DXY);
+ DUMPREG(MXR_TVOUT_CFG);
+
+#undef DUMPREG
+
+ mutex_unlock(&mdev->s_mutex);
+ return 0;
+}
+
+static int mxr_debugfs_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, mxr_debugfs_show, inode->i_private);
+}
+
+static const struct file_operations mxr_debugfs_fops = {
+ .open = mxr_debugfs_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+void mxr_debugfs_init(struct mxr_device *mdev)
+{
+ debugfs_create_file(dev_name(mdev->dev), S_IRUGO, NULL,
+ mdev, &mxr_debugfs_fops);
+}
+
+static void mxr_reg_mxr_dump(struct mxr_device *mdev)
+{
+#define DUMPREG(reg_id) \
+do { \
+ mxr_dbg(mdev, #reg_id " = %08x\n", \
+ (u32)readl(mdev->res.mxr_regs + reg_id)); \
+} while (0)
+
+ DUMPREG(MXR_STATUS);
+ DUMPREG(MXR_CFG);
+ DUMPREG(MXR_INT_EN);
+ DUMPREG(MXR_INT_STATUS);
+
+ DUMPREG(MXR_LAYER_CFG);
+ DUMPREG(MXR_VIDEO_CFG);
+
+ DUMPREG(MXR_GRAPHIC0_CFG);
+ DUMPREG(MXR_GRAPHIC0_BASE);
+ DUMPREG(MXR_GRAPHIC0_SPAN);
+ DUMPREG(MXR_GRAPHIC0_WH);
+ DUMPREG(MXR_GRAPHIC0_SXY);
+ DUMPREG(MXR_GRAPHIC0_DXY);
+
+ DUMPREG(MXR_GRAPHIC1_CFG);
+ DUMPREG(MXR_GRAPHIC1_BASE);
+ DUMPREG(MXR_GRAPHIC1_SPAN);
+ DUMPREG(MXR_GRAPHIC1_WH);
+ DUMPREG(MXR_GRAPHIC1_SXY);
+ DUMPREG(MXR_GRAPHIC1_DXY);
+
+ if (soc_is_exynos5250()) {
+ DUMPREG(MXR1_LAYER_CFG);
+ DUMPREG(MXR1_VIDEO_CFG);
+
+ DUMPREG(MXR1_GRAPHIC0_CFG);
+ DUMPREG(MXR1_GRAPHIC0_BASE);
+ DUMPREG(MXR1_GRAPHIC0_SPAN);
+ DUMPREG(MXR1_GRAPHIC0_WH);
+ DUMPREG(MXR1_GRAPHIC0_SXY);
+ DUMPREG(MXR1_GRAPHIC0_DXY);
+
+ DUMPREG(MXR1_GRAPHIC1_CFG);
+ DUMPREG(MXR1_GRAPHIC1_BASE);
+ DUMPREG(MXR1_GRAPHIC1_SPAN);
+ DUMPREG(MXR1_GRAPHIC1_WH);
+ DUMPREG(MXR1_GRAPHIC1_SXY);
+ DUMPREG(MXR1_GRAPHIC1_DXY);
+
+ DUMPREG(MXR_TVOUT_CFG);
+ }
+#undef DUMPREG
+}
+
+static void mxr_reg_vp_dump(struct mxr_device *mdev)
+{
+#define DUMPREG(reg_id) \
+do { \
+ mxr_dbg(mdev, #reg_id " = %08x\n", \
+ (u32) readl(mdev->res.vp_regs + reg_id)); \
+} while (0)
+
+#if defined(CONFIG_ARCH_EXYNOS4)
+ DUMPREG(VP_ENABLE);
+ DUMPREG(VP_SRESET);
+ DUMPREG(VP_SHADOW_UPDATE);
+ DUMPREG(VP_FIELD_ID);
+ DUMPREG(VP_MODE);
+ DUMPREG(VP_IMG_SIZE_Y);
+ DUMPREG(VP_IMG_SIZE_C);
+ DUMPREG(VP_PER_RATE_CTRL);
+ DUMPREG(VP_TOP_Y_PTR);
+ DUMPREG(VP_BOT_Y_PTR);
+ DUMPREG(VP_TOP_C_PTR);
+ DUMPREG(VP_BOT_C_PTR);
+ DUMPREG(VP_ENDIAN_MODE);
+ DUMPREG(VP_SRC_H_POSITION);
+ DUMPREG(VP_SRC_V_POSITION);
+ DUMPREG(VP_SRC_WIDTH);
+ DUMPREG(VP_SRC_HEIGHT);
+ DUMPREG(VP_DST_H_POSITION);
+ DUMPREG(VP_DST_V_POSITION);
+ DUMPREG(VP_DST_WIDTH);
+ DUMPREG(VP_DST_HEIGHT);
+ DUMPREG(VP_H_RATIO);
+ DUMPREG(VP_V_RATIO);
+#endif
+
+#undef DUMPREG
+}
+
+void mxr_reg_dump(struct mxr_device *mdev)
+{
+ mxr_reg_mxr_dump(mdev);
+ mxr_reg_vp_dump(mdev);
+}
diff --git a/drivers/media/video/exynos/tv/mixer_vb2.c b/drivers/media/video/exynos/tv/mixer_vb2.c
new file mode 100644
index 0000000..47368db
--- /dev/null
+++ b/drivers/media/video/exynos/tv/mixer_vb2.c
@@ -0,0 +1,73 @@
+/* linux/drivers/media/video/exynos/tv/mixer_vb2.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Videobuf2 allocator operations file
+ *
+ * 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.
+*/
+#include <linux/platform_device.h>
+#if defined(CONFIG_VIDEOBUF2_CMA_PHYS)
+#include <media/videobuf2-cma-phys.h>
+#elif defined(CONFIG_VIDEOBUF2_ION)
+#include <media/videobuf2-ion.h>
+#endif
+
+#include "mixer.h"
+
+#if defined(CONFIG_VIDEOBUF2_CMA_PHYS)
+void *mxr_cma_init(struct mxr_device *mdev)
+{
+ return vb2_cma_phys_init(mdev->dev, NULL, 0, false);
+}
+
+int mxr_cma_resume(void *alloc_ctx) {}
+void mxr_cma_suspend(void *alloc_ctx) {}
+void mxr_cma_set_cacheable(void *alloc_ctx, bool cacheable) {}
+
+int mxr_cma_cache_flush(struct vb2_buffer *vb, u32 plane_no)
+{
+ return 0;
+}
+
+const struct mxr_vb2 mxr_vb2_cma = {
+ .ops = &vb2_cma_phys_memops,
+ .init = mxr_cma_init,
+ .cleanup = vb2_cma_phys_cleanup,
+ .plane_addr = vb2_cma_phys_plane_paddr,
+ .resume = mxr_cma_resume,
+ .suspend = mxr_cma_suspend,
+ .cache_flush = mxr_cma_cache_flush,
+ .set_cacheable = mxr_cma_set_cacheable,
+};
+#elif defined(CONFIG_VIDEOBUF2_ION)
+void *mxr_ion_init(struct mxr_device *mdev)
+{
+ return vb2_ion_create_context(mdev->dev, SZ_4K,
+ VB2ION_CTX_VMCONTIG | VB2ION_CTX_UNCACHED | VB2ION_CTX_IOMMU);
+}
+
+unsigned long mxr_ion_plane_addr(struct vb2_buffer *vb, u32 plane_no)
+{
+ void *cookie = vb2_plane_cookie(vb, plane_no);
+ dma_addr_t dva = 0;
+
+ WARN_ON(vb2_ion_dma_address(cookie, &dva) != 0);
+
+ return dva;
+}
+
+const struct mxr_vb2 mxr_vb2_ion = {
+ .ops = &vb2_ion_memops,
+ .init = mxr_ion_init,
+ .cleanup = vb2_ion_destroy_context,
+ .plane_addr = mxr_ion_plane_addr,
+ .resume = vb2_ion_attach_iommu,
+ .suspend = vb2_ion_detach_iommu,
+ .cache_flush = vb2_ion_cache_flush,
+ .set_cacheable = vb2_ion_set_cached,
+};
+#endif
diff --git a/drivers/media/video/exynos/tv/mixer_video.c b/drivers/media/video/exynos/tv/mixer_video.c
new file mode 100644
index 0000000..4f69d48
--- /dev/null
+++ b/drivers/media/video/exynos/tv/mixer_video.c
@@ -0,0 +1,1290 @@
+/*
+ * Samsung TV Mixer driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * Tomasz Stanislawski, <t.stanislaws@samsung.com>
+ *
+ * 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
+ */
+#include "mixer.h"
+
+#include <linux/videodev2.h>
+#include <linux/videodev2_exynos_media.h>
+#include <linux/mm.h>
+#include <linux/version.h>
+#include <linux/timer.h>
+#include <linux/export.h>
+
+#include <media/exynos_mc.h>
+#include <media/v4l2-ioctl.h>
+#if defined(CONFIG_VIDEOBUF2_CMA_PHYS)
+#include <media/videobuf2-cma-phys.h>
+#elif defined(CONFIG_VIDEOBUF2_ION)
+#include <media/videobuf2-ion.h>
+#endif
+
+int __devinit mxr_acquire_video(struct mxr_device *mdev,
+ struct mxr_output_conf *output_conf, int output_count)
+{
+ int i;
+ int ret = 0;
+ struct v4l2_subdev *sd;
+
+ mdev->alloc_ctx = mdev->vb2->init(mdev);
+ if (IS_ERR_OR_NULL(mdev->alloc_ctx)) {
+ mxr_err(mdev, "could not acquire vb2 allocator\n");
+ ret = PTR_ERR(mdev->alloc_ctx);
+ goto fail;
+ }
+
+ /* registering outputs */
+ mdev->output_cnt = 0;
+ for (i = 0; i < output_count; ++i) {
+ struct mxr_output_conf *conf = &output_conf[i];
+ struct mxr_output *out;
+
+ /* find subdev of output devices */
+ sd = (struct v4l2_subdev *)
+ module_name_to_driver_data(conf->module_name);
+ /* trying to register next output */
+ if (sd == NULL)
+ continue;
+ out = kzalloc(sizeof *out, GFP_KERNEL);
+ if (out == NULL) {
+ mxr_err(mdev, "no memory for '%s'\n",
+ conf->output_name);
+ ret = -ENOMEM;
+ /* registered subdevs are removed in fail_v4l2_dev */
+ goto fail_output;
+ }
+ strlcpy(out->name, conf->output_name, sizeof(out->name));
+ out->sd = sd;
+ out->cookie = conf->cookie;
+ mdev->output[mdev->output_cnt++] = out;
+ mxr_info(mdev, "added output '%s' from module '%s'\n",
+ conf->output_name, conf->module_name);
+ /* checking if maximal number of outputs is reached */
+ if (mdev->output_cnt >= MXR_MAX_OUTPUTS)
+ break;
+ }
+
+ if (mdev->output_cnt == 0) {
+ mxr_err(mdev, "failed to register any output\n");
+ ret = -ENODEV;
+ /* skipping fail_output because there is nothing to free */
+ goto fail_vb2_allocator;
+ }
+
+ return 0;
+
+fail_output:
+ /* kfree is NULL-safe */
+ for (i = 0; i < mdev->output_cnt; ++i)
+ kfree(mdev->output[i]);
+ memset(mdev->output, 0, sizeof mdev->output);
+
+fail_vb2_allocator:
+ /* freeing allocator context */
+ mdev->vb2->cleanup(mdev->alloc_ctx);
+
+fail:
+ return ret;
+}
+
+void mxr_release_video(struct mxr_device *mdev)
+{
+ int i;
+
+ /* kfree is NULL-safe */
+ for (i = 0; i < mdev->output_cnt; ++i)
+ kfree(mdev->output[i]);
+
+ mdev->vb2->cleanup(mdev->alloc_ctx);
+}
+
+static void tv_graph_pipeline_stream(struct mxr_pipeline *pipe, int on)
+{
+ struct mxr_device *mdev = pipe->layer->mdev;
+ struct media_entity *me = &pipe->layer->vfd.entity;
+ /* source pad of graphic layer entity */
+ struct media_pad *pad = &me->pads[0];
+ struct v4l2_subdev *sd;
+ struct exynos_entity_data md_data;
+
+ mxr_dbg(mdev, "%s TV graphic layer pipeline\n", on ? "start" : "stop");
+
+ /* find remote pad through enabled link */
+ pad = media_entity_remote_source(pad);
+ if (media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV
+ || pad == NULL)
+ mxr_warn(mdev, "cannot find remote pad\n");
+
+ sd = media_entity_to_v4l2_subdev(pad->entity);
+ mxr_dbg(mdev, "s_stream of %s sub-device is called\n", sd->name);
+
+ md_data.mxr_data_from = FROM_MXR_VD;
+ v4l2_set_subdevdata(sd, &md_data);
+ v4l2_subdev_call(sd, video, s_stream, on);
+}
+
+static int mxr_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct mxr_layer *layer = video_drvdata(file);
+
+ mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+
+ strlcpy(cap->driver, MXR_DRIVER_NAME, sizeof cap->driver);
+ strlcpy(cap->card, layer->vfd.name, sizeof cap->card);
+ sprintf(cap->bus_info, "%d", layer->idx);
+ cap->version = KERNEL_VERSION(0, 1, 0);
+ cap->capabilities = V4L2_CAP_STREAMING |
+ V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VIDEO_OUTPUT_MPLANE;
+
+ return 0;
+}
+
+/* Geometry handling */
+void mxr_layer_geo_fix(struct mxr_layer *layer)
+{
+ struct mxr_device *mdev = layer->mdev;
+ struct v4l2_mbus_framefmt mbus_fmt;
+
+ /* TODO: add some dirty flag to avoid unnecessary adjustments */
+ mxr_get_mbus_fmt(mdev, &mbus_fmt);
+ layer->geo.dst.full_width = mbus_fmt.width;
+ layer->geo.dst.full_height = mbus_fmt.height;
+ layer->geo.dst.field = mbus_fmt.field;
+ layer->ops.fix_geometry(layer);
+}
+
+void mxr_layer_default_geo(struct mxr_layer *layer)
+{
+ struct mxr_device *mdev = layer->mdev;
+ struct v4l2_mbus_framefmt mbus_fmt;
+
+ mxr_dbg(layer->mdev, "%s start\n", __func__);
+ memset(&layer->geo, 0, sizeof layer->geo);
+
+ mxr_get_mbus_fmt(mdev, &mbus_fmt);
+
+ layer->geo.dst.full_width = mbus_fmt.width;
+ layer->geo.dst.full_height = mbus_fmt.height;
+ layer->geo.dst.width = layer->geo.dst.full_width;
+ layer->geo.dst.height = layer->geo.dst.full_height;
+ layer->geo.dst.field = mbus_fmt.field;
+
+ layer->geo.src.full_width = mbus_fmt.width;
+ layer->geo.src.full_height = mbus_fmt.height;
+ layer->geo.src.width = layer->geo.src.full_width;
+ layer->geo.src.height = layer->geo.src.full_height;
+
+ layer->ops.fix_geometry(layer);
+}
+
+static void mxr_geometry_dump(struct mxr_device *mdev, struct mxr_geometry *geo)
+{
+ mxr_dbg(mdev, "src.full_size = (%u, %u)\n",
+ geo->src.full_width, geo->src.full_height);
+ mxr_dbg(mdev, "src.size = (%u, %u)\n",
+ geo->src.width, geo->src.height);
+ mxr_dbg(mdev, "src.offset = (%u, %u)\n",
+ geo->src.x_offset, geo->src.y_offset);
+ mxr_dbg(mdev, "dst.full_size = (%u, %u)\n",
+ geo->dst.full_width, geo->dst.full_height);
+ mxr_dbg(mdev, "dst.size = (%u, %u)\n",
+ geo->dst.width, geo->dst.height);
+ mxr_dbg(mdev, "dst.offset = (%u, %u)\n",
+ geo->dst.x_offset, geo->dst.y_offset);
+ mxr_dbg(mdev, "ratio = (%u, %u)\n",
+ geo->x_ratio, geo->y_ratio);
+}
+
+static const struct mxr_format *find_format_by_index(
+ struct mxr_layer *layer, unsigned long index);
+
+static int mxr_enum_fmt(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ struct mxr_layer *layer = video_drvdata(file);
+ struct mxr_device *mdev = layer->mdev;
+ const struct mxr_format *fmt;
+
+ mxr_dbg(mdev, "%s\n", __func__);
+ fmt = find_format_by_index(layer, f->index);
+ if (fmt == NULL)
+ return -EINVAL;
+
+ strlcpy(f->description, fmt->name, sizeof(f->description));
+ f->pixelformat = fmt->fourcc;
+
+ return 0;
+}
+
+static int mxr_s_fmt(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct mxr_layer *layer = video_drvdata(file);
+ const struct mxr_format *fmt;
+ struct v4l2_pix_format_mplane *pix;
+ struct mxr_device *mdev = layer->mdev;
+ struct mxr_geometry *geo = &layer->geo;
+
+ mxr_dbg(mdev, "%s:%d\n", __func__, __LINE__);
+
+ pix = &f->fmt.pix_mp;
+ fmt = find_format_by_fourcc(layer, pix->pixelformat);
+ if (fmt == NULL) {
+ mxr_warn(mdev, "not recognized fourcc: %08x\n",
+ pix->pixelformat);
+ return -EINVAL;
+ }
+ layer->fmt = fmt;
+ geo->src.full_width = pix->width;
+ geo->src.width = pix->width;
+ geo->src.full_height = pix->height;
+ geo->src.height = pix->height;
+ /* assure consistency of geometry */
+ mxr_layer_geo_fix(layer);
+ mxr_dbg(mdev, "width=%u height=%u span=%u\n",
+ geo->src.width, geo->src.height, geo->src.full_width);
+
+ return 0;
+}
+
+static unsigned int divup(unsigned int divident, unsigned int divisor)
+{
+ return (divident + divisor - 1) / divisor;
+}
+
+unsigned long mxr_get_plane_size(const struct mxr_block *blk,
+ unsigned int width, unsigned int height)
+{
+ unsigned int bl_width = divup(width, blk->width);
+ unsigned int bl_height = divup(height, blk->height);
+
+ return bl_width * bl_height * blk->size;
+}
+
+static void mxr_mplane_fill(struct v4l2_plane_pix_format *planes,
+ const struct mxr_format *fmt, u32 width, u32 height)
+{
+ int i;
+
+ memset(planes, 0, sizeof(*planes) * fmt->num_subframes);
+ for (i = 0; i < fmt->num_planes; ++i) {
+ struct v4l2_plane_pix_format *plane = planes
+ + fmt->plane2subframe[i];
+ const struct mxr_block *blk = &fmt->plane[i];
+ u32 bl_width = divup(width, blk->width);
+ u32 bl_height = divup(height, blk->height);
+ u32 sizeimage = bl_width * bl_height * blk->size;
+ u16 bytesperline = bl_width * blk->size / blk->height;
+
+ plane->sizeimage += sizeimage;
+ plane->bytesperline = max(plane->bytesperline, bytesperline);
+ }
+}
+
+static int mxr_g_fmt(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct mxr_layer *layer = video_drvdata(file);
+ struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
+
+ mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+
+ pix->width = layer->geo.src.full_width;
+ pix->height = layer->geo.src.full_height;
+ pix->field = V4L2_FIELD_NONE;
+ pix->pixelformat = layer->fmt->fourcc;
+ pix->colorspace = layer->fmt->colorspace;
+ mxr_mplane_fill(pix->plane_fmt, layer->fmt, pix->width, pix->height);
+
+ return 0;
+}
+
+static inline struct mxr_crop *choose_crop_by_type(struct mxr_geometry *geo,
+ enum v4l2_buf_type type)
+{
+ switch (type) {
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ return &geo->dst;
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ return &geo->src;
+ default:
+ return NULL;
+ }
+}
+
+static int mxr_g_crop(struct file *file, void *fh, struct v4l2_crop *a)
+{
+ struct mxr_layer *layer = video_drvdata(file);
+ struct mxr_crop *crop;
+
+ mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+ crop = choose_crop_by_type(&layer->geo, a->type);
+ if (crop == NULL)
+ return -EINVAL;
+ mxr_layer_geo_fix(layer);
+ a->c.left = crop->x_offset;
+ a->c.top = crop->y_offset;
+ a->c.width = crop->width;
+ a->c.height = crop->height;
+ return 0;
+}
+
+static int mxr_s_crop(struct file *file, void *fh, struct v4l2_crop *a)
+{
+ struct mxr_layer *layer = video_drvdata(file);
+ struct mxr_crop *crop;
+
+ mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+ crop = choose_crop_by_type(&layer->geo, a->type);
+ if (crop == NULL)
+ return -EINVAL;
+ crop->x_offset = a->c.left;
+ crop->y_offset = a->c.top;
+ crop->width = a->c.width;
+ crop->height = a->c.height;
+ mxr_layer_geo_fix(layer);
+ return 0;
+}
+
+static int mxr_cropcap(struct file *file, void *fh, struct v4l2_cropcap *a)
+{
+ struct mxr_layer *layer = video_drvdata(file);
+ struct mxr_crop *crop;
+
+ mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+ crop = choose_crop_by_type(&layer->geo, a->type);
+ if (crop == NULL)
+ return -EINVAL;
+ mxr_layer_geo_fix(layer);
+ a->bounds.left = 0;
+ a->bounds.top = 0;
+ a->bounds.width = crop->full_width;
+ a->bounds.top = crop->full_height;
+ a->defrect = a->bounds;
+ /* setting pixel aspect to 1/1 */
+ a->pixelaspect.numerator = 1;
+ a->pixelaspect.denominator = 1;
+ return 0;
+}
+
+static int mxr_check_ctrl_val(struct v4l2_control *ctrl)
+{
+ int ret = 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_TV_LAYER_BLEND_ALPHA:
+ case V4L2_CID_TV_CHROMA_VALUE:
+ if (ctrl->value < 0 || ctrl->value > 256)
+ ret = -ERANGE;
+ break;
+ }
+
+ return ret;
+}
+
+static int mxr_s_ctrl(struct file *file, void *fh, struct v4l2_control *ctrl)
+{
+ struct mxr_layer *layer = video_drvdata(file);
+ struct mxr_device *mdev = layer->mdev;
+ int v = ctrl->value;
+ int ret;
+
+ mxr_dbg(mdev, "%s start\n", __func__);
+
+ ret = mxr_check_ctrl_val(ctrl);
+ if (ret) {
+ mxr_err(mdev, "alpha value is out of range\n");
+ return ret;
+ }
+
+ switch (ctrl->id) {
+ case V4L2_CID_TV_LAYER_BLEND_ENABLE:
+ layer->layer_blend_en = v;
+ break;
+ case V4L2_CID_TV_LAYER_BLEND_ALPHA:
+ layer->layer_alpha = (u32)v;
+ break;
+ case V4L2_CID_TV_PIXEL_BLEND_ENABLE:
+ layer->pixel_blend_en = v;
+ break;
+ case V4L2_CID_TV_CHROMA_ENABLE:
+ layer->chroma_en = v;
+ break;
+ case V4L2_CID_TV_CHROMA_VALUE:
+ layer->chroma_val = (u32)v;
+ break;
+ case V4L2_CID_TV_HPD_STATUS:
+ v4l2_subdev_call(to_outsd(mdev), core, s_ctrl, ctrl);
+ break;
+ case V4L2_CID_TV_SET_DVI_MODE:
+ v4l2_subdev_call(to_outsd(mdev), core, s_ctrl, ctrl);
+ break;
+ case V4L2_CID_TV_SET_ASPECT_RATIO:
+ v4l2_subdev_call(to_outsd(mdev), core, s_ctrl, ctrl);
+ case V4L2_CID_TV_LAYER_PRIO:
+ layer->prio = (u8)v;
+ /* This can be turned on/off each layer while streaming */
+ if (layer->pipe.state == MXR_PIPELINE_STREAMING)
+ mxr_reg_set_layer_prio(mdev);
+ break;
+ default:
+ mxr_err(mdev, "invalid control id\n");
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int mxr_g_ctrl(struct file *file, void *fh, struct v4l2_control *ctrl)
+{
+ struct mxr_layer *layer = video_drvdata(file);
+ struct mxr_device *mdev = layer->mdev;
+ int num = 0;
+ int ret = 0;
+
+ mxr_dbg(mdev, "%s start\n", __func__);
+
+ if (layer->type == MXR_LAYER_TYPE_VIDEO)
+ num = 0;
+ else if (layer->type == MXR_LAYER_TYPE_GRP && layer->idx == 0)
+ num = 1;
+ else if (layer->type == MXR_LAYER_TYPE_GRP && layer->idx == 1)
+ num = 2;
+
+ ret = mxr_check_ctrl_val(ctrl);
+
+ switch (ctrl->id) {
+ case V4L2_CID_TV_HPD_STATUS:
+ v4l2_subdev_call(to_outsd(mdev), core, g_ctrl, ctrl);
+ break;
+ default:
+ mxr_err(mdev, "invalid control id\n");
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static int mxr_enum_dv_presets(struct file *file, void *fh,
+ struct v4l2_dv_enum_preset *preset)
+{
+ struct mxr_layer *layer = video_drvdata(file);
+ struct mxr_device *mdev = layer->mdev;
+ int ret;
+
+ /* lock protects from changing sd_out */
+ mutex_lock(&mdev->mutex);
+ ret = v4l2_subdev_call(to_outsd(mdev), video, enum_dv_presets, preset);
+ mutex_unlock(&mdev->mutex);
+
+ return ret ? -EINVAL : 0;
+}
+
+static int mxr_s_dv_preset(struct file *file, void *fh,
+ struct v4l2_dv_preset *preset)
+{
+ struct mxr_layer *layer = video_drvdata(file);
+ struct mxr_device *mdev = layer->mdev;
+ int ret;
+
+ /* lock protects from changing sd_out */
+ mutex_lock(&mdev->mutex);
+
+ /* preset change cannot be done while there is an entity
+ * dependant on output configuration
+ */
+ if (mdev->n_output > 0) {
+ mutex_unlock(&mdev->mutex);
+ return -EBUSY;
+ }
+
+ ret = v4l2_subdev_call(to_outsd(mdev), video, s_dv_preset, preset);
+
+ mutex_unlock(&mdev->mutex);
+
+ /* any failure should return EINVAL according to V4L2 doc */
+ return ret ? -EINVAL : 0;
+}
+
+static int mxr_g_dv_preset(struct file *file, void *fh,
+ struct v4l2_dv_preset *preset)
+{
+ struct mxr_layer *layer = video_drvdata(file);
+ struct mxr_device *mdev = layer->mdev;
+ int ret;
+
+ /* lock protects from changing sd_out */
+ mutex_lock(&mdev->mutex);
+ ret = v4l2_subdev_call(to_outsd(mdev), video, g_dv_preset, preset);
+ mutex_unlock(&mdev->mutex);
+
+ return ret ? -EINVAL : 0;
+}
+
+static int mxr_s_std(struct file *file, void *fh, v4l2_std_id *norm)
+{
+ struct mxr_layer *layer = video_drvdata(file);
+ struct mxr_device *mdev = layer->mdev;
+ int ret;
+
+ /* lock protects from changing sd_out */
+ mutex_lock(&mdev->mutex);
+
+ /* standard change cannot be done while there is an entity
+ * dependant on output configuration
+ */
+ if (mdev->n_output > 0) {
+ mutex_unlock(&mdev->mutex);
+ return -EBUSY;
+ }
+
+ ret = v4l2_subdev_call(to_outsd(mdev), video, s_std_output, *norm);
+
+ mutex_unlock(&mdev->mutex);
+
+ return ret ? -EINVAL : 0;
+}
+
+static int mxr_g_std(struct file *file, void *fh, v4l2_std_id *norm)
+{
+ struct mxr_layer *layer = video_drvdata(file);
+ struct mxr_device *mdev = layer->mdev;
+ int ret;
+
+ /* lock protects from changing sd_out */
+ mutex_lock(&mdev->mutex);
+ ret = v4l2_subdev_call(to_outsd(mdev), video, g_std_output, norm);
+ mutex_unlock(&mdev->mutex);
+
+ return ret ? -EINVAL : 0;
+}
+
+static int mxr_enum_output(struct file *file, void *fh, struct v4l2_output *a)
+{
+ struct mxr_layer *layer = video_drvdata(file);
+ struct mxr_device *mdev = layer->mdev;
+ struct mxr_output *out;
+ struct v4l2_subdev *sd;
+
+ if (a->index >= mdev->output_cnt)
+ return -EINVAL;
+ out = mdev->output[a->index];
+ BUG_ON(out == NULL);
+ sd = out->sd;
+ strlcpy(a->name, out->name, sizeof(a->name));
+
+ /* try to obtain supported tv norms */
+ v4l2_subdev_call(sd, video, g_tvnorms_output, &a->std);
+ a->capabilities = 0;
+ if (sd->ops->video && sd->ops->video->s_dv_preset)
+ a->capabilities |= V4L2_OUT_CAP_PRESETS;
+ if (sd->ops->video && sd->ops->video->s_std_output)
+ a->capabilities |= V4L2_OUT_CAP_STD;
+ a->type = V4L2_OUTPUT_TYPE_ANALOG;
+
+ return 0;
+}
+
+static int mxr_s_output(struct file *file, void *fh, unsigned int i)
+{
+ struct video_device *vfd = video_devdata(file);
+ struct mxr_layer *layer = video_drvdata(file);
+ struct mxr_device *mdev = layer->mdev;
+ int ret = 0;
+
+ if (i >= mdev->output_cnt || mdev->output[i] == NULL)
+ return -EINVAL;
+
+ mutex_lock(&mdev->mutex);
+ if (mdev->n_output > 0) {
+ ret = -EBUSY;
+ goto done;
+ }
+ mdev->current_output = i;
+ vfd->tvnorms = 0;
+ v4l2_subdev_call(to_outsd(mdev), video, g_tvnorms_output,
+ &vfd->tvnorms);
+ mxr_dbg(mdev, "tvnorms = %08llx\n", vfd->tvnorms);
+
+done:
+ mutex_unlock(&mdev->mutex);
+ return ret;
+}
+
+static int mxr_g_output(struct file *file, void *fh, unsigned int *p)
+{
+ struct mxr_layer *layer = video_drvdata(file);
+ struct mxr_device *mdev = layer->mdev;
+
+ mutex_lock(&mdev->mutex);
+ *p = mdev->current_output;
+ mutex_unlock(&mdev->mutex);
+
+ return 0;
+}
+
+static int mxr_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *p)
+{
+ struct mxr_layer *layer = video_drvdata(file);
+
+ mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+ return vb2_reqbufs(&layer->vb_queue, p);
+}
+
+static int mxr_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+ struct mxr_layer *layer = video_drvdata(file);
+
+ mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+ return vb2_querybuf(&layer->vb_queue, p);
+}
+
+static int mxr_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+ struct mxr_layer *layer = video_drvdata(file);
+
+ return vb2_qbuf(&layer->vb_queue, p);
+}
+
+static int mxr_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+ struct mxr_layer *layer = video_drvdata(file);
+
+ return vb2_dqbuf(&layer->vb_queue, p, file->f_flags & O_NONBLOCK);
+}
+
+static int mxr_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+ struct mxr_layer *layer = video_drvdata(file);
+ struct mxr_device *mdev = layer->mdev;
+
+ switch (layer->idx) {
+ case 0:
+ mdev->layer_en.graph0 = 1;
+ break;
+ case 1:
+ mdev->layer_en.graph1 = 1;
+ break;
+ case 2:
+ mdev->layer_en.graph2 = 1;
+ break;
+ case 3:
+ mdev->layer_en.graph3 = 1;
+ break;
+ default:
+ mxr_err(mdev, "invalid layer number\n");
+ return -EINVAL;
+ }
+
+ if ((mdev->layer_en.graph0 && mdev->layer_en.graph2) ||
+ (mdev->layer_en.graph1 && mdev->layer_en.graph3)) {
+ mdev->frame_packing = 1;
+ mxr_dbg(mdev, "frame packing mode\n");
+ }
+
+ mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+ return vb2_streamon(&layer->vb_queue, i);
+}
+
+static int mxr_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+ struct mxr_layer *layer = video_drvdata(file);
+ struct mxr_device *mdev = layer->mdev;
+
+ switch (layer->idx) {
+ case 0:
+ mdev->layer_en.graph0 = 0;
+ break;
+ case 1:
+ mdev->layer_en.graph1 = 0;
+ break;
+ case 2:
+ mdev->layer_en.graph2 = 0;
+ break;
+ case 3:
+ mdev->layer_en.graph3 = 0;
+ break;
+ default:
+ mxr_err(mdev, "invalid layer number\n");
+ return -EINVAL;
+ }
+
+ mdev->frame_packing = 0;
+ if ((mdev->layer_en.graph0 && mdev->layer_en.graph2) ||
+ (mdev->layer_en.graph1 && mdev->layer_en.graph3)) {
+ mdev->frame_packing = 1;
+ mxr_dbg(mdev, "frame packing mode\n");
+ }
+
+ mxr_dbg(mdev, "%s:%d\n", __func__, __LINE__);
+ return vb2_streamoff(&layer->vb_queue, i);
+}
+
+static const struct v4l2_ioctl_ops mxr_ioctl_ops = {
+ .vidioc_querycap = mxr_querycap,
+ /* format handling */
+ .vidioc_enum_fmt_vid_out = mxr_enum_fmt,
+ .vidioc_s_fmt_vid_out_mplane = mxr_s_fmt,
+ .vidioc_g_fmt_vid_out_mplane = mxr_g_fmt,
+ /* buffer control */
+ .vidioc_reqbufs = mxr_reqbufs,
+ .vidioc_querybuf = mxr_querybuf,
+ .vidioc_qbuf = mxr_qbuf,
+ .vidioc_dqbuf = mxr_dqbuf,
+ /* Streaming control */
+ .vidioc_streamon = mxr_streamon,
+ .vidioc_streamoff = mxr_streamoff,
+ /* Preset functions */
+ .vidioc_enum_dv_presets = mxr_enum_dv_presets,
+ .vidioc_s_dv_preset = mxr_s_dv_preset,
+ .vidioc_g_dv_preset = mxr_g_dv_preset,
+ /* analog TV standard functions */
+ .vidioc_s_std = mxr_s_std,
+ .vidioc_g_std = mxr_g_std,
+ /* Output handling */
+ .vidioc_enum_output = mxr_enum_output,
+ .vidioc_s_output = mxr_s_output,
+ .vidioc_g_output = mxr_g_output,
+ /* Crop ioctls */
+ .vidioc_g_crop = mxr_g_crop,
+ .vidioc_s_crop = mxr_s_crop,
+ .vidioc_cropcap = mxr_cropcap,
+ /* Alpha blending functions */
+ .vidioc_s_ctrl = mxr_s_ctrl,
+ .vidioc_g_ctrl = mxr_g_ctrl,
+};
+
+static int mxr_video_open(struct file *file)
+{
+ struct mxr_layer *layer = video_drvdata(file);
+ struct mxr_device *mdev = layer->mdev;
+ int ret = 0;
+
+ mxr_dbg(mdev, "%s:%d\n", __func__, __LINE__);
+ /* assure device probe is finished */
+ wait_for_device_probe();
+ /* creating context for file descriptor */
+ ret = v4l2_fh_open(file);
+ if (ret) {
+ mxr_err(mdev, "v4l2_fh_open failed\n");
+ return ret;
+ }
+
+ /* leaving if layer is already initialized */
+ if (!v4l2_fh_is_singular_file(file))
+ return 0;
+
+ ret = vb2_queue_init(&layer->vb_queue);
+ if (ret != 0) {
+ mxr_err(mdev, "failed to initialize vb2 queue\n");
+ goto fail_fh_open;
+ }
+ /* set default format, first on the list */
+ layer->fmt = layer->fmt_array[0];
+ /* setup default geometry */
+ mxr_layer_default_geo(layer);
+
+ return 0;
+
+fail_fh_open:
+ v4l2_fh_release(file);
+
+ return ret;
+}
+
+static unsigned int
+mxr_video_poll(struct file *file, struct poll_table_struct *wait)
+{
+ struct mxr_layer *layer = video_drvdata(file);
+
+ mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+
+ return vb2_poll(&layer->vb_queue, file, wait);
+}
+
+static int mxr_video_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct mxr_layer *layer = video_drvdata(file);
+
+ mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+
+ return vb2_mmap(&layer->vb_queue, vma);
+}
+
+static int mxr_video_release(struct file *file)
+{
+ struct mxr_layer *layer = video_drvdata(file);
+
+ mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+
+ /* initialize alpha blending variables */
+ layer->layer_blend_en = 0;
+ layer->layer_alpha = 0;
+ layer->pixel_blend_en = 0;
+ layer->chroma_en = 0;
+ layer->chroma_val = 0;
+
+ if (v4l2_fh_is_singular_file(file))
+ vb2_queue_release(&layer->vb_queue);
+
+ v4l2_fh_release(file);
+ return 0;
+}
+
+static const struct v4l2_file_operations mxr_fops = {
+ .owner = THIS_MODULE,
+ .open = mxr_video_open,
+ .poll = mxr_video_poll,
+ .mmap = mxr_video_mmap,
+ .release = mxr_video_release,
+ .unlocked_ioctl = video_ioctl2,
+};
+
+static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *pfmt,
+ unsigned int *nbuffers, unsigned int *nplanes,
+ unsigned int sizes[], void *alloc_ctxs[])
+{
+ struct mxr_layer *layer = vb2_get_drv_priv(vq);
+ const struct mxr_format *fmt = layer->fmt;
+ int i;
+ struct mxr_device *mdev = layer->mdev;
+ struct v4l2_plane_pix_format planes[3];
+
+ mxr_dbg(mdev, "%s\n", __func__);
+ /* checking if format was configured */
+ if (fmt == NULL)
+ return -EINVAL;
+ mxr_dbg(mdev, "fmt = %s\n", fmt->name);
+ mxr_mplane_fill(planes, fmt, layer->geo.src.full_width,
+ layer->geo.src.full_height);
+
+ *nplanes = fmt->num_subframes;
+ for (i = 0; i < fmt->num_subframes; ++i) {
+ alloc_ctxs[i] = layer->mdev->alloc_ctx;
+ sizes[i] = PAGE_ALIGN(planes[i].sizeimage);
+ mxr_dbg(mdev, "size[%d] = %08x\n", i, sizes[i]);
+ }
+
+ if (*nbuffers == 0)
+ *nbuffers = 1;
+
+ vb2_queue_init(vq);
+
+ return 0;
+}
+
+static void fence_work(struct work_struct *work)
+{
+ struct mxr_layer *layer = container_of(work, struct mxr_layer, fence_work);
+ struct mxr_pipeline *pipe = &layer->pipe;
+ struct mxr_buffer *buffer;
+ struct sync_fence *fence;
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&layer->enq_slock, flags);
+
+ while (!list_empty(&layer->fence_wait_list)) {
+ buffer = list_first_entry(&layer->fence_wait_list,
+ struct mxr_buffer, wait);
+ list_del(&buffer->wait);
+
+ fence = buffer->vb.acquire_fence;
+ if (fence) {
+ buffer->vb.acquire_fence = NULL;
+ spin_unlock_irqrestore(&layer->enq_slock, flags);
+
+ ret = sync_fence_wait(fence, 100);
+ if (ret)
+ mxr_err(layer->mdev, "sync_fence_wait() timeout");
+ sync_fence_put(fence);
+
+ spin_lock_irqsave(&layer->enq_slock, flags);
+ }
+
+ list_add_tail(&buffer->list, &layer->enq_list);
+ }
+
+ if (pipe->state == MXR_PIPELINE_STREAMING_START)
+ pipe->state = MXR_PIPELINE_STREAMING;
+
+ spin_unlock_irqrestore(&layer->enq_slock, flags);
+}
+
+static void buf_queue(struct vb2_buffer *vb)
+{
+ struct mxr_buffer *buffer = container_of(vb, struct mxr_buffer, vb);
+ struct mxr_layer *layer = vb2_get_drv_priv(vb->vb2_queue);
+ unsigned long flags;
+
+ spin_lock_irqsave(&layer->enq_slock, flags);
+ list_add_tail(&buffer->wait, &layer->fence_wait_list);
+ spin_unlock_irqrestore(&layer->enq_slock, flags);
+
+ queue_work(layer->fence_wq, &layer->fence_work);
+}
+
+static void wait_lock(struct vb2_queue *vq)
+{
+ struct mxr_layer *layer = vb2_get_drv_priv(vq);
+
+ mutex_lock(&layer->mutex);
+}
+
+static void wait_unlock(struct vb2_queue *vq)
+{
+ struct mxr_layer *layer = vb2_get_drv_priv(vq);
+
+ mutex_unlock(&layer->mutex);
+}
+
+static int buf_prepare(struct vb2_buffer *vb)
+{
+ struct mxr_layer *layer = vb2_get_drv_priv(vb->vb2_queue);
+ struct mxr_device *mdev = layer->mdev;
+ struct v4l2_subdev *sd;
+ struct media_pad *pad;
+ int i, j;
+ int enable = 0;
+
+ for (i = 0; i < MXR_MAX_SUB_MIXERS; ++i) {
+ sd = &mdev->sub_mxr[i].sd;
+
+ for (j = MXR_PAD_SOURCE_GSCALER; j < MXR_PADS_NUM; ++j) {
+ pad = &sd->entity.pads[j];
+
+ /* find sink pad of hdmi or sdo through enabled link*/
+ pad = media_entity_remote_source(pad);
+ if (media_entity_type(pad->entity)
+ == MEDIA_ENT_T_V4L2_SUBDEV) {
+ enable = 1;
+ break;
+ }
+ }
+ if (enable)
+ break;
+ }
+ if (!enable)
+ return -ENODEV;
+
+ sd = media_entity_to_v4l2_subdev(pad->entity);
+
+ /* current output device must be matched terminal entity
+ * which represents HDMI or SDO sub-device
+ */
+ if (strcmp(sd->name, to_output(mdev)->sd->name)) {
+ mxr_err(mdev, "subdev name : %s, output device name : %s\n",
+ sd->name, to_output(mdev)->sd->name);
+ mxr_err(mdev, "output device is not mached\n");
+ return -ERANGE;
+ }
+
+ return 0;
+}
+
+static int start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+ struct mxr_layer *layer = vb2_get_drv_priv(vq);
+ struct mxr_device *mdev = layer->mdev;
+ struct mxr_pipeline *pipe = &layer->pipe;
+ unsigned long flags;
+ int ret;
+
+ mxr_dbg(mdev, "%s\n", __func__);
+
+ if (count == 0) {
+ mxr_dbg(mdev, "no output buffers queued\n");
+ return -EINVAL;
+ }
+
+ /* enable mixer clock */
+ ret = mxr_power_get(mdev);
+ if (ret)
+ mxr_err(mdev, "power on failed\n");
+
+ /* block any changes in output configuration */
+ mxr_output_get(mdev);
+
+ /* update layers geometry */
+ mxr_layer_geo_fix(layer);
+ mxr_geometry_dump(mdev, &layer->geo);
+
+ layer->ops.format_set(layer);
+
+ spin_lock_irqsave(&layer->enq_slock, flags);
+ if (list_empty(&layer->enq_list))
+ pipe->state = MXR_PIPELINE_STREAMING_START;
+ else
+ pipe->state = MXR_PIPELINE_STREAMING;
+ spin_unlock_irqrestore(&layer->enq_slock, flags);
+
+ /* enabling layer in hardware */
+ layer->ops.stream_set(layer, MXR_ENABLE);
+ /* store starting entity ptr on the tv graphic pipeline */
+ pipe->layer = layer;
+ /* start streaming all entities on the tv graphic pipeline */
+ tv_graph_pipeline_stream(pipe, 1);
+
+ return 0;
+}
+
+static void mxr_watchdog(unsigned long arg)
+{
+ struct mxr_layer *layer = (struct mxr_layer *) arg;
+ struct mxr_device *mdev = layer->mdev;
+ unsigned long flags;
+
+ mxr_err(mdev, "watchdog fired for layer %s\n", layer->vfd.name);
+
+ spin_lock_irqsave(&layer->enq_slock, flags);
+
+ if (layer->update_buf == layer->shadow_buf)
+ layer->update_buf = NULL;
+ if (layer->update_buf) {
+ vb2_buffer_done(&layer->update_buf->vb, VB2_BUF_STATE_ERROR);
+ layer->update_buf = NULL;
+ }
+ if (layer->shadow_buf) {
+ vb2_buffer_done(&layer->shadow_buf->vb, VB2_BUF_STATE_ERROR);
+ layer->shadow_buf = NULL;
+ }
+ spin_unlock_irqrestore(&layer->enq_slock, flags);
+}
+
+static int stop_streaming(struct vb2_queue *vq)
+{
+ struct mxr_layer *layer = vb2_get_drv_priv(vq);
+ struct mxr_device *mdev = layer->mdev;
+ unsigned long flags;
+ struct timer_list watchdog;
+ struct mxr_buffer *buf, *buf_tmp;
+ struct mxr_pipeline *pipe = &layer->pipe;
+
+ mxr_dbg(mdev, "%s\n", __func__);
+
+ cancel_work_sync(&layer->fence_work);
+
+ spin_lock_irqsave(&layer->enq_slock, flags);
+
+ list_for_each_entry_safe(buf, buf_tmp, &layer->fence_wait_list, wait) {
+ list_del(&buf->wait);
+
+ if (buf->vb.acquire_fence) {
+ spin_unlock_irqrestore(&layer->enq_slock, flags);
+
+ sync_fence_put(buf->vb.acquire_fence);
+ buf->vb.acquire_fence = NULL;
+
+ spin_lock_irqsave(&layer->enq_slock, flags);
+ }
+
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+ }
+
+ /* reset list */
+ pipe->state = MXR_PIPELINE_STREAMING_FINISH;
+
+ /* set all buffer to be done */
+ list_for_each_entry_safe(buf, buf_tmp, &layer->enq_list, list) {
+ list_del(&buf->list);
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+ }
+
+ spin_unlock_irqrestore(&layer->enq_slock, flags);
+
+ /* give 1 seconds to complete to complete last buffers */
+ setup_timer_on_stack(&watchdog, mxr_watchdog,
+ (unsigned long)layer);
+ mod_timer(&watchdog, jiffies + msecs_to_jiffies(1000));
+
+ /* wait until all buffers are goes to done state */
+ vb2_wait_for_all_buffers(vq);
+
+ /* stop timer if all synchronization is done */
+ del_timer_sync(&watchdog);
+ destroy_timer_on_stack(&watchdog);
+
+ /* stopping hardware */
+ spin_lock_irqsave(&layer->enq_slock, flags);
+
+ pipe->state = MXR_PIPELINE_IDLE;
+ spin_unlock_irqrestore(&layer->enq_slock, flags);
+
+ /* disabling layer in hardware */
+ layer->ops.stream_set(layer, MXR_DISABLE);
+
+ /* starting entity on the pipeline */
+ pipe->layer = layer;
+ /* stop streaming all entities on the pipeline */
+ tv_graph_pipeline_stream(pipe, 0);
+
+ /* allow changes in output configuration */
+ mxr_output_put(mdev);
+
+ /* disable mixer clock */
+ mxr_power_put(mdev);
+
+ return 0;
+}
+
+static struct vb2_ops mxr_video_qops = {
+ .queue_setup = queue_setup,
+ .buf_queue = buf_queue,
+ .wait_prepare = wait_unlock,
+ .wait_finish = wait_lock,
+ .buf_prepare = buf_prepare,
+ .start_streaming = start_streaming,
+ .stop_streaming = stop_streaming,
+};
+
+/* FIXME: try to put this functions to mxr_base_layer_create */
+int mxr_base_layer_register(struct mxr_layer *layer)
+{
+ struct mxr_device *mdev = layer->mdev;
+ struct exynos_md *md;
+ int ret;
+
+ md = (struct exynos_md *)module_name_to_driver_data(MDEV_MODULE_NAME);
+ if (!md) {
+ mxr_err(mdev, "failed to get output media device\n");
+ return -ENODEV;
+ }
+
+ layer->vfd.v4l2_dev = &md->v4l2_dev;
+ ret = video_register_device(&layer->vfd, VFL_TYPE_GRABBER,
+ layer->minor);
+ if (ret)
+ mxr_err(mdev, "failed to register video device\n");
+ else
+ mxr_info(mdev, "registered layer %s as /dev/video%d\n",
+ layer->vfd.name, layer->vfd.num);
+ return ret;
+}
+
+void mxr_base_layer_unregister(struct mxr_layer *layer)
+{
+ video_unregister_device(&layer->vfd);
+}
+
+void mxr_layer_release(struct mxr_layer *layer)
+{
+ if (layer->ops.release)
+ layer->ops.release(layer);
+}
+
+void mxr_base_layer_release(struct mxr_layer *layer)
+{
+ kfree(layer->vb_queue.name);
+ kfree(layer);
+}
+
+static void mxr_vfd_release(struct video_device *vdev)
+{
+ printk(KERN_INFO "video device release\n");
+}
+
+struct mxr_layer *mxr_base_layer_create(struct mxr_device *mdev,
+ int idx, char *name, struct mxr_layer_ops *ops)
+{
+ struct mxr_layer *layer;
+ int ret;
+
+ layer = kzalloc(sizeof *layer, GFP_KERNEL);
+ if (layer == NULL) {
+ mxr_err(mdev, "not enough memory for layer.\n");
+ goto fail;
+ }
+
+ layer->mdev = mdev;
+ layer->idx = idx;
+ layer->ops = *ops;
+ layer->prio = idx + 2;
+
+ spin_lock_init(&layer->enq_slock);
+ INIT_LIST_HEAD(&layer->enq_list);
+ INIT_LIST_HEAD(&layer->fence_wait_list);
+ mutex_init(&layer->mutex);
+ INIT_WORK(&layer->fence_work, fence_work);
+
+ layer->fence_wq = create_singlethread_workqueue(name);
+ if (layer->fence_wq == NULL) {
+ mxr_err(mdev, "failed to create work queue\n");
+ goto fail_alloc;
+ }
+
+ layer->vfd = (struct video_device) {
+ .minor = -1,
+ .release = mxr_vfd_release,
+ .fops = &mxr_fops,
+ .ioctl_ops = &mxr_ioctl_ops,
+ };
+
+ /* media_entity_init must be called after initializing layer->vfd
+ * for preventing to overwrite
+ */
+ ret = media_entity_init(&layer->vfd.entity, 1, &layer->pad, 0);
+ if (ret) {
+ mxr_err(mdev, "media entity init failed\n");
+ goto fail_alloc;
+ }
+
+ strlcpy(layer->vfd.name, name, sizeof(layer->vfd.name));
+ layer->vfd.entity.name = layer->vfd.name;
+ /* let framework control PRIORITY */
+ set_bit(V4L2_FL_USE_FH_PRIO, &layer->vfd.flags);
+
+ video_set_drvdata(&layer->vfd, layer);
+ layer->vfd.lock = &layer->mutex;
+
+ layer->vb_queue = (struct vb2_queue) {
+ .name = kstrdup(name, GFP_KERNEL),
+ .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
+ .io_modes = VB2_MMAP | VB2_DMABUF,
+ .drv_priv = layer,
+ .buf_struct_size = sizeof(struct mxr_buffer),
+ .ops = &mxr_video_qops,
+ .mem_ops = mdev->vb2->ops,
+ };
+
+ return layer;
+
+fail_alloc:
+ if (layer->fence_wq)
+ destroy_workqueue(layer->fence_wq);
+ kfree(layer);
+
+fail:
+ return NULL;
+}
+
+const struct mxr_format *find_format_by_fourcc(
+ struct mxr_layer *layer, unsigned long fourcc)
+{
+ int i;
+
+ for (i = 0; i < layer->fmt_array_size; ++i)
+ if (layer->fmt_array[i]->fourcc == fourcc)
+ return layer->fmt_array[i];
+ return NULL;
+}
+
+static const struct mxr_format *find_format_by_index(
+ struct mxr_layer *layer, unsigned long index)
+{
+ if (index >= layer->fmt_array_size)
+ return NULL;
+ return layer->fmt_array[index];
+}
+
diff --git a/drivers/media/video/exynos/tv/mixer_video_layer.c b/drivers/media/video/exynos/tv/mixer_video_layer.c
new file mode 100644
index 0000000..f2f8921
--- /dev/null
+++ b/drivers/media/video/exynos/tv/mixer_video_layer.c
@@ -0,0 +1,89 @@
+/*
+ * Samsung TV Mixer driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * Tomasz Stanislawski, <t.stanislaws@samsung.com>
+ *
+ * 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 Foundiation. either version 2 of the License,
+ * or (at your option) any later version
+ */
+
+#include "mixer.h"
+
+#if defined(CONFIG_VIDEOBUF2_CMA_PHYS)
+#include <media/videobuf2-cma-phys.h>
+#elif defined(CONFIG_VIDEOBUF2_ION)
+#include <media/videobuf2-ion.h>
+#endif
+
+/* AUXILIARY CALLBACKS */
+
+static void mxr_video_layer_release(struct mxr_layer *layer)
+{
+ mxr_base_layer_release(layer);
+}
+
+static void mxr_video_stream_set(struct mxr_layer *layer, int en)
+{
+ mxr_reg_video_layer_stream(layer->mdev, layer->idx, en);
+}
+
+static void mxr_video_format_set(struct mxr_layer *layer)
+{
+ mxr_reg_video_geo(layer->mdev, layer->cur_mxr, layer->idx, &layer->geo);
+}
+
+static void mxr_video_fix_geometry(struct mxr_layer *layer)
+{
+ struct mxr_geometry *geo = &layer->geo;
+
+ mxr_dbg(layer->mdev, "%s start\n", __func__);
+ geo->dst.x_offset = clamp_val(geo->dst.x_offset, 0,
+ geo->dst.full_width - 1);
+ geo->dst.y_offset = clamp_val(geo->dst.y_offset, 0,
+ geo->dst.full_height - 1);
+
+ /* mixer scale-up is unuseful. so no use it */
+ geo->dst.width = clamp_val(geo->dst.width, 1,
+ geo->dst.full_width - geo->dst.x_offset);
+ geo->dst.height = clamp_val(geo->dst.height, 1,
+ geo->dst.full_height - geo->dst.y_offset);
+}
+
+/* PUBLIC API */
+
+struct mxr_layer *mxr_video_layer_create(struct mxr_device *mdev, int cur_mxr,
+ int idx)
+{
+ struct mxr_layer *layer;
+ struct mxr_layer_ops ops = {
+ .release = mxr_video_layer_release,
+ .stream_set = mxr_video_stream_set,
+ .format_set = mxr_video_format_set,
+ .fix_geometry = mxr_video_fix_geometry,
+ };
+
+ layer = kzalloc(sizeof *layer, GFP_KERNEL);
+ if (layer == NULL) {
+ mxr_err(mdev, "not enough memory for layer.\n");
+ goto fail;
+ }
+
+ layer->mdev = mdev;
+ layer->idx = idx;
+ layer->type = MXR_LAYER_TYPE_VIDEO;
+ layer->ops = ops;
+ layer->prio = 1;
+
+ layer->cur_mxr = cur_mxr;
+
+ mxr_layer_default_geo(layer);
+
+ return layer;
+
+fail:
+ return NULL;
+}
diff --git a/drivers/media/video/exynos/tv/mixer_vp_layer.c b/drivers/media/video/exynos/tv/mixer_vp_layer.c
new file mode 100644
index 0000000..65bdbbe
--- /dev/null
+++ b/drivers/media/video/exynos/tv/mixer_vp_layer.c
@@ -0,0 +1,221 @@
+/*
+ * Samsung TV Mixer driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * Tomasz Stanislawski, <t.stanislaws@samsung.com>
+ *
+ * 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 Foundiation. either version 2 of the License,
+ * or (at your option) any later version
+ */
+
+#include "mixer.h"
+
+#include "regs-vp.h"
+
+#if defined(CONFIG_VIDEOBUF2_CMA_PHYS)
+#include <media/videobuf2-cma-phys.h>
+#elif defined(CONFIG_VIDEOBUF2_ION)
+#include <media/videobuf2-ion.h>
+#endif
+
+/* FORMAT DEFINITIONS */
+static const struct mxr_format mxr_fmt_nv12 = {
+ .name = "NV12",
+ .fourcc = V4L2_PIX_FMT_NV12,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .num_planes = 2,
+ .plane = {
+ { .width = 1, .height = 1, .size = 1 },
+ { .width = 2, .height = 2, .size = 2 },
+ },
+ .num_subframes = 1,
+ .cookie = VP_MODE_NV12 | VP_MODE_MEM_LINEAR,
+};
+
+static const struct mxr_format mxr_fmt_nv21 = {
+ .name = "NV21",
+ .fourcc = V4L2_PIX_FMT_NV21,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .num_planes = 2,
+ .plane = {
+ { .width = 1, .height = 1, .size = 1 },
+ { .width = 2, .height = 2, .size = 2 },
+ },
+ .num_subframes = 1,
+ .cookie = VP_MODE_NV21 | VP_MODE_MEM_LINEAR,
+};
+
+static const struct mxr_format mxr_fmt_nv12m = {
+ .name = "NV12 (mplane)",
+ .fourcc = V4L2_PIX_FMT_NV12M,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .num_planes = 2,
+ .plane = {
+ { .width = 1, .height = 1, .size = 1 },
+ { .width = 2, .height = 2, .size = 2 },
+ },
+ .num_subframes = 2,
+ .plane2subframe = {0, 1},
+ .cookie = VP_MODE_NV12 | VP_MODE_MEM_LINEAR,
+};
+
+static const struct mxr_format mxr_fmt_nv12mt = {
+ .name = "NV12 tiled (mplane)",
+ .fourcc = V4L2_PIX_FMT_NV12MT,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .num_planes = 2,
+ .plane = {
+ { .width = 128, .height = 32, .size = 4096 },
+ { .width = 128, .height = 32, .size = 2048 },
+ },
+ .num_subframes = 2,
+ .plane2subframe = {0, 1},
+ .cookie = VP_MODE_NV12 | VP_MODE_MEM_TILED,
+};
+
+static const struct mxr_format *mxr_video_format[] = {
+ &mxr_fmt_nv12,
+ &mxr_fmt_nv21,
+ &mxr_fmt_nv12m,
+ &mxr_fmt_nv12mt,
+};
+
+/* AUXILIARY CALLBACKS */
+
+static void mxr_vp_layer_release(struct mxr_layer *layer)
+{
+ mxr_base_layer_unregister(layer);
+ mxr_base_layer_release(layer);
+}
+
+static void mxr_vp_buffer_set(struct mxr_layer *layer,
+ struct mxr_buffer *buf)
+{
+ struct mxr_device *mdev = layer->mdev;
+ dma_addr_t luma_addr[2] = {0, 0};
+ dma_addr_t chroma_addr[2] = {0, 0};
+
+ if (buf == NULL) {
+ mxr_reg_vp_buffer(mdev, luma_addr, chroma_addr);
+ return;
+ }
+
+ luma_addr[0] = mdev->vb2->plane_addr(&buf->vb, 0);
+ if (layer->fmt->num_subframes == 2) {
+ chroma_addr[0] = mdev->vb2->plane_addr(&buf->vb, 1);
+ } else {
+ /* FIXME: mxr_get_plane_size compute integer division,
+ * which is slow and should not be performed in interrupt */
+ chroma_addr[0] = luma_addr[0] + mxr_get_plane_size(
+ &layer->fmt->plane[0], layer->geo.src.full_width,
+ layer->geo.src.full_height);
+ }
+ if (layer->fmt->cookie & VP_MODE_MEM_TILED) {
+ luma_addr[1] = luma_addr[0] + 0x40;
+ chroma_addr[1] = chroma_addr[0] + 0x40;
+ } else {
+ luma_addr[1] = luma_addr[0] + layer->geo.src.full_width;
+ chroma_addr[1] = chroma_addr[0];
+ }
+ mxr_reg_vp_buffer(layer->mdev, luma_addr, chroma_addr);
+}
+
+static void mxr_vp_stream_set(struct mxr_layer *layer, int en)
+{
+ mxr_reg_vp_layer_stream(layer->mdev, en);
+}
+
+static void mxr_vp_format_set(struct mxr_layer *layer)
+{
+ mxr_reg_vp_format(layer->mdev, layer->fmt, &layer->geo);
+}
+
+static void mxr_vp_fix_geometry(struct mxr_layer *layer)
+{
+ struct mxr_geometry *geo = &layer->geo;
+
+ mxr_dbg(layer->mdev, "%s start\n", __func__);
+ /* align horizontal size to 8 pixels */
+ geo->src.full_width = ALIGN(geo->src.full_width, 8);
+ /* limit to boundary size */
+ geo->src.full_width = clamp_val(geo->src.full_width, 8, 8192);
+ geo->src.full_height = clamp_val(geo->src.full_height, 1, 8192);
+ geo->src.width = clamp_val(geo->src.width, 32, geo->src.full_width);
+ geo->src.width = min(geo->src.width, 2047U);
+ geo->src.height = clamp_val(geo->src.height, 4, geo->src.full_height);
+ geo->src.height = min(geo->src.height, 2047U);
+
+ /* setting size of output window */
+ geo->dst.width = clamp_val(geo->dst.width, 8, geo->dst.full_width);
+ geo->dst.height = clamp_val(geo->dst.height, 1, geo->dst.full_height);
+
+ /* ensure that scaling is in range 1/4x to 16x */
+ if (geo->src.width >= 4 * geo->dst.width)
+ geo->src.width = 4 * geo->dst.width;
+ if (geo->dst.width >= 16 * geo->src.width)
+ geo->dst.width = 16 * geo->src.width;
+ if (geo->src.height >= 4 * geo->dst.height)
+ geo->src.height = 4 * geo->dst.height;
+ if (geo->dst.height >= 16 * geo->src.height)
+ geo->dst.height = 16 * geo->src.height;
+
+ /* setting scaling ratio */
+ geo->x_ratio = (geo->src.width << 16) / geo->dst.width;
+ geo->y_ratio = (geo->src.height << 16) / geo->dst.height;
+
+ /* adjust offsets */
+ geo->src.x_offset = min(geo->src.x_offset,
+ geo->src.full_width - geo->src.width);
+ geo->src.y_offset = min(geo->src.y_offset,
+ geo->src.full_height - geo->src.height);
+ geo->dst.x_offset = min(geo->dst.x_offset,
+ geo->dst.full_width - geo->dst.width);
+ geo->dst.y_offset = min(geo->dst.y_offset,
+ geo->dst.full_height - geo->dst.height);
+}
+
+/* PUBLIC API */
+
+struct mxr_layer *mxr_vp_layer_create(struct mxr_device *mdev, int cur_mxr,
+ int idx, int nr)
+{
+ struct mxr_layer *layer;
+ int ret;
+ struct mxr_layer_ops ops = {
+ .release = mxr_vp_layer_release,
+ .buffer_set = mxr_vp_buffer_set,
+ .stream_set = mxr_vp_stream_set,
+ .format_set = mxr_vp_format_set,
+ .fix_geometry = mxr_vp_fix_geometry,
+ };
+ char name[32];
+
+ sprintf(name, "mxr%d_video%d", cur_mxr, idx);
+
+ layer = mxr_base_layer_create(mdev, idx, name, &ops);
+ if (layer == NULL) {
+ mxr_err(mdev, "failed to initialize layer(%d) base\n", idx);
+ goto fail;
+ }
+
+ layer->fmt_array = mxr_video_format;
+ layer->fmt_array_size = ARRAY_SIZE(mxr_video_format);
+ layer->minor = nr;
+ layer->type = MXR_LAYER_TYPE_VIDEO;
+
+ ret = mxr_base_layer_register(layer);
+ if (ret)
+ goto fail_layer;
+
+ layer->cur_mxr = cur_mxr;
+ return layer;
+
+fail_layer:
+ mxr_base_layer_release(layer);
+
+fail:
+ return NULL;
+}
diff --git a/drivers/media/video/exynos/tv/regs-hdmi-4210.h b/drivers/media/video/exynos/tv/regs-hdmi-4210.h
new file mode 100644
index 0000000..74c36d7
--- /dev/null
+++ b/drivers/media/video/exynos/tv/regs-hdmi-4210.h
@@ -0,0 +1,142 @@
+/* linux/arch/arm/mach-exynos4/include/mach/regs-hdmi.h
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * HDMI register header file for Samsung TVOUT driver
+ *
+ * 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.
+*/
+
+#ifndef SAMSUNG_REGS_HDMI_H
+#define SAMSUNG_REGS_HDMI_H
+
+/*
+ * Register part
+*/
+
+#define HDMI_CTRL_BASE(x) ((x) + 0x00000000)
+#define HDMI_CORE_BASE(x) ((x) + 0x00010000)
+#define HDMI_TG_BASE(x) ((x) + 0x00050000)
+
+/* Control registers */
+#define HDMI_INTC_CON HDMI_CTRL_BASE(0x0000)
+#define HDMI_INTC_FLAG HDMI_CTRL_BASE(0x0004)
+#define HDMI_HPD_STATUS HDMI_CTRL_BASE(0x000C)
+#define HDMI_PHY_RSTOUT HDMI_CTRL_BASE(0x0014)
+#define HDMI_PHY_VPLL HDMI_CTRL_BASE(0x0018)
+#define HDMI_PHY_CMU HDMI_CTRL_BASE(0x001C)
+#define HDMI_CORE_RSTOUT HDMI_CTRL_BASE(0x0020)
+
+/* Core registers */
+#define HDMI_CON_0 HDMI_CORE_BASE(0x0000)
+#define HDMI_CON_1 HDMI_CORE_BASE(0x0004)
+#define HDMI_CON_2 HDMI_CORE_BASE(0x0008)
+#define HDMI_SYS_STATUS HDMI_CORE_BASE(0x0010)
+#define HDMI_PHY_STATUS HDMI_CORE_BASE(0x0014)
+#define HDMI_STATUS_EN HDMI_CORE_BASE(0x0020)
+#define HDMI_HPD HDMI_CORE_BASE(0x0030)
+#define HDMI_MODE_SEL HDMI_CORE_BASE(0x0040)
+#define HDMI_BLUE_SCREEN_0 HDMI_CORE_BASE(0x0050)
+#define HDMI_BLUE_SCREEN_1 HDMI_CORE_BASE(0x0054)
+#define HDMI_BLUE_SCREEN_2 HDMI_CORE_BASE(0x0058)
+#define HDMI_H_BLANK_0 HDMI_CORE_BASE(0x00A0)
+#define HDMI_H_BLANK_1 HDMI_CORE_BASE(0x00A4)
+#define HDMI_V_BLANK_0 HDMI_CORE_BASE(0x00B0)
+#define HDMI_V_BLANK_1 HDMI_CORE_BASE(0x00B4)
+#define HDMI_V_BLANK_2 HDMI_CORE_BASE(0x00B8)
+#define HDMI_H_V_LINE_0 HDMI_CORE_BASE(0x00C0)
+#define HDMI_H_V_LINE_1 HDMI_CORE_BASE(0x00C4)
+#define HDMI_H_V_LINE_2 HDMI_CORE_BASE(0x00C8)
+#define HDMI_VSYNC_POL HDMI_CORE_BASE(0x00E4)
+#define HDMI_INT_PRO_MODE HDMI_CORE_BASE(0x00E8)
+#define HDMI_V_BLANK_F_0 HDMI_CORE_BASE(0x0110)
+#define HDMI_V_BLANK_F_1 HDMI_CORE_BASE(0x0114)
+#define HDMI_V_BLANK_F_2 HDMI_CORE_BASE(0x0118)
+#define HDMI_H_SYNC_GEN_0 HDMI_CORE_BASE(0x0120)
+#define HDMI_H_SYNC_GEN_1 HDMI_CORE_BASE(0x0124)
+#define HDMI_H_SYNC_GEN_2 HDMI_CORE_BASE(0x0128)
+#define HDMI_V_SYNC_GEN_1_0 HDMI_CORE_BASE(0x0130)
+#define HDMI_V_SYNC_GEN_1_1 HDMI_CORE_BASE(0x0134)
+#define HDMI_V_SYNC_GEN_1_2 HDMI_CORE_BASE(0x0138)
+#define HDMI_V_SYNC_GEN_2_0 HDMI_CORE_BASE(0x0140)
+#define HDMI_V_SYNC_GEN_2_1 HDMI_CORE_BASE(0x0144)
+#define HDMI_V_SYNC_GEN_2_2 HDMI_CORE_BASE(0x0148)
+#define HDMI_V_SYNC_GEN_3_0 HDMI_CORE_BASE(0x0150)
+#define HDMI_V_SYNC_GEN_3_1 HDMI_CORE_BASE(0x0154)
+#define HDMI_V_SYNC_GEN_3_2 HDMI_CORE_BASE(0x0158)
+#define HDMI_AVI_CON HDMI_CORE_BASE(0x0300)
+#define HDMI_AVI_BYTE(n) HDMI_CORE_BASE(0x0320 + 4 * (n))
+#define HDMI_DC_CONTROL HDMI_CORE_BASE(0x05C0)
+#define HDMI_VIDEO_PATTERN_GEN HDMI_CORE_BASE(0x05C4)
+#define HDMI_HPD_GEN HDMI_CORE_BASE(0x05C8)
+
+/* Timing generator registers */
+#define HDMI_TG_CMD HDMI_TG_BASE(0x0000)
+#define HDMI_TG_H_FSZ_L HDMI_TG_BASE(0x0018)
+#define HDMI_TG_H_FSZ_H HDMI_TG_BASE(0x001C)
+#define HDMI_TG_HACT_ST_L HDMI_TG_BASE(0x0020)
+#define HDMI_TG_HACT_ST_H HDMI_TG_BASE(0x0024)
+#define HDMI_TG_HACT_SZ_L HDMI_TG_BASE(0x0028)
+#define HDMI_TG_HACT_SZ_H HDMI_TG_BASE(0x002C)
+#define HDMI_TG_V_FSZ_L HDMI_TG_BASE(0x0030)
+#define HDMI_TG_V_FSZ_H HDMI_TG_BASE(0x0034)
+#define HDMI_TG_VSYNC_L HDMI_TG_BASE(0x0038)
+#define HDMI_TG_VSYNC_H HDMI_TG_BASE(0x003C)
+#define HDMI_TG_VSYNC2_L HDMI_TG_BASE(0x0040)
+#define HDMI_TG_VSYNC2_H HDMI_TG_BASE(0x0044)
+#define HDMI_TG_VACT_ST_L HDMI_TG_BASE(0x0048)
+#define HDMI_TG_VACT_ST_H HDMI_TG_BASE(0x004C)
+#define HDMI_TG_VACT_SZ_L HDMI_TG_BASE(0x0050)
+#define HDMI_TG_VACT_SZ_H HDMI_TG_BASE(0x0054)
+#define HDMI_TG_FIELD_CHG_L HDMI_TG_BASE(0x0058)
+#define HDMI_TG_FIELD_CHG_H HDMI_TG_BASE(0x005C)
+#define HDMI_TG_VACT_ST2_L HDMI_TG_BASE(0x0060)
+#define HDMI_TG_VACT_ST2_H HDMI_TG_BASE(0x0064)
+#define HDMI_TG_VSYNC_TOP_HDMI_L HDMI_TG_BASE(0x0078)
+#define HDMI_TG_VSYNC_TOP_HDMI_H HDMI_TG_BASE(0x007C)
+#define HDMI_TG_VSYNC_BOT_HDMI_L HDMI_TG_BASE(0x0080)
+#define HDMI_TG_VSYNC_BOT_HDMI_H HDMI_TG_BASE(0x0084)
+#define HDMI_TG_FIELD_TOP_HDMI_L HDMI_TG_BASE(0x0088)
+#define HDMI_TG_FIELD_TOP_HDMI_H HDMI_TG_BASE(0x008C)
+#define HDMI_TG_FIELD_BOT_HDMI_L HDMI_TG_BASE(0x0090)
+#define HDMI_TG_FIELD_BOT_HDMI_H HDMI_TG_BASE(0x0094)
+
+/*
+ * Bit definition part
+ */
+
+/* HDMI_INTC_CON */
+#define HDMI_INTC_EN_GLOBAL (1 << 6)
+#define HDMI_INTC_EN_HPD_PLUG (1 << 3)
+#define HDMI_INTC_EN_HPD_UNPLUG (1 << 2)
+
+/* HDMI_INTC_FLAG */
+#define HDMI_INTC_FLAG_HPD_PLUG (1 << 3)
+#define HDMI_INTC_FLAG_HPD_UNPLUG (1 << 2)
+
+/* HDMI_PHY_RSTOUT */
+#define HDMI_PHY_SW_RSTOUT (1 << 0)
+
+/* HDMI_CORE_RSTOUT */
+#define HDMI_CORE_SW_RSTOUT (1 << 0)
+
+/* HDMI_CON_0 */
+#define HDMI_BLUE_SCR_EN (1 << 5)
+#define HDMI_EN (1 << 0)
+
+/* HDMI_PHY_STATUS */
+#define HDMI_PHY_STATUS_READY (1 << 0)
+
+/* HDMI_MODE_SEL */
+#define HDMI_MODE_HDMI_EN (1 << 1)
+#define HDMI_MODE_DVI_EN (1 << 0)
+#define HDMI_MODE_MASK (3 << 0)
+
+/* HDMI_TG_CMD */
+#define HDMI_FIELD_EN (1 << 1)
+#define HDMI_TG_EN (1 << 0)
+
+#endif /* SAMSUNG_REGS_HDMI_H */
diff --git a/drivers/media/video/exynos/tv/regs-hdmi-5250.h b/drivers/media/video/exynos/tv/regs-hdmi-5250.h
new file mode 100644
index 0000000..140ec96
--- /dev/null
+++ b/drivers/media/video/exynos/tv/regs-hdmi-5250.h
@@ -0,0 +1,1276 @@
+/* linux/arch/arm/mach-exynos4/include/mach/regs-hdmi_14.h
+ *
+ * Copyright (c) 2010 Samsung Electronics
+ * http://www.samsung.com/
+ *
+ * HDMI register header file for Samsung TVOUT driver
+ *
+ * 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.
+*/
+
+#ifndef __ARCH_ARM_REGS_HDMI_H
+#define __ARCH_ARM_REGS_HDMI_H
+
+/*
+ * Register part
+*/
+
+#define S5P_HDMI_I2C_PHY_BASE(x) (x)
+
+#define HDMI_I2C_CON S5P_HDMI_I2C_PHY_BASE(0x0000)
+#define HDMI_I2C_STAT S5P_HDMI_I2C_PHY_BASE(0x0004)
+#define HDMI_I2C_ADD S5P_HDMI_I2C_PHY_BASE(0x0008)
+#define HDMI_I2C_DS S5P_HDMI_I2C_PHY_BASE(0x000c)
+#define HDMI_I2C_LC S5P_HDMI_I2C_PHY_BASE(0x0010)
+
+#define HDMI_CTRL_BASE(x) ((x) + 0x00000000)
+#define HDMI_CORE_BASE(x) ((x) + 0x00010000)
+#define HDMI_SPDIF_BASE(x) ((x) + 0x00030000)
+#define HDMI_I2S_BASE(x) ((x) + 0x00040000)
+#define HDMI_TG_BASE(x) ((x) + 0x00050000)
+#define HDMI_EFUSE_BASE(x) ((x) + 0x00060000)
+
+/* Control registers */
+#define HDMI_INTC_CON_0 HDMI_CTRL_BASE(0x0000)
+#define HDMI_INTC_FLAG_0 HDMI_CTRL_BASE(0x0004)
+#define HDMI_HDCP_KEY_LOAD HDMI_CTRL_BASE(0x0008)
+#define HDMI_HPD_STATUS HDMI_CTRL_BASE(0x000C)
+
+#define HDMI_INTC_CON_1 HDMI_CTRL_BASE(0x0010)
+#define HDMI_INTC_FLAG_1 HDMI_CTRL_BASE(0x0014)
+#define HDMI_PHY_STATUS_0 HDMI_CTRL_BASE(0x0020)
+#define HDMI_PHY_STATUS_PLL HDMI_CTRL_BASE(0x0028)
+#define HDMI_PHY_CON_0 HDMI_CTRL_BASE(0x0030)
+
+#define HDMI_HPD_CTRL HDMI_CTRL_BASE(0x0040)
+#define HDMI_HPD_TH_(n) HDMI_CTRL_BASE(0x0050 + 4 * (n))
+
+#define HDMI_AUDIO_CLKSEL HDMI_CTRL_BASE(0x0070)
+#define HDMI_PHY_RSTOUT HDMI_CTRL_BASE(0x0074)
+#define HDMI_PHY_VPLL HDMI_CTRL_BASE(0x0078)
+#define HDMI_PHY_CMU HDMI_CTRL_BASE(0x007C)
+#define HDMI_CORE_RSTOUT HDMI_CTRL_BASE(0x080)
+
+/* HDMI core registers */
+#define HDMI_CON_0 HDMI_CORE_BASE(0x000)
+#define HDMI_CON_1 HDMI_CORE_BASE(0x004)
+#define HDMI_CON_2 HDMI_CORE_BASE(0x008)
+#define HDMI_SIM_MODE HDMI_CORE_BASE(0x00C)
+#define HDMI_STATUS HDMI_CORE_BASE(0x010)
+#define HDMI_PHY_STATUS HDMI_CORE_BASE(0x014)
+#define HDMI_STATUS_EN HDMI_CORE_BASE(0x020)
+#define HDMI_HPD HDMI_CORE_BASE(0x030)
+#define HDMI_MODE_SEL HDMI_CORE_BASE(0x040)
+#define HDMI_ENC_EN HDMI_CORE_BASE(0x044)
+
+/* Video related registers */
+#define HDMI_YMAX HDMI_CORE_BASE(0x060)
+#define HDMI_YMIN HDMI_CORE_BASE(0x064)
+#define HDMI_CMAX HDMI_CORE_BASE(0x068)
+#define HDMI_CMIN HDMI_CORE_BASE(0x06c)
+
+#define HDMI_DI_PREFIX HDMI_CORE_BASE(0x078)
+#define HDMI_VBI_ST_MG HDMI_CORE_BASE(0x080)
+#define HDMI_END_MG HDMI_CORE_BASE(0x084)
+
+#define HDMI_AUTH_ST_MG0 HDMI_CORE_BASE(0x090)
+#define HDMI_AUTH_ST_MG1 HDMI_CORE_BASE(0x094)
+#define HDMI_AUTH_END_MG0 HDMI_CORE_BASE(0x098)
+#define HDMI_AUTH_END_MG1 HDMI_CORE_BASE(0x09C)
+
+#define HDMI_H_BLANK_0 HDMI_CORE_BASE(0x0a0)
+#define HDMI_H_BLANK_1 HDMI_CORE_BASE(0x0a4)
+
+#define HDMI_V2_BLANK_0 HDMI_CORE_BASE(0x0b0)
+#define HDMI_V2_BLANK_1 HDMI_CORE_BASE(0x0b4)
+#define HDMI_V1_BLANK_0 HDMI_CORE_BASE(0x0b8)
+#define HDMI_V1_BLANK_1 HDMI_CORE_BASE(0x0bC)
+
+#define HDMI_V_LINE_0 HDMI_CORE_BASE(0x0c0)
+#define HDMI_V_LINE_1 HDMI_CORE_BASE(0x0c4)
+#define HDMI_H_LINE_0 HDMI_CORE_BASE(0x0c8)
+#define HDMI_H_LINE_1 HDMI_CORE_BASE(0x0cC)
+#define HDMI_HSYNC_POL HDMI_CORE_BASE(0x0E0)
+
+#define HDMI_VSYNC_POL HDMI_CORE_BASE(0x0e4)
+#define HDMI_INT_PRO_MODE HDMI_CORE_BASE(0x0e8)
+
+#define HDMI_V_BLANK_F0_0 HDMI_CORE_BASE(0x110)
+#define HDMI_V_BLANK_F0_1 HDMI_CORE_BASE(0x114)
+#define HDMI_V_BLANK_F1_0 HDMI_CORE_BASE(0x118)
+#define HDMI_V_BLANK_F1_1 HDMI_CORE_BASE(0x11C)
+
+#define HDMI_H_SYNC_START_0 HDMI_CORE_BASE(0x120)
+#define HDMI_H_SYNC_START_1 HDMI_CORE_BASE(0x124)
+#define HDMI_H_SYNC_END_0 HDMI_CORE_BASE(0x128)
+#define HDMI_H_SYNC_END_1 HDMI_CORE_BASE(0x12C)
+
+#define HDMI_V_SYNC_LINE_BEF_2_0 HDMI_CORE_BASE(0x130)
+#define HDMI_V_SYNC_LINE_BEF_2_1 HDMI_CORE_BASE(0x134)
+#define HDMI_V_SYNC_LINE_BEF_1_0 HDMI_CORE_BASE(0x138)
+#define HDMI_V_SYNC_LINE_BEF_1_1 HDMI_CORE_BASE(0x13C)
+
+#define HDMI_V_SYNC_LINE_AFT_2_0 HDMI_CORE_BASE(0x140)
+#define HDMI_V_SYNC_LINE_AFT_2_1 HDMI_CORE_BASE(0x144)
+#define HDMI_V_SYNC_LINE_AFT_1_0 HDMI_CORE_BASE(0x148)
+#define HDMI_V_SYNC_LINE_AFT_1_1 HDMI_CORE_BASE(0x14C)
+
+#define HDMI_V_SYNC_LINE_AFT_PXL_2_0 HDMI_CORE_BASE(0x150)
+#define HDMI_V_SYNC_LINE_AFT_PXL_2_1 HDMI_CORE_BASE(0x154)
+#define HDMI_V_SYNC_LINE_AFT_PXL_1_0 HDMI_CORE_BASE(0x158)
+#define HDMI_V_SYNC_LINE_AFT_PXL_1_1 HDMI_CORE_BASE(0x15C)
+
+#define HDMI_V_BLANK_F2_0 HDMI_CORE_BASE(0x160)
+#define HDMI_V_BLANK_F2_1 HDMI_CORE_BASE(0x164)
+#define HDMI_V_BLANK_F3_0 HDMI_CORE_BASE(0x168)
+#define HDMI_V_BLANK_F3_1 HDMI_CORE_BASE(0x16C)
+#define HDMI_V_BLANK_F4_0 HDMI_CORE_BASE(0x170)
+#define HDMI_V_BLANK_F4_1 HDMI_CORE_BASE(0x174)
+#define HDMI_V_BLANK_F5_0 HDMI_CORE_BASE(0x178)
+#define HDMI_V_BLANK_F5_1 HDMI_CORE_BASE(0x17C)
+
+#define HDMI_V_SYNC_LINE_AFT_3_0 HDMI_CORE_BASE(0x180)
+#define HDMI_V_SYNC_LINE_AFT_3_1 HDMI_CORE_BASE(0x184)
+#define HDMI_V_SYNC_LINE_AFT_4_0 HDMI_CORE_BASE(0x188)
+#define HDMI_V_SYNC_LINE_AFT_4_1 HDMI_CORE_BASE(0x18C)
+#define HDMI_V_SYNC_LINE_AFT_5_0 HDMI_CORE_BASE(0x190)
+#define HDMI_V_SYNC_LINE_AFT_5_1 HDMI_CORE_BASE(0x194)
+#define HDMI_V_SYNC_LINE_AFT_6_0 HDMI_CORE_BASE(0x198)
+#define HDMI_V_SYNC_LINE_AFT_6_1 HDMI_CORE_BASE(0x19C)
+
+#define HDMI_V_SYNC_LINE_AFT_PXL_3_0 HDMI_CORE_BASE(0x1A0)
+#define HDMI_V_SYNC_LINE_AFT_PXL_3_1 HDMI_CORE_BASE(0x1A4)
+#define HDMI_V_SYNC_LINE_AFT_PXL_4_0 HDMI_CORE_BASE(0x1A8)
+#define HDMI_V_SYNC_LINE_AFT_PXL_4_1 HDMI_CORE_BASE(0x1AC)
+#define HDMI_V_SYNC_LINE_AFT_PXL_5_0 HDMI_CORE_BASE(0x1B0)
+#define HDMI_V_SYNC_LINE_AFT_PXL_5_1 HDMI_CORE_BASE(0x1B4)
+#define HDMI_V_SYNC_LINE_AFT_PXL_6_0 HDMI_CORE_BASE(0x1B8)
+#define HDMI_V_SYNC_LINE_AFT_PXL_6_1 HDMI_CORE_BASE(0x1BC)
+
+#define HDMI_VACT_SPACE_1_0 HDMI_CORE_BASE(0x1C0)
+#define HDMI_VACT_SPACE_1_1 HDMI_CORE_BASE(0x1C4)
+#define HDMI_VACT_SPACE_2_0 HDMI_CORE_BASE(0x1C8)
+#define HDMI_VACT_SPACE_2_1 HDMI_CORE_BASE(0x1CC)
+#define HDMI_VACT_SPACE_3_0 HDMI_CORE_BASE(0x1D0)
+#define HDMI_VACT_SPACE_3_1 HDMI_CORE_BASE(0x1D4)
+#define HDMI_VACT_SPACE_4_0 HDMI_CORE_BASE(0x1D8)
+#define HDMI_VACT_SPACE_4_1 HDMI_CORE_BASE(0x1DC)
+#define HDMI_VACT_SPACE_5_0 HDMI_CORE_BASE(0x1E0)
+#define HDMI_VACT_SPACE_5_1 HDMI_CORE_BASE(0x1E4)
+#define HDMI_VACT_SPACE_6_0 HDMI_CORE_BASE(0x1E8)
+#define HDMI_VACT_SPACE_6_1 HDMI_CORE_BASE(0x1EC)
+#define HDMI_CSC_MUX HDMI_CORE_BASE(0x1F0)
+#define HDMI_SYNC_GEN_MUX HDMI_CORE_BASE(0x1F4)
+
+#define HDMI_GCP_CON HDMI_CORE_BASE(0x200)
+#define HDMI_GCP_CON_EX HDMI_CORE_BASE(0x204)
+#define HDMI_GCP_BYTE1 HDMI_CORE_BASE(0x210)
+#define HDMI_GCP_BYTE2 HDMI_CORE_BASE(0x214)
+#define HDMI_GCP_BYTE3 HDMI_CORE_BASE(0x218)
+
+/* Audio related registers */
+#define HDMI_ASP_CON HDMI_CORE_BASE(0x300)
+#define HDMI_ASP_SP_FLAT HDMI_CORE_BASE(0x304)
+#define HDMI_ASP_CHCFG0 HDMI_CORE_BASE(0x310)
+#define HDMI_ASP_CHCFG1 HDMI_CORE_BASE(0x314)
+#define HDMI_ASP_CHCFG2 HDMI_CORE_BASE(0x318)
+#define HDMI_ASP_CHCFG3 HDMI_CORE_BASE(0x31c)
+
+#define HDMI_ACR_CON HDMI_CORE_BASE(0x400)
+#define HDMI_ACR_MCTS0 HDMI_CORE_BASE(0x410)
+#define HDMI_ACR_MCTS1 HDMI_CORE_BASE(0x414)
+#define HDMI_ACR_MCTS2 HDMI_CORE_BASE(0x418)
+#define HDMI_ACR_CTS0 HDMI_CORE_BASE(0x420)
+#define HDMI_ACR_CTS1 HDMI_CORE_BASE(0x424)
+#define HDMI_ACR_CTS2 HDMI_CORE_BASE(0x428)
+#define HDMI_ACR_N0 HDMI_CORE_BASE(0x430)
+#define HDMI_ACR_N1 HDMI_CORE_BASE(0x434)
+#define HDMI_ACR_N2 HDMI_CORE_BASE(0x438)
+#define HDMI_ACR_LSB2 HDMI_CORE_BASE(0x440)
+#define HDMI_ACR_TXCNT HDMI_CORE_BASE(0x444)
+#define HDMI_ACR_TXINTERNAL HDMI_CORE_BASE(0x448)
+#define HDMI_ACR_CTS_OFFSET HDMI_CORE_BASE(0x44c)
+
+#define HDMI_ACP_CON HDMI_CORE_BASE(0x500)
+#define HDMI_ACP_TYPE HDMI_CORE_BASE(0x514)
+/* offset of HDMI_ACP_DATA00 ~ 16 : 0x0520 ~ 0x0560 */
+#define HDMI_ACP_DATA(n) HDMI_CORE_BASE(0x520 + 4 * (n))
+
+#define HDMI_ISRC_CON HDMI_CORE_BASE(0x600)
+#define HDMI_ISRC1_HEADER1 HDMI_CORE_BASE(0x614)
+/* offset of HDMI_ISRC1_DATA00 ~ 15 : 0x0620 ~ 0x065C */
+#define HDMI_ISRC1_DATA(n) HDMI_CORE_BASE(0x620 + 4 * (n))
+/* offset of HDMI_ISRC2_DATA00 ~ 15 : 0x06A0 ~ 0x06DC */
+#define HDMI_ISRC2_DATA(n) HDMI_CORE_BASE(0x6A0 + 4 * (n))
+
+#define HDMI_AVI_CON HDMI_CORE_BASE(0x700)
+#define HDMI_AVI_HEADER0 HDMI_CORE_BASE(0x710)
+#define HDMI_AVI_HEADER1 HDMI_CORE_BASE(0x714)
+#define HDMI_AVI_HEADER2 HDMI_CORE_BASE(0x718)
+#define HDMI_AVI_CHECK_SUM HDMI_CORE_BASE(0x71C)
+/* offset of HDMI_AVI_BYTE1 ~ 13 : 0x0720 ~ 0x0750 */
+#define HDMI_AVI_BYTE(n) HDMI_CORE_BASE(0x720 + 4 * (n - 1))
+
+#define HDMI_AUI_CON HDMI_CORE_BASE(0x800)
+#define HDMI_AUI_HEADER0 HDMI_CORE_BASE(0x810)
+#define HDMI_AUI_HEADER1 HDMI_CORE_BASE(0x814)
+#define HDMI_AUI_HEADER2 HDMI_CORE_BASE(0x818)
+#define HDMI_AUI_CHECK_SUM HDMI_CORE_BASE(0x81C)
+/* offset of HDMI_AUI_BYTE1 ~ 12 : 0x0820 ~ 0x084C */
+#define HDMI_AUI_BYTE(n) HDMI_CORE_BASE(0x820 + 4 * (n - 1))
+
+#define HDMI_MPG_CON HDMI_CORE_BASE(0x900)
+#define HDMI_MPG_CHECK_SUM HDMI_CORE_BASE(0x91C)
+/* offset of HDMI_MPG_BYTE1 ~ 6 : 0x0920 ~ 0x0934 */
+#define HDMI_MPG_BYTE(n) HDMI_CORE_BASE(0x920 + 4 * (n - 1))
+
+#define HDMI_SPD_CON HDMI_CORE_BASE(0xA00)
+#define HDMI_SPD_HEADER0 HDMI_CORE_BASE(0xA10)
+#define HDMI_SPD_HEADER1 HDMI_CORE_BASE(0xA14)
+#define HDMI_SPD_HEADER2 HDMI_CORE_BASE(0xA18)
+/* offset of HDMI_SPD_DATA00 ~ 27 : 0x0A20 ~ 0x0A8C */
+#define HDMI_SPD_DATA0(n) HDMI_CORE_BASE(0xA20 + 4 * (n))
+
+#define HDMI_GAMUT_CON HDMI_CORE_BASE(0xB00)
+#define HDMI_GAMUT_HEADER0 HDMI_CORE_BASE(0xB10)
+#define HDMI_GAMUT_HEADER1 HDMI_CORE_BASE(0xB14)
+#define HDMI_GAMUT_HEADER2 HDMI_CORE_BASE(0xB18)
+/* offset of HDMI_GAMUT_METADATA00 ~ 27 : 0x0B20 ~ 0x0B8C */
+#define HDMI_GAMUT_METADATA(n) HDMI_CORE_BASE(0xB20 + 4 * (n))
+
+#define HDMI_VSI_CON HDMI_CORE_BASE(0xC00)
+#define HDMI_VSI_HEADER0 HDMI_CORE_BASE(0xC10)
+#define HDMI_VSI_HEADER1 HDMI_CORE_BASE(0xC14)
+#define HDMI_VSI_HEADER2 HDMI_CORE_BASE(0xC18)
+/* offset of HDMI_VSI_DATA00 ~ 27 : 0x0C20 ~ 0x0C8C */
+#define HDMI_VSI_DATA(n) HDMI_CORE_BASE(0xC20 + 4 * (n))
+
+#define HDMI_DC_CONTROL HDMI_CORE_BASE(0xD00)
+#define HDMI_VIDEO_PATTERN_GEN HDMI_CORE_BASE(0xD04)
+#define HDMI_HPD_GEN0 HDMI_CORE_BASE(0xD08)
+#define HDMI_HPD_GEN1 HDMI_CORE_BASE(0xD0C)
+#define HDMI_HPD_GEN2 HDMI_CORE_BASE(0xD10)
+#define HDMI_HPD_GEN3 HDMI_CORE_BASE(0xD14)
+
+#define HDMI_DIM_CON HDMI_CORE_BASE(0xD30)
+
+/* HDCP related registers */
+/* offset of HDMI_HDCP_SHA1_00 ~ 19 : 0x7000 ~ 0x704C */
+#define HDMI_HDCP_SHA1_(n) HDMI_CORE_BASE(0x7000 + 4 * (n))
+
+/* offset of HDMI_HDCP_KSV_LIST_0 ~ 4 : 0x7050 ~ 0x7060 */
+#define HDMI_HDCP_KSV_LIST_(n) HDMI_CORE_BASE(0x7050 + 4 * (n))
+
+#define HDMI_HDCP_KSV_LIST_CON HDMI_CORE_BASE(0x7064)
+#define HDMI_HDCP_SHA_RESULT HDMI_CORE_BASE(0x7070)
+#define HDMI_HDCP_CTRL1 HDMI_CORE_BASE(0x7080)
+#define HDMI_HDCP_CTRL2 HDMI_CORE_BASE(0x7084)
+#define HDMI_HDCP_CHECK_RESULT HDMI_CORE_BASE(0x7090)
+
+/* offset of HDMI_HDCP_BKSV_0 ~ 4 : 0x70A0 ~ 0x70B0 */
+#define HDMI_HDCP_BKSV_(n) HDMI_CORE_BASE(0x70A0 + 4 * (n))
+/* offset of HDMI_HDCP_AKSV_0 ~ 4 : 0x70C0 ~ 0x70D0 */
+#define HDMI_HDCP_AKSV_(n) HDMI_CORE_BASE(0x70C0 + 4 * (n))
+
+/* offset of HDMI_HDCP_AN_0 ~ 7 : 0x70E0 ~ 0x70FC */
+#define HDMI_HDCP_AN_(n) HDMI_CORE_BASE(0x70E0 + 4 * (n))
+
+#define HDMI_HDCP_BCAPS HDMI_CORE_BASE(0x7100)
+#define HDMI_HDCP_BSTATUS_0 HDMI_CORE_BASE(0x7110)
+#define HDMI_HDCP_BSTATUS_1 HDMI_CORE_BASE(0x7114)
+#define HDMI_HDCP_RI_0 HDMI_CORE_BASE(0x7140)
+#define HDMI_HDCP_RI_1 HDMI_CORE_BASE(0x7144)
+#define HDMI_HDCP_I2C_INT HDMI_CORE_BASE(0x7180)
+#define HDMI_HDCP_AN_INT HDMI_CORE_BASE(0x7190)
+#define HDMI_HDCP_WDT_INT HDMI_CORE_BASE(0x71a0)
+#define HDMI_HDCP_RI_INT HDMI_CORE_BASE(0x71b0)
+
+#define HDMI_HDCP_RI_COMPARE_0 HDMI_CORE_BASE(0x71d0)
+#define HDMI_HDCP_RI_COMPARE_1 HDMI_CORE_BASE(0x71d4)
+#define HDMI_HDCP_FRAME_COUNT HDMI_CORE_BASE(0x71e0)
+
+#define HDMI_RGB_ROUND_EN HDMI_CORE_BASE(0xD500)
+
+#define HDMI_VACT_SPACE_R_0 HDMI_CORE_BASE(0xD504)
+#define HDMI_VACT_SPACE_R_1 HDMI_CORE_BASE(0xD508)
+
+#define HDMI_VACT_SPACE_G_0 HDMI_CORE_BASE(0xD50C)
+#define HDMI_VACT_SPACE_G_1 HDMI_CORE_BASE(0xD510)
+
+#define HDMI_VACT_SPACE_B_0 HDMI_CORE_BASE(0xD514)
+#define HDMI_VACT_SPACE_B_1 HDMI_CORE_BASE(0xD518)
+
+#define HDMI_BLUE_SCREEN_B_0 HDMI_CORE_BASE(0xD520)
+#define HDMI_BLUE_SCREEN_B_1 HDMI_CORE_BASE(0xD524)
+#define HDMI_BLUE_SCREEN_G_0 HDMI_CORE_BASE(0xD528)
+#define HDMI_BLUE_SCREEN_G_1 HDMI_CORE_BASE(0xD52C)
+#define HDMI_BLUE_SCREEN_R_0 HDMI_CORE_BASE(0xD530)
+#define HDMI_BLUE_SCREEN_R_1 HDMI_CORE_BASE(0xD534)
+
+/* SPDIF registers */
+#define HDMI_SPDIFIN_CLK_CTRL HDMI_SPDIF_BASE(0x000)
+#define HDMI_SPDIFIN_OP_CTRL HDMI_SPDIF_BASE(0x004)
+#define HDMI_SPDIFIN_IRQ_MASK HDMI_SPDIF_BASE(0x008)
+#define HDMI_SPDIFIN_IRQ_STATUS HDMI_SPDIF_BASE(0x00c)
+#define HDMI_SPDIFIN_CONFIG_1 HDMI_SPDIF_BASE(0x010)
+#define HDMI_SPDIFIN_CONFIG_2 HDMI_SPDIF_BASE(0x014)
+#define HDMI_SPDIFIN_USER_VALUE_1 HDMI_SPDIF_BASE(0x020)
+#define HDMI_SPDIFIN_USER_VALUE_2 HDMI_SPDIF_BASE(0x024)
+#define HDMI_SPDIFIN_USER_VALUE_3 HDMI_SPDIF_BASE(0x028)
+#define HDMI_SPDIFIN_USER_VALUE_4 HDMI_SPDIF_BASE(0x02c)
+#define HDMI_SPDIFIN_CH_STATUS_0_1 HDMI_SPDIF_BASE(0x030)
+#define HDMI_SPDIFIN_CH_STATUS_0_2 HDMI_SPDIF_BASE(0x034)
+#define HDMI_SPDIFIN_CH_STATUS_0_3 HDMI_SPDIF_BASE(0x038)
+#define HDMI_SPDIFIN_CH_STATUS_0_4 HDMI_SPDIF_BASE(0x03c)
+#define HDMI_SPDIFIN_CH_STATUS_1 HDMI_SPDIF_BASE(0x040)
+#define HDMI_SPDIFIN_FRAME_PERIOD_1 HDMI_SPDIF_BASE(0x048)
+#define HDMI_SPDIFIN_FRAME_PERIOD_2 HDMI_SPDIF_BASE(0x04c)
+#define HDMI_SPDIFIN_PC_INFO_1 HDMI_SPDIF_BASE(0x050)
+#define HDMI_SPDIFIN_PC_INFO_2 HDMI_SPDIF_BASE(0x054)
+#define HDMI_SPDIFIN_PD_INFO_1 HDMI_SPDIF_BASE(0x058)
+#define HDMI_SPDIFIN_PD_INFO_2 HDMI_SPDIF_BASE(0x05c)
+#define HDMI_SPDIFIN_DATA_BUF_0_1 HDMI_SPDIF_BASE(0x060)
+#define HDMI_SPDIFIN_DATA_BUF_0_2 HDMI_SPDIF_BASE(0x064)
+#define HDMI_SPDIFIN_DATA_BUF_0_3 HDMI_SPDIF_BASE(0x068)
+#define HDMI_SPDIFIN_USER_BUF_0 HDMI_SPDIF_BASE(0x06c)
+#define HDMI_SPDIFIN_DATA_BUF_1_1 HDMI_SPDIF_BASE(0x070)
+#define HDMI_SPDIFIN_DATA_BUF_1_2 HDMI_SPDIF_BASE(0x074)
+#define HDMI_SPDIFIN_DATA_BUF_1_3 HDMI_SPDIF_BASE(0x078)
+#define HDMI_SPDIFIN_USER_BUF_1 HDMI_SPDIF_BASE(0x07c)
+
+/* I2S registers */
+#define HDMI_I2S_CLK_CON HDMI_I2S_BASE(0x000)
+#define HDMI_I2S_CON_1 HDMI_I2S_BASE(0x004)
+#define HDMI_I2S_CON_2 HDMI_I2S_BASE(0x008)
+#define HDMI_I2S_PIN_SEL_0 HDMI_I2S_BASE(0x00c)
+#define HDMI_I2S_PIN_SEL_1 HDMI_I2S_BASE(0x010)
+#define HDMI_I2S_PIN_SEL_2 HDMI_I2S_BASE(0x014)
+#define HDMI_I2S_PIN_SEL_3 HDMI_I2S_BASE(0x018)
+#define HDMI_I2S_DSD_CON HDMI_I2S_BASE(0x01c)
+#define HDMI_I2S_IN_MUX_CON HDMI_I2S_BASE(0x020)
+#define HDMI_I2S_CH_ST_CON HDMI_I2S_BASE(0x024)
+#define HDMI_I2S_CH_ST_0 HDMI_I2S_BASE(0x028)
+#define HDMI_I2S_CH_ST_1 HDMI_I2S_BASE(0x02c)
+#define HDMI_I2S_CH_ST_2 HDMI_I2S_BASE(0x030)
+#define HDMI_I2S_CH_ST_3 HDMI_I2S_BASE(0x034)
+#define HDMI_I2S_CH_ST_4 HDMI_I2S_BASE(0x038)
+#define HDMI_I2S_CH_ST_SH_0 HDMI_I2S_BASE(0x03c)
+#define HDMI_I2S_CH_ST_SH_1 HDMI_I2S_BASE(0x040)
+#define HDMI_I2S_CH_ST_SH_2 HDMI_I2S_BASE(0x044)
+#define HDMI_I2S_CH_ST_SH_3 HDMI_I2S_BASE(0x048)
+#define HDMI_I2S_CH_ST_SH_4 HDMI_I2S_BASE(0x04c)
+#define HDMI_I2S_VD_DATA HDMI_I2S_BASE(0x050)
+#define HDMI_I2S_MUX_CH HDMI_I2S_BASE(0x054)
+#define HDMI_I2S_MUX_CUV HDMI_I2S_BASE(0x058)
+#define HDMI_I2S_IRQ_MASK HDMI_I2S_BASE(0x05c)
+#define HDMI_I2S_IRQ_STATUS HDMI_I2S_BASE(0x060)
+
+#define HDMI_I2S_CH0_L_0 HDMI_I2S_BASE(0x0064)
+#define HDMI_I2S_CH0_L_1 HDMI_I2S_BASE(0x0068)
+#define HDMI_I2S_CH0_L_2 HDMI_I2S_BASE(0x006C)
+#define HDMI_I2S_CH0_L_3 HDMI_I2S_BASE(0x0070)
+#define HDMI_I2S_CH0_R_0 HDMI_I2S_BASE(0x0074)
+#define HDMI_I2S_CH0_R_1 HDMI_I2S_BASE(0x0078)
+#define HDMI_I2S_CH0_R_2 HDMI_I2S_BASE(0x007C)
+#define HDMI_I2S_CH0_R_3 HDMI_I2S_BASE(0x0080)
+#define HDMI_I2S_CH1_L_0 HDMI_I2S_BASE(0x0084)
+#define HDMI_I2S_CH1_L_1 HDMI_I2S_BASE(0x0088)
+#define HDMI_I2S_CH1_L_2 HDMI_I2S_BASE(0x008C)
+#define HDMI_I2S_CH1_L_3 HDMI_I2S_BASE(0x0090)
+#define HDMI_I2S_CH1_R_0 HDMI_I2S_BASE(0x0094)
+#define HDMI_I2S_CH1_R_1 HDMI_I2S_BASE(0x0098)
+#define HDMI_I2S_CH1_R_2 HDMI_I2S_BASE(0x009C)
+#define HDMI_I2S_CH1_R_3 HDMI_I2S_BASE(0x00A0)
+#define HDMI_I2S_CH2_L_0 HDMI_I2S_BASE(0x00A4)
+#define HDMI_I2S_CH2_L_1 HDMI_I2S_BASE(0x00A8)
+#define HDMI_I2S_CH2_L_2 HDMI_I2S_BASE(0x00AC)
+#define HDMI_I2S_CH2_L_3 HDMI_I2S_BASE(0x00B0)
+#define HDMI_I2S_CH2_R_0 HDMI_I2S_BASE(0x00B4)
+#define HDMI_I2S_CH2_R_1 HDMI_I2S_BASE(0x00B8)
+#define HDMI_I2S_CH2_R_2 HDMI_I2S_BASE(0x00BC)
+#define HDMI_I2S_Ch2_R_3 HDMI_I2S_BASE(0x00C0)
+#define HDMI_I2S_CH3_L_0 HDMI_I2S_BASE(0x00C4)
+#define HDMI_I2S_CH3_L_1 HDMI_I2S_BASE(0x00C8)
+#define HDMI_I2S_CH3_L_2 HDMI_I2S_BASE(0x00CC)
+#define HDMI_I2S_CH3_R_0 HDMI_I2S_BASE(0x00D0)
+#define HDMI_I2S_CH3_R_1 HDMI_I2S_BASE(0x00D4)
+#define HDMI_I2S_CH3_R_2 HDMI_I2S_BASE(0x00D8)
+#define HDMI_I2S_CUV_L_R HDMI_I2S_BASE(0x00DC)
+
+/* Timing Generator registers */
+#define HDMI_TG_CMD HDMI_TG_BASE(0x000)
+#define HDMI_TG_CFG HDMI_TG_BASE(0x004)
+#define HDMI_TG_CB_SZ HDMI_TG_BASE(0x008)
+#define HDMI_TG_INDELAY_L HDMI_TG_BASE(0x00c)
+#define HDMI_TG_INDELAY_H HDMI_TG_BASE(0x010)
+#define HDMI_TG_POL_CTRL HDMI_TG_BASE(0x014)
+#define HDMI_TG_H_FSZ_L HDMI_TG_BASE(0x018)
+#define HDMI_TG_H_FSZ_H HDMI_TG_BASE(0x01c)
+#define HDMI_TG_HACT_ST_L HDMI_TG_BASE(0x020)
+#define HDMI_TG_HACT_ST_H HDMI_TG_BASE(0x024)
+#define HDMI_TG_HACT_SZ_L HDMI_TG_BASE(0x028)
+#define HDMI_TG_HACT_SZ_H HDMI_TG_BASE(0x02c)
+#define HDMI_TG_V_FSZ_L HDMI_TG_BASE(0x030)
+#define HDMI_TG_V_FSZ_H HDMI_TG_BASE(0x034)
+#define HDMI_TG_VSYNC_L HDMI_TG_BASE(0x038)
+#define HDMI_TG_VSYNC_H HDMI_TG_BASE(0x03c)
+#define HDMI_TG_VSYNC2_L HDMI_TG_BASE(0x040)
+#define HDMI_TG_VSYNC2_H HDMI_TG_BASE(0x044)
+#define HDMI_TG_VACT_ST_L HDMI_TG_BASE(0x048)
+#define HDMI_TG_VACT_ST_H HDMI_TG_BASE(0x04c)
+#define HDMI_TG_VACT_SZ_L HDMI_TG_BASE(0x050)
+#define HDMI_TG_VACT_SZ_H HDMI_TG_BASE(0x054)
+#define HDMI_TG_FIELD_CHG_L HDMI_TG_BASE(0x058)
+#define HDMI_TG_FIELD_CHG_H HDMI_TG_BASE(0x05c)
+#define HDMI_TG_VACT_ST2_L HDMI_TG_BASE(0x060)
+#define HDMI_TG_VACT_ST2_H HDMI_TG_BASE(0x064)
+#define HDMI_TG_VACT_ST3_L HDMI_TG_BASE(0x068)
+#define HDMI_TG_VACT_ST3_H HDMI_TG_BASE(0x06c)
+#define HDMI_TG_VACT_ST4_L HDMI_TG_BASE(0x070)
+#define HDMI_TG_VACT_ST4_H HDMI_TG_BASE(0x074)
+
+#define HDMI_TG_VSYNC_TOP_HDMI_L HDMI_TG_BASE(0x078)
+#define HDMI_TG_VSYNC_TOP_HDMI_H HDMI_TG_BASE(0x07c)
+#define HDMI_TG_VSYNC_BOT_HDMI_L HDMI_TG_BASE(0x080)
+#define HDMI_TG_VSYNC_BOT_HDMI_H HDMI_TG_BASE(0x084)
+#define HDMI_TG_FIELD_TOP_HDMI_L HDMI_TG_BASE(0x088)
+#define HDMI_TG_FIELD_TOP_HDMI_H HDMI_TG_BASE(0x08c)
+#define HDMI_TG_FIELD_BOT_HDMI_L HDMI_TG_BASE(0x090)
+#define HDMI_TG_FIELD_BOT_HDMI_H HDMI_TG_BASE(0x094)
+
+#define HDMI_TG_3D HDMI_TG_BASE(0x0F0)
+
+#define HDMI_MHL_HSYNC_WIDTH HDMI_TG_BASE(0x17C)
+#define HDMI_MHL_VSYNC_WIDTH HDMI_TG_BASE(0x180)
+#define HDMI_MHL_CLK_INV HDMI_TG_BASE(0x184)
+
+/* HDMI eFUSE registers */
+#define HDMI_EFUSE_CTRL HDMI_EFUSE_BASE(0x000)
+#define HDMI_EFUSE_STATUS HDMI_EFUSE_BASE(0x004)
+#define HDMI_EFUSE_ADDR_WIDTH HDMI_EFUSE_BASE(0x008)
+#define HDMI_EFUSE_SIGDEV_ASSERT HDMI_EFUSE_BASE(0x00c)
+#define HDMI_EFUSE_SIGDEV_DE_ASSERT HDMI_EFUSE_BASE(0x010)
+#define HDMI_EFUSE_PRCHG_ASSERT HDMI_EFUSE_BASE(0x014)
+#define HDMI_EFUSE_PRCHG_DE_ASSERT HDMI_EFUSE_BASE(0x018)
+#define HDMI_EFUSE_FSET_ASSERT HDMI_EFUSE_BASE(0x01c)
+#define HDMI_EFUSE_FSET_DE_ASSERT HDMI_EFUSE_BASE(0x020)
+#define HDMI_EFUSE_SENSING HDMI_EFUSE_BASE(0x024)
+#define HDMI_EFUSE_SCK_ASSERT HDMI_EFUSE_BASE(0x028)
+#define HDMI_EFUSE_SCK_DE_ASSERT HDMI_EFUSE_BASE(0x02c)
+#define HDMI_EFUSE_SDOUT_OFFSET HDMI_EFUSE_BASE(0x030)
+#define HDMI_EFUSE_READ_OFFSET HDMI_EFUSE_BASE(0x034)
+
+/*
+ * Bit definition part
+ */
+
+/* Control Register */
+
+/* HDMI_INTC_CON_0 */
+#define HDMI_INTC_POL (1 << 7)
+#define HDMI_INTC_EN_GLOBAL (1 << 6)
+#define HDMI_INTC_EN_I2S (1 << 5)
+#define HDMI_INTC_EN_CEC (1 << 4)
+#define HDMI_INTC_EN_HPD_PLUG (1 << 3)
+#define HDMI_INTC_EN_HPD_UNPLUG (1 << 2)
+#define HDMI_INTC_EN_SPDIF (1 << 1)
+#define HDMI_INTC_EN_HDCP (1 << 0)
+
+/* HDMI_INTC_FLAG_0 */
+#define HDMI_INTC_FLAG_I2S (1 << 5)
+#define HDMI_INTC_FLAG_CEC (1 << 4)
+#define HDMI_INTC_FLAG_HPD_PLUG (1 << 3)
+#define HDMI_INTC_FLAG_HPD_UNPLUG (1 << 2)
+#define HDMI_INTC_FLAG_SPDIF (1 << 1)
+#define HDMI_INTC_FLAG_HDCP (1 << 0)
+
+/* HDMI_HDCP_KEY_LOAD */
+#define HDMI_HDCP_KEY_LOAD_DONE (1 << 0)
+
+/* HDMI_HPD_STATUS */
+#define HDMI_HPD_VALUE (1 << 0)
+
+/* AUDIO_CLKSEL */
+#define HDMI_AUDIO_SPDIF_CLK (1 << 0)
+#define HDMI_AUDIO_PCLK (0 << 0)
+
+/* HDMI_PHY_RSTOUT */
+#define HDMI_PHY_SW_RSTOUT (1 << 0)
+
+/* HDMI_PHY_VPLL */
+#define HDMI_PHY_VPLL_LOCK (1 << 7)
+#define HDMI_PHY_VPLL_CODE_MASK (0x7 << 0)
+
+/* HDMI_PHY_CMU */
+#define HDMI_PHY_CMU_LOCK (1 << 7)
+#define HDMI_PHY_CMU_CODE_MASK (0x7 << 0)
+
+/* HDMI_CORE_RSTOUT */
+#define HDMI_CORE_SW_RSTOUT (1 << 0)
+
+/* Core Register */
+
+/* HDMI_CON_0 */
+#define HDMI_BLUE_SCR_EN (1 << 5)
+#define HDMI_BLUE_SCR_DIS (0 << 5)
+#define HDMI_ENC_OPTION (1 << 4)
+#define HDMI_ASP_ENABLE (1 << 2)
+#define HDMI_ASP_DISABLE (0 << 2)
+#define HDMI_PWDN_ENB_NORMAL (1 << 1)
+#define HDMI_PWDN_ENB_PD (0 << 1)
+#define HDMI_EN (1 << 0)
+#define HDMI_DIS (~(1 << 0))
+
+/* HDMI_CON_1 */
+#define HDMI_PX_LMT_CTRL_BYPASS (0 << 5)
+#define HDMI_PX_LMT_CTRL_RGB (1 << 5)
+#define HDMI_PX_LMT_CTRL_YPBPR (2 << 5)
+#define HDMI_PX_LMT_CTRL_RESERVED (3 << 5)
+#define HDMI_CON_PXL_REP_RATIO_MASK (1 << 1 | 1 << 0)
+#define HDMI_DOUBLE_PIXEL_REPETITION (0x01)
+
+/* HDMI_CON_2 */
+#define HDMI_VID_PREAMBLE_EN (0 << 5)
+#define HDMI_VID_PREAMBLE_DIS (1 << 5)
+#define HDMI_GUARD_BAND_EN (0 << 1)
+#define HDMI_GUARD_BAND_DIS (1 << 1)
+
+/* STATUS */
+#define HDMI_AUTHEN_ACK_AUTH (1 << 7)
+#define HDMI_AUTHEN_ACK_NOT (0 << 7)
+#define HDMI_AUD_FIFO_OVF_FULL (1 << 6)
+#define HDMI_AUD_FIFO_OVF_NOT (0 << 6)
+#define HDMI_UPDATE_RI_INT_OCC (1 << 4)
+#define HDMI_UPDATE_RI_INT_NOT (0 << 4)
+#define HDMI_UPDATE_RI_INT_CLEAR (1 << 4)
+#define HDMI_UPDATE_PJ_INT_OCC (1 << 3)
+#define HDMI_UPDATE_PJ_INT_NOT (0 << 3)
+#define HDMI_UPDATE_PJ_INT_CLEAR (1 << 3)
+#define HDMI_WRITE_INT_OCC (1 << 2)
+#define HDMI_WRITE_INT_NOT (0 << 2)
+#define HDMI_WRITE_INT_CLEAR (1 << 2)
+#define HDMI_WATCHDOG_INT_OCC (1 << 1)
+#define HDMI_WATCHDOG_INT_NOT (0 << 1)
+#define HDMI_WATCHDOG_INT_CLEAR (1 << 1)
+#define HDMI_WTFORACTIVERX_INT_OCC (1)
+#define HDMI_WTFORACTIVERX_INT_NOT (0)
+#define HDMI_WTFORACTIVERX_INT_CLEAR (1)
+
+/* PHY_STATUS */
+#define HDMI_PHY_STATUS_READY (1)
+
+/* HDMI_MODE_SEL */
+#define HDMI_MODE_HDMI_EN (1 << 1)
+#define HDMI_MODE_DVI_EN (1 << 0)
+#define HDMI_MODE_MASK (3 << 0)
+
+/* STATUS_EN */
+#define HDMI_AUD_FIFO_OVF_EN (1 << 6)
+#define HDMI_AUD_FIFO_OVF_DIS (0 << 6)
+#define HDMI_UPDATE_RI_INT_EN (1 << 4)
+#define HDMI_UPDATE_RI_INT_DIS (0 << 4)
+#define HDMI_UPDATE_PJ_INT_EN (1 << 3)
+#define HDMI_UPDATE_PJ_INT_DIS (0 << 3)
+#define HDMI_WRITE_INT_EN (1 << 2)
+#define HDMI_WRITE_INT_DIS (0 << 2)
+#define HDMI_WATCHDOG_INT_EN (1 << 1)
+#define HDMI_WATCHDOG_INT_DIS (0 << 1)
+#define HDMI_WTFORACTIVERX_INT_EN (1)
+#define HDMI_WTFORACTIVERX_INT_DIS (0)
+#define HDMI_INT_EN_ALL (HDMI_UPDATE_RI_INT_EN|\
+ HDMI_UPDATE_PJ_INT_DIS|\
+ HDMI_WRITE_INT_EN|\
+ HDMI_WATCHDOG_INT_EN|\
+ HDMI_WTFORACTIVERX_INT_EN)
+#define HDMI_INT_DIS_ALL (~0x1F)
+
+/* HPD */
+#define HDMI_SW_HPD_PLUGGED (1 << 1)
+#define HDMI_SW_HPD_UNPLUGGED (0 << 1)
+#define HDMI_HPD_SEL_I_HPD (1)
+#define HDMI_HPD_SEL_SW_HPD (0)
+
+/* MODE_SEL */
+#define HDMI_MODE_EN (1 << 1)
+#define HDMI_MODE_DIS (0 << 1)
+#define HDMI_DVI_MODE_EN (1)
+#define HDMI_DVI_MODE_DIS (0)
+
+/* ENC_EN */
+#define HDMI_HDCP_ENC_ENABLE (1)
+#define HDMI_HDCP_ENC_DISABLE (0)
+
+/* Video Related Register */
+
+/* BLUESCREEN_0/1/2 */
+
+/* HDMI_YMAX/YMIN/CMAX/CMIN */
+
+/* H_BLANK_0/1 */
+
+/* V_BLANK_0/1/2 */
+
+/* H_V_LINE_0/1/2 */
+
+/* VSYNC_POL */
+#define HDMI_V_SYNC_POL_ACT_LOW (1)
+#define HDMI_V_SYNC_POL_ACT_HIGH (0)
+
+/* INT_PRO_MODE */
+#define HDMI_INTERLACE_MODE (1)
+#define HDMI_PROGRESSIVE_MODE (0)
+
+/* V_BLANK_F_0/1/2 */
+
+/* H_SYNC_GEN_0/1/2 */
+
+/* V_SYNC_GEN1_0/1/2 */
+
+/* V_SYNC_GEN2_0/1/2 */
+
+/* V_SYNC_GEN3_0/1/2 */
+
+/* Audio Related Packet Register */
+
+/* ASP_CON */
+#define HDMI_AUD_DST_DOUBLE (1 << 7)
+#define HDMI_AUD_NO_DST_DOUBLE (0 << 7)
+#define HDMI_AUD_TYPE_SAMPLE (0 << 5)
+#define HDMI_AUD_TYPE_ONE_BIT (1 << 5)
+#define HDMI_AUD_TYPE_HBR (2 << 5)
+#define HDMI_AUD_TYPE_DST (3 << 5)
+#define HDMI_AUD_MODE_TWO_CH (0 << 4)
+#define HDMI_AUD_MODE_MULTI_CH (1 << 4)
+#define HDMI_AUD_SP_AUD3_EN (1 << 3)
+#define HDMI_AUD_SP_AUD2_EN (1 << 2)
+#define HDMI_AUD_SP_AUD1_EN (1 << 1)
+#define HDMI_AUD_SP_AUD0_EN (1 << 0)
+#define HDMI_AUD_SP_ALL_DIS (0 << 0)
+
+#define HDMI_AUD_SET_SP_PRE(x) ((x) & 0xF)
+
+/* ASP_SP_FLAT */
+#define HDMI_ASP_SP_FLAT_AUD_SAMPLE (0)
+
+/* ASP_CHCFG0/1/2/3 */
+#define HDMI_SPK3R_SEL_I_PCM0L (0 << 27)
+#define HDMI_SPK3R_SEL_I_PCM0R (1 << 27)
+#define HDMI_SPK3R_SEL_I_PCM1L (2 << 27)
+#define HDMI_SPK3R_SEL_I_PCM1R (3 << 27)
+#define HDMI_SPK3R_SEL_I_PCM2L (4 << 27)
+#define HDMI_SPK3R_SEL_I_PCM2R (5 << 27)
+#define HDMI_SPK3R_SEL_I_PCM3L (6 << 27)
+#define HDMI_SPK3R_SEL_I_PCM3R (7 << 27)
+#define HDMI_SPK3L_SEL_I_PCM0L (0 << 24)
+#define HDMI_SPK3L_SEL_I_PCM0R (1 << 24)
+#define HDMI_SPK3L_SEL_I_PCM1L (2 << 24)
+#define HDMI_SPK3L_SEL_I_PCM1R (3 << 24)
+#define HDMI_SPK3L_SEL_I_PCM2L (4 << 24)
+#define HDMI_SPK3L_SEL_I_PCM2R (5 << 24)
+#define HDMI_SPK3L_SEL_I_PCM3L (6 << 24)
+#define HDMI_SPK3L_SEL_I_PCM3R (7 << 24)
+#define HDMI_SPK2R_SEL_I_PCM0L (0 << 19)
+#define HDMI_SPK2R_SEL_I_PCM0R (1 << 19)
+#define HDMI_SPK2R_SEL_I_PCM1L (2 << 19)
+#define HDMI_SPK2R_SEL_I_PCM1R (3 << 19)
+#define HDMI_SPK2R_SEL_I_PCM2L (4 << 19)
+#define HDMI_SPK2R_SEL_I_PCM2R (5 << 19)
+#define HDMI_SPK2R_SEL_I_PCM3L (6 << 19)
+#define HDMI_SPK2R_SEL_I_PCM3R (7 << 19)
+#define HDMI_SPK2L_SEL_I_PCM0L (0 << 16)
+#define HDMI_SPK2L_SEL_I_PCM0R (1 << 16)
+#define HDMI_SPK2L_SEL_I_PCM1L (2 << 16)
+#define HDMI_SPK2L_SEL_I_PCM1R (3 << 16)
+#define HDMI_SPK2L_SEL_I_PCM2L (4 << 16)
+#define HDMI_SPK2L_SEL_I_PCM2R (5 << 16)
+#define HDMI_SPK2L_SEL_I_PCM3L (6 << 16)
+#define HDMI_SPK2L_SEL_I_PCM3R (7 << 16)
+#define HDMI_SPK1R_SEL_I_PCM0L (0 << 11)
+#define HDMI_SPK1R_SEL_I_PCM0R (1 << 11)
+#define HDMI_SPK1R_SEL_I_PCM1L (2 << 11)
+#define HDMI_SPK1R_SEL_I_PCM1R (3 << 11)
+#define HDMI_SPK1R_SEL_I_PCM2L (4 << 11)
+#define HDMI_SPK1R_SEL_I_PCM2R (5 << 11)
+#define HDMI_SPK1R_SEL_I_PCM3L (6 << 11)
+#define HDMI_SPK1R_SEL_I_PCM3R (7 << 11)
+#define HDMI_SPK1L_SEL_I_PCM0L (0 << 8)
+#define HDMI_SPK1L_SEL_I_PCM0R (1 << 8)
+#define HDMI_SPK1L_SEL_I_PCM1L (2 << 8)
+#define HDMI_SPK1L_SEL_I_PCM1R (3 << 8)
+#define HDMI_SPK1L_SEL_I_PCM2L (4 << 8)
+#define HDMI_SPK1L_SEL_I_PCM2R (5 << 8)
+#define HDMI_SPK1L_SEL_I_PCM3L (6 << 8)
+#define HDMI_SPK1L_SEL_I_PCM3R (7 << 8)
+#define HDMI_SPK0R_SEL_I_PCM0L (0 << 3)
+#define HDMI_SPK0R_SEL_I_PCM0R (1 << 3)
+#define HDMI_SPK0R_SEL_I_PCM1L (2 << 3)
+#define HDMI_SPK0R_SEL_I_PCM1R (3 << 3)
+#define HDMI_SPK0R_SEL_I_PCM2L (4 << 3)
+#define HDMI_SPK0R_SEL_I_PCM2R (5 << 3)
+#define HDMI_SPK0R_SEL_I_PCM3L (6 << 3)
+#define HDMI_SPK0R_SEL_I_PCM3R (7 << 3)
+#define HDMI_SPK0L_SEL_I_PCM0L (0)
+#define HDMI_SPK0L_SEL_I_PCM0R (1)
+#define HDMI_SPK0L_SEL_I_PCM1L (2)
+#define HDMI_SPK0L_SEL_I_PCM1R (3)
+#define HDMI_SPK0L_SEL_I_PCM2L (4)
+#define HDMI_SPK0L_SEL_I_PCM2R (5)
+#define HDMI_SPK0L_SEL_I_PCM3L (6)
+#define HDMI_SPK0L_SEL_I_PCM3R (7)
+
+/* ACR_CON */
+#define HDMI_ACR_CON_TX_MODE_NO_TX (0 << 0)
+#define HDMI_ACR_CON_TX_MODE_MESURED_CTS (4 << 0)
+
+/* ACR_MCTS0/1/2 */
+
+/* ACR_CTS0/1/2 */
+
+/* ACR_N0/1/2 */
+#define HDMI_ACR_N0_VAL(x) (x & 0xff)
+#define HDMI_ACR_N1_VAL(x) ((x >> 8) & 0xff)
+#define HDMI_ACR_N2_VAL(x) ((x >> 16) & 0xff)
+
+/* ACR_LSB2 */
+#define HDMI_ACR_LSB2_MASK (0xFF)
+
+/* ACR_TXCNT */
+#define HDMI_ACR_TXCNT_MASK (0x1F)
+
+/* ACR_TXINTERNAL */
+#define HDMI_ACR_TX_INTERNAL_MASK (0xFF)
+
+/* ACR_CTS_OFFSET */
+#define HDMI_ACR_CTS_OFFSET_MASK (0xFF)
+
+/* GCP_CON */
+#define HDMI_GCP_CON_EN_1ST_VSYNC (1 << 3)
+#define HDMI_GCP_CON_EN_2ST_VSYNC (1 << 2)
+#define HDMI_GCP_CON_TRANS_EVERY_VSYNC (2)
+#define HDMI_GCP_CON_NO_TRAN (0)
+#define HDMI_GCP_CON_TRANS_ONCE (1)
+#define HDMI_GCP_CON_TRANS_EVERY_VSYNC (2)
+
+/* GCP_BYTE1 */
+#define HDMI_GCP_BYTE1_MASK (0xFF)
+
+/* GCP_BYTE2 */
+#define HDMI_GCP_BYTE2_PP_MASK (0xF << 4)
+#define HDMI_GCP_24BPP (1 << 2)
+#define HDMI_GCP_30BPP (1 << 0 | 1 << 2)
+#define HDMI_GCP_36BPP (1 << 1 | 1 << 2)
+#define HDMI_GCP_48BPP (1 << 0 | 1 << 1 | 1 << 2)
+
+/* GCP_BYTE3 */
+#define HDMI_GCP_BYTE3_MASK (0xFF)
+
+/* ACP Packet Register */
+
+/* ACP_CON */
+#define HDMI_ACP_FR_RATE_MASK (0x1F << 3)
+#define HDMI_ACP_CON_NO_TRAN (0)
+#define HDMI_ACP_CON_TRANS_ONCE (1)
+#define HDMI_ACP_CON_TRANS_EVERY_VSYNC (2)
+
+/* ACP_TYPE */
+#define HDMI_ACP_TYPE_MASK (0xFF)
+
+/* ACP_DATA00~16 */
+#define HDMI_ACP_DATA_MASK (0xFF)
+
+/* ISRC1/2 Packet Register */
+
+/* ISRC_CON */
+#define HDMI_ISRC_FR_RATE_MASK (0x1F << 3)
+#define HDMI_ISRC_EN (1 << 2)
+#define HDMI_ISRC_DIS (0 << 2)
+
+/* ISRC1_HEADER1 */
+#define HDMI_ISRC1_HEADER_MASK (0xFF)
+
+/* ISRC1_DATA 00~15 */
+#define HDMI_ISRC1_DATA_MASK (0xFF)
+
+/* ISRC2_DATA 00~15 */
+#define HDMI_ISRC2_DATA_MASK (0xFF)
+
+/* AVI InfoFrame Register */
+
+/* AVI_CON */
+#define HDMI_AVI_CON_DO_NOT_TRANSMIT (0 << 1)
+#define HDMI_AVI_CON_EVERY_VSYNC (1 << 1)
+
+/* AVI_CHECK_SUM */
+
+/* AVI_DATA01~13 */
+#define HDMI_AVI_PIXEL_REPETITION_DOUBLE (1<<0)
+#define HDMI_AVI_PICTURE_ASPECT_4_3 (1<<4)
+#define HDMI_AVI_PICTURE_ASPECT_16_9 (1<<5)
+
+/* Audio InfoFrame Register */
+
+/* AUI_CON */
+#define HDMI_AUI_CON_NO_TRAN (0 << 0)
+#define HDMI_AUI_CON_TRANS_ONCE (1 << 0)
+#define HDMI_AUI_CON_TRANS_EVERY_VSYNC (2 << 0)
+
+/* AUI_CHECK_SUM */
+
+/* AUI_DATA1~5 */
+
+/* MPEG Source InfoFrame registers */
+
+/* MPG_CON */
+
+/* HDMI_MPG_CHECK_SUM */
+
+/* MPG_DATA1~5 */
+
+/* Source Product Descriptor Infoframe registers */
+
+/* SPD_CON */
+
+/* SPD_HEADER0/1/2 */
+
+/* SPD_DATA0~27 */
+
+/* VSI_CON */
+#define HDMI_VSI_CON_DO_NOT_TRANSMIT (0 << 0)
+#define HDMI_VSI_CON_EVERY_VSYNC (1 << 1)
+
+/* VSI_DATA00 ~ 27 */
+#define HDMI_VSI_DATA04_VIDEO_FORMAT(x) (x << 5)
+#define HDMI_VSI_DATA05_3D_STRUCTURE(x) (x << 4)
+#define HDMI_VSI_DATA06_3D_EXT_DATA(x) (x << 4)
+
+/* HDCP Register */
+
+/* HDCP_SHA1_00~19 */
+
+/* HDCP_KSV_LIST_0~4 */
+
+/* HDCP_KSV_LIST_CON */
+#define HDMI_HDCP_KSV_WRITE_DONE (0x1 << 3)
+#define HDMI_HDCP_KSV_LIST_EMPTY (0x1 << 2)
+#define HDMI_HDCP_KSV_END (0x1 << 1)
+#define HDMI_HDCP_KSV_READ (0x1 << 0)
+
+/* HDCP_CTRL1 */
+#define HDMI_HDCP_EN_PJ_EN (1 << 4)
+#define HDMI_HDCP_EN_PJ_DIS (~(1 << 4))
+#define HDMI_HDCP_SET_REPEATER_TIMEOUT (1 << 2)
+#define HDMI_HDCP_CLEAR_REPEATER_TIMEOUT (~(1 << 2))
+#define HDMI_HDCP_CP_DESIRED_EN (1 << 1)
+#define HDMI_HDCP_CP_DESIRED_DIS (~(1 << 1))
+#define HDMI_HDCP_ENABLE_1_1_FEATURE_EN (1)
+#define HDMI_HDCP_ENABLE_1_1_FEATURE_DIS (~(1))
+
+/* HDCP_CHECK_RESULT */
+#define HDMI_HDCP_PI_MATCH_RESULT_Y ((0x1 << 3) | (0x1 << 2))
+#define HDMI_HDCP_PI_MATCH_RESULT_N ((0x1 << 3) | (0x0 << 2))
+#define HDMI_HDCP_RI_MATCH_RESULT_Y ((0x1 << 1) | (0x1 << 0))
+#define HDMI_HDCP_RI_MATCH_RESULT_N ((0x1 << 1) | (0x0 << 0))
+#define HDMI_HDCP_CLR_ALL_RESULTS (0)
+
+/* HDCP_BKSV0~4 */
+/* HDCP_AKSV0~4 */
+
+/* HDCP_BCAPS */
+#define HDMI_HDCP_BCAPS_REPEATER (1 << 6)
+#define HDMI_HDCP_BCAPS_READY (1 << 5)
+#define HDMI_HDCP_BCAPS_FAST (1 << 4)
+#define HDMI_HDCP_BCAPS_1_1_FEATURES (1 << 1)
+#define HDMI_HDCP_BCAPS_FAST_REAUTH (1)
+
+/* HDCP_BSTATUS_0/1 */
+/* HDCP_Ri_0/1 */
+/* HDCP_I2C_INT */
+/* HDCP_AN_INT */
+/* HDCP_WATCHDOG_INT */
+/* HDCP_RI_INT/1 */
+/* HDCP_Ri_Compare_0 */
+/* HDCP_Ri_Compare_1 */
+/* HDCP_Frame_Count */
+
+/* Gamut Metadata Packet Register */
+
+/* GAMUT_CON */
+/* GAMUT_HEADER0 */
+/* GAMUT_HEADER1 */
+/* GAMUT_HEADER2 */
+/* GAMUT_METADATA0~27 */
+
+/* Video Mode Register */
+
+/* VIDEO_PATTERN_GEN */
+/* HPD_GEN */
+/* HDCP_Ri_Compare_0 */
+/* HDCP_Ri_Compare_0 */
+/* HDCP_Ri_Compare_0 */
+/* HDCP_Ri_Compare_0 */
+/* HDCP_Ri_Compare_0 */
+/* HDCP_Ri_Compare_0 */
+/* HDCP_Ri_Compare_0 */
+/* HDCP_Ri_Compare_0 */
+/* HDCP_Ri_Compare_0 */
+/* HDCP_Ri_Compare_0 */
+
+/* SPDIF Register */
+
+/* SPDIFIN_CLK_CTRL */
+#define HDMI_SPDIFIN_READY_CLK_DOWN (1 << 1)
+#define HDMI_SPDIFIN_CLK_ON (1 << 0)
+
+/* SPDIFIN_OP_CTRL */
+#define HDMI_SPDIFIN_SW_RESET (0 << 0)
+#define HDMI_SPDIFIN_STATUS_CHECK_MODE (1 << 0)
+#define HDMI_SPDIFIN_STATUS_CHECK_MODE_HDMI (3 << 0)
+
+/* SPDIFIN_IRQ_MASK */
+
+/* SPDIFIN_IRQ_STATUS */
+#define HDMI_SPDIFIN_IRQ_OVERFLOW_EN (1 << 7)
+#define HDMI_SPDIFIN_IRQ_ABNORMAL_PD_EN (1 << 6)
+#define HDMI_SPDIFIN_IRQ_SH_NOT_DETECTED_RIGHTTIME_EN (1 << 5)
+#define HDMI_SPDIFIN_IRQ_SH_DETECTED_EN (1 << 4)
+#define HDMI_SPDIFIN_IRQ_SH_NOT_DETECTED_EN (1 << 3)
+#define HDMI_SPDIFIN_IRQ_WRONG_PREAMBLE_EN (1 << 2)
+#define HDMI_SPDIFIN_IRQ_CH_STATUS_RECOVERED_EN (1 << 1)
+#define HDMI_SPDIFIN_IRQ_WRONG_SIG_EN (1 << 0)
+
+/* SPDIFIN_CONFIG_1 */
+#define HDMI_SPDIFIN_CFG_NOISE_FILTER_2_SAMPLE (1 << 6)
+#define HDMI_SPDIFIN_CFG_PCPD_MANUAL (1 << 4)
+#define HDMI_SPDIFIN_CFG_WORD_LENGTH_MANUAL (1 << 3)
+#define HDMI_SPDIFIN_CFG_UVCP_REPORT (1 << 2)
+#define HDMI_SPDIFIN_CFG_HDMI_2_BURST (1 << 1)
+#define HDMI_SPDIFIN_CFG_DATA_ALIGN_32 (1 << 0)
+
+/* SPDIFIN_CONFIG_2 */
+#define HDMI_SPDIFIN_CFG2_NO_CLK_DIV (0)
+
+/* SPDIFIN_USER_VALUE_1 */
+#define HDMI_SPDIFIN_USER_VAL_REPETITION_TIME_LOW(x) ((x & 0xf) << 4)
+#define HDMI_SPDIFIN_USER_VAL_WORD_LENGTH_24 (0xb << 0)
+#define HDMI_SPDIFIN_USER_VAL_REPETITION_TIME_HIGH(x) ((x >> 4) & 0xff)
+/* SPDIFIN_USER_VALUE_2 */
+/* SPDIFIN_USER_VALUE_3 */
+/* SPDIFIN_USER_VALUE_4 */
+/* SPDIFIN_CH_STATUS_0_1 */
+/* SPDIFIN_CH_STATUS_0_2 */
+/* SPDIFIN_CH_STATUS_0_3 */
+/* SPDIFIN_CH_STATUS_0_4 */
+/* SPDIFIN_CH_STATUS_1 */
+/* SPDIFIN_FRAME_PERIOD_1 */
+/* SPDIFIN_FRAME_PERIOD_2 */
+/* SPDIFIN_PC_INFO_1 */
+/* SPDIFIN_PC_INFO_2 */
+/* SPDIFIN_PD_INFO_1 */
+/* SPDIFIN_PD_INFO_2 */
+/* SPDIFIN_DATA_BUF_0_1 */
+/* SPDIFIN_DATA_BUF_0_2 */
+/* SPDIFIN_DATA_BUF_0_3 */
+/* SPDIFIN_USER_BUF_0 */
+/* SPDIFIN_USER_BUF_1_1 */
+/* SPDIFIN_USER_BUF_1_2 */
+/* SPDIFIN_USER_BUF_1_3 */
+/* SPDIFIN_USER_BUF_1 */
+
+/* I2S Register */
+
+/* I2S_CLK_CON */
+#define HDMI_I2S_CLK_DISABLE (0)
+#define HDMI_I2S_CLK_ENABLE (1)
+
+/* I2S_CON_1 */
+#define HDMI_I2S_SCLK_FALLING_EDGE (0 << 1)
+#define HDMI_I2S_SCLK_RISING_EDGE (1 << 1)
+#define HDMI_I2S_L_CH_LOW_POL (0)
+#define HDMI_I2S_L_CH_HIGH_POL (1)
+
+/* I2S_CON_2 */
+#define HDMI_I2S_MSB_FIRST_MODE (0 << 6)
+#define HDMI_I2S_LSB_FIRST_MODE (1 << 6)
+#define HDMI_I2S_BIT_CH_32FS (0 << 4)
+#define HDMI_I2S_BIT_CH_48FS (1 << 4)
+#define HDMI_I2S_BIT_CH_RESERVED (2 << 4)
+#define HDMI_I2S_SDATA_16BIT (1 << 2)
+#define HDMI_I2S_SDATA_20BIT (2 << 2)
+#define HDMI_I2S_SDATA_24BIT (3 << 2)
+#define HDMI_I2S_BASIC_FORMAT (0)
+#define HDMI_I2S_L_JUST_FORMAT (2)
+#define HDMI_I2S_R_JUST_FORMAT (3)
+#define HDMI_I2S_CON_2_CLR (~(0xFF))
+#define HDMI_I2S_SET_BIT_CH(x) (((x) & 0x7) << 4)
+#define HDMI_I2S_SET_SDATA_BIT(x) (((x) & 0x7) << 2)
+
+/* I2S_PIN_SEL_0 */
+#define HDMI_I2S_SEL_SCLK(x) (((x) & 0x7) << 4)
+#define HDMI_I2S_SEL_LRCK(x) ((x) & 0x7)
+
+/* I2S_PIN_SEL_1 */
+#define HDMI_I2S_SEL_SDATA1(x) (((x) & 0x7) << 4)
+#define HDMI_I2S_SEL_SDATA0(x) ((x) & 0x7)
+
+/* I2S_PIN_SEL_2 */
+#define HDMI_I2S_SEL_SDATA3(x) (((x) & 0x7) << 4)
+#define HDMI_I2S_SEL_SDATA2(x) ((x) & 0x7)
+
+/* I2S_PIN_SEL_3 */
+#define HDMI_I2S_SEL_DSD(x) ((x) & 0x7)
+
+/* I2S_DSD_CON */
+#define HDMI_I2S_DSD_CLK_RI_EDGE (1 << 1)
+#define HDMI_I2S_DSD_CLK_FA_EDGE (0 << 1)
+#define HDMI_I2S_DSD_ENABLE (1 << 0)
+#define HDMI_I2S_DSD_DISABLE (0 << 0)
+
+/* I2S_MUX_CON */
+#define HDMI_I2S_NOISE_FILTER_ZERO (0 << 5)
+#define HDMI_I2S_NOISE_FILTER_2_STAGE (1 << 5)
+#define HDMI_I2S_NOISE_FILTER_3_STAGE (2 << 5)
+#define HDMI_I2S_NOISE_FILTER_4_STAGE (3 << 5)
+#define HDMI_I2S_NOISE_FILTER_5_STAGE (4 << 5)
+#define HDMI_I2S_IN_ENABLE (1 << 4)
+#define HDMI_I2S_IN_DISABLE (0 << 4)
+#define HDMI_I2S_AUD_SPDIF (0 << 2)
+#define HDMI_I2S_AUD_I2S (1 << 2)
+#define HDMI_I2S_AUD_DSD (2 << 2)
+#define HDMI_I2S_CUV_SPDIF_ENABLE (0 << 1)
+#define HDMI_I2S_CUV_I2S_ENABLE (1 << 1)
+#define HDMI_I2S_MUX_DISABLE (0 << 0)
+#define HDMI_I2S_MUX_ENABLE (1 << 0)
+
+/* I2S_CH_ST_CON */
+#define HDMI_I2S_CH_STATUS_RELOAD (1 << 0)
+#define HDMI_I2S_CH_ST_CON_CLR (~(1))
+
+/* I2S_CH_ST_0 / I2S_CH_ST_SH_0 */
+#define HDMI_I2S_CH_STATUS_MODE_0 (0 << 6)
+#define HDMI_I2S_2AUD_CH_WITHOUT_PREEMPH (0 << 3)
+#define HDMI_I2S_2AUD_CH_WITH_PREEMPH (1 << 3)
+#define HDMI_I2S_DEFAULT_EMPHASIS (0 << 3)
+#define HDMI_I2S_COPYRIGHT (0 << 2)
+#define HDMI_I2S_NO_COPYRIGHT (1 << 2)
+#define HDMI_I2S_LINEAR_PCM (0 << 1)
+#define HDMI_I2S_NO_LINEAR_PCM (1 << 1)
+#define HDMI_I2S_CONSUMER_FORMAT (0)
+#define HDMI_I2S_PROF_FORMAT (1)
+#define HDMI_I2S_CH_ST_0_CLR (~(0xFF))
+
+/* I2S_CH_ST_1 / I2S_CH_ST_SH_1 */
+#define HDMI_I2S_CD_PLAYER (0x00)
+#define HDMI_I2S_DAT_PLAYER (0x03)
+#define HDMI_I2S_DCC_PLAYER (0x43)
+#define HDMI_I2S_MINI_DISC_PLAYER (0x49)
+
+/* I2S_CH_ST_2 / I2S_CH_ST_SH_2 */
+#define HDMI_I2S_CHANNEL_NUM_MASK (0xF << 4)
+#define HDMI_I2S_SOURCE_NUM_MASK (0xF)
+#define HDMI_I2S_SET_CHANNEL_NUM(x) ((x) & (0xF) << 4)
+#define HDMI_I2S_SET_SOURCE_NUM(x) ((x) & (0xF))
+
+/* I2S_CH_ST_3 / I2S_CH_ST_SH_3 */
+#define HDMI_I2S_CLK_ACCUR_LEVEL_1 (1 << 4)
+#define HDMI_I2S_CLK_ACCUR_LEVEL_2 (0 << 4)
+#define HDMI_I2S_CLK_ACCUR_LEVEL_3 (2 << 4)
+#define HDMI_I2S_SAMPLING_FREQ_44_1 (0x0)
+#define HDMI_I2S_SAMPLING_FREQ_48 (0x2)
+#define HDMI_I2S_SAMPLING_FREQ_32 (0x3)
+#define HDMI_I2S_SAMPLING_FREQ_96 (0xA)
+#define HDMI_I2S_SET_SAMPLING_FREQ(x) ((x) & (0xF))
+
+/* I2S_CH_ST_4 / I2S_CH_ST_SH_4 */
+#define HDMI_I2S_ORG_SAMPLING_FREQ_44_1 (0xF << 4)
+#define HDMI_I2S_ORG_SAMPLING_FREQ_88_2 (0x7 << 4)
+#define HDMI_I2S_ORG_SAMPLING_FREQ_22_05 (0xB << 4)
+#define HDMI_I2S_ORG_SAMPLING_FREQ_176_4 (0x3 << 4)
+#define HDMI_I2S_WORD_LENGTH_NOT_DEFINE (0x0 << 1)
+#define HDMI_I2S_WORD_LENGTH_MAX24_20BITS (0x1 << 1)
+#define HDMI_I2S_WORD_LENGTH_MAX24_22BITS (0x2 << 1)
+#define HDMI_I2S_WORD_LENGTH_MAX24_23BITS (0x4 << 1)
+#define HDMI_I2S_WORD_LENGTH_MAX24_24BITS (0x5 << 1)
+#define HDMI_I2S_WORD_LENGTH_MAX24_21BITS (0x6 << 1)
+#define HDMI_I2S_WORD_LENGTH_MAX20_16BITS (0x1 << 1)
+#define HDMI_I2S_WORD_LENGTH_MAX20_18BITS (0x2 << 1)
+#define HDMI_I2S_WORD_LENGTH_MAX20_19BITS (0x4 << 1)
+#define HDMI_I2S_WORD_LENGTH_MAX20_20BITS (0x5 << 1)
+#define HDMI_I2S_WORD_LENGTH_MAX20_17BITS (0x6 << 1)
+#define HDMI_I2S_WORD_LENGTH_MAX_24BITS (1)
+#define HDMI_I2S_WORD_LENGTH_MAX_20BITS (0)
+
+/* I2S_VD_DATA */
+#define HDMI_I2S_VD_AUD_SAMPLE_RELIABLE (0)
+#define HDMI_I2S_VD_AUD_SAMPLE_UNRELIABLE (1)
+
+/* I2S_MUX_CH */
+#define HDMI_I2S_CH3_R_EN (1 << 7)
+#define HDMI_I2S_CH3_L_EN (1 << 6)
+#define HDMI_I2S_CH2_R_EN (1 << 5)
+#define HDMI_I2S_CH2_L_EN (1 << 4)
+#define HDMI_I2S_CH1_R_EN (1 << 3)
+#define HDMI_I2S_CH1_L_EN (1 << 2)
+#define HDMI_I2S_CH0_R_EN (1 << 1)
+#define HDMI_I2S_CH0_L_EN (1)
+#define HDMI_I2S_CH_ALL_EN (0xFF)
+#define HDMI_I2S_MUX_CH_CLR (~HDMI_I2S_CH_ALL_EN)
+
+/* I2S_MUX_CUV */
+#define HDMI_I2S_CUV_R_EN (1 << 1)
+#define HDMI_I2S_CUV_L_EN (1 << 0)
+#define HDMI_I2S_CUV_RL_EN (0x03)
+
+/* I2S_IRQ_MASK */
+#define HDMI_I2S_INT2_DIS (0 << 1)
+#define HDMI_I2S_INT2_EN (1 << 1)
+
+/* I2S_IRQ_STATUS */
+#define HDMI_I2S_INT2_STATUS (1 << 1)
+
+/* I2S_CH0_L_0 */
+/* I2S_CH0_L_1 */
+/* I2S_CH0_L_2 */
+/* I2S_CH0_L_3 */
+/* I2S_CH0_R_0 */
+/* I2S_CH0_R_1 */
+/* I2S_CH0_R_2 */
+/* I2S_CH0_R_3 */
+/* I2S_CH1_L_0 */
+/* I2S_CH1_L_1 */
+/* I2S_CH1_L_2 */
+/* I2S_CH1_L_3 */
+/* I2S_CH1_R_0 */
+/* I2S_CH1_R_1 */
+/* I2S_CH1_R_2 */
+/* I2S_CH1_R_3 */
+/* I2S_CH2_L_0 */
+/* I2S_CH2_L_1 */
+/* I2S_CH2_L_2 */
+/* I2S_CH2_L_3 */
+/* I2S_CH2_R_0 */
+/* I2S_CH2_R_1 */
+/* I2S_CH2_R_2 */
+/* I2S_Ch2_R_3 */
+/* I2S_CH3_L_0 */
+/* I2S_CH3_L_1 */
+/* I2S_CH3_L_2 */
+/* I2S_CH3_R_0 */
+/* I2S_CH3_R_1 */
+/* I2S_CH3_R_2 */
+
+/* I2S_CUV_L_R */
+#define HDMI_I2S_CUV_R_DATA_MASK (0x7 << 4)
+#define HDMI_I2S_CUV_L_DATA_MASK (0x7)
+
+/* Timing Generator Register */
+/* TG_CMD */
+#define HDMI_GETSYNC_TYPE (1 << 4)
+#define HDMI_GETSYNC (1 << 3)
+
+/* HDMI_TG_CMD */
+#define HDMI_FIELD_EN (1 << 1)
+#define HDMI_TG_EN (1 << 0)
+
+/* TG_CFG */
+/* TG_CB_SZ */
+/* TG_INDELAY_L */
+/* TG_INDELAY_H */
+/* TG_POL_CTRL */
+
+/* TG_H_FSZ_L */
+/* TG_H_FSZ_H */
+/* TG_HACT_ST_L */
+/* TG_HACT_ST_H */
+/* TG_HACT_SZ_L */
+/* TG_HACT_SZ_H */
+/* TG_V_FSZ_L */
+/* TG_V_FSZ_H */
+/* TG_VSYNC_L */
+/* TG_VSYNC_H */
+/* TG_VSYNC2_L */
+/* TG_VSYNC2_H */
+/* TG_VACT_ST_L */
+/* TG_VACT_ST_H */
+/* TG_VACT_SZ_L */
+/* TG_VACT_SZ_H */
+/* TG_FIELD_CHG_L */
+/* TG_FIELD_CHG_H */
+/* TG_VACT_ST2_L */
+/* TG_VACT_ST2_H */
+/* TG_VACT_SC_ST_L */
+/* TG_VACT_SC_ST_H */
+/* TG_VACT_SC_SZ_L */
+/* TG_VACT_SC_SZ_H */
+
+/* TG_VSYNC_TOP_HDMI_L */
+/* TG_VSYNC_TOP_HDMI_H */
+/* TG_VSYNC_BOT_HDMI_L */
+/* TG_VSYNC_BOT_HDMI_H */
+/* TG_FIELD_TOP_HDMI_L */
+/* TG_FIELD_TOP_HDMI_H */
+/* TG_FIELD_BOT_HDMI_L */
+/* TG_FIELD_BOT_HDMI_H */
+/* TG_HSYNC_HDOUT_ST_L */
+/* TG_HSYNC_HDOUT_ST_H */
+/* TG_HSYNC_HDOUT_END_L */
+/* TG_HSYNC_HDOUT_END_H */
+/* TG_VSYNC_HDOUT_ST_L */
+/* TG_VSYNC_HDOUT_ST_H */
+/* TG_VSYNC_HDOUT_END_L */
+/* TG_VSYNC_HDOUT_END_H */
+/* TG_VSYNC_HDOUT_DLY_L */
+/* TG_VSYNC_HDOUT_DLY_H */
+/* TG_BT_ERR_RANGE */
+/* TG_BT_ERR_RESULT */
+/* TG_COR_THR */
+/* TG_COR_NUM */
+/* TG_BT_CON */
+/* TG_BT_H_FSZ_L */
+/* TG_BT_H_FSZ_H */
+/* TG_BT_HSYNC_ST */
+/* TG_BT_HSYNC_SZ */
+/* TG_BT_FSZ_L */
+/* TG_BT_FSZ_H */
+/* TG_BT_VACT_T_ST_L */
+/* TG_BT_VACT_T_ST_H */
+/* TG_BT_VACT_B_ST_L */
+/* TG_BT_VACT_B_ST_H */
+/* TG_BT_VACT_SZ_L */
+/* TG_BT_VACT_SZ_H */
+/* TG_BT_VSYNC_SZ */
+
+/* HDCP E-FUSE Control Register */
+/* HDCP_E_FUSE_CTRL */
+#define HDMI_EFUSE_CTRL_HDCP_KEY_READ (1 << 0)
+
+/* HDCP_E_FUSE_STATUS */
+#define HDMI_EFUSE_ECC_FAIL (1 << 2)
+#define HDMI_EFUSE_ECC_BUSY (1 << 1)
+#define HDMI_EFUSE_ECC_DONE (1)
+
+/* EFUSE_ADDR_WIDTH */
+/* EFUSE_SIGDEV_ASSERT */
+/* EFUSE_SIGDEV_DE-ASSERT */
+/* EFUSE_PRCHG_ASSERT */
+/* EFUSE_PRCHG_DE-ASSERT */
+/* EFUSE_FSET_ASSERT */
+/* EFUSE_FSET_DE-ASSERT */
+/* EFUSE_SENSING */
+/* EFUSE_SCK_ASSERT */
+/* EFUSE_SCK_DEASSERT */
+/* EFUSE_SDOUT_OFFSET */
+/* EFUSE_READ_OFFSET */
+
+/* HDCP_SHA_RESULT */
+#define HDMI_HDCP_SHA_VALID_NO_RD (0 << 1)
+#define HDMI_HDCP_SHA_VALID_RD (1 << 1)
+#define HDMI_HDCP_SHA_VALID (1)
+#define HDMI_HDCP_SHA_NO_VALID (0)
+
+/* DC_CONTRAL */
+#define HDMI_DC_CTL_12 (1 << 1)
+#define HDMI_DC_CTL_8 (0)
+#define HDMI_DC_CTL_10 (1)
+#endif /* __ARCH_ARM_REGS_HDMI_H */
diff --git a/drivers/media/video/exynos/tv/regs-mixer.h b/drivers/media/video/exynos/tv/regs-mixer.h
new file mode 100644
index 0000000..15ad119
--- /dev/null
+++ b/drivers/media/video/exynos/tv/regs-mixer.h
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Mixer register header file for Samsung Mixer driver
+ *
+ * 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.
+*/
+#ifndef SAMSUNG_REGS_MIXER_H
+#define SAMSUNG_REGS_MIXER_H
+
+#include <plat/map-base.h>
+
+/* SYSREG for local path between Gscaler and Mixer */
+#define SYSREG_DISP1BLK_CFG (S3C_VA_SYS + 0x0214)
+
+#define DISP1BLK_CFG_FIFORST_DISP1 (1 << 23)
+#define DISP1BLK_CFG_MIXER_MASK (0x3F << 2)
+#define DISP1BLK_CFG_MIXER0_VALID (1 << 7)
+#define DISP1BLK_CFG_MIXER0_SRC_GSC(x) (x << 5)
+#define DISP1BLK_CFG_MIXER1_VALID (1 << 4)
+#define DISP1BLK_CFG_MIXER1_SRC_GSC(x) (x << 2)
+
+/*
+ * Register part
+ */
+#define MXR_STATUS 0x0000
+#define MXR_CFG 0x0004
+#define MXR_INT_EN 0x0008
+#define MXR_INT_STATUS 0x000C
+#define MXR_LAYER_CFG 0x0010
+#define MXR_VIDEO_CFG 0x0014
+#define MXR_GRAPHIC0_CFG 0x0020
+#define MXR_GRAPHIC0_BASE 0x0024
+#define MXR_GRAPHIC0_SPAN 0x0028
+#define MXR_GRAPHIC0_SXY 0x002C
+#define MXR_GRAPHIC0_WH 0x0030
+#define MXR_GRAPHIC0_DXY 0x0034
+#define MXR_GRAPHIC0_BLANK 0x0038
+#define MXR_GRAPHIC1_CFG 0x0040
+#define MXR_GRAPHIC1_BASE 0x0044
+#define MXR_GRAPHIC1_SPAN 0x0048
+#define MXR_GRAPHIC1_SXY 0x004C
+#define MXR_GRAPHIC1_WH 0x0050
+#define MXR_GRAPHIC1_DXY 0x0054
+#define MXR_GRAPHIC1_BLANK 0x0058
+#define MXR_BG_CFG 0x0060
+#define MXR_BG_COLOR0 0x0064
+#define MXR_BG_COLOR1 0x0068
+#define MXR_BG_COLOR2 0x006C
+#define MXR_CM_COEFF_Y 0x0080
+#define MXR_CM_COEFF_CB 0x0084
+#define MXR_CM_COEFF_CR 0x0088
+/* after EXYNOS5250 for video layer transfered from Gscaler */
+#define MXR_VIDEO_LT 0x0090
+#define MXR_VIDEO_RB 0x0094
+
+/* after EXYNOS4212 for setting 3D */
+#define MXR_TVOUT_CFG 0x0100
+#define MXR_3D_ACTIVE_VIDEO 0x0104
+#define MXR_3D_ACTIVE_SPACE 0x0108
+
+/* after EXYNOS5250, support 2 sub-mixers */
+#define MXR1_LAYER_CFG 0x0110
+#define MXR1_VIDEO_CFG 0x0114
+#define MXR1_GRAPHIC0_CFG 0x0120
+#define MXR1_GRAPHIC0_BASE 0x0124
+#define MXR1_GRAPHIC0_SPAN 0x0128
+#define MXR1_GRAPHIC0_SXY 0x012C
+#define MXR1_GRAPHIC0_WH 0x0130
+#define MXR1_GRAPHIC0_DXY 0x0134
+#define MXR1_GRAPHIC0_BLANK 0x0138
+#define MXR1_GRAPHIC1_CFG 0x0140
+#define MXR1_GRAPHIC1_BASE 0x0144
+#define MXR1_GRAPHIC1_SPAN 0x0148
+#define MXR1_GRAPHIC1_SXY 0x014C
+#define MXR1_GRAPHIC1_WH 0x0150
+#define MXR1_GRAPHIC1_DXY 0x0154
+#define MXR1_GRAPHIC1_BLANK 0x0158
+#define MXR1_BG_CFG 0x0160
+#define MXR1_BG_COLOR0 0x0164
+#define MXR1_BG_COLOR1 0x0168
+#define MXR1_BG_COLOR2 0x016C
+#define MXR1_CM_COEFF_Y 0x0180
+#define MXR1_CM_COEFF_CB 0x0184
+#define MXR1_CM_COEFF_CR 0x0188
+/* after EXYNOS5250 for video layer transfered from Gscaler */
+#define MXR1_VIDEO_LT 0x0190
+#define MXR1_VIDEO_RB 0x0194
+
+/* for parametrized access to layer registers */
+#define MXR_GRAPHIC_CFG(i) (0x0020 + (i) * 0x20)
+#define MXR_GRAPHIC_BASE(i) (0x0024 + (i) * 0x20)
+#define MXR_GRAPHIC_SPAN(i) (0x0028 + (i) * 0x20)
+#define MXR_GRAPHIC_SXY(i) (0x002C + (i) * 0x20)
+#define MXR_GRAPHIC_WH(i) (0x0030 + (i) * 0x20)
+#define MXR_GRAPHIC_DXY(i) (0x0034 + (i) * 0x20)
+#define MXR_GRAPHIC_BLANK(i) (0x0038 + (i) * 0x20)
+
+/* after EXYNOS5250, support 2 sub-mixers */
+#define MXR1_GRAPHIC_CFG(i) (0x0120 + (i) * 0x20)
+#define MXR1_GRAPHIC_BASE(i) (0x0124 + (i) * 0x20)
+#define MXR1_GRAPHIC_SPAN(i) (0x0128 + (i) * 0x20)
+#define MXR1_GRAPHIC_SXY(i) (0x012C + (i) * 0x20)
+#define MXR1_GRAPHIC_WH(i) (0x0130 + (i) * 0x20)
+#define MXR1_GRAPHIC_DXY(i) (0x0134 + (i) * 0x20)
+#define MXR1_GRAPHIC_BLANK(i) (0x0138 + (i) * 0x20)
+
+/*
+ * Bit definition part
+ */
+
+/* generates mask for range of bits */
+#define MXR_MASK(high_bit, low_bit) \
+ (((2 << ((high_bit) - (low_bit))) - 1) << (low_bit))
+
+#define MXR_MASK_VAL(val, high_bit, low_bit) \
+ (((val) << (low_bit)) & MXR_MASK(high_bit, low_bit))
+
+/* bits for MXR_STATUS */
+#define MXR_STATUS_SOFT_RESET (1 << 8)
+#define MXR_STATUS_16_BURST (1 << 7)
+#define MXR_STATUS_BURST_MASK (1 << 7)
+#define MXR_STATUS_LAYER_SYNC (1 << 6)
+#define MXR_STATUS_SYNC_ENABLE (1 << 2)
+#define MXR_STATUS_REG_RUN (1 << 0)
+
+/* bits for MXR_CFG */
+#define MXR_CFG_LAYER_UPDATE (1 << 31)
+#define MXR_CFG_LAYER_UPDATE_COUNTER (3 << 29)
+#define MXR_CFG_MX1_GRP1_ENABLE (1 << 15)
+#define MXR_CFG_MX1_GRP0_ENABLE (1 << 14)
+#define MXR_CFG_MX1_VIDEO_ENABLE (1 << 13)
+#define MXR_CFG_OUT_YUV444 (0 << 8)
+#define MXR_CFG_OUT_RGB888 (1 << 8)
+#define MXR_CFG_OUT_MASK (1 << 8)
+#define MXR_CFG_DST_SDO (0 << 7)
+#define MXR_CFG_DST_HDMI (1 << 7)
+#define MXR_CFG_DST_MASK (1 << 7)
+#define MXR_CFG_SCAN_HD_720 (0 << 6)
+#define MXR_CFG_SCAN_HD_1080 (1 << 6)
+#define MXR_CFG_GRP1_ENABLE (1 << 5)
+#define MXR_CFG_GRP0_ENABLE (1 << 4)
+#define MXR_CFG_VIDEO_ENABLE (1 << 3)
+#define MXR_CFG_SCAN_INTERLACE (0 << 2)
+#define MXR_CFG_SCAN_PROGRASSIVE (1 << 2)
+#define MXR_CFG_SCAN_NTSC (0 << 1)
+#define MXR_CFG_SCAN_PAL (1 << 1)
+#define MXR_CFG_SCAN_SD (0 << 0)
+#define MXR_CFG_SCAN_HD (1 << 0)
+#define MXR_CFG_SCAN_MASK 0x47
+
+/* bits for MXR_GRAPHICn_CFG */
+#define MXR_GRP_CFG_BLANK_KEY_OFF (1 << 21)
+#define MXR_GRP_CFG_LAYER_BLEND_EN (1 << 17)
+#define MXR_GRP_CFG_PIXEL_BLEND_EN (1 << 16)
+#define MXR_GRP_CFG_FORMAT_VAL(x) MXR_MASK_VAL(x, 11, 8)
+#define MXR_GRP_CFG_FORMAT_MASK MXR_GRP_CFG_FORMAT_VAL(~0)
+#define MXR_GRP_CFG_ALPHA_VAL(x) MXR_MASK_VAL(x, 7, 0)
+
+/* bits for MXR_GRAPHICn_WH */
+#define MXR_GRP_WH_H_SCALE(x) MXR_MASK_VAL(x, 28, 28)
+#define MXR_GRP_WH_V_SCALE(x) MXR_MASK_VAL(x, 12, 12)
+#define MXR_GRP_WH_WIDTH(x) MXR_MASK_VAL(x, 26, 16)
+#define MXR_GRP_WH_HEIGHT(x) MXR_MASK_VAL(x, 10, 0)
+
+/* bits for MXR_GRAPHICn_SXY */
+#define MXR_GRP_SXY_SX(x) MXR_MASK_VAL(x, 26, 16)
+#define MXR_GRP_SXY_SY(x) MXR_MASK_VAL(x, 10, 0)
+
+/* bits for MXR_GRAPHICn_DXY */
+#define MXR_GRP_DXY_DX(x) MXR_MASK_VAL(x, 26, 16)
+#define MXR_GRP_DXY_DY(x) MXR_MASK_VAL(x, 10, 0)
+
+/* bits for MXR_INT_EN */
+#define MXR_INT_EN_VSYNC (1 << 11)
+#define MXR_INT_EN_ALL (0x38b80)
+
+/* bit for MXR_INT_STATUS */
+#define MXR_INT_STATUS_MX1_GRP1 (1 << 17)
+#define MXR_INT_STATUS_MX1_GRP0 (1 << 16)
+#define MXR_INT_STATUS_MX1_VIDEO (1 << 15)
+#define MXR_INT_CLEAR_VSYNC (1 << 11)
+#define MXR_INT_STATUS_MX0_GRP1 (1 << 9)
+#define MXR_INT_STATUS_MX0_GRP0 (1 << 8)
+#define MXR_INT_STATUS_MX0_VIDEO (1 << 7)
+#define MXR_INT_STATUS_VSYNC (1 << 0)
+
+/* bit for MXR_LAYER_CFG */
+#define MXR_LAYER_CFG_GRP1_VAL(x) MXR_MASK_VAL(x, 11, 8)
+#define MXR_LAYER_CFG_GRP0_VAL(x) MXR_MASK_VAL(x, 7, 4)
+#define MXR_LAYER_CFG_VP_VAL(x) MXR_MASK_VAL(x, 3, 0)
+
+/* bit for MXR_VIDEO_CFG */
+#define MXR_VIDEO_CFG_BLEND_EN (1 << 16)
+#define MXR_VIDEO_CFG_ALPHA(x) MXR_MASK_VAL(x, 7, 0)
+
+/* bit for MXR_VIDEO_LT */
+#define MXR_VIDEO_LT_LEFT_VAL(x) MXR_MASK_VAL(x, 31, 16)
+#define MXR_VIDEO_LT_TOP_VAL(x) MXR_MASK_VAL(x, 15, 0)
+
+/* bit for MXR_VIDEO_RB */
+#define MXR_VIDEO_RB_RIGHT_VAL(x) MXR_MASK_VAL(x, 31, 16)
+#define MXR_VIDEO_RB_BOTTOM_VAL(x) MXR_MASK_VAL(x, 15, 0)
+
+/* bit for MXR_TVOUT_CFG */
+#define MXR_TVOUT_CFG_3D_FROMAT_VAL(x) MXR_MASK_VAL(x, 5, 4)
+#define MXR_TVOUT_CFG_PATH_MIXER0 (0 << 3)
+#define MXR_TVOUT_CFG_PATH_MIXER1 (1 << 3)
+#define MXR_TVOUT_CFG_ONE_PATH (1 << 2)
+#define MXR_TVOUT_CFG_TWO_PATH (0 << 2)
+#define MXR_TVOUT_CFG_PATH_MASK (3 << 2)
+#define MXR_TVOUT_CFG_STEREO_SCOPIC (1 << 0)
+
+#endif /* SAMSUNG_REGS_MIXER_H */
diff --git a/drivers/media/video/exynos/tv/regs-sdo.h b/drivers/media/video/exynos/tv/regs-sdo.h
new file mode 100644
index 0000000..7f7c2b8a
--- /dev/null
+++ b/drivers/media/video/exynos/tv/regs-sdo.h
@@ -0,0 +1,63 @@
+/* drivers/media/video/s5p-tv/regs-sdo.h
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * SDO register description file
+ *
+ * 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.
+ */
+
+#ifndef SAMSUNG_REGS_SDO_H
+#define SAMSUNG_REGS_SDO_H
+
+/*
+ * Register part
+ */
+
+#define SDO_CLKCON 0x0000
+#define SDO_CONFIG 0x0008
+#define SDO_VBI 0x0014
+#define SDO_DAC 0x003C
+#define SDO_CCCON 0x0180
+#define SDO_IRQ 0x0280
+#define SDO_IRQMASK 0x0284
+#define SDO_VERSION 0x03D8
+
+/*
+ * Bit definition part
+ */
+
+/* SDO Clock Control Register (SDO_CLKCON) */
+#define SDO_TVOUT_SW_RESET (1 << 4)
+#define SDO_TVOUT_CLOCK_READY (1 << 1)
+#define SDO_TVOUT_CLOCK_ON (1 << 0)
+
+/* SDO Video Standard Configuration Register (SDO_CONFIG) */
+#define SDO_PROGRESSIVE (1 << 4)
+#define SDO_NTSC_M 0
+#define SDO_PAL_M 1
+#define SDO_PAL_BGHID 2
+#define SDO_PAL_N 3
+#define SDO_PAL_NC 4
+#define SDO_NTSC_443 8
+#define SDO_PAL_60 9
+#define SDO_STANDARD_MASK 0xf
+
+/* SDO VBI Configuration Register (SDO_VBI) */
+#define SDO_CVBS_WSS_INS (1 << 14)
+#define SDO_CVBS_CLOSED_CAPTION_MASK (3 << 12)
+
+/* SDO DAC Configuration Register (SDO_DAC) */
+#define SDO_POWER_ON_DAC (1 << 0)
+
+/* SDO Color Compensation On/Off Control (SDO_CCCON) */
+#define SDO_COMPENSATION_BHS_ADJ_OFF (1 << 4)
+#define SDO_COMPENSATION_CVBS_COMP_OFF (1 << 0)
+
+/* SDO Interrupt Request Register (SDO_IRQ) */
+#define SDO_VSYNC_IRQ_PEND (1 << 0)
+
+#endif /* SAMSUNG_REGS_SDO_H */
diff --git a/drivers/media/video/exynos/tv/regs-vp.h b/drivers/media/video/exynos/tv/regs-vp.h
new file mode 100644
index 0000000..6c63984
--- /dev/null
+++ b/drivers/media/video/exynos/tv/regs-vp.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Video processor register header file for Samsung Mixer driver
+ *
+ * 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.
+ */
+
+#ifndef SAMSUNG_REGS_VP_H
+#define SAMSUNG_REGS_VP_H
+
+/*
+ * Register part
+ */
+
+#define VP_ENABLE 0x0000
+#define VP_SRESET 0x0004
+#define VP_SHADOW_UPDATE 0x0008
+#define VP_FIELD_ID 0x000C
+#define VP_MODE 0x0010
+#define VP_IMG_SIZE_Y 0x0014
+#define VP_IMG_SIZE_C 0x0018
+#define VP_PER_RATE_CTRL 0x001C
+#define VP_TOP_Y_PTR 0x0028
+#define VP_BOT_Y_PTR 0x002C
+#define VP_TOP_C_PTR 0x0030
+#define VP_BOT_C_PTR 0x0034
+#define VP_ENDIAN_MODE 0x03CC
+#define VP_SRC_H_POSITION 0x0044
+#define VP_SRC_V_POSITION 0x0048
+#define VP_SRC_WIDTH 0x004C
+#define VP_SRC_HEIGHT 0x0050
+#define VP_DST_H_POSITION 0x0054
+#define VP_DST_V_POSITION 0x0058
+#define VP_DST_WIDTH 0x005C
+#define VP_DST_HEIGHT 0x0060
+#define VP_H_RATIO 0x0064
+#define VP_V_RATIO 0x0068
+#define VP_POLY8_Y0_LL 0x006C
+#define VP_POLY4_Y0_LL 0x00EC
+#define VP_POLY4_C0_LL 0x012C
+
+/*
+ * Bit definition part
+ */
+
+/* generates mask for range of bits */
+
+#define VP_MASK(high_bit, low_bit) \
+ (((2 << ((high_bit) - (low_bit))) - 1) << (low_bit))
+
+#define VP_MASK_VAL(val, high_bit, low_bit) \
+ (((val) << (low_bit)) & VP_MASK(high_bit, low_bit))
+
+ /* VP_ENABLE */
+#define VP_ENABLE_ON (1 << 0)
+
+/* VP_SRESET */
+#define VP_SRESET_PROCESSING (1 << 0)
+
+/* VP_SHADOW_UPDATE */
+#define VP_SHADOW_UPDATE_ENABLE (1 << 0)
+
+/* VP_MODE */
+#define VP_MODE_NV12 (0 << 6)
+#define VP_MODE_NV21 (1 << 6)
+#define VP_MODE_LINE_SKIP (1 << 5)
+#define VP_MODE_MEM_LINEAR (0 << 4)
+#define VP_MODE_MEM_TILED (1 << 4)
+#define VP_MODE_FMT_MASK (5 << 4)
+#define VP_MODE_FIELD_ID_AUTO_TOGGLING (1 << 2)
+#define VP_MODE_2D_IPC (1 << 1)
+
+/* VP_IMG_SIZE_Y */
+/* VP_IMG_SIZE_C */
+#define VP_IMG_HSIZE(x) VP_MASK_VAL(x, 29, 16)
+#define VP_IMG_VSIZE(x) VP_MASK_VAL(x, 13, 0)
+
+/* VP_SRC_H_POSITION */
+#define VP_SRC_H_POSITION_VAL(x) VP_MASK_VAL(x, 14, 4)
+
+/* VP_ENDIAN_MODE */
+#define VP_ENDIAN_MODE_LITTLE (1 << 0)
+
+#endif /* SAMSUNG_REGS_VP_H */
diff --git a/drivers/media/video/exynos/tv/sdo_drv.c b/drivers/media/video/exynos/tv/sdo_drv.c
new file mode 100644
index 0000000..c2975db
--- /dev/null
+++ b/drivers/media/video/exynos/tv/sdo_drv.c
@@ -0,0 +1,540 @@
+/*
+ * Samsung Standard Definition Output (SDO) driver
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ *
+ * Tomasz Stanislawski, <t.stanislaws@samsung.com>
+ *
+ * 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 Foundiation. either version 2 of the License,
+ * or (at your option) any later version
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+
+#include <media/v4l2-subdev.h>
+#include <media/exynos_mc.h>
+
+#include "regs-sdo.h"
+
+MODULE_AUTHOR("Tomasz Stanislawski, <t.stanislaws@samsung.com>");
+MODULE_DESCRIPTION("Samsung Standard Definition Output (SDO)");
+MODULE_LICENSE("GPL");
+
+/* SDO pad definitions */
+#define SDO_PAD_SINK 0
+#define SDO_PADS_NUM 1
+
+#define SDO_DEFAULT_STD V4L2_STD_PAL
+
+struct sdo_format {
+ v4l2_std_id id;
+ /* all modes are 720 pixels wide */
+ unsigned int height;
+ unsigned int cookie;
+};
+
+struct sdo_device {
+ /** pointer to device parent */
+ struct device *dev;
+ /** base address of SDO registers */
+ void __iomem *regs;
+ /** SDO interrupt */
+ unsigned int irq;
+ /** DAC source clock */
+ struct clk *sclk_dac;
+ /** DAC clock */
+ struct clk *dac;
+ /** DAC physical interface */
+ struct clk *dacphy;
+ /** clock for control of VPLL */
+ struct clk *fout_vpll;
+ /** regulator for SDO IP power */
+ struct regulator *vdac;
+ /** regulator for SDO plug detection */
+ struct regulator *vdet;
+ /** subdev used as device interface */
+ struct v4l2_subdev sd;
+ /** sink pad connected to mixer */
+ struct media_pad pad;
+ /** current format */
+ const struct sdo_format *fmt;
+};
+
+static inline struct sdo_device *sd_to_sdev(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct sdo_device, sd);
+}
+
+static inline
+void sdo_write_mask(struct sdo_device *sdev, u32 reg_id, u32 value, u32 mask)
+{
+ u32 old = readl(sdev->regs + reg_id);
+ value = (value & mask) | (old & ~mask);
+ writel(value, sdev->regs + reg_id);
+}
+
+static inline
+void sdo_write(struct sdo_device *sdev, u32 reg_id, u32 value)
+{
+ writel(value, sdev->regs + reg_id);
+}
+
+static inline
+u32 sdo_read(struct sdo_device *sdev, u32 reg_id)
+{
+ return readl(sdev->regs + reg_id);
+}
+
+static irqreturn_t sdo_irq_handler(int irq, void *dev_data)
+{
+ struct sdo_device *sdev = dev_data;
+
+ /* clear interrupt */
+ sdo_write_mask(sdev, SDO_IRQ, ~0, SDO_VSYNC_IRQ_PEND);
+ return IRQ_HANDLED;
+}
+
+static void sdo_reg_debug(struct sdo_device *sdev)
+{
+#define DBGREG(reg_id) \
+ dev_info(sdev->dev, #reg_id " = %08x\n", \
+ sdo_read(sdev, reg_id))
+
+ DBGREG(SDO_CLKCON);
+ DBGREG(SDO_CONFIG);
+ DBGREG(SDO_VBI);
+ DBGREG(SDO_DAC);
+ DBGREG(SDO_IRQ);
+ DBGREG(SDO_IRQMASK);
+ DBGREG(SDO_VERSION);
+}
+
+static const struct sdo_format sdo_format[] = {
+ { V4L2_STD_PAL_N, .height = 576, .cookie = SDO_PAL_N },
+ { V4L2_STD_PAL_Nc, .height = 576, .cookie = SDO_PAL_NC },
+ { V4L2_STD_PAL_M, .height = 480, .cookie = SDO_PAL_M },
+ { V4L2_STD_PAL_60, .height = 480, .cookie = SDO_PAL_60 },
+ { V4L2_STD_NTSC_443, .height = 480, .cookie = SDO_NTSC_443 },
+ { V4L2_STD_PAL, .height = 576, .cookie = SDO_PAL_BGHID },
+ { V4L2_STD_NTSC_M, .height = 480, .cookie = SDO_NTSC_M },
+};
+
+static const struct sdo_format *sdo_find_format(v4l2_std_id id)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(sdo_format); ++i)
+ if (sdo_format[i].id & id)
+ return &sdo_format[i];
+ return NULL;
+}
+
+static int sdo_g_tvnorms_output(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+ *std = V4L2_STD_NTSC_M | V4L2_STD_PAL_M | V4L2_STD_PAL |
+ V4L2_STD_PAL_N | V4L2_STD_PAL_Nc |
+ V4L2_STD_NTSC_443 | V4L2_STD_PAL_60;
+ return 0;
+}
+
+static int sdo_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+ struct sdo_device *sdev = sd_to_sdev(sd);
+ const struct sdo_format *fmt;
+ fmt = sdo_find_format(std);
+ if (fmt == NULL)
+ return -EINVAL;
+ sdev->fmt = fmt;
+ return 0;
+}
+
+static int sdo_g_std_output(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+ *std = sd_to_sdev(sd)->fmt->id;
+ return 0;
+}
+
+static int sdo_g_mbus_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *fmt)
+{
+ struct sdo_device *sdev = sd_to_sdev(sd);
+
+ if (!sdev->fmt)
+ return -ENXIO;
+ /* all modes are 720 pixels wide */
+ fmt->width = 720;
+ fmt->height = sdev->fmt->height;
+ fmt->code = V4L2_MBUS_FMT_FIXED;
+ fmt->field = V4L2_FIELD_INTERLACED;
+ return 0;
+}
+
+static int sdo_s_power(struct v4l2_subdev *sd, int on)
+{
+ struct sdo_device *sdev = sd_to_sdev(sd);
+ struct device *dev = sdev->dev;
+ int ret;
+
+ dev_info(dev, "sdo_s_power(%d)\n", on);
+
+ if (on)
+ ret = pm_runtime_get_sync(dev);
+ else
+ ret = pm_runtime_put_sync(dev);
+
+ /* only values < 0 indicate errors */
+ return IS_ERR_VALUE(ret) ? ret : 0;
+}
+
+static int sdo_streamon(struct sdo_device *sdev)
+{
+ /* set proper clock for Timing Generator */
+ clk_set_rate(sdev->fout_vpll, 54000000);
+ dev_info(sdev->dev, "fout_vpll.rate = %lu\n",
+ clk_get_rate(sdev->fout_vpll));
+ /* enable clock in SDO */
+ sdo_write_mask(sdev, SDO_CLKCON, ~0, SDO_TVOUT_CLOCK_ON);
+ clk_enable(sdev->dacphy);
+ /* enable DAC */
+ sdo_write_mask(sdev, SDO_DAC, ~0, SDO_POWER_ON_DAC);
+ sdo_reg_debug(sdev);
+ return 0;
+}
+
+static int sdo_streamoff(struct sdo_device *sdev)
+{
+ int tries;
+
+ sdo_write_mask(sdev, SDO_DAC, 0, SDO_POWER_ON_DAC);
+ clk_disable(sdev->dacphy);
+ sdo_write_mask(sdev, SDO_CLKCON, 0, SDO_TVOUT_CLOCK_ON);
+ for (tries = 100; tries; --tries) {
+ if (sdo_read(sdev, SDO_CLKCON) & SDO_TVOUT_CLOCK_READY)
+ break;
+ mdelay(1);
+ }
+ if (tries == 0)
+ dev_err(sdev->dev, "failed to stop streaming\n");
+ return tries ? 0 : -EIO;
+}
+
+static int sdo_s_stream(struct v4l2_subdev *sd, int on)
+{
+ struct sdo_device *sdev = sd_to_sdev(sd);
+ return on ? sdo_streamon(sdev) : sdo_streamoff(sdev);
+}
+
+static const struct v4l2_subdev_core_ops sdo_sd_core_ops = {
+ .s_power = sdo_s_power,
+};
+
+static const struct v4l2_subdev_video_ops sdo_sd_video_ops = {
+ .s_std_output = sdo_s_std_output,
+ .g_std_output = sdo_g_std_output,
+ .g_tvnorms_output = sdo_g_tvnorms_output,
+ .g_mbus_fmt = sdo_g_mbus_fmt,
+ .s_stream = sdo_s_stream,
+};
+
+static const struct v4l2_subdev_ops sdo_sd_ops = {
+ .core = &sdo_sd_core_ops,
+ .video = &sdo_sd_video_ops,
+};
+
+static int sdo_runtime_suspend(struct device *dev)
+{
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct sdo_device *sdev = sd_to_sdev(sd);
+
+ dev_info(dev, "suspend\n");
+ regulator_disable(sdev->vdet);
+ regulator_disable(sdev->vdac);
+ clk_disable(sdev->sclk_dac);
+ return 0;
+}
+
+static int sdo_runtime_resume(struct device *dev)
+{
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct sdo_device *sdev = sd_to_sdev(sd);
+
+ dev_info(dev, "resume\n");
+ clk_enable(sdev->sclk_dac);
+ regulator_enable(sdev->vdac);
+ regulator_enable(sdev->vdet);
+
+ /* software reset */
+ sdo_write_mask(sdev, SDO_CLKCON, ~0, SDO_TVOUT_SW_RESET);
+ mdelay(10);
+ sdo_write_mask(sdev, SDO_CLKCON, 0, SDO_TVOUT_SW_RESET);
+
+ /* setting TV mode */
+ sdo_write_mask(sdev, SDO_CONFIG, sdev->fmt->cookie, SDO_STANDARD_MASK);
+ /* XXX: forcing interlaced mode using undocumented bit */
+ sdo_write_mask(sdev, SDO_CONFIG, 0, SDO_PROGRESSIVE);
+ /* turn all VBI off */
+ sdo_write_mask(sdev, SDO_VBI, 0, SDO_CVBS_WSS_INS |
+ SDO_CVBS_CLOSED_CAPTION_MASK);
+ /* turn all post processing off */
+ sdo_write_mask(sdev, SDO_CCCON, ~0, SDO_COMPENSATION_BHS_ADJ_OFF |
+ SDO_COMPENSATION_CVBS_COMP_OFF);
+ sdo_reg_debug(sdev);
+ return 0;
+}
+
+static const struct dev_pm_ops sdo_pm_ops = {
+ .runtime_suspend = sdo_runtime_suspend,
+ .runtime_resume = sdo_runtime_resume,
+};
+
+static int sdo_link_setup(struct media_entity *entity,
+ const struct media_pad *local,
+ const struct media_pad *remote, u32 flags)
+{
+ return 0;
+}
+
+/* sdo entity operations */
+static const struct media_entity_operations sdo_entity_ops = {
+ .link_setup = sdo_link_setup,
+};
+
+static int sdo_register_entity(struct sdo_device *sdev)
+{
+ struct v4l2_subdev *sd = &sdev->sd;
+ struct v4l2_device *v4l2_dev;
+ struct media_pad *pads = &sdev->pad;
+ struct media_entity *me = &sd->entity;
+ struct device *dev = sdev->dev;
+ struct exynos_md *md;
+ int ret;
+
+ dev_dbg(dev, "SDO entity init\n");
+
+ /* init sdo subdev */
+ v4l2_subdev_init(sd, &sdo_sd_ops);
+ sd->owner = THIS_MODULE;
+ strlcpy(sd->name, "s5p-sdo", sizeof(sd->name));
+
+ dev_set_drvdata(dev, sd);
+
+ /* init sdo sub-device as entity */
+ pads[SDO_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+ me->ops = &sdo_entity_ops;
+ ret = media_entity_init(me, SDO_PADS_NUM, pads, 0);
+ if (ret) {
+ dev_err(dev, "failed to initialize media entity\n");
+ return ret;
+ }
+
+ /* get output media ptr for registering sdo's sd */
+ md = (struct exynos_md *)module_name_to_driver_data(MDEV_MODULE_NAME);
+ if (!md) {
+ dev_err(dev, "failed to get output media device\n");
+ return -ENODEV;
+ }
+
+ v4l2_dev = &md->v4l2_dev;
+
+ /* regiser SDO subdev as entity to v4l2_dev pointer of
+ * output media device
+ */
+ ret = v4l2_device_register_subdev(v4l2_dev, sd);
+ if (ret) {
+ dev_err(dev, "failed to register SDO subdev\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static void sdo_entity_info_print(struct sdo_device *sdev)
+{
+ struct v4l2_subdev *sd = &sdev->sd;
+ struct media_entity *me = &sd->entity;
+
+ dev_dbg(sdev->dev, "\n************** SDO entity info **************\n");
+ dev_dbg(sdev->dev, "[SUB DEVICE INFO]\n");
+ entity_info_print(me, sdev->dev);
+ dev_dbg(sdev->dev, "*********************************************\n\n");
+}
+
+static int __devinit sdo_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct sdo_device *sdev;
+ struct resource *res;
+ int ret = 0;
+ struct clk *sclk_vpll;
+
+ dev_info(dev, "probe start\n");
+ sdev = kzalloc(sizeof *sdev, GFP_KERNEL);
+ if (!sdev) {
+ dev_err(dev, "not enough memory.\n");
+ ret = -ENOMEM;
+ goto fail;
+ }
+ sdev->dev = dev;
+
+ /* mapping registers */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(dev, "get memory resource failed.\n");
+ ret = -ENXIO;
+ goto fail_sdev;
+ }
+
+ sdev->regs = ioremap(res->start, resource_size(res));
+ if (sdev->regs == NULL) {
+ dev_err(dev, "register mapping failed.\n");
+ ret = -ENXIO;
+ goto fail_sdev;
+ }
+
+ /* acquiring interrupt */
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (res == NULL) {
+ dev_err(dev, "get interrupt resource failed.\n");
+ ret = -ENXIO;
+ goto fail_regs;
+ }
+ ret = request_irq(res->start, sdo_irq_handler, 0, "s5p-sdo", sdev);
+ if (ret) {
+ dev_err(dev, "request interrupt failed.\n");
+ goto fail_regs;
+ }
+ sdev->irq = res->start;
+
+ /* acquire clocks */
+ sdev->sclk_dac = clk_get(dev, "sclk_dac");
+ if (IS_ERR_OR_NULL(sdev->sclk_dac)) {
+ dev_err(dev, "failed to get clock 'sclk_dac'\n");
+ ret = -ENXIO;
+ goto fail_irq;
+ }
+ sdev->dac = clk_get(dev, "dac");
+ if (IS_ERR_OR_NULL(sdev->dac)) {
+ dev_err(dev, "failed to get clock 'dac'\n");
+ ret = -ENXIO;
+ goto fail_sclk_dac;
+ }
+ sdev->dacphy = clk_get(dev, "dacphy");
+ if (IS_ERR_OR_NULL(sdev->dacphy)) {
+ dev_err(dev, "failed to get clock 'dacphy'\n");
+ ret = -ENXIO;
+ goto fail_dac;
+ }
+ sclk_vpll = clk_get(dev, "sclk_vpll");
+ if (IS_ERR_OR_NULL(sclk_vpll)) {
+ dev_err(dev, "failed to get clock 'sclk_vpll'\n");
+ ret = -ENXIO;
+ goto fail_dacphy;
+ }
+ clk_set_parent(sdev->sclk_dac, sclk_vpll);
+ clk_put(sclk_vpll);
+ sdev->fout_vpll = clk_get(dev, "fout_vpll");
+ if (IS_ERR_OR_NULL(sdev->fout_vpll)) {
+ dev_err(dev, "failed to get clock 'fout_vpll'\n");
+ goto fail_dacphy;
+ }
+ dev_info(dev, "fout_vpll.rate = %lu\n", clk_get_rate(sclk_vpll));
+
+ /* enable gate for dac clock, because mixer uses it */
+ clk_enable(sdev->dac);
+
+ /* configure power management */
+ pm_runtime_enable(dev);
+
+ /* set default format */
+ sdev->fmt = sdo_find_format(SDO_DEFAULT_STD);
+ BUG_ON(sdev->fmt == NULL);
+
+ ret = sdo_register_entity(sdev);
+ if (ret)
+ goto fail_dacphy;
+
+ sdo_entity_info_print(sdev);
+
+ dev_info(dev, "probe succeeded\n");
+ return 0;
+
+fail_dacphy:
+ clk_put(sdev->dacphy);
+fail_dac:
+ clk_put(sdev->dac);
+fail_sclk_dac:
+ clk_put(sdev->sclk_dac);
+fail_irq:
+ free_irq(sdev->irq, sdev);
+fail_regs:
+ iounmap(sdev->regs);
+fail_sdev:
+ kfree(sdev);
+fail:
+ dev_info(dev, "probe failed\n");
+ return ret;
+}
+
+static int __devexit sdo_remove(struct platform_device *pdev)
+{
+ struct v4l2_subdev *sd = dev_get_drvdata(&pdev->dev);
+ struct sdo_device *sdev = sd_to_sdev(sd);
+
+ pm_runtime_disable(&pdev->dev);
+ clk_disable(sdev->dac);
+ regulator_put(sdev->vdet);
+ regulator_put(sdev->vdac);
+ clk_put(sdev->fout_vpll);
+ clk_put(sdev->dacphy);
+ clk_put(sdev->dac);
+ clk_put(sdev->sclk_dac);
+ free_irq(sdev->irq, sdev);
+ iounmap(sdev->regs);
+ kfree(sdev);
+
+ dev_info(&pdev->dev, "remove successful\n");
+ return 0;
+}
+
+static struct platform_driver sdo_driver __refdata = {
+ .probe = sdo_probe,
+ .remove = __devexit_p(sdo_remove),
+ .driver = {
+ .name = "s5p-sdo",
+ .owner = THIS_MODULE,
+ .pm = &sdo_pm_ops,
+ }
+};
+
+static int __init sdo_init(void)
+{
+ int ret;
+ static const char banner[] __initdata = KERN_INFO \
+ "Samsung Standard Definition Output (SDO) driver, "
+ "(c) 2010-2011 Samsung Electronics Co., Ltd.\n";
+ printk(banner);
+
+ ret = platform_driver_register(&sdo_driver);
+ if (ret)
+ printk(KERN_ERR "SDO platform driver register failed\n");
+
+ return ret;
+}
+module_init(sdo_init);
+
+static void __exit sdo_exit(void)
+{
+ platform_driver_unregister(&sdo_driver);
+}
+module_exit(sdo_exit);
diff --git a/drivers/media/video/m5mols/Kconfig b/drivers/media/video/m5mols/Kconfig
index 302dc3d..ddb3314 100644
--- a/drivers/media/video/m5mols/Kconfig
+++ b/drivers/media/video/m5mols/Kconfig
@@ -1,5 +1,6 @@
config VIDEO_M5MOLS
tristate "Fujitsu M-5MOLS 8MP sensor support"
- depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+ depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API &&\
+ (VIDEO_S5P_MIPI_CSIS || VIDEO_EXYNOS_MIPI_CSIS)
---help---
This driver supports Fujitsu M-5MOLS camera sensor with ISP
diff --git a/drivers/media/video/m5mols/Makefile b/drivers/media/video/m5mols/Makefile
index 0a44e02..b5d19bf 100644
--- a/drivers/media/video/m5mols/Makefile
+++ b/drivers/media/video/m5mols/Makefile
@@ -1,3 +1,3 @@
-m5mols-objs := m5mols_core.o m5mols_controls.o m5mols_capture.o
+m5mols-objs := m5mols_core.o m5mols_controls.o
obj-$(CONFIG_VIDEO_M5MOLS) += m5mols.o
diff --git a/drivers/media/video/m5mols/m5mols.h b/drivers/media/video/m5mols/m5mols.h
index 4b021e1..94022e2 100644
--- a/drivers/media/video/m5mols/m5mols.h
+++ b/drivers/media/video/m5mols/m5mols.h
@@ -1,5 +1,5 @@
/*
- * Header for M-5MOLS 8M Pixel camera sensor with ISP
+ * Header for M5MOLS 8M Pixel camera sensor with ISP
*
* Copyright (C) 2011 Samsung Electronics Co., Ltd.
* Author: HeungJun Kim <riverful.kim@samsung.com>
@@ -19,12 +19,24 @@
#include <media/v4l2-subdev.h>
#include "m5mols_reg.h"
+#define M5MO_JPEG_MAXSIZE 0x3A0000
+#define M5MO_THUMB_MAXSIZE 0xFC00
+#define M5MO_POST_MAXSIZE 0xBB800
+#define M5MO_JPEG_MEMSIZE M5MO_JPEG_MAXSIZE + M5MO_THUMB_MAXSIZE + M5MO_POST_MAXSIZE
+
+#define v4l2msg(fmt, arg...) do { \
+ v4l2_dbg(1, m5mols_debug, &info->sd, fmt, ## arg); \
+} while (0)
+
extern int m5mols_debug;
-#define to_m5mols(__sd) container_of(__sd, struct m5mols_info, sd)
-
-#define to_sd(__ctrl) \
- (&container_of(__ctrl->handler, struct m5mols_info, handle)->sd)
+enum m5mols_mode {
+ MODE_SYSINIT,
+ MODE_PARMSET,
+ MODE_MONITOR,
+ MODE_CAPTURE,
+ MODE_UNKNOWN,
+};
enum m5mols_restype {
M5MOLS_RESTYPE_MONITOR,
@@ -32,268 +44,341 @@
M5MOLS_RESTYPE_MAX,
};
-/**
- * struct m5mols_resolution - structure for the resolution
- * @type: resolution type according to the pixel code
- * @width: width of the resolution
- * @height: height of the resolution
- * @reg: resolution preset register value
- */
+enum m5mols_status {
+ STATUS_SYSINIT,
+ STATUS_PARMSET,
+ STATUS_MONITOR,
+ STATUS_AUTO_FOCUS,
+ STATUS_FACE_DETECTION,
+ STATUS_DUAL_CAPTURE,
+ STATUS_SINGLE_CAPTURE,
+ STATUS_PREVIEW,
+ STATUS_UNKNOWN,
+};
+
+enum m5mols_intterrupt_bit {
+ INT_BIT_MODE,
+ INT_BIT_AF,
+ INT_BIT_ZOOM,
+ INT_BIT_CAPTURE,
+ INT_BIT_FRAME_SYNC,
+ INT_BIT_FD,
+ INT_BIT_LENS_INIT,
+ INT_BIT_SOUND,
+};
+
+enum m5mols_i2c_size {
+ I2C_8BIT = 1,
+ I2C_16BIT = 2,
+ I2C_32BIT = 4,
+ I2C_MAX = 4,
+};
+
+enum m5mols_fps {
+ M5MOLS_FPS_AUTO = 0,
+ M5MOLS_FPS_10 = 10,
+ M5MOLS_FPS_12 = 12,
+ M5MOLS_FPS_15 = 15,
+ M5MOLS_FPS_20 = 20,
+ M5MOLS_FPS_21 = 21,
+ M5MOLS_FPS_22 = 22,
+ M5MOLS_FPS_23 = 23,
+ M5MOLS_FPS_24 = 24,
+ M5MOLS_FPS_30 = 30,
+ M5MOLS_FPS_MAX = M5MOLS_FPS_30,
+};
+
+enum m5mols_res_type {
+ M5MOLS_RES_MON,
+ /* It's not supported below yet. */
+ M5MOLS_RES_CAPTURE,
+ M5MOLS_RES_MAX,
+};
+
struct m5mols_resolution {
- u8 reg;
- enum m5mols_restype type;
- u16 width;
- u16 height;
+ u8 value;
+ enum m5mols_res_type type;
+ u16 width;
+ u16 height;
};
-/**
- * struct m5mols_exif - structure for the EXIF information of M-5MOLS
- * @exposure_time: exposure time register value
- * @shutter_speed: speed of the shutter register value
- * @aperture: aperture register value
- * @exposure_bias: it calls also EV bias
- * @iso_speed: ISO register value
- * @flash: status register value of the flash
- * @sdr: status register value of the Subject Distance Range
- * @qval: not written exact meaning in document
- */
+struct m5mols_format {
+ enum v4l2_mbus_pixelcode code;
+ enum v4l2_colorspace colorspace;
+};
+
+struct m5mols_control {
+ u32 id;
+ s32 min;
+ s32 max;
+ u32 step;
+ s32 def;
+};
+
struct m5mols_exif {
- u32 exposure_time;
- u32 shutter_speed;
- u32 aperture;
- u32 brightness;
- u32 exposure_bias;
- u16 iso_speed;
- u16 flash;
- u16 sdr;
- u16 qval;
+ u32 exposure_time;
+ u32 shutter_speed;
+ u32 aperture;
+ u32 brightness;
+ u32 exposure_bias;
+ u16 iso_speed;
+ u16 flash;
+ u16 sdr; /* subject(object) distance range */
+ u16 qval; /* This is not written precisely in datasheet. */
};
-/**
- * struct m5mols_capture - Structure for the capture capability
- * @exif: EXIF information
- * @main: size in bytes of the main image
- * @thumb: size in bytes of the thumb image, if it was accompanied
- * @total: total size in bytes of the produced image
- */
struct m5mols_capture {
- struct m5mols_exif exif;
- u32 main;
- u32 thumb;
- u32 total;
+ struct m5mols_exif exif;
+ u32 main;
+ u32 thumb;
+ u32 total;
};
-/**
- * struct m5mols_scenemode - structure for the scenemode capability
- * @metering: metering light register value
- * @ev_bias: EV bias register value
- * @wb_mode: mode which means the WhiteBalance is Auto or Manual
- * @wb_preset: whitebalance preset register value in the Manual mode
- * @chroma_en: register value whether the Chroma capability is enabled or not
- * @chroma_lvl: chroma's level register value
- * @edge_en: register value Whether the Edge capability is enabled or not
- * @edge_lvl: edge's level register value
- * @af_range: Auto Focus's range
- * @fd_mode: Face Detection mode
- * @mcc: Multi-axis Color Conversion which means emotion color
- * @light: status of the Light
- * @flash: status of the Flash
- * @tone: Tone color which means Contrast
- * @iso: ISO register value
- * @capt_mode: Mode of the Image Stabilization while the camera capturing
- * @wdr: Wide Dynamic Range register value
- *
- * The each value according to each scenemode is recommended in the documents.
- */
-struct m5mols_scenemode {
- u8 metering;
- u8 ev_bias;
- u8 wb_mode;
- u8 wb_preset;
- u8 chroma_en;
- u8 chroma_lvl;
- u8 edge_en;
- u8 edge_lvl;
- u8 af_range;
- u8 fd_mode;
- u8 mcc;
- u8 light;
- u8 flash;
- u8 tone;
- u8 iso;
- u8 capt_mode;
- u8 wdr;
-};
-
-/**
- * struct m5mols_version - firmware version information
- * @customer: customer information
- * @project: version of project information according to customer
- * @fw: firmware revision
- * @hw: hardware revision
- * @param: version of the parameter
- * @awb: Auto WhiteBalance algorithm version
- * @str: information about manufacturer and packaging vendor
- * @af: Auto Focus version
- *
- * The register offset starts the customer version at 0x0, and it ends
- * the awb version at 0x09. The customer, project information occupies 1 bytes
- * each. And also the fw, hw, param, awb each requires 2 bytes. The str is
- * unique string associated with firmware's version. It includes information
- * about manufacturer and the vendor of the sensor's packaging. The least
- * significant 2 bytes of the string indicate packaging manufacturer.
- */
-#define VERSION_STRING_SIZE 22
struct m5mols_version {
- u8 customer;
- u8 project;
- u16 fw;
- u16 hw;
- u16 param;
- u16 awb;
- u8 str[VERSION_STRING_SIZE];
- u8 af;
+ u8 ctm_code; /* customer code */
+ u8 pj_code; /* project code */
+ u16 fw; /* firmware version */
+ u16 hw; /* hardware version */
+ u16 parm; /* parameter version */
+ u16 awb; /* AWB version */
};
-/**
- * struct m5mols_info - M-5MOLS driver data structure
- * @pdata: platform data
- * @sd: v4l-subdev instance
- * @pad: media pad
- * @ffmt: current fmt according to resolution type
- * @res_type: current resolution type
- * @irq_waitq: waitqueue for the capture
- * @flags: state variable for the interrupt handler
- * @handle: control handler
- * @autoexposure: Auto Exposure control
- * @exposure: Exposure control
- * @autowb: Auto White Balance control
- * @colorfx: Color effect control
- * @saturation: Saturation control
- * @zoom: Zoom control
- * @ver: information of the version
- * @cap: the capture mode attributes
- * @power: current sensor's power status
- * @isp_ready: 1 when the ISP controller has completed booting
- * @ctrl_sync: 1 when the control handler state is restored in H/W
- * @lock_ae: true means the Auto Exposure is locked
- * @lock_awb: true means the Aut WhiteBalance is locked
- * @resolution: register value for current resolution
- * @mode: register value for current operation mode
- * @set_power: optional power callback to the board code
- */
struct m5mols_info {
- const struct m5mols_platform_data *pdata;
- struct v4l2_subdev sd;
+ struct v4l2_subdev sd;
struct media_pad pad;
- struct v4l2_mbus_framefmt ffmt[M5MOLS_RESTYPE_MAX];
int res_type;
-
- wait_queue_head_t irq_waitq;
- atomic_t irq_done;
-
- struct v4l2_ctrl_handler handle;
-
- /* Autoexposure/exposure control cluster */
- struct v4l2_ctrl *autoexposure;
- struct v4l2_ctrl *exposure;
-
- struct v4l2_ctrl *autowb;
- struct v4l2_ctrl *colorfx;
- struct v4l2_ctrl *saturation;
- struct v4l2_ctrl *zoom;
-
- struct m5mols_version ver;
- struct m5mols_capture cap;
-
- unsigned int isp_ready:1;
- unsigned int power:1;
- unsigned int ctrl_sync:1;
-
- bool lock_ae;
- bool lock_awb;
u8 resolution;
- u8 mode;
+ struct v4l2_mbus_framefmt fmt[M5MOLS_RES_MAX];
+ struct v4l2_fract tpf;
+ struct v4l2_ctrl_handler handle;
+ struct {
+ /* support only AE of the Monitor Mode in this version */
+ struct v4l2_ctrl *autoexposure;
+ struct v4l2_ctrl *exposure;
+ bool is_ae_lock;
+ };
+ struct v4l2_ctrl *autofocus;
+ bool is_focus;
+ struct v4l2_ctrl *autowb;
+ bool is_awb_lock;
+ struct v4l2_ctrl *colorfx;
+ struct v4l2_ctrl *saturation;
+ struct v4l2_ctrl *zoom;
+ struct v4l2_ctrl *jpeg_size;
+ struct v4l2_ctrl *encoded_size;
+
+ enum m5mols_mode mode;
+ enum m5mols_mode mode_backup;
+ enum m5mols_status status;
+ enum v4l2_mbus_pixelcode code;
+
+ struct m5mols_capture cap;
+ wait_queue_head_t cap_wait;
+ bool captured;
+
+ const struct m5mols_platform_data *pdata;
+ struct m5mols_version ver;
+ struct work_struct work;
+ bool power;
+
+ /* for additional power if needed. */
int (*set_power)(struct device *dev, int on);
};
-#define is_available_af(__info) (__info->ver.af)
-#define is_code(__code, __type) (__code == m5mols_default_ffmt[__type].code)
-#define is_manufacturer(__info, __manufacturer) \
- (__info->ver.str[0] == __manufacturer[0] && \
- __info->ver.str[1] == __manufacturer[1])
-/*
- * I2C operation of the M-5MOLS
- *
- * The I2C read operation of the M-5MOLS requires 2 messages. The first
- * message sends the information about the command, command category, and total
- * message size. The second message is used to retrieve the data specifed in
- * the first message
- *
- * 1st message 2nd message
- * +-------+---+----------+-----+-------+ +------+------+------+------+
- * | size1 | R | category | cmd | size2 | | d[0] | d[1] | d[2] | d[3] |
- * +-------+---+----------+-----+-------+ +------+------+------+------+
- * - size1: message data size(5 in this case)
- * - size2: desired buffer size of the 2nd message
- * - d[0..3]: according to size2
- *
- * The I2C write operation needs just one message. The message includes
- * category, command, total size, and desired data.
- *
- * 1st message
- * +-------+---+----------+-----+------+------+------+------+
- * | size1 | W | category | cmd | d[0] | d[1] | d[2] | d[3] |
- * +-------+---+----------+-----+------+------+------+------+
- * - d[0..3]: according to size1
- */
-int m5mols_read_u8(struct v4l2_subdev *sd, u32 reg_comb, u8 *val);
-int m5mols_read_u16(struct v4l2_subdev *sd, u32 reg_comb, u16 *val);
-int m5mols_read_u32(struct v4l2_subdev *sd, u32 reg_comb, u32 *val);
-int m5mols_write(struct v4l2_subdev *sd, u32 reg_comb, u32 val);
-
-int m5mols_busy_wait(struct v4l2_subdev *sd, u32 reg, u32 value, u32 mask,
- int timeout);
-
-/* Mask value for busy waiting until M-5MOLS I2C interface is initialized */
-#define M5MOLS_I2C_RDY_WAIT_FL (1 << 16)
-/* ISP state transition timeout, in ms */
-#define M5MOLS_MODE_CHANGE_TIMEOUT 200
-#define M5MOLS_BUSY_WAIT_DEF_TIMEOUT 250
-
-/*
- * Mode operation of the M-5MOLS
- *
- * Changing the mode of the M-5MOLS is needed right executing order.
- * There are three modes(PARAMETER, MONITOR, CAPTURE) which can be changed
- * by user. There are various categories associated with each mode.
- *
- * +============================================================+
- * | mode | category |
- * +============================================================+
- * | FLASH | FLASH(only after Stand-by or Power-on) |
- * | SYSTEM | SYSTEM(only after sensor arm-booting) |
- * | PARAMETER | PARAMETER |
- * | MONITOR | MONITOR(preview), Auto Focus, Face Detection |
- * | CAPTURE | Single CAPTURE, Preview(recording) |
- * +============================================================+
- *
- * The available executing order between each modes are as follows:
- * PARAMETER <---> MONITOR <---> CAPTURE
- */
-int m5mols_mode(struct m5mols_info *info, u8 mode);
-
-int m5mols_enable_interrupt(struct v4l2_subdev *sd, u8 reg);
-int m5mols_wait_interrupt(struct v4l2_subdev *sd, u8 condition, u32 timeout);
-int m5mols_restore_controls(struct m5mols_info *info);
-int m5mols_start_capture(struct m5mols_info *info);
-int m5mols_do_scenemode(struct m5mols_info *info, u8 mode);
-int m5mols_lock_3a(struct m5mols_info *info, bool lock);
+/* control functions */
int m5mols_set_ctrl(struct v4l2_ctrl *ctrl);
-/* The firmware function */
-int m5mols_update_fw(struct v4l2_subdev *sd,
- int (*set_power)(struct m5mols_info *, bool));
+/* I2C functions - referenced by below I2C helper functions */
+int m5mols_read_reg(struct v4l2_subdev *sd, enum m5mols_i2c_size size,
+ u8 category, u8 cmd, u32 *val);
+int m5mols_write_reg(struct v4l2_subdev *sd, enum m5mols_i2c_size size,
+ u8 category, u8 cmd, u32 val);
+int m5mols_check_busy(struct v4l2_subdev *sd,
+ u8 category, u8 cmd, u32 value);
+int m5mols_set_mode(struct v4l2_subdev *sd, enum m5mols_mode mode);
+enum m5mols_status m5mols_get_status(struct v4l2_subdev *sd);
+/*
+ * helper functions
+ */
+static inline struct m5mols_info *to_m5mols(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct m5mols_info, sd);
+}
+
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+ return &container_of(ctrl->handler, struct m5mols_info, handle)->sd;
+}
+
+static inline bool is_streaming(struct v4l2_subdev *sd)
+{
+ struct m5mols_info *info = to_m5mols(sd);
+ return (info->mode == MODE_MONITOR) || (info->mode == MODE_CAPTURE);
+}
+
+static inline bool is_stoped(struct v4l2_subdev *sd)
+{
+ struct m5mols_info *info = to_m5mols(sd);
+ return (info->mode != MODE_MONITOR) && (info->mode != MODE_CAPTURE);
+}
+
+static inline bool is_powerup(struct v4l2_subdev *sd)
+{
+ struct m5mols_info *info = to_m5mols(sd);
+ return info->power;
+}
+
+static inline int m5mols_set_mode_backup(struct v4l2_subdev *sd,
+ enum m5mols_mode mode)
+{
+ struct m5mols_info *info = to_m5mols(sd);
+
+ info->mode_backup = info->mode;
+ return m5mols_set_mode(sd, mode);
+}
+
+static inline int m5mols_set_mode_restore(struct v4l2_subdev *sd)
+{
+ struct m5mols_info *info = to_m5mols(sd);
+ int ret;
+
+ ret = m5mols_set_mode(sd, info->mode_backup);
+ if (!ret)
+ info->mode = info->mode_backup;
+ return ret;
+}
+
+static inline int __must_check i2c_w8_system(struct v4l2_subdev *sd,
+ u8 cmd, u32 val)
+{
+ return m5mols_write_reg(sd, I2C_8BIT, CAT_SYSTEM, cmd, val);
+}
+
+static inline int __must_check i2c_w8_param(struct v4l2_subdev *sd,
+ u8 cmd, u32 val)
+{
+ return m5mols_write_reg(sd, I2C_8BIT, CAT_PARAM, cmd, val);
+}
+
+static inline int __must_check i2c_w8_mon(struct v4l2_subdev *sd,
+ u8 cmd, u32 val)
+{
+ return m5mols_write_reg(sd, I2C_8BIT, CAT_MON, cmd, val);
+}
+
+static inline int __must_check i2c_w8_ae(struct v4l2_subdev *sd,
+ u8 cmd, u32 val)
+{
+ return m5mols_write_reg(sd, I2C_8BIT, CAT_AE, cmd, val);
+}
+
+static inline int __must_check i2c_w16_ae(struct v4l2_subdev *sd,
+ u8 cmd, u32 val)
+{
+ return m5mols_write_reg(sd, I2C_16BIT, CAT_AE, cmd, val);
+}
+
+static inline int __must_check i2c_w8_wb(struct v4l2_subdev *sd,
+ u8 cmd, u32 val)
+{
+ return m5mols_write_reg(sd, I2C_8BIT, CAT_WB, cmd, val);
+}
+
+static inline int __must_check i2c_w8_lens(struct v4l2_subdev *sd,
+ u8 cmd, u32 val)
+{
+ return m5mols_write_reg(sd, I2C_8BIT, CAT_LENS, cmd, val);
+}
+
+static inline int __must_check i2c_w8_capt_parm(struct v4l2_subdev *sd,
+ u8 cmd, u32 val)
+{
+ return m5mols_write_reg(sd, I2C_8BIT, CAT_CAPTURE_PARAMETER, cmd, val);
+}
+
+static inline int __must_check i2c_w8_capt_ctrl(struct v4l2_subdev *sd,
+ u8 cmd, u32 val)
+{
+ return m5mols_write_reg(sd, I2C_8BIT, CAT_CAPTURE_CONTROL, cmd, val);
+}
+
+static inline int __must_check i2c_w8_flash(struct v4l2_subdev *sd,
+ u8 cmd, u32 val)
+{
+ return m5mols_write_reg(sd, I2C_8BIT, CAT_FLASH, cmd, val);
+}
+
+static inline int __must_check i2c_r8_system(struct v4l2_subdev *sd,
+ u8 cmd, u32 *val)
+{
+ return m5mols_read_reg(sd, I2C_8BIT, CAT_SYSTEM, cmd, val);
+}
+
+static inline int __must_check i2c_r8_param(struct v4l2_subdev *sd,
+ u8 cmd, u32 *val)
+{
+ return m5mols_read_reg(sd, I2C_8BIT, CAT_PARAM, cmd, val);
+}
+
+static inline int __must_check i2c_r8_mon(struct v4l2_subdev *sd,
+ u8 cmd, u32 *val)
+{
+ return m5mols_read_reg(sd, I2C_8BIT, CAT_MON, cmd, val);
+}
+
+static inline int __must_check i2c_r8_ae(struct v4l2_subdev *sd,
+ u8 cmd, u32 *val)
+{
+ return m5mols_read_reg(sd, I2C_8BIT, CAT_AE, cmd, val);
+}
+
+static inline int __must_check i2c_r16_ae(struct v4l2_subdev *sd,
+ u8 cmd, u32 *val)
+{
+ return m5mols_read_reg(sd, I2C_16BIT, CAT_AE, cmd, val);
+}
+
+static inline int __must_check i2c_r8_lens(struct v4l2_subdev *sd,
+ u8 cmd, u32 *val)
+{
+ return m5mols_read_reg(sd, I2C_8BIT, CAT_LENS, cmd, val);
+}
+
+static inline int __must_check i2c_r32_capt_ctrl(struct v4l2_subdev *sd,
+ u8 cmd, u32 *val)
+{
+ return m5mols_read_reg(sd, I2C_32BIT, CAT_CAPTURE_CONTROL, cmd, val);
+}
+
+static inline int __must_check i2c_r16_exif(struct v4l2_subdev *sd,
+ u8 cmd, u32 *val)
+{
+ return m5mols_read_reg(sd, I2C_16BIT, CAT_EXIF, cmd, val);
+}
+
+static inline int __must_check i2c_r32_exif(struct v4l2_subdev *sd,
+ u8 cmd, u32 *val)
+{
+ return m5mols_read_reg(sd, I2C_32BIT, CAT_EXIF, cmd, val);
+}
+
+static int m5mols_set_ae_lock(struct m5mols_info *info, bool lock)
+{
+ struct v4l2_subdev *sd = &info->sd;
+
+ info->is_ae_lock = lock;
+
+ return i2c_w8_ae(sd, CAT3_AE_LOCK, !!lock);
+}
+
+static int m5mols_set_awb_lock(struct m5mols_info *info, bool lock)
+{
+ struct v4l2_subdev *sd = &info->sd;
+
+ info->is_awb_lock = lock;
+
+ return i2c_w8_wb(sd, CAT6_AWB_LOCK, !!lock);
+}
#endif /* M5MOLS_H */
diff --git a/drivers/media/video/m5mols/m5mols_capture.c b/drivers/media/video/m5mols/m5mols_capture.c
index ba25e8e..d947192 100644
--- a/drivers/media/video/m5mols/m5mols_capture.c
+++ b/drivers/media/video/m5mols/m5mols_capture.c
@@ -1,4 +1,3 @@
-
/*
* The Capture code for Fujitsu M-5MOLS ISP
*
@@ -19,18 +18,35 @@
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
+#include <linux/version.h>
#include <linux/gpio.h>
#include <linux/regulator/consumer.h>
#include <linux/videodev2.h>
+#include <linux/version.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-subdev.h>
#include <media/m5mols.h>
-#include <media/s5p_fimc.h>
#include "m5mols.h"
#include "m5mols_reg.h"
+static int m5mols_capture_error_handler(struct m5mols_info *info,
+ int timeout)
+{
+ int ret;
+
+ /* Disable all interrupts and clear relevant interrupt staus bits */
+ ret = m5mols_write(&info->sd, SYSTEM_INT_ENABLE,
+ info->interrupt & ~(REG_INT_CAPTURE));
+ if (ret)
+ return ret;
+
+ if (timeout == 0)
+ return -ETIMEDOUT;
+
+ return 0;
+}
/**
* m5mols_read_rational - I2C read of a rational number
*
@@ -107,54 +123,69 @@
{
struct v4l2_subdev *sd = &info->sd;
u8 resolution = info->resolution;
+ int timeout;
int ret;
/*
- * Synchronize the controls, set the capture frame resolution and color
- * format. The frame capture is initiated during switching from Monitor
- * to Capture mode.
+ * Preparing capture. Setting control & interrupt before entering
+ * capture mode
+ *
+ * 1) change to MONITOR mode for operating control & interrupt
+ * 2) set controls (considering v4l2_control value & lock 3A)
+ * 3) set interrupt
+ * 4) change to CAPTURE mode
*/
ret = m5mols_mode(info, REG_MONITOR);
if (!ret)
- ret = m5mols_restore_controls(info);
+ ret = m5mols_sync_controls(info);
+ if (!ret)
+ ret = m5mols_lock_3a(info, true);
+ if (!ret)
+ ret = m5mols_enable_interrupt(sd, REG_INT_CAPTURE);
+ if (!ret)
+ ret = m5mols_mode(info, REG_CAPTURE);
+ if (!ret) {
+ /* Wait for capture interrupt, after changing capture mode */
+ timeout = wait_event_interruptible_timeout(info->irq_waitq,
+ test_bit(ST_CAPT_IRQ, &info->flags),
+ msecs_to_jiffies(2000));
+ if (test_and_clear_bit(ST_CAPT_IRQ, &info->flags))
+ ret = m5mols_capture_error_handler(info, timeout);
+ }
+ if (!ret)
+ ret = m5mols_lock_3a(info, false);
+ if (ret)
+ return ret;
+ /*
+ * Starting capture. Setting capture frame count and resolution and
+ * the format(available format: JPEG, Bayer RAW, YUV).
+ *
+ * 1) select single or multi(enable to 25), format, size
+ * 2) set interrupt
+ * 3) start capture(for main image, now)
+ * 4) get information
+ * 5) notify file size to v4l2 device(e.g, to s5p-fimc v4l2 device)
+ */
+ ret = m5mols_write(sd, CAPC_SEL_FRAME, 1);
if (!ret)
ret = m5mols_write(sd, CAPP_YUVOUT_MAIN, REG_JPEG);
if (!ret)
ret = m5mols_write(sd, CAPP_MAIN_IMAGE_SIZE, resolution);
if (!ret)
- ret = m5mols_lock_3a(info, true);
- if (!ret)
- ret = m5mols_mode(info, REG_CAPTURE);
- if (!ret)
- /* Wait until a frame is captured to ISP internal memory */
- ret = m5mols_wait_interrupt(sd, REG_INT_CAPTURE, 2000);
- if (!ret)
- ret = m5mols_lock_3a(info, false);
- if (ret)
- return ret;
-
- /*
- * Initiate the captured data transfer to a MIPI-CSI receiver.
- */
- ret = m5mols_write(sd, CAPC_SEL_FRAME, 1);
+ ret = m5mols_enable_interrupt(sd, REG_INT_CAPTURE);
if (!ret)
ret = m5mols_write(sd, CAPC_START, REG_CAP_START_MAIN);
if (!ret) {
- bool captured = false;
- unsigned int size;
-
/* Wait for the capture completion interrupt */
- ret = m5mols_wait_interrupt(sd, REG_INT_CAPTURE, 2000);
- if (!ret) {
- captured = true;
+ timeout = wait_event_interruptible_timeout(info->irq_waitq,
+ test_bit(ST_CAPT_IRQ, &info->flags),
+ msecs_to_jiffies(2000));
+ if (test_and_clear_bit(ST_CAPT_IRQ, &info->flags)) {
ret = m5mols_capture_info(info);
+ if (!ret)
+ v4l2_subdev_notify(sd, 0, &info->cap.total);
}
- size = captured ? info->cap.main : 0;
- v4l2_dbg(1, m5mols_debug, sd, "%s: size: %d, thumb.: %d B\n",
- __func__, size, info->cap.thumb);
-
- v4l2_subdev_notify(sd, S5P_FIMC_TX_END_NOTIFY, &size);
}
- return ret;
+ return m5mols_capture_error_handler(info, timeout);
}
diff --git a/drivers/media/video/m5mols/m5mols_controls.c b/drivers/media/video/m5mols/m5mols_controls.c
index d135d20..3e08018 100644
--- a/drivers/media/video/m5mols/m5mols_controls.c
+++ b/drivers/media/video/m5mols/m5mols_controls.c
@@ -1,5 +1,5 @@
/*
- * Controls for M-5MOLS 8M Pixel camera sensor with ISP
+ * Controls for M5MOLS 8M Pixel camera sensor with ISP
*
* Copyright (C) 2011 Samsung Electronics Co., Ltd.
* Author: HeungJun Kim <riverful.kim@samsung.com>
@@ -14,285 +14,186 @@
*/
#include <linux/i2c.h>
-#include <linux/delay.h>
#include <linux/videodev2.h>
#include <media/v4l2-ctrls.h>
#include "m5mols.h"
#include "m5mols_reg.h"
-static struct m5mols_scenemode m5mols_default_scenemode[] = {
- [REG_SCENE_NORMAL] = {
- REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
- REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
- REG_AF_NORMAL, REG_FD_OFF,
- REG_MCC_NORMAL, REG_LIGHT_OFF, REG_FLASH_OFF,
- 5, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
- },
- [REG_SCENE_PORTRAIT] = {
- REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
- REG_CHROMA_ON, 3, REG_EDGE_ON, 4,
- REG_AF_NORMAL, BIT_FD_EN | BIT_FD_DRAW_FACE_FRAME,
- REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
- 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
- },
- [REG_SCENE_LANDSCAPE] = {
- REG_AE_ALL, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
- REG_CHROMA_ON, 4, REG_EDGE_ON, 6,
- REG_AF_NORMAL, REG_FD_OFF,
- REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
- 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
- },
- [REG_SCENE_SPORTS] = {
- REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
- REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
- REG_AF_NORMAL, REG_FD_OFF,
- REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
- 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
- },
- [REG_SCENE_PARTY_INDOOR] = {
- REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
- REG_CHROMA_ON, 4, REG_EDGE_ON, 5,
- REG_AF_NORMAL, REG_FD_OFF,
- REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
- 6, REG_ISO_200, REG_CAP_NONE, REG_WDR_OFF,
- },
- [REG_SCENE_BEACH_SNOW] = {
- REG_AE_CENTER, REG_AE_INDEX_10_POS, REG_AWB_AUTO, 0,
- REG_CHROMA_ON, 4, REG_EDGE_ON, 5,
- REG_AF_NORMAL, REG_FD_OFF,
- REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
- 6, REG_ISO_50, REG_CAP_NONE, REG_WDR_OFF,
- },
- [REG_SCENE_SUNSET] = {
- REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_PRESET,
- REG_AWB_DAYLIGHT,
- REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
- REG_AF_NORMAL, REG_FD_OFF,
- REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
- 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
- },
- [REG_SCENE_DAWN_DUSK] = {
- REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_PRESET,
- REG_AWB_FLUORESCENT_1,
- REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
- REG_AF_NORMAL, REG_FD_OFF,
- REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
- 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
- },
- [REG_SCENE_FALL] = {
- REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
- REG_CHROMA_ON, 5, REG_EDGE_ON, 5,
- REG_AF_NORMAL, REG_FD_OFF,
- REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
- 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
- },
- [REG_SCENE_NIGHT] = {
- REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
- REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
- REG_AF_NORMAL, REG_FD_OFF,
- REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
- 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
- },
- [REG_SCENE_AGAINST_LIGHT] = {
- REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
- REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
- REG_AF_NORMAL, REG_FD_OFF,
- REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
- 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
- },
- [REG_SCENE_FIRE] = {
- REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
- REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
- REG_AF_NORMAL, REG_FD_OFF,
- REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
- 6, REG_ISO_50, REG_CAP_NONE, REG_WDR_OFF,
- },
- [REG_SCENE_TEXT] = {
- REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
- REG_CHROMA_ON, 3, REG_EDGE_ON, 7,
- REG_AF_MACRO, REG_FD_OFF,
- REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
- 6, REG_ISO_AUTO, REG_CAP_ANTI_SHAKE, REG_WDR_ON,
- },
- [REG_SCENE_CANDLE] = {
- REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
- REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
- REG_AF_NORMAL, REG_FD_OFF,
- REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
- 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
- },
-};
-
-/**
- * m5mols_do_scenemode() - Change current scenemode
- * @mode: Desired mode of the scenemode
- *
- * WARNING: The execution order is important. Do not change the order.
- */
-int m5mols_do_scenemode(struct m5mols_info *info, u8 mode)
+static int m5mols_wb_mode(struct m5mols_info *info, struct v4l2_ctrl *ctrl)
{
struct v4l2_subdev *sd = &info->sd;
- struct m5mols_scenemode scenemode = m5mols_default_scenemode[mode];
int ret;
- if (mode > REG_SCENE_CANDLE)
- return -EINVAL;
+ if (info->is_awb_lock) {
+ ret = m5mols_set_awb_lock(info, false);
+ if (!ret)
+ return ret;
+ }
- ret = m5mols_lock_3a(info, false);
- if (!ret)
- ret = m5mols_write(sd, AE_EV_PRESET_MONITOR, mode);
- if (!ret)
- ret = m5mols_write(sd, AE_EV_PRESET_CAPTURE, mode);
- if (!ret)
- ret = m5mols_write(sd, AE_MODE, scenemode.metering);
- if (!ret)
- ret = m5mols_write(sd, AE_INDEX, scenemode.ev_bias);
- if (!ret)
- ret = m5mols_write(sd, AWB_MODE, scenemode.wb_mode);
- if (!ret)
- ret = m5mols_write(sd, AWB_MANUAL, scenemode.wb_preset);
- if (!ret)
- ret = m5mols_write(sd, MON_CHROMA_EN, scenemode.chroma_en);
- if (!ret)
- ret = m5mols_write(sd, MON_CHROMA_LVL, scenemode.chroma_lvl);
- if (!ret)
- ret = m5mols_write(sd, MON_EDGE_EN, scenemode.edge_en);
- if (!ret)
- ret = m5mols_write(sd, MON_EDGE_LVL, scenemode.edge_lvl);
- if (!ret && is_available_af(info))
- ret = m5mols_write(sd, AF_MODE, scenemode.af_range);
- if (!ret && is_available_af(info))
- ret = m5mols_write(sd, FD_CTL, scenemode.fd_mode);
- if (!ret)
- ret = m5mols_write(sd, MON_TONE_CTL, scenemode.tone);
- if (!ret)
- ret = m5mols_write(sd, AE_ISO, scenemode.iso);
- if (!ret)
- ret = m5mols_mode(info, REG_CAPTURE);
- if (!ret)
- ret = m5mols_write(sd, CAPP_WDR_EN, scenemode.wdr);
- if (!ret)
- ret = m5mols_write(sd, CAPP_MCC_MODE, scenemode.mcc);
- if (!ret)
- ret = m5mols_write(sd, CAPP_LIGHT_CTRL, scenemode.light);
- if (!ret)
- ret = m5mols_write(sd, CAPP_FLASH_CTRL, scenemode.flash);
- if (!ret)
- ret = m5mols_write(sd, CAPC_MODE, scenemode.capt_mode);
- if (!ret)
- ret = m5mols_mode(info, REG_MONITOR);
+ /* 0x01 : Auto Whitebalance, 0x02 : Manual Whitebalance. */
+ return i2c_w8_wb(sd, CAT6_AWB_MODE, (ctrl->val) ? 0x1 : 0x2);
- return ret;
}
-static int m5mols_lock_ae(struct m5mols_info *info, bool lock)
+static int m5mols_exposure_mode(struct m5mols_info *info,
+ struct v4l2_ctrl *ctrl)
{
- int ret = 0;
-
- if (info->lock_ae != lock)
- ret = m5mols_write(&info->sd, AE_LOCK,
- lock ? REG_AE_LOCK : REG_AE_UNLOCK);
- if (!ret)
- info->lock_ae = lock;
-
- return ret;
-}
-
-static int m5mols_lock_awb(struct m5mols_info *info, bool lock)
-{
- int ret = 0;
-
- if (info->lock_awb != lock)
- ret = m5mols_write(&info->sd, AWB_LOCK,
- lock ? REG_AWB_LOCK : REG_AWB_UNLOCK);
- if (!ret)
- info->lock_awb = lock;
-
- return ret;
-}
-
-/* m5mols_lock_3a() - Lock 3A(Auto Exposure, Auto Whitebalance, Auto Focus) */
-int m5mols_lock_3a(struct m5mols_info *info, bool lock)
-{
+ struct v4l2_subdev *sd = &info->sd;
int ret;
- ret = m5mols_lock_ae(info, lock);
+ if (info->is_ae_lock) {
+ ret = m5mols_set_ae_lock(info, false);
+ if (ret)
+ return ret;
+ }
+
+ /* 0x01 : Auto Exposure, 0x0 : Manual Exposure. */
+ return i2c_w8_ae(sd, CAT3_AE_MODE,
+ (ctrl->val == V4L2_EXPOSURE_AUTO) ? 0x1 : 0x0);
+}
+
+static int m5mols_exposure(struct m5mols_info *info)
+{
+ struct v4l2_subdev *sd = &info->sd;
+
+ return i2c_w16_ae(sd, CAT3_MANUAL_GAIN_MON, info->exposure->val);
+}
+
+static int m5mols_zoom(struct m5mols_info *info, struct v4l2_ctrl *ctrl)
+{
+ struct v4l2_subdev *sd = &info->sd;
+
+ return i2c_w8_mon(sd, CAT2_ZOOM, ctrl->val);
+}
+
+static int m5mols_focus_mode(struct m5mols_info *info,
+ struct v4l2_ctrl *ctrl)
+{
+ struct v4l2_subdev *sd = &info->sd;
+ u32 reg;
+ int ret;
+
+ ret = m5mols_set_mode(sd, MODE_MONITOR);
if (!ret)
- ret = m5mols_lock_awb(info, lock);
- /* Don't need to handle unlocking AF */
- if (!ret && is_available_af(info) && lock)
- ret = m5mols_write(&info->sd, AF_EXECUTE, REG_AF_STOP);
+ ret = i2c_r8_system(sd, CAT0_INT_FACTOR, ®);
+ if (!ret)
+ ret = i2c_w8_system(sd, CAT0_INT_ENABLE, (1 << INT_BIT_AF));
+ if (!ret)
+ /* must be excuted in the monitor mode */
+ ret = i2c_w8_lens(sd, CATA_INIT_AF_FUNC, 0x1);
+
+ /* 0x0 : Normal AF mode
+ * 0x1 : Macro AF mode
+ * 0x2 : Continuous AF mode (Not working) */
+ return i2c_w8_lens(sd, CATA_AF_MODE, 0x0);
+}
+
+static int m5mols_focus(struct m5mols_info *info, struct v4l2_ctrl *ctrl)
+{
+ struct v4l2_subdev *sd = &info->sd;
+
+ /* 0x0: Stop,
+ 0x1: Excute AF,
+ 0x02: Excutre MF rel(Not tested),
+ 0x03: Excute MF absol(Not tested) */
+ return i2c_w8_lens(sd, CATA_AF_EXCUTE, ctrl->val);
+}
+
+static int m5mols_set_saturation(struct m5mols_info *info,
+ struct v4l2_ctrl *ctrl)
+{
+ struct v4l2_subdev *sd = &info->sd;
+ static u8 m5mols_chroma_lvl[] = {
+ 0x1c, 0x3e, 0x5f, 0x80, 0xa1, 0xc2, 0xe4,
+ };
+ int ret;
+
+ ret = i2c_w8_mon(sd, CAT2_CHROMA_LVL, m5mols_chroma_lvl[ctrl->val]);
+ if (!ret)
+ ret = i2c_w8_mon(sd, CAT2_CHROMA_EN, true);
return ret;
}
-/* m5mols_set_ctrl() - The main s_ctrl function called by m5mols_set_ctrl() */
+static int m5mols_set_colorfx(struct m5mols_info *info, struct v4l2_ctrl *ctrl)
+{
+ struct v4l2_subdev *sd = &info->sd;
+ static u8 m5mols_effects_gamma[] = { /* cat 1: Effects */
+ [V4L2_COLORFX_NEGATIVE] = 0x01,
+ [V4L2_COLORFX_EMBOSS] = 0x06,
+ [V4L2_COLORFX_SKETCH] = 0x07,
+ };
+ static u8 m5mols_cfixb_chroma[] = { /* cat 2: Cr for effect */
+ [V4L2_COLORFX_BW] = 0x0,
+ [V4L2_COLORFX_SEPIA] = 0xd8,
+ [V4L2_COLORFX_SKY_BLUE] = 0x40,
+ [V4L2_COLORFX_GRASS_GREEN] = 0xe0,
+ };
+ static u8 m5mols_cfixr_chroma[] = { /* cat 2: Cb for effect */
+ [V4L2_COLORFX_BW] = 0x0,
+ [V4L2_COLORFX_SEPIA] = 0x18,
+ [V4L2_COLORFX_SKY_BLUE] = 0x00,
+ [V4L2_COLORFX_GRASS_GREEN] = 0xe0,
+ };
+ int ret = -EINVAL;
+
+ switch (ctrl->val) {
+ case V4L2_COLORFX_NONE:
+ return i2c_w8_mon(sd, CAT2_COLOR_EFFECT, false);
+ case V4L2_COLORFX_BW: /* chroma: Gray */
+ case V4L2_COLORFX_SEPIA: /* chroma: Sepia */
+ case V4L2_COLORFX_SKY_BLUE: /* chroma: Blue */
+ case V4L2_COLORFX_GRASS_GREEN: /* chroma: Green */
+ ret = i2c_w8_mon(sd, CAT2_CFIXB,
+ m5mols_cfixb_chroma[ctrl->val]);
+ if (!ret)
+ ret = i2c_w8_mon(sd, CAT2_CFIXR,
+ m5mols_cfixr_chroma[ctrl->val]);
+ if (!ret)
+ ret = i2c_w8_mon(sd, CAT2_COLOR_EFFECT, true);
+ return ret;
+ case V4L2_COLORFX_NEGATIVE: /* gamma: Negative */
+ case V4L2_COLORFX_EMBOSS: /* gamma: Emboss */
+ case V4L2_COLORFX_SKETCH: /* gamma: Outline */
+ ret = i2c_w8_param(sd, CAT1_EFFECT,
+ m5mols_effects_gamma[ctrl->val]);
+ if (!ret)
+ ret = i2c_w8_mon(sd, CAT2_COLOR_EFFECT, true);
+ return ret;
+ }
+
+ return ret;
+}
+
int m5mols_set_ctrl(struct v4l2_ctrl *ctrl)
{
struct v4l2_subdev *sd = to_sd(ctrl);
struct m5mols_info *info = to_m5mols(sd);
- int ret;
+ int ret = 0;
switch (ctrl->id) {
case V4L2_CID_ZOOM_ABSOLUTE:
- return m5mols_write(sd, MON_ZOOM, ctrl->val);
-
+ return m5mols_zoom(info, ctrl);
+ case V4L2_CID_FOCUS_AUTO:
+ if (ctrl->val != 0)
+ ret = m5mols_focus_mode(info, ctrl);
+ if (!ret)
+ ret = m5mols_focus(info, ctrl);
+ return ret;
case V4L2_CID_EXPOSURE_AUTO:
- ret = m5mols_lock_ae(info,
- ctrl->val == V4L2_EXPOSURE_AUTO ? false : true);
- if (!ret && ctrl->val == V4L2_EXPOSURE_AUTO)
- ret = m5mols_write(sd, AE_MODE, REG_AE_ALL);
- if (!ret && ctrl->val == V4L2_EXPOSURE_MANUAL) {
- int val = info->exposure->val;
- ret = m5mols_write(sd, AE_MODE, REG_AE_OFF);
- if (!ret)
- ret = m5mols_write(sd, AE_MAN_GAIN_MON, val);
- if (!ret)
- ret = m5mols_write(sd, AE_MAN_GAIN_CAP, val);
- }
+ if (!ctrl->is_new)
+ ctrl->val = V4L2_EXPOSURE_MANUAL;
+ ret = m5mols_exposure_mode(info, ctrl);
+ if (!ret && ctrl->val == V4L2_EXPOSURE_MANUAL)
+ ret = m5mols_exposure(info);
return ret;
-
case V4L2_CID_AUTO_WHITE_BALANCE:
- ret = m5mols_lock_awb(info, ctrl->val ? false : true);
- if (!ret)
- ret = m5mols_write(sd, AWB_MODE, ctrl->val ?
- REG_AWB_AUTO : REG_AWB_PRESET);
- return ret;
-
+ return m5mols_wb_mode(info, ctrl);
case V4L2_CID_SATURATION:
- ret = m5mols_write(sd, MON_CHROMA_LVL, ctrl->val);
- if (!ret)
- ret = m5mols_write(sd, MON_CHROMA_EN, REG_CHROMA_ON);
- return ret;
-
+ return m5mols_set_saturation(info, ctrl);
case V4L2_CID_COLORFX:
- /*
- * This control uses two kinds of registers: normal & color.
- * The normal effect belongs to category 1, while the color
- * one belongs to category 2.
- *
- * The normal effect uses one register: CAT1_EFFECT.
- * The color effect uses three registers:
- * CAT2_COLOR_EFFECT, CAT2_CFIXR, CAT2_CFIXB.
- */
- ret = m5mols_write(sd, PARM_EFFECT,
- ctrl->val == V4L2_COLORFX_NEGATIVE ? REG_EFFECT_NEGA :
- ctrl->val == V4L2_COLORFX_EMBOSS ? REG_EFFECT_EMBOSS :
- REG_EFFECT_OFF);
- if (!ret)
- ret = m5mols_write(sd, MON_EFFECT,
- ctrl->val == V4L2_COLORFX_SEPIA ?
- REG_COLOR_EFFECT_ON : REG_COLOR_EFFECT_OFF);
- if (!ret)
- ret = m5mols_write(sd, MON_CFIXR,
- ctrl->val == V4L2_COLORFX_SEPIA ?
- REG_CFIXR_SEPIA : 0);
- if (!ret)
- ret = m5mols_write(sd, MON_CFIXB,
- ctrl->val == V4L2_COLORFX_SEPIA ?
- REG_CFIXB_SEPIA : 0);
- return ret;
+ return m5mols_set_colorfx(info, ctrl);
}
return -EINVAL;
diff --git a/drivers/media/video/m5mols/m5mols_core.c b/drivers/media/video/m5mols/m5mols_core.c
index d718aee..2fe8f71 100644
--- a/drivers/media/video/m5mols/m5mols_core.c
+++ b/drivers/media/video/m5mols/m5mols_core.c
@@ -1,5 +1,5 @@
/*
- * Driver for M-5MOLS 8M Pixel camera sensor with ISP
+ * Driver for M5MOLS 8M Pixel camera sensor with ISP
*
* Copyright (C) 2011 Samsung Electronics Co., Ltd.
* Author: HeungJun Kim <riverful.kim@samsung.com>
@@ -18,10 +18,13 @@
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
+#include <linux/version.h>
#include <linux/gpio.h>
#include <linux/regulator/consumer.h>
#include <linux/videodev2.h>
+#include <linux/videodev2_exynos_media.h>
#include <linux/module.h>
+#include <linux/moduleparam.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-subdev.h>
@@ -33,35 +36,66 @@
int m5mols_debug;
module_param(m5mols_debug, int, 0644);
-#define MODULE_NAME "M5MOLS"
-#define M5MOLS_I2C_CHECK_RETRY 500
+#define MOD_NAME "M5MOLS"
+#define M5MOLS_I2C_CHECK_RETRY 50
+#define DEBUG
+#define DEFAULT_SENSOR_WIDTH 800
+#define DEFAULT_SENSOR_HEIGHT 480
-/* The regulator consumer names for external voltage regulators */
+#define m5_err \
+ do { printk("%s : %d : ret : %d\n", __func__, __LINE__, ret);\
+ } while(0)
+/* M5MOLS mode */
+static u8 m5mols_reg_mode[] = {
+ [MODE_SYSINIT] = 0x00,
+ [MODE_PARMSET] = 0x01,
+ [MODE_MONITOR] = 0x02,
+ [MODE_CAPTURE] = 0x03,
+ [MODE_UNKNOWN] = 0xff,
+};
+
+/* M5MOLS status */
+static u8 m5mols_reg_status[] = {
+ [STATUS_SYSINIT] = 0x00,
+ [STATUS_PARMSET] = 0x01,
+ [STATUS_MONITOR] = 0x02,
+ [STATUS_AUTO_FOCUS] = 0x03,
+ [STATUS_FACE_DETECTION] = 0x04,
+ [STATUS_DUAL_CAPTURE] = 0x05,
+ [STATUS_SINGLE_CAPTURE] = 0x06,
+ [STATUS_PREVIEW] = 0x07,
+ [STATUS_UNKNOWN] = 0xff,
+};
+
+/* M5MOLS regulator consumer names */
+/* The DEFAULT names of power are referenced with M5MO datasheet. */
static struct regulator_bulk_data supplies[] = {
{
- .supply = "core", /* ARM core power, 1.2V */
+ /* core power - 1.2v, generally at the M5MOLS */
+ .supply = "core",
}, {
- .supply = "dig_18", /* digital power 1, 1.8V */
+ .supply = "dig_18", /* digital power 1 - 1.8v */
}, {
- .supply = "d_sensor", /* sensor power 1, 1.8V */
+ .supply = "d_sensor", /* sensor power 1 - 1.8v */
}, {
- .supply = "dig_28", /* digital power 2, 2.8V */
+ .supply = "dig_28", /* digital power 2 - 2.8v */
}, {
- .supply = "a_sensor", /* analog power */
+ .supply = "a_sensor", /* analog power */
}, {
- .supply = "dig_12", /* digital power 3, 1.2V */
+ .supply = "dig_12", /* digital power 3 - 1.2v */
},
};
-static struct v4l2_mbus_framefmt m5mols_default_ffmt[M5MOLS_RESTYPE_MAX] = {
- [M5MOLS_RESTYPE_MONITOR] = {
- .width = 1920,
- .height = 1080,
- .code = V4L2_MBUS_FMT_VYUY8_2X8,
+/* M5MOLS default format (codes, sizes, preset values) */
+static struct v4l2_mbus_framefmt default_fmt[M5MOLS_RES_MAX] = {
+ [M5MOLS_RES_MON] = {
+ .width = DEFAULT_SENSOR_WIDTH,
+ .height = DEFAULT_SENSOR_HEIGHT,
+ .code = V4L2_MBUS_FMT_YUYV8_2X8,
.field = V4L2_FIELD_NONE,
.colorspace = V4L2_COLORSPACE_JPEG,
},
- [M5MOLS_RESTYPE_CAPTURE] = {
+ [M5MOLS_RES_CAPTURE] = {
.width = 1920,
.height = 1080,
.code = V4L2_MBUS_FMT_JPEG_1X8,
@@ -69,197 +103,201 @@
.colorspace = V4L2_COLORSPACE_JPEG,
},
};
-#define SIZE_DEFAULT_FFMT ARRAY_SIZE(m5mols_default_ffmt)
-static const struct m5mols_resolution m5mols_reg_res[] = {
- { 0x01, M5MOLS_RESTYPE_MONITOR, 128, 96 }, /* SUB-QCIF */
- { 0x03, M5MOLS_RESTYPE_MONITOR, 160, 120 }, /* QQVGA */
- { 0x05, M5MOLS_RESTYPE_MONITOR, 176, 144 }, /* QCIF */
- { 0x06, M5MOLS_RESTYPE_MONITOR, 176, 176 },
- { 0x08, M5MOLS_RESTYPE_MONITOR, 240, 320 }, /* QVGA */
- { 0x09, M5MOLS_RESTYPE_MONITOR, 320, 240 }, /* QVGA */
- { 0x0c, M5MOLS_RESTYPE_MONITOR, 240, 400 }, /* WQVGA */
- { 0x0d, M5MOLS_RESTYPE_MONITOR, 400, 240 }, /* WQVGA */
- { 0x0e, M5MOLS_RESTYPE_MONITOR, 352, 288 }, /* CIF */
- { 0x13, M5MOLS_RESTYPE_MONITOR, 480, 360 },
- { 0x15, M5MOLS_RESTYPE_MONITOR, 640, 360 }, /* qHD */
- { 0x17, M5MOLS_RESTYPE_MONITOR, 640, 480 }, /* VGA */
- { 0x18, M5MOLS_RESTYPE_MONITOR, 720, 480 },
- { 0x1a, M5MOLS_RESTYPE_MONITOR, 800, 480 }, /* WVGA */
- { 0x1f, M5MOLS_RESTYPE_MONITOR, 800, 600 }, /* SVGA */
- { 0x21, M5MOLS_RESTYPE_MONITOR, 1280, 720 }, /* HD */
- { 0x25, M5MOLS_RESTYPE_MONITOR, 1920, 1080 }, /* 1080p */
- { 0x29, M5MOLS_RESTYPE_MONITOR, 3264, 2448 }, /* 2.63fps 8M */
- { 0x39, M5MOLS_RESTYPE_MONITOR, 800, 602 }, /* AHS_MON debug */
+#define SIZE_DEFAULT_FFMT ARRAY_SIZE(default_fmt)
- { 0x02, M5MOLS_RESTYPE_CAPTURE, 320, 240 }, /* QVGA */
- { 0x04, M5MOLS_RESTYPE_CAPTURE, 400, 240 }, /* WQVGA */
- { 0x07, M5MOLS_RESTYPE_CAPTURE, 480, 360 },
- { 0x08, M5MOLS_RESTYPE_CAPTURE, 640, 360 }, /* qHD */
- { 0x09, M5MOLS_RESTYPE_CAPTURE, 640, 480 }, /* VGA */
- { 0x0a, M5MOLS_RESTYPE_CAPTURE, 800, 480 }, /* WVGA */
- { 0x10, M5MOLS_RESTYPE_CAPTURE, 1280, 720 }, /* HD */
- { 0x14, M5MOLS_RESTYPE_CAPTURE, 1280, 960 }, /* 1M */
- { 0x17, M5MOLS_RESTYPE_CAPTURE, 1600, 1200 }, /* 2M */
- { 0x19, M5MOLS_RESTYPE_CAPTURE, 1920, 1080 }, /* Full-HD */
- { 0x1a, M5MOLS_RESTYPE_CAPTURE, 2048, 1152 }, /* 3Mega */
- { 0x1b, M5MOLS_RESTYPE_CAPTURE, 2048, 1536 },
- { 0x1c, M5MOLS_RESTYPE_CAPTURE, 2560, 1440 }, /* 4Mega */
- { 0x1d, M5MOLS_RESTYPE_CAPTURE, 2560, 1536 },
- { 0x1f, M5MOLS_RESTYPE_CAPTURE, 2560, 1920 }, /* 5Mega */
- { 0x21, M5MOLS_RESTYPE_CAPTURE, 3264, 1836 }, /* 6Mega */
- { 0x22, M5MOLS_RESTYPE_CAPTURE, 3264, 1960 },
- { 0x25, M5MOLS_RESTYPE_CAPTURE, 3264, 2448 }, /* 8Mega */
+static const struct m5mols_format m5mols_formats[] = {
+ [M5MOLS_RES_MON] = {
+ .code = V4L2_MBUS_FMT_YUYV8_2X8,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ },
+ [M5MOLS_RES_CAPTURE] = {
+ .code = V4L2_MBUS_FMT_JPEG_1X8,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ },
};
-/**
- * m5mols_swap_byte - an byte array to integer conversion function
- * @size: size in bytes of I2C packet defined in the M-5MOLS datasheet
- *
- * Convert I2C data byte array with performing any required byte
- * reordering to assure proper values for each data type, regardless
- * of the architecture endianness.
- */
-static u32 m5mols_swap_byte(u8 *data, u8 length)
+static const struct m5mols_resolution m5mols_resolutions[] = {
+ /* monitor size */
+ { 0x01, M5MOLS_RES_MON, 128, 96 }, /* SUB-QCIF */
+ { 0x03, M5MOLS_RES_MON, 160, 120 }, /* QQVGA */
+ { 0x05, M5MOLS_RES_MON, 176, 144 }, /* QCIF */
+ { 0x06, M5MOLS_RES_MON, 176, 176 }, /* 176*176 */
+ { 0x08, M5MOLS_RES_MON, 240, 320 }, /* 1 QVGA */
+ { 0x09, M5MOLS_RES_MON, 320, 240 }, /* QVGA */
+ { 0x0c, M5MOLS_RES_MON, 240, 400 }, /* l WQVGA */
+ { 0x0d, M5MOLS_RES_MON, 400, 240 }, /* WQVGA */
+ { 0x0e, M5MOLS_RES_MON, 352, 288 }, /* CIF */
+ { 0x13, M5MOLS_RES_MON, 480, 360 }, /* 480*360 */
+ { 0x15, M5MOLS_RES_MON, 640, 360 }, /* qHD */
+ { 0x17, M5MOLS_RES_MON, 640, 480 }, /* VGA */
+ { 0x18, M5MOLS_RES_MON, 720, 480 }, /* 720x480 */
+ { 0x1a, M5MOLS_RES_MON, 800, 480 }, /* WVGA */
+ { 0x1f, M5MOLS_RES_MON, 800, 600 }, /* SVGA */
+ { 0x21, M5MOLS_RES_MON, 1280, 720 }, /* HD */
+ { 0x25, M5MOLS_RES_MON, 1920, 1080 }, /* 1080p */
+ { 0x29, M5MOLS_RES_MON, 3264, 2448 }, /* 8M (2.63fps@3264*2448) */
+ { 0x30, M5MOLS_RES_MON, 320, 240 }, /* 60fps for slow motion */
+ { 0x31, M5MOLS_RES_MON, 320, 240 }, /* 120fps for slow motion */
+ { 0x39, M5MOLS_RES_MON, 800, 602 }, /* AHS_MON debug */
+
+ /* capture(JPEG or Bayer RAW or YUV Raw) size */
+ { 0x02, M5MOLS_RES_CAPTURE, 320, 240 }, /* QVGA */
+ { 0x04, M5MOLS_RES_CAPTURE, 400, 240 }, /* WQVGA */
+ { 0x07, M5MOLS_RES_CAPTURE, 480, 360 }, /* 480 x 360 */
+ { 0x08, M5MOLS_RES_CAPTURE, 640, 360 }, /* qHD */
+ { 0x09, M5MOLS_RES_CAPTURE, 640, 480 }, /* VGA */
+ { 0x0a, M5MOLS_RES_CAPTURE, 800, 480 }, /* WVGA */
+ { 0x10, M5MOLS_RES_CAPTURE, 1280, 720 }, /* HD */
+ { 0x14, M5MOLS_RES_CAPTURE, 1280, 960 }, /* 1M */
+ { 0x17, M5MOLS_RES_CAPTURE, 1600, 1200 }, /* 2M */
+ { 0x19, M5MOLS_RES_CAPTURE, 1920, 1080 }, /* Full-HD */
+ { 0x1a, M5MOLS_RES_CAPTURE, 2048, 1152 }, /* 3M */
+ { 0x1b, M5MOLS_RES_CAPTURE, 2048, 1536 }, /* 3M */
+ { 0x1c, M5MOLS_RES_CAPTURE, 2560, 1440 }, /* 4M */
+ { 0x1d, M5MOLS_RES_CAPTURE, 2560, 1536 }, /* 4M */
+ { 0x1f, M5MOLS_RES_CAPTURE, 2560, 1920 }, /* 5M */
+ { 0x21, M5MOLS_RES_CAPTURE, 3264, 1836 }, /* 6M */
+ { 0x22, M5MOLS_RES_CAPTURE, 3264, 1960 }, /* 6M */
+ { 0x25, M5MOLS_RES_CAPTURE, 3264, 2448 }, /* 8M */
+#ifdef M5MO_THUMB_SUPPORT
+ /* capture thumb(JPEG) size */
+ { 0x00, M5MOLS_RES_THUMB, 160, 90 }, /* 160 x 90 */
+ { 0x02, M5MOLS_RES_THUMB, 160, 120 }, /* QQVGA */
+ { 0x04, M5MOLS_RES_THUMB, 320, 240 }, /* QVGA */
+ { 0x06, M5MOLS_RES_THUMB, 400, 240 }, /* WQVGA */
+ { 0x09, M5MOLS_RES_THUMB, 480, 360 }, /* 480 x 360 */
+ { 0x0a, M5MOLS_RES_THUMB, 640, 360 }, /* qHD */
+ { 0x0b, M5MOLS_RES_THUMB, 640, 480 }, /* VGA */
+ { 0x0c, M5MOLS_RES_THUMB, 800, 480 }, /* WVGA */
+#endif
+};
+
+/* M5MOLS default FPS */
+static const struct v4l2_fract default_fps = {
+ .numerator = 1,
+ .denominator = M5MOLS_FPS_AUTO,
+};
+
+static u8 m5mols_reg_fps[] = {
+ [M5MOLS_FPS_AUTO] = 0x01,
+ [M5MOLS_FPS_10] = 0x05,
+ [M5MOLS_FPS_12] = 0x04,
+ [M5MOLS_FPS_15] = 0x03,
+ [M5MOLS_FPS_20] = 0x08,
+ [M5MOLS_FPS_21] = 0x09,
+ [M5MOLS_FPS_22] = 0x0a,
+ [M5MOLS_FPS_23] = 0x0b,
+ [M5MOLS_FPS_24] = 0x07,
+ [M5MOLS_FPS_30] = 0x02,
+};
+
+static u32 m5mols_swap_byte(u8 *data, enum m5mols_i2c_size size)
{
- if (length == 1)
+ if (size == I2C_8BIT)
return *data;
- else if (length == 2)
+ else if (size == I2C_16BIT)
return be16_to_cpu(*((u16 *)data));
else
return be32_to_cpu(*((u32 *)data));
}
-/**
- * m5mols_read - I2C read function
- * @reg: combination of size, category and command for the I2C packet
- * @size: desired size of I2C packet
- * @val: read value
+/*
+ * m5mols_read_reg/m5mols_write_reg - handle sensor's I2C communications.
*
- * Returns 0 on success, or else negative errno.
+ * The I2C command packet of M5MOLS is made up 3 kinds of I2C bytes(category,
+ * command, bytes). Reference m5mols.h.
+ *
+ * The packet is needed 2, when M5MOLS is read through I2C.
+ * The packet is needed 1, when M5MOLS is written through I2C.
+ *
+ * I2C packet common order(including both reading/writing)
+ * 1st : size (data size + 4)
+ * 2nd : READ/WRITE (R - 0x01, W - 0x02)
+ * 3rd : Category
+ * 4th : Command
+ *
+ * I2C packet order for READING operation
+ * 5th : data real size for reading
+ * And, read another I2C packet again, until data size.
+ *
+ * I2C packet order for WRITING operation
+ * 5th to 8th: an actual data to write
*/
-static int m5mols_read(struct v4l2_subdev *sd, u32 size, u32 reg, u32 *val)
+
+#define M5MOLS_BYTE_READ 0x01
+#define M5MOLS_BYTE_WRITE 0x02
+
+int m5mols_read_reg(struct v4l2_subdev *sd,
+ enum m5mols_i2c_size size,
+ u8 category, u8 cmd, u32 *val)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct m5mols_info *info = to_m5mols(sd);
- u8 rbuf[M5MOLS_I2C_MAX_SIZE + 1];
- u8 category = I2C_CATEGORY(reg);
- u8 cmd = I2C_COMMAND(reg);
struct i2c_msg msg[2];
- u8 wbuf[5];
+ u8 wbuf[5], rbuf[I2C_MAX + 1];
int ret;
if (!client->adapter)
return -ENODEV;
+ if (size != I2C_8BIT && size != I2C_16BIT && size != I2C_32BIT)
+ return -EINVAL;
+
+ /* 1st I2C operation for writing category & command. */
msg[0].addr = client->addr;
msg[0].flags = 0;
- msg[0].len = 5;
+ msg[0].len = 5; /* 1(cmd size per bytes) + 4 */
msg[0].buf = wbuf;
- wbuf[0] = 5;
+ wbuf[0] = 5; /* same right above this */
wbuf[1] = M5MOLS_BYTE_READ;
wbuf[2] = category;
wbuf[3] = cmd;
wbuf[4] = size;
+ /* 2nd I2C operation for reading data. */
msg[1].addr = client->addr;
msg[1].flags = I2C_M_RD;
msg[1].len = size + 1;
msg[1].buf = rbuf;
- /* minimum stabilization time */
- usleep_range(200, 200);
-
ret = i2c_transfer(client->adapter, msg, 2);
-
- if (ret == 2) {
- *val = m5mols_swap_byte(&rbuf[1], size);
- return 0;
- }
-
- if (info->isp_ready)
- v4l2_err(sd, "read failed: size:%d cat:%02x cmd:%02x. %d\n",
- size, category, cmd, ret);
-
- return ret < 0 ? ret : -EIO;
-}
-
-int m5mols_read_u8(struct v4l2_subdev *sd, u32 reg, u8 *val)
-{
- u32 val_32;
- int ret;
-
- if (I2C_SIZE(reg) != 1) {
- v4l2_err(sd, "Wrong data size\n");
- return -EINVAL;
- }
-
- ret = m5mols_read(sd, I2C_SIZE(reg), reg, &val_32);
- if (ret)
+ if (ret < 0) {
+ m5_err;
+ dev_err(&client->dev, "failed READ[%d] at "
+ "cat[%02x] cmd[%02x]\n",
+ size, category, cmd);
return ret;
-
- *val = (u8)val_32;
- return ret;
-}
-
-int m5mols_read_u16(struct v4l2_subdev *sd, u32 reg, u16 *val)
-{
- u32 val_32;
- int ret;
-
- if (I2C_SIZE(reg) != 2) {
- v4l2_err(sd, "Wrong data size\n");
- return -EINVAL;
}
- ret = m5mols_read(sd, I2C_SIZE(reg), reg, &val_32);
- if (ret)
- return ret;
+ *val = m5mols_swap_byte(&rbuf[1], size);
- *val = (u16)val_32;
- return ret;
+ usleep_range(15000, 20000); /* must be for stabilization */
+
+ return 0;
}
-int m5mols_read_u32(struct v4l2_subdev *sd, u32 reg, u32 *val)
-{
- if (I2C_SIZE(reg) != 4) {
- v4l2_err(sd, "Wrong data size\n");
- return -EINVAL;
- }
-
- return m5mols_read(sd, I2C_SIZE(reg), reg, val);
-}
-
-/**
- * m5mols_write - I2C command write function
- * @reg: combination of size, category and command for the I2C packet
- * @val: value to write
- *
- * Returns 0 on success, or else negative errno.
- */
-int m5mols_write(struct v4l2_subdev *sd, u32 reg, u32 val)
+int m5mols_write_reg(struct v4l2_subdev *sd,
+ enum m5mols_i2c_size size,
+ u8 category, u8 cmd, u32 val)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct m5mols_info *info = to_m5mols(sd);
- u8 wbuf[M5MOLS_I2C_MAX_SIZE + 4];
- u8 category = I2C_CATEGORY(reg);
- u8 cmd = I2C_COMMAND(reg);
- u8 size = I2C_SIZE(reg);
- u32 *buf = (u32 *)&wbuf[4];
+ struct device *cdev = &client->dev;
struct i2c_msg msg[1];
+ u8 wbuf[I2C_MAX + 4];
+ u32 *buf = (u32 *)&wbuf[4];
int ret;
if (!client->adapter)
return -ENODEV;
- if (size != 1 && size != 2 && size != 4) {
- v4l2_err(sd, "Wrong data size\n");
+ if (size != I2C_8BIT && size != I2C_16BIT && size != I2C_32BIT) {
+ dev_err(cdev, "Wrong data size\n");
return -EINVAL;
}
msg->addr = client->addr;
msg->flags = 0;
- msg->len = (u16)size + 4;
+ msg->len = size + 4;
msg->buf = wbuf;
wbuf[0] = size + 4;
wbuf[1] = M5MOLS_BYTE_WRITE;
@@ -268,213 +306,964 @@
*buf = m5mols_swap_byte((u8 *)&val, size);
- usleep_range(200, 200);
-
ret = i2c_transfer(client->adapter, msg, 1);
- if (ret == 1)
- return 0;
+ if (ret < 0) {
+ m5_err;
+ dev_err(&client->dev, "failed WRITE[%d] at "
+ "cat[%02x] cmd[%02x], ret %d\n",
+ size, msg->buf[2], msg->buf[3], ret);
+ return ret;
+ }
- if (info->isp_ready)
- v4l2_err(sd, "write failed: cat:%02x cmd:%02x ret:%d\n",
- category, cmd, ret);
+ usleep_range(15000, 20000); /* must be for stabilization */
- return ret < 0 ? ret : -EIO;
+ return 0;
}
-/**
- * m5mols_busy_wait - Busy waiting with I2C register polling
- * @reg: the I2C_REG() address of an 8-bit status register to check
- * @value: expected status register value
- * @mask: bit mask for the read status register value
- * @timeout: timeout in miliseconds, or -1 for default timeout
- *
- * The @reg register value is ORed with @mask before comparing with @value.
- *
- * Return: 0 if the requested condition became true within less than
- * @timeout ms, or else negative errno.
- */
-int m5mols_busy_wait(struct v4l2_subdev *sd, u32 reg, u32 value, u32 mask,
- int timeout)
+int m5mols_check_busy(struct v4l2_subdev *sd, u8 category, u8 cmd, u32 value)
{
- int ms = timeout < 0 ? M5MOLS_BUSY_WAIT_DEF_TIMEOUT : timeout;
- unsigned long end = jiffies + msecs_to_jiffies(ms);
- u8 status;
+ u32 busy, i;
+ int ret;
- do {
- int ret = m5mols_read_u8(sd, reg, &status);
-
- if (ret < 0 && !(mask & M5MOLS_I2C_RDY_WAIT_FL))
+ for (i = 0; i < M5MOLS_I2C_CHECK_RETRY; i++) {
+ ret = m5mols_read_reg(sd, I2C_8BIT, category, cmd, &busy);
+ if (ret < 0)
return ret;
- if (!ret && (status & mask & 0xff) == (value & 0xff))
- return 0;
- usleep_range(100, 250);
- } while (ms > 0 && time_is_after_jiffies(end));
+ if (busy == value) /* bingo */
+ return 0;
+
+ /* must be for stabilization */
+ usleep_range(10000, 10000);
+ }
return -EBUSY;
}
-/**
- * m5mols_enable_interrupt - Clear interrupt pending bits and unmask interrupts
+/*
+ * m5mols_set_mode - change and set mode of M5MOLS.
*
- * Before writing desired interrupt value the INT_FACTOR register should
- * be read to clear pending interrupts.
+ * This driver supports now only 3 modes(System, Monitor, Parameter).
*/
-int m5mols_enable_interrupt(struct v4l2_subdev *sd, u8 reg)
+int m5mols_set_mode(struct v4l2_subdev *sd, enum m5mols_mode mode)
{
struct m5mols_info *info = to_m5mols(sd);
- u8 mask = is_available_af(info) ? REG_INT_AF : 0;
- u8 dummy;
- int ret;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct device *cdev = &client->dev;
+ const char *m5mols_str_mode[] = {
+ "System initialization",
+ "Parameter setting",
+ "Monitor setting",
+ "Capture setting",
+ "Unknown",
+ };
+ int ret = 0;
- ret = m5mols_read_u8(sd, SYSTEM_INT_FACTOR, &dummy);
- if (!ret)
- ret = m5mols_write(sd, SYSTEM_INT_ENABLE, reg & ~mask);
- return ret;
-}
+ if (mode < MODE_SYSINIT || mode > MODE_UNKNOWN)
+ return -EINVAL;
-int m5mols_wait_interrupt(struct v4l2_subdev *sd, u8 irq_mask, u32 timeout)
-{
- struct m5mols_info *info = to_m5mols(sd);
-
- int ret = wait_event_interruptible_timeout(info->irq_waitq,
- atomic_add_unless(&info->irq_done, -1, 0),
- msecs_to_jiffies(timeout));
- if (ret <= 0)
- return ret ? ret : -ETIMEDOUT;
-
- return m5mols_busy_wait(sd, SYSTEM_INT_FACTOR, irq_mask,
- M5MOLS_I2C_RDY_WAIT_FL | irq_mask, -1);
-}
-
-/**
- * m5mols_reg_mode - Write the mode and check busy status
- *
- * It always accompanies a little delay changing the M-5MOLS mode, so it is
- * needed checking current busy status to guarantee right mode.
- */
-static int m5mols_reg_mode(struct v4l2_subdev *sd, u8 mode)
-{
- int ret = m5mols_write(sd, SYSTEM_SYSMODE, mode);
+ ret = i2c_w8_system(sd, CAT0_SYSMODE, m5mols_reg_mode[mode]);
+ if (!ret) {
+ /* bug detect, capture status is not 0x3 but 0x6 */
+ if (mode == MODE_CAPTURE)
+ mode = STATUS_SINGLE_CAPTURE;
+ ret = m5mols_check_busy(sd, CAT_SYSTEM, CAT0_STATUS,
+ m5mols_reg_status[mode]);
+ if (ret)
+ m5_err;
+ }
if (ret < 0)
return ret;
- return m5mols_busy_wait(sd, SYSTEM_SYSMODE, mode, 0xff,
- M5MOLS_MODE_CHANGE_TIMEOUT);
-}
-/**
- * m5mols_mode - manage the M-5MOLS's mode
- * @mode: the required operation mode
- *
- * The commands of M-5MOLS are grouped into specific modes. Each functionality
- * can be guaranteed only when the sensor is operating in mode which which
- * a command belongs to.
- */
-int m5mols_mode(struct m5mols_info *info, u8 mode)
-{
- struct v4l2_subdev *sd = &info->sd;
- int ret = -EINVAL;
- u8 reg;
-
- if (mode < REG_PARAMETER || mode > REG_CAPTURE)
- return ret;
-
- ret = m5mols_read_u8(sd, SYSTEM_SYSMODE, ®);
- if (ret || reg == mode)
- return ret;
-
- switch (reg) {
- case REG_PARAMETER:
- ret = m5mols_reg_mode(sd, REG_MONITOR);
- if (mode == REG_MONITOR)
- break;
- if (!ret)
- ret = m5mols_reg_mode(sd, REG_CAPTURE);
- break;
-
- case REG_MONITOR:
- if (mode == REG_PARAMETER) {
- ret = m5mols_reg_mode(sd, REG_PARAMETER);
- break;
- }
-
- ret = m5mols_reg_mode(sd, REG_CAPTURE);
- break;
-
- case REG_CAPTURE:
- ret = m5mols_reg_mode(sd, REG_MONITOR);
- if (mode == REG_MONITOR)
- break;
- if (!ret)
- ret = m5mols_reg_mode(sd, REG_PARAMETER);
- break;
-
- default:
- v4l2_warn(sd, "Wrong mode: %d\n", mode);
- }
-
- if (!ret)
- info->mode = mode;
+ info->mode = m5mols_reg_mode[mode];
+ dev_dbg(cdev, " mode: %s\n", m5mols_str_mode[mode]);
return ret;
}
-/**
- * m5mols_get_version - retrieve full revisions information of M-5MOLS
- *
- * The version information includes revisions of hardware and firmware,
- * AutoFocus alghorithm version and the version string.
+/*
+ * m5mols_get_status - get status of M5MOLS.
*/
-static int m5mols_get_version(struct v4l2_subdev *sd)
+enum m5mols_status m5mols_get_status(struct v4l2_subdev *sd)
{
struct m5mols_info *info = to_m5mols(sd);
- struct m5mols_version *ver = &info->ver;
- u8 *str = ver->str;
- int i;
- int ret;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct device *cdev = &client->dev;
+ const char *m5mols_str_status[] = {
+ "System initialization",
+ "Parameter setting",
+ "Monitor setting",
+ "Auto Focus",
+ "Face Detection",
+ "Multi/Dual Capture",
+ "Single Capture",
+ "Preview (Data transfer)", /* It means recording, not preview. */
+ "Unknown",
+ };
+ u32 reg;
+ int ret = 0;
- ret = m5mols_read_u8(sd, SYSTEM_VER_CUSTOMER, &ver->customer);
- if (!ret)
- ret = m5mols_read_u8(sd, SYSTEM_VER_PROJECT, &ver->project);
- if (!ret)
- ret = m5mols_read_u16(sd, SYSTEM_VER_FIRMWARE, &ver->fw);
- if (!ret)
- ret = m5mols_read_u16(sd, SYSTEM_VER_HARDWARE, &ver->hw);
- if (!ret)
- ret = m5mols_read_u16(sd, SYSTEM_VER_PARAMETER, &ver->param);
- if (!ret)
- ret = m5mols_read_u16(sd, SYSTEM_VER_AWB, &ver->awb);
- if (!ret)
- ret = m5mols_read_u8(sd, AF_VERSION, &ver->af);
+ ret = i2c_r8_system(sd, CAT0_STATUS, ®);
if (ret)
return ret;
- for (i = 0; i < VERSION_STRING_SIZE; i++) {
- ret = m5mols_read_u8(sd, SYSTEM_VER_STRING, &str[i]);
+ if (reg < STATUS_SYSINIT || reg >= STATUS_UNKNOWN)
+ return -EINVAL;
+
+ info->status = m5mols_reg_status[reg];
+ dev_dbg(cdev, " status: %s\n", m5mols_str_status[reg]);
+
+ return ret;
+}
+
+/*
+ * get_version - get M5MOLS sensor versions.
+ */
+static int get_version(struct v4l2_subdev *sd)
+{
+ struct m5mols_info *info = to_m5mols(sd);
+ union {
+ struct m5mols_version ver;
+ u8 bytes[10];
+ } value;
+ int ret, i;
+
+ for (i = CAT0_CUSTOMER_CODE; i <= CAT0_VERSION_AWB_L; i++) {
+ ret = i2c_r8_system(sd, i, (u32 *)&value.bytes[i]);
if (ret)
return ret;
}
- ver->fw = be16_to_cpu(ver->fw);
- ver->hw = be16_to_cpu(ver->hw);
- ver->param = be16_to_cpu(ver->param);
- ver->awb = be16_to_cpu(ver->awb);
+ info->ver = value.ver;
- v4l2_info(sd, "Manufacturer\t[%s]\n",
- is_manufacturer(info, REG_SAMSUNG_ELECTRO) ?
- "Samsung Electro-Machanics" :
- is_manufacturer(info, REG_SAMSUNG_OPTICS) ?
- "Samsung Fiber-Optics" :
- is_manufacturer(info, REG_SAMSUNG_TECHWIN) ?
- "Samsung Techwin" : "None");
- v4l2_info(sd, "Customer/Project\t[0x%02x/0x%02x]\n",
- info->ver.customer, info->ver.project);
-
- if (!is_available_af(info))
- v4l2_info(sd, "No support Auto Focus on this firmware\n");
+ info->ver.fw = be16_to_cpu(info->ver.fw);
+ info->ver.hw = be16_to_cpu(info->ver.hw);
+ info->ver.parm = be16_to_cpu(info->ver.parm);
+ info->ver.awb = be16_to_cpu(info->ver.awb);
return ret;
}
+static void m5mols_show_version(struct v4l2_subdev *sd)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct device *dev = &client->dev;
+ struct m5mols_info *info = to_m5mols(sd);
+
+ dev_info(dev, "customer code\t0x%02x\n", info->ver.ctm_code);
+ dev_info(dev, "project code\t0x%02x\n", info->ver.pj_code);
+ dev_info(dev, "firmware version\t0x%04x\n", info->ver.fw);
+ dev_info(dev, "hardware version\t0x%04x\n", info->ver.hw);
+ dev_info(dev, "parameter version\t0x%04x\n", info->ver.parm);
+ dev_info(dev, "AWB version\t0x%04x\n", info->ver.awb);
+}
+
+/*
+ * get_res_preset - find out M5MOLS register value from requested resolution.
+ *
+ * @width: requested width
+ * @height: requested height
+ * @type: requested type of each modes. It supports only monitor mode now.
+ */
+static int get_res_preset(struct v4l2_subdev *sd, u16 width, u16 height,
+ enum m5mols_res_type type)
+{
+ struct m5mols_info *info = to_m5mols(sd);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(m5mols_resolutions); i++) {
+ if ((m5mols_resolutions[i].type == type) &&
+ (m5mols_resolutions[i].width == width) &&
+ (m5mols_resolutions[i].height == height))
+ break;
+ }
+
+ if (i >= ARRAY_SIZE(m5mols_resolutions)) {
+ v4l2msg("no matching resolution\n");
+ return -EINVAL;
+ }
+
+ return m5mols_resolutions[i].value;
+}
+
+/*
+ * get_fps - calc & check FPS from v4l2_captureparm, if FPS is adequate, set.
+ *
+ * In M5MOLS case, the denominator means FPS. The each value of numerator and
+ * denominator should not be minus. If numerator is 0, it sets AUTO FPS. If
+ * numerator is not 1, it recalculates denominator. After it checks, the
+ * denominator is set to timeperframe.denominator, and used by FPS.
+ */
+static int get_fps(struct v4l2_subdev *sd,
+ struct v4l2_captureparm *parm)
+{
+ int numerator = parm->timeperframe.numerator;
+ int denominator = parm->timeperframe.denominator;
+
+ /* The denominator should be +, except 0. The numerator shoud be +. */
+ if (numerator < 0 || denominator <= 0)
+ return -EINVAL;
+
+ /* The numerator is 0, return auto fps. */
+ if (numerator == 0) {
+ parm->timeperframe.denominator = M5MOLS_FPS_AUTO;
+ return 0;
+ }
+
+ /* calc FPS(not time per frame) per 1 numerator */
+ denominator = denominator / numerator;
+
+ if (denominator < M5MOLS_FPS_AUTO || denominator > M5MOLS_FPS_MAX)
+ return -EINVAL;
+
+ if (!m5mols_reg_fps[denominator])
+ return -EINVAL;
+
+ return 0;
+}
+
+/*
+ * to_code - return pixelcode of M5MOLS according to resolution type.
+ */
+static enum v4l2_mbus_pixelcode to_code(enum m5mols_res_type res_type)
+{
+ return m5mols_formats[res_type].code;
+}
+
+/*
+ * to_res_type - return resolution type of M5MOLS according to pixelcode.
+ */
+static enum m5mols_res_type to_res_type(struct v4l2_subdev *sd,
+ enum v4l2_mbus_pixelcode code)
+{
+ int i = ARRAY_SIZE(m5mols_formats);
+
+ while (i--)
+ if (code == m5mols_formats[i].code)
+ break;
+ if (i < 0)
+ return M5MOLS_RES_MAX;
+
+ if (code == m5mols_formats[M5MOLS_RES_MON].code)
+ return M5MOLS_RES_MON;
+ else
+ return M5MOLS_RES_CAPTURE;
+}
+
+static int m5mols_g_mbus_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *ffmt)
+{
+ struct m5mols_info *info = to_m5mols(sd);
+ enum m5mols_res_type res_type;
+
+ res_type = to_res_type(sd, ffmt->code);
+ if (res_type == M5MOLS_RES_MAX)
+ return -EINVAL;
+
+ *ffmt = info->fmt[res_type];
+ info->code = ffmt->code;
+
+ return 0;
+}
+
+static int m5mols_into_monitor(struct v4l2_subdev *sd, int res_size)
+{
+ int ret;
+
+ ret = m5mols_set_mode(sd, MODE_PARMSET);
+ if (!ret)
+ ret = i2c_w8_param(sd, CAT1_MONITOR_SIZE, (u8)res_size);
+ if (!ret)
+ ret = m5mols_set_mode(sd, MODE_PARMSET);
+
+ return ret;
+}
+
+static int m5mols_into_capture(struct v4l2_subdev *sd, int res_size)
+{
+ struct m5mols_info *info = to_m5mols(sd);
+ u32 reg;
+ int ret, timeout = 1;
+ u32 temp = 0;
+
+ info->captured = false;
+
+ /*
+ * The sequence of preparing Capture mode.
+ * 1. Clear Interrupt bit (for dummy)
+ * 2. Enable Capture bit at Interrupt
+ * 3. Lock AE/AWB
+ * 4. Enter Still Capture mode
+ */
+
+ ret = m5mols_set_mode(sd, MODE_MONITOR);
+ if (!ret)
+ /* FIXME: setting capture exposure at the middle of a amount. */
+ ret = i2c_w16_ae(sd, CAT3_MANUAL_GAIN_CAP, 0x90);
+ if (!ret)
+ ret = m5mols_set_ae_lock(info, true);
+ if (!ret)
+ ret = m5mols_set_awb_lock(info, true);
+ if (!ret)
+ ret = i2c_r8_system(sd, CAT0_INT_FACTOR, ®);
+ if (!ret)
+ ret = i2c_w8_system(sd, CAT0_INT_ENABLE, 1 << INT_BIT_CAPTURE);
+ if (!ret)
+ ret = m5mols_set_mode(sd, MODE_CAPTURE);
+ if (!ret)
+ timeout = wait_event_interruptible_timeout(info->cap_wait,
+ info->captured, msecs_to_jiffies(2000));
+
+ /* disable all interrupt & clear interrupt */
+ ret = i2c_w8_system(sd, CAT0_INT_ENABLE, 0x0);
+ if (!ret)
+ ret = i2c_r8_system(sd, CAT0_INT_FACTOR, ®);
+ if (ret)
+ return -EPERM;
+
+ /* If all timeout exhausted, return error. */
+ if (!timeout)
+ return -ETIMEDOUT;
+
+ ret = i2c_r32_capt_ctrl(sd, CATC_CAP_IMAGE_SIZE, &temp);
+ info->captured = false;
+ return ret;
+}
+
+static int m5mols_s_mbus_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *ffmt)
+{
+ struct m5mols_info *info = to_m5mols(sd);
+ enum m5mols_res_type res_type;
+ int size;
+ int ret = -EINVAL;
+
+ res_type = to_res_type(sd, ffmt->code);
+ if (res_type == M5MOLS_RES_MAX)
+ return -EINVAL;
+
+ /* If user set portrait for preview, it is substitued width width height
+ * unless get_res_preset will fail that M5MOLS did not support
+ * reverse WVGA */
+ if (ffmt->width < ffmt->height) {
+ int temp;
+ temp = ffmt->width;
+ ffmt->width = ffmt->height;
+ ffmt->height = temp;
+ }
+ size = get_res_preset(sd, ffmt->width, ffmt->height, res_type);
+ if (size < 0)
+ return -EINVAL;
+
+ if (ffmt->code == m5mols_formats[M5MOLS_RES_MON].code)
+ ret = m5mols_into_monitor(sd, size);
+ else
+ ret = m5mols_into_capture(sd, 0);
+
+ info->fmt[res_type] = default_fmt[res_type];
+ info->fmt[res_type].width = ffmt->width;
+ info->fmt[res_type].height = ffmt->height;
+
+ *ffmt = info->fmt[res_type];
+ info->code = ffmt->code;
+
+ return ret;
+}
+
+static int m5mols_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned int index,
+ enum v4l2_mbus_pixelcode *code)
+{
+ if (!code || index >= ARRAY_SIZE(m5mols_formats))
+ return -EINVAL;
+
+ *code = m5mols_formats[index].code;
+
+ return 0;
+}
+
+static int m5mols_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
+{
+ struct m5mols_info *info = to_m5mols(sd);
+ struct v4l2_captureparm *cp = &parms->parm.capture;
+
+ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+ parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ return -EINVAL;
+
+ cp->capability = V4L2_CAP_TIMEPERFRAME;
+ cp->timeperframe = info->tpf;
+
+ return 0;
+}
+
+static int m5mols_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
+{
+ struct m5mols_info *info = to_m5mols(sd);
+ struct v4l2_captureparm *cp = &parms->parm.capture;
+ int ret = -EINVAL;
+
+ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+ parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ return -EINVAL;
+
+ ret = m5mols_set_mode_backup(sd, MODE_PARMSET);
+ if (!ret)
+ ret = get_fps(sd, cp); /* set right FPS to denominator. */
+ if (!ret)
+ ret = i2c_w8_param(sd, CAT1_MONITOR_FPS,
+ m5mols_reg_fps[cp->timeperframe.denominator]);
+ if (!ret)
+ ret = m5mols_set_mode_restore(sd);
+ if (!ret) {
+ cp->capability = V4L2_CAP_TIMEPERFRAME;
+ info->tpf = cp->timeperframe;
+ }
+
+ v4l2msg("denominator: %d / numerator: %d.\n",
+ cp->timeperframe.denominator, cp->timeperframe.numerator);
+
+ return ret;
+}
+
+static int m5mols_get_info_capture(struct v4l2_subdev *sd)
+{
+ struct m5mols_info *info = to_m5mols(sd);
+ struct m5mols_exif *exif = &info->cap.exif;
+ int denominator, numerator;
+ int ret = 0;
+
+ ret = i2c_r32_exif(sd, CAT7_INFO_EXPTIME_NU, &numerator);
+ if (!ret)
+ ret = i2c_r32_exif(sd, CAT7_INFO_EXPTIME_DE, &denominator);
+ if (!ret)
+ exif->exposure_time = (u32)(numerator / denominator);
+ if (ret)
+ return ret;
+
+ ret = i2c_r32_exif(sd, CAT7_INFO_TV_NU, &numerator);
+ if (!ret)
+ ret = i2c_r32_exif(sd, CAT7_INFO_TV_DE, &denominator);
+ if (!ret)
+ exif->shutter_speed = (u32)(numerator / denominator);
+ if (ret)
+ return ret;
+
+ ret = i2c_r32_exif(sd, CAT7_INFO_AV_NU, &numerator);
+ if (!ret)
+ ret = i2c_r32_exif(sd, CAT7_INFO_AV_DE, &denominator);
+ if (!ret)
+ exif->aperture = (u32)(numerator / denominator);
+ if (ret)
+ return ret;
+
+ ret = i2c_r32_exif(sd, CAT7_INFO_BV_NU, &numerator);
+ if (!ret)
+ ret = i2c_r32_exif(sd, CAT7_INFO_BV_DE, &denominator);
+ if (!ret)
+ exif->brightness = (u32)(numerator / denominator);
+ if (ret)
+ return ret;
+
+ ret = i2c_r32_exif(sd, CAT7_INFO_EBV_NU, &numerator);
+ if (!ret)
+ ret = i2c_r32_exif(sd, CAT7_INFO_EBV_DE, &denominator);
+ if (!ret)
+ exif->exposure_bias = (u32)(numerator / denominator);
+ if (ret)
+ return ret;
+
+ ret = i2c_r16_exif(sd, CAT7_INFO_ISO, (u32 *)&exif->iso_speed);
+ if (!ret)
+ ret = i2c_r16_exif(sd, CAT7_INFO_FLASH, (u32 *)&exif->flash);
+ if (!ret)
+ ret = i2c_r16_exif(sd, CAT7_INFO_SDR, (u32 *)&exif->sdr);
+ if (!ret)
+ ret = i2c_r16_exif(sd, CAT7_INFO_QVAL, (u32 *)&exif->qval);
+ if (ret)
+ return ret;
+ if (!ret)
+ ret = i2c_r32_capt_ctrl(sd, CATC_CAP_IMAGE_SIZE,
+ &info->cap.main);
+ if (!ret)
+ ret = i2c_r32_capt_ctrl(sd, CATC_CAP_THUMB_SIZE,
+ &info->cap.thumb);
+
+ info->cap.total = info->cap.main + info->cap.thumb;
+
+ v4l2_info(sd, "%s: capture total size %d\n", __func__, info->cap.total);
+ v4l2_info(sd, "%s: capture main size %d\n", __func__, info->cap.main);
+ v4l2_info(sd, "%s: capture thumb size %d\n", __func__, info->cap.thumb);
+ v4l2_info(sd, "%s: exposure_time %d\n", __func__, exif->exposure_time);
+ v4l2_info(sd, "%s: shutter_speed %d\n", __func__, exif->shutter_speed);
+ v4l2_info(sd, "%s: aperture %d\n", __func__, exif->aperture);
+ v4l2_info(sd, "%s: brightness %d\n", __func__, exif->brightness);
+ v4l2_info(sd, "%s: exposure_bias %d\n", __func__, exif->exposure_bias);
+ v4l2_info(sd, "%s: iso_speed %d\n", __func__, exif->iso_speed);
+ v4l2_info(sd, "%s: flash %d\n", __func__, exif->flash);
+ v4l2_info(sd, "%s: sdr %d\n", __func__, exif->sdr);
+ v4l2_info(sd, "%s: qval %d\n", __func__, exif->qval);
+
+ return ret;
+}
+
+/* TODO: not verified. */
+static int m5mols_start_capture(struct v4l2_subdev *sd)
+{
+ struct m5mols_info *info = to_m5mols(sd);
+ u32 reg, size;
+ int ret, timeout;
+
+ u8 reg_capt_fmt[] = {
+ 0x10, /* JPEG with header + Thumbnail JPEG(YUV422@QVGA) */
+ }; /* YUV422, JPEG(422), JPEG(420) */
+ info->captured = false;
+
+ size = get_res_preset(sd,
+ info->fmt[M5MOLS_RES_CAPTURE].width,
+ info->fmt[M5MOLS_RES_CAPTURE].height,
+ M5MOLS_RES_CAPTURE);
+ if (size < 0)
+ return -EINVAL;
+ ret = 0;
+ /*
+ * The sequence of Starting Capture mode.
+ * 1. Select capture Single or Multi
+ * 2. Select format (YUV422, JPEG(YUV420, YUV422))
+ * 3. Set image size preset of Capture
+ * 4. Read Interrupt bit (for dummy)
+ * 5. Enable Capture bit at Interrupt
+ * 6. Start Capture
+ * 7. Check interrupt and register value
+ * 8. Get Image & Thumb size
+ */
+ ret = i2c_w8_capt_ctrl(sd, CATC_CAP_SEL_FRAME, true); /* single capture */
+ if (!ret)
+ ret = i2c_w8_capt_parm(sd, CATB_YUVOUT_MAIN, reg_capt_fmt[0]);
+ if (!ret)
+ ret = i2c_w8_capt_parm(sd, CATB_MAIN_IMAGE_SIZE, size);
+ if (!ret)
+ ret = i2c_r8_system(sd, CAT0_INT_FACTOR, ®);
+ if (!ret)
+ ret = i2c_w8_system(sd, CAT0_INT_ENABLE, 1 << INT_BIT_CAPTURE);
+ if (!ret)
+ ret = i2c_w8_capt_ctrl(sd, CATC_CAP_START, true);
+ if (!ret) {
+ timeout = wait_event_interruptible_timeout(info->cap_wait,
+ info->captured, msecs_to_jiffies(2000));
+
+ if (info->captured) {
+ ret = m5mols_get_info_capture(sd);
+
+ if (!ret)
+ v4l2_subdev_notify(sd, info->cap.total, NULL);
+ else
+ return ret;
+ }
+
+ /* disable all interrupt & clear interrupt */
+ ret = i2c_w8_system(sd, CAT0_INT_ENABLE, 0x0);
+ if (!ret)
+ ret = i2c_r8_system(sd, CAT0_INT_FACTOR, ®);
+ if (ret)
+ return -EPERM;
+
+ /* If all timeout exhausted, return error. */
+ if (!timeout)
+ return -ETIMEDOUT;
+
+ info->captured = false;
+
+ ret = 0;
+ }
+
+ /* TODO: complete capture. */
+
+ return ret;
+}
+
+static int m5mols_start_monitor(struct v4l2_subdev *sd)
+{
+ return m5mols_set_mode(sd, MODE_MONITOR);
+}
+
+static int m5mols_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct m5mols_info *info = to_m5mols(sd);
+
+ printk("%s\n", __func__);
+ if (enable) {
+ if (info->code == to_code(M5MOLS_RES_MON)) {
+ v4l2_info(sd, "%s : monitor mode\n", __func__);
+ return m5mols_start_monitor(sd);
+ }
+ if (info->code == to_code(M5MOLS_RES_CAPTURE)) {
+ v4l2_info(sd, "%s : capture mode\n", __func__);
+ return m5mols_start_capture(sd);
+ }
+ return -EINVAL;
+ } else {
+ if (is_streaming(sd))
+ return m5mols_set_mode(sd, MODE_PARMSET);
+ return -EINVAL;
+ }
+}
+
+static const struct v4l2_subdev_video_ops m5mols_video_ops = {
+ .g_mbus_fmt = m5mols_g_mbus_fmt,
+ .s_mbus_fmt = m5mols_s_mbus_fmt,
+ .enum_mbus_fmt = m5mols_enum_mbus_fmt,
+ .g_parm = m5mols_g_parm,
+ .s_parm = m5mols_s_parm,
+ .s_stream = m5mols_s_stream,
+};
+
+static int m5mols_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct v4l2_subdev *sd = to_sd(ctrl);
+ int ret;
+
+ ret = m5mols_set_mode_backup(sd, MODE_PARMSET);
+ if (!ret)
+ ret = m5mols_set_ctrl(ctrl);
+ if (!ret)
+ ret = m5mols_set_mode_restore(sd);
+
+ return ret;
+}
+
+static int m5mols_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct v4l2_subdev *sd = to_sd(ctrl);
+ struct m5mols_info *info = to_m5mols(sd);
+ int ret = 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_CAM_JPEG_ENCODEDSIZE:
+ ctrl->cur.val = info->cap.total;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static const struct v4l2_ctrl_ops m5mols_ctrl_ops = {
+ .s_ctrl = m5mols_s_ctrl,
+ .g_volatile_ctrl = m5mols_g_volatile_ctrl,
+};
+
+static const struct v4l2_ctrl_config ctrl_private[] = {
+ {
+ .ops = &m5mols_ctrl_ops,
+ .id = V4L2_CID_CAM_JPEG_MEMSIZE,
+ .name = "Jpeg memory size",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .flags = V4L2_CTRL_FLAG_SLIDER,
+ .max = M5MO_JPEG_MEMSIZE,
+ .step = 1,
+ .min = 0,
+ .def = M5MO_JPEG_MEMSIZE,
+ .is_private = 1,
+ }, {
+ .ops = &m5mols_ctrl_ops,
+ .id = V4L2_CID_CAM_JPEG_ENCODEDSIZE,
+ .name = "Jpeg encoded size",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .flags = V4L2_CTRL_FLAG_SLIDER,
+ .max = M5MO_JPEG_MEMSIZE,
+ .step = 1,
+ .min = 0,
+ .def = 0,
+ .is_private = 1,
+ },
+};
+/*
+ * m5mols_sensor_power - handle sensor power up/down.
+ *
+ * @enable: If it is true, power up. If is not, power down.
+ */
+static int m5mols_sensor_power(struct m5mols_info *info, bool enable)
+{
+ struct v4l2_subdev *sd = &info->sd;
+ struct i2c_client *c = v4l2_get_subdevdata(sd);
+ int ret;
+
+ if (enable) {
+ if (is_powerup(sd))
+ return 0;
+
+ /* power-on additional power */
+ if (info->set_power) {
+ ret = info->set_power(&c->dev, 1);
+ if (ret)
+ return ret;
+ }
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(supplies), supplies);
+ if (ret)
+ return ret;
+
+ gpio_set_value(info->pdata->gpio_rst, info->pdata->enable_rst);
+ usleep_range(1000, 1000);
+
+ info->power = true;
+ } else {
+ if (!is_powerup(sd))
+ return 0;
+
+ ret = regulator_bulk_disable(ARRAY_SIZE(supplies), supplies);
+ if (ret)
+ return ret;
+
+ /* power-off additional power */
+ if (info->set_power) {
+ ret = info->set_power(&c->dev, 0);
+ if (ret)
+ return ret;
+ }
+
+ info->power = false;
+
+ gpio_set_value(info->pdata->gpio_rst, !info->pdata->enable_rst);
+ usleep_range(1000, 1000);
+ }
+
+ return ret;
+}
+
+static void m5mols_irq_work(struct work_struct *work)
+{
+ struct m5mols_info *info = container_of(work, struct m5mols_info, work);
+ struct v4l2_subdev *sd = &info->sd;
+ u32 reg;
+ int ret;
+ if (is_powerup(sd)) {
+ ret = i2c_r8_system(sd, CAT0_INT_FACTOR, ®);
+ if (!ret) {
+ switch (reg & 0x0f) {
+ case (1 << INT_BIT_AF):
+ /* Except returning zero at just that upper
+ * statments, not entering in this parenthesis.
+ * The return value is below:
+ * 0x0 : AF Fail
+ * 0x2 : AF Success
+ * 0x4 : Idle Status
+ * 0x5 : Busy Status */
+ ret = i2c_r8_lens(sd, CATA_AF_STATUS, ®);
+ if (!ret && (reg == 0x02))
+ info->is_focus = true;
+ else
+ info->is_focus = false;
+ printk("%s = AF %02x, focus %d\n",
+ __func__, reg, info->is_focus);
+ break;
+ case (1 << INT_BIT_CAPTURE):
+ printk("%s = CAPTURE\n", __func__);
+ if (!info->captured) {
+ wake_up_interruptible(&info->cap_wait);
+ info->captured = true;
+ }
+ break;
+ case (1 << INT_BIT_ZOOM):
+ case (1 << INT_BIT_FRAME_SYNC):
+ case (1 << INT_BIT_FD):
+ case (1 << INT_BIT_LENS_INIT):
+ case (1 << INT_BIT_SOUND):
+ printk("%s = Nothing : 0x%08x\n", __func__, reg);
+ break;
+ case (1 << INT_BIT_MODE):
+ default:
+ break;
+ }
+ }
+ }
+}
+
+static irqreturn_t m5mols_irq_handler(int irq, void *data)
+{
+ struct v4l2_subdev *sd = data;
+ struct m5mols_info *info = to_m5mols(sd);
+
+ v4l2_info(sd, "%s\n", __func__);
+
+ schedule_work(&info->work);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * m5mols_sensor_armboot - booting M5MOLS internal ARM core-controller.
+ *
+ * It makes to ready M5MOLS for I2C & MIPI interface. After it's powered up,
+ * it activates if it gets armboot command for I2C interface. After getting
+ * cmd, it must wait about least 500ms referenced by M5MOLS datasheet.
+ */
+static int m5mols_sensor_armboot(struct v4l2_subdev *sd)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct m5mols_info *info = to_m5mols(sd);
+ static u8 m5mols_mipi_value = 0x02;
+ u32 reg;
+ int ret;
+
+ /* 1. ARM booting */
+ ret = i2c_w8_flash(sd, CATC_CAM_START, true);
+ if (ret < 0)
+ return ret;
+
+ msleep(500);
+ dev_dbg(&client->dev, "Success ARM Booting\n");
+
+ /* after ARM booting, the M5MOLS state changed Parameter mode. */
+ info->mode = MODE_PARMSET;
+
+ ret = i2c_r8_system(sd, CAT0_INT_FACTOR, ®); /* clear intterupt */
+ if (!ret)
+ ret = i2c_w8_system(sd, CAT0_INT_ENABLE, 0x0); /* all disable */
+ if (!ret)
+ ret = get_version(sd);
+ if (!ret)
+ ret = i2c_w8_param(sd, CAT1_DATA_INTERFACE, m5mols_mipi_value);
+
+ m5mols_show_version(sd);
+
+ return ret;
+}
+
+/*
+ * m5mols_init_controls - initialization using v4l2_ctrl.
+ */
+static int m5mols_init_controls(struct m5mols_info *info)
+{
+ struct v4l2_subdev *sd = &info->sd;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ u16 max_ex_mon;
+ int ret;
+
+ /* check minimum & maximum of M5MOLS controls */
+ ret = i2c_r16_ae(sd, CAT3_MAX_GAIN_MON, (u32 *)&max_ex_mon);
+ if (ret)
+ return ret;
+
+ /* set the controls using v4l2 control frameworks */
+ v4l2_ctrl_handler_init(&info->handle, 9);
+
+ info->colorfx = v4l2_ctrl_new_std_menu(&info->handle,
+ &m5mols_ctrl_ops, V4L2_CID_COLORFX,
+ 9, 1, V4L2_COLORFX_NONE);
+ info->autoexposure = v4l2_ctrl_new_std_menu(&info->handle,
+ &m5mols_ctrl_ops, V4L2_CID_EXPOSURE_AUTO,
+ 1, 0, V4L2_EXPOSURE_AUTO);
+ info->exposure = v4l2_ctrl_new_std(&info->handle,
+ &m5mols_ctrl_ops, V4L2_CID_EXPOSURE,
+ 0, max_ex_mon, 1, (int)max_ex_mon/2);
+ info->autofocus = v4l2_ctrl_new_std(&info->handle,
+ &m5mols_ctrl_ops, V4L2_CID_FOCUS_AUTO,
+ 0, 1, 1, 0);
+ info->autowb = v4l2_ctrl_new_std(&info->handle,
+ &m5mols_ctrl_ops, V4L2_CID_AUTO_WHITE_BALANCE,
+ 0, 1, 1, 1);
+ info->saturation = v4l2_ctrl_new_std(&info->handle,
+ &m5mols_ctrl_ops, V4L2_CID_SATURATION,
+ 0, 6, 1, 3);
+ info->zoom = v4l2_ctrl_new_std(&info->handle,
+ &m5mols_ctrl_ops, V4L2_CID_ZOOM_ABSOLUTE,
+ 0, 70, 1, 0);
+ info->jpeg_size = v4l2_ctrl_new_custom(&info->handle,
+ &ctrl_private[0],
+ NULL);
+ info->encoded_size = v4l2_ctrl_new_custom(&info->handle,
+ &ctrl_private[1],
+ NULL);
+
+ sd->ctrl_handler = &info->handle;
+
+ if (info->handle.error) {
+ dev_err(&client->dev, "Failed to init controls, %d\n", ret);
+ v4l2_ctrl_handler_free(&info->handle);
+ return info->handle.error;
+ }
+
+ v4l2_ctrl_cluster(2, &info->autoexposure);
+ /* If above ctrl value is not good image, so it is better that not set */
+ v4l2_ctrl_handler_setup(&info->handle);
+
+ return 0;
+}
+
+/*
+ * m5mols_setup_default - set default size & fps in the monitor mode.
+ */
+static int m5mols_setup_default(struct v4l2_subdev *sd)
+{
+ struct m5mols_info *info = to_m5mols(sd);
+ int value;
+ int ret = -EINVAL;
+
+ value = get_res_preset(sd,
+ default_fmt[M5MOLS_RES_MON].width,
+ default_fmt[M5MOLS_RES_MON].height,
+ M5MOLS_RES_MON);
+ if (value >= 0)
+ ret = i2c_w8_param(sd, CAT1_MONITOR_SIZE, (u8)value);
+ if (!ret)
+ ret = i2c_w8_param(sd, CAT1_MONITOR_FPS,
+ m5mols_reg_fps[default_fps.denominator]);
+ if (!ret)
+ ret = m5mols_init_controls(info);
+ if (!ret)
+ ret = m5mols_set_ae_lock(info, false);
+ if (!ret)
+ ret = m5mols_set_awb_lock(info, false);
+ if (!ret) {
+ info->fmt[M5MOLS_RES_MON] = default_fmt[M5MOLS_RES_MON];
+ info->tpf = default_fps;
+
+ ret = 0;
+ }
+
+ return ret;
+}
+
+static int m5mols_s_power(struct v4l2_subdev *sd, int on)
+{
+ struct m5mols_info *info = to_m5mols(sd);
+ int ret;
+
+ if (on) {
+ ret = m5mols_sensor_power(info, true);
+ if (!ret)
+ ret = m5mols_sensor_armboot(sd);
+ if (!ret)
+ ret = m5mols_setup_default(sd);
+ } else {
+ ret = m5mols_sensor_power(info, false);
+ }
+
+ return ret;
+}
+
+static int m5mols_log_status(struct v4l2_subdev *sd)
+{
+ struct m5mols_info *info = to_m5mols(sd);
+
+ v4l2_ctrl_handler_log_status(&info->handle, sd->name);
+
+ return 0;
+}
+
+static const struct v4l2_subdev_core_ops m5mols_core_ops = {
+ .s_power = m5mols_s_power,
+ .g_ctrl = v4l2_subdev_g_ctrl,
+ .s_ctrl = v4l2_subdev_s_ctrl,
+ .queryctrl = v4l2_subdev_queryctrl,
+ .querymenu = v4l2_subdev_querymenu,
+ .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+ .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+ .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+ .log_status = m5mols_log_status,
+};
+
/**
* __find_restype - Lookup M-5MOLS resolution type according to pixel code
* @code: pixel code
@@ -484,7 +1273,7 @@
enum m5mols_restype type = M5MOLS_RESTYPE_MONITOR;
do {
- if (code == m5mols_default_ffmt[type].code)
+ if (code == default_fmt[type].code)
return type;
} while (type++ != SIZE_DEFAULT_FFMT);
@@ -505,10 +1294,10 @@
enum m5mols_restype *type,
u32 *resolution)
{
- const struct m5mols_resolution *fsize = &m5mols_reg_res[0];
+ const struct m5mols_resolution *fsize = &m5mols_resolutions[0];
const struct m5mols_resolution *match = NULL;
enum m5mols_restype stype = __find_restype(mf->code);
- int i = ARRAY_SIZE(m5mols_reg_res);
+ int i = ARRAY_SIZE(m5mols_resolutions);
unsigned int min_err = ~0;
while (i--) {
@@ -527,7 +1316,7 @@
if (match) {
mf->width = match->width;
mf->height = match->height;
- *resolution = match->reg;
+ *resolution = match->value;
*type = stype;
return 0;
}
@@ -543,7 +1332,7 @@
if (which == V4L2_SUBDEV_FORMAT_TRY)
return fh ? v4l2_subdev_get_try_format(fh, 0) : NULL;
- return &info->ffmt[type];
+ return &info->fmt[type];
}
static int m5mols_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
@@ -552,6 +1341,9 @@
struct m5mols_info *info = to_m5mols(sd);
struct v4l2_mbus_framefmt *format;
+ if (fmt->pad != 0)
+ return -EINVAL;
+
format = __find_format(info, fh, fmt->which, info->res_type);
if (!format)
return -EINVAL;
@@ -570,6 +1362,9 @@
u32 resolution = 0;
int ret;
+ if (fmt->pad != 0)
+ return -EINVAL;
+
ret = __find_resolution(sd, format, &type, &resolution);
if (ret < 0)
return ret;
@@ -578,14 +1373,13 @@
if (!sfmt)
return 0;
-
- format->code = m5mols_default_ffmt[type].code;
- format->colorspace = V4L2_COLORSPACE_JPEG;
- format->field = V4L2_FIELD_NONE;
+ sfmt = &default_fmt[type];
+ sfmt->width = format->width;
+ sfmt->height = format->height;
if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
- *sfmt = *format;
info->resolution = resolution;
+ info->code = format->code;
info->res_type = type;
}
@@ -599,7 +1393,7 @@
if (!code || code->index >= SIZE_DEFAULT_FFMT)
return -EINVAL;
- code->code = m5mols_default_ffmt[code->index].code;
+ code->code = default_fmt[code->index].code;
return 0;
}
@@ -610,450 +1404,183 @@
.set_fmt = m5mols_set_fmt,
};
-/**
- * m5mols_restore_controls - Apply current control values to the registers
- *
- * m5mols_do_scenemode() handles all parameters for which there is yet no
- * individual control. It should be replaced at some point by setting each
- * control individually, in required register set up order.
- */
-int m5mols_restore_controls(struct m5mols_info *info)
-{
- int ret;
-
- if (info->ctrl_sync)
- return 0;
-
- ret = m5mols_do_scenemode(info, REG_SCENE_NORMAL);
- if (ret)
- return ret;
-
- ret = v4l2_ctrl_handler_setup(&info->handle);
- info->ctrl_sync = !ret;
-
- return ret;
-}
-
-/**
- * m5mols_start_monitor - Start the monitor mode
- *
- * Before applying the controls setup the resolution and frame rate
- * in PARAMETER mode, and then switch over to MONITOR mode.
- */
-static int m5mols_start_monitor(struct m5mols_info *info)
-{
- struct v4l2_subdev *sd = &info->sd;
- int ret;
-
- ret = m5mols_mode(info, REG_PARAMETER);
- if (!ret)
- ret = m5mols_write(sd, PARM_MON_SIZE, info->resolution);
- if (!ret)
- ret = m5mols_write(sd, PARM_MON_FPS, REG_FPS_30);
- if (!ret)
- ret = m5mols_mode(info, REG_MONITOR);
- if (!ret)
- ret = m5mols_restore_controls(info);
-
- return ret;
-}
-
-static int m5mols_s_stream(struct v4l2_subdev *sd, int enable)
-{
- struct m5mols_info *info = to_m5mols(sd);
- u32 code = info->ffmt[info->res_type].code;
-
- if (enable) {
- int ret = -EINVAL;
-
- if (is_code(code, M5MOLS_RESTYPE_MONITOR))
- ret = m5mols_start_monitor(info);
- if (is_code(code, M5MOLS_RESTYPE_CAPTURE))
- ret = m5mols_start_capture(info);
-
- return ret;
- }
-
- return m5mols_mode(info, REG_PARAMETER);
-}
-
-static const struct v4l2_subdev_video_ops m5mols_video_ops = {
- .s_stream = m5mols_s_stream,
-};
-
-static int m5mols_s_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct v4l2_subdev *sd = to_sd(ctrl);
- struct m5mols_info *info = to_m5mols(sd);
- int ispstate = info->mode;
- int ret;
-
- /*
- * If needed, defer restoring the controls until
- * the device is fully initialized.
- */
- if (!info->isp_ready) {
- info->ctrl_sync = 0;
- return 0;
- }
-
- ret = m5mols_mode(info, REG_PARAMETER);
- if (ret < 0)
- return ret;
- ret = m5mols_set_ctrl(ctrl);
- if (ret < 0)
- return ret;
- return m5mols_mode(info, ispstate);
-}
-
-static const struct v4l2_ctrl_ops m5mols_ctrl_ops = {
- .s_ctrl = m5mols_s_ctrl,
-};
-
-static int m5mols_sensor_power(struct m5mols_info *info, bool enable)
-{
- struct v4l2_subdev *sd = &info->sd;
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- const struct m5mols_platform_data *pdata = info->pdata;
- int ret;
-
- if (info->power == enable)
- return 0;
-
- if (enable) {
- if (info->set_power) {
- ret = info->set_power(&client->dev, 1);
- if (ret)
- return ret;
- }
-
- ret = regulator_bulk_enable(ARRAY_SIZE(supplies), supplies);
- if (ret) {
- info->set_power(&client->dev, 0);
- return ret;
- }
-
- gpio_set_value(pdata->gpio_reset, !pdata->reset_polarity);
- info->power = 1;
-
- return ret;
- }
-
- ret = regulator_bulk_disable(ARRAY_SIZE(supplies), supplies);
- if (ret)
- return ret;
-
- if (info->set_power)
- info->set_power(&client->dev, 0);
-
- gpio_set_value(pdata->gpio_reset, pdata->reset_polarity);
-
- info->isp_ready = 0;
- info->power = 0;
-
- return ret;
-}
-
-/* m5mols_update_fw - optional firmware update routine */
-int __attribute__ ((weak)) m5mols_update_fw(struct v4l2_subdev *sd,
- int (*set_power)(struct m5mols_info *, bool))
-{
- return 0;
-}
-
-/**
- * m5mols_fw_start - M-5MOLS internal ARM controller initialization
- *
- * Execute the M-5MOLS internal ARM controller initialization sequence.
- * This function should be called after the supply voltage has been
- * applied and before any requests to the device are made.
- */
-static int m5mols_fw_start(struct v4l2_subdev *sd)
-{
- struct m5mols_info *info = to_m5mols(sd);
- int ret;
-
- atomic_set(&info->irq_done, 0);
- /* Wait until I2C slave is initialized in Flash Writer mode */
- ret = m5mols_busy_wait(sd, FLASH_CAM_START, REG_IN_FLASH_MODE,
- M5MOLS_I2C_RDY_WAIT_FL | 0xff, -1);
- if (!ret)
- ret = m5mols_write(sd, FLASH_CAM_START, REG_START_ARM_BOOT);
- if (!ret)
- ret = m5mols_wait_interrupt(sd, REG_INT_MODE, 2000);
- if (ret < 0)
- return ret;
-
- info->isp_ready = 1;
-
- ret = m5mols_get_version(sd);
- if (!ret)
- ret = m5mols_update_fw(sd, m5mols_sensor_power);
- if (ret)
- return ret;
-
- v4l2_dbg(1, m5mols_debug, sd, "Success ARM Booting\n");
-
- ret = m5mols_write(sd, PARM_INTERFACE, REG_INTERFACE_MIPI);
- if (!ret)
- ret = m5mols_enable_interrupt(sd,
- REG_INT_AF | REG_INT_CAPTURE);
-
- return ret;
-}
-
-static int m5mols_init_controls(struct m5mols_info *info)
-{
- struct v4l2_subdev *sd = &info->sd;
- u16 max_exposure;
- u16 step_zoom;
- int ret;
-
- /* Determine value's range & step of controls for various FW version */
- ret = m5mols_read_u16(sd, AE_MAX_GAIN_MON, &max_exposure);
- if (!ret)
- step_zoom = is_manufacturer(info, REG_SAMSUNG_OPTICS) ? 31 : 1;
- if (ret)
- return ret;
-
- v4l2_ctrl_handler_init(&info->handle, 6);
- info->autowb = v4l2_ctrl_new_std(&info->handle,
- &m5mols_ctrl_ops, V4L2_CID_AUTO_WHITE_BALANCE,
- 0, 1, 1, 0);
- info->saturation = v4l2_ctrl_new_std(&info->handle,
- &m5mols_ctrl_ops, V4L2_CID_SATURATION,
- 1, 5, 1, 3);
- info->zoom = v4l2_ctrl_new_std(&info->handle,
- &m5mols_ctrl_ops, V4L2_CID_ZOOM_ABSOLUTE,
- 1, 70, step_zoom, 1);
- info->exposure = v4l2_ctrl_new_std(&info->handle,
- &m5mols_ctrl_ops, V4L2_CID_EXPOSURE,
- 0, max_exposure, 1, (int)max_exposure/2);
- info->colorfx = v4l2_ctrl_new_std_menu(&info->handle,
- &m5mols_ctrl_ops, V4L2_CID_COLORFX,
- 4, (1 << V4L2_COLORFX_BW), V4L2_COLORFX_NONE);
- info->autoexposure = v4l2_ctrl_new_std_menu(&info->handle,
- &m5mols_ctrl_ops, V4L2_CID_EXPOSURE_AUTO,
- 1, 0, V4L2_EXPOSURE_AUTO);
-
- sd->ctrl_handler = &info->handle;
- if (info->handle.error) {
- v4l2_err(sd, "Failed to initialize controls: %d\n", ret);
- v4l2_ctrl_handler_free(&info->handle);
- return info->handle.error;
- }
-
- v4l2_ctrl_cluster(2, &info->autoexposure);
-
- return 0;
-}
-
-/**
- * m5mols_s_power - Main sensor power control function
- *
- * To prevent breaking the lens when the sensor is powered off the Soft-Landing
- * algorithm is called where available. The Soft-Landing algorithm availability
- * dependends on the firmware provider.
- */
-static int m5mols_s_power(struct v4l2_subdev *sd, int on)
-{
- struct m5mols_info *info = to_m5mols(sd);
- int ret;
-
- if (on) {
- ret = m5mols_sensor_power(info, true);
- if (!ret)
- ret = m5mols_fw_start(sd);
- return ret;
- }
-
- if (is_manufacturer(info, REG_SAMSUNG_TECHWIN)) {
- ret = m5mols_mode(info, REG_MONITOR);
- if (!ret)
- ret = m5mols_write(sd, AF_EXECUTE, REG_AF_STOP);
- if (!ret)
- ret = m5mols_write(sd, AF_MODE, REG_AF_POWEROFF);
- if (!ret)
- ret = m5mols_busy_wait(sd, SYSTEM_STATUS, REG_AF_IDLE,
- 0xff, -1);
- if (ret < 0)
- v4l2_warn(sd, "Soft landing lens failed\n");
- }
-
- ret = m5mols_sensor_power(info, false);
- info->ctrl_sync = 0;
-
- return ret;
-}
-
-static int m5mols_log_status(struct v4l2_subdev *sd)
-{
- struct m5mols_info *info = to_m5mols(sd);
-
- v4l2_ctrl_handler_log_status(&info->handle, sd->name);
-
- return 0;
-}
-
-static const struct v4l2_subdev_core_ops m5mols_core_ops = {
- .s_power = m5mols_s_power,
- .g_ctrl = v4l2_subdev_g_ctrl,
- .s_ctrl = v4l2_subdev_s_ctrl,
- .queryctrl = v4l2_subdev_queryctrl,
- .querymenu = v4l2_subdev_querymenu,
- .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
- .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
- .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
- .log_status = m5mols_log_status,
-};
-
-/*
- * V4L2 subdev internal operations
- */
-static int m5mols_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
-{
- struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(fh, 0);
-
- *format = m5mols_default_ffmt[0];
- return 0;
-}
-
-static const struct v4l2_subdev_internal_ops m5mols_subdev_internal_ops = {
- .open = m5mols_open,
-};
-
static const struct v4l2_subdev_ops m5mols_ops = {
- .core = &m5mols_core_ops,
- .pad = &m5mols_pad_ops,
- .video = &m5mols_video_ops,
+ .core = &m5mols_core_ops,
+ .pad = &m5mols_pad_ops,
+ .video = &m5mols_video_ops,
};
-static irqreturn_t m5mols_irq_handler(int irq, void *data)
+static int m5mols_link_setup(struct media_entity *entity,
+ const struct media_pad *local,
+ const struct media_pad *remote, u32 flags)
{
- struct m5mols_info *info = to_m5mols(data);
+ printk("%s\n", __func__);
+ return 0;
+}
+static const struct media_entity_operations m5mols_media_ops = {
+ .link_setup = m5mols_link_setup,
+};
- atomic_set(&info->irq_done, 1);
- wake_up_interruptible(&info->irq_waitq);
+static int m5mols_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+ struct v4l2_subdev_format format;
- return IRQ_HANDLED;
+ memset(&format, 0, sizeof(format));
+ format.pad = 0;
+ format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
+ format.format.code = m5mols_formats[M5MOLS_RES_MON].code;
+ format.format.width = DEFAULT_SENSOR_WIDTH;
+ format.format.height = DEFAULT_SENSOR_HEIGHT;
+
+ m5mols_set_fmt(sd, fh, &format);
+
+ return 0;
}
-static int __devinit m5mols_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int m5mols_subdev_close(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh)
{
- const struct m5mols_platform_data *pdata = client->dev.platform_data;
+ v4l2_dbg(1, m5mols_debug, sd, "%s", __func__);
+ return 0;
+}
+
+static int m5mols_subdev_registered(struct v4l2_subdev *sd)
+{
+ v4l2_dbg(1, m5mols_debug, sd, "%s", __func__);
+ return 0;
+}
+
+static void m5mols_subdev_unregistered(struct v4l2_subdev *sd)
+{
+ v4l2_dbg(1, m5mols_debug, sd, "%s", __func__);
+}
+
+static const struct v4l2_subdev_internal_ops m5mols_v4l2_internal_ops = {
+ .open = m5mols_init_formats,
+ .close = m5mols_subdev_close,
+ .registered = m5mols_subdev_registered,
+ .unregistered = m5mols_subdev_unregistered,
+};
+
+static int m5mols_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ const struct m5mols_platform_data *pdata =
+ client->dev.platform_data;
struct m5mols_info *info;
struct v4l2_subdev *sd;
- int ret;
+ int ret = 0;
if (pdata == NULL) {
dev_err(&client->dev, "No platform data\n");
return -EINVAL;
}
- if (!gpio_is_valid(pdata->gpio_reset)) {
- dev_err(&client->dev, "No valid RESET GPIO specified\n");
+ if (!gpio_is_valid(pdata->gpio_rst)) {
+ dev_err(&client->dev, "No valid nRST gpio pin.\n");
return -EINVAL;
}
- if (!client->irq) {
- dev_err(&client->dev, "Interrupt not assigned\n");
+ if (!pdata->irq) {
+ dev_err(&client->dev, "Interrupt not assigned.\n");
return -EINVAL;
}
info = kzalloc(sizeof(struct m5mols_info), GFP_KERNEL);
- if (!info)
+ if (info == NULL) {
+ dev_err(&client->dev, "Failed to allocate info\n");
return -ENOMEM;
-
- info->pdata = pdata;
- info->set_power = pdata->set_power;
-
- ret = gpio_request(pdata->gpio_reset, "M5MOLS_NRST");
- if (ret) {
- dev_err(&client->dev, "Failed to request gpio: %d\n", ret);
- goto out_free;
}
- gpio_direction_output(pdata->gpio_reset, pdata->reset_polarity);
- ret = regulator_bulk_get(&client->dev, ARRAY_SIZE(supplies), supplies);
+ info->pdata = pdata;
+ if (info->pdata->set_power) /* for additional power if needed. */
+ info->set_power = pdata->set_power;
+
+ if (info->pdata->irq) {
+ INIT_WORK(&info->work, m5mols_irq_work);
+ ret = request_irq(info->pdata->irq, m5mols_irq_handler,
+ IRQF_TRIGGER_RISING, MOD_NAME, &info->sd);
+ if (ret) {
+ dev_err(&client->dev, "Failed to request irq: %d\n", ret);
+ return ret;
+ }
+ }
+
+ ret = gpio_request(info->pdata->gpio_rst, "M5MOLS nRST");
if (ret) {
- dev_err(&client->dev, "Failed to get regulators: %d\n", ret);
+ dev_err(&client->dev, "Failed to set gpio, %d\n", ret);
goto out_gpio;
}
- sd = &info->sd;
- v4l2_i2c_subdev_init(sd, client, &m5mols_ops);
- strlcpy(sd->name, MODULE_NAME, sizeof(sd->name));
- sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ gpio_direction_output(info->pdata->gpio_rst, !info->pdata->enable_rst);
- sd->internal_ops = &m5mols_subdev_internal_ops;
+ ret = regulator_bulk_get(&client->dev, ARRAY_SIZE(supplies), supplies);
+ if (ret) {
+ dev_err(&client->dev, "Failed to get regulators, %d\n", ret);
+ goto out_reg;
+ }
+
+ sd = &info->sd;
+
+ init_waitqueue_head(&info->cap_wait);
+
+ v4l2_i2c_subdev_init(sd, client, &m5mols_ops);
info->pad.flags = MEDIA_PAD_FL_SOURCE;
ret = media_entity_init(&sd->entity, 1, &info->pad, 0);
if (ret < 0)
goto out_reg;
+
+ m5mols_init_formats(sd, NULL);
+
+ strlcpy(sd->name, MOD_NAME, sizeof(sd->name));
sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
+ sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
+ sd->internal_ops = &m5mols_v4l2_internal_ops;
+ sd->entity.ops = &m5mols_media_ops;
- init_waitqueue_head(&info->irq_waitq);
- ret = request_irq(client->irq, m5mols_irq_handler,
- IRQF_TRIGGER_RISING, MODULE_NAME, sd);
- if (ret) {
- dev_err(&client->dev, "Interrupt request failed: %d\n", ret);
- goto out_me;
- }
info->res_type = M5MOLS_RESTYPE_MONITOR;
- info->ffmt[0] = m5mols_default_ffmt[0];
- info->ffmt[1] = m5mols_default_ffmt[1];
- ret = m5mols_sensor_power(info, true);
- if (ret)
- goto out_me;
+ v4l2_info(sd, "%s : m5mols driver probed success\n", __func__);
- ret = m5mols_fw_start(sd);
- if (!ret)
- ret = m5mols_init_controls(info);
+ return 0;
- m5mols_sensor_power(info, false);
- if (!ret)
- return 0;
-out_me:
- media_entity_cleanup(&sd->entity);
out_reg:
regulator_bulk_free(ARRAY_SIZE(supplies), supplies);
out_gpio:
- gpio_free(pdata->gpio_reset);
-out_free:
+ gpio_free(info->pdata->gpio_rst);
kfree(info);
+
return ret;
}
-static int __devexit m5mols_remove(struct i2c_client *client)
+static int m5mols_remove(struct i2c_client *client)
{
struct v4l2_subdev *sd = i2c_get_clientdata(client);
struct m5mols_info *info = to_m5mols(sd);
v4l2_device_unregister_subdev(sd);
- v4l2_ctrl_handler_free(sd->ctrl_handler);
- free_irq(client->irq, sd);
-
+ v4l2_ctrl_handler_free(&info->handle);
+ free_irq(info->pdata->irq, sd);
regulator_bulk_free(ARRAY_SIZE(supplies), supplies);
- gpio_free(info->pdata->gpio_reset);
+ gpio_free(info->pdata->gpio_rst);
media_entity_cleanup(&sd->entity);
kfree(info);
+
return 0;
}
static const struct i2c_device_id m5mols_id[] = {
- { MODULE_NAME, 0 },
+ { MOD_NAME, 0 },
{ },
};
MODULE_DEVICE_TABLE(i2c, m5mols_id);
static struct i2c_driver m5mols_i2c_driver = {
.driver = {
- .name = MODULE_NAME,
+ .name = MOD_NAME,
},
.probe = m5mols_probe,
- .remove = __devexit_p(m5mols_remove),
+ .remove = m5mols_remove,
.id_table = m5mols_id,
};
@@ -1061,5 +1588,5 @@
MODULE_AUTHOR("HeungJun Kim <riverful.kim@samsung.com>");
MODULE_AUTHOR("Dongsoo Kim <dongsoo45.kim@samsung.com>");
-MODULE_DESCRIPTION("Fujitsu M-5MOLS 8M Pixel camera driver");
+MODULE_DESCRIPTION("Fujitsu M5MOLS 8M Pixel camera sensor with ISP driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/m5mols/m5mols_reg.h b/drivers/media/video/m5mols/m5mols_reg.h
index ae4aced..da9cab5 100644
--- a/drivers/media/video/m5mols/m5mols_reg.h
+++ b/drivers/media/video/m5mols/m5mols_reg.h
@@ -1,5 +1,5 @@
/*
- * Register map for M-5MOLS 8M Pixel camera sensor with ISP
+ * Register map for M5MOLS 8M Pixel camera sensor with ISP
*
* Copyright (C) 2011 Samsung Electronics Co., Ltd.
* Author: HeungJun Kim <riverful.kim@samsung.com>
@@ -16,346 +16,149 @@
#ifndef M5MOLS_REG_H
#define M5MOLS_REG_H
-#define M5MOLS_I2C_MAX_SIZE 4
-#define M5MOLS_BYTE_READ 0x01
-#define M5MOLS_BYTE_WRITE 0x02
-
-#define I2C_CATEGORY(__cat) ((__cat >> 16) & 0xff)
-#define I2C_COMMAND(__comm) ((__comm >> 8) & 0xff)
-#define I2C_SIZE(__reg_s) ((__reg_s) & 0xff)
-#define I2C_REG(__cat, __cmd, __reg_s) ((__cat << 16) | (__cmd << 8) | __reg_s)
-
/*
* Category section register
*
- * The category means set including relevant command of M-5MOLS.
+ * The category means a kind of command set. Including category section,
+ * all defined categories in this version supports only, as you see below:
*/
#define CAT_SYSTEM 0x00
#define CAT_PARAM 0x01
-#define CAT_MONITOR 0x02
+#define CAT_MON 0x02
#define CAT_AE 0x03
#define CAT_WB 0x06
#define CAT_EXIF 0x07
-#define CAT_FD 0x09
#define CAT_LENS 0x0a
-#define CAT_CAPT_PARM 0x0b
-#define CAT_CAPT_CTRL 0x0c
-#define CAT_FLASH 0x0f /* related to FW, revisions, booting */
+#define CAT_CAPTURE_PARAMETER 0x0b
+#define CAT_CAPTURE_CONTROL 0x0c
+#define CAT_FLASH 0x0f /* related with FW, Verions, booting */
/*
- * Category 0 - SYSTEM mode
+ * Category 0 - System
*
- * The SYSTEM mode in the M-5MOLS means area available to handle with the whole
- * & all-round system of sensor. It deals with version/interrupt/setting mode &
- * even sensor's status. Especially, the M-5MOLS sensor with ISP varies by
- * packaging & manufacturer, even the customer and project code. And the
- * function details may vary among them. The version information helps to
- * determine what methods shall be used in the driver.
- *
- * There is many registers between customer version address and awb one. For
- * more specific contents, see definition if file m5mols.h.
+ * This category supports FW version, managing mode, even interrupt.
*/
-#define SYSTEM_VER_CUSTOMER I2C_REG(CAT_SYSTEM, 0x00, 1)
-#define SYSTEM_VER_PROJECT I2C_REG(CAT_SYSTEM, 0x01, 1)
-#define SYSTEM_VER_FIRMWARE I2C_REG(CAT_SYSTEM, 0x02, 2)
-#define SYSTEM_VER_HARDWARE I2C_REG(CAT_SYSTEM, 0x04, 2)
-#define SYSTEM_VER_PARAMETER I2C_REG(CAT_SYSTEM, 0x06, 2)
-#define SYSTEM_VER_AWB I2C_REG(CAT_SYSTEM, 0x08, 2)
-
-#define SYSTEM_SYSMODE I2C_REG(CAT_SYSTEM, 0x0b, 1)
-#define REG_SYSINIT 0x00 /* SYSTEM mode */
-#define REG_PARAMETER 0x01 /* PARAMETER mode */
-#define REG_MONITOR 0x02 /* MONITOR mode */
-#define REG_CAPTURE 0x03 /* CAPTURE mode */
-
-#define SYSTEM_CMD(__cmd) I2C_REG(CAT_SYSTEM, cmd, 1)
-#define SYSTEM_VER_STRING I2C_REG(CAT_SYSTEM, 0x0a, 1)
-#define REG_SAMSUNG_ELECTRO "SE" /* Samsung Electro-Mechanics */
-#define REG_SAMSUNG_OPTICS "OP" /* Samsung Fiber-Optics */
-#define REG_SAMSUNG_TECHWIN "TB" /* Samsung Techwin */
-/* SYSTEM mode status */
-#define SYSTEM_STATUS I2C_REG(CAT_SYSTEM, 0x0c, 1)
-
-/* Interrupt pending register */
-#define SYSTEM_INT_FACTOR I2C_REG(CAT_SYSTEM, 0x10, 1)
-/* interrupt enable register */
-#define SYSTEM_INT_ENABLE I2C_REG(CAT_SYSTEM, 0x11, 1)
-#define REG_INT_MODE (1 << 0)
-#define REG_INT_AF (1 << 1)
-#define REG_INT_ZOOM (1 << 2)
-#define REG_INT_CAPTURE (1 << 3)
-#define REG_INT_FRAMESYNC (1 << 4)
-#define REG_INT_FD (1 << 5)
-#define REG_INT_LENS_INIT (1 << 6)
-#define REG_INT_SOUND (1 << 7)
-#define REG_INT_MASK 0x0f
+#define CAT0_CUSTOMER_CODE 0x00
+#define CAT0_PJ_CODE 0x01
+#define CAT0_VERSION_FW_H 0x02
+#define CAT0_VERSION_FW_L 0x03
+#define CAT0_VERSION_HW_H 0x04
+#define CAT0_VERSION_HW_L 0x05
+#define CAT0_VERSION_PARM_H 0x06
+#define CAT0_VERSION_PARM_L 0x07
+#define CAT0_VERSION_AWB_H 0x08
+#define CAT0_VERSION_AWB_L 0x09
+#define CAT0_SYSMODE 0x0b
+#define CAT0_STATUS 0x0c
+#define CAT0_INT_QUEUE 0x0e
+#define CAT0_INT_FACTOR 0x10 /* ver 10bit: 0x10, other 0x1c */
+#define CAT0_INT_ENABLE 0x11 /* ver 10bit: 0x11, other 0x10 */
+#define CAT0_INT_ROOTEN 0x12
+#define CAT0_INT_INFO 0x18
/*
- * category 1 - PARAMETER mode
+ * category 1 - Parameter mode
*
- * This category supports function of camera features of M-5MOLS. It means we
- * can handle with preview(MONITOR) resolution size/frame per second/interface
- * between the sensor and the Application Processor/even the image effect.
+ * This category is dealing with almost camera vendor. In spite of that,
+ * It's a register to be able to detailed value for whole camera syste.
+ * The key parameter like a resolution, FPS, data interface connecting
+ * with Mobile AP, even effects.
*/
-
-/* Resolution in the MONITOR mode */
-#define PARM_MON_SIZE I2C_REG(CAT_PARAM, 0x01, 1)
-
-/* Frame rate */
-#define PARM_MON_FPS I2C_REG(CAT_PARAM, 0x02, 1)
-#define REG_FPS_30 0x02
-
-/* Video bus between the sensor and a host processor */
-#define PARM_INTERFACE I2C_REG(CAT_PARAM, 0x00, 1)
-#define REG_INTERFACE_MIPI 0x02
-
-/* Image effects */
-#define PARM_EFFECT I2C_REG(CAT_PARAM, 0x0b, 1)
-#define REG_EFFECT_OFF 0x00
-#define REG_EFFECT_NEGA 0x01
-#define REG_EFFECT_EMBOSS 0x06
-#define REG_EFFECT_OUTLINE 0x07
-#define REG_EFFECT_WATERCOLOR 0x08
+#define CAT1_DATA_INTERFACE 0x00
+#define CAT1_MONITOR_SIZE 0x01
+#define CAT1_MONITOR_FPS 0x02
+#define CAT1_EFFECT 0x0b
/*
- * Category 2 - MONITOR mode
+ * Category 2 - Monitor mode
*
- * The MONITOR mode is same as preview mode as we said. The M-5MOLS has another
- * mode named "Preview", but this preview mode is used at the case specific
- * vider-recording mode. This mmode supports only YUYV format. On the other
- * hand, the JPEG & RAW formats is supports by CAPTURE mode. And, there are
- * another options like zoom/color effect(different with effect in PARAMETER
- * mode)/anti hand shaking algorithm.
+ * This category supports only monitoring mode. The monitoring mode means,
+ * similar to preview. It supports like a YUYV format. At the capture mode,
+ * it is handled like a JPEG & RAW formats.
*/
-
-/* Target digital zoom position */
-#define MON_ZOOM I2C_REG(CAT_MONITOR, 0x01, 1)
-
-/* CR value for color effect */
-#define MON_CFIXR I2C_REG(CAT_MONITOR, 0x0a, 1)
-/* CB value for color effect */
-#define MON_CFIXB I2C_REG(CAT_MONITOR, 0x09, 1)
-#define REG_CFIXB_SEPIA 0xd8
-#define REG_CFIXR_SEPIA 0x18
-
-#define MON_EFFECT I2C_REG(CAT_MONITOR, 0x0b, 1)
-#define REG_COLOR_EFFECT_OFF 0x00
-#define REG_COLOR_EFFECT_ON 0x01
-
-/* Chroma enable */
-#define MON_CHROMA_EN I2C_REG(CAT_MONITOR, 0x10, 1)
-/* Chroma level */
-#define MON_CHROMA_LVL I2C_REG(CAT_MONITOR, 0x0f, 1)
-#define REG_CHROMA_OFF 0x00
-#define REG_CHROMA_ON 0x01
-
-/* Sharpness on/off */
-#define MON_EDGE_EN I2C_REG(CAT_MONITOR, 0x12, 1)
-/* Sharpness level */
-#define MON_EDGE_LVL I2C_REG(CAT_MONITOR, 0x11, 1)
-#define REG_EDGE_OFF 0x00
-#define REG_EDGE_ON 0x01
-
-/* Set color tone (contrast) */
-#define MON_TONE_CTL I2C_REG(CAT_MONITOR, 0x25, 1)
+#define CAT2_ZOOM 0x01
+#define CAT2_ZOOM_POSITION 0x02
+#define CAT2_ZOOM_STEP 0x03
+#define CAT2_CFIXB 0x09
+#define CAT2_CFIXR 0x0a
+#define CAT2_COLOR_EFFECT 0x0b
+#define CAT2_CHROMA_LVL 0x0f
+#define CAT2_CHROMA_EN 0x10
/*
* Category 3 - Auto Exposure
*
- * The M-5MOLS exposure capbility is detailed as which is similar to digital
- * camera. This category supports AE locking/various AE mode(range of exposure)
- * /ISO/flickering/EV bias/shutter/meteoring, and anything else. And the
- * maximum/minimum exposure gain value depending on M-5MOLS firmware, may be
- * different. So, this category also provide getting the max/min values. And,
- * each MONITOR and CAPTURE mode has each gain/shutter/max exposure values.
+ * Currently, it supports only gain value with monitor mode. This device
+ * is able to support Shutter, Gain(similar with Aperture), Flicker, at
+ * monitor mode & capture mode both.
*/
-
-/* Auto Exposure locking */
-#define AE_LOCK I2C_REG(CAT_AE, 0x00, 1)
-#define REG_AE_UNLOCK 0x00
-#define REG_AE_LOCK 0x01
-
-/* Auto Exposure algorithm mode */
-#define AE_MODE I2C_REG(CAT_AE, 0x01, 1)
-#define REG_AE_OFF 0x00 /* AE off */
-#define REG_AE_ALL 0x01 /* calc AE in all block integral */
-#define REG_AE_CENTER 0x03 /* calc AE in center weighted */
-#define REG_AE_SPOT 0x06 /* calc AE in specific spot */
-
-#define AE_ISO I2C_REG(CAT_AE, 0x05, 1)
-#define REG_ISO_AUTO 0x00
-#define REG_ISO_50 0x01
-#define REG_ISO_100 0x02
-#define REG_ISO_200 0x03
-#define REG_ISO_400 0x04
-#define REG_ISO_800 0x05
-
-/* EV (scenemode) preset for MONITOR */
-#define AE_EV_PRESET_MONITOR I2C_REG(CAT_AE, 0x0a, 1)
-/* EV (scenemode) preset for CAPTURE */
-#define AE_EV_PRESET_CAPTURE I2C_REG(CAT_AE, 0x0b, 1)
-#define REG_SCENE_NORMAL 0x00
-#define REG_SCENE_PORTRAIT 0x01
-#define REG_SCENE_LANDSCAPE 0x02
-#define REG_SCENE_SPORTS 0x03
-#define REG_SCENE_PARTY_INDOOR 0x04
-#define REG_SCENE_BEACH_SNOW 0x05
-#define REG_SCENE_SUNSET 0x06
-#define REG_SCENE_DAWN_DUSK 0x07
-#define REG_SCENE_FALL 0x08
-#define REG_SCENE_NIGHT 0x09
-#define REG_SCENE_AGAINST_LIGHT 0x0a
-#define REG_SCENE_FIRE 0x0b
-#define REG_SCENE_TEXT 0x0c
-#define REG_SCENE_CANDLE 0x0d
-
-/* Manual gain in MONITOR mode */
-#define AE_MAN_GAIN_MON I2C_REG(CAT_AE, 0x12, 2)
-/* Maximum gain in MONITOR mode */
-#define AE_MAX_GAIN_MON I2C_REG(CAT_AE, 0x1a, 2)
-/* Manual gain in CAPTURE mode */
-#define AE_MAN_GAIN_CAP I2C_REG(CAT_AE, 0x26, 2)
-
-#define AE_INDEX I2C_REG(CAT_AE, 0x38, 1)
-#define REG_AE_INDEX_20_NEG 0x00
-#define REG_AE_INDEX_15_NEG 0x01
-#define REG_AE_INDEX_10_NEG 0x02
-#define REG_AE_INDEX_05_NEG 0x03
-#define REG_AE_INDEX_00 0x04
-#define REG_AE_INDEX_05_POS 0x05
-#define REG_AE_INDEX_10_POS 0x06
-#define REG_AE_INDEX_15_POS 0x07
-#define REG_AE_INDEX_20_POS 0x08
+#define CAT3_AE_LOCK 0x00
+#define CAT3_AE_MODE 0x01
+#define CAT3_MANUAL_GAIN_MON 0x12 /* 2 bytes operations belows */
+#define CAT3_MANUAL_SHUT_MON 0x14
+#define CAT3_MAX_EXPOSURE_MON 0x16
+#define CAT3_MAX_EXPOSURE_CAP 0x18
+#define CAT3_MAX_GAIN_MON 0x1a
+#define CAT3_MAX_GAIN_CAP 0x1c
+#define CAT3_MANUAL_GAIN_CAP 0x26
+#define CAT3_MANUAL_SHUT_CAP 0x28
/*
* Category 6 - White Balance
+ *
+ * Currently, it supports only auto white balance.
*/
-
-/* Auto Whitebalance locking */
-#define AWB_LOCK I2C_REG(CAT_WB, 0x00, 1)
-#define REG_AWB_UNLOCK 0x00
-#define REG_AWB_LOCK 0x01
-
-#define AWB_MODE I2C_REG(CAT_WB, 0x02, 1)
-#define REG_AWB_AUTO 0x01 /* AWB off */
-#define REG_AWB_PRESET 0x02 /* AWB preset */
-
-/* Manual WB (preset) */
-#define AWB_MANUAL I2C_REG(CAT_WB, 0x03, 1)
-#define REG_AWB_INCANDESCENT 0x01
-#define REG_AWB_FLUORESCENT_1 0x02
-#define REG_AWB_FLUORESCENT_2 0x03
-#define REG_AWB_DAYLIGHT 0x04
-#define REG_AWB_CLOUDY 0x05
-#define REG_AWB_SHADE 0x06
-#define REG_AWB_HORIZON 0x07
-#define REG_AWB_LEDLIGHT 0x09
+#define CAT6_AWB_LOCK 0x00
+#define CAT6_AWB_MODE 0x02
+#define CAT6_AWB_MANUAL 0x03
/*
- * Category 7 - EXIF information
+ * Category 7 - EXIF Information
*/
-#define EXIF_INFO_EXPTIME_NU I2C_REG(CAT_EXIF, 0x00, 4)
-#define EXIF_INFO_EXPTIME_DE I2C_REG(CAT_EXIF, 0x04, 4)
-#define EXIF_INFO_TV_NU I2C_REG(CAT_EXIF, 0x08, 4)
-#define EXIF_INFO_TV_DE I2C_REG(CAT_EXIF, 0x0c, 4)
-#define EXIF_INFO_AV_NU I2C_REG(CAT_EXIF, 0x10, 4)
-#define EXIF_INFO_AV_DE I2C_REG(CAT_EXIF, 0x14, 4)
-#define EXIF_INFO_BV_NU I2C_REG(CAT_EXIF, 0x18, 4)
-#define EXIF_INFO_BV_DE I2C_REG(CAT_EXIF, 0x1c, 4)
-#define EXIF_INFO_EBV_NU I2C_REG(CAT_EXIF, 0x20, 4)
-#define EXIF_INFO_EBV_DE I2C_REG(CAT_EXIF, 0x24, 4)
-#define EXIF_INFO_ISO I2C_REG(CAT_EXIF, 0x28, 2)
-#define EXIF_INFO_FLASH I2C_REG(CAT_EXIF, 0x2a, 2)
-#define EXIF_INFO_SDR I2C_REG(CAT_EXIF, 0x2c, 2)
-#define EXIF_INFO_QVAL I2C_REG(CAT_EXIF, 0x2e, 2)
-
-/*
- * Category 9 - Face Detection
- */
-#define FD_CTL I2C_REG(CAT_FD, 0x00, 1)
-#define BIT_FD_EN 0
-#define BIT_FD_DRAW_FACE_FRAME 4
-#define BIT_FD_DRAW_SMILE_LVL 6
-#define REG_FD(shift) (1 << shift)
-#define REG_FD_OFF 0x0
+#define CAT7_INFO_EXPTIME_NU 0x00
+#define CAT7_INFO_EXPTIME_DE 0x04
+#define CAT7_INFO_TV_NU 0x08
+#define CAT7_INFO_TV_DE 0x0c
+#define CAT7_INFO_AV_NU 0x10
+#define CAT7_INFO_AV_DE 0x14
+#define CAT7_INFO_BV_NU 0x18
+#define CAT7_INFO_BV_DE 0x1c
+#define CAT7_INFO_EBV_NU 0x20
+#define CAT7_INFO_EBV_DE 0x24
+#define CAT7_INFO_ISO 0x28
+#define CAT7_INFO_FLASH 0x2a
+#define CAT7_INFO_SDR 0x2c
+#define CAT7_INFO_QVAL 0x2e
/*
* Category A - Lens Parameter
*/
-#define AF_MODE I2C_REG(CAT_LENS, 0x01, 1)
-#define REG_AF_NORMAL 0x00 /* Normal AF, one time */
-#define REG_AF_MACRO 0x01 /* Macro AF, one time */
-#define REG_AF_POWEROFF 0x07
-
-#define AF_EXECUTE I2C_REG(CAT_LENS, 0x02, 1)
-#define REG_AF_STOP 0x00
-#define REG_AF_EXE_AUTO 0x01
-#define REG_AF_EXE_CAF 0x02
-
-#define AF_STATUS I2C_REG(CAT_LENS, 0x03, 1)
-#define REG_AF_FAIL 0x00
-#define REG_AF_SUCCESS 0x02
-#define REG_AF_IDLE 0x04
-#define REG_AF_BUSY 0x05
-
-#define AF_VERSION I2C_REG(CAT_LENS, 0x0a, 1)
+#define CATA_INIT_AF_FUNC 0x00
+#define CATA_AF_MODE 0x01
+#define CATA_AF_EXCUTE 0x02
+#define CATA_AF_STATUS 0x03
+#define CATA_AF_VERSION 0x0a
/*
- * Category B - CAPTURE Parameter
+ * Category B - Capture Parameter
*/
-#define CAPP_YUVOUT_MAIN I2C_REG(CAT_CAPT_PARM, 0x00, 1)
-#define REG_YUV422 0x00
-#define REG_BAYER10 0x05
-#define REG_BAYER8 0x06
-#define REG_JPEG 0x10
-
-#define CAPP_MAIN_IMAGE_SIZE I2C_REG(CAT_CAPT_PARM, 0x01, 1)
-
-#define CAPP_MCC_MODE I2C_REG(CAT_CAPT_PARM, 0x1d, 1)
-#define REG_MCC_OFF 0x00
-#define REG_MCC_NORMAL 0x01
-
-#define CAPP_WDR_EN I2C_REG(CAT_CAPT_PARM, 0x2c, 1)
-#define REG_WDR_OFF 0x00
-#define REG_WDR_ON 0x01
-#define REG_WDR_AUTO 0x02
-
-#define CAPP_LIGHT_CTRL I2C_REG(CAT_CAPT_PARM, 0x40, 1)
-#define REG_LIGHT_OFF 0x00
-#define REG_LIGHT_ON 0x01
-#define REG_LIGHT_AUTO 0x02
-
-#define CAPP_FLASH_CTRL I2C_REG(CAT_CAPT_PARM, 0x41, 1)
-#define REG_FLASH_OFF 0x00
-#define REG_FLASH_ON 0x01
-#define REG_FLASH_AUTO 0x02
+#define CATB_YUVOUT_MAIN 0x00
+#define CATB_MAIN_IMAGE_SIZE 0x01
/*
- * Category C - CAPTURE Control
+ * Category C - Capture Control
*/
-#define CAPC_MODE I2C_REG(CAT_CAPT_CTRL, 0x00, 1)
-#define REG_CAP_NONE 0x00
-#define REG_CAP_ANTI_SHAKE 0x02
-
-/* Select single- or multi-shot capture */
-#define CAPC_SEL_FRAME I2C_REG(CAT_CAPT_CTRL, 0x06, 1)
-
-#define CAPC_START I2C_REG(CAT_CAPT_CTRL, 0x09, 1)
-#define REG_CAP_START_MAIN 0x01
-#define REG_CAP_START_THUMB 0x03
-
-#define CAPC_IMAGE_SIZE I2C_REG(CAT_CAPT_CTRL, 0x0d, 4)
-#define CAPC_THUMB_SIZE I2C_REG(CAT_CAPT_CTRL, 0x11, 4)
+#define CATC_CAP_SEL_FRAME 0x06 /* It determines Single or Multi. */
+#define CATC_CAP_START 0x09
+#define CATC_CAP_IMAGE_SIZE 0x0d
+#define CATC_CAP_THUMB_SIZE 0x11
/*
* Category F - Flash
*
- * This mode provides functions about internal flash stuff and system startup.
+ * This mode provides functions about internal Flash works and System startup.
*/
-
-/* Starts internal ARM core booting after power-up */
-#define FLASH_CAM_START I2C_REG(CAT_FLASH, 0x12, 1)
-#define REG_START_ARM_BOOT 0x01 /* write value */
-#define REG_IN_FLASH_MODE 0x00 /* read value */
+#define CATC_CAM_START 0x12 /* It start internal ARM core booting
+ * after power-up */
#endif /* M5MOLS_REG_H */
diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c
index 5b2ec1f..021053e 100644
--- a/drivers/media/video/v4l2-ioctl.c
+++ b/drivers/media/video/v4l2-ioctl.c
@@ -188,6 +188,7 @@
[V4L2_MEMORY_MMAP] = "mmap",
[V4L2_MEMORY_USERPTR] = "userptr",
[V4L2_MEMORY_OVERLAY] = "overlay",
+ [V4L2_MEMORY_DMABUF] = "dmabuf",
};
#define prt_names(a, arr) ((((a) >= 0) && ((a) < ARRAY_SIZE(arr))) ? \
diff --git a/drivers/media/video/v4l2-mem2mem.c b/drivers/media/video/v4l2-mem2mem.c
index 975d0fa..da0308a 100644
--- a/drivers/media/video/v4l2-mem2mem.c
+++ b/drivers/media/video/v4l2-mem2mem.c
@@ -38,7 +38,8 @@
#define TRANS_QUEUED (1 << 0)
/* Instance is currently running in hardware */
#define TRANS_RUNNING (1 << 1)
-
+/* Instance is stopped */
+#define TRANS_STOPPED (1 << 2)
/* Offset base for buffers on the destination queue - used to distinguish
* between source and destination buffers when mmapping - they receive the same
@@ -184,6 +185,34 @@
}
/**
+ * v4l2_m2m_get_next_job() - find the remainging job and run it if it's
+ * different from previous job.
+ */
+void v4l2_m2m_get_next_job(struct v4l2_m2m_dev *m2m_dev, struct v4l2_m2m_ctx *m2m_ctx)
+{
+ unsigned long flags;
+ struct v4l2_m2m_ctx *cm2m_ctx, *tm2m_ctx, *next_job = NULL;
+
+ spin_lock_irqsave(&m2m_dev->job_spinlock, flags);
+ list_for_each_entry_safe(cm2m_ctx, tm2m_ctx, &m2m_dev->job_queue, queue) {
+ if (cm2m_ctx->job_flags & TRANS_STOPPED)
+ list_del_init(&cm2m_ctx->queue);
+ }
+ m2m_ctx->job_flags &= ~TRANS_STOPPED;
+ spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags);
+
+ if (!list_empty(&m2m_dev->job_queue)) {
+ next_job = list_first_entry(&m2m_dev->job_queue, struct v4l2_m2m_ctx,
+ queue);
+ if ((next_job != m2m_dev->curr_ctx) && (m2m_dev->curr_ctx != NULL)) {
+ m2m_dev->curr_ctx = NULL;
+ v4l2_m2m_try_run(m2m_dev);
+ }
+ }
+}
+EXPORT_SYMBOL(v4l2_m2m_get_next_job);
+
+/**
* v4l2_m2m_try_schedule() - check whether an instance is ready to be added to
* the pending job queue and add it if so.
* @m2m_ctx: m2m context assigned to the instance to be checked
@@ -199,7 +228,7 @@
* An example of the above could be an instance that requires more than one
* src/dst buffer per transaction.
*/
-static void v4l2_m2m_try_schedule(struct v4l2_m2m_ctx *m2m_ctx)
+void v4l2_m2m_try_schedule(struct v4l2_m2m_ctx *m2m_ctx)
{
struct v4l2_m2m_dev *m2m_dev;
unsigned long flags_job, flags;
diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c
index de4fa4e..b457c8b 100644
--- a/drivers/media/video/videobuf-core.c
+++ b/drivers/media/video/videobuf-core.c
@@ -335,6 +335,9 @@
case V4L2_MEMORY_OVERLAY:
b->m.offset = vb->boff;
break;
+ case V4L2_MEMORY_DMABUF:
+ /* DMABUF is not handled in videobuf framework */
+ break;
}
b->flags = 0;
@@ -411,6 +414,7 @@
break;
case V4L2_MEMORY_USERPTR:
case V4L2_MEMORY_OVERLAY:
+ case V4L2_MEMORY_DMABUF:
/* nothing */
break;
}
diff --git a/drivers/media/video/videobuf2-cma-phys.c b/drivers/media/video/videobuf2-cma-phys.c
new file mode 100644
index 0000000..34256a3
--- /dev/null
+++ b/drivers/media/video/videobuf2-cma-phys.c
@@ -0,0 +1,413 @@
+/* linux/drivers/media/video/videobuf2-cma-phys.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * CMA-phys memory allocator for videobuf2
+ *
+ * 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.
+*/
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/cma.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/file.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-memops.h>
+
+#include <asm/cacheflush.h>
+
+#define SIZE_THRESHOLD SZ_1M
+
+struct vb2_cma_phys_conf {
+ struct device *dev;
+ const char *type;
+ unsigned long alignment;
+ bool cacheable;
+};
+
+struct vb2_cma_phys_buf {
+ struct vb2_cma_phys_conf *conf;
+ dma_addr_t paddr;
+ unsigned long size;
+ struct vm_area_struct *vma;
+ atomic_t refcount;
+ struct vb2_vmarea_handler handler;
+ bool cacheable;
+};
+
+static void vb2_cma_phys_put(void *buf_priv);
+
+static void *vb2_cma_phys_alloc(void *alloc_ctx, unsigned long size)
+{
+ struct vb2_cma_phys_conf *conf = alloc_ctx;
+ struct vb2_cma_phys_buf *buf;
+
+ buf = kzalloc(sizeof *buf, GFP_KERNEL);
+ if (!buf)
+ return ERR_PTR(-ENOMEM);
+
+ buf->paddr = cma_alloc(conf->dev, conf->type, size, conf->alignment);
+ if (IS_ERR((void *)buf->paddr)) {
+ printk(KERN_ERR "cma_alloc of size %ld failed\n", size);
+ kfree(buf);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ buf->conf = conf;
+ buf->size = size;
+ buf->cacheable = conf->cacheable;
+
+ buf->handler.refcount = &buf->refcount;
+ buf->handler.put = vb2_cma_phys_put;
+ buf->handler.arg = buf;
+
+ atomic_inc(&buf->refcount);
+
+ return buf;
+}
+
+static void vb2_cma_phys_put(void *buf_priv)
+{
+ struct vb2_cma_phys_buf *buf = buf_priv;
+
+ if (atomic_dec_and_test(&buf->refcount)) {
+ cma_free(buf->paddr);
+ kfree(buf);
+ }
+}
+
+static void *vb2_cma_phys_cookie(void *buf_priv)
+{
+ struct vb2_cma_phys_buf *buf = buf_priv;
+
+ return (void *)buf->paddr;
+}
+
+static unsigned int vb2_cma_phys_num_users(void *buf_priv)
+{
+ struct vb2_cma_phys_buf *buf = buf_priv;
+
+ return atomic_read(&buf->refcount);
+}
+
+/**
+ * vb2_cma_mmap_pfn_range() - map physical pages to userspace
+ * @vma: virtual memory region for the mapping
+ * @paddr: starting physical address of the memory to be mapped
+ * @size: size of the memory to be mapped
+ * @vm_ops: vm operations to be assigned to the created area
+ * @priv: private data to be associated with the area
+ *
+ * Returns 0 on success.
+ */
+int vb2_cma_phys_mmap_pfn_range(struct vm_area_struct *vma, unsigned long paddr,
+ unsigned long size,
+ const struct vm_operations_struct *vm_ops,
+ void *priv)
+{
+ int ret;
+
+ size = min_t(unsigned long, vma->vm_end - vma->vm_start, size);
+
+ ret = remap_pfn_range(vma, vma->vm_start, paddr >> PAGE_SHIFT,
+ size, vma->vm_page_prot);
+ if (ret) {
+ printk(KERN_ERR "Remapping memory failed, error: %d\n", ret);
+ return ret;
+ }
+
+ vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED;
+ vma->vm_private_data = priv;
+ vma->vm_ops = vm_ops;
+
+ vma->vm_ops->open(vma);
+
+ printk(KERN_DEBUG "%s: mapped paddr 0x%08lx at 0x%08lx, size %ld\n",
+ __func__, paddr, vma->vm_start, size);
+
+ return 0;
+}
+
+static int vb2_cma_phys_mmap(void *buf_priv, struct vm_area_struct *vma)
+{
+ struct vb2_cma_phys_buf *buf = buf_priv;
+
+ if (!buf) {
+ printk(KERN_ERR "No buffer to map\n");
+ return -EINVAL;
+ }
+
+ if (!buf->cacheable)
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+
+ return vb2_cma_phys_mmap_pfn_range(vma, buf->paddr, buf->size,
+ &vb2_common_vm_ops, &buf->handler);
+}
+
+static void *vb2_cma_phys_get_userptr(void *alloc_ctx, unsigned long vaddr,
+ unsigned long size, int write)
+{
+ struct vb2_cma_phys_buf *buf;
+
+ buf = kzalloc(sizeof *buf, GFP_KERNEL);
+ if (!buf)
+ return ERR_PTR(-ENOMEM);
+
+ printk(KERN_DEBUG "[%s] paddr(0x%08lx)\n", __func__, vaddr);
+ buf->size = size;
+ buf->paddr = vaddr; /* drv directly gets phys. addr. from user. */
+
+ return buf;
+}
+
+static void vb2_cma_phys_put_userptr(void *mem_priv)
+{
+ struct vb2_cma_phys_buf *buf = mem_priv;
+
+ if (!buf)
+ return;
+
+ kfree(buf);
+}
+
+static void *vb2_cma_phys_vaddr(void *mem_priv)
+{
+ struct vb2_cma_phys_buf *buf = mem_priv;
+ if (!buf)
+ return 0;
+
+ return phys_to_virt(buf->paddr);
+}
+
+const struct vb2_mem_ops vb2_cma_phys_memops = {
+ .alloc = vb2_cma_phys_alloc,
+ .put = vb2_cma_phys_put,
+ .cookie = vb2_cma_phys_cookie,
+ .mmap = vb2_cma_phys_mmap,
+ .get_userptr = vb2_cma_phys_get_userptr,
+ .put_userptr = vb2_cma_phys_put_userptr,
+ .num_users = vb2_cma_phys_num_users,
+ .vaddr = vb2_cma_phys_vaddr,
+};
+EXPORT_SYMBOL_GPL(vb2_cma_phys_memops);
+
+void *vb2_cma_phys_init(struct device *dev, const char *type,
+ unsigned long alignment, bool cacheable)
+{
+ struct vb2_cma_phys_conf *conf;
+
+ conf = kzalloc(sizeof *conf, GFP_KERNEL);
+ if (!conf)
+ return ERR_PTR(-ENOMEM);
+
+ conf->dev = dev;
+ conf->type = type;
+ conf->alignment = alignment;
+ conf->cacheable = cacheable;
+
+ return conf;
+}
+EXPORT_SYMBOL_GPL(vb2_cma_phys_init);
+
+void vb2_cma_phys_cleanup(void *conf)
+{
+ kfree(conf);
+}
+EXPORT_SYMBOL_GPL(vb2_cma_phys_cleanup);
+
+void **vb2_cma_phys_init_multi(struct device *dev,
+ unsigned int num_planes,
+ const char *types[],
+ unsigned long alignments[],
+ bool cacheable)
+{
+ struct vb2_cma_phys_conf *cma_conf;
+ void **alloc_ctxes;
+ unsigned int i;
+
+ alloc_ctxes = kzalloc((sizeof *alloc_ctxes + sizeof *cma_conf)
+ * num_planes, GFP_KERNEL);
+ if (!alloc_ctxes)
+ return ERR_PTR(-ENOMEM);
+
+ cma_conf = (void *)(alloc_ctxes + num_planes);
+
+ for (i = 0; i < num_planes; ++i, ++cma_conf) {
+ alloc_ctxes[i] = cma_conf;
+ cma_conf->dev = dev;
+ cma_conf->type = types[i];
+ cma_conf->alignment = alignments[i];
+ cma_conf->cacheable = cacheable;
+ }
+
+ return alloc_ctxes;
+}
+EXPORT_SYMBOL_GPL(vb2_cma_phys_init_multi);
+
+void vb2_cma_phys_cleanup_multi(void **alloc_ctxes)
+{
+ kfree(alloc_ctxes);
+}
+EXPORT_SYMBOL_GPL(vb2_cma_phys_cleanup_multi);
+
+void vb2_cma_phys_set_cacheable(void *alloc_ctx, bool cacheable)
+{
+ ((struct vb2_cma_phys_conf *)alloc_ctx)->cacheable = cacheable;
+}
+
+bool vb2_cma_phys_get_cacheable(void *alloc_ctx)
+{
+ return ((struct vb2_cma_phys_conf *)alloc_ctx)->cacheable;
+}
+
+static void _vb2_cma_phys_cache_flush_all(void)
+{
+ flush_cache_all(); /* L1 */
+ smp_call_function((smp_call_func_t)__cpuc_flush_kern_all, NULL, 1);
+ outer_flush_all(); /* L2 */
+}
+
+static void _vb2_cma_phys_cache_flush_range(struct vb2_cma_phys_buf *buf,
+ unsigned long size)
+{
+ phys_addr_t start = buf->paddr;
+ phys_addr_t end = start + size - 1;
+
+ if (size > SZ_64K) {
+ flush_cache_all(); /* L1 */
+ smp_call_function((smp_call_func_t)__cpuc_flush_kern_all, NULL, 1);
+ } else {
+ dmac_flush_range(phys_to_virt(start), phys_to_virt(end));
+ }
+
+ outer_flush_range(start, end); /* L2 */
+}
+
+int vb2_cma_phys_cache_flush(struct vb2_buffer *vb, u32 num_planes)
+{
+ struct vb2_cma_phys_buf *buf;
+ unsigned long size = 0;
+ int i;
+
+ for (i = 0; i < num_planes; i++) {
+ buf = vb->planes[i].mem_priv;
+ if (!buf->cacheable) {
+ pr_warning("This is non-cacheable buffer allocator\n");
+ return -EINVAL;
+ }
+
+ size += buf->size;
+ }
+
+ if (size > (unsigned long)SIZE_THRESHOLD) {
+ _vb2_cma_phys_cache_flush_all();
+ } else {
+ for (i = 0; i < num_planes; i++) {
+ buf = vb->planes[i].mem_priv;
+ _vb2_cma_phys_cache_flush_range(buf, size);
+ }
+ }
+
+ return 0;
+}
+
+int vb2_cma_phys_cache_inv(struct vb2_buffer *vb, u32 num_planes)
+{
+ struct vb2_cma_phys_buf *buf;
+ phys_addr_t start;
+ size_t size;
+ int i;
+
+ for (i = 0; i < num_planes; i++) {
+ buf = vb->planes[i].mem_priv;
+ start = buf->paddr;
+ size = buf->size;
+
+ if (!buf->cacheable) {
+ pr_warning("This is non-cacheable buffer allocator\n");
+ return -EINVAL;
+ }
+
+ dmac_unmap_area(phys_to_virt(start), size, DMA_FROM_DEVICE);
+ outer_inv_range(start, start + size); /* L2 */
+ }
+
+ return 0;
+}
+
+int vb2_cma_phys_cache_clean(struct vb2_buffer *vb, u32 num_planes)
+{
+ struct vb2_cma_phys_buf *buf;
+ phys_addr_t start;
+ size_t size;
+ int i;
+
+ for (i = 0; i < num_planes; i++) {
+ buf = vb->planes[i].mem_priv;
+ start = buf->paddr;
+ size = buf->size;
+
+ if (!buf->cacheable) {
+ pr_warning("This is non-cacheable buffer allocator\n");
+ return -EINVAL;
+ }
+
+ dmac_unmap_area(phys_to_virt(start), size, DMA_TO_DEVICE);
+ outer_clean_range(start, start + size - 1); /* L2 */
+ }
+
+ return 0;
+}
+
+/* FIXME: l2 cache clean all should be implemented */
+int vb2_cma_phys_cache_clean2(struct vb2_buffer *vb, u32 num_planes)
+{
+ struct vb2_cma_phys_buf *buf;
+ unsigned long t_size = 0;
+ phys_addr_t start;
+ size_t size;
+ int i;
+
+ for (i = 0; i < num_planes; i++) {
+ buf = vb->planes[i].mem_priv;
+ if (!buf->cacheable) {
+ pr_warning("This is non-cacheable buffer allocator\n");
+ return -EINVAL;
+ }
+
+ t_size += buf->size;
+ }
+
+ if (t_size > (unsigned long)SIZE_THRESHOLD) {
+ for (i = 0; i < num_planes; i++) {
+ buf = vb->planes[i].mem_priv;
+ start = buf->paddr;
+ size = buf->size;
+
+ dmac_unmap_area(phys_to_virt(start), size, DMA_TO_DEVICE);
+ }
+ } else {
+ for (i = 0; i < num_planes; i++) {
+ buf = vb->planes[i].mem_priv;
+ start = buf->paddr;
+ size = buf->size;
+
+ dmac_unmap_area(phys_to_virt(start), size, DMA_TO_DEVICE);
+ outer_clean_range(start, start + size - 1); /* L2 */
+ }
+ }
+
+ return 0;
+}
+
+MODULE_AUTHOR("Jonghun, Han <jonghun.han@samsung.com>");
+MODULE_DESCRIPTION("CMA-phys allocator handling routines for videobuf2");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c
index 2e8f1df..a25adc9 100644
--- a/drivers/media/video/videobuf2-core.c
+++ b/drivers/media/video/videobuf2-core.c
@@ -106,6 +106,36 @@
}
/**
+ * __vb2_plane_dmabuf_put() - release memory associated with
+ * a DMABUF shared plane
+ */
+static void __vb2_plane_dmabuf_put(struct vb2_queue *q, struct vb2_plane *p)
+{
+ if (!p->mem_priv)
+ return;
+
+ if (p->dbuf_mapped)
+ call_memop(q, unmap_dmabuf, p->mem_priv);
+
+ call_memop(q, detach_dmabuf, p->mem_priv);
+ dma_buf_put(p->dbuf);
+ memset(p, 0, sizeof *p);
+}
+
+/**
+ * __vb2_buf_dmabuf_put() - release memory associated with
+ * a DMABUF shared buffer
+ */
+static void __vb2_buf_dmabuf_put(struct vb2_buffer *vb)
+{
+ struct vb2_queue *q = vb->vb2_queue;
+ unsigned int plane;
+
+ for (plane = 0; plane < vb->num_planes; ++plane)
+ __vb2_plane_dmabuf_put(q, &vb->planes[plane]);
+}
+
+/**
* __setup_offsets() - setup unique offsets ("cookies") for every plane in
* every buffer on the queue
*/
@@ -156,6 +186,13 @@
struct vb2_buffer *vb;
int ret;
+ q->timeline_max = 0;
+ q->timeline = sw_sync_timeline_create(q->name);
+ if (!q->timeline) {
+ dprintk(1, "Failed to create timeline\n");
+ return -ENOMEM;
+ }
+
for (buffer = 0; buffer < num_buffers; ++buffer) {
/* Allocate videobuf buffer structures */
vb = kzalloc(q->buf_struct_size, GFP_KERNEL);
@@ -227,6 +264,8 @@
/* Free MMAP buffers or release USERPTR buffers */
if (q->memory == V4L2_MEMORY_MMAP)
__vb2_buf_mem_free(vb);
+ else if (q->memory == V4L2_MEMORY_DMABUF)
+ __vb2_buf_dmabuf_put(vb);
else
__vb2_buf_userptr_put(vb);
}
@@ -265,6 +304,11 @@
if (!q->num_buffers)
q->memory = 0;
INIT_LIST_HEAD(&q->queued_list);
+
+ if (q->timeline) {
+ sync_timeline_destroy(&q->timeline->obj);
+ q->timeline = NULL;
+ }
}
/**
@@ -349,6 +393,12 @@
*/
memcpy(b->m.planes, vb->v4l2_planes,
b->length * sizeof(struct v4l2_plane));
+
+ if (q->memory == V4L2_MEMORY_DMABUF) {
+ unsigned int plane;
+ for (plane = 0; plane < vb->num_planes; ++plane)
+ b->m.planes[plane].m.fd = 0;
+ }
} else {
/*
* We use length and offset in v4l2_planes array even for
@@ -360,6 +410,8 @@
b->m.offset = vb->v4l2_planes[0].m.mem_offset;
else if (q->memory == V4L2_MEMORY_USERPTR)
b->m.userptr = vb->v4l2_planes[0].m.userptr;
+ else if (q->memory == V4L2_MEMORY_DMABUF)
+ b->m.fd = 0;
}
/*
@@ -451,6 +503,20 @@
}
/**
+ * __verify_dmabuf_ops() - verify that all memory operations required for
+ * DMABUF queue type have been provided
+ */
+static int __verify_dmabuf_ops(struct vb2_queue *q)
+{
+ if (!(q->io_modes & VB2_DMABUF) || !q->mem_ops->attach_dmabuf ||
+ !q->mem_ops->detach_dmabuf || !q->mem_ops->map_dmabuf ||
+ !q->mem_ops->unmap_dmabuf)
+ return -EINVAL;
+
+ return 0;
+}
+
+/**
* vb2_reqbufs() - Initiate streaming
* @q: videobuf2 queue
* @req: struct passed from userspace to vidioc_reqbufs handler in driver
@@ -483,8 +549,9 @@
return -EBUSY;
}
- if (req->memory != V4L2_MEMORY_MMAP
- && req->memory != V4L2_MEMORY_USERPTR) {
+ if (req->memory != V4L2_MEMORY_MMAP &&
+ req->memory != V4L2_MEMORY_DMABUF &&
+ req->memory != V4L2_MEMORY_USERPTR) {
dprintk(1, "reqbufs: unsupported memory type\n");
return -EINVAL;
}
@@ -513,6 +580,11 @@
return -EINVAL;
}
+ if (req->memory == V4L2_MEMORY_DMABUF && __verify_dmabuf_ops(q)) {
+ dprintk(1, "reqbufs: DMABUF for current setup unsupported\n");
+ return -EINVAL;
+ }
+
if (req->count == 0 || q->num_buffers != 0 || q->memory != req->memory) {
/*
* We already have buffers allocated, so first check if they
@@ -619,8 +691,9 @@
return -EBUSY;
}
- if (create->memory != V4L2_MEMORY_MMAP
- && create->memory != V4L2_MEMORY_USERPTR) {
+ if (create->memory != V4L2_MEMORY_MMAP &&
+ create->memory != V4L2_MEMORY_USERPTR &&
+ create->memory != V4L2_MEMORY_DMABUF) {
dprintk(1, "%s(): unsupported memory type\n", __func__);
return -EINVAL;
}
@@ -644,6 +717,11 @@
return -EINVAL;
}
+ if (create->memory == V4L2_MEMORY_DMABUF && __verify_dmabuf_ops(q)) {
+ dprintk(1, "%s(): DMABUF for current setup unsupported\n", __func__);
+ return -EINVAL;
+ }
+
if (q->num_buffers == VIDEO_MAX_FRAME) {
dprintk(1, "%s(): maximum number of buffers already allocated\n",
__func__);
@@ -753,8 +831,12 @@
{
struct vb2_queue *q = vb->vb2_queue;
- if (plane_no > vb->num_planes || !vb->planes[plane_no].mem_priv)
+ if (plane_no > vb->num_planes || !vb->planes[plane_no].mem_priv) {
+ pr_err("%s: vb=%p (q=%s) plane=%d num_planes=%d mem_priv=%p\n",
+ __func__, vb, q->name, plane_no, vb->num_planes,
+ vb->planes[plane_no].mem_priv);
return NULL;
+ }
return call_memop(q, cookie, vb->planes[plane_no].mem_priv);
}
@@ -776,6 +858,7 @@
{
struct vb2_queue *q = vb->vb2_queue;
unsigned long flags;
+ unsigned int plane;
if (vb->state != VB2_BUF_STATE_ACTIVE)
return;
@@ -786,11 +869,16 @@
dprintk(4, "Done processing on buffer %d, state: %d\n",
vb->v4l2_buf.index, vb->state);
+ /* sync buffers */
+ for (plane = 0; plane < vb->num_planes; ++plane)
+ call_memop(q, finish, vb->planes[plane].mem_priv);
+
/* Add the buffer to the done buffers list */
spin_lock_irqsave(&q->done_lock, flags);
vb->state = state;
list_add_tail(&vb->done_entry, &q->done_list);
atomic_dec(&q->queued_count);
+ sw_sync_timeline_inc(q->timeline, 1);
spin_unlock_irqrestore(&q->done_lock, flags);
/* Inform any processes that may be waiting for buffers */
@@ -807,6 +895,7 @@
{
unsigned int plane;
int ret;
+ int fence_fd = (int)b->reserved;
if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) {
/*
@@ -839,6 +928,14 @@
b->m.planes[plane].length;
}
}
+ if (b->memory == V4L2_MEMORY_DMABUF) {
+ for (plane = 0; plane < vb->num_planes; ++plane) {
+ v4l2_planes[plane].bytesused =
+ b->m.planes[plane].bytesused;
+ v4l2_planes[plane].m.fd =
+ b->m.planes[plane].m.fd;
+ }
+ }
} else {
/*
* Single-planar buffers do not use planes array,
@@ -853,6 +950,18 @@
v4l2_planes[0].m.userptr = b->m.userptr;
v4l2_planes[0].length = b->length;
}
+
+ if (b->memory == V4L2_MEMORY_DMABUF)
+ v4l2_planes[0].m.fd = b->m.fd;
+
+ }
+
+ if ((b->flags & V4L2_BUF_FLAG_USE_SYNC) && fence_fd >= 0) {
+ vb->acquire_fence = sync_fence_fdget(fence_fd);
+ if (!vb->acquire_fence) {
+ dprintk(1, "failed to import fence fd %d\n", fence_fd);
+ return -EINVAL;
+ }
}
vb->v4l2_buf.field = b->field;
@@ -957,14 +1066,114 @@
}
/**
+ * __qbuf_dmabuf() - handle qbuf of a DMABUF buffer
+ */
+static int __qbuf_dmabuf(struct vb2_buffer *vb, const struct v4l2_buffer *b)
+{
+ struct v4l2_plane planes[VIDEO_MAX_PLANES];
+ struct vb2_queue *q = vb->vb2_queue;
+ void *mem_priv;
+ unsigned int plane;
+ int ret;
+ int write = !V4L2_TYPE_IS_OUTPUT(q->type);
+
+ /* Verify and copy relevant information provided by the userspace */
+ ret = __fill_vb2_buffer(vb, b, planes);
+ if (ret)
+ return ret;
+
+ for (plane = 0; plane < vb->num_planes; ++plane) {
+ struct dma_buf *dbuf = dma_buf_get(planes[plane].m.fd);
+
+ if (IS_ERR_OR_NULL(dbuf)) {
+ dprintk(1, "qbuf: invalid dmabuf fd for "
+ "plane %d\n", plane);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ /* Skip the plane if already verified */
+ if (dbuf == vb->planes[plane].dbuf) {
+ planes[plane].length = dbuf->size;
+ dma_buf_put(dbuf);
+ continue;
+ }
+
+ dprintk(3, "qbuf: buffer description for plane %d changed, "
+ "reattaching dma buf\n", plane);
+
+ /* Release previously acquired memory if present */
+ __vb2_plane_dmabuf_put(q, &vb->planes[plane]);
+
+ /* Acquire each plane's memory */
+ mem_priv = call_memop(q, attach_dmabuf, q->alloc_ctx[plane],
+ dbuf, q->plane_sizes[plane], write);
+ if (IS_ERR(mem_priv)) {
+ dprintk(1, "qbuf: failed acquiring dmabuf "
+ "memory for plane %d\n", plane);
+ ret = PTR_ERR(mem_priv);
+ goto err;
+ }
+
+ planes[plane].length = dbuf->size;
+ vb->planes[plane].dbuf = dbuf;
+ vb->planes[plane].mem_priv = mem_priv;
+ }
+
+ /* TODO: This pins the buffer(s) with dma_buf_map_attachment()).. but
+ * really we want to do this just before the DMA, not while queueing
+ * the buffer(s)..
+ */
+ for (plane = 0; plane < vb->num_planes; ++plane) {
+ ret = call_memop(q, map_dmabuf, vb->planes[plane].mem_priv);
+ if (ret) {
+ dprintk(1, "qbuf: failed mapping dmabuf "
+ "memory for plane %d\n", plane);
+ goto err;
+ }
+ vb->planes[plane].dbuf_mapped = 1;
+ }
+
+ /*
+ * Call driver-specific initialization on the newly acquired buffer,
+ * if provided.
+ */
+ ret = call_qop(q, buf_init, vb);
+ if (ret) {
+ dprintk(1, "qbuf: buffer initialization failed\n");
+ goto err;
+ }
+
+ /*
+ * Now that everything is in order, copy relevant information
+ * provided by userspace.
+ */
+ for (plane = 0; plane < vb->num_planes; ++plane)
+ vb->v4l2_planes[plane] = planes[plane];
+
+ return 0;
+err:
+ /* In case of errors, release planes that were already acquired */
+ __vb2_buf_dmabuf_put(vb);
+
+ return ret;
+}
+
+/**
* __enqueue_in_driver() - enqueue a vb2_buffer in driver for processing
*/
static void __enqueue_in_driver(struct vb2_buffer *vb)
{
struct vb2_queue *q = vb->vb2_queue;
+ unsigned int plane;
vb->state = VB2_BUF_STATE_ACTIVE;
atomic_inc(&q->queued_count);
+
+ /* sync buffers */
+ for (plane = 0; plane < vb->num_planes; ++plane)
+ call_memop(q, prepare, vb->planes[plane].mem_priv);
+
q->ops->buf_queue(vb);
}
@@ -980,6 +1189,9 @@
case V4L2_MEMORY_USERPTR:
ret = __qbuf_userptr(vb, b);
break;
+ case V4L2_MEMORY_DMABUF:
+ ret = __qbuf_dmabuf(vb, b);
+ break;
default:
WARN(1, "Invalid queue type\n");
ret = -EINVAL;
@@ -1155,6 +1367,24 @@
list_add_tail(&vb->queued_entry, &q->queued_list);
vb->state = VB2_BUF_STATE_QUEUED;
+ q->timeline_max++;
+ if (b->flags & V4L2_BUF_FLAG_USE_SYNC) {
+ struct sync_pt *pt;
+ struct sync_fence *fence;
+ int fd;
+
+ fd = get_unused_fd();
+ if (fd >= 0) {
+ pt = sw_sync_pt_create(q->timeline, q->timeline_max);
+ fence = sync_fence_create("vb2", pt);
+ sync_fence_install(fence, fd);
+ vb->v4l2_buf.reserved = fd;
+ } else {
+ dprintk(1, "qbuf: failed to get unused fd\n");
+ vb->v4l2_buf.reserved = -1;
+ }
+ }
+
/*
* If already streaming, give the buffer to driver for processing.
* If not, the buffer will be given to driver on next streamon.
@@ -1335,6 +1565,19 @@
return ret;
}
+ /* TODO: this unpins the buffer(dma_buf_unmap_attachment()).. but
+ * really we want to do this just after DMA, not when the
+ * buffer is dequeued..
+ */
+ if (q->memory == V4L2_MEMORY_DMABUF) {
+ unsigned int i;
+
+ for (i = 0; i < vb->num_planes; ++i) {
+ call_memop(q, unmap_dmabuf, vb->planes[i].mem_priv);
+ vb->planes[i].dbuf_mapped = 0;
+ }
+ }
+
switch (vb->state) {
case VB2_BUF_STATE_DONE:
dprintk(3, "dqbuf: Returning done buffer\n");
@@ -1368,6 +1611,7 @@
*/
static void __vb2_queue_cancel(struct vb2_queue *q)
{
+ struct vb2_buffer *vb;
unsigned int i;
/*
@@ -1381,20 +1625,46 @@
/*
* Remove all buffers from videobuf's list...
*/
+ list_for_each_entry(vb, &q->queued_list, queued_entry) {
+ if (vb->acquire_fence) {
+ sync_fence_put(vb->acquire_fence);
+ vb->acquire_fence = NULL;
+ }
+ }
INIT_LIST_HEAD(&q->queued_list);
/*
* ...and done list; userspace will not receive any buffers it
* has not already dequeued before initiating cancel.
*/
INIT_LIST_HEAD(&q->done_list);
+ if (q->timeline)
+ sw_sync_timeline_inc(q->timeline, atomic_read(&q->queued_count));
atomic_set(&q->queued_count, 0);
wake_up_all(&q->done_wq);
/*
* Reinitialize all buffers for next use.
*/
- for (i = 0; i < q->num_buffers; ++i)
- q->bufs[i]->state = VB2_BUF_STATE_DEQUEUED;
+ for (i = 0; i < q->num_buffers; ++i) {
+ struct vb2_buffer *vb = q->bufs[i];
+ int plane;
+
+ vb->state = VB2_BUF_STATE_DEQUEUED;
+
+ if (q->memory != V4L2_MEMORY_DMABUF)
+ continue;
+
+ for (plane = 0; plane < vb->num_planes; ++plane) {
+ struct vb2_plane *p = &vb->planes[plane];
+
+ if (!p->mem_priv)
+ continue;
+ if (p->dbuf_mapped) {
+ call_memop(q, unmap_dmabuf, p->mem_priv);
+ p->dbuf_mapped = 0;
+ }
+ }
+ }
}
/**
@@ -1724,6 +1994,9 @@
spin_lock_init(&q->done_lock);
init_waitqueue_head(&q->done_wq);
+ if (!q->name)
+ q->name = "vb2";
+
if (q->buf_struct_size == 0)
q->buf_struct_size = sizeof(struct vb2_buffer);
diff --git a/drivers/media/video/videobuf2-dma-contig.c b/drivers/media/video/videobuf2-dma-contig.c
index 4b71326..a05784f 100644
--- a/drivers/media/video/videobuf2-dma-contig.c
+++ b/drivers/media/video/videobuf2-dma-contig.c
@@ -32,9 +32,9 @@
struct vb2_vmarea_handler handler;
};
-static void vb2_dma_contig_put(void *buf_priv);
+static void vb2_dc_put(void *buf_priv);
-static void *vb2_dma_contig_alloc(void *alloc_ctx, unsigned long size)
+static void *vb2_dc_alloc(void *alloc_ctx, unsigned long size)
{
struct vb2_dc_conf *conf = alloc_ctx;
struct vb2_dc_buf *buf;
@@ -56,7 +56,7 @@
buf->size = size;
buf->handler.refcount = &buf->refcount;
- buf->handler.put = vb2_dma_contig_put;
+ buf->handler.put = vb2_dc_put;
buf->handler.arg = buf;
atomic_inc(&buf->refcount);
@@ -64,7 +64,7 @@
return buf;
}
-static void vb2_dma_contig_put(void *buf_priv)
+static void vb2_dc_put(void *buf_priv)
{
struct vb2_dc_buf *buf = buf_priv;
@@ -75,14 +75,14 @@
}
}
-static void *vb2_dma_contig_cookie(void *buf_priv)
+static void *vb2_dc_cookie(void *buf_priv)
{
struct vb2_dc_buf *buf = buf_priv;
return &buf->dma_addr;
}
-static void *vb2_dma_contig_vaddr(void *buf_priv)
+static void *vb2_dc_vaddr(void *buf_priv)
{
struct vb2_dc_buf *buf = buf_priv;
if (!buf)
@@ -91,14 +91,14 @@
return buf->vaddr;
}
-static unsigned int vb2_dma_contig_num_users(void *buf_priv)
+static unsigned int vb2_dc_num_users(void *buf_priv)
{
struct vb2_dc_buf *buf = buf_priv;
return atomic_read(&buf->refcount);
}
-static int vb2_dma_contig_mmap(void *buf_priv, struct vm_area_struct *vma)
+static int vb2_dc_mmap(void *buf_priv, struct vm_area_struct *vma)
{
struct vb2_dc_buf *buf = buf_priv;
@@ -111,7 +111,7 @@
&vb2_common_vm_ops, &buf->handler);
}
-static void *vb2_dma_contig_get_userptr(void *alloc_ctx, unsigned long vaddr,
+static void *vb2_dc_get_userptr(void *alloc_ctx, unsigned long vaddr,
unsigned long size, int write)
{
struct vb2_dc_buf *buf;
@@ -138,7 +138,7 @@
return buf;
}
-static void vb2_dma_contig_put_userptr(void *mem_priv)
+static void vb2_dc_put_userptr(void *mem_priv)
{
struct vb2_dc_buf *buf = mem_priv;
@@ -150,14 +150,14 @@
}
const struct vb2_mem_ops vb2_dma_contig_memops = {
- .alloc = vb2_dma_contig_alloc,
- .put = vb2_dma_contig_put,
- .cookie = vb2_dma_contig_cookie,
- .vaddr = vb2_dma_contig_vaddr,
- .mmap = vb2_dma_contig_mmap,
- .get_userptr = vb2_dma_contig_get_userptr,
- .put_userptr = vb2_dma_contig_put_userptr,
- .num_users = vb2_dma_contig_num_users,
+ .alloc = vb2_dc_alloc,
+ .put = vb2_dc_put,
+ .cookie = vb2_dc_cookie,
+ .vaddr = vb2_dc_vaddr,
+ .mmap = vb2_dc_mmap,
+ .get_userptr = vb2_dc_get_userptr,
+ .put_userptr = vb2_dc_put_userptr,
+ .num_users = vb2_dc_num_users,
};
EXPORT_SYMBOL_GPL(vb2_dma_contig_memops);
diff --git a/drivers/media/video/videobuf2-ion.c b/drivers/media/video/videobuf2-ion.c
new file mode 100755
index 0000000..0a80da5
--- /dev/null
+++ b/drivers/media/video/videobuf2-ion.c
@@ -0,0 +1,720 @@
+/* linux/drivers/media/video/videobuf2-ion.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Implementation of Android ION memory allocator for videobuf2
+ *
+ * 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.
+*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/file.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/highmem.h>
+#include <linux/dma-buf.h>
+#include <linux/fs.h>
+#include <linux/mutex.h>
+
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-memops.h>
+#include <media/videobuf2-ion.h>
+
+#include <asm/cacheflush.h>
+
+#include <plat/iovmm.h>
+#include <plat/cpu.h>
+
+struct vb2_ion_context {
+ struct device *dev;
+ struct ion_client *client;
+ unsigned long alignment;
+ long flags;
+
+ /* protects iommu_active_cnt and protected */
+ struct mutex lock;
+ int iommu_active_cnt;
+ bool protected;
+};
+
+struct vb2_ion_buf {
+ struct vb2_ion_context *ctx;
+ struct vb2_vmarea_handler handler;
+ struct ion_handle *handle;
+ struct dma_buf *dma_buf;
+ struct dma_buf_attachment *attachment;
+ enum dma_data_direction direction;
+ void *kva;
+ unsigned long size;
+ atomic_t ref;
+ bool cached;
+ struct vb2_ion_cookie cookie;
+};
+
+#define ctx_cached(ctx) (!(ctx->flags & VB2ION_CTX_UNCACHED))
+#define ctx_iommu(ctx) (!!(ctx->flags & VB2ION_CTX_IOMMU))
+
+void vb2_ion_set_cached(void *ctx, bool cached)
+{
+ struct vb2_ion_context *vb2ctx = ctx;
+
+ if (cached)
+ vb2ctx->flags &= ~VB2ION_CTX_UNCACHED;
+ else
+ vb2ctx->flags |= VB2ION_CTX_UNCACHED;
+}
+EXPORT_SYMBOL(vb2_ion_set_cached);
+
+/*
+ * when a context is protected, we cannot use the IOMMU since
+ * secure world is in charge.
+ */
+void vb2_ion_set_protected(void *ctx, bool ctx_protected)
+{
+ struct vb2_ion_context *vb2ctx = ctx;
+
+ mutex_lock(&vb2ctx->lock);
+
+ if (vb2ctx->protected == ctx_protected)
+ goto out;
+ vb2ctx->protected = ctx_protected;
+
+ if (ctx_protected) {
+ if (vb2ctx->iommu_active_cnt) {
+ dev_dbg(vb2ctx->dev, "detaching active MMU\n");
+ iovmm_deactivate(vb2ctx->dev);
+ }
+ } else {
+ if (vb2ctx->iommu_active_cnt) {
+ dev_dbg(vb2ctx->dev, "re-attaching active MMU\n");
+ iovmm_activate(vb2ctx->dev);
+ }
+ }
+
+out:
+ mutex_unlock(&vb2ctx->lock);
+}
+EXPORT_SYMBOL(vb2_ion_set_protected);
+
+int vb2_ion_set_alignment(void *ctx, size_t alignment)
+{
+ struct vb2_ion_context *vb2ctx = ctx;
+
+ if ((alignment != 0) && (alignment < PAGE_SIZE))
+ return -EINVAL;
+
+ if (alignment & ~alignment)
+ return -EINVAL;
+
+ if (alignment == 0)
+ vb2ctx->alignment = PAGE_SIZE;
+ else
+ vb2ctx->alignment = alignment;
+
+ return 0;
+}
+EXPORT_SYMBOL(vb2_ion_set_alignment);
+
+void *vb2_ion_create_context(struct device *dev, size_t alignment, long flags)
+{
+ struct vb2_ion_context *ctx;
+ unsigned int heapmask = ion_heapflag(flags);
+
+ /* ion_client_create() expects the current thread to be a kernel thread
+ * to create a new ion_client
+ */
+ WARN_ON(!(current->group_leader->flags & PF_KTHREAD));
+
+ /* non-contigous memory without H/W virtualization is not supported */
+ if ((flags & VB2ION_CTX_VMCONTIG) && !(flags & VB2ION_CTX_IOMMU))
+ return ERR_PTR(-EINVAL);
+
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return ERR_PTR(-ENOMEM);
+
+ ctx->dev = dev;
+ ctx->client = ion_client_create(ion_exynos, dev_name(dev));
+ if (IS_ERR(ctx->client)) {
+ void *retp = ctx->client;
+ kfree(ctx);
+ return retp;
+ }
+
+ vb2_ion_set_alignment(ctx, alignment);
+ ctx->flags = flags;
+ mutex_init(&ctx->lock);
+
+ return ctx;
+}
+EXPORT_SYMBOL(vb2_ion_create_context);
+
+void vb2_ion_destroy_context(void *ctx)
+{
+ struct vb2_ion_context *vb2ctx = ctx;
+
+ mutex_destroy(&vb2ctx->lock);
+ ion_client_destroy(vb2ctx->client);
+ kfree(vb2ctx);
+}
+EXPORT_SYMBOL(vb2_ion_destroy_context);
+
+void *vb2_ion_private_alloc(void *alloc_ctx, size_t size)
+{
+ struct vb2_ion_context *ctx = alloc_ctx;
+ struct vb2_ion_buf *buf;
+ int flags = ion_heapflag(ctx->flags);
+ int ret = 0;
+
+ buf = kzalloc(sizeof(*buf), GFP_KERNEL);
+ if (!buf)
+ return ERR_PTR(-ENOMEM);
+
+ size = PAGE_ALIGN(size);
+
+ buf->handle = ion_alloc(ctx->client, size, ctx->alignment,
+ flags, flags);
+ if (IS_ERR(buf->handle)) {
+ ret = -ENOMEM;
+ goto err_alloc;
+ }
+
+ buf->cookie.sgt = ion_sg_table(ctx->client, buf->handle);
+
+ buf->ctx = ctx;
+ buf->size = size;
+ buf->cached = ctx_cached(ctx);
+
+ buf->kva = ion_map_kernel(ctx->client, buf->handle);
+ if (IS_ERR(buf->kva)) {
+ ret = PTR_ERR(buf->kva);
+ buf->kva = NULL;
+ goto err_map_kernel;
+ }
+
+ mutex_lock(&ctx->lock);
+ if (ctx_iommu(ctx) && !ctx->protected) {
+ buf->cookie.ioaddr = iovmm_map(ctx->dev,
+ buf->cookie.sgt->sgl, 0,
+ buf->size);
+ if (IS_ERR_VALUE(buf->cookie.ioaddr)) {
+ ret = (int)buf->cookie.ioaddr;
+ mutex_unlock(&ctx->lock);
+ goto err_ion_map_io;
+ }
+ }
+ mutex_unlock(&ctx->lock);
+
+ return &buf->cookie;
+
+err_ion_map_io:
+ ion_unmap_kernel(ctx->client, buf->handle);
+err_map_kernel:
+ ion_free(ctx->client, buf->handle);
+err_alloc:
+ kfree(buf);
+
+ pr_err("%s: Error occured while allocating\n", __func__);
+ return ERR_PTR(ret);
+}
+
+void vb2_ion_private_free(void *cookie)
+{
+ struct vb2_ion_buf *buf =
+ container_of(cookie, struct vb2_ion_buf, cookie);
+ struct vb2_ion_context *ctx;
+
+ if (WARN_ON(IS_ERR_OR_NULL(cookie)))
+ return;
+
+ ctx = buf->ctx;
+ mutex_lock(&ctx->lock);
+ if (ctx_iommu(ctx) && !ctx->protected)
+ iovmm_unmap(ctx->dev, buf->cookie.ioaddr);
+ mutex_unlock(&ctx->lock);
+
+ ion_unmap_kernel(ctx->client, buf->handle);
+
+ ion_free(ctx->client, buf->handle);
+
+ kfree(buf);
+}
+
+static void vb2_ion_put(void *buf_priv)
+{
+ struct vb2_ion_buf *buf = buf_priv;
+
+ if (atomic_dec_and_test(&buf->ref))
+ vb2_ion_private_free(&buf->cookie);
+}
+
+static void *vb2_ion_alloc(void *alloc_ctx, unsigned long size)
+{
+ struct vb2_ion_buf *buf;
+ void *cookie;
+
+ cookie = vb2_ion_private_alloc(alloc_ctx, size);
+ if (IS_ERR(cookie))
+ return cookie;
+
+ buf = container_of(cookie, struct vb2_ion_buf, cookie);
+
+ buf->handler.refcount = &buf->ref;
+ buf->handler.put = vb2_ion_put;
+ buf->handler.arg = buf;
+ atomic_set(&buf->ref, 1);
+
+ return buf;
+}
+
+
+void *vb2_ion_private_vaddr(void *cookie)
+{
+ if (WARN_ON(IS_ERR_OR_NULL(cookie)))
+ return NULL;
+
+ return container_of(cookie, struct vb2_ion_buf, cookie)->kva;
+}
+
+static void *vb2_ion_cookie(void *buf_priv)
+{
+ struct vb2_ion_buf *buf = buf_priv;
+
+ if (WARN_ON(!buf))
+ return NULL;
+
+ return (void *)&buf->cookie;
+}
+
+static void *vb2_ion_vaddr(void *buf_priv)
+{
+ struct vb2_ion_buf *buf = buf_priv;
+
+ if (WARN_ON(!buf))
+ return NULL;
+
+ if (buf->kva != NULL)
+ return buf->kva;
+
+ if (dma_buf_begin_cpu_access(buf->dma_buf,
+ 0, buf->size, buf->direction))
+ return NULL;
+
+ buf->kva = dma_buf_kmap(buf->dma_buf, 0);
+
+ if (buf->kva == NULL)
+ dma_buf_end_cpu_access(buf->dma_buf, 0,
+ buf->size, buf->direction);
+
+ return buf->kva;
+}
+
+static unsigned int vb2_ion_num_users(void *buf_priv)
+{
+ struct vb2_ion_buf *buf = buf_priv;
+
+ if (WARN_ON(!buf))
+ return 0;
+
+ return atomic_read(&buf->ref);
+}
+
+static int vb2_ion_mmap(void *buf_priv, struct vm_area_struct *vma)
+{
+ struct vb2_ion_buf *buf = buf_priv;
+ unsigned long vm_start = vma->vm_start;
+ unsigned long vm_end = vma->vm_end;
+ struct scatterlist *sg = buf->cookie.sgt->sgl;
+ unsigned long size;
+ int ret = -EINVAL;
+
+ if (buf->size < (vm_end - vm_start))
+ return ret;
+
+ if (!buf->cached)
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+
+ size = min_t(size_t, vm_end - vm_start, sg_dma_len(sg));
+
+ ret = remap_pfn_range(vma, vm_start, page_to_pfn(sg_page(sg)),
+ size, vma->vm_page_prot);
+
+ for (sg = sg_next(sg), vm_start += size;
+ !ret && sg && (vm_start < vm_end);
+ vm_start += size, sg = sg_next(sg)) {
+ size = min_t(size_t, vm_end - vm_start, sg_dma_len(sg));
+ ret = remap_pfn_range(vma, vm_start, page_to_pfn(sg_page(sg)),
+ size, vma->vm_page_prot);
+ }
+
+ if (ret)
+ return ret;
+
+ if (vm_start < vm_end)
+ return -EINVAL;
+
+ vma->vm_flags |= VM_DONTEXPAND;
+ vma->vm_private_data = &buf->handler;
+ vma->vm_ops = &vb2_common_vm_ops;
+
+ vma->vm_ops->open(vma);
+
+ return ret;
+}
+
+static int vb2_ion_map_dmabuf(void *mem_priv)
+{
+ struct vb2_ion_buf *buf = mem_priv;
+ struct vb2_ion_context *ctx = buf->ctx;
+
+ if (WARN_ON(!buf->attachment)) {
+ pr_err("trying to pin a non attached buffer\n");
+ return -EINVAL;
+ }
+
+ if (WARN_ON(buf->cookie.sgt)) {
+ pr_err("dmabuf buffer is already pinned\n");
+ return 0;
+ }
+
+ /* get the associated scatterlist for this buffer */
+ buf->cookie.sgt = dma_buf_map_attachment(buf->attachment,
+ buf->direction);
+ if (IS_ERR_OR_NULL(buf->cookie.sgt)) {
+ pr_err("Error getting dmabuf scatterlist\n");
+ return -EINVAL;
+ }
+
+ buf->cookie.offset = 0;
+ /* buf->kva = NULL; */
+
+ mutex_lock(&ctx->lock);
+ if (ctx_iommu(ctx) && !ctx->protected && buf->cookie.ioaddr == 0) {
+ buf->cookie.ioaddr = iovmm_map(ctx->dev,
+ buf->cookie.sgt->sgl, 0, buf->size);
+ if (IS_ERR_VALUE(buf->cookie.ioaddr)) {
+ mutex_unlock(&ctx->lock);
+ dma_buf_unmap_attachment(buf->attachment,
+ buf->cookie.sgt, buf->direction);
+ return (int)buf->cookie.ioaddr;
+ }
+ }
+ mutex_unlock(&ctx->lock);
+
+ return 0;
+}
+
+static void vb2_ion_unmap_dmabuf(void *mem_priv)
+{
+ struct vb2_ion_buf *buf = mem_priv;
+
+ if (WARN_ON(!buf->attachment)) {
+ pr_err("trying to unpin a not attached buffer\n");
+ return;
+ }
+
+ if (WARN_ON(!buf->cookie.sgt)) {
+ pr_err("dmabuf buffer is already unpinned\n");
+ return;
+ }
+
+ dma_buf_unmap_attachment(buf->attachment,
+ buf->cookie.sgt, buf->direction);
+ buf->cookie.sgt = NULL;
+}
+
+static void vb2_ion_detach_dmabuf(void *mem_priv)
+{
+ struct vb2_ion_buf *buf = mem_priv;
+ struct vb2_ion_context *ctx = buf->ctx;
+
+ mutex_lock(&ctx->lock);
+ if (buf->cookie.ioaddr && ctx_iommu(ctx) && !ctx->protected ) {
+ iovmm_unmap(ctx->dev, buf->cookie.ioaddr);
+ buf->cookie.ioaddr = 0;
+ }
+ mutex_unlock(&ctx->lock);
+
+ if (buf->kva != NULL) {
+ dma_buf_kunmap(buf->dma_buf, 0, buf->kva);
+ dma_buf_end_cpu_access(buf->dma_buf, 0, buf->size, 0);
+ }
+
+ /* detach this attachment */
+ dma_buf_detach(buf->dma_buf, buf->attachment);
+ kfree(buf);
+}
+
+static void *vb2_ion_attach_dmabuf(void *alloc_ctx, struct dma_buf *dbuf,
+ unsigned long size, int write)
+{
+ struct vb2_ion_buf *buf;
+ struct dma_buf_attachment *attachment;
+
+ if (dbuf->size < size)
+ return ERR_PTR(-EFAULT);
+
+ buf = kzalloc(sizeof *buf, GFP_KERNEL);
+ if (!buf)
+ return ERR_PTR(-ENOMEM);
+
+ buf->ctx = alloc_ctx;
+ /* create attachment for the dmabuf with the user device */
+ attachment = dma_buf_attach(dbuf, buf->ctx->dev);
+ if (IS_ERR(attachment)) {
+ pr_err("failed to attach dmabuf\n");
+ kfree(buf);
+ return attachment;
+ }
+
+ buf->direction = write ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+ buf->size = size;
+ buf->dma_buf = dbuf;
+ buf->attachment = attachment;
+
+ return buf;
+}
+
+const struct vb2_mem_ops vb2_ion_memops = {
+ .alloc = vb2_ion_alloc,
+ .put = vb2_ion_put,
+ .cookie = vb2_ion_cookie,
+ .vaddr = vb2_ion_vaddr,
+ .mmap = vb2_ion_mmap,
+ .map_dmabuf = vb2_ion_map_dmabuf,
+ .unmap_dmabuf = vb2_ion_unmap_dmabuf,
+ .attach_dmabuf = vb2_ion_attach_dmabuf,
+ .detach_dmabuf = vb2_ion_detach_dmabuf,
+ .num_users = vb2_ion_num_users,
+};
+EXPORT_SYMBOL_GPL(vb2_ion_memops);
+
+void vb2_ion_sync_for_device(void *cookie, off_t offset, size_t size,
+ enum dma_data_direction dir)
+{
+ struct vb2_ion_cookie *vb2cookie = cookie;
+ struct vb2_ion_context *ctx =
+ container_of(cookie, struct vb2_ion_buf, cookie)->ctx;
+ struct scatterlist *sg;
+
+ for (sg = vb2cookie->sgt->sgl; sg != NULL; sg = sg_next(sg)) {
+ if (sg_dma_len(sg) <= offset)
+ offset -= sg_dma_len(sg);
+ else
+ break;
+ }
+
+ if (WARN_ON(sg == NULL)) /* Too big offset */
+ return;
+
+ while ((size != 0) && (sg != NULL)) {
+ size_t sg_size;
+
+ sg_size = min_t(size_t, size, sg_dma_len(sg) - offset);
+ dma_map_page(ctx->dev, sg_page(sg) + PFN_DOWN(offset),
+ offset & ~PAGE_MASK, sg_size, dir);
+
+ offset = 0;
+ size -= sg_size;
+ sg = sg_next(sg);
+ }
+
+ WARN_ON(size != 0); /* Too big size */
+}
+EXPORT_SYMBOL_GPL(vb2_ion_sync_for_device);
+
+void vb2_ion_sync_for_cpu(void *cookie, off_t offset, size_t size,
+ enum dma_data_direction dir)
+{
+ struct vb2_ion_cookie *vb2cookie = cookie;
+ struct vb2_ion_context *ctx =
+ container_of(cookie, struct vb2_ion_buf, cookie)->ctx;
+ struct scatterlist *sg;
+
+ for (sg = vb2cookie->sgt->sgl; sg != NULL; sg = sg_next(sg)) {
+ if (sg_dma_len(sg) <= offset)
+ offset -= sg_dma_len(sg);
+ else
+ break;
+ }
+
+ if (WARN_ON(sg == NULL)) /* Too big offset */
+ return;
+
+ while ((size != 0) && (sg != NULL)) {
+ size_t sg_size;
+
+ sg_size = min_t(size_t, size, sg_dma_len(sg) - offset);
+ dma_unmap_page(ctx->dev, sg_phys(sg) + offset, sg_size, dir);
+
+ offset = 0;
+ size -= sg_size;
+ sg = sg_next(sg);
+ }
+
+ WARN_ON(size != 0); /* Too big size */
+}
+EXPORT_SYMBOL_GPL(vb2_ion_sync_for_cpu);
+
+static void flush_entire_dcache(void *p)
+{
+ flush_cache_all();
+}
+
+int vb2_ion_cache_flush(struct vb2_buffer *vb, u32 num_planes)
+{
+ int i;
+ size_t sz = 0;
+ struct vb2_ion_buf *buf;
+ enum dma_data_direction dir;
+
+ for (i = 0; i < num_planes; i++) {
+ buf = vb->planes[i].mem_priv;
+ if (!buf->cached)
+ continue;
+
+ sz += buf->size;
+ }
+
+ if (sz >= SZ_2M) { /* performance tuning */
+ smp_call_function(&flush_entire_dcache, NULL, 1);
+ outer_flush_all();
+ return 0;
+ }
+
+ dir = V4L2_TYPE_IS_OUTPUT(vb->v4l2_buf.type) ?
+ DMA_TO_DEVICE : DMA_FROM_DEVICE;
+
+ while (num_planes-- > 0) {
+ struct scatterlist *sg;
+ off_t start_off;
+ int num_pages;
+ struct page *page;
+
+ buf = vb->planes[num_planes].mem_priv;
+ if (!buf->cached)
+ continue;
+
+ sg = buf->cookie.sgt->sgl;
+ start_off = buf->cookie.offset;
+ sz = buf->size;
+
+ while (sg && (start_off >= sg_dma_len(sg))) {
+ start_off -= sg_dma_len(sg);
+ sg = sg_next(sg);
+ }
+
+ for (; (sg != NULL) && (sz > 0); sg = sg_next(sg)) {
+ int pages_to_pass;
+ void *addr;
+ bool kmapped = false;
+
+ start_off += sg->offset;
+
+ num_pages = PFN_DOWN(
+ PAGE_ALIGN(sg_dma_len(sg) + sg->offset));
+ pages_to_pass = PFN_DOWN(
+ round_down(start_off, PAGE_SIZE));
+ num_pages -= pages_to_pass;
+
+ page = sg_page(sg) + pages_to_pass;
+ start_off &= ~PAGE_MASK;
+
+ for (i = 0; (i < num_pages) && (sz > 0); i++, page++) {
+ size_t szflush;
+
+ szflush = min_t(size_t,
+ PAGE_SIZE - start_off, sz);
+
+ addr = page_address(page);
+ if (!addr) {
+ addr = kmap_atomic(page);
+ kmapped = true;
+ }
+
+ dmac_map_area(addr + start_off, szflush, dir);
+
+ if (dir == DMA_TO_DEVICE)
+ outer_clean_range(
+ page_to_phys(page) + start_off,
+ page_to_phys(page) + szflush);
+ else
+ outer_inv_range(
+ page_to_phys(page) + start_off,
+ page_to_phys(page) + szflush);
+
+ if (kmapped) {
+ kunmap_atomic(addr);
+ kmapped = false;
+ }
+
+ sz -= szflush;
+ start_off = 0;
+ }
+ }
+
+ WARN_ON(sz > 0);
+ }
+
+ return 0;
+}
+
+int vb2_ion_cache_inv(struct vb2_buffer *vb, u32 num_planes)
+{
+ struct vb2_ion_buf *buf;
+ int i;
+
+ for (i = 0; i < num_planes; i++) {
+ buf = vb->planes[i].mem_priv;
+ if (!buf->cached)
+ continue;
+
+ vb2_ion_sync_for_device(&buf->cookie, buf->cookie.offset,
+ buf->size, DMA_FROM_DEVICE);
+ }
+
+ return 0;
+}
+
+void vb2_ion_detach_iommu(void *alloc_ctx)
+{
+ struct vb2_ion_context *ctx = alloc_ctx;
+
+ if (!ctx_iommu(ctx))
+ return;
+
+ mutex_lock(&ctx->lock);
+ BUG_ON(ctx->iommu_active_cnt == 0);
+
+ if (--ctx->iommu_active_cnt == 0 && !ctx->protected)
+ iovmm_deactivate(ctx->dev);
+ mutex_unlock(&ctx->lock);
+}
+EXPORT_SYMBOL_GPL(vb2_ion_detach_iommu);
+
+int vb2_ion_attach_iommu(void *alloc_ctx)
+{
+ struct vb2_ion_context *ctx = alloc_ctx;
+ int ret = 0;
+
+ if (!ctx_iommu(ctx))
+ return -ENOENT;
+
+ mutex_lock(&ctx->lock);
+ if (ctx->iommu_active_cnt == 0 && !ctx->protected)
+ ret = iovmm_activate(ctx->dev);
+ if (!ret)
+ ctx->iommu_active_cnt++;
+ mutex_unlock(&ctx->lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(vb2_ion_attach_iommu);
+
+MODULE_AUTHOR("Jonghun, Han <jonghun.han@samsung.com>");
+MODULE_DESCRIPTION("Android ION allocator handling routines for videobuf2");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c
index 9d7ca1e..38db765 100644
--- a/drivers/mfd/wm8994-core.c
+++ b/drivers/mfd/wm8994-core.c
@@ -375,7 +375,7 @@
static const __devinitdata struct reg_default wm1811_reva_patch[] = {
{ 0x102, 0x3 },
- { 0x56, 0x7 },
+ { 0x56, 0xc07 },
{ 0x5d, 0x7e },
{ 0x5e, 0x0 },
{ 0x102, 0x0 },
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 54c8322..93fee57 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -58,6 +58,13 @@
#define INAND_CMD38_ARG_SECTRIM1 0x81
#define INAND_CMD38_ARG_SECTRIM2 0x88
+#define mmc_req_rel_wr(req) (((req->cmd_flags & REQ_FUA) || \
+ (req->cmd_flags & REQ_META)) && \
+ (rq_data_dir(req) == WRITE))
+#define PACKED_CMD_VER 0x01
+#define PACKED_CMD_RD 0x01
+#define PACKED_CMD_WR 0x02
+
static DEFINE_MUTEX(block_mutex);
/*
@@ -98,6 +105,7 @@
#define MMC_BLK_WRITE BIT(1)
#define MMC_BLK_DISCARD BIT(2)
#define MMC_BLK_SECDISCARD BIT(3)
+#define MMC_BLK_WR_HDR BIT(4)
/*
* Only set in main mmc_blk_data associated
@@ -123,9 +131,24 @@
MMC_BLK_NOMEDIUM,
};
+enum {
+ MMC_PACKED_N_IDX = -1,
+ MMC_PACKED_N_ZERO,
+ MMC_PACKED_N_SINGLE,
+};
+
module_param(perdev_minors, int, 0444);
MODULE_PARM_DESC(perdev_minors, "Minors numbers to allocate per device");
+static inline void mmc_blk_clear_packed(struct mmc_queue_req *mqrq)
+{
+ mqrq->packed_cmd = MMC_PACKED_NONE;
+ mqrq->packed_num = MMC_PACKED_N_ZERO;
+ mqrq->packed_sg_flag = MMC_PACKED_NONE_SG;
+ mqrq->mmc_active.__mrq = NULL;
+ mqrq->mmc_active.__cond = false;
+}
+
static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
{
struct mmc_blk_data *md;
@@ -1049,7 +1072,8 @@
* kind. If it was a write, we may have transitioned to
* program mode, which we have to wait for it to complete.
*/
- if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) {
+ if ((!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) ||
+ (mq_mrq->packed_cmd == MMC_PACKED_WR_HDR)) {
u32 status;
do {
int err = get_card_status(card, &status, 5);
@@ -1074,7 +1098,8 @@
(unsigned)blk_rq_sectors(req),
brq->cmd.resp[0], brq->stop.resp[0]);
- if (rq_data_dir(req) == READ) {
+ if (rq_data_dir(req) == READ &&
+ mq_mrq->packed_cmd != MMC_PACKED_WR_HDR) {
if (ecc_err)
return MMC_BLK_ECC_ERR;
return MMC_BLK_DATA_ERR;
@@ -1086,12 +1111,61 @@
if (!brq->data.bytes_xfered)
return MMC_BLK_RETRY;
+ if (mq_mrq->packed_cmd != MMC_PACKED_NONE) {
+ if (unlikely(brq->data.blocks << 9 != brq->data.bytes_xfered))
+ return MMC_BLK_PARTIAL;
+ else
+ return MMC_BLK_SUCCESS;
+ }
+
if (blk_rq_bytes(req) != brq->data.bytes_xfered)
return MMC_BLK_PARTIAL;
return MMC_BLK_SUCCESS;
}
+static int mmc_blk_packed_err_check(struct mmc_card *card,
+ struct mmc_async_req *areq)
+{
+ struct mmc_queue_req *mq_rq = container_of(areq, struct mmc_queue_req,
+ mmc_active);
+ struct request *req = mq_rq->req;
+ int err, check, status;
+ u8 ext_csd[512];
+
+ mq_rq->packed_retries--;
+ check = mmc_blk_err_check(card, areq);
+ err = get_card_status(card, &status, 0);
+ if (err) {
+ pr_err("%s: error %d sending status command\n",
+ req->rq_disk->disk_name, err);
+ return MMC_BLK_ABORT;
+ }
+
+ if (status & R1_EXP_EVENT) {
+ err = mmc_send_ext_csd(card, ext_csd);
+ if (err) {
+ pr_err("%s: error %d sending ext_csd\n",
+ req->rq_disk->disk_name, err);
+ return MMC_BLK_ABORT;
+ }
+
+ if ((ext_csd[EXT_CSD_EXP_EVENTS_STATUS] &
+ EXT_CSD_PACKED_FAILURE) &&
+ (ext_csd[EXT_CSD_PACKED_CMD_STATUS] &
+ EXT_CSD_PACKED_GENERIC_ERROR)) {
+ if (ext_csd[EXT_CSD_PACKED_CMD_STATUS] &
+ EXT_CSD_PACKED_INDEXED_ERROR) {
+ mq_rq->packed_fail_idx =
+ ext_csd[EXT_CSD_PACKED_FAILURE_INDEX] - 1;
+ return MMC_BLK_PARTIAL;
+ }
+ }
+ }
+
+ return check;
+}
+
static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
struct mmc_card *card,
int disable_multi,
@@ -1246,10 +1320,274 @@
mmc_queue_bounce_pre(mqrq);
}
+static u8 mmc_blk_prep_packed_list(struct mmc_queue *mq, struct request *req)
+{
+ struct request_queue *q = mq->queue;
+ struct mmc_card *card = mq->card;
+ struct request *cur = req, *next = NULL;
+ struct mmc_blk_data *md = mq->data;
+ bool en_rel_wr = card->ext_csd.rel_param & EXT_CSD_WR_REL_PARAM_EN;
+ unsigned int req_sectors = 0, phys_segments = 0;
+ unsigned int max_blk_count, max_phys_segs;
+ u8 put_back = 0;
+ u8 max_packed_rw = 0;
+ u8 reqs = 0;
+
+ mmc_blk_clear_packed(mq->mqrq_cur);
+
+ if (!(md->flags & MMC_BLK_CMD23) ||
+ !card->ext_csd.packed_event_en)
+ goto no_packed;
+
+ if ((rq_data_dir(cur) == WRITE) &&
+ (card->host->caps2 & MMC_CAP2_PACKED_WR))
+ max_packed_rw = card->ext_csd.max_packed_writes;
+ else if ((rq_data_dir(cur) == READ) &&
+ (card->host->caps2 & MMC_CAP2_PACKED_RD))
+ max_packed_rw = card->ext_csd.max_packed_reads;
+
+ if (max_packed_rw == 0)
+ goto no_packed;
+
+ if (mmc_req_rel_wr(cur) &&
+ (md->flags & MMC_BLK_REL_WR) &&
+ !en_rel_wr)
+ goto no_packed;
+
+ max_blk_count = min(card->host->max_blk_count,
+ card->host->max_req_size >> 9);
+ if (unlikely(max_blk_count > 0xffff))
+ max_blk_count = 0xffff;
+
+ max_phys_segs = queue_max_segments(q);
+ req_sectors += blk_rq_sectors(cur);
+ phys_segments += cur->nr_phys_segments;
+
+ if (rq_data_dir(cur) == WRITE) {
+ req_sectors++;
+ phys_segments++;
+ }
+
+ while (reqs < max_packed_rw - 1) {
+ spin_lock_irq(q->queue_lock);
+ next = blk_fetch_request(q);
+ spin_unlock_irq(q->queue_lock);
+ if (!next)
+ break;
+
+ if (next->cmd_flags & REQ_DISCARD ||
+ next->cmd_flags & REQ_FLUSH) {
+ put_back = 1;
+ break;
+ }
+
+ if (rq_data_dir(cur) != rq_data_dir(next)) {
+ put_back = 1;
+ break;
+ }
+
+ if (mmc_req_rel_wr(next) &&
+ (md->flags & MMC_BLK_REL_WR) &&
+ !en_rel_wr) {
+ put_back = 1;
+ break;
+ }
+
+ req_sectors += blk_rq_sectors(next);
+ if (req_sectors > max_blk_count) {
+ put_back = 1;
+ break;
+ }
+
+ phys_segments += next->nr_phys_segments;
+ if (phys_segments > max_phys_segs) {
+ put_back = 1;
+ break;
+ }
+
+ list_add_tail(&next->queuelist, &mq->mqrq_cur->packed_list);
+ cur = next;
+ reqs++;
+ }
+
+ if (put_back) {
+ spin_lock_irq(q->queue_lock);
+ blk_requeue_request(q, next);
+ spin_unlock_irq(q->queue_lock);
+ }
+
+ if (reqs > 0) {
+ list_add(&req->queuelist, &mq->mqrq_cur->packed_list);
+ mq->mqrq_cur->packed_num = ++reqs;
+ mq->mqrq_cur->packed_retries = reqs;
+ return reqs;
+ }
+
+no_packed:
+ mmc_blk_clear_packed(mq->mqrq_cur);
+ return 0;
+}
+
+static void mmc_blk_packed_rrq_prep(struct mmc_queue_req *mqrq,
+ struct mmc_card *card,
+ struct mmc_queue *mq)
+{
+ struct mmc_queue_req *__mqrq = mq->mqrq_hdr;
+ struct mmc_blk_request *brq = &mqrq->brq;
+ struct request *req = mqrq->req;
+
+ mqrq->packed_cmd = MMC_PACKED_READ;
+ mqrq->packed_sg_flag = MMC_PACKED_RD_SG;
+
+ memset(brq, 0, sizeof(struct mmc_blk_request));
+ brq->mrq.cmd = &brq->cmd;
+ brq->mrq.data = &brq->data;
+ brq->mrq.stop = &brq->stop;
+
+ brq->cmd.opcode = MMC_READ_MULTIPLE_BLOCK;
+ brq->cmd.arg = blk_rq_pos(req);
+ if (!mmc_card_blockaddr(card))
+ brq->cmd.arg <<= 9;
+ brq->cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
+ brq->data.blksz = 512;
+ brq->data.blocks = mqrq->packed_blocks;
+ brq->data.flags |= MMC_DATA_READ;
+
+ brq->stop.opcode = MMC_STOP_TRANSMISSION;
+ brq->stop.arg = 0;
+ brq->stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
+
+ mmc_set_data_timeout(&brq->data, card);
+
+ brq->data.sg = mqrq->sg;
+ brq->data.sg_len = mmc_queue_map_sg(mq, mqrq);
+
+ mqrq->mmc_active.mrq = &brq->mrq;
+ mqrq->mmc_active.__mrq = NULL;
+ mqrq->mmc_active.__cond = true;
+ mqrq->mmc_active.err_check = mmc_blk_packed_err_check;
+ __mqrq->mmc_active.__mrq = &brq->mrq;
+}
+
+static void mmc_blk_packed_hdr_wrq_prep(struct mmc_queue_req *mqrq,
+ struct mmc_card *card,
+ struct mmc_queue *mq)
+{
+ struct mmc_queue_req *__mqrq;
+ struct mmc_blk_request *brq;
+ struct request *req = mqrq->req;
+ struct request *prq;
+ struct mmc_blk_data *md = mq->data;
+ bool do_rel_wr, do_data_tag;
+ u32 *packed_cmd_hdr;
+ u8 i = 1;
+
+ if (rq_data_dir(req) == READ) {
+ __mqrq = mq->mqrq_hdr;
+ __mqrq->packed_cmd = MMC_PACKED_WR_HDR;
+ __mqrq->packed_sg_flag = MMC_PACKED_HDR_SG;
+ __mqrq->req = mqrq->req;
+ } else {
+ __mqrq = mqrq;
+ __mqrq->packed_cmd = MMC_PACKED_WRITE;
+ __mqrq->packed_sg_flag = MMC_PACKED_WR_SG;
+ }
+
+ brq = &__mqrq->brq;
+ packed_cmd_hdr = __mqrq->packed_cmd_hdr;
+
+ mqrq->packed_blocks = 0;
+ mqrq->packed_fail_idx = MMC_PACKED_N_IDX;
+
+ memset(packed_cmd_hdr, 0, sizeof(__mqrq->packed_cmd_hdr));
+ packed_cmd_hdr[0] = (mqrq->packed_num << 16) |
+ (((rq_data_dir(req) == READ) ?
+ PACKED_CMD_RD : PACKED_CMD_WR) << 8) |
+ PACKED_CMD_VER;
+
+ /*
+ * Argument for each entry of packed group
+ */
+ list_for_each_entry(prq, &mqrq->packed_list, queuelist) {
+ do_rel_wr = mmc_req_rel_wr(prq) && (md->flags & MMC_BLK_REL_WR);
+ do_data_tag = (card->ext_csd.data_tag_unit_size) &&
+ (prq->cmd_flags & REQ_META) &&
+ (rq_data_dir(prq) == WRITE) &&
+ ((brq->data.blocks * brq->data.blksz) >=
+ card->ext_csd.data_tag_unit_size);
+ /* Argument of CMD23 */
+ packed_cmd_hdr[(i * 2)] =
+ (do_rel_wr ? MMC_CMD23_ARG_REL_WR : 0) |
+ (do_data_tag ? MMC_CMD23_ARG_TAG_REQ : 0) |
+ blk_rq_sectors(prq);
+ /* Argument of CMD18 or CMD25 */
+ packed_cmd_hdr[((i * 2)) + 1] =
+ mmc_card_blockaddr(card) ?
+ blk_rq_pos(prq) : blk_rq_pos(prq) << 9;
+ mqrq->packed_blocks += blk_rq_sectors(prq);
+ i++;
+ }
+
+ memset(brq, 0, sizeof(struct mmc_blk_request));
+ brq->mrq.cmd = &brq->cmd;
+ brq->mrq.data = &brq->data;
+ brq->mrq.sbc = &brq->sbc;
+ brq->mrq.stop = &brq->stop;
+
+ brq->sbc.opcode = MMC_SET_BLOCK_COUNT;
+ brq->sbc.arg = MMC_CMD23_ARG_PACKED |
+ ((rq_data_dir(req) == READ) ? 1 : mqrq->packed_blocks + 1);
+ brq->sbc.flags = MMC_RSP_R1 | MMC_CMD_AC;
+
+ brq->cmd.opcode = MMC_WRITE_MULTIPLE_BLOCK;
+ brq->cmd.arg = blk_rq_pos(req);
+ if (!mmc_card_blockaddr(card))
+ brq->cmd.arg <<= 9;
+ brq->cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
+
+ brq->data.blksz = 512;
+ /*
+ * Write separately the packd command header only for packed read.
+ * In case of packed write, header is sent with blocks of data.
+ */
+ brq->data.blocks = (rq_data_dir(req) == READ) ?
+ 1 : mqrq->packed_blocks + 1;
+ brq->data.flags |= MMC_DATA_WRITE;
+
+ brq->stop.opcode = MMC_STOP_TRANSMISSION;
+ brq->stop.arg = 0;
+ brq->stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
+
+ mmc_set_data_timeout(&brq->data, card);
+
+ brq->data.sg = __mqrq->sg;
+ brq->data.sg_len = mmc_queue_map_sg(mq, __mqrq);
+
+ __mqrq->mmc_active.mrq = &brq->mrq;
+
+ if (rq_data_dir(req) == READ)
+ __mqrq->mmc_active.err_check = mmc_blk_err_check;
+ else
+ __mqrq->mmc_active.err_check = mmc_blk_packed_err_check;
+
+ mmc_queue_bounce_pre(__mqrq);
+
+ /*
+ * In case of packed read, header is split with data.
+ * Prepare the data ahead for packed read.
+ * This will preserve the asynchronos transfer.
+ */
+ if (rq_data_dir(req) == READ)
+ mmc_blk_packed_rrq_prep(mqrq, card, mq);
+}
+
static int mmc_blk_cmd_err(struct mmc_blk_data *md, struct mmc_card *card,
struct mmc_blk_request *brq, struct request *req,
int ret)
{
+ struct mmc_queue_req *mq_rq;
+ mq_rq = container_of(brq, struct mmc_queue_req, brq);
+
/*
* If this is an SD card and we're writing, we can first
* mark the known good sectors as ok.
@@ -1268,13 +1606,134 @@
spin_unlock_irq(&md->lock);
}
} else {
- spin_lock_irq(&md->lock);
- ret = __blk_end_request(req, 0, brq->data.bytes_xfered);
- spin_unlock_irq(&md->lock);
+ if (mq_rq->packed_cmd == MMC_PACKED_NONE) {
+ spin_lock_irq(&md->lock);
+ ret = __blk_end_request(req, 0, brq->data.bytes_xfered);
+ spin_unlock_irq(&md->lock);
+ }
}
return ret;
}
+static int mmc_blk_end_packed_req(struct mmc_queue *mq,
+ struct mmc_queue_req *mq_rq)
+{
+ struct mmc_blk_data *md = mq->data;
+ struct request *prq;
+ int idx = mq_rq->packed_fail_idx, i = 0;
+ int ret = 0;
+
+ while (!list_empty(&mq_rq->packed_list)) {
+ prq = list_entry_rq(mq_rq->packed_list.next);
+ if (idx == i) {
+ /* retry from error index */
+ mq_rq->packed_num -= idx;
+ mq_rq->req = prq;
+ ret = 1;
+
+ if (mq_rq->packed_num == MMC_PACKED_N_SINGLE) {
+ list_del_init(&prq->queuelist);
+ mmc_blk_clear_packed(mq_rq);
+ }
+ return ret;
+ }
+ list_del_init(&prq->queuelist);
+ spin_lock_irq(&md->lock);
+ __blk_end_request(prq, 0, blk_rq_bytes(prq));
+ spin_unlock_irq(&md->lock);
+ i++;
+ }
+
+ mmc_blk_clear_packed(mq_rq);
+ return ret;
+}
+
+static int mmc_blk_chk_hdr_err(struct mmc_queue *mq, int status)
+{
+ struct mmc_blk_data *md = mq->data;
+ struct mmc_card *card = md->queue.card;
+ int type = MMC_BLK_WR_HDR, err = 0;
+
+ switch (status) {
+ case MMC_BLK_PARTIAL:
+ case MMC_BLK_RETRY:
+ err = 0;
+ break;
+ case MMC_BLK_CMD_ERR:
+ case MMC_BLK_ABORT:
+ case MMC_BLK_DATA_ERR:
+ case MMC_BLK_ECC_ERR:
+ err = mmc_blk_reset(md, card->host, type);
+ if (!err)
+ mmc_blk_reset_success(md, type);
+ break;
+ }
+
+ return err;
+}
+
+static int mmc_blk_issue_packed_rd(struct mmc_queue *mq,
+ struct mmc_queue_req *mq_rq)
+{
+ struct mmc_blk_data *md = mq->data;
+ struct mmc_card *card = md->queue.card;
+ int status, ret = -EIO, retry = 2;
+
+ do {
+ mmc_start_req(card->host, &mq_rq->mmc_active, &status);
+ if (!status) {
+ ret = 0;
+ break;
+ }
+
+ ret = mmc_blk_chk_hdr_err(mq, status);
+ if (ret)
+ break;
+ mmc_blk_packed_hdr_wrq_prep(mq_rq, card, mq);
+ mmc_start_req(card->host, &mq->mqrq_hdr->mmc_active, NULL);
+ } while (retry-- > 0);
+
+ return ret;
+}
+
+static void mmc_blk_abort_packed_req(struct mmc_queue *mq,
+ struct mmc_queue_req *mq_rq)
+{
+ struct mmc_blk_data *md = mq->data;
+ struct request *prq;
+
+ while (!list_empty(&mq_rq->packed_list)) {
+ prq = list_entry_rq(mq_rq->packed_list.next);
+ list_del_init(&prq->queuelist);
+ spin_lock_irq(&md->lock);
+ __blk_end_request(prq, -EIO, blk_rq_bytes(prq));
+ spin_unlock_irq(&md->lock);
+ }
+
+ mmc_blk_clear_packed(mq_rq);
+}
+
+static void mmc_blk_revert_packed_req(struct mmc_queue *mq,
+ struct mmc_queue_req *mq_rq)
+{
+ struct request *prq;
+ struct request_queue *q = mq->queue;
+
+ while (!list_empty(&mq_rq->packed_list)) {
+ prq = list_entry_rq(mq_rq->packed_list.prev);
+ if (prq->queuelist.prev != &mq_rq->packed_list) {
+ list_del_init(&prq->queuelist);
+ spin_lock_irq(q->queue_lock);
+ blk_requeue_request(mq->queue, prq);
+ spin_unlock_irq(q->queue_lock);
+ } else {
+ list_del_init(&prq->queuelist);
+ }
+ }
+
+ mmc_blk_clear_packed(mq_rq);
+}
+
static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
{
struct mmc_blk_data *md = mq->data;
@@ -1285,19 +1744,37 @@
struct mmc_queue_req *mq_rq;
struct request *req;
struct mmc_async_req *areq;
+ const u8 packed_num = 2;
+ u8 reqs = 0;
if (!rqc && !mq->mqrq_prev->req)
return 0;
+ if (rqc)
+ reqs = mmc_blk_prep_packed_list(mq, rqc);
+
do {
if (rqc) {
- mmc_blk_rw_rq_prep(mq->mqrq_cur, card, 0, mq);
- areq = &mq->mqrq_cur->mmc_active;
+ if (reqs >= packed_num)
+ mmc_blk_packed_hdr_wrq_prep(mq->mqrq_cur,
+ card, mq);
+ else
+ mmc_blk_rw_rq_prep(mq->mqrq_cur, card, 0, mq);
+
+ if (mq->mqrq_cur->packed_cmd == MMC_PACKED_READ)
+ areq = &mq->mqrq_hdr->mmc_active;
+ else
+ areq = &mq->mqrq_cur->mmc_active;
} else
areq = NULL;
+
areq = mmc_start_req(card->host, areq, (int *) &status);
- if (!areq)
- return 0;
+ if (!areq) {
+ if (mq->mqrq_cur->packed_cmd == MMC_PACKED_READ)
+ goto snd_packed_rd;
+ else
+ return 0;
+ }
mq_rq = container_of(areq, struct mmc_queue_req, mmc_active);
brq = &mq_rq->brq;
@@ -1312,10 +1789,16 @@
* A block was successfully transferred.
*/
mmc_blk_reset_success(md, type);
- spin_lock_irq(&md->lock);
- ret = __blk_end_request(req, 0,
+
+ if (mq_rq->packed_cmd != MMC_PACKED_NONE) {
+ ret = mmc_blk_end_packed_req(mq, mq_rq);
+ break;
+ } else {
+ spin_lock_irq(&md->lock);
+ ret = __blk_end_request(req, 0,
brq->data.bytes_xfered);
- spin_unlock_irq(&md->lock);
+ spin_unlock_irq(&md->lock);
+ }
/*
* If the blk_end_request function returns non-zero even
* though all data has been transferred and no errors
@@ -1348,7 +1831,8 @@
err = mmc_blk_reset(md, card->host, type);
if (!err)
break;
- if (err == -ENODEV)
+ if (err == -ENODEV ||
+ mq_rq->packed_cmd != MMC_PACKED_NONE)
goto cmd_abort;
/* Fall through */
}
@@ -1377,27 +1861,60 @@
}
if (ret) {
- /*
- * In case of a incomplete request
- * prepare it again and resend.
- */
- mmc_blk_rw_rq_prep(mq_rq, card, disable_multi, mq);
- mmc_start_req(card->host, &mq_rq->mmc_active, NULL);
+ if (mq_rq->packed_cmd == MMC_PACKED_NONE) {
+ /*
+ * In case of a incomplete request
+ * prepare it again and resend.
+ */
+ mmc_blk_rw_rq_prep(mq_rq, card,
+ disable_multi, mq);
+ mmc_start_req(card->host,
+ &mq_rq->mmc_active, NULL);
+ } else {
+ if (!mq_rq->packed_retries)
+ goto cmd_abort;
+ mmc_blk_packed_hdr_wrq_prep(mq_rq, card, mq);
+ if (mq_rq->packed_cmd == MMC_PACKED_READ) {
+ mmc_start_req(card->host,
+ &mq->mqrq_hdr->mmc_active,
+ NULL);
+ if (mmc_blk_issue_packed_rd(mq, mq_rq))
+ goto cmd_abort;
+ } else
+ mmc_start_req(card->host,
+ &mq_rq->mmc_active, NULL);
+ }
}
} while (ret);
+snd_packed_rd:
+ if (mq->mqrq_cur->packed_cmd == MMC_PACKED_READ) {
+ if (mmc_blk_issue_packed_rd(mq, mq->mqrq_cur))
+ goto start_new_req;
+ }
return 1;
cmd_abort:
- spin_lock_irq(&md->lock);
- if (mmc_card_removed(card))
- req->cmd_flags |= REQ_QUIET;
- while (ret)
- ret = __blk_end_request(req, -EIO, blk_rq_cur_bytes(req));
- spin_unlock_irq(&md->lock);
+ if (mq_rq->packed_cmd == MMC_PACKED_NONE) {
+ spin_lock_irq(&md->lock);
+ if (mmc_card_removed(card))
+ req->cmd_flags |= REQ_QUIET;
+ while (ret)
+ ret = __blk_end_request(req, -EIO,
+ blk_rq_cur_bytes(req));
+ spin_unlock_irq(&md->lock);
+ } else {
+ mmc_blk_abort_packed_req(mq, mq_rq);
+ }
start_new_req:
if (rqc) {
+ /*
+ * If current request is packed, it needs to put back.
+ */
+ if (mq->mqrq_cur->packed_cmd != MMC_PACKED_NONE)
+ mmc_blk_revert_packed_req(mq, mq->mqrq_cur);
+
mmc_blk_rw_rq_prep(mq->mqrq_cur, card, 0, mq);
mmc_start_req(card->host, &mq->mqrq_cur->mmc_active, NULL);
}
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index 996f8e3..b3a0896 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -166,6 +166,7 @@
int ret;
struct mmc_queue_req *mqrq_cur = &mq->mqrq[0];
struct mmc_queue_req *mqrq_prev = &mq->mqrq[1];
+ struct mmc_queue_req *mqrq_hdr = &mq->mqrq[2];
if (mmc_dev(host)->dma_mask && *mmc_dev(host)->dma_mask)
limit = *mmc_dev(host)->dma_mask;
@@ -177,8 +178,15 @@
memset(&mq->mqrq_cur, 0, sizeof(mq->mqrq_cur));
memset(&mq->mqrq_prev, 0, sizeof(mq->mqrq_prev));
+ memset(&mq->mqrq_hdr, 0, sizeof(mq->mqrq_hdr));
+
+ INIT_LIST_HEAD(&mqrq_cur->packed_list);
+ INIT_LIST_HEAD(&mqrq_prev->packed_list);
+ INIT_LIST_HEAD(&mqrq_hdr->packed_list);
+
mq->mqrq_cur = mqrq_cur;
mq->mqrq_prev = mqrq_prev;
+ mq->mqrq_hdr = mqrq_hdr;
mq->queue->queuedata = mq;
blk_queue_prep_rq(mq->queue, mmc_prep_request);
@@ -214,9 +222,21 @@
kfree(mqrq_cur->bounce_buf);
mqrq_cur->bounce_buf = NULL;
}
+
+ mqrq_hdr->bounce_buf = kmalloc(bouncesz, GFP_KERNEL);
+ if (!mqrq_hdr->bounce_buf) {
+ printk(KERN_WARNING "%s: unable to "
+ "allocate bounce hdr buffer\n",
+ mmc_card_name(card));
+ kfree(mqrq_cur->bounce_buf);
+ mqrq_cur->bounce_buf = NULL;
+ kfree(mqrq_prev->bounce_buf);
+ mqrq_prev->bounce_buf = NULL;
+ }
}
- if (mqrq_cur->bounce_buf && mqrq_prev->bounce_buf) {
+ if (mqrq_cur->bounce_buf && mqrq_prev->bounce_buf &&
+ mqrq_hdr->bounce_buf) {
blk_queue_bounce_limit(mq->queue, BLK_BOUNCE_ANY);
blk_queue_max_hw_sectors(mq->queue, bouncesz / 512);
blk_queue_max_segments(mq->queue, bouncesz / 512);
@@ -239,11 +259,21 @@
mmc_alloc_sg(bouncesz / 512, &ret);
if (ret)
goto cleanup_queue;
+
+ mqrq_hdr->sg = mmc_alloc_sg(1, &ret);
+ if (ret)
+ goto cleanup_queue;
+
+ mqrq_hdr->bounce_sg =
+ mmc_alloc_sg(bouncesz / 512, &ret);
+ if (ret)
+ goto cleanup_queue;
}
}
#endif
- if (!mqrq_cur->bounce_buf && !mqrq_prev->bounce_buf) {
+ if (!mqrq_cur->bounce_buf && !mqrq_prev->bounce_buf &&
+ !mqrq_hdr->bounce_buf) {
blk_queue_bounce_limit(mq->queue, limit);
blk_queue_max_hw_sectors(mq->queue,
min(host->max_blk_count, host->max_req_size / 512));
@@ -254,10 +284,13 @@
if (ret)
goto cleanup_queue;
-
mqrq_prev->sg = mmc_alloc_sg(host->max_segs, &ret);
if (ret)
goto cleanup_queue;
+
+ mqrq_hdr->sg = mmc_alloc_sg(host->max_segs, &ret);
+ if (ret)
+ goto cleanup_queue;
}
sema_init(&mq->thread_sem, 1);
@@ -276,6 +309,8 @@
mqrq_cur->bounce_sg = NULL;
kfree(mqrq_prev->bounce_sg);
mqrq_prev->bounce_sg = NULL;
+ kfree(mqrq_hdr->bounce_sg);
+ mqrq_hdr->bounce_sg = NULL;
cleanup_queue:
kfree(mqrq_cur->sg);
@@ -288,6 +323,11 @@
kfree(mqrq_prev->bounce_buf);
mqrq_prev->bounce_buf = NULL;
+ kfree(mqrq_hdr->sg);
+ mqrq_hdr->sg = NULL;
+ kfree(mqrq_hdr->bounce_buf);
+ mqrq_hdr->bounce_buf = NULL;
+
blk_cleanup_queue(mq->queue);
return ret;
}
@@ -298,6 +338,7 @@
unsigned long flags;
struct mmc_queue_req *mqrq_cur = mq->mqrq_cur;
struct mmc_queue_req *mqrq_prev = mq->mqrq_prev;
+ struct mmc_queue_req *mqrq_hdr = mq->mqrq_hdr;
/* Make sure the queue isn't suspended, as that will deadlock */
mmc_queue_resume(mq);
@@ -329,6 +370,15 @@
kfree(mqrq_prev->bounce_buf);
mqrq_prev->bounce_buf = NULL;
+ kfree(mqrq_hdr->bounce_sg);
+ mqrq_prev->bounce_sg = NULL;
+
+ kfree(mqrq_hdr->sg);
+ mqrq_prev->sg = NULL;
+
+ kfree(mqrq_hdr->bounce_buf);
+ mqrq_prev->bounce_buf = NULL;
+
mq->card = NULL;
}
EXPORT_SYMBOL(mmc_cleanup_queue);
@@ -377,6 +427,37 @@
}
}
+static unsigned int mmc_queue_packed_map_sg(struct mmc_queue *mq,
+ struct mmc_queue_req *mqrq,
+ struct scatterlist *sg)
+{
+ struct scatterlist *__sg;
+ unsigned int sg_len = 0;
+ struct request *req;
+ enum mmc_packed_sg_flag sg_flag = mqrq->packed_sg_flag;
+
+ if (sg_flag == MMC_PACKED_HDR_SG || sg_flag == MMC_PACKED_WR_SG) {
+ __sg = sg;
+ sg_set_buf(__sg, mqrq->packed_cmd_hdr,
+ sizeof(mqrq->packed_cmd_hdr));
+ sg_len++;
+ if (sg_flag == MMC_PACKED_HDR_SG) {
+ sg_mark_end(__sg);
+ return sg_len;
+ }
+ __sg->page_link &= ~0x02;
+ }
+
+ __sg = sg + sg_len;
+ list_for_each_entry(req, &mqrq->packed_list, queuelist) {
+ sg_len += blk_rq_map_sg(mq->queue, req, __sg);
+ __sg = sg + (sg_len - 1);
+ (__sg++)->page_link &= ~0x02;
+ }
+ sg_mark_end(sg + (sg_len - 1));
+ return sg_len;
+}
+
/*
* Prepare the sg list(s) to be handed of to the host driver
*/
@@ -385,14 +466,22 @@
unsigned int sg_len;
size_t buflen;
struct scatterlist *sg;
+ enum mmc_packed_sg_flag sg_flag = mqrq->packed_sg_flag;
int i;
- if (!mqrq->bounce_buf)
- return blk_rq_map_sg(mq->queue, mqrq->req, mqrq->sg);
+ if (!mqrq->bounce_buf) {
+ if (sg_flag != MMC_PACKED_NONE_SG)
+ return mmc_queue_packed_map_sg(mq, mqrq, mqrq->sg);
+ else
+ return blk_rq_map_sg(mq->queue, mqrq->req, mqrq->sg);
+ }
BUG_ON(!mqrq->bounce_sg);
- sg_len = blk_rq_map_sg(mq->queue, mqrq->req, mqrq->bounce_sg);
+ if (sg_flag != MMC_PACKED_NONE_SG)
+ sg_len = mmc_queue_packed_map_sg(mq, mqrq, mqrq->bounce_sg);
+ else
+ sg_len = blk_rq_map_sg(mq->queue, mqrq->req, mqrq->bounce_sg);
mqrq->bounce_sg_len = sg_len;
@@ -414,7 +503,8 @@
if (!mqrq->bounce_buf)
return;
- if (rq_data_dir(mqrq->req) != WRITE)
+ if (rq_data_dir(mqrq->req) != WRITE &&
+ mqrq->packed_cmd != MMC_PACKED_WR_HDR)
return;
sg_copy_to_buffer(mqrq->bounce_sg, mqrq->bounce_sg_len,
diff --git a/drivers/mmc/card/queue.h b/drivers/mmc/card/queue.h
index d2a1eb4..bbd8e4c 100644
--- a/drivers/mmc/card/queue.h
+++ b/drivers/mmc/card/queue.h
@@ -12,14 +12,36 @@
struct mmc_data data;
};
+enum mmc_packed_cmd {
+ MMC_PACKED_NONE = 0,
+ MMC_PACKED_WR_HDR,
+ MMC_PACKED_WRITE,
+ MMC_PACKED_READ,
+};
+
+enum mmc_packed_sg_flag {
+ MMC_PACKED_NONE_SG = 0,
+ MMC_PACKED_HDR_SG,
+ MMC_PACKED_WR_SG,
+ MMC_PACKED_RD_SG,
+};
+
struct mmc_queue_req {
struct request *req;
struct mmc_blk_request brq;
struct scatterlist *sg;
+ enum mmc_packed_sg_flag packed_sg_flag;
char *bounce_buf;
struct scatterlist *bounce_sg;
unsigned int bounce_sg_len;
struct mmc_async_req mmc_active;
+ struct list_head packed_list;
+ u32 packed_cmd_hdr[128];
+ unsigned int packed_blocks;
+ enum mmc_packed_cmd packed_cmd;
+ int packed_retries;
+ int packed_fail_idx;
+ u8 packed_num;
};
struct mmc_queue {
@@ -30,9 +52,10 @@
int (*issue_fn)(struct mmc_queue *, struct request *);
void *data;
struct request_queue *queue;
- struct mmc_queue_req mqrq[2];
+ struct mmc_queue_req mqrq[3];
struct mmc_queue_req *mqrq_cur;
struct mmc_queue_req *mqrq_prev;
+ struct mmc_queue_req *mqrq_hdr;
};
extern int mmc_init_queue(struct mmc_queue *, struct mmc_card *, spinlock_t *,
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 95902a7..9b77227 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -348,8 +348,12 @@
struct mmc_async_req *data = host->areq;
/* Prepare a new request */
- if (areq)
+ if (areq && !areq->__cond) {
mmc_pre_req(host, areq->mrq, !host->areq);
+ if (areq->__mrq) {
+ mmc_pre_req(host, areq->__mrq, 0);
+ }
+ }
if (host->areq) {
mmc_wait_for_req_done(host, host->areq->mrq);
@@ -363,8 +367,11 @@
mmc_post_req(host, host->areq->mrq, 0);
/* Cancel a prepared request if it was not started. */
- if ((err || start_err) && areq)
- mmc_post_req(host, areq->mrq, -EINVAL);
+ if ((err || start_err) && areq) {
+ mmc_post_req(host, areq->mrq, -EINVAL);
+ if (areq->__mrq)
+ mmc_post_req(host, areq->__mrq, -EINVAL);
+ }
if (err)
host->areq = NULL;
@@ -1051,6 +1058,13 @@
BUG_ON(!host);
+ /* Some devices use only dedicated specific signaling level for
+ * design reasons. MMC_CAP2_BROKEN_VOLTAGE flag is used when
+ * there is no needs to change to any signaling level.
+ */
+ if (host->caps2 & MMC_CAP2_BROKEN_VOLTAGE)
+ return 0;
+
/*
* Send CMD11 only if the request is to switch the card to
* 1.8V signalling.
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 54df5ad..aafc946 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -235,6 +235,36 @@
return err;
}
+static void mmc_select_card_type(struct mmc_card *card)
+{
+ struct mmc_host *host = card->host;
+ u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
+ unsigned int caps = host->caps, caps2 = host->caps2;
+ unsigned int hs_max_dtr = 0;
+
+ if (card_type & EXT_CSD_CARD_TYPE_26)
+ hs_max_dtr = MMC_HIGH_26_MAX_DTR;
+
+ if (caps & MMC_CAP_MMC_HIGHSPEED &&
+ card_type & EXT_CSD_CARD_TYPE_52)
+ hs_max_dtr = MMC_HIGH_52_MAX_DTR;
+
+ if ((caps & MMC_CAP_1_8V_DDR &&
+ card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) ||
+ (caps & MMC_CAP_1_2V_DDR &&
+ card_type & EXT_CSD_CARD_TYPE_DDR_1_2V))
+ hs_max_dtr = MMC_HIGH_DDR_MAX_DTR;
+
+ if ((caps2 & MMC_CAP2_HS200_1_8V_SDR &&
+ card_type & EXT_CSD_CARD_TYPE_SDR_1_8V) ||
+ (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
+ card_type & EXT_CSD_CARD_TYPE_SDR_1_2V))
+ hs_max_dtr = MMC_HS200_MAX_DTR;
+
+ card->ext_csd.hs_max_dtr = hs_max_dtr;
+ card->ext_csd.card_type = card_type;
+}
+
/*
* Decode extended CSD.
*/
@@ -284,56 +314,9 @@
if (card->ext_csd.sectors > (2u * 1024 * 1024 * 1024) / 512)
mmc_card_set_blockaddr(card);
}
+
card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
- switch (ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_MASK) {
- case EXT_CSD_CARD_TYPE_SDR_ALL:
- case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V:
- case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V:
- case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52:
- card->ext_csd.hs_max_dtr = 200000000;
- card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_200;
- break;
- case EXT_CSD_CARD_TYPE_SDR_1_2V_ALL:
- case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V:
- case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V:
- case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52:
- card->ext_csd.hs_max_dtr = 200000000;
- card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_1_2V;
- break;
- case EXT_CSD_CARD_TYPE_SDR_1_8V_ALL:
- case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V:
- case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V:
- case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52:
- card->ext_csd.hs_max_dtr = 200000000;
- card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_1_8V;
- break;
- case EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_52 |
- EXT_CSD_CARD_TYPE_26:
- card->ext_csd.hs_max_dtr = 52000000;
- card->ext_csd.card_type = EXT_CSD_CARD_TYPE_DDR_52;
- break;
- case EXT_CSD_CARD_TYPE_DDR_1_2V | EXT_CSD_CARD_TYPE_52 |
- EXT_CSD_CARD_TYPE_26:
- card->ext_csd.hs_max_dtr = 52000000;
- card->ext_csd.card_type = EXT_CSD_CARD_TYPE_DDR_1_2V;
- break;
- case EXT_CSD_CARD_TYPE_DDR_1_8V | EXT_CSD_CARD_TYPE_52 |
- EXT_CSD_CARD_TYPE_26:
- card->ext_csd.hs_max_dtr = 52000000;
- card->ext_csd.card_type = EXT_CSD_CARD_TYPE_DDR_1_8V;
- break;
- case EXT_CSD_CARD_TYPE_52 | EXT_CSD_CARD_TYPE_26:
- card->ext_csd.hs_max_dtr = 52000000;
- break;
- case EXT_CSD_CARD_TYPE_26:
- card->ext_csd.hs_max_dtr = 26000000;
- break;
- default:
- /* MMC v4 spec says this cannot happen */
- pr_warning("%s: card is mmc v4 but doesn't "
- "support any high-speed modes.\n",
- mmc_hostname(card->host));
- }
+ mmc_select_card_type(card);
card->ext_csd.raw_s_a_timeout = ext_csd[EXT_CSD_S_A_TIMEOUT];
card->ext_csd.raw_erase_timeout_mult =
@@ -533,6 +516,11 @@
} else {
card->ext_csd.data_tag_unit_size = 0;
}
+
+ card->ext_csd.max_packed_writes =
+ ext_csd[EXT_CSD_MAX_PACKED_WRITES];
+ card->ext_csd.max_packed_reads =
+ ext_csd[EXT_CSD_MAX_PACKED_READS];
}
out:
@@ -745,7 +733,7 @@
*/
static int mmc_select_hs200(struct mmc_card *card)
{
- int idx, err = 0;
+ int idx, err = -EINVAL;
struct mmc_host *host;
static unsigned ext_csd_bits[] = {
EXT_CSD_BUS_WIDTH_4,
@@ -761,10 +749,12 @@
host = card->host;
if (card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_2V &&
- host->caps2 & MMC_CAP2_HS200_1_2V_SDR)
- if (mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120, 0))
- err = mmc_set_signal_voltage(host,
- MMC_SIGNAL_VOLTAGE_180, 0);
+ host->caps2 & MMC_CAP2_HS200_1_2V_SDR)
+ err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120, 0);
+
+ if (err && card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_8V &&
+ host->caps2 & MMC_CAP2_HS200_1_8V_SDR)
+ err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180, 0);
/* If fails try again during next card power cycle */
if (err)
@@ -1267,6 +1257,26 @@
}
}
+ if ((host->caps2 & MMC_CAP2_PACKED_WR &&
+ card->ext_csd.max_packed_writes > 0) ||
+ (host->caps2 & MMC_CAP2_PACKED_RD &&
+ card->ext_csd.max_packed_reads > 0)) {
+ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_EXP_EVENTS_CTRL,
+ EXT_CSD_PACKED_EVENT_EN,
+ card->ext_csd.generic_cmd6_time);
+ if (err && err != -EBADMSG)
+ goto free_card;
+ if (err) {
+ pr_warning("%s: Enabling packed event failed\n",
+ mmc_hostname(card->host));
+ card->ext_csd.packed_event_en = 0;
+ err = 0;
+ } else {
+ card->ext_csd.packed_event_en = 1;
+ }
+ }
+
if (!oldcard)
host->card = card;
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 69370f4..2a2fed8 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -335,6 +335,7 @@
return mmc_send_cxd_data(card, card->host, MMC_SEND_EXT_CSD,
ext_csd, 512);
}
+EXPORT_SYMBOL_GPL(mmc_send_ext_csd);
int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp)
{
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 341b4c0..8a35814 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -488,23 +488,27 @@
bus_speed = SDIO_SPEED_SDR104;
timing = MMC_TIMING_UHS_SDR104;
card->sw_caps.uhs_max_dtr = UHS_SDR104_MAX_DTR;
+ card->sd_bus_speed = UHS_SDR104_BUS_SPEED;
} else if ((card->host->caps & MMC_CAP_UHS_DDR50) &&
(card->sw_caps.sd3_bus_mode & SD_MODE_UHS_DDR50)) {
bus_speed = SDIO_SPEED_DDR50;
timing = MMC_TIMING_UHS_DDR50;
card->sw_caps.uhs_max_dtr = UHS_DDR50_MAX_DTR;
+ card->sd_bus_speed = UHS_DDR50_BUS_SPEED;
} else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
MMC_CAP_UHS_SDR50)) && (card->sw_caps.sd3_bus_mode &
SD_MODE_UHS_SDR50)) {
bus_speed = SDIO_SPEED_SDR50;
timing = MMC_TIMING_UHS_SDR50;
card->sw_caps.uhs_max_dtr = UHS_SDR50_MAX_DTR;
+ card->sd_bus_speed = UHS_SDR50_BUS_SPEED;
} else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25)) &&
(card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR25)) {
bus_speed = SDIO_SPEED_SDR25;
timing = MMC_TIMING_UHS_SDR25;
card->sw_caps.uhs_max_dtr = UHS_SDR25_MAX_DTR;
+ card->sd_bus_speed = UHS_SDR25_BUS_SPEED;
} else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25 |
MMC_CAP_UHS_SDR12)) && (card->sw_caps.sd3_bus_mode &
@@ -512,6 +516,7 @@
bus_speed = SDIO_SPEED_SDR12;
timing = MMC_TIMING_UHS_SDR12;
card->sw_caps.uhs_max_dtr = UHS_SDR12_MAX_DTR;
+ card->sd_bus_speed = UHS_SDR12_BUS_SPEED;
}
err = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_SPEED, 0, &speed);
@@ -586,6 +591,15 @@
BUG_ON(!host);
WARN_ON(!host->claimed);
+ /* If host that supports UHS-I sets S18R to 1 in arg of CMD5 to request
+ * change of signaling level to 1.8V
+ */
+ if (host->caps &
+ (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
+ MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 |
+ MMC_CAP_UHS_DDR50))
+ host->ocr |= R4_18V_PRESENT;
+
/*
* Inform the card of the voltage
*/
diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c
index 92ec3eb..58ed89b 100644
--- a/drivers/mmc/host/dw_mmc-pltfm.c
+++ b/drivers/mmc/host/dw_mmc-pltfm.c
@@ -21,7 +21,7 @@
#include <linux/mmc/dw_mmc.h>
#include "dw_mmc.h"
-static int dw_mci_pltfm_probe(struct platform_device *pdev)
+static int __init dw_mci_pltfm_probe(struct platform_device *pdev)
{
struct dw_mci *host;
struct resource *regs;
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index ab3fc46..1132de6 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -22,6 +22,7 @@
#include <linux/ioport.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/ratelimit.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/stat.h>
@@ -29,6 +30,8 @@
#include <linux/irq.h>
#include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/sdio.h>
#include <linux/mmc/dw_mmc.h>
#include <linux/bitops.h>
#include <linux/regulator/consumer.h>
@@ -46,7 +49,7 @@
DW_MCI_CMD_ERROR_FLAGS | SDMMC_INT_HLE)
#define DW_MCI_SEND_STATUS 1
#define DW_MCI_RECV_STATUS 2
-#define DW_MCI_DMA_THRESHOLD 16
+#define DW_MCI_DMA_THRESHOLD 4
#ifdef CONFIG_MMC_DW_IDMAC
struct idmac_desc {
@@ -69,6 +72,37 @@
};
#endif /* CONFIG_MMC_DW_IDMAC */
+#define MAX_TUNING_LOOP 40
+static const u8 tuning_blk_pattern_4bit[] = {
+ 0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc,
+ 0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef,
+ 0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb,
+ 0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef,
+ 0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c,
+ 0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee,
+ 0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff,
+ 0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde,
+};
+
+static const u8 tuning_blk_pattern_8bit[] = {
+ 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
+ 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc,
+ 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff,
+ 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff,
+ 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd,
+ 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb,
+ 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff,
+ 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff,
+ 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc,
+ 0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff,
+ 0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee,
+ 0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd,
+ 0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff,
+ 0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff,
+ 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee,
+};
+
/**
* struct dw_mci_slot - MMC slot state
* @mmc: The mmc_host representing this slot.
@@ -232,16 +266,24 @@
static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
{
struct mmc_data *data;
- u32 cmdr;
+ struct dw_mci_slot *slot = mmc_priv(mmc);
+
+ u32 cmdr, argr;
cmd->error = -EINPROGRESS;
cmdr = cmd->opcode;
+ argr = ((cmd->arg >> 9) & 0xFF);
if (cmdr == MMC_STOP_TRANSMISSION)
cmdr |= SDMMC_CMD_STOP;
else
cmdr |= SDMMC_CMD_PRV_DAT_WAIT;
+ if ((cmd->opcode == 52) && (argr == 0x06)) {
+ cmdr &= ~SDMMC_CMD_PRV_DAT_WAIT;
+ cmdr |= SDMMC_CMD_STOP;
+ }
+
if (cmd->flags & MMC_RSP_PRESENT) {
/* We expect a response, so set this bit */
cmdr |= SDMMC_CMD_RESP_EXP;
@@ -261,6 +303,44 @@
cmdr |= SDMMC_CMD_DAT_WR;
}
+ /* Use hold bit register */
+ if (slot->host->pdata->set_io_timing)
+ cmdr |= SDMMC_USE_HOLD_REG;
+
+ return cmdr;
+}
+
+static u32 dw_mci_prep_stop(struct dw_mci *host, struct mmc_command *cmd)
+{
+ struct mmc_command *stop = &host->stop;
+ u32 cmdr = cmd->opcode;
+
+ memset(stop, 0, sizeof(struct mmc_command));
+
+ if (cmdr == MMC_READ_SINGLE_BLOCK ||
+ cmdr == MMC_READ_MULTIPLE_BLOCK ||
+ cmdr == MMC_WRITE_BLOCK ||
+ cmdr == MMC_WRITE_MULTIPLE_BLOCK) {
+ stop->opcode = MMC_STOP_TRANSMISSION;
+ stop->arg = 0;
+ stop->flags = MMC_RSP_R1B | MMC_CMD_AC;
+ } else if (cmdr == SD_IO_RW_EXTENDED) {
+ stop->opcode = SD_IO_RW_DIRECT;
+ stop->arg = 0x80000000;
+ /* stop->arg &= ~(1 << 28); */
+ stop->arg |= (cmd->arg >> 28) & 0x7;
+ stop->arg |= SDIO_CCCR_ABORT << 9;
+ stop->flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC;;
+ } else
+ return 0;
+
+ cmdr = stop->opcode | SDMMC_CMD_STOP |
+ SDMMC_CMD_RESP_CRC | SDMMC_CMD_RESP_EXP;
+
+ /* Use hold bit register */
+ if (host->pdata->set_io_timing)
+ cmdr |= SDMMC_USE_HOLD_REG;
+
return cmdr;
}
@@ -289,12 +369,94 @@
if (host->using_dma) {
host->dma_ops->stop(host);
host->dma_ops->cleanup(host);
+ host->dma_ops->reset(host);
} else {
/* Data transfer was stopped by the interrupt handler */
set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
}
}
+static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg)
+{
+ struct dw_mci *host = slot->host;
+ unsigned long timeout = jiffies + msecs_to_jiffies(500);
+ unsigned int cmd_status = 0;
+
+ mci_writel(host, CMDARG, arg);
+ wmb();
+ mci_writel(host, CMD, SDMMC_CMD_START | cmd);
+
+ while (time_before(jiffies, timeout)) {
+ cmd_status = mci_readl(host, CMD);
+ if (!(cmd_status & SDMMC_CMD_START))
+ return;
+ }
+ dev_err(&slot->mmc->class_dev,
+ "Timeout sending command (cmd %#x arg %#x status %#x)\n",
+ cmd, arg, cmd_status);
+}
+
+static bool dw_mci_wait_reset(struct device *dev, struct dw_mci *host,
+ unsigned int reset_val)
+{
+ unsigned long timeout = jiffies + msecs_to_jiffies(500);
+ unsigned int ctrl;
+
+ ctrl = mci_readl(host, CTRL);
+ ctrl |= reset_val;
+ mci_writel(host, CTRL, ctrl);
+
+ /* wait till resets clear */
+ do {
+ if (!(mci_readl(host, CTRL) & reset_val))
+ return true;
+ } while (time_before(jiffies, timeout));
+
+ dev_err(dev, "%s: Timeout resetting block (ctrl %#x)\n",
+ __func__, ctrl);
+
+ return false;
+}
+
+static bool dw_mci_wait_fifo_reset(struct device *dev, struct dw_mci *host)
+{
+ unsigned long timeout = jiffies + msecs_to_jiffies(500);
+ unsigned int ctrl;
+ bool result;
+
+ result = dw_mci_wait_reset(&host->dev, host,
+ SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET);
+ if (result) {
+ do {
+ ctrl = mci_readl(host, STATUS);
+ if (!(ctrl & SDMMC_STATUS_DMA_REQ)) {
+ result = dw_mci_wait_reset(&host->dev, host,
+ SDMMC_CTRL_FIFO_RESET);
+ if (result) {
+ /* clear exception raw interrupts can not be handled
+ ex) fifo full => RXDR interrupt rising */
+ ctrl = mci_readl(host, RINTSTS);
+ ctrl = ctrl & ~(mci_readl(host, MINTSTS));
+ if (ctrl)
+ mci_writel(host, RINTSTS, ctrl);
+
+ /* After CTRL Reset, Should be needed clk val to CIU */
+ mci_send_cmd(host->cur_slot,
+ SDMMC_CMD_UPD_CLK, 0);
+ return true;
+ }
+ }
+ } while (time_before(jiffies, timeout));
+ }
+
+ dev_err(dev, "%s: Timeout resetting while resetting SDMMC control FIFO\n",
+ __func__);
+
+ return false;
+}
+
+
+#ifdef CONFIG_MMC_DW_IDMAC
static int dw_mci_get_dma_dir(struct mmc_data *data)
{
if (data->flags & MMC_DATA_WRITE)
@@ -303,7 +465,6 @@
return DMA_FROM_DEVICE;
}
-#ifdef CONFIG_MMC_DW_IDMAC
static void dw_mci_dma_cleanup(struct dw_mci *host)
{
struct mmc_data *data = host->data;
@@ -323,15 +484,27 @@
/* Disable and reset the IDMAC interface */
temp = mci_readl(host, CTRL);
temp &= ~SDMMC_CTRL_USE_IDMAC;
- temp |= SDMMC_CTRL_DMA_RESET;
mci_writel(host, CTRL, temp);
+ /* reset the IDMAC interface */
+ dw_mci_wait_reset(&host->dev, host, SDMMC_CTRL_DMA_RESET);
+
/* Stop the IDMAC running */
temp = mci_readl(host, BMOD);
temp &= ~(SDMMC_IDMAC_ENABLE | SDMMC_IDMAC_FB);
mci_writel(host, BMOD, temp);
}
+static void dw_mci_idma_reset_dma(struct dw_mci *host)
+{
+ u32 temp;
+
+ temp = mci_readl(host, BMOD);
+ /* Software reset of DMA */
+ temp |= SDMMC_IDMAC_SWRESET;
+ mci_writel(host, BMOD, temp);
+}
+
static void dw_mci_idmac_complete_dma(struct dw_mci *host)
{
struct mmc_data *data = host->data;
@@ -410,7 +583,7 @@
int i;
/* Number of descriptors in the ring buffer */
- host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc);
+ host->ring_size = host->desc_sz * PAGE_SIZE / sizeof(struct idmac_desc);
/* Forward link the descriptor list */
for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; i++, p++)
@@ -420,6 +593,8 @@
p->des3 = host->sg_dma;
p->des0 = IDMAC_DES0_ER;
+ mci_writel(host, BMOD, SDMMC_IDMAC_SWRESET);
+
/* Mask out interrupts - get Tx & Rx complete only */
mci_writel(host, IDINTEN, SDMMC_IDMAC_INT_NI | SDMMC_IDMAC_INT_RI |
SDMMC_IDMAC_INT_TI);
@@ -429,15 +604,6 @@
return 0;
}
-static struct dw_mci_dma_ops dw_mci_idmac_ops = {
- .init = dw_mci_idmac_init,
- .start = dw_mci_idmac_start_dma,
- .stop = dw_mci_idmac_stop_dma,
- .complete = dw_mci_idmac_complete_dma,
- .cleanup = dw_mci_dma_cleanup,
-};
-#endif /* CONFIG_MMC_DW_IDMAC */
-
static int dw_mci_pre_dma_transfer(struct dw_mci *host,
struct mmc_data *data,
bool next)
@@ -514,6 +680,25 @@
data->host_cookie = 0;
}
+static struct dw_mci_dma_ops dw_mci_idmac_ops = {
+ .init = dw_mci_idmac_init,
+ .start = dw_mci_idmac_start_dma,
+ .stop = dw_mci_idmac_stop_dma,
+ .reset = dw_mci_idma_reset_dma,
+ .complete = dw_mci_idmac_complete_dma,
+ .cleanup = dw_mci_dma_cleanup,
+};
+#else
+static int dw_mci_pre_dma_transfer(struct dw_mci *host,
+ struct mmc_data *data,
+ bool next)
+{
+ return -ENOSYS;
+}
+#define dw_mci_pre_req NULL
+#define dw_mci_post_req NULL
+#endif /* CONFIG_MMC_DW_IDMAC */
+
static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data)
{
int sg_len;
@@ -544,6 +729,7 @@
mci_writel(host, CTRL, temp);
/* Disable RX/TX IRQs, let DMA handle it */
+ mci_writel(host, RINTSTS, SDMMC_INT_TXDR | SDMMC_INT_RXDR);
temp = mci_readl(host, INTMASK);
temp &= ~(SDMMC_INT_RXDR | SDMMC_INT_TXDR);
mci_writel(host, INTMASK, temp);
@@ -556,6 +742,8 @@
static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data)
{
u32 temp;
+ struct dw_mci_slot *slot = host->cur_slot;
+ struct mmc_card *card = slot->mmc->card;
data->error = -EINPROGRESS;
@@ -563,6 +751,57 @@
host->sg = NULL;
host->data = data;
+ if (host->quirks & DW_MCI_QUIRK_NO_DETECT_EBIT) {
+ temp = mci_readl(host, INTMASK);
+ if (data->flags & MMC_DATA_READ)
+ temp &= ~SDMMC_INT_EBE;
+ else
+ temp |= SDMMC_INT_EBE;
+ mci_writel(host, INTMASK, temp);
+ }
+
+ if (card && mmc_card_sdio(card)) {
+ unsigned int rxwmark_val, msize_val, i;
+ unsigned int msize[8] = {1, 4, 8, 16, 32, 64, 128, 256};
+
+ for (i = 1; sizeof(msize) / sizeof(unsigned int); i++) {
+ if ((data->blksz / 4) % msize[i] == 0)
+ continue;
+ else
+ break;
+ }
+ if (data->blksz < host->fifo_depth / 2) {
+ if (i > 1) {
+ msize_val = i - 1;
+ rxwmark_val = msize[i-1] - 1;
+ } else {
+ msize_val = 0;
+ rxwmark_val = 1;
+ }
+ } else {
+ if (i > 2) {
+ msize_val = i - 2;
+ rxwmark_val = msize[i-2] - 1;
+ } else {
+ msize_val = 0;
+ rxwmark_val = 1;
+ }
+ }
+ dev_dbg(&slot->mmc->class_dev,
+ "msize_val : %d, rxwmark_val : %d\n",
+ msize_val, rxwmark_val);
+
+ host->fifoth_val = ((msize_val << 28) | (rxwmark_val << 16) |
+ ((host->fifo_depth/2) << 0));
+
+ mci_writel(host, FIFOTH, host->fifoth_val);
+
+ if (mmc_card_uhs(card)
+ && card->host->caps & MMC_CAP_UHS_SDR104
+ && data->flags & MMC_DATA_READ)
+ mci_writel(host, CDTHRCTL, data->blksz << 16 | 1);
+ }
+
if (data->flags & MMC_DATA_READ)
host->dir_status = DW_MCI_RECV_STATUS;
else
@@ -591,40 +830,44 @@
}
}
-static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg)
+static void dw_mci_setup_bus(struct dw_mci_slot *slot, int force)
{
struct dw_mci *host = slot->host;
- unsigned long timeout = jiffies + msecs_to_jiffies(500);
- unsigned int cmd_status = 0;
+ u32 div, actual_speed;
+ bool reset_div = false;
- mci_writel(host, CMDARG, arg);
- wmb();
- mci_writel(host, CMD, SDMMC_CMD_START | cmd);
+ if ((slot->clock != host->current_speed) || force) {
+ do {
+ div = host->bus_hz / slot->clock;
+ if ((host->bus_hz % slot->clock) &&
+ (host->bus_hz > slot->clock))
+ /*
+ * move the + 1 after the divide to prevent
+ * over-clocking the card.
+ */
+ div++;
- while (time_before(jiffies, timeout)) {
- cmd_status = mci_readl(host, CMD);
- if (!(cmd_status & SDMMC_CMD_START))
- return;
- }
- dev_err(&slot->mmc->class_dev,
- "Timeout sending command (cmd %#x arg %#x status %#x)\n",
- cmd, arg, cmd_status);
-}
+ div = (host->bus_hz != slot->clock) ?
+ DIV_ROUND_UP(div, 2) : 0;
-static void dw_mci_setup_bus(struct dw_mci_slot *slot)
-{
- struct dw_mci *host = slot->host;
- u32 div;
+ /* CLKDIV limitation is 0xFF */
+ if (div > 0xFF)
+ div = 0xFF;
- if (slot->clock != host->current_speed) {
- if (host->bus_hz % slot->clock)
- /*
- * move the + 1 after the divide to prevent
- * over-clocking the card.
- */
- div = ((host->bus_hz / slot->clock) >> 1) + 1;
- else
- div = (host->bus_hz / slot->clock) >> 1;
+ actual_speed = div ?
+ (host->bus_hz / div) >> 1 : host->bus_hz;
+
+ /* Change SCLK_MMC */
+ if (actual_speed > slot->clock &&
+ host->bus_hz != 0 && !reset_div) {
+ dev_err(&host->dev,
+ "Actual clock is high than a reqeust clock."
+ "Source clock is needed to change\n");
+ reset_div = true;
+ slot->host->pdata->set_io_timing(slot->host, MMC_TIMING_LEGACY);
+ } else
+ reset_div = false;
+ } while(reset_div);
dev_info(&slot->mmc->class_dev,
"Bus speed (slot %d) = %dHz (slot req %dHz, actual %dHZ"
@@ -667,14 +910,17 @@
{
struct mmc_request *mrq;
struct mmc_data *data;
- u32 cmdflags;
+ u32 cmdflags, timeout = 0;
+ host->prv_err = false;
mrq = slot->mrq;
+ host->stop_cmdr = 0;
+ host->stop_snd = false;
if (host->pdata->select_slot)
host->pdata->select_slot(slot->id);
/* Slot specific timing and width adjustment */
- dw_mci_setup_bus(slot);
+ dw_mci_setup_bus(slot, 0);
host->cur_slot = slot;
host->mrq = mrq;
@@ -688,7 +934,13 @@
dw_mci_set_timeout(host);
mci_writel(host, BYTCNT, data->blksz*data->blocks);
mci_writel(host, BLKSIZ, data->blksz);
- }
+ timeout = data->timeout_ns / 1000000;
+ } else
+ timeout= cmd->cmd_timeout_ms;
+
+ /* s/w reset value adds 2 second to give opportunity to host controller */
+ mod_timer(&host->timer, jiffies +
+ msecs_to_jiffies(timeout + 2000));
cmdflags = dw_mci_prepare_command(slot->mmc, cmd);
@@ -705,6 +957,10 @@
if (mrq->stop)
host->stop_cmdr = dw_mci_prepare_command(slot->mmc, mrq->stop);
+ else {
+ if (data)
+ host->stop_cmdr = dw_mci_prep_stop(host, cmd);
+ }
}
static void dw_mci_start_request(struct dw_mci *host,
@@ -738,9 +994,35 @@
{
struct dw_mci_slot *slot = mmc_priv(mmc);
struct dw_mci *host = slot->host;
+ unsigned long timeout = jiffies + msecs_to_jiffies(1000);
+ u32 status;
WARN_ON(slot->mrq);
+ do {
+ if (mrq->cmd->opcode == MMC_STOP_TRANSMISSION)
+ break;
+
+ status = mci_readl(host, STATUS);
+ if (!(status & BIT(9)))
+ break;
+
+ if (time_after(jiffies, timeout)) {
+ /* card is checked every 1s by CMD13 at least */
+ if (mrq->cmd->opcode == MMC_SEND_STATUS)
+ break;
+ dev_err(&host->dev,
+ "Data0: Never released by cmd%d\n",
+ mrq->cmd->opcode);
+ mrq->cmd->error = -ENOTRECOVERABLE;
+ host->prv_err = true;
+ mmc_request_done(mmc, mrq);
+ return;
+ }
+
+ usleep_range(10, 20);
+ } while (1);
+
/*
* The check for card presence and queueing of the request must be
* atomic, otherwise the card could be removed in between and the
@@ -751,6 +1033,7 @@
if (!test_bit(DW_MMC_CARD_PRESENT, &slot->flags)) {
spin_unlock_bh(&host->lock);
mrq->cmd->error = -ENOMEDIUM;
+ host->prv_err = true;
mmc_request_done(mmc, mrq);
return;
}
@@ -763,7 +1046,8 @@
static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
struct dw_mci_slot *slot = mmc_priv(mmc);
- u32 regs;
+ struct dw_mci_board *brd = slot->host->pdata;
+ u32 regs, width = 1;
/* set default 1 bit mode */
slot->ctype = SDMMC_CTYPE_1BIT;
@@ -771,12 +1055,15 @@
switch (ios->bus_width) {
case MMC_BUS_WIDTH_1:
slot->ctype = SDMMC_CTYPE_1BIT;
+ width = 1;
break;
case MMC_BUS_WIDTH_4:
slot->ctype = SDMMC_CTYPE_4BIT;
+ width = 4;
break;
case MMC_BUS_WIDTH_8:
slot->ctype = SDMMC_CTYPE_8BIT;
+ width = 8;
break;
}
@@ -788,6 +1075,15 @@
else
regs &= ~(0x1 << slot->id) << 16;
+ if (slot->host->pdata->caps &
+ (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
+ MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 |
+ MMC_CAP_UHS_DDR50))
+ regs |= (0x1 << slot->id);
+
+ if (slot->host->pdata->set_io_timing)
+ slot->host->pdata->set_io_timing(slot->host, ios->timing);
+
mci_writel(slot->host, UHS_REG, regs);
if (ios->clock) {
@@ -802,9 +1098,20 @@
case MMC_POWER_UP:
set_bit(DW_MMC_CARD_NEED_INIT, &slot->flags);
break;
+ case MMC_POWER_ON:
+ /* To cheat supporting hardware reset using power off/on
+ * as reset function to modify reset function value of ext_csd reg
+ */
+ if (mmc->caps & MMC_CAP_HW_RESET && mmc->card &&
+ slot->host->quirks & DW_MMC_QUIRK_HW_RESET_PW)
+ mmc->card->ext_csd.rst_n_function |= EXT_CSD_RST_N_ENABLED;
+ break;
default:
break;
}
+
+ if (brd->cfg_gpio)
+ brd->cfg_gpio(width);
}
static int dw_mci_get_ro(struct mmc_host *mmc)
@@ -859,13 +1166,186 @@
int_mask = mci_readl(host, INTMASK);
if (enb) {
mci_writel(host, INTMASK,
- (int_mask | (1 << SDMMC_INT_SDIO(slot->id))));
+ (int_mask | SDMMC_INT_SDIO(slot->id)));
} else {
mci_writel(host, INTMASK,
- (int_mask & ~(1 << SDMMC_INT_SDIO(slot->id))));
+ (int_mask & ~SDMMC_INT_SDIO(slot->id)));
}
}
+static u8 dw_mci_tuning_sampling(struct dw_mci *host)
+{
+ u32 clksel;
+ u8 sample;
+
+ clksel = mci_readl(host, CLKSEL);
+ sample = (clksel + 1) & 0x7;
+ clksel = (clksel & 0xfffffff8) | sample;
+ mci_writel(host, CLKSEL, clksel);
+
+ return sample;
+}
+
+static void dw_mci_set_sampling(struct dw_mci *host, u8 sample)
+{
+ u32 clksel;
+
+ clksel = mci_readl(host, CLKSEL);
+ clksel = (clksel & 0xfffffff8) | (sample & 0x7);
+ mci_writel(host, CLKSEL, clksel);
+}
+
+static u8 dw_mci_get_sampling(struct dw_mci *host)
+{
+ u32 clksel;
+ u8 sample;
+
+ clksel = mci_readl(host, CLKSEL);
+ sample = clksel & 0x7;
+
+ return sample;
+}
+
+static s8 get_median_sample(u8 map)
+{
+ const u8 iter = 8;
+ u8 __map;
+ s8 i, sel = -1;
+
+ for (i = 0; i < iter; i++) {
+ __map = (map >> i) | (map << (iter - i));
+ if ((__map & 0xc7) == 0xc7) {
+ sel = i;
+ break;
+ }
+ }
+
+ return sel;
+}
+
+static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode)
+{
+ struct dw_mci_slot *slot = mmc_priv(mmc);
+ struct dw_mci *host = slot->host;
+ unsigned int tuning_loop = MAX_TUNING_LOOP;
+ const u8 *tuning_blk_pattern;
+ u8 *tuning_blk;
+ u8 blksz;
+ u8 tune, start_tune, map = 0;
+ s8 mid;
+
+ if (opcode == MMC_SEND_TUNING_BLOCK_HS200) {
+ if (mmc->ios.bus_width == MMC_BUS_WIDTH_8) {
+ tuning_blk_pattern = tuning_blk_pattern_8bit;
+ blksz = 128;
+ } else if (mmc->ios.bus_width == MMC_BUS_WIDTH_4) {
+ tuning_blk_pattern = tuning_blk_pattern_4bit;
+ blksz = 64;
+ } else
+ return -EINVAL;
+ } else if (opcode == MMC_SEND_TUNING_BLOCK) {
+ tuning_blk_pattern = tuning_blk_pattern_4bit;
+ blksz = 64;
+ } else {
+ dev_err(&mmc->class_dev,
+ "Undefined command(%d) for tuning\n",
+ opcode);
+ return -EINVAL;
+ }
+
+ if (host->pdata->tuned) {
+ dw_mci_set_sampling(host, host->pdata->clk_smpl);
+ mci_writel(host, CDTHRCTL, host->cd_rd_thr << 16 | 1);
+ return 0;
+ }
+
+ tuning_blk = kmalloc(blksz, GFP_KERNEL);
+ if (!tuning_blk)
+ return -ENOMEM;
+
+ start_tune = dw_mci_get_sampling(host);
+ host->cd_rd_thr = 512;
+ mci_writel(host, CDTHRCTL, host->cd_rd_thr << 16 | 1);
+
+ do {
+ struct mmc_request mrq = {NULL};
+ struct mmc_command cmd = {0};
+ struct mmc_command stop = {0};
+ struct mmc_data data = {0};
+ struct scatterlist sg;
+
+ cmd.opcode = opcode;
+ cmd.arg = 0;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+
+ stop.opcode = MMC_STOP_TRANSMISSION;
+ stop.arg = 0;
+ stop.flags = MMC_RSP_R1B | MMC_CMD_AC;
+
+ data.blksz = blksz;
+ data.blocks = 1;
+ data.flags = MMC_DATA_READ;
+ data.sg = &sg;
+ data.sg_len = 1;
+
+ sg_init_one(&sg, tuning_blk, blksz);
+ dw_mci_set_timeout(host);
+
+ mrq.cmd = &cmd;
+ mrq.stop = &stop;
+ mrq.data = &data;
+ host->mrq = &mrq;
+
+ tune = dw_mci_tuning_sampling(host);
+
+ mmc_wait_for_req(mmc, &mrq);
+
+ if (!cmd.error && !data.error) {
+ if (!memcmp(tuning_blk_pattern, tuning_blk, blksz))
+ map |= (1 << tune);
+ } else {
+ dev_dbg(&mmc->class_dev,
+ "Tuning error: cmd.error:%d, data.error:%d\n",
+ cmd.error, data.error);
+ }
+
+ if (start_tune == tune) {
+ mid = get_median_sample(map);
+ if (mid < 0) {
+ tuning_loop = 0;
+ break;
+ }
+
+ host->pdata->clk_smpl = mid;
+ host->pdata->tuned = true;
+ dw_mci_set_sampling(host, mid);
+ break;
+ }
+ } while (--tuning_loop);
+
+ kfree(tuning_blk);
+
+ if (!tuning_loop) {
+ mci_writel(host, CDTHRCTL, 0 << 16 | 0);
+ dw_mci_set_sampling(host, start_tune);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static void dw_mci_hw_reset(struct mmc_host *host)
+{
+ struct dw_mci_slot *slot = mmc_priv(host);
+ struct dw_mci_board *brd = slot->host->pdata;
+
+ dev_warn(&host->class_dev, "device is being hw reset\n");
+
+ /* Use platform hw_reset function */
+ if (brd->hw_reset)
+ brd->hw_reset(slot->id);
+}
+
static const struct mmc_host_ops dw_mci_ops = {
.request = dw_mci_request,
.pre_req = dw_mci_pre_req,
@@ -874,6 +1354,8 @@
.get_ro = dw_mci_get_ro,
.get_cd = dw_mci_get_cd,
.enable_sdio_irq = dw_mci_enable_sdio_irq,
+ .execute_tuning = dw_mci_execute_tuning,
+ .hw_reset = dw_mci_hw_reset,
};
static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq)
@@ -885,6 +1367,8 @@
WARN_ON(host->cmd || host->data);
+ del_timer(&host->timer);
+
host->cur_slot->mrq = NULL;
host->mrq = NULL;
if (!list_empty(&host->queue)) {
@@ -939,11 +1423,7 @@
/* newer ip versions need a delay between retries */
if (host->quirks & DW_MCI_QUIRK_RETRY_DELAY)
mdelay(20);
-
- if (cmd->data) {
- host->data = NULL;
- dw_mci_stop_dma(host);
- }
+ host->prv_err = true;
}
}
@@ -951,7 +1431,7 @@
{
struct dw_mci *host = (struct dw_mci *)priv;
struct mmc_data *data;
- struct mmc_command *cmd;
+ struct mmc_command *cmd = NULL;
enum dw_mci_state state;
enum dw_mci_state prev_state;
u32 status, ctrl;
@@ -984,6 +1464,21 @@
goto unlock;
}
+ if (data && cmd->error &&
+ cmd != data->stop) {
+ if (host->mrq->data->stop)
+ send_stop_cmd(host, host->mrq->data);
+ else {
+ dw_mci_start_command(host, &host->stop,
+ host->stop_cmdr);
+ host->stop_snd = true;
+ }
+ /* To avoid fifo full condition */
+ dw_mci_wait_fifo_reset(&host->dev, host);
+ state = STATE_SENDING_STOP;
+ break;
+ }
+
if (!host->mrq->data || cmd->error) {
dw_mci_request_end(host, host->mrq);
goto unlock;
@@ -995,9 +1490,18 @@
case STATE_SENDING_DATA:
if (test_and_clear_bit(EVENT_DATA_ERROR,
&host->pending_events)) {
- dw_mci_stop_dma(host);
+ set_bit(EVENT_XFER_COMPLETE,
+ &host->pending_events);
if (data->stop)
send_stop_cmd(host, data);
+ else {
+ dw_mci_start_command(host,
+ &host->stop,
+ host->stop_cmdr);
+ host->stop_snd = true;
+ }
+ /* To avoid fifo full condition */
+ dw_mci_wait_fifo_reset(&host->dev, host);
state = STATE_DATA_ERROR;
break;
}
@@ -1020,11 +1524,11 @@
status = host->data_status;
if (status & DW_MCI_DATA_ERROR_FLAGS) {
- if (status & SDMMC_INT_DTO) {
+ if (status & SDMMC_INT_DTO)
data->error = -ETIMEDOUT;
- } else if (status & SDMMC_INT_DCRC) {
+ else if (status & SDMMC_INT_DCRC)
data->error = -EILSEQ;
- } else if (status & SDMMC_INT_EBE &&
+ else if (status & SDMMC_INT_EBE &&
host->dir_status ==
DW_MCI_SEND_STATUS) {
/*
@@ -1034,13 +1538,19 @@
*/
data->bytes_xfered = 0;
data->error = -ETIMEDOUT;
- } else {
- dev_err(&host->dev,
- "data FIFO error "
- "(status=%08x)\n",
- status);
+ } else
data->error = -EIO;
- }
+
+ /* For debug, output the minimum required register */
+ dev_err(&host->dev,
+ "cmd%d data error:%d pending:%x "
+ "status:%x tcb:%x tbb:%x\n",
+ cmd ? cmd->opcode :
+ SDMMC_CMD_INDX(mci_readl(host, CMD)),
+ data->error, status,
+ mci_readl(host, STATUS),
+ mci_readl(host, TCBCNT),
+ mci_readl(host, TBBCNT));
/*
* After an error, there may be data lingering
* in the FIFO, so reset it - doing so
@@ -1049,15 +1559,14 @@
*/
sg_miter_stop(&host->sg_miter);
host->sg = NULL;
- ctrl = mci_readl(host, CTRL);
- ctrl |= SDMMC_CTRL_FIFO_RESET;
- mci_writel(host, CTRL, ctrl);
+ dw_mci_wait_fifo_reset(&host->dev, host);
+ host->prv_err = true;
} else {
data->bytes_xfered = data->blocks * data->blksz;
data->error = 0;
}
- if (!data->stop) {
+ if (!data->stop && !host->stop_snd) {
dw_mci_request_end(host, host->mrq);
goto unlock;
}
@@ -1078,8 +1587,22 @@
&host->pending_events))
break;
+ if (host->mrq->cmd->error &&
+ host->mrq->data) {
+ dw_mci_stop_dma(host);
+ sg_miter_stop(&host->sg_miter);
+ host->sg = NULL;
+ dw_mci_wait_fifo_reset(&host->dev, host);
+ }
+
host->cmd = NULL;
- dw_mci_command_complete(host, host->mrq->stop);
+ host->data = NULL;
+
+ if (host->mrq->stop)
+ dw_mci_command_complete(host, host->mrq->stop);
+ else
+ host->cmd_status = 0;
+
dw_mci_request_end(host, host->mrq);
goto unlock;
@@ -1088,6 +1611,9 @@
&host->pending_events))
break;
+ dw_mci_stop_dma(host);
+ set_bit(EVENT_XFER_COMPLETE, &host->completed_events);
+
state = STATE_DATA_BUSY;
break;
}
@@ -1420,18 +1946,6 @@
status = mci_readl(host, MINTSTS);
mci_writel(host, RINTSTS, SDMMC_INT_RXDR);
- if (status & DW_MCI_DATA_ERROR_FLAGS) {
- host->data_status = status;
- data->bytes_xfered += nbytes;
- sg_miter_stop(sg_miter);
- host->sg = NULL;
- smp_wmb();
-
- set_bit(EVENT_DATA_ERROR, &host->pending_events);
-
- tasklet_schedule(&host->tasklet);
- return;
- }
} while (status & SDMMC_INT_RXDR); /*if the RXDR is ready read again*/
data->bytes_xfered += nbytes;
@@ -1488,19 +2002,6 @@
status = mci_readl(host, MINTSTS);
mci_writel(host, RINTSTS, SDMMC_INT_TXDR);
- if (status & DW_MCI_DATA_ERROR_FLAGS) {
- host->data_status = status;
- data->bytes_xfered += nbytes;
- sg_miter_stop(sg_miter);
- host->sg = NULL;
-
- smp_wmb();
-
- set_bit(EVENT_DATA_ERROR, &host->pending_events);
-
- tasklet_schedule(&host->tasklet);
- return;
- }
} while (status & SDMMC_INT_TXDR); /* if TXDR write again */
data->bytes_xfered += nbytes;
@@ -1537,6 +2038,7 @@
u32 status, pending;
unsigned int pass_count = 0;
int i;
+ int ret = IRQ_NONE;
do {
status = mci_readl(host, RINTSTS);
@@ -1557,26 +2059,29 @@
if (pending & DW_MCI_CMD_ERROR_FLAGS) {
mci_writel(host, RINTSTS, DW_MCI_CMD_ERROR_FLAGS);
- host->cmd_status = status;
+ host->cmd_status = pending;
smp_wmb();
set_bit(EVENT_CMD_COMPLETE, &host->pending_events);
+ ret = IRQ_HANDLED;
}
if (pending & DW_MCI_DATA_ERROR_FLAGS) {
/* if there is an error report DATA_ERROR */
mci_writel(host, RINTSTS, DW_MCI_DATA_ERROR_FLAGS);
- host->data_status = status;
+ host->data_status = pending;
smp_wmb();
set_bit(EVENT_DATA_ERROR, &host->pending_events);
- if (!(pending & (SDMMC_INT_DTO | SDMMC_INT_DCRC |
- SDMMC_INT_SBE | SDMMC_INT_EBE)))
- tasklet_schedule(&host->tasklet);
+ if (pending & SDMMC_INT_SBE)
+ set_bit(EVENT_DATA_COMPLETE,
+ &host->pending_events);
+ tasklet_schedule(&host->tasklet);
+ ret = IRQ_HANDLED;
}
if (pending & SDMMC_INT_DATA_OVER) {
mci_writel(host, RINTSTS, SDMMC_INT_DATA_OVER);
if (!host->data_status)
- host->data_status = status;
+ host->data_status = pending;
smp_wmb();
if (host->dir_status == DW_MCI_RECV_STATUS) {
if (host->sg != NULL)
@@ -1584,28 +2089,39 @@
}
set_bit(EVENT_DATA_COMPLETE, &host->pending_events);
tasklet_schedule(&host->tasklet);
+ ret = IRQ_HANDLED;
}
if (pending & SDMMC_INT_RXDR) {
mci_writel(host, RINTSTS, SDMMC_INT_RXDR);
if (host->dir_status == DW_MCI_RECV_STATUS && host->sg)
dw_mci_read_data_pio(host);
+ ret = IRQ_HANDLED;
}
if (pending & SDMMC_INT_TXDR) {
mci_writel(host, RINTSTS, SDMMC_INT_TXDR);
if (host->dir_status == DW_MCI_SEND_STATUS && host->sg)
dw_mci_write_data_pio(host);
+ ret = IRQ_HANDLED;
}
if (pending & SDMMC_INT_CMD_DONE) {
mci_writel(host, RINTSTS, SDMMC_INT_CMD_DONE);
- dw_mci_cmd_interrupt(host, status);
+ dw_mci_cmd_interrupt(host, pending);
+ ret = IRQ_HANDLED;
}
if (pending & SDMMC_INT_CD) {
mci_writel(host, RINTSTS, SDMMC_INT_CD);
queue_work(dw_mci_card_workqueue, &host->card_work);
+ ret = IRQ_HANDLED;
+ }
+
+ if (pending & SDMMC_INT_HLE) {
+ mci_writel(host, RINTSTS, SDMMC_INT_HLE);
+ dev_err(&host->dev, "Hardware locked write error\n");
+ ret = IRQ_HANDLED;
}
/* Handle SDIO Interrupts */
@@ -1614,6 +2130,7 @@
if (pending & SDMMC_INT_SDIO(i)) {
mci_writel(host, RINTSTS, SDMMC_INT_SDIO(i));
mmc_signal_sdio_irq(slot->mmc);
+ ret = IRQ_HANDLED;
}
}
@@ -1625,12 +2142,18 @@
if (pending & (SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI)) {
mci_writel(host, IDSTS, SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI);
mci_writel(host, IDSTS, SDMMC_IDMAC_INT_NI);
- set_bit(EVENT_DATA_COMPLETE, &host->pending_events);
host->dma_ops->complete(host);
+ ret = IRQ_HANDLED;
}
#endif
- return IRQ_HANDLED;
+ if (ret == IRQ_NONE)
+ pr_warn_ratelimited("%s: no interrupts handled, pending %08x %08x\n",
+ dev_name(&host->dev),
+ mci_readl(host, MINTSTS),
+ mci_readl(host, IDSTS));
+
+ return ret;
}
static void dw_mci_work_routine_card(struct work_struct *work)
@@ -1660,8 +2183,12 @@
slot->last_detect_state = present;
/* Mark card as present if applicable */
- if (present != 0)
+ if (present != 0) {
+ if (host->pdata->setpower)
+ host->pdata->setpower(slot->id,
+ mmc->ocr_avail);
set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
+ }
/* Clean up queue if present */
mrq = slot->mrq;
@@ -1675,6 +2202,7 @@
break;
case STATE_SENDING_CMD:
mrq->cmd->error = -ENOMEDIUM;
+ host->prv_err = true;
if (!mrq->data)
break;
/* fall through */
@@ -1686,11 +2214,10 @@
case STATE_DATA_ERROR:
if (mrq->data->error == -EINPROGRESS)
mrq->data->error = -ENOMEDIUM;
- if (!mrq->stop)
- break;
/* fall through */
case STATE_SENDING_STOP:
- mrq->stop->error = -ENOMEDIUM;
+ if (mrq->stop)
+ mrq->stop->error = -ENOMEDIUM;
break;
}
@@ -1698,11 +2225,13 @@
} else {
list_del(&slot->queue_node);
mrq->cmd->error = -ENOMEDIUM;
+ host->prv_err = true;
if (mrq->data)
mrq->data->error = -ENOMEDIUM;
if (mrq->stop)
mrq->stop->error = -ENOMEDIUM;
+ del_timer(&host->timer);
spin_unlock(&host->lock);
mmc_request_done(slot->mmc, mrq);
spin_lock(&host->lock);
@@ -1711,6 +2240,8 @@
/* Power down slot */
if (present == 0) {
+ if (host->pdata->setpower)
+ host->pdata->setpower(slot->id, 0);
clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
/*
@@ -1721,16 +2252,7 @@
sg_miter_stop(&host->sg_miter);
host->sg = NULL;
- ctrl = mci_readl(host, CTRL);
- ctrl |= SDMMC_CTRL_FIFO_RESET;
- mci_writel(host, CTRL, ctrl);
-
-#ifdef CONFIG_MMC_DW_IDMAC
- ctrl = mci_readl(host, BMOD);
- ctrl |= 0x01; /* Software reset of DMA */
- mci_writel(host, BMOD, ctrl);
-#endif
-
+ dw_mci_wait_fifo_reset(&host->dev, host);
}
spin_unlock_bh(&host->lock);
@@ -1747,7 +2269,35 @@
}
}
-static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
+static void dw_mci_notify_change(struct platform_device *dev, int state)
+{
+ struct dw_mci *host = platform_get_drvdata(dev);
+ unsigned long flags;
+
+ if (host) {
+ spin_lock_irqsave(&host->lock, flags);
+ if (state) {
+ dev_dbg(&dev->dev, "card inserted.\n");
+ host->pdata->quirks |= DW_MCI_QUIRK_BROKEN_CARD_DETECTION;
+ } else {
+ dev_dbg(&dev->dev, "card removed.\n");
+ host->pdata->quirks &= ~DW_MCI_QUIRK_BROKEN_CARD_DETECTION;
+ }
+ queue_work(dw_mci_card_workqueue, &host->card_work);
+ spin_unlock_irqrestore(&host->lock, flags);
+ }
+}
+
+static irqreturn_t dw_mci_detect_interrupt(int irq, void *dev_id)
+{
+ struct dw_mci_slot *slot = dev_id;
+
+ queue_work(dw_mci_card_workqueue, &slot->host->card_work);
+
+ return IRQ_HANDLED;
+}
+
+static int __devinit dw_mci_init_slot(struct dw_mci *host, unsigned int id)
{
struct mmc_host *mmc;
struct dw_mci_slot *slot;
@@ -1763,7 +2313,7 @@
mmc->ops = &dw_mci_ops;
mmc->f_min = DIV_ROUND_UP(host->bus_hz, 510);
- mmc->f_max = host->bus_hz;
+ mmc->f_max = host->max_bus_hz;
if (host->pdata->get_ocr)
mmc->ocr_avail = host->pdata->get_ocr(id);
@@ -1779,13 +2329,29 @@
if (host->pdata->caps)
mmc->caps = host->pdata->caps;
+ else
+ mmc->caps = 0;
if (host->pdata->caps2)
mmc->caps2 = host->pdata->caps2;
+ else
+ mmc->caps2 = 0;
- if (host->pdata->get_bus_wd)
- if (host->pdata->get_bus_wd(slot->id) >= 4)
+ if (host->pdata->pm_caps) {
+ mmc->pm_caps |= host->pdata->pm_caps;
+ mmc->pm_flags = mmc->pm_caps;
+ }
+
+ if (host->pdata->get_bus_wd) {
+ if (host->pdata->get_bus_wd(slot->id) >= 4) {
mmc->caps |= MMC_CAP_4_BIT_DATA;
+ if (host->pdata->cfg_gpio)
+ host->pdata->cfg_gpio(4);
+ } else {
+ if (host->pdata->cfg_gpio)
+ host->pdata->cfg_gpio(1);
+ }
+ }
if (host->pdata->quirks & DW_MCI_QUIRK_HIGHSPEED)
mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
@@ -1806,9 +2372,9 @@
#ifdef CONFIG_MMC_DW_IDMAC
mmc->max_segs = host->ring_size;
mmc->max_blk_size = 65536;
- mmc->max_blk_count = host->ring_size;
mmc->max_seg_size = 0x1000;
- mmc->max_req_size = mmc->max_seg_size * mmc->max_blk_count;
+ mmc->max_req_size = mmc->max_seg_size * host->ring_size;
+ mmc->max_blk_count = mmc->max_req_size / 512;
#else
mmc->max_segs = 64;
mmc->max_blk_size = 65536; /* BLKSIZ is 16 bits */
@@ -1825,6 +2391,8 @@
} else
regulator_enable(host->vmmc);
+ host->pdata->init(id, dw_mci_detect_interrupt, host);
+
if (dw_mci_get_cd(mmc))
set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
else
@@ -1863,8 +2431,13 @@
static void dw_mci_init_dma(struct dw_mci *host)
{
+ if (host->pdata->desc_sz)
+ host->desc_sz = host->pdata->desc_sz;
+ else
+ host->desc_sz = 1;
+
/* Alloc memory for sg translation */
- host->sg_cpu = dma_alloc_coherent(&host->dev, PAGE_SIZE,
+ host->sg_cpu = dma_alloc_coherent(&host->dev, host->desc_sz * PAGE_SIZE,
&host->sg_dma, GFP_KERNEL);
if (!host->sg_cpu) {
dev_err(&host->dev, "%s: could not alloc DMA memory\n",
@@ -1923,7 +2496,58 @@
return false;
}
-int dw_mci_probe(struct dw_mci *host)
+static void dw_mci_timeout_timer(unsigned long data)
+{
+ struct dw_mci *host = (struct dw_mci *)data;
+ struct mmc_request *mrq;
+
+ if (host && host->mrq) {
+ mrq = host->mrq;
+
+ dev_err(&host->dev,
+ "Timeout waiting for hardware interrupt\n"
+ "cmd%d, state: %d, status: %08X, rintsts: %08X\n",
+ mrq->cmd->opcode, host->state,
+ mci_readl(host, STATUS), mci_readl(host, RINTSTS));
+
+ spin_lock(&host->lock);
+ host->data = NULL;
+ host->cmd = NULL;
+
+ switch (host->state) {
+ case STATE_IDLE:
+ break;
+ case STATE_SENDING_CMD:
+ mrq->cmd->error = -ENOMEDIUM;
+ if (!mrq->data)
+ break;
+ /* fall through */
+ case STATE_SENDING_DATA:
+ mrq->data->error = -ENOMEDIUM;
+ dw_mci_stop_dma(host);
+ break;
+ case STATE_DATA_BUSY:
+ case STATE_DATA_ERROR:
+ if (mrq->data->error == -EINPROGRESS)
+ mrq->data->error = -ENOMEDIUM;
+ /* fall through */
+ case STATE_SENDING_STOP:
+ if (!mrq->stop)
+ break;
+ mrq->stop->error = -ENOMEDIUM;
+ break;
+ }
+
+ spin_unlock(&host->lock);
+ dw_mci_wait_fifo_reset(&host->dev, host);
+ spin_lock(&host->lock);
+
+ dw_mci_request_end(host, mrq);
+ spin_unlock(&host->lock);
+ }
+}
+
+int __devinit dw_mci_probe(struct dw_mci *host)
{
int width, i, ret = 0;
u32 fifo_size;
@@ -1946,16 +2570,31 @@
return -ENODEV;
}
+ host->hclk = clk_get(&host->dev, host->pdata->hclk_name);
+ if (IS_ERR(host->hclk)) {
+ dev_err(&host->dev,
+ "failed to get hclk\n");
+ ret = PTR_ERR(host->hclk);
+ goto err_freehost;
+ }
+ clk_enable(host->hclk);
+
+ host->cclk = clk_get(&host->dev, host->pdata->cclk_name);
+ if (IS_ERR(host->cclk)) {
+ dev_err(&host->dev,
+ "failed to get cclk\n");
+ ret = PTR_ERR(host->cclk);
+ goto err_free_hclk;
+ }
+ clk_enable(host->cclk);
+
host->bus_hz = host->pdata->bus_hz;
+ host->max_bus_hz = host->pdata->max_bus_hz;
host->quirks = host->pdata->quirks;
spin_lock_init(&host->lock);
INIT_LIST_HEAD(&host->queue);
-
- host->dma_ops = host->pdata->dma_ops;
- dw_mci_init_dma(host);
-
/*
* Get the host data width - this assumes that HCON has been set with
* the correct values.
@@ -1985,9 +2624,12 @@
/* Reset all blocks */
if (!mci_wait_reset(&host->dev, host)) {
ret = -ENODEV;
- goto err_dmaunmap;
+ goto err_free_hclk;
}
+ host->dma_ops = host->pdata->dma_ops;
+ dw_mci_init_dma(host);
+
/* Clear the interrupts for the host controller */
mci_writel(host, RINTSTS, 0xFFFFFFFF);
mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */
@@ -2012,7 +2654,7 @@
fifo_size = host->pdata->fifo_depth;
}
host->fifo_depth = fifo_size;
- host->fifoth_val = ((0x2 << 28) | ((fifo_size/2 - 1) << 16) |
+ host->fifoth_val = ((0x4 << 28) | ((fifo_size/4 - 1) << 16) |
((fifo_size/2) << 0));
mci_writel(host, FIFOTH, host->fifoth_val);
@@ -2026,6 +2668,9 @@
if (!dw_mci_card_workqueue)
goto err_dmaunmap;
INIT_WORK(&host->card_work, dw_mci_work_routine_card);
+
+ setup_timer(&host->timer, dw_mci_timeout_timer, (unsigned long)host);
+
ret = request_irq(host->irq, dw_mci_interrupt, host->irq_flags, "dw-mci", host);
if (ret)
goto err_workqueue;
@@ -2056,6 +2701,12 @@
else
host->data_offset = DATA_240A_OFFSET;
+ if (host->pdata->caps & MMC_CAP_UHS_SDR50)
+ clk_set_rate(host->cclk, 200 * 1000 * 1000);
+
+ if (host->pdata->cd_type == DW_MCI_CD_EXTERNAL)
+ host->pdata->ext_cd_init(&dw_mci_notify_change);
+
/*
* Enable interrupts for command done, data over, data empty, card det,
* receive ready and error such as transmit, receive timeout, crc error
@@ -2090,13 +2741,23 @@
err_dmaunmap:
if (host->use_dma && host->dma_ops->exit)
host->dma_ops->exit(host);
- dma_free_coherent(&host->dev, PAGE_SIZE,
+ dma_free_coherent(&host->dev, host->desc_sz * PAGE_SIZE,
host->sg_cpu, host->sg_dma);
if (host->vmmc) {
regulator_disable(host->vmmc);
regulator_put(host->vmmc);
}
+
+ clk_disable(host->cclk);
+ clk_put(host->cclk);
+
+err_free_hclk:
+ clk_disable(host->hclk);
+ clk_put(host->hclk);
+
+err_freehost:
+ kfree(host);
return ret;
}
EXPORT_SYMBOL(dw_mci_probe);
@@ -2108,6 +2769,9 @@
mci_writel(host, RINTSTS, 0xFFFFFFFF);
mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */
+ if (host->pdata->cd_type == DW_MCI_CD_EXTERNAL)
+ host->pdata->ext_cd_cleanup(&dw_mci_notify_change);
+
for (i = 0; i < host->num_slots; i++) {
dev_dbg(&host->dev, "remove slot %d\n", i);
if (host->slot[i])
@@ -2119,8 +2783,12 @@
mci_writel(host, CLKSRC, 0);
free_irq(host->irq, host);
+
+ del_timer_sync(&host->timer);
+
destroy_workqueue(dw_mci_card_workqueue);
- dma_free_coherent(&host->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
+ dma_free_coherent(&host->dev, host->desc_sz * PAGE_SIZE,
+ host->sg_cpu, host->sg_dma);
if (host->use_dma && host->dma_ops->exit)
host->dma_ops->exit(host);
@@ -2130,6 +2798,10 @@
regulator_put(host->vmmc);
}
+ clk_disable(host->cclk);
+ clk_put(host->cclk);
+ clk_disable(host->hclk);
+ clk_put(host->hclk);
}
EXPORT_SYMBOL(dw_mci_remove);
@@ -2147,6 +2819,8 @@
struct dw_mci_slot *slot = host->slot[i];
if (!slot)
continue;
+ if (slot->mmc)
+ slot->mmc->pm_flags |= slot->mmc->pm_caps;
ret = mmc_suspend_host(slot->mmc);
if (ret < 0) {
while (--i >= 0) {
@@ -2172,14 +2846,14 @@
if (host->vmmc)
regulator_enable(host->vmmc);
- if (host->dma_ops->init)
- host->dma_ops->init(host);
-
if (!mci_wait_reset(&host->dev, host)) {
ret = -ENODEV;
return ret;
}
+ if (host->dma_ops->init)
+ host->dma_ops->init(host);
+
/* Restore the old value at FIFOTH register */
mci_writel(host, FIFOTH, host->fifoth_val);
@@ -2193,6 +2867,12 @@
struct dw_mci_slot *slot = host->slot[i];
if (!slot)
continue;
+
+ if (slot->mmc->pm_flags & MMC_PM_KEEP_POWER) {
+ dw_mci_set_ios(slot->mmc, &slot->mmc->ios);
+ dw_mci_setup_bus(slot, 1);
+ }
+
ret = mmc_resume_host(host->slot[i]->mmc);
if (ret < 0)
return ret;
diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
index 15c27e1..463a390 100644
--- a/drivers/mmc/host/dw_mmc.h
+++ b/drivers/mmc/host/dw_mmc.h
@@ -53,6 +53,8 @@
#define SDMMC_IDINTEN 0x090
#define SDMMC_DSCADDR 0x094
#define SDMMC_BUFADDR 0x098
+#define SDMMC_CLKSEL 0x09c
+#define SDMMC_CDTHRCTL 0x100
#define SDMMC_DATA(x) (x)
/*
@@ -111,6 +113,7 @@
#define SDMMC_INT_ERROR 0xbfc2
/* Command register defines */
#define SDMMC_CMD_START BIT(31)
+#define SDMMC_USE_HOLD_REG BIT(29)
#define SDMMC_CMD_CCS_EXP BIT(23)
#define SDMMC_CMD_CEATA_RD BIT(22)
#define SDMMC_CMD_UPD_CLK BIT(21)
@@ -126,6 +129,7 @@
#define SDMMC_CMD_RESP_EXP BIT(6)
#define SDMMC_CMD_INDX(n) ((n) & 0x1F)
/* Status register defines */
+#define SDMMC_STATUS_DMA_REQ BIT(31)
#define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF)
/* Internal DMAC interrupt defines */
#define SDMMC_IDMAC_INT_AI BIT(9)
diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c
index 55a164f..b676f96 100644
--- a/drivers/mmc/host/sdhci-s3c.c
+++ b/drivers/mmc/host/sdhci-s3c.c
@@ -568,8 +568,10 @@
break;
}
- if (pdata->pm_caps)
+ if (pdata->pm_caps) {
host->mmc->pm_caps |= pdata->pm_caps;
+ host->mmc->pm_flags = host->mmc->pm_caps;
+ }
host->quirks |= (SDHCI_QUIRK_32BIT_DMA_ADDR |
SDHCI_QUIRK_32BIT_DMA_SIZE);
@@ -676,6 +678,8 @@
{
struct sdhci_host *host = dev_get_drvdata(dev);
+ if (host->mmc)
+ host->mmc->pm_flags |= host->mmc->pm_caps;
return sdhci_suspend_host(host);
}
diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c
index 3f3a297..e370107 100644
--- a/drivers/rtc/rtc-s3c.c
+++ b/drivers/rtc/rtc-s3c.c
@@ -172,7 +172,7 @@
/* Time read/write */
-static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
+static int s3c_rtc_gettime_internal(struct rtc_time *rtc_tm)
{
unsigned int have_retried = 0;
void __iomem *base = s3c_rtc_base;
@@ -215,6 +215,11 @@
return rtc_valid_tm(rtc_tm);
}
+static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
+{
+ return s3c_rtc_gettime_internal(rtc_tm);
+}
+
static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm)
{
void __iomem *base = s3c_rtc_base;
@@ -423,6 +428,25 @@
clk_disable(rtc_clk);
}
+/**
+ * read_persistent_clock - Return time from a persistent clock.
+ */
+void read_persistent_clock(struct timespec *ts)
+{
+ struct rtc_time rtc_tm;
+ unsigned long time;
+
+ if ((s3c_rtc_base == NULL) || s3c_rtc_gettime_internal(&rtc_tm)) {
+ ts->tv_sec = 0;
+ ts->tv_nsec = 0;
+ return;
+ }
+
+ rtc_tm_to_time(&rtc_tm, &time);
+ ts->tv_sec = time;
+ ts->tv_nsec = 0;
+}
+
static int __devexit s3c_rtc_remove(struct platform_device *dev)
{
struct rtc_device *rtc = platform_get_drvdata(dev);
@@ -521,12 +545,13 @@
}
clk_enable(rtc_clk);
+ s3c_rtc_cpu_type = s3c_rtc_get_driver_data(pdev);
/* check to see if everything is setup correctly */
s3c_rtc_enable(pdev, 1);
- pr_debug("s3c2410_rtc: RTCCON=%02x\n",
+ pr_debug("s3c2410_rtc: RTCCON=%04x\n",
readw(s3c_rtc_base + S3C2410_RTCCON));
device_init_wakeup(&pdev->dev, 1);
@@ -542,8 +567,6 @@
goto err_nortc;
}
- s3c_rtc_cpu_type = s3c_rtc_get_driver_data(pdev);
-
/* Check RTC Time */
s3c_rtc_gettime(NULL, &rtc_tm);
@@ -627,10 +650,12 @@
{
clk_enable(rtc_clk);
/* save TICNT for anyone using periodic interrupts */
- ticnt_save = readb(s3c_rtc_base + S3C2410_TICNT);
if (s3c_rtc_cpu_type == TYPE_S3C64XX) {
ticnt_en_save = readw(s3c_rtc_base + S3C2410_RTCCON);
ticnt_en_save &= S3C64XX_RTCCON_TICEN;
+ ticnt_save = readl(s3c_rtc_base + S3C2410_TICNT);
+ } else {
+ ticnt_save = readb(s3c_rtc_base + S3C2410_TICNT);
}
s3c_rtc_enable(pdev, 0);
@@ -651,10 +676,16 @@
clk_enable(rtc_clk);
s3c_rtc_enable(pdev, 1);
- writeb(ticnt_save, s3c_rtc_base + S3C2410_TICNT);
- if (s3c_rtc_cpu_type == TYPE_S3C64XX && ticnt_en_save) {
- tmp = readw(s3c_rtc_base + S3C2410_RTCCON);
- writew(tmp | ticnt_en_save, s3c_rtc_base + S3C2410_RTCCON);
+ if (s3c_rtc_cpu_type == TYPE_S3C64XX) {
+ writel(ticnt_save, s3c_rtc_base + S3C2410_TICNT);
+
+ if (ticnt_en_save) {
+ tmp = readw(s3c_rtc_base + S3C2410_RTCCON);
+ writew(tmp | ticnt_en_save,
+ s3c_rtc_base + S3C2410_RTCCON);
+ }
+ } else {
+ writeb(ticnt_save, s3c_rtc_base + S3C2410_TICNT);
}
if (device_may_wakeup(&pdev->dev) && wake_en) {
diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c
index 972a94c..4842bd2 100644
--- a/drivers/spi/spi-s3c64xx.c
+++ b/drivers/spi/spi-s3c64xx.c
@@ -191,6 +191,10 @@
writel(0, regs + S3C64XX_SPI_PACKET_CNT);
val = readl(regs + S3C64XX_SPI_CH_CFG);
+ val &= ~(S3C64XX_SPI_CH_RXCH_ON | S3C64XX_SPI_CH_TXCH_ON);
+ writel(val, regs + S3C64XX_SPI_CH_CFG);
+
+ val = readl(regs + S3C64XX_SPI_CH_CFG);
val |= S3C64XX_SPI_CH_SW_RST;
val &= ~S3C64XX_SPI_CH_HS_EN;
writel(val, regs + S3C64XX_SPI_CH_CFG);
@@ -224,10 +228,6 @@
val = readl(regs + S3C64XX_SPI_MODE_CFG);
val &= ~(S3C64XX_SPI_MODE_TXDMA_ON | S3C64XX_SPI_MODE_RXDMA_ON);
writel(val, regs + S3C64XX_SPI_MODE_CFG);
-
- val = readl(regs + S3C64XX_SPI_CH_CFG);
- val &= ~(S3C64XX_SPI_CH_RXCH_ON | S3C64XX_SPI_CH_TXCH_ON);
- writel(val, regs + S3C64XX_SPI_CH_CFG);
}
static void s3c64xx_spi_dmacb(void *data)
@@ -262,14 +262,24 @@
unsigned len, dma_addr_t buf)
{
struct s3c64xx_spi_driver_data *sdd;
- struct samsung_dma_prep_info info;
+ struct samsung_dma_prep info;
+ struct samsung_dma_config config;
- if (dma->direction == DMA_DEV_TO_MEM)
+ if (dma->direction == DMA_DEV_TO_MEM) {
sdd = container_of((void *)dma,
struct s3c64xx_spi_driver_data, rx_dma);
- else
+ config.direction = sdd->rx_dma.direction;
+ config.fifo = sdd->sfr_start + S3C64XX_SPI_RX_DATA;
+ config.width = sdd->cur_bpw / 8;
+ sdd->ops->config(sdd->rx_dma.ch, &config);
+ } else {
sdd = container_of((void *)dma,
struct s3c64xx_spi_driver_data, tx_dma);
+ config.direction = sdd->tx_dma.direction;
+ config.fifo = sdd->sfr_start + S3C64XX_SPI_TX_DATA;
+ config.width = sdd->cur_bpw / 8;
+ sdd->ops->config(sdd->tx_dma.ch, &config);
+ }
info.cap = DMA_SLAVE;
info.len = len;
@@ -284,20 +294,15 @@
static int acquire_dma(struct s3c64xx_spi_driver_data *sdd)
{
- struct samsung_dma_info info;
+ struct samsung_dma_req req;
sdd->ops = samsung_dma_get_ops();
- info.cap = DMA_SLAVE;
- info.client = &s3c64xx_spi_dma_client;
- info.width = sdd->cur_bpw / 8;
+ req.cap = DMA_SLAVE;
+ req.client = &s3c64xx_spi_dma_client;
- info.direction = sdd->rx_dma.direction;
- info.fifo = sdd->sfr_start + S3C64XX_SPI_RX_DATA;
- sdd->rx_dma.ch = sdd->ops->request(sdd->rx_dma.dmach, &info);
- info.direction = sdd->tx_dma.direction;
- info.fifo = sdd->sfr_start + S3C64XX_SPI_TX_DATA;
- sdd->tx_dma.ch = sdd->ops->request(sdd->tx_dma.dmach, &info);
+ sdd->rx_dma.ch = sdd->ops->request(sdd->rx_dma.dmach, &req);
+ sdd->tx_dma.ch = sdd->ops->request(sdd->tx_dma.dmach, &req);
return 1;
}
@@ -643,6 +648,10 @@
u32 speed;
u8 bpw;
+ /* Acquire DMA channels */
+ while (!acquire_dma(sdd))
+ msleep(10);
+
/* If Master's(controller) state differs from that needed by Slave */
if (sdd->cur_speed != spi->max_speed_hz
|| sdd->cur_mode != spi->mode
@@ -745,8 +754,6 @@
if (list_is_last(&xfer->transfer_list,
&msg->transfers))
cs_toggle = 1;
- else
- disable_cs(sdd, spi);
}
msg->actual_length += xfer->len;
@@ -764,6 +771,10 @@
msg->status = status;
+ /* Free DMA channels */
+ sdd->ops->release(sdd->rx_dma.ch, &s3c64xx_spi_dma_client);
+ sdd->ops->release(sdd->tx_dma.ch, &s3c64xx_spi_dma_client);
+
spi_finalize_current_message(master);
return 0;
@@ -773,10 +784,6 @@
{
struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi);
- /* Acquire DMA channels */
- while (!acquire_dma(sdd))
- msleep(10);
-
pm_runtime_get_sync(&sdd->pdev->dev);
return 0;
@@ -786,10 +793,6 @@
{
struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi);
- /* Free DMA channels */
- sdd->ops->release(sdd->rx_dma.ch, &s3c64xx_spi_dma_client);
- sdd->ops->release(sdd->tx_dma.ch, &s3c64xx_spi_dma_client);
-
pm_runtime_put(&sdd->pdev->dev);
return 0;
@@ -1053,26 +1056,23 @@
goto err3;
}
- if (clk_enable(sdd->clk)) {
- dev_err(&pdev->dev, "Couldn't enable clock 'spi'\n");
- ret = -EBUSY;
- goto err4;
- }
-
sprintf(clk_name, "spi_busclk%d", sci->src_clk_nr);
sdd->src_clk = clk_get(&pdev->dev, clk_name);
if (IS_ERR(sdd->src_clk)) {
dev_err(&pdev->dev,
"Unable to acquire clock '%s'\n", clk_name);
ret = PTR_ERR(sdd->src_clk);
- goto err5;
+ goto err4;
}
- if (clk_enable(sdd->src_clk)) {
- dev_err(&pdev->dev, "Couldn't enable clock '%s'\n", clk_name);
- ret = -EBUSY;
- goto err6;
- }
+ pm_runtime_enable(&pdev->dev);
+
+#if defined(CONFIG_PM_RUNTIME)
+ pm_runtime_get_sync(&pdev->dev);
+#else
+ clk_enable(sdd->clk);
+ clk_enable(sdd->src_clk);
+#endif
/* Setup Deufult Mode */
s3c64xx_spi_hwinit(sdd, pdev->id);
@@ -1085,7 +1085,7 @@
if (ret != 0) {
dev_err(&pdev->dev, "Failed to request IRQ %d: %d\n",
irq, ret);
- goto err7;
+ goto err5;
}
writel(S3C64XX_SPI_INT_RX_OVERRUN_EN | S3C64XX_SPI_INT_RX_UNDERRUN_EN |
@@ -1095,7 +1095,7 @@
if (spi_register_master(master)) {
dev_err(&pdev->dev, "cannot register SPI master\n");
ret = -EBUSY;
- goto err8;
+ goto err6;
}
dev_dbg(&pdev->dev, "Samsung SoC SPI Driver loaded for Bus SPI-%d "
@@ -1105,18 +1105,21 @@
mem_res->end, mem_res->start,
sdd->rx_dma.dmach, sdd->tx_dma.dmach);
- pm_runtime_enable(&pdev->dev);
+ pm_runtime_put(&pdev->dev);
return 0;
-err8:
- free_irq(irq, sdd);
-err7:
- clk_disable(sdd->src_clk);
err6:
- clk_put(sdd->src_clk);
+ free_irq(irq, sdd);
err5:
+#if defined(CONFIG_PM_RUNTIME)
+ pm_runtime_put(&pdev->dev);
+#else
+ clk_disable(sdd->src_clk);
clk_disable(sdd->clk);
+#endif
+ pm_runtime_disable(&pdev->dev);
+ clk_put(sdd->src_clk);
err4:
clk_put(sdd->clk);
err3:
@@ -1137,18 +1140,20 @@
struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
struct resource *mem_res;
- pm_runtime_disable(&pdev->dev);
-
spi_unregister_master(master);
writel(0, sdd->regs + S3C64XX_SPI_INT_EN);
free_irq(platform_get_irq(pdev, 0), sdd);
+#ifndef CONFIG_PM_RUNTIME
clk_disable(sdd->src_clk);
- clk_put(sdd->src_clk);
-
clk_disable(sdd->clk);
+#endif
+
+ pm_runtime_disable(&pdev->dev);
+
+ clk_put(sdd->src_clk);
clk_put(sdd->clk);
iounmap((void *) sdd->regs);
@@ -1171,9 +1176,11 @@
spi_master_suspend(master);
+#ifndef CONFIG_PM_RUNTIME
/* Disable the clock */
clk_disable(sdd->src_clk);
clk_disable(sdd->clk);
+#endif
sdd->cur_speed = 0; /* Output Clock is stopped */
@@ -1189,14 +1196,20 @@
sci->cfg_gpio(pdev);
+#if defined(CONFIG_PM_RUNTIME)
+ pm_runtime_get_sync(&sdd->pdev->dev);
+#else
/* Enable the clock */
clk_enable(sdd->src_clk);
clk_enable(sdd->clk);
+#endif
s3c64xx_spi_hwinit(sdd, pdev->id);
spi_master_resume(master);
+ pm_runtime_put(&sdd->pdev->dev);
+
return 0;
}
#endif /* CONFIG_PM */
@@ -1206,6 +1219,10 @@
{
struct spi_master *master = spi_master_get(dev_get_drvdata(dev));
struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
+ struct s3c64xx_spi_info *sci = sdd->cntrlr_info;
+
+ if (sci->gpio_pull_up)
+ sci->gpio_pull_up(false);
clk_disable(sdd->clk);
clk_disable(sdd->src_clk);
@@ -1217,10 +1234,14 @@
{
struct spi_master *master = spi_master_get(dev_get_drvdata(dev));
struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
+ struct s3c64xx_spi_info *sci = sdd->cntrlr_info;
clk_enable(sdd->src_clk);
clk_enable(sdd->clk);
+ if (sci->gpio_pull_up)
+ sci->gpio_pull_up(true);
+
return 0;
}
#endif /* CONFIG_PM_RUNTIME */
diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c
index d8b0aee..0a3fac3 100644
--- a/drivers/tty/serial/samsung.c
+++ b/drivers/tty/serial/samsung.c
@@ -529,7 +529,7 @@
switch (level) {
case 3:
- if (!IS_ERR(ourport->baudclk) && ourport->baudclk != NULL)
+ if (!IS_ERR(ourport->baudclk))
clk_disable(ourport->baudclk);
clk_disable(ourport->clk);
@@ -538,7 +538,7 @@
case 0:
clk_enable(ourport->clk);
- if (!IS_ERR(ourport->baudclk) && ourport->baudclk != NULL)
+ if (!IS_ERR(ourport->baudclk))
clk_enable(ourport->baudclk);
break;
@@ -604,7 +604,6 @@
char clkname[MAX_CLK_NAME_LENGTH];
int calc_deviation, deviation = (1 << 30) - 1;
- *best_clk = NULL;
clk_sel = (ourport->cfg->clk_sel) ? ourport->cfg->clk_sel :
ourport->info->def_clk_sel;
for (cnt = 0; cnt < info->num_clks; cnt++) {
@@ -613,7 +612,7 @@
sprintf(clkname, "clk_uart_baud%d", cnt);
clk = clk_get(ourport->port.dev, clkname);
- if (IS_ERR_OR_NULL(clk))
+ if (IS_ERR(clk))
continue;
rate = clk_get_rate(clk);
@@ -684,7 +683,7 @@
{
struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port);
struct s3c24xx_uart_port *ourport = to_ourport(port);
- struct clk *clk = NULL;
+ struct clk *clk = ERR_PTR(-EINVAL);
unsigned long flags;
unsigned int baud, quot, clk_sel = 0;
unsigned int ulcon;
@@ -705,7 +704,7 @@
quot = s3c24xx_serial_getclk(ourport, baud, &clk, &clk_sel);
if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST)
quot = port->custom_divisor;
- if (!clk)
+ if (IS_ERR(clk))
return;
/* check to see if we need to change clock source */
@@ -713,9 +712,9 @@
if (ourport->baudclk != clk) {
s3c24xx_serial_setsource(port, clk_sel);
- if (ourport->baudclk != NULL && !IS_ERR(ourport->baudclk)) {
+ if (!IS_ERR(ourport->baudclk)) {
clk_disable(ourport->baudclk);
- ourport->baudclk = NULL;
+ ourport->baudclk = ERR_PTR(-EINVAL);
}
clk_enable(clk);
@@ -1014,10 +1013,10 @@
* a disturbance in the clock-rate over the change.
*/
- if (IS_ERR(port->clk))
+ if (IS_ERR(port->baudclk))
goto exit;
- if (port->baudclk_rate == clk_get_rate(port->clk))
+ if (port->baudclk_rate == clk_get_rate(port->baudclk))
goto exit;
if (val == CPUFREQ_PRECHANGE) {
@@ -1160,7 +1159,11 @@
struct uart_port *port = s3c24xx_dev_to_port(dev);
struct s3c24xx_uart_port *ourport = to_ourport(port);
- return snprintf(buf, PAGE_SIZE, "* %s\n", ourport->baudclk->name);
+ if (IS_ERR(ourport->baudclk))
+ return -EINVAL;
+
+ return snprintf(buf, PAGE_SIZE, "* %s\n",
+ ourport->baudclk->name ?: "(null)");
}
static DEVICE_ATTR(clock_source, S_IRUGO, s3c24xx_serial_show_clksrc, NULL);
@@ -1169,7 +1172,6 @@
/* Device driver serial port probe */
static const struct of_device_id s3c24xx_uart_dt_match[];
-static int probe_index;
static inline struct s3c24xx_serial_drv_data *s3c24xx_get_driver_data(
struct platform_device *pdev)
@@ -1190,9 +1192,12 @@
struct s3c24xx_uart_port *ourport;
int ret;
- dbg("s3c24xx_serial_probe(%p) %d\n", pdev, probe_index);
+ dbg("s3c24xx_serial_probe(%p) %d\n", pdev, pdev->id);
- ourport = &s3c24xx_serial_ports[probe_index];
+ if (pdev->id >= CONFIG_SERIAL_SAMSUNG_UARTS)
+ return -EINVAL;
+
+ ourport = &s3c24xx_serial_ports[pdev->id];
ourport->drv_data = s3c24xx_get_driver_data(pdev);
if (!ourport->drv_data) {
@@ -1200,6 +1205,7 @@
return -ENODEV;
}
+ ourport->baudclk = ERR_PTR(-EINVAL);
ourport->info = ourport->drv_data->info;
ourport->cfg = (pdev->dev.platform_data) ?
(struct s3c2410_uartcfg *)pdev->dev.platform_data :
@@ -1207,9 +1213,7 @@
ourport->port.fifosize = (ourport->info->fifosize) ?
ourport->info->fifosize :
- ourport->drv_data->fifosize[probe_index];
-
- probe_index++;
+ ourport->drv_data->fifosize[pdev->id];
dbg("%s: initialising port %p...\n", __func__, ourport);
@@ -1250,10 +1254,14 @@
/* UART power management code */
#ifdef CONFIG_PM_SLEEP
+unsigned int s3c24xx_serial_mask_save[CONFIG_SERIAL_SAMSUNG_UARTS];
+
static int s3c24xx_serial_suspend(struct device *dev)
{
struct uart_port *port = s3c24xx_dev_to_port(dev);
+ s3c24xx_serial_mask_save[port -> line] = rd_regl(port, S3C64XX_UINTM);
+
if (port)
uart_suspend_port(&s3c24xx_uart_drv, port);
@@ -1267,6 +1275,7 @@
if (port) {
clk_enable(ourport->clk);
+ wr_regl(port, S3C64XX_UINTM, s3c24xx_serial_mask_save[port->line]);
s3c24xx_serial_resetport(port, s3c24xx_port_to_cfg(port));
clk_disable(ourport->clk);
@@ -1387,7 +1396,7 @@
sprintf(clk_name, "clk_uart_baud%d", clk_sel);
clk = clk_get(port->dev, clk_name);
- if (!IS_ERR(clk) && clk != NULL)
+ if (!IS_ERR(clk))
rate = clk_get_rate(clk);
else
rate = 1;
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index a04b3f5..fba62bd 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -268,6 +268,26 @@
The Samsung S3C64XX USB2.0 high-speed gadget controller
integrated into the S3C64XX series SoC.
+config USB_S3C_OTGD
+ tristate "S3C HS USB OTG Device"
+ depends on S3C_DEV_USB_HSOTG
+ select USB_GADGET_DUALSPEED
+ help
+ Samsung's S3C64XX processors include high speed USB OTG2.0
+ controller. It has 15 configurable endpoints, as well as
+ endpoint zero (for control transfers).
+
+ This driver has been tested on the S3C6410, S5P6440, S5PC100, S5PV210,
+ EXYNOS4210, EXYNOS4x12, EXYNOS5250 processor.
+
+config USB_EXYNOS_SS_UDC
+ tristate "EXYNOS SuperSpeed USB 3.0 Device controller"
+ depends on EXYNOS_DEV_SS_UDC
+ select USB_GADGET_DUALSPEED
+ select USB_GADGET_SUPERSPEED
+ help
+ DWC SuperSpeed USB 3.0 Device controller.
+
config USB_IMX
tristate "Freescale i.MX1 USB Peripheral Controller"
depends on ARCH_MXC
@@ -855,6 +875,12 @@
Each function can be configured and enabled/disabled
dynamically from userspace through a sysfs interface.
+config USB_ANDROID_RNDIS_DWORD_ALIGNED
+ boolean "Use double word aligned"
+ depends on USB_G_ANDROID
+ help
+ Provides dword aligned for DMA controller.
+
config USB_CDC_COMPOSITE
tristate "CDC Composite Device (Ethernet and ACM)"
depends on NET
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index b91866a6..f62c0e7 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -14,6 +14,7 @@
obj-$(CONFIG_USB_GOKU) += goku_udc.o
obj-$(CONFIG_USB_OMAP) += omap_udc.o
obj-$(CONFIG_USB_S3C2410) += s3c2410_udc.o
+obj-$(CONFIG_USB_S3C_OTGD) += s3c_udc_otg.o
obj-$(CONFIG_USB_AT91) += at91_udc.o
obj-$(CONFIG_USB_ATMEL_USBA) += atmel_usba_udc.o
obj-$(CONFIG_USB_FSL_USB2) += fsl_usb2_udc.o
@@ -25,6 +26,7 @@
obj-$(CONFIG_USB_CI13XXX_PCI) += ci13xxx_pci.o
obj-$(CONFIG_USB_S3C_HSOTG) += s3c-hsotg.o
obj-$(CONFIG_USB_S3C_HSUDC) += s3c-hsudc.o
+obj-$(CONFIG_USB_EXYNOS_SS_UDC) += exynos_ss_udc.o
obj-$(CONFIG_USB_LANGWELL) += langwell_udc.o
obj-$(CONFIG_USB_EG20T) += pch_udc.o
obj-$(CONFIG_USB_MV_UDC) += mv_udc.o
diff --git a/drivers/usb/gadget/exynos_ss_udc.c b/drivers/usb/gadget/exynos_ss_udc.c
new file mode 100644
index 0000000..50222ed
--- /dev/null
+++ b/drivers/usb/gadget/exynos_ss_udc.c
@@ -0,0 +1,2536 @@
+/* linux/drivers/usb/gadget/exynos_ss_udc.c
+ *
+ * Copyright 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * EXYNOS SuperSpeed USB 3.0 Device Controlle driver
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/platform_data/exynos_usb3_drd.h>
+
+#include <asm/byteorder.h>
+
+#include <mach/map.h>
+#include <mach/regs-usb3-exynos-drd-phy.h>
+#include <mach/regs-usb3-exynos-drd.h>
+#include <mach/regs-pmu.h>
+
+#include <plat/usb-phy.h>
+#include <plat/cpu.h>
+
+#include "exynos_ss_udc.h"
+
+static void exynos_ss_udc_kill_all_requests(struct exynos_ss_udc *udc,
+ struct exynos_ss_udc_ep *udc_ep,
+ int result);
+static void exynos_ss_udc_complete_setup(struct usb_ep *ep,
+ struct usb_request *req);
+static void exynos_ss_udc_complete_request(struct exynos_ss_udc *udc,
+ struct exynos_ss_udc_ep *udc_ep,
+ struct exynos_ss_udc_req *udc_req,
+ int result);
+static void exynos_ss_udc_start_req(struct exynos_ss_udc *udc,
+ struct exynos_ss_udc_ep *udc_ep,
+ struct exynos_ss_udc_req *udc_req,
+ bool continuing);
+static void exynos_ss_udc_ep_activate(struct exynos_ss_udc *udc,
+ struct exynos_ss_udc_ep *udc_ep);
+static void exynos_ss_udc_ep_deactivate(struct exynos_ss_udc *udc,
+ struct exynos_ss_udc_ep *udc_ep);
+static int exynos_ss_udc_start(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver);
+static int exynos_ss_udc_stop(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver);
+
+
+static int poll_bit_set(void __iomem *ptr, u32 val, int timeout)
+{
+ u32 reg;
+
+ do {
+ reg = readl(ptr);
+ if (reg & val)
+ return 0;
+
+ udelay(1);
+ } while (timeout-- > 0);
+
+ return -ETIME;
+}
+
+static int poll_bit_clear(void __iomem *ptr, u32 val, int timeout)
+{
+ u32 reg;
+
+ do {
+ reg = readl(ptr);
+ if (!(reg & val))
+ return 0;
+
+ udelay(1);
+ } while (timeout-- > 0);
+
+ return -ETIME;
+}
+
+/**
+ * ep_from_windex - convert control wIndex value to endpoint
+ * @udc: The device state.
+ * @windex: The control request wIndex field (in host order).
+ *
+ * Convert the given wIndex into a pointer to an driver endpoint
+ * structure, or return NULL if it is not a valid endpoint.
+ */
+static struct exynos_ss_udc_ep *ep_from_windex(struct exynos_ss_udc *udc,
+ u32 windex)
+{
+ struct exynos_ss_udc_ep *ep = &udc->eps[windex & 0x7F];
+ int dir = (windex & USB_DIR_IN) ? 1 : 0;
+ int idx = windex & 0x7F;
+
+ if (windex >= 0x100)
+ return NULL;
+
+ if (idx > EXYNOS_USB3_EPS)
+ return NULL;
+
+ if (idx && ep->dir_in != dir)
+ return NULL;
+
+ return ep;
+}
+
+/**
+ * get_ep_head - return the first request on the endpoint
+ * @udc_ep: The endpoint to get request from.
+ *
+ * Get the first request on the endpoint.
+ */
+static struct exynos_ss_udc_req *get_ep_head(struct exynos_ss_udc_ep *udc_ep)
+{
+ if (list_empty(&udc_ep->queue))
+ return NULL;
+
+ return list_first_entry(&udc_ep->queue,
+ struct exynos_ss_udc_req,
+ queue);
+}
+
+/**
+ * on_list - check request is on the given endpoint
+ * @ep: The endpoint to check.
+ * @test: The request to test if it is on the endpoint.
+ */
+static bool on_list(struct exynos_ss_udc_ep *udc_ep,
+ struct exynos_ss_udc_req *test)
+{
+ struct exynos_ss_udc_req *udc_req, *treq;
+
+ list_for_each_entry_safe(udc_req, treq, &udc_ep->queue, queue) {
+ if (udc_req == test)
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * exynos_ss_udc_map_dma - map the DMA memory being used for the request
+ * @udc: The device state.
+ * @udc_ep: The endpoint the request is on.
+ * @req: The request being processed.
+ *
+ * We've been asked to queue a request, so ensure that the memory buffer
+ * is correctly setup for DMA. If we've been passed an extant DMA address
+ * then ensure the buffer has been synced to memory. If our buffer has no
+ * DMA memory, then we map the memory and mark our request to allow us to
+ * cleanup on completion.
+ */
+static int exynos_ss_udc_map_dma(struct exynos_ss_udc *udc,
+ struct exynos_ss_udc_ep *udc_ep,
+ struct usb_request *req)
+{
+ enum dma_data_direction dir;
+ struct exynos_ss_udc_req *udc_req = our_req(req);
+
+ dir = udc_ep->dir_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
+
+ /* if the length is zero, ignore the DMA data */
+ if (udc_req->req.length == 0)
+ return 0;
+
+ if (req->dma == DMA_ADDR_INVALID) {
+ dma_addr_t dma;
+
+ dma = dma_map_single(udc->dev,
+ req->buf, req->length, dir);
+
+ if (unlikely(dma_mapping_error(udc->dev, dma)))
+ goto dma_error;
+
+ udc_req->mapped = 1;
+ req->dma = dma;
+ } else
+ dma_sync_single_for_device(udc->dev,
+ req->dma, req->length, dir);
+
+ return 0;
+
+dma_error:
+ dev_err(udc->dev, "%s: failed to map buffer %p, %d bytes\n",
+ __func__, req->buf, req->length);
+
+ return -EIO;
+}
+
+/**
+ * exynos_ss_udc_unmap_dma - unmap the DMA memory being used for the request
+ * @udc: The device state.
+ * @udc_ep: The endpoint for the request.
+ * @udc_req: The request being processed.
+ *
+ * This is the reverse of exynos_ss_udc_map_dma(), called for the completion
+ * of a request to ensure the buffer is ready for access by the caller.
+ */
+static void exynos_ss_udc_unmap_dma(struct exynos_ss_udc *udc,
+ struct exynos_ss_udc_ep *udc_ep,
+ struct exynos_ss_udc_req *udc_req)
+{
+ struct usb_request *req = &udc_req->req;
+ enum dma_data_direction dir;
+
+ dir = udc_ep->dir_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
+
+ /* ignore this if we're not moving any data */
+ if (udc_req->req.length == 0)
+ return;
+
+ if (udc_req->mapped) {
+ /* we mapped this, so unmap and remove the dma */
+
+ dma_unmap_single(udc->dev, req->dma, req->length, dir);
+
+ req->dma = DMA_ADDR_INVALID;
+ udc_req->mapped = 0;
+ }
+}
+
+/**
+ * exynos_ss_udc_issue_epcmd - issue physical endpoint-specific command
+ * @udc: The device state.
+ * @epcmd: The command to issue.
+ */
+static int exynos_ss_udc_issue_epcmd(struct exynos_ss_udc *udc,
+ struct exynos_ss_udc_ep_command *epcmd)
+{
+ int res;
+ u32 depcmd;
+
+ /* If some of parameters are not in use, we will write it anyway
+ for simplification */
+ writel(epcmd->param0, udc->regs + EXYNOS_USB3_DEPCMDPAR0(epcmd->ep));
+ writel(epcmd->param1, udc->regs + EXYNOS_USB3_DEPCMDPAR1(epcmd->ep));
+ writel(epcmd->param2, udc->regs + EXYNOS_USB3_DEPCMDPAR2(epcmd->ep));
+
+ depcmd = epcmd->cmdtyp | epcmd->cmdflags;
+ writel(depcmd, udc->regs + EXYNOS_USB3_DEPCMD(epcmd->ep));
+
+ res = poll_bit_clear(udc->regs + EXYNOS_USB3_DEPCMD(epcmd->ep),
+ EXYNOS_USB3_DEPCMDx_CmdAct,
+ 1000);
+ return res;
+}
+
+/**
+ * exynos_ss_udc_run_stop - start/stop the device controller operation
+ * @udc: The device state.
+ * @is_on: The action to take (1 - start, 0 - stop).
+ */
+static void exynos_ss_udc_run_stop(struct exynos_ss_udc *udc, int is_on)
+{
+ int res;
+
+ if (is_on) {
+ if (readl(udc->regs + EXYNOS_USB3_DCTL)
+ & EXYNOS_USB3_DCTL_Run_Stop) {
+ __bic32(udc->regs + EXYNOS_USB3_DCTL,
+ EXYNOS_USB3_DCTL_Run_Stop);
+ res = poll_bit_set(udc->regs + EXYNOS_USB3_DSTS,
+ EXYNOS_USB3_DSTS_DevCtrlHlt,
+ 1000);
+ }
+ __orr32(udc->regs + EXYNOS_USB3_DCTL,
+ EXYNOS_USB3_DCTL_Run_Stop);
+ res = poll_bit_clear(udc->regs + EXYNOS_USB3_DSTS,
+ EXYNOS_USB3_DSTS_DevCtrlHlt,
+ 1000);
+ } else {
+ __bic32(udc->regs + EXYNOS_USB3_DCTL,
+ EXYNOS_USB3_DCTL_Run_Stop);
+ res = poll_bit_set(udc->regs + EXYNOS_USB3_DSTS,
+ EXYNOS_USB3_DSTS_DevCtrlHlt,
+ 1000);
+ }
+
+ if (res < 0)
+ dev_dbg(udc->dev, "Failed to %sconnect by software\n",
+ is_on ? "" : "dis");
+}
+
+/**
+ * exynos_ss_udc_pullup - software-controlled connect/disconnect to USB host
+ * @gadget: The peripheral being connected/disconnected.
+ * @is_on: The action to take (1 - connect, 0 - disconnect).
+ */
+static int exynos_ss_udc_pullup(struct usb_gadget *gadget, int is_on)
+{
+ struct exynos_ss_udc *udc = our_udc(gadget);
+
+ exynos_ss_udc_run_stop(udc, is_on);
+
+ return 0;
+}
+
+/**
+ * exynos_ss_udc_get_config_params - get UDC configuration
+ * @params: The controller parameters being returned to the caller.
+ */
+void exynos_ss_udc_get_config_params(struct usb_dcd_config_params *params)
+{
+ params->bU1devExitLat = EXYNOS_USB3_U1_DEV_EXIT_LAT;
+ params->bU2DevExitLat = cpu_to_le16(EXYNOS_USB3_U2_DEV_EXIT_LAT);
+}
+
+static struct usb_gadget_ops exynos_ss_udc_gadget_ops = {
+ .pullup = exynos_ss_udc_pullup,
+ .get_config_params = exynos_ss_udc_get_config_params,
+ .udc_start = exynos_ss_udc_start,
+ .udc_stop = exynos_ss_udc_stop,
+};
+
+/**
+ * exynos_ss_udc_ep_enable - configure endpoint, making it usable
+ * @ep: The endpoint being configured.
+ * @desc: The descriptor for desired behavior.
+ */
+static int exynos_ss_udc_ep_enable(struct usb_ep *ep,
+ const struct usb_endpoint_descriptor *desc)
+{
+ struct exynos_ss_udc_ep *udc_ep = our_ep(ep);
+ struct exynos_ss_udc *udc = udc_ep->parent;
+ unsigned long flags;
+ int dir_in;
+ int epnum;
+
+ dev_dbg(udc->dev,
+ "%s: ep %s: a 0x%02x, attr 0x%02x, mps 0x%04x, intr %d\n",
+ __func__, ep->name, desc->bEndpointAddress, desc->bmAttributes,
+ desc->wMaxPacketSize, desc->bInterval);
+
+ /* not to be called for EP0 */
+ WARN_ON(udc_ep->epnum == 0);
+
+ if (udc_ep->enabled)
+ return -EINVAL;
+
+ epnum = (desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+ if (epnum != udc_ep->epnum) {
+ dev_err(udc->dev, "%s: EP number mismatch!\n", __func__);
+ return -EINVAL;
+ }
+
+ dir_in = (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ? 1 : 0;
+ if (dir_in != udc_ep->dir_in) {
+ dev_err(udc->dev, "%s: EP direction mismatch!\n", __func__);
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&udc_ep->lock, flags);
+
+ /* update the endpoint state */
+ udc_ep->ep.maxpacket = le16_to_cpu(desc->wMaxPacketSize);
+ udc_ep->type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+
+ switch (udc_ep->type) {
+ case USB_ENDPOINT_XFER_ISOC:
+ dev_err(udc->dev, "no current ISOC support\n");
+ spin_unlock_irqrestore(&udc_ep->lock, flags);
+ return -EINVAL;
+
+ case USB_ENDPOINT_XFER_BULK:
+ dev_dbg(udc->dev, "Bulk endpoint\n");
+ break;
+
+ case USB_ENDPOINT_XFER_INT:
+ dev_dbg(udc->dev, "Interrupt endpoint\n");
+ break;
+
+ case USB_ENDPOINT_XFER_CONTROL:
+ dev_dbg(udc->dev, "Control endpoint\n");
+ break;
+ }
+
+ exynos_ss_udc_ep_activate(udc, udc_ep);
+ udc_ep->enabled = 1;
+ udc_ep->halted = udc_ep->wedged = 0;
+ spin_unlock_irqrestore(&udc_ep->lock, flags);
+
+ return 0;
+}
+
+/**
+ * exynos_ss_udc_ep_disable - endpoint is no longer usable
+ * @ep: The endpoint being unconfigured.
+ */
+static int exynos_ss_udc_ep_disable(struct usb_ep *ep)
+{
+ struct exynos_ss_udc_ep *udc_ep = our_ep(ep);
+ struct exynos_ss_udc *udc = udc_ep->parent;
+ unsigned long flags;
+
+ dev_dbg(udc->dev, "%s: ep%d%s\n", __func__,
+ udc_ep->epnum, udc_ep->dir_in ? "in" : "out");
+
+ spin_lock_irqsave(&udc_ep->lock, flags);
+ exynos_ss_udc_ep_deactivate(udc, udc_ep);
+ udc_ep->enabled = 0;
+ spin_unlock_irqrestore(&udc_ep->lock, flags);
+
+ /* terminate all requests with shutdown */
+ exynos_ss_udc_kill_all_requests(udc, udc_ep, -ESHUTDOWN);
+
+ return 0;
+}
+
+/**
+ * exynos_ss_udc_ep_alloc_request - allocate a request object
+ * @ep: The endpoint to be used with the request.
+ * @flags: Allocation flags.
+ *
+ * Allocate a new USB request structure appropriate for the specified endpoint.
+ */
+static struct usb_request *exynos_ss_udc_ep_alloc_request(struct usb_ep *ep,
+ gfp_t flags)
+{
+ struct exynos_ss_udc_ep *udc_ep = our_ep(ep);
+ struct exynos_ss_udc *udc = udc_ep->parent;
+ struct exynos_ss_udc_req *req;
+
+ dev_dbg(udc->dev, "%s: ep%d\n", __func__, udc_ep->epnum);
+
+ req = kzalloc(sizeof(struct exynos_ss_udc_req), flags);
+ if (!req)
+ return NULL;
+
+ INIT_LIST_HEAD(&req->queue);
+
+ req->req.dma = DMA_ADDR_INVALID;
+ return &req->req;
+}
+
+/**
+ * exynos_ss_udc_ep_free_request - free a request object
+ * @ep: The endpoint associated with the request.
+ * @req: The request being freed.
+ *
+ * Reverse the effect of exynos_ss_udc_ep_alloc_request().
+ */
+static void exynos_ss_udc_ep_free_request(struct usb_ep *ep,
+ struct usb_request *req)
+{
+ struct exynos_ss_udc_ep *udc_ep = our_ep(ep);
+ struct exynos_ss_udc *udc = udc_ep->parent;
+ struct exynos_ss_udc_req *udc_req = our_req(req);
+
+ dev_dbg(udc->dev, "%s: ep%d, req %p\n", __func__, udc_ep->epnum, req);
+
+ kfree(udc_req);
+}
+
+/**
+ * exynos_ss_udc_ep_queue - queue (submit) an I/O request to an endpoint
+ * @ep: The endpoint associated with the request.
+ * @req: The request being submitted.
+ * @gfp_flags: Not used.
+ *
+ * Queue a request and start it if the first.
+ */
+static int exynos_ss_udc_ep_queue(struct usb_ep *ep,
+ struct usb_request *req,
+ gfp_t gfp_flags)
+{
+ struct exynos_ss_udc_req *udc_req = our_req(req);
+ struct exynos_ss_udc_ep *udc_ep = our_ep(ep);
+ struct exynos_ss_udc *udc = udc_ep->parent;
+ unsigned long irqflags;
+ bool first;
+ int ret;
+
+ dev_dbg(udc->dev, "%s: ep%d%s (%p): %d@%p, noi=%d, zero=%d, snok=%d\n",
+ __func__, udc_ep->epnum,
+ udc_ep->dir_in ? "in" : "out", req,
+ req->length, req->buf, req->no_interrupt,
+ req->zero, req->short_not_ok);
+
+ /* initialise status of the request */
+ INIT_LIST_HEAD(&udc_req->queue);
+
+ req->actual = 0;
+ req->status = -EINPROGRESS;
+
+ /* Sync the buffers as necessary */
+ if (req->buf == udc->ctrl_buff)
+ req->dma = udc->ctrl_buff_dma;
+ else if (req->buf == udc->ep0_buff)
+ req->dma = udc->ep0_buff_dma;
+ else {
+ ret = exynos_ss_udc_map_dma(udc, udc_ep, req);
+ if (ret)
+ return ret;
+ }
+
+ spin_lock_irqsave(&udc_ep->lock, irqflags);
+
+ first = list_empty(&udc_ep->queue);
+ list_add_tail(&udc_req->queue, &udc_ep->queue);
+
+ if (first && !udc_ep->not_ready)
+ exynos_ss_udc_start_req(udc, udc_ep, udc_req, false);
+
+ spin_unlock_irqrestore(&udc_ep->lock, irqflags);
+
+ return 0;
+}
+
+/**
+ * exynos_ss_udc_ep_dequeue - dequeue an I/O request from an endpoint
+ * @ep: The endpoint associated with the request.
+ * @req: The request being canceled.
+ *
+ * Dequeue a request and call its completion routine.
+ */
+static int exynos_ss_udc_ep_dequeue(struct usb_ep *ep, struct usb_request *req)
+{
+ struct exynos_ss_udc_req *udc_req = our_req(req);
+ struct exynos_ss_udc_ep *udc_ep = our_ep(ep);
+ struct exynos_ss_udc *udc = udc_ep->parent;
+ unsigned long flags;
+
+ dev_dbg(udc->dev, "%s: ep%d%s (%p)\n", __func__,
+ udc_ep->epnum, udc_ep->dir_in ? "in" : "out", req);
+
+ spin_lock_irqsave(&udc_ep->lock, flags);
+
+ if (!on_list(udc_ep, udc_req)) {
+ spin_unlock_irqrestore(&udc_ep->lock, flags);
+ return -EINVAL;
+ }
+
+ exynos_ss_udc_complete_request(udc, udc_ep, udc_req, -ECONNRESET);
+ spin_unlock_irqrestore(&udc_ep->lock, flags);
+
+ return 0;
+}
+
+/**
+ * exynos_ss_udc_ep_sethalt - set/clear the endpoint halt feature
+ * @ep: The endpoint being stalled/reset.
+ * @value: The action to take (1 - set stall, 0 - clear stall).
+ */
+static int exynos_ss_udc_ep_sethalt(struct usb_ep *ep, int value)
+{
+ struct exynos_ss_udc_ep *udc_ep = our_ep(ep);
+ struct exynos_ss_udc *udc = udc_ep->parent;
+ struct exynos_ss_udc_ep_command epcmd;
+ int index = get_phys_epnum(udc_ep);
+ unsigned long irqflags;
+ int res;
+
+ dev_dbg(udc->dev, "%s(ep %p %s, %d)\n", __func__, ep, ep->name, value);
+
+ spin_lock_irqsave(&udc_ep->lock, irqflags);
+
+ if (value && udc_ep->dir_in && udc_ep->req) {
+ dev_dbg(udc->dev, "%s: transfer in progress!\n", __func__);
+ spin_unlock_irqrestore(&udc_ep->lock, irqflags);
+ return -EAGAIN;
+ }
+
+ if (udc_ep->epnum == 0)
+ /* Only OUT direction can be stalled */
+ epcmd.ep = 0;
+ else
+ epcmd.ep = index;
+
+ if (value)
+ epcmd.cmdtyp = EXYNOS_USB3_DEPCMDx_CmdTyp_DEPSSTALL;
+ else
+ epcmd.cmdtyp = EXYNOS_USB3_DEPCMDx_CmdTyp_DEPCSTALL;
+
+ epcmd.cmdflags = EXYNOS_USB3_DEPCMDx_CmdAct;
+
+ res = exynos_ss_udc_issue_epcmd(udc, &epcmd);
+ if (res < 0) {
+ dev_err(udc->dev, "Failed to set/clear stall\n");
+ spin_unlock_irqrestore(&udc_ep->lock, irqflags);
+ return res;
+ }
+
+ if (udc_ep->epnum == 0)
+ udc->ep0_state = EP0_STALL;
+
+ /* If everything is Ok, we mark endpoint as halted */
+ if (value)
+ udc_ep->halted = 1;
+ else
+ udc_ep->halted = udc_ep->wedged = 0;
+
+ spin_unlock_irqrestore(&udc_ep->lock, irqflags);
+
+ return 0;
+}
+
+/**
+ * exynos_ss_udc_ep_setwedge - set the halt feature and ignore clear requests
+ * @ep: The endpoint being wedged.
+ */
+static int exynos_ss_udc_ep_setwedge(struct usb_ep *ep)
+{
+ struct exynos_ss_udc_ep *udc_ep = our_ep(ep);
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&udc_ep->lock, irqflags);
+ udc_ep->wedged = 1;
+ spin_unlock_irqrestore(&udc_ep->lock, irqflags);
+
+ return exynos_ss_udc_ep_sethalt(ep, 1);
+}
+
+static struct usb_ep_ops exynos_ss_udc_ep_ops = {
+ .enable = exynos_ss_udc_ep_enable,
+ .disable = exynos_ss_udc_ep_disable,
+ .alloc_request = exynos_ss_udc_ep_alloc_request,
+ .free_request = exynos_ss_udc_ep_free_request,
+ .queue = exynos_ss_udc_ep_queue,
+ .dequeue = exynos_ss_udc_ep_dequeue,
+ .set_halt = exynos_ss_udc_ep_sethalt,
+ .set_wedge = exynos_ss_udc_ep_setwedge,
+};
+
+/**
+ * exynos_ss_udc_start_req - start a USB request from an endpoint's queue
+ * @udc: The device state.
+ * @udc_ep: The endpoint to process a request for.
+ * @udc_req: The request being started.
+ * @continuing: True if we are doing more for the current request.
+ *
+ * Start the given request running by setting the TRB appropriately,
+ * and issuing Start Transfer endpoint command.
+ */
+static void exynos_ss_udc_start_req(struct exynos_ss_udc *udc,
+ struct exynos_ss_udc_ep *udc_ep,
+ struct exynos_ss_udc_req *udc_req,
+ bool continuing)
+{
+ struct exynos_ss_udc_ep_command epcmd;
+ struct usb_request *ureq = &udc_req->req;
+ enum trb_control trb_type = NORMAL;
+ int epnum = udc_ep->epnum;
+ int xfer_length;
+ int res;
+
+ dev_dbg(udc->dev, "%s: ep%d%s, req %p\n", __func__, epnum,
+ udc_ep->dir_in ? "in" : "out", ureq);
+
+ /* If endpoint is stalled, we will restart request later */
+ if (udc_ep->halted) {
+ dev_dbg(udc->dev, "%s: ep%d is stalled\n", __func__, epnum);
+ return;
+ }
+
+ udc_ep->req = udc_req;
+
+ /* Get type of TRB */
+ if (epnum == 0 && !continuing)
+ switch (udc->ep0_state) {
+ case EP0_SETUP_PHASE:
+ trb_type = CONTROL_SETUP;
+ break;
+
+ case EP0_DATA_PHASE:
+ trb_type = CONTROL_DATA;
+ break;
+
+ case EP0_STATUS_PHASE_2:
+ trb_type = CONTROL_STATUS_2;
+ break;
+
+ case EP0_STATUS_PHASE_3:
+ trb_type = CONTROL_STATUS_3;
+ break;
+ default:
+ dev_warn(udc->dev, "%s: Erroneous EP0 state (%d)",
+ __func__, udc->ep0_state);
+ return;
+ break;
+ }
+ else
+ trb_type = NORMAL;
+
+ /* Get transfer length */
+ if (udc_ep->dir_in)
+ xfer_length = ureq->length;
+ else
+ xfer_length = (ureq->length + udc_ep->ep.maxpacket - 1) &
+ ~(udc_ep->ep.maxpacket - 1);
+
+ /* Fill TRB */
+ udc_ep->trb->buff_ptr_low = (u32) ureq->dma;
+ udc_ep->trb->buff_ptr_high = 0;
+ udc_ep->trb->param1 = EXYNOS_USB3_TRB_BUFSIZ(xfer_length);
+ udc_ep->trb->param2 = EXYNOS_USB3_TRB_IOC |
+ EXYNOS_USB3_TRB_LST |
+ EXYNOS_USB3_TRB_HWO |
+ EXYNOS_USB3_TRB_TRBCTL(trb_type);
+
+ /* Start Transfer */
+ epcmd.ep = get_phys_epnum(udc_ep);
+ epcmd.param0 = 0;
+ epcmd.param1 = udc_ep->trb_dma;
+ epcmd.cmdtyp = EXYNOS_USB3_DEPCMDx_CmdTyp_DEPSTRTXFER;
+ epcmd.cmdflags = EXYNOS_USB3_DEPCMDx_CmdAct;
+
+ res = exynos_ss_udc_issue_epcmd(udc, &epcmd);
+ if (res < 0)
+ dev_err(udc->dev, "Failed to start transfer\n");
+
+ udc_ep->tri = (readl(udc->regs + EXYNOS_USB3_DEPCMD(epcmd.ep)) >>
+ EXYNOS_USB3_DEPCMDx_EventParam_SHIFT) &
+ EXYNOS_USB3_DEPCMDx_XferRscIdx_LIMIT;
+}
+
+/**
+ * exynos_ss_udc_enqueue_status - start a request for EP0 status stage
+ * @udc: The device state.
+ */
+static void exynos_ss_udc_enqueue_status(struct exynos_ss_udc *udc)
+{
+ struct usb_request *req = udc->ctrl_req;
+ struct exynos_ss_udc_req *udc_req = our_req(req);
+ int ret;
+
+ dev_dbg(udc->dev, "%s: queueing status request\n", __func__);
+
+ req->zero = 0;
+ req->length = 0;
+ req->buf = udc->ctrl_buff;
+ req->complete = NULL;
+
+ if (!list_empty(&udc_req->queue)) {
+ dev_info(udc->dev, "%s already queued???\n", __func__);
+ return;
+ }
+
+ ret = exynos_ss_udc_ep_queue(&udc->eps[0].ep, req, GFP_ATOMIC);
+ if (ret < 0)
+ dev_err(udc->dev, "%s: failed queue (%d)\n", __func__, ret);
+}
+
+/**
+ * exynos_ss_udc_enqueue_data - start a request for EP0 data stage
+ * @udc: The device state.
+ * @buff: The buffer used for data.
+ * @length: The length of data.
+ * @complete: The function called when request completes.
+ */
+static int exynos_ss_udc_enqueue_data(struct exynos_ss_udc *udc,
+ void *buff, int length,
+ void (*complete) (struct usb_ep *ep,
+ struct usb_request *req))
+{
+ struct usb_request *req = udc->ctrl_req;
+ struct exynos_ss_udc_req *udc_req = our_req(req);
+ int ret;
+
+ dev_dbg(udc->dev, "%s: queueing data request\n", __func__);
+
+ req->zero = 0;
+ req->length = length;
+
+ if (buff == NULL)
+ req->buf = udc->ep0_buff;
+ else
+ req->buf = buff;
+
+ req->complete = complete;
+
+ if (!list_empty(&udc_req->queue)) {
+ dev_info(udc->dev, "%s: already queued???\n", __func__);
+ return -EAGAIN;
+ }
+
+ ret = exynos_ss_udc_ep_queue(&udc->eps[0].ep, req, GFP_ATOMIC);
+ if (ret < 0) {
+ dev_err(udc->dev, "%s: failed to enqueue data request (%d)\n",
+ __func__, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * exynos_ss_udc_enqueue_setup - start a request for EP0 setup stage
+ * @udc: The device state.
+ *
+ * Enqueue a request on EP0 if necessary to receive any SETUP packets
+ * from the host.
+ */
+static void exynos_ss_udc_enqueue_setup(struct exynos_ss_udc *udc)
+{
+ struct usb_request *req = udc->ctrl_req;
+ struct exynos_ss_udc_req *udc_req = our_req(req);
+ int ret;
+
+ dev_dbg(udc->dev, "%s: queueing setup request\n", __func__);
+
+ req->zero = 0;
+ req->length = EXYNOS_USB3_CTRL_BUFF_SIZE;
+ req->buf = udc->ctrl_buff;
+ req->complete = exynos_ss_udc_complete_setup;
+
+ if (!list_empty(&udc_req->queue)) {
+ dev_dbg(udc->dev, "%s already queued???\n", __func__);
+ return;
+ }
+
+ udc->eps[0].dir_in = 0;
+
+ ret = exynos_ss_udc_ep_queue(&udc->eps[0].ep, req, GFP_ATOMIC);
+ if (ret < 0)
+ dev_err(udc->dev, "%s: failed queue (%d)\n", __func__, ret);
+}
+
+/**
+ * exynos_ss_udc_complete_set_sel - completion of SET_SEL request data stage
+ * @ep: The endpoint the request was on.
+ * @req: The request completed.
+ */
+static void exynos_ss_udc_complete_set_sel(struct usb_ep *ep,
+ struct usb_request *req)
+{
+ struct exynos_ss_udc_ep *udc_ep = our_ep(ep);
+ struct exynos_ss_udc *udc = udc_ep->parent;
+ u8 *sel = req->buf;
+ u32 param;
+ u32 dgcmd;
+ int res;
+
+ /* Our device is U1/U2 enabled, so we will use U2PEL */
+ param = sel[5] << 8 | sel[4];
+ /* Documentation says "If the value is greater than 125us, then
+ * software must program a value of zero into this register */
+ if (param > 125)
+ param = 0;
+
+ dev_dbg(udc->dev, "%s: dgcmd_param = 0x%08x\n", __func__, param);
+
+ dgcmd = EXYNOS_USB3_DGCMD_CmdAct |
+ EXYNOS_USB3_DGCMD_CmdTyp_SetPerParams;
+
+ writel(param, udc->regs + EXYNOS_USB3_DGCMDPAR);
+ writel(dgcmd, udc->regs + EXYNOS_USB3_DGCMD);
+ res = poll_bit_clear(udc->regs + EXYNOS_USB3_DGCMD,
+ EXYNOS_USB3_DGCMD_CmdAct,
+ 1000);
+ if (res < 0)
+ dev_err(udc->dev, "Failed to set periodic parameters\n");
+}
+
+/**
+ * exynos_ss_udc_process_set_sel - process request SET_SEL
+ * @udc: The device state.
+ */
+static int exynos_ss_udc_process_set_sel(struct exynos_ss_udc *udc)
+{
+ int ret;
+
+ dev_dbg(udc->dev, "%s\n", __func__);
+
+ ret = exynos_ss_udc_enqueue_data(udc, udc->ep0_buff,
+ EXYNOS_USB3_EP0_BUFF_SIZE,
+ exynos_ss_udc_complete_set_sel);
+ if (ret < 0) {
+ dev_err(udc->dev, "%s: failed to become ready for SEL data\n",
+ __func__);
+ return ret;
+ }
+
+ return 1;
+}
+
+/**
+ * exynos_ss_udc_process_clr_feature - process request CLEAR_FEATURE
+ * @udc: The device state.
+ * @ctrl: The USB control request.
+ */
+static int exynos_ss_udc_process_clr_feature(struct exynos_ss_udc *udc,
+ struct usb_ctrlrequest *ctrl)
+{
+ struct exynos_ss_udc_ep *udc_ep;
+ struct exynos_ss_udc_req *udc_req;
+ bool restart;
+
+ dev_dbg(udc->dev, "%s\n", __func__);
+
+ switch (ctrl->bRequestType & USB_RECIP_MASK) {
+ case USB_RECIP_DEVICE:
+ switch (le16_to_cpu(ctrl->wValue)) {
+ case USB_DEVICE_U1_ENABLE:
+ __bic32(udc->regs + EXYNOS_USB3_DCTL,
+ EXYNOS_USB3_DCTL_InitU1Ena);
+ break;
+
+ case USB_DEVICE_U2_ENABLE:
+ __bic32(udc->regs + EXYNOS_USB3_DCTL,
+ EXYNOS_USB3_DCTL_InitU2Ena);
+ break;
+
+ default:
+ return -ENOENT;
+ }
+ break;
+
+ case USB_RECIP_ENDPOINT:
+ udc_ep = ep_from_windex(udc, le16_to_cpu(ctrl->wIndex));
+ if (!udc_ep) {
+ dev_dbg(udc->dev, "%s: no endpoint for 0x%04x\n",
+ __func__, le16_to_cpu(ctrl->wIndex));
+ return -ENOENT;
+ }
+
+ switch (le16_to_cpu(ctrl->wValue)) {
+ case USB_ENDPOINT_HALT:
+ if (!udc_ep->wedged) {
+ exynos_ss_udc_ep_sethalt(&udc_ep->ep, 0);
+
+ /* If we have pending request, then start it */
+ restart = !list_empty(&udc_ep->queue);
+ if (restart) {
+ udc_req = get_ep_head(udc_ep);
+ exynos_ss_udc_start_req(udc, udc_ep,
+ udc_req, false);
+ }
+ }
+ break;
+
+ default:
+ return -ENOENT;
+ }
+
+ break;
+
+ default:
+ return -ENOENT;
+ }
+
+ return 1;
+}
+
+/**
+ * exynos_ss_udc_process_set_feature - process request SET_FEATURE
+ * @udc: The device state.
+ * @ctrl: The USB control request.
+ */
+static int exynos_ss_udc_process_set_feature(struct exynos_ss_udc *udc,
+ struct usb_ctrlrequest *ctrl)
+{
+ struct exynos_ss_udc_ep *udc_ep;
+
+ dev_dbg(udc->dev, "%s\n", __func__);
+
+ switch (ctrl->bRequestType & USB_RECIP_MASK) {
+ case USB_RECIP_DEVICE:
+ switch (le16_to_cpu(ctrl->wValue)) {
+ case USB_DEVICE_U1_ENABLE:
+ /* Temporarily disabled because of HW bug */
+#if 0
+ __orr32(udc->regs + EXYNOS_USB3_DCTL,
+ EXYNOS_USB3_DCTL_InitU1Ena);
+#endif
+ break;
+
+ case USB_DEVICE_U2_ENABLE:
+ /* Temporarily disabled because of HW bug */
+#if 0
+ __orr32(udc->regs + EXYNOS_USB3_DCTL,
+ EXYNOS_USB3_DCTL_InitU2Ena);
+#endif
+ break;
+
+ default:
+ return -ENOENT;
+ }
+ break;
+
+ case USB_RECIP_ENDPOINT:
+ udc_ep = ep_from_windex(udc, le16_to_cpu(ctrl->wIndex));
+ if (!udc_ep) {
+ dev_dbg(udc->dev, "%s: no endpoint for 0x%04x\n",
+ __func__, le16_to_cpu(ctrl->wIndex));
+ return -ENOENT;
+ }
+
+ switch (le16_to_cpu(ctrl->wValue)) {
+ case USB_ENDPOINT_HALT:
+ exynos_ss_udc_ep_sethalt(&udc_ep->ep, 1);
+ break;
+
+ default:
+ return -ENOENT;
+ }
+
+ break;
+
+ default:
+ return -ENOENT;
+ }
+
+ return 1;
+}
+
+/**
+ * exynos_ss_udc_process_get_status - process request GET_STATUS
+ * @udc: The device state.
+ * @ctrl: The USB control request.
+ */
+static int exynos_ss_udc_process_get_status(struct exynos_ss_udc *udc,
+ struct usb_ctrlrequest *ctrl)
+{
+ struct exynos_ss_udc_ep *udc_ep0 = &udc->eps[0];
+ struct exynos_ss_udc_ep *udc_ep;
+ u8 *reply = udc->ep0_buff;
+ u32 reg;
+ int ret;
+
+ dev_dbg(udc->dev, "%s: USB_REQ_GET_STATUS\n", __func__);
+
+ if (!udc_ep0->dir_in) {
+ dev_warn(udc->dev, "%s: direction out?\n", __func__);
+ return -EINVAL;
+ }
+
+ if (le16_to_cpu(ctrl->wLength) != 2)
+ return -EINVAL;
+
+ switch (ctrl->bRequestType & USB_RECIP_MASK) {
+ case USB_RECIP_DEVICE:
+ *reply = 1;
+ if (udc->gadget.speed == USB_SPEED_SUPER) {
+ reg = readl(udc->regs + EXYNOS_USB3_DCTL);
+
+ if (reg & EXYNOS_USB3_DCTL_InitU1Ena)
+ *reply |= 1 << 2;
+
+ if (reg & EXYNOS_USB3_DCTL_InitU2Ena)
+ *reply |= 1 << 3;
+ }
+ *(reply + 1) = 0;
+ break;
+
+ case USB_RECIP_INTERFACE:
+ /* currently, the data result should be zero */
+ *reply = 0;
+ *(reply + 1) = 0;
+ break;
+
+ case USB_RECIP_ENDPOINT:
+ udc_ep = ep_from_windex(udc, le16_to_cpu(ctrl->wIndex));
+ if (!udc_ep)
+ return -ENOENT;
+
+ *reply = udc_ep->halted ? 1 : 0;
+ *(reply + 1) = 0;
+ break;
+
+ default:
+ return 0;
+ }
+
+ ret = exynos_ss_udc_enqueue_data(udc, reply, 2, NULL);
+ if (ret) {
+ dev_err(udc->dev, "%s: failed to send reply\n", __func__);
+ return ret;
+ }
+
+ return 1;
+}
+
+/**
+ * exynos_ss_udc_process_control - process a control request
+ * @udc: The device state.
+ * @ctrl: The control request received.
+ *
+ * The controller has received the SETUP phase of a control request, and
+ * needs to work out what to do next (and whether to pass it on to the
+ * gadget driver).
+ */
+static void exynos_ss_udc_process_control(struct exynos_ss_udc *udc,
+ struct usb_ctrlrequest *ctrl)
+{
+ struct exynos_ss_udc_ep *ep0 = &udc->eps[0];
+ int ret = 0;
+
+ dev_dbg(udc->dev, "ctrl Req=%02x, Type=%02x, V=%04x, L=%04x\n",
+ ctrl->bRequest, ctrl->bRequestType,
+ ctrl->wValue, ctrl->wLength);
+
+ /* record the direction of the request, for later use when enquing
+ * packets onto EP0. */
+
+ ep0->dir_in = (ctrl->bRequestType & USB_DIR_IN) ? 1 : 0;
+ dev_dbg(udc->dev, "ctrl: dir_in=%d\n", ep0->dir_in);
+
+ /* if we've no data with this request, then the last part of the
+ * transaction is going to implicitly be IN. */
+ if (ctrl->wLength == 0) {
+ ep0->dir_in = 1;
+ udc->ep0_three_stage = 0;
+ udc->ep0_state = EP0_STATUS_PHASE_2;
+ } else
+ udc->ep0_three_stage = 1;
+
+ if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
+ switch (ctrl->bRequest) {
+ case USB_REQ_SET_ADDRESS:
+ __bic32(udc->regs + EXYNOS_USB3_DCFG,
+ EXYNOS_USB3_DCFG_DevAddr_MASK);
+ __orr32(udc->regs + EXYNOS_USB3_DCFG,
+ EXYNOS_USB3_DCFG_DevAddr(ctrl->wValue));
+
+ dev_dbg(udc->dev, "new address %d\n", ctrl->wValue);
+
+ udc->ep0_state = EP0_WAIT_NRDY;
+ return;
+
+ case USB_REQ_GET_STATUS:
+ ret = exynos_ss_udc_process_get_status(udc, ctrl);
+ break;
+
+ case USB_REQ_CLEAR_FEATURE:
+ ret = exynos_ss_udc_process_clr_feature(udc, ctrl);
+ udc->ep0_state = EP0_WAIT_NRDY;
+ break;
+
+ case USB_REQ_SET_FEATURE:
+ ret = exynos_ss_udc_process_set_feature(udc, ctrl);
+ udc->ep0_state = EP0_WAIT_NRDY;
+ break;
+
+ case USB_REQ_SET_SEL:
+ ret = exynos_ss_udc_process_set_sel(udc);
+ break;
+ }
+ }
+
+ /* as a fallback, try delivering it to the driver to deal with */
+
+ if (ret == 0 && udc->driver) {
+ ret = udc->driver->setup(&udc->gadget, ctrl);
+ if (ret < 0)
+ dev_dbg(udc->dev, "driver->setup() ret %d\n", ret);
+ }
+
+ /* the request is either unhandlable, or is not formatted correctly
+ * so respond with a STALL for the status stage to indicate failure.
+ */
+
+ if (ret < 0) {
+ struct exynos_ss_udc_ep_command epcmd;
+ int res;
+
+ dev_dbg(udc->dev, "ep0 stall (dir=%d)\n", ep0->dir_in);
+ epcmd.ep = 0;
+ epcmd.cmdtyp = EXYNOS_USB3_DEPCMDx_CmdTyp_DEPSSTALL;
+ epcmd.cmdflags = EXYNOS_USB3_DEPCMDx_CmdAct;
+
+ res = exynos_ss_udc_issue_epcmd(udc, &epcmd);
+ if (res < 0)
+ dev_err(udc->dev, "Failed to set/clear stall\n");
+
+ udc->ep0_state = EP0_SETUP_PHASE;
+ exynos_ss_udc_enqueue_setup(udc);
+ }
+}
+
+/**
+ * exynos_ss_udc_complete_setup - completion of a setup transfer
+ * @ep: The endpoint the request was on.
+ * @req: The request completed.
+ *
+ * Called on completion of any requests the driver itself submitted for
+ * EP0 setup packets.
+ */
+static void exynos_ss_udc_complete_setup(struct usb_ep *ep,
+ struct usb_request *req)
+{
+ struct exynos_ss_udc_ep *udc_ep = our_ep(ep);
+ struct exynos_ss_udc *udc = udc_ep->parent;
+
+ if (req->status < 0) {
+ dev_dbg(udc->dev, "%s: failed %d\n", __func__, req->status);
+ return;
+ }
+
+ exynos_ss_udc_process_control(udc, req->buf);
+}
+
+/**
+ * exynos_ss_udc_kill_all_requests - remove all requests from the endpoint's queue
+ * @udc: The device state.
+ * @ep: The endpoint the requests may be on.
+ * @result: The result code to use.
+ *
+ * Go through the requests on the given endpoint and mark them
+ * completed with the given result code.
+ */
+static void exynos_ss_udc_kill_all_requests(struct exynos_ss_udc *udc,
+ struct exynos_ss_udc_ep *udc_ep,
+ int result)
+{
+ struct exynos_ss_udc_req *udc_req, *treq;
+ unsigned long flags;
+
+ dev_dbg(udc->dev, "%s: ep%d\n", __func__, udc_ep->epnum);
+
+ spin_lock_irqsave(&udc_ep->lock, flags);
+
+ list_for_each_entry_safe(udc_req, treq, &udc_ep->queue, queue) {
+
+ exynos_ss_udc_complete_request(udc, udc_ep, udc_req, result);
+ }
+
+ spin_unlock_irqrestore(&udc_ep->lock, flags);
+}
+
+/**
+ * exynos_ss_udc_complete_request - complete a request given to us
+ * @udc: The device state.
+ * @udc_ep: The endpoint the request was on.
+ * @udc_req: The request being completed.
+ * @result: The result code (0 => Ok, otherwise errno)
+ *
+ * The given request has finished, so call the necessary completion
+ * if it has one and then look to see if we can start a new request
+ * on the endpoint.
+ *
+ * Note, expects the ep to already be locked as appropriate.
+ */
+static void exynos_ss_udc_complete_request(struct exynos_ss_udc *udc,
+ struct exynos_ss_udc_ep *udc_ep,
+ struct exynos_ss_udc_req *udc_req,
+ int result)
+{
+ bool restart;
+
+ if (!udc_req) {
+ dev_dbg(udc->dev, "%s: nothing to complete\n", __func__);
+ return;
+ }
+
+ dev_dbg(udc->dev, "complete: ep %p %s, req %p, %d => %p\n",
+ udc_ep, udc_ep->ep.name, udc_req,
+ result, udc_req->req.complete);
+
+ /* only replace the status if we've not already set an error
+ * from a previous transaction */
+
+ if (udc_req->req.status == -EINPROGRESS)
+ udc_req->req.status = result;
+
+ udc_ep->req = NULL;
+ udc_ep->tri = 0;
+ list_del_init(&udc_req->queue);
+
+ if (udc_req->req.buf != udc->ctrl_buff &&
+ udc_req->req.buf != udc->ep0_buff)
+ exynos_ss_udc_unmap_dma(udc, udc_ep, udc_req);
+
+ if (udc_ep->epnum == 0) {
+ switch (udc->ep0_state) {
+ case EP0_SETUP_PHASE:
+ udc->ep0_state = EP0_DATA_PHASE;
+ break;
+ case EP0_DATA_PHASE:
+ udc->ep0_state = EP0_WAIT_NRDY;
+ break;
+ case EP0_STATUS_PHASE_2:
+ case EP0_STATUS_PHASE_3:
+ udc->ep0_state = EP0_SETUP_PHASE;
+ break;
+ default:
+ dev_err(udc->dev, "%s: Erroneous EP0 state (%d)",
+ __func__, udc->ep0_state);
+ /* Will try to repair from it */
+ udc->ep0_state = EP0_SETUP_PHASE;
+ return;
+ break;
+ }
+ }
+
+ /* call the complete request with the locks off, just in case the
+ * request tries to queue more work for this endpoint. */
+
+ if (udc_req->req.complete) {
+ spin_unlock(&udc_ep->lock);
+ udc_req->req.complete(&udc_ep->ep, &udc_req->req);
+ spin_lock(&udc_ep->lock);
+ }
+
+ /* Look to see if there is anything else to do. Note, the completion
+ * of the previous request may have caused a new request to be started
+ * so be careful when doing this. */
+
+ if (!udc_ep->req && result >= 0) {
+ restart = !list_empty(&udc_ep->queue);
+ if (restart) {
+ udc_req = get_ep_head(udc_ep);
+ exynos_ss_udc_start_req(udc, udc_ep, udc_req, false);
+ }
+ }
+}
+
+/**
+ * exynos_ss_udc_complete_request_lock - complete a request given to us (locked)
+ * @udc: The device state.
+ * @udc_ep: The endpoint the request was on.
+ * @udc_req: The request being completed.
+ * @result: The result code (0 => Ok, otherwise errno).
+ *
+ * See exynos_ss_udc_complete_request(), but called with the endpoint's
+ * lock held.
+ */
+static void exynos_ss_udc_complete_request_lock(struct exynos_ss_udc *udc,
+ struct exynos_ss_udc_ep *udc_ep,
+ struct exynos_ss_udc_req *udc_req,
+ int result)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&udc_ep->lock, flags);
+ exynos_ss_udc_complete_request(udc, udc_ep, udc_req, result);
+ spin_unlock_irqrestore(&udc_ep->lock, flags);
+}
+
+/**
+ * exynos_ss_udc_complete_in - complete IN transfer
+ * @udc: The device state.
+ * @udc_ep: The endpoint that has just completed.
+ *
+ * An IN transfer has been completed, update the transfer's state and then
+ * call the relevant completion routines.
+ */
+static void exynos_ss_udc_complete_in(struct exynos_ss_udc *udc,
+ struct exynos_ss_udc_ep *udc_ep)
+{
+ struct exynos_ss_udc_req *udc_req = udc_ep->req;
+ struct usb_request *req = &udc_req->req;
+ int size_left;
+
+ dev_dbg(udc->dev, "%s: ep%d, req %p\n", __func__, udc_ep->epnum, req);
+
+ if (!udc_req) {
+ dev_dbg(udc->dev, "XferCompl but no req\n");
+ return;
+ }
+
+ if (udc_ep->trb->param2 & EXYNOS_USB3_TRB_HWO) {
+ dev_dbg(udc->dev, "%s: HWO bit set!\n", __func__);
+ return;
+ }
+
+ size_left = udc_ep->trb->param1 & EXYNOS_USB3_TRB_BUFSIZ_MASK;
+ udc_req->req.actual = udc_req->req.length - size_left;
+
+ if (size_left)
+ dev_dbg(udc->dev, "%s: BUFSIZ is not zero (%d)",
+ __func__, size_left);
+
+ exynos_ss_udc_complete_request_lock(udc, udc_ep, udc_req, 0);
+}
+
+
+/**
+ * exynos_ss_udc_complete_out - complete OUT transfer
+ * @udc: The device state.
+ * @epnum: The endpoint that has just completed.
+ *
+ * An OUT transfer has been completed, update the transfer's state and then
+ * call the relevant completion routines.
+ */
+static void exynos_ss_udc_complete_out(struct exynos_ss_udc *udc,
+ struct exynos_ss_udc_ep *udc_ep)
+{
+ struct exynos_ss_udc_req *udc_req = udc_ep->req;
+ struct usb_request *req = &udc_req->req;
+ int len, size_left;
+
+ dev_dbg(udc->dev, "%s: ep%d, req %p\n", __func__, udc_ep->epnum, req);
+
+ if (!udc_req) {
+ dev_dbg(udc->dev, "%s: no request active\n", __func__);
+ return;
+ }
+
+ if (udc_ep->trb->param2 & EXYNOS_USB3_TRB_HWO) {
+ dev_dbg(udc->dev, "%s: HWO bit set!\n", __func__);
+ return;
+ }
+
+ size_left = udc_ep->trb->param1 & EXYNOS_USB3_TRB_BUFSIZ_MASK;
+ len = (req->length + udc_ep->ep.maxpacket - 1) &
+ ~(udc_ep->ep.maxpacket - 1);
+ udc_req->req.actual = len - size_left;
+
+ if (size_left)
+ dev_dbg(udc->dev, "%s: BUFSIZ is not zero (%d)",
+ __func__, size_left);
+
+ exynos_ss_udc_complete_request_lock(udc, udc_ep, udc_req, 0);
+}
+
+/**
+ * exynos_ss_udc_irq_connectdone - process event Connection Done
+ * @udc: The device state.
+ *
+ * Get the speed of connection and configure physical endpoints 0 & 1.
+ */
+static void exynos_ss_udc_irq_connectdone(struct exynos_ss_udc *udc)
+{
+ struct exynos_ss_udc_ep_command epcmd;
+ u32 reg, speed;
+ int mps0, mps;
+ int i;
+ int res;
+
+ dev_dbg(udc->dev, "%s\n", __func__);
+
+ reg = readl(udc->regs + EXYNOS_USB3_DSTS);
+ speed = reg & EXYNOS_USB3_DSTS_ConnectSpd_MASK;
+
+ /* Suspend the inactive Phy */
+ if (speed == USB_SPEED_SUPER)
+ __orr32(udc->regs + EXYNOS_USB3_GUSB2PHYCFG(0),
+ EXYNOS_USB3_GUSB2PHYCFGx_SusPHY);
+ else
+ __orr32(udc->regs + EXYNOS_USB3_GUSB3PIPECTL(0),
+ EXYNOS_USB3_GUSB3PIPECTLx_SuspSSPhy);
+
+ switch (speed) {
+ /* High-speed */
+ case 0:
+ udc->gadget.speed = USB_SPEED_HIGH;
+ mps0 = EP0_HS_MPS;
+ mps = EP_HS_MPS;
+ break;
+ /* Full-speed */
+ case 1:
+ case 3:
+ udc->gadget.speed = USB_SPEED_FULL;
+ mps0 = EP0_FS_MPS;
+ mps = EP_FS_MPS;
+ break;
+ /* Low-speed */
+ case 2:
+ udc->gadget.speed = USB_SPEED_LOW;
+ mps0 = EP0_LS_MPS;
+ mps = EP_LS_MPS;
+ break;
+ /* SuperSpeed */
+ case 4:
+ udc->gadget.speed = USB_SPEED_SUPER;
+ mps0 = EP0_SS_MPS;
+ mps = EP_SS_MPS;
+ break;
+ }
+
+ udc->eps[0].ep.maxpacket = mps0;
+ for (i = 1; i < EXYNOS_USB3_EPS; i++)
+ udc->eps[i].ep.maxpacket = mps;
+
+ epcmd.ep = 0;
+ epcmd.param0 = EXYNOS_USB3_DEPCMDPAR0x_MPS(mps0);
+ epcmd.param1 = EXYNOS_USB3_DEPCMDPAR1x_XferNRdyEn |
+ EXYNOS_USB3_DEPCMDPAR1x_XferCmplEn;
+ epcmd.cmdtyp = EXYNOS_USB3_DEPCMDx_CmdTyp_DEPCFG;
+ epcmd.cmdflags = EXYNOS_USB3_DEPCMDx_CmdAct;
+
+ res = exynos_ss_udc_issue_epcmd(udc, &epcmd);
+ if (res < 0)
+ dev_err(udc->dev, "Failed to configure physical EP0\n");
+
+ epcmd.ep = 1;
+ epcmd.param1 = EXYNOS_USB3_DEPCMDPAR1x_EpDir |
+ EXYNOS_USB3_DEPCMDPAR1x_XferNRdyEn |
+ EXYNOS_USB3_DEPCMDPAR1x_XferCmplEn;
+ epcmd.cmdflags = EXYNOS_USB3_DEPCMDx_CmdAct;
+
+ res = exynos_ss_udc_issue_epcmd(udc, &epcmd);
+ if (res < 0)
+ dev_err(udc->dev, "Failed to configure physical EP1\n");
+}
+
+/**
+ * exynos_ss_udc_irq_usbrst - process event USB Reset
+ * @udc: The device state.
+ */
+static void exynos_ss_udc_irq_usbrst(struct exynos_ss_udc *udc)
+{
+ struct exynos_ss_udc_ep_command epcmd;
+ struct exynos_ss_udc_ep *ep;
+ int res;
+ int epnum;
+
+ dev_dbg(udc->dev, "%s\n", __func__);
+
+ epcmd.cmdtyp = EXYNOS_USB3_DEPCMDx_CmdTyp_DEPENDXFER;
+
+ /* End transfer, kill all requests and clear STALL on the
+ non-EP0 endpoints */
+ for (epnum = 1; epnum < EXYNOS_USB3_EPS; epnum++) {
+
+ ep = &udc->eps[epnum];
+
+ epcmd.ep = get_phys_epnum(ep);
+
+ if (ep->tri) {
+ epcmd.cmdflags = (ep->tri <<
+ EXYNOS_USB3_DEPCMDx_CommandParam_SHIFT) |
+ EXYNOS_USB3_DEPCMDx_HiPri_ForceRM |
+ EXYNOS_USB3_DEPCMDx_CmdIOC |
+ EXYNOS_USB3_DEPCMDx_CmdAct;
+
+ res = exynos_ss_udc_issue_epcmd(udc, &epcmd);
+ if (res < 0) {
+ dev_err(udc->dev, "Failed to end transfer\n");
+ ep->not_ready = 1;
+ }
+
+ ep->tri = 0;
+ }
+
+ exynos_ss_udc_kill_all_requests(udc, ep, -ECONNRESET);
+
+ if (ep->halted)
+ exynos_ss_udc_ep_sethalt(&ep->ep, 0);
+ }
+
+ /* Set device address to 0 */
+ __bic32(udc->regs + EXYNOS_USB3_DCFG, EXYNOS_USB3_DCFG_DevAddr_MASK);
+}
+
+/**
+ * exynos_ss_udc_handle_depevt - handle endpoint-specific event
+ * @udc: The device state.
+ * @event: The event being handled.
+ */
+static void exynos_ss_udc_handle_depevt(struct exynos_ss_udc *udc, u32 event)
+{
+ int index = (event & EXYNOS_USB3_DEPEVT_EPNUM_MASK) >> 1;
+ int dir_in = index & 1;
+ int epnum = get_usb_epnum(index);
+ struct exynos_ss_udc_ep *udc_ep = &udc->eps[epnum];
+ struct exynos_ss_udc_ep_command *epcmd, *tepcmd;
+ struct exynos_ss_udc_req *udc_req;
+ bool restart;
+ int res;
+
+ switch (event & EXYNOS_USB3_DEPEVT_EVENT_MASK) {
+ case EXYNOS_USB3_DEPEVT_EVENT_XferNotReady:
+ dev_dbg(udc->dev, "Xfer Not Ready: ep%d%s\n",
+ epnum, dir_in ? "in" : "out");
+ if (epnum == 0 && udc->ep0_state == EP0_WAIT_NRDY) {
+ udc_ep->dir_in = dir_in;
+
+ if (udc->ep0_three_stage)
+ udc->ep0_state = EP0_STATUS_PHASE_3;
+ else
+ udc->ep0_state = EP0_STATUS_PHASE_2;
+
+ exynos_ss_udc_enqueue_status(udc);
+ }
+ break;
+
+ case EXYNOS_USB3_DEPEVT_EVENT_XferComplete:
+ dev_dbg(udc->dev, "Xfer Complete: ep%d%s\n",
+ epnum, dir_in ? "in" : "out");
+ if (dir_in) {
+ /* Handle "transfer complete" for IN EPs */
+ exynos_ss_udc_complete_in(udc, udc_ep);
+ } else {
+ /* Handle "transfer complete" for OUT EPs */
+ exynos_ss_udc_complete_out(udc, udc_ep);
+ }
+
+ if (epnum == 0 && udc->ep0_state == EP0_SETUP_PHASE)
+ exynos_ss_udc_enqueue_setup(udc);
+
+ break;
+
+ case EXYNOS_USB3_DEPEVT_EVENT_EPCmdCmplt:
+ dev_dbg(udc->dev, "EP Cmd complete: ep%d%s\n",
+ epnum, dir_in ? "in" : "out");
+
+ udc_ep->not_ready = 0;
+
+ /* Issue all pending commands for endpoint */
+ list_for_each_entry_safe(epcmd, tepcmd,
+ &udc_ep->cmd_queue, queue) {
+
+ dev_dbg(udc->dev, "Pending command %02xh for ep%d%s\n",
+ epcmd->cmdtyp, epnum,
+ dir_in ? "in" : "out");
+
+ res = exynos_ss_udc_issue_epcmd(udc, epcmd);
+ if (res < 0)
+ dev_err(udc->dev, "Failed to issue command\n");
+
+ list_del_init(&epcmd->queue);
+ kfree(epcmd);
+ }
+
+ /* If we have pending request, then start it */
+ restart = !list_empty(&udc_ep->queue);
+ if (restart) {
+ udc_req = get_ep_head(udc_ep);
+ exynos_ss_udc_start_req(udc, udc_ep,
+ udc_req, false);
+ }
+
+ break;
+ }
+}
+
+/**
+ * exynos_ss_udc_handle_devt - handle device-specific event
+ * @udc: The driver state.
+ * @event: The event being handled.
+ */
+static void exynos_ss_udc_handle_devt(struct exynos_ss_udc *udc, u32 event)
+{
+ int event_info;
+
+ switch (event & EXYNOS_USB3_DEVT_EVENT_MASK) {
+ case EXYNOS_USB3_DEVT_EVENT_ULStChng:
+ dev_dbg(udc->dev, "USB-Link State Change");
+ event_info = event & EXYNOS_USB3_DEVT_EventParam_MASK;
+ if (event_info == EXYNOS_USB3_DEVT_EventParam(0x3) ||
+ event_info == EXYNOS_USB3_DEVT_EventParam(0x4)) {
+ call_gadget(udc, disconnect);
+ }
+ break;
+
+ case EXYNOS_USB3_DEVT_EVENT_ConnectDone:
+ dev_dbg(udc->dev, "Connection Done");
+ exynos_ss_udc_irq_connectdone(udc);
+ break;
+
+ case EXYNOS_USB3_DEVT_EVENT_USBRst:
+ dev_dbg(udc->dev, "USB Reset");
+ exynos_ss_udc_irq_usbrst(udc);
+ break;
+
+ case EXYNOS_USB3_DEVT_EVENT_DisconnEvt:
+ dev_dbg(udc->dev, "Disconnection Detected");
+ call_gadget(udc, disconnect);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void exynos_ss_udc_handle_otgevt(struct exynos_ss_udc *udc, u32 event)
+{}
+
+static void exynos_ss_udc_handle_gevt(struct exynos_ss_udc *udc, u32 event)
+{}
+
+/**
+ * exynos_ss_udc_irq - handle device interrupt
+ * @irq: The IRQ number triggered.
+ * @pw: The pw value when registered the handler.
+ */
+static irqreturn_t exynos_ss_udc_irq(int irq, void *pw)
+{
+ struct exynos_ss_udc *udc = pw;
+ int indx = udc->event_indx;
+ int gevntcount;
+ u32 event;
+ u32 ecode1, ecode2;
+
+ gevntcount = readl(udc->regs + EXYNOS_USB3_GEVNTCOUNT(0)) &
+ EXYNOS_USB3_GEVNTCOUNTx_EVNTCount_MASK;
+ /* TODO: what if number of events more then buffer size? */
+
+ dev_dbg(udc->dev, "INTERRUPT (%d)\n", gevntcount >> 2);
+
+ while (gevntcount) {
+ event = udc->event_buff[indx++];
+
+ dev_dbg(udc->dev, "event[%x] = 0x%08x\n",
+ (unsigned int) &udc->event_buff[indx - 1], event);
+
+ ecode1 = event & 0x01;
+
+ if (ecode1 == 0)
+ /* Device Endpoint-Specific Event */
+ exynos_ss_udc_handle_depevt(udc, event);
+ else {
+ ecode2 = (event & 0xfe) >> 1;
+
+ switch (ecode2) {
+ /* Device-Specific Event */
+ case 0x00:
+ exynos_ss_udc_handle_devt(udc, event);
+ break;
+
+ /* OTG Event */
+ case 0x01:
+ exynos_ss_udc_handle_otgevt(udc, event);
+ break;
+
+ /* Other Core Event */
+ case 0x03:
+ case 0x04:
+ exynos_ss_udc_handle_gevt(udc, event);
+ break;
+
+ /* Unknown Event Type */
+ default:
+ dev_info(udc->dev, "Unknown event type\n");
+ break;
+ }
+ }
+ /* We processed 1 event (4 bytes) */
+ writel(4, udc->regs + EXYNOS_USB3_GEVNTCOUNT(0));
+
+ if (indx > (EXYNOS_USB3_EVENT_BUFF_WSIZE - 1))
+ indx = 0;
+
+ gevntcount -= 4;
+ }
+
+ udc->event_indx = indx;
+ /* Do we need to read GEVENTCOUNT here and retry? */
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * exynos_ss_udc_free_all_trb - free all allocated TRBs
+ * @udc: The device state.
+ */
+static void exynos_ss_udc_free_all_trb(struct exynos_ss_udc *udc)
+{
+ int epnum;
+
+ for (epnum = 0; epnum < EXYNOS_USB3_EPS; epnum++) {
+ struct exynos_ss_udc_ep *udc_ep = &udc->eps[epnum];
+
+ if (udc_ep->trb_dma)
+ dma_free_coherent(NULL,
+ sizeof(struct exynos_ss_udc_trb),
+ udc_ep->trb,
+ udc_ep->trb_dma);
+ }
+}
+
+/**
+ * exynos_ss_udc_initep - initialize a single endpoint
+ * @udc: The device state.
+ * @udc_ep: The endpoint being initialised.
+ * @epnum: The endpoint number.
+ *
+ * Initialise the given endpoint (as part of the probe and device state
+ * creation) to give to the gadget driver. Setup the endpoint name, any
+ * direction information and other state that may be required.
+ */
+static int __devinit exynos_ss_udc_initep(struct exynos_ss_udc *udc,
+ struct exynos_ss_udc_ep *udc_ep,
+ int epnum)
+{
+ char *dir;
+
+ if (epnum == 0)
+ dir = "";
+ else if ((epnum % 2) == 0) {
+ dir = "out";
+ } else {
+ dir = "in";
+ udc_ep->dir_in = 1;
+ }
+
+ udc_ep->epnum = epnum;
+
+ snprintf(udc_ep->name, sizeof(udc_ep->name), "ep%d%s", epnum, dir);
+
+ INIT_LIST_HEAD(&udc_ep->queue);
+ INIT_LIST_HEAD(&udc_ep->cmd_queue);
+ INIT_LIST_HEAD(&udc_ep->ep.ep_list);
+
+ spin_lock_init(&udc_ep->lock);
+
+ /* add to the list of endpoints known by the gadget driver */
+ if (epnum)
+ list_add_tail(&udc_ep->ep.ep_list, &udc->gadget.ep_list);
+
+ udc_ep->parent = udc;
+ udc_ep->ep.name = udc_ep->name;
+ udc_ep->ep.maxpacket = epnum ? EP_SS_MPS : EP0_SS_MPS;
+ udc_ep->ep.ops = &exynos_ss_udc_ep_ops;
+ udc_ep->trb = dma_alloc_coherent(NULL,
+ sizeof(struct exynos_ss_udc_trb),
+ &udc_ep->trb_dma,
+ GFP_KERNEL);
+ if (!udc_ep->trb)
+ return -ENOMEM;
+
+ memset(udc_ep->trb, 0, sizeof(struct exynos_ss_udc_trb));
+
+ if (epnum == 0) {
+ /* allocate EP0 control request */
+ udc->ctrl_req = exynos_ss_udc_ep_alloc_request(&udc->eps[0].ep,
+ GFP_KERNEL);
+ if (!udc->ctrl_req)
+ return -ENOMEM;
+
+ udc->ep0_state = EP0_UNCONNECTED;
+ }
+
+ return 0;
+}
+
+/**
+ * exynos_ss_udc_phy_set - intitialize the controller PHY interface
+ * @pdev: The platform-level device instance.
+ */
+static void exynos_ss_udc_phy_set(struct platform_device *pdev)
+{
+ struct exynos_usb3_drd_pdata *plat = pdev->dev.platform_data;
+ struct exynos_ss_udc *udc = platform_get_drvdata(pdev);
+ /* The reset values:
+ * GUSB2PHYCFG(0) = 0x00002400
+ * GUSB3PIPECTL(0) = 0x00260002
+ */
+
+ __orr32(udc->regs + EXYNOS_USB3_GCTL, EXYNOS_USB3_GCTL_CoreSoftReset);
+ __orr32(udc->regs + EXYNOS_USB3_GUSB2PHYCFG(0),
+ EXYNOS_USB3_GUSB2PHYCFGx_PHYSoftRst);
+ __orr32(udc->regs + EXYNOS_USB3_GUSB3PIPECTL(0),
+ EXYNOS_USB3_GUSB3PIPECTLx_PHYSoftRst);
+
+ /* PHY initialization */
+ if (plat && plat->phy_init)
+ plat->phy_init(pdev, S5P_USB_PHY_DRD);
+
+ __bic32(udc->regs + EXYNOS_USB3_GUSB2PHYCFG(0),
+ EXYNOS_USB3_GUSB2PHYCFGx_PHYSoftRst);
+ __bic32(udc->regs + EXYNOS_USB3_GUSB3PIPECTL(0),
+ EXYNOS_USB3_GUSB3PIPECTLx_PHYSoftRst);
+ __bic32(udc->regs + EXYNOS_USB3_GCTL, EXYNOS_USB3_GCTL_CoreSoftReset);
+
+
+ __bic32(udc->regs + EXYNOS_USB3_GUSB2PHYCFG(0),
+ EXYNOS_USB3_GUSB2PHYCFGx_SusPHY |
+ EXYNOS_USB3_GUSB2PHYCFGx_EnblSlpM |
+ EXYNOS_USB3_GUSB2PHYCFGx_USBTrdTim_MASK);
+ __orr32(udc->regs + EXYNOS_USB3_GUSB2PHYCFG(0),
+ EXYNOS_USB3_GUSB2PHYCFGx_USBTrdTim(9));
+
+ __bic32(udc->regs + EXYNOS_USB3_GUSB3PIPECTL(0),
+ EXYNOS_USB3_GUSB3PIPECTLx_SuspSSPhy);
+
+ dev_dbg(udc->dev, "GUSB2PHYCFG(0)=0x%08x, GUSB3PIPECTL(0)=0x%08x",
+ readl(udc->regs + EXYNOS_USB3_GUSB2PHYCFG(0)),
+ readl(udc->regs + EXYNOS_USB3_GUSB3PIPECTL(0)));
+}
+
+/**
+ * exynos_ss_udc_phy_unset - disable the controller PHY interface
+ * @pdev: The platform-level device instance.
+ */
+static void exynos_ss_udc_phy_unset(struct platform_device *pdev)
+{
+ struct exynos_usb3_drd_pdata *plat = pdev->dev.platform_data;
+ struct exynos_ss_udc *udc = platform_get_drvdata(pdev);
+
+ __orr32(udc->regs + EXYNOS_USB3_GUSB2PHYCFG(0),
+ EXYNOS_USB3_GUSB2PHYCFGx_SusPHY |
+ EXYNOS_USB3_GUSB2PHYCFGx_EnblSlpM);
+ __orr32(udc->regs + EXYNOS_USB3_GUSB3PIPECTL(0),
+ EXYNOS_USB3_GUSB3PIPECTLx_SuspSSPhy);
+
+ if (plat && plat->phy_exit)
+ plat->phy_exit(pdev, S5P_USB_PHY_DRD);
+
+ dev_dbg(udc->dev, "GUSB2PHYCFG(0)=0x%08x, GUSB3PIPECTL(0)=0x%08x",
+ readl(udc->regs + EXYNOS_USB3_GUSB2PHYCFG(0)),
+ readl(udc->regs + EXYNOS_USB3_GUSB3PIPECTL(0)));
+}
+
+/**
+ * exynos_ss_udc_corereset - issue softreset to the core
+ * @udc: The device state.
+ *
+ * Issue a soft reset to the core, and await the core finishing it.
+ */
+static int exynos_ss_udc_corereset(struct exynos_ss_udc *udc)
+{
+ int res;
+
+ /* issue soft reset */
+ __orr32(udc->regs + EXYNOS_USB3_DCTL, EXYNOS_USB3_DCTL_CSftRst);
+
+ res = poll_bit_clear(udc->regs + EXYNOS_USB3_DCTL,
+ EXYNOS_USB3_DCTL_CSftRst,
+ 1000);
+ if (res < 0)
+ dev_err(udc->dev, "Failed to get CSftRst asserted\n");
+
+ return res;
+}
+
+/**
+ * exynos_ss_udc_ep0_activate - activate USB endpoint 0
+ * @udc: The device state.
+ *
+ * Configure physical endpoints 0 & 1.
+ */
+static void exynos_ss_udc_ep0_activate(struct exynos_ss_udc *udc)
+{
+ struct exynos_ss_udc_ep_command epcmd;
+ int res;
+
+ /* Start New Configuration */
+ epcmd.ep = 0;
+ epcmd.cmdtyp = EXYNOS_USB3_DEPCMDx_CmdTyp_DEPSTARTCFG;
+ epcmd.cmdflags = EXYNOS_USB3_DEPCMDx_CmdAct;
+
+ res = exynos_ss_udc_issue_epcmd(udc, &epcmd);
+ if (res < 0)
+ dev_err(udc->dev, "Failed to start new configuration\n");
+
+ /* Configure Physical Endpoint 0 */
+ epcmd.ep = 0;
+ epcmd.param0 = EXYNOS_USB3_DEPCMDPAR0x_MPS(EP0_SS_MPS);
+ epcmd.param1 = EXYNOS_USB3_DEPCMDPAR1x_XferNRdyEn |
+ EXYNOS_USB3_DEPCMDPAR1x_XferCmplEn;
+ epcmd.cmdtyp = EXYNOS_USB3_DEPCMDx_CmdTyp_DEPCFG;
+ epcmd.cmdflags = EXYNOS_USB3_DEPCMDx_CmdAct;
+
+ res = exynos_ss_udc_issue_epcmd(udc, &epcmd);
+ if (res < 0)
+ dev_err(udc->dev, "Failed to configure physical EP0\n");
+
+ /* Configure Physical Endpoint 1 */
+ epcmd.ep = 1;
+ epcmd.param0 = EXYNOS_USB3_DEPCMDPAR0x_MPS(EP0_SS_MPS);
+ epcmd.param1 = EXYNOS_USB3_DEPCMDPAR1x_EpDir |
+ EXYNOS_USB3_DEPCMDPAR1x_XferNRdyEn |
+ EXYNOS_USB3_DEPCMDPAR1x_XferCmplEn;
+ epcmd.cmdtyp = EXYNOS_USB3_DEPCMDx_CmdTyp_DEPCFG;
+ epcmd.cmdflags = EXYNOS_USB3_DEPCMDx_CmdAct;
+
+ res = exynos_ss_udc_issue_epcmd(udc, &epcmd);
+ if (res < 0)
+ dev_err(udc->dev, "Failed to configure physical EP1\n");
+
+ /* Configure Pysical Endpoint 0 Transfer Resource */
+ epcmd.ep = 0;
+ epcmd.param0 = EXYNOS_USB3_DEPCMDPAR0x_NumXferRes(1);
+ epcmd.cmdtyp = EXYNOS_USB3_DEPCMDx_CmdTyp_DEPXFERCFG;
+ epcmd.cmdflags = EXYNOS_USB3_DEPCMDx_CmdAct;
+
+ res = exynos_ss_udc_issue_epcmd(udc, &epcmd);
+ if (res < 0)
+ dev_err(udc->dev,
+ "Failed to configure physical EP0 transfer resource\n");
+
+ /* Configure Pysical Endpoint 1 Transfer Resource */
+ epcmd.ep = 1;
+ epcmd.param0 = EXYNOS_USB3_DEPCMDPAR0x_NumXferRes(1);
+ epcmd.cmdtyp = EXYNOS_USB3_DEPCMDx_CmdTyp_DEPXFERCFG;
+ epcmd.cmdflags = EXYNOS_USB3_DEPCMDx_CmdAct;
+
+ res = exynos_ss_udc_issue_epcmd(udc, &epcmd);
+ if (res < 0)
+ dev_err(udc->dev,
+ "Failed to configure physical EP1 transfer resource\n");
+
+ /* Enable Physical Endpoints 0 and 1 */
+ writel(3, udc->regs + EXYNOS_USB3_DALEPENA);
+}
+
+/**
+ * exynos_ss_udc_ep_activate - activate USB endpoint
+ * @udc: The device state.
+ * @udc_ep: The endpoint being activated.
+ *
+ * Configure physical endpoints > 1.
+ */
+static void exynos_ss_udc_ep_activate(struct exynos_ss_udc *udc,
+ struct exynos_ss_udc_ep *udc_ep)
+{
+ struct exynos_ss_udc_ep_command ep_command;
+ struct exynos_ss_udc_ep_command *epcmd = &ep_command;
+ int epnum = udc_ep->epnum;
+ int maxburst = udc_ep->ep.maxburst;
+ int res;
+
+ if (!udc->eps_enabled) {
+ udc->eps_enabled = true;
+
+ /* Start New Configuration */
+ epcmd->ep = 0;
+ epcmd->cmdtyp = EXYNOS_USB3_DEPCMDx_CmdTyp_DEPSTARTCFG;
+ epcmd->cmdflags =
+ (2 << EXYNOS_USB3_DEPCMDx_CommandParam_SHIFT) |
+ EXYNOS_USB3_DEPCMDx_CmdAct;
+
+ res = exynos_ss_udc_issue_epcmd(udc, epcmd);
+ if (res < 0)
+ dev_err(udc->dev, "Failed to start new configuration\n");
+ }
+
+ if (udc_ep->not_ready) {
+ epcmd = kzalloc(sizeof(struct exynos_ss_udc_ep_command),
+ GFP_ATOMIC);
+ if (!epcmd) {
+ /* Will try to issue command immediately */
+ epcmd = &ep_command;
+ udc_ep->not_ready = 0;
+ }
+ }
+
+ epcmd->ep = get_phys_epnum(udc_ep);
+ epcmd->param0 = EXYNOS_USB3_DEPCMDPAR0x_EPType(udc_ep->type) |
+ EXYNOS_USB3_DEPCMDPAR0x_MPS(udc_ep->ep.maxpacket) |
+ EXYNOS_USB3_DEPCMDPAR0x_BrstSiz(maxburst);
+ if (udc_ep->dir_in)
+ epcmd->param0 |= EXYNOS_USB3_DEPCMDPAR0x_FIFONum(epnum);
+ epcmd->param1 = EXYNOS_USB3_DEPCMDPAR1x_EpNum(epnum) |
+ (udc_ep->dir_in ? EXYNOS_USB3_DEPCMDPAR1x_EpDir : 0) |
+ EXYNOS_USB3_DEPCMDPAR1x_XferNRdyEn |
+ EXYNOS_USB3_DEPCMDPAR1x_XferCmplEn;
+ epcmd->cmdtyp = EXYNOS_USB3_DEPCMDx_CmdTyp_DEPCFG;
+ epcmd->cmdflags = EXYNOS_USB3_DEPCMDx_CmdAct;
+
+ if (udc_ep->not_ready)
+ list_add_tail(&epcmd->queue, &udc_ep->cmd_queue);
+ else {
+ res = exynos_ss_udc_issue_epcmd(udc, epcmd);
+ if (res < 0)
+ dev_err(udc->dev, "Failed to configure physical EP\n");
+ }
+
+ /* Configure Pysical Endpoint Transfer Resource */
+ if (udc_ep->not_ready) {
+ epcmd = kzalloc(sizeof(struct exynos_ss_udc_ep_command),
+ GFP_ATOMIC);
+ if (!epcmd) {
+ epcmd = &ep_command;
+ udc_ep->not_ready = 0;
+ }
+ }
+
+ epcmd->ep = get_phys_epnum(udc_ep);
+ epcmd->param0 = EXYNOS_USB3_DEPCMDPAR0x_NumXferRes(1);
+ epcmd->cmdtyp = EXYNOS_USB3_DEPCMDx_CmdTyp_DEPXFERCFG;
+ epcmd->cmdflags = EXYNOS_USB3_DEPCMDx_CmdAct;
+
+ if (udc_ep->not_ready)
+ list_add_tail(&epcmd->queue, &udc_ep->cmd_queue);
+ else {
+ res = exynos_ss_udc_issue_epcmd(udc, epcmd);
+ if (res < 0)
+ dev_err(udc->dev, "Failed to configure physical EP "
+ "transfer resource\n");
+ }
+
+ /* Enable Physical Endpoint */
+ __orr32(udc->regs + EXYNOS_USB3_DALEPENA, 1 << epcmd->ep);
+}
+
+/**
+ * exynos_ss_udc_ep_deactivate - deactivate USB endpoint
+ * @udc: The device state.
+ * @udc_ep: The endpoint being deactivated.
+ *
+ * End any active transfer and disable endpoint.
+ */
+static void exynos_ss_udc_ep_deactivate(struct exynos_ss_udc *udc,
+ struct exynos_ss_udc_ep *udc_ep)
+{
+ struct exynos_ss_udc_ep_command epcmd;
+ int index = get_phys_epnum(udc_ep);
+
+ udc->eps_enabled = false;
+
+ if (udc_ep->tri && !udc_ep->not_ready) {
+ int res;
+
+ epcmd.ep = get_phys_epnum(udc_ep);
+ epcmd.cmdtyp = EXYNOS_USB3_DEPCMDx_CmdTyp_DEPENDXFER;
+ epcmd.cmdflags = (udc_ep->tri <<
+ EXYNOS_USB3_DEPCMDx_CommandParam_SHIFT) |
+ EXYNOS_USB3_DEPCMDx_HiPri_ForceRM |
+ EXYNOS_USB3_DEPCMDx_CmdIOC |
+ EXYNOS_USB3_DEPCMDx_CmdAct;
+
+ res = exynos_ss_udc_issue_epcmd(udc, &epcmd);
+ if (res < 0) {
+ dev_err(udc->dev, "Failed to end transfer\n");
+ udc_ep->not_ready = 1;
+ }
+
+ udc_ep->tri = 0;
+ }
+
+ __bic32(udc->regs + EXYNOS_USB3_DALEPENA, 1 << index);
+}
+
+/**
+ * exynos_ss_udc_init - initialize the controller
+ * @udc: The device state.
+ *
+ * Initialize the event buffer, enable events, activate USB EP0,
+ * and start the controller operation.
+ */
+static void exynos_ss_udc_init(struct exynos_ss_udc *udc)
+{
+ u32 reg;
+
+ reg = readl(udc->regs + EXYNOS_USB3_GSNPSID);
+ udc->release = reg & 0xffff;
+ dev_info(udc->dev, "Core ID Number: 0x%04x\n", reg >> 16);
+ dev_info(udc->dev, "Release Number: 0x%04x\n", udc->release);
+
+ __orr32(udc->regs + EXYNOS_USB3_GCTL, EXYNOS_USB3_GCTL_U2RSTECN);
+
+ writel(EXYNOS_USB3_GSBUSCFG0_INCR16BrstEna,
+ udc->regs + EXYNOS_USB3_GSBUSCFG0);
+ writel(EXYNOS_USB3_GSBUSCFG1_BREQLIMIT(3),
+ udc->regs + EXYNOS_USB3_GSBUSCFG1);
+
+ /* Event buffer */
+ udc->event_indx = 0;
+ writel(0, udc->regs + EXYNOS_USB3_GEVNTADR_63_32(0));
+ writel(udc->event_buff_dma,
+ udc->regs + EXYNOS_USB3_GEVNTADR_31_0(0));
+ /* Set Event Buffer size */
+ writel(EXYNOS_USB3_EVENT_BUFF_BSIZE,
+ udc->regs + EXYNOS_USB3_GEVNTSIZ(0));
+
+ writel(EXYNOS_USB3_DCFG_NumP(1) | EXYNOS_USB3_DCFG_PerFrInt(2) |
+ EXYNOS_USB3_DCFG_DevSpd(4),
+ udc->regs + EXYNOS_USB3_DCFG);
+
+ /* Flush any pending events */
+ __orr32(udc->regs + EXYNOS_USB3_GEVNTSIZ(0),
+ EXYNOS_USB3_GEVNTSIZx_EvntIntMask);
+
+ reg = readl(udc->regs + EXYNOS_USB3_GEVNTCOUNT(0));
+ writel(reg, udc->regs + EXYNOS_USB3_GEVNTCOUNT(0));
+
+ __bic32(udc->regs + EXYNOS_USB3_GEVNTSIZ(0),
+ EXYNOS_USB3_GEVNTSIZx_EvntIntMask);
+
+ /* Enable events */
+ writel(EXYNOS_USB3_DEVTEN_ULStCngEn | EXYNOS_USB3_DEVTEN_ConnectDoneEn |
+ EXYNOS_USB3_DEVTEN_USBRstEn | EXYNOS_USB3_DEVTEN_DisconnEvtEn,
+ udc->regs + EXYNOS_USB3_DEVTEN);
+
+ exynos_ss_udc_ep0_activate(udc);
+
+ /* Start the device controller operation */
+ __bic32(udc->regs + EXYNOS_USB3_DCTL,
+ EXYNOS_USB3_DCTL_Run_Stop);
+}
+
+static int exynos_ss_udc_start(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver)
+{
+ struct exynos_ss_udc *udc = our_udc(gadget);
+
+ if (!udc) {
+ printk(KERN_ERR "%s: called with no device\n", __func__);
+ return -ENODEV;
+ }
+
+ if (!driver) {
+ dev_err(udc->dev, "%s: no driver\n", __func__);
+ return -EINVAL;
+ }
+
+ if (driver->max_speed < USB_SPEED_FULL) {
+ dev_err(udc->dev, "%s: bad speed\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!driver->setup) {
+ dev_err(udc->dev, "%s: missing entry points\n", __func__);
+ return -EINVAL;
+ }
+
+ WARN_ON(udc->driver);
+
+ driver->driver.bus = NULL;
+ udc->driver = driver;
+ udc->gadget.dev.driver = &driver->driver;
+
+ /* we must now enable ep0 ready for host detection and then
+ * set configuration. */
+
+ exynos_ss_udc_corereset(udc);
+
+ exynos_ss_udc_init(udc);
+
+ udc->ep0_state = EP0_SETUP_PHASE;
+ exynos_ss_udc_enqueue_setup(udc);
+
+ /* report to the user, and return */
+ dev_info(udc->dev, "bound driver %s\n", driver->driver.name);
+ return 0;
+}
+
+static int exynos_ss_udc_stop(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver)
+{
+ struct exynos_ss_udc *udc = our_udc(gadget);
+ int ep;
+
+ if (!udc)
+ return -ENODEV;
+
+ if (!driver || driver != udc->driver)
+ return -EINVAL;
+
+ /* all endpoints should be shutdown */
+ for (ep = 0; ep < EXYNOS_USB3_EPS; ep++)
+ exynos_ss_udc_ep_disable(&udc->eps[ep].ep);
+
+ call_gadget(udc, disconnect);
+
+ udc->driver = NULL;
+ udc->gadget.dev.driver = NULL;
+ udc->gadget.speed = USB_SPEED_UNKNOWN;
+
+ exynos_ss_udc_run_stop(udc, 0);
+ dev_info(udc->dev, "unregistered gadget driver '%s'\n",
+ driver->driver.name);
+
+ return 0;
+}
+
+static int __devinit exynos_ss_udc_probe(struct platform_device *pdev)
+{
+ struct exynos_usb3_drd_pdata *plat = pdev->dev.platform_data;
+ struct device *dev = &pdev->dev;
+ struct exynos_ss_udc *udc;
+ struct resource *res;
+ int epnum;
+ int ret;
+
+ if (!plat) {
+ dev_err(dev, "cannot get platform data\n");
+ return -ENODEV;
+ }
+
+ udc = kzalloc(sizeof(struct exynos_ss_udc), GFP_KERNEL);
+ if (!udc) {
+ dev_err(dev, "cannot get memory\n");
+ ret = -ENOMEM;
+ goto err_mem;
+ }
+
+ udc->dev = dev;
+ udc->plat = plat;
+
+ udc->event_buff = dma_alloc_coherent(NULL,
+ EXYNOS_USB3_EVENT_BUFF_BSIZE,
+ &udc->event_buff_dma,
+ GFP_KERNEL);
+ if (!udc->event_buff) {
+ dev_err(dev, "cannot get memory for event buffer\n");
+ ret = -ENOMEM;
+ goto err_mem;
+ }
+ memset(udc->event_buff, 0, EXYNOS_USB3_EVENT_BUFF_BSIZE);
+
+ udc->ctrl_buff = dma_alloc_coherent(NULL,
+ EXYNOS_USB3_CTRL_BUFF_SIZE,
+ &udc->ctrl_buff_dma,
+ GFP_KERNEL);
+ if (!udc->ctrl_buff) {
+ dev_err(dev, "cannot get memory for control buffer\n");
+ ret = -ENOMEM;
+ goto err_mem;
+ }
+ memset(udc->ctrl_buff, 0, EXYNOS_USB3_CTRL_BUFF_SIZE);
+
+ udc->ep0_buff = dma_alloc_coherent(NULL,
+ EXYNOS_USB3_EP0_BUFF_SIZE,
+ &udc->ep0_buff_dma,
+ GFP_KERNEL);
+ if (!udc->ep0_buff) {
+ dev_err(dev, "cannot get memory for EP0 buffer\n");
+ ret = -ENOMEM;
+ goto err_mem;
+ }
+ memset(udc->ep0_buff, 0, EXYNOS_USB3_EP0_BUFF_SIZE);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(dev, "cannot find register resource 0\n");
+ ret = -EINVAL;
+ goto err_mem;
+ }
+
+ if (!request_mem_region(res->start, resource_size(res),
+ dev_name(dev))) {
+ dev_err(dev, "cannot reserve registers\n");
+ ret = -ENOENT;
+ goto err_mem;
+ }
+
+ udc->regs = ioremap(res->start, resource_size(res));
+ if (!udc->regs) {
+ dev_err(dev, "cannot map registers\n");
+ ret = -ENXIO;
+ goto err_remap;
+ }
+
+ ret = platform_get_irq(pdev, 0);
+ if (ret < 0) {
+ dev_err(dev, "cannot find irq\n");
+ goto err_irq;
+ }
+
+ udc->irq = ret;
+
+ ret = request_irq(ret, exynos_ss_udc_irq, 0, dev_name(dev), udc);
+ if (ret < 0) {
+ dev_err(dev, "cannot claim IRQ\n");
+ goto err_irq;
+ }
+
+ dev_info(dev, "regs %p, irq %d\n", udc->regs, udc->irq);
+
+ udc->clk = clk_get(&pdev->dev, "usbdrd30");
+ if (IS_ERR(udc->clk)) {
+ dev_err(dev, "cannot get UDC clock\n");
+ ret = -EINVAL;
+ goto err_clk;
+ }
+
+ dev_set_name(&udc->gadget.dev, "gadget");
+
+ udc->gadget.max_speed = USB_SPEED_SUPER;
+ udc->gadget.ops = &exynos_ss_udc_gadget_ops;
+ udc->gadget.name = dev_name(dev);
+ udc->gadget.dev.parent = dev;
+ udc->gadget.dev.dma_mask = dev->dma_mask;
+ udc->gadget.speed = USB_SPEED_UNKNOWN;
+
+ /* setup endpoint information */
+
+ INIT_LIST_HEAD(&udc->gadget.ep_list);
+ udc->gadget.ep0 = &udc->eps[0].ep;
+
+ /* initialise the endpoints */
+ for (epnum = 0; epnum < EXYNOS_USB3_EPS; epnum++) {
+ ret = exynos_ss_udc_initep(udc, &udc->eps[epnum], epnum);
+ if (ret < 0) {
+ dev_err(dev, "cannot get memory for TRB\n");
+ goto err_ep;
+ }
+ }
+
+ platform_set_drvdata(pdev, udc);
+
+ clk_enable(udc->clk);
+ exynos_ss_udc_phy_set(pdev);
+
+ ret = device_register(&udc->gadget.dev);
+ if (ret) {
+ dev_err(udc->dev, "failed to register gadget device\n");
+ goto err_add_device;
+ }
+
+ ret = usb_add_gadget_udc(&pdev->dev, &udc->gadget);
+ if (ret) {
+ dev_err(udc->dev, "failed to add gadget to udc list\n");
+ goto err_add_udc;
+ }
+
+ return 0;
+
+err_add_udc:
+ device_unregister(&udc->gadget.dev);
+err_add_device:
+ clk_disable(udc->clk);
+err_ep:
+ exynos_ss_udc_ep_free_request(&udc->eps[0].ep, udc->ctrl_req);
+ exynos_ss_udc_free_all_trb(udc);
+ clk_put(udc->clk);
+err_clk:
+ free_irq(udc->irq, udc);
+err_irq:
+ iounmap(udc->regs);
+err_remap:
+ release_mem_region(res->start, resource_size(res));
+err_mem:
+ if (udc->ep0_buff)
+ dma_free_coherent(NULL, EXYNOS_USB3_EP0_BUFF_SIZE,
+ udc->ep0_buff, udc->ep0_buff_dma);
+ if (udc->ctrl_buff)
+ dma_free_coherent(NULL, EXYNOS_USB3_CTRL_BUFF_SIZE,
+ udc->ctrl_buff, udc->ctrl_buff_dma);
+ if (udc->event_buff)
+ dma_free_coherent(NULL, EXYNOS_USB3_EVENT_BUFF_BSIZE,
+ udc->event_buff, udc->event_buff_dma);
+ kfree(udc);
+
+ platform_set_drvdata(pdev, NULL);
+
+ return ret;
+}
+
+static int __devexit exynos_ss_udc_remove(struct platform_device *pdev)
+{
+ struct exynos_ss_udc *udc = platform_get_drvdata(pdev);
+ struct resource *res;
+
+ usb_gadget_unregister_driver(udc->driver);
+
+ usb_del_gadget_udc(&udc->gadget);
+
+ exynos_ss_udc_phy_unset(pdev);
+
+ clk_disable(udc->clk);
+ clk_put(udc->clk);
+
+ free_irq(udc->irq, udc);
+
+ iounmap(udc->regs);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(res->start, resource_size(res));
+
+ device_unregister(&udc->gadget.dev);
+
+ exynos_ss_udc_ep_free_request(&udc->eps[0].ep, udc->ctrl_req);
+ exynos_ss_udc_free_all_trb(udc);
+
+ dma_free_coherent(NULL, EXYNOS_USB3_EP0_BUFF_SIZE,
+ udc->ep0_buff, udc->ep0_buff_dma);
+ dma_free_coherent(NULL, EXYNOS_USB3_CTRL_BUFF_SIZE,
+ udc->ctrl_buff, udc->ctrl_buff_dma);
+ dma_free_coherent(NULL, EXYNOS_USB3_EVENT_BUFF_BSIZE,
+ udc->event_buff, udc->event_buff_dma);
+ kfree(udc);
+
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int exynos_ss_udc_suspend(struct platform_device *pdev,
+ pm_message_t state)
+{
+ struct exynos_ss_udc *udc = platform_get_drvdata(pdev);
+ int ep;
+
+ if (udc->driver) {
+ call_gadget(udc, suspend);
+
+ /* all endpoints should be shutdown */
+ for (ep = 0; ep < EXYNOS_USB3_EPS; ep++)
+ exynos_ss_udc_ep_disable(&udc->eps[ep].ep);
+
+ call_gadget(udc, disconnect);
+ udc->gadget.speed = USB_SPEED_UNKNOWN;
+ }
+
+ exynos_ss_udc_run_stop(udc, 0);
+ exynos_ss_udc_phy_unset(pdev);
+
+ clk_disable(udc->clk);
+
+ return 0;
+}
+
+static int exynos_ss_udc_resume(struct platform_device *pdev)
+{
+ struct exynos_ss_udc *udc = platform_get_drvdata(pdev);
+
+ clk_enable(udc->clk);
+
+ exynos_ss_udc_phy_set(pdev);
+
+ if (udc->driver) {
+ /* we must now enable ep0 ready for host detection and then
+ * set configuration. */
+
+ exynos_ss_udc_corereset(udc);
+
+ exynos_ss_udc_init(udc);
+
+ udc->ep0_state = EP0_SETUP_PHASE;
+ exynos_ss_udc_enqueue_setup(udc);
+
+ call_gadget(udc, resume);
+ }
+
+ return 0;
+}
+#else
+#define exynos_ss_udc_suspend NULL
+#define exynos_ss_udc_resume NULL
+#endif /* CONFIG_PM */
+
+static struct platform_driver exynos_ss_udc_driver = {
+ .driver = {
+ .name = "exynos-ss-udc",
+ .owner = THIS_MODULE,
+ },
+ .probe = exynos_ss_udc_probe,
+ .remove = __devexit_p(exynos_ss_udc_remove),
+ .suspend = exynos_ss_udc_suspend,
+ .resume = exynos_ss_udc_resume,
+};
+
+module_platform_driver(exynos_ss_udc_driver);
+
+MODULE_DESCRIPTION("EXYNOS SuperSpeed USB 3.0 Device Controller");
+MODULE_AUTHOR("Anton Tikhomirov <av.tikhomirov@samsung.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/gadget/exynos_ss_udc.h b/drivers/usb/gadget/exynos_ss_udc.h
new file mode 100644
index 0000000..05a4419
--- /dev/null
+++ b/drivers/usb/gadget/exynos_ss_udc.h
@@ -0,0 +1,264 @@
+/* linux/drivers/usb/gadget/exynos_ss_udc.h
+ *
+ * Copyright 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * EXYNOS SuperSpeed USB 3.0 Device Controlle driver
+ *
+ * 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.
+ */
+#ifndef __EXYNOS_SS_UDC_H__
+#define __EXYNOS_SS_UDC_H__
+
+#define DMA_ADDR_INVALID (~((dma_addr_t)0))
+
+/* Maximum packet size for different speeds */
+#define EP0_LS_MPS 8
+#define EP_LS_MPS 8
+
+#define EP0_FS_MPS 64
+#define EP_FS_MPS 64
+
+#define EP0_HS_MPS 64
+#define EP_HS_MPS 512
+
+#define EP0_SS_MPS 512
+#define EP_SS_MPS 1024
+
+#define EXYNOS_USB3_EPS 9
+
+/* Has to be multiple of four */
+#define EXYNOS_USB3_EVENT_BUFF_WSIZE 256
+#define EXYNOS_USB3_EVENT_BUFF_BSIZE (EXYNOS_USB3_EVENT_BUFF_WSIZE << 2)
+
+#define EXYNOS_USB3_CTRL_BUFF_SIZE 8
+#define EXYNOS_USB3_EP0_BUFF_SIZE 512
+
+#define EXYNOS_USB3_U1_DEV_EXIT_LAT 0
+#define EXYNOS_USB3_U2_DEV_EXIT_LAT 0x20
+
+#define call_gadget(_udc, _entry) do { \
+ if ((_udc)->gadget.speed != USB_SPEED_UNKNOWN && \
+ (_udc)->driver && (_udc)->driver->_entry) \
+ (_udc)->driver->_entry(&(_udc)->gadget); \
+} while (0)
+
+/**
+ * States of EP0
+ */
+enum ctrl_ep_state {
+ EP0_UNCONNECTED,
+ EP0_SETUP_PHASE,
+ EP0_DATA_PHASE,
+ EP0_WAIT_NRDY,
+ EP0_STATUS_PHASE_2,
+ EP0_STATUS_PHASE_3,
+ EP0_STALL,
+};
+
+/**
+ * Types of TRB
+ */
+enum trb_control {
+ NORMAL = 1,
+ CONTROL_SETUP,
+ CONTROL_STATUS_2,
+ CONTROL_STATUS_3,
+ CONTROL_DATA,
+ ISOCHRONOUS_FIRST,
+ ISOCHRONOUS,
+ LINK_TRB,
+};
+
+/**
+ * struct exynos_ss_udc_trb - transfer request block (TRB)
+ * @buff_ptr_low: Buffer pointer low.
+ * @buff_ptr_high: Buffer pointer high.
+ * @param1: TRB parameter 1.
+ * @param2: TRB parameter 2.
+ */
+struct exynos_ss_udc_trb {
+ u32 buff_ptr_low;
+ u32 buff_ptr_high;
+ u32 param1;
+ u32 param2;
+};
+
+/**
+ * struct exynos_ss_udc_ep_command - endpoint command.
+ * @queue: The list of commands for the endpoint.
+ * @ep: physical endpoint number.
+ * @param0: Command parameter 0.
+ * @param1: Command parameter 1.
+ * @param2: Command parameter 2.
+ * @cmdtype: Command to issue.
+ * @cmdflags: Command flags.
+ */
+struct exynos_ss_udc_ep_command {
+ struct list_head queue;
+
+ int ep;
+ u32 param0;
+ u32 param1;
+ u32 param2;
+ u32 cmdtyp;
+ u32 cmdflags;
+};
+
+/**
+ * struct exynos_ss_udc_req - data transfer request
+ * @req: The USB gadget request.
+ * @queue: The list of requests for the endpoint this is queued for.
+ * @mapped: DMA buffer for this request has been mapped via dma_map_single().
+ */
+struct exynos_ss_udc_req {
+ struct usb_request req;
+ struct list_head queue;
+ unsigned char mapped;
+};
+
+/**
+ * struct exynos_ss_udc_ep - driver endpoint definition.
+ * @ep: The gadget layer representation of the endpoint.
+ * @queue: Queue of requests for this endpoint.
+ * @cmd_queue: Queue of commands for this endpoint.
+ * @parent: Reference back to the parent device structure.
+ * @req: The current request that the endpoint is processing. This is
+ * used to indicate an request has been loaded onto the endpoint
+ * and has yet to be completed (maybe due to data move, or simply
+ * awaiting an ack from the core all the data has been completed).
+ * @lock: State lock to protect contents of endpoint.
+ * @trb: Transfer Request Block.
+ * @trb_dma: Transfer Request Block DMA address.
+ * @tri: Transfer resource index.
+ * @epnum: The USB endpoint number.
+ * @type: The endpoint type.
+ * @dir_in: Set to true if this endpoint is of the IN direction, which
+ * means that it is sending data to the Host.
+ * @halted: Set if the endpoint has been halted.
+ * @enabled: Set to true if endpoint is enabled.
+ * @wedged: Set if the endpoint has been wedged.
+ * @not_ready: Set to true if a command for the endpoint hasn't completed
+ * during timeout interval.
+ * @name: The driver generated name for the endpoint.
+ *
+ * This is the driver's state for each registered enpoint, allowing it
+ * to keep track of transactions that need doing. Each endpoint has a
+ * lock to protect the state, to try and avoid using an overall lock
+ * for the host controller as much as possible.
+ */
+struct exynos_ss_udc_ep {
+ struct usb_ep ep;
+ struct list_head queue;
+ struct list_head cmd_queue;
+ struct exynos_ss_udc *parent;
+ struct exynos_ss_udc_req *req;
+
+ spinlock_t lock;
+
+ struct exynos_ss_udc_trb *trb;
+ dma_addr_t trb_dma;
+ u8 tri;
+
+ unsigned char epnum;
+ unsigned int type;
+ unsigned int dir_in:1;
+ unsigned int halted:1;
+ unsigned int enabled:1;
+ unsigned int wedged:1;
+ unsigned int not_ready:1;
+
+ char name[10];
+};
+
+/**
+ * struct exynos_ss_udc - driver state.
+ * @dev: The parent device supplied to the probe function
+ * @driver: USB gadget driver
+ * @plat: The platform specific configuration data.
+ * @regs: The memory area mapped for accessing registers.
+ * @irq: The IRQ number we are using.
+ * @clk: The clock we are using.
+ * @release: The core release number.
+ * @event_buff: Event buffer.
+ * @event_buff_dma: Event buffer DMA address.
+ * @event_indx: Event buffer index.
+ * @eps_enabled: Set if new configuration for physical endpoints > 1 started.
+ * @ep0_state: State of EP0.
+ * @ep0_three_stage: Set if control transfer has three stages.
+ * @ep0_buff: Buffer for EP0 data.
+ * @ep0_buff_dma: EP0 data buffer DMA address.
+ * @ctrl_buff: Buffer for EP0 control requests.
+ * @ctrl_buff_dma: EP0 control request buffer DMA address.
+ * @ctrl_req: Request for EP0 control packets.
+ * @gadget: Represents USB slave device.
+ * @eps: The endpoints being supplied to the gadget framework
+ */
+struct exynos_ss_udc {
+ struct device *dev;
+ struct usb_gadget_driver *driver;
+ struct exynos_usb3_drd_pdata *plat;
+
+ void __iomem *regs;
+ int irq;
+ struct clk *clk;
+
+ u16 release;
+
+ u32 *event_buff;
+ dma_addr_t event_buff_dma;
+ u32 event_indx;
+
+ bool eps_enabled;
+ enum ctrl_ep_state ep0_state;
+ int ep0_three_stage;
+
+ u8 *ep0_buff;
+ dma_addr_t ep0_buff_dma;
+ u8 *ctrl_buff;
+ dma_addr_t ctrl_buff_dma;
+ struct usb_request *ctrl_req;
+
+ struct usb_gadget gadget;
+ struct exynos_ss_udc_ep eps[EXYNOS_USB3_EPS];
+};
+
+/* conversion functions */
+static inline struct exynos_ss_udc *our_udc(struct usb_gadget *gadget)
+{
+ return container_of(gadget, struct exynos_ss_udc, gadget);
+}
+
+static inline struct exynos_ss_udc_req *our_req(struct usb_request *req)
+{
+ return container_of(req, struct exynos_ss_udc_req, req);
+}
+
+static inline struct exynos_ss_udc_ep *our_ep(struct usb_ep *ep)
+{
+ return container_of(ep, struct exynos_ss_udc_ep, ep);
+}
+
+static inline void __orr32(void __iomem *ptr, u32 val)
+{
+ writel(readl(ptr) | val, ptr);
+}
+
+static inline void __bic32(void __iomem *ptr, u32 val)
+{
+ writel(readl(ptr) & ~val, ptr);
+}
+
+static inline int get_phys_epnum(struct exynos_ss_udc_ep *udc_ep)
+{
+ return udc_ep->epnum * 2 + udc_ep->dir_in;
+}
+
+static inline int get_usb_epnum(int index)
+{
+ return index >> 1;
+}
+
+#endif /* __EXYNOS_SS_UDC_H__ */
diff --git a/drivers/usb/gadget/f_adb.c b/drivers/usb/gadget/f_adb.c
index 1629ffb..5e81173 100644
--- a/drivers/usb/gadget/f_adb.c
+++ b/drivers/usb/gadget/f_adb.c
@@ -270,15 +270,13 @@
struct adb_dev *dev = fp->private_data;
struct usb_request *req;
int r = count, xfer;
+ int maxp;
int ret;
pr_debug("adb_read(%d)\n", count);
if (!_adb_dev)
return -ENODEV;
- if (count > ADB_BULK_BUFFER_SIZE)
- return -EINVAL;
-
if (adb_lock(&dev->read_excl))
return -EBUSY;
@@ -297,6 +295,12 @@
goto done;
}
+ maxp = usb_endpoint_maxp(dev->ep_out->desc);
+ count = round_up(count, maxp);
+
+ if (count > ADB_BULK_BUFFER_SIZE)
+ return -EINVAL;
+
requeue_req:
/* queue a request */
req = dev->rx_req;
diff --git a/drivers/usb/gadget/s3c_udc.h b/drivers/usb/gadget/s3c_udc.h
new file mode 100644
index 0000000..2c21ef8
--- /dev/null
+++ b/drivers/usb/gadget/s3c_udc.h
@@ -0,0 +1,153 @@
+/*
+ * drivers/usb/gadget/s3c_udc.h
+ * Samsung S3C on-chip full/high speed USB device controllers
+ * Copyright (C) 2005 for Samsung Electronics
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef __S3C_UDC_H
+#define __S3C_UDC_H
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/types.h>
+#include <linux/version.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/proc_fs.h>
+#include <linux/mm.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+#include <asm/byteorder.h>
+#include <asm/dma.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+
+/* Max packet size */
+#if defined(CONFIG_USB_GADGET_S3C_FS)
+#define EP0_FIFO_SIZE 8
+#define EP_FIFO_SIZE 64
+#define S3C_MAX_ENDPOINTS 5
+#elif defined(CONFIG_USB_GADGET_S3C_HS) || defined(CONFIG_PLAT_S5P64XX)\
+ || defined(CONFIG_PLAT_S5PC11X) || defined(CONFIG_CPU_S5P6442)\
+ || defined(CONFIG_CPU_S5P6450) || defined(CONFIG_CPU_S5PV310)\
+ || defined(CONFIG_ARCH_EXYNOS)
+
+#define EP0_FIFO_SIZE 64
+#define EP_FIFO_SIZE 512
+#define EP_FIFO_SIZE2 1024
+#define S3C_MAX_ENDPOINTS 16
+#define DED_TX_FIFO 1 /* Dedicated NPTx fifo for s5p6440 */
+#else
+#define EP0_FIFO_SIZE 64
+#define EP_FIFO_SIZE 512
+#define EP_FIFO_SIZE2 1024
+#define S3C_MAX_ENDPOINTS 16
+#endif
+
+#define WAIT_FOR_SETUP 0
+#define DATA_STATE_XMIT 1
+#define DATA_STATE_NEED_ZLP 2
+#define WAIT_FOR_OUT_STATUS 3
+#define DATA_STATE_RECV 4
+#define RegReadErr 5
+#define FAIL_TO_SETUP 6
+#define WAIT_FOR_SETUP_NAK 7
+
+#define TEST_J_SEL 0x1
+#define TEST_K_SEL 0x2
+#define TEST_SE0_NAK_SEL 0x3
+#define TEST_PACKET_SEL 0x4
+#define TEST_FORCE_ENABLE_SEL 0x5
+
+/* ************************************************************************* */
+/* IO
+ */
+
+enum ep_type_list {
+ ep_control, ep_bulk_in, ep_bulk_out, ep_interrupt, ep_isochronous
+};
+
+struct s3c_ep {
+ struct usb_ep ep;
+ struct s3c_udc *dev;
+
+ const struct usb_endpoint_descriptor *desc;
+ struct list_head queue;
+ unsigned long pio_irqs;
+
+ u8 stopped;
+ u8 bEndpointAddress;
+ u8 bmAttributes;
+
+ enum ep_type_list ep_type;
+ u32 fifo;
+#ifdef CONFIG_USB_GADGET_S3C_FS
+ u32 csr1;
+ u32 csr2;
+#endif
+};
+
+struct s3c_request {
+ struct usb_request req;
+ struct list_head queue;
+ unsigned char mapped;
+ unsigned written_bytes;
+};
+
+struct s3c_udc {
+ struct usb_gadget gadget;
+ struct usb_gadget_driver *driver;
+ struct platform_device *dev;
+ struct clk *clk;
+ spinlock_t lock;
+
+ int ep0state;
+ struct s3c_ep ep[S3C_MAX_ENDPOINTS];
+
+ unsigned char usb_address;
+ struct usb_ctrlrequest *usb_ctrl;
+ dma_addr_t usb_ctrl_dma;
+
+ void __iomem *regs;
+ struct resource *regs_res;
+ unsigned int irq;
+ unsigned req_pending:1, req_std:1, req_config:1;
+};
+
+extern struct s3c_udc *the_controller;
+extern void samsung_cable_check_status(int flag);
+
+#define ep_is_in(EP) (((EP)->bEndpointAddress&USB_DIR_IN) == USB_DIR_IN)
+
+#define ep_index(EP) ((EP)->bEndpointAddress&0xF)
+#define ep_maxpacket(EP) ((EP)->ep.maxpacket)
+
+#endif
diff --git a/drivers/usb/gadget/s3c_udc_otg.c b/drivers/usb/gadget/s3c_udc_otg.c
new file mode 100644
index 0000000..ad85378
--- /dev/null
+++ b/drivers/usb/gadget/s3c_udc_otg.c
@@ -0,0 +1,1371 @@
+/*
+ * drivers/usb/gadget/s3c_udc_otg.c
+ * Samsung S3C on-chip full/high speed USB OTG 2.0 device controllers
+ *
+ * Copyright (C) 2008 for Samsung Electronics
+ *
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <plat/regs-otg.h>
+#include <plat/usb-phy.h>
+#include <plat/udc-hs.h>
+#include <plat/cpu.h>
+
+#include "s3c_udc.h"
+
+#undef DEBUG_S3C_UDC_SETUP
+#undef DEBUG_S3C_UDC_EP0
+#undef DEBUG_S3C_UDC_ISR
+#undef DEBUG_S3C_UDC_OUT_EP
+#undef DEBUG_S3C_UDC_IN_EP
+#undef DEBUG_S3C_UDC
+
+#define EP0_CON 0
+#define EP1_OUT 1
+#define EP2_IN 2
+#define EP3_IN 3
+#define EP_MASK 0xF
+
+#define BACK2BACK_SIZE 4
+
+#if defined(DEBUG_S3C_UDC_SETUP) || defined(DEBUG_S3C_UDC_ISR)\
+ || defined(DEBUG_S3C_UDC_OUT_EP)
+
+static char *state_names[] = {
+ "WAIT_FOR_SETUP",
+ "DATA_STATE_XMIT",
+ "DATA_STATE_NEED_ZLP",
+ "WAIT_FOR_OUT_STATUS",
+ "DATA_STATE_RECV",
+ };
+#endif
+
+#ifdef DEBUG_S3C_UDC_SETUP
+#define DEBUG_SETUP(fmt, args...) printk(fmt, ##args)
+#else
+#define DEBUG_SETUP(fmt, args...) do {} while (0)
+#endif
+
+#ifdef DEBUG_S3C_UDC_EP0
+#define DEBUG_EP0(fmt, args...) printk(fmt, ##args)
+#else
+#define DEBUG_EP0(fmt, args...) do {} while (0)
+#endif
+
+#ifdef DEBUG_S3C_UDC
+#define DEBUG(fmt, args...) printk(fmt, ##args)
+#else
+#define DEBUG(fmt, args...) do {} while (0)
+#endif
+
+#ifdef DEBUG_S3C_UDC_ISR
+#define DEBUG_ISR(fmt, args...) printk(fmt, ##args)
+#else
+#define DEBUG_ISR(fmt, args...) do {} while (0)
+#endif
+
+#ifdef DEBUG_S3C_UDC_OUT_EP
+#define DEBUG_OUT_EP(fmt, args...) printk(fmt, ##args)
+#else
+#define DEBUG_OUT_EP(fmt, args...) do {} while (0)
+#endif
+
+#ifdef DEBUG_S3C_UDC_IN_EP
+#define DEBUG_IN_EP(fmt, args...) printk(fmt, ##args)
+#else
+#define DEBUG_IN_EP(fmt, args...) do {} while (0)
+#endif
+
+#define DRIVER_DESC "S3C HS USB OTG Device Driver,"\
+ "(c) 2008-2009 Samsung Electronics"
+#define DRIVER_VERSION "15 March 2009"
+
+struct s3c_udc *the_controller;
+
+static const char driver_name[] = "s3c-hsotg";
+static const char driver_desc[] = DRIVER_DESC;
+static const char ep0name[] = "ep0-control";
+
+/* Max packet size*/
+static unsigned int ep0_fifo_size = 64;
+static unsigned int ep_fifo_size = 512;
+static unsigned int ep_fifo_size2 = 1024;
+static int reset_available = 1;
+
+/*
+ Local declarations.
+*/
+static int s3c_ep_enable(struct usb_ep *ep,
+ const struct usb_endpoint_descriptor *);
+static int s3c_ep_disable(struct usb_ep *ep);
+static struct usb_request *s3c_alloc_request(struct usb_ep *ep,
+ gfp_t gfp_flags);
+static void s3c_free_request(struct usb_ep *ep, struct usb_request *);
+
+static int s3c_queue(struct usb_ep *ep, struct usb_request *, gfp_t gfp_flags);
+static int s3c_dequeue(struct usb_ep *ep, struct usb_request *);
+static int s3c_fifo_status(struct usb_ep *ep);
+static void s3c_fifo_flush(struct usb_ep *ep);
+static void s3c_ep0_read(struct s3c_udc *dev);
+static void s3c_ep0_kick(struct s3c_udc *dev, struct s3c_ep *ep);
+static void s3c_handle_ep0(struct s3c_udc *dev);
+static int s3c_ep0_write(struct s3c_udc *dev);
+static int write_fifo_ep0(struct s3c_ep *ep, struct s3c_request *req);
+static void done(struct s3c_ep *ep,
+ struct s3c_request *req, int status);
+static void stop_activity(struct s3c_udc *dev,
+ struct usb_gadget_driver *driver);
+static int udc_enable(struct s3c_udc *dev);
+static void udc_disable(struct s3c_udc *dev);
+static void udc_set_address(struct s3c_udc *dev, unsigned char address);
+static void reset_usbd(void);
+static void reconfig_usbd(void);
+static void set_max_pktsize(struct s3c_udc *dev, enum usb_device_speed speed);
+static void nuke(struct s3c_ep *ep, int status);
+static int s3c_udc_set_halt(struct usb_ep *_ep, int value);
+static void s3c_udc_soft_connect(void);
+static void s3c_udc_soft_disconnect(void);
+
+static struct usb_ep_ops s3c_ep_ops = {
+ .enable = s3c_ep_enable,
+ .disable = s3c_ep_disable,
+
+ .alloc_request = s3c_alloc_request,
+ .free_request = s3c_free_request,
+
+ .queue = s3c_queue,
+ .dequeue = s3c_dequeue,
+
+ .set_halt = s3c_udc_set_halt,
+ .fifo_status = s3c_fifo_status,
+ .fifo_flush = s3c_fifo_flush,
+};
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+
+static const char proc_node_name[] = "driver/udc";
+
+static int
+udc_proc_read(char *page, char **start, off_t off, int count,
+ int *eof, void *_dev)
+{
+ char *buf = page;
+ struct s3c_udc *dev = _dev;
+ char *next = buf;
+ unsigned size = count;
+ unsigned long flags;
+ int t;
+
+ if (off != 0)
+ return 0;
+
+ local_irq_save(flags);
+
+ /* basic device status */
+ t = scnprintf(next, size,
+ DRIVER_DESC "\n"
+ "%s version: %s\n"
+ "Gadget driver: %s\n"
+ "\n",
+ driver_name, DRIVER_VERSION,
+ dev->driver ? dev->driver->driver.name : "(none)");
+ size -= t;
+ next += t;
+
+ local_irq_restore(flags);
+ *eof = 1;
+ return count - size;
+}
+
+#define create_proc_files() \
+ create_proc_read_entry(proc_node_name, 0, NULL, udc_proc_read, dev)
+#define remove_proc_files() \
+ remove_proc_entry(proc_node_name, NULL)
+
+#else /* !CONFIG_USB_GADGET_DEBUG_FILES */
+
+#define create_proc_files() do {} while (0)
+#define remove_proc_files() do {} while (0)
+
+#endif /* CONFIG_USB_GADGET_DEBUG_FILES */
+
+#include "s3c_udc_otg_xfer_dma.c"
+
+/*
+ * udc_disable - disable USB device controller
+ */
+static void udc_disable(struct s3c_udc *dev)
+{
+ struct platform_device *pdev = dev->dev;
+ struct s3c_hsotg_plat *pdata = pdev->dev.platform_data;
+ u32 utemp;
+ DEBUG_SETUP("%s: %p\n", __func__, dev);
+
+ disable_irq(dev->irq);
+ udc_set_address(dev, 0);
+
+ dev->ep0state = WAIT_FOR_SETUP;
+ dev->gadget.speed = USB_SPEED_UNKNOWN;
+ dev->usb_address = 0;
+
+ /* Mask the core interrupt */
+ __raw_writel(0, dev->regs + S3C_UDC_OTG_GINTMSK);
+
+ /* Put the OTG device core in the disconnected state.*/
+ utemp = __raw_readl(dev->regs + S3C_UDC_OTG_DCTL);
+ utemp |= SOFT_DISCONNECT;
+ __raw_writel(utemp, dev->regs + S3C_UDC_OTG_DCTL);
+ udelay(20);
+ if (pdata && pdata->phy_exit)
+ pdata->phy_exit(pdev, S5P_USB_PHY_DEVICE);
+ clk_disable(dev->clk);
+}
+
+/*
+ * udc_reinit - initialize software state
+ */
+static void udc_reinit(struct s3c_udc *dev)
+{
+ unsigned int i;
+
+ DEBUG_SETUP("%s: %p\n", __func__, dev);
+
+ /* device/ep0 records init */
+ INIT_LIST_HEAD(&dev->gadget.ep_list);
+ INIT_LIST_HEAD(&dev->gadget.ep0->ep_list);
+ dev->ep0state = WAIT_FOR_SETUP;
+
+ /* basic endpoint records init */
+ for (i = 0; i < S3C_MAX_ENDPOINTS; i++) {
+ struct s3c_ep *ep = &dev->ep[i];
+
+ if (i != 0)
+ list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list);
+
+ ep->desc = 0;
+ ep->stopped = 0;
+ INIT_LIST_HEAD(&ep->queue);
+ ep->pio_irqs = 0;
+ }
+
+ /* the rest was statically initialized, and is read-only */
+}
+
+#define BYTES2MAXP(x) (x / 8)
+#define MAXP2BYTES(x) (x * 8)
+
+/* until it's enabled, this UDC should be completely invisible
+ * to any USB host.
+ */
+static int udc_enable(struct s3c_udc *dev)
+{
+ struct platform_device *pdev = dev->dev;
+ struct s3c_hsotg_plat *pdata = pdev->dev.platform_data;
+ DEBUG_SETUP("%s: %p\n", __func__, dev);
+
+ enable_irq(dev->irq);
+ clk_enable(dev->clk);
+ if (pdata->phy_init)
+ pdata->phy_init(pdev, S5P_USB_PHY_DEVICE);
+ reconfig_usbd();
+
+ DEBUG_SETUP("S3C USB 2.0 OTG Controller Core Initialized : 0x%x\n",
+ __raw_readl(dev->regs + S3C_UDC_OTG_GINTMSK));
+
+ dev->gadget.speed = USB_SPEED_UNKNOWN;
+
+ return 0;
+}
+
+static int s3c_vbus_enable(struct usb_gadget *gadget, int is_active)
+{
+ unsigned long flags;
+ struct s3c_udc *dev = container_of(gadget, struct s3c_udc, gadget);
+
+ if (!is_active) {
+ spin_lock_irqsave(&dev->lock, flags);
+ stop_activity(dev, dev->driver);
+ spin_unlock_irqrestore(&dev->lock, flags);
+ udc_disable(dev);
+ } else {
+ udc_reinit(dev);
+ udc_enable(dev);
+ s3c_udc_soft_connect();
+ }
+
+ return 0;
+}
+
+static int s3c_vbus_draw(struct usb_gadget *gadget, unsigned mA)
+{
+ struct s3c_udc *dev = container_of(gadget, struct s3c_udc, gadget);
+
+ if (dev->phy)
+ return usb_phy_set_power(dev->phy, mA);
+
+ return 0;
+}
+
+/*
+ Register entry point for the peripheral controller driver.
+*/
+static int s3c_udc_start(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver)
+{
+ struct s3c_udc *dev = the_controller;
+
+ DEBUG_SETUP("%s: %s\n", __func__, driver->driver.name);
+
+ if (!driver
+ || driver->max_speed < USB_SPEED_FULL
+ || !driver->disconnect || !driver->setup)
+ return -EINVAL;
+ if (!dev)
+ return -ENODEV;
+ if (dev->driver)
+ return -EBUSY;
+
+ /* first hook up the driver ... */
+ dev->driver = driver;
+ dev->gadget.dev.driver = &driver->driver;
+
+ printk(KERN_INFO "bound driver '%s'\n",
+ driver->driver.name);
+ udc_enable(dev);
+
+ return 0;
+}
+
+/*
+ Unregister entry point for the peripheral controller driver.
+*/
+static int s3c_udc_stop(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver)
+{
+ struct s3c_udc *dev = the_controller;
+ unsigned long flags;
+
+ if (!dev)
+ return -ENODEV;
+ if (!driver || driver != dev->driver)
+ return -EINVAL;
+
+ spin_lock_irqsave(&dev->lock, flags);
+ dev->driver = NULL;
+ stop_activity(dev, driver);
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ udc_disable(dev);
+
+ printk(KERN_INFO "Unregistered gadget driver '%s'\n",
+ driver->driver.name);
+
+ return 0;
+}
+
+/*
+ * done - retire a request; caller blocked irqs
+ */
+static void done(struct s3c_ep *ep, struct s3c_request *req, int status)
+{
+ unsigned int stopped = ep->stopped;
+ struct device *dev = &the_controller->dev->dev;
+
+ DEBUG("%s: %s %p, req = %p, stopped = %d\n",
+ __func__, ep->ep.name, ep, &req->req, stopped);
+
+ list_del_init(&req->queue);
+
+ if (likely(req->req.status == -EINPROGRESS))
+ req->req.status = status;
+ else
+ status = req->req.status;
+
+ if (req->mapped) {
+ dma_unmap_single(dev, req->req.dma, req->req.length,
+ (ep->bEndpointAddress & USB_DIR_IN) ?
+ DMA_TO_DEVICE : DMA_FROM_DEVICE);
+ req->req.dma = DMA_ADDR_INVALID;
+ req->mapped = 0;
+ }
+
+ if (status && status != -ESHUTDOWN) {
+ DEBUG("complete %s req %p stat %d len %u/%u\n",
+ ep->ep.name, &req->req, status,
+ req->req.actual, req->req.length);
+ }
+
+ /* don't modify queue heads during completion callback */
+ ep->stopped = 1;
+
+ spin_unlock(&ep->dev->lock);
+ req->req.complete(&ep->ep, &req->req);
+ spin_lock(&ep->dev->lock);
+
+ ep->stopped = stopped;
+}
+
+/*
+ * nuke - dequeue ALL requests
+ */
+static void nuke(struct s3c_ep *ep, int status)
+{
+ struct s3c_request *req;
+
+ DEBUG("%s: %s %p\n", __func__, ep->ep.name, ep);
+
+ /* called with irqs blocked */
+ while (!list_empty(&ep->queue)) {
+ req = list_entry(ep->queue.next, struct s3c_request, queue);
+ done(ep, req, status);
+ }
+}
+
+static void stop_activity(struct s3c_udc *dev,
+ struct usb_gadget_driver *driver)
+{
+ int i;
+
+ /* don't disconnect drivers more than once */
+ if (dev->gadget.speed == USB_SPEED_UNKNOWN)
+ driver = 0;
+ dev->gadget.speed = USB_SPEED_UNKNOWN;
+
+ /* prevent new request submissions, kill any outstanding requests */
+ for (i = 0; i < S3C_MAX_ENDPOINTS; i++) {
+ struct s3c_ep *ep = &dev->ep[i];
+ ep->stopped = 1;
+ nuke(ep, -ESHUTDOWN);
+ }
+
+ /* report disconnect; the driver is already quiesced */
+ if (driver) {
+ spin_unlock(&dev->lock);
+ driver->disconnect(&dev->gadget);
+ spin_lock(&dev->lock);
+ }
+
+ /* re-init driver-visible data structures */
+ udc_reinit(dev);
+}
+
+static void reset_usbd(void)
+{
+ struct s3c_udc *dev = the_controller;
+ unsigned int utemp;
+#ifdef DED_TX_FIFO
+ int i;
+
+ for (i = 0; i < S3C_MAX_ENDPOINTS; i++) {
+ utemp = __raw_readl(dev->regs + S3C_UDC_OTG_DIEPCTL(i));
+
+ if (utemp & DEPCTL_EPENA)
+ __raw_writel(utemp|DEPCTL_EPDIS|DEPCTL_SNAK,
+ dev->regs + S3C_UDC_OTG_DIEPCTL(i));
+
+ /* OUT EP0 cannot be disabled */
+ if (i != 0) {
+ utemp = __raw_readl(dev->regs + S3C_UDC_OTG_DOEPCTL(i));
+
+ if (utemp & DEPCTL_EPENA)
+ __raw_writel(utemp|DEPCTL_EPDIS|DEPCTL_SNAK,
+ dev->regs + S3C_UDC_OTG_DOEPCTL(i));
+ }
+ }
+#endif
+
+ /* 5. Configure OTG Core to initial settings of device mode.*/
+ __raw_writel(1<<18|0x0<<0,
+ dev->regs + S3C_UDC_OTG_DCFG);
+
+ mdelay(1);
+
+ /* 6. Unmask the core interrupts*/
+ __raw_writel(GINTMSK_INIT, dev->regs + S3C_UDC_OTG_GINTMSK);
+
+ /* 7. Set NAK bit of OUT EP0*/
+ __raw_writel(DEPCTL_SNAK,
+ dev->regs + S3C_UDC_OTG_DOEPCTL(EP0_CON));
+
+ /* 8. Unmask EPO interrupts*/
+ __raw_writel(((1<<EP0_CON)<<DAINT_OUT_BIT)|(1<<EP0_CON),
+ dev->regs + S3C_UDC_OTG_DAINTMSK);
+
+ /* 9. Unmask device OUT EP common interrupts*/
+ __raw_writel(DOEPMSK_INIT, dev->regs + S3C_UDC_OTG_DOEPMSK);
+
+ /* 10. Unmask device IN EP common interrupts*/
+ __raw_writel(DIEPMSK_INIT, dev->regs + S3C_UDC_OTG_DIEPMSK);
+
+ /* 11. Set Rx FIFO Size (in 32-bit words) */
+ __raw_writel(RX_FIFO_SIZE, dev->regs + S3C_UDC_OTG_GRXFSIZ);
+
+ /* 12. Set Non Periodic Tx FIFO Size*/
+ __raw_writel((NPTX_FIFO_SIZE) << 16 | (NPTX_FIFO_START_ADDR) << 0,
+ dev->regs + S3C_UDC_OTG_GNPTXFSIZ);
+
+#ifdef DED_TX_FIFO
+ for (i = 1; i < S3C_MAX_ENDPOINTS; i++)
+ __raw_writel((PTX_FIFO_SIZE) << 16 |
+ (NPTX_FIFO_START_ADDR + NPTX_FIFO_SIZE
+ + PTX_FIFO_SIZE*(i-1)) << 0,
+ dev->regs + S3C_UDC_OTG_DIEPTXF(i));
+#endif
+
+ /* Flush the RX FIFO */
+ __raw_writel(0x10, dev->regs + S3C_UDC_OTG_GRSTCTL);
+ while (__raw_readl(dev->regs + S3C_UDC_OTG_GRSTCTL) & 0x10)
+ ;
+
+ /* Flush all the Tx FIFO's */
+ __raw_writel(0x10<<6, dev->regs + S3C_UDC_OTG_GRSTCTL);
+ __raw_writel((0x10<<6)|0x20, dev->regs + S3C_UDC_OTG_GRSTCTL);
+ while (__raw_readl(dev->regs + S3C_UDC_OTG_GRSTCTL) & 0x20)
+ ;
+
+ /* 13. Clear NAK bit of OUT EP0*/
+ /* For Slave mode*/
+ __raw_writel(DEPCTL_CNAK,
+ dev->regs + S3C_UDC_OTG_DOEPCTL(EP0_CON));
+
+ /* 14. Initialize OTG Link Core.*/
+ __raw_writel(GAHBCFG_INIT, dev->regs + S3C_UDC_OTG_GAHBCFG);
+}
+
+static void reconfig_usbd(void)
+{
+ struct s3c_udc *dev = the_controller;
+ unsigned int utemp;
+
+ /* 2. Soft-reset OTG Core and then unreset again. */
+ __raw_writel(CORE_SOFT_RESET, dev->regs + S3C_UDC_OTG_GRSTCTL);
+
+ utemp = (0<<15 /* PHY Low Power Clock sel */
+ |1<<14 /* Non-Periodic TxFIFO Rewind Enable */
+ |0<<9 /* [0:HNP disable, 1:HNP enable] */
+ |0<<8 /* [ 0:SRP disable, 1:SRP enable] */
+ |0<<7 /* Ulpi DDR sel */
+ |0<<6 /* 0: high speed utmi+, 1: full speed serial */
+ |0<<4 /* 0: utmi+, 1:ulpi */
+ |0x7<<0); /* HS/FS Timeout */
+ /* [13:10] Turnaround time 0x5:16-bit 0x9:8-bit UTMI+ */
+ /* [3] phy i/f 0:8bit, 1:16bit */
+ if (soc_is_exynos4210())
+ utemp |= (0x5<<10 | 1<<3);
+ else
+ utemp |= (0x9<<10 | 0<<3);
+ __raw_writel(utemp, dev->regs + S3C_UDC_OTG_GUSBCFG);
+
+ /* 3. Put the OTG device core in the disconnected state.*/
+ utemp = __raw_readl(dev->regs + S3C_UDC_OTG_DCTL);
+ utemp |= SOFT_DISCONNECT;
+ __raw_writel(utemp, dev->regs + S3C_UDC_OTG_DCTL);
+
+ reset_usbd();
+}
+
+static void set_max_pktsize(struct s3c_udc *dev, enum usb_device_speed speed)
+{
+ unsigned int ep_ctrl;
+ int i;
+
+ if (speed == USB_SPEED_HIGH) {
+ ep0_fifo_size = 64;
+ ep_fifo_size = 512;
+ ep_fifo_size2 = 1024;
+ dev->gadget.speed = USB_SPEED_HIGH;
+ } else {
+ ep0_fifo_size = 64;
+ ep_fifo_size = 64;
+ ep_fifo_size2 = 1023;
+ dev->gadget.speed = USB_SPEED_FULL;
+ }
+
+ dev->ep[0].ep.maxpacket = ep0_fifo_size;
+ for (i = 1; i < S3C_MAX_ENDPOINTS; i++) {
+ /* fullspeed limitations don't apply to isochronous endpoints */
+ if (dev->ep[i].bmAttributes == USB_ENDPOINT_XFER_ISOC)
+ dev->ep[i].ep.maxpacket = ep_fifo_size2;
+ else
+ dev->ep[i].ep.maxpacket = ep_fifo_size;
+ }
+
+ /* EP0 - Control IN (64 bytes)*/
+ ep_ctrl = __raw_readl(dev->regs + S3C_UDC_OTG_DIEPCTL(EP0_CON));
+ __raw_writel(ep_ctrl|(0<<0), dev->regs + S3C_UDC_OTG_DIEPCTL(EP0_CON));
+
+ /* EP0 - Control OUT (64 bytes)*/
+ ep_ctrl = __raw_readl(dev->regs + S3C_UDC_OTG_DOEPCTL(EP0_CON));
+ __raw_writel(ep_ctrl|(0<<0), dev->regs + S3C_UDC_OTG_DOEPCTL(EP0_CON));
+}
+
+static int s3c_ep_enable(struct usb_ep *_ep,
+ const struct usb_endpoint_descriptor *desc)
+{
+ struct s3c_ep *ep;
+ struct s3c_udc *dev;
+ unsigned long flags;
+
+ DEBUG("%s: %p\n", __func__, _ep);
+ ep = container_of(_ep, struct s3c_ep, ep);
+ if (!_ep || !desc || ep->desc || _ep->name == ep0name
+ || desc->bDescriptorType != USB_DT_ENDPOINT
+ || ep->bEndpointAddress != desc->bEndpointAddress
+ || ep_maxpacket(ep) < le16_to_cpu(desc->wMaxPacketSize)) {
+
+ DEBUG("%s: bad ep or descriptor\n", __func__);
+ return -EINVAL;
+ }
+
+ /* xfer types must match, except that interrupt ~= bulk */
+ if (ep->bmAttributes !=
+ (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+ && ep->bmAttributes != USB_ENDPOINT_XFER_BULK
+ && desc->bmAttributes != USB_ENDPOINT_XFER_INT) {
+
+ DEBUG("%s: %s type mismatch\n", __func__, _ep->name);
+ return -EINVAL;
+ }
+
+ /* hardware _could_ do smaller, but driver doesn't */
+ if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK
+ && le16_to_cpu(desc->wMaxPacketSize) != ep_maxpacket(ep))
+ || !desc->wMaxPacketSize) {
+
+ DEBUG("%s: bad %s maxpacket\n", __func__, _ep->name);
+ return -ERANGE;
+ }
+
+ dev = ep->dev;
+ if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) {
+
+ DEBUG("%s: bogus device state\n", __func__);
+ return -ESHUTDOWN;
+ }
+
+ ep->stopped = 0;
+ ep->desc = desc;
+ ep->pio_irqs = 0;
+ ep->ep.maxpacket = le16_to_cpu(desc->wMaxPacketSize);
+
+ /* Reset halt state */
+ s3c_udc_set_halt(_ep, 0);
+
+ spin_lock_irqsave(&ep->dev->lock, flags);
+ s3c_udc_ep_activate(ep);
+ spin_unlock_irqrestore(&ep->dev->lock, flags);
+
+ DEBUG("%s: enabled %s, stopped = %d, maxpacket = %d\n",
+ __func__, _ep->name, ep->stopped, ep->ep.maxpacket);
+ return 0;
+}
+
+/** Disable EP
+ */
+static int s3c_ep_disable(struct usb_ep *_ep)
+{
+ struct s3c_ep *ep;
+ unsigned long flags;
+
+ DEBUG("%s: %p\n", __func__, _ep);
+
+ ep = container_of(_ep, struct s3c_ep, ep);
+ if (!_ep || !ep->desc) {
+ DEBUG("%s: %s not enabled\n", __func__,
+ _ep ? ep->ep.name : NULL);
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&ep->dev->lock, flags);
+
+ /* Nuke all pending requests */
+ nuke(ep, -ESHUTDOWN);
+
+ ep->desc = 0;
+ ep->stopped = 1;
+
+ spin_unlock_irqrestore(&ep->dev->lock, flags);
+
+ DEBUG("%s: disabled %s\n", __func__, _ep->name);
+ return 0;
+}
+
+static struct usb_request *s3c_alloc_request(struct usb_ep *ep,
+ gfp_t gfp_flags)
+{
+ struct s3c_request *req;
+
+ DEBUG("%s: %s %p\n", __func__, ep->name, ep);
+
+ req = kmalloc(sizeof *req, gfp_flags);
+ if (!req)
+ return 0;
+
+ memset(req, 0, sizeof *req);
+ INIT_LIST_HEAD(&req->queue);
+ return &req->req;
+}
+
+static void s3c_free_request(struct usb_ep *ep, struct usb_request *_req)
+{
+ struct s3c_request *req;
+
+ DEBUG("%s: %p\n", __func__, ep);
+
+ req = container_of(_req, struct s3c_request, req);
+ WARN_ON(!list_empty(&req->queue));
+ kfree(req);
+}
+
+/* dequeue JUST ONE request */
+static int s3c_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+ struct s3c_ep *ep;
+ struct s3c_request *req;
+ unsigned long flags;
+
+ DEBUG("%s: %p\n", __func__, _ep);
+
+ ep = container_of(_ep, struct s3c_ep, ep);
+ if (!_ep || ep->ep.name == ep0name)
+ return -EINVAL;
+
+ spin_lock_irqsave(&ep->dev->lock, flags);
+
+ /* make sure it's actually queued on this endpoint */
+ list_for_each_entry(req, &ep->queue, queue) {
+ if (&req->req == _req)
+ break;
+ }
+ if (&req->req != _req) {
+ spin_unlock_irqrestore(&ep->dev->lock, flags);
+ return -EINVAL;
+ }
+
+ done(ep, req, -ECONNRESET);
+
+ spin_unlock_irqrestore(&ep->dev->lock, flags);
+ return 0;
+}
+
+/** Return bytes in EP FIFO
+ */
+static int s3c_fifo_status(struct usb_ep *_ep)
+{
+ int count = 0;
+ struct s3c_ep *ep;
+
+ ep = container_of(_ep, struct s3c_ep, ep);
+ if (!_ep) {
+ DEBUG("%s: bad ep\n", __func__);
+ return -ENODEV;
+ }
+
+ DEBUG("%s: %d\n", __func__, ep_index(ep));
+
+ /* LPD can't report unclaimed bytes from IN fifos */
+ if (ep_is_in(ep))
+ return -EOPNOTSUPP;
+
+ return count;
+}
+
+/** Flush EP FIFO
+ */
+static void s3c_fifo_flush(struct usb_ep *_ep)
+{
+ struct s3c_ep *ep;
+
+ ep = container_of(_ep, struct s3c_ep, ep);
+ if (unlikely(!_ep || (!ep->desc && ep->ep.name != ep0name))) {
+ DEBUG("%s: bad ep\n", __func__);
+ return;
+ }
+
+ DEBUG("%s: %d\n", __func__, ep_index(ep));
+}
+
+/* ---------------------------------------------------------------------------
+ * device-scoped parts of the api to the usb controller hardware
+ * ---------------------------------------------------------------------------
+ */
+
+static int s3c_udc_get_frame(struct usb_gadget *_gadget)
+{
+ struct s3c_udc *dev = container_of(_gadget, struct s3c_udc, gadget);
+ /*fram count number [21:8]*/
+ unsigned int frame = __raw_readl(dev->regs + S3C_UDC_OTG_DSTS);
+
+ DEBUG("%s: %p\n", __func__, _gadget);
+ return frame & 0x3ff00;
+}
+
+static int s3c_udc_wakeup(struct usb_gadget *_gadget)
+{
+ DEBUG("%s: %p\n", __func__, _gadget);
+ return -ENOTSUPP;
+}
+
+static void s3c_udc_soft_connect(void)
+{
+ struct s3c_udc *dev = the_controller;
+ u32 uTemp;
+
+ DEBUG("[%s]\n", __func__);
+ uTemp = __raw_readl(dev->regs + S3C_UDC_OTG_DCTL);
+ uTemp = uTemp & ~SOFT_DISCONNECT;
+ __raw_writel(uTemp, dev->regs + S3C_UDC_OTG_DCTL);
+}
+
+static void s3c_udc_soft_disconnect(void)
+{
+ struct s3c_udc *dev = the_controller;
+ u32 uTemp;
+ unsigned long flags;
+
+ DEBUG("[%s]\n", __func__);
+ uTemp = __raw_readl(dev->regs + S3C_UDC_OTG_DCTL);
+ uTemp |= SOFT_DISCONNECT;
+ __raw_writel(uTemp, dev->regs + S3C_UDC_OTG_DCTL);
+
+ spin_lock_irqsave(&dev->lock, flags);
+ stop_activity(dev, dev->driver);
+ spin_unlock_irqrestore(&dev->lock, flags);
+}
+
+static int s3c_udc_pullup(struct usb_gadget *gadget, int is_on)
+{
+ if (is_on)
+ s3c_udc_soft_connect();
+ else
+ s3c_udc_soft_disconnect();
+ return 0;
+}
+
+static const struct usb_gadget_ops s3c_udc_ops = {
+ .get_frame = s3c_udc_get_frame,
+ .wakeup = s3c_udc_wakeup,
+ /* current versions must always be self-powered */
+ .pullup = s3c_udc_pullup,
+ .vbus_session = s3c_vbus_enable,
+ .vbus_draw = s3c_vbus_draw,
+ .udc_start = s3c_udc_start,
+ .udc_stop = s3c_udc_stop,
+};
+
+static void nop_release(struct device *dev)
+{
+ DEBUG("%s %s\n", __func__, dev->bus_id);
+}
+
+static struct s3c_udc memory = {
+ .usb_address = 0,
+
+ .gadget = {
+ .ops = &s3c_udc_ops,
+ .ep0 = &memory.ep[0].ep,
+ .name = driver_name,
+ .dev = {
+ .release = nop_release,
+ },
+ },
+
+ /* control endpoint */
+ .ep[0] = {
+ .ep = {
+ .name = ep0name,
+ .ops = &s3c_ep_ops,
+ .maxpacket = EP0_FIFO_SIZE,
+ },
+ .dev = &memory,
+
+ .bEndpointAddress = 0,
+ .bmAttributes = 0,
+
+ .ep_type = ep_control,
+ .fifo = (unsigned int) S3C_UDC_OTG_EP0_FIFO,
+ },
+
+ /* first group of endpoints */
+ .ep[1] = {
+ .ep = {
+ .name = "ep1in-bulk",
+ .ops = &s3c_ep_ops,
+ .maxpacket = EP_FIFO_SIZE,
+ },
+ .dev = &memory,
+
+ .bEndpointAddress = USB_DIR_IN | 1,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+
+ .ep_type = ep_bulk_out,
+ .fifo = (unsigned int) S3C_UDC_OTG_EP1_FIFO,
+ },
+
+ .ep[2] = {
+ .ep = {
+ .name = "ep2out-bulk",
+ .ops = &s3c_ep_ops,
+ .maxpacket = EP_FIFO_SIZE,
+ },
+ .dev = &memory,
+
+ .bEndpointAddress = USB_DIR_OUT | 2,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+
+ .ep_type = ep_bulk_in,
+ .fifo = (unsigned int) S3C_UDC_OTG_EP2_FIFO,
+ },
+
+ .ep[3] = {
+ .ep = {
+ .name = "ep3in-int",
+ .ops = &s3c_ep_ops,
+ .maxpacket = EP_FIFO_SIZE,
+ },
+ .dev = &memory,
+
+ .bEndpointAddress = USB_DIR_IN | 3,
+ .bmAttributes = USB_ENDPOINT_XFER_INT,
+
+ .ep_type = ep_interrupt,
+ .fifo = (unsigned int) S3C_UDC_OTG_EP3_FIFO,
+ },
+ .ep[4] = {
+ .ep = {
+ .name = "ep4out-bulk",
+ .ops = &s3c_ep_ops,
+ .maxpacket = EP_FIFO_SIZE,
+ },
+ .dev = &memory,
+
+ .bEndpointAddress = USB_DIR_OUT | 4,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+
+ .ep_type = ep_bulk_out,
+ .fifo = (unsigned int) S3C_UDC_OTG_EP4_FIFO,
+ },
+ .ep[5] = {
+ .ep = {
+ .name = "ep5in-bulk",
+ .ops = &s3c_ep_ops,
+ .maxpacket = EP_FIFO_SIZE,
+ },
+ .dev = &memory,
+
+ .bEndpointAddress = USB_DIR_IN | 5,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+
+ .ep_type = ep_bulk_in,
+ .fifo = (unsigned int) S3C_UDC_OTG_EP5_FIFO,
+ },
+ .ep[6] = {
+ .ep = {
+ .name = "ep6in-int",
+ .ops = &s3c_ep_ops,
+ .maxpacket = EP_FIFO_SIZE,
+ },
+ .dev = &memory,
+
+ .bEndpointAddress = USB_DIR_IN | 6,
+ .bmAttributes = USB_ENDPOINT_XFER_INT,
+
+ .ep_type = ep_interrupt,
+ .fifo = (unsigned int) S3C_UDC_OTG_EP6_FIFO,
+ },
+ .ep[7] = {
+ .ep = {
+ .name = "ep7out-bulk",
+ .ops = &s3c_ep_ops,
+ .maxpacket = EP_FIFO_SIZE,
+ },
+ .dev = &memory,
+
+ .bEndpointAddress = USB_DIR_OUT | 7,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+
+ .ep_type = ep_bulk_out,
+ .fifo = (unsigned int) S3C_UDC_OTG_EP7_FIFO,
+ },
+ .ep[8] = {
+ .ep = {
+ .name = "ep8in-bulk",
+ .ops = &s3c_ep_ops,
+ .maxpacket = EP_FIFO_SIZE,
+ },
+ .dev = &memory,
+
+ .bEndpointAddress = USB_DIR_IN | 8,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+
+ .ep_type = ep_bulk_in,
+ .fifo = (unsigned int) S3C_UDC_OTG_EP8_FIFO,
+ },
+ .ep[9] = {
+ .ep = {
+ .name = "ep9in-int",
+ .ops = &s3c_ep_ops,
+ .maxpacket = EP_FIFO_SIZE,
+ },
+ .dev = &memory,
+
+ .bEndpointAddress = USB_DIR_IN | 9,
+ .bmAttributes = USB_ENDPOINT_XFER_INT,
+
+ .ep_type = ep_interrupt,
+ .fifo = (unsigned int) S3C_UDC_OTG_EP9_FIFO,
+ },
+ .ep[10] = {
+ .ep = {
+ .name = "ep10out-bulk",
+ .ops = &s3c_ep_ops,
+ .maxpacket = EP_FIFO_SIZE,
+ },
+ .dev = &memory,
+
+ .bEndpointAddress = USB_DIR_OUT | 10,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+
+ .ep_type = ep_bulk_out,
+ .fifo = (unsigned int) S3C_UDC_OTG_EP10_FIFO,
+ },
+ .ep[11] = {
+ .ep = {
+ .name = "ep11in-bulk",
+ .ops = &s3c_ep_ops,
+ .maxpacket = EP_FIFO_SIZE,
+ },
+ .dev = &memory,
+
+ .bEndpointAddress = USB_DIR_IN | 11,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+
+ .ep_type = ep_bulk_in,
+ .fifo = (unsigned int) S3C_UDC_OTG_EP11_FIFO,
+ },
+ .ep[12] = {
+ .ep = {
+ .name = "ep12in-int",
+ .ops = &s3c_ep_ops,
+ .maxpacket = EP_FIFO_SIZE,
+ },
+ .dev = &memory,
+
+ .bEndpointAddress = USB_DIR_IN | 12,
+ .bmAttributes = USB_ENDPOINT_XFER_INT,
+
+ .ep_type = ep_interrupt,
+ .fifo = (unsigned int) S3C_UDC_OTG_EP12_FIFO,
+ },
+ .ep[13] = {
+ .ep = {
+ .name = "ep13out-bulk",
+ .ops = &s3c_ep_ops,
+ .maxpacket = EP_FIFO_SIZE,
+ },
+ .dev = &memory,
+
+ .bEndpointAddress = USB_DIR_OUT | 13,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+
+ .ep_type = ep_bulk_out,
+ .fifo = (unsigned int) S3C_UDC_OTG_EP13_FIFO,
+ },
+ .ep[14] = {
+ .ep = {
+ .name = "ep14in-bulk",
+ .ops = &s3c_ep_ops,
+ .maxpacket = EP_FIFO_SIZE,
+ },
+ .dev = &memory,
+
+ .bEndpointAddress = USB_DIR_IN | 14,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+
+ .ep_type = ep_bulk_in,
+ .fifo = (unsigned int) S3C_UDC_OTG_EP14_FIFO,
+ },
+ .ep[15] = {
+ .ep = {
+ .name = "ep15-iso",
+ .ops = &s3c_ep_ops,
+ .maxpacket = EP_FIFO_SIZE2,
+ },
+ .dev = &memory,
+
+ .bEndpointAddress = USB_DIR_IN | 15,
+ .bmAttributes = USB_ENDPOINT_XFER_ISOC,
+
+ .ep_type = ep_isochronous,
+ .fifo = (unsigned int) S3C_UDC_OTG_EP15_FIFO,
+ },
+};
+
+/*
+ * probe - binds to the platform device
+ */
+static int s3c_udc_probe(struct platform_device *pdev)
+{
+ struct s3c_hsotg_plat *pdata;
+ struct s3c_udc *dev = &memory;
+ struct resource *res;
+ unsigned int irq;
+ int retval;
+
+ DEBUG("%s: %p\n", __func__, pdev);
+
+ pdata = pdev->dev.platform_data;
+ if (!pdata) {
+ dev_err(&pdev->dev, "No platform data defined\n");
+ return -EINVAL;
+ }
+
+ spin_lock_init(&dev->lock);
+ dev->dev = pdev;
+
+ dev->gadget.dev.parent = &pdev->dev;
+ dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
+ dev_set_name(&dev->gadget.dev, "gadget");
+
+ dev->gadget.speed = USB_SPEED_UNKNOWN;
+ dev->gadget.max_speed = USB_SPEED_HIGH;
+ dev->gadget.is_otg = 0;
+ dev->gadget.is_a_peripheral = 0;
+ dev->gadget.b_hnp_enable = 0;
+ dev->gadget.a_hnp_support = 0;
+ dev->gadget.a_alt_hnp_support = 0;
+
+ the_controller = dev;
+ platform_set_drvdata(pdev, dev);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ DEBUG(KERN_ERR "cannot find register resource 0\n");
+ return -EINVAL;
+ }
+
+ dev->regs_res = request_mem_region(res->start, resource_size(res),
+ dev_name(&pdev->dev));
+ if (!dev->regs_res) {
+ DEBUG(KERN_ERR "cannot reserve registers\n");
+ return -ENOENT;
+ }
+
+ dev->regs = ioremap(res->start, resource_size(res));
+ if (!dev->regs) {
+ DEBUG(KERN_ERR "cannot map registers\n");
+ retval = -ENXIO;
+ goto err_regs_res;
+ }
+
+ udc_reinit(dev);
+
+ dev->clk = clk_get(&pdev->dev, "usbotg");
+ if (IS_ERR(dev->clk)) {
+ dev_err(&pdev->dev, "Failed to get clock\n");
+ retval = -ENXIO;
+ goto err_irq;
+ }
+ clk_enable(dev->clk);
+
+ dev->usb_ctrl = dma_alloc_coherent(&pdev->dev,
+ sizeof(struct usb_ctrlrequest)*BACK2BACK_SIZE,
+ &dev->usb_ctrl_dma, GFP_KERNEL);
+
+ if (!dev->usb_ctrl) {
+ DEBUG(KERN_ERR "%s: can't get usb_ctrl dma memory\n",
+ driver_name);
+ retval = -ENOMEM;
+ goto err_clk;
+ }
+
+ /* Mask any interrupt left unmasked by the bootloader */
+ __raw_writel(0, dev->regs + S3C_UDC_OTG_GINTMSK);
+
+ /* irq setup after old hardware state is cleaned up */
+ irq = platform_get_irq(pdev, 0);
+ retval =
+ request_irq(irq, s3c_udc_irq, 0, driver_name, dev);
+
+ if (retval != 0) {
+ DEBUG(KERN_ERR "%s: can't get irq %i, err %d\n", driver_name,
+ dev->irq, retval);
+ retval = -EBUSY;
+ goto err_regs;
+ }
+ dev->irq = irq;
+
+ disable_irq(dev->irq);
+ clk_disable(dev->clk);
+
+ retval = device_register(&dev->gadget.dev);
+ if (retval) {
+ dev_err(&pdev->dev, "failed to register gadget device\n");
+ goto err_add_device;
+ }
+
+ retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget);
+ if (retval) {
+ dev_err(&pdev->dev, "failed to add gadget to udc list\n");
+ goto err_add_udc;
+ }
+
+ create_proc_files();
+
+ return retval;
+
+err_add_udc:
+ device_unregister(&dev->gadget.dev);
+err_add_device:
+ dma_free_coherent(&pdev->dev,
+ sizeof(struct usb_ctrlrequest)*BACK2BACK_SIZE,
+ dev->usb_ctrl, dev->usb_ctrl_dma);
+err_clk:
+ clk_put(dev->clk);
+err_irq:
+ free_irq(dev->irq, dev);
+err_regs:
+ iounmap(dev->regs);
+err_regs_res:
+ release_mem_region(res->start, resource_size(res));
+ return retval;
+}
+
+static int s3c_udc_remove(struct platform_device *pdev)
+{
+ struct s3c_udc *dev = platform_get_drvdata(pdev);
+ struct resource *res;
+
+ DEBUG("%s: %p\n", __func__, pdev);
+
+ remove_proc_files();
+ usb_gadget_unregister_driver(dev->driver);
+ usb_del_gadget_udc(&dev->gadget);
+ device_unregister(&dev->gadget.dev);
+
+ clk_put(dev->clk);
+ if (dev->usb_ctrl)
+ dma_free_coherent(&pdev->dev,
+ sizeof(struct usb_ctrlrequest)*BACK2BACK_SIZE,
+ dev->usb_ctrl, dev->usb_ctrl_dma);
+ free_irq(dev->irq, dev);
+ iounmap(dev->regs);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(res->start, resource_size(res));
+
+ platform_set_drvdata(pdev, 0);
+
+ the_controller = 0;
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int s3c_udc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct s3c_udc *dev = the_controller;
+ int i;
+
+ if (dev->driver) {
+ if (dev->driver->suspend)
+ dev->driver->suspend(&dev->gadget);
+
+ /* Terminate any outstanding requests */
+ for (i = 0; i < S3C_MAX_ENDPOINTS; i++) {
+ struct s3c_ep *ep = &dev->ep[i];
+ unsigned long flags;
+
+ if (ep->dev != NULL)
+ spin_lock_irqsave(&ep->dev->lock, flags);
+ ep->stopped = 1;
+ nuke(ep, -ESHUTDOWN);
+ if (ep->dev != NULL)
+ spin_unlock_irqrestore(&ep->dev->lock, flags);
+ }
+
+ if (dev->driver->disconnect)
+ dev->driver->disconnect(&dev->gadget);
+
+ udc_disable(dev);
+ }
+
+ return 0;
+}
+
+static int s3c_udc_resume(struct platform_device *pdev)
+{
+ struct s3c_udc *dev = the_controller;
+
+ if (dev->driver) {
+ udc_reinit(dev);
+ udc_enable(dev);
+ s3c_udc_soft_connect();
+
+ if (dev->driver->resume)
+ dev->driver->resume(&dev->gadget);
+ }
+
+ return 0;
+}
+#else
+#define s3c_udc_suspend NULL
+#define s3c_udc_resume NULL
+#endif /* CONFIG_PM */
+
+/*-------------------------------------------------------------------------*/
+static struct platform_driver s3c_udc_driver = {
+ .probe = s3c_udc_probe,
+ .remove = s3c_udc_remove,
+ .suspend = s3c_udc_suspend,
+ .resume = s3c_udc_resume,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "s3c-hsotg",
+ },
+};
+
+static int __init udc_init(void)
+{
+ int ret;
+
+ ret = platform_driver_register(&s3c_udc_driver);
+ if (!ret)
+ printk(KERN_INFO "%s : %s\n"
+ "%s : version %s\n",
+ driver_name, DRIVER_DESC,
+ driver_name, DRIVER_VERSION);
+
+ return ret;
+}
+
+static void __exit udc_exit(void)
+{
+ platform_driver_unregister(&s3c_udc_driver);
+ printk(KERN_INFO "Unloaded %s version %s\n",
+ driver_name, DRIVER_VERSION);
+}
+
+module_init(udc_init);
+module_exit(udc_exit);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Samsung");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/gadget/s3c_udc_otg_xfer_dma.c b/drivers/usb/gadget/s3c_udc_otg_xfer_dma.c
new file mode 100644
index 0000000..82fbdf3
--- /dev/null
+++ b/drivers/usb/gadget/s3c_udc_otg_xfer_dma.c
@@ -0,0 +1,1402 @@
+/* drivers/usb/gadget/s3c_udc_otg_xfer_dma.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Samsung S3C on-chip full/high speed USB OTG 2.0 device controllers
+ *
+ * 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.
+ */
+
+#define GINTMSK_INIT (INT_OUT_EP | INT_IN_EP | INT_RESUME |\
+ INT_ENUMDONE|INT_RESET|INT_SUSPEND)
+#define DOEPMSK_INIT (CTRL_OUT_EP_SETUP_PHASE_DONE | AHB_ERROR |\
+ TRANSFER_DONE)
+#define DIEPMSK_INIT (NON_ISO_IN_EP_TIMEOUT|AHB_ERROR|TRANSFER_DONE)
+#define GAHBCFG_INIT (PTXFE_HALF | NPTXFE_HALF | MODE_DMA | BURST_INCR4 |\
+ GBL_INT_UNMASK)
+
+#define DMA_ADDR_INVALID (~(dma_addr_t)0)
+
+/* Bulk-Only Mass Storage Reset (class-specific request) */
+#define GET_MAX_LUN_REQUEST 0xFE
+#define BOT_RESET_REQUEST 0xFF
+
+/* TEST MODE in set_feature request */
+#define TEST_SELECTOR_MASK 0xFF
+#define TEST_PKT_SIZE 53
+
+static u8 clear_feature_num;
+static int clear_feature_flag;
+static int set_conf_done;
+static u16 g_status __aligned(8);
+
+static u8 test_pkt[TEST_PKT_SIZE] __aligned(8) = {
+ /* JKJKJKJK x 9 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* JJKKJJKK x 8 */
+ 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
+ /* JJJJKKKK x 8 */
+ 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE,
+ /* JJJJJJJKKKKKKK x8 - '1' */
+ 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ /* '1' + JJJJJJJK x 8 */
+ 0x7F, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD,
+ /* {JKKKKKKK x 10},JK */
+ 0xFC, 0x7E, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, 0x7E
+};
+
+static void s3c_udc_ep_set_stall(struct s3c_ep *ep);
+
+static inline void s3c_udc_ep0_zlp(struct s3c_udc *dev)
+{
+ u32 ep_ctrl;
+
+ __raw_writel(dev->usb_ctrl_dma,
+ dev->regs + S3C_UDC_OTG_DIEPDMA(EP0_CON));
+ __raw_writel((1<<19 | 0<<0), dev->regs + S3C_UDC_OTG_DIEPTSIZ(EP0_CON));
+
+ ep_ctrl = __raw_readl(dev->regs + S3C_UDC_OTG_DIEPCTL(EP0_CON));
+ __raw_writel(ep_ctrl | DEPCTL_EPENA | DEPCTL_CNAK,
+ dev->regs + S3C_UDC_OTG_DIEPCTL(EP0_CON));
+
+ DEBUG_EP0("%s:EP0 ZLP DIEPCTL0 = 0x%x\n",
+ __func__,
+ __raw_readl(dev->regs + S3C_UDC_OTG_DIEPCTL(EP0_CON)));
+}
+
+static inline void s3c_udc_pre_setup(struct s3c_udc *dev, bool need_nak)
+{
+ u32 ep_ctrl;
+
+ DEBUG_IN_EP("%s : Prepare Setup packets.\n", __func__);
+
+ __raw_writel((3<<29) | (1<<19) | sizeof(struct usb_ctrlrequest),
+ dev->regs + S3C_UDC_OTG_DOEPTSIZ(EP0_CON));
+ __raw_writel(dev->usb_ctrl_dma,
+ dev->regs + S3C_UDC_OTG_DOEPDMA(EP0_CON));
+
+ ep_ctrl = __raw_readl(dev->regs + S3C_UDC_OTG_DOEPCTL(EP0_CON));
+ if (need_nak)
+ ep_ctrl |= (DEPCTL_EPENA|DEPCTL_SNAK);
+ else
+ ep_ctrl |= (DEPCTL_EPENA|DEPCTL_CNAK);
+ __raw_writel(ep_ctrl, dev->regs + S3C_UDC_OTG_DOEPCTL(EP0_CON));
+}
+
+static int setdma_rx(struct s3c_ep *ep, struct s3c_request *req)
+{
+ u32 *buf, ctrl;
+ u32 length, pktcnt;
+ u32 ep_num = ep_index(ep);
+ struct s3c_udc *udc = ep->dev;
+ struct device *dev = &udc->dev->dev;
+
+ buf = req->req.buf + req->req.actual;
+ prefetchw(buf);
+
+ length = req->req.length - req->req.actual;
+
+ req->req.dma = dma_map_single(dev, buf,
+ length, DMA_FROM_DEVICE);
+ req->mapped = 1;
+
+ if (length == 0)
+ pktcnt = 1;
+ else
+ pktcnt = (length - 1)/(ep->ep.maxpacket) + 1;
+
+ ctrl = __raw_readl(udc->regs + S3C_UDC_OTG_DOEPCTL(ep_num));
+
+ __raw_writel(virt_to_phys(buf),
+ udc->regs + S3C_UDC_OTG_DOEPDMA(ep_num));
+ __raw_writel((pktcnt<<19) | (length<<0),
+ udc->regs + S3C_UDC_OTG_DOEPTSIZ(ep_num));
+ __raw_writel(DEPCTL_EPENA | DEPCTL_CNAK | ctrl,
+ udc->regs + S3C_UDC_OTG_DOEPCTL(ep_num));
+
+ DEBUG_OUT_EP("%s: EP%d RX DMA start : DOEPDMA = 0x%x,"
+ "DOEPTSIZ = 0x%x, DOEPCTL = 0x%x\n"
+ "\tbuf = 0x%p, pktcnt = %d, xfersize = %d\n",
+ __func__, ep_num,
+ __raw_readl(udc->regs + S3C_UDC_OTG_DOEPDMA(ep_num)),
+ __raw_readl(udc->regs + S3C_UDC_OTG_DOEPTSIZ(ep_num)),
+ __raw_readl(udc->regs + S3C_UDC_OTG_DOEPCTL(ep_num)),
+ buf, pktcnt, length);
+ return 0;
+}
+
+static int setdma_tx(struct s3c_ep *ep, struct s3c_request *req)
+{
+ u32 *buf, ctrl = 0;
+ u32 length, pktcnt;
+ u32 ep_num = ep_index(ep);
+ struct s3c_udc *udc = ep->dev;
+ struct device *dev = &udc->dev->dev;
+
+ buf = req->req.buf + req->req.actual;
+ prefetch(buf);
+ length = req->req.length - req->req.actual;
+
+ if (ep_num == EP0_CON)
+ length = min_t(u32, length, (u32)ep_maxpacket(ep));
+
+ req->req.actual += length;
+
+ req->req.dma = dma_map_single(dev, buf,
+ length, DMA_TO_DEVICE);
+ req->mapped = 1;
+
+ if (length == 0)
+ pktcnt = 1;
+ else
+ pktcnt = (length - 1)/(ep->ep.maxpacket) + 1;
+
+#ifdef DED_TX_FIFO
+ /* Write the FIFO number to be used for this endpoint */
+ ctrl = __raw_readl(udc->regs + S3C_UDC_OTG_DIEPCTL(ep_num));
+ ctrl &= ~DEPCTL_TXFNUM_MASK;
+ ctrl |= (ep_num << DEPCTL_TXFNUM_BIT);
+ __raw_writel(ctrl , udc->regs + S3C_UDC_OTG_DIEPCTL(ep_num));
+#endif
+
+ __raw_writel(virt_to_phys(buf),
+ udc->regs + S3C_UDC_OTG_DIEPDMA(ep_num));
+ __raw_writel((pktcnt<<19)|(length<<0),
+ udc->regs + S3C_UDC_OTG_DIEPTSIZ(ep_num));
+ ctrl = __raw_readl(udc->regs + S3C_UDC_OTG_DIEPCTL(ep_num));
+
+ if ((ctrl & DEPCTL_TYPE_MASK) == DEPCTL_ISO_TYPE) {
+ if (ctrl & DEPCTL_EO_FRNUM)
+ ctrl |= DEPCTL_SETD0PID;
+ else
+ ctrl |= DEPCTL_SETD1PID;
+ }
+
+ __raw_writel(DEPCTL_EPENA|DEPCTL_CNAK|ctrl,
+ udc->regs + S3C_UDC_OTG_DIEPCTL(ep_num));
+
+#ifndef DED_TX_FIFO
+ ctrl = __raw_readl(udc->regs + S3C_UDC_OTG_DIEPCTL(EP0_CON));
+ ctrl = (ctrl & ~(EP_MASK<<DEPCTL_NEXT_EP_BIT)) |
+ (ep_num<<DEPCTL_NEXT_EP_BIT);
+ __raw_writel(ctrl, udc->regs + S3C_UDC_OTG_DIEPCTL(EP0_CON));
+#endif
+
+ DEBUG_IN_EP("%s:EP%d TX DMA start : DIEPDMA0 = 0x%x,"
+ "DIEPTSIZ0 = 0x%x, DIEPCTL0 = 0x%x\n"
+ "\tbuf = 0x%p, pktcnt = %d, xfersize = %d\n",
+ __func__, ep_num,
+ __raw_readl(udc->regs + S3C_UDC_OTG_DIEPDMA(ep_num)),
+ __raw_readl(udc->regs + S3C_UDC_OTG_DIEPTSIZ(ep_num)),
+ __raw_readl(udc->regs + S3C_UDC_OTG_DIEPCTL(ep_num)),
+ buf, pktcnt, length);
+
+ req->written_bytes = length;
+ return length;
+}
+
+static void complete_rx(struct s3c_udc *dev, u8 ep_num)
+{
+ struct s3c_ep *ep = &dev->ep[ep_num];
+ struct s3c_request *req = NULL;
+ u32 ep_tsr = 0, xfer_size = 0, xfer_length, is_short = 0;
+
+ if (list_empty(&ep->queue)) {
+ DEBUG_OUT_EP("%s: RX DMA done : NULL REQ on OUT EP-%d\n",
+ __func__, ep_num);
+ return;
+ }
+
+ req = list_entry(ep->queue.next, struct s3c_request, queue);
+
+ ep_tsr = __raw_readl(dev->regs + S3C_UDC_OTG_DOEPTSIZ(ep_num));
+
+ if (ep_num == EP0_CON)
+ xfer_size = (ep_tsr & 0x7f);
+
+ else
+ xfer_size = (ep_tsr & 0x7fff);
+
+ __dma_single_cpu_to_dev(req->req.buf, req->req.length, DMA_FROM_DEVICE);
+ xfer_length = req->req.length - xfer_size;
+ req->req.actual += min(xfer_length, req->req.length - req->req.actual);
+ is_short = (xfer_length < ep->ep.maxpacket);
+
+ DEBUG_OUT_EP("%s: RX DMA done : ep = %d, rx bytes = %d/%d, "
+ "is_short = %d, DOEPTSIZ = 0x%x, remained bytes = %d\n",
+ __func__, ep_num, req->req.actual, req->req.length,
+ is_short, ep_tsr, xfer_size);
+
+ if (is_short || req->req.actual == xfer_length) {
+ if (ep_num == EP0_CON && dev->ep0state == DATA_STATE_RECV) {
+ done(ep, req, 0);
+ DEBUG_OUT_EP(" => Send ZLP\n");
+ dev->ep0state = WAIT_FOR_OUT_STATUS;
+ s3c_udc_ep0_zlp(dev);
+ } else {
+ done(ep, req, 0);
+
+ if (!list_empty(&ep->queue)) {
+ req = list_entry(ep->queue.next,
+ struct s3c_request, queue);
+ DEBUG_OUT_EP("%s: Next Rx request start...\n",
+ __func__);
+ setdma_rx(ep, req);
+ }
+ }
+ }
+}
+
+static void complete_tx(struct s3c_udc *dev, u8 ep_num)
+{
+ struct s3c_ep *ep = &dev->ep[ep_num];
+ struct s3c_request *req;
+ u32 ep_tsr = 0, xfer_size = 0, xfer_length, is_short = 0;
+
+ if (ep_num == EP0_CON && dev->ep0state == WAIT_FOR_OUT_STATUS) {
+ DEBUG_IN_EP("%s: EP-%d WAIT_FOR_OUT_STATUS -> WAIT_FOR_SETUP\n",
+ __func__, ep_num);
+ /* zlp transmitted */
+ dev->ep0state = WAIT_FOR_SETUP_NAK;
+ return;
+ }
+
+ if (list_empty(&ep->queue)) {
+ DEBUG_IN_EP("%s: TX DMA done : NULL REQ on IN EP-%d\n",
+ __func__, ep_num);
+ return;
+ }
+
+ req = list_entry(ep->queue.next, struct s3c_request, queue);
+
+ if (ep_num == EP0_CON && dev->ep0state == DATA_STATE_XMIT) {
+ DEBUG_IN_EP("%s: ep_num = %d, ep0stat == DATA_STATE_XMIT\n",
+ __func__, ep_num);
+
+ write_fifo_ep0(ep, req);
+
+ return;
+ }
+
+ ep_tsr = __raw_readl(dev->regs + S3C_UDC_OTG_DIEPTSIZ(ep_num));
+
+ if (ep_num == EP0_CON)
+ xfer_size = (ep_tsr & 0x7f);
+ else
+ xfer_size = (ep_tsr & 0x7fff);
+
+ req->req.actual = req->req.length - xfer_size;
+ xfer_length = req->req.length - xfer_size;
+ req->req.actual += min(xfer_length, req->req.length - req->req.actual);
+ is_short = (xfer_length < ep->ep.maxpacket);
+
+ DEBUG_IN_EP("%s: TX DMA done : ep = %d, tx bytes = %d/%d, "
+ "is_short = %d, DIEPTSIZ = 0x%x, remained bytes = %d\n",
+ __func__, ep_num, req->req.actual, req->req.length,
+ is_short, ep_tsr, xfer_size);
+
+ if (req->req.actual == req->req.length) {
+ /* send ZLP when req.zero is set
+ and the last packet is maxpacket */
+ if (req->req.zero) {
+ req->req.zero = 0;
+ if (req->written_bytes == ep_maxpacket(ep)) {
+ setdma_tx(ep, req);
+ return;
+ }
+ }
+ done(ep, req, 0);
+
+ if (!list_empty(&ep->queue)) {
+ req = list_entry(ep->queue.next, struct s3c_request,
+ queue);
+ DEBUG_IN_EP("%s: Next Tx request start...\n", __func__);
+ setdma_tx(ep, req);
+ }
+ }
+}
+
+static inline void s3c_udc_check_tx_queue(struct s3c_udc *dev, u8 ep_num)
+{
+ struct s3c_ep *ep = &dev->ep[ep_num];
+ struct s3c_request *req;
+
+ DEBUG_IN_EP("%s: Check queue, ep_num = %d\n", __func__, ep_num);
+
+ if (!list_empty(&ep->queue)) {
+ req = list_entry(ep->queue.next, struct s3c_request, queue);
+ DEBUG_IN_EP("%s: Next Tx request(0x%p) start...\n",
+ __func__, req);
+
+ if (ep_is_in(ep))
+ setdma_tx(ep, req);
+ else
+ setdma_rx(ep, req);
+ } else
+ DEBUG_IN_EP("%s: NULL REQ on IN EP-%d\n", __func__, ep_num);
+}
+
+static void process_ep_in_intr(struct s3c_udc *dev)
+{
+ u32 ep_intr, ep_intr_status;
+ u8 ep_num = 0;
+
+ ep_intr = __raw_readl(dev->regs + S3C_UDC_OTG_DAINT);
+ DEBUG_IN_EP("*** %s: EP In interrupt : DAINT = 0x%x\n",
+ __func__, ep_intr);
+
+ ep_intr &= DAINT_MASK;
+
+ while (ep_intr) {
+ if (ep_intr & 0x1) {
+ ep_intr_status = __raw_readl(dev->regs +
+ S3C_UDC_OTG_DIEPINT(ep_num));
+ DEBUG_IN_EP("\tEP%d-IN : DIEPINT = 0x%x\n",
+ ep_num, ep_intr_status);
+
+ /* Interrupt Clear */
+ __raw_writel(ep_intr_status,
+ dev->regs + S3C_UDC_OTG_DIEPINT(ep_num));
+
+ if (ep_intr_status & TRANSFER_DONE) {
+ complete_tx(dev, ep_num);
+
+ if (ep_num == 0) {
+ /* continue transfer after
+ set_clear_halt for DMA mode */
+ if (clear_feature_flag == 1) {
+ s3c_udc_check_tx_queue(dev,
+ clear_feature_num);
+ clear_feature_flag = 0;
+ }
+ }
+ }
+ }
+ ep_num++;
+ ep_intr >>= 1;
+ }
+}
+
+static void process_ep_out_intr(struct s3c_udc *dev)
+{
+ u32 ep_intr, ep_intr_status;
+ u8 ep_num = 0;
+ ep_intr = __raw_readl(dev->regs + S3C_UDC_OTG_DAINT);
+ DEBUG_OUT_EP("*** %s: EP OUT interrupt : DAINT = 0x%x\n",
+ __func__, ep_intr);
+
+ ep_intr = (ep_intr >> DAINT_OUT_BIT) & DAINT_MASK;
+
+ while (ep_intr) {
+ if (ep_intr & 0x1) {
+ ep_intr_status = __raw_readl(dev->regs +
+ S3C_UDC_OTG_DOEPINT(ep_num));
+ DEBUG_OUT_EP("\tEP%d-OUT : DOEPINT = 0x%x\n",
+ ep_num, ep_intr_status);
+
+ /* Interrupt Clear */
+ __raw_writel(ep_intr_status,
+ dev->regs + S3C_UDC_OTG_DOEPINT(ep_num));
+
+ if (ep_num == 0) {
+ if (ep_intr_status &
+ CTRL_OUT_EP_SETUP_PHASE_DONE) {
+ DEBUG_OUT_EP("\tSETUP"
+ "packet(transaction)"
+ "arrived\n");
+ s3c_handle_ep0(dev);
+ }
+ }
+
+ if (ep_intr_status & TRANSFER_DONE)
+ complete_rx(dev, ep_num);
+ }
+ ep_num++;
+ ep_intr >>= 1;
+ }
+}
+
+/*
+ * usb client interrupt handler.
+ */
+static irqreturn_t s3c_udc_irq(int irq, void *_dev)
+{
+ struct s3c_udc *dev = _dev;
+ u32 intr_status;
+ u32 usb_status, gintmsk;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->lock, flags);
+
+ intr_status = __raw_readl(dev->regs + S3C_UDC_OTG_GINTSTS);
+ gintmsk = __raw_readl(dev->regs + S3C_UDC_OTG_GINTMSK);
+
+ DEBUG_ISR("\n*** %s : GINTSTS=0x%x(on state %s), GINTMSK :"
+ "0x%x, DAINT : 0x%x, DAINTMSK : 0x%x\n",
+ __func__, intr_status,
+ state_names[dev->ep0state], gintmsk,
+ __raw_readl(dev->regs + S3C_UDC_OTG_DAINT),
+ __raw_readl(dev->regs + S3C_UDC_OTG_DAINTMSK));
+
+ if (!intr_status) {
+ spin_unlock_irqrestore(&dev->lock, flags);
+ return IRQ_HANDLED;
+ }
+
+ if (intr_status & INT_ENUMDONE) {
+ DEBUG_ISR("\tSpeed Detection interrupt\n");
+
+ __raw_writel(INT_ENUMDONE, dev->regs + S3C_UDC_OTG_GINTSTS);
+ usb_status = (__raw_readl(dev->regs + S3C_UDC_OTG_DSTS) & 0x6);
+
+ if (usb_status & (USB_FULL_30_60MHZ | USB_FULL_48MHZ)) {
+ DEBUG_ISR("\t\tFull Speed Detection\n");
+ set_max_pktsize(dev, USB_SPEED_FULL);
+
+ } else {
+ DEBUG_ISR("\t\tHigh Speed Detection : 0x%x\n",
+ usb_status);
+ set_max_pktsize(dev, USB_SPEED_HIGH);
+ }
+ }
+
+ if (intr_status & INT_EARLY_SUSPEND) {
+ DEBUG_ISR("\tEarly suspend interrupt\n");
+ __raw_writel(INT_EARLY_SUSPEND,
+ dev->regs + S3C_UDC_OTG_GINTSTS);
+ }
+
+ if (intr_status & INT_SUSPEND) {
+ usb_status = __raw_readl(dev->regs + S3C_UDC_OTG_DSTS);
+ DEBUG_ISR("\tSuspend interrupt :(DSTS):0x%x\n", usb_status);
+ __raw_writel(INT_SUSPEND, dev->regs + S3C_UDC_OTG_GINTSTS);
+
+ if (dev->gadget.speed != USB_SPEED_UNKNOWN
+ && dev->driver
+ && dev->driver->suspend) {
+
+ dev->driver->suspend(&dev->gadget);
+ }
+ }
+
+ if (intr_status & INT_RESUME) {
+ DEBUG_ISR("\tResume interrupt\n");
+ __raw_writel(INT_RESUME, dev->regs + S3C_UDC_OTG_GINTSTS);
+
+ if (dev->gadget.speed != USB_SPEED_UNKNOWN
+ && dev->driver
+ && dev->driver->resume) {
+ dev->driver->resume(&dev->gadget);
+ }
+ }
+
+ if (intr_status & INT_RESET) {
+ usb_status = __raw_readl(dev->regs + S3C_UDC_OTG_GOTGCTL);
+ DEBUG_ISR("\tReset interrupt - (GOTGCTL):0x%x\n", usb_status);
+ __raw_writel(INT_RESET, dev->regs + S3C_UDC_OTG_GINTSTS);
+
+ set_conf_done = 0;
+ udc_set_address(dev, 0);
+
+ if ((usb_status & 0xc0000) == (0x3 << 18)) {
+ if (reset_available) {
+ DEBUG_ISR("\t\tOTG core got reset (%d)!!\n",
+ reset_available);
+ reset_usbd();
+ dev->ep0state = WAIT_FOR_SETUP;
+ reset_available = 0;
+ } else
+ reset_available = 1;
+ } else {
+ reset_available = 1;
+ DEBUG_ISR("\t\tRESET handling skipped\n");
+ /* report disconnect; the driver is already quiesced */
+ if (dev->driver) {
+ spin_unlock(&dev->lock);
+ dev->driver->disconnect(&dev->gadget);
+ spin_lock(&dev->lock);
+ }
+ }
+ }
+
+ if (intr_status & INT_IN_EP)
+ process_ep_in_intr(dev);
+
+ if (intr_status & INT_OUT_EP)
+ process_ep_out_intr(dev);
+
+ if (dev->ep0state == WAIT_FOR_SETUP) {
+ s3c_udc_pre_setup(dev, false);
+ } else if (dev->ep0state == WAIT_FOR_SETUP_NAK) {
+ s3c_udc_pre_setup(dev, true);
+ dev->ep0state = WAIT_FOR_SETUP;
+ }
+
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ return IRQ_HANDLED;
+}
+
+/** Queue one request
+ * Kickstart transfer if needed
+ */
+static int s3c_queue(struct usb_ep *_ep, struct usb_request *_req,
+ gfp_t gfp_flags)
+{
+ struct s3c_request *req;
+ struct s3c_ep *ep;
+ struct s3c_udc *dev;
+ unsigned long flags;
+ u32 ep_num, gintsts;
+
+ req = container_of(_req, struct s3c_request, req);
+ if (unlikely(!_req || !_req->complete ||
+ !_req->buf || !list_empty(&req->queue))) {
+ DEBUG("%s: bad params\n", __func__);
+ return -EINVAL;
+ }
+
+ ep = container_of(_ep, struct s3c_ep, ep);
+
+ if (unlikely(!_ep || (!ep->desc && ep->ep.name != ep0name))) {
+ DEBUG("%s: bad ep\n", __func__);
+ return -EINVAL;
+ }
+
+ ep_num = ep_index(ep);
+ dev = ep->dev;
+ if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)) {
+ DEBUG("%s: bogus device state %p\n", __func__, dev->driver);
+ return -ESHUTDOWN;
+ }
+
+ spin_lock_irqsave(&dev->lock, flags);
+
+ _req->status = -EINPROGRESS;
+ _req->actual = 0;
+
+ /* kickstart this i/o queue? */
+ DEBUG("\n*** %s: %s-%s req = %p, len = %d, buf = %p"
+ "Q empty = %d, stopped = %d\n",
+ __func__, _ep->name, ep_is_in(ep) ? "in" : "out",
+ _req, _req->length, _req->buf,
+ list_empty(&ep->queue), ep->stopped);
+
+ if (list_empty(&ep->queue) && !ep->stopped) {
+ if (ep_num == 0) {
+ /* EP0 */
+ list_add_tail(&req->queue, &ep->queue);
+ s3c_ep0_kick(dev, ep);
+ req = 0;
+ } else if (ep_is_in(ep)) {
+ gintsts = __raw_readl(dev->regs + S3C_UDC_OTG_GINTSTS);
+ DEBUG_IN_EP("%s: ep_is_in, S3C_UDC_OTG_GINTSTS=0x%x\n",
+ __func__, gintsts);
+
+ if (set_conf_done == 1)
+ setdma_tx(ep, req);
+ else {
+ done(ep, req, 0);
+ DEBUG("%s: Not yet Set_configureation,"
+ "ep_num = %d, req = %p\n",
+ __func__, ep_num, req);
+ req = 0;
+ }
+
+ } else {
+ gintsts = __raw_readl(dev->regs + S3C_UDC_OTG_GINTSTS);
+ DEBUG_OUT_EP("%s: ep_is_out,"
+ "S3C_UDC_OTG_GINTSTS=0x%x\n",
+ __func__, gintsts);
+
+ setdma_rx(ep, req);
+ }
+ }
+
+ /* pio or dma irq handler advances the queue. */
+ if (likely(req != 0))
+ list_add_tail(&req->queue, &ep->queue);
+
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ return 0;
+}
+
+/****************************************************************/
+/* End Point 0 related functions */
+/****************************************************************/
+
+/* return: 0 = still running, 1 = completed, negative = errno */
+static int write_fifo_ep0(struct s3c_ep *ep, struct s3c_request *req)
+{
+ u32 max;
+ unsigned count;
+ int is_last;
+
+ max = ep_maxpacket(ep);
+
+ DEBUG_EP0("%s: max = %d\n", __func__, max);
+
+ count = setdma_tx(ep, req);
+
+ /* last packet is usually short (or a zlp) */
+ if (likely(count != max))
+ is_last = 1;
+ else {
+ if (likely(req->req.length != req->req.actual))
+ is_last = 0;
+ else
+ is_last = 1;
+ }
+
+ DEBUG_EP0("%s: wrote %s %d bytes%s %d left %p\n", __func__,
+ ep->ep.name, count,
+ is_last ? "/L" : "", req->req.length - req->req.actual, req);
+
+ /* requests complete when all IN data is in the FIFO */
+ if (is_last) {
+ DEBUG_EP0("%s: last packet\n", __func__);
+ ep->dev->ep0state = WAIT_FOR_SETUP;
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * udc_set_address - set the USB address for this device
+ * @address:
+ *
+ * Called from control endpoint function
+ * after it decodes a set address setup packet.
+ */
+static void udc_set_address(struct s3c_udc *dev, unsigned char address)
+{
+ u32 ctrl = __raw_readl(dev->regs + S3C_UDC_OTG_DCFG);
+ ctrl &= ~(0x7F << 4);
+ __raw_writel(address << 4 | ctrl, dev->regs + S3C_UDC_OTG_DCFG);
+
+ DEBUG_EP0("%s: USB OTG 2.0 Device address=%d, DCFG=0x%x\n",
+ __func__, address, __raw_readl(dev->regs + S3C_UDC_OTG_DCFG));
+
+ dev->usb_address = address;
+}
+
+static inline void s3c_udc_ep0_set_stall(struct s3c_ep *ep)
+{
+ struct s3c_udc *dev;
+ u32 ep_ctrl = 0;
+
+ dev = ep->dev;
+ ep_ctrl = __raw_readl(dev->regs + S3C_UDC_OTG_DIEPCTL(EP0_CON));
+
+ /* set the disable and stall bits */
+ if (ep_ctrl & DEPCTL_EPENA)
+ ep_ctrl |= DEPCTL_EPDIS;
+
+ ep_ctrl |= DEPCTL_STALL;
+
+ __raw_writel(ep_ctrl, dev->regs + S3C_UDC_OTG_DIEPCTL(EP0_CON));
+
+ DEBUG_EP0("%s: set ep%d stall, DIEPCTL0 = 0x%x\n",
+ __func__, ep_index(ep),
+ __raw_readl(dev->regs + S3C_UDC_OTG_DIEPCTL(EP0_CON)));
+ /*
+ * The application can only set this bit, and the core clears it,
+ * when a SETUP token is received for this endpoint
+ */
+ dev->ep0state = WAIT_FOR_SETUP;
+}
+
+static void s3c_ep0_read(struct s3c_udc *dev)
+{
+ struct s3c_request *req;
+ struct s3c_ep *ep = &dev->ep[0];
+ int ret;
+
+ if (!list_empty(&ep->queue))
+ req = list_entry(ep->queue.next, struct s3c_request, queue);
+ else {
+ DEBUG("%s: ---> BUG\n", __func__);
+ BUG();
+ return;
+ }
+
+ DEBUG_EP0("%s: req = %p, req.length = 0x%x, req.actual = 0x%x\n",
+ __func__, req, req->req.length, req->req.actual);
+
+ if (req->req.length == 0) {
+ /* zlp for Set_configuration, Set_interface,
+ * or Bulk-Only mass storge reset */
+
+ dev->ep0state = WAIT_FOR_SETUP;
+ set_conf_done = 1;
+ s3c_udc_ep0_zlp(dev);
+
+ DEBUG_EP0("%s: req.length = 0, bRequest = %d\n",
+ __func__, dev->usb_ctrl->bRequest);
+ return;
+ }
+
+ ret = setdma_rx(ep, req);
+}
+
+/*
+ * DATA_STATE_XMIT
+ */
+static int s3c_ep0_write(struct s3c_udc *dev)
+{
+ struct s3c_request *req;
+ struct s3c_ep *ep = &dev->ep[0];
+ int ret;
+
+ if (list_empty(&ep->queue))
+ req = 0;
+ else
+ req = list_entry(ep->queue.next, struct s3c_request, queue);
+
+ if (!req) {
+ DEBUG_EP0("%s: NULL REQ\n", __func__);
+ return 0;
+ }
+
+ DEBUG_EP0("%s: req = %p, req.length = 0x%x, req.actual = 0x%x\n",
+ __func__, req, req->req.length, req->req.actual);
+
+ write_fifo_ep0(ep, req);
+
+ return 1;
+}
+
+static int s3c_udc_get_status(struct s3c_udc *dev,
+ struct usb_ctrlrequest *crq)
+{
+ u8 ep_num = crq->wIndex & 0x7F;
+ u32 ep_ctrl;
+
+ DEBUG_SETUP("%s: *** USB_REQ_GET_STATUS\n", __func__);
+
+ switch (crq->bRequestType & USB_RECIP_MASK) {
+ case USB_RECIP_INTERFACE:
+ g_status = 0;
+ DEBUG_SETUP("\tGET_STATUS: USB_RECIP_INTERFACE,"
+ "g_stauts = %d\n", g_status);
+ break;
+
+ case USB_RECIP_DEVICE:
+ g_status = 0x0;
+ DEBUG_SETUP("\tGET_STATUS: USB_RECIP_DEVICE,"
+ "g_stauts = %d\n", g_status);
+ break;
+
+ case USB_RECIP_ENDPOINT:
+ if (crq->wLength > 2) {
+ DEBUG_SETUP("\tGET_STATUS:"
+ "Not support EP or wLength\n");
+ return 1;
+ }
+
+ g_status = dev->ep[ep_num].stopped;
+ DEBUG_SETUP("\tGET_STATUS: USB_RECIP_ENDPOINT,"
+ "g_stauts = %d\n", g_status);
+
+ break;
+ default:
+ return 1;
+ }
+
+ __dma_single_cpu_to_dev(&g_status, 2, DMA_TO_DEVICE);
+
+ __raw_writel(virt_to_phys(&g_status),
+ dev->regs + S3C_UDC_OTG_DIEPDMA(EP0_CON));
+ __raw_writel((1<<19)|(2<<0),
+ dev->regs + S3C_UDC_OTG_DIEPTSIZ(EP0_CON));
+
+ ep_ctrl = __raw_readl(dev->regs + S3C_UDC_OTG_DIEPCTL(EP0_CON));
+ __raw_writel(ep_ctrl|DEPCTL_EPENA|DEPCTL_CNAK,
+ dev->regs + S3C_UDC_OTG_DIEPCTL(EP0_CON));
+ dev->ep0state = WAIT_FOR_SETUP;
+
+ return 0;
+}
+
+static void s3c_udc_ep_set_stall(struct s3c_ep *ep)
+{
+ struct s3c_udc *dev = ep->dev;
+ u8 ep_num;
+ u32 ep_ctrl = 0;
+
+ ep_num = ep_index(ep);
+ DEBUG("%s: ep_num = %d, ep_type = %d\n", __func__, ep_num, ep->ep_type);
+
+ if (ep_is_in(ep)) {
+ ep_ctrl = __raw_readl(dev->regs + S3C_UDC_OTG_DIEPCTL(ep_num));
+
+ /* set the disable and stall bits */
+ if (ep_ctrl & DEPCTL_EPENA)
+ ep_ctrl |= DEPCTL_EPDIS;
+
+ ep_ctrl |= DEPCTL_STALL;
+
+ __raw_writel(ep_ctrl, dev->regs + S3C_UDC_OTG_DIEPCTL(ep_num));
+ DEBUG("%s: set stall, DIEPCTL%d = 0x%x\n",
+ __func__, ep_num,
+ __raw_readl(dev->regs + S3C_UDC_OTG_DIEPCTL(ep_num)));
+ } else {
+ ep_ctrl = __raw_readl(dev->regs + S3C_UDC_OTG_DOEPCTL(ep_num));
+
+ /* set the stall bit */
+ ep_ctrl |= DEPCTL_STALL;
+
+ __raw_writel(ep_ctrl, dev->regs + S3C_UDC_OTG_DOEPCTL(ep_num));
+ DEBUG("%s: set stall, DOEPCTL%d = 0x%x\n",
+ __func__, ep_num,
+ __raw_readl(dev->regs + S3C_UDC_OTG_DOEPCTL(ep_num)));
+ }
+}
+
+void s3c_udc_ep_clear_stall(struct s3c_ep *ep)
+{
+ struct s3c_udc *dev = ep->dev;
+ u8 ep_num;
+ u32 ep_ctrl = 0;
+
+ ep_num = ep_index(ep);
+ DEBUG("%s: ep_num = %d, ep_type = %d\n", __func__, ep_num, ep->ep_type);
+
+ if (ep_is_in(ep)) {
+ ep_ctrl = __raw_readl(dev->regs + S3C_UDC_OTG_DIEPCTL(ep_num));
+
+ /* clear stall bit */
+ ep_ctrl &= ~DEPCTL_STALL;
+
+ /*
+ * USB Spec 9.4.5: For endpoints using data toggle, regardless
+ * of whether an endpoint has the Halt feature set, a
+ * ClearFeature(ENDPOINT_HALT) request always results in the
+ * data toggle being reinitialized to DATA0.
+ */
+ if (ep->bmAttributes == USB_ENDPOINT_XFER_INT
+ || ep->bmAttributes == USB_ENDPOINT_XFER_BULK)
+ ep_ctrl |= DEPCTL_SETD0PID; /* DATA0 */
+
+ __raw_writel(ep_ctrl, dev->regs + S3C_UDC_OTG_DIEPCTL(ep_num));
+ DEBUG("%s: cleared stall, DIEPCTL%d = 0x%x\n",
+ __func__, ep_num,
+ __raw_readl(dev->regs + S3C_UDC_OTG_DIEPCTL(ep_num)));
+ } else {
+ ep_ctrl = __raw_readl(dev->regs + S3C_UDC_OTG_DOEPCTL(ep_num));
+
+ /* clear stall bit */
+ ep_ctrl &= ~DEPCTL_STALL;
+
+ if (ep->bmAttributes == USB_ENDPOINT_XFER_INT
+ || ep->bmAttributes == USB_ENDPOINT_XFER_BULK)
+ ep_ctrl |= DEPCTL_SETD0PID; /* DATA0 */
+
+ __raw_writel(ep_ctrl, dev->regs + S3C_UDC_OTG_DOEPCTL(ep_num));
+ DEBUG("%s: cleared stall, DOEPCTL%d = 0x%x\n",
+ __func__, ep_num,
+ __raw_readl(dev->regs + S3C_UDC_OTG_DOEPCTL(ep_num)));
+ }
+}
+
+static int s3c_udc_set_halt(struct usb_ep *_ep, int value)
+{
+ struct s3c_ep *ep;
+ struct s3c_udc *dev;
+ unsigned long flags;
+ u8 ep_num;
+
+ ep = container_of(_ep, struct s3c_ep, ep);
+ ep_num = ep_index(ep);
+
+ if (unlikely(!_ep || !ep->desc || ep_num == EP0_CON ||
+ ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC)) {
+ DEBUG("%s: %s bad ep or descriptor\n", __func__, ep->ep.name);
+ return -EINVAL;
+ }
+
+ /* Attempt to halt IN ep will fail if any transfer requests
+ * are still queue */
+ if (value && ep_is_in(ep) && !list_empty(&ep->queue)) {
+ DEBUG("%s: %s queue not empty, req = %p\n",
+ __func__, ep->ep.name,
+ list_entry(ep->queue.next, struct s3c_request, queue));
+
+ return -EAGAIN;
+ }
+
+ dev = ep->dev;
+ DEBUG("%s: ep_num = %d, value = %d\n", __func__, ep_num, value);
+
+ spin_lock_irqsave(&dev->lock, flags);
+
+ if (value == 0) {
+ ep->stopped = 0;
+ s3c_udc_ep_clear_stall(ep);
+ } else {
+ ep->stopped = 1;
+ s3c_udc_ep_set_stall(ep);
+ }
+
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ return 0;
+}
+
+void s3c_udc_ep_activate(struct s3c_ep *ep)
+{
+ struct s3c_udc *dev = ep->dev;
+ u8 ep_num;
+ u32 ep_ctrl = 0, daintmsk = 0;
+
+ ep_num = ep_index(ep);
+
+ /* Read DEPCTLn register */
+ if (ep_is_in(ep)) {
+ ep_ctrl = __raw_readl(dev->regs + S3C_UDC_OTG_DIEPCTL(ep_num));
+ daintmsk = 1 << ep_num;
+ } else {
+ ep_ctrl = __raw_readl(dev->regs + S3C_UDC_OTG_DOEPCTL(ep_num));
+ daintmsk = (1 << ep_num) << DAINT_OUT_BIT;
+ }
+
+ DEBUG("%s: EPCTRL%d = 0x%x, ep_is_in = %d\n",
+ __func__, ep_num, ep_ctrl, ep_is_in(ep));
+
+ /* If the EP is already active don't change the EP Control
+ * register. */
+ if (!(ep_ctrl & DEPCTL_USBACTEP)) {
+ ep_ctrl = (ep_ctrl & ~DEPCTL_TYPE_MASK) |
+ (ep->bmAttributes << DEPCTL_TYPE_BIT);
+ ep_ctrl = (ep_ctrl & ~DEPCTL_MPS_MASK) |
+ (ep->ep.maxpacket << DEPCTL_MPS_BIT);
+
+ if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC)
+ ep_ctrl |= (DEPCTL_SETD1PID | DEPCTL_USBACTEP | DEPCTL_SNAK);
+ else
+ ep_ctrl |= (DEPCTL_SETD0PID | DEPCTL_USBACTEP | DEPCTL_SNAK);
+
+ if (ep_is_in(ep)) {
+ __raw_writel(ep_ctrl,
+ dev->regs + S3C_UDC_OTG_DIEPCTL(ep_num));
+ DEBUG("%s: USB Ative EP%d, DIEPCTRL%d = 0x%x\n",
+ __func__, ep_num, ep_num,
+ __raw_readl(dev->regs +
+ S3C_UDC_OTG_DIEPCTL(ep_num)));
+ } else {
+ __raw_writel(ep_ctrl,
+ dev->regs + S3C_UDC_OTG_DOEPCTL(ep_num));
+ DEBUG("%s: USB Ative EP%d, DOEPCTRL%d = 0x%x\n",
+ __func__, ep_num, ep_num,
+ __raw_readl(dev->regs +
+ S3C_UDC_OTG_DOEPCTL(ep_num)));
+ }
+ }
+
+ /* Unmask EP Interrtupt */
+ __raw_writel(__raw_readl(dev->regs + S3C_UDC_OTG_DAINTMSK)|daintmsk,
+ dev->regs + S3C_UDC_OTG_DAINTMSK);
+ DEBUG("%s: DAINTMSK = 0x%x\n", __func__,
+ __raw_readl(dev->regs + S3C_UDC_OTG_DAINTMSK));
+}
+
+static int s3c_udc_clear_feature(struct usb_ep *_ep)
+{
+ struct s3c_ep *ep;
+ u8 ep_num;
+ struct usb_ctrlrequest *usb_ctrl;
+
+ ep = container_of(_ep, struct s3c_ep, ep);
+ ep_num = ep_index(ep);
+ usb_ctrl = ep->dev->usb_ctrl;
+
+ DEBUG_SETUP("%s: ep_num = %d, is_in = %d, clear_feature_flag = %d\n",
+ __func__, ep_num, ep_is_in(ep), clear_feature_flag);
+
+ if (usb_ctrl->wLength != 0) {
+ DEBUG_SETUP("\tCLEAR_FEATURE:"
+ "wLength is not zero.....\n");
+ return 1;
+ }
+
+ switch (usb_ctrl->bRequestType & USB_RECIP_MASK) {
+ case USB_RECIP_DEVICE:
+ switch (usb_ctrl->wValue) {
+ case USB_DEVICE_REMOTE_WAKEUP:
+ DEBUG_SETUP("\tCLEAR_FEATURE:"
+ "USB_DEVICE_REMOTE_WAKEUP\n");
+ break;
+
+ case USB_DEVICE_TEST_MODE:
+ DEBUG_SETUP("\tCLEAR_FEATURE:"
+ "USB_DEVICE_TEST_MODE\n");
+ /** @todo Add CLEAR_FEATURE for TEST modes. */
+ break;
+ }
+
+ s3c_udc_ep0_zlp(ep->dev);
+ break;
+
+ case USB_RECIP_ENDPOINT:
+ DEBUG_SETUP("\tCLEAR_FEATURE: USB_RECIP_ENDPOINT,"
+ "wValue = %d\n", usb_ctrl->wValue);
+
+ if (usb_ctrl->wValue == USB_ENDPOINT_HALT) {
+ if (ep_num == 0) {
+ s3c_udc_ep0_set_stall(ep);
+ return 0;
+ }
+
+ s3c_udc_ep0_zlp(ep->dev);
+
+ s3c_udc_ep_clear_stall(ep);
+ s3c_udc_ep_activate(ep);
+ ep->stopped = 0;
+
+ clear_feature_num = ep_num;
+ clear_feature_flag = 1;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+/* Set into the test mode for Test Mode set_feature request */
+static inline void set_test_mode(struct s3c_udc *dev)
+{
+ u32 ep_ctrl, dctl;
+ u8 test_selector = (dev->usb_ctrl->wIndex>>8) &
+ TEST_SELECTOR_MASK;
+
+ if (test_selector > 0 && test_selector < 6) {
+ ep_ctrl = __raw_readl(dev->regs + S3C_UDC_OTG_DIEPCTL(EP0_CON));
+
+ __raw_writel(1<<19 | 0<<0,
+ dev->regs + S3C_UDC_OTG_DIEPTSIZ(EP0_CON));
+ __raw_writel(ep_ctrl | DEPCTL_EPENA | DEPCTL_CNAK
+ | EP0_CON<<DEPCTL_NEXT_EP_BIT,
+ dev->regs + S3C_UDC_OTG_DIEPCTL(EP0_CON));
+ }
+
+ switch (test_selector) {
+ case TEST_J_SEL:
+ /* some delay is necessary like printk() or udelay() */
+ printk(KERN_INFO "Test mode selector in set_feature request is"
+ "TEST J\n");
+
+ dctl = __raw_readl(dev->regs + S3C_UDC_OTG_DCTL);
+ __raw_writel((dctl & ~(TEST_CONTROL_MASK)) | TEST_J_MODE,
+ dev->regs + S3C_UDC_OTG_DCTL);
+ break;
+ case TEST_K_SEL:
+ /* some delay is necessary like printk() or udelay() */
+ printk(KERN_INFO "Test mode selector in set_feature request is"
+ "TEST K\n");
+
+ dctl = __raw_readl(dev->regs + S3C_UDC_OTG_DCTL);
+ __raw_writel((dctl&~(TEST_CONTROL_MASK))|TEST_K_MODE,
+ dev->regs + S3C_UDC_OTG_DCTL);
+ break;
+ case TEST_SE0_NAK_SEL:
+ /* some delay is necessary like printk() or udelay() */
+ printk(KERN_INFO "Test mode selector in set_feature request is"
+ "TEST SE0 NAK\n");
+
+ dctl = __raw_readl(dev->regs + S3C_UDC_OTG_DCTL);
+ __raw_writel((dctl & ~(TEST_CONTROL_MASK)) | TEST_SE0_NAK_MODE,
+ dev->regs + S3C_UDC_OTG_DCTL);
+ break;
+ case TEST_PACKET_SEL:
+ /* some delay is necessary like printk() or udelay() */
+ printk(KERN_INFO "Test mode selector in set_feature request is"
+ "TEST PACKET\n");
+
+ __dma_single_cpu_to_dev(test_pkt, TEST_PKT_SIZE, DMA_TO_DEVICE);
+ __raw_writel(virt_to_phys(test_pkt),
+ dev->regs + S3C_UDC_OTG_DIEPDMA(EP0_CON));
+
+ ep_ctrl = __raw_readl(dev->regs + S3C_UDC_OTG_DIEPCTL(EP0_CON));
+
+ __raw_writel(1<<19 | TEST_PKT_SIZE<<0,
+ dev->regs + S3C_UDC_OTG_DIEPTSIZ(EP0_CON));
+ __raw_writel(ep_ctrl | DEPCTL_EPENA | DEPCTL_CNAK
+ | EP0_CON<<DEPCTL_NEXT_EP_BIT,
+ dev->regs + S3C_UDC_OTG_DIEPCTL(EP0_CON));
+
+ dctl = __raw_readl(dev->regs + S3C_UDC_OTG_DCTL);
+ __raw_writel((dctl & ~(TEST_CONTROL_MASK)) | TEST_PACKET_MODE,
+ dev->regs + S3C_UDC_OTG_DCTL);
+ break;
+ case TEST_FORCE_ENABLE_SEL:
+ /* some delay is necessary like printk() or udelay() */
+ printk(KERN_INFO "Test mode selector in set_feature request is"
+ "TEST FORCE ENABLE\n");
+
+ dctl = __raw_readl(dev->regs + S3C_UDC_OTG_DCTL);
+ __raw_writel((dctl & ~(TEST_CONTROL_MASK)) |
+ TEST_FORCE_ENABLE_MODE,
+ dev->regs + S3C_UDC_OTG_DCTL);
+ break;
+ }
+}
+
+static int s3c_udc_set_feature(struct usb_ep *_ep)
+{
+ struct s3c_ep *ep;
+ u8 ep_num;
+ struct usb_ctrlrequest *usb_ctrl;
+
+ ep = container_of(_ep, struct s3c_ep, ep);
+ ep_num = ep_index(ep);
+ usb_ctrl = ep->dev->usb_ctrl;
+
+ DEBUG_SETUP("%s: *** USB_REQ_SET_FEATURE,"
+ "ep_num = %d\n", __func__, ep_num);
+
+ if (usb_ctrl->wLength != 0) {
+ DEBUG_SETUP("\tSET_FEATURE: wLength is not zero.....\n");
+ return 1;
+ }
+
+ switch (usb_ctrl->bRequestType & USB_RECIP_MASK) {
+ case USB_RECIP_DEVICE:
+ switch (usb_ctrl->wValue) {
+ case USB_DEVICE_REMOTE_WAKEUP:
+ DEBUG_SETUP("\tSET_FEATURE:"
+ "USB_DEVICE_REMOTE_WAKEUP\n");
+ break;
+
+ case USB_DEVICE_TEST_MODE:
+ DEBUG_SETUP("\tSET_FEATURE: USB_DEVICE_TEST_MODE\n");
+ set_test_mode(ep->dev);
+ break;
+
+ case USB_DEVICE_B_HNP_ENABLE:
+ DEBUG_SETUP("\tSET_FEATURE: USB_DEVICE_B_HNP_ENABLE\n");
+ break;
+
+ case USB_DEVICE_A_HNP_SUPPORT:
+ /* RH port supports HNP */
+ DEBUG_SETUP("\tSET_FEATURE:"
+ "USB_DEVICE_A_HNP_SUPPORT\n");
+ break;
+
+ case USB_DEVICE_A_ALT_HNP_SUPPORT:
+ /* other RH port does */
+ DEBUG_SETUP("\tSET_FEATURE:"
+ "USB_DEVICE_A_ALT_HNP_SUPPORT\n");
+ break;
+ }
+
+ s3c_udc_ep0_zlp(ep->dev);
+ return 0;
+
+ case USB_RECIP_INTERFACE:
+ DEBUG_SETUP("\tSET_FEATURE: USB_RECIP_INTERFACE\n");
+ break;
+
+ case USB_RECIP_ENDPOINT:
+ DEBUG_SETUP("\tSET_FEATURE: USB_RECIP_ENDPOINT\n");
+ if (usb_ctrl->wValue == USB_ENDPOINT_HALT) {
+ if (ep_num == 0) {
+ s3c_udc_ep0_set_stall(ep);
+ return 0;
+ }
+ ep->stopped = 1;
+ s3c_udc_ep_set_stall(ep);
+ }
+
+ s3c_udc_ep0_zlp(ep->dev);
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * WAIT_FOR_SETUP (OUT_PKT_RDY)
+ */
+static void s3c_ep0_setup(struct s3c_udc *dev)
+{
+ struct s3c_ep *ep = &dev->ep[0];
+ int i, is_in;
+ u8 ep_num;
+ struct usb_ctrlrequest *usb_ctrl = dev->usb_ctrl;
+
+ /* Nuke all previous transfers */
+ nuke(ep, -EPROTO);
+
+ DEBUG_SETUP("%s: bRequestType = 0x%x(%s), bRequest = 0x%x"
+ "\twLength = 0x%x, wValue = 0x%x, wIndex= 0x%x\n",
+ __func__, usb_ctrl->bRequestType,
+ (usb_ctrl->bRequestType & USB_DIR_IN) ? "IN" : "OUT",
+ usb_ctrl->bRequest, usb_ctrl->wLength, usb_ctrl->wValue,
+ usb_ctrl->wIndex);
+
+ if (usb_ctrl->bRequest == GET_MAX_LUN_REQUEST &&
+ usb_ctrl->wLength != 1) {
+ DEBUG_SETUP("\t%s:GET_MAX_LUN_REQUEST:invalid wLength = %d,"
+ "setup returned\n", __func__, usb_ctrl->wLength);
+
+ s3c_udc_ep0_set_stall(ep);
+ dev->ep0state = WAIT_FOR_SETUP;
+
+ return;
+ } else if (usb_ctrl->bRequest ==
+ BOT_RESET_REQUEST && usb_ctrl->wLength != 0) {
+ /* Bulk-Only *mass storge reset of class-specific request */
+ DEBUG_SETUP("\t%s:BOT Rest:invalid wLength = %d,"
+ "setup returned\n",
+ __func__, usb_ctrl->wLength);
+
+ s3c_udc_ep0_set_stall(ep);
+ dev->ep0state = WAIT_FOR_SETUP;
+
+ return;
+ }
+
+ /* Set direction of EP0 */
+ if (likely(usb_ctrl->bRequestType & USB_DIR_IN)) {
+ ep->bEndpointAddress |= USB_DIR_IN;
+ is_in = 1;
+
+ } else {
+ ep->bEndpointAddress &= ~USB_DIR_IN;
+ is_in = 0;
+ }
+ /* cope with automagic for some standard requests. */
+ dev->req_std = (usb_ctrl->bRequestType & USB_TYPE_MASK)
+ == USB_TYPE_STANDARD;
+ dev->req_config = 0;
+ dev->req_pending = 1;
+
+ /* Handle some SETUP packets ourselves */
+ switch (usb_ctrl->bRequest) {
+ case USB_REQ_SET_ADDRESS:
+ DEBUG_SETUP("%s: *** USB_REQ_SET_ADDRESS (%d)\n",
+ __func__, usb_ctrl->wValue);
+
+ if (usb_ctrl->bRequestType
+ != (USB_TYPE_STANDARD | USB_RECIP_DEVICE))
+ break;
+
+ udc_set_address(dev, usb_ctrl->wValue);
+ s3c_udc_ep0_zlp(dev);
+
+ return;
+
+ case USB_REQ_SET_CONFIGURATION:
+ DEBUG_SETUP("============================================\n");
+ DEBUG_SETUP("%s: USB_REQ_SET_CONFIGURATION (%d)\n",
+ __func__, usb_ctrl->wValue);
+
+ if (usb_ctrl->bRequestType == USB_RECIP_DEVICE) {
+ reset_available = 1;
+ dev->req_config = 1;
+ }
+ break;
+
+ case USB_REQ_GET_DESCRIPTOR:
+ DEBUG_SETUP("%s: *** USB_REQ_GET_DESCRIPTOR\n", __func__);
+ break;
+
+ case USB_REQ_SET_INTERFACE:
+ DEBUG_SETUP("%s: *** USB_REQ_SET_INTERFACE (%d)\n",
+ __func__, usb_ctrl->wValue);
+
+ if (usb_ctrl->bRequestType == USB_RECIP_INTERFACE) {
+ reset_available = 1;
+ dev->req_config = 1;
+ }
+ break;
+
+ case USB_REQ_GET_CONFIGURATION:
+ DEBUG_SETUP("%s: *** USB_REQ_GET_CONFIGURATION\n", __func__);
+ break;
+
+ case USB_REQ_GET_STATUS:
+ if (dev->req_std) {
+ if (!s3c_udc_get_status(dev, usb_ctrl))
+ return;
+ }
+ break;
+
+ case USB_REQ_CLEAR_FEATURE:
+ ep_num = usb_ctrl->wIndex & 0x7f;
+
+ if (!s3c_udc_clear_feature(&dev->ep[ep_num].ep))
+ return;
+ break;
+ case USB_REQ_SET_FEATURE:
+ ep_num = usb_ctrl->wIndex & 0x7f;
+
+ if (!s3c_udc_set_feature(&dev->ep[ep_num].ep))
+ return;
+ break;
+ default:
+ DEBUG_SETUP("%s: *** Default of usb_ctrl->bRequest=0x%x"
+ "happened.\n", __func__, usb_ctrl->bRequest);
+ break;
+ }
+
+ if (likely(dev->driver)) {
+ /* device-2-host (IN) or no data setup command,
+ * process immediately */
+ DEBUG_SETUP("%s: usb_ctrlrequest will be passed to"
+ "fsg_setup()\n", __func__);
+
+ spin_unlock(&dev->lock);
+ i = dev->driver->setup(&dev->gadget, usb_ctrl);
+ spin_lock(&dev->lock);
+
+ if (i < 0) {
+ if (dev->req_config)
+ DEBUG_SETUP("\tconfig change 0x%02x fail %d?\n",
+ (u32)usb_ctrl->bRequest, i);
+
+ /* setup processing failed, force stall */
+ s3c_udc_ep0_set_stall(ep);
+ dev->ep0state = WAIT_FOR_SETUP;
+
+ DEBUG_SETUP("\tdev->driver->setup failed (%d),"
+ "bRequest = %d\n",
+ i, usb_ctrl->bRequest);
+ } else if (dev->req_pending) {
+ dev->req_pending = 0;
+ DEBUG_SETUP("\tdev->req_pending...\n");
+ }
+
+ DEBUG_SETUP("\tep0state = %s\n", state_names[dev->ep0state]);
+ }
+}
+
+/*
+ * handle ep0 interrupt
+ */
+static void s3c_handle_ep0(struct s3c_udc *dev)
+{
+ if (dev->ep0state == WAIT_FOR_SETUP) {
+ DEBUG_OUT_EP("%s: WAIT_FOR_SETUP\n", __func__);
+ s3c_ep0_setup(dev);
+ } else
+ DEBUG_OUT_EP("%s: strange state!!(state = %s)\n",
+ __func__, state_names[dev->ep0state]);
+}
+
+static void s3c_ep0_kick(struct s3c_udc *dev, struct s3c_ep *ep)
+{
+ DEBUG_EP0("%s: ep_is_in = %d\n", __func__, ep_is_in(ep));
+ if (ep_is_in(ep)) {
+ dev->ep0state = DATA_STATE_XMIT;
+ s3c_ep0_write(dev);
+ } else {
+ dev->ep0state = DATA_STATE_RECV;
+ s3c_ep0_read(dev);
+ }
+}
diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c
index c8702c8..fcfba1c 100644
--- a/drivers/usb/gadget/u_ether.c
+++ b/drivers/usb/gadget/u_ether.c
@@ -241,11 +241,13 @@
goto enomem;
}
+#ifndef CONFIG_USB_ANDROID_RNDIS_DWORD_ALIGNED
/* Some platforms perform better when IP packets are aligned,
* but on at least one, checksumming fails otherwise. Note:
* RNDIS headers involve variable numbers of LE32 values.
*/
skb_reserve(skb, NET_IP_ALIGN);
+#endif
req->buf = skb->data;
req->length = size;
@@ -475,7 +477,10 @@
list_add(&req->list, &dev->tx_reqs);
spin_unlock(&dev->req_lock);
dev_kfree_skb_any(skb);
-
+#ifdef CONFIG_USB_ANDROID_RNDIS_DWORD_ALIGNED
+ if (req->buf != skb->data)
+ kfree(req->buf);
+#endif
atomic_dec(&dev->tx_qlen);
if (netif_carrier_ok(dev->net))
netif_wake_queue(dev->net);
@@ -569,7 +574,21 @@
length = skb->len;
}
+
+#ifdef CONFIG_USB_ANDROID_RNDIS_DWORD_ALIGNED
+ if ((int)skb->data & 3) {
+ req->buf = kmalloc(skb->len, GFP_ATOMIC);
+ if (!req->buf)
+ goto drop;
+ memcpy((void *)req->buf, (void *)skb->data, skb->len);
+ }
+ else {
+ req->buf = skb->data;
+ }
+#else
req->buf = skb->data;
+#endif
+
req->context = skb;
req->complete = tx_complete;
@@ -611,6 +630,10 @@
dev_kfree_skb_any(skb);
drop:
dev->net->stats.tx_dropped++;
+#ifdef CONFIG_USB_ANDROID_RNDIS_DWORD_ALIGNED
+ if (req->buf != skb->data)
+ kfree(req->buf);
+#endif
spin_lock_irqsave(&dev->req_lock, flags);
if (list_empty(&dev->tx_reqs))
netif_start_queue(net);
diff --git a/drivers/usb/gadget/udc-core.c b/drivers/usb/gadget/udc-core.c
index e5e44f8..7260d97 100644
--- a/drivers/usb/gadget/udc-core.c
+++ b/drivers/usb/gadget/udc-core.c
@@ -347,7 +347,15 @@
driver->unbind(udc->gadget);
goto err1;
}
- usb_gadget_connect(udc->gadget);
+ /*
+ * HACK: The Android gadget driver disconnects the gadget
+ * on bind and expects the gadget to stay disconnected until
+ * it calls usb_gadget_connect when userspace is ready. Remove
+ * the call to usb_gadget_connect bellow to avoid enabling the
+ * pullup before userspace is ready.
+ *
+ * usb_gadget_connect(udc->gadget);
+ */
} else {
ret = usb_gadget_start(udc->gadget, driver, bind);
diff --git a/drivers/usb/host/ehci-s5p.c b/drivers/usb/host/ehci-s5p.c
index f098e2a..02febbb 100644
--- a/drivers/usb/host/ehci-s5p.c
+++ b/drivers/usb/host/ehci-s5p.c
@@ -198,6 +198,9 @@
struct s5p_ehci_hcd *s5p_ehci = platform_get_drvdata(pdev);
struct usb_hcd *hcd = s5p_ehci->hcd;
+ if (!hcd->rh_registered)
+ return;
+
if (hcd->driver->shutdown)
hcd->driver->shutdown(hcd);
}
diff --git a/drivers/usb/host/ohci-exynos.c b/drivers/usb/host/ohci-exynos.c
index 37bb20e..b75d19b 100644
--- a/drivers/usb/host/ohci-exynos.c
+++ b/drivers/usb/host/ohci-exynos.c
@@ -22,6 +22,20 @@
struct clk *clk;
};
+static int ohci_exynos_init(struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+ int ret;
+
+ ohci_dbg(ohci, "ohci_exynos_init, ohci:%p", ohci);
+
+ ret = ohci_init(ohci);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
static int ohci_exynos_start(struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci(hcd);
@@ -29,10 +43,6 @@
ohci_dbg(ohci, "ohci_exynos_start, ohci:%p", ohci);
- ret = ohci_init(ohci);
- if (ret < 0)
- return ret;
-
ret = ohci_run(ohci);
if (ret < 0) {
err("can't start %s", hcd->self.bus_name);
@@ -51,6 +61,7 @@
.irq = ohci_irq,
.flags = HCD_MEMORY|HCD_USB11,
+ .reset = ohci_exynos_init,
.start = ohci_exynos_start,
.stop = ohci_stop,
.shutdown = ohci_shutdown,
@@ -192,6 +203,9 @@
struct exynos_ohci_hcd *exynos_ohci = platform_get_drvdata(pdev);
struct usb_hcd *hcd = exynos_ohci->hcd;
+ if (!hcd->rh_registered)
+ return;
+
if (hcd->driver->shutdown)
hcd->driver->shutdown(hcd);
}
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 65b07f4..8e1eda6 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -25,6 +25,8 @@
source "drivers/gpu/ion/Kconfig"
+source "drivers/gpu/arm/Kconfig"
+
config VGASTATE
tristate
default n
@@ -2039,7 +2041,7 @@
config FB_S3C
tristate "Samsung S3C framebuffer support"
- depends on FB && (S3C_DEV_FB || S5P_DEV_FIMD0)
+ depends on FB && (S3C_DEV_FB || S5P_DEV_FIMD0 || S5P_DEV_FIMD1)
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
@@ -2055,12 +2057,44 @@
Currently the support is only for the S3C6400 and S3C6410 SoCs.
+config FB_MIPI_DSIM
+ bool "Samsung MIPI DSIM"
+ depends on FB_S3C
+ default n
+ ---help---
+ This enables support for Samsung MIPI DSIM feature
+
+config FB_EXYNOS_FIMD_V8
+ bool "regiter extensions for FIMD version 8"
+ depends on FB_S3C && ARCH_EXYNOS5
+ default y
+ ---help---
+
+config FB_EXYNOS_FIMD_MC
+ bool "Support of media controller on FIMD for local path"
+ depends on FB_S3C && ARCH_EXYNOS5 && MEDIA_CONTROLLER
+ default y
+ ---help---
+
+config FB_EXYNOS_FIMD_MC_WB
+ bool "Support of media controller on FIMD for writeback to GScaler"
+ depends on FB_S3C && ARCH_EXYNOS5 && MEDIA_CONTROLLER
+ default y
+ ---help---
+
config FB_S3C_DEBUG_REGWRITE
bool "Debug register writes"
depends on FB_S3C
---help---
Show all register writes via printk(KERN_DEBUG)
+config S5P_DP
+ tristate "Samsung SoC DP support"
+ depends on FB_S3C && ARCH_EXYNOS5
+ default n
+ ---help---
+ This enables support for DP device.
+
config FB_S3C2410
tristate "S3C2410 LCD framebuffer support"
depends on FB && ARCH_S3C24XX
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 9356add..4f3ae50 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -121,7 +121,9 @@
obj-$(CONFIG_FB_S1D13XXX) += s1d13xxxfb.o
obj-$(CONFIG_FB_SH7760) += sh7760fb.o
obj-$(CONFIG_FB_IMX) += imxfb.o
+obj-$(CONFIG_FB_MIPI_DSIM) += s5p_mipi_dsi.o s5p_mipi_dsi_lowlevel.o
obj-$(CONFIG_FB_S3C) += s3c-fb.o
+obj-$(CONFIG_S5P_DP) += s5p-dp-core.o s5p-dp-reg.o
obj-$(CONFIG_FB_S3C2410) += s3c2410fb.o
obj-$(CONFIG_FB_FSL_DIU) += fsl-diu-fb.o
obj-$(CONFIG_FB_COBALT) += cobalt_lcdfb.o
@@ -167,3 +169,8 @@
#video output switch sysfs driver
obj-$(CONFIG_VIDEO_OUTPUT_CONTROL) += output.o
+
+ifeq ($(CONFIG_MALI_T6XX),y)
+ EXTRA_CFLAGS += -Idrivers/gpu/arm/t6xx
+endif
+
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index af16884..71709e5 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -125,6 +125,22 @@
If you have an AMS369FG06 AMOLED Panel, say Y to enable its
LCD control driver.
+config LCD_MIPI_S6E8AB0
+ tristate "1280 X 800 S6E8AB0 AMOLED MIPI LCD Driver"
+ depends on BACKLIGHT_CLASS_DEVICE
+ default n
+ help
+ If you have an S6E8AB0 MIPI LCD Panel, say Y to enable its
+ LCD control driver.
+
+config LCD_MIPI_TC358764
+ tristate "1280 X 800 TC358764 AMOLED MIPI LCD Driver"
+ depends on BACKLIGHT_CLASS_DEVICE
+ default n
+ help
+ If you have an TC358764 MIPI LCD Panel, say Y to enable its
+ LCD control driver.
+
endif # LCD_CLASS_DEVICE
#
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index 36855ae..2bc96c1 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -14,6 +14,8 @@
obj-$(CONFIG_LCD_S6E63M0) += s6e63m0.o
obj-$(CONFIG_LCD_LD9040) += ld9040.o
obj-$(CONFIG_LCD_AMS369FG06) += ams369fg06.o
+obj-$(CONFIG_LCD_MIPI_S6E8AB0) += s6e8ab0_mipi_lcd.o
+obj-$(CONFIG_LCD_MIPI_TC358764) += tc358764_mipi_lcd.o
obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o
obj-$(CONFIG_BACKLIGHT_ATMEL_PWM) += atmel-pwm-bl.o
diff --git a/drivers/video/backlight/s6e8ab0_mipi_lcd.c b/drivers/video/backlight/s6e8ab0_mipi_lcd.c
new file mode 100644
index 0000000..4352809
--- /dev/null
+++ b/drivers/video/backlight/s6e8ab0_mipi_lcd.c
@@ -0,0 +1,77 @@
+/* linux/drivers/video/backlight/s6e8ab0_mipi_lcd.c
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics
+ *
+ * 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.
+ *
+ *
+*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/mutex.h>
+#include <linux/wait.h>
+#include <linux/ctype.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/workqueue.h>
+#include <linux/backlight.h>
+#include <linux/lcd.h>
+
+#include <video/mipi_display.h>
+
+#include <plat/gpio-cfg.h>
+#include <plat/regs-dsim.h>
+
+#include <plat/dsim.h>
+#include <plat/mipi_dsi.h>
+
+void init_lcd(struct mipi_dsim_device *dsim)
+{
+ s5p_mipi_dsi_wr_data(dsim, MIPI_DSI_DCS_SHORT_WRITE,
+ 0, 0);
+ mdelay(60);
+ /* Exit sleep */
+ s5p_mipi_dsi_wr_data(dsim, MIPI_DSI_DCS_SHORT_WRITE,
+ 0x11, 0);
+ mdelay(600);
+ s5p_mipi_dsi_wr_data(dsim, MIPI_DSI_TURN_ON_PERIPHERAL,
+ 0, 0);
+}
+
+void s6e8ab0_mipi_lcd_off(struct mipi_dsim_device *dsim)
+{
+ mdelay(1);
+}
+
+static int s6e8ab0_mipi_lcd_suspend(struct mipi_dsim_device *dsim)
+{
+ s6e8ab0_mipi_lcd_off(dsim);
+ return 0;
+}
+
+static int s6e8ab0_mipi_lcd_displayon(struct mipi_dsim_device *dsim)
+{
+ init_lcd(dsim);
+
+ return 0;
+}
+
+static int s6e8ab0_mipi_lcd_resume(struct mipi_dsim_device *dsim)
+{
+ init_lcd(dsim);
+ return 0;
+}
+
+struct mipi_dsim_lcd_driver s6e8ab0_mipi_lcd_driver = {
+ .suspend = s6e8ab0_mipi_lcd_suspend,
+ .displayon = s6e8ab0_mipi_lcd_displayon,
+ .resume = s6e8ab0_mipi_lcd_resume,
+};
diff --git a/drivers/video/backlight/tc358764_mipi_lcd.c b/drivers/video/backlight/tc358764_mipi_lcd.c
new file mode 100644
index 0000000..2ad2122
--- /dev/null
+++ b/drivers/video/backlight/tc358764_mipi_lcd.c
@@ -0,0 +1,168 @@
+/* linux/drivers/video/backlight/tc358764_mipi_lcd.c
+ *
+ *
+ * Copyright (c) 2011 Samsung Electronics
+ *
+ * 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.
+ *
+ *
+*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/mutex.h>
+#include <linux/wait.h>
+#include <linux/ctype.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/workqueue.h>
+#include <linux/backlight.h>
+#include <linux/lcd.h>
+
+#include <video/mipi_display.h>
+
+#include <plat/gpio-cfg.h>
+#include <plat/regs-mipidsim.h>
+
+#include <plat/dsim.h>
+#include <plat/mipi_dsi.h>
+
+static int init_lcd(struct mipi_dsim_device *dsim)
+{
+ unsigned char initcode_013c[6] = {0x3c, 0x01, 0x03, 0x00, 0x02, 0x00};
+ unsigned char initcode_0114[6] = {0x14, 0x01, 0x02, 0x00, 0x00, 0x00};
+ unsigned char initcode_0164[6] = {0x64, 0x01, 0x05, 0x00, 0x00, 0x00};
+ unsigned char initcode_0168[6] = {0x68, 0x01, 0x05, 0x00, 0x00, 0x00};
+ unsigned char initcode_016c[6] = {0x6c, 0x01, 0x05, 0x00, 0x00, 0x00};
+ unsigned char initcode_0170[6] = {0x70, 0x01, 0x05, 0x00, 0x00, 0x00};
+ unsigned char initcode_0134[6] = {0x34, 0x01, 0x1f, 0x00, 0x00, 0x00};
+ unsigned char initcode_0210[6] = {0x10, 0x02, 0x1f, 0x00, 0x00, 0x00};
+ unsigned char initcode_0104[6] = {0x04, 0x01, 0x01, 0x00, 0x00, 0x00};
+ unsigned char initcode_0204[6] = {0x04, 0x02, 0x01, 0x00, 0x00, 0x00};
+ unsigned char initcode_0450[6] = {0x50, 0x04, 0x20, 0x01, 0xfa, 0x00};
+ unsigned char initcode_0454[6] = {0x54, 0x04, 0x20, 0x00, 0x50, 0x00};
+ unsigned char initcode_0458[6] = {0x58, 0x04, 0x00, 0x05, 0x30, 0x00};
+ unsigned char initcode_045c[6] = {0x5c, 0x04, 0x05, 0x00, 0x0a, 0x00};
+ unsigned char initcode_0460[6] = {0x60, 0x04, 0x20, 0x03, 0x0a, 0x00};
+ unsigned char initcode_0464[6] = {0x64, 0x04, 0x01, 0x00, 0x00, 0x00};
+ unsigned char initcode_04a0_1[6] = {0xa0, 0x04, 0x06, 0x80, 0x44, 0x00};
+ unsigned char initcode_04a0_2[6] = {0xa0, 0x04, 0x06, 0x80, 0x04, 0x00};
+ unsigned char initcode_0504[6] = {0x04, 0x05, 0x04, 0x00, 0x00, 0x00};
+ unsigned char initcode_049c[6] = {0x9c, 0x04, 0x0d, 0x00, 0x00, 0x00};
+
+ if (s5p_mipi_dsi_wr_data(dsim, MIPI_DSI_GENERIC_LONG_WRITE,
+ (unsigned int) initcode_013c, sizeof(initcode_013c)) == -1)
+ return 0;
+ mdelay(6);
+ if (s5p_mipi_dsi_wr_data(dsim, MIPI_DSI_GENERIC_LONG_WRITE,
+ (unsigned int) initcode_0114, sizeof(initcode_0114)) == -1)
+ return 0;
+ mdelay(6);
+ if (s5p_mipi_dsi_wr_data(dsim, MIPI_DSI_GENERIC_LONG_WRITE,
+ (unsigned int) initcode_0164, sizeof(initcode_0164)) == -1)
+ return 0;
+ mdelay(6);
+ if (s5p_mipi_dsi_wr_data(dsim, MIPI_DSI_GENERIC_LONG_WRITE,
+ (unsigned int) initcode_0168, sizeof(initcode_0168)) == -1)
+ return 0;
+ mdelay(6);
+ if (s5p_mipi_dsi_wr_data(dsim, MIPI_DSI_GENERIC_LONG_WRITE,
+ (unsigned int) initcode_016c, sizeof(initcode_016c)) == -1)
+ return 0;
+ mdelay(6);
+ if (s5p_mipi_dsi_wr_data(dsim, MIPI_DSI_GENERIC_LONG_WRITE,
+ (unsigned int) initcode_0170, sizeof(initcode_0170)) == -1)
+ return 0;
+ mdelay(6);
+ if (s5p_mipi_dsi_wr_data(dsim, MIPI_DSI_GENERIC_LONG_WRITE,
+ (unsigned int) initcode_0134, sizeof(initcode_0134)) == -1)
+ return 0;
+ mdelay(6);
+ if (s5p_mipi_dsi_wr_data(dsim, MIPI_DSI_GENERIC_LONG_WRITE,
+ (unsigned int) initcode_0210, sizeof(initcode_0210)) == -1)
+ return 0;
+ mdelay(6);
+ if (s5p_mipi_dsi_wr_data(dsim, MIPI_DSI_GENERIC_LONG_WRITE,
+ (unsigned int) initcode_0104, sizeof(initcode_0104)) == -1)
+ return 0;
+ mdelay(6);
+ if (s5p_mipi_dsi_wr_data(dsim, MIPI_DSI_GENERIC_LONG_WRITE,
+ (unsigned int) initcode_0204, sizeof(initcode_0204)) == -1)
+ return 0;
+ mdelay(6);
+ if (s5p_mipi_dsi_wr_data(dsim, MIPI_DSI_GENERIC_LONG_WRITE,
+ (unsigned int) initcode_0450, sizeof(initcode_0450)) == -1)
+ return 0;
+ mdelay(6);
+ if (s5p_mipi_dsi_wr_data(dsim, MIPI_DSI_GENERIC_LONG_WRITE,
+ (unsigned int) initcode_0454, sizeof(initcode_0454)) == -1)
+ return 0;
+ mdelay(6);
+ if (s5p_mipi_dsi_wr_data(dsim, MIPI_DSI_GENERIC_LONG_WRITE,
+ (unsigned int) initcode_0458, sizeof(initcode_0458)) == -1)
+ return 0;
+ mdelay(6);
+ if (s5p_mipi_dsi_wr_data(dsim, MIPI_DSI_GENERIC_LONG_WRITE,
+ (unsigned int) initcode_045c, sizeof(initcode_045c)) == -1)
+ return 0;
+ mdelay(6);
+ if (s5p_mipi_dsi_wr_data(dsim, MIPI_DSI_GENERIC_LONG_WRITE,
+ (unsigned int) initcode_0460, sizeof(initcode_0460)) == -1)
+ return 0;
+ mdelay(6);
+ if (s5p_mipi_dsi_wr_data(dsim, MIPI_DSI_GENERIC_LONG_WRITE,
+ (unsigned int) initcode_0464, sizeof(initcode_0464)) == -1)
+ return 0;
+ mdelay(6);
+ if (s5p_mipi_dsi_wr_data(dsim, MIPI_DSI_GENERIC_LONG_WRITE,
+ (unsigned int) initcode_04a0_1, sizeof(initcode_04a0_1)) == -1)
+ return 0;
+ mdelay(12);
+ if (s5p_mipi_dsi_wr_data(dsim, MIPI_DSI_GENERIC_LONG_WRITE,
+ (unsigned int) initcode_04a0_2, sizeof(initcode_04a0_2)) == -1)
+ return 0;
+ mdelay(6);
+ if (s5p_mipi_dsi_wr_data(dsim, MIPI_DSI_GENERIC_LONG_WRITE,
+ (unsigned int) initcode_0504, sizeof(initcode_0504)) == -1)
+ return 0;
+ mdelay(6);
+ if (s5p_mipi_dsi_wr_data(dsim, MIPI_DSI_GENERIC_LONG_WRITE,
+ (unsigned int) initcode_049c, sizeof(initcode_049c)) == -1)
+ return 0;
+ mdelay(800);
+
+ return 1;
+}
+
+void tc358764_mipi_lcd_off(struct mipi_dsim_device *dsim)
+{
+ mdelay(1);
+}
+
+static int tc358764_mipi_lcd_suspend(struct mipi_dsim_device *dsim)
+{
+ tc358764_mipi_lcd_off(dsim);
+ return 0;
+}
+
+static int tc358764_mipi_lcd_displayon(struct mipi_dsim_device *dsim)
+{
+ return init_lcd(dsim);
+}
+
+static int tc358764_mipi_lcd_resume(struct mipi_dsim_device *dsim)
+{
+ return init_lcd(dsim);
+}
+
+struct mipi_dsim_lcd_driver tc358764_mipi_lcd_driver = {
+ .suspend = tc358764_mipi_lcd_suspend,
+ .displayon = tc358764_mipi_lcd_displayon,
+ .resume = tc358764_mipi_lcd_resume,
+};
diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c
index f310516..489038c 100644
--- a/drivers/video/s3c-fb.c
+++ b/drivers/video/s3c-fb.c
@@ -24,11 +24,41 @@
#include <linux/uaccess.h>
#include <linux/interrupt.h>
#include <linux/pm_runtime.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+#if defined(CONFIG_FB_EXYNOS_FIMD_MC) || defined(CONFIG_FB_EXYNOS_FIMD_MC_WB)
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-device.h>
+#include <media/exynos_mc.h>
+#include <plat/map-base.h>
+#endif
+
+#include <mach/exynos5_bus.h>
#include <mach/map.h>
#include <plat/regs-fb-v4.h>
#include <plat/fb.h>
+#ifdef CONFIG_ION_EXYNOS
+#include <linux/dma-buf.h>
+#include <linux/exynos_ion.h>
+#include <linux/ion.h>
+#include <linux/highmem.h>
+#include <linux/memblock.h>
+#include <linux/sw_sync.h>
+#include <plat/devs.h>
+#include <plat/iovmm.h>
+#include <plat/sysmmu.h>
+#include <mach/sysmmu.h>
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+#include <linux/debugfs.h>
+#endif
+
+
/* This driver will export a number of framebuffer interfaces depending
* on the configuration passed in via the platform data. Each fb instance
* maps to a hardware window. Currently there is no support for runtime
@@ -52,13 +82,36 @@
} while (0)
#endif /* FB_S3C_DEBUG_REGWRITE */
-/* irq_flags bits */
-#define S3C_FB_VSYNC_IRQ_EN 0
-
#define VSYNC_TIMEOUT_MSEC 50
+#define MAX_BW_PER_WINDOW (2560 * 1600 * 4 * 60)
+
struct s3c_fb;
+#ifdef CONFIG_ION_EXYNOS
+extern struct ion_device *ion_exynos;
+#endif
+
+#ifdef CONFIG_FB_EXYNOS_FIMD_MC
+#define SYSREG_MIXER0_VALID (1 << 7)
+#define SYSREG_MIXER1_VALID (1 << 4)
+#define FIMD_PAD_SINK_FROM_GSCALER_SRC 0
+#define FIMD_PADS_NUM 1
+
+/* SYSREG for local path between Gscaler and Mixer */
+#define SYSREG_DISP1BLK_CFG (S3C_VA_SYS + 0x0214)
+#endif
+
+#ifdef CONFIG_FB_EXYNOS_FIMD_MC_WB
+#define SYSREG_DISP1WB_DEST(_x) ((_x) << 10)
+#define SYSREG_DISP1WB_DEST_MASK (0x3 << 10)
+#define FIMD_WB_PAD_SRC_TO_GSCALER_SINK 0
+#define FIMD_WB_PADS_NUM 1
+
+/* SYSREG for local path between Gscaler and Mixer */
+#define SYSREG_GSCLBLK_CFG (S3C_VA_SYS + 0x0224)
+#endif
+
#define VALID_BPP(x) (1 << ((x) - 1))
#define OSD_BASE(win, variant) ((variant).osd + ((win) * (variant).osd_stride))
@@ -83,6 +136,7 @@
* @has_prtcon: Set if has PRTCON register.
* @has_shadowcon: Set if has SHADOWCON register.
* @has_blendcon: Set if has BLENDCON register.
+ * @has_alphacon: Set if has VIDWALPHA register.
* @has_clksel: Set if VIDCON0 register has CLKSEL bit.
* @has_fixvclk: Set if VIDCON1 register has FIXVCLK bits.
*/
@@ -103,6 +157,7 @@
unsigned int has_prtcon:1;
unsigned int has_shadowcon:1;
unsigned int has_blendcon:1;
+ unsigned int has_alphacon:1;
unsigned int has_clksel:1;
unsigned int has_fixvclk:1;
};
@@ -154,6 +209,36 @@
struct fb_bitfield a;
};
+#ifdef CONFIG_ION_EXYNOS
+struct s3c_dma_buf_data {
+ struct ion_handle *ion_handle;
+ struct dma_buf *dma_buf;
+ struct dma_buf_attachment *attachment;
+ struct sg_table *sg_table;
+ dma_addr_t dma_addr;
+ struct sync_fence *fence;
+};
+
+struct s3c_reg_data {
+ struct list_head list;
+ u32 shadowcon;
+ u32 wincon[S3C_FB_MAX_WIN];
+ u32 win_rgborder[S3C_FB_MAX_WIN];
+ u32 winmap[S3C_FB_MAX_WIN];
+ u32 vidosd_a[S3C_FB_MAX_WIN];
+ u32 vidosd_b[S3C_FB_MAX_WIN];
+ u32 vidosd_c[S3C_FB_MAX_WIN];
+ u32 vidosd_d[S3C_FB_MAX_WIN];
+ u32 vidw_alpha0[S3C_FB_MAX_WIN];
+ u32 vidw_alpha1[S3C_FB_MAX_WIN];
+ u32 blendeq[S3C_FB_MAX_WIN - 1];
+ u32 vidw_buf_start[S3C_FB_MAX_WIN];
+ u32 vidw_buf_end[S3C_FB_MAX_WIN];
+ u32 vidw_buf_size[S3C_FB_MAX_WIN];
+ struct s3c_dma_buf_data dma_buf_data[S3C_FB_MAX_WIN];
+};
+#endif
+
/**
* struct s3c_fb_win - per window private data for each framebuffer.
* @windata: The platform data supplied for the window configuration.
@@ -175,18 +260,52 @@
u32 *palette_buffer;
u32 pseudo_palette[16];
unsigned int index;
+#ifdef CONFIG_ION_EXYNOS
+ struct s3c_dma_buf_data dma_buf_data;
+ struct fb_var_screeninfo prev_var;
+ struct fb_fix_screeninfo prev_fix;
+#endif
+
+ int fps;
+
+#ifdef CONFIG_FB_EXYNOS_FIMD_MC
+ int use; /* use of widnow subdev in fimd */
+ int local; /* use of local path gscaler to window in fimd */
+ struct media_pad pads[FIMD_PADS_NUM]; /* window's pad : 1 sink */
+ struct v4l2_subdev sd; /* Take a window as a v4l2_subdevice */
+#endif
};
/**
* struct s3c_fb_vsync - vsync information
- * @wait: a queue for processes waiting for vsync
- * @count: vsync interrupt count
+ * @wait: a queue for processes waiting for vsync
+ * @timestamp: the time of the last vsync interrupt
+ * @active: whether userspace is requesting vsync notifications
+ * @irq_refcount: reference count for the underlying irq
+ * @irq_lock: mutex protecting the irq refcount and register
+ * @thread: notification-generating thread
*/
struct s3c_fb_vsync {
wait_queue_head_t wait;
- unsigned int count;
+ ktime_t timestamp;
+ bool active;
+ int irq_refcount;
+ struct mutex irq_lock;
+ struct task_struct *thread;
};
+#ifdef CONFIG_DEBUG_FS
+#define S3C_FB_DEBUG_FIFO_TIMESTAMPS 32
+#define S3C_FB_DEBUG_REGS_SIZE 0x0280
+
+struct s3c_fb_debug {
+ ktime_t fifo_timestamps[S3C_FB_DEBUG_FIFO_TIMESTAMPS];
+ unsigned int num_timestamps;
+ unsigned int first_timestamp;
+ u8 regs_at_underflow[S3C_FB_DEBUG_REGS_SIZE];
+};
+#endif
+
/**
* struct s3c_fb - overall hardware state of the hardware
* @slock: The spinlock protection for this data sturcture.
@@ -200,7 +319,6 @@
* @pdata: The platform configuration data passed with the device.
* @windows: The hardware windows that have been claimed.
* @irq_no: IRQ line number
- * @irq_flags: irq flags
* @vsync_info: VSYNC-related information (count, queues...)
*/
struct s3c_fb {
@@ -211,17 +329,82 @@
void __iomem *regs;
struct s3c_fb_variant variant;
- unsigned char enabled;
- bool output_on;
+ bool output_on;
+ struct mutex output_lock;
struct s3c_fb_platdata *pdata;
struct s3c_fb_win *windows[S3C_FB_MAX_WIN];
int irq_no;
- unsigned long irq_flags;
struct s3c_fb_vsync vsync_info;
+
+#ifdef CONFIG_ION_EXYNOS
+ struct ion_client *fb_ion_client;
+
+ struct list_head update_regs_list;
+ struct mutex update_regs_list_lock;
+ struct kthread_worker update_regs_worker;
+ struct task_struct *update_regs_thread;
+ struct kthread_work update_regs_work;
+
+ struct sw_sync_timeline *timeline;
+ int timeline_max;
+#endif
+
+#ifdef CONFIG_FB_EXYNOS_FIMD_MC
+ struct exynos_md *md;
+#endif
+#ifdef CONFIG_FB_EXYNOS_FIMD_MC_WB
+ struct exynos_md *md_wb;
+ int use_wb; /* use of fimd subdev for writeback */
+ int local_wb; /* use of writeback path to gscaler in fimd */
+ struct media_pad pads_wb; /* FIMD1's pad */
+ struct v4l2_subdev sd_wb; /* Take a FIMD1 as a v4l2_subdevice */
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+ struct dentry *debug_dentry;
+ struct s3c_fb_debug debug_data;
+#endif
+ struct exynos5_bus_mif_handle *fb_mif_handle;
+ struct exynos5_bus_int_handle *fb_int_handle;
+
};
+static void s3c_fb_dump_registers(struct s3c_fb *sfb)
+{
+#ifdef CONFIG_FB_EXYNOS_FIMD_V8
+ pr_err("dumping registers\n");
+ print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS, 32, 4, sfb->regs,
+ 0x0280, false);
+ pr_err("...\n");
+ print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS, 32, 4,
+ sfb->regs + SHD_VIDW_BUF_START(0), 0x74, false);
+ pr_err("...\n");
+ print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS, 32, 4,
+ sfb->regs + 0x20000, 0x20, false);
+#endif
+}
+
+static bool s3c_fb_validate_x_alignment(struct s3c_fb *sfb, int x, u32 w,
+ u32 bits_per_pixel)
+{
+ uint8_t pixel_alignment = 32 / bits_per_pixel;
+
+ if (x % pixel_alignment) {
+ dev_err(sfb->dev, "left X coordinate not properly aligned to %u-pixel boundary (bpp = %u, x = %u)\n",
+ pixel_alignment, bits_per_pixel, x);
+ return 0;
+ }
+ if ((x + w) % pixel_alignment) {
+ dev_err(sfb->dev, "right X coordinate not properly aligned to %u-pixel boundary (bpp = %u, x = %u, w = %u)\n",
+ pixel_alignment, bits_per_pixel, x, w);
+ return 0;
+ }
+
+ return 1;
+}
+
/**
* s3c_fb_validate_win_bpp - validate the bits-per-pixel for this mode.
* @win: The device window.
@@ -245,6 +428,8 @@
{
struct s3c_fb_win *win = info->par;
struct s3c_fb *sfb = win->parent;
+ int x, y;
+ unsigned long long hz;
dev_dbg(sfb->dev, "checking parameters\n");
@@ -257,6 +442,10 @@
return -EINVAL;
}
+ if (!s3c_fb_validate_x_alignment(sfb, 0, var->xres,
+ var->bits_per_pixel))
+ return -EINVAL;
+
/* always ensure these are zero, for drop through cases below */
var->transp.offset = 0;
var->transp.length = 0;
@@ -331,6 +520,19 @@
dev_err(sfb->dev, "invalid bpp\n");
}
+ x = var->xres + var->left_margin + var->right_margin + var->hsync_len;
+ y = var->yres + var->upper_margin + var->lower_margin + var->vsync_len;
+
+ hz = 1000000000000ULL; /* 1e12 picoseconds per second */
+
+ hz += (x * y) / 2;
+ do_div(hz, x * y); /* divide by x * y with rounding */
+
+ hz += var->pixclock / 2;
+ do_div(hz, var->pixclock); /* divide by pixclock with rounding */
+
+ win->fps = hz;
+
dev_dbg(sfb->dev, "%s: verified parameters\n", __func__);
return 0;
}
@@ -360,32 +562,10 @@
do_div(tmp, 1000000000UL);
result = (unsigned int)tmp / 1000;
- dev_dbg(sfb->dev, "pixclk=%u, clk=%lu, div=%d (%lu)\n",
- pixclk, clk, result, clk / result);
-
return result;
}
/**
- * s3c_fb_align_word() - align pixel count to word boundary
- * @bpp: The number of bits per pixel
- * @pix: The value to be aligned.
- *
- * Align the given pixel count so that it will start on an 32bit word
- * boundary.
- */
-static int s3c_fb_align_word(unsigned int bpp, unsigned int pix)
-{
- int pix_per_word;
-
- if (bpp > 16)
- return pix;
-
- pix_per_word = (8 * 32) / bpp;
- return ALIGN(pix, pix_per_word);
-}
-
-/**
* vidosd_set_size() - set OSD size for a window
*
* @win: the window to set OSD size for
@@ -402,20 +582,6 @@
}
/**
- * vidosd_set_alpha() - set alpha transparency for a window
- *
- * @win: the window to set OSD size for
- * @alpha: alpha register value
- */
-static void vidosd_set_alpha(struct s3c_fb_win *win, u32 alpha)
-{
- struct s3c_fb *sfb = win->parent;
-
- if (win->variant.has_osd_alpha)
- writel(alpha, sfb->regs + VIDOSD_C(win->index, sfb->variant));
-}
-
-/**
* shadow_protect_win() - disable updating values from shadow registers at vsync
*
* @win: window to protect registers for
@@ -445,191 +611,88 @@
}
}
-/**
- * s3c_fb_enable() - Set the state of the main LCD output
- * @sfb: The main framebuffer state.
- * @enable: The state to set.
- */
-static void s3c_fb_enable(struct s3c_fb *sfb, int enable)
+static inline u32 fb_visual(u32 bits_per_pixel, unsigned short palette_sz)
{
- u32 vidcon0 = readl(sfb->regs + VIDCON0);
-
- if (enable && !sfb->output_on)
- pm_runtime_get_sync(sfb->dev);
-
- if (enable) {
- vidcon0 |= VIDCON0_ENVID | VIDCON0_ENVID_F;
- } else {
- /* see the note in the framebuffer datasheet about
- * why you cannot take both of these bits down at the
- * same time. */
-
- if (vidcon0 & VIDCON0_ENVID) {
- vidcon0 |= VIDCON0_ENVID;
- vidcon0 &= ~VIDCON0_ENVID_F;
- }
- }
-
- writel(vidcon0, sfb->regs + VIDCON0);
-
- if (!enable && sfb->output_on)
- pm_runtime_put_sync(sfb->dev);
-
- sfb->output_on = enable;
-}
-
-/**
- * s3c_fb_set_par() - framebuffer request to set new framebuffer state.
- * @info: The framebuffer to change.
- *
- * Framebuffer layer request to set a new mode for the specified framebuffer
- */
-static int s3c_fb_set_par(struct fb_info *info)
-{
- struct fb_var_screeninfo *var = &info->var;
- struct s3c_fb_win *win = info->par;
- struct s3c_fb *sfb = win->parent;
- void __iomem *regs = sfb->regs;
- void __iomem *buf = regs;
- int win_no = win->index;
- u32 alpha = 0;
- u32 data;
- u32 pagewidth;
- int clkdiv;
-
- dev_dbg(sfb->dev, "setting framebuffer parameters\n");
-
- pm_runtime_get_sync(sfb->dev);
-
- shadow_protect_win(win, 1);
-
- switch (var->bits_per_pixel) {
+ switch (bits_per_pixel) {
case 32:
case 24:
case 16:
case 12:
- info->fix.visual = FB_VISUAL_TRUECOLOR;
- break;
+ return FB_VISUAL_TRUECOLOR;
case 8:
- if (win->variant.palette_sz >= 256)
- info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+ if (palette_sz >= 256)
+ return FB_VISUAL_PSEUDOCOLOR;
else
- info->fix.visual = FB_VISUAL_TRUECOLOR;
- break;
+ return FB_VISUAL_TRUECOLOR;
case 1:
- info->fix.visual = FB_VISUAL_MONO01;
- break;
+ return FB_VISUAL_MONO01;
default:
- info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
- break;
+ return FB_VISUAL_PSEUDOCOLOR;
}
+}
- info->fix.line_length = (var->xres_virtual * var->bits_per_pixel) / 8;
+static inline u32 fb_linelength(u32 xres_virtual, u32 bits_per_pixel)
+{
+ return (xres_virtual * bits_per_pixel) / 8;
+}
- info->fix.xpanstep = info->var.xres_virtual > info->var.xres ? 1 : 0;
- info->fix.ypanstep = info->var.yres_virtual > info->var.yres ? 1 : 0;
+static inline u16 fb_panstep(u32 res, u32 res_virtual)
+{
+ return res_virtual > res ? 1 : 0;
+}
- /* disable the window whilst we update it */
- writel(0, regs + WINCON(win_no));
-
- /* use platform specified window as the basis for the lcd timings */
-
- if (win_no == sfb->pdata->default_win) {
- clkdiv = s3c_fb_calc_pixclk(sfb, var->pixclock);
-
- data = sfb->pdata->vidcon0;
- data &= ~(VIDCON0_CLKVAL_F_MASK | VIDCON0_CLKDIR);
-
- if (clkdiv > 1)
- data |= VIDCON0_CLKVAL_F(clkdiv-1) | VIDCON0_CLKDIR;
- else
- data &= ~VIDCON0_CLKDIR; /* 1:1 clock */
-
- /* write the timing data to the panel */
-
- if (sfb->variant.is_2443)
- data |= (1 << 5);
-
- writel(data, regs + VIDCON0);
-
- s3c_fb_enable(sfb, 1);
-
- data = VIDTCON0_VBPD(var->upper_margin - 1) |
- VIDTCON0_VFPD(var->lower_margin - 1) |
- VIDTCON0_VSPW(var->vsync_len - 1);
-
- writel(data, regs + sfb->variant.vidtcon);
-
- data = VIDTCON1_HBPD(var->left_margin - 1) |
- VIDTCON1_HFPD(var->right_margin - 1) |
- VIDTCON1_HSPW(var->hsync_len - 1);
-
- /* VIDTCON1 */
- writel(data, regs + sfb->variant.vidtcon + 4);
-
- data = VIDTCON2_LINEVAL(var->yres - 1) |
- VIDTCON2_HOZVAL(var->xres - 1) |
- VIDTCON2_LINEVAL_E(var->yres - 1) |
- VIDTCON2_HOZVAL_E(var->xres - 1);
- writel(data, regs + sfb->variant.vidtcon + 8);
- }
-
- /* write the buffer address */
-
- /* start and end registers stride is 8 */
- buf = regs + win_no * 8;
-
- writel(info->fix.smem_start, buf + sfb->variant.buf_start);
-
- data = info->fix.smem_start + info->fix.line_length * var->yres;
- writel(data, buf + sfb->variant.buf_end);
-
- pagewidth = (var->xres * var->bits_per_pixel) >> 3;
- data = VIDW_BUF_SIZE_OFFSET(info->fix.line_length - pagewidth) |
+static inline u32 vidw_buf_size(u32 xres, u32 line_length, u32 bits_per_pixel)
+{
+ u32 pagewidth = (xres * bits_per_pixel) >> 3;
+ return VIDW_BUF_SIZE_OFFSET(line_length - pagewidth) |
VIDW_BUF_SIZE_PAGEWIDTH(pagewidth) |
- VIDW_BUF_SIZE_OFFSET_E(info->fix.line_length - pagewidth) |
+ VIDW_BUF_SIZE_OFFSET_E(line_length - pagewidth) |
VIDW_BUF_SIZE_PAGEWIDTH_E(pagewidth);
- writel(data, regs + sfb->variant.buf_size + (win_no * 4));
+}
- /* write 'OSD' registers to control position of framebuffer */
+static inline u32 vidosd_a(int x, int y)
+{
+ return VIDOSDxA_TOPLEFT_X(x) |
+ VIDOSDxA_TOPLEFT_Y(y) |
+ VIDOSDxA_TOPLEFT_X_E(x) |
+ VIDOSDxA_TOPLEFT_Y_E(y);
+}
- data = VIDOSDxA_TOPLEFT_X(0) | VIDOSDxA_TOPLEFT_Y(0) |
- VIDOSDxA_TOPLEFT_X_E(0) | VIDOSDxA_TOPLEFT_Y_E(0);
- writel(data, regs + VIDOSD_A(win_no, sfb->variant));
+static inline u32 vidosd_b(int x, int y, u32 xres, u32 yres)
+{
+ return VIDOSDxB_BOTRIGHT_X(x + xres - 1) |
+ VIDOSDxB_BOTRIGHT_Y(y + yres - 1) |
+ VIDOSDxB_BOTRIGHT_X_E(x + xres - 1) |
+ VIDOSDxB_BOTRIGHT_Y_E(y + yres - 1);
+}
- data = VIDOSDxB_BOTRIGHT_X(s3c_fb_align_word(var->bits_per_pixel,
- var->xres - 1)) |
- VIDOSDxB_BOTRIGHT_Y(var->yres - 1) |
- VIDOSDxB_BOTRIGHT_X_E(s3c_fb_align_word(var->bits_per_pixel,
- var->xres - 1)) |
- VIDOSDxB_BOTRIGHT_Y_E(var->yres - 1);
+static inline u32 vidosd_c(u8 r0, u8 g0, u8 b0, u8 r1, u8 g1, u8 b1)
+{
+ return VIDOSDxC_ALPHA0_R_H(r0) |
+ VIDOSDxC_ALPHA0_G_H(g0) |
+ VIDOSDxC_ALPHA0_B_H(b0) |
+ VIDOSDxC_ALPHA1_R_H(r1) |
+ VIDOSDxC_ALPHA1_G_H(g1) |
+ VIDOSDxC_ALPHA1_B_H(b1);
+}
- writel(data, regs + VIDOSD_B(win_no, sfb->variant));
+static inline u32 vidw_alpha(bool has_osd_alpha, u8 r, u8 g, u8 b)
+{
+ if (has_osd_alpha)
+ return VIDWxALPHAx_R_L(r) |
+ VIDWxALPHAx_G_L(g) |
+ VIDWxALPHAx_B_L(b);
+ else
+ return VIDWxALPHAx_R(r) |
+ VIDWxALPHAx_G(g) |
+ VIDWxALPHAx_B(b);
+}
- data = var->xres * var->yres;
+static inline u32 wincon(u32 bits_per_pixel, u32 transp_length, u32 red_length)
+{
+ u32 data = 0;
- alpha = VIDISD14C_ALPHA1_R(0xf) |
- VIDISD14C_ALPHA1_G(0xf) |
- VIDISD14C_ALPHA1_B(0xf);
-
- vidosd_set_alpha(win, alpha);
- vidosd_set_size(win, data);
-
- /* Enable DMA channel for this window */
- if (sfb->variant.has_shadowcon) {
- data = readl(sfb->regs + SHADOWCON);
- data |= SHADOWCON_CHx_ENABLE(win_no);
- writel(data, sfb->regs + SHADOWCON);
- }
-
- data = WINCONx_ENWIN;
- sfb->enabled |= (1 << win->index);
-
- /* note, since we have to round up the bits-per-pixel, we end up
- * relying on the bitfield information for r/g/b/a to work out
- * exactly which mode of operation is intended. */
-
- switch (var->bits_per_pixel) {
+ switch (bits_per_pixel) {
case 1:
data |= WINCON0_BPPMODE_1BPP;
data |= WINCONx_BITSWP;
@@ -646,7 +709,7 @@
data |= WINCONx_BURSTLEN_8WORD;
break;
case 8:
- if (var->transp.length != 0)
+ if (transp_length != 0)
data |= WINCON1_BPPMODE_8BPP_1232;
else
data |= WINCON0_BPPMODE_8BPP_PALETTE;
@@ -654,8 +717,12 @@
data |= WINCONx_BYTSWP;
break;
case 16:
- if (var->transp.length != 0)
- data |= WINCON1_BPPMODE_16BPP_A1555;
+ if (transp_length == 1)
+ data |= WINCON1_BPPMODE_16BPP_A1555
+ | WINCON1_BLD_PIX;
+ else if (transp_length == 4)
+ data |= WINCON1_BPPMODE_16BPP_A4444
+ | WINCON1_BLD_PIX;
else
data |= WINCON0_BPPMODE_16BPP_565;
data |= WINCONx_HAWSWP;
@@ -663,18 +730,18 @@
break;
case 24:
case 32:
- if (var->red.length == 6) {
- if (var->transp.length != 0)
+ if (red_length == 6) {
+ if (transp_length != 0)
data |= WINCON1_BPPMODE_19BPP_A1666;
else
data |= WINCON1_BPPMODE_18BPP_666;
- } else if (var->transp.length == 1)
+ } else if (transp_length == 1)
data |= WINCON1_BPPMODE_25BPP_A1888
| WINCON1_BLD_PIX;
- else if ((var->transp.length == 4) ||
- (var->transp.length == 8))
+ else if ((transp_length == 4) ||
+ (transp_length == 8))
data |= WINCON1_BPPMODE_28BPP_A4888
- | WINCON1_BLD_PIX | WINCON1_ALPHA_SEL;
+ | WINCON1_BLD_PIX;
else
data |= WINCON0_BPPMODE_24BPP_888;
@@ -683,6 +750,181 @@
break;
}
+ if (transp_length != 1)
+ data |= WINCON1_ALPHA_SEL;
+
+ return data;
+}
+
+static inline u32 blendeq(enum s3c_fb_blending blending, u8 transp_length)
+{
+ u8 a, b;
+
+ if (transp_length == 1 && blending == S3C_FB_BLENDING_PREMULT)
+ blending = S3C_FB_BLENDING_COVERAGE;
+
+ switch (blending) {
+ case S3C_FB_BLENDING_NONE:
+ a = BLENDEQ_COEF_ONE;
+ b = BLENDEQ_COEF_ZERO;
+ break;
+
+ case S3C_FB_BLENDING_PREMULT:
+ a = BLENDEQ_COEF_ONE;
+ b = BLENDEQ_COEF_ONE_MINUS_ALPHA_A;
+ break;
+
+ case S3C_FB_BLENDING_COVERAGE:
+ a = BLENDEQ_COEF_ALPHA_A;
+ b = BLENDEQ_COEF_ONE_MINUS_ALPHA_A;
+ break;
+
+ default:
+ return 0;
+ }
+
+ return BLENDEQ_A_FUNC(a) |
+ BLENDEQ_B_FUNC(b) |
+ BLENDEQ_P_FUNC(BLENDEQ_COEF_ZERO) |
+ BLENDEQ_Q_FUNC(BLENDEQ_COEF_ZERO);
+}
+
+static void s3c_fb_configure_lcd(struct s3c_fb *sfb,
+ struct fb_videomode *win_mode)
+{
+ int clkdiv = s3c_fb_calc_pixclk(sfb, win_mode->pixclock);
+ u32 data = sfb->pdata->vidcon0;
+ data &= ~(VIDCON0_CLKVAL_F_MASK | VIDCON0_CLKDIR);
+ if (clkdiv > 1)
+ data |= VIDCON0_CLKVAL_F(clkdiv-1) | VIDCON0_CLKDIR;
+ else
+ data &= ~VIDCON0_CLKDIR;
+
+ /* write the timing data to the panel */
+ if (sfb->variant.is_2443)
+ data |= (1 << 5);
+
+ data |= VIDCON0_ENVID | VIDCON0_ENVID_F;
+ writel(data, sfb->regs + VIDCON0);
+ data = readl(sfb->regs + VIDCON2);
+ data &= ~(VIDCON2_RGB_ORDER_E_MASK | VIDCON2_RGB_ORDER_O_MASK);
+ data |= VIDCON2_RGB_ORDER_E_BGR | VIDCON2_RGB_ORDER_O_BGR;
+ writel(data, sfb->regs + VIDCON2);
+
+ /* Set alpha value width */
+ if (sfb->variant.has_blendcon) {
+ data = readl(sfb->regs + BLENDCON);
+ data &= ~BLENDCON_NEW_MASK;
+ data |= BLENDCON_NEW_8BIT_ALPHA_VALUE;
+ writel(data, sfb->regs + BLENDCON);
+ }
+
+ data = VIDTCON0_VBPD(win_mode->upper_margin - 1)
+ | VIDTCON0_VFPD(win_mode->lower_margin - 1)
+ | VIDTCON0_VSPW(win_mode->vsync_len - 1);
+ writel(data, sfb->regs + sfb->variant.vidtcon);
+ data = VIDTCON1_HBPD(win_mode->left_margin - 1)
+ | VIDTCON1_HFPD(win_mode->right_margin - 1)
+ | VIDTCON1_HSPW(win_mode->hsync_len - 1);
+ /* VIDTCON1 */
+ writel(data, sfb->regs + sfb->variant.vidtcon + 4);
+ data = VIDTCON2_LINEVAL(win_mode->yres - 1)
+ | VIDTCON2_HOZVAL(win_mode->xres - 1)
+ | VIDTCON2_LINEVAL_E(win_mode->yres - 1)
+ | VIDTCON2_HOZVAL_E(win_mode->xres - 1);
+ /* VIDTCON2 */
+ writel(data, sfb->regs + sfb->variant.vidtcon + 8);
+}
+
+static unsigned int s3c_fb_calc_bandwidth(u32 w, u32 h, u32 bits_per_pixel, int fps)
+{
+ unsigned int bw = w * h;
+
+ bw *= DIV_ROUND_UP(bits_per_pixel, 8);
+ bw *= fps;
+
+ return bw;
+}
+
+/**
+ * s3c_fb_set_par() - framebuffer request to set new framebuffer state.
+ * @info: The framebuffer to change.
+ *
+ * Framebuffer layer request to set a new mode for the specified framebuffer
+ */
+static int s3c_fb_set_par(struct fb_info *info)
+{
+ struct fb_var_screeninfo *var = &info->var;
+ struct s3c_fb_win *win = info->par;
+ struct s3c_fb *sfb = win->parent;
+ void __iomem *regs = sfb->regs;
+ void __iomem *buf = regs;
+ int win_no = win->index;
+ u32 data;
+ int old_wincon;
+
+ dev_dbg(sfb->dev, "setting framebuffer parameters\n");
+
+ pm_runtime_get_sync(sfb->dev);
+
+ shadow_protect_win(win, 1);
+
+ info->fix.visual = fb_visual(var->bits_per_pixel,
+ win->variant.palette_sz);
+
+ info->fix.line_length = fb_linelength(var->xres_virtual,
+ var->bits_per_pixel);
+
+ info->fix.xpanstep = fb_panstep(var->xres, var->xres_virtual);
+ info->fix.ypanstep = fb_panstep(var->yres, var->yres_virtual);
+
+ /* disable the window whilst we update it */
+ old_wincon = readl(regs + WINCON(win_no));
+ writel(0, regs + WINCON(win_no));
+
+ /* write the buffer address */
+
+ /* start and end registers stride is 8 */
+ buf = regs + win_no * 8;
+
+ writel(info->fix.smem_start, buf + sfb->variant.buf_start);
+
+ data = info->fix.smem_start + info->fix.line_length * var->yres;
+ writel(data, buf + sfb->variant.buf_end);
+
+ data = vidw_buf_size(var->xres, info->fix.line_length,
+ var->bits_per_pixel);
+ writel(data, regs + sfb->variant.buf_size + (win_no * 4));
+
+ /* write 'OSD' registers to control position of framebuffer */
+
+ data = vidosd_a(0, 0);
+ writel(data, regs + VIDOSD_A(win_no, sfb->variant));
+
+ data = vidosd_b(0, 0, var->xres, var->yres);
+ writel(data, regs + VIDOSD_B(win_no, sfb->variant));
+
+ data = var->xres * var->yres;
+
+ if (win->variant.has_osd_alpha) {
+ data = vidosd_c(0, 0, 0, 0xff, 0xff, 0xff);
+ writel(data, regs + VIDOSD_C(win_no, sfb->variant));
+ }
+ data = vidw_alpha(win->variant.has_osd_alpha, 0, 0, 0);
+ writel(data, regs + VIDW_ALPHA0(win_no));
+ data = vidw_alpha(win->variant.has_osd_alpha, 0xff, 0xff, 0xff);
+ writel(data, regs + VIDW_ALPHA1(win_no));
+
+ /* preserve whether window was enabled */
+ data = old_wincon & WINCONx_ENWIN;
+
+ /* note, since we have to round up the bits-per-pixel, we end up
+ * relying on the bitfield information for r/g/b/a to work out
+ * exactly which mode of operation is intended. */
+
+ data |= wincon(var->bits_per_pixel, var->transp.length,
+ var->red.length);
+
/* Enable the colour keying for the window below this one */
if (win_no > 0) {
u32 keycon0_data = 0, keycon1_data = 0;
@@ -703,17 +945,6 @@
writel(data, regs + sfb->variant.wincon + (win_no * 4));
writel(0x0, regs + sfb->variant.winmap + (win_no * 4));
- /* Set alpha value width */
- if (sfb->variant.has_blendcon) {
- data = readl(sfb->regs + BLENDCON);
- data &= ~BLENDCON_NEW_MASK;
- if (var->transp.length > 4)
- data |= BLENDCON_NEW_8BIT_ALPHA_VALUE;
- else
- data |= BLENDCON_NEW_4BIT_ALPHA_VALUE;
- writel(data, sfb->regs + BLENDCON);
- }
-
shadow_protect_win(win, 0);
pm_runtime_put_sync(sfb->dev);
@@ -826,6 +1057,25 @@
return 0;
}
+static void s3c_fb_activate_window(struct s3c_fb *sfb, unsigned int index)
+{
+ u32 wincon = readl(sfb->regs + WINCON(index));
+ wincon |= WINCONx_ENWIN;
+ writel(wincon, sfb->regs + WINCON(index));
+}
+
+static void s3c_fb_activate_window_dma(struct s3c_fb *sfb, unsigned int index)
+{
+ u32 shadowcon = readl(sfb->regs + SHADOWCON);
+ shadowcon |= SHADOWCON_CHx_ENABLE(index);
+ writel(shadowcon, sfb->regs + SHADOWCON);
+
+ writel(0, sfb->regs + WINxMAP(index));
+}
+
+static int s3c_fb_enable(struct s3c_fb *sfb);
+static int s3c_fb_disable(struct s3c_fb *sfb);
+
/**
* s3c_fb_blank() - blank or unblank the given window
* @blank_mode: The blank state from FB_BLANK_*
@@ -837,74 +1087,31 @@
{
struct s3c_fb_win *win = info->par;
struct s3c_fb *sfb = win->parent;
- unsigned int index = win->index;
- u32 wincon;
+ int ret = 0;
dev_dbg(sfb->dev, "blank mode %d\n", blank_mode);
pm_runtime_get_sync(sfb->dev);
- wincon = readl(sfb->regs + sfb->variant.wincon + (index * 4));
-
switch (blank_mode) {
case FB_BLANK_POWERDOWN:
- wincon &= ~WINCONx_ENWIN;
- sfb->enabled &= ~(1 << index);
- /* fall through to FB_BLANK_NORMAL */
-
case FB_BLANK_NORMAL:
- /* disable the DMA and display 0x0 (black) */
- shadow_protect_win(win, 1);
- writel(WINxMAP_MAP | WINxMAP_MAP_COLOUR(0x0),
- sfb->regs + sfb->variant.winmap + (index * 4));
- shadow_protect_win(win, 0);
+ ret = s3c_fb_disable(sfb);
break;
case FB_BLANK_UNBLANK:
- shadow_protect_win(win, 1);
- writel(0x0, sfb->regs + sfb->variant.winmap + (index * 4));
- shadow_protect_win(win, 0);
- wincon |= WINCONx_ENWIN;
- sfb->enabled |= (1 << index);
+ ret = s3c_fb_enable(sfb);
break;
case FB_BLANK_VSYNC_SUSPEND:
case FB_BLANK_HSYNC_SUSPEND:
default:
- pm_runtime_put_sync(sfb->dev);
- return 1;
- }
-
- shadow_protect_win(win, 1);
- writel(wincon, sfb->regs + sfb->variant.wincon + (index * 4));
- shadow_protect_win(win, 0);
-
- /* Check the enabled state to see if we need to be running the
- * main LCD interface, as if there are no active windows then
- * it is highly likely that we also do not need to output
- * anything.
- */
-
- /* We could do something like the following code, but the current
- * system of using framebuffer events means that we cannot make
- * the distinction between just window 0 being inactive and all
- * the windows being down.
- *
- * s3c_fb_enable(sfb, sfb->enabled ? 1 : 0);
- */
-
- /* we're stuck with this until we can do something about overriding
- * the power control using the blanking event for a single fb.
- */
- if (index == sfb->pdata->default_win) {
- shadow_protect_win(win, 1);
- s3c_fb_enable(sfb, blank_mode != FB_BLANK_POWERDOWN ? 1 : 0);
- shadow_protect_win(win, 0);
+ ret = -EINVAL;
}
pm_runtime_put_sync(sfb->dev);
- return 0;
+ return ret;
}
/**
@@ -957,6 +1164,9 @@
* both start and end addresses are updated to prevent corruption */
shadow_protect_win(win, 1);
+ s3c_fb_activate_window_dma(sfb, win->index);
+ s3c_fb_activate_window(sfb, win->index);
+
writel(info->fix.smem_start + start_boff, buf + sfb->variant.buf_start);
writel(info->fix.smem_start + end_boff, buf + sfb->variant.buf_end);
@@ -975,20 +1185,29 @@
void __iomem *regs = sfb->regs;
u32 irq_ctrl_reg;
- if (!test_and_set_bit(S3C_FB_VSYNC_IRQ_EN, &sfb->irq_flags)) {
- /* IRQ disabled, enable it */
- irq_ctrl_reg = readl(regs + VIDINTCON0);
+ pm_runtime_get_sync(sfb->dev);
+ irq_ctrl_reg = readl(regs + VIDINTCON0);
- irq_ctrl_reg |= VIDINTCON0_INT_ENABLE;
- irq_ctrl_reg |= VIDINTCON0_INT_FRAME;
+ irq_ctrl_reg |= VIDINTCON0_INT_ENABLE;
+ irq_ctrl_reg |= VIDINTCON0_INT_FRAME;
+#ifdef CONFIG_DEBUG_FS
+ irq_ctrl_reg &= ~VIDINTCON0_FIFOLEVEL_MASK;
+ irq_ctrl_reg |= VIDINTCON0_FIFOLEVEL_EMPTY;
+ irq_ctrl_reg |= VIDINTCON0_INT_FIFO;
+ irq_ctrl_reg |= VIDINTCON0_FIFIOSEL_WINDOW0;
+ irq_ctrl_reg |= VIDINTCON0_FIFIOSEL_WINDOW1;
+ irq_ctrl_reg |= VIDINTCON0_FIFIOSEL_WINDOW2;
+ irq_ctrl_reg |= VIDINTCON0_FIFIOSEL_WINDOW3;
+ irq_ctrl_reg |= VIDINTCON0_FIFIOSEL_WINDOW4;
+#endif
- irq_ctrl_reg &= ~VIDINTCON0_FRAMESEL0_MASK;
- irq_ctrl_reg |= VIDINTCON0_FRAMESEL0_VSYNC;
- irq_ctrl_reg &= ~VIDINTCON0_FRAMESEL1_MASK;
- irq_ctrl_reg |= VIDINTCON0_FRAMESEL1_NONE;
+ irq_ctrl_reg &= ~VIDINTCON0_FRAMESEL0_MASK;
+ irq_ctrl_reg |= VIDINTCON0_FRAMESEL0_VSYNC;
+ irq_ctrl_reg &= ~VIDINTCON0_FRAMESEL1_MASK;
+ irq_ctrl_reg |= VIDINTCON0_FRAMESEL1_NONE;
- writel(irq_ctrl_reg, regs + VIDINTCON0);
- }
+ writel(irq_ctrl_reg, regs + VIDINTCON0);
+ pm_runtime_put_sync(sfb->dev);
}
/**
@@ -1000,15 +1219,68 @@
void __iomem *regs = sfb->regs;
u32 irq_ctrl_reg;
- if (test_and_clear_bit(S3C_FB_VSYNC_IRQ_EN, &sfb->irq_flags)) {
- /* IRQ enabled, disable it */
- irq_ctrl_reg = readl(regs + VIDINTCON0);
+ pm_runtime_get_sync(sfb->dev);
+ irq_ctrl_reg = readl(regs + VIDINTCON0);
- irq_ctrl_reg &= ~VIDINTCON0_INT_FRAME;
- irq_ctrl_reg &= ~VIDINTCON0_INT_ENABLE;
+#ifdef CONFIG_DEBUG_FS
+ irq_ctrl_reg &= VIDINTCON0_INT_FIFO;
+#endif
+ irq_ctrl_reg &= ~VIDINTCON0_INT_FRAME;
+ irq_ctrl_reg &= ~VIDINTCON0_INT_ENABLE;
- writel(irq_ctrl_reg, regs + VIDINTCON0);
+ writel(irq_ctrl_reg, regs + VIDINTCON0);
+ pm_runtime_put_sync(sfb->dev);
+}
+
+static void s3c_fb_activate_vsync(struct s3c_fb *sfb)
+{
+ int prev_refcount;
+
+ mutex_lock(&sfb->vsync_info.irq_lock);
+
+ prev_refcount = sfb->vsync_info.irq_refcount++;
+ if (!prev_refcount)
+ s3c_fb_enable_irq(sfb);
+
+ mutex_unlock(&sfb->vsync_info.irq_lock);
+}
+
+static void s3c_fb_deactivate_vsync(struct s3c_fb *sfb)
+{
+ int new_refcount;
+
+ mutex_lock(&sfb->vsync_info.irq_lock);
+
+ new_refcount = --sfb->vsync_info.irq_refcount;
+ WARN_ON(new_refcount < 0);
+ if (!new_refcount)
+ s3c_fb_disable_irq(sfb);
+
+ mutex_unlock(&sfb->vsync_info.irq_lock);
+}
+
+/**
+ * sfb_fb_log_fifo_underflow_locked - log a FIFO underflow event. Caller must
+ * hold the driver's spin lock while calling.
+ *
+ * @sfb: main hardware state
+ * @timestamp: timestamp of the FIFO underflow event
+ */
+void s3c_fb_log_fifo_underflow_locked(struct s3c_fb *sfb, ktime_t timestamp)
+{
+#ifdef CONFIG_DEBUG_FS
+ unsigned int idx = sfb->debug_data.num_timestamps %
+ S3C_FB_DEBUG_FIFO_TIMESTAMPS;
+ sfb->debug_data.fifo_timestamps[idx] = timestamp;
+ sfb->debug_data.num_timestamps++;
+ if (sfb->debug_data.num_timestamps > S3C_FB_DEBUG_FIFO_TIMESTAMPS) {
+ sfb->debug_data.first_timestamp++;
+ sfb->debug_data.first_timestamp %= S3C_FB_DEBUG_FIFO_TIMESTAMPS;
}
+
+ memcpy(sfb->debug_data.regs_at_underflow, sfb->regs,
+ sizeof(sfb->debug_data.regs_at_underflow));
+#endif
}
static irqreturn_t s3c_fb_irq(int irq, void *dev_id)
@@ -1016,6 +1288,7 @@
struct s3c_fb *sfb = dev_id;
void __iomem *regs = sfb->regs;
u32 irq_sts_reg;
+ ktime_t timestamp = ktime_get();
spin_lock(&sfb->slock);
@@ -1026,14 +1299,13 @@
/* VSYNC interrupt, accept it */
writel(VIDINTCON1_INT_FRAME, regs + VIDINTCON1);
- sfb->vsync_info.count++;
- wake_up_interruptible(&sfb->vsync_info.wait);
+ sfb->vsync_info.timestamp = timestamp;
+ wake_up_interruptible_all(&sfb->vsync_info.wait);
}
-
- /* We only support waiting for VSYNC for now, so it's safe
- * to always disable irqs here.
- */
- s3c_fb_disable_irq(sfb);
+ if (irq_sts_reg & VIDINTCON1_INT_FIFO) {
+ writel(VIDINTCON1_INT_FIFO, regs + VIDINTCON1);
+ s3c_fb_log_fifo_underflow_locked(sfb, timestamp);
+ }
spin_unlock(&sfb->slock);
return IRQ_HANDLED;
@@ -1042,32 +1314,859 @@
/**
* s3c_fb_wait_for_vsync() - sleep until next VSYNC interrupt or timeout
* @sfb: main hardware state
- * @crtc: head index.
+ * @timeout: timeout in msecs, or 0 to wait indefinitely.
*/
-static int s3c_fb_wait_for_vsync(struct s3c_fb *sfb, u32 crtc)
+static int s3c_fb_wait_for_vsync(struct s3c_fb *sfb, u32 timeout)
{
- unsigned long count;
+ ktime_t timestamp;
int ret;
- if (crtc != 0)
- return -ENODEV;
-
pm_runtime_get_sync(sfb->dev);
- count = sfb->vsync_info.count;
- s3c_fb_enable_irq(sfb);
- ret = wait_event_interruptible_timeout(sfb->vsync_info.wait,
- count != sfb->vsync_info.count,
- msecs_to_jiffies(VSYNC_TIMEOUT_MSEC));
+ timestamp = sfb->vsync_info.timestamp;
+ s3c_fb_activate_vsync(sfb);
+ if (timeout) {
+ ret = wait_event_interruptible_timeout(sfb->vsync_info.wait,
+ !ktime_equal(timestamp,
+ sfb->vsync_info.timestamp),
+ msecs_to_jiffies(timeout));
+ } else {
+ ret = wait_event_interruptible(sfb->vsync_info.wait,
+ !ktime_equal(timestamp,
+ sfb->vsync_info.timestamp));
+ }
+ s3c_fb_deactivate_vsync(sfb);
pm_runtime_put_sync(sfb->dev);
- if (ret == 0)
+ if (timeout && ret == 0)
return -ETIMEDOUT;
return 0;
}
+int s3c_fb_set_window_position(struct fb_info *info,
+ struct s3c_fb_user_window user_window)
+{
+ struct s3c_fb_win *win = info->par;
+ struct s3c_fb *sfb = win->parent;
+ struct fb_var_screeninfo *var = &info->var;
+ int win_no = win->index;
+ void __iomem *regs = sfb->regs;
+ u32 data;
+
+ pm_runtime_get_sync(sfb->dev);
+ shadow_protect_win(win, 1);
+
+ if (!s3c_fb_validate_x_alignment(sfb, user_window.x, var->xres,
+ var->bits_per_pixel))
+ return -EINVAL;
+
+ /* write 'OSD' registers to control position of framebuffer */
+ data = vidosd_a(user_window.x, user_window.y);
+ writel(data, regs + VIDOSD_A(win_no, sfb->variant));
+
+ data = vidosd_b(user_window.x, user_window.y, var->xres, var->yres);
+ writel(data, regs + VIDOSD_B(win_no, sfb->variant));
+
+ shadow_protect_win(win, 0);
+ pm_runtime_put_sync(sfb->dev);
+ return 0;
+}
+
+int s3c_fb_set_plane_alpha_blending(struct fb_info *info,
+ struct s3c_fb_user_plane_alpha user_alpha)
+{
+ struct s3c_fb_win *win = info->par;
+ struct s3c_fb *sfb = win->parent;
+ int win_no = win->index;
+ void __iomem *regs = sfb->regs;
+ u32 data;
+
+ u32 alpha_high = 0;
+ u32 alpha_low = 0;
+
+ alpha_high = ((((user_alpha.red & 0xf0) >> 4) << 8) |
+ (((user_alpha.green & 0xf0) >> 4) << 4) |
+ (((user_alpha.blue & 0xf0) >> 4) << 0));
+
+ alpha_low = ((((user_alpha.red & 0xf)) << 16) |
+ (((user_alpha.green & 0xf)) << 8) |
+ (((user_alpha.blue & 0xf)) << 0));
+
+ pm_runtime_get_sync(sfb->dev);
+ shadow_protect_win(win, 1);
+
+ data = readl(regs + sfb->variant.wincon + (win_no * 4));
+ data &= ~(WINCON1_BLD_PIX | WINCON1_ALPHA_SEL);
+ data |= WINCON1_BLD_PLANE;
+
+ if (user_alpha.channel == 0)
+ alpha_high = alpha_high << 12;
+ else {
+ data |= WINCON1_ALPHA_SEL;
+ alpha_high = alpha_high << 0;
+ }
+
+ writel(data, regs + sfb->variant.wincon + (win_no * 4));
+ writel(alpha_high, regs + VIDOSD_C(win_no, sfb->variant));
+
+ if (sfb->variant.has_alphacon) {
+ if (user_alpha.channel == 0)
+ writel(alpha_low, regs + VIDW_ALPHA0(win_no));
+ else
+ writel(alpha_low, regs + VIDW_ALPHA1(win_no));
+ }
+
+ shadow_protect_win(win, 0);
+ pm_runtime_put_sync(sfb->dev);
+
+ return 0;
+}
+
+int s3c_fb_set_chroma_key(struct fb_info *info,
+ struct s3c_fb_user_chroma user_chroma)
+{
+ struct s3c_fb_win *win = info->par;
+ struct s3c_fb *sfb = win->parent;
+ int win_no = win->index;
+ void __iomem *regs = sfb->regs;
+ void __iomem *keycon = regs + sfb->variant.keycon;
+
+ u32 data = 0;
+
+ u32 chroma_value;
+
+ chroma_value = (((user_chroma.red & 0xff) << 16) |
+ ((user_chroma.green & 0xff) << 8) |
+ ((user_chroma.blue & 0xff) << 0));
+
+ pm_runtime_get_sync(sfb->dev);
+ shadow_protect_win(win, 1);
+
+ if (user_chroma.enabled)
+ data |= WxKEYCON0_KEYEN_F;
+
+ keycon += (win_no-1) * 8;
+ writel(data, keycon + WKEYCON0);
+
+ data = (chroma_value & 0xffffff);
+ writel(data, keycon + WKEYCON1);
+
+ shadow_protect_win(win, 0);
+ pm_runtime_put_sync(sfb->dev);
+
+ return 0;
+}
+
+int s3c_fb_set_vsync_int(struct fb_info *info,
+ bool active)
+{
+ struct s3c_fb_win *win = info->par;
+ struct s3c_fb *sfb = win->parent;
+ bool prev_active = sfb->vsync_info.active;
+
+ sfb->vsync_info.active = active;
+ smp_wmb();
+
+ if (active && !prev_active)
+ s3c_fb_activate_vsync(sfb);
+ else if (!active && prev_active)
+ s3c_fb_deactivate_vsync(sfb);
+
+ return 0;
+}
+
+#ifdef CONFIG_ION_EXYNOS
+static unsigned int s3c_fb_map_ion_handle(struct s3c_fb *sfb,
+ struct s3c_dma_buf_data *dma, struct ion_handle *ion_handle,
+ int fd)
+{
+ dma->fence = NULL;
+
+ dma->dma_buf = dma_buf_get(fd);
+ if (IS_ERR_OR_NULL(dma->dma_buf)) {
+ dev_err(sfb->dev, "dma_buf_get() failed: %ld\n",
+ PTR_ERR(dma->dma_buf));
+ goto err_share_dma_buf;
+ }
+
+ dma->attachment = dma_buf_attach(dma->dma_buf, sfb->dev);
+ if (IS_ERR_OR_NULL(dma->attachment)) {
+ dev_err(sfb->dev, "dma_buf_attach() failed: %ld\n",
+ PTR_ERR(dma->attachment));
+ goto err_buf_map_attach;
+ }
+
+ dma->sg_table = dma_buf_map_attachment(dma->attachment,
+ DMA_BIDIRECTIONAL);
+ if (IS_ERR_OR_NULL(dma->sg_table)) {
+ dev_err(sfb->dev, "dma_buf_map_attachment() failed: %ld\n",
+ PTR_ERR(dma->sg_table));
+ goto err_buf_map_attachment;
+ }
+
+ dma->dma_addr = iovmm_map(&s5p_device_fimd1.dev, dma->sg_table->sgl, 0,
+ dma->dma_buf->size);
+ if (!dma->dma_addr || IS_ERR_VALUE(dma->dma_addr)) {
+ dev_err(sfb->dev, "iovmm_map() failed: %d\n", dma->dma_addr);
+ goto err_iovmm_map;
+ }
+
+ dma->ion_handle = ion_handle;
+ return dma->dma_buf->size;
+
+err_iovmm_map:
+ dma_buf_unmap_attachment(dma->attachment, dma->sg_table,
+ DMA_BIDIRECTIONAL);
+err_buf_map_attachment:
+ dma_buf_detach(dma->dma_buf, dma->attachment);
+err_buf_map_attach:
+ dma_buf_put(dma->dma_buf);
+err_share_dma_buf:
+ return 0;
+}
+
+static void s3c_fb_free_dma_buf(struct s3c_fb *sfb,
+ struct s3c_dma_buf_data *dma)
+{
+ if (!dma->dma_addr)
+ return;
+
+ if (dma->fence)
+ sync_fence_put(dma->fence);
+ iovmm_unmap(sfb->dev, dma->dma_addr);
+ dma_buf_unmap_attachment(dma->attachment, dma->sg_table,
+ DMA_BIDIRECTIONAL);
+ dma_buf_detach(dma->dma_buf, dma->attachment);
+ dma_buf_put(dma->dma_buf);
+ ion_free(sfb->fb_ion_client, dma->ion_handle);
+ memset(dma, 0, sizeof(struct s3c_dma_buf_data));
+}
+
+static u32 s3c_fb_red_length(int format)
+{
+ switch (format) {
+ case S3C_FB_PIXEL_FORMAT_RGBA_8888:
+ case S3C_FB_PIXEL_FORMAT_RGBX_8888:
+ case S3C_FB_PIXEL_FORMAT_BGRA_8888:
+ return 8;
+
+ case S3C_FB_PIXEL_FORMAT_RGBA_5551:
+ return 5;
+
+ case S3C_FB_PIXEL_FORMAT_RGB_565:
+ return 5;
+
+ default:
+ pr_warn("s3c-fb: unrecognized pixel format %u\n", format);
+ return 0;
+ }
+}
+
+static u32 s3c_fb_red_offset(int format)
+{
+ switch (format) {
+ case S3C_FB_PIXEL_FORMAT_RGBA_8888:
+ case S3C_FB_PIXEL_FORMAT_RGBX_8888:
+ case S3C_FB_PIXEL_FORMAT_RGBA_5551:
+ return 0;
+
+ case S3C_FB_PIXEL_FORMAT_RGB_565:
+ return 11;
+
+ case S3C_FB_PIXEL_FORMAT_BGRA_8888:
+ return 16;
+
+ default:
+ pr_warn("s3c-fb: unrecognized pixel format %u\n", format);
+ return 0;
+ }
+}
+
+static u32 s3c_fb_green_length(int format)
+{
+ switch (format) {
+ case S3C_FB_PIXEL_FORMAT_RGBA_8888:
+ case S3C_FB_PIXEL_FORMAT_RGBX_8888:
+ case S3C_FB_PIXEL_FORMAT_BGRA_8888:
+ return 8;
+
+ case S3C_FB_PIXEL_FORMAT_RGBA_5551:
+ return 5;
+
+ case S3C_FB_PIXEL_FORMAT_RGB_565:
+ return 6;
+
+ default:
+ pr_warn("s3c-fb: unrecognized pixel format %u\n", format);
+ return 0;
+ }
+}
+
+static u32 s3c_fb_green_offset(int format)
+{
+ switch (format) {
+ case S3C_FB_PIXEL_FORMAT_RGBA_8888:
+ case S3C_FB_PIXEL_FORMAT_RGBX_8888:
+ case S3C_FB_PIXEL_FORMAT_BGRA_8888:
+ return 8;
+
+ case S3C_FB_PIXEL_FORMAT_RGBA_5551:
+ case S3C_FB_PIXEL_FORMAT_RGB_565:
+ return 5;
+ default:
+ pr_warn("s3c-fb: unrecognized pixel format %u\n", format);
+ return 0;
+ }
+}
+
+static u32 s3c_fb_blue_length(int format)
+{
+ return s3c_fb_red_length(format);
+}
+
+static u32 s3c_fb_blue_offset(int format)
+{
+ switch (format) {
+ case S3C_FB_PIXEL_FORMAT_RGBA_8888:
+ case S3C_FB_PIXEL_FORMAT_RGBX_8888:
+ return 16;
+
+ case S3C_FB_PIXEL_FORMAT_RGBA_5551:
+ return 10;
+
+ case S3C_FB_PIXEL_FORMAT_RGB_565:
+ case S3C_FB_PIXEL_FORMAT_BGRA_8888:
+ return 0;
+
+ default:
+ pr_warn("s3c-fb: unrecognized pixel format %u\n", format);
+ return 0;
+ }
+}
+
+static u32 s3c_fb_transp_length(int format)
+{
+ switch (format) {
+ case S3C_FB_PIXEL_FORMAT_RGBA_8888:
+ case S3C_FB_PIXEL_FORMAT_BGRA_8888:
+ return 8;
+
+ case S3C_FB_PIXEL_FORMAT_RGBA_5551:
+ return 1;
+
+ case S3C_FB_PIXEL_FORMAT_RGBX_8888:
+ case S3C_FB_PIXEL_FORMAT_RGB_565:
+ return 0;
+
+ default:
+ pr_warn("s3c-fb: unrecognized pixel format %u\n", format);
+ return 0;
+ }
+}
+
+static u32 s3c_fb_transp_offset(int format)
+{
+ switch (format) {
+ case S3C_FB_PIXEL_FORMAT_RGBA_8888:
+ case S3C_FB_PIXEL_FORMAT_BGRA_8888:
+ return 24;
+
+ case S3C_FB_PIXEL_FORMAT_RGBA_5551:
+ return 15;
+
+ case S3C_FB_PIXEL_FORMAT_RGBX_8888:
+ return s3c_fb_blue_offset(format);
+
+ case S3C_FB_PIXEL_FORMAT_RGB_565:
+ return 0;
+
+ default:
+ pr_warn("s3c-fb: unrecognized pixel format %u\n", format);
+ return 0;
+ }
+}
+
+static u32 s3c_fb_padding(int format)
+{
+ switch (format) {
+ case S3C_FB_PIXEL_FORMAT_RGBX_8888:
+ return 8;
+
+ case S3C_FB_PIXEL_FORMAT_RGBA_8888:
+ case S3C_FB_PIXEL_FORMAT_RGBA_5551:
+ case S3C_FB_PIXEL_FORMAT_RGB_565:
+ case S3C_FB_PIXEL_FORMAT_BGRA_8888:
+ return 0;
+
+ default:
+ pr_warn("s3c-fb: unrecognized pixel format %u\n", format);
+ return 0;
+ }
+
+}
+
+static u32 s3c_fb_rgborder(int format)
+{
+ switch (format) {
+ case S3C_FB_PIXEL_FORMAT_RGBX_8888:
+ case S3C_FB_PIXEL_FORMAT_RGBA_8888:
+ case S3C_FB_PIXEL_FORMAT_RGBA_5551:
+ return WIN_RGB_ORDER_RGB;
+
+ case S3C_FB_PIXEL_FORMAT_RGB_565:
+ case S3C_FB_PIXEL_FORMAT_BGRA_8888:
+ return WIN_RGB_ORDER_BGR;
+
+ default:
+ pr_warn("s3c-fb: unrecognized pixel format %u\n", format);
+ return 0;
+ }
+
+}
+static int s3c_fb_set_win_buffer(struct s3c_fb *sfb, struct s3c_fb_win *win,
+ struct s3c_fb_win_config *win_config, struct s3c_reg_data *regs)
+{
+ struct ion_handle *handle;
+ struct fb_var_screeninfo prev_var = win->fbinfo->var;
+ struct s3c_dma_buf_data dma_buf_data;
+ unsigned short win_no = win->index;
+ int ret;
+ size_t buf_size, window_size;
+ u8 alpha0, alpha1;
+
+ if (win_config->format >= S3C_FB_PIXEL_FORMAT_MAX) {
+ dev_err(sfb->dev, "unknown pixel format %u\n",
+ win_config->format);
+ return -EINVAL;
+ }
+
+ if (win_config->blending >= S3C_FB_BLENDING_MAX) {
+ dev_err(sfb->dev, "unknown blending %u\n",
+ win_config->blending);
+ return -EINVAL;
+ }
+
+ if (win_no == 0 && win_config->blending != S3C_FB_BLENDING_NONE) {
+ dev_err(sfb->dev, "blending not allowed on window 0\n");
+ return -EINVAL;
+ }
+
+ if (win_config->w == 0 || win_config->h == 0) {
+ dev_err(sfb->dev, "window is size 0 (w = %u, h = %u)\n",
+ win_config->w, win_config->h);
+ return -EINVAL;
+ }
+
+ win->fbinfo->var.red.length = s3c_fb_red_length(win_config->format);
+ win->fbinfo->var.red.offset = s3c_fb_red_offset(win_config->format);
+ win->fbinfo->var.green.length = s3c_fb_green_length(win_config->format);
+ win->fbinfo->var.green.offset = s3c_fb_green_offset(win_config->format);
+ win->fbinfo->var.blue.length = s3c_fb_blue_length(win_config->format);
+ win->fbinfo->var.blue.offset = s3c_fb_blue_offset(win_config->format);
+ win->fbinfo->var.transp.length =
+ s3c_fb_transp_length(win_config->format);
+ win->fbinfo->var.transp.offset =
+ s3c_fb_transp_offset(win_config->format);
+ win->fbinfo->var.bits_per_pixel = win->fbinfo->var.red.length +
+ win->fbinfo->var.green.length +
+ win->fbinfo->var.blue.length +
+ win->fbinfo->var.transp.length +
+ s3c_fb_padding(win_config->format);
+
+
+ regs->win_rgborder[win_no] = s3c_fb_rgborder(win_config->format);
+
+ if (win_config->w * win->fbinfo->var.bits_per_pixel / 8 < 128) {
+ dev_err(sfb->dev, "window must be at least 128 bytes wide (width = %u, bpp = %u)\n",
+ win_config->w,
+ win->fbinfo->var.bits_per_pixel);
+ ret = -EINVAL;
+ goto err_invalid;
+ }
+
+ if (win_config->stride <
+ win_config->w * win->fbinfo->var.bits_per_pixel / 8) {
+ dev_err(sfb->dev, "stride shorter than buffer width (stride = %u, width = %u, bpp = %u)\n",
+ win_config->stride, win_config->w,
+ win->fbinfo->var.bits_per_pixel);
+ ret = -EINVAL;
+ goto err_invalid;
+ }
+
+ if (!s3c_fb_validate_x_alignment(sfb, win_config->x, win_config->w,
+ win->fbinfo->var.bits_per_pixel)) {
+ ret = -EINVAL;
+ goto err_invalid;
+ }
+
+ handle = ion_import_dma_buf(sfb->fb_ion_client, win_config->fd);
+ if (IS_ERR(handle)) {
+ dev_err(sfb->dev, "failed to import fd\n");
+ ret = PTR_ERR(handle);
+ goto err_invalid;
+ }
+
+ buf_size = s3c_fb_map_ion_handle(sfb, &dma_buf_data, handle,
+ win_config->fd);
+ if (!buf_size) {
+ ret = -ENOMEM;
+ ion_free(sfb->fb_ion_client, handle);
+ goto err_invalid;
+ }
+
+ if (win_config->fence_fd >= 0) {
+ dma_buf_data.fence = sync_fence_fdget(win_config->fence_fd);
+ if (!dma_buf_data.fence) {
+ dev_err(sfb->dev, "failed to import fence fd\n");
+ ret = -EINVAL;
+ goto err_offset;
+ }
+ }
+
+ window_size = win_config->stride * (win_config->h + 1);
+ if (win_config->offset + window_size > buf_size) {
+ dev_err(sfb->dev, "window goes past end of buffer (width = %u, height = %u, stride = %u, offset = %u, buf_size = %u)\n",
+ win_config->w, win_config->h,
+ win_config->stride, win_config->offset,
+ buf_size);
+ ret = -EINVAL;
+ goto err_offset;
+ }
+
+ win->fbinfo->fix.smem_start = dma_buf_data.dma_addr
+ + win_config->offset;
+ win->fbinfo->fix.smem_len = window_size;
+ win->fbinfo->var.xres = win_config->w;
+ win->fbinfo->var.xres_virtual = win_config->stride * 8 /
+ win->fbinfo->var.bits_per_pixel;
+ win->fbinfo->var.yres = win->fbinfo->var.yres_virtual = win_config->h;
+ win->fbinfo->var.xoffset = win_config->offset % win_config->stride;
+ win->fbinfo->var.yoffset = win_config->offset / win_config->stride;
+
+ win->fbinfo->fix.visual = fb_visual(win->fbinfo->var.bits_per_pixel,
+ win->variant.palette_sz);
+ win->fbinfo->fix.line_length = win_config->stride;
+ win->fbinfo->fix.xpanstep = fb_panstep(win_config->w,
+ win->fbinfo->var.xres_virtual);
+ win->fbinfo->fix.ypanstep = fb_panstep(win_config->h, win_config->h);
+
+ regs->dma_buf_data[win_no] = dma_buf_data;
+ regs->vidw_buf_start[win_no] = win->fbinfo->fix.smem_start;
+ regs->vidw_buf_end[win_no] = regs->vidw_buf_start[win_no] +
+ window_size;
+ regs->vidw_buf_size[win_no] = vidw_buf_size(win_config->w,
+ win->fbinfo->fix.line_length,
+ win->fbinfo->var.bits_per_pixel);
+
+ regs->vidosd_a[win_no] = vidosd_a(win_config->x, win_config->y);
+ regs->vidosd_b[win_no] = vidosd_b(win_config->x, win_config->y,
+ win_config->w, win_config->h);
+
+ if (win->fbinfo->var.transp.length == 1 &&
+ win_config->blending == S3C_FB_BLENDING_NONE) {
+ alpha0 = 0xff;
+ alpha1 = 0xff;
+ }
+ else {
+ alpha0 = 0;
+ alpha1 = 0xff;
+ }
+
+ if (win->variant.has_osd_alpha)
+ regs->vidosd_c[win_no] = vidosd_c(alpha0, alpha0, alpha0,
+ alpha1, alpha1, alpha1);
+ regs->vidw_alpha0[win_no] = vidw_alpha(win->variant.has_osd_alpha,
+ alpha0, alpha0, alpha0);
+ regs->vidw_alpha1[win_no] = vidw_alpha(win->variant.has_osd_alpha,
+ alpha1, alpha1, alpha1);
+
+ if (win->variant.osd_size_off) {
+ u32 size = win_config->w * win_config->h;
+ if (win->variant.has_osd_alpha)
+ regs->vidosd_d[win_no] = size;
+ else
+ regs->vidosd_c[win_no] = size;
+ }
+
+ regs->shadowcon |= SHADOWCON_CHx_ENABLE(win_no);
+
+ regs->wincon[win_no] = wincon(win->fbinfo->var.bits_per_pixel,
+ win->fbinfo->var.transp.length,
+ win->fbinfo->var.red.length);
+ if (win_no)
+ regs->blendeq[win_no - 1] = blendeq(win_config->blending,
+ win->fbinfo->var.transp.length);
+
+ return 0;
+
+err_offset:
+ s3c_fb_free_dma_buf(sfb, &dma_buf_data);
+err_invalid:
+ win->fbinfo->var = prev_var;
+ return ret;
+}
+
+static int s3c_fb_set_win_config(struct s3c_fb *sfb,
+ struct s3c_fb_win_config_data *win_data)
+{
+ struct s3c_fb_win_config *win_config = win_data->config;
+ int ret = 0;
+ unsigned short i;
+ struct s3c_reg_data *regs;
+ struct sync_fence *fence;
+ struct sync_pt *pt;
+ int fd;
+ unsigned int bw = 0;
+
+ fd = get_unused_fd();
+
+ if (fd < 0)
+ return fd;
+
+ mutex_lock(&sfb->output_lock);
+
+ if (!sfb->output_on) {
+ sfb->timeline_max++;
+ pt = sw_sync_pt_create(sfb->timeline, sfb->timeline_max);
+ fence = sync_fence_create("display", pt);
+ sync_fence_install(fence, fd);
+ win_data->fence = fd;
+
+ sw_sync_timeline_inc(sfb->timeline, 1);
+ goto err;
+ }
+
+ regs = kzalloc(sizeof(struct s3c_reg_data), GFP_KERNEL);
+ if (!regs) {
+ dev_err(sfb->dev, "could not allocate s3c_reg_data\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ for (i = 0; i < sfb->variant.nr_windows; i++) {
+ sfb->windows[i]->prev_fix = sfb->windows[i]->fbinfo->fix;
+ sfb->windows[i]->prev_var = sfb->windows[i]->fbinfo->var;
+ }
+
+ for (i = 0; i < sfb->variant.nr_windows && !ret; i++) {
+ struct s3c_fb_win_config *config = &win_config[i];
+ struct s3c_fb_win *win = sfb->windows[i];
+
+ bool enabled = 0;
+ u32 color_map = WINxMAP_MAP | WINxMAP_MAP_COLOUR(0);
+
+ switch (config->state) {
+ case S3C_FB_WIN_STATE_DISABLED:
+ break;
+ case S3C_FB_WIN_STATE_COLOR:
+ enabled = 1;
+ color_map |= WINxMAP_MAP_COLOUR(config->color);
+ regs->vidosd_a[i] = vidosd_a(config->x, config->y);
+ regs->vidosd_b[i] = vidosd_b(config->x, config->y,
+ config->w, config->h);
+ break;
+ case S3C_FB_WIN_STATE_BUFFER:
+ ret = s3c_fb_set_win_buffer(sfb, win, config, regs);
+ if (!ret) {
+ enabled = 1;
+ color_map = 0;
+ }
+ break;
+ default:
+ dev_warn(sfb->dev, "unrecognized window state %u",
+ config->state);
+ ret = -EINVAL;
+ break;
+ }
+
+ if (enabled)
+ regs->wincon[i] |= WINCONx_ENWIN;
+ else
+ regs->wincon[i] &= ~WINCONx_ENWIN;
+ regs->winmap[i] = color_map;
+
+ if (enabled && config->state == S3C_FB_WIN_STATE_BUFFER) {
+ bw += s3c_fb_calc_bandwidth(config->w, config->h,
+ win->fbinfo->var.bits_per_pixel,
+ win->fps);
+ }
+ }
+
+ dev_dbg(sfb->dev, "Total BW = %d Mbits, Max BW per window = %d Mbits\n",
+ bw / (1024 * 1024), MAX_BW_PER_WINDOW / (1024 * 1024));
+
+ if (bw > MAX_BW_PER_WINDOW)
+ exynos5_mif_multiple_windows(true);
+ else
+ exynos5_mif_multiple_windows(false);
+
+ if (ret) {
+ for (i = 0; i < sfb->variant.nr_windows; i++) {
+ sfb->windows[i]->fbinfo->fix =
+ sfb->windows[i]->prev_fix;
+ sfb->windows[i]->fbinfo->var =
+ sfb->windows[i]->prev_var;
+ s3c_fb_free_dma_buf(sfb, ®s->dma_buf_data[i]);
+ }
+ put_unused_fd(fd);
+ kfree(regs);
+ } else {
+ mutex_lock(&sfb->update_regs_list_lock);
+ sfb->timeline_max++;
+ pt = sw_sync_pt_create(sfb->timeline, sfb->timeline_max);
+ fence = sync_fence_create("display", pt);
+ sync_fence_install(fence, fd);
+ win_data->fence = fd;
+
+ list_add_tail(®s->list, &sfb->update_regs_list);
+ mutex_unlock(&sfb->update_regs_list_lock);
+ queue_kthread_work(&sfb->update_regs_worker,
+ &sfb->update_regs_work);
+ }
+
+err:
+ mutex_unlock(&sfb->output_lock);
+ return ret;
+}
+
+static void __s3c_fb_update_regs(struct s3c_fb *sfb, struct s3c_reg_data *regs)
+{
+ unsigned short i;
+
+ for (i = 0; i < sfb->variant.nr_windows; i++)
+ shadow_protect_win(sfb->windows[i], 1);
+
+ for (i = 0; i < sfb->variant.nr_windows; i++) {
+ writel(regs->wincon[i], sfb->regs + WINCON(i));
+ writel(regs->win_rgborder[i], sfb->regs + WIN_RGB_ORDER(i));
+ writel(regs->winmap[i], sfb->regs + WINxMAP(i));
+ writel(regs->vidosd_a[i],
+ sfb->regs + VIDOSD_A(i, sfb->variant));
+ writel(regs->vidosd_b[i],
+ sfb->regs + VIDOSD_B(i, sfb->variant));
+ if (sfb->windows[i]->variant.has_osd_c)
+ writel(regs->vidosd_c[i],
+ sfb->regs + VIDOSD_C(i, sfb->variant));
+ if (sfb->windows[i]->variant.has_osd_d)
+ writel(regs->vidosd_d[i],
+ sfb->regs + VIDOSD_D(i, sfb->variant));
+ writel(regs->vidw_alpha0[i],
+ sfb->regs + VIDW_ALPHA0(i));
+ writel(regs->vidw_alpha1[i],
+ sfb->regs + VIDW_ALPHA1(i));
+ writel(regs->vidw_buf_start[i],
+ sfb->regs + VIDW_BUF_START(i));
+ writel(regs->vidw_buf_end[i],
+ sfb->regs + VIDW_BUF_END(i));
+ writel(regs->vidw_buf_size[i],
+ sfb->regs + VIDW_BUF_SIZE(i));
+ if (i)
+ writel(regs->blendeq[i - 1], sfb->regs + BLENDEQ(i));
+
+ sfb->windows[i]->dma_buf_data = regs->dma_buf_data[i];
+ }
+ if (sfb->variant.has_shadowcon)
+ writel(regs->shadowcon, sfb->regs + SHADOWCON);
+
+ for (i = 0; i < sfb->variant.nr_windows; i++)
+ shadow_protect_win(sfb->windows[i], 0);
+}
+
+static void s3c_fd_fence_wait(struct s3c_fb *sfb, struct sync_fence *fence)
+{
+ int err = sync_fence_wait(fence, 1000);
+ if (err >= 0)
+ return;
+
+ if (err == -ETIME)
+ err = sync_fence_wait(fence, 10 * MSEC_PER_SEC);
+
+ if (err < 0)
+ dev_warn(sfb->dev, "error waiting on fence: %d\n", err);
+}
+
+static void s3c_fb_update_regs(struct s3c_fb *sfb, struct s3c_reg_data *regs)
+{
+ struct s3c_dma_buf_data old_dma_bufs[S3C_FB_MAX_WIN];
+ bool wait_for_vsync;
+ int count = 100;
+ int i;
+
+ pm_runtime_get_sync(sfb->dev);
+
+ for (i = 0; i < sfb->variant.nr_windows; i++) {
+ old_dma_bufs[i] = sfb->windows[i]->dma_buf_data;
+
+ if (regs->dma_buf_data[i].fence)
+ s3c_fd_fence_wait(sfb, regs->dma_buf_data[i].fence);
+ }
+
+ do {
+ __s3c_fb_update_regs(sfb, regs);
+ s3c_fb_wait_for_vsync(sfb, VSYNC_TIMEOUT_MSEC);
+ wait_for_vsync = false;
+
+ for (i = 0; i < sfb->variant.nr_windows; i++) {
+ u32 new_start = regs->vidw_buf_start[i];
+ u32 shadow_start = readl(sfb->regs +
+ SHD_VIDW_BUF_START(i));
+ if (unlikely(new_start != shadow_start)) {
+ wait_for_vsync = true;
+ break;
+ }
+ }
+ } while (wait_for_vsync && count--);
+ if (wait_for_vsync) {
+ pr_err("%s: failed to update registers\n", __func__);
+ for (i = 0; i < sfb->variant.nr_windows; i++)
+ pr_err("window %d new value %08x register value %08x\n",
+ i, regs->vidw_buf_start[i],
+ readl(sfb->regs + SHD_VIDW_BUF_START(i)));
+ }
+
+ pm_runtime_put_sync(sfb->dev);
+ sw_sync_timeline_inc(sfb->timeline, 1);
+
+ for (i = 0; i < sfb->variant.nr_windows; i++)
+ s3c_fb_free_dma_buf(sfb, &old_dma_bufs[i]);
+}
+
+static void s3c_fb_update_regs_handler(struct kthread_work *work)
+{
+ struct s3c_fb *sfb =
+ container_of(work, struct s3c_fb, update_regs_work);
+ struct s3c_reg_data *data, *next;
+ struct list_head saved_list;
+
+ mutex_lock(&sfb->update_regs_list_lock);
+ saved_list = sfb->update_regs_list;
+ list_replace_init(&sfb->update_regs_list, &saved_list);
+ mutex_unlock(&sfb->update_regs_list_lock);
+
+ list_for_each_entry_safe(data, next, &saved_list, list) {
+ s3c_fb_update_regs(sfb, data);
+ list_del(&data->list);
+ kfree(data);
+ }
+}
+
+static int s3c_fb_get_user_ion_handle(struct s3c_fb *sfb,
+ struct s3c_fb_win *win,
+ struct s3c_fb_user_ion_client *user_ion_client)
+{
+ /* Create fd for ion_buffer */
+ user_ion_client->fd = ion_share_dma_buf(sfb->fb_ion_client,
+ win->dma_buf_data.ion_handle);
+ if (user_ion_client->fd < 0) {
+ pr_err("ion_share_fd failed\n");
+ return user_ion_client->fd;
+ }
+ return 0;
+}
+#endif
+
static int s3c_fb_ioctl(struct fb_info *info, unsigned int cmd,
unsigned long arg)
{
@@ -1076,6 +2175,18 @@
int ret;
u32 crtc;
+ struct fb_var_screeninfo *var = &info->var;
+ int offset;
+
+ union {
+ struct s3c_fb_user_window user_window;
+ struct s3c_fb_user_plane_alpha user_alpha;
+ struct s3c_fb_user_chroma user_chroma;
+ struct s3c_fb_user_ion_client user_ion_client;
+ struct s3c_fb_win_config_data win_data;
+ u32 vsync;
+ } p;
+
switch (cmd) {
case FBIO_WAITFORVSYNC:
if (get_user(crtc, (u32 __user *)arg)) {
@@ -1083,8 +2194,112 @@
break;
}
- ret = s3c_fb_wait_for_vsync(sfb, crtc);
+ if (crtc == 0)
+ ret = s3c_fb_wait_for_vsync(sfb, VSYNC_TIMEOUT_MSEC);
+ else
+ ret = -ENODEV;
+
break;
+
+ case S3CFB_WIN_POSITION:
+ if (copy_from_user(&p.user_window,
+ (struct s3c_fb_user_window __user *)arg,
+ sizeof(p.user_window))) {
+ ret = -EFAULT;
+ break;
+ }
+
+ if (p.user_window.x < 0)
+ p.user_window.x = 0;
+ if (p.user_window.y < 0)
+ p.user_window.y = 0;
+
+ ret = s3c_fb_set_window_position(info, p.user_window);
+ break;
+
+ case S3CFB_WIN_SET_PLANE_ALPHA:
+ if (copy_from_user(&p.user_alpha,
+ (struct s3c_fb_user_plane_alpha __user *)arg,
+ sizeof(p.user_alpha))) {
+ ret = -EFAULT;
+ break;
+ }
+
+ ret = s3c_fb_set_plane_alpha_blending(info, p.user_alpha);
+ break;
+
+ case S3CFB_WIN_SET_CHROMA:
+ if (copy_from_user(&p.user_chroma,
+ (struct s3c_fb_user_chroma __user *)arg,
+ sizeof(p.user_chroma))) {
+ ret = -EFAULT;
+ break;
+ }
+
+ ret = s3c_fb_set_chroma_key(info, p.user_chroma);
+ break;
+
+ case S3CFB_SET_VSYNC_INT:
+ if (get_user(p.vsync, (int __user *)arg)) {
+ ret = -EFAULT;
+ break;
+ }
+
+ ret = s3c_fb_set_vsync_int(info, p.vsync);
+ break;
+
+#ifdef CONFIG_ION_EXYNOS
+ case S3CFB_WIN_CONFIG:
+ if (copy_from_user(&p.win_data,
+ (struct s3c_fb_win_config_data __user *)arg,
+ sizeof(p.win_data))) {
+ ret = -EFAULT;
+ break;
+ }
+
+ ret = s3c_fb_set_win_config(sfb, &p.win_data);
+ if (ret)
+ break;
+
+ if (copy_to_user((struct s3c_fb_win_config_data __user *)arg,
+ &p.win_data,
+ sizeof(p.user_ion_client))) {
+ ret = -EFAULT;
+ break;
+ }
+
+ break;
+
+ case S3CFB_GET_ION_USER_HANDLE:
+ if (copy_from_user(&p.user_ion_client,
+ (struct s3c_fb_user_ion_client __user *)arg,
+ sizeof(p.user_ion_client))) {
+ ret = -EFAULT;
+ break;
+ }
+
+ if (s3c_fb_get_user_ion_handle(sfb, win, &p.user_ion_client)) {
+ ret = -EFAULT;
+ break;
+ }
+
+ offset = var->xres_virtual * var->yoffset + var->xoffset;
+ offset *= var->bits_per_pixel / 8;
+ p.user_ion_client.offset = offset;
+
+ dev_dbg(sfb->dev, "Buffer offset: 0x%x\n",
+ p.user_ion_client.offset);
+
+ if (copy_to_user((struct s3c_fb_user_ion_client __user *)arg,
+ &p.user_ion_client,
+ sizeof(p.user_ion_client))) {
+ ret = -EFAULT;
+ break;
+ }
+ ret = 0;
+ break;
+#endif
+
default:
ret = -ENOTTY;
}
@@ -1092,6 +2307,14 @@
return ret;
}
+static int s3c_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+ struct s3c_fb_win *win = info->par;
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+ return dma_buf_mmap(win->dma_buf_data.dma_buf, vma, 0);
+}
+
static struct fb_ops s3c_fb_ops = {
.owner = THIS_MODULE,
.fb_check_var = s3c_fb_check_var,
@@ -1103,6 +2326,7 @@
.fb_imageblit = cfb_imageblit,
.fb_pan_display = s3c_fb_pan_display,
.fb_ioctl = s3c_fb_ioctl,
+ .fb_mmap = s3c_fb_mmap,
};
/**
@@ -1120,8 +2344,11 @@
mode->xres;
div *= mode->upper_margin + mode->vsync_len + mode->lower_margin +
mode->yres;
+#if defined(CONFIG_LCD_MIPI_S6E8AB0) /* this define will be delete after mipi lcd supports 60Hz */
+ div *= mode->refresh ? : 40;
+#else
div *= mode->refresh ? : 60;
-
+#endif
do_div(pixclk, div);
mode->pixclock = pixclk;
@@ -1140,7 +2367,11 @@
struct s3c_fb_pd_win *windata = win->windata;
unsigned int real_size, virt_size, size;
struct fb_info *fbi = win->fbinfo;
+ struct ion_handle *handle;
dma_addr_t map_dma;
+ int fd;
+ unsigned int ret;
+ struct file *file;
dev_dbg(sfb->dev, "allocating memory for display\n");
@@ -1158,8 +2389,27 @@
fbi->fix.smem_len = size;
size = PAGE_ALIGN(size);
- dev_dbg(sfb->dev, "want %u bytes for window\n", size);
+ dev_dbg(sfb->dev, "want %u bytes for window[%d]\n", size, win->index);
+#if defined(CONFIG_ION_EXYNOS)
+ handle = ion_alloc(sfb->fb_ion_client, (size_t)size, 0,
+ EXYNOS_ION_HEAP_EXYNOS_MASK, 0);
+ if (IS_ERR(handle)) {
+ dev_err(sfb->dev, "failed to ion_alloc\n");
+ return -ENOMEM;
+ }
+
+ fd = ion_share_dma_buf(sfb->fb_ion_client, handle);
+ if (fd < 0) {
+ dev_err(sfb->dev, "ion_share_dma_buf() failed\n");
+ goto err_share_dma_buf;
+ }
+
+ ret = s3c_fb_map_ion_handle(sfb, &win->dma_buf_data, handle, fd);
+ if (!ret)
+ goto err_map;
+ map_dma = win->dma_buf_data.dma_addr;
+#else
fbi->screen_base = dma_alloc_writecombine(sfb->dev, size,
&map_dma, GFP_KERNEL);
if (!fbi->screen_base)
@@ -1169,9 +2419,20 @@
(unsigned int)map_dma, fbi->screen_base);
memset(fbi->screen_base, 0x0, size);
+#endif
fbi->fix.smem_start = map_dma;
return 0;
+
+#ifdef CONFIG_ION_EXYNOS
+err_map:
+ file = fget(fd);
+ fput(file);
+ fput(file);
+err_share_dma_buf:
+ ion_free(sfb->fb_ion_client, handle);
+ return -ENOMEM;
+#endif
}
/**
@@ -1183,11 +2444,16 @@
*/
static void s3c_fb_free_memory(struct s3c_fb *sfb, struct s3c_fb_win *win)
{
+#if defined(CONFIG_ION_EXYNOS)
+ s3c_fb_free_dma_buf(sfb, &win->dma_buf_data);
+#else
struct fb_info *fbi = win->fbinfo;
if (fbi->screen_base)
dma_free_writecombine(sfb->dev, PAGE_ALIGN(fbi->fix.smem_len),
fbi->screen_base, fbi->fix.smem_start);
+#endif
+
}
/**
@@ -1208,7 +2474,6 @@
data &= ~SHADOWCON_CHx_LOCAL_ENABLE(win->index);
writel(data, sfb->regs + SHADOWCON);
}
- unregister_framebuffer(win->fbinfo);
if (win->fbinfo->cmap.len)
fb_dealloc_cmap(&win->fbinfo->cmap);
s3c_fb_free_memory(sfb, win);
@@ -1266,6 +2531,7 @@
win->windata = windata;
win->index = win_no;
win->palette_buffer = (u32 *)(win + 1);
+ memset(&win->dma_buf_data, 0, sizeof(win->dma_buf_data));
ret = s3c_fb_alloc_memory(sfb, win);
if (ret) {
@@ -1301,6 +2567,8 @@
fbinfo->var.activate = FB_ACTIVATE_NOW;
fbinfo->var.vmode = FB_VMODE_NONINTERLACED;
fbinfo->var.bits_per_pixel = windata->default_bpp;
+ fbinfo->var.width = windata->width;
+ fbinfo->var.height = windata->height;
fbinfo->fbops = &s3c_fb_ops;
fbinfo->flags = FBINFO_FLAG_DEFAULT;
fbinfo->pseudo_palette = &win->pseudo_palette;
@@ -1321,20 +2589,6 @@
else
dev_err(sfb->dev, "failed to allocate fb cmap\n");
- s3c_fb_set_par(fbinfo);
-
- dev_dbg(sfb->dev, "about to register framebuffer\n");
-
- /* run the check_var and set_par on our configuration. */
-
- ret = register_framebuffer(fbinfo);
- if (ret < 0) {
- dev_err(sfb->dev, "failed to register framebuffer\n");
- return ret;
- }
-
- dev_info(sfb->dev, "window %d: fb %s\n", win_no, fbinfo->fix.id);
-
return 0;
}
@@ -1354,10 +2608,813 @@
writel(0, regs + VIDOSD_A(win, sfb->variant));
writel(0, regs + VIDOSD_B(win, sfb->variant));
writel(0, regs + VIDOSD_C(win, sfb->variant));
- reg = readl(regs + SHADOWCON);
- writel(reg & ~SHADOWCON_WINx_PROTECT(win), regs + SHADOWCON);
+ if (sfb->variant.has_shadowcon) {
+ reg = readl(sfb->regs + SHADOWCON);
+ reg &= ~SHADOWCON_CHx_ENABLE(win);
+ reg &= ~SHADOWCON_WINx_PROTECT(win);
+ writel(reg, sfb->regs + SHADOWCON);
+ }
+ reg = readl(sfb->regs + WINCON(win));
+ reg &= ~WINCONx_ENWIN;
+ writel(reg, sfb->regs + WINCON(win));
}
+/* --------------------For Local path from Gscaler ------------------------*/
+#ifdef CONFIG_FB_EXYNOS_FIMD_MC
+static inline struct s3c_fb_win *v4l2_subdev_to_s3c_fb_win(struct v4l2_subdev *sd)
+{
+ /* member instance, name of the parent structure, name of memeber in the parent structure */
+ return container_of(sd, struct s3c_fb_win, sd);
+}
+
+static int s3c_fb_sd_pad_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *format)
+{
+ u32 data;
+ struct s3c_fb_win *win = v4l2_subdev_to_s3c_fb_win(sd);
+ struct s3c_fb *sfb = win->parent;
+
+ /* (width, height) : (xres, yres) */
+ win->fbinfo->var.xres = format->format.width;
+ win->fbinfo->var.yres = format->format.height;
+ data = win->fbinfo->var.xres * win->fbinfo->var.yres;
+
+ vidosd_set_size(win, data);
+
+ if (data > (1280*720)) {
+ data = readl(sfb->regs + WINCON(win->index));
+ data |= WINCONx_CSC_CON_EQ709;
+ writel(data, sfb->regs + WINCON(win->index));
+ dev_dbg(sfb->dev, "Over HD size : (width, height) : (%d, %d)\n",
+ win->fbinfo->var.xres, win->fbinfo->var.yres);
+ }
+
+ dev_dbg(sfb->dev, "Set sd pad format (width, height) : (%d, %d)\n",
+ win->fbinfo->var.xres, win->fbinfo->var.yres);
+ return 0;
+}
+
+static int s3c_fb_sd_pad_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *format)
+{
+ struct s3c_fb_win *win = v4l2_subdev_to_s3c_fb_win(sd);
+ struct s3c_fb *sfb = win->parent;
+
+ /* (width, height) : (xres, yres) */
+ format->format.width = win->fbinfo->var.xres;
+ format->format.height = win->fbinfo->var.yres;
+
+ /* FIMD only accept the YUV data via local bus from GSCALER */
+ format->format.code = V4L2_MBUS_FMT_YUV8_1X24;
+
+ dev_dbg(sfb->dev, "Get sd pad format (width, height) : (%d, %d)\n",
+ format->format.width, format->format.height);
+ return 0;
+}
+
+static int s3c_fb_sd_set_pad_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_crop *crop)
+{
+ int ret;
+ struct s3c_fb_win *win = v4l2_subdev_to_s3c_fb_win(sd);
+ struct s3c_fb *sfb = win->parent;
+ struct s3c_fb_user_window user_window;
+
+ /* (left, top) : (xoffset, yoffset) */
+ user_window.x = crop->rect.left;
+ user_window.y = crop->rect.top;
+
+ ret = s3c_fb_set_window_position(win->fbinfo, user_window);
+
+ if (ret)
+ return ret;
+
+ dev_dbg(sfb->dev, "Set sd pad crop (x, y) : (%d, %d)\n",
+ crop->rect.left, crop->rect.top);
+ return 0;
+}
+
+static int s3c_fb_sd_pad_get_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_crop *crop)
+{
+ struct s3c_fb_win *win = v4l2_subdev_to_s3c_fb_win(sd);
+ struct s3c_fb *sfb = win->parent;
+
+ /* (width, height) : (xres, yres) */
+ crop->rect.width = win->fbinfo->var.xres;
+ crop->rect.height = win->fbinfo->var.yres;
+ dev_dbg(sfb->dev, "Get sd pad crop (width, height) : (%d, %d)\n",
+ crop->rect.width, crop->rect.height);
+
+ /* (left, top) : (xoffset, yoffset) */
+ crop->rect.left = win->fbinfo->var.xoffset;
+ crop->rect.top = win->fbinfo->var.yoffset;
+ dev_dbg(sfb->dev, "Get sd pad crop (left, top) : (%d, %d)\n",
+ crop->rect.left, crop->rect.top);
+
+ return 0;
+}
+
+static int s3c_fb_sd_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ u32 data = 0;
+ struct s3c_fb_win *win = v4l2_subdev_to_s3c_fb_win(sd);
+ struct s3c_fb *sfb = win->parent;
+
+ if (enable) { /* Enable 1 channel to a local path for a window in fimd1 */
+ /* The following sequence should be observed to enable a local path */
+ /* Enlocal On --> Enlocal Channel On --> Window On*/
+ shadow_protect_win(win, 1);
+ data = readl(sfb->regs + WINCON(win->index));
+ data &= ~WINCONx_ENLOCAL_MASK;
+ data |= (WINCONx_ENLOCAL | WINCONx_INRGB_YCBCR);
+ writel(data, sfb->regs + WINCON(win->index));
+
+ data = readl(sfb->regs + SHADOWCON);
+ data &= ~(SHADOWCON_CHx_ENABLE(win->index) | SHADOWCON_CHx_LOCAL_ENABLE(win->index));
+ data |= (SHADOWCON_CHx_ENABLE(win->index) | SHADOWCON_CHx_LOCAL_ENABLE(win->index));
+ writel(data, sfb->regs + SHADOWCON);
+ shadow_protect_win(win, 0);
+
+ s3c_fb_blank(FB_BLANK_UNBLANK, win->fbinfo);
+
+ } else { /* Disable 1 channel to a local path for a window in fimd1 */
+ /* The following sequence should be observed to disable a local path */
+ /* Enlocal channel Off --> Window Off --> Enlocal Off */
+ shadow_protect_win(win, 1);
+ data = readl(sfb->regs + SHADOWCON);
+ data &= ~(SHADOWCON_CHx_ENABLE(win->index) | SHADOWCON_CHx_LOCAL_ENABLE(win->index));
+ writel(data, sfb->regs + SHADOWCON);
+ shadow_protect_win(win, 0);
+
+ s3c_fb_blank(FB_BLANK_POWERDOWN, win->fbinfo);
+
+ shadow_protect_win(win, 1);
+ data = readl(sfb->regs + WINCON(win->index));
+ data &= ~WINCONx_ENLOCAL;
+ writel(data, sfb->regs + WINCON(win->index));
+ shadow_protect_win(win, 0);
+ }
+
+ dev_dbg(sfb->dev, "Get the window via local path started/stopped : %d\n",
+ enable);
+ return 0;
+}
+
+static const struct v4l2_subdev_pad_ops s3c_fb_sd_pad_ops = {
+ .set_fmt = s3c_fb_sd_pad_set_fmt,
+ .get_fmt = s3c_fb_sd_pad_get_fmt,
+ .get_crop = s3c_fb_sd_pad_get_crop,
+ .set_crop = s3c_fb_sd_set_pad_crop,
+};
+
+static const struct v4l2_subdev_video_ops s3c_fb_sd_video_ops = {
+ .s_stream = s3c_fb_sd_s_stream,
+};
+
+static const struct v4l2_subdev_ops s3c_fb_sd_ops = {
+ .pad = &s3c_fb_sd_pad_ops,
+ .video = &s3c_fb_sd_video_ops,
+};
+
+static void s3c_fb_mc_local_path_setup(struct s3c_fb_win *win)
+{
+ u32 data = 0;
+ struct s3c_fb *sfb = win->parent;
+
+ if (win->local) {
+ /* Enable the channel 1 to a local path for the window1
+ in fimd1 */
+
+ /* MIXER0_VALID[7] & MIXER1_VALID[4] : should be 0
+ (FIMD1 Data Valid) */
+ data = __raw_readl(SYSREG_DISP1BLK_CFG);
+ data &= ~(SYSREG_MIXER0_VALID | SYSREG_MIXER1_VALID);
+ writel(data, SYSREG_DISP1BLK_CFG);
+ }
+
+ dev_dbg(sfb->dev, "Local path set up in Winow[%d] : %d\n", win->index,
+ win->local);
+}
+
+static int s3c_fb_me_link_setup(struct media_entity *entity,
+ const struct media_pad *local,
+ const struct media_pad *remote, u32 flags)
+{
+ int i;
+ struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
+ struct s3c_fb_win *win = v4l2_subdev_to_s3c_fb_win(sd);
+ struct s3c_fb *sfb = win->parent;
+
+ if (flags & MEDIA_LNK_FL_ENABLED) {
+ win->use = 1;
+ if (local->index == FIMD_PAD_SINK_FROM_GSCALER_SRC)
+ win->local = 1;
+ } else {
+ if (local->index == FIMD_PAD_SINK_FROM_GSCALER_SRC)
+ win->local = 0;
+ win->use = 0;
+
+ for (i = 0; i < entity->num_links; ++i)
+ if (entity->links[i].flags & MEDIA_LNK_FL_ENABLED)
+ win->use = 1;
+ }
+
+ s3c_fb_mc_local_path_setup(win);
+
+ dev_dbg(sfb->dev, "MC link set up between Window[%d] and Gscaler: \
+ flag - %d\n", win->index, flags);
+ return 0;
+}
+
+/* media entity operations */
+static const struct media_entity_operations s3c_fb_me_ops = {
+ .link_setup = s3c_fb_me_link_setup,
+};
+
+/*---- In probing function (local path) ------*/
+static int s3c_fb_register_mc_entity(struct s3c_fb_win *win, struct exynos_md *md)
+{
+ int ret;
+ struct s3c_fb *sfb = win->parent;
+ struct v4l2_subdev *sd = &win->sd;
+ struct media_pad *pads = win->pads;
+ struct media_entity *me = &sd->entity;
+
+ /* Init a window of fimd as a sub-device */
+ v4l2_subdev_init(sd, &s3c_fb_sd_ops);
+ sd->owner = THIS_MODULE;
+ sprintf(sd->name, "s3c-fb-window%d", win->index);
+
+ /* fimd sub-devices can be opened in user space */
+ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+ /* FIMD takes a role of SINK between FIMD and Gscaler */
+ pads[FIMD_PAD_SINK_FROM_GSCALER_SRC].flags = MEDIA_PAD_FL_SINK;
+ me->ops = &s3c_fb_me_ops;
+
+ /* Init a sub-device as an entity */
+ ret = media_entity_init(me, FIMD_PADS_NUM, pads, 0);
+ if (ret) {
+ dev_err(sfb->dev, "failed to initialize media entity in FIMD\n");
+ return ret;
+ }
+
+ ret = v4l2_device_register_subdev(&md->v4l2_dev, sd);
+ if (ret) {
+ dev_err(sfb->dev, "failed to register FIMD Window subdev\n");
+ return ret;
+ }
+
+ dev_dbg(sfb->dev, "FIMD Winow[%d] MC entity init & subdev registered: %s\n",
+ win->index, sd->name);
+
+ return 0;
+}
+
+static int s3c_fb_register_mc_components(struct s3c_fb_win *win)
+{
+ int ret;
+ struct exynos_md *md;
+ struct s3c_fb *sfb = win->parent;
+
+ /* Local paths have been set up only between Gscaler0~2 and Window0~2 */
+ if (win->index >= 3)
+ return -ENODEV;
+
+ if (sfb->md == NULL) {
+ md = (struct exynos_md *)module_name_to_driver_data(MDEV_MODULE_NAME);
+
+ if (!md) {
+ dev_err(sfb->dev, "failed to get output media device\n");
+ return -ENODEV;
+ }
+ sfb->md = md;
+ }
+
+ ret = s3c_fb_register_mc_entity(win, sfb->md);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int s3c_fb_register_mc_subdev_nodes(struct s3c_fb *sfb)
+{
+ int ret;
+
+ /* This function is for exposing sub-devices nodes to user space
+ * in case of marking with V4L2_SUBDEV_FL_HAS_DEVNODE flag.
+ *
+ * And it depends on probe sequence
+ * because v4l2_dev ptr is shared all of output devices below
+ *
+ * probe sequence of output devices
+ * output media device -> gscaler -> window in fimd
+ */
+ ret = v4l2_device_register_subdev_nodes(&sfb->md->v4l2_dev);
+ if (ret) {
+ dev_err(sfb->dev, "failed to make nodes for subdev\n");
+ return ret;
+ }
+
+ dev_dbg(sfb->dev, "Register V4L2 subdev nodes for FIMD\n");
+
+ return 0;
+}
+
+static int s3c_fb_create_mc_links(struct s3c_fb_win *win)
+{
+ int ret;
+ int flags;
+ char err[80];
+ struct exynos_md *md;
+ struct s3c_fb *sfb = win->parent;
+
+ if (win->use)
+ flags = MEDIA_LNK_FL_ENABLED;
+ else
+ flags = 0;
+
+ /* link creation between pads: Gscaler[1] -> Window[0] */
+ md = (struct exynos_md *)module_name_to_driver_data(MDEV_MODULE_NAME);
+
+ /* Gscaler 0 --> Winwow 0, Gscaler 1 --> Winow 1,
+ Gscaler 2 --> Window 2, Gscaler 3 --> Window 3 */
+ if (md->gsc_sd[win->index] != NULL) {
+ ret = media_entity_create_link(&md->gsc_sd[win->index]->entity,
+ GSC_OUT_PAD_SOURCE,
+ &win->sd.entity,
+ FIMD_PAD_SINK_FROM_GSCALER_SRC, 0);
+ if (ret) {
+ sprintf(err, "%s --> %s",
+ md->gsc_sd[win->index]->entity.name,
+ win->sd.entity.name);
+ goto mc_link_create_fail;
+ }
+ }
+
+ dev_dbg(sfb->dev, "A link between Gscaler and window[%d] is created \
+ successfully\n", win->index);
+
+ return 0;
+
+mc_link_create_fail:
+ dev_err(sfb->dev, "failed to create a link between Gscaler and \
+ window[%d]: %s\n", win->index, err);
+ return ret;
+}
+
+static void s3c_fb_unregister_mc_entities(struct s3c_fb_win *win)
+{
+ v4l2_device_unregister_subdev(&win->sd);
+}
+#endif
+
+/* --------------------For Writeback to Scaler ------------------------*/
+#ifdef CONFIG_FB_EXYNOS_FIMD_MC_WB
+static inline struct s3c_fb *v4l2_subdev_to_s3c_fb(struct v4l2_subdev *sd)
+{
+ /* member instance, name of the parent structure, name of memeber
+ in the parent structure */
+ return container_of(sd, struct s3c_fb, sd_wb);
+}
+static int s3c_fb_sd_wb_s_stream(struct v4l2_subdev *sd_wb, int enable)
+{
+ struct s3c_fb *sfb = v4l2_subdev_to_s3c_fb(sd_wb);
+ u32 ret;
+ u32 vidcon0 = readl(sfb->regs + VIDCON0);
+ u32 vidcon2 = readl(sfb->regs + VIDCON2);
+
+ vidcon0 &= ~VIDCON0_VIDOUT_MASK;
+ vidcon2 &= ~(VIDCON2_WB_MASK | VIDCON2_TVFORMATSEL_HW_SW_MASK | \
+ VIDCON2_TVFORMATSEL_MASK);
+
+ if (enable) {
+ vidcon0 |= VIDCON0_VIDOUT_WB;
+ vidcon2 |= (VIDCON2_WB_ENABLE | VIDCON2_TVFORMATSEL_SW | \
+ VIDCON2_TVFORMATSEL_YUV444);
+ } else {
+ vidcon0 |= VIDCON0_VIDOUT_RGB;
+ vidcon2 |= VIDCON2_WB_DISABLE;
+ }
+
+ ret = s3c_fb_wait_for_vsync(sfb, VSYNC_TIMEOUT_MSEC);
+ if (ret) {
+ dev_err(sfb->dev, "wait timeout(writeback) : %s\n", __func__);
+ return ret;
+ }
+
+ writel(vidcon0, sfb->regs + VIDCON0);
+ writel(vidcon2, sfb->regs + VIDCON2);
+
+ dev_dbg(sfb->dev, "Get the writeback started/stopped : %d\n", enable);
+ return 0;
+}
+
+static int s3c_fb_sd_wb_pad_get_fmt(struct v4l2_subdev *sd_wb, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *format)
+{
+ struct s3c_fb *sfb = v4l2_subdev_to_s3c_fb(sd_wb);
+ int default_win = sfb->pdata->default_win;
+
+ /* (width, height) : (xres, yres) */
+ format->format.width = sfb->windows[default_win]->fbinfo->var.xres;
+ format->format.height = sfb->windows[default_win]->fbinfo->var.yres;
+
+ /* FIMD writes the video data back to GSCALER */
+ format->format.code = V4L2_MBUS_FMT_XRGB8888_4X8_LE;
+
+ dev_dbg(sfb->dev, "Get sd wb pad format (width, height) : (%d, %d)\n",
+ format->format.width, format->format.height);
+ return 0;
+}
+
+static const struct v4l2_subdev_pad_ops s3c_fb_sd_wb_pad_ops = {
+ .get_fmt = s3c_fb_sd_wb_pad_get_fmt,
+};
+
+static const struct v4l2_subdev_video_ops s3c_fb_sd_wb_video_ops = {
+ .s_stream = s3c_fb_sd_wb_s_stream,
+};
+
+static const struct v4l2_subdev_ops s3c_fb_sd_wb_ops = {
+ .video = &s3c_fb_sd_wb_video_ops,
+ .pad = &s3c_fb_sd_wb_pad_ops,
+};
+
+static int s3c_fb_me_wb_link_setup(struct media_entity *entity,
+ const struct media_pad *local,
+ const struct media_pad *remote, u32 flags)
+{
+ int i;
+ struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
+ struct s3c_fb *sfb = v4l2_subdev_to_s3c_fb(sd);
+
+ if (flags & MEDIA_LNK_FL_ENABLED) {
+ sfb->use_wb = 1;
+ if (local->index == FIMD_WB_PAD_SRC_TO_GSCALER_SINK)
+ sfb->local_wb = 1;
+ } else {
+ if (local->index == FIMD_WB_PAD_SRC_TO_GSCALER_SINK)
+ sfb->local_wb = 0;
+ sfb->use_wb = 0;
+
+ for (i = 0; i < entity->num_links; ++i)
+ if (entity->links[i].flags & MEDIA_LNK_FL_ENABLED)
+ sfb->use_wb = 1;
+ }
+
+ dev_dbg(sfb->dev, "MC WB link set up between FIMD and Gscaler: \
+ flag - %d\n", flags);
+ return 0;
+}
+
+/* media entity operations */
+static const struct media_entity_operations s3c_fb_me_wb_ops = {
+ .link_setup = s3c_fb_me_wb_link_setup,
+};
+
+/* --- In probing function (writeback) ---*/
+static int s3c_fb_register_mc_wb_entity(struct s3c_fb *sfb, struct exynos_md *md_wb)
+{
+ int ret;
+
+ struct v4l2_subdev *sd_wb = &sfb->sd_wb;
+ struct media_pad *pads_wb = &sfb->pads_wb;
+ struct media_entity *me_wb = &sd_wb->entity;
+
+ /* Init a window of fimd as a sub-device */
+ v4l2_subdev_init(sd_wb, &s3c_fb_sd_wb_ops);
+ sd_wb->owner = THIS_MODULE;
+ sprintf(sd_wb->name, "s5p-fimd1");
+
+ /* fimd sub-devices can be opened in user space */
+ sd_wb->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+ /* FIMD takes a role of sources between FIMD and Gscaler */
+ pads_wb->flags = MEDIA_PAD_FL_SOURCE;
+ me_wb->ops = &s3c_fb_me_wb_ops;
+
+ /* Init a sub-device as an entity */
+ ret = media_entity_init(me_wb, FIMD_WB_PADS_NUM, pads_wb, 0);
+ if (ret) {
+ dev_err(sfb->dev, "failed to initialize media entity in FIMD WB\n");
+ return ret;
+ }
+
+ ret = v4l2_device_register_subdev(&md_wb->v4l2_dev, sd_wb);
+ if (ret) {
+ dev_err(sfb->dev, "failed to register FIMD WB subdev\n");
+ return ret;
+ }
+
+ dev_dbg(sfb->dev, "FIMD1 WB MC entity init & subdev registered: %s\n", sd_wb->name);
+
+ return 0;
+}
+
+static int fimd_get_media_info(struct device *dev, void *p)
+{
+ struct exynos_md **mdev = p;
+ struct platform_device *pdev = to_platform_device(dev);
+
+ mdev[pdev->id] = dev_get_drvdata(dev);
+
+ if (!mdev[pdev->id])
+ return -ENODEV;
+
+ return 0;
+}
+
+static int s3c_fb_register_mc_wb_components(struct s3c_fb *sfb)
+{
+ int ret;
+ struct exynos_md *mdev[2] = {NULL, NULL};
+ struct device_driver *driver;
+
+ driver = driver_find(MDEV_MODULE_NAME, &platform_bus_type);
+ if (!driver)
+ dev_err(sfb->dev, "MC driver not found in s3c_fb\n");
+
+ ret = driver_for_each_device(driver, NULL, &mdev[0],
+ fimd_get_media_info);
+
+ sfb->md_wb = mdev[MDEV_CAPTURE];
+
+ /* Local paths have been set up only between FIMD1 and Gscaler0~3 */
+ ret = s3c_fb_register_mc_wb_entity(sfb, sfb->md_wb);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int s3c_fb_create_mc_wb_links(struct s3c_fb *sfb)
+{
+ int ret, i;
+ int flags;
+ char err[80];
+
+ if (sfb->use_wb)
+ flags = MEDIA_LNK_FL_ENABLED;
+ else
+ flags = 0;
+
+ /* FIMD1 --> Gscaler 0, Gscaler 1, Gscaler 2, or Gscaler 3 */
+ for (i = 0; i < MAX_GSC_SUBDEV; ++i) {
+ if (sfb->md_wb->gsc_cap_sd[i] != NULL) {
+ ret = media_entity_create_link(&sfb->sd_wb.entity, /* source */
+ FIMD_WB_PAD_SRC_TO_GSCALER_SINK,
+ &sfb->md_wb->gsc_cap_sd[i]->entity, /* sink */
+ GSC_CAP_PAD_SINK, 0);
+ if (ret) {
+ sprintf(err, "%s --> %s",
+ sfb->md_wb->gsc_cap_sd[i]->entity.name,
+ sfb->sd_wb.entity.name);
+ goto mc_wb_link_create_fail;
+ }
+ }
+
+ dev_dbg(sfb->dev, "A link between FIMD1 and Gscaler[%d] is created \
+ successfully\n", i);
+ }
+
+ return 0;
+
+mc_wb_link_create_fail:
+ dev_err(sfb->dev, "failed to create a link FIMD1 and Gscaler[%d] \
+ %s\n", i, err);
+ return ret;
+}
+
+static int s3c_fb_register_mc_subdev_wb_nodes(struct s3c_fb *sfb)
+{
+ int ret;
+
+ /* This function is for exposing sub-devices nodes to user space
+ * in case of marking with V4L2_SUBDEV_FL_HAS_DEVNODE flag.
+ *
+ * And it depends on probe sequence
+ * because v4l2_dev ptr is shared all of output devices below
+ *
+ * probe sequence of output devices
+ * output media device -> gscaler -> window in fimd
+ */
+ ret = v4l2_device_register_subdev_nodes(&sfb->md_wb->v4l2_dev);
+ if (ret) {
+ dev_err(sfb->dev, "failed to make nodes for subdev\n");
+ return ret;
+ }
+
+ dev_dbg(sfb->dev, "Register V4L2 subdev nodes for FIMD\n");
+
+ return 0;
+}
+
+static void s3c_fb_unregister_mc_wb_entities(struct s3c_fb *sfb)
+{
+ v4l2_device_unregister_subdev(&sfb->sd_wb);
+}
+#endif
+
+static int s3c_fb_wait_for_vsync_thread(void *data)
+{
+ struct s3c_fb *sfb = data;
+
+ while (!kthread_should_stop()) {
+ ktime_t timestamp = sfb->vsync_info.timestamp;
+ int ret = wait_event_interruptible(sfb->vsync_info.wait,
+ !ktime_equal(timestamp, sfb->vsync_info.timestamp) &&
+ sfb->vsync_info.active);
+
+ if (!ret) {
+ exynos5_ppmu_trace();
+ sysfs_notify(&sfb->dev->kobj, NULL, "vsync");
+ }
+ }
+
+ return 0;
+}
+
+/*------------------------------------------------------------------ */
+
+static ssize_t s3c_fb_vsync_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct s3c_fb *sfb = dev_get_drvdata(dev);
+ return scnprintf(buf, PAGE_SIZE, "%llu\n",
+ ktime_to_ns(sfb->vsync_info.timestamp));
+}
+
+static DEVICE_ATTR(vsync, S_IRUGO, s3c_fb_vsync_show, NULL);
+
+#ifdef CONFIG_ION_EXYNOS
+int s3c_fb_sysmmu_fault_handler(struct device *dev,
+ enum exynos_sysmmu_inttype itype, unsigned long pgtable_base,
+ unsigned long fault_addr)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct s3c_fb *sfb = platform_get_drvdata(pdev);
+
+ pr_err("FIMD1 PAGE FAULT occurred at 0x%lx (Page table base: 0x%lx)\n",
+ fault_addr, pgtable_base);
+
+ s3c_fb_dump_registers(sfb);
+
+ pr_err("Generating Kernel OOPS... because it is unrecoverable.\n");
+
+ BUG();
+
+ return 0;
+}
+
+static int __devinit s3c_fb_copy_bootloader_fb(struct platform_device *pdev,
+ struct dma_buf *dest_buf)
+{
+ struct resource *res;
+ int ret = 0;
+ size_t i;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!res || !res->start || !resource_size(res)) {
+ dev_warn(&pdev->dev, "failed to find bootloader framebuffer\n");
+ return -ENOENT;
+ }
+
+ ret = dma_buf_begin_cpu_access(dest_buf, 0, resource_size(res),
+ DMA_TO_DEVICE);
+ if (ret < 0) {
+ dev_warn(&pdev->dev, "dma_buf_begin_cpu_access() failed on bootloader framebuffer: %u\n",
+ ret);
+ goto err;
+ }
+ for (i = 0; i < resource_size(res); i += PAGE_SIZE) {
+ void *page = phys_to_page(res->start + i);
+ void *from_virt = kmap(page);
+ void *to_virt = dma_buf_kmap(dest_buf, i / PAGE_SIZE);
+ memcpy(to_virt, from_virt, PAGE_SIZE);
+ kunmap(page);
+ dma_buf_kunmap(dest_buf, i / PAGE_SIZE, to_virt);
+ }
+
+ dma_buf_end_cpu_access(dest_buf, 0, resource_size(res), DMA_TO_DEVICE);
+
+err:
+ if (memblock_free(res->start, resource_size(res)))
+ dev_warn(&pdev->dev, "failed to free bootloader framebuffer memblock\n");
+
+ return ret;
+}
+
+static int __devinit s3c_fb_clear_fb(struct s3c_fb *sfb,
+ struct dma_buf *dest_buf, size_t size)
+{
+ size_t i;
+
+ int ret = dma_buf_begin_cpu_access(dest_buf, 0, dest_buf->size,
+ DMA_TO_DEVICE);
+ if (ret < 0) {
+ dev_warn(sfb->dev, "dma_buf_begin_cpu_access() failed while clearing framebuffer: %u\n",
+ ret);
+ return ret;
+ }
+
+ for (i = 0; i < dest_buf->size / PAGE_SIZE; i++) {
+ void *to_virt = dma_buf_kmap(dest_buf, i);
+ memset(to_virt, 0, PAGE_SIZE);
+ dma_buf_kunmap(dest_buf, i, to_virt);
+ }
+
+ dma_buf_end_cpu_access(dest_buf, 0, size, DMA_TO_DEVICE);
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+
+static int s3c_fb_debugfs_show(struct seq_file *f, void *offset)
+{
+ struct s3c_fb *sfb = f->private;
+ struct s3c_fb_debug *debug_data = kzalloc(sizeof(struct s3c_fb_debug),
+ GFP_KERNEL);
+
+ if (!debug_data) {
+ seq_printf(f, "kmalloc() failed; can't generate file\n");
+ return -ENOMEM;
+ }
+
+ spin_lock(&sfb->slock);
+ memcpy(debug_data, &sfb->debug_data, sizeof(sfb->debug_data));
+ spin_unlock(&sfb->slock);
+
+ seq_printf(f, "%u FIFO underflows\n", debug_data->num_timestamps);
+ if (debug_data->num_timestamps) {
+ unsigned int i;
+ unsigned int temp = S3C_FB_DEBUG_FIFO_TIMESTAMPS;
+ unsigned int n = min(debug_data->num_timestamps, temp);
+
+ seq_printf(f, "Last %u FIFO underflow timestamps:\n", n);
+ for (i = 0; i < n; i++) {
+ unsigned int idx = (debug_data->first_timestamp + i) %
+ S3C_FB_DEBUG_FIFO_TIMESTAMPS;
+ ktime_t timestamp = debug_data->fifo_timestamps[idx];
+ seq_printf(f, "\t%lld\n", ktime_to_ns(timestamp));
+ }
+
+ seq_printf(f, "Registers at time of last underflow:\n");
+ for (i = 0; i < S3C_FB_DEBUG_REGS_SIZE; i += 32) {
+ unsigned char buf[128];
+ hex_dump_to_buffer(debug_data->regs_at_underflow + i,
+ 32, 32, 4, buf,
+ sizeof(buf), false);
+ seq_printf(f, "%.8x: %s\n", i, buf);
+ }
+ }
+
+ kfree(debug_data);
+ return 0;
+}
+
+static int s3c_fb_debugfs_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, s3c_fb_debugfs_show, inode->i_private);
+}
+
+static const struct file_operations s3c_fb_debugfs_fops = {
+ .owner = THIS_MODULE,
+ .open = s3c_fb_debugfs_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int s3c_fb_debugfs_init(struct s3c_fb *sfb)
+{
+ sfb->debug_dentry = debugfs_create_file("s3c-fb", S_IRUGO, NULL, sfb,
+ &s3c_fb_debugfs_fops);
+ if (IS_ERR_OR_NULL(sfb->debug_dentry)) {
+ sfb->debug_dentry = NULL;
+ dev_err(sfb->dev, "debugfs_create_file() failed\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static void s3c_fb_debugfs_cleanup(struct s3c_fb *sfb)
+{
+ if (sfb->debug_dentry)
+ debugfs_remove(sfb->debug_dentry);
+}
+
+#else
+
+static int s3c_fb_debugfs_init(struct s3c_fb *sfb) { return 0; }
+static void s3c_fb_debugfs_cleanup(struct s3c_fb *sfb) { }
+
+#endif
+
static int __devinit s3c_fb_probe(struct platform_device *pdev)
{
const struct platform_device_id *platid;
@@ -1366,7 +3423,10 @@
struct s3c_fb_platdata *pd;
struct s3c_fb *sfb;
struct resource *res;
+ struct fb_info *fbinfo;
int win;
+ int default_win;
+ int i;
int ret = 0;
u32 reg;
@@ -1397,6 +3457,31 @@
sfb->variant = fbdrv->variant;
spin_lock_init(&sfb->slock);
+ mutex_init(&sfb->output_lock);
+
+ ret = s3c_fb_debugfs_init(sfb);
+ if (ret)
+ dev_warn(dev, "failed to initialize debugfs entry\n");
+
+#ifdef CONFIG_ION_EXYNOS
+ INIT_LIST_HEAD(&sfb->update_regs_list);
+ mutex_init(&sfb->update_regs_list_lock);
+ init_kthread_worker(&sfb->update_regs_worker);
+
+ sfb->update_regs_thread = kthread_run(kthread_worker_fn,
+ &sfb->update_regs_worker, "s3c-fb");
+ if (IS_ERR(sfb->update_regs_thread)) {
+ int err = PTR_ERR(sfb->update_regs_thread);
+ sfb->update_regs_thread = NULL;
+
+ dev_err(dev, "failed to run update_regs thread\n");
+ return err;
+ }
+ init_kthread_work(&sfb->update_regs_work, s3c_fb_update_regs_handler);
+ sfb->timeline = sw_sync_timeline_create("s3c-fb");
+ sfb->timeline_max = 1;
+ /* XXX need to cleanup on errors */
+#endif
sfb->bus_clk = clk_get(dev, "lcd");
if (IS_ERR(sfb->bus_clk)) {
@@ -1468,9 +3553,9 @@
}
/* zero all windows before we do anything */
-
for (win = 0; win < fbdrv->variant.nr_windows; win++)
- s3c_fb_clear_win(sfb, win);
+ if (win != pd->default_win)
+ s3c_fb_clear_win(sfb, win);
/* initialise colour key controls */
for (win = 0; win < (fbdrv->variant.nr_windows - 1); win++) {
@@ -1480,15 +3565,38 @@
writel(0xffffff, regs + WKEYCON0);
writel(0xffffff, regs + WKEYCON1);
}
+#ifdef CONFIG_ION_EXYNOS
+ sfb->fb_ion_client = ion_client_create(ion_exynos, "fimd");
+ if (IS_ERR(sfb->fb_ion_client)) {
+ dev_err(sfb->dev, "failed to ion_client_create\n");
+ goto err_pm_runtime;
+ }
- /* we have the register setup, start allocating framebuffers */
+ /* setup vmm */
+ platform_set_sysmmu(&SYSMMU_PLATDEV(fimd1).dev, &s5p_device_fimd1.dev);
+ exynos_sysmmu_set_fault_handler(&s5p_device_fimd1.dev,
+ s3c_fb_sysmmu_fault_handler);
+#endif
+ default_win = sfb->pdata->default_win;
for (win = 0; win < fbdrv->variant.nr_windows; win++) {
if (!pd->win[win])
continue;
if (!pd->win[win]->win_mode.pixclock)
s3c_fb_missing_pixclock(&pd->win[win]->win_mode);
+ }
+
+ /* use platform specified window as the basis for the lcd timings */
+ s3c_fb_configure_lcd(sfb, &pd->win[default_win]->win_mode);
+
+ /* we have the register setup, start allocating framebuffers */
+ for (i = 0; i < fbdrv->variant.nr_windows; i++) {
+ win = i;
+ if (i == 0)
+ win = default_win;
+ if (i == default_win)
+ win = 0;
ret = s3c_fb_probe_win(sfb, win, fbdrv->win[win],
&sfb->windows[win]);
@@ -1498,13 +3606,154 @@
s3c_fb_release_win(sfb, sfb->windows[win]);
goto err_pm_runtime;
}
+
+#ifdef CONFIG_FB_EXYNOS_FIMD_MC
+ /* local path is only supported for windows 0-2 */
+ if (win > 2)
+ continue;
+
+ /* register a window subdev as entity */
+ ret = s3c_fb_register_mc_components(sfb->windows[win]);
+ if (ret) {
+ dev_err(sfb->dev, "failed to register s3c_fb mc entities\n");
+ goto err_mc_entity_create_fail;
+ }
+
+ /* create links connected between gscaler and fimd */
+ ret = s3c_fb_create_mc_links(sfb->windows[win]);
+ if (ret) {
+ dev_err(sfb->dev, "failed to create s3c_fb mc links\n");
+ goto err_mc_link_create_fail;
+ }
+#endif
}
+#ifdef CONFIG_FB_EXYNOS_FIMD_MC
+ ret = s3c_fb_register_mc_subdev_nodes(sfb);
+ if (ret) {
+ dev_err(sfb->dev, "failed to register s3c_fb mc subdev node\n");
+ goto err_mc_link_create_fail;
+ }
+#endif
+
+#ifdef CONFIG_FB_EXYNOS_FIMD_MC_WB
+ /* register a window subdev as entity */
+ ret = s3c_fb_register_mc_wb_components(sfb);
+ if (ret) {
+ dev_err(sfb->dev, "failed to register s3c_fb mc entities\n");
+ goto err_mc_wb_entity_create_fail;
+ }
+
+ /* create links connected between gscaler and fimd */
+ ret = s3c_fb_create_mc_wb_links(sfb);
+ if (ret) {
+ dev_err(sfb->dev, "failed to create s3c_fb mc links\n");
+ goto err_mc_wb_link_create_fail;
+ }
+
+ ret = s3c_fb_register_mc_subdev_wb_nodes(sfb);
+ if (ret) {
+ dev_err(sfb->dev, "failed to register s3c_fb mc subdev node\n");
+ goto err_mc_wb_link_create_fail;
+ }
+#endif
+
+#ifdef CONFIG_S5P_DP
+ writel(DPCLKCON_ENABLE, sfb->regs + DPCLKCON);
+#endif
platform_set_drvdata(pdev, sfb);
- pm_runtime_put_sync(sfb->dev);
+
+ mutex_init(&sfb->vsync_info.irq_lock);
+
+ ret = device_create_file(sfb->dev, &dev_attr_vsync);
+ if (ret) {
+ dev_err(sfb->dev, "failed to create vsync file\n");
+ goto err_create_file;
+ }
+
+ sfb->vsync_info.thread = kthread_run(s3c_fb_wait_for_vsync_thread,
+ sfb, "s3c-fb-vsync");
+ if (sfb->vsync_info.thread == ERR_PTR(-ENOMEM)) {
+ dev_err(sfb->dev, "failed to run vsync thread\n");
+ sfb->vsync_info.thread = NULL;
+ }
+
+#ifdef CONFIG_ION_EXYNOS
+ ret = s3c_fb_copy_bootloader_fb(pdev,
+ sfb->windows[default_win]->dma_buf_data.dma_buf);
+ if (ret < 0) {
+ struct s3c_fb_win *win = sfb->windows[default_win];
+ dev_warn(sfb->dev, "couldn't copy bootloader framebuffer into default window; clearing instead\n");
+ s3c_fb_clear_fb(sfb, win->dma_buf_data.dma_buf,
+ PAGE_ALIGN(win->fbinfo->fix.smem_len));
+ }
+#endif
+
+ s3c_fb_set_par(sfb->windows[default_win]->fbinfo);
+
+#ifdef CONFIG_ION_EXYNOS
+ s3c_fb_wait_for_vsync(sfb, 0);
+ ret = iovmm_activate(&s5p_device_fimd1.dev);
+ if (ret < 0) {
+ dev_err(sfb->dev, "failed to activate vmm\n");
+ goto err_iovmm;
+ }
+#endif
+
+ if (!sfb->fb_mif_handle) {
+ sfb->fb_mif_handle = exynos5_bus_mif_min(300000);
+ if (!sfb->fb_mif_handle)
+ dev_err(sfb->dev, "failed to request min_freq for mif \n");
+ }
+
+ if (!sfb->fb_int_handle) {
+ sfb->fb_int_handle = exynos5_bus_int_min(160000);
+ if (!sfb->fb_int_handle)
+ dev_err(sfb->dev, "failed to request min_freq for int \n");
+ }
+
+ s3c_fb_activate_window_dma(sfb, default_win);
+ s3c_fb_activate_window(sfb, default_win);
+ sfb->output_on = true;
+
+ dev_dbg(sfb->dev, "about to register framebuffer\n");
+
+ /* run the check_var and set_par on our configuration. */
+
+ fbinfo = sfb->windows[default_win]->fbinfo;
+ ret = register_framebuffer(fbinfo);
+ if (ret < 0) {
+ dev_err(sfb->dev, "failed to register framebuffer\n");
+ goto err_fb;
+ }
+
+ dev_info(sfb->dev, "window %d: fb %s\n", default_win, fbinfo->fix.id);
return 0;
+err_fb:
+ if (sfb->fb_mif_handle)
+ exynos5_bus_mif_put(sfb->fb_mif_handle);
+ if (sfb->fb_int_handle)
+ exynos5_bus_int_put(sfb->fb_int_handle);
+ iovmm_deactivate(&s5p_device_fimd1.dev);
+
+err_iovmm:
+ device_remove_file(sfb->dev, &dev_attr_vsync);
+
+err_create_file:
+#ifdef CONFIG_FB_EXYNOS_FIMD_MC_WB
+err_mc_wb_entity_create_fail:
+err_mc_wb_link_create_fail:
+ s3c_fb_unregister_mc_wb_entities(sfb);
+#endif
+
+#ifdef CONFIG_FB_EXYNOS_FIMD_MC
+err_mc_entity_create_fail:
+err_mc_link_create_fail:
+ s3c_fb_unregister_mc_entities(sfb->windows[win]);
+#endif
+
err_pm_runtime:
pm_runtime_put_sync(sfb->dev);
@@ -1521,6 +3770,9 @@
clk_put(sfb->bus_clk);
err_sfb:
+#ifdef CONFIG_ION_EXYNOS
+ kthread_stop(sfb->update_regs_thread);
+#endif
return ret;
}
@@ -1538,10 +3790,20 @@
pm_runtime_get_sync(sfb->dev);
+ unregister_framebuffer(sfb->windows[sfb->pdata->default_win]->fbinfo);
+
+ if (sfb->update_regs_thread)
+ kthread_stop(sfb->update_regs_thread);
+
for (win = 0; win < S3C_FB_MAX_WIN; win++)
if (sfb->windows[win])
s3c_fb_release_win(sfb, sfb->windows[win]);
+ if (sfb->vsync_info.thread)
+ kthread_stop(sfb->vsync_info.thread);
+
+ device_remove_file(sfb->dev, &dev_attr_vsync);
+
if (!sfb->variant.has_clksel) {
clk_disable(sfb->lcd_clk);
clk_put(sfb->lcd_clk);
@@ -1550,45 +3812,90 @@
clk_disable(sfb->bus_clk);
clk_put(sfb->bus_clk);
+ s3c_fb_debugfs_cleanup(sfb);
+
pm_runtime_put_sync(sfb->dev);
pm_runtime_disable(sfb->dev);
+ if (sfb->fb_mif_handle)
+ exynos5_bus_mif_put(sfb->fb_mif_handle);
+ if (sfb->fb_int_handle)
+ exynos5_bus_int_put(sfb->fb_int_handle);
+
return 0;
}
-#ifdef CONFIG_PM_SLEEP
-static int s3c_fb_suspend(struct device *dev)
+static int s3c_fb_disable(struct s3c_fb *sfb)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct s3c_fb *sfb = platform_get_drvdata(pdev);
- struct s3c_fb_win *win;
- int win_no;
+ u32 vidcon0;
+ int ret = 0;
+ int i;
- for (win_no = S3C_FB_MAX_WIN - 1; win_no >= 0; win_no--) {
- win = sfb->windows[win_no];
- if (!win)
- continue;
+ mutex_lock(&sfb->output_lock);
- /* use the blank function to push into power-down */
- s3c_fb_blank(FB_BLANK_POWERDOWN, win->fbinfo);
+ if (!sfb->output_on) {
+ ret = -EBUSY;
+ goto err;
}
+ if (sfb->pdata->backlight_off)
+ sfb->pdata->backlight_off();
+
+ if (sfb->pdata->lcd_off)
+ sfb->pdata->lcd_off();
+
+ flush_kthread_worker(&sfb->update_regs_worker);
+
+ vidcon0 = readl(sfb->regs + VIDCON0);
+
+ /* see the note in the framebuffer datasheet about
+ * why you cannot take both of these bits down at the
+ * same time. */
+
+ if (vidcon0 & VIDCON0_ENVID) {
+ vidcon0 |= VIDCON0_ENVID;
+ vidcon0 &= ~VIDCON0_ENVID_F;
+ writel(vidcon0, sfb->regs + VIDCON0);
+ } else
+ dev_warn(sfb->dev, "ENVID not set while disabling fb");
+
if (!sfb->variant.has_clksel)
clk_disable(sfb->lcd_clk);
clk_disable(sfb->bus_clk);
- return 0;
+#ifdef CONFIG_ION_EXYNOS
+ iovmm_deactivate(&s5p_device_fimd1.dev);
+#endif
+
+ pm_runtime_put_sync(sfb->dev);
+ sfb->output_on = false;
+
+ exynos5_mif_multiple_windows(false);
+err:
+ mutex_unlock(&sfb->output_lock);
+ return ret;
}
-static int s3c_fb_resume(struct device *dev)
+/**
+ * s3c_fb_enable() - Enable the main LCD output
+ * @sfb: The main framebuffer state.
+ */
+static int s3c_fb_enable(struct s3c_fb *sfb)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct s3c_fb *sfb = platform_get_drvdata(pdev);
struct s3c_fb_platdata *pd = sfb->pdata;
- struct s3c_fb_win *win;
int win_no;
+ int default_win;
+ int ret;
u32 reg;
+ mutex_lock(&sfb->output_lock);
+ if (sfb->output_on) {
+ ret = -EBUSY;
+ goto err;
+ }
+
+ pm_runtime_get_sync(sfb->dev);
+
clk_enable(sfb->bus_clk);
if (!sfb->variant.has_clksel)
@@ -1597,6 +3904,8 @@
/* setup gpio and output polarity controls */
pd->setup_gpio();
writel(pd->vidcon1, sfb->regs + VIDCON1);
+ writel(REG_CLKGATE_MODE_NON_CLOCK_GATE,
+ sfb->regs + REG_CLKGATE_MODE);
/* set video clock running at under-run */
if (sfb->variant.has_fixvclk) {
@@ -1610,29 +3919,57 @@
for (win_no = 0; win_no < sfb->variant.nr_windows; win_no++)
s3c_fb_clear_win(sfb, win_no);
- for (win_no = 0; win_no < sfb->variant.nr_windows - 1; win_no++) {
- void __iomem *regs = sfb->regs + sfb->variant.keycon;
- win = sfb->windows[win_no];
- if (!win)
- continue;
+ /* use platform specified window as the basis for the lcd timings */
+ default_win = sfb->pdata->default_win;
+ s3c_fb_configure_lcd(sfb, &pd->win[default_win]->win_mode);
- shadow_protect_win(win, 1);
- regs += (win_no * 8);
- writel(0xffffff, regs + WKEYCON0);
- writel(0xffffff, regs + WKEYCON1);
- shadow_protect_win(win, 0);
+ mutex_lock(&sfb->vsync_info.irq_lock);
+ if (sfb->vsync_info.irq_refcount)
+ s3c_fb_enable_irq(sfb);
+ mutex_unlock(&sfb->vsync_info.irq_lock);
+
+#ifdef CONFIG_ION_EXYNOS
+ ret = iovmm_activate(&s5p_device_fimd1.dev);
+ if (ret < 0) {
+ dev_err(sfb->dev, "failed to reactivate vmm\n");
+ goto err;
}
+#endif
- /* restore framebuffers */
- for (win_no = 0; win_no < S3C_FB_MAX_WIN; win_no++) {
- win = sfb->windows[win_no];
- if (!win)
- continue;
+#ifdef CONFIG_S5P_DP
+ writel(DPCLKCON_ENABLE, sfb->regs + DPCLKCON);
+#endif
- dev_dbg(&pdev->dev, "resuming window %d\n", win_no);
- s3c_fb_set_par(win->fbinfo);
+ reg = readl(sfb->regs + VIDCON0);
+ reg |= VIDCON0_ENVID | VIDCON0_ENVID_F;
+ writel(reg, sfb->regs + VIDCON0);
+
+ sfb->output_on = true;
+
+err:
+ mutex_unlock(&sfb->output_lock);
+ return ret;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int s3c_fb_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct s3c_fb *sfb = platform_get_drvdata(pdev);
+ int ret = 0;
+
+ mutex_lock(&sfb->output_lock);
+ if (sfb->output_on) {
+ dev_warn(dev, "LCD output on while entering suspend\n");
+ ret = -EBUSY;
}
+ mutex_unlock(&sfb->output_lock);
+ return ret;
+}
+
+static int s3c_fb_resume(struct device *dev)
+{
return 0;
}
#endif
@@ -1648,6 +3985,18 @@
clk_disable(sfb->bus_clk);
+ if (sfb->fb_mif_handle) {
+ if(exynos5_bus_mif_put(sfb->fb_mif_handle))
+ dev_err(sfb->dev, "failed to free min_freq for mif \n");
+ sfb->fb_mif_handle = NULL;
+ }
+
+ if (sfb->fb_int_handle) {
+ if(exynos5_bus_int_put(sfb->fb_int_handle))
+ dev_err(sfb->dev, "failed to free min_freq for int \n");
+ sfb->fb_int_handle = NULL;
+ }
+
return 0;
}
@@ -1657,6 +4006,18 @@
struct s3c_fb *sfb = platform_get_drvdata(pdev);
struct s3c_fb_platdata *pd = sfb->pdata;
+ if (!sfb->fb_mif_handle) {
+ sfb->fb_mif_handle = exynos5_bus_mif_min(300000);
+ if (!sfb->fb_mif_handle)
+ dev_err(sfb->dev, "failed to request min_freq for mif \n");
+ }
+
+ if (!sfb->fb_int_handle) {
+ sfb->fb_int_handle = exynos5_bus_int_min(160000);
+ if (!sfb->fb_int_handle)
+ dev_err(sfb->dev, "failed to request min_freq for int \n");
+ }
+
clk_enable(sfb->bus_clk);
if (!sfb->variant.has_clksel)
@@ -1837,6 +4198,7 @@
.has_prtcon = 1,
.has_blendcon = 1,
+ .has_alphacon = 1,
.has_clksel = 1,
},
.win[0] = &s3c_fb_data_s5p_wins[0],
@@ -1869,6 +4231,7 @@
.has_shadowcon = 1,
.has_blendcon = 1,
+ .has_alphacon = 1,
.has_clksel = 1,
.has_fixvclk = 1,
},
@@ -1902,6 +4265,7 @@
.has_shadowcon = 1,
.has_blendcon = 1,
+ .has_alphacon = 1,
.has_fixvclk = 1,
},
.win[0] = &s3c_fb_data_s5p_wins[0],
@@ -1933,6 +4297,7 @@
},
.has_shadowcon = 1,
.has_blendcon = 1,
+ .has_alphacon = 1,
.has_fixvclk = 1,
},
.win[0] = &s3c_fb_data_s5p_wins[0],
@@ -2050,7 +4415,22 @@
},
};
-module_platform_driver(s3c_fb_driver);
+static int __init s3c_fb_init(void)
+{
+ return platform_driver_register(&s3c_fb_driver);
+}
+
+static void __exit s3c_fb_cleanup(void)
+{
+ platform_driver_unregister(&s3c_fb_driver);
+}
+
+#if defined(CONFIG_FB_EXYNOS_FIMD_MC) || defined(CONFIG_FB_EXYNOS_FIMD_MC_WB)
+late_initcall(s3c_fb_init);
+#else
+module_init(s3c_fb_init);
+#endif
+module_exit(s3c_fb_cleanup);
MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
MODULE_DESCRIPTION("Samsung S3C SoC Framebuffer driver");
diff --git a/drivers/video/s5p-dp-core.c b/drivers/video/s5p-dp-core.c
new file mode 100644
index 0000000..7135bee
--- /dev/null
+++ b/drivers/video/s5p-dp-core.c
@@ -0,0 +1,1375 @@
+/*
+ * Samsung SoC DP (Display Port) interface driver.
+ *
+ * Copyright (C) 2012 Samsung Electronics Co., Ltd.
+ * Author: Jingoo Han <jg1.han@samsung.com>
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/pm_runtime.h>
+#include <linux/lcd.h>
+
+#include <video/s5p-dp.h>
+
+#include <plat/cpu.h>
+
+#include "s5p-dp-core.h"
+
+static int s5p_dp_init_dp(struct s5p_dp_device *dp)
+{
+ s5p_dp_reset(dp);
+
+ /* SW defined function Normal operation */
+ s5p_dp_enable_sw_function(dp);
+
+ if (!soc_is_exynos5250())
+ s5p_dp_config_interrupt(dp);
+
+ s5p_dp_init_analog_func(dp);
+
+ s5p_dp_init_hpd(dp);
+ s5p_dp_init_aux(dp);
+
+ return 0;
+}
+
+static int s5p_dp_detect_hpd(struct s5p_dp_device *dp)
+{
+ int timeout_loop = 0;
+
+ s5p_dp_init_hpd(dp);
+
+ udelay(200);
+
+ while (s5p_dp_get_plug_in_status(dp) != 0) {
+ timeout_loop++;
+ if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
+ dev_err(dp->dev, "failed to get hpd plug status\n");
+ return -ETIMEDOUT;
+ }
+ udelay(10);
+ }
+
+ return 0;
+}
+
+static unsigned char s5p_dp_calc_edid_check_sum(unsigned char *edid_data)
+{
+ int i;
+ unsigned char sum = 0;
+
+ for (i = 0; i < EDID_BLOCK_LENGTH; i++)
+ sum = sum + edid_data[i];
+
+ return sum;
+}
+
+static int s5p_dp_read_edid(struct s5p_dp_device *dp)
+{
+ unsigned char edid[EDID_BLOCK_LENGTH * 2];
+ unsigned int extend_block = 0;
+ unsigned char sum;
+ unsigned char test_vector;
+ int retval;
+
+ /*
+ * EDID device address is 0x50.
+ * However, if necessary, you must have set upper address
+ * into E-EDID in I2C device, 0x30.
+ */
+
+ /* Read Extension Flag, Number of 128-byte EDID extension blocks */
+ retval = s5p_dp_read_byte_from_i2c(dp, I2C_EDID_DEVICE_ADDR,
+ EDID_EXTENSION_FLAG,
+ &extend_block);
+ if (retval < 0) {
+ dev_err(dp->dev, "EDID extension flag failed!\n");
+ return -EIO;
+ }
+
+ if (extend_block > 0) {
+ dev_dbg(dp->dev, "EDID data includes a single extension!\n");
+
+ /* Read EDID data */
+ retval = s5p_dp_read_bytes_from_i2c(dp, I2C_EDID_DEVICE_ADDR,
+ EDID_HEADER_PATTERN,
+ EDID_BLOCK_LENGTH,
+ &edid[EDID_HEADER_PATTERN]);
+ if (retval != 0) {
+ dev_err(dp->dev, "EDID Read failed!\n");
+ return -EIO;
+ }
+ sum = s5p_dp_calc_edid_check_sum(edid);
+ if (sum != 0) {
+ dev_err(dp->dev, "EDID bad checksum!\n");
+ return -EIO;
+ }
+
+ /* Read additional EDID data */
+ retval = s5p_dp_read_bytes_from_i2c(dp,
+ I2C_EDID_DEVICE_ADDR,
+ EDID_BLOCK_LENGTH,
+ EDID_BLOCK_LENGTH,
+ &edid[EDID_BLOCK_LENGTH]);
+ if (retval != 0) {
+ dev_err(dp->dev, "EDID Read failed!\n");
+ return -EIO;
+ }
+ sum = s5p_dp_calc_edid_check_sum(&edid[EDID_BLOCK_LENGTH]);
+ if (sum != 0) {
+ dev_err(dp->dev, "EDID bad checksum!\n");
+ return -EIO;
+ }
+
+ retval = s5p_dp_read_byte_from_dpcd(dp,
+ DPCD_ADDR_TEST_REQUEST,
+ &test_vector);
+ if (retval < 0) {
+ dev_err(dp->dev, "DPCD EDID Read failed!\n");
+ return retval;
+ }
+
+ if (test_vector & DPCD_TEST_EDID_READ) {
+ retval = s5p_dp_write_byte_to_dpcd(dp,
+ DPCD_ADDR_TEST_EDID_CHECKSUM,
+ edid[EDID_BLOCK_LENGTH + EDID_CHECKSUM]);
+ if (retval < 0) {
+ dev_err(dp->dev, "DPCD EDID Write failed!\n");
+ return retval;
+ }
+ retval = s5p_dp_write_byte_to_dpcd(dp,
+ DPCD_ADDR_TEST_RESPONSE,
+ DPCD_TEST_EDID_CHECKSUM_WRITE);
+ if (retval < 0) {
+ dev_err(dp->dev, "DPCD EDID checksum failed!\n");
+ return retval;
+ }
+ }
+ } else {
+ dev_info(dp->dev, "EDID data does not include any extensions.\n");
+
+ /* Read EDID data */
+ retval = s5p_dp_read_bytes_from_i2c(dp,
+ I2C_EDID_DEVICE_ADDR,
+ EDID_HEADER_PATTERN,
+ EDID_BLOCK_LENGTH,
+ &edid[EDID_HEADER_PATTERN]);
+ if (retval != 0) {
+ dev_err(dp->dev, "EDID Read failed!\n");
+ return -EIO;
+ }
+ sum = s5p_dp_calc_edid_check_sum(edid);
+ if (sum != 0) {
+ dev_err(dp->dev, "EDID bad checksum!\n");
+ return -EIO;
+ }
+
+ retval = s5p_dp_read_byte_from_dpcd(dp,
+ DPCD_ADDR_TEST_REQUEST,
+ &test_vector);
+ if (retval < 0) {
+ dev_err(dp->dev, "DPCD EDID Read failed!\n");
+ return retval;
+ }
+
+ if (test_vector & DPCD_TEST_EDID_READ) {
+ retval = s5p_dp_write_byte_to_dpcd(dp,
+ DPCD_ADDR_TEST_EDID_CHECKSUM,
+ edid[EDID_CHECKSUM]);
+ if (retval < 0) {
+ dev_err(dp->dev, "DPCD EDID Write failed!\n");
+ return retval;
+ }
+ retval = s5p_dp_write_byte_to_dpcd(dp,
+ DPCD_ADDR_TEST_RESPONSE,
+ DPCD_TEST_EDID_CHECKSUM_WRITE);
+ if (retval < 0) {
+ dev_err(dp->dev, "DPCD EDID checksum failed!\n");
+ return retval;
+ }
+ }
+ }
+
+ dev_err(dp->dev, "EDID Read success!\n");
+ return 0;
+}
+
+static int s5p_dp_handle_edid(struct s5p_dp_device *dp)
+{
+ u8 buf[12];
+ int i;
+ int retval;
+
+ /* Read DPCD DPCD_ADDR_DPCD_REV~RECEIVE_PORT1_CAP_1 */
+ retval = s5p_dp_read_bytes_from_dpcd(dp,
+ DPCD_ADDR_DPCD_REV,
+ 12, buf);
+ if (retval < 0)
+ return retval;
+
+ /* Read EDID */
+ for (i = 0; i < 3; i++) {
+ retval = s5p_dp_read_edid(dp);
+ if (retval == 0)
+ break;
+ }
+
+ return retval;
+}
+
+static int s5p_dp_enable_rx_to_enhanced_mode(struct s5p_dp_device *dp,
+ bool enable)
+{
+ u8 data;
+ int retval;
+
+ retval = s5p_dp_read_byte_from_dpcd(dp,
+ DPCD_ADDR_LANE_COUNT_SET, &data);
+ if (retval < 0)
+ return retval;
+
+ if (enable) {
+ retval = s5p_dp_write_byte_to_dpcd(dp,
+ DPCD_ADDR_LANE_COUNT_SET,
+ DPCD_ENHANCED_FRAME_EN |
+ DPCD_LANE_COUNT_SET(data));
+ } else {
+ retval = s5p_dp_write_byte_to_dpcd(dp,
+ DPCD_ADDR_CONFIGURATION_SET, 0);
+
+ retval = s5p_dp_write_byte_to_dpcd(dp,
+ DPCD_ADDR_LANE_COUNT_SET,
+ DPCD_LANE_COUNT_SET(data));
+ }
+
+ return retval;
+}
+
+void s5p_dp_rx_control(struct s5p_dp_device *dp, bool enable)
+{
+ s5p_dp_write_byte_to_dpcd(dp, DPCD_ADDR_USER_DEFINED1,0);
+ s5p_dp_write_byte_to_dpcd(dp, DPCD_ADDR_USER_DEFINED2,0x90);
+
+ if (enable) {
+ s5p_dp_write_byte_to_dpcd(dp, DPCD_ADDR_USER_DEFINED3,0x84);
+ s5p_dp_write_byte_to_dpcd(dp, DPCD_ADDR_USER_DEFINED3,0x00);
+ } else {
+ s5p_dp_write_byte_to_dpcd(dp, DPCD_ADDR_USER_DEFINED3,0x80);
+ }
+}
+
+static int s5p_dp_is_enhanced_mode_available(struct s5p_dp_device *dp)
+{
+ u8 data;
+ int retval;
+
+ retval = s5p_dp_read_byte_from_dpcd(dp,
+ DPCD_ADDR_MAX_LANE_COUNT, &data);
+ if (retval < 0)
+ return retval;
+
+ return DPCD_ENHANCED_FRAME_CAP(data);
+}
+
+static void s5p_dp_disable_rx_zmux(struct s5p_dp_device *dp)
+{
+ s5p_dp_write_byte_to_dpcd(dp,
+ DPCD_ADDR_USER_DEFINED1, 0);
+ s5p_dp_write_byte_to_dpcd(dp,
+ DPCD_ADDR_USER_DEFINED2, 0x83);
+ s5p_dp_write_byte_to_dpcd(dp,
+ DPCD_ADDR_USER_DEFINED3, 0x27);
+}
+
+static int s5p_dp_set_enhanced_mode(struct s5p_dp_device *dp)
+{
+ u8 data;
+ int retval;
+
+ retval = s5p_dp_is_enhanced_mode_available(dp);
+ if (retval < 0)
+ return retval;
+
+ data = (u8)retval;
+ retval = s5p_dp_enable_rx_to_enhanced_mode(dp, data);
+ if (retval < 0)
+ return retval;
+
+ s5p_dp_enable_enhanced_mode(dp, data);
+
+ return 0;
+}
+
+static int s5p_dp_training_pattern_dis(struct s5p_dp_device *dp)
+{
+ int retval;
+
+ s5p_dp_set_training_pattern(dp, DP_NONE);
+
+ retval = s5p_dp_write_byte_to_dpcd(dp,
+ DPCD_ADDR_TRAINING_PATTERN_SET,
+ DPCD_TRAINING_PATTERN_DISABLED);
+ if (retval < 0)
+ return retval;
+
+ return 0;
+}
+
+static void s5p_dp_set_lane_lane_pre_emphasis(struct s5p_dp_device *dp,
+ int pre_emphasis, int lane)
+{
+ switch (lane) {
+ case 0:
+ s5p_dp_set_lane0_pre_emphasis(dp, pre_emphasis);
+ break;
+ case 1:
+ s5p_dp_set_lane1_pre_emphasis(dp, pre_emphasis);
+ break;
+
+ case 2:
+ s5p_dp_set_lane2_pre_emphasis(dp, pre_emphasis);
+ break;
+
+ case 3:
+ s5p_dp_set_lane3_pre_emphasis(dp, pre_emphasis);
+ break;
+ }
+}
+
+static int s5p_dp_link_start(struct s5p_dp_device *dp)
+{
+ u8 buf[4];
+ int lane;
+ int lane_count;
+ int retval;
+
+ lane_count = dp->link_train.lane_count;
+
+ dp->link_train.lt_state = CLOCK_RECOVERY;
+ dp->link_train.eq_loop = 0;
+
+ for (lane = 0; lane < lane_count; lane++)
+ dp->link_train.cr_loop[lane] = 0;
+
+ /* Set sink to D0 (Sink Not Ready) mode. */
+ retval = s5p_dp_write_byte_to_dpcd(dp, DPCD_ADDR_SINK_POWER_STATE,
+ DPCD_SET_POWER_STATE_D0);
+ if (retval < 0) {
+ dev_err(dp->dev, "failed to set sink device to D0!\n");
+ return retval;
+ }
+
+ /* Set link rate and count as you want to establish*/
+ s5p_dp_set_link_bandwidth(dp, dp->link_train.link_rate);
+ s5p_dp_set_lane_count(dp, dp->link_train.lane_count);
+
+ /* Setup RX configuration */
+ buf[0] = dp->link_train.link_rate;
+ buf[1] = dp->link_train.lane_count;
+ retval = s5p_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_LINK_BW_SET,
+ 2, buf);
+ if (retval < 0) {
+ dev_err(dp->dev, "failed to set bandwidth and lane count!\n");
+ return retval;
+ }
+
+ /* Set TX pre-emphasis to level1 */
+ for (lane = 0; lane < lane_count; lane++)
+ s5p_dp_set_lane_lane_pre_emphasis(dp,
+ PRE_EMPHASIS_LEVEL_1, lane);
+
+ /* Set training pattern 1 */
+ s5p_dp_set_training_pattern(dp, TRAINING_PTN1);
+
+ /* Set RX training pattern */
+ retval = s5p_dp_write_byte_to_dpcd(dp,
+ DPCD_ADDR_TRAINING_PATTERN_SET,
+ DPCD_SCRAMBLING_DISABLED |
+ DPCD_TRAINING_PATTERN_1);
+ if (retval < 0) {
+ dev_err(dp->dev, "failed to set training pattern 1!\n");
+ return retval;
+ }
+
+ for (lane = 0; lane < lane_count; lane++)
+ buf[lane] = DPCD_PRE_EMPHASIS_PATTERN2_LEVEL0 |
+ DPCD_VOLTAGE_SWING_PATTERN1_LEVEL0;
+ retval = s5p_dp_write_bytes_to_dpcd(dp,
+ DPCD_ADDR_TRAINING_LANE0_SET,
+ lane_count, buf);
+ if (retval < 0) {
+ dev_err(dp->dev, "failed to set training lane!\n");
+ return retval;
+ }
+
+ return 0;
+}
+
+static unsigned char s5p_dp_get_lane_status(u8 link_status[2], int lane)
+{
+ int shift = (lane & 1) * 4;
+ u8 link_value = link_status[lane>>1];
+
+ return (link_value >> shift) & 0xf;
+}
+
+static int s5p_dp_clock_recovery_ok(u8 link_status[2], int lane_count)
+{
+ int lane;
+ u8 lane_status;
+
+ for (lane = 0; lane < lane_count; lane++) {
+ lane_status = s5p_dp_get_lane_status(link_status, lane);
+ if ((lane_status & DPCD_LANE_CR_DONE) == 0)
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int s5p_dp_channel_eq_ok(u8 link_align[3], int lane_count)
+{
+ int lane;
+ u8 lane_align;
+ u8 lane_status;
+
+ lane_align = link_align[2];
+ if ((lane_align & DPCD_INTERLANE_ALIGN_DONE) == 0)
+ return -EINVAL;
+
+ for (lane = 0; lane < lane_count; lane++) {
+ lane_status = s5p_dp_get_lane_status(link_align, lane);
+ lane_status &= DPCD_CHANNEL_EQ_BITS;
+ if (lane_status != DPCD_CHANNEL_EQ_BITS)
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static unsigned char s5p_dp_get_adjust_request_voltage(u8 adjust_request[2],
+ int lane)
+{
+ int shift = (lane & 1) * 4;
+ u8 link_value = adjust_request[lane>>1];
+
+ return (link_value >> shift) & 0x3;
+}
+
+static unsigned char s5p_dp_get_adjust_request_pre_emphasis(
+ u8 adjust_request[2],
+ int lane)
+{
+ int shift = (lane & 1) * 4;
+ u8 link_value = adjust_request[lane>>1];
+
+ return ((link_value >> shift) & 0xc) >> 2;
+}
+
+static void s5p_dp_set_lane_link_training(struct s5p_dp_device *dp,
+ u8 training_lane_set, int lane)
+{
+ switch (lane) {
+ case 0:
+ s5p_dp_set_lane0_link_training(dp, training_lane_set);
+ break;
+ case 1:
+ s5p_dp_set_lane1_link_training(dp, training_lane_set);
+ break;
+
+ case 2:
+ s5p_dp_set_lane2_link_training(dp, training_lane_set);
+ break;
+
+ case 3:
+ s5p_dp_set_lane3_link_training(dp, training_lane_set);
+ break;
+ }
+}
+
+static unsigned int s5p_dp_get_lane_link_training(
+ struct s5p_dp_device *dp,
+ int lane)
+{
+ u32 reg;
+
+ switch (lane) {
+ case 0:
+ reg = s5p_dp_get_lane0_link_training(dp);
+ break;
+ case 1:
+ reg = s5p_dp_get_lane1_link_training(dp);
+ break;
+ case 2:
+ reg = s5p_dp_get_lane2_link_training(dp);
+ break;
+ case 3:
+ reg = s5p_dp_get_lane3_link_training(dp);
+ break;
+ }
+
+ return reg;
+}
+
+static void s5p_dp_reduce_link_rate(struct s5p_dp_device *dp)
+{
+ s5p_dp_training_pattern_dis(dp);
+
+ dp->link_train.lt_state = FAILED;
+}
+
+static int s5p_dp_process_clock_recovery(struct s5p_dp_device *dp)
+{
+ u8 link_status[2];
+ int lane;
+ int lane_count;
+
+ u8 adjust_request[2];
+ u8 voltage_swing;
+ u8 pre_emphasis;
+ u8 training_lane;
+ int retval;
+
+ udelay(100);
+
+ lane_count = dp->link_train.lane_count;
+
+ retval = s5p_dp_read_bytes_from_dpcd(dp,
+ DPCD_ADDR_LANE0_1_STATUS,
+ 2, link_status);
+ if (retval < 0) {
+ dev_err(dp->dev, "failed to read lane status!\n");
+ return retval;
+ }
+
+ if (s5p_dp_clock_recovery_ok(link_status, lane_count) == 0) {
+ /* set training pattern 2 for EQ */
+ s5p_dp_set_training_pattern(dp, TRAINING_PTN2);
+
+ for (lane = 0; lane < lane_count; lane++) {
+ retval = s5p_dp_read_bytes_from_dpcd(dp,
+ DPCD_ADDR_ADJUST_REQUEST_LANE0_1,
+ 2, adjust_request);
+ if (retval < 0) {
+ dev_err(dp->dev, "failed to read adjust request!\n");
+ return retval;
+ }
+
+ voltage_swing = s5p_dp_get_adjust_request_voltage(
+ adjust_request, lane);
+ pre_emphasis = s5p_dp_get_adjust_request_pre_emphasis(
+ adjust_request, lane);
+ training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) |
+ DPCD_PRE_EMPHASIS_SET(pre_emphasis);
+
+ if (voltage_swing == VOLTAGE_LEVEL_3)
+ training_lane |= DPCD_MAX_SWING_REACHED;
+ if (pre_emphasis == PRE_EMPHASIS_LEVEL_3)
+ training_lane |= DPCD_MAX_PRE_EMPHASIS_REACHED;
+
+ dp->link_train.training_lane[lane] = training_lane;
+
+ s5p_dp_set_lane_link_training(dp,
+ dp->link_train.training_lane[lane],
+ lane);
+ }
+
+ retval = s5p_dp_write_byte_to_dpcd(dp,
+ DPCD_ADDR_TRAINING_PATTERN_SET,
+ DPCD_SCRAMBLING_DISABLED |
+ DPCD_TRAINING_PATTERN_2);
+ if (retval < 0) {
+ dev_err(dp->dev, "failed to set training pattern 2!\n");
+ return retval;
+ }
+
+ retval = s5p_dp_write_bytes_to_dpcd(dp,
+ DPCD_ADDR_TRAINING_LANE0_SET,
+ lane_count,
+ dp->link_train.training_lane);
+ if (retval < 0) {
+ dev_err(dp->dev, "failed to set training lane!\n");
+ return retval;
+ }
+
+ dev_info(dp->dev, "Link Training Clock Recovery success\n");
+ dp->link_train.lt_state = EQUALIZER_TRAINING;
+ } else {
+ for (lane = 0; lane < lane_count; lane++) {
+ training_lane = s5p_dp_get_lane_link_training(
+ dp, lane);
+ retval = s5p_dp_read_bytes_from_dpcd(dp,
+ DPCD_ADDR_ADJUST_REQUEST_LANE0_1,
+ 2, adjust_request);
+ if (retval < 0) {
+ dev_err(dp->dev, "failed to read adjust request!\n");
+ return retval;
+ }
+
+ voltage_swing = s5p_dp_get_adjust_request_voltage(
+ adjust_request, lane);
+ pre_emphasis = s5p_dp_get_adjust_request_pre_emphasis(
+ adjust_request, lane);
+
+ if (voltage_swing == VOLTAGE_LEVEL_3 ||
+ pre_emphasis == PRE_EMPHASIS_LEVEL_3) {
+ dev_err(dp->dev, "voltage or pre emphasis reached max level\n");
+ goto reduce_link_rate;
+ }
+
+ if ((DPCD_VOLTAGE_SWING_GET(training_lane) ==
+ voltage_swing) &&
+ (DPCD_PRE_EMPHASIS_GET(training_lane) ==
+ pre_emphasis)) {
+ dp->link_train.cr_loop[lane]++;
+ if (dp->link_train.cr_loop[lane] == MAX_CR_LOOP) {
+ dev_err(dp->dev, "CR Max loop\n");
+ goto reduce_link_rate;
+ }
+ }
+
+ training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) |
+ DPCD_PRE_EMPHASIS_SET(pre_emphasis);
+
+ if (voltage_swing == VOLTAGE_LEVEL_3)
+ training_lane |= DPCD_MAX_SWING_REACHED;
+ if (pre_emphasis == PRE_EMPHASIS_LEVEL_3)
+ training_lane |= DPCD_MAX_PRE_EMPHASIS_REACHED;
+
+ dp->link_train.training_lane[lane] = training_lane;
+
+ s5p_dp_set_lane_link_training(dp,
+ dp->link_train.training_lane[lane], lane);
+ }
+
+ retval = s5p_dp_write_bytes_to_dpcd(dp,
+ DPCD_ADDR_TRAINING_LANE0_SET,
+ lane_count,
+ dp->link_train.training_lane);
+ if (retval < 0) {
+ dev_err(dp->dev, "failed to set training lane!\n");
+ return retval;
+ }
+ }
+
+ return 0;
+
+reduce_link_rate:
+ s5p_dp_reduce_link_rate(dp);
+ return -EIO;
+}
+
+static int s5p_dp_process_equalizer_training(struct s5p_dp_device *dp)
+{
+ u8 link_status[2];
+ u8 link_align[3];
+ int lane;
+ int lane_count;
+ u32 reg;
+
+ u8 adjust_request[2];
+ u8 voltage_swing;
+ u8 pre_emphasis;
+ u8 training_lane;
+ int retval;
+
+ udelay(400);
+
+ lane_count = dp->link_train.lane_count;
+
+ retval = s5p_dp_read_bytes_from_dpcd(dp,
+ DPCD_ADDR_LANE0_1_STATUS,
+ 2, link_status);
+ if (retval < 0) {
+ dev_err(dp->dev, "failed to read lane status!\n");
+ return retval;
+ }
+
+ if (s5p_dp_clock_recovery_ok(link_status, lane_count) == 0) {
+ link_align[0] = link_status[0];
+ link_align[1] = link_status[1];
+
+ retval = s5p_dp_read_byte_from_dpcd(dp,
+ DPCD_ADDR_LANE_ALIGN_STATUS_UPDATED,
+ &link_align[2]);
+ if (retval < 0) {
+ dev_err(dp->dev, "failed to read lane aligne status!\n");
+ return retval;
+ }
+
+ for (lane = 0; lane < lane_count; lane++) {
+ retval = s5p_dp_read_bytes_from_dpcd(dp,
+ DPCD_ADDR_ADJUST_REQUEST_LANE0_1,
+ 2, adjust_request);
+ if (retval < 0) {
+ dev_err(dp->dev, "failed to read adjust request!\n");
+ return retval;
+ }
+
+ voltage_swing = s5p_dp_get_adjust_request_voltage(
+ adjust_request, lane);
+ pre_emphasis = s5p_dp_get_adjust_request_pre_emphasis(
+ adjust_request, lane);
+ training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) |
+ DPCD_PRE_EMPHASIS_SET(pre_emphasis);
+
+ if (voltage_swing == VOLTAGE_LEVEL_3)
+ training_lane |= DPCD_MAX_SWING_REACHED;
+ if (pre_emphasis == PRE_EMPHASIS_LEVEL_3)
+ training_lane |= DPCD_MAX_PRE_EMPHASIS_REACHED;
+
+ dp->link_train.training_lane[lane] = training_lane;
+ }
+
+ if (s5p_dp_channel_eq_ok(link_align, lane_count) == 0) {
+ /* traing pattern Set to Normal */
+ retval = s5p_dp_training_pattern_dis(dp);
+ if (retval < 0) {
+ dev_err(dp->dev, "failed to disable training pattern!\n");
+ return retval;
+ }
+
+ dev_info(dp->dev, "Link Training success!\n");
+
+ s5p_dp_get_link_bandwidth(dp, ®);
+ dp->link_train.link_rate = reg;
+ dev_dbg(dp->dev, "final bandwidth = %.2x\n",
+ dp->link_train.link_rate);
+
+ s5p_dp_get_lane_count(dp, ®);
+ dp->link_train.lane_count = reg;
+ dev_dbg(dp->dev, "final lane count = %.2x\n",
+ dp->link_train.lane_count);
+
+ dp->link_train.lt_state = FINISHED;
+ } else {
+ /* not all locked */
+ dp->link_train.eq_loop++;
+
+ if (dp->link_train.eq_loop > MAX_EQ_LOOP) {
+ dev_err(dp->dev, "EQ Max loop\n");
+ goto reduce_link_rate;
+ }
+
+ for (lane = 0; lane < lane_count; lane++)
+ s5p_dp_set_lane_link_training(dp,
+ dp->link_train.training_lane[lane],
+ lane);
+
+ retval = s5p_dp_write_bytes_to_dpcd(dp,
+ DPCD_ADDR_TRAINING_LANE0_SET,
+ lane_count,
+ dp->link_train.training_lane);
+ if (retval < 0) {
+ dev_err(dp->dev, "failed to set training lane!\n");
+ return retval;
+ }
+ }
+ } else {
+ goto reduce_link_rate;
+ }
+
+ return 0;
+
+reduce_link_rate:
+ s5p_dp_reduce_link_rate(dp);
+ return -EIO;
+}
+
+static int s5p_dp_get_max_rx_bandwidth(struct s5p_dp_device *dp,
+ u8 *bandwidth)
+{
+ u8 data;
+ int retval;
+
+ /*
+ * For DP rev.1.1, Maximum link rate of Main Link lanes
+ * 0x06 = 1.62 Gbps, 0x0a = 2.7 Gbps
+ */
+ retval = s5p_dp_read_byte_from_dpcd(dp,
+ DPCD_ADDR_MAX_LINK_RATE, &data);
+ if (retval < 0)
+ return retval;
+
+ *bandwidth = data;
+ return 0;
+}
+
+static int s5p_dp_get_max_rx_lane_count(struct s5p_dp_device *dp,
+ u8 *lane_count)
+{
+ u8 data;
+ int retval;
+
+ /*
+ * For DP rev.1.1, Maximum number of Main Link lanes
+ * 0x01 = 1 lane, 0x02 = 2 lanes, 0x04 = 4 lanes
+ */
+ retval = s5p_dp_read_byte_from_dpcd(dp,
+ DPCD_ADDR_MAX_LANE_COUNT, &data);
+ if (retval < 0)
+ return retval;
+
+ *lane_count = DPCD_MAX_LANE_COUNT(data);
+ return 0;
+}
+
+static int s5p_dp_init_training(struct s5p_dp_device *dp,
+ enum link_lane_count_type max_lane,
+ enum link_rate_type max_rate)
+{
+ int retval;
+
+ /*
+ * MACRO_RST must be applied after the PLL_LOCK to avoid
+ * the DP inter pair skew issue for at least 10 us
+ */
+ s5p_dp_reset_macro(dp);
+
+ /* Initialize by reading RX's DPCD */
+ retval = s5p_dp_get_max_rx_bandwidth(dp, &dp->link_train.link_rate);
+ if (retval < 0)
+ return retval;
+
+ retval = s5p_dp_get_max_rx_lane_count(dp, &dp->link_train.lane_count);
+ if (retval < 0)
+ return retval;
+
+ if ((dp->link_train.link_rate != LINK_RATE_1_62GBPS) &&
+ (dp->link_train.link_rate != LINK_RATE_2_70GBPS)) {
+ dev_err(dp->dev, "Rx Max Link Rate is abnormal :%x !\n",
+ dp->link_train.link_rate);
+ dp->link_train.link_rate = LINK_RATE_1_62GBPS;
+ }
+
+ if (dp->link_train.lane_count == 0) {
+ dev_err(dp->dev, "Rx Max Lane count is abnormal :%x !\n",
+ dp->link_train.lane_count);
+ dp->link_train.lane_count = (u8)LANE_COUNT1;
+ }
+
+ /* Setup TX lane count & rate */
+ if (dp->link_train.lane_count > max_lane)
+ dp->link_train.lane_count = max_lane;
+ if (dp->link_train.link_rate > max_rate)
+ dp->link_train.link_rate = max_rate;
+
+ /* All DP analog module power up */
+ s5p_dp_set_analog_power_down(dp, POWER_ALL, 0);
+
+ return 0;
+}
+
+static int s5p_dp_sw_link_training(struct s5p_dp_device *dp)
+{
+ int retval = 0;
+ int training_finished = 0;
+
+ dp->link_train.lt_state = START;
+
+ /* Process here */
+ while (!training_finished) {
+ switch (dp->link_train.lt_state) {
+ case START:
+ retval = s5p_dp_link_start(dp);
+ if (retval)
+ dev_err(dp->dev, "LT Start failed\n");
+ break;
+ case CLOCK_RECOVERY:
+ retval = s5p_dp_process_clock_recovery(dp);
+ if (retval)
+ dev_err(dp->dev, "LT CR failed\n");
+ break;
+ case EQUALIZER_TRAINING:
+ retval = s5p_dp_process_equalizer_training(dp);
+ if (retval)
+ dev_err(dp->dev, "LT EQ failed\n");
+ break;
+ case FINISHED:
+ training_finished = 1;
+ break;
+ case FAILED:
+ return -EREMOTEIO;
+ }
+ }
+
+ return retval;
+}
+
+static int s5p_dp_set_link_train(struct s5p_dp_device *dp,
+ u32 count,
+ u32 bwtype)
+{
+ int retval;
+
+ retval = s5p_dp_init_training(dp, count, bwtype);
+ if (retval < 0)
+ dev_err(dp->dev, "DP LT init failed!\n");
+
+ retval = s5p_dp_sw_link_training(dp);
+ if (retval < 0)
+ dev_err(dp->dev, "DP LT failed!\n");
+
+ return retval;
+}
+
+static int s5p_dp_config_video(struct s5p_dp_device *dp,
+ struct video_info *video_info)
+{
+ int retval = 0;
+ int timeout_loop = 0;
+ int done_count = 0;
+
+ s5p_dp_config_video_slave_mode(dp, video_info);
+
+ s5p_dp_set_video_color_format(dp, video_info->color_depth,
+ video_info->color_space,
+ video_info->dynamic_range,
+ video_info->ycbcr_coeff);
+
+ if (s5p_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
+ dev_err(dp->dev, "PLL is not locked yet.\n");
+ return -EINVAL;
+ }
+
+ for (;;) {
+ timeout_loop++;
+ if (s5p_dp_is_slave_video_stream_clock_on(dp) == 0)
+ break;
+ if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
+ dev_err(dp->dev, "Timeout of video streamclk ok\n");
+ return -ETIMEDOUT;
+ }
+
+ usleep_range(1, 1);
+ }
+
+ /* Set to use the register calculated M/N video */
+ s5p_dp_set_video_cr_mn(dp, CALCULATED_M, 0, 0);
+
+ /* For video bist, Video timing must be generated by register */
+ s5p_dp_set_video_timing_mode(dp, VIDEO_TIMING_FROM_CAPTURE);
+
+ /* Disable video mute */
+ s5p_dp_enable_video_mute(dp, 0);
+
+ /* Configure video slave mode */
+ s5p_dp_enable_video_master(dp, 0);
+
+ /* Enable video */
+ s5p_dp_start_video(dp);
+
+ timeout_loop = 0;
+
+ for (;;) {
+ timeout_loop++;
+ if (s5p_dp_is_video_stream_on(dp) == 0) {
+ done_count++;
+ if (done_count > 10)
+ break;
+ } else if (done_count) {
+ done_count = 0;
+ }
+ if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
+ dev_err(dp->dev, "Timeout of video streamclk ok\n");
+ return -ETIMEDOUT;
+ }
+
+ usleep_range(1000, 1000);
+ }
+
+ if (retval != 0)
+ dev_err(dp->dev, "Video stream is not detected!\n");
+
+ return retval;
+}
+
+static int s5p_dp_enable_scramble(struct s5p_dp_device *dp, bool enable)
+{
+ u8 data;
+ int retval;
+
+ if (enable) {
+ s5p_dp_enable_scrambling(dp);
+
+ retval = s5p_dp_read_byte_from_dpcd(dp,
+ DPCD_ADDR_TRAINING_PATTERN_SET,
+ &data);
+ if (retval < 0)
+ return retval;
+
+ retval = s5p_dp_write_byte_to_dpcd(dp,
+ DPCD_ADDR_TRAINING_PATTERN_SET,
+ (u8)(data & ~DPCD_SCRAMBLING_DISABLED));
+ if (retval < 0)
+ return retval;
+ } else {
+ s5p_dp_disable_scrambling(dp);
+
+ retval = s5p_dp_read_byte_from_dpcd(dp,
+ DPCD_ADDR_TRAINING_PATTERN_SET,
+ &data);
+ if (retval < 0)
+ return retval;
+
+ retval = s5p_dp_write_byte_to_dpcd(dp,
+ DPCD_ADDR_TRAINING_PATTERN_SET,
+ (u8)(data | DPCD_SCRAMBLING_DISABLED));
+ if (retval < 0)
+ return retval;
+ }
+
+ return 0;
+}
+
+static irqreturn_t s5p_dp_irq_handler(int irq, void *arg)
+{
+ struct s5p_dp_device *dp = arg;
+
+ dev_err(dp->dev, "s5p_dp_irq_handler\n");
+ return IRQ_HANDLED;
+}
+
+static int s5p_dp_enable(struct s5p_dp_device *dp)
+{
+ int ret = 0;
+ int retry = 0;
+ struct s5p_dp_platdata *pdata = dp->dev->platform_data;
+
+ mutex_lock(&dp->lock);
+
+ if (dp->enabled)
+ goto out;
+
+ dp->enabled = 1;
+
+ clk_enable(dp->clock);
+ pm_runtime_get_sync(dp->dev);
+
+dp_phy_init:
+
+ if (pdata->phy_init)
+ pdata->phy_init();
+
+ s5p_dp_init_dp(dp);
+
+ if (!soc_is_exynos5250()) {
+ ret = s5p_dp_detect_hpd(dp);
+ if (ret) {
+ dev_err(dp->dev, "unable to detect hpd\n");
+ goto out;
+ }
+ }
+
+ ret = s5p_dp_handle_edid(dp);
+ if (ret) {
+ dev_err(dp->dev, "unable to handle edid\n");
+ goto out;
+ }
+
+ s5p_dp_disable_rx_zmux(dp);
+
+ /* Non-enhance mode setting */
+ ret = s5p_dp_enable_scramble(dp, 0);
+ if (ret) {
+ dev_err(dp->dev, "unable to set scramble\n");
+ goto out;
+ }
+
+ ret = s5p_dp_enable_rx_to_enhanced_mode(dp, 0);
+ if (ret) {
+ dev_err(dp->dev, "unable to set enhanced mode\n");
+ goto out;
+ }
+ s5p_dp_enable_enhanced_mode(dp, 0);
+
+ /* Rx data disable */
+ s5p_dp_rx_control(dp,0);
+
+ /* Link Training */
+ ret = s5p_dp_set_link_train(dp, dp->video_info->lane_count,
+ dp->video_info->link_rate);
+ if (ret) {
+ dev_err(dp->dev, "unable to do link train\n");
+ goto out;
+ }
+
+ /* Rx data enable */
+ s5p_dp_rx_control(dp,1);
+
+ s5p_dp_set_lane_count(dp, dp->video_info->lane_count);
+ s5p_dp_set_link_bandwidth(dp, dp->video_info->link_rate);
+
+ s5p_dp_init_video(dp);
+ ret = s5p_dp_config_video(dp, dp->video_info);
+ if (ret) {
+ dev_err(dp->dev, "unable to config video\n");
+ goto out;
+ }
+
+ if (pdata->backlight_on)
+ pdata->backlight_on();
+
+ mutex_unlock(&dp->lock);
+ return 0;
+
+out:
+ if (pdata->phy_exit)
+ pdata->phy_exit();
+
+ if (retry < 3) {
+ if (pdata->lcd_off)
+ pdata->lcd_off();
+
+ if (pdata->lcd_on)
+ pdata->lcd_on();
+
+ retry++;
+ goto dp_phy_init;
+ }
+ dev_err(dp->dev, "DP LT exceeds max retry count");
+
+ mutex_unlock(&dp->lock);
+ return ret;
+}
+
+static void s5p_dp_disable(struct s5p_dp_device *dp)
+{
+ struct s5p_dp_platdata *pdata = dp->dev->platform_data;
+
+ mutex_lock(&dp->lock);
+
+ if (!dp->enabled)
+ goto out;
+
+ dp->enabled = 0;
+
+ s5p_dp_reset(dp);
+ s5p_dp_set_pll_power_down(dp, 1);
+ s5p_dp_set_analog_power_down(dp, POWER_ALL, 1);
+
+ if (pdata && pdata->phy_exit)
+ pdata->phy_exit();
+
+ clk_disable(dp->clock);
+ pm_runtime_put_sync(dp->dev);
+
+out:
+ mutex_unlock(&dp->lock);
+}
+
+static int s5p_dp_set_power(struct lcd_device *lcd, int power)
+{
+ struct s5p_dp_device *dp = lcd_get_data(lcd);
+ int retval;
+
+ if (power == FB_BLANK_UNBLANK) {
+ retval = s5p_dp_enable(dp);
+ if (retval < 0)
+ return retval;
+ } else {
+ s5p_dp_disable(dp);
+ }
+
+ return 0;
+}
+
+struct lcd_ops s5p_dp_lcd_ops = {
+ .set_power = s5p_dp_set_power,
+};
+
+static int __devinit s5p_dp_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct s5p_dp_device *dp;
+ struct s5p_dp_platdata *pdata;
+
+ int ret = 0;
+
+ pdata = pdev->dev.platform_data;
+ if (!pdata) {
+ dev_err(&pdev->dev, "no platform data\n");
+ return -EINVAL;
+ }
+
+ dp = kzalloc(sizeof(struct s5p_dp_device), GFP_KERNEL);
+ if (!dp) {
+ dev_err(&pdev->dev, "no memory for device data\n");
+ return -ENOMEM;
+ }
+
+ mutex_init(&dp->lock);
+
+ dp->dev = &pdev->dev;
+
+ dp->clock = clk_get(&pdev->dev, "dp");
+ if (IS_ERR(dp->clock)) {
+ dev_err(&pdev->dev, "failed to get clock\n");
+ ret = PTR_ERR(dp->clock);
+ goto err_dp;
+ }
+
+ pm_runtime_enable(dp->dev);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "failed to get registers\n");
+ ret = -EINVAL;
+ goto err_clock;
+ }
+
+ res = request_mem_region(res->start, resource_size(res),
+ dev_name(&pdev->dev));
+ if (!res) {
+ dev_err(&pdev->dev, "failed to request registers region\n");
+ ret = -EINVAL;
+ goto err_clock;
+ }
+
+ dp->res = res;
+
+ dp->reg_base = ioremap(res->start, resource_size(res));
+ if (!dp->reg_base) {
+ dev_err(&pdev->dev, "failed to ioremap\n");
+ ret = -ENOMEM;
+ goto err_req_region;
+ }
+
+ dp->irq = platform_get_irq(pdev, 0);
+ if (!dp->irq) {
+ dev_err(&pdev->dev, "failed to get irq\n");
+ ret = -ENODEV;
+ goto err_ioremap;
+ }
+
+ ret = request_irq(dp->irq, s5p_dp_irq_handler, 0,
+ "s5p-dp", dp);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to request irq\n");
+ goto err_ioremap;
+ }
+
+ dp->video_info = pdata->video_info;
+
+ platform_set_drvdata(pdev, dp);
+
+ dp->lcd = lcd_device_register("s5p_dp", &pdev->dev, dp, &s5p_dp_lcd_ops);
+ if (IS_ERR(dp->lcd)) {
+ ret = PTR_ERR(dp->lcd);
+ goto err_irq;
+ }
+
+ ret = s5p_dp_enable(dp);
+ if (ret)
+ goto err_fb;
+
+ return 0;
+
+err_fb:
+ lcd_device_unregister(dp->lcd);
+err_irq:
+ free_irq(dp->irq, dp);
+err_ioremap:
+ iounmap(dp->reg_base);
+err_req_region:
+ release_mem_region(res->start, resource_size(res));
+err_clock:
+ clk_put(dp->clock);
+err_dp:
+ mutex_destroy(&dp->lock);
+ kfree(dp);
+
+ return ret;
+}
+
+static int __devexit s5p_dp_remove(struct platform_device *pdev)
+{
+ struct s5p_dp_device *dp = platform_get_drvdata(pdev);
+
+ free_irq(dp->irq, dp);
+
+ lcd_device_unregister(dp->lcd);
+
+ s5p_dp_disable(dp);
+
+ iounmap(dp->reg_base);
+ clk_put(dp->clock);
+
+ release_mem_region(dp->res->start, resource_size(dp->res));
+
+ pm_runtime_disable(dp->dev);
+
+ kfree(dp);
+
+ return 0;
+}
+
+static int s5p_dp_shutdown(struct platform_device *pdev)
+{
+ struct s5p_dp_device *dp = platform_get_drvdata(pdev);
+ struct s5p_dp_platdata *pdata = dp->dev->platform_data;
+
+ lcd_device_unregister(dp->lcd);
+
+ if (pdata->backlight_off)
+ pdata->backlight_off();
+
+ if (pdata->lcd_off)
+ pdata->lcd_off();
+
+ s5p_dp_disable(dp);
+
+ free_irq(dp->irq, dp);
+ iounmap(dp->reg_base);
+ clk_put(dp->clock);
+
+ release_mem_region(dp->res->start, resource_size(dp->res));
+
+ pm_runtime_disable(dp->dev);
+
+ kfree(dp);
+
+ return 0;
+}
+
+static struct platform_driver s5p_dp_driver = {
+ .probe = s5p_dp_probe,
+ .remove = __devexit_p(s5p_dp_remove),
+ .shutdown = s5p_dp_shutdown,
+ .driver = {
+ .name = "s5p-dp",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init s5p_dp_init(void)
+{
+ return platform_driver_probe(&s5p_dp_driver, s5p_dp_probe);
+}
+
+static void __exit s5p_dp_exit(void)
+{
+ platform_driver_unregister(&s5p_dp_driver);
+}
+
+#ifdef CONFIG_FB_EXYNOS_FIMD_MC
+late_initcall(s5p_dp_init);
+#else
+module_init(s5p_dp_init);
+#endif
+module_exit(s5p_dp_exit);
+
+MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>");
+MODULE_DESCRIPTION("Samsung SoC DP Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/s5p-dp-core.h b/drivers/video/s5p-dp-core.h
new file mode 100644
index 0000000..3cddd49
--- /dev/null
+++ b/drivers/video/s5p-dp-core.h
@@ -0,0 +1,215 @@
+/*
+ * Header file for Samsung DP (Display Port) interface driver.
+ *
+ * Copyright (C) 2012 Samsung Electronics Co., Ltd.
+ * Author: Jingoo Han <jg1.han@samsung.com>
+ *
+ * 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.
+ */
+
+#ifndef _S5P_DP_CORE_H
+#define _S5P_DP_CORE_H
+
+#include <linux/lcd.h>
+
+struct link_train {
+ int eq_loop;
+ int cr_loop[4];
+
+ u8 link_rate;
+ u8 lane_count;
+ u8 training_lane[4];
+
+ enum link_training_state lt_state;
+};
+
+struct s5p_dp_device {
+ struct device *dev;
+ struct resource *res;
+ struct clk *clock;
+ unsigned int irq;
+ void __iomem *reg_base;
+ int enabled;
+ bool user_disabled;
+ struct mutex lock;
+
+ struct video_info *video_info;
+ struct link_train link_train;
+
+ struct lcd_device *lcd;
+};
+
+/* s5p_dp_reg.c */
+void s5p_dp_enable_video_mute(struct s5p_dp_device *dp, bool enable);
+void s5p_dp_stop_video(struct s5p_dp_device *dp);
+void s5p_dp_lane_swap(struct s5p_dp_device *dp, bool enable);
+void s5p_dp_init_analog_param(struct s5p_dp_device *dp);
+void s5p_dp_init_interrupt(struct s5p_dp_device *dp);
+void s5p_dp_reset(struct s5p_dp_device *dp);
+void s5p_dp_config_interrupt(struct s5p_dp_device *dp);
+u32 s5p_dp_get_pll_lock_status(struct s5p_dp_device *dp);
+void s5p_dp_set_pll_power_down(struct s5p_dp_device *dp, bool enable);
+void s5p_dp_set_analog_power_down(struct s5p_dp_device *dp,
+ enum analog_power_block block,
+ bool enable);
+void s5p_dp_init_analog_func(struct s5p_dp_device *dp);
+void s5p_dp_init_hpd(struct s5p_dp_device *dp);
+void s5p_dp_reset_aux(struct s5p_dp_device *dp);
+void s5p_dp_init_aux(struct s5p_dp_device *dp);
+int s5p_dp_get_plug_in_status(struct s5p_dp_device *dp);
+void s5p_dp_enable_sw_function(struct s5p_dp_device *dp);
+int s5p_dp_start_aux_transaction(struct s5p_dp_device *dp);
+int s5p_dp_write_byte_to_dpcd(struct s5p_dp_device *dp,
+ unsigned int reg_addr,
+ unsigned char data);
+int s5p_dp_read_byte_from_dpcd(struct s5p_dp_device *dp,
+ unsigned int reg_addr,
+ unsigned char *data);
+int s5p_dp_write_bytes_to_dpcd(struct s5p_dp_device *dp,
+ unsigned int reg_addr,
+ unsigned int count,
+ unsigned char data[]);
+int s5p_dp_read_bytes_from_dpcd(struct s5p_dp_device *dp,
+ unsigned int reg_addr,
+ unsigned int count,
+ unsigned char data[]);
+int s5p_dp_select_i2c_device(struct s5p_dp_device *dp,
+ unsigned int device_addr,
+ unsigned int reg_addr);
+int s5p_dp_read_byte_from_i2c(struct s5p_dp_device *dp,
+ unsigned int device_addr,
+ unsigned int reg_addr,
+ unsigned int *data);
+int s5p_dp_read_bytes_from_i2c(struct s5p_dp_device *dp,
+ unsigned int device_addr,
+ unsigned int reg_addr,
+ unsigned int count,
+ unsigned char edid[]);
+void s5p_dp_set_link_bandwidth(struct s5p_dp_device *dp, u32 bwtype);
+void s5p_dp_get_link_bandwidth(struct s5p_dp_device *dp, u32 *bwtype);
+void s5p_dp_set_lane_count(struct s5p_dp_device *dp, u32 count);
+void s5p_dp_get_lane_count(struct s5p_dp_device *dp, u32 *count);
+void s5p_dp_enable_enhanced_mode(struct s5p_dp_device *dp, bool enable);
+void s5p_dp_set_training_pattern(struct s5p_dp_device *dp,
+ enum pattern_set pattern);
+void s5p_dp_set_lane0_pre_emphasis(struct s5p_dp_device *dp, u32 level);
+void s5p_dp_set_lane1_pre_emphasis(struct s5p_dp_device *dp, u32 level);
+void s5p_dp_set_lane2_pre_emphasis(struct s5p_dp_device *dp, u32 level);
+void s5p_dp_set_lane3_pre_emphasis(struct s5p_dp_device *dp, u32 level);
+void s5p_dp_set_lane0_link_training(struct s5p_dp_device *dp,
+ u32 training_lane);
+void s5p_dp_set_lane1_link_training(struct s5p_dp_device *dp,
+ u32 training_lane);
+void s5p_dp_set_lane2_link_training(struct s5p_dp_device *dp,
+ u32 training_lane);
+void s5p_dp_set_lane3_link_training(struct s5p_dp_device *dp,
+ u32 training_lane);
+u32 s5p_dp_get_lane0_link_training(struct s5p_dp_device *dp);
+u32 s5p_dp_get_lane1_link_training(struct s5p_dp_device *dp);
+u32 s5p_dp_get_lane2_link_training(struct s5p_dp_device *dp);
+u32 s5p_dp_get_lane3_link_training(struct s5p_dp_device *dp);
+void s5p_dp_reset_macro(struct s5p_dp_device *dp);
+int s5p_dp_init_video(struct s5p_dp_device *dp);
+
+void s5p_dp_set_video_color_format(struct s5p_dp_device *dp,
+ u32 color_depth,
+ u32 color_space,
+ u32 dynamic_range,
+ u32 coeff);
+int s5p_dp_is_slave_video_stream_clock_on(struct s5p_dp_device *dp);
+void s5p_dp_set_video_cr_mn(struct s5p_dp_device *dp,
+ enum clock_recovery_m_value_type type,
+ u32 m_value,
+ u32 n_value);
+void s5p_dp_set_video_timing_mode(struct s5p_dp_device *dp, u32 type);
+void s5p_dp_enable_video_master(struct s5p_dp_device *dp, bool enable);
+void s5p_dp_start_video(struct s5p_dp_device *dp);
+int s5p_dp_is_video_stream_on(struct s5p_dp_device *dp);
+void s5p_dp_config_video_slave_mode(struct s5p_dp_device *dp,
+ struct video_info *video_info);
+void s5p_dp_enable_scrambling(struct s5p_dp_device *dp);
+void s5p_dp_disable_scrambling(struct s5p_dp_device *dp);
+void s5p_dp_rx_control(struct s5p_dp_device *dp, bool enable);
+
+/* I2C EDID Chip ID, Slave Address */
+#define I2C_EDID_DEVICE_ADDR 0x50
+#define I2C_E_EDID_DEVICE_ADDR 0x30
+
+#define EDID_BLOCK_LENGTH 0x80
+#define EDID_HEADER_PATTERN 0x00
+#define EDID_EXTENSION_FLAG 0x7e
+#define EDID_CHECKSUM 0x7f
+
+/* Definition for DPCD Register */
+#define DPCD_ADDR_DPCD_REV 0x0000
+#define DPCD_ADDR_MAX_LINK_RATE 0x0001
+#define DPCD_ADDR_MAX_LANE_COUNT 0x0002
+#define DPCD_ADDR_LINK_BW_SET 0x0100
+#define DPCD_ADDR_LANE_COUNT_SET 0x0101
+#define DPCD_ADDR_TRAINING_PATTERN_SET 0x0102
+#define DPCD_ADDR_TRAINING_LANE0_SET 0x0103
+#define DPCD_ADDR_CONFIGURATION_SET 0x010a
+#define DPCD_ADDR_LANE0_1_STATUS 0x0202
+#define DPCD_ADDR_LANE_ALIGN_STATUS_UPDATED 0x0204
+#define DPCD_ADDR_ADJUST_REQUEST_LANE0_1 0x0206
+#define DPCD_ADDR_ADJUST_REQUEST_LANE2_3 0x0207
+#define DPCD_ADDR_TEST_REQUEST 0x0218
+#define DPCD_ADDR_TEST_RESPONSE 0x0260
+#define DPCD_ADDR_TEST_EDID_CHECKSUM 0x0261
+#define DPCD_ADDR_USER_DEFINED1 0x0491
+#define DPCD_ADDR_USER_DEFINED2 0x0492
+#define DPCD_ADDR_USER_DEFINED3 0x0493
+#define DPCD_ADDR_SINK_POWER_STATE 0x0600
+
+/* DPCD_ADDR_MAX_LANE_COUNT */
+#define DPCD_ENHANCED_FRAME_CAP(x) (((x) >> 7) & 0x1)
+#define DPCD_MAX_LANE_COUNT(x) ((x) & 0x1f)
+
+/* DPCD_ADDR_LANE_COUNT_SET */
+#define DPCD_ENHANCED_FRAME_EN (0x1 << 7)
+#define DPCD_LANE_COUNT_SET(x) ((x) & 0x1f)
+
+/* DPCD_ADDR_TRAINING_PATTERN_SET */
+#define DPCD_SCRAMBLING_DISABLED (0x1 << 5)
+#define DPCD_SCRAMBLING_ENABLED (0x0 << 5)
+#define DPCD_TRAINING_PATTERN_2 (0x2 << 0)
+#define DPCD_TRAINING_PATTERN_1 (0x1 << 0)
+#define DPCD_TRAINING_PATTERN_DISABLED (0x0 << 0)
+
+/* DPCD_ADDR_TRAINING_LANE0_SET */
+#define DPCD_MAX_PRE_EMPHASIS_REACHED (0x1 << 5)
+#define DPCD_PRE_EMPHASIS_SET(x) (((x) & 0x3) << 3)
+#define DPCD_PRE_EMPHASIS_GET(x) (((x) >> 3) & 0x3)
+#define DPCD_PRE_EMPHASIS_PATTERN2_LEVEL0 (0x0 << 3)
+#define DPCD_MAX_SWING_REACHED (0x1 << 2)
+#define DPCD_VOLTAGE_SWING_SET(x) (((x) & 0x3) << 0)
+#define DPCD_VOLTAGE_SWING_GET(x) (((x) >> 0) & 0x3)
+#define DPCD_VOLTAGE_SWING_PATTERN1_LEVEL0 (0x0 << 0)
+
+/* DPCD_ADDR_LANE0_1_STATUS */
+#define DPCD_LANE_SYMBOL_LOCKED (0x1 << 2)
+#define DPCD_LANE_CHANNEL_EQ_DONE (0x1 << 1)
+#define DPCD_LANE_CR_DONE (0x1 << 0)
+#define DPCD_CHANNEL_EQ_BITS (DPCD_LANE_CR_DONE| \
+ DPCD_LANE_CHANNEL_EQ_DONE|\
+ DPCD_LANE_SYMBOL_LOCKED)
+
+/* DPCD_ADDR_LANE_ALIGN__STATUS_UPDATED */
+#define DPCD_LINK_STATUS_UPDATED (0x1 << 7)
+#define DPCD_DOWNSTREAM_PORT_STATUS_CHANGED (0x1 << 6)
+#define DPCD_INTERLANE_ALIGN_DONE (0x1 << 0)
+
+/* DPCD_ADDR_TEST_REQUEST */
+#define DPCD_TEST_EDID_READ (0x1 << 2)
+
+/* DPCD_ADDR_TEST_RESPONSE */
+#define DPCD_TEST_EDID_CHECKSUM_WRITE (0x1 << 2)
+
+/* DPCD_ADDR_SINK_POWER_STATE */
+#define DPCD_SET_POWER_STATE_D0 (0x1 << 0)
+#define DPCD_SET_POWER_STATE_D4 (0x2 << 0)
+
+#endif /* _S5P_DP_CORE_H */
diff --git a/drivers/video/s5p-dp-reg.c b/drivers/video/s5p-dp-reg.c
new file mode 100644
index 0000000..6af5c51
--- /dev/null
+++ b/drivers/video/s5p-dp-reg.c
@@ -0,0 +1,1262 @@
+/*
+ * Samsung DP (Display port) register interface driver.
+ *
+ * Copyright (C) 2012 Samsung Electronics Co., Ltd.
+ * Author: Jingoo Han <jg1.han@samsung.com>
+ *
+ * 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.
+ */
+
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+
+#include <video/s5p-dp.h>
+
+#include <plat/cpu.h>
+
+#include "s5p-dp-core.h"
+#include "s5p-dp-reg.h"
+
+#define COMMON_INT_MASK_1 (0)
+#define COMMON_INT_MASK_2 (0)
+#define COMMON_INT_MASK_3 (0)
+#define COMMON_INT_MASK_4 (0)
+#define INT_STA_MASK (0)
+
+void s5p_dp_enable_video_mute(struct s5p_dp_device *dp, bool enable)
+{
+ u32 reg;
+
+ if (enable) {
+ reg = readl(dp->reg_base + S5P_DP_VIDEO_CTL_1);
+ reg |= HDCP_VIDEO_MUTE;
+ writel(reg, dp->reg_base + S5P_DP_VIDEO_CTL_1);
+ } else {
+ reg = readl(dp->reg_base + S5P_DP_VIDEO_CTL_1);
+ reg &= ~HDCP_VIDEO_MUTE;
+ writel(reg, dp->reg_base + S5P_DP_VIDEO_CTL_1);
+ }
+}
+
+void s5p_dp_stop_video(struct s5p_dp_device *dp)
+{
+ u32 reg;
+
+ reg = readl(dp->reg_base + S5P_DP_VIDEO_CTL_1);
+ reg &= ~VIDEO_EN;
+ writel(reg, dp->reg_base + S5P_DP_VIDEO_CTL_1);
+}
+
+void s5p_dp_lane_swap(struct s5p_dp_device *dp, bool enable)
+{
+ u32 reg;
+
+ if (soc_is_exynos5250()) {
+ if (enable)
+ reg = LANE3_MAP_LOGIC_LANE_0 | LANE2_MAP_LOGIC_LANE_1 |
+ LANE1_MAP_LOGIC_LANE_2 | LANE0_MAP_LOGIC_LANE_3;
+ else
+ reg = LANE3_MAP_LOGIC_LANE_3 | LANE2_MAP_LOGIC_LANE_2 |
+ LANE1_MAP_LOGIC_LANE_1 | LANE0_MAP_LOGIC_LANE_0;
+ } else {
+ if (enable)
+ reg = LANE1_MAP_LOGIC_LANE_0 | LANE0_MAP_LOGIC_LANE_1;
+ else
+ reg = LANE1_MAP_LOGIC_LANE_1 | LANE0_MAP_LOGIC_LANE_0;
+ }
+
+ writel(reg, dp->reg_base + S5P_DP_LANE_MAP);
+}
+
+void s5p_dp_init_analog_param(struct s5p_dp_device *dp)
+{
+ u32 reg;
+ struct s5p_dp_platdata *pdata = dp->dev->platform_data;
+ struct analog_param *analog_param = pdata->analog_param;
+
+ reg = TX_TERMINAL_CTRL_50_OHM;
+ writel(reg, dp->reg_base + S5P_DP_ANALOG_CTL_1);
+
+ reg = SEL_24M | TX_DVDD_BIT_1_0625V;
+ writel(reg, dp->reg_base + S5P_DP_ANALOG_CTL_2);
+
+ reg = DRIVE_DVDD_BIT_1_0625V | VCO_BIT_600_MICRO;
+ writel(reg, dp->reg_base + S5P_DP_ANALOG_CTL_3);
+
+ if (!analog_param) {
+ reg = PD_RING_OSC | AUX_TERMINAL_CTRL_50_OHM |
+ TX_CUR1_2X | TX_CUR_16_MA;
+ writel(reg, dp->reg_base + S5P_DP_PLL_FILTER_CTL_1);
+
+ reg = CH3_AMP_400_MV | CH2_AMP_400_MV |
+ CH1_AMP_400_MV | CH0_AMP_400_MV;
+ writel(reg, dp->reg_base + S5P_DP_TX_AMP_TUNING_CTL);
+ } else {
+ int tx_amp;
+
+ reg = PD_RING_OSC | TX_CUR1_2X | TX_CUR_16_MA;
+ switch (analog_param->aux_tx_terminal_resistor) {
+ case AUX_TX_37_5_OHM:
+ reg |= AUX_TERMINAL_CTRL_37_5_OHM;
+ break;
+ case AUX_TX_45_OHM:
+ reg |= AUX_TERMINAL_CTRL_45_OHM;
+ break;
+ case AUX_TX_50_OHM:
+ reg |= AUX_TERMINAL_CTRL_50_OHM;
+ break;
+ case AUX_TX_65_OHM:
+ reg |= AUX_TERMINAL_CTRL_65_OHM;
+ break;
+ }
+ writel(reg, dp->reg_base + S5P_DP_PLL_FILTER_CTL_1);
+
+ tx_amp = analog_param->tx_amplitude;
+ if (tx_amp < 200000 || tx_amp > 500000) {
+ dev_warn(dp->dev,
+ "TX amp out of range, defaulting to 400mV\n");
+ tx_amp = 400000;
+ }
+
+ tx_amp = ((tx_amp - 400000) / 12500) & 0x1f;
+
+ reg = (tx_amp << CH3_AMP_SHIFT) | (tx_amp << CH2_AMP_SHIFT) |
+ (tx_amp << CH1_AMP_SHIFT) | (tx_amp << CH0_AMP_SHIFT);
+ writel(reg, dp->reg_base + S5P_DP_TX_AMP_TUNING_CTL);
+ }
+}
+
+void s5p_dp_init_interrupt(struct s5p_dp_device *dp)
+{
+ /* Set interrupt pin assertion polarity as high */
+ writel(INT_POL, dp->reg_base + S5P_DP_INT_CTL);
+
+ /* Clear pending regisers */
+ writel(0xff, dp->reg_base + S5P_DP_COMMON_INT_STA_1);
+ writel(0x4f, dp->reg_base + S5P_DP_COMMON_INT_STA_2);
+ writel(0xe0, dp->reg_base + S5P_DP_COMMON_INT_STA_3);
+ if (soc_is_exynos5250())
+ writel(0xe7, dp->reg_base + S5P_DP_COMMON_INT_STA_4);
+ else
+ writel(0x27, dp->reg_base + S5P_DP_COMMON_INT_STA_4);
+ writel(0x63, dp->reg_base + S5P_DP_INT_STA);
+
+ /* 0:mask,1: unmask */
+ writel(0x00, dp->reg_base + S5P_DP_COMMON_INT_MASK_1);
+ writel(0x00, dp->reg_base + S5P_DP_COMMON_INT_MASK_2);
+ writel(0x00, dp->reg_base + S5P_DP_COMMON_INT_MASK_3);
+ writel(0x00, dp->reg_base + S5P_DP_COMMON_INT_MASK_4);
+ writel(0x00, dp->reg_base + S5P_DP_INT_STA_MASK);
+}
+
+void s5p_dp_reset(struct s5p_dp_device *dp)
+{
+ u32 reg;
+
+ writel(RESET_DP_TX, dp->reg_base + S5P_DP_TX_SW_RESET);
+
+ s5p_dp_stop_video(dp);
+ s5p_dp_enable_video_mute(dp, 0);
+
+ reg = MASTER_VID_FUNC_EN_N | SLAVE_VID_FUNC_EN_N |
+ AUD_FIFO_FUNC_EN_N | AUD_FUNC_EN_N |
+ HDCP_FUNC_EN_N | SW_FUNC_EN_N;
+ writel(reg, dp->reg_base + S5P_DP_FUNC_EN_1);
+
+ reg = SSC_FUNC_EN_N | AUX_FUNC_EN_N |
+ SERDES_FIFO_FUNC_EN_N |
+ LS_CLK_DOMAIN_FUNC_EN_N;
+ writel(reg, dp->reg_base + S5P_DP_FUNC_EN_2);
+
+ udelay(20);
+
+ s5p_dp_lane_swap(dp, 0);
+
+ writel(0x0, dp->reg_base + S5P_DP_SYS_CTL_1);
+ writel(0x40, dp->reg_base + S5P_DP_SYS_CTL_2);
+ writel(0x0, dp->reg_base + S5P_DP_SYS_CTL_3);
+ writel(0x0, dp->reg_base + S5P_DP_SYS_CTL_4);
+
+ writel(0x0, dp->reg_base + S5P_DP_PKT_SEND_CTL);
+ writel(0x0, dp->reg_base + S5P_DP_HDCP_CTL);
+
+ writel(0x5e, dp->reg_base + S5P_DP_HPD_DEGLITCH_L);
+ writel(0x1a, dp->reg_base + S5P_DP_HPD_DEGLITCH_H);
+
+ writel(0x10, dp->reg_base + S5P_DP_LINK_DEBUG_CTL);
+
+ writel(0x0, dp->reg_base + S5P_DP_PHY_TEST);
+
+ writel(0x0, dp->reg_base + S5P_DP_VIDEO_FIFO_THRD);
+ writel(0x20, dp->reg_base + S5P_DP_AUDIO_MARGIN);
+
+ writel(0x4, dp->reg_base + S5P_DP_M_VID_GEN_FILTER_TH);
+ writel(0x2, dp->reg_base + S5P_DP_M_AUD_GEN_FILTER_TH);
+
+ writel(0x00000101, dp->reg_base + S5P_DP_SOC_GENERAL_CTL);
+
+ s5p_dp_init_analog_param(dp);
+ s5p_dp_init_interrupt(dp);
+}
+
+void s5p_dp_config_interrupt(struct s5p_dp_device *dp)
+{
+ u32 reg;
+
+ /* 0: mask, 1: unmask */
+ reg = COMMON_INT_MASK_1;
+ writel(reg, dp->reg_base + S5P_DP_COMMON_INT_MASK_1);
+
+ reg = COMMON_INT_MASK_2;
+ writel(reg, dp->reg_base + S5P_DP_COMMON_INT_MASK_2);
+
+ reg = COMMON_INT_MASK_3;
+ writel(reg, dp->reg_base + S5P_DP_COMMON_INT_MASK_3);
+
+ reg = COMMON_INT_MASK_4;
+ writel(reg, dp->reg_base + S5P_DP_COMMON_INT_MASK_4);
+
+ reg = INT_STA_MASK;
+ writel(reg, dp->reg_base + S5P_DP_INT_STA_MASK);
+}
+
+u32 s5p_dp_get_pll_lock_status(struct s5p_dp_device *dp)
+{
+ u32 reg;
+
+ reg = readl(dp->reg_base + S5P_DP_DEBUG_CTL);
+ if (reg & PLL_LOCK)
+ return PLL_LOCKED;
+ else
+ return PLL_UNLOCKED;
+}
+
+void s5p_dp_set_pll_power_down(struct s5p_dp_device *dp, bool enable)
+{
+ u32 reg;
+
+ if (enable) {
+ reg = readl(dp->reg_base + S5P_DP_PLL_CTL);
+ reg |= DP_PLL_PD;
+ writel(reg, dp->reg_base + S5P_DP_PLL_CTL);
+ } else {
+ reg = readl(dp->reg_base + S5P_DP_PLL_CTL);
+ reg &= ~DP_PLL_PD;
+ writel(reg, dp->reg_base + S5P_DP_PLL_CTL);
+ }
+}
+
+void s5p_dp_set_analog_power_down(struct s5p_dp_device *dp,
+ enum analog_power_block block,
+ bool enable)
+{
+ u32 reg;
+
+ switch (block) {
+ case AUX_BLOCK:
+ if (enable) {
+ reg = readl(dp->reg_base + S5P_DP_PHY_PD);
+ reg |= AUX_PD;
+ writel(reg, dp->reg_base + S5P_DP_PHY_PD);
+ } else {
+ reg = readl(dp->reg_base + S5P_DP_PHY_PD);
+ reg &= ~AUX_PD;
+ writel(reg, dp->reg_base + S5P_DP_PHY_PD);
+ }
+ break;
+ case CH0_BLOCK:
+ if (enable) {
+ reg = readl(dp->reg_base + S5P_DP_PHY_PD);
+ reg |= CH0_PD;
+ writel(reg, dp->reg_base + S5P_DP_PHY_PD);
+ } else {
+ reg = readl(dp->reg_base + S5P_DP_PHY_PD);
+ reg &= ~CH0_PD;
+ writel(reg, dp->reg_base + S5P_DP_PHY_PD);
+ }
+ break;
+ case CH1_BLOCK:
+ if (enable) {
+ reg = readl(dp->reg_base + S5P_DP_PHY_PD);
+ reg |= CH1_PD;
+ writel(reg, dp->reg_base + S5P_DP_PHY_PD);
+ } else {
+ reg = readl(dp->reg_base + S5P_DP_PHY_PD);
+ reg &= ~CH1_PD;
+ writel(reg, dp->reg_base + S5P_DP_PHY_PD);
+ }
+ break;
+ case CH2_BLOCK:
+ if (enable) {
+ reg = readl(dp->reg_base + S5P_DP_PHY_PD);
+ reg |= CH2_PD;
+ writel(reg, dp->reg_base + S5P_DP_PHY_PD);
+ } else {
+ reg = readl(dp->reg_base + S5P_DP_PHY_PD);
+ reg &= ~CH2_PD;
+ writel(reg, dp->reg_base + S5P_DP_PHY_PD);
+ }
+ break;
+ case CH3_BLOCK:
+ if (enable) {
+ reg = readl(dp->reg_base + S5P_DP_PHY_PD);
+ reg |= CH3_PD;
+ writel(reg, dp->reg_base + S5P_DP_PHY_PD);
+ } else {
+ reg = readl(dp->reg_base + S5P_DP_PHY_PD);
+ reg &= ~CH3_PD;
+ writel(reg, dp->reg_base + S5P_DP_PHY_PD);
+ }
+ break;
+ case ANALOG_TOTAL:
+ if (enable) {
+ reg = readl(dp->reg_base + S5P_DP_PHY_PD);
+ reg |= DP_PHY_PD;
+ writel(reg, dp->reg_base + S5P_DP_PHY_PD);
+ } else {
+ reg = readl(dp->reg_base + S5P_DP_PHY_PD);
+ reg &= ~DP_PHY_PD;
+ writel(reg, dp->reg_base + S5P_DP_PHY_PD);
+ }
+ break;
+ case POWER_ALL:
+ if (enable) {
+ reg = DP_PHY_PD | AUX_PD | CH3_PD | CH2_PD |
+ CH1_PD | CH0_PD;
+ writel(reg, dp->reg_base + S5P_DP_PHY_PD);
+ } else {
+ writel(0x00, dp->reg_base + S5P_DP_PHY_PD);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void s5p_dp_init_analog_func(struct s5p_dp_device *dp)
+{
+ u32 reg;
+
+ s5p_dp_set_analog_power_down(dp, POWER_ALL, 0);
+
+ reg = PLL_LOCK_CHG;
+ writel(reg, dp->reg_base + S5P_DP_COMMON_INT_STA_1);
+
+ reg = readl(dp->reg_base + S5P_DP_DEBUG_CTL);
+ reg &= ~(F_PLL_LOCK | PLL_LOCK_CTRL);
+ writel(reg, dp->reg_base + S5P_DP_DEBUG_CTL);
+
+ /* Power up PLL */
+ if (s5p_dp_get_pll_lock_status(dp) == PLL_UNLOCKED)
+ s5p_dp_set_pll_power_down(dp, 0);
+
+ /* Enable Serdes FIFO function and Link symbol clock domain module */
+ reg = readl(dp->reg_base + S5P_DP_FUNC_EN_2);
+ reg &= ~(SERDES_FIFO_FUNC_EN_N | LS_CLK_DOMAIN_FUNC_EN_N
+ | AUX_FUNC_EN_N);
+ writel(reg, dp->reg_base + S5P_DP_FUNC_EN_2);
+}
+
+void s5p_dp_init_hpd(struct s5p_dp_device *dp)
+{
+ u32 reg;
+
+ reg = HOTPLUG_CHG | HPD_LOST | PLUG;
+ writel(reg, dp->reg_base + S5P_DP_COMMON_INT_STA_4);
+
+ reg = INT_HPD;
+ writel(reg, dp->reg_base + S5P_DP_INT_STA);
+
+ reg = readl(dp->reg_base + S5P_DP_SYS_CTL_3);
+ reg &= ~(F_HPD | HPD_CTRL);
+ writel(reg, dp->reg_base + S5P_DP_SYS_CTL_3);
+}
+
+void s5p_dp_reset_aux(struct s5p_dp_device *dp)
+{
+ u32 reg;
+
+ /* Disable AUX channel module */
+ reg = readl(dp->reg_base + S5P_DP_FUNC_EN_2);
+ reg |= AUX_FUNC_EN_N;
+ writel(reg, dp->reg_base + S5P_DP_FUNC_EN_2);
+}
+
+void s5p_dp_init_aux(struct s5p_dp_device *dp)
+{
+ u32 reg;
+
+ /* Clear inerrupts related to AUX channel */
+ reg = RPLY_RECEIV | AUX_ERR;
+ writel(reg, dp->reg_base + S5P_DP_INT_STA);
+
+ s5p_dp_reset_aux(dp);
+
+ /* Disable AUX transaction H/W retry */
+ reg = AUX_BIT_PERIOD_EXPECTED_DELAY(3) | AUX_HW_RETRY_COUNT_SEL(0)|
+ AUX_HW_RETRY_INTERVAL_600_MICROSECONDS;
+ writel(reg, dp->reg_base + S5P_DP_AUX_HW_RETRY_CTL) ;
+
+ /* Receive AUX Channel DEFER commands equal to DEFFER_COUNT*64 */
+ reg = DEFER_CTRL_EN | DEFER_COUNT(1);
+ writel(reg, dp->reg_base + S5P_DP_AUX_CH_DEFER_CTL);
+
+ /* Enable AUX channel module */
+ reg = readl(dp->reg_base + S5P_DP_FUNC_EN_2);
+ reg &= ~AUX_FUNC_EN_N;
+ writel(reg, dp->reg_base + S5P_DP_FUNC_EN_2);
+}
+
+int s5p_dp_get_plug_in_status(struct s5p_dp_device *dp)
+{
+ u32 reg;
+
+ reg = readl(dp->reg_base + S5P_DP_SYS_CTL_3);
+ if (reg & HPD_STATUS)
+ return 0;
+
+ return -EINVAL;
+}
+
+void s5p_dp_enable_sw_function(struct s5p_dp_device *dp)
+{
+ u32 reg;
+
+ reg = readl(dp->reg_base + S5P_DP_FUNC_EN_1);
+ reg &= ~SW_FUNC_EN_N;
+ writel(reg, dp->reg_base + S5P_DP_FUNC_EN_1);
+}
+
+int s5p_dp_start_aux_transaction(struct s5p_dp_device *dp)
+{
+ int reg;
+ int retval = 0;
+ int timeout_loop = 0;
+ int aux_timeout = 0;
+
+ /* Enable AUX CH operation */
+ reg = readl(dp->reg_base + S5P_DP_AUX_CH_CTL_2);
+ reg |= AUX_EN;
+ writel(reg, dp->reg_base + S5P_DP_AUX_CH_CTL_2);
+
+ /* Is AUX CH operation enabled? */
+ reg = readl(dp->reg_base + S5P_DP_AUX_CH_CTL_2);
+ while (reg & AUX_EN) {
+ aux_timeout++;
+ if ((DP_TIMEOUT_LOOP_COUNT * 10) < aux_timeout) {
+ dev_err(dp->dev, "AUX CH enable timeout!\n");
+ return -ETIMEDOUT;
+ }
+ reg = readl(dp->reg_base + S5P_DP_AUX_CH_CTL_2);
+ udelay(100);
+ }
+
+ /* Is AUX CH command reply received? */
+ reg = readl(dp->reg_base + S5P_DP_INT_STA);
+ while (!(reg & RPLY_RECEIV)) {
+ timeout_loop++;
+ if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
+ dev_err(dp->dev, "AUX CH command reply failed!\n");
+ return -ETIMEDOUT;
+ }
+ reg = readl(dp->reg_base + S5P_DP_INT_STA);
+ udelay(10);
+ }
+
+ /* Clear interrupt source for AUX CH command reply */
+ writel(RPLY_RECEIV, dp->reg_base + S5P_DP_INT_STA);
+
+ /* Clear interrupt source for AUX CH access error */
+ reg = readl(dp->reg_base + S5P_DP_INT_STA);
+ if (reg & AUX_ERR) {
+ writel(AUX_ERR, dp->reg_base + S5P_DP_INT_STA);
+ return -EREMOTEIO;
+ }
+
+ /* Check AUX CH error access status */
+ reg = readl(dp->reg_base + S5P_DP_AUX_CH_STA);
+ if ((reg & AUX_STATUS_MASK) != 0) {
+ dev_err(dp->dev, "AUX CH error happens: %d\n\n",
+ reg & AUX_STATUS_MASK);
+ return -EREMOTEIO;
+ }
+
+ return retval;
+}
+
+int s5p_dp_write_byte_to_dpcd(struct s5p_dp_device *dp,
+ unsigned int reg_addr,
+ unsigned char data)
+{
+ u32 reg;
+ int i;
+ int retval;
+
+ for (i = 0; i < 3; i++) {
+ /* Clear AUX CH data buffer */
+ reg = BUF_CLR;
+ writel(reg, dp->reg_base + S5P_DP_BUFFER_DATA_CTL);
+
+ /* Select DPCD device address */
+ reg = AUX_ADDR_7_0(reg_addr);
+ writel(reg, dp->reg_base + S5P_DP_AUX_ADDR_7_0);
+ reg = AUX_ADDR_15_8(reg_addr);
+ writel(reg, dp->reg_base + S5P_DP_AUX_ADDR_15_8);
+ reg = AUX_ADDR_19_16(reg_addr);
+ writel(reg, dp->reg_base + S5P_DP_AUX_ADDR_19_16);
+
+ /* Write data buffer */
+ reg = (unsigned int)data;
+ writel(reg, dp->reg_base + S5P_DP_BUF_DATA_0);
+
+ /*
+ * Set DisplayPort transaction and write 1 byte
+ * If bit 3 is 1, DisplayPort transaction.
+ * If Bit 3 is 0, I2C transaction.
+ */
+ reg = AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_WRITE;
+ writel(reg, dp->reg_base + S5P_DP_AUX_CH_CTL_1);
+
+ /* Start AUX transaction */
+ retval = s5p_dp_start_aux_transaction(dp);
+ if (retval == 0)
+ break;
+ else
+ dev_dbg(dp->dev, "Aux Transaction fail!\n");
+ }
+
+ return retval;
+}
+
+int s5p_dp_read_byte_from_dpcd(struct s5p_dp_device *dp,
+ unsigned int reg_addr,
+ unsigned char *data)
+{
+ u32 reg;
+ int i;
+ int retval;
+
+ for (i = 0; i < 10; i++) {
+ /* Clear AUX CH data buffer */
+ reg = BUF_CLR;
+ writel(reg, dp->reg_base + S5P_DP_BUFFER_DATA_CTL);
+
+ /* Select DPCD device address */
+ reg = AUX_ADDR_7_0(reg_addr);
+ writel(reg, dp->reg_base + S5P_DP_AUX_ADDR_7_0);
+ reg = AUX_ADDR_15_8(reg_addr);
+ writel(reg, dp->reg_base + S5P_DP_AUX_ADDR_15_8);
+ reg = AUX_ADDR_19_16(reg_addr);
+ writel(reg, dp->reg_base + S5P_DP_AUX_ADDR_19_16);
+
+ /*
+ * Set DisplayPort transaction and read 1 byte
+ * If bit 3 is 1, DisplayPort transaction.
+ * If Bit 3 is 0, I2C transaction.
+ */
+ reg = AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_READ;
+ writel(reg, dp->reg_base + S5P_DP_AUX_CH_CTL_1);
+
+ /* Start AUX transaction */
+ retval = s5p_dp_start_aux_transaction(dp);
+ if (retval == 0)
+ break;
+ else
+ dev_dbg(dp->dev, "Aux Transaction fail!\n");
+ }
+
+ /* Read data buffer */
+ reg = readl(dp->reg_base + S5P_DP_BUF_DATA_0);
+ *data = (unsigned char)(reg & 0xff);
+
+ return retval;
+}
+
+int s5p_dp_write_bytes_to_dpcd(struct s5p_dp_device *dp,
+ unsigned int reg_addr,
+ unsigned int count,
+ unsigned char data[])
+{
+ u32 reg;
+ unsigned int start_offset;
+ unsigned int cur_data_count;
+ unsigned int cur_data_idx;
+ int i;
+ int retval = 0;
+
+ /* Clear AUX CH data buffer */
+ reg = BUF_CLR;
+ writel(reg, dp->reg_base + S5P_DP_BUFFER_DATA_CTL);
+
+ start_offset = 0;
+ while (start_offset < count) {
+ /* Buffer size of AUX CH is 16 * 4bytes */
+ if ((count - start_offset) > 16)
+ cur_data_count = 16;
+ else
+ cur_data_count = count - start_offset;
+
+ for (i = 0; i < 10; i++) {
+ /* Select DPCD device address */
+ reg = AUX_ADDR_7_0(reg_addr + start_offset);
+ writel(reg, dp->reg_base + S5P_DP_AUX_ADDR_7_0);
+ reg = AUX_ADDR_15_8(reg_addr + start_offset);
+ writel(reg, dp->reg_base + S5P_DP_AUX_ADDR_15_8);
+ reg = AUX_ADDR_19_16(reg_addr + start_offset);
+ writel(reg, dp->reg_base + S5P_DP_AUX_ADDR_19_16);
+
+ for (cur_data_idx = 0; cur_data_idx < cur_data_count;
+ cur_data_idx++) {
+ reg = data[start_offset + cur_data_idx];
+ writel(reg, dp->reg_base + S5P_DP_BUF_DATA_0
+ + 4 * cur_data_idx);
+ }
+
+ /*
+ * Set DisplayPort transaction and write
+ * If bit 3 is 1, DisplayPort transaction.
+ * If Bit 3 is 0, I2C transaction.
+ */
+ reg = AUX_LENGTH(cur_data_count) |
+ AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_WRITE;
+ writel(reg, dp->reg_base + S5P_DP_AUX_CH_CTL_1);
+
+ /* Start AUX transaction */
+ retval = s5p_dp_start_aux_transaction(dp);
+ if (retval == 0)
+ break;
+ else
+ dev_dbg(dp->dev, "Aux Transaction fail!\n");
+ }
+
+ start_offset += cur_data_count;
+ }
+
+ return retval;
+}
+
+int s5p_dp_read_bytes_from_dpcd(struct s5p_dp_device *dp,
+ unsigned int reg_addr,
+ unsigned int count,
+ unsigned char data[])
+{
+ u32 reg;
+ unsigned int start_offset;
+ unsigned int cur_data_count;
+ unsigned int cur_data_idx;
+ int i;
+ int retval = 0;
+
+ /* Clear AUX CH data buffer */
+ reg = BUF_CLR;
+ writel(reg, dp->reg_base + S5P_DP_BUFFER_DATA_CTL);
+
+ start_offset = 0;
+ while (start_offset < count) {
+ /* Buffer size of AUX CH is 16 * 4bytes */
+ if ((count - start_offset) > 16)
+ cur_data_count = 16;
+ else
+ cur_data_count = count - start_offset;
+
+ /* AUX CH Request Transaction process */
+ for (i = 0; i < 10; i++) {
+ /* Select DPCD device address */
+ reg = AUX_ADDR_7_0(reg_addr + start_offset);
+ writel(reg, dp->reg_base + S5P_DP_AUX_ADDR_7_0);
+ reg = AUX_ADDR_15_8(reg_addr + start_offset);
+ writel(reg, dp->reg_base + S5P_DP_AUX_ADDR_15_8);
+ reg = AUX_ADDR_19_16(reg_addr + start_offset);
+ writel(reg, dp->reg_base + S5P_DP_AUX_ADDR_19_16);
+
+ /*
+ * Set DisplayPort transaction and read
+ * If bit 3 is 1, DisplayPort transaction.
+ * If Bit 3 is 0, I2C transaction.
+ */
+ reg = AUX_LENGTH(cur_data_count) |
+ AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_READ;
+ writel(reg, dp->reg_base + S5P_DP_AUX_CH_CTL_1);
+
+ /* Start AUX transaction */
+ retval = s5p_dp_start_aux_transaction(dp);
+ if (retval == 0)
+ break;
+ else
+ dev_dbg(dp->dev, "Aux Transaction fail!\n");
+ }
+
+ for (cur_data_idx = 0; cur_data_idx < cur_data_count;
+ cur_data_idx++) {
+ reg = readl(dp->reg_base + S5P_DP_BUF_DATA_0
+ + 4 * cur_data_idx);
+ data[start_offset + cur_data_idx] =
+ (unsigned char)reg;
+ }
+
+ start_offset += cur_data_count;
+ }
+
+ return retval;
+}
+
+int s5p_dp_select_i2c_device(struct s5p_dp_device *dp,
+ unsigned int device_addr,
+ unsigned int reg_addr)
+{
+ u32 reg;
+ int retval;
+
+ /* Set EDID device address */
+ reg = device_addr;
+ writel(reg, dp->reg_base + S5P_DP_AUX_ADDR_7_0);
+ writel(0x0, dp->reg_base + S5P_DP_AUX_ADDR_15_8);
+ writel(0x0, dp->reg_base + S5P_DP_AUX_ADDR_19_16);
+
+ /* Set offset from base address of EDID device */
+ writel(reg_addr, dp->reg_base + S5P_DP_BUF_DATA_0);
+
+ /*
+ * Set I2C transaction and write address
+ * If bit 3 is 1, DisplayPort transaction.
+ * If Bit 3 is 0, I2C transaction.
+ */
+ reg = AUX_TX_COMM_I2C_TRANSACTION | AUX_TX_COMM_MOT |
+ AUX_TX_COMM_WRITE;
+ writel(reg, dp->reg_base + S5P_DP_AUX_CH_CTL_1);
+
+ /* Start AUX transaction */
+ retval = s5p_dp_start_aux_transaction(dp);
+ if (retval != 0)
+ dev_dbg(dp->dev, "Aux Transaction fail!\n");
+
+ return retval;
+}
+
+int s5p_dp_read_byte_from_i2c(struct s5p_dp_device *dp,
+ unsigned int device_addr,
+ unsigned int reg_addr,
+ unsigned int *data)
+{
+ u32 reg;
+ int i;
+ int retval;
+
+ for (i = 0; i < 10; i++) {
+ /* Clear AUX CH data buffer */
+ reg = BUF_CLR;
+ writel(reg, dp->reg_base + S5P_DP_BUFFER_DATA_CTL);
+
+ /* Select EDID device */
+ retval = s5p_dp_select_i2c_device(dp, device_addr, reg_addr);
+ if (retval != 0) {
+ dev_err(dp->dev, "Select EDID device fail!\n");
+ continue;
+ }
+
+ /*
+ * Set I2C transaction and read data
+ * If bit 3 is 1, DisplayPort transaction.
+ * If Bit 3 is 0, I2C transaction.
+ */
+ reg = AUX_TX_COMM_I2C_TRANSACTION |
+ AUX_TX_COMM_READ;
+ writel(reg, dp->reg_base + S5P_DP_AUX_CH_CTL_1);
+
+ /* Start AUX transaction */
+ retval = s5p_dp_start_aux_transaction(dp);
+ if (retval == 0)
+ break;
+ else
+ dev_dbg(dp->dev, "Aux Transaction fail!\n");
+ }
+
+ /* Read data */
+ if (retval == 0)
+ *data = readl(dp->reg_base + S5P_DP_BUF_DATA_0);
+
+ return retval;
+}
+
+int s5p_dp_read_bytes_from_i2c(struct s5p_dp_device *dp,
+ unsigned int device_addr,
+ unsigned int reg_addr,
+ unsigned int count,
+ unsigned char edid[])
+{
+ u32 reg;
+ unsigned int i, j;
+ unsigned int cur_data_idx;
+ unsigned int defer = 0;
+ int retval = 0;
+
+ for (i = 0; i < count; i += 16) {
+ for (j = 0; j < 100; j++) {
+ /* Clear AUX CH data buffer */
+ reg = BUF_CLR;
+ writel(reg, dp->reg_base + S5P_DP_BUFFER_DATA_CTL);
+
+ /* Set normal AUX CH command */
+ reg = readl(dp->reg_base + S5P_DP_AUX_CH_CTL_2);
+ reg &= ~ADDR_ONLY;
+ writel(reg, dp->reg_base + S5P_DP_AUX_CH_CTL_2);
+
+ /*
+ * If Rx sends defer, Tx sends only reads
+ * request without sending addres
+ */
+ if (!defer)
+ retval = s5p_dp_select_i2c_device(dp,
+ device_addr, reg_addr + i);
+ else
+ defer = 0;
+
+ /*
+ * Set I2C transaction and write data
+ * If bit 3 is 1, DisplayPort transaction.
+ * If Bit 3 is 0, I2C transaction.
+ */
+ reg = AUX_LENGTH(16) |
+ AUX_TX_COMM_I2C_TRANSACTION |
+ AUX_TX_COMM_READ;
+ writel(reg, dp->reg_base +
+ S5P_DP_AUX_CH_CTL_1);
+
+ /* Start AUX transaction */
+ retval = s5p_dp_start_aux_transaction(dp);
+ if (retval == 0)
+ break;
+ else
+ dev_dbg(dp->dev, "Aux Transaction fail!\n");
+
+ /* Check if Rx sends defer */
+ reg = readl(dp->reg_base + S5P_DP_AUX_RX_COMM);
+ if (reg == AUX_RX_COMM_AUX_DEFER ||
+ reg == AUX_RX_COMM_I2C_DEFER) {
+ dev_err(dp->dev, "Defer: %d\n\n", reg);
+ defer = 1;
+ }
+ }
+
+ for (cur_data_idx = 0; cur_data_idx < 16; cur_data_idx++) {
+ reg = readl(dp->reg_base + S5P_DP_BUF_DATA_0
+ + 4 * cur_data_idx);
+ edid[i + cur_data_idx] = (unsigned char)reg;
+ }
+ }
+
+ return retval;
+}
+
+void s5p_dp_set_link_bandwidth(struct s5p_dp_device *dp, u32 bwtype)
+{
+ u32 reg;
+
+ reg = bwtype;
+ if ((bwtype == LINK_RATE_2_70GBPS) || (bwtype == LINK_RATE_1_62GBPS))
+ writel(reg, dp->reg_base + S5P_DP_LINK_BW_SET);
+}
+
+void s5p_dp_get_link_bandwidth(struct s5p_dp_device *dp, u32 *bwtype)
+{
+ u32 reg;
+
+ reg = readl(dp->reg_base + S5P_DP_LINK_BW_SET);
+ *bwtype = reg;
+}
+
+void s5p_dp_set_lane_count(struct s5p_dp_device *dp, u32 count)
+{
+ u32 reg;
+
+ reg = count;
+ writel(reg, dp->reg_base + S5P_DP_LANE_COUNT_SET);
+}
+
+void s5p_dp_get_lane_count(struct s5p_dp_device *dp, u32 *count)
+{
+ u32 reg;
+
+ reg = readl(dp->reg_base + S5P_DP_LANE_COUNT_SET);
+ *count = reg;
+}
+
+void s5p_dp_enable_enhanced_mode(struct s5p_dp_device *dp, bool enable)
+{
+ u32 reg;
+
+ if (enable) {
+ reg = readl(dp->reg_base + S5P_DP_SYS_CTL_4);
+ reg |= ENHANCED;
+ writel(reg, dp->reg_base + S5P_DP_SYS_CTL_4);
+ } else {
+ reg = readl(dp->reg_base + S5P_DP_SYS_CTL_4);
+ reg &= ~ENHANCED;
+ writel(reg, dp->reg_base + S5P_DP_SYS_CTL_4);
+ }
+}
+
+void s5p_dp_set_training_pattern(struct s5p_dp_device *dp,
+ enum pattern_set pattern)
+{
+ u32 reg;
+
+ switch (pattern) {
+ case PRBS7:
+ reg = SCRAMBLING_ENABLE | LINK_QUAL_PATTERN_SET_PRBS7;
+ writel(reg, dp->reg_base + S5P_DP_TRAINING_PTN_SET);
+ break;
+ case D10_2:
+ reg = SCRAMBLING_ENABLE | LINK_QUAL_PATTERN_SET_D10_2;
+ writel(reg, dp->reg_base + S5P_DP_TRAINING_PTN_SET);
+ break;
+ case TRAINING_PTN1:
+ reg = SCRAMBLING_DISABLE | SW_TRAINING_PATTERN_SET_PTN1;
+ writel(reg, dp->reg_base + S5P_DP_TRAINING_PTN_SET);
+ break;
+ case TRAINING_PTN2:
+ reg = SCRAMBLING_DISABLE | SW_TRAINING_PATTERN_SET_PTN2;
+ writel(reg, dp->reg_base + S5P_DP_TRAINING_PTN_SET);
+ break;
+ case DP_NONE:
+ reg = SCRAMBLING_ENABLE |
+ LINK_QUAL_PATTERN_SET_DISABLE |
+ SW_TRAINING_PATTERN_SET_NORMAL;
+ writel(reg, dp->reg_base + S5P_DP_TRAINING_PTN_SET);
+ break;
+ default:
+ break;
+ }
+}
+
+void s5p_dp_set_lane0_pre_emphasis(struct s5p_dp_device *dp, u32 level)
+{
+ u32 reg;
+
+ reg = level << PRE_EMPHASIS_SET_SHIFT;
+ writel(reg, dp->reg_base + S5P_DP_LN0_LINK_TRAINING_CTL);
+}
+
+void s5p_dp_set_lane1_pre_emphasis(struct s5p_dp_device *dp, u32 level)
+{
+ u32 reg;
+
+ reg = level << PRE_EMPHASIS_SET_SHIFT;
+ writel(reg, dp->reg_base + S5P_DP_LN1_LINK_TRAINING_CTL);
+}
+
+void s5p_dp_set_lane2_pre_emphasis(struct s5p_dp_device *dp, u32 level)
+{
+ u32 reg;
+
+ reg = level << PRE_EMPHASIS_SET_SHIFT;
+ writel(reg, dp->reg_base + S5P_DP_LN2_LINK_TRAINING_CTL);
+}
+
+void s5p_dp_set_lane3_pre_emphasis(struct s5p_dp_device *dp, u32 level)
+{
+ u32 reg;
+
+ reg = level << PRE_EMPHASIS_SET_SHIFT;
+ writel(reg, dp->reg_base + S5P_DP_LN3_LINK_TRAINING_CTL);
+}
+
+void s5p_dp_set_lane0_link_training(struct s5p_dp_device *dp,
+ u32 training_lane)
+{
+ u32 reg;
+
+ reg = training_lane;
+ writel(reg, dp->reg_base + S5P_DP_LN0_LINK_TRAINING_CTL);
+}
+
+void s5p_dp_set_lane1_link_training(struct s5p_dp_device *dp,
+ u32 training_lane)
+{
+ u32 reg;
+
+ reg = training_lane;
+ writel(reg, dp->reg_base + S5P_DP_LN1_LINK_TRAINING_CTL);
+}
+
+void s5p_dp_set_lane2_link_training(struct s5p_dp_device *dp,
+ u32 training_lane)
+{
+ u32 reg;
+
+ reg = training_lane;
+ writel(reg, dp->reg_base + S5P_DP_LN2_LINK_TRAINING_CTL);
+}
+
+void s5p_dp_set_lane3_link_training(struct s5p_dp_device *dp,
+ u32 training_lane)
+{
+ u32 reg;
+
+ reg = training_lane;
+ writel(reg, dp->reg_base + S5P_DP_LN3_LINK_TRAINING_CTL);
+}
+
+u32 s5p_dp_get_lane0_link_training(struct s5p_dp_device *dp)
+{
+ u32 reg;
+
+ reg = readl(dp->reg_base + S5P_DP_LN0_LINK_TRAINING_CTL);
+ return reg;
+}
+
+u32 s5p_dp_get_lane1_link_training(struct s5p_dp_device *dp)
+{
+ u32 reg;
+
+ reg = readl(dp->reg_base + S5P_DP_LN1_LINK_TRAINING_CTL);
+ return reg;
+}
+
+u32 s5p_dp_get_lane2_link_training(struct s5p_dp_device *dp)
+{
+ u32 reg;
+
+ reg = readl(dp->reg_base + S5P_DP_LN2_LINK_TRAINING_CTL);
+ return reg;
+}
+
+u32 s5p_dp_get_lane3_link_training(struct s5p_dp_device *dp)
+{
+ u32 reg;
+
+ reg = readl(dp->reg_base + S5P_DP_LN3_LINK_TRAINING_CTL);
+ return reg;
+}
+
+void s5p_dp_reset_macro(struct s5p_dp_device *dp)
+{
+ u32 reg;
+
+ reg = readl(dp->reg_base + S5P_DP_PHY_TEST);
+ reg |= MACRO_RST;
+ writel(reg, dp->reg_base + S5P_DP_PHY_TEST);
+
+ /* 10 us is the minimum reset time. */
+ udelay(10);
+
+ reg &= ~MACRO_RST;
+ writel(reg, dp->reg_base + S5P_DP_PHY_TEST);
+}
+
+int s5p_dp_init_video(struct s5p_dp_device *dp)
+{
+ u32 reg;
+
+ reg = VSYNC_DET | VID_FORMAT_CHG | VID_CLK_CHG;
+ writel(reg, dp->reg_base + S5P_DP_COMMON_INT_STA_1);
+
+ reg = 0x0;
+ writel(reg, dp->reg_base + S5P_DP_SYS_CTL_1);
+
+ reg = CHA_CRI(4) | CHA_CTRL;
+ writel(reg, dp->reg_base + S5P_DP_SYS_CTL_2);
+
+ reg = 0x0;
+ writel(reg, dp->reg_base + S5P_DP_SYS_CTL_3);
+
+ reg = VID_HRES_TH(2) | VID_VRES_TH(0);
+ writel(reg, dp->reg_base + S5P_DP_VIDEO_CTL_8);
+
+ return 0;
+}
+
+void s5p_dp_set_video_color_format(struct s5p_dp_device *dp,
+ u32 color_depth,
+ u32 color_space,
+ u32 dynamic_range,
+ u32 coeff)
+{
+ u32 reg;
+
+ /* Configure the input color depth, color space, dynamic range */
+ reg = (dynamic_range << IN_D_RANGE_SHIFT) |
+ (color_depth << IN_BPC_SHIFT) |
+ (color_space << IN_COLOR_F_SHIFT);
+ writel(reg, dp->reg_base + S5P_DP_VIDEO_CTL_2);
+
+ /* Set Input Color YCbCr Coefficients to ITU601 or ITU709 */
+ reg = readl(dp->reg_base + S5P_DP_VIDEO_CTL_3);
+ reg &= ~IN_YC_COEFFI_MASK;
+ if (coeff)
+ reg |= IN_YC_COEFFI_ITU709;
+ else
+ reg |= IN_YC_COEFFI_ITU601;
+ writel(reg, dp->reg_base + S5P_DP_VIDEO_CTL_3);
+}
+
+int s5p_dp_is_slave_video_stream_clock_on(struct s5p_dp_device *dp)
+{
+ u32 reg;
+
+ reg = readl(dp->reg_base + S5P_DP_SYS_CTL_1);
+ writel(reg, dp->reg_base + S5P_DP_SYS_CTL_1);
+
+ reg = readl(dp->reg_base + S5P_DP_SYS_CTL_1);
+
+ if (!(reg & DET_STA)) {
+ dev_dbg(dp->dev, "Input stream clock not detected.\n");
+ return -EINVAL;
+ }
+
+ reg = readl(dp->reg_base + S5P_DP_SYS_CTL_2);
+ writel(reg, dp->reg_base + S5P_DP_SYS_CTL_2);
+
+ reg = readl(dp->reg_base + S5P_DP_SYS_CTL_2);
+ dev_dbg(dp->dev, "wait SYS_CTL_2.\n");
+
+ if (reg & CHA_STA) {
+ dev_dbg(dp->dev, "Input stream clk is changing\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+void s5p_dp_set_video_cr_mn(struct s5p_dp_device *dp,
+ enum clock_recovery_m_value_type type,
+ u32 m_value,
+ u32 n_value)
+{
+ u32 reg;
+
+ if (type == REGISTER_M) {
+ reg = readl(dp->reg_base + S5P_DP_SYS_CTL_4);
+ reg |= FIX_M_VID;
+ writel(reg, dp->reg_base + S5P_DP_SYS_CTL_4);
+ reg = m_value & 0xff;
+ writel(reg, dp->reg_base + S5P_DP_M_VID_0);
+ reg = (m_value >> 8) & 0xff;
+ writel(reg, dp->reg_base + S5P_DP_M_VID_1);
+ reg = (m_value >> 16) & 0xff;
+ writel(reg, dp->reg_base + S5P_DP_M_VID_2);
+
+ reg = n_value & 0xff;
+ writel(reg, dp->reg_base + S5P_DP_N_VID_0);
+ reg = (n_value >> 8) & 0xff;
+ writel(reg, dp->reg_base + S5P_DP_N_VID_1);
+ reg = (n_value >> 16) & 0xff;
+ writel(reg, dp->reg_base + S5P_DP_N_VID_2);
+ } else {
+ reg = readl(dp->reg_base + S5P_DP_SYS_CTL_4);
+ reg &= ~FIX_M_VID;
+ writel(reg, dp->reg_base + S5P_DP_SYS_CTL_4);
+
+ writel(0x00, dp->reg_base + S5P_DP_N_VID_0);
+ writel(0x80, dp->reg_base + S5P_DP_N_VID_1);
+ writel(0x00, dp->reg_base + S5P_DP_N_VID_2);
+ }
+}
+
+void s5p_dp_set_video_timing_mode(struct s5p_dp_device *dp, u32 type)
+{
+ u32 reg;
+
+ if (type == VIDEO_TIMING_FROM_CAPTURE) {
+ reg = readl(dp->reg_base + S5P_DP_VIDEO_CTL_10);
+ reg &= ~FORMAT_SEL;
+ writel(reg, dp->reg_base + S5P_DP_VIDEO_CTL_10);
+ } else {
+ reg = readl(dp->reg_base + S5P_DP_VIDEO_CTL_10);
+ reg |= FORMAT_SEL;
+ writel(reg, dp->reg_base + S5P_DP_VIDEO_CTL_10);
+ }
+}
+
+void s5p_dp_enable_video_master(struct s5p_dp_device *dp, bool enable)
+{
+ u32 reg;
+
+ if (enable) {
+ reg = readl(dp->reg_base + S5P_DP_SOC_GENERAL_CTL);
+ reg &= ~VIDEO_MODE_MASK;
+ reg |= VIDEO_MASTER_MODE_EN | VIDEO_MODE_MASTER_MODE;
+ writel(reg, dp->reg_base + S5P_DP_SOC_GENERAL_CTL);
+ } else {
+ reg = readl(dp->reg_base + S5P_DP_SOC_GENERAL_CTL);
+ reg &= ~VIDEO_MODE_MASK;
+ reg |= VIDEO_MODE_SLAVE_MODE;
+ writel(reg, dp->reg_base + S5P_DP_SOC_GENERAL_CTL);
+ }
+}
+
+void s5p_dp_start_video(struct s5p_dp_device *dp)
+{
+ u32 reg;
+
+ reg = readl(dp->reg_base + S5P_DP_VIDEO_CTL_1);
+ reg |= VIDEO_EN;
+ writel(reg, dp->reg_base + S5P_DP_VIDEO_CTL_1);
+}
+
+int s5p_dp_is_video_stream_on(struct s5p_dp_device *dp)
+{
+ u32 reg;
+
+ reg = readl(dp->reg_base + S5P_DP_SYS_CTL_3);
+ writel(reg, dp->reg_base + S5P_DP_SYS_CTL_3);
+
+ reg = readl(dp->reg_base + S5P_DP_SYS_CTL_3);
+ if (!(reg & STRM_VALID)) {
+ dev_dbg(dp->dev, "Input video stream is not detected.\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+void s5p_dp_config_video_slave_mode(struct s5p_dp_device *dp,
+ struct video_info *video_info)
+{
+ u32 reg;
+
+ reg = readl(dp->reg_base + S5P_DP_FUNC_EN_1);
+ reg &= ~(MASTER_VID_FUNC_EN_N|SLAVE_VID_FUNC_EN_N);
+ reg |= MASTER_VID_FUNC_EN_N;
+ writel(reg, dp->reg_base + S5P_DP_FUNC_EN_1);
+
+ reg = readl(dp->reg_base + S5P_DP_VIDEO_CTL_10);
+ reg &= ~INTERACE_SCAN_CFG;
+ reg |= (video_info->interlaced << 2);
+ writel(reg, dp->reg_base + S5P_DP_VIDEO_CTL_10);
+
+ reg = readl(dp->reg_base + S5P_DP_VIDEO_CTL_10);
+ reg &= ~VSYNC_POLARITY_CFG;
+ reg |= (video_info->v_sync_polarity << 1);
+ writel(reg, dp->reg_base + S5P_DP_VIDEO_CTL_10);
+
+ reg = readl(dp->reg_base + S5P_DP_VIDEO_CTL_10);
+ reg &= ~HSYNC_POLARITY_CFG;
+ reg |= (video_info->h_sync_polarity << 0);
+ writel(reg, dp->reg_base + S5P_DP_VIDEO_CTL_10);
+
+ reg = AUDIO_MODE_SPDIF_MODE | VIDEO_MODE_SLAVE_MODE;
+ writel(reg, dp->reg_base + S5P_DP_SOC_GENERAL_CTL);
+}
+
+void s5p_dp_enable_scrambling(struct s5p_dp_device *dp)
+{
+ u32 reg;
+
+ reg = readl(dp->reg_base + S5P_DP_TRAINING_PTN_SET);
+ reg &= ~SCRAMBLING_DISABLE;
+ writel(reg, dp->reg_base + S5P_DP_TRAINING_PTN_SET);
+}
+
+void s5p_dp_disable_scrambling(struct s5p_dp_device *dp)
+{
+ u32 reg;
+
+ reg = readl(dp->reg_base + S5P_DP_TRAINING_PTN_SET);
+ reg |= SCRAMBLING_DISABLE;
+ writel(reg, dp->reg_base + S5P_DP_TRAINING_PTN_SET);
+}
diff --git a/drivers/video/s5p-dp-reg.h b/drivers/video/s5p-dp-reg.h
new file mode 100644
index 0000000..216f4ed
--- /dev/null
+++ b/drivers/video/s5p-dp-reg.h
@@ -0,0 +1,372 @@
+/*
+ * Register definition file for Samsung DP driver
+ *
+ * Copyright (C) 2012 Samsung Electronics Co., Ltd.
+ * Author: Jingoo Han <jg1.han@samsung.com>
+ *
+ * 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.
+ */
+
+#ifndef _S5P_REGS_DP_H
+#define _S5P_REGS_DP_H __FILE__
+
+#define S5P_DP_TX_SW_RESET 0x14
+#define S5P_DP_FUNC_EN_1 0x18
+#define S5P_DP_FUNC_EN_2 0x1C
+#define S5P_DP_VIDEO_CTL_1 0x20
+#define S5P_DP_VIDEO_CTL_2 0x24
+#define S5P_DP_VIDEO_CTL_3 0x28
+
+#define S5P_DP_VIDEO_CTL_8 0x3C
+#define S5P_DP_VIDEO_CTL_10 0x44
+
+#define S5P_DP_LANE_MAP 0x35C
+
+#define S5P_DP_ANALOG_CTL_1 0x370
+#define S5P_DP_ANALOG_CTL_2 0x374
+#define S5P_DP_ANALOG_CTL_3 0x378
+#define S5P_DP_PLL_FILTER_CTL_1 0x37C
+#define S5P_DP_TX_AMP_TUNING_CTL 0x380
+
+#define S5P_DP_AUX_HW_RETRY_CTL 0x390
+
+#define S5P_DP_COMMON_INT_STA_1 0x3C4
+#define S5P_DP_COMMON_INT_STA_2 0x3C8
+#define S5P_DP_COMMON_INT_STA_3 0x3CC
+#define S5P_DP_COMMON_INT_STA_4 0x3D0
+#define S5P_DP_INT_STA 0x3DC
+#define S5P_DP_COMMON_INT_MASK_1 0x3E0
+#define S5P_DP_COMMON_INT_MASK_2 0x3E4
+#define S5P_DP_COMMON_INT_MASK_3 0x3E8
+#define S5P_DP_COMMON_INT_MASK_4 0x3EC
+#define S5P_DP_INT_STA_MASK 0x3F8
+#define S5P_DP_INT_CTL 0x3FC
+
+#define S5P_DP_SYS_CTL_1 0x600
+#define S5P_DP_SYS_CTL_2 0x604
+#define S5P_DP_SYS_CTL_3 0x608
+#define S5P_DP_SYS_CTL_4 0x60C
+
+#define S5P_DP_PKT_SEND_CTL 0x640
+#define S5P_DP_HDCP_CTL 0x648
+
+#define S5P_DP_LINK_BW_SET 0x680
+#define S5P_DP_LANE_COUNT_SET 0x684
+#define S5P_DP_TRAINING_PTN_SET 0x688
+#define S5P_DP_LN0_LINK_TRAINING_CTL 0x68C
+#define S5P_DP_LN1_LINK_TRAINING_CTL 0x690
+#define S5P_DP_LN2_LINK_TRAINING_CTL 0x694
+#define S5P_DP_LN3_LINK_TRAINING_CTL 0x698
+
+#define S5P_DP_DEBUG_CTL 0x6C0
+#define S5P_DP_HPD_DEGLITCH_L 0x6C4
+#define S5P_DP_HPD_DEGLITCH_H 0x6C8
+#define S5P_DP_LINK_DEBUG_CTL 0x6E0
+
+#define S5P_DP_M_VID_0 0x700
+#define S5P_DP_M_VID_1 0x704
+#define S5P_DP_M_VID_2 0x708
+#define S5P_DP_N_VID_0 0x70C
+#define S5P_DP_N_VID_1 0x710
+#define S5P_DP_N_VID_2 0x714
+
+#define S5P_DP_PLL_CTL 0x71C
+#define S5P_DP_PHY_PD 0x720
+#define S5P_DP_PHY_TEST 0x724
+
+#define S5P_DP_VIDEO_FIFO_THRD 0x730
+#define S5P_DP_AUDIO_MARGIN 0x73C
+
+#define S5P_DP_M_VID_GEN_FILTER_TH 0x764
+#define S5P_DP_M_AUD_GEN_FILTER_TH 0x778
+#define S5P_DP_AUX_CH_STA 0x780
+#define S5P_DP_AUX_CH_DEFER_CTL 0x788
+#define S5P_DP_AUX_RX_COMM 0x78C
+#define S5P_DP_BUFFER_DATA_CTL 0x790
+#define S5P_DP_AUX_CH_CTL_1 0x794
+#define S5P_DP_AUX_ADDR_7_0 0x798
+#define S5P_DP_AUX_ADDR_15_8 0x79C
+#define S5P_DP_AUX_ADDR_19_16 0x7A0
+#define S5P_DP_AUX_CH_CTL_2 0x7A4
+
+#define S5P_DP_BUF_DATA_0 0x7C0
+
+#define S5P_DP_SOC_GENERAL_CTL 0x800
+
+/* S5P_DP_TX_SW_RESET */
+#define RESET_DP_TX (0x1 << 0)
+
+/* S5P_DP_FUNC_EN_1 */
+#define MASTER_VID_FUNC_EN_N (0x1 << 7)
+#define SLAVE_VID_FUNC_EN_N (0x1 << 5)
+#define AUD_FIFO_FUNC_EN_N (0x1 << 4)
+#define AUD_FUNC_EN_N (0x1 << 3)
+#define HDCP_FUNC_EN_N (0x1 << 2)
+#define CRC_FUNC_EN_N (0x1 << 1)
+#define SW_FUNC_EN_N (0x1 << 0)
+
+/* S5P_DP_FUNC_EN_2 */
+#define SSC_FUNC_EN_N (0x1 << 7)
+#define AUX_FUNC_EN_N (0x1 << 2)
+#define SERDES_FIFO_FUNC_EN_N (0x1 << 1)
+#define LS_CLK_DOMAIN_FUNC_EN_N (0x1 << 0)
+
+/* S5P_DP_VIDEO_CTL_1 */
+#define VIDEO_EN (0x1 << 7)
+#define HDCP_VIDEO_MUTE (0x1 << 6)
+
+/* S5P_DP_VIDEO_CTL_1 */
+#define IN_D_RANGE_MASK (0x1 << 7)
+#define IN_D_RANGE_SHIFT (7)
+#define IN_D_RANGE_CEA (0x1 << 7)
+#define IN_D_RANGE_VESA (0x0 << 7)
+#define IN_BPC_MASK (0x7 << 4)
+#define IN_BPC_SHIFT (4)
+#define IN_BPC_12_BITS (0x3 << 4)
+#define IN_BPC_10_BITS (0x2 << 4)
+#define IN_BPC_8_BITS (0x1 << 4)
+#define IN_BPC_6_BITS (0x0 << 4)
+#define IN_COLOR_F_MASK (0x3 << 0)
+#define IN_COLOR_F_SHIFT (0)
+#define IN_COLOR_F_YCBCR444 (0x2 << 0)
+#define IN_COLOR_F_YCBCR422 (0x1 << 0)
+#define IN_COLOR_F_RGB (0x0 << 0)
+
+/* S5P_DP_VIDEO_CTL_3 */
+#define IN_YC_COEFFI_MASK (0x1 << 7)
+#define IN_YC_COEFFI_SHIFT (7)
+#define IN_YC_COEFFI_ITU709 (0x1 << 7)
+#define IN_YC_COEFFI_ITU601 (0x0 << 7)
+#define VID_CHK_UPDATE_TYPE_MASK (0x1 << 4)
+#define VID_CHK_UPDATE_TYPE_SHIFT (4)
+#define VID_CHK_UPDATE_TYPE_1 (0x1 << 4)
+#define VID_CHK_UPDATE_TYPE_0 (0x0 << 4)
+
+/* S5P_DP_VIDEO_CTL_8 */
+#define VID_HRES_TH(x) (((x) & 0xf) << 4)
+#define VID_VRES_TH(x) (((x) & 0xf) << 0)
+
+/* S5P_DP_VIDEO_CTL_10 */
+#define FORMAT_SEL (0x1 << 4)
+#define INTERACE_SCAN_CFG (0x1 << 2)
+#define VSYNC_POLARITY_CFG (0x1 << 1)
+#define HSYNC_POLARITY_CFG (0x1 << 0)
+
+/* S5P_DP_LANE_MAP */
+#define LANE3_MAP_LOGIC_LANE_0 (0x0 << 6)
+#define LANE3_MAP_LOGIC_LANE_1 (0x1 << 6)
+#define LANE3_MAP_LOGIC_LANE_2 (0x2 << 6)
+#define LANE3_MAP_LOGIC_LANE_3 (0x3 << 6)
+#define LANE2_MAP_LOGIC_LANE_0 (0x0 << 4)
+#define LANE2_MAP_LOGIC_LANE_1 (0x1 << 4)
+#define LANE2_MAP_LOGIC_LANE_2 (0x2 << 4)
+#define LANE2_MAP_LOGIC_LANE_3 (0x3 << 4)
+#define LANE1_MAP_LOGIC_LANE_0 (0x0 << 2)
+#define LANE1_MAP_LOGIC_LANE_1 (0x1 << 2)
+#define LANE1_MAP_LOGIC_LANE_2 (0x2 << 2)
+#define LANE1_MAP_LOGIC_LANE_3 (0x3 << 2)
+#define LANE0_MAP_LOGIC_LANE_0 (0x0 << 0)
+#define LANE0_MAP_LOGIC_LANE_1 (0x1 << 0)
+#define LANE0_MAP_LOGIC_LANE_2 (0x2 << 0)
+#define LANE0_MAP_LOGIC_LANE_3 (0x3 << 0)
+
+/* S5P_DP_ANALOG_CTL_1 */
+#define TX_TERMINAL_CTRL_50_OHM (0x1 << 4)
+
+/* S5P_DP_ANALOG_CTL_2 */
+#define SEL_24M (0x1 << 3)
+#define TX_DVDD_BIT_1_0625V (0x4 << 0)
+
+/* S5P_DP_ANALOG_CTL_3 */
+#define DRIVE_DVDD_BIT_1_0625V (0x4 << 5)
+#define VCO_BIT_600_MICRO (0x5 << 0)
+
+/* S5P_DP_PLL_FILTER_CTL_1 */
+#define PD_RING_OSC (0x1 << 6)
+#define AUX_TERMINAL_CTRL_37_5_OHM (0x0 << 4)
+#define AUX_TERMINAL_CTRL_45_OHM (0x1 << 4)
+#define AUX_TERMINAL_CTRL_50_OHM (0x2 << 4)
+#define AUX_TERMINAL_CTRL_65_OHM (0x3 << 4)
+#define TX_CUR1_2X (0x1 << 2)
+#define TX_CUR_16_MA (0x3 << 0)
+
+/* S5P_DP_TX_AMP_TUNING_CTL */
+#define CH3_AMP_SHIFT (24)
+#define CH3_AMP_400_MV (0x0 << 24)
+#define CH2_AMP_SHIFT (16)
+#define CH2_AMP_400_MV (0x0 << 16)
+#define CH1_AMP_SHIFT (8)
+#define CH1_AMP_400_MV (0x0 << 8)
+#define CH0_AMP_SHIFT (0)
+#define CH0_AMP_400_MV (0x0 << 0)
+
+/* S5P_DP_AUX_HW_RETRY_CTL */
+#define AUX_BIT_PERIOD_EXPECTED_DELAY(x) (((x) & 0x7) << 8)
+#define AUX_HW_RETRY_INTERVAL_MASK (0x3 << 3)
+#define AUX_HW_RETRY_INTERVAL_600_MICROSECONDS (0x0 << 3)
+#define AUX_HW_RETRY_INTERVAL_800_MICROSECONDS (0x1 << 3)
+#define AUX_HW_RETRY_INTERVAL_1000_MICROSECONDS (0x2 << 3)
+#define AUX_HW_RETRY_INTERVAL_1800_MICROSECONDS (0x3 << 3)
+#define AUX_HW_RETRY_COUNT_SEL(x) (((x) & 0x7) << 0)
+
+/* S5P_DP_COMMON_INT_STA_1 */
+#define VSYNC_DET (0x1 << 7)
+#define PLL_LOCK_CHG (0x1 << 6)
+#define SPDIF_ERR (0x1 << 5)
+#define SPDIF_UNSTBL (0x1 << 4)
+#define VID_FORMAT_CHG (0x1 << 3)
+#define AUD_CLK_CHG (0x1 << 2)
+#define VID_CLK_CHG (0x1 << 1)
+#define SW_INT (0x1 << 0)
+
+/* S5P_DP_COMMON_INT_STA_2 */
+#define ENC_EN_CHG (0x1 << 6)
+#define HW_BKSV_RDY (0x1 << 3)
+#define HW_SHA_DONE (0x1 << 2)
+#define HW_AUTH_STATE_CHG (0x1 << 1)
+#define HW_AUTH_DONE (0x1 << 0)
+
+/* S5P_DP_COMMON_INT_STA_3 */
+#define AFIFO_UNDER (0x1 << 7)
+#define AFIFO_OVER (0x1 << 6)
+#define R0_CHK_FLAG (0x1 << 5)
+
+/* S5P_DP_COMMON_INT_STA_4 */
+#define PSR_ACTIVE (0x1 << 7)
+#define PSR_INACTIVE (0x1 << 6)
+#define SPDIF_BI_PHASE_ERR (0x1 << 5)
+#define HOTPLUG_CHG (0x1 << 2)
+#define HPD_LOST (0x1 << 1)
+#define PLUG (0x1 << 0)
+
+/* S5P_DP_INT_STA */
+#define INT_HPD (0x1 << 6)
+#define HW_TRAINING_FINISH (0x1 << 5)
+#define RPLY_RECEIV (0x1 << 1)
+#define AUX_ERR (0x1 << 0)
+
+/* S5P_DP_INT_CTL */
+#define SOFT_INT_CTRL (0x1 << 2)
+#define INT_POL (0x1 << 0)
+
+/* S5P_DP_SYS_CTL_1 */
+#define DET_STA (0x1 << 2)
+#define FORCE_DET (0x1 << 1)
+#define DET_CTRL (0x1 << 0)
+
+/* S5P_DP_SYS_CTL_2 */
+#define CHA_CRI(x) (((x) & 0xf) << 4)
+#define CHA_STA (0x1 << 2)
+#define FORCE_CHA (0x1 << 1)
+#define CHA_CTRL (0x1 << 0)
+
+/* S5P_DP_SYS_CTL_3 */
+#define HPD_STATUS (0x1 << 6)
+#define F_HPD (0x1 << 5)
+#define HPD_CTRL (0x1 << 4)
+#define HDCP_RDY (0x1 << 3)
+#define STRM_VALID (0x1 << 2)
+#define F_VALID (0x1 << 1)
+#define VALID_CTRL (0x1 << 0)
+
+/* S5P_DP_SYS_CTL_4 */
+#define FIX_M_AUD (0x1 << 4)
+#define ENHANCED (0x1 << 3)
+#define FIX_M_VID (0x1 << 2)
+#define M_VID_UPDATE_CTRL (0x3 << 0)
+
+/* S5P_DP_TRAINING_PTN_SET */
+#define SCRAMBLER_TYPE (0x1 << 9)
+#define HW_LINK_TRAINING_PATTERN (0x1 << 8)
+#define SCRAMBLING_DISABLE (0x1 << 5)
+#define SCRAMBLING_ENABLE (0x0 << 5)
+#define LINK_QUAL_PATTERN_SET_MASK (0x3 << 2)
+#define LINK_QUAL_PATTERN_SET_PRBS7 (0x3 << 2)
+#define LINK_QUAL_PATTERN_SET_D10_2 (0x1 << 2)
+#define LINK_QUAL_PATTERN_SET_DISABLE (0x0 << 2)
+#define SW_TRAINING_PATTERN_SET_MASK (0x3 << 0)
+#define SW_TRAINING_PATTERN_SET_PTN2 (0x2 << 0)
+#define SW_TRAINING_PATTERN_SET_PTN1 (0x1 << 0)
+#define SW_TRAINING_PATTERN_SET_NORMAL (0x0 << 0)
+
+/* S5P_DP_LN0_LINK_TRAINING_CTL */
+#define PRE_EMPHASIS_SET_MASK (0x3 << 3)
+#define PRE_EMPHASIS_SET_SHIFT (3)
+
+/* S5P_DP_DEBUG_CTL */
+#define PLL_LOCK (0x1 << 4)
+#define F_PLL_LOCK (0x1 << 3)
+#define PLL_LOCK_CTRL (0x1 << 2)
+#define PN_INV (0x1 << 0)
+
+/* S5P_DP_PLL_CTL */
+#define DP_PLL_PD (0x1 << 7)
+#define DP_PLL_RESET (0x1 << 6)
+#define DP_PLL_LOOP_BIT_DEFAULT (0x1 << 4)
+#define DP_PLL_REF_BIT_1_1250V (0x5 << 0)
+#define DP_PLL_REF_BIT_1_2500V (0x7 << 0)
+
+/* S5P_DP_PHY_PD */
+#define DP_PHY_PD (0x1 << 5)
+#define AUX_PD (0x1 << 4)
+#define CH3_PD (0x1 << 3)
+#define CH2_PD (0x1 << 2)
+#define CH1_PD (0x1 << 1)
+#define CH0_PD (0x1 << 0)
+
+/* S5P_DP_PHY_TEST */
+#define MACRO_RST (0x1 << 5)
+#define CH1_TEST (0x1 << 1)
+#define CH0_TEST (0x1 << 0)
+
+/* S5P_DP_AUX_CH_STA */
+#define AUX_BUSY (0x1 << 4)
+#define AUX_STATUS_MASK (0xf << 0)
+
+/* S5P_DP_AUX_CH_DEFER_CTL */
+#define DEFER_CTRL_EN (0x1 << 7)
+#define DEFER_COUNT(x) (((x) & 0x7f) << 0)
+
+/* S5P_DP_AUX_RX_COMM */
+#define AUX_RX_COMM_I2C_DEFER (0x2 << 2)
+#define AUX_RX_COMM_AUX_DEFER (0x2 << 0)
+
+/* S5P_DP_BUFFER_DATA_CTL */
+#define BUF_CLR (0x1 << 7)
+#define BUF_DATA_COUNT(x) (((x) & 0x1f) << 0)
+
+/* S5P_DP_AUX_CH_CTL_1 */
+#define AUX_LENGTH(x) (((x - 1) & 0xf) << 4)
+#define AUX_TX_COMM_MASK (0xf << 0)
+#define AUX_TX_COMM_DP_TRANSACTION (0x1 << 3)
+#define AUX_TX_COMM_I2C_TRANSACTION (0x0 << 3)
+#define AUX_TX_COMM_MOT (0x1 << 2)
+#define AUX_TX_COMM_WRITE (0x0 << 0)
+#define AUX_TX_COMM_READ (0x1 << 0)
+
+/* S5P_DP_AUX_ADDR_7_0 */
+#define AUX_ADDR_7_0(x) (((x) >> 0) & 0xff)
+
+/* S5P_DP_AUX_ADDR_15_8 */
+#define AUX_ADDR_15_8(x) (((x) >> 8) & 0xff)
+
+/* S5P_DP_AUX_ADDR_19_16 */
+#define AUX_ADDR_19_16(x) (((x) >> 16) & 0x0f)
+
+/* S5P_DP_AUX_CH_CTL_2 */
+#define ADDR_ONLY (0x1 << 1)
+#define AUX_EN (0x1 << 0)
+
+/* S5P_DP_SOC_GENERAL_CTL */
+#define AUDIO_MODE_SPDIF_MODE (0x1 << 8)
+#define AUDIO_MODE_MASTER_MODE (0x0 << 8)
+#define MASTER_VIDEO_INTERLACE_EN (0x1 << 4)
+#define VIDEO_MASTER_CLK_SEL (0x1 << 2)
+#define VIDEO_MASTER_MODE_EN (0x1 << 1)
+#define VIDEO_MODE_MASK (0x1 << 0)
+#define VIDEO_MODE_SLAVE_MODE (0x1 << 0)
+#define VIDEO_MODE_MASTER_MODE (0x0 << 0)
+
+#endif /* _S5P_REGS_DP_H */
diff --git a/drivers/video/s5p_mipi_dsi.c b/drivers/video/s5p_mipi_dsi.c
new file mode 100644
index 0000000..5c74aa6
--- /dev/null
+++ b/drivers/video/s5p_mipi_dsi.c
@@ -0,0 +1,950 @@
+/* linux/drivers/video/s5p_mipi_dsi.c
+ *
+ * Samsung SoC MIPI-DSIM driver.
+ *
+ * Copyright (c) 2011 Samsung Electronics
+ *
+ * InKi Dae, <inki.dae@samsung.com>
+ *
+ * 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.
+*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/clk.h>
+#include <linux/mutex.h>
+#include <linux/wait.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/fb.h>
+#include <linux/ctype.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/memory.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/kthread.h>
+#include <linux/regulator/consumer.h>
+#include <linux/notifier.h>
+#include <linux/pm_runtime.h>
+
+#include <linux/gpio.h>
+
+#include <video/mipi_display.h>
+
+#include <plat/fb.h>
+#include <plat/regs-mipidsim.h>
+#include <plat/dsim.h>
+
+#include <mach/map.h>
+
+#include "s5p_mipi_dsi_lowlevel.h"
+#include "s5p_mipi_dsi.h"
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif
+
+static unsigned int dpll_table[15] = {
+ 100, 120, 170, 220, 270,
+ 320, 390, 450, 510, 560,
+ 640, 690, 770, 870, 950 };
+
+#ifdef CONFIG_LCD_MIPI_TC358764
+int s5p_mipi_dsi_wait_int_status(struct mipi_dsim_device *dsim, unsigned int intSrc)
+{
+ while (1) {
+ if ((s5p_mipi_dsi_get_int_status(dsim) & intSrc)) {
+ s5p_mipi_dsi_clear_int_status(dsim, intSrc);
+ return 1;
+ } else if ((s5p_mipi_dsi_get_FIFOCTRL_status(dsim) & 0xf00000) == 0)
+ return 0;
+ }
+}
+#endif
+
+static void s5p_mipi_dsi_long_data_wr(struct mipi_dsim_device *dsim, unsigned int data0, unsigned int data1)
+{
+ unsigned int data_cnt = 0, payload = 0;
+
+ /* in case that data count is more then 4 */
+ for (data_cnt = 0; data_cnt < data1; data_cnt += 4) {
+ /*
+ * after sending 4bytes per one time,
+ * send remainder data less then 4.
+ */
+ if ((data1 - data_cnt) < 4) {
+ if ((data1 - data_cnt) == 3) {
+ payload = *(u8 *)(data0 + data_cnt) |
+ (*(u8 *)(data0 + (data_cnt + 1))) << 8 |
+ (*(u8 *)(data0 + (data_cnt + 2))) << 16;
+ dev_dbg(dsim->dev, "count = 3 payload = %x, %x %x %x\n",
+ payload, *(u8 *)(data0 + data_cnt),
+ *(u8 *)(data0 + (data_cnt + 1)),
+ *(u8 *)(data0 + (data_cnt + 2)));
+ } else if ((data1 - data_cnt) == 2) {
+ payload = *(u8 *)(data0 + data_cnt) |
+ (*(u8 *)(data0 + (data_cnt + 1))) << 8;
+ dev_dbg(dsim->dev,
+ "count = 2 payload = %x, %x %x\n", payload,
+ *(u8 *)(data0 + data_cnt),
+ *(u8 *)(data0 + (data_cnt + 1)));
+ } else if ((data1 - data_cnt) == 1) {
+ payload = *(u8 *)(data0 + data_cnt);
+ }
+
+ s5p_mipi_dsi_wr_tx_data(dsim, payload);
+ /* send 4bytes per one time. */
+ } else {
+ payload = *(u8 *)(data0 + data_cnt) |
+ (*(u8 *)(data0 + (data_cnt + 1))) << 8 |
+ (*(u8 *)(data0 + (data_cnt + 2))) << 16 |
+ (*(u8 *)(data0 + (data_cnt + 3))) << 24;
+
+ dev_dbg(dsim->dev,
+ "count = 4 payload = %x, %x %x %x %x\n",
+ payload, *(u8 *)(data0 + data_cnt),
+ *(u8 *)(data0 + (data_cnt + 1)),
+ *(u8 *)(data0 + (data_cnt + 2)),
+ *(u8 *)(data0 + (data_cnt + 3)));
+
+ s5p_mipi_dsi_wr_tx_data(dsim, payload);
+ }
+ }
+}
+
+int s5p_mipi_dsi_wr_data(struct mipi_dsim_device *dsim, unsigned int data_id,
+ unsigned int data0, unsigned int data1)
+{
+ unsigned long delay_val, udelay;
+ unsigned int check_rx_ack = 0;
+
+ if (dsim->state == DSIM_STATE_ULPS) {
+ dev_err(dsim->dev, "state is ULPS.\n");
+
+ return -EINVAL;
+ }
+
+ delay_val = MHZ / dsim->dsim_config->esc_clk;
+ udelay = 10 * delay_val;
+
+ mdelay(udelay);
+
+ switch (data_id) {
+ /* short packet types of packet types for command. */
+ case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM:
+ case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM:
+ case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM:
+ case MIPI_DSI_DCS_SHORT_WRITE:
+ case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
+ case MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE:
+ s5p_mipi_dsi_wr_tx_header(dsim, data_id, data0, data1);
+ if (check_rx_ack)
+ /* process response func should be implemented */
+ return 0;
+ else
+ return -EINVAL;
+
+ /* general command */
+ case MIPI_DSI_COLOR_MODE_OFF:
+ case MIPI_DSI_COLOR_MODE_ON:
+ case MIPI_DSI_SHUTDOWN_PERIPHERAL:
+ case MIPI_DSI_TURN_ON_PERIPHERAL:
+ s5p_mipi_dsi_wr_tx_header(dsim, data_id, data0, data1);
+ if (check_rx_ack)
+ /* process response func should be implemented. */
+ return 0;
+ else
+ return -EINVAL;
+
+ /* packet types for video data */
+ case MIPI_DSI_V_SYNC_START:
+ case MIPI_DSI_V_SYNC_END:
+ case MIPI_DSI_H_SYNC_START:
+ case MIPI_DSI_H_SYNC_END:
+ case MIPI_DSI_END_OF_TRANSMISSION:
+ return 0;
+
+ /* short and response packet types for command */
+ case MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM:
+ case MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM:
+ case MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM:
+ case MIPI_DSI_DCS_READ:
+ s5p_mipi_dsi_clear_all_interrupt(dsim);
+ s5p_mipi_dsi_wr_tx_header(dsim, data_id, data0, data1);
+ /* process response func should be implemented. */
+ return 0;
+
+ /* long packet type and null packet */
+ case MIPI_DSI_NULL_PACKET:
+ case MIPI_DSI_BLANKING_PACKET:
+ return 0;
+ case MIPI_DSI_GENERIC_LONG_WRITE:
+ case MIPI_DSI_DCS_LONG_WRITE:
+ {
+ unsigned int size, data_cnt = 0, payload = 0;
+
+ size = data1 * 4;
+
+ /* if data count is less then 4, then send 3bytes data. */
+ if (data1 < 4) {
+ payload = *(u8 *)(data0) |
+ *(u8 *)(data0 + 1) << 8 |
+ *(u8 *)(data0 + 2) << 16;
+
+ s5p_mipi_dsi_wr_tx_data(dsim, payload);
+
+ dev_dbg(dsim->dev, "count = %d payload = %x,%x %x %x\n",
+ data1, payload,
+ *(u8 *)(data0 + data_cnt),
+ *(u8 *)(data0 + (data_cnt + 1)),
+ *(u8 *)(data0 + (data_cnt + 2)));
+ /* in case that data count is more then 4 */
+ } else
+ s5p_mipi_dsi_long_data_wr(dsim, data0, data1);
+
+ /* put data into header fifo */
+ s5p_mipi_dsi_wr_tx_header(dsim, data_id, data1 & 0xff,
+ (data1 & 0xff00) >> 8);
+ }
+#ifdef CONFIG_LCD_MIPI_TC358764
+ if (s5p_mipi_dsi_wait_int_status(dsim, INTSRC_SFR_FIFO_EMPTY) == 0)
+ return -1;
+#endif
+
+ if (check_rx_ack)
+ /* process response func should be implemented. */
+ return 0;
+ else
+ return -EINVAL;
+
+ /* packet typo for video data */
+ case MIPI_DSI_PACKED_PIXEL_STREAM_16:
+ case MIPI_DSI_PACKED_PIXEL_STREAM_18:
+ case MIPI_DSI_PIXEL_STREAM_3BYTE_18:
+ case MIPI_DSI_PACKED_PIXEL_STREAM_24:
+ if (check_rx_ack)
+ /* process response func should be implemented. */
+ return 0;
+ else
+ return -EINVAL;
+ default:
+ dev_warn(dsim->dev,
+ "data id %x is not supported current DSI spec.\n",
+ data_id);
+
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int s5p_mipi_dsi_pll_on(struct mipi_dsim_device *dsim, unsigned int enable)
+{
+ int sw_timeout;
+
+ if (enable) {
+ sw_timeout = 1000;
+
+ s5p_mipi_dsi_clear_interrupt(dsim, INTSRC_PLL_STABLE);
+ s5p_mipi_dsi_enable_pll(dsim, 1);
+ while (1) {
+ sw_timeout--;
+ if (s5p_mipi_dsi_is_pll_stable(dsim))
+ return 0;
+ if (sw_timeout == 0)
+ return -EINVAL;
+ }
+ } else
+ s5p_mipi_dsi_enable_pll(dsim, 0);
+
+ return 0;
+}
+
+unsigned long s5p_mipi_dsi_change_pll(struct mipi_dsim_device *dsim,
+ unsigned int pre_divider, unsigned int main_divider,
+ unsigned int scaler)
+{
+ unsigned long dfin_pll, dfvco, dpll_out;
+ unsigned int i, freq_band = 0xf;
+
+ dfin_pll = (FIN_HZ / pre_divider);
+
+ if (dfin_pll < DFIN_PLL_MIN_HZ || dfin_pll > DFIN_PLL_MAX_HZ) {
+ dev_warn(dsim->dev, "fin_pll range should be 6MHz ~ 12MHz\n");
+ s5p_mipi_dsi_enable_afc(dsim, 0, 0);
+ } else {
+ if (dfin_pll < 7 * MHZ)
+ s5p_mipi_dsi_enable_afc(dsim, 1, 0x1);
+ else if (dfin_pll < 8 * MHZ)
+ s5p_mipi_dsi_enable_afc(dsim, 1, 0x0);
+ else if (dfin_pll < 9 * MHZ)
+ s5p_mipi_dsi_enable_afc(dsim, 1, 0x3);
+ else if (dfin_pll < 10 * MHZ)
+ s5p_mipi_dsi_enable_afc(dsim, 1, 0x2);
+ else if (dfin_pll < 11 * MHZ)
+ s5p_mipi_dsi_enable_afc(dsim, 1, 0x5);
+ else
+ s5p_mipi_dsi_enable_afc(dsim, 1, 0x4);
+ }
+
+ dfvco = dfin_pll * main_divider;
+ dev_dbg(dsim->dev, "dfvco = %lu, dfin_pll = %lu, main_divider = %d\n",
+ dfvco, dfin_pll, main_divider);
+ if (dfvco < DFVCO_MIN_HZ || dfvco > DFVCO_MAX_HZ)
+ dev_warn(dsim->dev, "fvco range should be 500MHz ~ 1000MHz\n");
+
+ dpll_out = dfvco / (1 << scaler);
+ dev_dbg(dsim->dev, "dpll_out = %lu, dfvco = %lu, scaler = %d\n",
+ dpll_out, dfvco, scaler);
+
+ for (i = 0; i < ARRAY_SIZE(dpll_table); i++) {
+ if (dpll_out < dpll_table[i] * MHZ) {
+ freq_band = i;
+ break;
+ }
+ }
+
+ dev_dbg(dsim->dev, "freq_band = %d\n", freq_band);
+
+ s5p_mipi_dsi_pll_freq(dsim, pre_divider, main_divider, scaler);
+
+ s5p_mipi_dsi_hs_zero_ctrl(dsim, 0);
+ s5p_mipi_dsi_prep_ctrl(dsim, 0);
+
+ /* Freq Band */
+ s5p_mipi_dsi_pll_freq_band(dsim, freq_band);
+
+ /* Stable time */
+ s5p_mipi_dsi_pll_stable_time(dsim, dsim->dsim_config->pll_stable_time);
+
+ /* Enable PLL */
+ dev_dbg(dsim->dev, "FOUT of mipi dphy pll is %luMHz\n",
+ (dpll_out / MHZ));
+
+ return dpll_out;
+}
+
+int s5p_mipi_dsi_set_clock(struct mipi_dsim_device *dsim,
+ unsigned int byte_clk_sel, unsigned int enable)
+{
+ unsigned int esc_div;
+ unsigned long esc_clk_error_rate;
+
+ if (enable) {
+ dsim->e_clk_src = byte_clk_sel;
+
+ /* Escape mode clock and byte clock source */
+ s5p_mipi_dsi_set_byte_clock_src(dsim, byte_clk_sel);
+
+ /* DPHY, DSIM Link : D-PHY clock out */
+ if (byte_clk_sel == DSIM_PLL_OUT_DIV8) {
+ dsim->hs_clk = s5p_mipi_dsi_change_pll(dsim,
+ dsim->dsim_config->p, dsim->dsim_config->m,
+ dsim->dsim_config->s);
+ if (dsim->hs_clk == 0) {
+ dev_err(dsim->dev,
+ "failed to get hs clock.\n");
+ return -EINVAL;
+ }
+
+ dsim->byte_clk = dsim->hs_clk / 8;
+ s5p_mipi_dsi_enable_pll_bypass(dsim, 0);
+ s5p_mipi_dsi_pll_on(dsim, 1);
+ /* DPHY : D-PHY clock out, DSIM link : external clock out */
+ } else if (byte_clk_sel == DSIM_EXT_CLK_DIV8)
+ dev_warn(dsim->dev,
+ "this project is not support \
+ external clock source for MIPI DSIM\n");
+ else if (byte_clk_sel == DSIM_EXT_CLK_BYPASS)
+ dev_warn(dsim->dev,
+ "this project is not support \
+ external clock source for MIPI DSIM\n");
+
+ /* escape clock divider */
+ esc_div = dsim->byte_clk / (dsim->dsim_config->esc_clk);
+ dev_dbg(dsim->dev,
+ "esc_div = %d, byte_clk = %lu, esc_clk = %lu\n",
+ esc_div, dsim->byte_clk, dsim->dsim_config->esc_clk);
+ if ((dsim->byte_clk / esc_div) >= (20 * MHZ) ||
+ (dsim->byte_clk / esc_div) >
+ dsim->dsim_config->esc_clk)
+ esc_div += 1;
+
+ dsim->escape_clk = dsim->byte_clk / esc_div;
+ dev_dbg(dsim->dev,
+ "escape_clk = %lu, byte_clk = %lu, esc_div = %d\n",
+ dsim->escape_clk, dsim->byte_clk, esc_div);
+
+ /* enable escape clock. */
+ s5p_mipi_dsi_enable_byte_clock(dsim, DSIM_ESCCLK_ON);
+
+ /* enable byte clk and escape clock */
+ s5p_mipi_dsi_set_esc_clk_prs(dsim, 1, esc_div);
+ /* escape clock on lane */
+ s5p_mipi_dsi_enable_esc_clk_on_lane(dsim,
+ (DSIM_LANE_CLOCK | dsim->data_lane), 1);
+
+ dev_dbg(dsim->dev, "byte clock is %luMHz\n",
+ (dsim->byte_clk / MHZ));
+ dev_dbg(dsim->dev, "escape clock that user's need is %lu\n",
+ (dsim->dsim_config->esc_clk / MHZ));
+ dev_dbg(dsim->dev, "escape clock divider is %x\n", esc_div);
+ dev_dbg(dsim->dev, "escape clock is %luMHz\n",
+ ((dsim->byte_clk / esc_div) / MHZ));
+
+ if ((dsim->byte_clk / esc_div) > dsim->escape_clk) {
+ esc_clk_error_rate = dsim->escape_clk /
+ (dsim->byte_clk / esc_div);
+ dev_warn(dsim->dev, "error rate is %lu over.\n",
+ (esc_clk_error_rate / 100));
+ } else if ((dsim->byte_clk / esc_div) < (dsim->escape_clk)) {
+ esc_clk_error_rate = (dsim->byte_clk / esc_div) /
+ dsim->escape_clk;
+ dev_warn(dsim->dev, "error rate is %lu under.\n",
+ (esc_clk_error_rate / 100));
+ }
+ } else {
+ s5p_mipi_dsi_enable_esc_clk_on_lane(dsim,
+ (DSIM_LANE_CLOCK | dsim->data_lane), 0);
+ s5p_mipi_dsi_set_esc_clk_prs(dsim, 0, 0);
+
+ /* disable escape clock. */
+ s5p_mipi_dsi_enable_byte_clock(dsim, DSIM_ESCCLK_OFF);
+
+ if (byte_clk_sel == DSIM_PLL_OUT_DIV8)
+ s5p_mipi_dsi_pll_on(dsim, 0);
+ }
+
+ return 0;
+}
+
+void s5p_mipi_dsi_d_phy_onoff(struct mipi_dsim_device *dsim,
+ unsigned int enable)
+{
+ if (dsim->pd->init_d_phy)
+ dsim->pd->init_d_phy(dsim, enable);
+}
+
+int s5p_mipi_dsi_init_dsim(struct mipi_dsim_device *dsim)
+{
+ s5p_mipi_dsi_d_phy_onoff(dsim, 1);
+
+ dsim->state = DSIM_STATE_INIT;
+
+ switch (dsim->dsim_config->e_no_data_lane) {
+ case DSIM_DATA_LANE_1:
+ dsim->data_lane = DSIM_LANE_DATA0;
+ break;
+ case DSIM_DATA_LANE_2:
+ dsim->data_lane = DSIM_LANE_DATA0 | DSIM_LANE_DATA1;
+ break;
+ case DSIM_DATA_LANE_3:
+ dsim->data_lane = DSIM_LANE_DATA0 | DSIM_LANE_DATA1 |
+ DSIM_LANE_DATA2;
+ break;
+ case DSIM_DATA_LANE_4:
+ dsim->data_lane = DSIM_LANE_DATA0 | DSIM_LANE_DATA1 |
+ DSIM_LANE_DATA2 | DSIM_LANE_DATA3;
+ break;
+ default:
+ dev_info(dsim->dev, "data lane is invalid.\n");
+ return -EINVAL;
+ };
+
+ s5p_mipi_dsi_sw_reset(dsim);
+ s5p_mipi_dsi_dp_dn_swap(dsim, 0);
+
+ return 0;
+}
+
+int s5p_mipi_dsi_enable_frame_done_int(struct mipi_dsim_device *dsim,
+ unsigned int enable)
+{
+ /* enable only frame done interrupt */
+ s5p_mipi_dsi_set_interrupt_mask(dsim, INTMSK_FRAME_DONE, enable);
+
+ return 0;
+}
+
+int s5p_mipi_dsi_set_display_mode(struct mipi_dsim_device *dsim,
+ struct mipi_dsim_config *dsim_config)
+{
+ struct fb_videomode *lcd_video = NULL;
+ struct s3c_fb_pd_win *pd;
+ unsigned int width = 0, height = 0;
+ pd = (struct s3c_fb_pd_win *)dsim->dsim_config->lcd_panel_info;
+ lcd_video = (struct fb_videomode *)&pd->win_mode;
+
+ width = dsim->pd->dsim_lcd_config->lcd_size.width;
+ height = dsim->pd->dsim_lcd_config->lcd_size.height;
+
+ /* in case of VIDEO MODE (RGB INTERFACE) */
+ if (dsim->dsim_config->e_interface == (u32) DSIM_VIDEO) {
+ s5p_mipi_dsi_set_main_disp_vporch(dsim,
+ DSIM_CMD_LEN,
+ dsim->pd->dsim_lcd_config->rgb_timing.left_margin,
+ dsim->pd->dsim_lcd_config->rgb_timing.right_margin);
+ s5p_mipi_dsi_set_main_disp_hporch(dsim,
+ dsim->pd->dsim_lcd_config->rgb_timing.upper_margin,
+ dsim->pd->dsim_lcd_config->rgb_timing.lower_margin);
+ s5p_mipi_dsi_set_main_disp_sync_area(dsim,
+ dsim->pd->dsim_lcd_config->rgb_timing.vsync_len,
+ dsim->pd->dsim_lcd_config->rgb_timing.hsync_len);
+ }
+ s5p_mipi_dsi_set_main_disp_resol(dsim, height, width);
+ s5p_mipi_dsi_display_config(dsim);
+ return 0;
+}
+
+int s5p_mipi_dsi_init_link(struct mipi_dsim_device *dsim)
+{
+ unsigned int time_out = 100;
+ unsigned int id;
+ id = dsim->id;
+ switch (dsim->state) {
+ case DSIM_STATE_INIT:
+ s5p_mipi_dsi_sw_reset(dsim);
+ s5p_mipi_dsi_init_fifo_pointer(dsim, 0x1f);
+
+ /* dsi configuration */
+ s5p_mipi_dsi_init_config(dsim);
+ s5p_mipi_dsi_enable_lane(dsim, DSIM_LANE_CLOCK, 1);
+ s5p_mipi_dsi_enable_lane(dsim, dsim->data_lane, 1);
+
+ /* set clock configuration */
+ s5p_mipi_dsi_set_clock(dsim, dsim->dsim_config->e_byte_clk, 1);
+
+ mdelay(100);
+
+ /* check clock and data lane state are stop state */
+ while (!(s5p_mipi_dsi_is_lane_state(dsim))) {
+ time_out--;
+ if (time_out == 0) {
+ dev_err(dsim->dev,
+ "DSI Master is not stop state.\n");
+ dev_err(dsim->dev,
+ "Check initialization process\n");
+
+ return -EINVAL;
+ }
+ }
+
+ if (time_out != 0) {
+ dev_info(dsim->dev,
+ "DSI Master driver has been completed.\n");
+ dev_info(dsim->dev, "DSI Master state is stop state\n");
+ }
+
+ dsim->state = DSIM_STATE_STOP;
+
+ /* BTA sequence counters */
+ s5p_mipi_dsi_set_stop_state_counter(dsim,
+ dsim->dsim_config->stop_holding_cnt);
+ s5p_mipi_dsi_set_bta_timeout(dsim,
+ dsim->dsim_config->bta_timeout);
+ s5p_mipi_dsi_set_lpdr_timeout(dsim,
+ dsim->dsim_config->rx_timeout);
+
+ return 0;
+ default:
+ dev_info(dsim->dev, "DSI Master is already init.\n");
+ return 0;
+ }
+
+ return 0;
+}
+
+int s5p_mipi_dsi_set_hs_enable(struct mipi_dsim_device *dsim)
+{
+ if (dsim->state == DSIM_STATE_STOP) {
+ if (dsim->e_clk_src != DSIM_EXT_CLK_BYPASS) {
+ dsim->state = DSIM_STATE_HSCLKEN;
+
+ /* set LCDC and CPU transfer mode to HS. */
+ s5p_mipi_dsi_set_lcdc_transfer_mode(dsim, 0);
+ s5p_mipi_dsi_set_cpu_transfer_mode(dsim, 0);
+
+ s5p_mipi_dsi_enable_hs_clock(dsim, 1);
+
+ return 0;
+ } else
+ dev_warn(dsim->dev,
+ "clock source is external bypass.\n");
+ } else
+ dev_warn(dsim->dev, "DSIM is not stop state.\n");
+
+ return 0;
+}
+
+int s5p_mipi_dsi_set_data_transfer_mode(struct mipi_dsim_device *dsim,
+ unsigned int mode)
+{
+ if (mode) {
+ if (dsim->state != DSIM_STATE_HSCLKEN) {
+ dev_err(dsim->dev, "HS Clock lane is not enabled.\n");
+ return -EINVAL;
+ }
+
+ s5p_mipi_dsi_set_lcdc_transfer_mode(dsim, 0);
+ } else {
+ if (dsim->state == DSIM_STATE_INIT || dsim->state ==
+ DSIM_STATE_ULPS) {
+ dev_err(dsim->dev,
+ "DSI Master is not STOP or HSDT state.\n");
+ return -EINVAL;
+ }
+
+ s5p_mipi_dsi_set_cpu_transfer_mode(dsim, 0);
+ }
+ return 0;
+}
+
+int s5p_mipi_dsi_get_frame_done_status(struct mipi_dsim_device *dsim)
+{
+ return _s5p_mipi_dsi_get_frame_done_status(dsim);
+}
+
+int s5p_mipi_dsi_clear_frame_done(struct mipi_dsim_device *dsim)
+{
+ _s5p_mipi_dsi_clear_frame_done(dsim);
+
+ return 0;
+}
+
+static irqreturn_t s5p_mipi_dsi_interrupt_handler(int irq, void *dev_id)
+{
+ unsigned int int_src;
+ struct mipi_dsim_device *dsim = dev_id;
+
+ s5p_mipi_dsi_set_interrupt_mask(dsim, 0xffffffff, 1);
+
+ int_src = readl(dsim->reg_base + S5P_DSIM_INTSRC);
+ s5p_mipi_dsi_clear_interrupt(dsim, int_src);
+
+ if (!(int_src && INTSRC_PLL_STABLE))
+ printk(KERN_ERR "mipi dsi interrupt source (%x).\n", int_src);
+
+ s5p_mipi_dsi_set_interrupt_mask(dsim, 0xffffffff, 0);
+ return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_PM
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void s5p_mipi_dsi_early_suspend(struct early_suspend *handler)
+{
+ struct mipi_dsim_device *dsim =
+ container_of(handler, struct mipi_dsim_device, early_suspend);
+ struct platform_device *pdev = to_platform_device(dsim->dev);
+
+ dsim->dsim_lcd_drv->suspend(dsim);
+ s5p_mipi_dsi_d_phy_onoff(dsim, 0);
+ clk_disable(dsim->clock);
+ pm_runtime_put_sync(&pdev->dev);
+}
+
+static void s5p_mipi_dsi_late_resume(struct early_suspend *handler)
+{
+ struct mipi_dsim_device *dsim =
+ container_of(handler, struct mipi_dsim_device, early_suspend);
+ struct platform_device *pdev = to_platform_device(dsim->dev);
+
+#if defined(CONFIG_LCD_MIPI_TC358764)
+ int again = 1;
+ while (again != 0 && again <= 1000) {
+ pm_runtime_get_sync(&pdev->dev);
+ clk_enable(dsim->clock);
+ s5p_mipi_dsi_init_dsim(dsim);
+ s5p_mipi_dsi_init_link(dsim);
+ s5p_mipi_dsi_enable_hs_clock(dsim, 1);
+ s5p_mipi_dsi_set_cpu_transfer_mode(dsim, 1);
+ s5p_mipi_dsi_set_display_mode(dsim, dsim->dsim_config);
+ s5p_mipi_dsi_clear_int_status(dsim, INTSRC_SFR_FIFO_EMPTY);
+ if (dsim->dsim_lcd_drv->displayon(dsim) == 0)
+ again++;
+ else
+ again = 0;
+ s5p_mipi_dsi_set_cpu_transfer_mode(dsim, 0);
+ if (again != 0)
+ s5p_mipi_dsi_sw_reset(dsim);
+ }
+#else
+ pm_runtime_get_sync(&pdev->dev);
+ clk_enable(dsim->clock);
+ s5p_mipi_dsi_init_dsim(dsim);
+ s5p_mipi_dsi_init_link(dsim);
+ s5p_mipi_dsi_set_data_transfer_mode(dsim, 0);
+ s5p_mipi_dsi_set_display_mode(dsim, dsim->dsim_config);
+ dsim->dsim_lcd_drv->displayon(dsim);
+ s5p_mipi_dsi_set_hs_enable(dsim);
+#endif
+}
+#else
+static int s5p_mipi_dsi_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct mipi_dsim_device *dsim = platform_get_drvdata(pdev);
+
+ dsim->dsim_lcd_drv->suspend(dsim);
+ s5p_mipi_dsi_d_phy_onoff(dsim, 0);
+ clk_disable(dsim->clock);
+ pm_runtime_put_sync(dev);
+ return 0;
+}
+
+static int s5p_mipi_dsi_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct mipi_dsim_device *dsim = platform_get_drvdata(pdev);
+
+#if defined(CONFIG_LCD_MIPI_TC358764)
+ int again = 1;
+ while (again != 0 && again <= 1000) {
+ pm_runtime_get_sync(dev);
+ clk_enable(dsim->clock);
+ s5p_mipi_dsi_init_dsim(dsim);
+ s5p_mipi_dsi_init_link(dsim);
+ s5p_mipi_dsi_enable_hs_clock(dsim, 1);
+ s5p_mipi_dsi_set_cpu_transfer_mode(dsim, 1);
+ s5p_mipi_dsi_set_display_mode(dsim, dsim->dsim_config);
+ s5p_mipi_dsi_clear_int_status(dsim, INTSRC_SFR_FIFO_EMPTY);
+ if (dsim->dsim_lcd_drv->displayon(dsim) == 0)
+ again++;
+ else
+ again = 0;
+ s5p_mipi_dsi_set_cpu_transfer_mode(dsim, 0);
+ if (again != 0)
+ s5p_mipi_dsi_sw_reset(dsim);
+ }
+#else
+ pm_runtime_get_sync(dev);
+ clk_enable(dsim->clock);
+ s5p_mipi_dsi_init_dsim(dsim);
+ s5p_mipi_dsi_init_link(dsim);
+ s5p_mipi_dsi_set_data_transfer_mode(dsim, 0);
+ s5p_mipi_dsi_set_display_mode(dsim, dsim->dsim_config);
+ dsim->dsim_lcd_drv->displayon(dsim);
+ s5p_mipi_dsi_set_hs_enable(dsim);
+#endif
+
+ return 0;
+}
+#endif
+static int s5p_mipi_dsi_runtime_suspend(struct device *dev)
+{
+ return 0;
+}
+
+static int s5p_mipi_dsi_runtime_resume(struct device *dev)
+{
+ return 0;
+}
+#else
+#define s5p_mipi_dsi_suspend NULL
+#define s5p_mipi_dsi_resume NULL
+#define s5p_mipi_dsi_runtime_suspend NULL
+#define s5p_mipi_dsi_runtime_resume NULL
+#endif
+
+
+static int s5p_mipi_dsi_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct mipi_dsim_device *dsim = NULL;
+ struct mipi_dsim_config *dsim_config;
+ struct s5p_platform_mipi_dsim *dsim_pd;
+ int ret = -1;
+
+#ifdef CONFIG_LCD_MIPI_TC358764
+ int again = 1;
+#endif
+
+ if (!dsim)
+ dsim = kzalloc(sizeof(struct mipi_dsim_device),
+ GFP_KERNEL);
+ if (!dsim) {
+ dev_err(&pdev->dev, "failed to allocate dsim object.\n");
+ return -EFAULT;
+ }
+
+ dsim->pd = to_dsim_plat(&pdev->dev);
+ dsim->dev = &pdev->dev;
+ dsim->id = pdev->id;
+
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_get_sync(&pdev->dev);
+
+ /* get s5p_platform_mipi_dsim. */
+ dsim_pd = (struct s5p_platform_mipi_dsim *)dsim->pd;
+ /* get mipi_dsim_config. */
+ dsim_config = dsim_pd->dsim_config;
+ dsim->dsim_config = dsim_config;
+
+ dsim->clock = clk_get(&pdev->dev, dsim->pd->clk_name);
+ if (IS_ERR(dsim->clock)) {
+ dev_err(&pdev->dev, "failed to get dsim clock source\n");
+ goto err_clock_get;
+ }
+ clk_enable(dsim->clock);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "failed to get io memory region\n");
+ ret = -EINVAL;
+ goto err_platform_get;
+ }
+ res = request_mem_region(res->start, resource_size(res),
+ dev_name(&pdev->dev));
+ if (!res) {
+ dev_err(&pdev->dev, "failed to request io memory region\n");
+ ret = -EINVAL;
+ goto err_mem_region;
+ }
+
+ dsim->res = res;
+ dsim->reg_base = ioremap(res->start, resource_size(res));
+ if (!dsim->reg_base) {
+ dev_err(&pdev->dev, "failed to remap io region\n");
+ ret = -EINVAL;
+ goto err_mem_region;
+ }
+
+ /*
+ * it uses frame done interrupt handler
+ * only in case of MIPI Video mode.
+ */
+ if (dsim->pd->dsim_config->e_interface == DSIM_VIDEO) {
+ dsim->irq = platform_get_irq(pdev, 0);
+ if (request_irq(dsim->irq, s5p_mipi_dsi_interrupt_handler,
+ IRQF_DISABLED, "mipi-dsi", dsim)) {
+ dev_err(&pdev->dev, "request_irq failed.\n");
+ goto err_irq;
+ }
+ }
+
+ dsim->dsim_lcd_drv = dsim->dsim_config->dsim_ddi_pd;
+
+ if (dsim->dsim_config == NULL) {
+ dev_err(&pdev->dev, "dsim_config is NULL.\n");
+ goto err_dsim_config;
+ }
+
+#if defined(CONFIG_LCD_MIPI_TC358764)
+ while (again != 0 && again <= 1000) {
+ s5p_mipi_dsi_init_dsim(dsim);
+ s5p_mipi_dsi_init_link(dsim);
+ /* initialize mipi-dsi client(lcd panel). */
+ s5p_mipi_dsi_enable_hs_clock(dsim, 1);
+ s5p_mipi_dsi_set_cpu_transfer_mode(dsim, 1);
+ s5p_mipi_dsi_set_display_mode(dsim, dsim->dsim_config);
+ s5p_mipi_dsi_clear_int_status(dsim, INTSRC_SFR_FIFO_EMPTY);
+ if (dsim->dsim_lcd_drv->displayon(dsim) == 0)
+ again++;
+ else
+ again = 0;
+ s5p_mipi_dsi_set_cpu_transfer_mode(dsim, 0);
+ if (again != 0)
+ s5p_mipi_dsi_sw_reset(dsim);
+ }
+#else
+ s5p_mipi_dsi_init_dsim(dsim);
+ s5p_mipi_dsi_init_link(dsim);
+ /* initialize mipi-dsi client(lcd panel). */
+ s5p_mipi_dsi_set_data_transfer_mode(dsim, 0);
+ s5p_mipi_dsi_set_display_mode(dsim, dsim->dsim_config);
+ dsim->dsim_lcd_drv->displayon(dsim);
+ s5p_mipi_dsi_set_hs_enable(dsim);
+#endif
+ dev_info(&pdev->dev, "mipi-dsi driver(%s mode) has been probed.\n",
+ (dsim_config->e_interface == DSIM_COMMAND) ?
+ "CPU" : "RGB");
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ dsim->early_suspend.suspend = s5p_mipi_dsi_early_suspend;
+ dsim->early_suspend.resume = s5p_mipi_dsi_late_resume;
+ dsim->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB + 1;
+ register_early_suspend(&(dsim->early_suspend));
+#endif
+ platform_set_drvdata(pdev, dsim);
+
+ return 0;
+
+err_dsim_config:
+err_irq:
+ release_resource(dsim->res);
+ kfree(dsim->res);
+
+ iounmap((void __iomem *) dsim->reg_base);
+
+err_mem_region:
+err_platform_get:
+ clk_disable(dsim->clock);
+ clk_put(dsim->clock);
+
+err_clock_get:
+ kfree(dsim);
+ pm_runtime_put_sync(&pdev->dev);
+ return ret;
+
+}
+
+static int __devexit s5p_mipi_dsi_remove(struct platform_device *pdev)
+{
+ struct mipi_dsim_device *dsim = platform_get_drvdata(pdev);
+
+ if (dsim->dsim_config->e_interface == DSIM_VIDEO)
+ free_irq(dsim->irq, dsim);
+
+ iounmap(dsim->reg_base);
+
+ clk_disable(dsim->clock);
+ clk_put(dsim->clock);
+
+ release_resource(dsim->res);
+ kfree(dsim->res);
+
+ kfree(dsim);
+
+ return 0;
+}
+
+static const struct dev_pm_ops mipi_dsi_pm_ops = {
+#ifndef CONFIG_HAS_EARLYSUSPEND
+ .suspend = s5p_mipi_dsi_suspend,
+ .resume = s5p_mipi_dsi_resume,
+#endif
+ .runtime_suspend = s5p_mipi_dsi_runtime_suspend,
+ .runtime_resume = s5p_mipi_dsi_runtime_resume,
+};
+
+static struct platform_driver s5p_mipi_dsi_driver = {
+ .probe = s5p_mipi_dsi_probe,
+ .remove = __devexit_p(s5p_mipi_dsi_remove),
+ .driver = {
+ .name = "s5p-mipi-dsim",
+ .owner = THIS_MODULE,
+ .pm = &mipi_dsi_pm_ops,
+ },
+};
+
+static int s5p_mipi_dsi_register(void)
+{
+ platform_driver_register(&s5p_mipi_dsi_driver);
+
+ return 0;
+}
+
+static void s5p_mipi_dsi_unregister(void)
+{
+ platform_driver_unregister(&s5p_mipi_dsi_driver);
+}
+module_init(s5p_mipi_dsi_register);
+module_exit(s5p_mipi_dsi_unregister);
+
+MODULE_AUTHOR("InKi Dae <inki.dae@samsung.com>");
+MODULE_DESCRIPTION("Samusung MIPI-DSI driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/s5p_mipi_dsi.h b/drivers/video/s5p_mipi_dsi.h
new file mode 100644
index 0000000..b8833e4
--- /dev/null
+++ b/drivers/video/s5p_mipi_dsi.h
@@ -0,0 +1,54 @@
+/* linux/drivers/video/s5p_mipi_dsi.h
+ *
+ * Header file for Samsung MIPI-DSI common driver.
+ *
+ * Copyright (c) 2011 Samsung Electronics
+ * InKi Dae <inki.dae@samsung.com>
+ *
+ * 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.
+*/
+
+#ifndef _S5P_MIPI_DSI_H
+#define _S5P_MIPI_DSI_H
+
+/* MIPI-DSIM status types. */
+enum {
+ DSIM_STATE_INIT, /* should be initialized. */
+ DSIM_STATE_STOP, /* CPU and LCDC are LP mode. */
+ DSIM_STATE_HSCLKEN, /* HS clock was enabled. */
+ DSIM_STATE_ULPS
+};
+
+/* define DSI lane types. */
+enum {
+ DSIM_LANE_CLOCK = (1 << 0),
+ DSIM_LANE_DATA0 = (1 << 1),
+ DSIM_LANE_DATA1 = (1 << 2),
+ DSIM_LANE_DATA2 = (1 << 3),
+ DSIM_LANE_DATA3 = (1 << 4),
+};
+
+#ifndef MHZ
+#define MHZ (1000 * 1000)
+#endif
+#define FIN_HZ (24 * MHZ)
+
+#define DFIN_PLL_MIN_HZ (6 * MHZ)
+#define DFIN_PLL_MAX_HZ (12 * MHZ)
+
+#define DFVCO_MIN_HZ (500 * MHZ)
+#define DFVCO_MAX_HZ (1000 * MHZ)
+
+#define TRY_GET_FIFO_TIMEOUT (5000 * 2)
+
+#define DSIM_ESCCLK_ON (0x1)
+#define DSIM_ESCCLK_OFF (0x0)
+
+#define DSIM_CMD_LEN (0xf)
+
+int s5p_mipi_dsi_wr_data(struct mipi_dsim_device *dsim, unsigned int
+ data_id,
+ unsigned int data0, unsigned int data1);
+#endif /* _S5P_MIPI_DSI_H */
diff --git a/drivers/video/s5p_mipi_dsi_lowlevel.c b/drivers/video/s5p_mipi_dsi_lowlevel.c
new file mode 100644
index 0000000..a8cd656
--- /dev/null
+++ b/drivers/video/s5p_mipi_dsi_lowlevel.c
@@ -0,0 +1,564 @@
+/* linux/drivers/video/s5p_mipi_dsi_lowlevel.c
+ *
+ * Samsung MIPI-DSI lowlevel driver.
+ *
+ * Copyright (c) 2011 Samsung Electronics
+ *
+ * InKi Dae, <inki.dae@samsung.com>
+ *
+ * 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.
+*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/mutex.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/ctype.h>
+#include <linux/io.h>
+
+#include <mach/map.h>
+
+#include <plat/dsim.h>
+#include <plat/regs-mipidsim.h>
+
+void s5p_mipi_dsi_func_reset(struct mipi_dsim_device *dsim)
+{
+ unsigned int reg;
+
+ reg = readl(dsim->reg_base + S5P_DSIM_SWRST);
+
+ reg |= DSIM_FUNCRST;
+
+ writel(reg, dsim->reg_base + S5P_DSIM_SWRST);
+}
+
+void s5p_mipi_dsi_sw_reset(struct mipi_dsim_device *dsim)
+{
+ unsigned int reg;
+
+ reg = readl(dsim->reg_base + S5P_DSIM_SWRST);
+
+ reg |= DSIM_SWRST;
+
+ writel(reg, dsim->reg_base + S5P_DSIM_SWRST);
+}
+
+void s5p_mipi_dsi_set_interrupt_mask(struct mipi_dsim_device *dsim,
+ unsigned int mode, unsigned int mask)
+{
+ unsigned int reg = readl(dsim->reg_base + S5P_DSIM_INTMSK);
+
+ if (mask)
+ reg |= mode;
+ else
+ reg &= ~mode;
+
+ writel(reg, dsim->reg_base + S5P_DSIM_INTMSK);
+}
+
+void s5p_mipi_dsi_init_fifo_pointer(struct mipi_dsim_device *dsim,
+ unsigned int cfg)
+{
+ unsigned int reg;
+
+ reg = readl(dsim->reg_base + S5P_DSIM_FIFOCTRL);
+
+ writel(reg & ~(cfg), dsim->reg_base + S5P_DSIM_FIFOCTRL);
+ mdelay(10);
+ reg |= cfg;
+
+ writel(reg, dsim->reg_base + S5P_DSIM_FIFOCTRL);
+}
+
+/*
+ * this function set PLL P, M and S value in D-PHY
+ */
+void s5p_mipi_dsi_set_phy_tunning(struct mipi_dsim_device *dsim,
+ unsigned int value)
+{
+ writel(DSIM_AFC_CTL(value), dsim->reg_base + S5P_DSIM_PHYACCHR);
+}
+
+void s5p_mipi_dsi_set_main_disp_resol(struct mipi_dsim_device *dsim,
+ unsigned int vert_resol, unsigned int hori_resol)
+{
+ unsigned int reg;
+
+ /* standby should be set after configuration so set to not ready*/
+ reg = (readl(dsim->reg_base + S5P_DSIM_MDRESOL)) &
+ ~(DSIM_MAIN_STAND_BY);
+ writel(reg, dsim->reg_base + S5P_DSIM_MDRESOL);
+
+ reg &= ~(0x7ff << 16) & ~(0x7ff << 0);
+ reg |= DSIM_MAIN_VRESOL(vert_resol) | DSIM_MAIN_HRESOL(hori_resol);
+
+ reg |= DSIM_MAIN_STAND_BY;
+ writel(reg, dsim->reg_base + S5P_DSIM_MDRESOL);
+}
+
+void s5p_mipi_dsi_set_main_disp_vporch(struct mipi_dsim_device *dsim,
+ unsigned int cmd_allow, unsigned int vfront, unsigned int vback)
+{
+ unsigned int reg;
+
+ reg = (readl(dsim->reg_base + S5P_DSIM_MVPORCH)) &
+ ~(DSIM_CMD_ALLOW_MASK) & ~(DSIM_STABLE_VFP_MASK) &
+ ~(DSIM_MAIN_VBP_MASK);
+
+ reg |= ((cmd_allow & 0xf) << DSIM_CMD_ALLOW_SHIFT) |
+ ((vfront & 0x7ff) << DSIM_STABLE_VFP_SHIFT) |
+ ((vback & 0x7ff) << DSIM_MAIN_VBP_SHIFT);
+
+ writel(reg, dsim->reg_base + S5P_DSIM_MVPORCH);
+}
+
+void s5p_mipi_dsi_set_main_disp_hporch(struct mipi_dsim_device *dsim,
+ unsigned int front, unsigned int back)
+{
+ unsigned int reg;
+
+ reg = (readl(dsim->reg_base + S5P_DSIM_MHPORCH)) &
+ ~(DSIM_MAIN_HFP_MASK) & ~(DSIM_MAIN_HBP_MASK);
+
+ reg |= (front << DSIM_MAIN_HFP_SHIFT) | (back << DSIM_MAIN_HBP_SHIFT);
+
+ writel(reg, dsim->reg_base + S5P_DSIM_MHPORCH);
+}
+
+void s5p_mipi_dsi_set_main_disp_sync_area(struct mipi_dsim_device *dsim,
+ unsigned int vert, unsigned int hori)
+{
+ unsigned int reg;
+
+ reg = (readl(dsim->reg_base + S5P_DSIM_MSYNC)) &
+ ~(DSIM_MAIN_VSA_MASK) & ~(DSIM_MAIN_HSA_MASK);
+
+ reg |= ((vert & 0x3ff) << DSIM_MAIN_VSA_SHIFT) |
+ (hori << DSIM_MAIN_HSA_SHIFT);
+
+ writel(reg, dsim->reg_base + S5P_DSIM_MSYNC);
+}
+
+void s5p_mipi_dsi_set_sub_disp_resol(struct mipi_dsim_device *dsim,
+ unsigned int vert, unsigned int hori)
+{
+ unsigned int reg;
+
+ reg = (readl(dsim->reg_base + S5P_DSIM_SDRESOL)) &
+ ~(DSIM_SUB_STANDY_MASK);
+
+ writel(reg, dsim->reg_base + S5P_DSIM_SDRESOL);
+
+ reg &= ~(DSIM_SUB_VRESOL_MASK) | ~(DSIM_SUB_HRESOL_MASK);
+ reg |= ((vert & 0x7ff) << DSIM_SUB_VRESOL_SHIFT) |
+ ((hori & 0x7ff) << DSIM_SUB_HRESOL_SHIFT);
+ writel(reg, dsim->reg_base + S5P_DSIM_SDRESOL);
+
+ reg |= (1 << DSIM_SUB_STANDY_SHIFT);
+ writel(reg, dsim->reg_base + S5P_DSIM_SDRESOL);
+}
+
+void s5p_mipi_dsi_init_config(struct mipi_dsim_device *dsim)
+{
+ struct mipi_dsim_config *dsim_config = dsim->dsim_config;
+
+ unsigned int cfg = (readl(dsim->reg_base + S5P_DSIM_CONFIG)) &
+ ~(1 << 28) & ~(0x1f << 20) & ~(0x3 << 5);
+
+ cfg = (dsim_config->auto_flush << 29) |
+ (dsim_config->eot_disable << 28) |
+ (dsim_config->auto_vertical_cnt << DSIM_AUTO_MODE_SHIFT) |
+ (dsim_config->hse << DSIM_HSE_MODE_SHIFT) |
+ (dsim_config->hfp << DSIM_HFP_MODE_SHIFT) |
+ (dsim_config->hbp << DSIM_HBP_MODE_SHIFT) |
+ (dsim_config->hsa << DSIM_HSA_MODE_SHIFT) |
+ (dsim_config->e_no_data_lane << DSIM_NUM_OF_DATALANE_SHIFT);
+
+ writel(cfg, dsim->reg_base + S5P_DSIM_CONFIG);
+}
+
+void s5p_mipi_dsi_display_config(struct mipi_dsim_device *dsim)
+{
+ u32 reg = (readl(dsim->reg_base + S5P_DSIM_CONFIG)) &
+ ~(0x3 << 26) & ~(1 << 25) & ~(0x3 << 18) & ~(0x7 << 12) &
+ ~(0x3 << 16) & ~(0x7 << 8);
+
+ if (dsim->pd->dsim_config->e_interface == DSIM_VIDEO)
+ reg |= (1 << 25);
+ else if (dsim->pd->dsim_config->e_interface == DSIM_COMMAND)
+ reg &= ~(1 << 25);
+ else {
+ dev_err(dsim->dev, "this ddi is not MIPI interface.\n");
+ return;
+ }
+
+ /* main lcd */
+ reg |= ((u8) (dsim->pd->dsim_config->e_burst_mode) & 0x3) << 26 |
+ ((u8) (dsim->pd->dsim_config->e_virtual_ch) & 0x3) << 18 |
+ ((u8) (dsim->pd->dsim_config->e_pixel_format) & 0x7) << 12;
+
+ writel(reg, dsim->reg_base + S5P_DSIM_CONFIG);
+}
+
+void s5p_mipi_dsi_enable_lane(struct mipi_dsim_device *dsim, unsigned int lane,
+ unsigned int enable)
+{
+ unsigned int reg;
+
+ reg = readl(dsim->reg_base + S5P_DSIM_CONFIG);
+
+ if (enable)
+ reg |= DSIM_LANE_ENx(lane);
+ else
+ reg &= ~DSIM_LANE_ENx(lane);
+
+ writel(reg, dsim->reg_base + S5P_DSIM_CONFIG);
+}
+
+
+void s5p_mipi_dsi_set_data_lane_number(struct mipi_dsim_device *dsim,
+ unsigned int count)
+{
+ unsigned int cfg;
+
+ /* get the data lane number. */
+ cfg = DSIM_NUM_OF_DATA_LANE(count);
+
+ writel(cfg, dsim->reg_base + S5P_DSIM_CONFIG);
+}
+
+void s5p_mipi_dsi_enable_afc(struct mipi_dsim_device *dsim, unsigned int enable,
+ unsigned int afc_code)
+{
+ unsigned int reg = readl(dsim->reg_base + S5P_DSIM_PHYACCHR);
+
+ if (enable) {
+ reg |= (1 << 14);
+ reg &= ~(0x7 << 5);
+ reg |= (afc_code & 0x7) << 5;
+ } else
+ reg &= ~(1 << 14);
+
+ writel(reg, dsim->reg_base + S5P_DSIM_PHYACCHR);
+}
+
+void s5p_mipi_dsi_enable_pll_bypass(struct mipi_dsim_device *dsim,
+ unsigned int enable)
+{
+ unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_CLKCTRL)) &
+ ~(DSIM_PLL_BYPASS_EXTERNAL);
+
+ reg |= enable << DSIM_PLL_BYPASS_SHIFT;
+
+ writel(reg, dsim->reg_base + S5P_DSIM_CLKCTRL);
+}
+
+void s5p_mipi_dsi_set_pll_pms(struct mipi_dsim_device *dsim, unsigned int p,
+ unsigned int m, unsigned int s)
+{
+ unsigned int reg = readl(dsim->reg_base + S5P_DSIM_PLLCTRL);
+
+ reg |= ((p & 0x3f) << 13) | ((m & 0x1ff) << 4) | ((s & 0x7) << 1);
+
+ writel(reg, dsim->reg_base + S5P_DSIM_PLLCTRL);
+}
+
+void s5p_mipi_dsi_pll_freq_band(struct mipi_dsim_device *dsim,
+ unsigned int freq_band)
+{
+ unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_PLLCTRL)) &
+ ~(0x1f << DSIM_FREQ_BAND_SHIFT);
+
+ reg |= ((freq_band & 0x1f) << DSIM_FREQ_BAND_SHIFT);
+
+ writel(reg, dsim->reg_base + S5P_DSIM_PLLCTRL);
+}
+
+void s5p_mipi_dsi_pll_freq(struct mipi_dsim_device *dsim,
+ unsigned int pre_divider, unsigned int main_divider,
+ unsigned int scaler)
+{
+ unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_PLLCTRL)) &
+ ~(0x7ffff << 1);
+
+ reg |= (pre_divider & 0x3f) << 13 | (main_divider & 0x1ff) << 4 |
+ (scaler & 0x7) << 1;
+
+ writel(reg, dsim->reg_base + S5P_DSIM_PLLCTRL);
+}
+
+void s5p_mipi_dsi_pll_stable_time(struct mipi_dsim_device *dsim,
+ unsigned int lock_time)
+{
+ writel(lock_time, dsim->reg_base + S5P_DSIM_PLLTMR);
+}
+
+void s5p_mipi_dsi_enable_pll(struct mipi_dsim_device *dsim, unsigned int enable)
+{
+ unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_PLLCTRL)) &
+ ~(0x1 << DSIM_PLL_EN_SHIFT);
+
+ reg |= ((enable & 0x1) << DSIM_PLL_EN_SHIFT);
+
+ writel(reg, dsim->reg_base + S5P_DSIM_PLLCTRL);
+}
+
+void s5p_mipi_dsi_set_byte_clock_src(struct mipi_dsim_device *dsim,
+ unsigned int src)
+{
+ unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_CLKCTRL)) &
+ ~(0x3 << DSIM_BYTE_CLK_SRC_SHIFT);
+
+ reg |= ((unsigned int) src) << DSIM_BYTE_CLK_SRC_SHIFT;
+
+ writel(reg, dsim->reg_base + S5P_DSIM_CLKCTRL);
+}
+
+void s5p_mipi_dsi_enable_byte_clock(struct mipi_dsim_device *dsim,
+ unsigned int enable)
+{
+ unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_CLKCTRL)) &
+ ~(1 << DSIM_BYTE_CLKEN_SHIFT);
+
+ reg |= enable << DSIM_BYTE_CLKEN_SHIFT;
+ writel(reg, dsim->reg_base + S5P_DSIM_CLKCTRL);
+}
+
+void s5p_mipi_dsi_set_esc_clk_prs(struct mipi_dsim_device *dsim,
+ unsigned int enable, unsigned int prs_val)
+{
+ unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_CLKCTRL)) &
+ ~(1 << DSIM_ESC_CLKEN_SHIFT) & ~(0xffff);
+
+ reg |= enable << DSIM_ESC_CLKEN_SHIFT;
+ if (enable)
+ reg |= prs_val;
+
+ writel(reg, dsim->reg_base + S5P_DSIM_CLKCTRL);
+}
+
+void s5p_mipi_dsi_enable_esc_clk_on_lane(struct mipi_dsim_device *dsim,
+ unsigned int lane_sel, unsigned int enable)
+{
+ unsigned int reg = readl(dsim->reg_base + S5P_DSIM_CLKCTRL);
+
+ if (enable)
+ reg |= DSIM_LANE_ESC_CLKEN(lane_sel);
+ else
+
+ reg &= ~DSIM_LANE_ESC_CLKEN(lane_sel);
+
+ writel(reg, dsim->reg_base + S5P_DSIM_CLKCTRL);
+}
+
+void s5p_mipi_dsi_force_dphy_stop_state(struct mipi_dsim_device *dsim,
+ unsigned int enable)
+{
+ unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_ESCMODE)) &
+ ~(0x1 << DSIM_FORCE_STOP_STATE_SHIFT);
+
+ reg |= ((enable & 0x1) << DSIM_FORCE_STOP_STATE_SHIFT);
+
+ writel(reg, dsim->reg_base + S5P_DSIM_ESCMODE);
+}
+
+unsigned int s5p_mipi_dsi_is_lane_state(struct mipi_dsim_device *dsim)
+{
+ unsigned int reg = readl(dsim->reg_base + S5P_DSIM_STATUS);
+ /**
+ * check clock and data lane states.
+ * if MIPI-DSI controller was enabled at bootloader then
+ * TX_READY_HS_CLK is enabled otherwise STOP_STATE_CLK.
+ * so it should be checked for two case.
+ */
+ if ((reg & DSIM_STOP_STATE_DAT(0xf)) &&
+ ((reg & DSIM_STOP_STATE_CLK) ||
+ (reg & DSIM_TX_READY_HS_CLK)))
+ return 1;
+ else
+ return 0;
+
+ return 0;
+}
+
+void s5p_mipi_dsi_set_stop_state_counter(struct mipi_dsim_device *dsim,
+ unsigned int cnt_val)
+{
+ unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_ESCMODE)) &
+ ~(0x7ff << DSIM_STOP_STATE_CNT_SHIFT);
+
+ reg |= ((cnt_val & 0x7ff) << DSIM_STOP_STATE_CNT_SHIFT);
+
+ writel(reg, dsim->reg_base + S5P_DSIM_ESCMODE);
+}
+
+void s5p_mipi_dsi_set_bta_timeout(struct mipi_dsim_device *dsim,
+ unsigned int timeout)
+{
+ unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_TIMEOUT)) &
+ ~(0xff << DSIM_BTA_TOUT_SHIFT);
+
+ reg |= (timeout << DSIM_BTA_TOUT_SHIFT);
+
+ writel(reg, dsim->reg_base + S5P_DSIM_TIMEOUT);
+}
+
+void s5p_mipi_dsi_set_lpdr_timeout(struct mipi_dsim_device *dsim,
+ unsigned int timeout)
+{
+ unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_TIMEOUT)) &
+ ~(0xffff << DSIM_LPDR_TOUT_SHIFT);
+
+ reg |= (timeout << DSIM_LPDR_TOUT_SHIFT);
+
+ writel(reg, dsim->reg_base + S5P_DSIM_TIMEOUT);
+}
+
+void s5p_mipi_dsi_set_cpu_transfer_mode(struct mipi_dsim_device *dsim,
+ unsigned int lp)
+{
+ unsigned int reg = readl(dsim->reg_base + S5P_DSIM_ESCMODE);
+
+ reg &= ~DSIM_CMD_LPDT_LP;
+
+ reg |= lp << DSIM_CMD_LPDT_SHIFT;
+
+ writel(reg, dsim->reg_base + S5P_DSIM_ESCMODE);
+}
+
+void s5p_mipi_dsi_set_lcdc_transfer_mode(struct mipi_dsim_device *dsim,
+ unsigned int lp)
+{
+ unsigned int reg = readl(dsim->reg_base + S5P_DSIM_ESCMODE);
+
+ reg &= ~DSIM_TX_LPDT_LP;
+
+ reg |= lp << DSIM_TX_LPDT_SHIFT;
+
+ writel(reg, dsim->reg_base + S5P_DSIM_ESCMODE);
+}
+
+void s5p_mipi_dsi_enable_hs_clock(struct mipi_dsim_device *dsim,
+ unsigned int enable)
+{
+ unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_CLKCTRL)) &
+ ~(1 << DSIM_TX_REQUEST_HSCLK_SHIFT);
+
+ reg |= enable << DSIM_TX_REQUEST_HSCLK_SHIFT;
+
+ writel(reg, dsim->reg_base + S5P_DSIM_CLKCTRL);
+}
+
+void s5p_mipi_dsi_dp_dn_swap(struct mipi_dsim_device *dsim,
+ unsigned int swap_en)
+{
+ unsigned int reg = readl(dsim->reg_base + S5P_DSIM_PHYACCHR1);
+
+ reg &= ~(0x3 << 0);
+ reg |= (swap_en & 0x3) << 0;
+
+ writel(reg, dsim->reg_base + S5P_DSIM_PHYACCHR1);
+}
+
+void s5p_mipi_dsi_hs_zero_ctrl(struct mipi_dsim_device *dsim,
+ unsigned int hs_zero)
+{
+ unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_PLLCTRL)) &
+ ~(0xf << 28);
+
+ reg |= ((hs_zero & 0xf) << 28);
+
+ writel(reg, dsim->reg_base + S5P_DSIM_PLLCTRL);
+}
+
+void s5p_mipi_dsi_prep_ctrl(struct mipi_dsim_device *dsim, unsigned int prep)
+{
+ unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_PLLCTRL)) &
+ ~(0x7 << 20);
+
+ reg |= ((prep & 0x7) << 20);
+
+ writel(reg, dsim->reg_base + S5P_DSIM_PLLCTRL);
+}
+
+void s5p_mipi_dsi_clear_interrupt(struct mipi_dsim_device *dsim,
+ unsigned int int_src)
+{
+ writel(int_src, dsim->reg_base + S5P_DSIM_INTSRC);
+}
+
+void s5p_mipi_dsi_clear_all_interrupt(struct mipi_dsim_device *dsim)
+{
+ unsigned int reg = readl(dsim->reg_base + S5P_DSIM_INTSRC);
+
+ reg |= 0xffffffff;
+
+ writel(reg, dsim->reg_base + S5P_DSIM_INTSRC);
+}
+
+unsigned int s5p_mipi_dsi_is_pll_stable(struct mipi_dsim_device *dsim)
+{
+ unsigned int reg;
+
+ reg = readl(dsim->reg_base + S5P_DSIM_STATUS);
+
+ return reg & (1 << 31) ? 1 : 0;
+}
+
+unsigned int s5p_mipi_dsi_get_fifo_state(struct mipi_dsim_device *dsim)
+{
+ unsigned int ret;
+
+ ret = readl(dsim->reg_base + S5P_DSIM_FIFOCTRL) & ~(0x1f);
+
+ return ret;
+}
+
+void s5p_mipi_dsi_wr_tx_header(struct mipi_dsim_device *dsim,
+ unsigned int di, unsigned int data0, unsigned int data1)
+{
+ unsigned int reg = (data1 << 16) | (data0 << 8) | ((di & 0x3f) << 0);
+ writel(reg, dsim->reg_base + S5P_DSIM_PKTHDR);
+}
+
+unsigned int _s5p_mipi_dsi_get_frame_done_status(struct mipi_dsim_device *dsim)
+{
+ unsigned int reg = readl(dsim->reg_base + S5P_DSIM_INTSRC);
+
+ return (reg & INTSRC_FRAME_DONE) ? 1 : 0;
+}
+
+void _s5p_mipi_dsi_clear_frame_done(struct mipi_dsim_device *dsim)
+{
+ unsigned int reg = readl(dsim->reg_base + S5P_DSIM_INTSRC);
+
+ writel(reg | INTSRC_FRAME_DONE, dsim->reg_base +
+ S5P_DSIM_INTSRC);
+}
+
+void s5p_mipi_dsi_wr_tx_data(struct mipi_dsim_device *dsim,
+ unsigned int tx_data)
+{
+ writel(tx_data, dsim->reg_base + S5P_DSIM_PAYLOAD);
+}
+
+unsigned int s5p_mipi_dsi_get_int_status(struct mipi_dsim_device *dsim)
+{
+ return readl(dsim->reg_base + S5P_DSIM_INTSRC);
+}
+
+void s5p_mipi_dsi_clear_int_status(struct mipi_dsim_device *dsim, unsigned int intSrc)
+{
+ writel(intSrc, dsim->reg_base + S5P_DSIM_INTSRC);
+}
+
+unsigned int s5p_mipi_dsi_get_FIFOCTRL_status(struct mipi_dsim_device *dsim)
+{
+ return readl(dsim->reg_base + S5P_DSIM_FIFOCTRL);
+}
diff --git a/drivers/video/s5p_mipi_dsi_lowlevel.h b/drivers/video/s5p_mipi_dsi_lowlevel.h
new file mode 100644
index 0000000..866b69d
--- /dev/null
+++ b/drivers/video/s5p_mipi_dsi_lowlevel.h
@@ -0,0 +1,103 @@
+/* linux/drivers/video/s5p_mipi_dsi_lowlevel.h
+ *
+ * Header file for Samsung MIPI-DSI lowlevel driver.
+ *
+ * Copyright (c) 2011 Samsung Electronics
+ * InKi Dae <inki.dae@samsung.com>
+ *
+ * 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.
+*/
+
+#ifndef _S5P_MIPI_DSI_LOWLEVEL_H
+#define _S5P_MIPI_DSI_LOWLEVEL_H
+
+void s5p_mipi_dsi_func_reset(struct mipi_dsim_device *dsim);
+void s5p_mipi_dsi_sw_reset(struct mipi_dsim_device *dsim);
+void s5p_mipi_dsi_set_interrupt_mask(struct mipi_dsim_device *dsim,
+ unsigned int mode, unsigned int mask);
+void s5p_mipi_dsi_set_data_lane_number(struct mipi_dsim_device *dsim,
+ unsigned int count);
+void s5p_mipi_dsi_init_fifo_pointer(struct mipi_dsim_device *dsim,
+ unsigned int cfg);
+void s5p_mipi_dsi_set_phy_tunning(struct mipi_dsim_device *dsim,
+ unsigned int value);
+void s5p_mipi_dsi_set_phy_tunning(struct mipi_dsim_device *dsim,
+ unsigned int value);
+void s5p_mipi_dsi_set_main_disp_resol(struct mipi_dsim_device *dsim,
+ unsigned int vert_resol, unsigned int hori_resol);
+void s5p_mipi_dsi_set_main_disp_vporch(struct mipi_dsim_device *dsim,
+ unsigned int cmd_allow, unsigned int vfront, unsigned int vback);
+void s5p_mipi_dsi_set_main_disp_hporch(struct mipi_dsim_device *dsim,
+ unsigned int front, unsigned int back);
+void s5p_mipi_dsi_set_main_disp_sync_area(struct mipi_dsim_device *dsim,
+ unsigned int vert, unsigned int hori);
+void s5p_mipi_dsi_set_sub_disp_resol(struct mipi_dsim_device *dsim,
+ unsigned int vert, unsigned int hori);
+void s5p_mipi_dsi_init_config(struct mipi_dsim_device *dsim);
+void s5p_mipi_dsi_display_config(struct mipi_dsim_device *dsim);
+void s5p_mipi_dsi_set_data_lane_number(struct mipi_dsim_device *dsim,
+ unsigned int count);
+void s5p_mipi_dsi_enable_lane(struct mipi_dsim_device *dsim,
+ unsigned int lane, unsigned int enable);
+void s5p_mipi_dsi_enable_afc(struct mipi_dsim_device *dsim,
+ unsigned int enable, unsigned int afc_code);
+void s5p_mipi_dsi_enable_pll_bypass(struct mipi_dsim_device *dsim,
+ unsigned int enable);
+void s5p_mipi_dsi_set_pll_pms(struct mipi_dsim_device *dsim,
+ unsigned int p, unsigned int m, unsigned int s);
+void s5p_mipi_dsi_pll_freq_band(struct mipi_dsim_device *dsim,
+ unsigned int freq_band);
+void s5p_mipi_dsi_pll_freq(struct mipi_dsim_device *dsim,
+ unsigned int pre_divider, unsigned int main_divider,
+ unsigned int scaler);
+void s5p_mipi_dsi_pll_stable_time(struct mipi_dsim_device *dsim,
+ unsigned int lock_time);
+void s5p_mipi_dsi_enable_pll(struct mipi_dsim_device *dsim,
+ unsigned int enable);
+void s5p_mipi_dsi_set_byte_clock_src(struct mipi_dsim_device *dsim,
+ unsigned int src);
+void s5p_mipi_dsi_enable_byte_clock(struct mipi_dsim_device *dsim,
+ unsigned int enable);
+void s5p_mipi_dsi_set_esc_clk_prs(struct mipi_dsim_device *dsim,
+ unsigned int enable, unsigned int prs_val);
+void s5p_mipi_dsi_enable_esc_clk_on_lane(struct mipi_dsim_device *dsim,
+ unsigned int lane_sel, unsigned int enable);
+void s5p_mipi_dsi_force_dphy_stop_state(struct mipi_dsim_device *dsim,
+ unsigned int enable);
+unsigned int s5p_mipi_dsi_is_lane_state(struct mipi_dsim_device *dsim);
+void s5p_mipi_dsi_set_stop_state_counter(struct mipi_dsim_device *dsim,
+ unsigned int cnt_val);
+void s5p_mipi_dsi_set_bta_timeout(struct mipi_dsim_device *dsim,
+ unsigned int timeout);
+void s5p_mipi_dsi_set_lpdr_timeout(struct mipi_dsim_device *dsim,
+ unsigned int timeout);
+void s5p_mipi_dsi_set_lcdc_transfer_mode(struct mipi_dsim_device *dsim,
+ unsigned int lp);
+void s5p_mipi_dsi_set_cpu_transfer_mode(struct mipi_dsim_device *dsim,
+ unsigned int lp);
+void s5p_mipi_dsi_enable_hs_clock(struct mipi_dsim_device *dsim,
+ unsigned int enable);
+void s5p_mipi_dsi_dp_dn_swap(struct mipi_dsim_device *dsim,
+ unsigned int swap_en);
+void s5p_mipi_dsi_hs_zero_ctrl(struct mipi_dsim_device *dsim,
+ unsigned int hs_zero);
+void s5p_mipi_dsi_prep_ctrl(struct mipi_dsim_device *dsim, unsigned int
+ prep);
+void s5p_mipi_dsi_clear_interrupt(struct mipi_dsim_device *dsim,
+ unsigned int int_src);
+void s5p_mipi_dsi_clear_all_interrupt(struct mipi_dsim_device *dsim);
+unsigned int s5p_mipi_dsi_is_pll_stable(struct mipi_dsim_device *dsim);
+unsigned int s5p_mipi_dsi_get_fifo_state(struct mipi_dsim_device *dsim);
+unsigned int _s5p_mipi_dsi_get_frame_done_status(struct mipi_dsim_device *dsim);
+void _s5p_mipi_dsi_clear_frame_done(struct mipi_dsim_device *dsim);
+void s5p_mipi_dsi_wr_tx_header(struct mipi_dsim_device *dsim,
+ unsigned int di, unsigned int data0, unsigned int data1);
+void s5p_mipi_dsi_wr_tx_data(struct mipi_dsim_device *dsim,
+ unsigned int tx_data);
+unsigned int s5p_mipi_dsi_get_int_status(struct mipi_dsim_device *dsim);
+void s5p_mipi_dsi_clear_int_status(struct mipi_dsim_device *dsim, unsigned int intSrc);
+unsigned int s5p_mipi_dsi_get_FIFOCTRL_status(struct mipi_dsim_device *dsim);
+
+#endif /* _S5P_MIPI_DSI_LOWLEVEL_H */
diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c
index 04e5a6d..7e2f3c9 100644
--- a/drivers/watchdog/s3c2410_wdt.c
+++ b/drivers/watchdog/s3c2410_wdt.c
@@ -42,10 +42,8 @@
#include <linux/err.h>
#include <mach/map.h>
-
-#undef S3C_VA_WATCHDOG
-#define S3C_VA_WATCHDOG (0)
-
+#include <plat/cpu.h>
+#include <plat/pm.h>
#include <plat/regs-watchdog.h>
#define CONFIG_S3C2410_WATCHDOG_ATBOOT (0)
@@ -78,10 +76,13 @@
static struct resource *wdt_mem;
static struct resource *wdt_irq;
static struct clk *wdt_clock;
-static void __iomem *wdt_base;
static unsigned int wdt_count;
static DEFINE_SPINLOCK(wdt_lock);
+static struct sleep_save wdt_save[] = {
+ SAVE_ITEM(S3C2410_WTCON),
+};
+
/* watchdog control routines */
#define DBG(fmt, ...) \
@@ -95,7 +96,7 @@
static int s3c2410wdt_keepalive(struct watchdog_device *wdd)
{
spin_lock(&wdt_lock);
- writel(wdt_count, wdt_base + S3C2410_WTCNT);
+ writel(wdt_count, S3C2410_WTCNT);
spin_unlock(&wdt_lock);
return 0;
@@ -105,9 +106,9 @@
{
unsigned long wtcon;
- wtcon = readl(wdt_base + S3C2410_WTCON);
+ wtcon = readl(S3C2410_WTCON);
wtcon &= ~(S3C2410_WTCON_ENABLE | S3C2410_WTCON_RSTEN);
- writel(wtcon, wdt_base + S3C2410_WTCON);
+ writel(wtcon, S3C2410_WTCON);
}
static int s3c2410wdt_stop(struct watchdog_device *wdd)
@@ -127,7 +128,7 @@
__s3c2410wdt_stop();
- wtcon = readl(wdt_base + S3C2410_WTCON);
+ wtcon = readl(S3C2410_WTCON);
wtcon |= S3C2410_WTCON_ENABLE | S3C2410_WTCON_DIV128;
if (soft_noboot) {
@@ -141,9 +142,9 @@
DBG("%s: wdt_count=0x%08x, wtcon=%08lx\n",
__func__, wdt_count, wtcon);
- writel(wdt_count, wdt_base + S3C2410_WTDAT);
- writel(wdt_count, wdt_base + S3C2410_WTCNT);
- writel(wtcon, wdt_base + S3C2410_WTCON);
+ writel(wdt_count, S3C2410_WTDAT);
+ writel(wdt_count, S3C2410_WTCNT);
+ writel(wtcon, S3C2410_WTCON);
spin_unlock(&wdt_lock);
return 0;
@@ -151,7 +152,7 @@
static inline int s3c2410wdt_is_running(void)
{
- return readl(wdt_base + S3C2410_WTCON) & S3C2410_WTCON_ENABLE;
+ return readl(S3C2410_WTCON) & S3C2410_WTCON_ENABLE;
}
static int s3c2410wdt_set_heartbeat(struct watchdog_device *wdd, unsigned timeout)
@@ -194,18 +195,28 @@
wdt_count = count;
/* update the pre-scaler */
- wtcon = readl(wdt_base + S3C2410_WTCON);
+ wtcon = readl(S3C2410_WTCON);
wtcon &= ~S3C2410_WTCON_PRESCALE_MASK;
wtcon |= S3C2410_WTCON_PRESCALE(divisor-1);
- writel(count, wdt_base + S3C2410_WTDAT);
- writel(wtcon, wdt_base + S3C2410_WTCON);
+ writel(count, S3C2410_WTDAT);
+ writel(wtcon, S3C2410_WTCON);
wdd->timeout = timeout;
return 0;
}
+void s3c2410wdt_save(void)
+{
+ s3c_pm_do_save(wdt_save, ARRAY_SIZE(wdt_save));
+}
+
+void s3c2410wdt_restore(void)
+{
+ s3c_pm_do_restore_core(wdt_save, ARRAY_SIZE(wdt_save));
+}
+
#define OPTIONS (WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE)
static const struct watchdog_info s3c2410_wdt_ident = {
@@ -281,12 +292,18 @@
static inline int s3c2410wdt_cpufreq_register(void)
{
+ if (soc_is_exynos5250())
+ return 0;
+
return cpufreq_register_notifier(&s3c2410wdt_cpufreq_transition_nb,
CPUFREQ_TRANSITION_NOTIFIER);
}
static inline void s3c2410wdt_cpufreq_deregister(void)
{
+ if (soc_is_exynos5250())
+ return;
+
cpufreq_unregister_notifier(&s3c2410wdt_cpufreq_transition_nb,
CPUFREQ_TRANSITION_NOTIFIER);
}
@@ -337,15 +354,6 @@
goto err;
}
- wdt_base = ioremap(wdt_mem->start, size);
- if (wdt_base == NULL) {
- dev_err(dev, "failed to ioremap() region\n");
- ret = -EINVAL;
- goto err_req;
- }
-
- DBG("probe: mapped wdt_base=%p\n", wdt_base);
-
wdt_clock = clk_get(&pdev->dev, "watchdog");
if (IS_ERR(wdt_clock)) {
dev_err(dev, "failed to find watchdog clock source\n");
@@ -404,7 +412,7 @@
/* print out a statement of readiness */
- wtcon = readl(wdt_base + S3C2410_WTCON);
+ wtcon = readl(S3C2410_WTCON);
dev_info(dev, "watchdog %sactive, reset %sabled, irq %sabled\n",
(wtcon & S3C2410_WTCON_ENABLE) ? "" : "in",
@@ -425,9 +433,6 @@
wdt_clock = NULL;
err_map:
- iounmap(wdt_base);
-
- err_req:
release_mem_region(wdt_mem->start, size);
err:
@@ -448,8 +453,6 @@
clk_put(wdt_clock);
wdt_clock = NULL;
- iounmap(wdt_base);
-
release_mem_region(wdt_mem->start, resource_size(wdt_mem));
wdt_irq = NULL;
wdt_mem = NULL;
@@ -469,8 +472,8 @@
static int s3c2410wdt_suspend(struct platform_device *dev, pm_message_t state)
{
/* Save watchdog state, and turn it off. */
- wtcon_save = readl(wdt_base + S3C2410_WTCON);
- wtdat_save = readl(wdt_base + S3C2410_WTDAT);
+ wtcon_save = readl(S3C2410_WTCON);
+ wtdat_save = readl(S3C2410_WTDAT);
/* Note that WTCNT doesn't need to be saved. */
s3c2410wdt_stop(&s3c2410_wdd);
@@ -482,9 +485,9 @@
{
/* Restore watchdog state. */
- writel(wtdat_save, wdt_base + S3C2410_WTDAT);
- writel(wtdat_save, wdt_base + S3C2410_WTCNT); /* Reset count */
- writel(wtcon_save, wdt_base + S3C2410_WTCON);
+ writel(wtdat_save, S3C2410_WTDAT);
+ writel(wtdat_save, S3C2410_WTCNT); /* Reset count */
+ writel(wtcon_save, S3C2410_WTCON);
pr_info("watchdog %sabled\n",
(wtcon_save & S3C2410_WTCON_ENABLE) ? "en" : "dis");
diff --git a/include/linux/amba/pl330.h b/include/linux/amba/pl330.h
index fe93758..c95df58 100644
--- a/include/linux/amba/pl330.h
+++ b/include/linux/amba/pl330.h
@@ -32,4 +32,6 @@
};
extern bool pl330_filter(struct dma_chan *chan, void *param);
+extern int pl330_dma_getposition(struct dma_chan *chan,
+ dma_addr_t *src, dma_addr_t *dst);
#endif /* __AMBA_PL330_H_ */
diff --git a/include/linux/cma.h b/include/linux/cma.h
new file mode 100644
index 0000000..0287f4e
--- /dev/null
+++ b/include/linux/cma.h
@@ -0,0 +1,493 @@
+#ifndef __LINUX_CMA_H
+#define __LINUX_CMA_H
+
+/* linux/include/linux/cma.h
+ *
+ * Contiguous Memory Allocator framework
+ * Copyright (c) 2010 by Samsung Electronics.
+ * Written by Michal Nazarewicz (m.nazarewicz@samsung.com)
+ *
+ * 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
+ */
+
+/*
+ * See Documentation/contiguous-memory.txt for details.
+ */
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+
+#define CMA_MAGIC (('c' << 24) | ('M' << 16) | ('a' << 8) | 0x42)
+
+enum {
+ CMA_REQ_DEV_KIND,
+ CMA_REQ_FROM_REG
+};
+
+/**
+ * An information about area exportable to user space.
+ * @magic: must always be CMA_MAGIC.
+ * @type: type of the request.
+ * @spec: either "dev/kind\0" or "regions\0" depending on @type.
+ * In any case, the string must be NUL terminated.
+ * additionally, in the latter case scanning stops at
+ * semicolon (';').
+ * @size: size of the chunk to allocate.
+ * @alignment: desired alignment of the chunk (must be power of two or zero).
+ * @start: when ioctl() finishes this stores physical address of the chunk.
+ */
+struct cma_alloc_request {
+ __u32 magic;
+ __u32 type;
+
+ /* __u64 to be compatible accross 32 and 64 bit systems. */
+ __u64 size;
+ __u64 alignment;
+ __u64 start;
+
+ char spec[32];
+};
+
+#define IOCTL_CMA_ALLOC _IOWR('p', 0, struct cma_alloc_request)
+
+
+/***************************** Kernel level API *****************************/
+
+#ifdef __KERNEL__
+
+#include <linux/rbtree.h>
+#include <linux/list.h>
+#if defined CONFIG_CMA_SYSFS
+# include <linux/kobject.h>
+#endif
+
+
+struct device;
+struct cma_info;
+
+/*
+ * Don't call it directly, use cma_alloc(), cma_alloc_from() or
+ * cma_alloc_from_region().
+ */
+dma_addr_t __must_check
+__cma_alloc(const struct device *dev, const char *type,
+ size_t size, dma_addr_t alignment);
+
+/* Don't call it directly, use cma_info() or cma_info_about(). */
+int
+__cma_info(struct cma_info *info, const struct device *dev, const char *type);
+
+
+/**
+ * cma_alloc - allocates contiguous chunk of memory.
+ * @dev: The device to perform allocation for.
+ * @type: A type of memory to allocate. Platform may define
+ * several different types of memory and device drivers
+ * can then request chunks of different types. Usually it's
+ * safe to pass NULL here which is the same as passing
+ * "common".
+ * @size: Size of the memory to allocate in bytes.
+ * @alignment: Desired alignment in bytes. Must be a power of two or
+ * zero. If alignment is less then a page size it will be
+ * set to page size. If unsure, pass zero here.
+ *
+ * On error returns a negative error cast to dma_addr_t. Use
+ * IS_ERR_VALUE() to check if returned value is indeed an error.
+ * Otherwise bus address of the chunk is returned.
+ */
+static inline dma_addr_t __must_check
+cma_alloc(const struct device *dev, const char *type,
+ size_t size, dma_addr_t alignment)
+{
+ return dev ? __cma_alloc(dev, type, size, alignment) : -EINVAL;
+}
+
+
+/**
+ * struct cma_info - information about regions returned by cma_info().
+ * @lower_bound: The smallest address that is possible to be
+ * allocated for given (dev, type) pair.
+ * @upper_bound: The one byte after the biggest address that is
+ * possible to be allocated for given (dev, type)
+ * pair.
+ * @total_size: Total size of regions mapped to (dev, type) pair.
+ * @free_size: Total free size in all of the regions mapped to (dev, type)
+ * pair. Because of possible race conditions, it is not
+ * guaranteed that the value will be correct -- it gives only
+ * an approximation.
+ * @count: Number of regions mapped to (dev, type) pair.
+ */
+struct cma_info {
+ dma_addr_t lower_bound, upper_bound;
+ size_t total_size, free_size;
+ unsigned count;
+};
+
+/**
+ * cma_info - queries information about regions.
+ * @info: Pointer to a structure where to save the information.
+ * @dev: The device to query information for.
+ * @type: A type of memory to query information for.
+ * If unsure, pass NULL here which is equal to passing
+ * "common".
+ *
+ * On error returns a negative error, zero otherwise.
+ */
+static inline int
+cma_info(struct cma_info *info, const struct device *dev, const char *type)
+{
+ return dev ? __cma_info(info, dev, type) : -EINVAL;
+}
+
+
+/**
+ * cma_free - frees a chunk of memory.
+ * @addr: Beginning of the chunk.
+ *
+ * Returns -ENOENT if there is no chunk at given location; otherwise
+ * zero. In the former case issues a warning.
+ */
+int cma_free(dma_addr_t addr);
+
+/**
+ * cma_get_virt - frees virtual address of cma memory.
+ * @phys: physical addrress
+ * @size: size of memory
+ * @noncached : 0 is cached, 1 is non-cached.
+ *
+ * Returns -ENOENT if there is no chunk at given location; otherwise
+ * zero. In the former case issues a warning.
+ */
+void *cma_get_virt(dma_addr_t phys, dma_addr_t size, int noncached);
+
+
+/****************************** Lower lever API *****************************/
+
+/**
+ * cma_alloc_from - allocates contiguous chunk of memory from named regions.
+ * @regions: Comma separated list of region names. Terminated by NUL
+ * byte or a semicolon.
+ * @size: Size of the memory to allocate in bytes.
+ * @alignment: Desired alignment in bytes. Must be a power of two or
+ * zero. If alignment is less then a page size it will be
+ * set to page size. If unsure, pass zero here.
+ *
+ * On error returns a negative error cast to dma_addr_t. Use
+ * IS_ERR_VALUE() to check if returned value is indeed an error.
+ * Otherwise bus address of the chunk is returned.
+ */
+static inline dma_addr_t __must_check
+cma_alloc_from(const char *regions, size_t size, dma_addr_t alignment)
+{
+ return __cma_alloc(NULL, regions, size, alignment);
+}
+
+/**
+ * cma_info_about - queries information about named regions.
+ * @info: Pointer to a structure where to save the information.
+ * @regions: Comma separated list of region names. Terminated by NUL
+ * byte or a semicolon.
+ *
+ * On error returns a negative error, zero otherwise.
+ */
+static inline int
+cma_info_about(struct cma_info *info, const const char *regions)
+{
+ return __cma_info(info, NULL, regions);
+}
+
+
+
+struct cma_allocator;
+
+/**
+ * struct cma_region - a region reserved for CMA allocations.
+ * @name: Unique name of the region. Read only.
+ * @start: Bus address of the region in bytes. Always aligned at
+ * least to a full page. Read only.
+ * @size: Size of the region in bytes. Multiply of a page size.
+ * Read only.
+ * @free_space: Free space in the region. Read only.
+ * @alignment: Desired alignment of the region in bytes. A power of two,
+ * always at least page size. Early.
+ * @alloc: Allocator used with this region. NULL means allocator is
+ * not attached. Private.
+ * @alloc_name: Allocator name read from cmdline. Private. This may be
+ * different from @alloc->name.
+ * @private_data: Allocator's private data.
+ * @users: Number of chunks allocated in this region.
+ * @list: Entry in list of regions. Private.
+ * @used: Whether region was already used, ie. there was at least
+ * one allocation request for. Private.
+ * @registered: Whether this region has been registered. Read only.
+ * @reserved: Whether this region has been reserved. Early. Read only.
+ * @copy_name: Whether @name and @alloc_name needs to be copied when
+ * this region is converted from early to normal. Early.
+ * Private.
+ * @free_alloc_name: Whether @alloc_name was kmalloced(). Private.
+ *
+ * Regions come in two types: an early region and normal region. The
+ * former can be reserved or not-reserved. Fields marked as "early"
+ * are only meaningful in early regions.
+ *
+ * Early regions are important only during initialisation. The list
+ * of early regions is built from the "cma" command line argument or
+ * platform defaults. Platform initialisation code is responsible for
+ * reserving space for unreserved regions that are placed on
+ * cma_early_regions list.
+ *
+ * Later, during CMA initialisation all reserved regions from the
+ * cma_early_regions list are registered as normal regions and can be
+ * used using standard mechanisms.
+ */
+struct cma_region {
+ const char *name;
+ dma_addr_t start;
+ size_t size;
+ union {
+ size_t free_space; /* Normal region */
+ dma_addr_t alignment; /* Early region */
+ };
+
+ struct cma_allocator *alloc;
+ const char *alloc_name;
+ void *private_data;
+
+ unsigned users;
+ struct list_head list;
+
+#if defined CONFIG_CMA_SYSFS
+ struct kobject kobj;
+#endif
+
+ unsigned used:1;
+ unsigned registered:1;
+ unsigned reserved:1;
+ unsigned copy_name:1;
+ unsigned free_alloc_name:1;
+};
+
+
+/**
+ * cma_region_register() - registers a region.
+ * @reg: Region to region.
+ *
+ * Region's start and size must be set.
+ *
+ * If name is set the region will be accessible using normal mechanism
+ * like mapping or cma_alloc_from() function otherwise it will be
+ * a private region and accessible only using the
+ * cma_alloc_from_region() function.
+ *
+ * If alloc is set function will try to initialise given allocator
+ * (and will return error if it failes). Otherwise alloc_name may
+ * point to a name of an allocator to use (if not set, the default
+ * will be used).
+ *
+ * All other fields are ignored and/or overwritten.
+ *
+ * Returns zero or negative error. In particular, -EADDRINUSE if
+ * region overlap with already existing region.
+ */
+int __must_check cma_region_register(struct cma_region *reg);
+
+/**
+ * cma_region_unregister() - unregisters a region.
+ * @reg: Region to unregister.
+ *
+ * Region is unregistered only if there are no chunks allocated for
+ * it. Otherwise, function returns -EBUSY.
+ *
+ * On success returs zero.
+ */
+int __must_check cma_region_unregister(struct cma_region *reg);
+
+
+/**
+ * cma_alloc_from_region() - allocates contiguous chunk of memory from region.
+ * @reg: Region to allocate chunk from.
+ * @size: Size of the memory to allocate in bytes.
+ * @alignment: Desired alignment in bytes. Must be a power of two or
+ * zero. If alignment is less then a page size it will be
+ * set to page size. If unsure, pass zero here.
+ *
+ * On error returns a negative error cast to dma_addr_t. Use
+ * IS_ERR_VALUE() to check if returned value is indeed an error.
+ * Otherwise bus address of the chunk is returned.
+ */
+dma_addr_t __must_check
+cma_alloc_from_region(struct cma_region *reg,
+ size_t size, dma_addr_t alignment);
+
+
+
+/****************************** Allocators API ******************************/
+
+/**
+ * struct cma_chunk - an allocated contiguous chunk of memory.
+ * @start: Bus address in bytes.
+ * @size: Size in bytes.
+ * @free_space: Free space in region in bytes. Read only.
+ * @reg: Region this chunk belongs to.
+ * @by_start: A node in an red-black tree with all chunks sorted by
+ * start address.
+ *
+ * The cma_allocator::alloc() operation need to set only the @start
+ * and @size fields. The rest is handled by the caller (ie. CMA
+ * glue).
+ */
+struct cma_chunk {
+ dma_addr_t start;
+ size_t size;
+
+ struct cma_region *reg;
+ struct rb_node by_start;
+};
+
+
+/**
+ * struct cma_allocator - a CMA allocator.
+ * @name: Allocator's unique name
+ * @init: Initialises an allocator on given region.
+ * @cleanup: Cleans up after init. May assume that there are no chunks
+ * allocated in given region.
+ * @alloc: Allocates a chunk of memory of given size in bytes and
+ * with given alignment. Alignment is a power of
+ * two (thus non-zero) and callback does not need to check it.
+ * May also assume that it is the only call that uses given
+ * region (ie. access to the region is synchronised with
+ * a mutex). This has to allocate the chunk object (it may be
+ * contained in a bigger structure with allocator-specific data.
+ * Required.
+ * @free: Frees allocated chunk. May also assume that it is the only
+ * call that uses given region. This has to free() the chunk
+ * object as well. Required.
+ * @list: Entry in list of allocators. Private.
+ */
+struct cma_allocator {
+ const char *name;
+
+ int (*init)(struct cma_region *reg);
+ void (*cleanup)(struct cma_region *reg);
+ struct cma_chunk *(*alloc)(struct cma_region *reg, size_t size,
+ dma_addr_t alignment);
+ void (*free)(struct cma_chunk *chunk);
+
+ struct list_head list;
+};
+
+
+/**
+ * cma_allocator_register() - Registers an allocator.
+ * @alloc: Allocator to register.
+ *
+ * Adds allocator to the list of allocators managed by CMA.
+ *
+ * All of the fields of cma_allocator structure must be set except for
+ * the optional name and the list's head which will be overriden
+ * anyway.
+ *
+ * Returns zero or negative error code.
+ */
+int cma_allocator_register(struct cma_allocator *alloc);
+
+
+/**************************** Initialisation API ****************************/
+
+/**
+ * cma_set_defaults() - specifies default command line parameters.
+ * @regions: A zero-sized entry terminated list of early regions.
+ * This array must not be placed in __initdata section.
+ * @map: Map attribute.
+ *
+ * This function should be called prior to cma_early_regions_reserve()
+ * and after early parameters have been parsed.
+ *
+ * Returns zero or negative error.
+ */
+int __init cma_set_defaults(struct cma_region *regions, const char *map);
+
+
+/**
+ * cma_early_regions - a list of early regions.
+ *
+ * Platform needs to allocate space for each of the region before
+ * initcalls are executed. If space is reserved, the reserved flag
+ * must be set. Platform initialisation code may choose to use
+ * cma_early_regions_allocate().
+ *
+ * Later, during CMA initialisation all reserved regions from the
+ * cma_early_regions list are registered as normal regions and can be
+ * used using standard mechanisms.
+ */
+extern struct list_head cma_early_regions __initdata;
+
+
+/**
+ * cma_early_region_register() - registers an early region.
+ * @reg: Region to add.
+ *
+ * Region's size, start and alignment must be set (however the last
+ * two can be zero). If name is set the region will be accessible
+ * using normal mechanism like mapping or cma_alloc_from() function
+ * otherwise it will be a private region accessible only using the
+ * cma_alloc_from_region().
+ *
+ * During platform initialisation, space is reserved for early
+ * regions. Later, when CMA initialises, the early regions are
+ * "converted" into normal regions. If cma_region::alloc is set, CMA
+ * will then try to setup given allocator on the region. Failure to
+ * do so will result in the region not being registered even though
+ * the space for it will still be reserved. If cma_region::alloc is
+ * not set, allocator will be attached to the region on first use and
+ * the value of cma_region::alloc_name will be taken into account if
+ * set.
+ *
+ * All other fields are ignored and/or overwritten.
+ *
+ * Returns zero or negative error. No checking if regions overlap is
+ * performed.
+ */
+int __init __must_check cma_early_region_register(struct cma_region *reg);
+
+
+/**
+ * cma_early_region_reserve() - reserves a physically contiguous memory region.
+ * @reg: Early region to reserve memory for.
+ *
+ * If platform supports bootmem this is the first allocator this
+ * function tries to use. If that failes (or bootmem is not
+ * supported) function tries to use memblec if it is available.
+ *
+ * On success sets reg->reserved flag.
+ *
+ * Returns zero or negative error.
+ */
+int __init cma_early_region_reserve(struct cma_region *reg);
+
+/**
+ * cma_early_regions_reserve() - helper function for reserving early regions.
+ * @reserve: Callbac function used to reserve space for region. Needs
+ * to return non-negative if allocation succeeded, negative
+ * error otherwise. NULL means cma_early_region_alloc() will
+ * be used.
+ *
+ * This function traverses the %cma_early_regions list and tries to
+ * reserve memory for each early region. It uses the @reserve
+ * callback function for that purpose. The reserved flag of each
+ * region is updated accordingly.
+ */
+void __init cma_early_regions_reserve(int (*reserve)(struct cma_region *reg));
+
+#else
+
+#define cma_set_defaults(regions, map) ((int)0)
+#define cma_early_region_reserve(region) ((int)-EOPNOTSUPP)
+#define cma_early_regions_reserve(reserve) do { } while (0)
+
+#endif
+
+#endif
diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
index 281c72a..0e21a1f 100644
--- a/include/linux/devfreq.h
+++ b/include/linux/devfreq.h
@@ -210,7 +210,20 @@
unsigned int downdifferential;
};
#endif
-
+#ifdef CONFIG_DEVFREQ_GOV_PM_QOS
+extern const struct devfreq_governor devfreq_pm_qos;
+/**
+ * struct devfreq_pm_qos_data - void *data fed to struct devfreq
+ * and devfreq_add_device
+ * @ bytes_per_sec_per_hz Ratio to convert throughput request to devfreq
+ * frequency.
+ * @ pm_qos_class pm_qos class to query for requested throughput
+ */
+struct devfreq_pm_qos_data {
+ unsigned int bytes_per_sec_per_hz;
+ int pm_qos_class;
+};
+#endif
#else /* !CONFIG_PM_DEVFREQ */
static struct devfreq *devfreq_add_device(struct device *dev,
struct devfreq_dev_profile *profile,
@@ -247,6 +260,7 @@
#define devfreq_performance NULL
#define devfreq_userspace NULL
#define devfreq_simple_ondemand NULL
+#define devfreq_pm_qos NULL
#endif /* CONFIG_PM_DEVFREQ */
diff --git a/include/linux/exynos_ion.h b/include/linux/exynos_ion.h
new file mode 100644
index 0000000..a79adb0
--- /dev/null
+++ b/include/linux/exynos_ion.h
@@ -0,0 +1,62 @@
+/*
+ * include/linux/exynos_ion.h
+ *
+ * Copyright (C) 2011 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#ifndef _LINUX_EXYNOS_ION_H
+#define _LINUX_EXYNOS_ION_H
+
+#include <linux/ion.h>
+
+enum {
+ ION_HEAP_TYPE_EXYNOS_CONTIG = ION_HEAP_TYPE_CUSTOM + 1,
+ ION_HEAP_TYPE_EXYNOS,
+ ION_HEAP_TYPE_EXYNOS_USER,
+};
+
+#define EXYNOS_ION_HEAP_SYSTEM_ID 0
+#define EXYNOS_ION_HEAP_EXYNOS_CONTIG_ID 4
+#define EXYNOS_ION_HEAP_EXYNOS_ID 5
+
+#define EXYNOS_ION_HEAP_EXYNOS_CONTIG_MASK (1 << EXYNOS_ION_HEAP_EXYNOS_CONTIG_ID)
+#define EXYNOS_ION_HEAP_EXYNOS_MASK (1 << EXYNOS_ION_HEAP_EXYNOS_ID)
+
+#define ION_EXYNOS_WRITE_MASK (1 << (BITS_PER_LONG - 1))
+#define ION_EXYNOS_MFC_SH_MASK (1 << (BITS_PER_LONG - 2))
+#define ION_EXYNOS_MSGBOX_SH_MASK (1 << (BITS_PER_LONG - 3))
+#define ION_EXYNOS_FIMD_VIDEO_MASK (1 << (BITS_PER_LONG - 4))
+#define ION_EXYNOS_GSC_MASK (1 << (BITS_PER_LONG - 5))
+#define ION_EXYNOS_MFC_OUTPUT_MASK (1 << (BITS_PER_LONG - 6))
+#define ION_EXYNOS_MFC_INPUT_MASK (1 << (BITS_PER_LONG - 7))
+#define ION_EXYNOS_MFC_FW_MASK (1 << (BITS_PER_LONG - 8))
+#define ION_EXYNOS_SECTBL_MASK (1 << (BITS_PER_LONG - 9))
+
+#define ION_HEAP_EXYNOS_MFC_SH_MASK \
+ (EXYNOS_ION_HEAP_EXYNOS_CONTIG_MASK|ION_EXYNOS_MFC_SH_MASK)
+#define ION_HEAP_EXYNOS_MFC_FW_MASK \
+ (EXYNOS_ION_HEAP_EXYNOS_CONTIG_MASK|ION_EXYNOS_MFC_FW_MASK)
+#define ION_HEAP_EXYNOS_SECTBL_MASK \
+ (EXYNOS_ION_HEAP_EXYNOS_CONTIG_MASK|ION_EXYNOS_SECTBL_MASK)
+#define ION_HEAP_EXYNOS_FIMD_VIDEO_MASK \
+ (EXYNOS_ION_HEAP_EXYNOS_CONTIG_MASK|ION_EXYNOS_FIMD_VIDEO_MASK)
+#define ION_HEAP_EXYNOS_GSC_MASK \
+ (EXYNOS_ION_HEAP_EXYNOS_CONTIG_MASK|ION_EXYNOS_GSC_MASK)
+#define ION_HEAP_EXYNOS_MFC_OUTPUT_MASK \
+ (EXYNOS_ION_HEAP_EXYNOS_CONTIG_MASK|ION_EXYNOS_MFC_OUTPUT_MASK)
+#define ION_HEAP_EXYNOS_MFC_INPUT_MASK \
+ (EXYNOS_ION_HEAP_EXYNOS_CONTIG_MASK|ION_EXYNOS_MFC_INPUT_MASK)
+#define ION_HEAP_EXYNOS_MSGBOX_SH_MASK \
+ (EXYNOS_ION_HEAP_EXYNOS_CONTIG_MASK|ION_EXYNOS_MSGBOX_SH_MASK)
+
+#endif /* _LINUX_ION_H */
diff --git a/include/linux/genalloc.h b/include/linux/genalloc.h
index 5e98eeb..4af1af6 100644
--- a/include/linux/genalloc.h
+++ b/include/linux/genalloc.h
@@ -72,7 +72,23 @@
return gen_pool_add_virt(pool, addr, -1, size, nid);
}
extern void gen_pool_destroy(struct gen_pool *);
-extern unsigned long gen_pool_alloc(struct gen_pool *, size_t);
+unsigned long __must_check
+gen_pool_alloc_aligned(struct gen_pool *pool, size_t size,
+ unsigned alignment_order);
+
+/**
+ * gen_pool_alloc() - allocate special memory from the pool
+ * @pool: Pool to allocate from.
+ * @size: Number of bytes to allocate from the pool.
+ *
+ * Allocate the requested number of bytes from the specified pool.
+ * Uses a first-fit algorithm.
+ */
+static inline unsigned long __must_check
+gen_pool_alloc(struct gen_pool *pool, size_t size)
+{
+ return gen_pool_alloc_aligned(pool, size, 0);
+}
extern void gen_pool_free(struct gen_pool *, unsigned long, size_t);
extern void gen_pool_for_each_chunk(struct gen_pool *,
void (*)(struct gen_pool *, struct gen_pool_chunk *, void *), void *);
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 629b823..4aeb4e9 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -53,11 +53,18 @@
u8 part_config;
u8 cache_ctrl;
u8 rst_n_function;
+ u8 max_packed_writes;
+ u8 max_packed_reads;
+ u8 packed_event_en;
unsigned int part_time; /* Units: ms */
unsigned int sa_timeout; /* Units: 100ns */
unsigned int generic_cmd6_time; /* Units: 10ms */
unsigned int power_off_longtime; /* Units: ms */
unsigned int hs_max_dtr;
+#define MMC_HIGH_26_MAX_DTR 26000000
+#define MMC_HIGH_52_MAX_DTR 52000000
+#define MMC_HIGH_DDR_MAX_DTR 52000000
+#define MMC_HS200_MAX_DTR 200000000
unsigned int sectors;
unsigned int card_type;
unsigned int hc_erase_size; /* In sectors */
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index 1b431c7..d787037 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -18,6 +18,9 @@
struct mmc_command {
u32 opcode;
u32 arg;
+#define MMC_CMD23_ARG_REL_WR (1 << 31)
+#define MMC_CMD23_ARG_PACKED ((0 << 31) | (1 << 30))
+#define MMC_CMD23_ARG_TAG_REQ (1 << 29)
u32 resp[4];
unsigned int flags; /* expected response type */
#define MMC_RSP_PRESENT (1 << 0)
@@ -143,6 +146,7 @@
extern int mmc_wait_for_app_cmd(struct mmc_host *, struct mmc_card *,
struct mmc_command *, int);
extern int mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int);
+extern int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd);
#define MMC_ERASE_ARG 0x00000000
#define MMC_SECURE_ERASE_ARG 0x80000000
diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
index 8f66e28..7c707e2 100644
--- a/include/linux/mmc/dw_mmc.h
+++ b/include/linux/mmc/dw_mmc.h
@@ -15,6 +15,7 @@
#define LINUX_MMC_DW_MMC_H
#include <linux/scatterlist.h>
+#include <linux/mmc/core.h>
#define MAX_MCI_SLOTS 2
@@ -125,6 +126,11 @@
struct mmc_request *mrq;
struct mmc_command *cmd;
struct mmc_data *data;
+ struct mmc_command stop;
+ bool stop_snd;
+ struct clk *hclk;
+ struct clk *cclk;
+ bool prv_err;
/* DMA interface members*/
int use_dma;
@@ -138,6 +144,7 @@
#else
struct dw_mci_dma_data *dma_data;
#endif
+ unsigned int desc_sz;
u32 cmd_status;
u32 data_status;
u32 stop_cmdr;
@@ -150,9 +157,11 @@
struct list_head queue;
u32 bus_hz;
+ u32 max_bus_hz;
u32 current_speed;
u32 num_slots;
u32 fifoth_val;
+ u32 cd_rd_thr;
u16 verid;
u16 data_offset;
struct device dev;
@@ -175,6 +184,9 @@
/* Workaround flags */
u32 quirks;
+ /* S/W reset timer */
+ struct timer_list timer;
+
struct regulator *vmmc; /* Power regulator */
unsigned long irq_flags; /* IRQ flags */
unsigned int irq;
@@ -187,6 +199,7 @@
void (*start)(struct dw_mci *host, unsigned int sg_len);
void (*complete)(struct dw_mci *host);
void (*stop)(struct dw_mci *host);
+ void (*reset)(struct dw_mci *host);
void (*cleanup)(struct dw_mci *host);
void (*exit)(struct dw_mci *host);
};
@@ -200,7 +213,18 @@
#define DW_MCI_QUIRK_HIGHSPEED BIT(2)
/* Unreliable card detection */
#define DW_MCI_QUIRK_BROKEN_CARD_DETECTION BIT(3)
+/* No detect end bit during read */
+#define DW_MCI_QUIRK_NO_DETECT_EBIT BIT(4)
+/* Hardware reset using power off/on of card */
+#define DW_MMC_QUIRK_HW_RESET_PW BIT(5)
+enum dw_mci_cd_types {
+ DW_MCI_CD_INTERNAL, /* use mmc internal CD line */
+ DW_MCI_CD_EXTERNAL, /* use external callback */
+ DW_MCI_CD_GPIO, /* use external gpio pin for CD line */
+ DW_MCI_CD_NONE, /* no CD line, use polling to detect card */
+ DW_MCI_CD_PERMANENT, /* no CD line, card permanently wired to host */
+};
struct dma_pdata;
@@ -218,9 +242,12 @@
u32 quirks; /* Workaround / Quirk flags */
unsigned int bus_hz; /* Bus speed */
+ unsigned int max_bus_hz; /* MAXIMUM Bus speed */
unsigned int caps; /* Capabilities */
unsigned int caps2; /* More capabilities */
+ unsigned int pm_caps; /* supported pm features */
+
/*
* Override fifo depth. If 0, autodetect it from the FIFOTH register,
* but note that this may not be reliable after a bootloader has used
@@ -231,11 +258,44 @@
/* delay in mS before detecting cards after interrupt */
u32 detect_delay_ms;
+ char *hclk_name;
+ char *cclk_name;
+
int (*init)(u32 slot_id, irq_handler_t , void *);
int (*get_ro)(u32 slot_id);
int (*get_cd)(u32 slot_id);
int (*get_ocr)(u32 slot_id);
int (*get_bus_wd)(u32 slot_id);
+ void (*cfg_gpio)(int width);
+ void (*hw_reset)(u32 slot_id);
+ void (*set_io_timing)(void *data, unsigned char timing);
+
+ /* Phase Shift Value */
+ unsigned int sdr_timing;
+ unsigned int ddr_timing;
+ u8 clk_drv;
+ u8 clk_smpl;
+ bool tuned;
+
+ /* cd_type: Type of Card Detection method (see cd_types enum above) */
+ enum dw_mci_cd_types cd_type;
+
+ /* Number of descriptors */
+ unsigned int desc_sz;
+
+ /* ext_cd_cleanup: Cleanup external card detect subsystem.
+ * ext_cd_init: Initialize external card detect subsystem.
+ * notify_func argument is a callback to the dwmci driver
+ * that triggers the card detection event. Callback arguments:
+ * dev is pointer to platform device of the host controller,
+ * state is new state of the card (0 - removed, 1 - inserted).
+ */
+
+ int (*ext_cd_init)(void (*notify_func)
+ (struct platform_device *, int state));
+ int (*ext_cd_cleanup)(void (*notify_func)
+ (struct platform_device *, int state));
+
/*
* Enable power to selected slot and set voltage to desired level.
* Voltage levels are specified using MMC_VDD_xxx defines defined
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 5674504..168148d 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -144,6 +144,8 @@
struct mmc_async_req {
/* active mmc request */
struct mmc_request *mrq;
+ struct mmc_request *__mrq;
+ bool __cond;
/*
* Check error status of completed mmc request.
* Returns 0 if success otherwise non zero.
@@ -239,6 +241,10 @@
#define MMC_CAP2_BROKEN_VOLTAGE (1 << 7) /* Use the broken voltage */
#define MMC_CAP2_DETECT_ON_ERR (1 << 8) /* On I/O err check card removal */
#define MMC_CAP2_HC_ERASE_SZ (1 << 9) /* High-capacity erase size */
+#define MMC_CAP2_PACKED_RD (1 << 10) /* Allow packed read */
+#define MMC_CAP2_PACKED_WR (1 << 11) /* Allow packed write */
+#define MMC_CAP2_PACKED_CMD (MMC_CAP2_PACKED_RD | \
+ MMC_CAP2_PACKED_WR) /* Allow packed commands */
mmc_pm_flag_t pm_caps; /* supported pm features */
unsigned int power_notify_type;
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index b822a2c..254901a 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -139,6 +139,7 @@
#define R1_CURRENT_STATE(x) ((x & 0x00001E00) >> 9) /* sx, b (4 bits) */
#define R1_READY_FOR_DATA (1 << 8) /* sx, a */
#define R1_SWITCH_ERROR (1 << 7) /* sx, c */
+#define R1_EXP_EVENT (1 << 6) /* sr, a */
#define R1_APP_CMD (1 << 5) /* sr, c */
#define R1_STATE_IDLE 0
@@ -274,6 +275,10 @@
#define EXT_CSD_FLUSH_CACHE 32 /* W */
#define EXT_CSD_CACHE_CTRL 33 /* R/W */
#define EXT_CSD_POWER_OFF_NOTIFICATION 34 /* R/W */
+#define EXT_CSD_PACKED_FAILURE_INDEX 35 /* RO */
+#define EXT_CSD_PACKED_CMD_STATUS 36 /* RO */
+#define EXT_CSD_EXP_EVENTS_STATUS 54 /* RO, 2 bytes */
+#define EXT_CSD_EXP_EVENTS_CTRL 56 /* R/W, 2 bytes */
#define EXT_CSD_DATA_SECTOR_SIZE 61 /* R */
#define EXT_CSD_GP_SIZE_MULT 143 /* R/W */
#define EXT_CSD_PARTITION_ATTRIBUTE 156 /* R/W */
@@ -318,6 +323,8 @@
#define EXT_CSD_CACHE_SIZE 249 /* RO, 4 bytes */
#define EXT_CSD_TAG_UNIT_SIZE 498 /* RO */
#define EXT_CSD_DATA_TAG_SUPPORT 499 /* RO */
+#define EXT_CSD_MAX_PACKED_WRITES 500 /* RO */
+#define EXT_CSD_MAX_PACKED_READS 501 /* RO */
#define EXT_CSD_HPI_FEATURES 503 /* RO */
/*
@@ -354,66 +361,6 @@
#define EXT_CSD_CARD_TYPE_SDR_1_2V (1<<5) /* Card can run at 200MHz */
/* SDR mode @1.2V I/O */
-#define EXT_CSD_CARD_TYPE_SDR_200 (EXT_CSD_CARD_TYPE_SDR_1_8V | \
- EXT_CSD_CARD_TYPE_SDR_1_2V)
-
-#define EXT_CSD_CARD_TYPE_SDR_ALL (EXT_CSD_CARD_TYPE_SDR_200 | \
- EXT_CSD_CARD_TYPE_52 | \
- EXT_CSD_CARD_TYPE_26)
-
-#define EXT_CSD_CARD_TYPE_SDR_1_2V_ALL (EXT_CSD_CARD_TYPE_SDR_1_2V | \
- EXT_CSD_CARD_TYPE_52 | \
- EXT_CSD_CARD_TYPE_26)
-
-#define EXT_CSD_CARD_TYPE_SDR_1_8V_ALL (EXT_CSD_CARD_TYPE_SDR_1_8V | \
- EXT_CSD_CARD_TYPE_52 | \
- EXT_CSD_CARD_TYPE_26)
-
-#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V (EXT_CSD_CARD_TYPE_SDR_1_2V | \
- EXT_CSD_CARD_TYPE_DDR_1_8V | \
- EXT_CSD_CARD_TYPE_52 | \
- EXT_CSD_CARD_TYPE_26)
-
-#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V (EXT_CSD_CARD_TYPE_SDR_1_8V | \
- EXT_CSD_CARD_TYPE_DDR_1_8V | \
- EXT_CSD_CARD_TYPE_52 | \
- EXT_CSD_CARD_TYPE_26)
-
-#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V (EXT_CSD_CARD_TYPE_SDR_1_2V | \
- EXT_CSD_CARD_TYPE_DDR_1_2V | \
- EXT_CSD_CARD_TYPE_52 | \
- EXT_CSD_CARD_TYPE_26)
-
-#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V (EXT_CSD_CARD_TYPE_SDR_1_8V | \
- EXT_CSD_CARD_TYPE_DDR_1_2V | \
- EXT_CSD_CARD_TYPE_52 | \
- EXT_CSD_CARD_TYPE_26)
-
-#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52 (EXT_CSD_CARD_TYPE_SDR_1_2V | \
- EXT_CSD_CARD_TYPE_DDR_52 | \
- EXT_CSD_CARD_TYPE_52 | \
- EXT_CSD_CARD_TYPE_26)
-
-#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52 (EXT_CSD_CARD_TYPE_SDR_1_8V | \
- EXT_CSD_CARD_TYPE_DDR_52 | \
- EXT_CSD_CARD_TYPE_52 | \
- EXT_CSD_CARD_TYPE_26)
-
-#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V (EXT_CSD_CARD_TYPE_SDR_200 | \
- EXT_CSD_CARD_TYPE_DDR_1_8V | \
- EXT_CSD_CARD_TYPE_52 | \
- EXT_CSD_CARD_TYPE_26)
-
-#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V (EXT_CSD_CARD_TYPE_SDR_200 | \
- EXT_CSD_CARD_TYPE_DDR_1_2V | \
- EXT_CSD_CARD_TYPE_52 | \
- EXT_CSD_CARD_TYPE_26)
-
-#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52 (EXT_CSD_CARD_TYPE_SDR_200 | \
- EXT_CSD_CARD_TYPE_DDR_52 | \
- EXT_CSD_CARD_TYPE_52 | \
- EXT_CSD_CARD_TYPE_26)
-
#define EXT_CSD_BUS_WIDTH_1 0 /* Card is in 1 bit mode */
#define EXT_CSD_BUS_WIDTH_4 1 /* Card is in 4 bit mode */
#define EXT_CSD_BUS_WIDTH_8 2 /* Card is in 8 bit mode */
@@ -437,6 +384,14 @@
#define EXT_CSD_PWR_CL_4BIT_MASK 0x0F /* 8 bit PWR CLS */
#define EXT_CSD_PWR_CL_8BIT_SHIFT 4
#define EXT_CSD_PWR_CL_4BIT_SHIFT 0
+
+#define EXT_CSD_PACKED_EVENT_EN (1 << 3)
+
+#define EXT_CSD_PACKED_FAILURE (1 << 3)
+
+#define EXT_CSD_PACKED_GENERIC_ERROR (1 << 0)
+#define EXT_CSD_PACKED_INDEXED_ERROR (1 << 1)
+
/*
* MMC_SWITCH access modes
*/
diff --git a/include/linux/platform_data/exynos_usb3_drd.h b/include/linux/platform_data/exynos_usb3_drd.h
new file mode 100644
index 0000000..dab4f77
--- /dev/null
+++ b/include/linux/platform_data/exynos_usb3_drd.h
@@ -0,0 +1,23 @@
+/* inlude/linux/platform_data/exynos_usb3_drd.h
+*
+* Copyright (c) 2012 Samsung Electronics Co. Ltd
+* Author: Anton Tikhomirov <av.tikhomirov@samsung.com>
+*
+* EXYNOS SuperSpeed USB 3.0 DRD Controller platform data
+*
+* 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.
+*/
+
+#ifndef _EXYNOS_USB3_DRD_H_
+#define _EXYNOS_USB3_DRD_H_
+
+struct exynos_usb3_drd_pdata {
+ int phy_type;
+ int (*phy_init)(struct platform_device *pdev, int type);
+ int (*phy_exit)(struct platform_device *pdev, int type);
+};
+
+extern void exynos_ss_udc_set_platdata(struct exynos_usb3_drd_pdata *pd);
+#endif
diff --git a/include/linux/pm_qos.h b/include/linux/pm_qos.h
index 233149c..de71108 100644
--- a/include/linux/pm_qos.h
+++ b/include/linux/pm_qos.h
@@ -14,6 +14,7 @@
PM_QOS_RESERVED = 0,
PM_QOS_CPU_DMA_LATENCY,
PM_QOS_NETWORK_LATENCY,
+ PM_QOS_MEMORY_THROUGHPUT,
PM_QOS_NETWORK_THROUGHPUT,
/* insert new class ID */
@@ -24,6 +25,7 @@
#define PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE (2000 * USEC_PER_SEC)
#define PM_QOS_NETWORK_LAT_DEFAULT_VALUE (2000 * USEC_PER_SEC)
+#define PM_QOS_MEMORY_THROUGHPUT_DEFAULT_VALUE 0
#define PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE 0
#define PM_QOS_DEV_LAT_DEFAULT_VALUE 0
@@ -41,7 +43,8 @@
enum pm_qos_type {
PM_QOS_UNITIALIZED,
PM_QOS_MAX, /* return the largest value */
- PM_QOS_MIN /* return the smallest value */
+ PM_QOS_MIN, /* return the smallest value */
+ PM_QOS_SUM, /* return sum of values greater than zero */
};
/*
diff --git a/include/linux/rbtree.h b/include/linux/rbtree.h
index 033b507..fcda1b2 100644
--- a/include/linux/rbtree.h
+++ b/include/linux/rbtree.h
@@ -130,6 +130,17 @@
}
#define RB_ROOT (struct rb_root) { NULL, }
+
+static inline void rb_root_init(struct rb_root *root, struct rb_node *node)
+{
+ root->rb_node = node;
+ if (node) {
+ node->rb_parent_color = RB_BLACK; /* black, no parent */
+ node->rb_left = NULL;
+ node->rb_right = NULL;
+ }
+}
+
#define rb_entry(ptr, type, member) container_of(ptr, type, member)
#define RB_EMPTY_ROOT(root) ((root)->rb_node == NULL)
diff --git a/include/linux/s3c-fb.h b/include/linux/s3c-fb.h
new file mode 100644
index 0000000..130bca3
--- /dev/null
+++ b/include/linux/s3c-fb.h
@@ -0,0 +1,109 @@
+/* include/linux/s3c-fb.h
+ *
+ * Copyright 2008 Openmoko Inc.
+ * Copyright 2008-2010 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ * http://armlinux.simtec.co.uk/
+ *
+ * Samsung SoC Framebuffer driver
+ *
+ * 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.
+*/
+
+#ifndef __S3C_FB_H__
+#define __S3C_FB_H__
+
+struct s3c_fb_user_window {
+ int x;
+ int y;
+};
+
+struct s3c_fb_user_plane_alpha {
+ int channel;
+ unsigned char red;
+ unsigned char green;
+ unsigned char blue;
+};
+
+struct s3c_fb_user_chroma {
+ int enabled;
+ unsigned char red;
+ unsigned char green;
+ unsigned char blue;
+};
+
+struct s3c_fb_user_ion_client {
+ int fd;
+ int offset;
+};
+
+enum s3c_fb_pixel_format {
+ S3C_FB_PIXEL_FORMAT_RGBA_8888 = 0,
+ S3C_FB_PIXEL_FORMAT_RGBX_8888 = 1,
+ S3C_FB_PIXEL_FORMAT_RGBA_5551 = 2,
+ S3C_FB_PIXEL_FORMAT_RGB_565 = 3,
+ S3C_FB_PIXEL_FORMAT_BGRA_8888 = 4,
+ S3C_FB_PIXEL_FORMAT_MAX = 5,
+};
+
+enum s3c_fb_blending {
+ S3C_FB_BLENDING_NONE = 0,
+ S3C_FB_BLENDING_PREMULT = 1,
+ S3C_FB_BLENDING_COVERAGE = 2,
+ S3C_FB_BLENDING_MAX = 3,
+};
+
+struct s3c_fb_win_config {
+ enum {
+ S3C_FB_WIN_STATE_DISABLED = 0,
+ S3C_FB_WIN_STATE_COLOR,
+ S3C_FB_WIN_STATE_BUFFER,
+ } state;
+
+ union {
+ __u32 color;
+ struct {
+ int fd;
+ __u32 offset;
+ __u32 stride;
+ enum s3c_fb_pixel_format format;
+ enum s3c_fb_blending blending;
+ int fence_fd;
+ };
+ };
+
+ int x;
+ int y;
+ __u32 w;
+ __u32 h;
+};
+
+/* S3C_FB_MAX_WIN
+ * Set to the maximum number of windows that any of the supported hardware
+ * can use. Since the platform data uses this for an array size, having it
+ * set to the maximum of any version of the hardware can do is safe.
+ */
+#define S3C_FB_MAX_WIN (5)
+
+struct s3c_fb_win_config_data {
+ int fence;
+ struct s3c_fb_win_config config[S3C_FB_MAX_WIN];
+};
+
+/* IOCTL commands */
+#define S3CFB_WIN_POSITION _IOW('F', 203, \
+ struct s3c_fb_user_window)
+#define S3CFB_WIN_SET_PLANE_ALPHA _IOW('F', 204, \
+ struct s3c_fb_user_plane_alpha)
+#define S3CFB_WIN_SET_CHROMA _IOW('F', 205, \
+ struct s3c_fb_user_chroma)
+#define S3CFB_SET_VSYNC_INT _IOW('F', 206, __u32)
+
+#define S3CFB_GET_ION_USER_HANDLE _IOWR('F', 208, \
+ struct s3c_fb_user_ion_client)
+#define S3CFB_WIN_CONFIG _IOW('F', 209, \
+ struct s3c_fb_win_config_data)
+
+#endif /* __S3C_FB_H__ */
diff --git a/include/linux/usb/ch9.h b/include/linux/usb/ch9.h
index af21f31..6ca8a35 100644
--- a/include/linux/usb/ch9.h
+++ b/include/linux/usb/ch9.h
@@ -88,6 +88,7 @@
#define USB_REQ_GET_INTERFACE 0x0A
#define USB_REQ_SET_INTERFACE 0x0B
#define USB_REQ_SYNCH_FRAME 0x0C
+#define USB_REQ_SET_SEL 0x30
#define USB_REQ_SET_ENCRYPTION 0x0D /* Wireless USB */
#define USB_REQ_GET_ENCRYPTION 0x0E
diff --git a/include/linux/v4l2-mediabus.h b/include/linux/v4l2-mediabus.h
index 5ea7f75..1a13cf3 100644
--- a/include/linux/v4l2-mediabus.h
+++ b/include/linux/v4l2-mediabus.h
@@ -46,6 +46,7 @@
V4L2_MBUS_FMT_BGR565_2X8_LE = 0x1006,
V4L2_MBUS_FMT_RGB565_2X8_BE = 0x1007,
V4L2_MBUS_FMT_RGB565_2X8_LE = 0x1008,
+ V4L2_MBUS_FMT_XRGB8888_4X8_LE = 0x1009,
/* YUV (including grey) - next is 0x2014 */
V4L2_MBUS_FMT_Y8_1X8 = 0x2001,
@@ -65,6 +66,7 @@
V4L2_MBUS_FMT_VYUY8_1X16 = 0x2010,
V4L2_MBUS_FMT_YUYV8_1X16 = 0x2011,
V4L2_MBUS_FMT_YVYU8_1X16 = 0x2012,
+ V4L2_MBUS_FMT_YUV8_1X24 = 0x2014,
V4L2_MBUS_FMT_YUYV10_1X20 = 0x200d,
V4L2_MBUS_FMT_YVYU10_1X20 = 0x200e,
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index c9c9a46..f3ca644 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -185,6 +185,7 @@
V4L2_MEMORY_MMAP = 1,
V4L2_MEMORY_USERPTR = 2,
V4L2_MEMORY_OVERLAY = 3,
+ V4L2_MEMORY_DMABUF = 4,
};
/* see also http://vektor.theorem.ca/graphics/ycbcr/ */
@@ -588,6 +589,8 @@
* should be passed to mmap() called on the video node)
* @userptr: when memory is V4L2_MEMORY_USERPTR, a userspace pointer
* pointing to this plane
+ * @fd: when memory is V4L2_MEMORY_DMABUF, a userspace file
+ * descriptor associated with this plane
* @data_offset: offset in the plane to the start of data; usually 0,
* unless there is a header in front of the data
*
@@ -602,6 +605,7 @@
union {
__u32 mem_offset;
unsigned long userptr;
+ int fd;
} m;
__u32 data_offset;
__u32 reserved[11];
@@ -624,6 +628,8 @@
* (or a "cookie" that should be passed to mmap() as offset)
* @userptr: for non-multiplanar buffers with memory == V4L2_MEMORY_USERPTR;
* a userspace pointer pointing to this buffer
+ * @fd: for non-multiplanar buffers with memory == V4L2_MEMORY_DMABUF;
+ * a userspace file descriptor associated with this buffer
* @planes: for multiplanar buffers; userspace pointer to the array of plane
* info structs for this buffer
* @length: size in bytes of the buffer (NOT its payload) for single-plane
@@ -650,6 +656,7 @@
__u32 offset;
unsigned long userptr;
struct v4l2_plane *planes;
+ int fd;
} m;
__u32 length;
__u32 input;
@@ -671,6 +678,8 @@
/* Cache handling flags */
#define V4L2_BUF_FLAG_NO_CACHE_INVALIDATE 0x0800
#define V4L2_BUF_FLAG_NO_CACHE_CLEAN 0x1000
+/* Expects and returns a sync fence */
+#define V4L2_BUF_FLAG_USE_SYNC 0x2000
/*
* O V E R L A Y P R E V I E W
@@ -982,6 +991,34 @@
#define V4L2_DV_1080P50 17 /* BT.1120 */
#define V4L2_DV_1080P60 18 /* BT.1120 */
+#define V4L2_DV_480P60 19
+#define V4L2_DV_1080I59_94 20
+#define V4L2_DV_1080P59_94 21
+
+#define V4L2_DV_720P60_FP 22
+#define V4L2_DV_720P60_SB_HALF 23
+#define V4L2_DV_720P60_TB 24
+#define V4L2_DV_720P59_94_FP 25
+#define V4L2_DV_720P59_94_SB_HALF 26
+#define V4L2_DV_720P59_94_TB 27
+#define V4L2_DV_720P50_FP 28
+#define V4L2_DV_720P50_SB_HALF 29
+#define V4L2_DV_720P50_TB 30
+#define V4L2_DV_1080P24_FP 31
+#define V4L2_DV_1080P24_SB_HALF 32
+#define V4L2_DV_1080P24_TB 33
+#define V4L2_DV_1080P23_98_FP 34
+#define V4L2_DV_1080P23_98_SB_HALF 35
+#define V4L2_DV_1080P23_98_TB 36
+#define V4L2_DV_1080I60_SB_HALF 37
+#define V4L2_DV_1080I59_94_SB_HALF 38
+#define V4L2_DV_1080I50_SB_HALF 39
+#define V4L2_DV_1080P60_SB_HALF 40
+#define V4L2_DV_1080P60_TB 41
+#define V4L2_DV_1080P30_FP 42
+#define V4L2_DV_1080P30_SB_HALF 43
+#define V4L2_DV_1080P30_TB 44
+
/*
* D V B T T I M I N G S
*/
@@ -1137,6 +1174,7 @@
#define V4L2_CTRL_CLASS_FM_TX 0x009b0000 /* FM Modulator control class */
#define V4L2_CTRL_CLASS_FLASH 0x009c0000 /* Camera flash controls */
#define V4L2_CTRL_CLASS_JPEG 0x009d0000 /* JPEG-compression controls */
+#define V4L2_CTRL_CLASS_CODEC 0x009e0000 /* Codec control class */
#define V4L2_CTRL_ID_MASK (0x0fffffff)
#define V4L2_CTRL_ID2CLASS(id) ((id) & 0x0fff0000UL)
diff --git a/include/linux/videodev2_exynos_camera.h b/include/linux/videodev2_exynos_camera.h
new file mode 100644
index 0000000..9a2634a0
--- /dev/null
+++ b/include/linux/videodev2_exynos_camera.h
@@ -0,0 +1,1215 @@
+/*
+ * Video for Linux Two header file for samsung
+ *
+ * Copyright (C) 2009, Dongsoo Nathaniel Kim<dongsoo45.kim@samsung.com>
+ *
+ * This header file contains several v4l2 APIs to be proposed to v4l2
+ * community and until bein accepted, will be used restrictly in Samsung's
+ * camera interface driver FIMC.
+ *
+ * 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.
+ */
+
+#ifndef __LINUX_VIDEODEV2_EXYNOS_CAMERA_H
+#define __LINUX_VIDEODEV2_EXYNOS_CAMERA_H
+
+/* Values for 'capabilities' field */
+/* Object detection device */
+#define V4L2_CAP_OBJ_RECOGNITION 0x10000000
+/* strobe control */
+#define V4L2_CAP_STROBE 0x20000000
+
+#define V4L2_CID_FOCUS_MODE (V4L2_CID_CAMERA_CLASS_BASE+17)
+/* Focus Methods */
+enum v4l2_focus_mode {
+ V4L2_FOCUS_MODE_AUTO = 0,
+ V4L2_FOCUS_MODE_MACRO = 1,
+ V4L2_FOCUS_MODE_MANUAL = 2,
+ V4L2_FOCUS_MODE_LASTP = 2,
+};
+
+#define V4L2_CID_ZOOM_MODE (V4L2_CID_CAMERA_CLASS_BASE+18)
+/* Zoom Methods */
+enum v4l2_zoom_mode {
+ V4L2_ZOOM_MODE_CONTINUOUS = 0,
+ V4L2_ZOOM_MODE_OPTICAL = 1,
+ V4L2_ZOOM_MODE_DIGITAL = 2,
+ V4L2_ZOOM_MODE_LASTP = 2,
+};
+
+/* Exposure Methods */
+#define V4L2_CID_PHOTOMETRY (V4L2_CID_CAMERA_CLASS_BASE+19)
+enum v4l2_photometry_mode {
+ V4L2_PHOTOMETRY_MULTISEG = 0, /*Multi Segment*/
+ V4L2_PHOTOMETRY_CWA = 1, /*Centre Weighted Average*/
+ V4L2_PHOTOMETRY_SPOT = 2,
+ V4L2_PHOTOMETRY_AFSPOT = 3, /*Spot metering on focused point*/
+ V4L2_PHOTOMETRY_LASTP = V4L2_PHOTOMETRY_AFSPOT,
+};
+
+/* Manual exposure control items menu type: iris, shutter, iso */
+#define V4L2_CID_CAM_APERTURE (V4L2_CID_CAMERA_CLASS_BASE+20)
+#define V4L2_CID_CAM_SHUTTER (V4L2_CID_CAMERA_CLASS_BASE+21)
+#define V4L2_CID_CAM_ISO (V4L2_CID_CAMERA_CLASS_BASE+22)
+
+/* Following CIDs are menu type */
+#define V4L2_CID_SCENEMODE (V4L2_CID_CAMERA_CLASS_BASE+23)
+#define V4L2_CID_CAM_STABILIZE (V4L2_CID_CAMERA_CLASS_BASE+24)
+#define V4L2_CID_CAM_MULTISHOT (V4L2_CID_CAMERA_CLASS_BASE+25)
+
+/* Control dynamic range */
+#define V4L2_CID_CAM_DR (V4L2_CID_CAMERA_CLASS_BASE+26)
+
+/* White balance preset control */
+#define V4L2_CID_WHITE_BALANCE_PRESET (V4L2_CID_CAMERA_CLASS_BASE+27)
+#define V4L2_CID_CAM_SENSOR_FW_VER (V4L2_CID_CAMERA_CLASS_BASE + 28)
+#define V4L2_CID_CAM_PHONE_FW_VER (V4L2_CID_CAMERA_CLASS_BASE + 29)
+
+/* CID extensions */
+#define V4L2_CID_ROTATION (V4L2_CID_PRIVATE_BASE + 0)
+#define V4L2_CID_PADDR_Y (V4L2_CID_PRIVATE_BASE + 1)
+#define V4L2_CID_PADDR_CB (V4L2_CID_PRIVATE_BASE + 2)
+#define V4L2_CID_PADDR_CR (V4L2_CID_PRIVATE_BASE + 3)
+#define V4L2_CID_PADDR_CBCR (V4L2_CID_PRIVATE_BASE + 4)
+#define V4L2_CID_OVERLAY_AUTO (V4L2_CID_PRIVATE_BASE + 5)
+#define V4L2_CID_OVERLAY_VADDR0 (V4L2_CID_PRIVATE_BASE + 6)
+#define V4L2_CID_OVERLAY_VADDR1 (V4L2_CID_PRIVATE_BASE + 7)
+#define V4L2_CID_OVERLAY_VADDR2 (V4L2_CID_PRIVATE_BASE + 8)
+#define V4L2_CID_OVLY_MODE (V4L2_CID_PRIVATE_BASE + 9)
+#define V4L2_CID_DST_INFO (V4L2_CID_PRIVATE_BASE + 10)
+/* UMP secure id control */
+#define V4L2_CID_GET_UMP_SECURE_ID (V4L2_CID_PRIVATE_BASE + 11)
+#define V4L2_CID_GET_PHY_SRC_YADDR (V4L2_CID_PRIVATE_BASE + 12)
+#define V4L2_CID_GET_PHY_SRC_CADDR (V4L2_CID_PRIVATE_BASE + 13)
+#define V4L2_CID_IMAGE_EFFECT_FN (V4L2_CID_PRIVATE_BASE + 16)
+#define V4L2_CID_IMAGE_EFFECT_APPLY (V4L2_CID_PRIVATE_BASE + 17)
+#define V4L2_CID_IMAGE_EFFECT_CB (V4L2_CID_PRIVATE_BASE + 18)
+#define V4L2_CID_IMAGE_EFFECT_CR (V4L2_CID_PRIVATE_BASE + 19)
+#define V4L2_CID_RESERVED_MEM_BASE_ADDR (V4L2_CID_PRIVATE_BASE + 20)
+#define V4L2_CID_FIMC_VERSION (V4L2_CID_PRIVATE_BASE + 21)
+
+#define V4L2_CID_STREAM_PAUSE (V4L2_CID_PRIVATE_BASE + 53)
+#define V4L2_CID_CACHE_FLUSH (V4L2_CID_PRIVATE_BASE + 61)
+#define V4L2_CID_RESERVED_MEM_SIZE (V4L2_CID_PRIVATE_BASE + 63)
+
+/* CID Extensions for camera sensor operations */
+#define V4L2_CID_CAM_PREVIEW_ONOFF (V4L2_CID_PRIVATE_BASE + 64)
+#define V4L2_CID_CAM_CAPTURE (V4L2_CID_PRIVATE_BASE + 65)
+/* #define V4L2_CID_CAM_JPEG_MEMSIZE (V4L2_CID_PRIVATE_BASE + 66) */
+
+#define V4L2_CID_CAM_DATE_INFO_YEAR (V4L2_CID_PRIVATE_BASE + 14)
+#define V4L2_CID_CAM_DATE_INFO_MONTH (V4L2_CID_PRIVATE_BASE + 15)
+#define V4L2_CID_CAM_DATE_INFO_DATE (V4L2_CID_PRIVATE_BASE + 22)
+#define V4L2_CID_CAM_SENSOR_VER (V4L2_CID_PRIVATE_BASE + 23)
+#define V4L2_CID_CAM_FW_MINOR_VER (V4L2_CID_PRIVATE_BASE + 24)
+#define V4L2_CID_CAM_FW_MAJOR_VER (V4L2_CID_PRIVATE_BASE + 25)
+#define V4L2_CID_CAM_PRM_MINOR_VER (V4L2_CID_PRIVATE_BASE + 26)
+#define V4L2_CID_CAM_PRM_MAJOR_VER (V4L2_CID_PRIVATE_BASE + 27)
+#define V4L2_CID_CAM_FW_VER (V4L2_CID_PRIVATE_BASE + 28)
+#define V4L2_CID_CAM_SET_FW_ADDR (V4L2_CID_PRIVATE_BASE + 29)
+#define V4L2_CID_CAM_SET_FW_SIZE (V4L2_CID_PRIVATE_BASE + 30)
+#define V4L2_CID_CAM_UPDATE_FW (V4L2_CID_PRIVATE_BASE + 31)
+enum v4l2_firmware_mode {
+ FW_MODE_UPDATE,
+ FW_MODE_VERSION,
+ FW_MODE_DUMP,
+};
+
+#define V4L2_CID_CAM_JPEG_MAIN_SIZE (V4L2_CID_PRIVATE_BASE + 32)
+#define V4L2_CID_CAM_JPEG_MAIN_OFFSET (V4L2_CID_PRIVATE_BASE + 33)
+#define V4L2_CID_CAM_JPEG_THUMB_SIZE (V4L2_CID_PRIVATE_BASE + 34)
+#define V4L2_CID_CAM_JPEG_THUMB_OFFSET (V4L2_CID_PRIVATE_BASE + 35)
+#define V4L2_CID_CAM_JPEG_POSTVIEW_OFFSET (V4L2_CID_PRIVATE_BASE + 36)
+#define V4L2_CID_CAM_JPEG_QUALITY (V4L2_CID_PRIVATE_BASE + 37)
+#define V4L2_CID_CAM_SENSOR_MAKER (V4L2_CID_PRIVATE_BASE + 38)
+#define V4L2_CID_CAM_SENSOR_OPTICAL (V4L2_CID_PRIVATE_BASE + 39)
+#define V4L2_CID_CAM_AF_VER_LOW (V4L2_CID_PRIVATE_BASE + 40)
+#define V4L2_CID_CAM_AF_VER_HIGH (V4L2_CID_PRIVATE_BASE + 41)
+#define V4L2_CID_CAM_GAMMA_RG_LOW (V4L2_CID_PRIVATE_BASE + 42)
+#define V4L2_CID_CAM_GAMMA_RG_HIGH (V4L2_CID_PRIVATE_BASE + 43)
+#define V4L2_CID_CAM_GAMMA_BG_LOW (V4L2_CID_PRIVATE_BASE + 44)
+#define V4L2_CID_CAM_GAMMA_BG_HIGH (V4L2_CID_PRIVATE_BASE + 45)
+#define V4L2_CID_CAM_DUMP_FW (V4L2_CID_PRIVATE_BASE + 46)
+#define V4L2_CID_CAM_GET_DUMP_SIZE (V4L2_CID_PRIVATE_BASE + 47)
+#define V4L2_CID_CAMERA_VT_MODE (V4L2_CID_PRIVATE_BASE + 48)
+#define V4L2_CID_CAMERA_VGA_BLUR (V4L2_CID_PRIVATE_BASE + 49)
+#define V4L2_CID_CAMERA_CAPTURE (V4L2_CID_PRIVATE_BASE + 50)
+#define V4L2_CID_CAMERA_HDR (V4L2_CID_PRIVATE_BASE + 51)
+
+#define V4L2_CID_MAIN_SW_DATE_INFO_YEAR (V4L2_CID_PRIVATE_BASE + 54)
+#define V4L2_CID_MAIN_SW_DATE_INFO_MONTH (V4L2_CID_PRIVATE_BASE + 55)
+#define V4L2_CID_MAIN_SW_DATE_INFO_DATE (V4L2_CID_PRIVATE_BASE + 56)
+#define V4L2_CID_MAIN_SW_FW_MINOR_VER (V4L2_CID_PRIVATE_BASE + 57)
+#define V4L2_CID_MAIN_SW_FW_MAJOR_VER (V4L2_CID_PRIVATE_BASE + 58)
+#define V4L2_CID_MAIN_SW_PRM_MINOR_VER (V4L2_CID_PRIVATE_BASE + 59)
+#define V4L2_CID_MAIN_SW_PRM_MAJOR_VER (V4L2_CID_PRIVATE_BASE + 60)
+
+#define V4L2_CID_FIMC_IS_BASE (V4L2_CTRL_CLASS_CAMERA | 0x1000)
+#define V4L2_CID_FIMC_IS_TUNE_BASE (V4L2_CTRL_CLASS_CAMERA | 0x2000)
+
+#define V4L2_CID_IS_LOAD_FW (V4L2_CID_FIMC_IS_BASE + 10)
+#define V4L2_CID_IS_INIT_PARAM (V4L2_CID_FIMC_IS_BASE + 11)
+#define V4L2_CID_IS_RESET (V4L2_CID_FIMC_IS_BASE + 12)
+#define V4L2_CID_IS_S_POWER (V4L2_CID_FIMC_IS_BASE + 13)
+enum is_set_power {
+ IS_POWER_OFF,
+ IS_POWER_ON
+};
+
+#define V4L2_CID_IS_S_STREAM (V4L2_CID_FIMC_IS_BASE + 14)
+enum is_set_stream {
+ IS_DISABLE_STREAM,
+ IS_ENABLE_STREAM
+};
+
+#define V4L2_CID_IS_S_SCENARIO_MODE (V4L2_CID_FIMC_IS_BASE + 15)
+#define V4L2_CID_IS_S_FORMAT_SCENARIO (V4L2_CID_FIMC_IS_BASE + 16)
+enum scenario_mode {
+ IS_MODE_PREVIEW_STILL,
+ IS_MODE_PREVIEW_VIDEO,
+ IS_MODE_CAPTURE_STILL,
+ IS_MODE_CAPTURE_VIDEO,
+ IS_MODE_MAX
+};
+
+#define V4L2_CID_IS_G_CAPABILITY (V4L2_CID_FIMC_IS_BASE + 17)
+#define V4L2_CID_IS_G_COMPLETES (V4L2_CID_FIMC_IS_BASE + 18)
+#define V4L2_CID_IS_FORCE_DONE (V4L2_CID_FIMC_IS_BASE + 50)
+
+/* global */
+#define V4L2_CID_IS_CAMERA_SHOT_MODE_NORMAL (V4L2_CID_FIMC_IS_BASE + 101)
+/* value : 1 : single shot , >=2 : continuous shot */
+
+#define V4L2_CID_IS_CAMERA_SENSOR_NUM (V4L2_CID_FIMC_IS_BASE + 201)
+
+#define V4L2_CID_IS_CAMERA_FOCUS_MODE (V4L2_CID_FIMC_IS_BASE + 401)
+enum is_focus_mode {
+ IS_FOCUS_MODE_AUTO,
+ IS_FOCUS_MODE_MACRO,
+ IS_FOCUS_MODE_INFINITY,
+ IS_FOCUS_MODE_CONTINUOUS,
+ IS_FOCUS_MODE_TOUCH,
+ IS_FOCUS_MODE_FACEDETECT,
+ IS_FOCUS_MODE_IDLE,
+ IS_FOCUS_MODE_MAX,
+};
+
+#define V4L2_CID_IS_CAMERA_FLASH_MODE (V4L2_CID_FIMC_IS_BASE + 402)
+enum is_flash_mode {
+ IS_FLASH_MODE_OFF,
+ IS_FLASH_MODE_AUTO,
+ IS_FLASH_MODE_AUTO_REDEYE,
+ IS_FLASH_MODE_ON,
+ IS_FLASH_MODE_TORCH,
+ IS_FLASH_MODE_MAX
+};
+
+#define V4L2_CID_IS_CAMERA_AWB_MODE (V4L2_CID_FIMC_IS_BASE + 403)
+enum is_awb_mode {
+ IS_AWB_AUTO,
+ IS_AWB_DAYLIGHT,
+ IS_AWB_CLOUDY,
+ IS_AWB_TUNGSTEN,
+ IS_AWB_FLUORESCENT,
+ IS_AWB_MAX
+};
+
+#define V4L2_CID_IS_CAMERA_IMAGE_EFFECT (V4L2_CID_FIMC_IS_BASE + 404)
+enum is_image_effect {
+ IS_IMAGE_EFFECT_DISABLE,
+ IS_IMAGE_EFFECT_MONOCHROME,
+ IS_IMAGE_EFFECT_NEGATIVE_MONO,
+ IS_IMAGE_EFFECT_NEGATIVE_COLOR,
+ IS_IMAGE_EFFECT_SEPIA,
+ IS_IMAGE_EFFECT_SEPIA_CB,
+ IS_IMAGE_EFFECT_SEPIA_CR,
+ IS_IMAGE_EFFECT_NEGATIVE,
+ IS_IMAGE_EFFECT_ARTFREEZE,
+ IS_IMAGE_EFFECT_EMBOSSING,
+ IS_IMAGE_EFFECT_SILHOUETTE,
+ IS_IMAGE_EFFECT_MAX
+};
+
+#define V4L2_CID_IS_CAMERA_ISO (V4L2_CID_FIMC_IS_BASE + 405)
+enum is_iso {
+ IS_ISO_AUTO,
+ IS_ISO_50,
+ IS_ISO_100,
+ IS_ISO_200,
+ IS_ISO_400,
+ IS_ISO_800,
+ IS_ISO_1600,
+ IS_ISO_MAX
+};
+
+#define V4L2_CID_IS_CAMERA_CONTRAST (V4L2_CID_FIMC_IS_BASE + 406)
+enum is_contrast {
+ IS_CONTRAST_AUTO,
+ IS_CONTRAST_MINUS_2,
+ IS_CONTRAST_MINUS_1,
+ IS_CONTRAST_DEFAULT,
+ IS_CONTRAST_PLUS_1,
+ IS_CONTRAST_PLUS_2,
+ IS_CONTRAST_MAX
+};
+
+#define V4L2_CID_IS_CAMERA_SATURATION (V4L2_CID_FIMC_IS_BASE + 407)
+enum is_saturation {
+ IS_SATURATION_MINUS_2,
+ IS_SATURATION_MINUS_1,
+ IS_SATURATION_DEFAULT,
+ IS_SATURATION_PLUS_1,
+ IS_SATURATION_PLUS_2,
+ IS_SATURATION_MAX
+};
+
+#define V4L2_CID_IS_CAMERA_SHARPNESS (V4L2_CID_FIMC_IS_BASE + 408)
+enum is_sharpness {
+ IS_SHARPNESS_MINUS_2,
+ IS_SHARPNESS_MINUS_1,
+ IS_SHARPNESS_DEFAULT,
+ IS_SHARPNESS_PLUS_1,
+ IS_SHARPNESS_PLUS_2,
+ IS_SHARPNESS_MAX
+};
+
+#define V4L2_CID_IS_CAMERA_EXPOSURE (V4L2_CID_FIMC_IS_BASE + 409)
+enum is_exposure {
+ IS_EXPOSURE_MINUS_4,
+ IS_EXPOSURE_MINUS_3,
+ IS_EXPOSURE_MINUS_2,
+ IS_EXPOSURE_MINUS_1,
+ IS_EXPOSURE_DEFAULT,
+ IS_EXPOSURE_PLUS_1,
+ IS_EXPOSURE_PLUS_2,
+ IS_EXPOSURE_PLUS_3,
+ IS_EXPOSURE_PLUS_4,
+ IS_EXPOSURE_MAX
+};
+
+#define V4L2_CID_IS_CAMERA_BRIGHTNESS (V4L2_CID_FIMC_IS_BASE + 410)
+enum is_brightness {
+ IS_BRIGHTNESS_MINUS_2,
+ IS_BRIGHTNESS_MINUS_1,
+ IS_BRIGHTNESS_DEFAULT,
+ IS_BRIGHTNESS_PLUS_1,
+ IS_BRIGHTNESS_PLUS_2,
+ IS_BRIGHTNESS_MAX
+};
+
+#define V4L2_CID_IS_CAMERA_HUE (V4L2_CID_FIMC_IS_BASE + 411)
+enum is_hue {
+ IS_HUE_MINUS_2,
+ IS_HUE_MINUS_1,
+ IS_HUE_DEFAULT,
+ IS_HUE_PLUS_1,
+ IS_HUE_PLUS_2,
+ IS_HUE_MAX
+};
+
+#define V4L2_CID_IS_CAMERA_METERING (V4L2_CID_FIMC_IS_BASE + 412)
+enum is_metering {
+ IS_METERING_AVERAGE,
+ IS_METERING_SPOT,
+ IS_METERING_MATRIX,
+ IS_METERING_CENTER,
+ IS_METERING_MAX
+};
+#define V4L2_CID_IS_CAMERA_METERING_POSITION_X (V4L2_CID_FIMC_IS_BASE + 500)
+#define V4L2_CID_IS_CAMERA_METERING_POSITION_Y (V4L2_CID_FIMC_IS_BASE + 501)
+#define V4L2_CID_IS_CAMERA_METERING_WINDOW_X (V4L2_CID_FIMC_IS_BASE + 502)
+#define V4L2_CID_IS_CAMERA_METERING_WINDOW_Y (V4L2_CID_FIMC_IS_BASE + 503)
+
+#define V4L2_CID_IS_CAMERA_AFC_MODE (V4L2_CID_FIMC_IS_BASE + 413)
+enum is_afc_mode {
+ IS_AFC_DISABLE,
+ IS_AFC_AUTO,
+ IS_AFC_MANUAL_50HZ,
+ IS_AFC_MANUAL_60HZ,
+ IS_AFC_MAX
+};
+
+#define V4L2_CID_IS_AWB_LOCK_UNLOCK (V4L2_CID_FIMC_IS_BASE + 496)
+enum is_awb_lock_unlock {
+ IS_AWB_LOCK,
+ IS_AWB_UNLOCK,
+ IS_AWB_LOCK_UNLOCK_MAX
+};
+
+#define V4L2_CID_IS_AE_LOCK_UNLOCK (V4L2_CID_FIMC_IS_BASE + 497)
+enum is_ae_lock_unlock {
+ IS_AE_LOCK,
+ IS_AE_UNLOCK,
+ IS_AE_LOCK_UNLOCK_MAX
+};
+
+#define V4L2_CID_IS_FD_GET_FACE_COUNT (V4L2_CID_FIMC_IS_BASE + 600)
+#define V4L2_CID_IS_FD_GET_FACE_FRAME_NUMBER (V4L2_CID_FIMC_IS_BASE + 601)
+#define V4L2_CID_IS_FD_GET_FACE_CONFIDENCE (V4L2_CID_FIMC_IS_BASE + 602)
+#define V4L2_CID_IS_FD_GET_FACE_SMILE_LEVEL (V4L2_CID_FIMC_IS_BASE + 603)
+#define V4L2_CID_IS_FD_GET_FACE_BLINK_LEVEL (V4L2_CID_FIMC_IS_BASE + 604)
+#define V4L2_CID_IS_FD_GET_FACE_TOPLEFT_X (V4L2_CID_FIMC_IS_BASE + 605)
+#define V4L2_CID_IS_FD_GET_FACE_TOPLEFT_Y (V4L2_CID_FIMC_IS_BASE + 606)
+#define V4L2_CID_IS_FD_GET_FACE_BOTTOMRIGHT_X (V4L2_CID_FIMC_IS_BASE + 607)
+#define V4L2_CID_IS_FD_GET_FACE_BOTTOMRIGHT_Y (V4L2_CID_FIMC_IS_BASE + 608)
+#define V4L2_CID_IS_FD_GET_LEFT_EYE_TOPLEFT_X (V4L2_CID_FIMC_IS_BASE + 609)
+#define V4L2_CID_IS_FD_GET_LEFT_EYE_TOPLEFT_Y (V4L2_CID_FIMC_IS_BASE + 610)
+#define V4L2_CID_IS_FD_GET_LEFT_EYE_BOTTOMRIGHT_X \
+ (V4L2_CID_FIMC_IS_BASE + 611)
+#define V4L2_CID_IS_FD_GET_LEFT_EYE_BOTTOMRIGHT_Y \
+ (V4L2_CID_FIMC_IS_BASE + 612)
+#define V4L2_CID_IS_FD_GET_RIGHT_EYE_TOPLEFT_X \
+ (V4L2_CID_FIMC_IS_BASE + 613)
+#define V4L2_CID_IS_FD_GET_RIGHT_EYE_TOPLEFT_Y \
+ (V4L2_CID_FIMC_IS_BASE + 614)
+#define V4L2_CID_IS_FD_GET_RIGHT_EYE_BOTTOMRIGHT_X \
+ (V4L2_CID_FIMC_IS_BASE + 615)
+#define V4L2_CID_IS_FD_GET_RIGHT_EYE_BOTTOMRIGHT_Y \
+ (V4L2_CID_FIMC_IS_BASE + 616)
+#define V4L2_CID_IS_FD_GET_MOUTH_TOPLEFT_X \
+ (V4L2_CID_FIMC_IS_BASE + 617)
+#define V4L2_CID_IS_FD_GET_MOUTH_TOPLEFT_Y \
+ (V4L2_CID_FIMC_IS_BASE + 618)
+#define V4L2_CID_IS_FD_GET_MOUTH_BOTTOMRIGHT_X \
+ (V4L2_CID_FIMC_IS_BASE + 619)
+#define V4L2_CID_IS_FD_GET_MOUTH_BOTTOMRIGHT_Y \
+ (V4L2_CID_FIMC_IS_BASE + 620)
+#define V4L2_CID_IS_FD_GET_ANGLE (V4L2_CID_FIMC_IS_BASE + 621)
+#define V4L2_CID_IS_FD_GET_YAW_ANGLE (V4L2_CID_FIMC_IS_BASE + 622)
+#define V4L2_CID_IS_FD_GET_NEXT (V4L2_CID_FIMC_IS_BASE + 623)
+#define V4L2_CID_IS_FD_GET_DATA (V4L2_CID_FIMC_IS_BASE + 624)
+
+#define V4L2_CID_IS_FD_SET_MAX_FACE_NUMBER (V4L2_CID_FIMC_IS_BASE + 650)
+#define V4L2_CID_IS_FD_SET_ROLL_ANGLE (V4L2_CID_FIMC_IS_BASE + 651)
+enum is_fd_roll_angle {
+ /* 0, 45, 0, -45 */
+ IS_FD_ROLL_ANGLE_BASIC = 0,
+ /* 0, 30, 0, -30, 0, 45, 0, -45 */
+ IS_FD_ROLL_ANGLE_PRECISE_BASIC = 1,
+ /* 0, 90, 0, -90 */
+ IS_FD_ROLL_ANGLE_SIDES = 2,
+ /* 0, 90, 0, -90 0, 45, 0, -45 */
+ IS_FD_ROLL_ANGLE_PRECISE_SIDES = 3,
+ /* 0, 90, 0, -90, 0, 180 */
+ IS_FD_ROLL_ANGLE_FULL = 4,
+ /* 0, 90, 0, -90, 0, 180, 0, 135, 0, -135 */
+ IS_FD_ROLL_ANGLE_PRECISE_FULL = 5,
+};
+
+#define V4L2_CID_IS_FD_SET_YAW_ANGLE (V4L2_CID_FIMC_IS_BASE + 652)
+enum is_fd_yaw_angle {
+ IS_FD_YAW_ANGLE_0 = 0,
+ IS_FD_YAW_ANGLE_45 = 1,
+ IS_FD_YAW_ANGLE_90 = 2,
+ IS_FD_YAW_ANGLE_45_90 = 3,
+};
+
+#define V4L2_CID_IS_FD_SET_SMILE_MODE (V4L2_CID_FIMC_IS_BASE + 653)
+enum is_fd_smile_mode {
+ IS_FD_SMILE_MODE_DISABLE = 0,
+ IS_FD_SMILE_MODE_ENABLE = 1,
+};
+
+#define V4L2_CID_IS_FD_SET_BLINK_MODE (V4L2_CID_FIMC_IS_BASE + 654)
+enum is_fd_blink_mode {
+ IS_FD_BLINK_MODE_DISABLE = 0,
+ IS_FD_BLINK_MODE_ENABLE = 1,
+};
+
+#define V4L2_CID_IS_FD_SET_EYE_DETECT_MODE (V4L2_CID_FIMC_IS_BASE + 655)
+enum is_fd_eye_detect_mode {
+ IS_FD_EYE_DETECT_DISABLE = 0,
+ IS_FD_EYE_DETECT_ENABLE = 1,
+};
+
+#define V4L2_CID_IS_FD_SET_MOUTH_DETECT_MODE (V4L2_CID_FIMC_IS_BASE + 656)
+enum is_fd_mouth_detect_mode {
+ IS_FD_MOUTH_DETECT_DISABLE = 0,
+ IS_FD_MOUTH_DETECT_ENABLE = 1,
+};
+
+#define V4L2_CID_IS_FD_SET_ORIENTATION_MODE (V4L2_CID_FIMC_IS_BASE + 657)
+enum is_fd_orientation_mode {
+ IS_FD_ORIENTATION_DISABLE = 0,
+ IS_FD_ORIENTATION_ENABLE = 1,
+};
+
+#define V4L2_CID_IS_FD_SET_ORIENTATION (V4L2_CID_FIMC_IS_BASE + 658)
+#define V4L2_CID_IS_FD_SET_DATA_ADDRESS (V4L2_CID_FIMC_IS_BASE + 659)
+
+#define V4L2_CID_IS_SET_ISP (V4L2_CID_FIMC_IS_BASE + 440)
+enum is_isp_bypass_mode {
+ IS_ISP_BYPASS_DISABLE,
+ IS_ISP_BYPASS_ENABLE,
+ IS_ISP_BYPASS_MAX
+};
+
+#define V4L2_CID_IS_SET_DRC (V4L2_CID_FIMC_IS_BASE + 441)
+enum is_drc_bypass_mode {
+ IS_DRC_BYPASS_DISABLE,
+ IS_DRC_BYPASS_ENABLE,
+ IS_DRC_BYPASS_MAX
+};
+
+#define V4L2_CID_IS_SET_FD (V4L2_CID_FIMC_IS_BASE + 442)
+enum is_fd_bypass_mode {
+ IS_FD_BYPASS_DISABLE,
+ IS_FD_BYPASS_ENABLE,
+ IS_FD_BYPASS_MAX
+};
+
+#define V4L2_CID_IS_SET_ODC (V4L2_CID_FIMC_IS_BASE + 443)
+enum is_odc_bypass_mode {
+ IS_ODC_BYPASS_DISABLE,
+ IS_ODC_BYPASS_ENABLE,
+ IS_ODC_BYPASS_MAX
+};
+
+#define V4L2_CID_IS_SET_DIS (V4L2_CID_FIMC_IS_BASE + 444)
+enum is_dis_bypass_mode {
+ IS_DIS_BYPASS_DISABLE,
+ IS_DIS_BYPASS_ENABLE,
+ IS_DIS_BYPASS_MAX
+};
+
+#define V4L2_CID_IS_SET_3DNR (V4L2_CID_FIMC_IS_BASE + 445)
+enum is_tdnr_bypass_mode {
+ IS_TDNR_BYPASS_DISABLE,
+ IS_TDNR_BYPASS_ENABLE,
+ IS_TDNR_BYPASS_MAX
+};
+
+#define V4L2_CID_IS_SET_SCALERC (V4L2_CID_FIMC_IS_BASE + 446)
+enum is_scalerc_bypass_mode {
+ IS_SCALERC_BYPASS_DISABLE,
+ IS_SCALERC_BYPASS_ENABLE,
+ IS_SCALERC_BYPASS_MAX
+};
+
+#define V4L2_CID_IS_SET_SCALERP (V4L2_CID_FIMC_IS_BASE + 446)
+enum is_scalerp_bypass_mode {
+ IS_SCALERP_BYPASS_DISABLE,
+ IS_SCALERP_BYPASS_ENABLE,
+ IS_SCALERP_BYPASS_MAX
+};
+
+#define V4L2_CID_IS_ROTATION_MODE (V4L2_CID_FIMC_IS_BASE + 450)
+enum is_rotation_mode {
+ IS_ROTATION_0,
+ IS_ROTATION_90,
+ IS_ROTATION_180,
+ IS_ROTATION_270,
+ IS_ROTATION_MAX
+};
+
+#define V4L2_CID_IS_3DNR_1ST_FRAME_MODE (V4L2_CID_FIMC_IS_BASE + 451)
+enum is_tdnr_1st_frame_mode {
+ IS_TDNR_1ST_FRAME_NOPROCESSING,
+ IS_TDNR_1ST_FRAME_2DNR,
+ IS_TDNR_MAX
+};
+
+#define V4L2_CID_IS_CAMERA_OBJECT_POSITION_X (V4L2_CID_FIMC_IS_BASE + 452)
+#define V4L2_CID_IS_CAMERA_OBJECT_POSITION_Y (V4L2_CID_FIMC_IS_BASE + 453)
+#define V4L2_CID_IS_CAMERA_WINDOW_SIZE_X (V4L2_CID_FIMC_IS_BASE + 454)
+#define V4L2_CID_IS_CAMERA_WINDOW_SIZE_Y (V4L2_CID_FIMC_IS_BASE + 455)
+
+#define V4L2_CID_IS_CAMERA_EXIF_EXPTIME (V4L2_CID_FIMC_IS_BASE + 456)
+#define V4L2_CID_IS_CAMERA_EXIF_FLASH (V4L2_CID_FIMC_IS_BASE + 457)
+#define V4L2_CID_IS_CAMERA_EXIF_ISO (V4L2_CID_FIMC_IS_BASE + 458)
+#define V4L2_CID_IS_CAMERA_EXIF_SHUTTERSPEED (V4L2_CID_FIMC_IS_BASE + 459)
+#define V4L2_CID_IS_CAMERA_EXIF_BRIGHTNESS (V4L2_CID_FIMC_IS_BASE + 460)
+
+#define V4L2_CID_IS_CAMERA_ISP_SEL_INPUT (V4L2_CID_FIMC_IS_BASE + 461)
+enum is_isp_sel_input {
+ IS_ISP_INPUT_OTF,
+ IS_ISP_INPUT_DMA1,
+ IS_ISP_INPUT_DMA2,
+ IS_ISP_INPUT_DMA12,
+ IS_ISP_INPUT_MAX
+};
+
+#define V4L2_CID_IS_CAMERA_ISP_SEL_OUTPUT (V4L2_CID_FIMC_IS_BASE + 462)
+enum is_isp_sel_output {
+ IS_ISP_OUTPUT_OTF,
+ IS_ISP_OUTPUT_DMA1,
+ IS_ISP_OUTPUT_DMA2,
+ IS_ISP_OUTPUT_DMA12,
+ IS_ISP_OUTPUT_OTF_DMA1,
+ IS_ISP_OUTPUT_OTF_DMA2,
+ IS_ISP_OUTPUT_OTF_DMA12,
+ IS_ISP_OUTPUT_MAX
+};
+
+#define V4L2_CID_IS_CAMERA_DRC_SEL_INPUT (V4L2_CID_FIMC_IS_BASE + 463)
+enum is_drc_sel_input {
+ IS_DRC_INPUT_OTF,
+ IS_DRC_INPUT_DMA,
+ IS_DRC_INPUT_MAX
+};
+
+#define V4L2_CID_IS_CAMERA_FD_SEL_INPUT (V4L2_CID_FIMC_IS_BASE + 464)
+enum is_fd_sel_input {
+ IS_FD_INPUT_OTF,
+ IS_FD_INPUT_DMA,
+ IS_FD_INPUT_MAX
+};
+
+#define V4L2_CID_IS_CAMERA_INIT_WIDTH (V4L2_CID_FIMC_IS_BASE + 465)
+#define V4L2_CID_IS_CAMERA_INIT_HEIGHT (V4L2_CID_FIMC_IS_BASE + 466)
+
+#define V4L2_CID_IS_CMD_ISP (V4L2_CID_FIMC_IS_BASE + 467)
+enum is_isp_cmd_mode {
+ IS_ISP_COMMAND_STOP,
+ IS_ISP_COMMAND_START,
+ IS_ISP_COMMAND_MAX
+};
+
+#define V4L2_CID_IS_CMD_DRC (V4L2_CID_FIMC_IS_BASE + 468)
+enum is_drc_cmd_mode {
+ IS_DRC_COMMAND_STOP,
+ IS_DRC_COMMAND_START,
+ IS_DRC_COMMAND_MAX
+};
+
+#define V4L2_CID_IS_CMD_FD (V4L2_CID_FIMC_IS_BASE + 469)
+enum is_fd_cmd_mode {
+ IS_FD_COMMAND_STOP,
+ IS_FD_COMMAND_START,
+ IS_FD_COMMAND_MAX
+};
+
+#define V4L2_CID_IS_CMD_ODC (V4L2_CID_FIMC_IS_BASE + 470)
+enum is_odc_cmd_mode {
+ IS_ODC_COMMAND_STOP,
+ IS_ODC_COMMAND_START,
+ IS_ODC_COMMAND_MAX
+};
+
+#define V4L2_CID_IS_CMD_DIS (V4L2_CID_FIMC_IS_BASE + 471)
+enum is_dis_cmd_mode {
+ IS_DIS_COMMAND_STOP,
+ IS_DIS_COMMAND_START,
+ IS_DIS_COMMAND_MAX
+};
+
+#define V4L2_CID_IS_CMD_TDNR (V4L2_CID_FIMC_IS_BASE + 472)
+enum is_tdnr_cmd_mode {
+ IS_TDNR_COMMAND_STOP,
+ IS_TDNR_COMMAND_START,
+ IS_TDNR_COMMAND_MAX
+};
+
+#define V4L2_CID_IS_CMD_SCALERC (V4L2_CID_FIMC_IS_BASE + 473)
+enum is_scalerc_cmd_mode {
+ IS_SCALERC_COMMAND_STOP,
+ IS_SCALERC_COMMAND_START,
+ IS_SCALERC_COMMAND_MAX
+};
+
+#define V4L2_CID_IS_CMD_SCALERP (V4L2_CID_FIMC_IS_BASE + 474)
+enum is_scalerp_cmd_mode {
+ IS_SCALERP_COMMAND_STOP,
+ IS_SCALERP_COMMAND_START,
+ IS_SCALERP_COMMAND_MAX
+};
+
+#define V4L2_CID_IS_GET_SENSOR_OFFSET_X (V4L2_CID_FIMC_IS_BASE + 480)
+#define V4L2_CID_IS_GET_SENSOR_OFFSET_Y (V4L2_CID_FIMC_IS_BASE + 481)
+#define V4L2_CID_IS_GET_SENSOR_WIDTH (V4L2_CID_FIMC_IS_BASE + 482)
+#define V4L2_CID_IS_GET_SENSOR_HEIGHT (V4L2_CID_FIMC_IS_BASE + 483)
+
+#define V4L2_CID_IS_GET_FRAME_VALID (V4L2_CID_FIMC_IS_BASE + 484)
+#define V4L2_CID_IS_SET_FRAME_VALID (V4L2_CID_FIMC_IS_BASE + 485)
+#define V4L2_CID_IS_GET_FRAME_BADMARK (V4L2_CID_FIMC_IS_BASE + 486)
+#define V4L2_CID_IS_SET_FRAME_BADMARK (V4L2_CID_FIMC_IS_BASE + 487)
+#define V4L2_CID_IS_GET_FRAME_CAPTURED (V4L2_CID_FIMC_IS_BASE + 488)
+#define V4L2_CID_IS_SET_FRAME_CAPTURED (V4L2_CID_FIMC_IS_BASE + 489)
+#define V4L2_CID_IS_SET_FRAME_NUMBER (V4L2_CID_FIMC_IS_BASE + 490)
+#define V4L2_CID_IS_GET_FRAME_NUMBER (V4L2_CID_FIMC_IS_BASE + 491)
+#define V4L2_CID_IS_CLEAR_FRAME_NUMBER (V4L2_CID_FIMC_IS_BASE + 492)
+#define V4L2_CID_IS_GET_LOSTED_FRAME_NUMBER (V4L2_CID_FIMC_IS_BASE + 493)
+#define V4L2_CID_IS_ISP_DMA_BUFFER_NUM (V4L2_CID_FIMC_IS_BASE + 494)
+#define V4L2_CID_IS_ISP_DMA_BUFFER_ADDRESS (V4L2_CID_FIMC_IS_BASE + 495)
+
+#define V4L2_CID_IS_ZOOM_STATE (V4L2_CID_FIMC_IS_BASE + 660)
+#define V4L2_CID_IS_ZOOM_MAX_LEVEL (V4L2_CID_FIMC_IS_BASE + 661)
+#define V4L2_CID_IS_ZOOM (V4L2_CID_FIMC_IS_BASE + 662)
+#define V4L2_CID_IS_FW_DEBUG_REGION_ADDR (V4L2_CID_FIMC_IS_BASE + 663)
+
+#define V4L2_CID_IS_TUNE_SEL_ENTRY (V4L2_CID_FIMC_IS_TUNE_BASE)
+#define V4L2_CID_IS_TUNE_SENSOR_EXPOSURE (V4L2_CID_FIMC_IS_TUNE_BASE + 1)
+#define V4L2_CID_IS_TUNE_SENSOR_ANALOG_GAIN (V4L2_CID_FIMC_IS_TUNE_BASE + 2)
+#define V4L2_CID_IS_TUNE_SENSOR_FRAME_RATE (V4L2_CID_FIMC_IS_TUNE_BASE + 3)
+#define V4L2_CID_IS_TUNE_SENSOR_ACTUATOR_POS (V4L2_CID_FIMC_IS_TUNE_BASE + 4)
+
+enum v4l2_blur {
+ BLUR_LEVEL_0 = 0,
+ BLUR_LEVEL_1,
+ BLUR_LEVEL_2,
+ BLUR_LEVEL_3,
+ BLUR_LEVEL_MAX,
+};
+
+#if 1
+#define V4L2_CID_CAMERA_SCENE_MODE (V4L2_CID_PRIVATE_BASE+70)
+enum v4l2_scene_mode {
+ SCENE_MODE_BASE,
+ SCENE_MODE_NONE,
+ SCENE_MODE_PORTRAIT,
+ SCENE_MODE_NIGHTSHOT,
+ SCENE_MODE_BACK_LIGHT,
+ SCENE_MODE_LANDSCAPE,
+ SCENE_MODE_SPORTS,
+ SCENE_MODE_PARTY_INDOOR,
+ SCENE_MODE_BEACH_SNOW,
+ SCENE_MODE_SUNSET,
+ SCENE_MODE_DUSK_DAWN,
+ SCENE_MODE_FALL_COLOR,
+ SCENE_MODE_FIREWORKS,
+ SCENE_MODE_TEXT,
+ SCENE_MODE_CANDLE_LIGHT,
+ SCENE_MODE_MAX,
+};
+
+#define V4L2_CID_CAMERA_FLASH_MODE (V4L2_CID_PRIVATE_BASE+71)
+enum v4l2_flash_mode {
+ FLASH_MODE_BASE,
+ FLASH_MODE_OFF,
+ FLASH_MODE_AUTO,
+ FLASH_MODE_ON,
+ FLASH_MODE_TORCH,
+ FLASH_MODE_MAX,
+};
+
+#define V4L2_CID_CAMERA_BRIGHTNESS (V4L2_CID_PRIVATE_BASE+72)
+enum v4l2_ev_mode {
+ EV_MINUS_4 = -4,
+ EV_MINUS_3 = -3,
+ EV_MINUS_2 = -2,
+ EV_MINUS_1 = -1,
+ EV_DEFAULT = 0,
+ EV_PLUS_1 = 1,
+ EV_PLUS_2 = 2,
+ EV_PLUS_3 = 3,
+ EV_PLUS_4 = 4,
+ EV_MAX,
+};
+
+#define V4L2_CID_CAMERA_WHITE_BALANCE (V4L2_CID_PRIVATE_BASE+73)
+enum v4l2_wb_mode {
+ WHITE_BALANCE_BASE = 0,
+ WHITE_BALANCE_AUTO,
+ WHITE_BALANCE_SUNNY,
+ WHITE_BALANCE_CLOUDY,
+ WHITE_BALANCE_TUNGSTEN,
+ WHITE_BALANCE_FLUORESCENT,
+ WHITE_BALANCE_MAX,
+};
+
+#define V4L2_CID_CAMERA_EFFECT (V4L2_CID_PRIVATE_BASE+74)
+enum v4l2_effect_mode {
+ IMAGE_EFFECT_BASE = 0,
+ IMAGE_EFFECT_NONE,
+ IMAGE_EFFECT_BNW,
+ IMAGE_EFFECT_SEPIA,
+ IMAGE_EFFECT_AQUA,
+ IMAGE_EFFECT_ANTIQUE,
+ IMAGE_EFFECT_NEGATIVE,
+ IMAGE_EFFECT_SHARPEN,
+ IMAGE_EFFECT_MAX,
+};
+
+#define V4L2_CID_CAMERA_ISO (V4L2_CID_PRIVATE_BASE+75)
+enum v4l2_iso_mode {
+ ISO_AUTO = 0,
+ ISO_50,
+ ISO_100,
+ ISO_200,
+ ISO_400,
+ ISO_800,
+ ISO_1600,
+ ISO_SPORTS,
+ ISO_NIGHT,
+ ISO_MOVIE,
+ ISO_MAX,
+};
+
+#define V4L2_CID_CAMERA_METERING (V4L2_CID_PRIVATE_BASE+76)
+enum v4l2_metering_mode {
+ METERING_BASE = 0,
+ METERING_MATRIX,
+ METERING_CENTER,
+ METERING_SPOT,
+ METERING_MAX,
+};
+
+#define V4L2_CID_CAMERA_CONTRAST (V4L2_CID_PRIVATE_BASE+77)
+enum v4l2_contrast_mode {
+ CONTRAST_MINUS_2 = 0,
+ CONTRAST_MINUS_1,
+ CONTRAST_DEFAULT,
+ CONTRAST_PLUS_1,
+ CONTRAST_PLUS_2,
+ CONTRAST_MAX,
+};
+
+#define V4L2_CID_CAMERA_SATURATION (V4L2_CID_PRIVATE_BASE+78)
+enum v4l2_saturation_mode {
+ SATURATION_MINUS_2 = 0,
+ SATURATION_MINUS_1,
+ SATURATION_DEFAULT,
+ SATURATION_PLUS_1,
+ SATURATION_PLUS_2,
+ SATURATION_MAX,
+};
+
+#define V4L2_CID_CAMERA_SHARPNESS (V4L2_CID_PRIVATE_BASE+79)
+enum v4l2_sharpness_mode {
+ SHARPNESS_MINUS_2 = 0,
+ SHARPNESS_MINUS_1,
+ SHARPNESS_DEFAULT,
+ SHARPNESS_PLUS_1,
+ SHARPNESS_PLUS_2,
+ SHARPNESS_MAX,
+};
+
+#define V4L2_CID_CAMERA_WDR (V4L2_CID_PRIVATE_BASE+80)
+enum v4l2_wdr_mode {
+ WDR_OFF,
+ WDR_ON,
+ WDR_MAX,
+};
+
+#define V4L2_CID_CAMERA_ANTI_SHAKE (V4L2_CID_PRIVATE_BASE+81)
+enum v4l2_anti_shake_mode {
+ ANTI_SHAKE_OFF,
+ ANTI_SHAKE_STILL_ON,
+ ANTI_SHAKE_MOVIE_ON,
+ ANTI_SHAKE_MAX,
+};
+
+#define V4L2_CID_CAMERA_TOUCH_AF_START_STOP (V4L2_CID_PRIVATE_BASE+82)
+enum v4l2_touch_af {
+ TOUCH_AF_STOP = 0,
+ TOUCH_AF_START,
+ TOUCH_AF_MAX,
+};
+
+#define V4L2_CID_CAMERA_SMART_AUTO (V4L2_CID_PRIVATE_BASE+83)
+enum v4l2_smart_auto {
+ SMART_AUTO_OFF = 0,
+ SMART_AUTO_ON,
+ SMART_AUTO_MAX,
+};
+
+#define V4L2_CID_CAMERA_VINTAGE_MODE (V4L2_CID_PRIVATE_BASE+84)
+enum v4l2_vintage_mode {
+ VINTAGE_MODE_BASE,
+ VINTAGE_MODE_OFF,
+ VINTAGE_MODE_NORMAL,
+ VINTAGE_MODE_WARM,
+ VINTAGE_MODE_COOL,
+ VINTAGE_MODE_BNW,
+ VINTAGE_MODE_MAX,
+};
+
+#define V4L2_CID_CAMERA_JPEG_QUALITY (V4L2_CID_PRIVATE_BASE+85)
+/* (V4L2_CID_PRIVATE_BASE+86) */
+#define V4L2_CID_CAMERA_GPS_LATITUDE (V4L2_CID_CAMERA_CLASS_BASE+30)
+/* (V4L2_CID_PRIVATE_BASE+87) */
+#define V4L2_CID_CAMERA_GPS_LONGITUDE (V4L2_CID_CAMERA_CLASS_BASE + 31)
+/* (V4L2_CID_PRIVATE_BASE+88) */
+#define V4L2_CID_CAMERA_GPS_TIMESTAMP (V4L2_CID_CAMERA_CLASS_BASE + 32)
+/* (V4L2_CID_PRIVATE_BASE+89)*/
+#define V4L2_CID_CAMERA_GPS_ALTITUDE (V4L2_CID_CAMERA_CLASS_BASE + 33)
+#define V4L2_CID_CAMERA_EXIF_TIME_INFO (V4L2_CID_CAMERA_CLASS_BASE + 34)
+#define V4L2_CID_CAMERA_GPS_PROCESSINGMETHOD (V4L2_CID_CAMERA_CLASS_BASE+35)
+
+#define V4L2_CID_FOCUS_AUTO_MODE (V4L2_CID_CAMERA_CLASS_BASE+36)
+enum v4l2_focus_mode_type {
+ V4L2_FOCUS_AUTO_NORMAL = 0,
+ V4L2_FOCUS_AUTO_MACRO,
+ V4L2_FOCUS_AUTO_CONTINUOUS,
+ V4L2_FOCUS_AUTO_FACE_DETECTION,
+ V4L2_FOCUS_AUTO_RECTANGLE,
+ V4L2_FOCUS_AUTO_MAX,
+};
+#define V4L2_CID_FOCUS_AUTO_RECTANGLE_LEFT (V4L2_CID_CAMERA_CLASS_BASE+37)
+#define V4L2_CID_FOCUS_AUTO_RECTANGLE_TOP (V4L2_CID_CAMERA_CLASS_BASE+38)
+#define V4L2_CID_FOCUS_AUTO_RECTANGLE_WIDTH (V4L2_CID_CAMERA_CLASS_BASE+39)
+#define V4L2_CID_FOCUS_AUTO_RECTANGLE_HEIGHT (V4L2_CID_CAMERA_CLASS_BASE+40)
+#define V4L2_CID_CAMERA_ZOOM (V4L2_CID_PRIVATE_BASE+90)
+enum v4l2_zoom_level {
+ ZOOM_LEVEL_0 = 0,
+ ZOOM_LEVEL_1,
+ ZOOM_LEVEL_2,
+ ZOOM_LEVEL_3,
+ ZOOM_LEVEL_4,
+ ZOOM_LEVEL_5,
+ ZOOM_LEVEL_6,
+ ZOOM_LEVEL_7,
+ ZOOM_LEVEL_8,
+ ZOOM_LEVEL_9,
+ ZOOM_LEVEL_10,
+ ZOOM_LEVEL_11,
+ ZOOM_LEVEL_12,
+ ZOOM_LEVEL_MAX = 31,
+};
+
+#define V4L2_CID_CAMERA_FACE_DETECTION (V4L2_CID_PRIVATE_BASE+91)
+enum v4l2_face_detection {
+ FACE_DETECTION_OFF = 0,
+ FACE_DETECTION_ON,
+ FACE_DETECTION_NOLINE,
+ FACE_DETECTION_ON_BEAUTY,
+ FACE_DETECTION_MAX,
+};
+
+#define V4L2_CID_CAMERA_SMART_AUTO_STATUS (V4L2_CID_PRIVATE_BASE+92)
+enum v4l2_smart_auto_status {
+ SMART_AUTO_STATUS_AUTO = 0,
+ SMART_AUTO_STATUS_LANDSCAPE,
+ SMART_AUTO_STATUS_PORTRAIT,
+ SMART_AUTO_STATUS_MACRO,
+ SMART_AUTO_STATUS_NIGHT,
+ SMART_AUTO_STATUS_PORTRAIT_NIGHT,
+ SMART_AUTO_STATUS_BACKLIT,
+ SMART_AUTO_STATUS_PORTRAIT_BACKLIT,
+ SMART_AUTO_STATUS_ANTISHAKE,
+ SMART_AUTO_STATUS_PORTRAIT_ANTISHAKE,
+ SMART_AUTO_STATUS_MAX,
+};
+
+#define V4L2_CID_CAMERA_SET_AUTO_FOCUS (V4L2_CID_PRIVATE_BASE+93)
+enum v4l2_auto_focus {
+ AUTO_FOCUS_OFF = 0,
+ AUTO_FOCUS_ON,
+ AUTO_FOCUS_MAX,
+};
+
+#define V4L2_CID_CAMERA_BEAUTY_SHOT (V4L2_CID_PRIVATE_BASE+94)
+enum v4l2_beauty_shot {
+ BEAUTY_SHOT_OFF = 0,
+ BEAUTY_SHOT_ON,
+ BEAUTY_SHOT_MAX,
+};
+
+#define V4L2_CID_CAMERA_AEAWB_LOCK_UNLOCK (V4L2_CID_PRIVATE_BASE+95)
+enum v4l2_ae_awb_lockunlock {
+ AE_UNLOCK_AWB_UNLOCK = 0,
+ AE_LOCK_AWB_UNLOCK,
+ AE_UNLOCK_AWB_LOCK,
+ AE_LOCK_AWB_LOCK,
+ AE_AWB_MAX
+};
+
+#define V4L2_CID_CAMERA_FACEDETECT_LOCKUNLOCK (V4L2_CID_PRIVATE_BASE+96)
+enum v4l2_face_lock {
+ FACE_LOCK_OFF = 0,
+ FACE_LOCK_ON,
+ FIRST_FACE_TRACKING,
+ FACE_LOCK_MAX,
+};
+
+#define V4L2_CID_CAMERA_OBJECT_POSITION_X (V4L2_CID_PRIVATE_BASE+97)
+#define V4L2_CID_CAMERA_OBJECT_POSITION_Y (V4L2_CID_PRIVATE_BASE+98)
+#define V4L2_CID_CAMERA_FOCUS_MODE (V4L2_CID_PRIVATE_BASE+99)
+enum v4l2_focusmode {
+ FOCUS_MODE_AUTO = 0,
+ FOCUS_MODE_MACRO,
+ FOCUS_MODE_FACEDETECT,
+ FOCUS_MODE_AUTO_DEFAULT,
+ FOCUS_MODE_MACRO_DEFAULT,
+ FOCUS_MODE_FACEDETECT_DEFAULT,
+ FOCUS_MODE_INFINITY,
+ FOCUS_MODE_FIXED,
+ FOCUS_MODE_CONTINUOUS,
+ FOCUS_MODE_CONTINUOUS_PICTURE,
+ FOCUS_MODE_CONTINUOUS_PICTURE_MACRO,
+ FOCUS_MODE_CONTINUOUS_VIDEO,
+ FOCUS_MODE_TOUCH,
+ FOCUS_MODE_MAX,
+ FOCUS_MODE_DEFAULT = (1 << 8),
+};
+
+#define V4L2_CID_CAMERA_OBJ_TRACKING_STATUS (V4L2_CID_PRIVATE_BASE+100)
+enum v4l2_obj_tracking_status {
+ OBJECT_TRACKING_STATUS_BASE,
+ OBJECT_TRACKING_STATUS_PROGRESSING,
+ OBJECT_TRACKING_STATUS_SUCCESS,
+ OBJECT_TRACKING_STATUS_FAIL,
+ OBJECT_TRACKING_STATUS_MISSING,
+ OBJECT_TRACKING_STATUS_MAX,
+};
+
+#define V4L2_CID_CAMERA_OBJ_TRACKING_START_STOP (V4L2_CID_PRIVATE_BASE+101)
+enum v4l2_ot_start_stop {
+ OT_STOP = 0,
+ OT_START,
+ OT_MAX,
+};
+
+#define V4L2_CID_CAMERA_CAF_START_STOP (V4L2_CID_PRIVATE_BASE+102)
+enum v4l2_caf_start_stop {
+ CAF_STOP = 0,
+ CAF_START,
+ CAF_MAX,
+};
+
+#define V4L2_CID_CAMERA_AUTO_FOCUS_RESULT (V4L2_CID_PRIVATE_BASE+103)
+enum v4l2_af_status {
+ CAMERA_AF_STATUS_IN_PROGRESS = 0,
+ CAMERA_AF_STATUS_SUCCESS,
+ CAMERA_AF_STATUS_FAIL,
+ CAMERA_AF_STATUS_1ST_SUCCESS,
+ CAMERA_AF_STATUS_MAX,
+};
+#define V4L2_CID_CAMERA_FRAME_RATE (V4L2_CID_PRIVATE_BASE+104)
+enum v4l2_frame_rate {
+ FRAME_RATE_AUTO = 0,
+ FRAME_RATE_7 = 7,
+ FRAME_RATE_15 = 15,
+ FRAME_RATE_20 = 20,
+ FRAME_RATE_30 = 30,
+ FRAME_RATE_60 = 60,
+ FRAME_RATE_120 = 120,
+ FRAME_RATE_MAX
+};
+
+#define V4L2_CID_CAMERA_ANTI_BANDING (V4L2_CID_PRIVATE_BASE+105)
+enum v4l2_anti_banding {
+ ANTI_BANDING_AUTO = 0,
+ ANTI_BANDING_50HZ = 1,
+ ANTI_BANDING_60HZ = 2,
+ ANTI_BANDING_OFF = 3,
+};
+
+#define V4L2_CID_CAMERA_SET_GAMMA (V4L2_CID_PRIVATE_BASE+106)
+enum v4l2_gamma_mode {
+ GAMMA_OFF = 0,
+ GAMMA_ON = 1,
+ GAMMA_MAX,
+};
+
+#define V4L2_CID_CAMERA_SET_SLOW_AE (V4L2_CID_PRIVATE_BASE+107)
+enum v4l2_slow_ae_mode {
+ SLOW_AE_OFF,
+ SLOW_AE_ON,
+ SLOW_AE_MAX,
+};
+
+#define V4L2_CID_CAMERA_BATCH_REFLECTION (V4L2_CID_PRIVATE_BASE+108)
+#define V4L2_CID_CAMERA_EXIF_ORIENTATION (V4L2_CID_PRIVATE_BASE+109)
+
+/* s1_camera [ Defense process by ESD input ] */
+#define V4L2_CID_CAMERA_RESET (V4L2_CID_PRIVATE_BASE+111)
+#define V4L2_CID_CAMERA_CHECK_DATALINE (V4L2_CID_PRIVATE_BASE+112)
+#define V4L2_CID_CAMERA_CHECK_DATALINE_STOP (V4L2_CID_PRIVATE_BASE+113)
+
+#endif
+
+/* Modify NTTS1 */
+#if defined(CONFIG_ARIES_NTT)
+#define V4L2_CID_CAMERA_AE_AWB_DISABLE_LOCK (V4L2_CID_PRIVATE_BASE+114)
+#endif
+#define V4L2_CID_CAMERA_THUMBNAIL_NULL (V4L2_CID_PRIVATE_BASE+115)
+#define V4L2_CID_CAMERA_SENSOR_MODE (V4L2_CID_PRIVATE_BASE+116)
+enum v4l2_sensor_mode {
+ SENSOR_CAMERA,
+ SENSOR_MOVIE,
+};
+
+enum stream_mode_t {
+ STREAM_MODE_CAM_OFF,
+ STREAM_MODE_CAM_ON,
+ STREAM_MODE_MOVIE_OFF,
+ STREAM_MODE_MOVIE_ON,
+};
+
+#define V4L2_CID_CAMERA_EXIF_EXPTIME (V4L2_CID_PRIVATE_BASE+117)
+#define V4L2_CID_CAMERA_EXIF_FLASH (V4L2_CID_PRIVATE_BASE+118)
+#define V4L2_CID_CAMERA_EXIF_ISO (V4L2_CID_PRIVATE_BASE+119)
+#define V4L2_CID_CAMERA_EXIF_TV (V4L2_CID_PRIVATE_BASE+120)
+#define V4L2_CID_CAMERA_EXIF_BV (V4L2_CID_PRIVATE_BASE+121)
+#define V4L2_CID_CAMERA_EXIF_EBV (V4L2_CID_PRIVATE_BASE+122)
+#define V4L2_CID_CAMERA_CHECK_ESD (V4L2_CID_PRIVATE_BASE+123)
+#define V4L2_CID_CAMERA_APP_CHECK (V4L2_CID_PRIVATE_BASE+124)
+
+#define V4L2_CID_CAMERA_FACE_ZOOM (V4L2_CID_PRIVATE_BASE + 132)
+enum v4l2_face_zoom {
+ FACE_ZOOM_STOP = 0,
+ FACE_ZOOM_START
+};
+/* control for post processing block in ISP */
+#define V4L2_CID_CAMERA_SET_ODC (V4L2_CID_PRIVATE_BASE+127)
+enum set_odc_mode {
+ CAMERA_ODC_ON,
+ CAMERA_ODC_OFF
+};
+
+#define V4L2_CID_CAMERA_SET_DIS (V4L2_CID_PRIVATE_BASE+128)
+enum set_dis_mode {
+ CAMERA_DIS_ON,
+ CAMERA_DIS_OFF
+};
+
+#define V4L2_CID_CAMERA_SET_3DNR (V4L2_CID_PRIVATE_BASE+129)
+enum set_3dnr_mode {
+ CAMERA_3DNR_ON,
+ CAMERA_3DNR_OFF
+};
+
+#define V4L2_CID_EMBEDDEDDATA_ENABLE (V4L2_CID_PRIVATE_BASE+130)
+
+#define V4L2_CID_CAMERA_CHECK_SENSOR_STATUS (V4L2_CID_PRIVATE_BASE+150)
+#define V4L2_CID_CAMERA_DEFAULT_FOCUS_POSITION (V4L2_CID_PRIVATE_BASE+151)
+/* Pixel format FOURCC depth Description */
+enum v4l2_pix_format_mode {
+ V4L2_PIX_FMT_MODE_PREVIEW,
+ V4L2_PIX_FMT_MODE_CAPTURE,
+ V4L2_PIX_FMT_MODE_HDR,
+ V4L2_PIX_FMT_MODE_VT_MIRROR,
+ V4L2_PIX_FMT_MODE_VT_NONMIRROR,
+};
+
+/* 12 Y/CbCr 4:2:0 64x32 macroblocks */
+#define V4L2_PIX_FMT_NV12T v4l2_fourcc('T', 'V', '1', '2')
+#define V4L2_PIX_FMT_NV21T v4l2_fourcc('T', 'V', '2', '1')
+#define V4L2_PIX_FMT_INTERLEAVED v4l2_fourcc('I', 'T', 'L', 'V')
+
+
+/*
+ * * V4L2 extention for digital camera
+ * */
+/* Strobe flash light */
+enum v4l2_strobe_control {
+ /* turn off the flash light */
+ V4L2_STROBE_CONTROL_OFF = 0,
+ /* turn on the flash light */
+ V4L2_STROBE_CONTROL_ON = 1,
+ /* act guide light before splash */
+ V4L2_STROBE_CONTROL_AFGUIDE = 2,
+ /* charge the flash light */
+ V4L2_STROBE_CONTROL_CHARGE = 3,
+};
+
+enum v4l2_strobe_conf {
+ V4L2_STROBE_OFF = 0, /* Always off */
+ V4L2_STROBE_ON = 1, /* Always splashes */
+ /* Auto control presets */
+ V4L2_STROBE_AUTO = 2,
+ V4L2_STROBE_REDEYE_REDUCTION = 3,
+ V4L2_STROBE_SLOW_SYNC = 4,
+ V4L2_STROBE_FRONT_CURTAIN = 5,
+ V4L2_STROBE_REAR_CURTAIN = 6,
+ /* Extra manual control presets */
+ /* keep turned on until turning off */
+ V4L2_STROBE_PERMANENT = 7,
+ V4L2_STROBE_EXTERNAL = 8,
+};
+
+enum v4l2_strobe_status {
+ V4L2_STROBE_STATUS_OFF = 0,
+ /* while processing configurations */
+ V4L2_STROBE_STATUS_BUSY = 1,
+ V4L2_STROBE_STATUS_ERR = 2,
+ V4L2_STROBE_STATUS_CHARGING = 3,
+ V4L2_STROBE_STATUS_CHARGED = 4,
+};
+
+/* capabilities field */
+/* No strobe supported */
+#define V4L2_STROBE_CAP_NONE 0x0000
+/* Always flash off mode */
+#define V4L2_STROBE_CAP_OFF 0x0001
+/* Always use flash light mode */
+#define V4L2_STROBE_CAP_ON 0x0002
+/* Flashlight works automatic */
+#define V4L2_STROBE_CAP_AUTO 0x0004
+/* Red-eye reduction */
+#define V4L2_STROBE_CAP_REDEYE 0x0008
+/* Slow sync */
+#define V4L2_STROBE_CAP_SLOWSYNC 0x0010
+/* Front curtain */
+#define V4L2_STROBE_CAP_FRONT_CURTAIN 0x0020
+/* Rear curtain */
+#define V4L2_STROBE_CAP_REAR_CURTAIN 0x0040
+/* keep turned on until turning off */
+#define V4L2_STROBE_CAP_PERMANENT 0x0080
+/* use external strobe */
+#define V4L2_STROBE_CAP_EXTERNAL 0x0100
+
+/* Set mode and Get status */
+struct v4l2_strobe {
+ /* off/on/charge:0/1/2 */
+ enum v4l2_strobe_control control;
+ /* supported strobe capabilities */
+ __u32 capabilities;
+ enum v4l2_strobe_conf mode;
+ enum v4l2_strobe_status status; /* read only */
+ /* default is 0 and range of value varies from each models */
+ __u32 flash_ev;
+ __u32 reserved[4];
+};
+
+#define VIDIOC_S_STROBE _IOWR('V', 83, struct v4l2_strobe)
+#define VIDIOC_G_STROBE _IOR('V', 84, struct v4l2_strobe)
+
+/* Object recognition and collateral actions */
+enum v4l2_recog_mode {
+ V4L2_RECOGNITION_MODE_OFF = 0,
+ V4L2_RECOGNITION_MODE_ON = 1,
+ V4L2_RECOGNITION_MODE_LOCK = 2,
+};
+
+enum v4l2_recog_action {
+ V4L2_RECOGNITION_ACTION_NONE = 0, /* only recognition */
+ V4L2_RECOGNITION_ACTION_BLINK = 1, /* Capture on blinking */
+ V4L2_RECOGNITION_ACTION_SMILE = 2, /* Capture on smiling */
+};
+
+enum v4l2_recog_pattern {
+ V4L2_RECOG_PATTERN_FACE = 0, /* Face */
+ V4L2_RECOG_PATTERN_HUMAN = 1, /* Human */
+ V4L2_RECOG_PATTERN_CHAR = 2, /* Character */
+};
+
+struct v4l2_recog_rect {
+ enum v4l2_recog_pattern p; /* detected pattern */
+ struct v4l2_rect o; /* detected area */
+ __u32 reserved[4];
+};
+
+struct v4l2_recog_data {
+ __u8 detect_cnt; /* detected object counter */
+ struct v4l2_rect o; /* detected area */
+ __u32 reserved[4];
+};
+
+struct v4l2_recognition {
+ enum v4l2_recog_mode mode;
+
+ /* Which pattern to detect */
+ enum v4l2_recog_pattern pattern;
+
+ /* How many object to detect */
+ __u8 obj_num;
+
+ /* select detected object */
+ __u32 detect_idx;
+
+ /* read only :Get object coordination */
+ struct v4l2_recog_data data;
+
+ enum v4l2_recog_action action;
+ __u32 reserved[4];
+};
+
+#define VIDIOC_S_RECOGNITION _IOWR('V', 85, struct v4l2_recognition)
+#define VIDIOC_G_RECOGNITION _IOR('V', 86, struct v4l2_recognition)
+
+#endif /* __LINUX_VIDEODEV2_EXYNOS_CAMERA_H */
diff --git a/include/linux/videodev2_exynos_media.h b/include/linux/videodev2_exynos_media.h
new file mode 100644
index 0000000..545667a
--- /dev/null
+++ b/include/linux/videodev2_exynos_media.h
@@ -0,0 +1,231 @@
+/*
+ * Video for Linux Two header file for Exynos
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * This header file contains several v4l2 APIs to be proposed to v4l2
+ * community and until being accepted, will be used restrictly for Exynos.
+ *
+ * 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.
+ */
+
+#ifndef __LINUX_VIDEODEV2_EXYNOS_MEDIA_H
+#define __LINUX_VIDEODEV2_EXYNOS_MEDIA_H
+
+/* Pixel format FOURCC depth Description */
+
+/* two planes -- one Y, one Cr + Cb interleaved */
+#define V4L2_PIX_FMT_YUV444_2P v4l2_fourcc('Y', 'U', '2', 'P') /* 24 Y/CbCr */
+#define V4L2_PIX_FMT_YVU444_2P v4l2_fourcc('Y', 'V', '2', 'P') /* 24 Y/CrCb */
+
+/* three planes -- one Y, one Cr, one Cb */
+#define V4L2_PIX_FMT_YUV444_3P v4l2_fourcc('Y', 'U', '3', 'P') /* 24 Y/Cb/Cr */
+
+/* two non contiguous planes - one Y, one Cr + Cb interleaved */
+/* 21 Y/CrCb 4:2:0 */
+#define V4L2_PIX_FMT_NV21M v4l2_fourcc('N', 'M', '2', '1')
+/* 12 Y/CbCr 4:2:0 16x16 macroblocks */
+#define V4L2_PIX_FMT_NV12MT_16X16 v4l2_fourcc('V', 'M', '1', '2')
+
+/* three non contiguous planes - Y, Cb, Cr */
+/* 12 YVU420 planar */
+#define V4L2_PIX_FMT_YVU420M v4l2_fourcc('Y', 'V', 'U', 'M')
+
+/* compressed formats */
+#define V4L2_PIX_FMT_H264_MVC v4l2_fourcc('M', '2', '6', '4') /* H264 MVC */
+#define V4L2_PIX_FMT_FIMV v4l2_fourcc('F', 'I', 'M', 'V') /* FIMV */
+#define V4L2_PIX_FMT_FIMV1 v4l2_fourcc('F', 'I', 'M', '1') /* FIMV1 */
+#define V4L2_PIX_FMT_FIMV2 v4l2_fourcc('F', 'I', 'M', '2') /* FIMV2 */
+#define V4L2_PIX_FMT_FIMV3 v4l2_fourcc('F', 'I', 'M', '3') /* FIMV3 */
+#define V4L2_PIX_FMT_FIMV4 v4l2_fourcc('F', 'I', 'M', '4') /* FIMV4 */
+#define V4L2_PIX_FMT_VP8 v4l2_fourcc('V', 'P', '8', '0') /* VP8 */
+
+/* yuv444 of JFIF JPEG */
+#define V4L2_PIX_FMT_JPEG_444 v4l2_fourcc('J', 'P', 'G', '4')
+/* yuv422 of JFIF JPEG */
+#define V4L2_PIX_FMT_JPEG_422 v4l2_fourcc('J', 'P', 'G', '2')
+/* yuv420 of JFIF JPEG */
+#define V4L2_PIX_FMT_JPEG_420 v4l2_fourcc('J', 'P', 'G', '0')
+/* grey of JFIF JPEG */
+#define V4L2_PIX_FMT_JPEG_GRAY v4l2_fourcc('J', 'P', 'G', 'G')
+
+/*
+ * C O N T R O L S
+ */
+/* CID base for Exynos controls (USER_CLASS) */
+#define V4L2_CID_EXYNOS_BASE (V4L2_CTRL_CLASS_USER | 0x2000)
+
+/* for rgb alpha function */
+#define V4L2_CID_GLOBAL_ALPHA (V4L2_CID_EXYNOS_BASE + 1)
+
+/* cacheable configuration */
+#define V4L2_CID_CACHEABLE (V4L2_CID_EXYNOS_BASE + 10)
+
+/* jpeg captured size */
+#define V4L2_CID_CAM_JPEG_MEMSIZE (V4L2_CID_EXYNOS_BASE + 20)
+#define V4L2_CID_CAM_JPEG_ENCODEDSIZE (V4L2_CID_EXYNOS_BASE + 21)
+
+#define V4L2_CID_SET_SHAREABLE (V4L2_CID_EXYNOS_BASE + 40)
+
+/* TV configuration */
+#define V4L2_CID_TV_LAYER_BLEND_ENABLE (V4L2_CID_EXYNOS_BASE + 50)
+#define V4L2_CID_TV_LAYER_BLEND_ALPHA (V4L2_CID_EXYNOS_BASE + 51)
+#define V4L2_CID_TV_PIXEL_BLEND_ENABLE (V4L2_CID_EXYNOS_BASE + 52)
+#define V4L2_CID_TV_CHROMA_ENABLE (V4L2_CID_EXYNOS_BASE + 53)
+#define V4L2_CID_TV_CHROMA_VALUE (V4L2_CID_EXYNOS_BASE + 54)
+#define V4L2_CID_TV_HPD_STATUS (V4L2_CID_EXYNOS_BASE + 55)
+#define V4L2_CID_TV_LAYER_PRIO (V4L2_CID_EXYNOS_BASE + 56)
+#define V4L2_CID_TV_SET_DVI_MODE (V4L2_CID_EXYNOS_BASE + 57)
+#define V4L2_CID_TV_GET_DVI_MODE (V4L2_CID_EXYNOS_BASE + 58)
+#define V4L2_CID_TV_SET_ASPECT_RATIO (V4L2_CID_EXYNOS_BASE + 59)
+
+/* for color space conversion equation selection */
+#define V4L2_CID_CSC_EQ_MODE (V4L2_CID_EXYNOS_BASE + 100)
+#define V4L2_CID_CSC_EQ (V4L2_CID_EXYNOS_BASE + 101)
+#define V4L2_CID_CSC_RANGE (V4L2_CID_EXYNOS_BASE + 102)
+
+#define V4L2_CID_CONTENT_PROTECTION (V4L2_CID_EXYNOS_BASE + 201)
+
+/* CID base for MFC controls (MPEG_CLASS) */
+#define V4L2_CID_MPEG_MFC_BASE (V4L2_CTRL_CLASS_MPEG | 0x2000)
+
+#define V4L2_CID_MPEG_VIDEO_H264_SEI_FP_AVAIL \
+ (V4L2_CID_MPEG_MFC_BASE + 1)
+#define V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRGMENT_ID \
+ (V4L2_CID_MPEG_MFC_BASE + 2)
+#define V4L2_CID_MPEG_VIDEO_H264_SEI_FP_INFO \
+ (V4L2_CID_MPEG_MFC_BASE + 3)
+#define V4L2_CID_MPEG_VIDEO_H264_SEI_FP_GRID_POS \
+ (V4L2_CID_MPEG_MFC_BASE + 4)
+
+#define V4L2_CID_MPEG_MFC51_VIDEO_PACKED_PB \
+ (V4L2_CID_MPEG_MFC_BASE + 5)
+#define V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TAG \
+ (V4L2_CID_MPEG_MFC_BASE + 6)
+#define V4L2_CID_MPEG_MFC51_VIDEO_CRC_ENABLE \
+ (V4L2_CID_MPEG_MFC_BASE + 7)
+#define V4L2_CID_MPEG_MFC51_VIDEO_CRC_DATA_LUMA \
+ (V4L2_CID_MPEG_MFC_BASE + 8)
+#define V4L2_CID_MPEG_MFC51_VIDEO_CRC_DATA_CHROMA \
+ (V4L2_CID_MPEG_MFC_BASE + 9)
+#define V4L2_CID_MPEG_MFC51_VIDEO_CRC_DATA_LUMA_BOT \
+ (V4L2_CID_MPEG_MFC_BASE + 10)
+#define V4L2_CID_MPEG_MFC51_VIDEO_CRC_DATA_CHROMA_BOT \
+ (V4L2_CID_MPEG_MFC_BASE + 11)
+#define V4L2_CID_MPEG_MFC51_VIDEO_CRC_GENERATED \
+ (V4L2_CID_MPEG_MFC_BASE + 12)
+#define V4L2_CID_MPEG_MFC51_VIDEO_CHECK_STATE \
+ (V4L2_CID_MPEG_MFC_BASE + 13)
+#define V4L2_CID_MPEG_MFC51_VIDEO_DISPLAY_STATUS \
+ (V4L2_CID_MPEG_MFC_BASE + 14)
+
+#define V4L2_CID_MPEG_MFC51_VIDEO_LUMA_ADDR \
+ (V4L2_CID_MPEG_MFC_BASE + 15)
+#define V4L2_CID_MPEG_MFC51_VIDEO_CHROMA_ADDR \
+ (V4L2_CID_MPEG_MFC_BASE + 16)
+
+#define V4L2_CID_MPEG_MFC51_VIDEO_STREAM_SIZE \
+ (V4L2_CID_MPEG_MFC_BASE + 17)
+#define V4L2_CID_MPEG_MFC51_VIDEO_FRAME_COUNT \
+ (V4L2_CID_MPEG_MFC_BASE + 18)
+#define V4L2_CID_MPEG_MFC51_VIDEO_FRAME_TYPE \
+ (V4L2_CID_MPEG_MFC_BASE + 19)
+enum v4l2_mpeg_mfc51_video_frame_type {
+ V4L2_MPEG_MFC51_VIDEO_FRAME_TYPE_NOT_CODED = 0,
+ V4L2_MPEG_MFC51_VIDEO_FRAME_TYPE_I_FRAME = 1,
+ V4L2_MPEG_MFC51_VIDEO_FRAME_TYPE_P_FRAME = 2,
+ V4L2_MPEG_MFC51_VIDEO_FRAME_TYPE_B_FRAME = 3,
+ V4L2_MPEG_MFC51_VIDEO_FRAME_TYPE_SKIPPED = 4,
+ V4L2_MPEG_MFC51_VIDEO_FRAME_TYPE_OTHERS = 5,
+};
+
+#define V4L2_CID_MPEG_MFC51_VIDEO_H264_INTERLACE \
+ (V4L2_CID_MPEG_MFC_BASE + 20)
+#define V4L2_CID_MPEG_MFC51_VIDEO_H264_RC_FRAME_RATE \
+ (V4L2_CID_MPEG_MFC_BASE + 21)
+#define V4L2_CID_MPEG_MFC51_VIDEO_MPEG4_VOP_TIME_RES \
+ (V4L2_CID_MPEG_MFC_BASE + 22)
+#define V4L2_CID_MPEG_MFC51_VIDEO_MPEG4_VOP_FRM_DELTA \
+ (V4L2_CID_MPEG_MFC_BASE + 23)
+#define V4L2_CID_MPEG_MFC51_VIDEO_H263_RC_FRAME_RATE \
+ (V4L2_CID_MPEG_MFC_BASE + 24)
+
+#define V4L2_CID_MPEG_MFC6X_VIDEO_FRAME_DELTA \
+ (V4L2_CID_MPEG_MFC_BASE + 25)
+
+#define V4L2_CID_MPEG_MFC51_VIDEO_I_PERIOD_CH V4L2_CID_MPEG_VIDEO_GOP_SIZE
+#define V4L2_CID_MPEG_MFC51_VIDEO_FRAME_RATE_CH \
+ V4L2_CID_MPEG_MFC51_VIDEO_H264_RC_FRAME_RATE
+#define V4L2_CID_MPEG_MFC51_VIDEO_BIT_RATE_CH V4L2_CID_MPEG_VIDEO_BITRATE
+
+/* new entry for enum v4l2_mpeg_video_mpeg4_level */
+#define V4L2_MPEG_VIDEO_MPEG4_LEVEL_6 8
+
+/* proposed CIDs, based on 3.3-rc3 */
+#define V4L2_CID_MPEG_VIDEO_VBV_DELAY (V4L2_CID_MPEG_MFC_BASE + 26)
+
+#define V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_S_B \
+ V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY
+
+#define V4L2_CID_MPEG_VIDEO_H264_SEI_FRAME_PACKING \
+ (V4L2_CID_MPEG_MFC_BASE + 27)
+#define V4L2_CID_MPEG_VIDEO_H264_SEI_FP_CURRENT_FRAME_0 \
+ (V4L2_CID_MPEG_MFC_BASE + 28)
+#define V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE \
+ (V4L2_CID_MPEG_MFC_BASE + 29)
+enum v4l2_mpeg_video_h264_sei_fp_arrangement_type {
+ V4L2_MPEG_VIDEO_H264_SEI_FP_TYPE_CHEKERBOARD = 0,
+ V4L2_MPEG_VIDEO_H264_SEI_FP_TYPE_COLUMN = 1,
+ V4L2_MPEG_VIDEO_H264_SEI_FP_TYPE_ROW = 2,
+ V4L2_MPEG_VIDEO_H264_SEI_FP_TYPE_SIDE_BY_SIDE = 3,
+ V4L2_MPEG_VIDEO_H264_SEI_FP_TYPE_TOP_BOTTOM = 4,
+ V4L2_MPEG_VIDEO_H264_SEI_FP_TYPE_TEMPORAL = 5,
+};
+#define V4L2_CID_MPEG_VIDEO_H264_FMO \
+ (V4L2_CID_MPEG_MFC_BASE + 30)
+#define V4L2_CID_MPEG_VIDEO_H264_FMO_MAP_TYPE \
+ (V4L2_CID_MPEG_MFC_BASE + 31)
+enum v4l2_mpeg_video_h264_fmo_map_type {
+ V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_INTERLEAVED_SLICES = 0,
+ V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_SCATTERED_SLICES = 1,
+ V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_FOREGROUND_WITH_LEFT_OVER = 2,
+ V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_BOX_OUT = 3,
+ V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_RASTER_SCAN = 4,
+ V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_WIPE_SCAN = 5,
+ V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_EXPLICIT = 6,
+};
+#define V4L2_CID_MPEG_VIDEO_H264_FMO_SLICE_GROUP \
+ (V4L2_CID_MPEG_MFC_BASE + 32)
+#define V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_DIRECTION \
+ (V4L2_CID_MPEG_MFC_BASE + 33)
+enum v4l2_mpeg_video_h264_fmo_change_dir {
+ V4L2_MPEG_VIDEO_H264_FMO_CHANGE_DIR_RIGHT = 0,
+ V4L2_MPEG_VIDEO_H264_FMO_CHANGE_DIR_LEFT = 1,
+};
+#define V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_RATE \
+ (V4L2_CID_MPEG_MFC_BASE + 34)
+#define V4L2_CID_MPEG_VIDEO_H264_FMO_RUN_LENGTH \
+ (V4L2_CID_MPEG_MFC_BASE + 35)
+#define V4L2_CID_MPEG_VIDEO_H264_ASO \
+ (V4L2_CID_MPEG_MFC_BASE + 36)
+#define V4L2_CID_MPEG_VIDEO_H264_ASO_SLICE_ORDER \
+ (V4L2_CID_MPEG_MFC_BASE + 37)
+#define V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING \
+ (V4L2_CID_MPEG_MFC_BASE + 38)
+#define V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE \
+ (V4L2_CID_MPEG_MFC_BASE + 39)
+enum v4l2_mpeg_video_h264_hierarchical_coding_type {
+ V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_B = 0,
+ V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P = 1,
+};
+#define V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER \
+ (V4L2_CID_MPEG_MFC_BASE + 40)
+#define V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_QP \
+ (V4L2_CID_MPEG_MFC_BASE + 41)
+
+#define V4L2_CID_MPEG_VIDEO_H264_MVC_VIEW_ID \
+ (V4L2_CID_MPEG_MFC_BASE + 42)
+#endif /* __LINUX_VIDEODEV2_EXYNOS_MEDIA_H */
diff --git a/include/media/exynos_camera.h b/include/media/exynos_camera.h
new file mode 100644
index 0000000..e7fafd1
--- /dev/null
+++ b/include/media/exynos_camera.h
@@ -0,0 +1,59 @@
+/* include/media/exynos_camera.h
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * The header file related to camera
+ *
+ * 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.
+ */
+
+#ifndef EXYNOS_CAMERA_H_
+#define EXYNOS_CAMERA_H_
+
+#include <media/exynos_mc.h>
+
+enum cam_bus_type {
+ CAM_TYPE_ITU = 1,
+ CAM_TYPE_MIPI,
+};
+
+enum cam_port {
+ CAM_PORT_A,
+ CAM_PORT_B,
+};
+
+#define CAM_CLK_INV_PCLK (1 << 0)
+#define CAM_CLK_INV_VSYNC (1 << 1)
+#define CAM_CLK_INV_HREF (1 << 2)
+#define CAM_CLK_INV_HSYNC (1 << 3)
+
+struct i2c_board_info;
+
+/**
+ * struct exynos_isp_info - image sensor information required for host
+ * interface configuration.
+ *
+ * @board_info: pointer to I2C subdevice's board info
+ * @clk_frequency: frequency of the clock the host interface provides to sensor
+ * @bus_type: determines bus type, MIPI, ITU-R BT.601 etc.
+ * @csi_data_align: MIPI-CSI interface data alignment in bits
+ * @i2c_bus_num: i2c control bus id the sensor is attached to
+ * @mux_id: FIMC camera interface multiplexer index (separate for MIPI and ITU)
+ * @flags: flags defining bus signals polarity inversion (High by default)
+ * @use_cam: a means of used by GSCALER
+ */
+struct exynos_isp_info {
+ struct i2c_board_info *board_info;
+ unsigned long clk_frequency;
+ const char *cam_srclk_name;
+ const char *cam_clk_name;
+ enum cam_bus_type bus_type;
+ u16 csi_data_align;
+ u16 i2c_bus_num;
+ enum cam_port cam_port;
+ u16 flags;
+};
+#endif /* EXYNOS_CAMERA_H_ */
diff --git a/include/media/exynos_fimc_is.h b/include/media/exynos_fimc_is.h
new file mode 100644
index 0000000..364e1eb
--- /dev/null
+++ b/include/media/exynos_fimc_is.h
@@ -0,0 +1,209 @@
+/* linux/arch/arm/plat-s5p/include/plat/fimc_is.h
+ *
+ * Copyright (C) 2011 Samsung Electronics, Co. Ltd
+ *
+ * Exynos 4 series FIMC-IS slave device support
+ *
+ * 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.
+ */
+#ifndef EXYNOS_FIMC_IS_H_
+#define EXYNOS_FIMC_IS_H_ __FILE__
+
+#include <linux/videodev2.h>
+
+#if defined CONFIG_VIDEO_EXYNOS5_FIMC_IS
+#define FIMC_IS_MODULE_NAME "exynos5-fimc-is"
+#elif defined CONFIG_VIDEO_EXYNOS5_FIMC_IS2
+#define FIMC_IS_MODULE_NAME "exynos5-fimc-is2"
+#endif
+
+#define FIMC_IS_MAX_CAMIF_CLIENTS 2
+#define FIMC_IS_MAX_NAME_LEN 32
+#define FIMC_IS_MAX_GPIO_NUM 32
+#define UART_ISP_SEL 0
+#define UART_ISP_RATIO 1
+
+#define to_fimc_is_plat(d) (to_platform_device(d)->dev.platform_data)
+
+enum exynos5_csi_id {
+ CSI_ID_A = 0,
+ CSI_ID_B
+};
+
+enum exynos5_flite_id {
+ FLITE_ID_A = 0,
+ FLITE_ID_B
+};
+
+enum exynos5_sensor_position {
+ SENSOR_POSITION_REAR = 0,
+ SENSOR_POSITION_FRONT
+};
+enum exynos5_sensor_id {
+ SENSOR_NAME_S5K3H2 = 1,
+ SENSOR_NAME_S5K6A3 = 2,
+ SENSOR_NAME_S5K4E5 = 3,
+ SENSOR_NAME_S5K3H7 = 4,
+ SENSOR_NAME_CUSTOM = 100,
+ SENSOR_NAME_END
+};
+
+struct exynos5_sensor_power_info {
+ char cam_core[FIMC_IS_MAX_NAME_LEN];
+ char cam_io_myself[FIMC_IS_MAX_NAME_LEN];
+ char cam_io_peer[FIMC_IS_MAX_NAME_LEN];
+ char cam_af[FIMC_IS_MAX_NAME_LEN];
+};
+
+enum actuator_name {
+ ACTUATOR_NAME_AD5823 = 1,
+ ACTUATOR_NAME_DWXXXX = 2,
+ ACTUATOR_NAME_AK7343 = 3,
+ ACTUATOR_NAME_HYBRIDVCA = 4,
+ ACTUATOR_NAME_NOTHING = 100,
+ ACTUATOR_NAME_END
+};
+
+enum flash_drv_name {
+ FLADRV_NAME_KTD267 = 1,
+ FLADRV_NAME_NOTHING = 100,
+ FLADRV_NAME_END
+};
+
+enum from_name {
+ FROMDRV_NAME_W25Q80BW = 1,
+ FROMDRV_NAME_NOTHING
+};
+
+enum sensor_peri_type {
+ SE_I2C,
+ SE_SPI,
+ SE_GPIO,
+ SE_MPWM,
+ SE_ADC,
+ SE_NULL
+};
+
+struct i2c_type {
+ u32 channel;
+ u32 slave_address;
+ u32 speed;
+};
+
+struct spi_type {
+ u32 channel;
+};
+
+struct gpio_type {
+ u32 first_gpio_port_no;
+ u32 second_gpio_port_no;
+};
+
+union sensor_peri_format {
+ struct i2c_type i2c;
+ struct spi_type spi;
+ struct gpio_type gpio;
+};
+
+struct sensor_protocol {
+ u32 product_name;
+ enum sensor_peri_type peri_type;
+ union sensor_peri_format peri_setting;
+};
+
+enum exynos5_sensor_channel {
+ SENSOR_CONTROL_I2C0 = 0,
+ SENSOR_CONTROL_I2C1 = 1
+};
+
+enum gpio_act {
+ GPIO_PULL_NONE = 0,
+ GPIO_OUTPUT,
+ GPIO_RESET
+};
+
+struct gpio_set {
+ unsigned int pin;
+ char name[FIMC_IS_MAX_NAME_LEN];
+ unsigned int value;
+ unsigned int act;
+};
+
+struct exynos5_sensor_gpio_info {
+ struct gpio_set cfg[FIMC_IS_MAX_GPIO_NUM];
+ struct gpio_set reset_myself;
+ struct gpio_set reset_peer;
+ struct gpio_set power;
+};
+
+struct platform_device;
+
+ /**
+ * struct exynos5_fimc_is_sensor_info - image sensor information required for host
+ * interace configuration.
+ */
+struct exynos5_fimc_is_sensor_info {
+ char sensor_name[FIMC_IS_MAX_NAME_LEN];
+ enum exynos5_sensor_position sensor_position;
+ enum exynos5_sensor_id sensor_id;
+ enum exynos5_csi_id csi_id;
+ enum exynos5_flite_id flite_id;
+ enum exynos5_sensor_channel i2c_channel;
+ struct exynos5_sensor_power_info sensor_power;
+ struct exynos5_sensor_gpio_info sensor_gpio;
+
+ int max_width;
+ int max_height;
+ int max_frame_rate;
+
+ int mipi_lanes; /* MIPI data lanes */
+ int mipi_settle; /* MIPI settle */
+ int mipi_align; /* MIPI data align: 24/32 */
+};
+
+struct sensor_open_extended {
+ struct sensor_protocol actuator_con;
+ struct sensor_protocol flash_con;
+ struct sensor_protocol from_con;
+
+ u32 mclk;
+ u32 mipi_lane_num;
+ u32 mipi_speed;
+ /* Skip setfile loading when fast_open_sensor is not 0 */
+ u32 fast_open_sensor;
+ /* Activatiing sensor self calibration mode (6A3) */
+ u32 self_calibration_mode;
+};
+
+/**
+* struct exynos5_platform_fimc_is - camera host interface platform data
+*
+* @isp_info: properties of camera sensor required for host interface setup
+*/
+struct exynos5_platform_fimc_is {
+ int hw_ver;
+ struct exynos5_fimc_is_sensor_info
+ *sensor_info[FIMC_IS_MAX_CAMIF_CLIENTS];
+ int (*clk_cfg)(struct platform_device *pdev);
+ int (*clk_on)(struct platform_device *pdev, int sensor_id);
+ int (*clk_off)(struct platform_device *pdev, int sensor_id);
+ int (*sensor_power_on)(struct platform_device *pdev,
+ int sensor_id);
+ int (*sensor_power_off)(struct platform_device *pdev,
+ int sensor_id);
+};
+
+extern void exynos5_fimc_is_set_platdata(struct exynos5_platform_fimc_is *pd);
+
+/* platform specific clock functions */
+extern int exynos5_fimc_is_cfg_clk(struct platform_device *pdev);
+extern int exynos5_fimc_is_clk_on(struct platform_device *pdev, int sensor_id);
+extern int exynos5_fimc_is_clk_off(struct platform_device *pdev, int sensor_id);
+extern int exynos5_fimc_is_sensor_power_on(struct platform_device *pdev,
+ int sensor_id);
+extern int exynos5_fimc_is_sensor_power_off(struct platform_device *pdev,
+ int sensor_id);
+
+#endif /* EXYNOS_FIMC_IS_H_ */
diff --git a/include/media/exynos_flite.h b/include/media/exynos_flite.h
new file mode 100644
index 0000000..5989d58
--- /dev/null
+++ b/include/media/exynos_flite.h
@@ -0,0 +1,44 @@
+/*
+ * Samsung S5P SoC camera interface driver header
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * 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.
+ */
+
+#ifndef EXYNOS_FLITE_H_
+#define EXYNOS_FLITE_H_
+
+#if defined(CONFIG_ARCH_EXYNOS4) && defined(CONFIG_VIDEO_FIMC)
+#define MAX_CAMIF_CLIENTS 3
+#include <plat/fimc.h>
+#else
+#include <media/exynos_camera.h>
+
+struct s3c_platform_camera {
+ enum cam_bus_type type;
+ bool use_isp;
+ int inv_pclk;
+ int inv_vsync;
+ int inv_href;
+ int inv_hsync;
+};
+#endif
+
+/**
+ * struct exynos_platform_flite - camera host interface platform data
+ *
+ * @cam: properties of camera sensor required for host interface setup
+ */
+struct exynos_platform_flite {
+ struct s3c_platform_camera *cam[MAX_CAMIF_CLIENTS];
+ struct exynos_isp_info *isp_info[MAX_CAMIF_CLIENTS];
+ u32 active_cam_index;
+ u32 num_clients;
+};
+
+extern struct exynos_platform_flite exynos_flite0_default_data;
+extern struct exynos_platform_flite exynos_flite1_default_data;
+#endif /* EXYNOS_FLITE_H_*/
diff --git a/include/media/exynos_gscaler.h b/include/media/exynos_gscaler.h
new file mode 100644
index 0000000..c161173
--- /dev/null
+++ b/include/media/exynos_gscaler.h
@@ -0,0 +1,42 @@
+/* include/media/exynos_gscaler.h
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Samsung EXYNOS SoC Gscaler driver header
+ *
+ * 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.
+ */
+
+#ifndef EXYNOS_GSCALER_H_
+#define EXYNOS_GSCALER_H_
+
+#include <media/exynos_camera.h>
+
+/**
+ * struct exynos_platform_gscaler - camera host interface platform data
+ *
+ * @isp_info: properties of camera sensor required for host interface setup
+ */
+struct exynos_platform_gscaler {
+ struct exynos_isp_info *isp_info[MAX_CAMIF_CLIENTS];
+ u32 active_cam_index;
+ u32 num_clients;
+ u32 cam_preview:1;
+ u32 cam_camcording:1;
+};
+
+extern struct exynos_platform_gscaler exynos_gsc0_default_data;
+extern struct exynos_platform_gscaler exynos_gsc1_default_data;
+extern struct exynos_platform_gscaler exynos_gsc2_default_data;
+extern struct exynos_platform_gscaler exynos_gsc3_default_data;
+
+/**
+ * exynos5_gsc_set_pdev_name() = Exynos setup function for gscaler pdev name
+ * @ id: gscaler device number
+ * @ name: pdev name for gscaler
+ */
+void __init exynos5_gsc_set_pdev_name(int id, char *name);
+#endif /* EXYNOS_GSCALER_H_ */
diff --git a/include/media/exynos_mc.h b/include/media/exynos_mc.h
new file mode 100644
index 0000000..18f8e70
--- /dev/null
+++ b/include/media/exynos_mc.h
@@ -0,0 +1,160 @@
+/* linux/inclue/media/exynos_mc.h
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * header file for exynos media device driver
+ *
+ * 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.
+ */
+
+#ifndef GSC_MDEVICE_H_
+#define GSC_MDEVICE_H_
+
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <media/media-device.h>
+#include <media/media-entity.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+
+#define err(fmt, args...) \
+ printk(KERN_ERR "%s:%d: " fmt "\n", __func__, __LINE__, ##args)
+
+#define MDEV_MODULE_NAME "exynos-mdev"
+#define MAX_GSC_SUBDEV 4
+#define MDEV_MAX_NUM 3
+
+#define GSC_OUT_PAD_SINK 0
+#define GSC_OUT_PAD_SOURCE 1
+
+#define GSC_CAP_PAD_SINK 0
+#define GSC_CAP_PAD_SOURCE 1
+
+#define FLITE_PAD_SINK 0
+#define FLITE_PAD_SOURCE_PREV 1
+#define FLITE_PAD_SOURCE_CAMCORD 2
+#define FLITE_PAD_SOURCE_MEM 3
+#define FLITE_PADS_NUM 4
+
+#define CSIS_PAD_SINK 0
+#define CSIS_PAD_SOURCE 1
+#define CSIS_PADS_NUM 2
+
+#define MAX_CAMIF_CLIENTS 2
+
+#define MXR_SUBDEV_NAME "s5p-mixer"
+
+#define GSC_MODULE_NAME "exynos-gsc"
+#define GSC_SUBDEV_NAME "exynos-gsc-sd"
+#define FIMD_MODULE_NAME "s5p-fimd1"
+#define FIMD_ENTITY_NAME "s3c-fb-window"
+#define FLITE_MODULE_NAME "exynos-fimc-lite"
+#define CSIS_MODULE_NAME "s5p-mipi-csis"
+
+#define GSC_CAP_GRP_ID (1 << 0)
+#define FLITE_GRP_ID (1 << 1)
+#define CSIS_GRP_ID (1 << 2)
+#define SENSOR_GRP_ID (1 << 3)
+#define FIMD_GRP_ID (1 << 4)
+
+#define SENSOR_MAX_ENTITIES MAX_CAMIF_CLIENTS
+#define FLITE_MAX_ENTITIES 2
+#define CSIS_MAX_ENTITIES 2
+
+enum mdev_node {
+ MDEV_OUTPUT,
+ MDEV_CAPTURE,
+ MDEV_ISP,
+};
+
+enum mxr_data_from {
+ FROM_GSC_SD,
+ FROM_MXR_VD,
+};
+
+struct exynos_media_ops {
+ int (*power_off)(struct v4l2_subdev *sd);
+};
+
+struct exynos_entity_data {
+ const struct exynos_media_ops *media_ops;
+ enum mxr_data_from mxr_data_from;
+};
+
+/**
+ * struct exynos_md - Exynos media device information
+ * @media_dev: top level media device
+ * @v4l2_dev: top level v4l2_device holding up the subdevs
+ * @pdev: platform device this media device is hooked up into
+ * @slock: spinlock protecting @sensor array
+ * @id: media device IDs
+ * @gsc_sd: each pointer of g-scaler's subdev array
+ */
+struct exynos_md {
+ struct media_device media_dev;
+ struct v4l2_device v4l2_dev;
+ struct platform_device *pdev;
+ struct v4l2_subdev *gsc_sd[MAX_GSC_SUBDEV];
+ struct v4l2_subdev *gsc_cap_sd[MAX_GSC_SUBDEV];
+ struct v4l2_subdev *csis_sd[CSIS_MAX_ENTITIES];
+ struct v4l2_subdev *flite_sd[FLITE_MAX_ENTITIES];
+ struct v4l2_subdev *sensor_sd[SENSOR_MAX_ENTITIES];
+ u16 id;
+ bool is_flite_on;
+ spinlock_t slock;
+};
+
+static int dummy_callback(struct device *dev, void *md)
+{
+ /* non-zero return stops iteration */
+ return -1;
+}
+
+static inline void *module_name_to_driver_data(char *module_name)
+{
+ struct device_driver *drv;
+ struct device *dev;
+ void *driver_data;
+
+ drv = driver_find(module_name, &platform_bus_type);
+ if (drv) {
+ dev = driver_find_device(drv, NULL, NULL, dummy_callback);
+ driver_data = dev_get_drvdata(dev);
+ return driver_data;
+ } else
+ return NULL;
+}
+
+/* print entity information for debug*/
+static inline void entity_info_print(struct media_entity *me, struct device *dev)
+{
+ u16 num_pads = me->num_pads;
+ u16 num_links = me->num_links;
+ int i;
+
+ dev_dbg(dev, "entity name : %s\n", me->name);
+ dev_dbg(dev, "number of pads = %d\n", num_pads);
+ for (i = 0; i < num_pads; ++i) {
+ dev_dbg(dev, "pad[%d] flag : %s\n", i,
+ (me->pads[i].flags == 1) ? "SINK" : "SOURCE");
+ }
+
+ dev_dbg(dev, "number of links = %d\n", num_links);
+
+ for (i = 0; i < num_links; ++i) {
+ dev_dbg(dev, "link[%d] info = ", i);
+ dev_dbg(dev, "%s : %s[%d] ---> %s : %s[%d]\n",
+ me->links[i].source->entity->name,
+ me->links[i].source->flags == 1 ? "SINK" : "SOURCE",
+ me->links[i].source->index,
+ me->links[i].sink->entity->name,
+ me->links[i].sink->flags == 1 ? "SINK" : "SOURCE",
+ me->links[i].sink->index);
+ }
+}
+#endif
diff --git a/include/media/m5mols.h b/include/media/m5mols.h
index 4a825ae..544a284 100644
--- a/include/media/m5mols.h
+++ b/include/media/m5mols.h
@@ -1,5 +1,5 @@
/*
- * Driver header for M-5MOLS 8M Pixel camera sensor with ISP
+ * Driver for M5MOLS 8M Pixel camera sensor with ISP
*
* Copyright (C) 2011 Samsung Electronics Co., Ltd.
* Author: HeungJun Kim <riverful.kim@samsung.com>
@@ -17,17 +17,19 @@
#define MEDIA_M5MOLS_H
/**
- * struct m5mols_platform_data - platform data for M-5MOLS driver
- * @gpio_reset: GPIO driving the reset pin of M-5MOLS
- * @reset_polarity: active state for gpio_reset pin, 0 or 1
- * @set_power: an additional callback to the board setup code
+* struct m5mols_platform_data - platform data for M5MOLS driver
+* @irq: GPIO getting the irq pin of M5MOLS
+* @gpio_rst: GPIO driving the reset pin of M5MOLS
+ * @enable_rst: the pin state when reset pin is enabled
+* @set_power: an additional callback to a board setup code
* to be called after enabling and before disabling
- * the sensor's supply regulators
+* the sensor device supply regulators
*/
struct m5mols_platform_data {
- int gpio_reset;
- u8 reset_polarity;
int (*set_power)(struct device *dev, int on);
+ int irq;
+ int gpio_rst;
+ bool enable_rst;
};
#endif /* MEDIA_M5MOLS_H */
diff --git a/include/media/v4l2-mem2mem.h b/include/media/v4l2-mem2mem.h
index 16ac473..514b155 100644
--- a/include/media/v4l2-mem2mem.h
+++ b/include/media/v4l2-mem2mem.h
@@ -84,16 +84,22 @@
struct v4l2_m2m_buffer {
struct vb2_buffer vb;
struct list_head list;
+ struct list_head wait;
};
void *v4l2_m2m_get_curr_priv(struct v4l2_m2m_dev *m2m_dev);
+void v4l2_m2m_get_next_job(struct v4l2_m2m_dev *m2m_dev,
+ struct v4l2_m2m_ctx *m2m_ctx);
+
struct vb2_queue *v4l2_m2m_get_vq(struct v4l2_m2m_ctx *m2m_ctx,
enum v4l2_buf_type type);
void v4l2_m2m_job_finish(struct v4l2_m2m_dev *m2m_dev,
struct v4l2_m2m_ctx *m2m_ctx);
+void v4l2_m2m_try_schedule(struct v4l2_m2m_ctx *m2m_ctx);
+
static inline void
v4l2_m2m_buf_done(struct vb2_buffer *buf, enum vb2_buffer_state state)
{
diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h
index a15d1f1..4e2125a 100644
--- a/include/media/videobuf2-core.h
+++ b/include/media/videobuf2-core.h
@@ -16,6 +16,8 @@
#include <linux/mutex.h>
#include <linux/poll.h>
#include <linux/videodev2.h>
+#include <linux/dma-buf.h>
+#include <linux/sw_sync.h>
struct vb2_alloc_ctx;
struct vb2_fileio_data;
@@ -41,6 +43,24 @@
* argument to other ops in this structure
* @put_userptr: inform the allocator that a USERPTR buffer will no longer
* be used
+ * @attach_dmabuf: attach a shared struct dma_buf for a hardware operation;
+ * used for DMABUF memory types; alloc_ctx is the alloc context
+ * dbuf is the shared dma_buf; returns NULL on failure;
+ * allocator private per-buffer structure on success;
+ * this needs to be used for further accesses to the buffer
+ * @detach_dmabuf: inform the exporter of the buffer that the current DMABUF
+ * buffer is no longer used; the buf_priv argument is the
+ * allocator private per-buffer structure previously returned
+ * from the attach_dmabuf callback
+ * @map_dmabuf: request for access to the dmabuf from allocator; the allocator
+ * of dmabuf is informed that this driver is going to use the
+ * dmabuf
+ * @unmap_dmabuf: releases access control to the dmabuf - allocator is notified
+ * that this driver is done using the dmabuf for now
+ * @prepare: called everytime the buffer is passed from userspace to the
+ * driver, usefull for cache synchronisation, optional
+ * @finish: called everytime the buffer is passed back from the driver
+ * to the userspace, also optional
* @vaddr: return a kernel virtual address to a given memory buffer
* associated with the passed private structure or NULL if no
* such mapping exists
@@ -56,6 +76,8 @@
* Required ops for USERPTR types: get_userptr, put_userptr.
* Required ops for MMAP types: alloc, put, num_users, mmap.
* Required ops for read/write access types: alloc, put, num_users, vaddr
+ * Required ops for DMABUF types: attach_dmabuf, detach_dmabuf, map_dmabuf,
+ * unmap_dmabuf.
*/
struct vb2_mem_ops {
void *(*alloc)(void *alloc_ctx, unsigned long size);
@@ -65,6 +87,15 @@
unsigned long size, int write);
void (*put_userptr)(void *buf_priv);
+ void (*prepare)(void *buf_priv);
+ void (*finish)(void *buf_priv);
+
+ void *(*attach_dmabuf)(void *alloc_ctx, struct dma_buf *dbuf,
+ unsigned long size, int write);
+ void (*detach_dmabuf)(void *buf_priv);
+ int (*map_dmabuf)(void *buf_priv);
+ void (*unmap_dmabuf)(void *buf_priv);
+
void *(*vaddr)(void *buf_priv);
void *(*cookie)(void *buf_priv);
@@ -75,6 +106,8 @@
struct vb2_plane {
void *mem_priv;
+ struct dma_buf *dbuf;
+ unsigned int dbuf_mapped;
};
/**
@@ -83,12 +116,14 @@
* @VB2_USERPTR: driver supports USERPTR with streaming API
* @VB2_READ: driver supports read() style access
* @VB2_WRITE: driver supports write() style access
+ * @VB2_DMABUF: driver supports DMABUF with streaming API
*/
enum vb2_io_modes {
VB2_MMAP = (1 << 0),
VB2_USERPTR = (1 << 1),
VB2_READ = (1 << 2),
VB2_WRITE = (1 << 3),
+ VB2_DMABUF = (1 << 4),
};
/**
@@ -142,6 +177,8 @@
* @vb2_queue: the queue to which this driver belongs
* @num_planes: number of planes in the buffer
* on an internal driver queue
+ * @acquire_fence: sync fence that will be signaled when the buffer's
+ * contents are available.
* @state: current buffer state; do not change
* @queued_entry: entry on the queued buffers list, which holds all
* buffers queued from userspace
@@ -157,6 +194,8 @@
unsigned int num_planes;
+ struct sync_fence *acquire_fence;
+
/* Private: internal use only */
enum vb2_buffer_state state;
@@ -247,6 +286,7 @@
/**
* struct vb2_queue - a videobuf queue
*
+ * @name: name of the queue
* @type: queue type (see V4L2_BUF_TYPE_* in linux/videodev2.h
* @io_modes: supported io methods (see vb2_io_modes enum)
* @io_flags: additional io flags (see vb2_fileio_flags enum)
@@ -270,6 +310,7 @@
* @fileio: file io emulator internal data, used only if emulator is active
*/
struct vb2_queue {
+ const char *name;
enum v4l2_buf_type type;
unsigned int io_modes;
unsigned int io_flags;
@@ -297,6 +338,9 @@
unsigned int streaming:1;
struct vb2_fileio_data *fileio;
+
+ struct sw_sync_timeline *timeline;
+ u32 timeline_max;
};
void *vb2_plane_vaddr(struct vb2_buffer *vb, unsigned int plane_no);
diff --git a/include/media/videobuf2-ion.h b/include/media/videobuf2-ion.h
new file mode 100644
index 0000000..7a1985b
--- /dev/null
+++ b/include/media/videobuf2-ion.h
@@ -0,0 +1,221 @@
+/* include/media/videobuf2-ion.h
+ *
+ * Copyright 2011-2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Definition of Android ION memory allocator for videobuf2
+ *
+ * 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.
+ */
+
+#ifndef _MEDIA_VIDEOBUF2_ION_H
+#define _MEDIA_VIDEOBUF2_ION_H
+
+#include <linux/scatterlist.h>
+#include <linux/dma-mapping.h>
+#include <linux/ion.h>
+#include <linux/exynos_ion.h>
+#include <linux/err.h>
+
+/* flags to vb2_ion_create_context
+ * These flags are dependet upon heap flags in ION.
+ *
+ * bit 0 ~ ION_NUM_HEAPS: ion heap flags
+ * bit ION_NUM_HEAPS+1 ~ 20: non-ion flags (cached, iommu)
+ * bit 21 ~ BITS_PER_LONG - 1: ion specific flags
+ */
+
+/* Allocate physically contiguous memory */
+#define VB2ION_CTX_PHCONTIG ION_HEAP_CARVEOUT_MASK
+/* Allocate virtually contiguous memory */
+#define VB2ION_CTX_VMCONTIG ION_HEAP_SYSTEM_MASK
+/* Provide device a virtual address space */
+#define VB2ION_CTX_IOMMU (1 << (ION_NUM_HEAPS + 1))
+/* Non-cached mapping to user when mmap */
+#define VB2ION_CTX_UNCACHED (1 << (ION_NUM_HEAPS + 2))
+
+/* flags for contents protection */
+#define VB2ION_CTX_DRM_MFCSH ION_HEAP_EXYNOS_MFC_SH_MASK
+#define VB2ION_CTX_DRM_VIDEO ION_HEAP_EXYNOS_MFC_OUTPUT_MASK
+#define VB2ION_CTX_DRM_MFCFW ION_HEAP_EXYNOS_MFC_FW_MASK
+
+#define VB2ION_CTX_MASK_ION (~((1 << (BITS_PER_LONG - 12)) - 1) \
+ | ((1 << ION_NUM_HEAPS) - 1))
+/* mask out all non-ion flags */
+#define ion_heapflag(flag) (flag & VB2ION_CTX_MASK_ION)
+
+struct device;
+struct vb2_buffer;
+
+/* vb2_ion_create_context - create a new vb2 context for buffer manipulation
+ * dev - device that needs to use vb2
+ * alignment - minimum alignment requirement for the start address of the
+ * allocated buffer from vb2.
+ * flags - detailed control to the vb2 context. See above flags that stats
+ * with VB2ION_*
+ *
+ * This function creates a new videobuf2 context which is internal data of
+ * videobuf2 for allocating and manipulating buffers. Drivers that obtain vb2
+ * contexts must regard the contexts as keys for videobuf2 to access the
+ * requirments of the drivers for the buffers allocated from videobuf2.
+ *
+ * Once a driver obtains vb2 contexts from vb2_ion_create_context(), it must
+ * assign those contexts to alloc_ctxs[] argument of vb2_ops.queue_setup().
+ *
+ * Some specifications of a vb2 context can be changed after it has been created
+ * and assigned to vb2 core with vb2_ops.queue_setup():
+ * - vb2_ion_set_cached(): Changes cached attribute of the buffer which will be
+ * allocated after calling this function. Cached attribute of a buffer is
+ * effected when it is mapped to user with mmap() function call.
+ * - vb2_ion_set_alignment(): Changes alignment requirement of the buffer which
+ * will be allocated after calling this function.
+ *
+ * For the devices that needs internal buffers for firmwares or devices'
+ * context buffers, their drivers can generate a vb2 context which is not
+ * handled by vb2 core but only by vb2-ion.
+ * That kinds of vb2 contexts can be passed to the first parameter of
+ * vb2_ion_private_alloc(void *alloc_ctx, size_t size).
+ *
+ * Drivers can generate vb2 contexts as many as they require with different
+ * requirements specified in flags argument. The only _restriction_ on
+ * generating a vb2 context is that the drivers must call
+ * vb2_ion_create_context() in a kernel thread due to the behavior of
+ * ion_client_create().
+ */
+void *vb2_ion_create_context(struct device *dev, size_t alignment, long flags);
+
+/* vb2_ion_destroy_context - destroys a vb2 context
+ * This function removes the given vb2 context which is created by
+ * vb2_ion_create_context()
+ */
+void vb2_ion_destroy_context(void *ctx);
+
+void vb2_ion_set_cached(void *ctx, bool cached);
+void vb2_ion_set_protected(void *ctx, bool ctx_protected);
+int vb2_ion_set_alignment(void *ctx, size_t alignment);
+
+/* Data type of the cookie returned by vb2_plane_cookie() function call.
+ * The drivers do not need the definition of this structure. The only reason
+ * why it is defined outside of videobuf2-ion.c is to make some functions
+ * inline.
+ */
+struct vb2_ion_cookie {
+ dma_addr_t ioaddr;
+ struct sg_table *sgt;
+ off_t offset;
+};
+
+/* vb2_ion_phys_address - returns the physical address of the given buffer
+ * - cookie: pointer returned by vb2_plane_cookie()
+ * - phys_addr: pointer to the store of the physical address of the buffer
+ * specified by cookie.
+ *
+ * Returns -EINVAL if the buffer does not have nor physically contiguous memory.
+ */
+static inline int vb2_ion_phys_address(void *cookie, phys_addr_t *phys_addr)
+{
+ struct vb2_ion_cookie *vb2cookie = cookie;
+
+ if (WARN_ON(!phys_addr || IS_ERR_OR_NULL(cookie)))
+ return -EINVAL;
+
+ if (vb2cookie->sgt->nents == 1)
+ *phys_addr = sg_phys(vb2cookie->sgt->sgl) + vb2cookie->offset;
+ else
+ return -EINVAL;
+
+ return 0;
+}
+
+/* vb2_ion_dma_address - returns the DMA address that device can see
+ * - cookie: pointer returned by vb2_plane_cookie()
+ * - dma_addr: pointer to the store of the address of the buffer specified
+ * by cookie. It can be either IO virtual address or physical address
+ * depending on the specification of allocation context which allocated
+ * the buffer.
+ *
+ * Returns -EINVAL if the buffer has neither IO virtual address nor physically
+ * contiguous memory
+ */
+static inline int vb2_ion_dma_address(void *cookie, dma_addr_t *dma_addr)
+{
+ struct vb2_ion_cookie *vb2cookie = cookie;
+
+ if (WARN_ON(!dma_addr || IS_ERR_OR_NULL(cookie)))
+ return -EINVAL;
+
+ if (vb2cookie->ioaddr == 0)
+ return vb2_ion_phys_address(cookie, (phys_addr_t *)dma_addr);
+
+ *dma_addr = vb2cookie->ioaddr;
+
+ return 0;
+}
+
+/* vb2_ion_get_sg - returns scatterlist of the given cookie.
+ * - cookie: pointer returned by vb2_plane_cookie()
+ * - nents: pointer to the store of number of elements in the returned
+ * scatterlist
+ *
+ * Returns the scatterlist of the buffer specified by cookie.
+ * If the arguments are not correct, returns NULL.
+ */
+static inline struct scatterlist *vb2_ion_get_sg(void *cookie, int *nents)
+{
+ struct vb2_ion_cookie *vb2cookie = cookie;
+
+ if (WARN_ON(!nents || IS_ERR_OR_NULL(cookie)))
+ return NULL;
+
+ *nents = vb2cookie->sgt->nents;
+ return vb2cookie->sgt->sgl;
+}
+
+/***** Device's internal/context buffer support *****/
+
+/* vb2_ion_private_vaddr - the kernelspace address for the given cookie
+ * cookie - pointer returned by vb2_ion_private_alloc()
+ *
+ * This function returns minus error value on error.
+ */
+void *vb2_ion_private_vaddr(void *cookie);
+
+/* vb2_ion_private_alloc - allocate a buffer for device drivers's private use
+ * alloc_ctx - pointer returned by vb2_ion_create_context
+ * size - size of the buffer allocated
+ *
+ * This function returns the pointer to a cookie that represents the allocated
+ * buffer or minus error value. With the cookie you can:
+ * - retrieve scatterlist of the buffer.
+ * - retrieve dma address. (IO virutal address if IOMMU is enabled when
+ * creating alloc_ctx or physical address)
+ * - retrieve virtual address in the kernel space.
+ * - free the allocated buffer
+ */
+void *vb2_ion_private_alloc(void *alloc_ctx, size_t size);
+
+/* vb2_ion_private_free - free the buffer allocated by vb2_ion_private_alloc */
+void vb2_ion_private_free(void *cookie);
+
+/***** Cache mainatenance operations *****/
+void vb2_ion_sync_for_device(void *cookie, off_t offset, size_t size,
+ enum dma_data_direction dir);
+void vb2_ion_sync_for_cpu(void *cookie, off_t offset, size_t size,
+ enum dma_data_direction dir);
+int vb2_ion_cache_flush(struct vb2_buffer *vb, u32 num_planes);
+int vb2_ion_cache_inv(struct vb2_buffer *vb, u32 num_planes);
+
+/* IOMMU support */
+
+/* vb2_ion_attach_iommu - enables IOMMU of the device specified in alloc_ctx */
+int vb2_ion_attach_iommu(void *alloc_ctx);
+
+/* vb2_ion_attach_iommu - disables IOMMU of the device specified in alloc_ctx */
+void vb2_ion_detach_iommu(void *alloc_ctx);
+
+extern const struct vb2_mem_ops vb2_ion_memops;
+extern struct ion_device *ion_exynos; /* drivers/gpu/ion/exynos/exynos-ion.c */
+
+#endif /* _MEDIA_VIDEOBUF2_ION_H */
diff --git a/include/trace/events/memory_bus.h b/include/trace/events/memory_bus.h
new file mode 100644
index 0000000..8ee69e1
--- /dev/null
+++ b/include/trace/events/memory_bus.h
@@ -0,0 +1,51 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM memory_bus
+
+#if !defined(_TRACE_BUS_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_MEMORY_BUS_H
+
+#include <linux/types.h>
+#include <linux/tracepoint.h>
+
+TRACE_EVENT(memory_bus_usage,
+
+ TP_PROTO(const char *name, unsigned long long rw_bytes,
+ unsigned long long r_bytes,
+ unsigned long long w_bytes,
+ unsigned long long cycles,
+ unsigned long long ns),
+
+ TP_ARGS(name, rw_bytes, r_bytes, w_bytes, cycles, ns),
+
+ TP_STRUCT__entry(
+ __string( name, name)
+ __field(unsigned long long, rw_bytes)
+ __field(unsigned long long, r_bytes)
+ __field(unsigned long long, w_bytes)
+ __field(unsigned long long, cycles)
+ __field(unsigned long long, ns)
+ ),
+
+ TP_fast_assign(
+ __assign_str(name, name);
+ __entry->rw_bytes = rw_bytes;
+ __entry->r_bytes = r_bytes;
+ __entry->w_bytes = w_bytes;
+ __entry->cycles = cycles;
+ __entry->ns = ns;
+ ),
+
+ TP_printk("bus=%s rw_bytes=%llu r_bytes=%llu w_bytes=%llu cycles=%llu ns=%llu",
+ __get_str(name),
+ __entry->rw_bytes,
+ __entry->r_bytes,
+ __entry->w_bytes,
+ __entry->cycles,
+ __entry->ns)
+);
+
+
+#endif /* _TRACE_MEMORY_BUS_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/include/video/s5p-dp.h b/include/video/s5p-dp.h
new file mode 100644
index 0000000..8b3d764
--- /dev/null
+++ b/include/video/s5p-dp.h
@@ -0,0 +1,148 @@
+/*
+ * Samsung SoC DP device support
+ *
+ * Copyright (C) 2012 Samsung Electronics Co., Ltd.
+ * Author: Jingoo Han <jg1.han@samsung.com>
+ *
+ * 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.
+ */
+
+#ifndef _S5P_DP_H
+#define _S5P_DP_H
+
+#define DP_TIMEOUT_LOOP_COUNT 100
+#define MAX_CR_LOOP 5
+#define MAX_EQ_LOOP 4
+
+enum link_rate_type {
+ LINK_RATE_1_62GBPS = 0x06,
+ LINK_RATE_2_70GBPS = 0x0a
+};
+
+enum link_lane_count_type {
+ LANE_COUNT1 = 1,
+ LANE_COUNT2 = 2,
+ LANE_COUNT4 = 4
+};
+
+enum link_training_state {
+ START,
+ CLOCK_RECOVERY,
+ EQUALIZER_TRAINING,
+ FINISHED,
+ FAILED
+};
+
+enum voltage_swing_level {
+ VOLTAGE_LEVEL_0,
+ VOLTAGE_LEVEL_1,
+ VOLTAGE_LEVEL_2,
+ VOLTAGE_LEVEL_3,
+};
+
+enum pre_emphasis_level {
+ PRE_EMPHASIS_LEVEL_0,
+ PRE_EMPHASIS_LEVEL_1,
+ PRE_EMPHASIS_LEVEL_2,
+ PRE_EMPHASIS_LEVEL_3,
+};
+
+enum pattern_set {
+ PRBS7,
+ D10_2,
+ TRAINING_PTN1,
+ TRAINING_PTN2,
+ DP_NONE
+};
+
+enum color_space {
+ COLOR_RGB,
+ COLOR_YCBCR422,
+ COLOR_YCBCR444
+};
+
+enum color_depth {
+ COLOR_6,
+ COLOR_8,
+ COLOR_10,
+ COLOR_12
+};
+
+enum color_coefficient {
+ COLOR_YCBCR601,
+ COLOR_YCBCR709
+};
+
+enum dynamic_range {
+ VESA,
+ CEA
+};
+
+enum pll_status {
+ PLL_UNLOCKED,
+ PLL_LOCKED
+};
+
+enum clock_recovery_m_value_type {
+ CALCULATED_M,
+ REGISTER_M
+};
+
+enum video_timing_recognition_type {
+ VIDEO_TIMING_FROM_CAPTURE,
+ VIDEO_TIMING_FROM_REGISTER
+};
+
+enum analog_power_block {
+ AUX_BLOCK,
+ CH0_BLOCK,
+ CH1_BLOCK,
+ CH2_BLOCK,
+ CH3_BLOCK,
+ ANALOG_TOTAL,
+ POWER_ALL
+};
+
+enum aux_tx_terminal_resistor {
+ AUX_TX_37_5_OHM,
+ AUX_TX_45_OHM,
+ AUX_TX_50_OHM,
+ AUX_TX_65_OHM
+};
+
+struct video_info {
+ char *name;
+
+ bool h_sync_polarity;
+ bool v_sync_polarity;
+ bool interlaced;
+
+ enum color_space color_space;
+ enum dynamic_range dynamic_range;
+ enum color_coefficient ycbcr_coeff;
+ enum color_depth color_depth;
+
+ enum link_rate_type link_rate;
+ enum link_lane_count_type lane_count;
+};
+
+struct analog_param {
+ enum aux_tx_terminal_resistor aux_tx_terminal_resistor;
+ unsigned int tx_amplitude;
+};
+
+struct s5p_dp_platdata {
+ struct video_info *video_info;
+ struct analog_param *analog_param;
+
+ void (*phy_init)(void);
+ void (*phy_exit)(void);
+ void (*backlight_on)(void);
+ void (*backlight_off)(void);
+ void (*lcd_on)(void);
+ void (*lcd_off)(void);
+};
+
+#endif /* _S5P_DP_H */
diff --git a/kernel/power/qos.c b/kernel/power/qos.c
index 6a031e6..5d1e898 100644
--- a/kernel/power/qos.c
+++ b/kernel/power/qos.c
@@ -41,6 +41,8 @@
#include <linux/platform_device.h>
#include <linux/init.h>
#include <linux/kernel.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
#include <linux/uaccess.h>
#include <linux/export.h>
@@ -86,6 +88,18 @@
.name = "network_latency",
};
+static BLOCKING_NOTIFIER_HEAD(memory_throughput_notifier);
+static struct pm_qos_constraints memory_tput_constraints = {
+ .list = PLIST_HEAD_INIT(memory_tput_constraints.list),
+ .target_value = PM_QOS_MEMORY_THROUGHPUT_DEFAULT_VALUE,
+ .default_value = PM_QOS_MEMORY_THROUGHPUT_DEFAULT_VALUE,
+ .type = PM_QOS_SUM,
+ .notifiers = &memory_throughput_notifier,
+};
+static struct pm_qos_object memory_throughput_pm_qos = {
+ .constraints = &memory_tput_constraints,
+ .name = "memory_throughput",
+};
static BLOCKING_NOTIFIER_HEAD(network_throughput_notifier);
static struct pm_qos_constraints network_tput_constraints = {
@@ -105,6 +119,7 @@
&null_pm_qos,
&cpu_dma_pm_qos,
&network_lat_pm_qos,
+ &memory_throughput_pm_qos,
&network_throughput_pm_qos
};
@@ -126,6 +141,9 @@
/* unlocked internal variant */
static inline int pm_qos_get_value(struct pm_qos_constraints *c)
{
+ unsigned int sum = 0;
+ struct plist_node *p;
+
if (plist_head_empty(&c->list))
return c->default_value;
@@ -136,6 +154,16 @@
case PM_QOS_MAX:
return plist_last(&c->list)->prio;
+ case PM_QOS_SUM:
+ plist_for_each(p, &c->list) {
+ if (p->prio < 0)
+ continue;
+ if (sum + p->prio > INT_MAX)
+ return INT_MAX;
+ sum += p->prio;
+ }
+ return sum;
+
default:
/* runtime check for not using enum */
BUG();
@@ -515,6 +543,47 @@
return count;
}
+static void pm_qos_debug_show_one(struct seq_file *s, struct pm_qos_object *qos)
+{
+ struct plist_node *p;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pm_qos_lock, flags);
+
+ seq_printf(s, "%s\n", qos->name);
+ seq_printf(s, " default value: %d\n", qos->constraints->default_value);
+ seq_printf(s, " target value: %d\n", qos->constraints->target_value);
+ seq_printf(s, " requests:\n");
+ plist_for_each(p, &qos->constraints->list)
+ seq_printf(s, " %pk: %d\n",
+ container_of(p, struct pm_qos_request, node),
+ p->prio);
+
+ spin_unlock_irqrestore(&pm_qos_lock, flags);
+
+}
+
+static int pm_qos_debug_show(struct seq_file *s, void *d)
+{
+ int i;
+
+ for (i = 1; i < PM_QOS_NUM_CLASSES; i++)
+ pm_qos_debug_show_one(s, pm_qos_array[i]);
+
+ return 0;
+}
+
+static int pm_qos_debug_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, pm_qos_debug_show, inode->i_private);
+}
+
+const static struct file_operations pm_qos_debug_fops = {
+ .open = pm_qos_debug_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
static int __init pm_qos_power_init(void)
{
@@ -532,6 +601,8 @@
}
}
+ debugfs_create_file("pm_qos", S_IRUGO, NULL, NULL, &pm_qos_debug_fops);
+
return ret;
}
diff --git a/lib/genalloc.c b/lib/genalloc.c
index 6bc04aa..27816a6 100644
--- a/lib/genalloc.c
+++ b/lib/genalloc.c
@@ -253,12 +253,17 @@
* gen_pool_alloc - allocate special memory from the pool
* @pool: pool to allocate from
* @size: number of bytes to allocate from the pool
+ * @alignment_order: Order the allocated space should be
+ * aligned to (eg. 20 means allocated space
+ * must be aligned to 1MiB).
*
* Allocate the requested number of bytes from the specified pool.
* Uses a first-fit algorithm. Can not be used in NMI handler on
* architectures without NMI-safe cmpxchg implementation.
*/
-unsigned long gen_pool_alloc(struct gen_pool *pool, size_t size)
+unsigned long __must_check
+gen_pool_alloc_aligned(struct gen_pool *pool, size_t size,
+ unsigned alignment_order)
{
struct gen_pool_chunk *chunk;
unsigned long addr = 0;
@@ -269,6 +274,9 @@
BUG_ON(in_nmi());
#endif
+ if (alignment_order < order)
+ alignment_order = order;
+
if (size == 0)
return 0;
@@ -281,7 +289,8 @@
end_bit = (chunk->end_addr - chunk->start_addr) >> order;
retry:
start_bit = bitmap_find_next_zero_area(chunk->bits, end_bit,
- start_bit, nbits, 0);
+ start_bit, nbits,
+ (1 << (alignment_order - order)) - 1);
if (start_bit >= end_bit)
continue;
remain = bitmap_set_ll(chunk->bits, start_bit, nbits);
@@ -300,7 +309,7 @@
rcu_read_unlock();
return addr;
}
-EXPORT_SYMBOL(gen_pool_alloc);
+EXPORT_SYMBOL(gen_pool_alloc_aligned);
/**
* gen_pool_free - free allocated special memory back to the pool
diff --git a/mm/Kconfig b/mm/Kconfig
index e338407..d76a351 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -379,3 +379,55 @@
in a negligible performance hit.
If unsure, say Y to enable cleancache
+
+config CMA
+ bool "Contiguous Memory Allocator framework"
+ # Currently there is only one allocator so force it on
+ select CMA_BEST_FIT
+ help
+ This enables the Contiguous Memory Allocator framework which
+ allows drivers to allocate big physically-contiguous blocks of
+ memory for use with hardware components that do not support I/O
+ map nor scatter-gather.
+
+ If you select this option you will also have to select at least
+ one allocator algorithm below.
+
+ To make use of CMA you need to specify the regions and
+ driver->region mapping on command line when booting the kernel.
+
+config CMA_DEVELOPEMENT
+ bool "Include CMA developement features"
+ depends on CMA
+ help
+ This lets you enable some developement features of the CMA
+ freamework.
+
+config CMA_DEBUG
+ bool "CMA debug messages"
+ depends on CMA_DEVELOPEMENT
+ help
+ Enable debug messages in CMA code.
+
+config CMA_SYSFS
+ bool "CMA SysFS interface support"
+ depends on CMA_DEVELOPEMENT
+ help
+ Enable support for SysFS interface.
+
+config CMA_CMDLINE
+ bool "CMA command line parameters support"
+ depends on CMA_DEVELOPEMENT
+ help
+ Enable support for cma, cma.map and cma.asterisk command line
+ parameters.
+
+config CMA_BEST_FIT
+ bool "CMA best-fit allocator"
+ depends on CMA
+ help
+ This is a best-fit algorithm running in O(n log n) time where
+ n is the number of existing holes (which is never greater then
+ the number of allocated regions and usually much smaller). It
+ allocates area from the smallest hole that is big enough for
+ allocation in question.
diff --git a/mm/Makefile b/mm/Makefile
index 50ec00e..b473c70 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -51,3 +51,5 @@
obj-$(CONFIG_DEBUG_KMEMLEAK) += kmemleak.o
obj-$(CONFIG_DEBUG_KMEMLEAK_TEST) += kmemleak-test.o
obj-$(CONFIG_CLEANCACHE) += cleancache.o
+obj-$(CONFIG_CMA) += cma.o
+obj-$(CONFIG_CMA_BEST_FIT) += cma-best-fit.o
diff --git a/mm/cma-best-fit.c b/mm/cma-best-fit.c
new file mode 100644
index 0000000..24c27c8
--- /dev/null
+++ b/mm/cma-best-fit.c
@@ -0,0 +1,408 @@
+/*
+ * Contiguous Memory Allocator framework: Best Fit allocator
+ * Copyright (c) 2010 by Samsung Electronics.
+ * Written by Michal Nazarewicz (m.nazarewicz@samsung.com)
+ *
+ * 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 optional) any later version of the license.
+ */
+
+#define pr_fmt(fmt) "cma: bf: " fmt
+
+#ifdef CONFIG_CMA_DEBUG
+# define DEBUG
+#endif
+
+#include <linux/errno.h> /* Error numbers */
+#include <linux/slab.h> /* kmalloc() */
+
+#include <linux/cma.h> /* CMA structures */
+
+
+/************************* Data Types *************************/
+
+struct cma_bf_item {
+ struct cma_chunk ch;
+ struct rb_node by_size;
+};
+
+struct cma_bf_private {
+ struct rb_root by_start_root;
+ struct rb_root by_size_root;
+};
+
+
+/************************* Prototypes *************************/
+
+/*
+ * Those are only for holes. They must be called whenever hole's
+ * properties change but also whenever chunk becomes a hole or hole
+ * becames a chunk.
+ */
+static void __cma_bf_hole_insert_by_size(struct cma_bf_item *item);
+static void __cma_bf_hole_erase_by_size(struct cma_bf_item *item);
+static int __must_check
+__cma_bf_hole_insert_by_start(struct cma_bf_item *item);
+static void __cma_bf_hole_erase_by_start(struct cma_bf_item *item);
+
+/**
+ * __cma_bf_hole_take - takes a chunk of memory out of a hole.
+ * @hole: hole to take chunk from
+ * @size: chunk's size
+ * @alignment: chunk's starting address alignment (must be power of two)
+ *
+ * Takes a @size bytes large chunk from hole @hole which must be able
+ * to hold the chunk. The "must be able" includes also alignment
+ * constraint.
+ *
+ * Returns allocated item or NULL on error (if kmalloc() failed).
+ */
+static struct cma_bf_item *__must_check
+__cma_bf_hole_take(struct cma_bf_item *hole, size_t size, dma_addr_t alignment);
+
+/**
+ * __cma_bf_hole_merge_maybe - tries to merge hole with neighbours.
+ * @item: hole to try and merge
+ *
+ * Which items are preserved is undefined so you may not rely on it.
+ */
+static void __cma_bf_hole_merge_maybe(struct cma_bf_item *item);
+
+
+/************************* Device API *************************/
+
+int cma_bf_init(struct cma_region *reg)
+{
+ struct cma_bf_private *prv;
+ struct cma_bf_item *item;
+
+ prv = kzalloc(sizeof *prv, GFP_KERNEL);
+ if (unlikely(!prv))
+ return -ENOMEM;
+
+ item = kzalloc(sizeof *item, GFP_KERNEL);
+ if (unlikely(!item)) {
+ kfree(prv);
+ return -ENOMEM;
+ }
+
+ item->ch.start = reg->start;
+ item->ch.size = reg->size;
+ item->ch.reg = reg;
+
+ rb_root_init(&prv->by_start_root, &item->ch.by_start);
+ rb_root_init(&prv->by_size_root, &item->by_size);
+
+ reg->private_data = prv;
+ return 0;
+}
+
+void cma_bf_cleanup(struct cma_region *reg)
+{
+ struct cma_bf_private *prv = reg->private_data;
+ struct cma_bf_item *item =
+ rb_entry(prv->by_size_root.rb_node,
+ struct cma_bf_item, by_size);
+
+ /* We can assume there is only a single hole in the tree. */
+ WARN_ON(item->by_size.rb_left || item->by_size.rb_right ||
+ item->ch.by_start.rb_left || item->ch.by_start.rb_right);
+
+ kfree(item);
+ kfree(prv);
+}
+
+struct cma_chunk *cma_bf_alloc(struct cma_region *reg,
+ size_t size, dma_addr_t alignment)
+{
+ struct cma_bf_private *prv = reg->private_data;
+ struct rb_node *node = prv->by_size_root.rb_node;
+ struct cma_bf_item *item = NULL;
+
+ /* First find hole that is large enough */
+ while (node) {
+ struct cma_bf_item *i =
+ rb_entry(node, struct cma_bf_item, by_size);
+
+ if (i->ch.size < size) {
+ node = node->rb_right;
+ } else if (i->ch.size >= size) {
+ node = node->rb_left;
+ item = i;
+ }
+ }
+ if (!item)
+ return NULL;
+
+ /* Now look for items which can satisfy alignment requirements */
+ node = &item->by_size;
+ for (;;) {
+ dma_addr_t start = ALIGN(item->ch.start, alignment);
+ dma_addr_t end = item->ch.start + item->ch.size;
+ if (start < end && end - start >= size) {
+ item = __cma_bf_hole_take(item, size, alignment);
+ return likely(item) ? &item->ch : NULL;
+ }
+
+ node = rb_next(node);
+ if (!node)
+ return NULL;
+
+ item = rb_entry(node, struct cma_bf_item, by_size);
+ }
+}
+
+void cma_bf_free(struct cma_chunk *chunk)
+{
+ struct cma_bf_item *item = container_of(chunk, struct cma_bf_item, ch);
+
+ /* Add new hole */
+ if (unlikely(__cma_bf_hole_insert_by_start(item))) {
+ /*
+ * We're screwed... Just free the item and forget
+ * about it. Things are broken beyond repair so no
+ * sense in trying to recover.
+ */
+ kfree(item);
+ } else {
+ __cma_bf_hole_insert_by_size(item);
+
+ /* Merge with prev and next sibling */
+ __cma_bf_hole_merge_maybe(item);
+ }
+}
+
+
+/************************* Basic Tree Manipulation *************************/
+
+static void __cma_bf_hole_insert_by_size(struct cma_bf_item *item)
+{
+ struct cma_bf_private *prv = item->ch.reg->private_data;
+ struct rb_node **link = &prv->by_size_root.rb_node, *parent = NULL;
+ const typeof(item->ch.size) value = item->ch.size;
+
+ while (*link) {
+ struct cma_bf_item *i;
+ parent = *link;
+ i = rb_entry(parent, struct cma_bf_item, by_size);
+ link = value <= i->ch.size
+ ? &parent->rb_left
+ : &parent->rb_right;
+ }
+
+ rb_link_node(&item->by_size, parent, link);
+ rb_insert_color(&item->by_size, &prv->by_size_root);
+}
+
+static void __cma_bf_hole_erase_by_size(struct cma_bf_item *item)
+{
+ struct cma_bf_private *prv = item->ch.reg->private_data;
+ rb_erase(&item->by_size, &prv->by_size_root);
+}
+
+static int __must_check
+__cma_bf_hole_insert_by_start(struct cma_bf_item *item)
+{
+ struct cma_bf_private *prv = item->ch.reg->private_data;
+ struct rb_node **link = &prv->by_start_root.rb_node, *parent = NULL;
+ const typeof(item->ch.start) value = item->ch.start;
+
+ while (*link) {
+ struct cma_bf_item *i;
+ parent = *link;
+ i = rb_entry(parent, struct cma_bf_item, ch.by_start);
+
+ if (WARN_ON(value == i->ch.start))
+ /*
+ * This should *never* happen. And I mean
+ * *never*. We could even BUG on it but
+ * hopefully things are only a bit broken,
+ * ie. system can still run. We produce
+ * a warning and return an error.
+ */
+ return -EBUSY;
+
+ link = value <= i->ch.start
+ ? &parent->rb_left
+ : &parent->rb_right;
+ }
+
+ rb_link_node(&item->ch.by_start, parent, link);
+ rb_insert_color(&item->ch.by_start, &prv->by_start_root);
+ return 0;
+}
+
+static void __cma_bf_hole_erase_by_start(struct cma_bf_item *item)
+{
+ struct cma_bf_private *prv = item->ch.reg->private_data;
+ rb_erase(&item->ch.by_start, &prv->by_start_root);
+}
+
+
+/************************* More Tree Manipulation *************************/
+
+static struct cma_bf_item *__must_check
+__cma_bf_hole_take(struct cma_bf_item *hole, size_t size, size_t alignment)
+{
+ struct cma_bf_item *item;
+
+ /*
+ * There are three cases:
+ * 1. the chunk takes the whole hole,
+ * 2. the chunk is at the beginning or at the end of the hole, or
+ * 3. the chunk is in the middle of the hole.
+ */
+
+
+ /* Case 1, the whole hole */
+ if (size == hole->ch.size) {
+ __cma_bf_hole_erase_by_size(hole);
+ __cma_bf_hole_erase_by_start(hole);
+ return hole;
+ }
+
+
+ /* Allocate */
+ item = kmalloc(sizeof *item, GFP_KERNEL);
+ if (unlikely(!item))
+ return NULL;
+
+ item->ch.start = ALIGN(hole->ch.start, alignment);
+ item->ch.size = size;
+
+ /* Case 3, in the middle */
+ if (item->ch.start != hole->ch.start
+ && item->ch.start + item->ch.size !=
+ hole->ch.start + hole->ch.size) {
+ struct cma_bf_item *tail;
+
+ /*
+ * Space between the end of the chunk and the end of
+ * the region, ie. space left after the end of the
+ * chunk. If this is dividable by alignment we can
+ * move the chunk to the end of the hole.
+ */
+ size_t left =
+ hole->ch.start + hole->ch.size -
+ (item->ch.start + item->ch.size);
+ if (left % alignment == 0) {
+ item->ch.start += left;
+ goto case_2;
+ }
+
+ /*
+ * We are going to add a hole at the end. This way,
+ * we will reduce the problem to case 2 -- the chunk
+ * will be at the end of the hole.
+ */
+ tail = kmalloc(sizeof *tail, GFP_KERNEL);
+ if (unlikely(!tail)) {
+ kfree(item);
+ return NULL;
+ }
+
+ tail->ch.start = item->ch.start + item->ch.size;
+ tail->ch.size =
+ hole->ch.start + hole->ch.size - tail->ch.start;
+ tail->ch.reg = hole->ch.reg;
+
+ if (unlikely(__cma_bf_hole_insert_by_start(tail))) {
+ /*
+ * Things are broken beyond repair... Abort
+ * inserting the hole but still continue with
+ * allocation (seems like the best we can do).
+ */
+
+ hole->ch.size = tail->ch.start - hole->ch.start;
+ kfree(tail);
+ } else {
+ __cma_bf_hole_insert_by_size(tail);
+ /*
+ * It's important that we first insert the new
+ * hole in the tree sorted by size and later
+ * reduce the size of the old hole. We will
+ * update the position of the old hole in the
+ * rb tree in code that handles case 2.
+ */
+ hole->ch.size = tail->ch.start - hole->ch.start;
+ }
+
+ /* Go to case 2 */
+ }
+
+
+ /* Case 2, at the beginning or at the end */
+case_2:
+ /* No need to update the tree; order preserved. */
+ if (item->ch.start == hole->ch.start)
+ hole->ch.start += item->ch.size;
+
+ /* Alter hole's size */
+ hole->ch.size -= size;
+ __cma_bf_hole_erase_by_size(hole);
+ __cma_bf_hole_insert_by_size(hole);
+
+ return item;
+}
+
+
+static void __cma_bf_hole_merge_maybe(struct cma_bf_item *item)
+{
+ struct cma_bf_item *prev;
+ struct rb_node *node;
+ int twice = 2;
+
+ node = rb_prev(&item->ch.by_start);
+ if (unlikely(!node))
+ goto next;
+ prev = rb_entry(node, struct cma_bf_item, ch.by_start);
+
+ for (;;) {
+ if (prev->ch.start + prev->ch.size == item->ch.start) {
+ /* Remove previous hole from trees */
+ __cma_bf_hole_erase_by_size(prev);
+ __cma_bf_hole_erase_by_start(prev);
+
+ /* Alter this hole */
+ item->ch.size += prev->ch.size;
+ item->ch.start = prev->ch.start;
+ __cma_bf_hole_erase_by_size(item);
+ __cma_bf_hole_insert_by_size(item);
+ /*
+ * No need to update by start trees as we do
+ * not break sequence order
+ */
+
+ /* Free prev hole */
+ kfree(prev);
+ }
+
+next:
+ if (!--twice)
+ break;
+
+ node = rb_next(&item->ch.by_start);
+ if (unlikely(!node))
+ break;
+ prev = item;
+ item = rb_entry(node, struct cma_bf_item, ch.by_start);
+ }
+}
+
+
+
+/************************* Register *************************/
+static int cma_bf_module_init(void)
+{
+ static struct cma_allocator alloc = {
+ .name = "bf",
+ .init = cma_bf_init,
+ .cleanup = cma_bf_cleanup,
+ .alloc = cma_bf_alloc,
+ .free = cma_bf_free,
+ };
+ return cma_allocator_register(&alloc);
+}
+module_init(cma_bf_module_init);
diff --git a/mm/cma.c b/mm/cma.c
new file mode 100644
index 0000000..546dd86
--- /dev/null
+++ b/mm/cma.c
@@ -0,0 +1,1413 @@
+/*
+ * Contiguous Memory Allocator framework
+ * Copyright (c) 2010 by Samsung Electronics.
+ * Written by Michal Nazarewicz (m.nazarewicz@samsung.com)
+ *
+ * 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 optional) any later version of the license.
+ */
+
+/*
+ * See Documentation/contiguous-memory.txt for details.
+ */
+
+#define pr_fmt(fmt) "cma: " fmt
+
+#ifdef CONFIG_CMA_DEBUG
+# define DEBUG
+#endif
+
+#ifndef CONFIG_NO_BOOTMEM
+# include <linux/bootmem.h> /* alloc_bootmem_pages_nopanic() */
+#endif
+#ifdef CONFIG_HAVE_MEMBLOCK
+# include <linux/memblock.h> /* memblock*() */
+#endif
+#include <linux/device.h> /* struct device, dev_name() */
+#include <linux/errno.h> /* Error numbers */
+#include <linux/err.h> /* IS_ERR, PTR_ERR, etc. */
+#include <linux/mm.h> /* PAGE_ALIGN() */
+#include <linux/module.h> /* EXPORT_SYMBOL_GPL() */
+#include <linux/mutex.h> /* mutex */
+#include <linux/slab.h> /* kmalloc() */
+#include <linux/string.h> /* str*() */
+
+#include <linux/cma.h>
+#include <linux/vmalloc.h>
+
+/*
+ * Protects cma_regions, cma_allocators, cma_map, cma_map_length,
+ * cma_kobj, cma_sysfs_regions and cma_chunks_by_start.
+ */
+static DEFINE_MUTEX(cma_mutex);
+
+
+
+/************************* Map attribute *************************/
+
+static const char *cma_map;
+static size_t cma_map_length;
+
+/*
+ * map-attr ::= [ rules [ ';' ] ]
+ * rules ::= rule [ ';' rules ]
+ * rule ::= patterns '=' regions
+ * patterns ::= pattern [ ',' patterns ]
+ * regions ::= REG-NAME [ ',' regions ]
+ * pattern ::= dev-pattern [ '/' TYPE-NAME ] | '/' TYPE-NAME
+ *
+ * See Documentation/contiguous-memory.txt for details.
+ */
+static ssize_t cma_map_validate(const char *param)
+{
+ const char *ch = param;
+
+ if (*ch == '\0' || *ch == '\n')
+ return 0;
+
+ for (;;) {
+ const char *start = ch;
+
+ while (*ch && *ch != '\n' && *ch != ';' && *ch != '=')
+ ++ch;
+
+ if (*ch != '=' || start == ch) {
+ pr_err("map: expecting \"<patterns>=<regions>\" near %s\n",
+ start);
+ return -EINVAL;
+ }
+
+ while (*++ch != ';')
+ if (*ch == '\0' || *ch == '\n')
+ return ch - param;
+ if (ch[1] == '\0' || ch[1] == '\n')
+ return ch - param;
+ ++ch;
+ }
+}
+
+static int __init cma_map_param(char *param)
+{
+ ssize_t len;
+
+ pr_debug("param: map: %s\n", param);
+
+ len = cma_map_validate(param);
+ if (len < 0)
+ return len;
+
+ cma_map = param;
+ cma_map_length = len;
+ return 0;
+}
+
+#if defined CONFIG_CMA_CMDLINE
+
+early_param("cma.map", cma_map_param);
+
+#endif
+
+
+
+/************************* Early regions *************************/
+
+struct list_head cma_early_regions __initdata =
+ LIST_HEAD_INIT(cma_early_regions);
+
+#ifdef CONFIG_CMA_CMDLINE
+
+/*
+ * regions-attr ::= [ regions [ ';' ] ]
+ * regions ::= region [ ';' regions ]
+ *
+ * region ::= [ '-' ] reg-name
+ * '=' size
+ * [ '@' start ]
+ * [ '/' alignment ]
+ * [ ':' alloc-name ]
+ *
+ * See Documentation/contiguous-memory.txt for details.
+ *
+ * Example:
+ * cma=reg1=64M:bf;reg2=32M@0x100000:bf;reg3=64M/1M:bf
+ *
+ * If allocator is ommited the first available allocater will be used.
+ */
+
+#define NUMPARSE(cond_ch, type, cond) ({ \
+ unsigned long long v = 0; \
+ if (*param == (cond_ch)) { \
+ const char *const msg = param + 1; \
+ v = memparse(msg, ¶m); \
+ if (!v || v > ~(type)0 || !(cond)) { \
+ pr_err("param: invalid value near %s\n", msg); \
+ ret = -EINVAL; \
+ break; \
+ } \
+ } \
+ v; \
+ })
+
+static int __init cma_param_parse(char *param)
+{
+ static struct cma_region regions[16];
+
+ size_t left = ARRAY_SIZE(regions);
+ struct cma_region *reg = regions;
+ int ret = 0;
+
+ pr_debug("param: %s\n", param);
+
+ for (; *param; ++reg) {
+ dma_addr_t start, alignment;
+ size_t size;
+
+ if (unlikely(!--left)) {
+ pr_err("param: too many early regions\n");
+ return -ENOSPC;
+ }
+
+ /* Parse name */
+ reg->name = param;
+ param = strchr(param, '=');
+ if (!param || param == reg->name) {
+ pr_err("param: expected \"<name>=\" near %s\n",
+ reg->name);
+ ret = -EINVAL;
+ break;
+ }
+ *param = '\0';
+
+ /* Parse numbers */
+ size = NUMPARSE('\0', size_t, true);
+ start = NUMPARSE('@', dma_addr_t, true);
+ alignment = NUMPARSE('/', dma_addr_t, (v & (v - 1)) == 0);
+
+ alignment = max(alignment, (dma_addr_t)PAGE_SIZE);
+ start = ALIGN(start, alignment);
+ size = PAGE_ALIGN(size);
+ if (start + size < start) {
+ pr_err("param: invalid start, size combination\n");
+ ret = -EINVAL;
+ break;
+ }
+
+ /* Parse allocator */
+ if (*param == ':') {
+ reg->alloc_name = ++param;
+ while (*param && *param != ';')
+ ++param;
+ if (param == reg->alloc_name)
+ reg->alloc_name = NULL;
+ }
+
+ /* Go to next */
+ if (*param == ';') {
+ *param = '\0';
+ ++param;
+ } else if (*param) {
+ pr_err("param: expecting ';' or end of parameter near %s\n",
+ param);
+ ret = -EINVAL;
+ break;
+ }
+
+ /* Add */
+ reg->size = size;
+ reg->start = start;
+ reg->alignment = alignment;
+ reg->copy_name = 1;
+
+ list_add_tail(®->list, &cma_early_regions);
+
+ pr_debug("param: registering early region %s (%p@%p/%p)\n",
+ reg->name, (void *)reg->size, (void *)reg->start,
+ (void *)reg->alignment);
+ }
+
+ return ret;
+}
+early_param("cma", cma_param_parse);
+
+#undef NUMPARSE
+
+#endif
+
+
+int __init __must_check cma_early_region_register(struct cma_region *reg)
+{
+ dma_addr_t start, alignment;
+ size_t size;
+
+ if (reg->alignment & (reg->alignment - 1))
+ return -EINVAL;
+
+ alignment = max(reg->alignment, (dma_addr_t)PAGE_SIZE);
+ start = ALIGN(reg->start, alignment);
+ size = PAGE_ALIGN(reg->size);
+
+ if (start + size < start)
+ return -EINVAL;
+
+ reg->size = size;
+ reg->start = start;
+ reg->alignment = alignment;
+
+ list_add_tail(®->list, &cma_early_regions);
+
+ pr_debug("param: registering early region %s (%p@%p/%p)\n",
+ reg->name, (void *)reg->size, (void *)reg->start,
+ (void *)reg->alignment);
+
+ return 0;
+}
+
+
+
+/************************* Regions & Allocators *************************/
+
+static void __cma_sysfs_region_add(struct cma_region *reg);
+
+static int __cma_region_attach_alloc(struct cma_region *reg);
+static void __maybe_unused __cma_region_detach_alloc(struct cma_region *reg);
+
+
+/* List of all regions. Named regions are kept before unnamed. */
+static LIST_HEAD(cma_regions);
+
+#define cma_foreach_region(reg) \
+ list_for_each_entry(reg, &cma_regions, list)
+
+int __must_check cma_region_register(struct cma_region *reg)
+{
+ const char *name, *alloc_name;
+ struct cma_region *r;
+ char *ch = NULL;
+ int ret = 0;
+
+ if (!reg->size || reg->start + reg->size < reg->start)
+ return -EINVAL;
+
+ reg->users = 0;
+ reg->used = 0;
+ reg->private_data = NULL;
+ reg->registered = 0;
+ reg->free_space = reg->size;
+
+ /* Copy name and alloc_name */
+ name = reg->name;
+ alloc_name = reg->alloc_name;
+ if (reg->copy_name && (reg->name || reg->alloc_name)) {
+ size_t name_size, alloc_size;
+
+ name_size = reg->name ? strlen(reg->name) + 1 : 0;
+ alloc_size = reg->alloc_name ? strlen(reg->alloc_name) + 1 : 0;
+
+ ch = kmalloc(name_size + alloc_size, GFP_KERNEL);
+ if (!ch) {
+ pr_err("%s: not enough memory to allocate name\n",
+ reg->name ?: "(private)");
+ return -ENOMEM;
+ }
+
+ if (name_size) {
+ memcpy(ch, reg->name, name_size);
+ name = ch;
+ ch += name_size;
+ }
+
+ if (alloc_size) {
+ memcpy(ch, reg->alloc_name, alloc_size);
+ alloc_name = ch;
+ }
+ }
+
+ mutex_lock(&cma_mutex);
+
+ /* Don't let regions overlap */
+ cma_foreach_region(r)
+ if (r->start + r->size > reg->start &&
+ r->start < reg->start + reg->size) {
+ ret = -EADDRINUSE;
+ goto done;
+ }
+
+ if (reg->alloc) {
+ ret = __cma_region_attach_alloc(reg);
+ if (unlikely(ret < 0))
+ goto done;
+ }
+
+ reg->name = name;
+ reg->alloc_name = alloc_name;
+ reg->registered = 1;
+ ch = NULL;
+
+ /*
+ * Keep named at the beginning and unnamed (private) at the
+ * end. This helps in traversal when named region is looked
+ * for.
+ */
+ if (name)
+ list_add(®->list, &cma_regions);
+ else
+ list_add_tail(®->list, &cma_regions);
+
+ __cma_sysfs_region_add(reg);
+
+done:
+ mutex_unlock(&cma_mutex);
+
+ pr_debug("%s: region %sregistered\n",
+ reg->name ?: "(private)", ret ? "not " : "");
+ kfree(ch);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(cma_region_register);
+
+static struct cma_region *__must_check
+__cma_region_find(const char **namep)
+{
+ struct cma_region *reg;
+ const char *ch, *name;
+ size_t n;
+
+ ch = *namep;
+ while (*ch && *ch != ',' && *ch != ';')
+ ++ch;
+ name = *namep;
+ *namep = *ch == ',' ? ch + 1 : ch;
+ n = ch - name;
+
+ /*
+ * Named regions are kept in front of unnamed so if we
+ * encounter unnamed region we can stop.
+ */
+ cma_foreach_region(reg)
+ if (!reg->name)
+ break;
+ else if (!strncmp(name, reg->name, n) && !reg->name[n])
+ return reg;
+
+ return NULL;
+}
+
+
+/* List of all allocators. */
+static LIST_HEAD(cma_allocators);
+
+#define cma_foreach_allocator(alloc) \
+ list_for_each_entry(alloc, &cma_allocators, list)
+
+int cma_allocator_register(struct cma_allocator *alloc)
+{
+ struct cma_region *reg;
+ int first;
+
+ if (!alloc->alloc || !alloc->free)
+ return -EINVAL;
+
+ mutex_lock(&cma_mutex);
+
+ first = list_empty(&cma_allocators);
+
+ list_add_tail(&alloc->list, &cma_allocators);
+
+ /*
+ * Attach this allocator to all allocator-less regions that
+ * request this particular allocator (reg->alloc_name equals
+ * alloc->name) or if region wants the first available
+ * allocator and we are the first.
+ */
+ cma_foreach_region(reg) {
+ if (reg->alloc)
+ continue;
+ if (reg->alloc_name
+ ? alloc->name && !strcmp(alloc->name, reg->alloc_name)
+ : (!reg->used && first))
+ continue;
+
+ reg->alloc = alloc;
+ __cma_region_attach_alloc(reg);
+ }
+
+ mutex_unlock(&cma_mutex);
+
+ pr_debug("%s: allocator registered\n", alloc->name ?: "(unnamed)");
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(cma_allocator_register);
+
+static struct cma_allocator *__must_check
+__cma_allocator_find(const char *name)
+{
+ struct cma_allocator *alloc;
+
+ if (!name)
+ return list_empty(&cma_allocators)
+ ? NULL
+ : list_entry(cma_allocators.next,
+ struct cma_allocator, list);
+
+ cma_foreach_allocator(alloc)
+ if (alloc->name && !strcmp(name, alloc->name))
+ return alloc;
+
+ return NULL;
+}
+
+
+
+/************************* Initialise CMA *************************/
+
+int __init cma_set_defaults(struct cma_region *regions, const char *map)
+{
+ if (map) {
+ int ret = cma_map_param((char *)map);
+ if (unlikely(ret < 0))
+ return ret;
+ }
+
+ if (!regions)
+ return 0;
+
+ for (; regions->size; ++regions) {
+ int ret = cma_early_region_register(regions);
+ if (unlikely(ret < 0))
+ return ret;
+ }
+
+ return 0;
+}
+
+
+int __init cma_early_region_reserve(struct cma_region *reg)
+{
+ int tried = 0;
+
+ if (!reg->size || (reg->alignment & (reg->alignment - 1)) ||
+ reg->reserved)
+ return -EINVAL;
+
+#ifndef CONFIG_NO_BOOTMEM
+
+ tried = 1;
+
+ {
+ void *ptr = __alloc_bootmem_nopanic(reg->size, reg->alignment,
+ reg->start);
+ if (ptr) {
+ reg->start = virt_to_phys(ptr);
+ reg->reserved = 1;
+ return 0;
+ }
+ }
+
+#endif
+
+#ifdef CONFIG_HAVE_MEMBLOCK
+
+ tried = 1;
+
+ if (reg->start) {
+ if (!memblock_is_region_reserved(reg->start, reg->size) &&
+ memblock_reserve(reg->start, reg->size) >= 0) {
+ reg->reserved = 1;
+ return 0;
+ }
+ } else {
+ /*
+ * Use __memblock_alloc_base() since
+ * memblock_alloc_base() panic()s.
+ */
+ u64 ret = __memblock_alloc_base(reg->size, reg->alignment, 0);
+ if (ret &&
+ ret < ~(dma_addr_t)0 &&
+ ret + reg->size < ~(dma_addr_t)0 &&
+ ret + reg->size > ret) {
+ reg->start = ret;
+ reg->reserved = 1;
+ return 0;
+ }
+
+ if (ret)
+ memblock_free(ret, reg->size);
+ }
+
+#endif
+
+ return tried ? -ENOMEM : -EOPNOTSUPP;
+}
+
+void __init cma_early_regions_reserve(int (*reserve)(struct cma_region *reg))
+{
+ struct cma_region *reg;
+
+ pr_debug("init: reserving early regions\n");
+
+ if (!reserve)
+ reserve = cma_early_region_reserve;
+
+ list_for_each_entry(reg, &cma_early_regions, list) {
+ if (reg->reserved) {
+ /* nothing */
+ } else if (reserve(reg) >= 0) {
+ pr_debug("init: %s: reserved %p@%p\n",
+ reg->name ?: "(private)",
+ (void *)reg->size, (void *)reg->start);
+ reg->reserved = 1;
+ } else {
+ pr_warn("init: %s: unable to reserve %p@%p/%p\n",
+ reg->name ?: "(private)",
+ (void *)reg->size, (void *)reg->start,
+ (void *)reg->alignment);
+ }
+ }
+}
+
+
+static int __init cma_init(void)
+{
+ struct cma_region *reg, *n;
+
+ pr_debug("init: initialising\n");
+
+ if (cma_map) {
+ char *val = kmemdup(cma_map, cma_map_length + 1, GFP_KERNEL);
+ cma_map = val;
+ if (!val)
+ return -ENOMEM;
+ val[cma_map_length] = '\0';
+ }
+
+ list_for_each_entry_safe(reg, n, &cma_early_regions, list) {
+ INIT_LIST_HEAD(®->list);
+ /*
+ * We don't care if there was an error. It's a pity
+ * but there's not much we can do about it any way.
+ * If the error is on a region that was parsed from
+ * command line then it will stay and waste a bit of
+ * space; if it was registered using
+ * cma_early_region_register() it's caller's
+ * responsibility to do something about it.
+ */
+ if (reg->reserved && cma_region_register(reg) < 0)
+ /* ignore error */;
+ }
+
+ INIT_LIST_HEAD(&cma_early_regions);
+
+ return 0;
+}
+/*
+ * We want to be initialised earlier than module_init/__initcall so
+ * that drivers that want to grab memory at boot time will get CMA
+ * ready. subsys_initcall() seems early enough and not too early at
+ * the same time.
+ */
+subsys_initcall(cma_init);
+
+
+
+/************************* SysFS *************************/
+
+#if defined CONFIG_CMA_SYSFS
+
+static struct kobject cma_sysfs_regions;
+static int cma_sysfs_regions_ready;
+
+
+#define CMA_ATTR_INLINE(_type, _name) \
+ (&((struct cma_ ## _type ## _attribute){ \
+ .attr = { \
+ .name = __stringify(_name), \
+ .mode = 0644, \
+ }, \
+ .show = cma_sysfs_ ## _type ## _ ## _name ## _show, \
+ .store = cma_sysfs_ ## _type ## _ ## _name ## _store, \
+ }).attr)
+
+#define CMA_ATTR_RO_INLINE(_type, _name) \
+ (&((struct cma_ ## _type ## _attribute){ \
+ .attr = { \
+ .name = __stringify(_name), \
+ .mode = 0444, \
+ }, \
+ .show = cma_sysfs_ ## _type ## _ ## _name ## _show, \
+ }).attr)
+
+
+struct cma_root_attribute {
+ struct attribute attr;
+ ssize_t (*show)(char *buf);
+ int (*store)(const char *buf);
+};
+
+static ssize_t cma_sysfs_root_map_show(char *page)
+{
+ ssize_t len;
+
+ len = cma_map_length;
+ if (!len) {
+ *page = 0;
+ len = 0;
+ } else {
+ if (len > (size_t)PAGE_SIZE - 1)
+ len = (size_t)PAGE_SIZE - 1;
+ memcpy(page, cma_map, len);
+ page[len++] = '\n';
+ }
+
+ return len;
+}
+
+static int cma_sysfs_root_map_store(const char *page)
+{
+ ssize_t len = cma_map_validate(page);
+ char *val = NULL;
+
+ if (len < 0)
+ return len;
+
+ if (len) {
+ val = kmemdup(page, len + 1, GFP_KERNEL);
+ if (!val)
+ return -ENOMEM;
+ val[len] = '\0';
+ }
+
+ kfree(cma_map);
+ cma_map = val;
+ cma_map_length = len;
+
+ return 0;
+}
+
+static ssize_t cma_sysfs_root_allocators_show(char *page)
+{
+ struct cma_allocator *alloc;
+ size_t left = PAGE_SIZE;
+ char *ch = page;
+
+ cma_foreach_allocator(alloc) {
+ ssize_t l = snprintf(ch, left, "%s ", alloc->name ?: "-");
+ ch += l;
+ left -= l;
+ }
+
+ if (ch != page)
+ ch[-1] = '\n';
+ return ch - page;
+}
+
+static ssize_t
+cma_sysfs_root_show(struct kobject *kobj, struct attribute *attr, char *buf)
+{
+ struct cma_root_attribute *rattr =
+ container_of(attr, struct cma_root_attribute, attr);
+ ssize_t ret;
+
+ mutex_lock(&cma_mutex);
+ ret = rattr->show(buf);
+ mutex_unlock(&cma_mutex);
+
+ return ret;
+}
+
+static ssize_t
+cma_sysfs_root_store(struct kobject *kobj, struct attribute *attr,
+ const char *buf, size_t count)
+{
+ struct cma_root_attribute *rattr =
+ container_of(attr, struct cma_root_attribute, attr);
+ int ret;
+
+ mutex_lock(&cma_mutex);
+ ret = rattr->store(buf);
+ mutex_unlock(&cma_mutex);
+
+ return ret < 0 ? ret : count;
+}
+
+static struct kobj_type cma_sysfs_root_type = {
+ .sysfs_ops = &(const struct sysfs_ops){
+ .show = cma_sysfs_root_show,
+ .store = cma_sysfs_root_store,
+ },
+ .default_attrs = (struct attribute * []) {
+ CMA_ATTR_INLINE(root, map),
+ CMA_ATTR_RO_INLINE(root, allocators),
+ NULL
+ },
+};
+
+static int __init cma_sysfs_init(void)
+{
+ static struct kobject root;
+ static struct kobj_type fake_type;
+
+ struct cma_region *reg;
+ int ret;
+
+ /* Root */
+ ret = kobject_init_and_add(&root, &cma_sysfs_root_type,
+ mm_kobj, "contiguous");
+ if (unlikely(ret < 0)) {
+ pr_err("init: unable to add root kobject: %d\n", ret);
+ return ret;
+ }
+
+ /* Regions */
+ ret = kobject_init_and_add(&cma_sysfs_regions, &fake_type,
+ &root, "regions");
+ if (unlikely(ret < 0)) {
+ pr_err("init: unable to add regions kobject: %d\n", ret);
+ return ret;
+ }
+
+ mutex_lock(&cma_mutex);
+ cma_sysfs_regions_ready = 1;
+ cma_foreach_region(reg)
+ __cma_sysfs_region_add(reg);
+ mutex_unlock(&cma_mutex);
+
+ return 0;
+}
+device_initcall(cma_sysfs_init);
+
+
+
+struct cma_region_attribute {
+ struct attribute attr;
+ ssize_t (*show)(struct cma_region *reg, char *buf);
+ int (*store)(struct cma_region *reg, const char *buf);
+};
+
+
+static ssize_t cma_sysfs_region_name_show(struct cma_region *reg, char *page)
+{
+ return reg->name ? snprintf(page, PAGE_SIZE, "%s\n", reg->name) : 0;
+}
+
+static ssize_t cma_sysfs_region_start_show(struct cma_region *reg, char *page)
+{
+ return snprintf(page, PAGE_SIZE, "%p\n", (void *)reg->start);
+}
+
+static ssize_t cma_sysfs_region_size_show(struct cma_region *reg, char *page)
+{
+ return snprintf(page, PAGE_SIZE, "%zu\n", reg->size);
+}
+
+static ssize_t cma_sysfs_region_free_show(struct cma_region *reg, char *page)
+{
+ return snprintf(page, PAGE_SIZE, "%zu\n", reg->free_space);
+}
+
+static ssize_t cma_sysfs_region_users_show(struct cma_region *reg, char *page)
+{
+ return snprintf(page, PAGE_SIZE, "%u\n", reg->users);
+}
+
+static ssize_t cma_sysfs_region_alloc_show(struct cma_region *reg, char *page)
+{
+ if (reg->alloc)
+ return snprintf(page, PAGE_SIZE, "%s\n",
+ reg->alloc->name ?: "-");
+ else if (reg->alloc_name)
+ return snprintf(page, PAGE_SIZE, "[%s]\n", reg->alloc_name);
+ else
+ return 0;
+}
+
+static int
+cma_sysfs_region_alloc_store(struct cma_region *reg, const char *page)
+{
+ char *s;
+
+ if (reg->alloc && reg->users)
+ return -EBUSY;
+
+ if (!*page || *page == '\n') {
+ s = NULL;
+ } else {
+ size_t len;
+
+ for (s = (char *)page; *++s && *s != '\n'; )
+ /* nop */;
+
+ len = s - page;
+ s = kmemdup(page, len + 1, GFP_KERNEL);
+ if (!s)
+ return -ENOMEM;
+ s[len] = '\0';
+ }
+
+ if (reg->alloc)
+ __cma_region_detach_alloc(reg);
+
+ if (reg->free_alloc_name)
+ kfree(reg->alloc_name);
+
+ reg->alloc_name = s;
+ reg->free_alloc_name = !!s;
+
+ return 0;
+}
+
+
+static ssize_t
+cma_sysfs_region_show(struct kobject *kobj, struct attribute *attr,
+ char *buf)
+{
+ struct cma_region *reg = container_of(kobj, struct cma_region, kobj);
+ struct cma_region_attribute *rattr =
+ container_of(attr, struct cma_region_attribute, attr);
+ ssize_t ret;
+
+ mutex_lock(&cma_mutex);
+ ret = rattr->show(reg, buf);
+ mutex_unlock(&cma_mutex);
+
+ return ret;
+}
+
+static int
+cma_sysfs_region_store(struct kobject *kobj, struct attribute *attr,
+ const char *buf, size_t count)
+{
+ struct cma_region *reg = container_of(kobj, struct cma_region, kobj);
+ struct cma_region_attribute *rattr =
+ container_of(attr, struct cma_region_attribute, attr);
+ int ret;
+
+ mutex_lock(&cma_mutex);
+ ret = rattr->store(reg, buf);
+ mutex_unlock(&cma_mutex);
+
+ return ret < 0 ? ret : count;
+}
+
+static struct kobj_type cma_sysfs_region_type = {
+ .sysfs_ops = &(const struct sysfs_ops){
+ .show = cma_sysfs_region_show,
+ .store = cma_sysfs_region_store,
+ },
+ .default_attrs = (struct attribute * []) {
+ CMA_ATTR_RO_INLINE(region, name),
+ CMA_ATTR_RO_INLINE(region, start),
+ CMA_ATTR_RO_INLINE(region, size),
+ CMA_ATTR_RO_INLINE(region, free),
+ CMA_ATTR_RO_INLINE(region, users),
+ CMA_ATTR_INLINE(region, alloc),
+ NULL
+ },
+};
+
+static void __cma_sysfs_region_add(struct cma_region *reg)
+{
+ int ret;
+
+ if (!cma_sysfs_regions_ready)
+ return;
+
+ memset(®->kobj, 0, sizeof reg->kobj);
+
+ ret = kobject_init_and_add(®->kobj, &cma_sysfs_region_type,
+ &cma_sysfs_regions,
+ "%p", (void *)reg->start);
+
+ if (reg->name &&
+ sysfs_create_link(&cma_sysfs_regions, ®->kobj, reg->name) < 0)
+ /* Ignore any errors. */;
+}
+
+#else
+
+static void __cma_sysfs_region_add(struct cma_region *reg)
+{
+ /* nop */
+}
+
+#endif
+
+
+/************************* Chunks *************************/
+
+/* All chunks sorted by start address. */
+static struct rb_root cma_chunks_by_start;
+
+static struct cma_chunk *__must_check __cma_chunk_find(dma_addr_t addr)
+{
+ struct cma_chunk *chunk;
+ struct rb_node *n;
+
+ for (n = cma_chunks_by_start.rb_node; n; ) {
+ chunk = rb_entry(n, struct cma_chunk, by_start);
+ if (addr < chunk->start)
+ n = n->rb_left;
+ else if (addr > chunk->start)
+ n = n->rb_right;
+ else
+ return chunk;
+ }
+ WARN(1, KERN_WARNING "no chunk starting at %p\n", (void *)addr);
+ return NULL;
+}
+
+static int __must_check __cma_chunk_insert(struct cma_chunk *chunk)
+{
+ struct rb_node **new, *parent = NULL;
+ typeof(chunk->start) addr = chunk->start;
+
+ for (new = &cma_chunks_by_start.rb_node; *new; ) {
+ struct cma_chunk *c =
+ container_of(*new, struct cma_chunk, by_start);
+
+ parent = *new;
+ if (addr < c->start) {
+ new = &(*new)->rb_left;
+ } else if (addr > c->start) {
+ new = &(*new)->rb_right;
+ } else {
+ /*
+ * We should never be here. If we are it
+ * means allocator gave us an invalid chunk
+ * (one that has already been allocated) so we
+ * refuse to accept it. Our caller will
+ * recover by freeing the chunk.
+ */
+ WARN_ON(1);
+ return -EADDRINUSE;
+ }
+ }
+
+ rb_link_node(&chunk->by_start, parent, new);
+ rb_insert_color(&chunk->by_start, &cma_chunks_by_start);
+
+ return 0;
+}
+
+static void __cma_chunk_free(struct cma_chunk *chunk)
+{
+ rb_erase(&chunk->by_start, &cma_chunks_by_start);
+
+ chunk->reg->free_space += chunk->size;
+ --chunk->reg->users;
+
+ chunk->reg->alloc->free(chunk);
+}
+
+
+/************************* The Device API *************************/
+
+static const char *__must_check
+__cma_where_from(const struct device *dev, const char *type);
+
+
+/* Allocate. */
+
+static dma_addr_t __must_check
+__cma_alloc_from_region(struct cma_region *reg,
+ size_t size, dma_addr_t alignment)
+{
+ struct cma_chunk *chunk;
+
+ pr_debug("allocate %p/%p from %s\n",
+ (void *)size, (void *)alignment,
+ reg ? reg->name ?: "(private)" : "(null)");
+
+ if (!reg || reg->free_space < size)
+ return -ENOMEM;
+
+ if (!reg->alloc) {
+ if (!reg->used)
+ __cma_region_attach_alloc(reg);
+ if (!reg->alloc)
+ return -ENOMEM;
+ }
+
+ chunk = reg->alloc->alloc(reg, size, alignment);
+ if (!chunk)
+ return -ENOMEM;
+
+ if (unlikely(__cma_chunk_insert(chunk) < 0)) {
+ /* We should *never* be here. */
+ chunk->reg->alloc->free(chunk);
+ kfree(chunk);
+ return -EADDRINUSE;
+ }
+
+ chunk->reg = reg;
+ ++reg->users;
+ reg->free_space -= chunk->size;
+ pr_debug("allocated at %p\n", (void *)chunk->start);
+ return chunk->start;
+}
+
+dma_addr_t __must_check
+cma_alloc_from_region(struct cma_region *reg,
+ size_t size, dma_addr_t alignment)
+{
+ dma_addr_t addr;
+
+ pr_debug("allocate %p/%p from %s\n",
+ (void *)size, (void *)alignment,
+ reg ? reg->name ?: "(private)" : "(null)");
+
+ if (!size || alignment & (alignment - 1) || !reg)
+ return -EINVAL;
+
+ mutex_lock(&cma_mutex);
+
+ addr = reg->registered ?
+ __cma_alloc_from_region(reg, PAGE_ALIGN(size),
+ max(alignment, (dma_addr_t)PAGE_SIZE)) :
+ -EINVAL;
+
+ mutex_unlock(&cma_mutex);
+
+ return addr;
+}
+EXPORT_SYMBOL_GPL(cma_alloc_from_region);
+
+dma_addr_t __must_check
+__cma_alloc(const struct device *dev, const char *type,
+ dma_addr_t size, dma_addr_t alignment)
+{
+ struct cma_region *reg;
+ const char *from;
+ dma_addr_t addr;
+
+ if (dev)
+ pr_debug("allocate %p/%p for %s/%s\n",
+ (void *)size, (void *)alignment,
+ dev_name(dev), type ?: "");
+
+ if (!size || (alignment & ~alignment))
+ return -EINVAL;
+
+ if (alignment < PAGE_SIZE)
+ alignment = PAGE_SIZE;
+
+ if (!IS_ALIGNED(size, alignment))
+ size = ALIGN(size, alignment);
+
+ mutex_lock(&cma_mutex);
+
+ from = __cma_where_from(dev, type);
+ if (unlikely(IS_ERR(from))) {
+ addr = PTR_ERR(from);
+ goto done;
+ }
+
+ pr_debug("allocate %p/%p from one of %s\n",
+ (void *)size, (void *)alignment, from);
+
+ while (*from && *from != ';') {
+ reg = __cma_region_find(&from);
+ addr = __cma_alloc_from_region(reg, size, alignment);
+ if (!IS_ERR_VALUE(addr))
+ goto done;
+ }
+
+ pr_debug("not enough memory\n");
+ addr = -ENOMEM;
+
+done:
+ mutex_unlock(&cma_mutex);
+
+ return addr;
+}
+EXPORT_SYMBOL_GPL(__cma_alloc);
+
+
+void *cma_get_virt(dma_addr_t phys, dma_addr_t size, int noncached)
+{
+ unsigned long num_pages, i;
+ struct page **pages;
+ void *virt;
+
+ if (noncached) {
+ num_pages = size >> PAGE_SHIFT;
+ pages = kmalloc(num_pages * sizeof(struct page *), GFP_KERNEL);
+
+ if (!pages)
+ return ERR_PTR(-ENOMEM);
+
+ for (i = 0; i < num_pages; i++)
+ pages[i] = pfn_to_page((phys >> PAGE_SHIFT) + i);
+
+ virt = vmap(pages, num_pages, VM_MAP,
+ pgprot_writecombine(PAGE_KERNEL));
+
+ if (!virt) {
+ kfree(pages);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ kfree(pages);
+ } else {
+ virt = phys_to_virt((unsigned long)phys);
+ }
+
+ return virt;
+}
+EXPORT_SYMBOL_GPL(cma_get_virt);
+
+/* Query information about regions. */
+static void __cma_info_add(struct cma_info *infop, struct cma_region *reg)
+{
+ infop->total_size += reg->size;
+ infop->free_size += reg->free_space;
+ if (infop->lower_bound > reg->start)
+ infop->lower_bound = reg->start;
+ if (infop->upper_bound < reg->start + reg->size)
+ infop->upper_bound = reg->start + reg->size;
+ ++infop->count;
+}
+
+int
+__cma_info(struct cma_info *infop, const struct device *dev, const char *type)
+{
+ struct cma_info info = { ~(dma_addr_t)0, 0, 0, 0, 0 };
+ struct cma_region *reg;
+ const char *from;
+ int ret;
+
+ if (unlikely(!infop))
+ return -EINVAL;
+
+ mutex_lock(&cma_mutex);
+
+ from = __cma_where_from(dev, type);
+ if (IS_ERR(from)) {
+ ret = PTR_ERR(from);
+ info.lower_bound = 0;
+ goto done;
+ }
+
+ while (*from && *from != ';') {
+ reg = __cma_region_find(&from);
+ if (reg)
+ __cma_info_add(&info, reg);
+ }
+
+ ret = 0;
+done:
+ mutex_unlock(&cma_mutex);
+
+ memcpy(infop, &info, sizeof info);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(__cma_info);
+
+
+/* Freeing. */
+int cma_free(dma_addr_t addr)
+{
+ struct cma_chunk *c;
+ int ret;
+
+ mutex_lock(&cma_mutex);
+
+ c = __cma_chunk_find(addr);
+
+ if (c) {
+ __cma_chunk_free(c);
+ ret = 0;
+ } else {
+ ret = -ENOENT;
+ }
+
+ mutex_unlock(&cma_mutex);
+
+ if (c)
+ pr_debug("free(%p): freed\n", (void *)addr);
+ else
+ pr_err("free(%p): not found\n", (void *)addr);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(cma_free);
+
+
+/************************* Miscellaneous *************************/
+
+static int __cma_region_attach_alloc(struct cma_region *reg)
+{
+ struct cma_allocator *alloc;
+ int ret;
+
+ /*
+ * If reg->alloc is set then caller wants us to use this
+ * allocator. Otherwise we need to find one by name.
+ */
+ if (reg->alloc) {
+ alloc = reg->alloc;
+ } else {
+ alloc = __cma_allocator_find(reg->alloc_name);
+ if (!alloc) {
+ pr_warn("init: %s: %s: no such allocator\n",
+ reg->name ?: "(private)",
+ reg->alloc_name ?: "(default)");
+ reg->used = 1;
+ return -ENOENT;
+ }
+ }
+
+ /* Try to initialise the allocator. */
+ reg->private_data = NULL;
+ ret = alloc->init ? alloc->init(reg) : 0;
+ if (unlikely(ret < 0)) {
+ pr_err("init: %s: %s: unable to initialise allocator\n",
+ reg->name ?: "(private)", alloc->name ?: "(unnamed)");
+ reg->alloc = NULL;
+ reg->used = 1;
+ } else {
+ reg->alloc = alloc;
+ pr_debug("init: %s: %s: initialised allocator\n",
+ reg->name ?: "(private)", alloc->name ?: "(unnamed)");
+ }
+ return ret;
+}
+
+static void __cma_region_detach_alloc(struct cma_region *reg)
+{
+ if (!reg->alloc)
+ return;
+
+ if (reg->alloc->cleanup)
+ reg->alloc->cleanup(reg);
+
+ reg->alloc = NULL;
+ reg->used = 1;
+}
+
+
+/*
+ * s ::= rules
+ * rules ::= rule [ ';' rules ]
+ * rule ::= patterns '=' regions
+ * patterns ::= pattern [ ',' patterns ]
+ * regions ::= REG-NAME [ ',' regions ]
+ * pattern ::= dev-pattern [ '/' TYPE-NAME ] | '/' TYPE-NAME
+ */
+static const char *__must_check
+__cma_where_from(const struct device *dev, const char *type)
+{
+ /*
+ * This function matches the pattern from the map attribute
+ * agains given device name and type. Type may be of course
+ * NULL or an emtpy string.
+ */
+
+ const char *s, *name;
+ int name_matched = 0;
+
+ /*
+ * If dev is NULL we were called in alternative form where
+ * type is the from string. All we have to do is return it.
+ */
+ if (!dev)
+ return type ?: ERR_PTR(-EINVAL);
+
+ if (!cma_map)
+ return ERR_PTR(-ENOENT);
+
+ name = dev_name(dev);
+ if (WARN_ON(!name || !*name))
+ return ERR_PTR(-EINVAL);
+
+ if (!type)
+ type = "common";
+
+ /*
+ * Now we go throught the cma_map attribute.
+ */
+ for (s = cma_map; *s; ++s) {
+ const char *c;
+
+ /*
+ * If the pattern starts with a slash, the device part of the
+ * pattern matches if it matched previously.
+ */
+ if (*s == '/') {
+ if (!name_matched)
+ goto look_for_next;
+ goto match_type;
+ }
+
+ /*
+ * We are now trying to match the device name. This also
+ * updates the name_matched variable. If, while reading the
+ * spec, we ecnounter comma it means that the pattern does not
+ * match and we need to start over with another pattern (the
+ * one afther the comma). If we encounter equal sign we need
+ * to start over with another rule. If there is a character
+ * that does not match, we neet to look for a comma (to get
+ * another pattern) or semicolon (to get another rule) and try
+ * again if there is one somewhere.
+ */
+
+ name_matched = 0;
+
+ for (c = name; *s != '*' && *c; ++c, ++s)
+ if (*s == '=')
+ goto next_rule;
+ else if (*s == ',')
+ goto next_pattern;
+ else if (*s != '?' && *c != *s)
+ goto look_for_next;
+ if (*s == '*')
+ ++s;
+
+ name_matched = 1;
+
+ /*
+ * Now we need to match the type part of the pattern. If the
+ * pattern is missing it we match only if type points to an
+ * empty string. Otherwise wy try to match it just like name.
+ */
+ if (*s == '/') {
+match_type: /* s points to '/' */
+ ++s;
+
+ for (c = type; *s && *c; ++c, ++s)
+ if (*s == '=')
+ goto next_rule;
+ else if (*s == ',')
+ goto next_pattern;
+ else if (*c != *s)
+ goto look_for_next;
+ }
+
+ /* Return the string behind the '=' sign of the rule. */
+ if (*s == '=')
+ return s + 1;
+ else if (*s == ',')
+ return strchr(s, '=') + 1;
+
+ /* Pattern did not match */
+
+look_for_next:
+ do {
+ ++s;
+ } while (*s != ',' && *s != '=');
+ if (*s == ',')
+ continue;
+
+next_rule: /* s points to '=' */
+ s = strchr(s, ';');
+ if (!s)
+ break;
+
+next_pattern:
+ continue;
+ }
+
+ return ERR_PTR(-ENOENT);
+}
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index f351b93..c4bda0a 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -2368,6 +2368,18 @@
configure_clock(codec);
+ /*
+ * If SYSCLK will be less than 50kHz adjust AIFnCLK dividers
+ * for detection.
+ */
+ if (max(wm8994->aifclk[0], wm8994->aifclk[1]) < 50000) {
+ dev_dbg(codec->dev, "Configuring AIFs for 128fs\n");
+ snd_soc_update_bits(codec, WM8994_AIF1_RATE,
+ WM8994_AIF1CLK_RATE_MASK, 0x1);
+ snd_soc_update_bits(codec, WM8994_AIF2_RATE,
+ WM8994_AIF2CLK_RATE_MASK, 0x1);
+ }
+
return 0;
}
diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig
index fe3995c..1a71d2e 100644
--- a/sound/soc/samsung/Kconfig
+++ b/sound/soc/samsung/Kconfig
@@ -1,6 +1,6 @@
config SND_SOC_SAMSUNG
tristate "ASoC support for Samsung"
- depends on ARCH_S3C24XX || ARCH_S3C64XX || ARCH_S5PC100 || ARCH_S5PV210 || ARCH_S5P64X0 || ARCH_EXYNOS4
+ depends on PLAT_SAMSUNG
select S3C64XX_DMA if ARCH_S3C64XX
select S3C2410_DMA if ARCH_S3C24XX
help
@@ -34,6 +34,20 @@
config SND_SAMSUNG_I2S
tristate
+config SND_SAMSUNG_USE_IDMA
+ depends on SND_SAMSUNG_I2S && ARCH_EXYNOS5
+ bool "Internal DMA for low power playback"
+ default y
+ help
+ Say Y if you want to support internal DMA for low power playback.
+
+config SND_PM_RUNTIME
+ tristate "Support Runtime PM for audio subsystem"
+ depends on SND_SOC_SAMSUNG && PM_RUNTIME
+ default y
+ help
+ Say Y if you want to add support runtime pm for audio subsystem.
+
config SND_SOC_SAMSUNG_NEO1973_WM8753
tristate "Audio support for Openmoko Neo1973 Smartphones (GTA01/GTA02)"
depends on SND_SOC_SAMSUNG && (MACH_NEO1973_GTA01 || MACH_NEO1973_GTA02)
@@ -63,7 +77,7 @@
config SND_SOC_SAMSUNG_SMDK_WM8994
tristate "SoC I2S Audio support for WM8994 on SMDK"
- depends on SND_SOC_SAMSUNG && (MACH_SMDKV310 || MACH_SMDKC210 || MACH_SMDK4212)
+ depends on SND_SOC_SAMSUNG && (MACH_SMDKV310 || MACH_SMDKC210 || MACH_SMDK4212 || MACH_SMDK5250)
depends on I2C=y && GENERIC_HARDIRQS
select MFD_WM8994
select SND_SOC_WM8994
@@ -71,6 +85,9 @@
help
Say Y if you want to add support for SoC audio on the SMDKs.
+# For support ALP audio
+source "sound/soc/samsung/srp_alp/Kconfig"
+
config SND_SOC_SAMSUNG_SMDK2443_WM9710
tristate "SoC AC97 Audio support for SMDK2443 - WM9710"
depends on SND_SOC_SAMSUNG && MACH_SMDK2443
@@ -162,7 +179,7 @@
config SND_SOC_SAMSUNG_SMDK_SPDIF
tristate "SoC S/PDIF Audio support for SMDK"
- depends on SND_SOC_SAMSUNG && (MACH_SMDKC100 || MACH_SMDKC110 || MACH_SMDKV210 || MACH_SMDKV310 || MACH_SMDK4212)
+ depends on SND_SOC_SAMSUNG && (MACH_SMDKC100 || MACH_SMDKC110 || MACH_SMDKV210 || MACH_SMDKV310 || MACH_SMDK4212 || MACH_SMDK5250)
select SND_SAMSUNG_SPDIF
help
Say Y if you want to add support for SoC S/PDIF audio on the SMDK.
@@ -177,7 +194,7 @@
config SND_SOC_SMDK_WM8994_PCM
tristate "SoC PCM Audio support for WM8994 on SMDK"
- depends on SND_SOC_SAMSUNG && (MACH_SMDKC210 || MACH_SMDKV310 || MACH_SMDK4212)
+ depends on SND_SOC_SAMSUNG && (MACH_SMDKC210 || MACH_SMDKV310 || MACH_SMDK4212 || MACH_SMDK5250)
depends on I2C=y && GENERIC_HARDIRQS
select MFD_WM8994
select SND_SOC_WM8994
diff --git a/sound/soc/samsung/Makefile b/sound/soc/samsung/Makefile
index 9d03beb..29e9aab 100644
--- a/sound/soc/samsung/Makefile
+++ b/sound/soc/samsung/Makefile
@@ -18,6 +18,7 @@
obj-$(CONFIG_SND_SAMSUNG_PCM) += snd-soc-pcm.o
obj-$(CONFIG_SND_SAMSUNG_I2S) += snd-soc-i2s.o
obj-$(CONFIG_SND_SAMSUNG_I2S) += snd-soc-idma.o
+obj-$(CONFIG_SND_SAMSUNG_ALP) += srp_alp/
# S3C24XX Machine Support
snd-soc-jive-wm8750-objs := jive_wm8750.o
diff --git a/sound/soc/samsung/dma.c b/sound/soc/samsung/dma.c
index ddc6cde..f19f69a 100644
--- a/sound/soc/samsung/dma.c
+++ b/sound/soc/samsung/dma.c
@@ -44,8 +44,8 @@
.channels_min = 2,
.channels_max = 2,
.buffer_bytes_max = 128*1024,
- .period_bytes_min = PAGE_SIZE,
- .period_bytes_max = PAGE_SIZE*2,
+ .period_bytes_min = 128,
+ .period_bytes_max = 64*1024,
.periods_min = 2,
.periods_max = 128,
.fifo_size = 32,
@@ -74,7 +74,7 @@
struct runtime_data *prtd = substream->runtime->private_data;
dma_addr_t pos = prtd->dma_pos;
unsigned int limit;
- struct samsung_dma_prep_info dma_info;
+ struct samsung_dma_prep dma_info;
pr_debug("Entered %s\n", __func__);
@@ -92,25 +92,31 @@
dma_info.period = prtd->dma_period;
dma_info.len = prtd->dma_period*limit;
- while (prtd->dma_loaded < limit) {
- pr_debug("dma_loaded: %d\n", prtd->dma_loaded);
-
- if ((pos + dma_info.period) > prtd->dma_end) {
- dma_info.period = prtd->dma_end - pos;
- pr_debug("%s: corrected dma len %ld\n",
- __func__, dma_info.period);
- }
-
- dma_info.buf = pos;
+ if (samsung_dma_has_infiniteloop()) {
+ dma_info.buf = prtd->dma_pos;
+ dma_info.infiniteloop = limit;
prtd->params->ops->prepare(prtd->params->ch, &dma_info);
+ } else {
+ dma_info.infiniteloop = 0;
+ while (prtd->dma_loaded < limit) {
+ pr_debug("dma_loaded: %d\n", prtd->dma_loaded);
- prtd->dma_loaded++;
- pos += prtd->dma_period;
- if (pos >= prtd->dma_end)
- pos = prtd->dma_start;
+ if ((pos + dma_info.period) > prtd->dma_end) {
+ dma_info.period = prtd->dma_end - pos;
+ pr_debug("%s: corrected dma len %ld\n",
+ __func__, dma_info.period);
+ }
+
+ dma_info.buf = pos;
+ prtd->params->ops->prepare(prtd->params->ch, &dma_info);
+
+ prtd->dma_loaded++;
+ pos += prtd->dma_period;
+ if (pos >= prtd->dma_end)
+ pos = prtd->dma_start;
+ }
+ prtd->dma_pos = pos;
}
-
- prtd->dma_pos = pos;
}
static void audio_buffdone(void *data)
@@ -120,23 +126,19 @@
pr_debug("Entered %s\n", __func__);
- if (prtd->state & ST_RUNNING) {
- prtd->dma_pos += prtd->dma_period;
- if (prtd->dma_pos >= prtd->dma_end)
- prtd->dma_pos = prtd->dma_start;
+ if (substream)
+ snd_pcm_period_elapsed(substream);
- if (substream)
- snd_pcm_period_elapsed(substream);
-
- spin_lock(&prtd->lock);
- if (!samsung_dma_has_circular()) {
- prtd->dma_loaded--;
+ spin_lock(&prtd->lock);
+ if (!samsung_dma_has_circular()) {
+ prtd->dma_loaded--;
+ if (!samsung_dma_has_infiniteloop())
dma_enqueue(substream);
- }
- spin_unlock(&prtd->lock);
}
+ spin_unlock(&prtd->lock);
}
+
static int dma_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
@@ -146,7 +148,8 @@
unsigned long totbytes = params_buffer_bytes(params);
struct s3c_dma_params *dma =
snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
- struct samsung_dma_info dma_info;
+ struct samsung_dma_req req;
+ struct samsung_dma_config config;
pr_debug("Entered %s\n", __func__);
@@ -166,16 +169,17 @@
prtd->params->ops = samsung_dma_get_ops();
- dma_info.cap = (samsung_dma_has_circular() ?
+ req.cap = (samsung_dma_has_circular() ?
DMA_CYCLIC : DMA_SLAVE);
- dma_info.client = prtd->params->client;
- dma_info.direction =
+ req.client = prtd->params->client;
+ config.direction =
(substream->stream == SNDRV_PCM_STREAM_PLAYBACK
? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM);
- dma_info.width = prtd->params->dma_size;
- dma_info.fifo = prtd->params->dma_addr;
+ config.width = prtd->params->dma_size;
+ config.fifo = prtd->params->dma_addr;
prtd->params->ch = prtd->params->ops->request(
- prtd->params->channel, &dma_info);
+ prtd->params->channel, &req);
+ prtd->params->ops->config(prtd->params->ch, &config);
}
snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
@@ -275,10 +279,16 @@
struct snd_pcm_runtime *runtime = substream->runtime;
struct runtime_data *prtd = runtime->private_data;
unsigned long res;
+ dma_addr_t src, dst;
pr_debug("Entered %s\n", __func__);
- res = prtd->dma_pos - prtd->dma_start;
+ prtd->params->ops->getposition(prtd->params->ch, &src, &dst);
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ res = dst - prtd->dma_start;
+ else
+ res = src - prtd->dma_start;
pr_debug("Pointer offset: %lu\n", res);
diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c
index 6ac7b82..4fa7f1e 100644
--- a/sound/soc/samsung/i2s.c
+++ b/sound/soc/samsung/i2s.c
@@ -21,11 +21,17 @@
#include <sound/pcm_params.h>
#include <plat/audio.h>
+#include <plat/clock.h>
+#include <plat/cpu.h>
+
+#include <mach/map.h>
+#include <mach/regs-audss.h>
#include "dma.h"
#include "idma.h"
#include "i2s.h"
#include "i2s-regs.h"
+#include "srp-type.h"
#define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t)
@@ -34,6 +40,8 @@
struct platform_device *pdev;
/* IOREMAP'd SFRs */
void __iomem *addr;
+ /* AUDSS SFRs */
+ void __iomem *audss_base;
/* Physical base address of SFRs */
u32 base;
/* Rate of RCLK source clock */
@@ -47,6 +55,10 @@
unsigned rfs, bfs;
/* I2S Controller's core clock */
struct clk *clk;
+#ifdef CONFIG_SND_SAMSUNG_USE_IDMA
+ /* SRP clock */
+ struct clk *srpclk;
+#endif
/* Clock for generating I2S signals */
struct clk *op_clk;
/* Array of clock names for op_clk */
@@ -65,9 +77,16 @@
struct s3c_dma_params dma_capture;
struct s3c_dma_params idma_playback;
u32 quirks;
+ u32 opencnt;
+
u32 suspend_i2smod;
u32 suspend_i2scon;
u32 suspend_i2spsr;
+ u32 suspend_i2sahb;
+
+ u32 suspend_audss_clksrc;
+ u32 suspend_audss_clkdiv;
+ u32 suspend_audss_clkgate;
};
/* Lock for cross i/f checks */
@@ -629,6 +648,32 @@
return 0;
}
+static void i2s_register_save(struct i2s_dai *i2s)
+{
+ i2s->suspend_i2smod = readl(i2s->addr + I2SMOD);
+ i2s->suspend_i2scon = readl(i2s->addr + I2SCON);
+ i2s->suspend_i2spsr = readl(i2s->addr + I2SPSR);
+ if ((i2s->pdev->id == 0) || (i2s->pdev->id == SAMSUNG_I2S_SECOFF)) {
+ i2s->suspend_i2sahb = readl(i2s->addr + I2SAHB);
+ i2s->suspend_audss_clksrc = readl(i2s->audss_base + EXYNOS_CLKSRC_AUDSS_OFFSET);
+ i2s->suspend_audss_clkdiv = readl(i2s->audss_base + EXYNOS_CLKDIV_AUDSS_OFFSET);
+ i2s->suspend_audss_clkgate = readl(i2s->audss_base + EXYNOS_CLKGATE_AUDSS_OFFSET);
+ }
+}
+
+static void i2s_register_restore(struct i2s_dai *i2s)
+{
+ writel(i2s->suspend_i2scon, i2s->addr + I2SCON);
+ writel(i2s->suspend_i2smod, i2s->addr + I2SMOD);
+ writel(i2s->suspend_i2spsr, i2s->addr + I2SPSR);
+ if ((i2s->pdev->id == 0) || (i2s->pdev->id == SAMSUNG_I2S_SECOFF)) {
+ writel(i2s->suspend_i2sahb, i2s->addr + I2SAHB);
+ writel(i2s->suspend_audss_clksrc, i2s->audss_base + EXYNOS_CLKSRC_AUDSS_OFFSET);
+ writel(i2s->suspend_audss_clkdiv, i2s->audss_base + EXYNOS_CLKDIV_AUDSS_OFFSET);
+ writel(i2s->suspend_audss_clkgate, i2s->audss_base + EXYNOS_CLKGATE_AUDSS_OFFSET);
+ }
+}
+
/* We set constraints on the substream acc to the version of I2S */
static int i2s_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
@@ -637,8 +682,18 @@
struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
unsigned long flags;
+#ifdef CONFIG_SND_PM_RUNTIME
+ struct platform_device *pdev = i2s->pri_dai ?
+ i2s->pri_dai->pdev : i2s->pdev;
+ struct s3c_audio_pdata *i2s_pdata = pdev->dev.platform_data;
+#endif
spin_lock_irqsave(&lock, flags);
+ if (i2s->opencnt++) {
+ spin_unlock_irqrestore(&lock, flags);
+ return 0;
+ }
+
i2s->mode |= DAI_OPENED;
if (is_manager(other))
@@ -651,6 +706,25 @@
spin_unlock_irqrestore(&lock, flags);
+ if (!is_opened(other)) {
+#ifdef CONFIG_SND_PM_RUNTIME
+ pm_runtime_get_sync(&pdev->dev);
+#endif
+ i2s_register_restore(i2s);
+#ifdef CONFIG_SND_SAMSUNG_USE_IDMA
+ clk_enable(i2s->srpclk);
+#endif
+ clk_enable(i2s->clk);
+
+#ifdef CONFIG_SND_PM_RUNTIME
+ if (i2s_pdata->cfg_gpio && i2s_pdata->cfg_gpio(pdev))
+ dev_err(&pdev->dev, "Unable to configure gpio\n");
+
+ if (i2s->quirks & QUIRK_NEED_RSTCLR)
+ writel(CON_RSTCLR, i2s->addr + I2SCON);
+#endif
+ }
+
return 0;
}
@@ -661,8 +735,17 @@
struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
unsigned long flags;
+#ifdef CONFIG_SND_PM_RUNTIME
+ struct platform_device *pdev = i2s->pri_dai ?
+ i2s->pri_dai->pdev : i2s->pdev;
+#endif
spin_lock_irqsave(&lock, flags);
+ if (--i2s->opencnt) {
+ spin_unlock_irqrestore(&lock, flags);
+ return;
+ }
+
i2s->mode &= ~DAI_OPENED;
i2s->mode &= ~DAI_MANAGER;
@@ -676,9 +759,20 @@
spin_unlock_irqrestore(&lock, flags);
/* Gate CDCLK by default */
- if (!is_opened(other))
+ if (!is_opened(other)) {
i2s_set_sysclk(dai, SAMSUNG_I2S_CDCLK,
0, SND_SOC_CLOCK_IN);
+
+ i2s_register_save(i2s);
+ clk_disable(i2s->clk);
+#ifdef CONFIG_SND_SAMSUNG_USE_IDMA
+ clk_disable(i2s->srpclk);
+#endif
+
+#ifdef CONFIG_SND_PM_RUNTIME
+ pm_runtime_put_sync(&pdev->dev);
+#endif
+ }
}
static int config_setup(struct i2s_dai *i2s)
@@ -777,7 +871,6 @@
i2s_fifo(i2s, FIC_RXFLUSH);
} else {
i2s_txctrl(i2s, 0);
- i2s_fifo(i2s, FIC_TXFLUSH);
}
local_irq_restore(flags);
@@ -834,11 +927,8 @@
{
struct i2s_dai *i2s = to_info(dai);
- if (dai->active) {
- i2s->suspend_i2smod = readl(i2s->addr + I2SMOD);
- i2s->suspend_i2scon = readl(i2s->addr + I2SCON);
- i2s->suspend_i2spsr = readl(i2s->addr + I2SPSR);
- }
+ if (dai->active)
+ i2s_register_save(i2s);
return 0;
}
@@ -847,11 +937,8 @@
{
struct i2s_dai *i2s = to_info(dai);
- if (dai->active) {
- writel(i2s->suspend_i2scon, i2s->addr + I2SCON);
- writel(i2s->suspend_i2smod, i2s->addr + I2SMOD);
- writel(i2s->suspend_i2spsr, i2s->addr + I2SPSR);
- }
+ if (dai->active)
+ i2s_register_restore(i2s);
return 0;
}
@@ -862,39 +949,97 @@
static int samsung_i2s_dai_probe(struct snd_soc_dai *dai)
{
+ struct clk *fout_epll, *mout_audss;
struct i2s_dai *i2s = to_info(dai);
struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
+ int ret;
- if (other && other->clk) /* If this is probe on secondary */
+#ifdef CONFIG_SND_PM_RUNTIME
+ struct platform_device *pdev = i2s->pri_dai ?
+ i2s->pri_dai->pdev : i2s->pdev;
+
+ pm_runtime_get_sync(&pdev->dev);
+#endif
+
+ if (other && other->clk) /* If this is second dai probe */
goto probe_exit;
- i2s->addr = ioremap(i2s->base, 0x100);
+ i2s->addr = ioremap(i2s->base, SZ_256);
if (i2s->addr == NULL) {
dev_err(&i2s->pdev->dev, "cannot ioremap registers\n");
- return -ENXIO;
+ ret = -ENOMEM;
+ goto err1;
+ }
+
+ i2s->audss_base = ioremap(EXYNOS_PA_AUDSS, SZ_4K);
+ if (i2s->audss_base == NULL) {
+ dev_err(&i2s->pdev->dev, "cannot ioremap registers\n");
+ ret = -ENOMEM;
+ goto err2;
}
i2s->clk = clk_get(&i2s->pdev->dev, "iis");
if (IS_ERR(i2s->clk)) {
- dev_err(&i2s->pdev->dev, "failed to get i2s_clock\n");
- iounmap(i2s->addr);
- return -ENOENT;
+ dev_err(&i2s->pdev->dev, "failed to get i2s clock\n");
+ ret = PTR_ERR(i2s->clk);
+ goto err3;
}
- clk_enable(i2s->clk);
+
+#ifdef CONFIG_SND_SAMSUNG_USE_IDMA
+ i2s->srpclk = clk_get(&i2s->pdev->dev, "srpclk");
+ if (IS_ERR(i2s->srpclk)) {
+ dev_err(&i2s->pdev->dev, "failed to get srp clock\n");
+ ret = PTR_ERR(i2s->srpclk);
+ goto err4;
+ }
+#endif
+
+probe_exit:
+ mout_audss = clk_get(&i2s->pdev->dev, "mout_audss");
+ if (IS_ERR(mout_audss)) {
+ dev_err(&i2s->pdev->dev, "failed to get mout_audss clock\n");
+ ret = PTR_ERR(mout_audss);
+ goto err5;
+ }
+
+ fout_epll = clk_get(&i2s->pdev->dev, "fout_epll");
+ if (IS_ERR(fout_epll)) {
+ dev_err(&i2s->pdev->dev, "failed to get fout_epll clock\n");
+ ret = PTR_ERR(fout_epll);
+ goto err6;
+ }
+
+ /* Set audio clock hierarchy for I2S */
+ ret = clk_set_parent(mout_audss, fout_epll);
+ if (ret) {
+ dev_err(&i2s->pdev->dev, "failed to set parent %s of clock %s.\n",
+ fout_epll->name, mout_audss->name);
+ goto err7;
+ }
if (other) {
other->addr = i2s->addr;
+ other->audss_base = i2s->audss_base;
other->clk = i2s->clk;
+#ifdef CONFIG_SND_SAMSUNG_USE_IDMA
+ other->srpclk = i2s->srpclk;
+#endif
}
+ clk_put(fout_epll);
+ clk_put(mout_audss);
+
+ if ((i2s->quirks & QUIRK_SEC_DAI) && !is_secondary(i2s))
+ idma_reg_addr_init(i2s->addr,
+ i2s->sec_dai->idma_playback.dma_addr);
+
+#ifdef CONFIG_SND_SAMSUNG_USE_IDMA
+ clk_enable(i2s->srpclk);
+#endif
+ clk_enable(i2s->clk);
if (i2s->quirks & QUIRK_NEED_RSTCLR)
writel(CON_RSTCLR, i2s->addr + I2SCON);
- if (i2s->quirks & QUIRK_SEC_DAI)
- idma_reg_addr_init(i2s->addr,
- i2s->sec_dai->idma_playback.dma_addr);
-
-probe_exit:
/* Reset any constraint on RFS and BFS */
i2s->rfs = 0;
i2s->bfs = 0;
@@ -909,7 +1054,34 @@
i2s_set_sysclk(dai, SAMSUNG_I2S_CDCLK,
0, SND_SOC_CLOCK_IN);
+ i2s_register_save(i2s);
+ clk_disable(i2s->clk);
+#ifdef CONFIG_SND_SAMSUNG_USE_IDMA
+ clk_disable(i2s->srpclk);
+#endif
+ i2s->opencnt = 0;
+#ifdef CONFIG_SND_PM_RUNTIME
+ pm_runtime_put_sync(&pdev->dev);
+#endif
+
return 0;
+
+err7:
+ clk_put(fout_epll);
+err6:
+ clk_put(mout_audss);
+err5:
+#ifdef CONFIG_SND_SAMSUNG_USE_IDMA
+ clk_put(i2s->srpclk);
+err4:
+#endif
+ clk_put(i2s->clk);
+err3:
+ iounmap(i2s->audss_base);
+err2:
+ iounmap(i2s->addr);
+err1:
+ return ret;
}
static int samsung_i2s_dai_remove(struct snd_soc_dai *dai)
@@ -922,6 +1094,10 @@
if (i2s->quirks & QUIRK_NEED_RSTCLR)
writel(0, i2s->addr + I2SCON);
+#ifdef CONFIG_SND_SAMSUNG_USE_IDMA
+ clk_disable(i2s->srpclk);
+ clk_put(i2s->srpclk);
+#endif
clk_disable(i2s->clk);
clk_put(i2s->clk);
@@ -1092,17 +1268,23 @@
sec_dai->dma_playback.dma_size = 4;
sec_dai->base = regs_base;
sec_dai->quirks = quirks;
- sec_dai->idma_playback.dma_addr = i2s_cfg->idma_addr;
+
+ if (soc_is_exynos5250() && srp_enabled_status())
+ sec_dai->idma_playback.dma_addr = srp_get_idma_addr();
+ else
+ sec_dai->idma_playback.dma_addr = i2s_cfg->idma_addr;
+
sec_dai->pri_dai = pri_dai;
pri_dai->sec_dai = sec_dai;
}
+#ifndef CONFIG_SND_PM_RUNTIME
if (i2s_pdata->cfg_gpio && i2s_pdata->cfg_gpio(pdev)) {
dev_err(&pdev->dev, "Unable to configure gpio\n");
ret = -EINVAL;
goto err;
}
-
+#endif
snd_soc_register_dai(&pri_dai->pdev->dev, &pri_dai->i2s_dai_drv);
pm_runtime_enable(&pdev->dev);
diff --git a/sound/soc/samsung/idma.c b/sound/soc/samsung/idma.c
index c227c31..648222e 100644
--- a/sound/soc/samsung/idma.c
+++ b/sound/soc/samsung/idma.c
@@ -47,7 +47,7 @@
.period_bytes_min = 128,
.period_bytes_max = MAX_IDMA_PERIOD,
.periods_min = 1,
- .periods_max = 2,
+ .periods_max = 4,
};
struct idma_ctrl {
diff --git a/sound/soc/samsung/smdk_wm8994.c b/sound/soc/samsung/smdk_wm8994.c
index 8eb309f..7629300 100644
--- a/sound/soc/samsung/smdk_wm8994.c
+++ b/sound/soc/samsung/smdk_wm8994.c
@@ -122,7 +122,19 @@
}
static struct snd_soc_dai_link smdk_dai[] = {
- { /* Primary DAI i/f */
+ { /* Sec_Fifo Playback i/f */
+ .name = "Sec_FIFO TX",
+ .stream_name = "Sec_Dai",
+ .cpu_dai_name = "samsung-i2s.4",
+ .codec_dai_name = "wm8994-aif1",
+#ifdef CONFIG_SND_SAMSUNG_ALP
+ .platform_name = "samsung-idma",
+#else
+ .platform_name = "samsung-audio",
+#endif
+ .codec_name = "wm8994-codec",
+ .ops = &smdk_ops,
+ }, { /* Primary DAI i/f */
.name = "WM8994 AIF1",
.stream_name = "Pri_Dai",
.cpu_dai_name = "samsung-i2s.0",
@@ -131,14 +143,6 @@
.codec_name = "wm8994-codec",
.init = smdk_wm8994_init_paiftx,
.ops = &smdk_ops,
- }, { /* Sec_Fifo Playback i/f */
- .name = "Sec_FIFO TX",
- .stream_name = "Sec_Dai",
- .cpu_dai_name = "samsung-i2s.4",
- .codec_dai_name = "wm8994-aif1",
- .platform_name = "samsung-audio",
- .codec_name = "wm8994-codec",
- .ops = &smdk_ops,
},
};
diff --git a/sound/soc/samsung/spdif.c b/sound/soc/samsung/spdif.c
index a5a56a1..6666c0b 100644
--- a/sound/soc/samsung/spdif.c
+++ b/sound/soc/samsung/spdif.c
@@ -13,6 +13,7 @@
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/module.h>
+#include <linux/pm_runtime.h>
#include <sound/soc.h>
#include <sound/pcm_params.h>
@@ -198,6 +199,7 @@
return -EINVAL;
}
+ pm_runtime_get_sync(spdif->dev);
snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_data);
spin_lock_irqsave(&spdif->lock, flags);
@@ -297,6 +299,8 @@
cpu_relax();
writel(clkcon & ~CLKCTL_PWR_ON, regs + CLKCON);
+
+ pm_runtime_put_sync(spdif->dev);
}
#ifdef CONFIG_PM
@@ -307,12 +311,16 @@
dev_dbg(spdif->dev, "Entered %s\n", __func__);
- spdif->saved_clkcon = readl(spdif->regs + CLKCON) & CLKCTL_MASK;
- spdif->saved_con = readl(spdif->regs + CON) & CON_MASK;
- spdif->saved_cstas = readl(spdif->regs + CSTAS) & CSTAS_MASK;
+ if (cpu_dai->active) {
+ spdif->saved_clkcon = readl(spdif->regs + CLKCON) & CLKCTL_MASK;
+ spdif->saved_con = readl(spdif->regs + CON) & CON_MASK;
+ spdif->saved_cstas = readl(spdif->regs + CSTAS) & CSTAS_MASK;
- writel(con | CON_SW_RESET, spdif->regs + CON);
- cpu_relax();
+ writel(con | CON_SW_RESET, spdif->regs + CON);
+ cpu_relax();
+
+ pm_runtime_put_sync(spdif->dev);
+ }
return 0;
}
@@ -323,9 +331,13 @@
dev_dbg(spdif->dev, "Entered %s\n", __func__);
- writel(spdif->saved_clkcon, spdif->regs + CLKCON);
- writel(spdif->saved_con, spdif->regs + CON);
- writel(spdif->saved_cstas, spdif->regs + CSTAS);
+ if (cpu_dai->active) {
+ pm_runtime_get_sync(spdif->dev);
+
+ writel(spdif->saved_clkcon, spdif->regs + CLKCON);
+ writel(spdif->saved_con, spdif->regs + CON);
+ writel(spdif->saved_cstas, spdif->regs + CSTAS);
+ }
return 0;
}
@@ -423,6 +435,7 @@
}
dev_set_drvdata(&pdev->dev, spdif);
+ pm_runtime_enable(spdif->dev);
ret = snd_soc_register_dai(&pdev->dev, &samsung_spdif_dai);
if (ret != 0) {
@@ -437,9 +450,13 @@
spdif->dma_playback = &spdif_stereo_out;
+ clk_disable(spdif->sclk);
+ clk_disable(spdif->pclk);
+
return 0;
err4:
+ pm_runtime_disable(spdif->dev);
iounmap(spdif->regs);
err3:
release_mem_region(mem_res->start, resource_size(mem_res));
@@ -466,20 +483,54 @@
if (mem_res)
release_mem_region(mem_res->start, resource_size(mem_res));
- clk_disable(spdif->sclk);
+ pm_runtime_put_sync(spdif->dev);
+ pm_runtime_disable(spdif->dev);
+
clk_put(spdif->sclk);
- clk_disable(spdif->pclk);
clk_put(spdif->pclk);
return 0;
}
+static int spdif_runtime_suspend(struct device *dev)
+{
+ struct samsung_spdif_info *spdif = dev_get_drvdata(dev);
+
+ dev_dbg(spdif->dev, "Entered %s\n", __func__);
+
+ clk_disable(spdif->sclk);
+ clk_disable(spdif->pclk);
+
+ return 0;
+}
+
+static int spdif_runtime_resume(struct device *dev)
+{
+ struct samsung_spdif_info *spdif = dev_get_drvdata(dev);
+
+ dev_dbg(spdif->dev, "Entered %s\n", __func__);
+
+ clk_enable(spdif->pclk);
+ clk_enable(spdif->sclk);
+
+ return 0;
+}
+
+static const struct dev_pm_ops spdif_pmops = {
+ SET_RUNTIME_PM_OPS(
+ spdif_runtime_suspend,
+ spdif_runtime_resume,
+ NULL
+ )
+};
+
static struct platform_driver samsung_spdif_driver = {
.probe = spdif_probe,
.remove = __devexit_p(spdif_remove),
.driver = {
.name = "samsung-spdif",
.owner = THIS_MODULE,
+ .pm = &spdif_pmops,
},
};
diff --git a/sound/soc/samsung/srp-type.h b/sound/soc/samsung/srp-type.h
new file mode 100644
index 0000000..cb3bf57
--- /dev/null
+++ b/sound/soc/samsung/srp-type.h
@@ -0,0 +1,24 @@
+/* linux/sound/soc/samsung/srp-type.h
+ *
+ * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * EXYNOS - SRP Type definitions
+ *
+ * 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.
+*/
+
+#ifndef __SND_SOC_SAMSUNG_SRP_TYPE_H
+#define __SND_SOC_SAMSUNG_SRP_TYPE_H
+
+#ifdef CONFIG_SND_SAMSUNG_ALP
+bool srp_enabled_status(void) {return 1;}
+extern unsigned int srp_get_idma_addr(void);
+#else
+bool srp_enabled_status(void) {return 0;}
+unsigned int srp_get_idma_addr(void) {return 0;}
+#endif
+
+#endif /* __SND_SOC_SAMSUNG_SRP_TYPE_H */
diff --git a/sound/soc/samsung/srp_alp/Kconfig b/sound/soc/samsung/srp_alp/Kconfig
new file mode 100644
index 0000000..b729a9c
--- /dev/null
+++ b/sound/soc/samsung/srp_alp/Kconfig
@@ -0,0 +1,19 @@
+config SND_SAMSUNG_ALP
+ depends on SND_SAMSUNG_I2S && ARCH_EXYNOS5
+ bool "Low power audio support with SRP"
+ default n
+ help
+ Say Y if you want to support ALP audio.
+
+config AUDIO_SAMSUNG_MEMSIZE_SRP
+ int "Memory size in kbytes for ALP Audio"
+ depends on SND_SAMSUNG_ALP
+ default "1024"
+
+config SND_SAMSUNG_RP_DEBUG
+ bool "Enable debug message for ALP Audio"
+ depends on SND_SAMSUNG_ALP
+ default n
+ help
+ Say Y if you want to add debug message for ALP Audio.
+
diff --git a/sound/soc/samsung/srp_alp/Makefile b/sound/soc/samsung/srp_alp/Makefile
new file mode 100644
index 0000000..ee16725
--- /dev/null
+++ b/sound/soc/samsung/srp_alp/Makefile
@@ -0,0 +1,3 @@
+# ALP(Advanced Low Power Audio) Solution Support with SRP
+obj-$(CONFIG_SND_SAMSUNG_ALP) += srp_alp.o
+
diff --git a/sound/soc/samsung/srp_alp/srp_alp.c b/sound/soc/samsung/srp_alp/srp_alp.c
new file mode 100644
index 0000000..6682ee5
--- /dev/null
+++ b/sound/soc/samsung/srp_alp/srp_alp.c
@@ -0,0 +1,1188 @@
+/* sound/soc/samsung/alp/srp_alp.c
+ *
+ * SRP Audio driver for Samsung Exynos
+ *
+ * Copyright (c) 2011 Samsung Electronics
+ * http://www.samsungsemi.com/
+ *
+ * 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.
+*/
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/serio.h>
+#include <linux/time.h>
+#include <linux/platform_device.h>
+#include <linux/miscdevice.h>
+#include <linux/clk.h>
+#include <linux/mutex.h>
+#include <linux/vmalloc.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/uaccess.h>
+#include <linux/cma.h>
+
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+#include <mach/map.h>
+#include <plat/cpu.h>
+
+#include "srp_alp.h"
+#include "srp_alp_reg.h"
+#include "srp_alp_fw.h"
+#include "srp_alp_ioctl.h"
+#include "srp_alp_error.h"
+
+static struct srp_info srp;
+static DEFINE_MUTEX(srp_mutex);
+static DECLARE_WAIT_QUEUE_HEAD(read_wq);
+static DECLARE_WAIT_QUEUE_HEAD(decinfo_wq);
+
+unsigned int srp_get_idma_addr(void)
+{
+ srp.idma_addr = SRP_IDMA_BASE;
+ return srp.idma_addr;
+}
+
+static void srp_obuf_elapsed(void)
+{
+ srp.obuf_ready = srp.obuf_ready ? 0 : 1;
+ srp.obuf_next = srp.obuf_next ? 0 : 1;
+}
+
+static void srp_wait_for_pending(void)
+{
+ unsigned long deadline = jiffies + HZ / 10;
+
+ do {
+ /* Wait for SRP Pending */
+ if (readl(srp.commbox + SRP_PENDING))
+ break;
+
+ msleep_interruptible(5);
+ } while (time_before(jiffies, deadline));
+
+ srp_info("Pending status[%s]\n",
+ readl(srp.commbox + SRP_PENDING) ? "STALL" : "RUN");
+}
+
+static void srp_pending_ctrl(int ctrl)
+{
+ unsigned int srp_ctrl = readl(srp.commbox + SRP_PENDING);
+
+ if (ctrl == srp_ctrl) {
+ srp_info("Already set SRP pending control[%d]\n", ctrl);
+
+ if (ctrl)
+ return;
+ else
+ srp_wait_for_pending();
+ }
+
+ writel(ctrl, srp.commbox + SRP_PENDING);
+ srp.is_pending = ctrl;
+
+ srp_debug("Current SRP Status[%s]\n",
+ readl(srp.commbox + SRP_PENDING) ? "STALL" : "RUN");
+}
+
+static void srp_check_stream_info(void)
+{
+ if (!srp.dec_info.channels) {
+ srp.dec_info.channels = readl(srp.commbox
+ + SRP_ARM_INTERRUPT_CODE);
+ srp.dec_info.channels >>= SRP_ARM_INTR_CODE_CHINF_SHIFT;
+ srp.dec_info.channels &= SRP_ARM_INTR_CODE_CHINF_MASK;
+ }
+
+ if (!srp.dec_info.sample_rate) {
+ srp.dec_info.sample_rate = readl(srp.commbox
+ + SRP_ARM_INTERRUPT_CODE);
+ srp.dec_info.sample_rate >>= SRP_ARM_INTR_CODE_SRINF_SHIFT;
+ srp.dec_info.sample_rate &= SRP_ARM_INTR_CODE_SRINF_MASK;
+ }
+}
+
+static void srp_flush_ibuf(void)
+{
+ memset(srp.ibuf0, 0xFF, srp.ibuf_size);
+ memset(srp.ibuf1, 0xFF, srp.ibuf_size);
+}
+
+static void srp_flush_obuf(void)
+{
+ memset(srp.obuf0, 0, srp.obuf_size);
+ memset(srp.obuf1, 0, srp.obuf_size);
+}
+
+static void srp_reset(void)
+{
+ unsigned int reg = 0;
+
+ srp_debug("Reset\n");
+
+ /* RESET */
+ writel(reg, srp.commbox + SRP_CONT);
+ writel(reg, srp.commbox + SRP_INTERRUPT);
+
+ /* Store Total Count */
+ srp.decoding_started = 0;
+
+ /* Next IBUF is IBUF0 */
+ srp.ibuf_next = 0;
+ srp.ibuf_empty[0] = 1;
+ srp.ibuf_empty[1] = 1;
+
+ srp.obuf_next = 1;
+ srp.obuf_ready = 0;
+ srp.obuf_fill_done[0] = 0;
+ srp.obuf_fill_done[1] = 0;
+ srp.obuf_copy_done[0] = 0;
+ srp.obuf_copy_done[1] = 0;
+
+ srp.wbuf_pos = 0;
+ srp.wbuf_fill_size = 0;
+
+ srp.set_bitstream_size = 0;
+ srp.stop_after_eos = 0;
+ srp.wait_for_eos = 0;
+ srp.prepare_for_eos = 0;
+ srp.play_done = 0;
+ srp.pcm_size = 0;
+}
+
+static void srp_fill_ibuf(void)
+{
+ unsigned long fill_size = 0;
+
+ if (!srp.wbuf_pos)
+ return;
+
+ if (srp.wbuf_pos >= srp.ibuf_size) {
+ fill_size = srp.ibuf_size;
+ srp.wbuf_pos -= fill_size;
+ } else {
+ if (srp.wait_for_eos) {
+ fill_size = srp.wbuf_pos;
+ memset(&srp.wbuf[fill_size], 0xFF,
+ srp.ibuf_size - fill_size);
+ srp.wbuf_pos = 0;
+ }
+ }
+
+ if (srp.ibuf_next == 0) {
+ memcpy(srp.ibuf0, srp.wbuf, srp.ibuf_size);
+ srp_debug("Fill IBUF0 (%lu)\n", fill_size);
+ srp.ibuf_empty[0] = 0;
+ srp.ibuf_next = 1;
+ } else {
+ memcpy(srp.ibuf1, srp.wbuf, srp.ibuf_size);
+ srp_debug("Fill IBUF1 (%lu)\n", fill_size);
+ srp.ibuf_empty[1] = 0;
+ srp.ibuf_next = 0;
+ }
+
+ if (srp.wbuf_pos)
+ memcpy(srp.wbuf, &srp.wbuf[srp.ibuf_size], srp.wbuf_pos);
+}
+
+static ssize_t srp_write(struct file *file, const char *buffer,
+ size_t size, loff_t *pos)
+{
+ unsigned long start_threshold = 0;
+ ssize_t ret = 0;
+
+ srp_debug("Write(%d bytes)\n", size);
+
+ if (srp.obuf_fill_done[srp.obuf_ready]
+ && srp.obuf_copy_done[srp.obuf_ready]) {
+ srp.obuf_fill_done[srp.obuf_ready] = 0;
+ srp.obuf_copy_done[srp.obuf_ready] = 0;
+ srp_obuf_elapsed();
+ }
+
+ if (srp.wbuf_pos + size > WBUF_SIZE) {
+ srp_debug("Occured Ibuf Overflow!!\n");
+ ret = SRP_ERROR_IBUF_OVERFLOW;
+ goto exit_func;
+ }
+
+ if (copy_from_user(&srp.wbuf[srp.wbuf_pos], buffer, size)) {
+ srp_err("Failed to copy_from_user!!\n");
+ ret = -EFAULT;
+ goto exit_func;
+ }
+
+ srp.wbuf_pos += size;
+ srp.wbuf_fill_size += size;
+
+ start_threshold = srp.decoding_started
+ ? srp.ibuf_size : START_THRESHOLD;
+
+ if (srp.wbuf_pos < start_threshold) {
+ ret = size;
+ goto exit_func;
+ }
+
+ mutex_lock(&srp_mutex);
+ if (!srp.decoding_started) {
+ srp_fill_ibuf();
+ srp_info("First Start decoding!!\n");
+ srp_pending_ctrl(RUN);
+ srp.decoding_started = 1;
+ }
+ mutex_unlock(&srp_mutex);
+
+exit_func:
+ return ret;
+}
+
+static ssize_t srp_read(struct file *file, char *buffer,
+ size_t size, loff_t *pos)
+{
+ struct srp_buf_info *argp = (struct srp_buf_info *)buffer;
+ unsigned char *mmapped_obuf0 = srp.obuf_info.addr;
+ unsigned char *mmapped_obuf1 = srp.obuf_info.addr + srp.obuf_size;
+ int ret = 0;
+ int i;
+
+ srp_debug("Entered Get Obuf in PCM function\n");
+
+ if (srp.prepare_for_eos) {
+ srp.obuf_fill_done[srp.obuf_ready] = 0;
+ srp_debug("Elapsed Obuf[%d] after Send EOS\n", srp.obuf_ready);
+ if (srp.pm_resumed)
+ srp.pm_suspended = false;
+
+ srp_pending_ctrl(RUN);
+ srp_obuf_elapsed();
+ }
+
+ if (srp.wait_for_eos)
+ srp.prepare_for_eos = 1;
+
+ if (srp.decoding_started) {
+ if (srp.obuf_copy_done[srp.obuf_ready] && !srp.wait_for_eos) {
+ srp_debug("Wrong ordering read() OBUF[%d] int!!!\n", srp.obuf_ready);
+ srp.pcm_info.size = 0;
+ return copy_to_user(argp, &srp.pcm_info, sizeof(struct srp_buf_info));
+ }
+
+ if (srp.obuf_fill_done[srp.obuf_ready]) {
+ srp_debug("Already filled OBUF[%d]\n", srp.obuf_ready);
+ } else {
+ srp_debug("Waiting for filling OBUF[%d]\n", srp.obuf_ready);
+ ret = wait_event_interruptible_timeout(read_wq,
+ srp.obuf_fill_done[srp.obuf_ready], HZ / 2);
+ if (!ret) {
+ srp_err("Couldn't occurred OBUF[%d] int!!!\n", srp.obuf_ready);
+ srp.pcm_info.size = 0;
+ return copy_to_user(argp, &srp.pcm_info, sizeof(struct srp_buf_info));
+ }
+ }
+ } else {
+ srp_debug("not prepared not yet! OBUF[%d]\n", srp.obuf_ready);
+ srp.pcm_info.size = 0;
+ return copy_to_user(argp, &srp.pcm_info, sizeof(struct srp_buf_info));
+ }
+
+ /* For EVT0 : will be removed on EVT1 */
+ if (soc_is_exynos5250()) {
+ if (srp.obuf_ready == 0) {
+ for (i = 0; i < srp.obuf_size; i += 4)
+ memcpy(&srp.obuf0[i], &srp.pcm_obuf0[i], 0x4);
+ } else {
+ for (i = 0; i < srp.obuf_size; i += 4)
+ memcpy(&srp.obuf1[i], &srp.pcm_obuf1[i], 0x4);
+ }
+ }
+
+ srp.pcm_info.addr = srp.obuf_ready ? mmapped_obuf1 : mmapped_obuf0;
+ srp.pcm_info.size = srp.pcm_size;
+ srp.pcm_info.num = srp.obuf_info.num;
+
+ if (srp.play_done && !srp.pcm_info.size) {
+ srp_info("Stop EOS by play done\n");
+ srp.pcm_info.size = 0;
+ srp.stop_after_eos = 1;
+ }
+
+ ret = copy_to_user(argp, &srp.pcm_info, sizeof(struct srp_buf_info));
+ srp_debug("Return OBUF Num[%d] fill size %d\n",
+ srp.obuf_ready, srp.pcm_info.size);
+
+ srp.obuf_copy_done[srp.obuf_ready] = 1;
+
+ if (!srp.obuf_fill_done[srp.obuf_next] && !srp.wait_for_eos) {
+ srp_debug("Decoding start for filling OBUF[%d]\n", srp.obuf_next);
+ if (srp.pm_resumed)
+ srp.pm_suspended = false;
+
+ srp_pending_ctrl(RUN);
+ }
+
+ return ret;
+}
+
+static void srp_commbox_init(void)
+{
+ unsigned int reg = 0;
+
+ writel(reg, srp.commbox + SRP_FRAME_INDEX);
+ writel(reg, srp.commbox + SRP_INTERRUPT);
+
+ /* Support Mono Decoding */
+ writel(SRP_ARM_INTR_CODE_SUPPORT_MONO, srp.commbox + SRP_ARM_INTERRUPT_CODE);
+
+ /* Init Ibuf information */
+ if (!soc_is_exynos5250()) {
+ writel(srp.ibuf0_pa, srp.commbox + SRP_BITSTREAM_BUFF_DRAM_ADDR0);
+ writel(srp.ibuf1_pa, srp.commbox + SRP_BITSTREAM_BUFF_DRAM_ADDR1);
+ writel(srp.ibuf_size, srp.commbox + SRP_BITSTREAM_BUFF_DRAM_SIZE);
+ }
+
+ /* Output PCM control : 16bit */
+ writel(SRP_CFGR_OUTPUT_PCM_16BIT, srp.commbox + SRP_CFGR);
+
+ /* Bit stream size : Max */
+ writel(BITSTREAM_SIZE_MAX, srp.commbox + SRP_BITSTREAM_SIZE);
+
+ /* Init Read bitstream size */
+ writel(reg, srp.commbox + SRP_READ_BITSTREAM_SIZE);
+
+ /* Configure fw address */
+ writel(srp.fw_info.vliw_pa, srp.commbox + SRP_CODE_START_ADDR);
+ writel(srp.fw_info.cga_pa, srp.commbox + SRP_CONF_START_ADDR);
+ writel(srp.fw_info.data_pa, srp.commbox + SRP_DATA_START_ADDR);
+}
+
+static void srp_commbox_deinit(void)
+{
+ unsigned int reg = 0;
+
+ srp_wait_for_pending();
+ srp_pending_ctrl(STALL);
+ srp.decoding_started = 0;
+ writel(reg, srp.commbox + SRP_INTERRUPT);
+}
+
+static void srp_clr_fw_buff(void)
+{
+ memset(srp.fw_info.vliw, 0, ICACHE_SIZE);
+ memset(srp.fw_info.cga, 0, CMEM_SIZE);
+ memset(srp.fw_info.data, 0, DMEM_SIZE);
+
+ memcpy(srp.fw_info.vliw, srp_fw_vliw, sizeof(srp_fw_vliw));
+ memcpy(srp.fw_info.cga, srp_fw_cga, sizeof(srp_fw_cga));
+ memcpy(srp.fw_info.data, srp_fw_data, sizeof(srp_fw_data));
+}
+
+static void srp_fw_download(void)
+{
+ unsigned long n;
+ unsigned long *pval;
+ unsigned int reg = 0;
+
+ /* Fill ICACHE with first 64KB area : ARM access I$ */
+ memcpy(srp.icache, srp.fw_info.vliw, ICACHE_SIZE);
+
+ /* Fill DMEM */
+ memcpy(srp.dmem, srp.fw_info.data, DMEM_SIZE);
+
+ /* Fill CMEM : Should be write by the 1word(32bit) */
+ pval = (unsigned long *)srp.fw_info.cga;
+ for (n = 0; n < CMEM_SIZE; n += 4, pval++)
+ writel(ENDIAN_CHK_CONV(*pval), srp.cmem + n);
+
+ reg = readl(srp.commbox + SRP_CFGR);
+ reg |= (SRP_CFGR_BOOT_INST_INT_CC | /* Fetchs instruction from I$ */
+ SRP_CFGR_USE_ICACHE_MEM | /* SRP can access I$ */
+ SRP_CFGR_USE_I2S_INTR |
+ SRP_CFGR_FLOW_CTRL_OFF);
+
+ writel(reg, srp.commbox + SRP_CFGR);
+}
+
+static void srp_set_default_fw(void)
+{
+ /* Initialize Commbox & default parameters */
+ srp_commbox_init();
+
+ srp_clr_fw_buff();
+
+ /* Download default Firmware */
+ srp_fw_download();
+}
+
+static void srp_set_stream_size(void)
+{
+ /* Leave stream size max, if data is available */
+ if (srp.wbuf_pos || srp.set_bitstream_size)
+ return;
+
+ srp.set_bitstream_size = srp.wbuf_fill_size;
+ writel(srp.set_bitstream_size, srp.commbox + SRP_BITSTREAM_SIZE);
+
+ srp_info("Set bitstream size = %ld\n", srp.set_bitstream_size);
+}
+
+static long srp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct srp_buf_info *argp = (struct srp_buf_info *)arg;
+ unsigned long val = 0;
+ long ret = 0;
+
+ mutex_lock(&srp_mutex);
+
+ switch (cmd) {
+ case SRP_INIT:
+ srp_debug("SRP_INIT\n");
+ srp_flush_ibuf();
+ srp_flush_obuf();
+ srp_set_default_fw();
+ srp_reset();
+ break;
+
+ case SRP_DEINIT:
+ srp_debug("SRP DEINIT\n");
+ srp_commbox_deinit();
+ break;
+
+ case SRP_GET_MMAP_SIZE:
+ srp.obuf_info.mmapped_size = srp.obuf_size * srp.obuf_num + srp.obuf_offset;
+ val = srp.obuf_info.mmapped_size;
+ ret = copy_to_user((unsigned long *)arg,
+ &val, sizeof(unsigned long));
+
+ srp_debug("OBUF_MMAP_SIZE = %ld\n", val);
+ break;
+
+ case SRP_FLUSH:
+ srp_debug("SRP_FLUSH\n");
+ srp_commbox_deinit();
+ srp_set_default_fw();
+ srp_flush_ibuf();
+ srp_flush_obuf();
+ srp_reset();
+ break;
+
+ case SRP_GET_IBUF_INFO:
+ srp.ibuf_info.addr = (void *) srp.wbuf;
+ srp.ibuf_info.size = srp.ibuf_size * 2;
+ srp.ibuf_info.num = srp.ibuf_num;
+
+ ret = copy_to_user(argp, &srp.ibuf_info,
+ sizeof(struct srp_buf_info));
+ break;
+
+ case SRP_GET_OBUF_INFO:
+ ret = copy_from_user(&srp.obuf_info, argp,
+ sizeof(struct srp_buf_info));
+ if (!ret) {
+ srp.obuf_info.addr = srp.obuf_info.mmapped_addr
+ + srp.obuf_offset;
+ srp.obuf_info.size = srp.obuf_size;
+ srp.obuf_info.num = srp.obuf_num;
+ }
+
+ ret = copy_to_user(argp, &srp.obuf_info,
+ sizeof(struct srp_buf_info));
+ break;
+
+ case SRP_SEND_EOS:
+ srp_info("Send End-Of-Stream\n");
+ if (srp.wbuf_fill_size == 0) {
+ srp.stop_after_eos = 1;
+ } else if (srp.wbuf_fill_size < srp.ibuf_size * 3) {
+ srp_debug("%ld, smaller than ibuf_size * 3\n", srp.wbuf_fill_size);
+ srp.wait_for_eos = 1;
+ srp_fill_ibuf();
+ srp_set_stream_size();
+ srp_pending_ctrl(RUN);
+ srp.decoding_started = 1;
+ } else if (srp.wbuf_fill_size >= srp.ibuf_size * 3) {
+ srp_debug("%ld Bigger than ibuf * 3!!\n", srp.wbuf_fill_size);
+ srp.wait_for_eos = 1;
+ }
+ break;
+
+ case SRP_STOP_EOS_STATE:
+ val = srp.stop_after_eos;
+
+ srp_debug("Stop [%s]\n", val == 1 ? "ON" : "OFF");
+ if (val) {
+ srp_info("Stop at EOS [0x%08lX:0x%08X]\n",
+ srp.wbuf_pos,
+ readl(srp.commbox + SRP_READ_BITSTREAM_SIZE));
+ srp.decoding_started = 0;
+ }
+ val = copy_to_user((unsigned long *)arg,
+ &val, sizeof(unsigned long));
+ break;
+
+ case SRP_GET_DEC_INFO:
+ if (!srp.decoding_started) {
+ srp.dec_info.sample_rate = 0;
+ srp.dec_info.channels = 0;
+ } else {
+ if (srp.dec_info.sample_rate && srp.dec_info.channels) {
+ srp_info("Already get dec info!\n");
+ } else {
+ ret = wait_event_interruptible_timeout(decinfo_wq,
+ srp.dec_info.channels != 0, HZ / 2);
+ if (!ret) {
+ srp_err("Couldn't Get Decoding info!!!\n");
+ ret = SRP_ERROR_GETINFO_FAIL;
+ }
+ }
+
+ srp_info("SampleRate[%d], Channels[%d]\n",
+ srp.dec_info.sample_rate,
+ srp.dec_info.channels);
+ }
+
+ val = copy_to_user((struct srp_dec_info *)arg, &srp.dec_info,
+ sizeof(struct srp_dec_info));
+ break;
+ }
+
+ mutex_unlock(&srp_mutex);
+
+ return ret;
+}
+
+static int srp_open(struct inode *inode, struct file *file)
+{
+ srp_info("Opened!\n");
+
+ mutex_lock(&srp_mutex);
+ if (srp.is_opened) {
+ srp_err("Already opened.\n");
+ mutex_unlock(&srp_mutex);
+ return -ENXIO;
+ }
+ srp.is_opened = 1;
+ mutex_unlock(&srp_mutex);
+
+ if (!(file->f_flags & O_NONBLOCK))
+ srp.block_mode = 1;
+ else
+ srp.block_mode = 0;
+
+ srp.dec_info.channels = 0;
+ srp.dec_info.sample_rate = 0;
+
+ srp.pm_suspended = false;
+ srp.pm_resumed = false;
+
+ return 0;
+}
+
+static int srp_release(struct inode *inode, struct file *file)
+{
+ srp_info("Released\n");
+
+ mutex_lock(&srp_mutex);
+ srp.is_opened = 0;
+ mutex_unlock(&srp_mutex);
+
+ return 0;
+}
+
+static int srp_mmap(struct file *filep, struct vm_area_struct *vma)
+{
+ unsigned long size = vma->vm_end - vma->vm_start;
+ unsigned int pfn;
+ unsigned int mmap_addr;
+
+ vma->vm_flags |= VM_IO;
+ vma->vm_flags |= VM_RESERVED;
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+
+ /* For EVT0 : will be removed on EVT1 */
+ mmap_addr = soc_is_exynos5250() ? srp.obuf0_pa
+ : SRP_DMEM_BASE;
+
+ pfn = __phys_to_pfn(mmap_addr);
+
+ if (remap_pfn_range(vma, vma->vm_start, pfn, size, vma->vm_page_prot)) {
+ srp_err("failed to mmap for Obuf\n");
+ return -EAGAIN;
+ }
+
+ return 0;
+}
+
+static void srp_check_obuf_info(void)
+{
+ unsigned int buf0 = readl(srp.commbox + SRP_PCM_BUFF0);
+ unsigned int buf1 = readl(srp.commbox + SRP_PCM_BUFF1);
+ unsigned int size = readl(srp.commbox + SRP_PCM_BUFF_SIZE);
+
+ /* For EVT0 : will be removed on EVT1 */
+ if (!soc_is_exynos5250()) {
+ if (srp.obuf0_pa != buf0)
+ srp_err("Wrong PCM BUF0[0x%x], OBUF0[0x%x]\n",
+ buf0, srp.obuf0_pa);
+ if (srp.obuf1_pa != buf1)
+ srp_err("Wrong PCM BUF1[0x%x], OBUF1[0x%x]\n",
+ buf1, srp.obuf1_pa);
+ }
+
+ if ((srp.obuf_size >> 2) != size)
+ srp_err("Wrong OBUF SIZE[%d]\n", size);
+}
+
+static irqreturn_t srp_irq(int irqno, void *dev_id)
+{
+ unsigned int irq_code = readl(srp.commbox + SRP_INTERRUPT_CODE);
+ unsigned int irq_code_req;
+ unsigned int wakeup_read = 0;
+ unsigned int wakeup_decinfo = 0;
+
+ srp_debug("IRQ: Code [0x%x], Pending [%s], CFGR [0x%x]", irq_code,
+ readl(srp.commbox + SRP_PENDING) ? "STALL" : "RUN",
+ readl(srp.commbox + SRP_CFGR));
+
+ irq_code &= SRP_INTR_CODE_MASK;
+ if (irq_code & SRP_INTR_CODE_REQUEST) {
+ irq_code_req = irq_code & SRP_INTR_CODE_REQUEST_MASK;
+ switch (irq_code_req) {
+ case SRP_INTR_CODE_NOTIFY_INFO:
+ srp_info("Notify SRP interrupt!\n");
+ srp_check_stream_info();
+ wakeup_decinfo = 1;
+ break;
+
+ case SRP_INTR_CODE_IBUF_REQUEST:
+ if ((irq_code & SRP_INTR_CODE_IBUF_MASK)
+ == SRP_INTR_CODE_IBUF0_EMPTY) {
+ srp_debug("IBUF0 empty\n");
+ srp.ibuf_empty[0] = 1;
+ } else {
+ srp_debug("IBUF1 empty\n");
+ srp.ibuf_empty[1] = 1;
+ }
+
+ srp_fill_ibuf();
+ if (srp.decoding_started) {
+ if (srp.wait_for_eos && !srp.wbuf_pos)
+ srp_set_stream_size();
+ }
+ break;
+
+ case SRP_INTR_CODE_OBUF_FULL:
+ if ((irq_code & SRP_INTR_CODE_OBUF_MASK)
+ == SRP_INTR_CODE_OBUF0_FULL) {
+ srp_debug("OBUF0 FULL\n");
+ srp.obuf_fill_done[0] = 1;
+ } else {
+ srp_debug("OBUF1 FULL\n");
+ srp.obuf_fill_done[1] = 1;
+ }
+
+ wakeup_read = 1;
+ srp.pcm_size = readl(srp.commbox + SRP_PCM_DUMP_ADDR);
+ writel(0, srp.commbox + SRP_PCM_DUMP_ADDR);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (irq_code & SRP_INTR_CODE_NOTIFY_OBUF)
+ srp_check_obuf_info();
+
+
+ if ((irq_code & (SRP_INTR_CODE_PLAYDONE | SRP_INTR_CODE_ERROR))
+ && (irq_code & SRP_INTR_CODE_PLAYEND)) {
+ srp_info("Play Done interrupt!!\n");
+ srp.pcm_size = 0;
+ srp.play_done = 1;
+
+ srp.obuf_fill_done[0] = 1;
+ srp.obuf_fill_done[1] = 1;
+ wakeup_read = 1;
+ }
+
+ if (irq_code & SRP_INTR_CODE_UART_OUTPUT) {
+ srp_debug("UART Code received [0x%08X]\n",
+ readl(srp.commbox + SRP_UART_INFORMATION));
+ }
+
+ writel(0, srp.commbox + SRP_INTERRUPT_CODE);
+ writel(0, srp.commbox + SRP_INTERRUPT);
+
+ if (wakeup_read) {
+ if (waitqueue_active(&read_wq))
+ wake_up_interruptible(&read_wq);
+ }
+
+ if (wakeup_decinfo) {
+ if (waitqueue_active(&decinfo_wq))
+ wake_up_interruptible(&decinfo_wq);
+ }
+
+ srp_debug("IRQ Exited!\n");
+
+ return IRQ_HANDLED;
+}
+
+static void srp_prepare_buff(struct device *dev)
+{
+ srp.ibuf_size = IBUF_SIZE;
+ srp.obuf_size = OBUF_SIZE;
+ srp.wbuf_size = WBUF_SIZE;
+ srp.ibuf_offset = IBUF_OFFSET;
+ srp.obuf_offset = OBUF_OFFSET;
+
+ srp.ibuf0 = soc_is_exynos5250() ? srp.dmem + srp.ibuf_offset
+ : srp.iram + srp.ibuf_offset;
+
+ /* For EVT0 : will be removed on EVT1 */
+ if (soc_is_exynos5250()) {
+ srp.obuf0 = dma_alloc_writecombine(dev, srp.obuf_size * 2,
+ &srp.obuf0_pa, GFP_KERNEL);
+ srp.pcm_obuf0 = srp.dmem + srp.obuf_offset;
+ srp.pcm_obuf1 = srp.pcm_obuf0 + srp.obuf_size;
+ srp.obuf_offset = 0;
+ } else {
+ srp.obuf0 = srp.dmem + srp.obuf_offset;
+ }
+
+ srp.ibuf1 = srp.ibuf0 + srp.ibuf_size;
+ srp.obuf1 = srp.obuf0 + srp.obuf_size;
+
+ if (!srp.ibuf0_pa)
+ srp.ibuf0_pa = SRP_IBUF_PHY_ADDR;
+
+ if (!srp.obuf0_pa)
+ srp.obuf0_pa = SRP_OBUF_PHY_ADDR;
+
+ srp.ibuf1_pa = srp.ibuf0_pa + srp.ibuf_size;
+ srp.obuf1_pa = srp.obuf0_pa + srp.obuf_size;
+
+ srp.ibuf_num = IBUF_NUM;
+ srp.obuf_num = OBUF_NUM;
+
+ srp_info("[VA]IBUF0[0x%p], [PA]IBUF0[0x%x]\n",
+ srp.ibuf0, srp.ibuf0_pa);
+ srp_info("[VA]IBUF1[0x%p], [PA]IBUF1[0x%x]\n",
+ srp.ibuf1, srp.ibuf1_pa);
+ srp_info("[VA]OBUF0[0x%p], [PA]OBUF0[0x%x]\n",
+ srp.obuf0, srp.obuf0_pa);
+ srp_info("[VA]OBUF1[0x%p], [PA]OBUF1[0x%x]\n",
+ srp.obuf1, srp.obuf1_pa);
+ srp_info("IBUF SIZE [%ld]Bytes, OBUF SIZE [%ld]Bytes\n",
+ srp.ibuf_size, srp.obuf_size);
+}
+
+static int srp_prepare_fw_buff(struct device *dev)
+{
+#if defined(CONFIG_CMA)
+ unsigned long mem_paddr;
+
+ srp.fw_info.mem_base = cma_alloc(dev, "srp", BASE_MEM_SIZE, 0);
+ if (IS_ERR_VALUE(srp.fw_info.mem_base)) {
+ srp_err("Failed to cma alloc for srp\n");
+ return -ENOMEM;
+ }
+
+ mem_paddr = srp.fw_info.mem_base;
+ srp.fw_info.vliw_pa = mem_paddr;
+ srp.fw_info.vliw = phys_to_virt(srp.fw_info.vliw_pa);
+ mem_paddr += ICACHE_SIZE;
+
+ srp.fw_info.cga_pa = mem_paddr;
+ srp.fw_info.cga = phys_to_virt(srp.fw_info.cga_pa);
+ mem_paddr += CMEM_SIZE;
+
+ srp.fw_info.data_pa = mem_paddr;
+ srp.fw_info.data = phys_to_virt(srp.fw_info.data_pa);
+ mem_paddr += DMEM_SIZE;
+
+ srp.wbuf = phys_to_virt(mem_paddr);
+ mem_paddr += WBUF_SIZE;
+
+ srp.sp_data.ibuf = phys_to_virt(mem_paddr);
+ mem_paddr += IBUF_SIZE * 2;
+
+ srp.sp_data.obuf = phys_to_virt(mem_paddr);
+ mem_paddr += OBUF_SIZE * 2;
+
+ srp.sp_data.commbox = phys_to_virt(mem_paddr);
+ mem_paddr += COMMBOX_SIZE;
+#else
+ srp.fw_info.vliw = dma_alloc_writecombine(dev, ICACHE_SIZE,
+ &srp.fw_info.vliw_pa, GFP_KERNEL);
+ if (!srp.fw_info.vliw) {
+ srp_err("Failed to alloc for vliw\n");
+ return -ENOMEM;
+ }
+
+ srp.fw_info.cga = dma_alloc_writecombine(dev, CMEM_SIZE,
+ &srp.fw_info.cga_pa, GFP_KERNEL);
+ if (!srp.fw_info.cga) {
+ srp_err("Failed to alloc for cga\n");
+ return -ENOMEM;
+ }
+
+ srp.fw_info.data = dma_alloc_writecombine(dev, DMEM_SIZE,
+ &srp.fw_info.data_pa, GFP_KERNEL);
+ if (!srp.fw_info.data) {
+ srp_err("Failed to alloc for data\n");
+ return -ENOMEM;
+ }
+
+ srp.wbuf = kzalloc(srp.wbuf_size, GFP_KERNEL);
+ if (!srp.wbuf) {
+ srp_err("Failed to allocation for WBUF!\n");
+ return -ENOMEM;
+ }
+
+ srp.sp_data.ibuf = kzalloc(IBUF_SIZE * 2, GFP_KERNEL);
+ if (!srp.sp_data.ibuf) {
+ srp_err("Failed to alloc ibuf for suspend/resume!\n");
+ return -ENOMEM;
+ }
+
+ srp.sp_data.obuf = kzalloc(OBUF_SIZE * 2, GFP_KERNEL);
+ if (!srp.sp_data.obuf) {
+ srp_err("Failed to alloc obuf for suspend/resume!\n");
+ return -ENOMEM;
+ }
+
+ srp.sp_data.commbox = kzalloc(COMMBOX_SIZE, GFP_KERNEL);
+ if (!srp.sp_data.commbox) {
+ srp_err("Failed to alloc commbox for suspend/resume\n");
+ return -ENOMEM;
+ }
+#endif
+
+ srp.fw_info.vliw_size = sizeof(srp_fw_vliw);
+ srp.fw_info.cga_size = sizeof(srp_fw_cga);
+ srp.fw_info.data_size = sizeof(srp_fw_data);
+
+ srp_info("VLIW_SIZE[%lu]Bytes\n", srp.fw_info.vliw_size);
+ srp_info("CGA_SIZE[%lu]Bytes\n", srp.fw_info.cga_size);
+ srp_info("DATA_SIZE[%lu]Bytes\n", srp.fw_info.data_size);
+
+ return 0;
+}
+
+static int srp_remove_fw_buff(struct device *dev)
+{
+#if defined(CONFIG_CMA)
+ cma_free(srp.fw_info.mem_base);
+#else
+ dma_free_writecombine(dev, ICACHE_SIZE, srp.fw_info.vliw,
+ srp.fw_info.vliw_pa);
+ dma_free_writecombine(dev, CMEM_SIZE, srp.fw_info.cga,
+ srp.fw_info.cga_pa);
+ dma_free_writecombine(dev, DMEM_SIZE, srp.fw_info.data,
+ srp.fw_info.data_pa);
+ kfree(srp.wbuf);
+ kfree(srp.sp_data.ibuf);
+ kfree(srp.sp_data.obuf);
+ kfree(srp.sp_data.commbox);
+#endif
+ srp.fw_info.vliw = NULL;
+ srp.fw_info.cga = NULL;
+ srp.fw_info.data = NULL;
+
+ srp.fw_info.vliw_pa = 0;
+ srp.fw_info.cga_pa = 0;
+ srp.fw_info.data_pa = 0;
+ srp.ibuf0_pa = 0;
+ srp.ibuf1_pa = 0;
+ srp.obuf0_pa = 0;
+ srp.obuf1_pa = 0;
+
+ return 0;
+}
+
+static const struct file_operations srp_fops = {
+ .owner = THIS_MODULE,
+ .open = srp_open,
+ .release = srp_release,
+ .read = srp_read,
+ .write = srp_write,
+ .unlocked_ioctl = srp_ioctl,
+ .mmap = srp_mmap,
+};
+
+static struct miscdevice srp_miscdev = {
+ .minor = SRP_DEV_MINOR,
+ .name = "srp",
+ .fops = &srp_fops,
+};
+
+#ifdef CONFIG_PM
+static void srp_request_pwr_mode(int mode)
+{
+ unsigned int pwr_mode = readl(srp.commbox + SRP_POWER_MODE);
+ unsigned int intr_en = readl(srp.commbox + SRP_INTREN);
+ unsigned int intr_msk = readl(srp.commbox + SRP_INTRMASK);
+ unsigned int intr_src = readl(srp.commbox + SRP_INTRSRC);
+
+ pwr_mode &= ~SRP_POWER_MODE_MASK;
+ intr_en &= ~SRP_INTR_DI;
+ intr_msk |= (SRP_ARM_INTR_MASK | SRP_DMA_INTR_MASK | SRP_TMR_INTR_MASK);
+ intr_src &= ~(SRP_INTRSRC_MASK);
+
+ if (!mode)
+ pwr_mode &= ~SRP_POWER_MODE_TRIGGER;
+ else
+ pwr_mode |= SRP_POWER_MODE_TRIGGER;
+
+ intr_en |= SRP_INTR_EN;
+ intr_msk &= ~SRP_ARM_INTR_MASK;
+ intr_src |= SRP_ARM_INTR_SRC;
+
+ writel(pwr_mode, srp.commbox + SRP_POWER_MODE);
+ writel(intr_en, srp.commbox + SRP_INTREN);
+ writel(intr_msk, srp.commbox + SRP_INTRMASK);
+ writel(intr_src, srp.commbox + SRP_INTRSRC);
+
+ srp_debug("PWR_MODE[0x%x], INTREN[0x%x], INTRMSK[0x%x], INTRSRC[0x%x]\n",
+ readl(srp.commbox + SRP_POWER_MODE),
+ readl(srp.commbox + SRP_INTREN),
+ readl(srp.commbox + SRP_INTRMASK),
+ readl(srp.commbox + SRP_INTRSRC));
+}
+
+static int srp_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ unsigned long deadline = jiffies + (HZ / 100);
+
+ srp_info("Suspend\n");
+
+ if (srp.is_opened) {
+ if (srp.decoding_started && !srp.pm_suspended) {
+
+ /* IBUF/OBUF Save */
+ memcpy(srp.sp_data.ibuf, srp.ibuf0, IBUF_SIZE * 2);
+ memcpy(srp.sp_data.obuf, srp.obuf0, OBUF_SIZE * 2);
+
+ /* Request Suspend mode */
+ srp_request_pwr_mode(SUSPEND);
+ srp_pending_ctrl(RUN);
+
+ do {
+ /* Waiting for completed suspended mode */
+ if ((readl(srp.commbox + SRP_POWER_MODE)
+ & SRP_SUSPENED_CHECKED))
+ break;
+ } while (time_before(jiffies, deadline));
+
+ srp_pending_ctrl(STALL);
+ memcpy(srp.fw_info.data, srp.dmem, DMEM_SIZE);
+ memcpy(srp.sp_data.commbox, srp.commbox, COMMBOX_SIZE);
+ srp.pm_suspended = true;
+ }
+ }
+
+ return 0;
+}
+
+static int srp_resume(struct platform_device *pdev)
+{
+ srp_info("Resume\n");
+
+ if (srp.is_opened) {
+ if (!srp.decoding_started) {
+ srp_set_default_fw();
+ srp_flush_ibuf();
+ srp_flush_obuf();
+ srp_reset();
+ } else if (srp.decoding_started && srp.pm_suspended) {
+ srp_fw_download();
+
+ memcpy(srp.commbox, srp.sp_data.commbox, COMMBOX_SIZE);
+ memcpy(srp.ibuf0, srp.sp_data.ibuf, IBUF_SIZE * 2);
+ memcpy(srp.obuf0, srp.sp_data.obuf, OBUF_SIZE * 2);
+
+ /* RESET */
+ writel(0x0, srp.commbox + SRP_CONT);
+ srp_request_pwr_mode(RESUME);
+
+ srp.pm_resumed = true;
+ }
+ }
+
+ return 0;
+}
+
+#else
+#define srp_suspend NULL
+#define srp_resume NULL
+#endif
+
+static __devinit int srp_probe(struct platform_device *pdev)
+{
+ struct resource *int_mem_res;
+ struct resource *commbox_res;
+ unsigned int int_mem_base = 0;
+ unsigned int commbox_base = 0;
+ int ret = 0;
+
+ int_mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!int_mem_res) {
+ srp_err("Unable to get internal mem resource\n");
+ return -ENXIO;
+ }
+
+ commbox_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!commbox_res) {
+ srp_err("Unable to get commbox resource\n");
+ return -ENXIO;
+ }
+
+ if (!request_mem_region(int_mem_res->start, resource_size(int_mem_res),
+ "samsung-rp")) {
+ srp_err("Unable to request internal mem\n");
+ return -EBUSY;
+ }
+ int_mem_base = int_mem_res->start;
+
+ if (!request_mem_region(commbox_res->start, resource_size(commbox_res),
+ "samsung-rp")) {
+ srp_err("Unable to request commbox\n");
+ ret = -EBUSY;
+ goto err1;
+ }
+ commbox_base = commbox_res->start;
+
+ srp.dmem = ioremap(int_mem_base, INT_MEM_SIZE);
+ if (srp.dmem == NULL) {
+ srp_err("Failed to ioremap for dmem\n");
+ ret = -ENOMEM;
+ goto err2;
+
+ }
+ srp.icache = srp.dmem + DMEM_SIZE;
+ srp.cmem = srp.icache + ICACHE_SIZE;
+
+ srp.commbox = ioremap(commbox_base, COMMBOX_SIZE);
+ if (srp.commbox == NULL) {
+ srp_err("Failed to ioremap for audio subsystem\n");
+ ret = -ENOMEM;
+ goto err3;
+ }
+
+ srp.iram = ioremap(SRP_IRAM_BASE, IRAM_SIZE);
+ if (srp.iram == NULL) {
+ srp_err("Failed to ioremap for sram area\n");
+ ret = -ENOMEM;
+ goto err4;
+ }
+
+ srp.clk = clk_get(&pdev->dev, "srpclk");
+ if (IS_ERR(srp.clk)) {
+ dev_err(&pdev->dev, "failed to get srp clock\n");
+ ret = PTR_ERR(srp.clk);
+ goto err5;
+ }
+ clk_enable(srp.clk);
+
+ ret = srp_prepare_fw_buff(&pdev->dev);
+ if (ret) {
+ srp_err("SRP: Can't prepare memory for srp\n");
+ goto err6;
+ }
+
+ ret = request_irq(IRQ_AUDIO_SS, srp_irq, IRQF_DISABLED, "samsung-rp", pdev);
+ if (ret < 0) {
+ srp_err("SRP: Fail to claim SRP(AUDIO_SS) irq\n");
+ goto err7;
+ }
+
+ ret = misc_register(&srp_miscdev);
+ if (ret) {
+ srp_err("SRP: Cannot register miscdev on minor=%d\n",
+ SRP_DEV_MINOR);
+ goto err8;
+ }
+
+ srp_prepare_buff(&pdev->dev);
+
+ return 0;
+
+err8:
+ free_irq(IRQ_AUDIO_SS, pdev);
+err7:
+ srp_remove_fw_buff(&pdev->dev);
+err6:
+ clk_put(srp.clk);
+err5:
+ iounmap(srp.iram);
+err4:
+ iounmap(srp.commbox);
+err3:
+ iounmap(srp.dmem);
+err2:
+ release_mem_region(commbox_base, resource_size(commbox_res));
+err1:
+ release_mem_region(int_mem_base, resource_size(int_mem_res));
+
+ return ret;
+}
+
+static __devexit int srp_remove(struct platform_device *pdev)
+{
+ free_irq(IRQ_AUDIO_SS, pdev);
+ srp_remove_fw_buff(&pdev->dev);
+
+ misc_deregister(&srp_miscdev);
+
+ iounmap(srp.commbox);
+ iounmap(srp.icache);
+ iounmap(srp.dmem);
+ iounmap(srp.iram);
+
+ return 0;
+}
+
+static struct platform_driver srp_driver = {
+ .probe = srp_probe,
+ .remove = srp_remove,
+ .suspend = srp_suspend,
+ .resume = srp_resume,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "samsung-rp",
+ },
+};
+
+static char banner[] __initdata =
+ KERN_INFO "Samsung SRP driver, (c)2011 Samsung Electronics\n";
+
+static int __init srp_init(void)
+{
+ printk(banner);
+
+ return platform_driver_register(&srp_driver);
+}
+
+static void __exit srp_exit(void)
+{
+ platform_driver_unregister(&srp_driver);
+}
+
+module_init(srp_init);
+module_exit(srp_exit);
+
+MODULE_AUTHOR("Yeongman Seo <yman.seo@samsung.com>");
+MODULE_DESCRIPTION("Samsung SRP driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/srp_alp/srp_alp.h b/sound/soc/samsung/srp_alp/srp_alp.h
new file mode 100644
index 0000000..7f6bd87e
--- /dev/null
+++ b/sound/soc/samsung/srp_alp/srp_alp.h
@@ -0,0 +1,203 @@
+#ifndef __SRP_ALP_H
+#define __SRP_ALP_H
+
+#define SRP_DEV_MINOR (250)
+
+/* Base address */
+#define SRP_IRAM_BASE (0x02020000)
+#define SRP_DMEM_BASE (0x03000000)
+#define SRP_IDMA_BASE (0x03000004)
+
+/* SRAM information */
+#define INT_MEM_SIZE (soc_is_exynos5250() ? \
+ (0x49000) : (0x39000))
+#define IRAM_SIZE ((soc_is_exynos4412() || soc_is_exynos4212()) ? \
+ (0x40000) : (0x20000))
+#define DMEM_SIZE (soc_is_exynos5250() ? \
+ (0x28000) : (0x20000))
+#define ICACHE_SIZE (soc_is_exynos5250() ? \
+ (0x18000) : (0x10000))
+#define CMEM_SIZE (0x9000)
+
+/* IBUF/OBUF Size */
+#define IBUF_SIZE (0x4000)
+#define WBUF_SIZE (IBUF_SIZE * 4)
+#define OBUF_SIZE (soc_is_exynos5250() ? \
+ (0x4000) : (0x8000))
+
+/* IBUF Offset */
+#if defined(CONFIG_ARCH_EXYNOS4)
+#define IBUF_OFFSET ((soc_is_exynos4412() || soc_is_exynos4212()) ? \
+ (0x30000) : (0x10000))
+#elif defined(CONFIG_ARCH_EXYNOS5)
+#define IBUF_OFFSET (0x8004)
+#endif
+
+/* OBUF Offset */
+#if defined(CONFIG_ARCH_EXYNOS4)
+#define OBUF_OFFSET (0x4)
+#elif defined(CONFIG_ARCH_EXYNOS5)
+#define OBUF_OFFSET (0x10004)
+#endif
+
+/* SRP Input/Output buffer physical address */
+#if defined(CONFIG_ARCH_EXYNOS4)
+#define SRP_IBUF_PHY_ADDR (SRP_IRAM_BASE + IBUF_OFFSET)
+#elif defined(CONFIG_ARCH_EXYNOS5)
+#define SRP_IBUF_PHY_ADDR (SRP_DMEM_BASE + IBUF_OFFSET)
+#endif
+#define SRP_OBUF_PHY_ADDR (SRP_DMEM_BASE + OBUF_OFFSET)
+
+/* IBUF/OBUF NUM */
+#define IBUF_NUM (0x2)
+#define OBUF_NUM (0x2)
+#define START_THRESHOLD (IBUF_SIZE * 3)
+
+/* Commbox & Etc information */
+#define COMMBOX_SIZE (0x200)
+
+/* Reserved memory on DRAM */
+#define BASE_MEM_SIZE (CONFIG_AUDIO_SAMSUNG_MEMSIZE_SRP << 10)
+#define BITSTREAM_SIZE_MAX (0x7FFFFFFF)
+
+/* F/W Endian Configuration */
+#ifdef USE_FW_ENDIAN_CONVERT
+#define ENDIAN_CHK_CONV(VAL) \
+ (((VAL >> 24) & 0x000000FF) | \
+ ((VAL >> 8) & 0x0000FF00) | \
+ ((VAL << 8) & 0x00FF0000) | \
+ ((VAL << 24) & 0xFF000000))
+#else
+#define ENDIAN_CHK_CONV(VAL) (VAL)
+#endif
+
+/* For Debugging */
+#ifdef CONFIG_SND_SAMSUNG_RP_DEBUG
+#define srp_info(x...) pr_info("SRP: " x)
+#define srp_debug(x...) pr_debug("SRP: " x)
+#define srp_err(x...) pr_err("SRP_ERR: " x)
+#else
+#define srp_info(x...)
+#define srp_debug(x...)
+#define srp_err(x...)
+#endif
+
+/* For SRP firmware */
+struct srp_fw_info {
+ unsigned char *vliw; /* VLIW */
+ unsigned char *cga; /* CGA */
+ unsigned char *data; /* DATA */
+
+ unsigned int mem_base; /* Physical address of base */
+ unsigned int vliw_pa; /* Physical address of VLIW */
+ unsigned int cga_pa; /* Physical address of CGA */
+ unsigned int data_pa; /* Physical address of DATA */
+ unsigned long vliw_size; /* Size of VLIW */
+ unsigned long cga_size; /* Size of CGA */
+ unsigned long data_size; /* Size of DATA */
+};
+
+/* OBUF/IBUF information */
+struct srp_buf_info {
+ void *mmapped_addr;
+ void *addr;
+ unsigned int mmapped_size;
+ unsigned int size;
+ int num;
+};
+
+/* Decoding information */
+struct srp_dec_info {
+ unsigned int sample_rate;
+ unsigned int channels;
+};
+
+struct srp_for_suspend {
+ unsigned char *ibuf;
+ unsigned char *obuf;
+ unsigned char *commbox;
+};
+
+struct srp_info {
+ struct srp_buf_info ibuf_info;
+ struct srp_buf_info obuf_info;
+ struct srp_buf_info pcm_info;
+
+ struct srp_fw_info fw_info;
+ struct srp_dec_info dec_info;
+ struct srp_for_suspend sp_data;
+ struct clk *clk;
+
+ void __iomem *iram;
+ void __iomem *dmem;
+ void __iomem *icache;
+ void __iomem *cmem;
+ void __iomem *commbox;
+
+ /* IBUF informaion */
+ unsigned char *ibuf0;
+ unsigned char *ibuf1;
+ unsigned int ibuf0_pa;
+ unsigned int ibuf1_pa;
+ unsigned int ibuf_num;
+ unsigned long ibuf_size;
+ unsigned long ibuf_offset;
+ unsigned int ibuf_next;
+ unsigned int ibuf_empty[2];
+
+ /* OBUF informaion */
+ unsigned char *obuf0;
+ unsigned char *obuf1;
+ unsigned int obuf0_pa;
+ unsigned int obuf1_pa;
+ unsigned int obuf_num;
+ unsigned long obuf_size;
+ unsigned long obuf_offset;
+ unsigned int obuf_fill_done[2];
+ unsigned int obuf_copy_done[2];
+ unsigned int obuf_ready;
+ unsigned int obuf_next;
+
+ /* For EVT0 : will be removed on EVT1 */
+ unsigned char *pcm_obuf0;
+ unsigned char *pcm_obuf1;
+
+ /* Temporary BUF informaion */
+ unsigned char *wbuf;
+ unsigned long wbuf_size;
+ unsigned long wbuf_pos;
+ unsigned long wbuf_fill_size;
+
+ /* Decoding informaion */
+ unsigned long set_bitstream_size;
+ unsigned long pcm_size;
+
+ /* SRP status information */
+ unsigned int decoding_started;
+ unsigned int is_opened;
+ unsigned int is_running;
+ unsigned int is_pending;
+ unsigned int block_mode;
+ unsigned int stop_after_eos;
+ unsigned int wait_for_eos;
+ unsigned int prepare_for_eos;
+ unsigned int play_done;
+ unsigned int idma_addr;
+
+ bool pm_suspended;
+ bool pm_resumed;
+};
+
+/* SRP Pending On/Off status */
+enum {
+ RUN = 0,
+ STALL,
+};
+
+/* Request Suspend/Resume */
+enum {
+ SUSPEND = 0,
+ RESUME = 1,
+};
+
+#endif /* __SRP_ALP_H */
diff --git a/sound/soc/samsung/srp_alp/srp_alp_error.h b/sound/soc/samsung/srp_alp/srp_alp_error.h
new file mode 100644
index 0000000..6bfcff8
--- /dev/null
+++ b/sound/soc/samsung/srp_alp/srp_alp_error.h
@@ -0,0 +1,22 @@
+#ifndef _SRP_ALP_ERROR_H_
+#define _SRP_ALP_ERROR_H_
+
+enum {
+ SRP_RETURN_OK = 0,
+
+ SRP_ERROR_OPEN_FAIL = -1000,
+ SRP_ERROR_ALREADY_OPEN = -1001,
+ SRP_ERROR_NOT_READY = -1002,
+
+ SRP_ERROR_IBUF_OVERFLOW = -2000,
+ SRP_ERROR_IBUF_INFO = -2001,
+
+ SRP_ERROR_OBUF_READ = -3000,
+ SRP_ERROR_OBUF_INFO = -3001,
+ SRP_ERROR_OBUF_MMAP = -3002,
+
+ SRP_ERROR_INVALID_SETTING = -4000,
+ SRP_ERROR_GETINFO_FAIL = -4001
+} SRP_ERRORTYPE;
+
+#endif /* _SRP_ALP_ERROR_H_ */
diff --git a/sound/soc/samsung/srp_alp/srp_alp_fw.h b/sound/soc/samsung/srp_alp/srp_alp_fw.h
new file mode 100644
index 0000000..ce410b7
--- /dev/null
+++ b/sound/soc/samsung/srp_alp/srp_alp_fw.h
@@ -0,0 +1,13671 @@
+/* sound/soc/samsung/srp_alp/srp_alp_fw.h
+ *
+ * SRP Audio Firmware for Samsung Exynos
+ *
+ * Copyright (c) 2011 Samsung Electronics
+ * http://www.samsungsemi.com/
+ *
+ * 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.
+*/
+
+#include <linux/init.h>
+
+/* SRP Firmeware */
+
+#if defined(CONFIG_ARCH_EXYNOS4)
+/* vliw */
+static unsigned long srp_fw_vliw[] __devinitdata = {
+0xd2000143,0x00000003,0x00000003,0x00000003,0x00000003,0x00000003,0x00000003,0x00000003,
+0x00000003,0x00000003,0x00000003,0x00000003,0x00000003,0x00000000,0x00000000,0x00000001,
+0xd2000167,0x00000003,0x00000003,0x00000003,0x00000003,0x00000003,0x00000003,0x00000003,
+0x00000003,0x00000003,0x00000003,0x00000003,0x00000003,0x00000000,0x00000000,0x00000001,
+0xd200015b,0x00000003,0x00000003,0x00000003,0x00000003,0x00000003,0x00000003,0x00000003,
+0x00000003,0x00000003,0x00000003,0x00000003,0x00000003,0x00000000,0x00000000,0x00000001,
+0xd200014f,0x00000003,0x00000003,0x00000003,0x00000003,0x00000003,0x00000003,0x00000003,
+0x00000003,0x00000003,0x00000003,0x00000003,0x00000003,0x00000000,0x00000000,0x00000001,
+0xd2000143,0x00000003,0x00000003,0x00000003,0x00000003,0x00000003,0x00000003,0x00000003,
+0x00000003,0x00000003,0x00000003,0x00000003,0x00000003,0x00000000,0x00000000,0x00000001,
+0xc2fc001d,0xc300011d,0x10920740,0x10900740,0x10924741,0xd1008dfb,0x07800001,0x07000103,
+0x07000101,0x00400202,0xf0000003,0x07000103,0xf1000003,0x07000103,0xff000003,0x07000103,
+0x00528201,0x07000100,0x12828a09,0x00408a02,0x00528200,0xc1fffd2d,0x07000101,0x02928a2d,
+0x00408a01,0x10900081,0xc200f8fc,0x900000f8,0x900040fd,0xd200010c,0x009000fc,0xc20100fd,
+0xc2e03cf8,0x9001c01c,0x90008009,0xc30001f8,0xc2e03408,0x0081c0fd,0x10900081,0xc200f8fc,
+0x900000f8,0x900040fd,0xd20000d8,0x009000fc,0xc20100fd,0xc2e040f8,0x9001c01c,0x90008009,
+0xc30001f8,0xc2e03408,0x0081c0fd,0x10900081,0xc200f8fc,0x900000f8,0x900040fd,0xd20000a4,
+0x009000fc,0xc20100fd,0xc2e044f8,0x9001c01c,0x90008009,0xc30001f8,0xc2e03408,0x0081c0fd,
+0x10900081,0xc200f8fc,0x900000f8,0x900040fd,0xc20014f9,0xc30382f9,0x00000000,0xb8003efb,
+0x00000001,0xe8000030,0x129fbe05,0x14103e01,0xd2000050,0x009000fc,0xc20100fd,0xc2e048f8,
+0x9001c01c,0x90008009,0xc30001f8,0xc2e03408,0x0081c0fd,0xc20020f9,0xc30382f9,0x00000000,
+0xb8003e1f,0x00000001,0xc20024f9,0xc30382f9,0x00000000,0xb8003e03,0x00000001,0xd20003c3,
+0xc3000108,0x9000c00c,0x90010011,0xc2e0380c,0xb8000208,0xb8003ef9,0x00510200,0xc300010c,
+0x90014015,0x10814080,0x90018018,0x90004005,0x00118400,0x90000520,0x90004525,0x12908208,
+0x90008528,0x9000c52d,0x00508300,0x90010530,0x90014535,0x00124000,0x90018538,0x9001c53d,
+0x00508000,0x10814580,0x90004709,0x00508100,0x90000710,0x90008709,0x00508400,0x00113e00,
+0x9000c709,0x0050bf00,0xb800030c,0x90010709,0x02818608,0x1081c760,0x90014709,0x00408600,
+0x90000540,0x90004545,0x10814540,0x90008548,0x9000c54d,0xe1000124,0x90000550,0x90004555,
+0xc2001808,0x90008558,0x9000c55d,0x04e0020c,0x9000001c,0x00120001,0xc2002058,0xc200245d,
+0xc3038258,0xc303825d,0x00000000,0x9000161c,0x90001701,0xe20000e4,0x90010560,0x90014565,
+0x10814580,0x90018568,0x9001c56d,0x10808220,0x90000570,0x90004575,0x04e0020c,0x90008578,
+0x9000c57d,0xe20000b4,0x90010580,0x90014585,0x10814580,0x90018588,0x9001c58d,0x10808220,
+0x90000590,0x90004595,0x04e0020c,0x90008598,0x9000c59d,0xe2000084,0x900105a0,0x900145a5,
+0x10814580,0x900185a8,0x9001c5ad,0x10808220,0x900005b0,0x900045b5,0x04e0020c,0x900085b8,
+0x9000c5bd,0xe2000054,0x900105c0,0x900145c5,0x10814580,0x900185c8,0x9001c5cd,0x10808220,
+0x900005d0,0x900045d5,0x04e0020c,0x900085d8,0x9000c5dd,0x10808220,0x900105e0,0x900145e5,
+0x10814580,0x900185e8,0x9001c5ed,0x00000000,0x900005f0,0x900045f5,0x07104400,0x00108003,
+0x00000000,0xc2e0380c,0x10910781,0xc300010c,0xb8008418,0xb801843d,0xc1001808,0xb800030c,
+0xb800c431,0x108140f0,0xb8010434,0xb8014439,0xe200012c,0xb8004540,0xb8008545,0x10814550,
+0xb800c548,0xb801054d,0x00000000,0xb8000550,0xb8004555,0x04e0020c,0xb8008558,0xb800c55f,
+0x00000001,0xe20000f8,0xb8010560,0xb8014565,0x10814580,0xb8018568,0xb801c56d,0x10808220,
+0xb8000570,0xb8004575,0x04e0020c,0xb8008578,0xb800c57f,0x00000001,0xe20000c4,0xb8010580,
+0xb8014585,0x10814580,0xb8018588,0xb801c58d,0x10808220,0xb8000590,0xb8004595,0x04e0020c,
+0xb8008598,0xb800c59f,0x00000001,0xe2000090,0xb80105a0,0xb80145a5,0x10814580,0xb80185a8,
+0xb801c5ad,0x10808220,0xb80005b0,0xb80045b5,0x04e0020c,0xb80085b8,0xb800c5bf,0x00000001,
+0xe200005c,0xb80105c0,0xb80145c5,0x10814580,0xb80185c8,0xb801c5cd,0x10808220,0xb80005d0,
+0xb80045d5,0x04e0020c,0xb80085d8,0xb800c5df,0x00000001,0x00000000,0xb80105e0,0xb80145e5,
+0x10814580,0xb80185e8,0xb801c5ed,0x00000000,0xb80005f0,0xb80045f7,0x00000001,0x00000000,
+0xb80085f8,0xb800c5fd,0x00000000,0x1080c080,0xb801c411,0x0040cc00,0xb8000320,0xb8004325,
+0x00400d00,0xb8008328,0xb800c32d,0x00404e00,0xb8010330,0xb8014335,0x00410f00,0xb8018338,
+0xb801c33d,0x004fc400,0xb8014014,0xb801c01d,0x00000000,0xb800c00c,0xb8010011,0x00000000,
+0xb8008008,0xb8018019,0x00000000,0xb8000000,0xb8004007,0x00000001,0x07300003,0xc20188f9,
+0xc30382f9,0x00000000,0xb8003eff,0x00000001,0xc2ffbff5,0xc3fffff5,0x029ffff5,0x00000000,
+0x90003efd,0x00000000,0xc2e0380c,0x10910781,0xc300010c,0xb8008418,0xb801843d,0xc1001808,
+0xb800030c,0xb800c431,0x108140f0,0xb8010434,0xb8014439,0xe200012c,0xb8004540,0xb8008545,
+0x10814550,0xb800c548,0xb801054d,0x00000000,0xb8000550,0xb8004555,0x04e0020c,0xb8008558,
+0xb800c55f,0x00000001,0xe20000f8,0xb8010560,0xb8014565,0x10814580,0xb8018568,0xb801c56d,
+0x10808220,0xb8000570,0xb8004575,0x04e0020c,0xb8008578,0xb800c57f,0x00000001,0xe20000c4,
+0xb8010580,0xb8014585,0x10814580,0xb8018588,0xb801c58d,0x10808220,0xb8000590,0xb8004595,
+0x04e0020c,0xb8008598,0xb800c59f,0x00000001,0xe2000090,0xb80105a0,0xb80145a5,0x10814580,
+0xb80185a8,0xb801c5ad,0x10808220,0xb80005b0,0xb80045b5,0x04e0020c,0xb80085b8,0xb800c5bf,
+0x00000001,0xe200005c,0xb80105c0,0xb80145c5,0x10814580,0xb80185c8,0xb801c5cd,0x10808220,
+0xb80005d0,0xb80045d5,0x04e0020c,0xb80085d8,0xb800c5df,0x00000001,0x00000000,0xb80105e0,
+0xb80145e5,0x10814580,0xb80185e8,0xb801c5ed,0x00000000,0xb80005f0,0xb80045f7,0x00000001,
+0x00000000,0xb80085f8,0xb800c5fd,0x00000000,0x1080c080,0xb801c411,0x0040cc00,0xb8000320,
+0xb8004325,0x00400d00,0xb8008328,0xb800c32d,0x00404e00,0xb8010330,0xb8014335,0x00410f00,
+0xb8018338,0xb801c33d,0x004fc400,0xb8014014,0xb801c01d,0x00000000,0xb800c00c,0xb8010011,
+0x00000000,0xb8008008,0xb8018019,0x00000000,0xb8000000,0xb8004007,0x00000001,0x07300003,
+0x10924941,0x1081c940,0x9000891d,0x10924741,0x1091c741,0x00000000,0xb800871d,0x07000102,
+0x10824741,0x10924941,0x1081c940,0x9000891d,0x10924741,0x1091c741,0x00000000,0xb800871d,
+0x07000102,0x10824741,0x10924941,0x1081c940,0x9000891c,0xc1002425,0x00924725,0x001e4201,
+0xe8000051,0x0490020c,0xc10000e1,0x120f0305,0xe800001d,0x04b039f0,0xc10001ed,0x108efb05,
+0x020e83ed,0xe8fffff9,0x04d039e9,0xc1ffffe9,0xc10001e8,0x008efbe9,0x020ec3ec,0x020ebaed,
+0x008e38e8,0x009e79ed,0xe8ffffc9,0x04f0390d,0xe8000011,0x14000401,0x00000000,0x900004e5,
+0x0011b801,0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,0x10924941,0x1081c940,
+0x9000891c,0x9000c905,0x10900740,0x10924741,0xd1ffff5a,0xc1000011,0x1091c741,0x00000000,
+0xb800c704,0xb800871f,0x10824742,0x07000102,0x00100901,0x10924941,0x1081c940,0x9000891c,
+0x9000c905,0x10900771,0x10920740,0x90004920,0x10924771,0xd1ffff14,0xc1fffce1,0x008108e2,
+0xc1fffce1,0x00000000,0x034188e3,0x00000001,0x1091c741,0x00000000,0xb800c704,0xb8004723,
+0x00000001,0x00000000,0xb800871d,0x07000101,0x10824741,0x00100901,0x10924941,0x1081c940,
+0x9000891d,0x10924771,0xc20004e8,0xc20004e4,0xc10001e1,0xc30001e8,0xc30001e5,0x008e42e4,
+0x030182e9,0x00000000,0x800039e3,0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,
+0x1092497d,0x10924945,0x1081c97c,0x9000891c,0x9000c905,0x1081c744,0xc1005c25,0x00900724,
+0x00924725,0xc1ffece8,0xc1ffe8e0,0xc1ffe4e5,0xc1ffe0e0,0x034307e8,0x0342c7e1,0x00000000,
+0x034287e4,0x034fc7e3,0x00000001,0x109f4971,0x109f8950,0xc10000ec,0x109e8961,0xc10001f0,
+0x109e09a0,0x109e4981,0x109e8990,0x90003a2c,0x90003e31,0xd1000048,0xc10000e4,0x900039f1,
+0x109e09b0,0x90003d28,0x900038e5,0x00000000,0x90003aec,0x900038fd,0x1091c77d,0x1091c745,
+0x00000000,0xb800c704,0xb800871f,0x1082477e,0x07000101,0x10824945,0x00100901,0x1092497d,
+0x10924975,0x1081c97c,0x9000891c,0x9000c905,0x1081c774,0xc1007025,0x00900724,0x00924725,
+0x00000000,0x9001c06c,0x90020071,0x00000000,0x90014064,0x90018069,0x00000000,0x9000c05c,
+0x90010061,0x00000000,0x90004054,0x90008059,0x00000000,0x90000051,0xc1ffe4e8,0xc1ffe8e0,
+0xc1ffeced,0xc1ffd8e0,0x034687e0,0xc1ffe0e5,0xc1ffdce4,0x0346c7ec,0x034607e5,0xc1ffd4e0,
+0x034647e8,0x034547e1,0x00000000,0x0345c7e4,0x034507e2,0x00158201,0x00170401,0xe8000061,
+0x14100201,0xc1ffff19,0x1091c77d,0x1091c774,0xb8004055,0x00000000,0xb800c704,0xb8010061,
+0x00000000,0xb8000050,0xb800c05d,0x00000000,0xb801c06c,0xb8020071,0x00000000,0xb8008058,
+0xb8018069,0x1082477c,0xb8014064,0xb800871d,0x07000101,0x10824975,0x00100901,0xe8000039,
+0x14000301,0xe8000065,0x14000305,0xe800006d,0x14000315,0xe8000075,0x14000309,0xe800007d,
+0x1400030d,0xe8000099,0x14000311,0xd2ffff7e,0xc1ffff19,0xc10e00e1,0x00000000,0x900142e1,
+0xe80000a5,0x14000401,0xe8000099,0x14000405,0xe8000129,0x14000409,0xe8000129,0x1400040d,
+0xd2ffff4a,0xc1ffff19,0xd2ffffd8,0xc10d00e1,0x00000000,0x900142e2,0xd2ffffc8,0xc10c00e1,
+0x00000000,0x900142e2,0xd2ffffb8,0xc10f00e1,0x00000000,0x900142e2,0xc20c00e0,0x129e453d,
+0xc30400e0,0x120e7971,0xd2ffff98,0x001e3801,0x028e38e5,0x00000000,0x900142e1,0xc20c00e0,
+0x129e453d,0xc30200e0,0x120e7971,0xd2ffff74,0x001e3801,0x028e38e5,0x00000000,0x900142e1,
+0x12165905,0xd10008c8,0x00109403,0x109e1804,0x129e94f0,0x109e5905,0x120eb840,0x120e1740,
+0x028efa19,0x00000000,0x028e7ae4,0x028e3855,0x00000000,0x9000d6e4,0x900016ed,0xe800006c,
+0x9000566c,0x900116e1,0x14001400,0x90009669,0xc10001e1,0x129eb804,0xc20000e4,0x129e1c0d,
+0x120eba50,0xb80156e0,0xc30001e5,0x120e7838,0x028ebae4,0xc23000e1,0x00000000,0x028e7ae5,
+0xd2fffe48,0x00000000,0x028e79e1,0x028e38e5,0xc1000018,0x900156e1,0xd2ffff6e,0x12165909,
+0xd2ffff66,0x1216590d,0xd2ffffae,0xc10000e1,0x10924941,0x1081c940,0x9000891c,0x9000c905,
+0x10900770,0x10924771,0x00000000,0x90000050,0x90004055,0x00154200,0x00150301,0xc10000e1,
+0xe8000019,0x04c03809,0xe8000011,0x14c0021d,0xe8000035,0x14100301,0xc1ffff19,0x1091c741,
+0x00000000,0xb800c704,0xb800871f,0x10824741,0x00000000,0xb8004054,0xb8000051,0x07000102,
+0x00100901,0xd1000647,0xd1fffbf0,0x00109503,0xd1000488,0x00109500,0x0010d403,0xd2ffffc2,
+0xc1000019,0x10924941,0x1081c940,0x9000c904,0x9000891d,0xc1004824,0x90004920,0x10920741,
+0x00900724,0x00924725,0x00000000,0x90000050,0x90004055,0x00154201,0x109e0961,0xc1ffe0ec,
+0xc10000e4,0x109e8951,0x120e8508,0x90003a10,0x008088ed,0xd1fffbcc,0x109e0970,0x9000380d,
+0x109e0980,0x900038e8,0xc100000d,0xc1000210,0x900038e4,0xc1000015,0xe8000021,0x14100600,
+0x00150601,0xd1fffeec,0xc1ffe0e1,0x00109500,0x0080c8e2,0x00150601,0x00119401,0x1091c741,
+0x00000000,0xb800c704,0xb8004723,0x00000000,0xb8004055,0x00000000,0xb8000050,0xb800871d,
+0x07000101,0x10824741,0x00100901,0x10924941,0x1081c940,0x9000c904,0x9000891d,0xc1004824,
+0x90004920,0x10920741,0x00900724,0x00924725,0x00000000,0x90000050,0x90004055,0x00154201,
+0x109e0961,0xc1ffe0ec,0xc10000e4,0x109e8951,0x120e8508,0x90003a10,0x008088ed,0xd1fffb04,
+0x109e0970,0x9000380d,0x109e0980,0x900038e8,0xc100050d,0xc1000210,0x900038e4,0xc1000015,
+0xe8000021,0x14100600,0x00150601,0xd1fffe24,0xc1ffe0e1,0x00109500,0x0080c8e2,0x00150601,
+0x00119401,0x1091c741,0x00000000,0xb800c704,0xb8004723,0x00000000,0xb8004055,0x00000000,
+0xb8000050,0xb800871d,0x07000101,0x10824741,0x00100901,0x10924941,0x1081c940,0x9000c904,
+0x9000891d,0xc1004824,0x90004920,0x10920741,0x00900724,0x00924725,0x00000000,0x90000050,
+0x90004055,0x00154201,0x109e0961,0xc1ffe0ec,0xc10000e4,0x109e8951,0x120e8508,0x90003a10,
+0x008088ed,0xd1fffa3c,0x109e0970,0x9000380d,0x109e0980,0x900038e8,0xc100010d,0xc1000210,
+0x900038e4,0xc1000015,0xe8000021,0x14100600,0x00150601,0xd1fffd5c,0xc1ffe0e1,0x00109500,
+0x0080c8e2,0x00150601,0x00119401,0x1091c741,0x00000000,0xb800c704,0xb8004723,0x00000000,
+0xb8004055,0x00000000,0xb8000050,0xb800871d,0x07000101,0x10824741,0x00100901,0x10924941,
+0x1081c940,0x9000891d,0x10924751,0xc2f000e1,0xc3000fe1,0x00000000,0xb800381b,0x00000001,
+0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,0x10924941,0x1081c940,0x9000891d,
+0x10924761,0xc2f000e4,0xc2f000e1,0xc3000fe4,0xc3000fe1,0x00000000,0xb8003919,0x00000000,
+0x9000380b,0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,0x10924941,0x1081c940,
+0x9000891c,0xc1002425,0x00924725,0x001e0200,0x001f0301,0x00000000,0xa00038ec,0xa0003ceb,
+0x00000001,0x009e7be9,0xe8000021,0x14103900,0x108f3c04,0x108e3805,0xe8000011,0x14003b01,
+0xe8ffffd5,0x14103a01,0x0011b901,0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,
+0x10924941,0x1081c940,0x9000891d,0x10924771,0x00000000,0xa00002e3,0x00000001,0xe800002d,
+0x14003800,0xc10000e8,0x001e4201,0x00000000,0xa00079e3,0x00000001,0xe8fffff5,0x14103800,
+0x108eba04,0x108e7905,0x0011ba01,0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,
+0x10924941,0x1081c940,0x9000891d,0x10924771,0x00000000,0xa00003e3,0x00000001,0xe8000034,
+0x800002e1,0x14003800,0x108e8304,0x108e4205,0x00000000,0xa0003ae3,0x00000001,0xe8fffff4,
+0x800039e1,0x14103800,0x108eba04,0x108e7905,0x00118201,0x1091c741,0x00000000,0xb800871d,
+0x07000102,0x10824741,0x10924941,0x1081c940,0x9000891c,0xc1002025,0x00924725,0x001ec200,
+0x001e8301,0xe800003d,0x14000401,0x109e4405,0x00000000,0xa0003ae3,0x00000001,0xe8000024,
+0x80003be1,0x14003800,0x108eba04,0x108efb05,0xc1ffffe1,0x008e79e1,0xe8ffffd9,0x141039fd,
+0x00118201,0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,0x10924941,0x00000000,
+0x9000891d,0x1081c940,0x9000c904,0xc1002c25,0x00900724,0x00924725,0x00000000,0x90000050,
+0x90004055,0x00154200,0x00150301,0xc20004e0,0xc10101e4,0xc21118e9,0xd10002d4,0xc3000fe8,
+0xc30001e1,0xc10001e0,0x008e42e0,0x020ef909,0x00108300,0x90003aec,0x800039e1,0xc21000e0,
+0x129e54f0,0x120ed515,0xc21000e8,0xc3000fe0,0x028f3919,0xc3000fe8,0xc10003e0,0x008e7be1,
+0x008e7be8,0x900039f1,0x00000000,0x900179e1,0x1091c741,0x00000000,0xb800c704,0xb800871f,
+0x10824741,0x00000000,0xb8004054,0xb8000051,0x07000102,0x00100901,0x10924941,0x1081c940,
+0x9000891c,0xc1002c25,0x00924725,0x001f8201,0xc20004e0,0xc10100e5,0xc30001e0,0x020f7909,
+0x00000000,0x030e02e3,0x00000001,0xe80000a9,0x14003801,0xc21110e1,0xc3000fe1,0x00000000,
+0xb80038e3,0x00000001,0xc10000e0,0x029e78f5,0xe8000031,0x041038e5,0xc21110e9,0xc3000fe9,
+0x001eba01,0x00000000,0xb8003ae3,0x00000001,0xc10000e0,0x029e78f5,0xe8ffffed,0x040038e5,
+0xc21000e8,0xc10014e4,0x120efe15,0xc3000fe8,0xc21118f0,0xc10000e1,0xc3000ff0,0x008e79e9,
+0x00000000,0x90003cf4,0x034e79ef,0x00000001,0x129e7905,0xe8000021,0x041038e5,0xc20004e4,
+0xc10000e1,0xc30001e5,0x008e7ee5,0x00000000,0x800039e1,0x1091c741,0x00000000,0xb800871d,
+0x07000102,0x10824741,0x10924941,0x1081c940,0x9000891c,0xc1002025,0x00924725,0x001ec201,
+0xc21000e4,0x120e8215,0xc10014e0,0xc3000fe5,0x008e78e5,0x00000000,0x034e39eb,0x00000001,
+0x129e3805,0xe8000021,0x14003801,0x00000000,0x034e39eb,0x00000001,0x129e3805,0xe8fffff1,
+0x14103801,0xc20004e4,0xc10000e1,0xc30001e5,0x008e7be5,0x00000000,0x800039e1,0x1091c741,
+0x00000000,0xb800871d,0x07000102,0x10824741,0x10924941,0x1081c940,0x9000891d,0x10924741,
+0x00000000,0xa800021b,0x00000001,0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,
+0x10924941,0x1081c940,0x9000891d,0x10924741,0x00000000,0x8400020d,0x1091c741,0x00000000,
+0xb800871d,0x07000102,0x10824741,0x10924941,0x1081c940,0x9000891d,0x10924741,0x00000000,
+0xb800021b,0x00000001,0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,0x10924941,
+0x1081c940,0x9000891d,0x10924741,0x00000000,0x9000020d,0x1091c741,0x00000000,0xb800871d,
+0x07000102,0x10824741,0x10924941,0x1081c940,0x9000891d,0x10924741,0x1091c741,0x00000000,
+0xb800871d,0x07000102,0x10824741,0x10924941,0x1081c940,0x9000891d,0x10924761,0xc20000e1,
+0xc30000e1,0xe8000019,0x04c03808,0xc10000e5,0xc20000e1,0xc30002e1,0x018e42e1,0xc10000e1,
+0x0101b8e5,0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,0x10924941,0x1081c940,
+0x9000891d,0x10924761,0xc20020e0,0xc1000119,0xc30383e1,0xc10080e0,0x001e7801,0x00000000,
+0x900039e1,0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,0x10924941,0x1081c940,
+0x9000891d,0x10924761,0xe8000039,0x14100205,0xc10001e1,0xc20020e0,0x120e781d,0xc30383e1,
+0x001e3801,0x00000000,0x900038e5,0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,
+0xd2ffffd6,0xc10000e1,0x10924941,0x1081c940,0x9000891c,0xc1002025,0x00924725,0xe8000045,
+0x14100205,0xc10001ed,0x120ebb18,0x120e7b14,0xc20020e1,0xc30383e0,0x028e7ae5,0x001e3800,
+0x028e79ed,0x00000000,0x900038e5,0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,
+0xd2ffffca,0xc10000ed,0x10924941,0x1081c940,0x9000891c,0xc1002425,0x00924725,0xe8000099,
+0x14100505,0xc10001e1,0xc20000e0,0xc20024e4,0x120eb81d,0xc30300e0,0xc30383e4,0xc20040ed,
+0x001e7800,0xc10040e0,0x001f3901,0xc30383ec,0x028e79e8,0xc20028e9,0xc10020e0,0x90003c08,
+0x028e79e1,0x001f3b00,0x121ec408,0xc30383e9,0xc20020e0,0x90003c0c,0x028e79e1,0x120efb40,
+0x001eba00,0x128e7921,0xc30383e0,0x90003aec,0x128e7905,0x001e3801,0x00000000,0x900038e5,
+0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,0xd2ffff76,0xc10000e1,0x10924941,
+0x00000000,0x9000891d,0x1081c940,0x9000c904,0xc1002025,0x00900724,0x00924725,0x00000000,
+0x90000050,0x90004055,0x00154300,0x00150401,0xd1ffe993,0xe8000061,0x14001501,0xc2e034e4,
+0xc10001e1,0xc30001e5,0x00000000,0x900039e1,0x108e540c,0xc2e038e1,0x121e7908,0xc30001e1,
+0x120e7909,0x00000000,0x900038e5,0x1091c741,0x00000000,0xb800c704,0xb800871f,0x10824741,
+0x00000000,0xb8004054,0xb8000051,0x07000102,0x00100901,0xd2ffffbc,0xc2e034e5,0xc30001e4,
+0xc10000e1,0x00000000,0x900039e1,0x10924941,0x1081c940,0x9000891d,0x10924751,0xc2e03ce1,
+0xc30001e1,0x00000000,0x90003809,0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,
+0x10924941,0x1081c940,0x9000891d,0x10924751,0xc2e040e1,0xc30001e1,0x00000000,0x90003809,
+0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,0x10924941,0x1081c940,0x9000891d,
+0x10924751,0xc2e044e1,0xc30001e1,0x00000000,0x90003809,0x1091c741,0x00000000,0xb800871d,
+0x07000102,0x10824741,0x10924941,0x1081c940,0x9000891d,0x10924751,0xc2e048e1,0xc30001e1,
+0x00000000,0x90003809,0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,0x10924941,
+0x1081c940,0x9000891d,0x10924741,0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,
+0x10924941,0x1081c940,0x9000891d,0x10924741,0x1091c741,0x00000000,0xb800871d,0x07000102,
+0x10824741,0x10924941,0x1081c940,0x9000891d,0x10924741,0x1091c741,0x00000000,0xb800871d,
+0x07000102,0x10824741,0x10924941,0x1081c940,0x9000891d,0x10924741,0x1091c741,0x00000000,
+0xb800871d,0x07000102,0x10824741,0x10924941,0x1081c940,0x9000c904,0x9000891d,0xc1004c24,
+0x90004920,0x10920741,0x00900724,0x00924725,0xc20074e5,0xe80000d0,0xc10001e0,0xc3000fe5,
+0x14100200,0x900039e1,0xc20120e0,0xc20000e8,0x109ec871,0xc30382e0,0xc30003e8,0x109e4861,
+0x00000000,0xb80038e0,0x900039ea,0xd1fffba2,0xc1000008,0x90003be1,0xc20023e8,0xc20100e4,
+0xc2be80e1,0xc300ffe8,0xc30090e4,0xc30001e1,0x109f8880,0x001f7a00,0x109f0851,0x001ef900,
+0x109e8840,0x001e7801,0x109e0830,0x90003cf4,0x90003e19,0x00000000,0x900038e4,0x90003aed,
+0xd1fff330,0xc1ffe0e1,0x00000000,0x0080c8e1,0xc1000009,0xd1fff9d6,0xc1000009,0x1091c741,
+0x00000000,0xb800c704,0xb8004723,0x00000001,0x00000000,0xb800871d,0x07000101,0x10824741,
+0x00100901,0xc20100ec,0xc20000e4,0x109e8871,0xc30382ec,0xc30003e4,0x109e0861,0x00000000,
+0xb8003be0,0x900038e6,0xd1fffae6,0xc1000008,0x90003ae1,0xc2be80e1,0xc20023e4,0xc30001e0,
+0xc20100e9,0xc300ffe4,0x109f0850,0xc30090e9,0x109f4880,0x001e7800,0x001e3901,0xd2ffff64,
+0x109e8840,0x001efa01,0x109e0830,0x90003ce0,0x90003d19,0x00000000,0x900038e4,0x90003aed,
+0x10924941,0x1081c940,0x9000c904,0x9000891d,0xc1005824,0x90004920,0x10920741,0x00900724,
+0x00924725,0x00000000,0x90008058,0x9000c05d,0x00000000,0x90000050,0x90004055,0xc20004e4,
+0xc100005d,0xc30001e5,0x001e7901,0x1085d704,0xc10000e1,0xe8fffff8,0x800039e1,0x14801720,
+0x108e7905,0xc21100e4,0xc2000050,0xc10001e1,0xc3000fe4,0xc2011858,0xc3000051,0xc3038258,
+0x900039e1,0xc100005c,0x00151400,0xc1000055,0xc1ffe0e0,0xb80016e8,0x109f4951,0x109f0960,
+0xc10400ec,0x109e8971,0xc10000e4,0x109e0980,0x008088e1,0xd1ffee6c,0x90003aec,0xc100000d,
+0xc1000210,0x90003c50,0x008e95e9,0xc1000014,0x900038e4,0x90003de9,0xd1fff198,0xc1ffe0e1,
+0x00000000,0x0080c8e1,0xc1000009,0x1085d704,0xc10080e0,0xc10400e5,0xe8ffff98,0xc10400e4,
+0x008555e5,0x048017e0,0x008514e5,0x1091c741,0x00000000,0xb800c704,0xb8008059,0x00000000,
+0xb800c05c,0xb8004722,0x00000000,0xb8004055,0x00000000,0xb8000050,0xb800871d,0x07000101,
+0x10824741,0x00100901,0x10924941,0x1081c940,0x9000891d,0x10924741,0x1091c741,0x00000000,
+0xb800871d,0x07000102,0x10824741,0x10924941,0x1081c940,0x9000891c,0xc1003025,0x00924725,
+0xc20014fc,0xc20010ed,0xc20018f4,0xc10000f8,0xc20028e5,0xc30001fc,0xc30001ec,0xc30001f5,
+0xc10000f0,0xc10000e0,0xc10000e9,0xc30001e4,0x90003df0,0x90003ff9,0xc1000018,0x840039e0,
+0x80003be9,0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,0x10924941,0x00000000,
+0x9000891d,0x1081c940,0x9000c904,0xc1003025,0x00900724,0x00924725,0x00000000,0x90000050,
+0x90004055,0x00154200,0x00150401,0xc20028e1,0xc30001e1,0x00000000,0xa80038e3,0x00000001,
+0xe8000089,0x14103801,0xc2001ce0,0xc20020e9,0xc30382e0,0xb80102f0,0xc30001e9,0x00000000,
+0xb80038e1,0xc1ff9fec,0xc10001e0,0xc20028e5,0xc30001e4,0x00000000,0xc100000d,0x129e7c0c,
+0x840039e0,0xc1000711,0x120e3914,0x029e78ec,0xc1000115,0x028eb9e0,0x90003ae5,0x00000000,
+0xb80142e7,0xc2ffffe1,0x029e39e1,0xd1007438,0xc2001ce0,0x120e7839,0xc30382e0,0x028e7ae5,
+0xc1000408,0x900038e5,0x00000000,0xb80255e4,0xb8039509,0x00115400,0xb802d511,0xd1001bc4,
+0xc20024e1,0xc30001e1,0x0010f900,0x900038e5,0xc20018e4,0xc21ef4e0,0xc20024ed,0xc30001e4,
+0xc30001e0,0xc2001ce9,0xc25cc8e0,0xb80039e8,0xb80038e1,0xc30001ec,0xc30001e8,0xc30001e1,
+0x00000000,0x90003ae0,0x90003b1a,0x008e7a19,0xe800016d,0x04b039e1,0xc20020e0,0x009e78e9,
+0xe8000144,0xc30001e1,0x14a03900,0x900038e5,0xc2001ce0,0x0010f901,0xc30001e1,0x00000000,
+0xb8003809,0xd1001e1f,0xc20010ec,0xc21ef4e0,0xc1ffffe9,0xc30001ec,0xc30001e0,0xc20010e5,
+0x00000000,0xa0003be0,0xb800380b,0x00000001,0xd1009028,0x02ae3ae1,0xc30001e4,0x129e3805,
+0x00000000,0x800039e1,0xc20020e0,0xc20018e8,0xc20024e5,0xc30001e0,0xc30001e8,0xc30001e5,
+0xc21ef4e0,0xb80038e0,0xc2001ced,0xc30001e0,0xb8003aec,0xb80039e1,0xc30001ec,0xb80038e0,
+0xc20020e9,0xc20018e4,0xb8003bf4,0xc30001e9,0x122f3805,0x120f3c04,0x00000000,0x008efbe1,
+0xd1001d80,0x00000000,0xc30001e5,0xc10000e0,0x0080bdf0,0x009efbe1,0x0010fb00,0x90003aec,
+0x900039e1,0xc20020e8,0xc20018e4,0xc20018e1,0xc30001e8,0xc30001e4,0xc30001e1,0x00000000,
+0xb8003ae8,0xb80039e7,0x00000001,0x008e79e9,0x00000000,0x900038e5,0xc1000019,0x1091c741,
+0x00000000,0xb800c704,0xb800871f,0x10824741,0x00000000,0xb8004054,0xb8000051,0x07000102,
+0x00100901,0xd2fffee4,0xc20020e5,0xc30001e4,0xc10000e1,0x00000000,0x900039e1,0xc20024e0,
+0xc25cc809,0xc30001e0,0xc3000109,0x00000000,0xb800380d,0xd1001ccf,0xc20024e8,0xc20018e4,
+0xc20018e1,0xc30001e8,0xc30001e4,0xc30001e1,0x00000000,0xb8003ae8,0xb80039e7,0xd2ffff7d,
+0x008e79e9,0x00000000,0x900038e5,0x10924941,0x00000000,0x9000891d,0x1081c940,0x9000c904,
+0xc1002025,0x00900724,0x00924725,0xc20018e1,0xc30001e1,0x00000000,0xb80038e3,0x00000001,
+0x121e3809,0xe8000049,0x14a03801,0xc20010ec,0xc20018e0,0xc1ffffe9,0xc30001ec,0xc30001e0,
+0xc20010e5,0x00000000,0xa0003be0,0xb800380b,0x00000001,0xd1008e64,0x02ae3ae1,0xc30001e4,
+0x129e3805,0x00000000,0x800039e1,0xc1000019,0x1091c741,0x00000000,0xb800c704,0xb800871f,
+0x10824742,0x07000102,0x00100901,0x10924941,0x00000000,0x9000891d,0x1081c940,0x9000c904,
+0xc1002425,0x00900724,0x00924725,0x00000000,0x90000050,0x90004055,0x00154200,0x00150301,
+0xd1001d7c,0xc10000e0,0xc10000e5,0x00000000,0x900202e0,0x9001c2e5,0xc1000b0c,0x10808371,
+0xd1001e2c,0x10809472,0xc100010d,0xe8000021,0x14100601,0x00000000,0xb801d5e7,0xc24000e1,
+0x028e39e1,0x00000000,0x9001d5e1,0xd1001e00,0x10809472,0xc100010d,0xe8000079,0x14100601,
+0x00000000,0xb801d5e7,0xc21000e1,0x028e39e1,0x00000000,0x9001d5e1,0xd1001dd4,0x10809472,
+0xc100020d,0xc10004e1,0x009e3819,0xe8000070,0x900015e1,0x14103811,0xc11005e0,0xc1ffff19,
+0x00000000,0x9003d4e1,0x1091c741,0x00000000,0xb800c704,0xb800871f,0x10824741,0x00000000,
+0xb8004054,0xb8000051,0x07000102,0x00100901,0x00000000,0xb801d5e7,0xc24000e1,0x029e39e1,
+0xe8ffff99,0x14003801,0xd2ffffc0,0xc11004e1,0x00000000,0x9003d4e1,0xc1ffff19,0xd1001d50,
+0x10809472,0xc100010d,0xe8000031,0x14100601,0x00000000,0xb801d5e0,0x10809473,0xd1001ea1,
+0x128e3841,0xc100100c,0x9001d5e0,0xc2ffff11,0x00000000,0x84031519,0xd1001d14,0x10809472,
+0xc100040d,0xe800001d,0x1410063d,0xd2ffff5c,0xc11006e1,0x00000000,0x9003d4e1,0xc1ffff19,
+0x00000000,0xb801d5e7,0xc21000e1,0x029e39e1,0xe8000071,0x14003801,0x00000000,0xb80015e3,
+0x00000001,0x122e3805,0xc1003ce0,0x108e780d,0xc20320e0,0x060e79e1,0xc30001e1,0x120e0608,
+0x008e79e1,0x00000000,0x034e39e3,0x00000001,0x00000000,0x900115e1,0xd1001c94,0x10809472,
+0xc100020d,0xe8000059,0x1410060d,0xd2fffedc,0xc11007e1,0x00000000,0x9003d4e1,0xc1ffff19,
+0x00000000,0xb80015e3,0x00000001,0xc1003ce0,0x109e7805,0xc20320e0,0x060e79e1,0xc30001e1,
+0x120e0608,0x008e79e1,0x00000000,0x034e39e2,0xd2ffffaa,0x00000000,0x900115e1,0xc2044ce0,
+0xb801d5e4,0x120e4609,0xc30001e1,0x00000000,0x034e79e1,0xc21000e1,0x029e39e1,0xe8000039,
+0x14003800,0x900155e5,0x121eb904,0xb801d5e5,0x00000000,0x900155ea,0xc24000e1,0x029e39e1,
+0xe8000015,0x14003801,0x121e3a05,0x00000000,0x900155e1,0xd1001bd8,0x10809472,0xc100010d,
+0xe8000021,0x14000601,0x00000000,0xb801d5e7,0xc10080e1,0x028e39e1,0x00000000,0x9001d5e1,
+0xd1001bac,0x10809472,0xc100010d,0xe8000021,0x14000601,0x00000000,0xb80215e7,0xc10100e1,
+0x028e39e1,0x00000000,0x900215e1,0xd1001b80,0x10809472,0xc100020d,0xd1001b74,0xc10003e1,
+0x009e3819,0xc100020c,0x900055e0,0x10809471,0xd1001b5d,0x00000000,0x90009518,0x10809471,
+0xc100010d,0xe8000021,0x14000601,0x00000000,0xb801d5e7,0xc10020e1,0x028e39e1,0x00000000,
+0x9001d5e1,0xd1001b28,0x10809472,0xc100010d,0xe8000021,0x14000601,0x00000000,0xb801d5e7,
+0xc10040e1,0x028e39e1,0x00000000,0x9001d5e1,0xd1001afc,0x10809472,0xc100020d,0x00000000,
+0xb801d5e0,0x9000d51b,0x00000001,0x129e3841,0xe800001d,0x14003801,0xd1001ad4,0x10809472,
+0xc100100d,0x00000000,0x84035519,0xd2fffd1e,0xc1000019,0x10924941,0x1081c940,0x9000c904,
+0x9000891d,0xc100a824,0x90004920,0x10920741,0x00900724,0x00924725,0x00000000,0x90010060,
+0x90014065,0x00000000,0x90008058,0x9000c05d,0x00000000,0x90000050,0x90004055,0x00154200,
+0x00158301,0x00000000,0xb801c2e7,0x109e0821,0x00000000,0x900038e5,0x00000000,0xb80202e7,
+0x109e0811,0x00000000,0x900038e5,0x00000000,0xb801c3eb,0xc10080e1,0x029e3ae1,0xe8000411,
+0x14003800,0xc1000051,0xc1000161,0x00000000,0xb80003e3,0x00000001,0xe8000015,0x1410380c,
+0xc10000e5,0xc21000e1,0x029e7ae1,0xe80003e9,0x14003901,0xc100485d,0xd1008347,0xe800032d,
+0x14100601,0xc103e8e0,0x120e9808,0xc10004e5,0xc10001e0,0x0615d7e0,0x009679e9,0x00963861,
+0xc1ffb8e4,0xb80015e4,0xc10048e1,0x00000000,0x0080c8e6,0x009e08e1,0x00000000,0x900038e5,
+0x00000000,0xb80055ea,0xc10044e1,0x009e48e0,0x00000000,0xc1ff94e1,0x00000000,0x900039e8,
+0x008088e1,0x00000000,0xb80095e6,0xc10040e1,0x009e08e1,0x00000000,0x900038e5,0x00000000,
+0xb800d5e7,0x109e08f1,0x00000000,0x900038e5,0x00000000,0xb80115e7,0x109e08e1,0x00000000,
+0x900038e5,0x00000000,0xb80155e7,0x109e08d1,0x00000000,0x900038e5,0x00000000,0xb80195e7,
+0x109e08c1,0x00000000,0x900038e5,0x00000000,0xb801d5e7,0x109e08b1,0x00000000,0x900038e5,
+0x00000000,0xb80215e7,0x109e08a1,0x00000000,0x900038e5,0x00000000,0xb80255e7,0x109e0891,
+0x00000000,0x900038e5,0x00000000,0xb80295e7,0x109e0881,0x00000000,0x900038e5,0x00000000,
+0xb802d5e7,0x109e0871,0x00000000,0x900038e5,0x00000000,0xb80315e7,0x109e0861,0x00000000,
+0x900038e5,0x00000000,0xb80355e7,0x109e0851,0x00000000,0x900038e5,0x00000000,0xb80395e7,
+0x109e0841,0x00000000,0x900038e5,0x00000000,0xb803d5e7,0x109e0831,0x00000000,0x900038e5,
+0x00000000,0xb80016e6,0xc1006ce1,0x009e08e1,0x00000000,0x900038e5,0x00000000,0xb80056e6,
+0xc10068e1,0x009e08e1,0x00000000,0x900038e5,0x00000000,0xb80096e6,0xc10064e1,0x009e08e1,
+0x00000000,0x900038e5,0x00000000,0xb800d6e6,0xc10060e1,0x009e08e1,0x00000000,0x900038e5,
+0x00000000,0xb80116e6,0xc1005ce1,0x009e08e1,0x00000000,0x900038e5,0x00000000,0xb80156e6,
+0xc10058e1,0x009e08e1,0x00000000,0x900038e5,0x00000000,0xb80196e6,0xc10054e1,0x009e08e1,
+0x00000000,0x900038e5,0x00000000,0xb801d6e6,0xc10050e1,0x009e08e1,0x00000000,0x900038e5,
+0x00000000,0xb80216e6,0xd1fff924,0xc1004ce1,0x009e08e1,0x00000000,0x900038e5,0xc1ff94e0,
+0xb80016e5,0xc1ffa8e0,0x034e88e0,0xb80156e1,0x00000000,0x034e48e3,0x110ec600,0x00000000,
+0x010ebae5,0x010e39e0,0x029e7be9,0x029e39e1,0xe800007d,0x14003801,0xd100162c,0x10809573,
+0x00000000,0xb80016e0,0xb80155e7,0x00000001,0xe800012d,0x14103804,0x009506e5,0x00000000,
+0xb80156e4,0x008e1953,0x00000001,0x00000000,0x061539e1,0xc10000e1,0xe8000025,0x04d03850,
+0xc10000e9,0xc10000e5,0xc2bb80e1,0x008e79e1,0xe8fffff9,0x04b03950,0x108eba05,0xc1ffffe1,
+0x00853ae1,0xe8000025,0x14f01421,0xd1001610,0x10809572,0xc100080d,0xd1008024,0x00109503,
+0xe8fffd01,0x14000601,0xc1fff8e1,0x00000000,0x034e08e3,0x00000001,0xc1fffce0,0x9001d5e1,
+0x00000000,0x034e08e3,0xe800002d,0x14901420,0x900215e1,0x00000000,0xb80016e3,0x00000001,
+0xe80000cd,0x1410380d,0xc10280e1,0xe80000c1,0x04b014e1,0xc11004e0,0xc1ffff19,0x00000000,
+0x9003d5e1,0x1091c741,0x00000000,0xb800c704,0xb8008059,0x00000000,0xb8004055,0x00000000,
+0xb8014064,0xb8004721,0x00000000,0xb8000050,0xb8010061,0x00000000,0xb800c05c,0xb800871d,
+0x07000101,0x10824741,0x00100901,0xd2fffc02,0xc1000061,0xd2fffc26,0xc100905d,0x00000000,
+0xb80156e4,0x008e1853,0x00000001,0x00000000,0x061539e1,0xc10000e1,0xe8000029,0x04d03850,
+0xc10000e9,0xc10000e1,0x00000000,0x00000000,0x008e385d,0xe8fffff5,0x04b03850,0x108eba05,
+0xd2fffee4,0xc1ffffe1,0x00853ae2,0xc103e8e0,0xc1000019,0xd2ffff50,0x061e14e2,0x00000000,
+0x900115e1,0x10924941,0x1081c940,0x9000891c,0xc1005025,0x00900724,0x00924725,0x00000000,
+0x90000050,0x90004055,0x00000000,0xa40202e4,0xac0082eb,0xc100d2e1,0x129e3908,0x0093bae1,
+0xe80000d1,0x14003801,0xc1000255,0x00000000,0xa40242e3,0x00000001,0xe80000c9,0x14103809,
+0x129e3921,0xe8000035,0x14003800,0xc1000050,0xc100004d,0x129e3911,0xe80000a1,0x14003801,
+0xc1ffff35,0xc2cc2c2c,0xc1000029,0x10830248,0xc300012d,0xd60120ea,0x00000000,0xa40342e8,
+0xa40382e5,0x00000000,0xa403c2e5,0xc10240e1,0xea000041,0x120efa0c,0x00000000,0x120eb90d,
+0x120e790c,0x00944ee8,0x00948eed,0x04f014e0,0x00940ee5,0x10835304,0x10831308,0x1083c249,
+0x12039308,0x1202cd08,0x12028c09,0xd6016112,0x1091c740,0xb8004055,0x00000000,0xb8000050,
+0xb800871d,0x07000101,0x10824741,0x00100901,0xd2ffff3e,0xc1000155,0xd2ffff6e,0xc1000035,
+0x129e3911,0xe8000025,0x14003801,0xc2cc2c2c,0x10830249,0xc100004c,0xc1000028,0xc300012d,
+0xd6002142,0xd2ffffaf,0xc100004c,0x1082c248,0xc1000029,0xd600214a,0xd2ffff9b,0x10924941,
+0x1081c940,0x9000891c,0xc1003425,0x00924725,0x192e4300,0xc10400e0,0x118ec301,0xe80000a4,
+0x122e7908,0x129eb90d,0x04f002e0,0x0992bbe8,0x099ffbe5,0xc2c4a0e0,0xc2b494e4,0x120e8209,
+0xc30001e0,0xc30001e5,0x00000000,0x031e02e0,0x034fbae7,0x00000001,0x008fffe1,0xe80000e1,
+0x14e03f01,0xc10000e4,0x11ce3f81,0x009ef9fd,0xc10001e4,0x109ebb05,0x020e79e9,0x008e7ee5,
+0x022ef9ed,0x09bfb8ed,0x108e4a0c,0xc2cc44e1,0x120e7908,0xc30001e1,0x00000000,0x034e39e3,
+0x00000001,0x00000000,0x21c1bee2,0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,
+0x121f420c,0xc2c4a0e4,0xc2c4a0e1,0xc2b494ec,0x108ebd04,0xc30001e5,0xc30001e0,0x120f3d08,
+0xc30001ed,0xc2b494e0,0x031e3ae0,0x031e7de5,0x120e7a08,0x034e7cec,0xc30001e1,0x00000000,
+0x034e79e2,0x108e3910,0x00000000,0x011ef9e1,0x008e38ec,0x00000000,0x022eb9ed,0x129e021c,
+0x009e79e8,0x008fffe1,0x00000000,0x061e39e1,0xd2ffff2d,0x122e380d,0x008fbae1,0xc2ffffe0,
+0x11ee7f14,0x020efefd,0xc37fffe1,0x001e3801,0xd2ffff38,0x009e38ed,0x09be39e1,0x008fb8ed,
+0x10924941,0x00000000,0x9000891d,0x1081c940,0x9000c904,0xc1003425,0x00900724,0x00924725,
+0x00000000,0x90000051,0x00150301,0xd10012c3,0x109fd404,0xc10001e0,0x109e5409,0xc2b1fce0,
+0x020ef8fc,0xc10000f1,0x02af86ec,0xc20000e8,0x120e7909,0xc30001e0,0x029f7eec,0xc1001ded,
+0xc31000e8,0x034e39e0,0x009e3cf5,0x001e3a00,0x028ebee0,0x009e7b51,0x022e38fc,0x020e7ae5,
+0x008e79e1,0x00000000,0x21c1b9e2,0x1091c741,0x00000000,0xb800c704,0xb800871f,0x10824741,
+0x00000000,0xb8000051,0x07000102,0x00100901,0x10924941,0x1081c940,0x9000c904,0x9000891d,
+0xc1005424,0x90004920,0x10920741,0x00900724,0x00924725,0x00000000,0x90008058,0x9000c05d,
+0x00000000,0x90000050,0x90004055,0x00150200,0x00154300,0x0015c401,0x00000000,0xb800435b,
+0x00000001,0xe8000139,0x14001601,0x00000000,0xb800830d,0xd10011db,0x109e8840,0xc1fff4e4,
+0xc1fff0e1,0x008108e4,0x90003a19,0x008148e0,0xb8001552,0xd1004f22,0x00108600,0x0010d401,
+0xc1fff0e8,0xc1fff8e4,0xc1fff0e1,0x008148e0,0x034088e8,0x008108e5,0xd1004efe,0x0010d401,
+0xc1fff0e8,0xc1fffce4,0xc1fff0e1,0x008148e0,0x034088e8,0x008108e5,0xd1004ede,0x0010d401,
+0xc1ffffe0,0xc10001e5,0xc1001de0,0x008e96e0,0xc1000029,0xc1fff4e0,0x009f7858,0x020fb9e9,
+0x008fc8e0,0x001ed700,0xc10000f1,0x00000000,0x00000000,0x034e3ff3,0x00000001,0x02aeb8f9,
+0xc10000e0,0xb80115e0,0x029e7af9,0x009e38e4,0xb800d5e1,0x028e3ae1,0x020e78f5,0x008e79e1,
+0x10828a04,0x00000000,0x21ce39e1,0xe8ffffc0,0x108f3c11,0x14900a0c,0x108efb10,0x90003be1,
+0x1091c741,0x00000000,0xb800c704,0xb8008059,0x00000000,0xb800c05c,0xb8004722,0x00000000,
+0xb8004055,0x00000000,0xb8000050,0xb800871d,0x07000101,0x10824741,0x00100901,0x00000000,
+0xb800835a,0xd10010aa,0x0010d601,0xd10010a0,0x109e0831,0x0010d600,0x90003818,0x00109402,
+0xd100108c,0x109e0821,0x0010d600,0x90003818,0x00109402,0xd2ffff0c,0x109e0811,0x00000000,
+0x9000381a,0x1092497d,0x10924925,0x1081c97c,0x9000891c,0x9000c905,0x1081c724,0xc1007025,
+0x00900724,0x00924725,0x00000000,0x90030080,0x90034085,0x00000000,0x90028078,0x9002c07d,
+0x00000000,0x90020070,0x90024075,0x00000000,0x90018068,0x9001c06d,0x00000000,0x90010060,
+0x90014065,0x00000000,0x90008058,0x9000c05d,0x00000000,0x90000050,0x90004055,0xc1ffece4,
+0xc1ffe8e0,0x0017c201,0x00000000,0x034707e4,0x034507e2,0x00178300,0x00154501,0x00174401,
+0xe8000334,0xc10000e0,0xc1000081,0x14000400,0x90001ce1,0xe8000319,0x14100305,0xc10001e1,
+0xe800032c,0x900014e1,0x14000401,0xc10008e1,0xd1000f9c,0x0010f803,0x00109f00,0x90001519,
+0x00000000,0xb800140d,0xd1000f87,0xc10000e0,0x90005519,0xe8000045,0x04103874,0xc100016d,
+0xc10000e1,0xe8000035,0x04f03878,0xc100026c,0xc1000085,0x10851521,0xd1000f54,0x00109f02,
+0xc100040d,0x10886104,0x80001419,0xe8ffffed,0x04902178,0x10851405,0xc10000e1,0xe8000221,
+0x04f0386c,0xc1000069,0x10865528,0x11061d00,0x1085d521,0xc10000e1,0xe80001f1,0x04f03878,
+0xc1000085,0x00159901,0xd1000f04,0x00109f02,0xc1000c0d,0xd1000ef9,0x00000000,0x84001618,
+0x00109f01,0xc100090d,0xd1000ee5,0x00000000,0x84005618,0x00109f01,0xc100080d,0xe8000258,
+0x84009619,0x14001d01,0xc10009e1,0xd1000ec0,0x00109f00,0x0010f803,0x00000000,0xac0056e4,
+0xac0016ed,0x00000000,0xb8001ce9,0x00000000,0x8400d619,0xc10120e1,0x110e2000,0x00000000,
+0x01ce79e1,0x008e7aec,0x029e39e1,0xe8000010,0x90001ce5,0x14003801,0xc1200d81,0xd1000e70,
+0xc10000e1,0x00000000,0x800216e0,0x00109f01,0xc100010d,0xe800020d,0x14000601,0xd1000e50,
+0x00109f02,0xc100020d,0x110e4600,0x110e2001,0x029e39e0,0x80025619,0xe800000d,0x14003801,
+0xc1200e81,0x110e4608,0x031e5784,0x110e2001,0x00000000,0x029e98e7,0x111e7901,0x029e7ae5,
+0x029e39e1,0xe800000d,0x14003801,0xc1200f81,0x00109f01,0xd1000df8,0xc10007e4,0xc10024e1,
+0x00000000,0x800456e0,0x800416e5,0xc100010d,0xe800016d,0x14000601,0x00000000,0xa40216e3,
+0x00000001,0xc100ffe0,0x128e7821,0x029e39e1,0x00000000,0x800216e1,0xd1000db4,0x00109f02,
+0xc100050d,0xd1000da9,0x00000000,0x80029618,0x00109f01,0xc100050d,0xc1000054,0x8002d618,
+0x10851635,0xd1000d88,0x00109f02,0xc100030d,0x10855504,0x80001419,0xe8ffffed,0x1490150c,
+0x10851405,0xe8000175,0x14001d01,0xc10002e1,0xd1000d5c,0x00109f00,0x0010f803,0x00000000,
+0xa40216e3,0x00000001,0x10886104,0x028e7818,0xc100ffe1,0xe8fffe34,0x029e39e1,0x04902178,
+0x108596e8,0x800216e1,0x10869a04,0xc10074e1,0xe8fffe04,0x008659e1,0x04901a6d,0x0011a001,
+0x1091c77c,0xb8000050,0xb8004055,0x1091c724,0xb8008058,0xb800c05d,0x00000000,0xb800c704,
+0xb8010061,0x00000000,0xb8014064,0xb8018069,0x00000000,0xb801c06c,0xb8020071,0x00000000,
+0xb8024074,0xb8028079,0x00000000,0xb802c07c,0xb8030081,0x1082477c,0xb8034084,0xb800871d,
+0x07000101,0x10824925,0x00100901,0xd2fffcf6,0xc10002e1,0xe8000011,0x14100305,0xd2fffce6,
+0xc10005e1,0xd2fffcde,0xc10003e1,0xd2fffce6,0xc10009e1,0xd2fffdba,0xc10004e1,0x00000000,
+0xa40256e3,0x00000001,0xe8fffeb1,0x14103809,0xd2fffea8,0xc10008e1,0x00000000,0x800416e2,
+0xc10000e0,0x10851629,0xc1000054,0x800256e1,0xd1000c3c,0x00109f02,0xc100050d,0x10855504,
+0x80001419,0xe8ffffed,0x1490150c,0x10851405,0xd1000c1c,0x00109f02,0xc100040d,0xd1000c11,
+0x00000000,0x80041618,0x00109f01,0xc100030d,0xd2fffe94,0x8004561b,0xd2fffe9a,0xc10003e1,
+0x10924941,0x1081c940,0x9000c904,0x9000891d,0xc1005024,0x90004920,0x10920741,0x00900724,
+0x00924725,0x00000000,0x9001c06c,0x90020071,0x00000000,0x90014064,0x90018069,0x00000000,
+0x9000c05c,0x90010061,0x00000000,0x90004054,0x90008059,0x00000000,0x90000051,0x00170401,
+0x00164200,0x00158500,0x00154301,0x00000000,0xb80002e9,0xc2c8a4e4,0xc10001e1,0xc30001e4,
+0xc1fff8f1,0x109e0820,0x00000000,0x008e78e5,0x00000000,0x900038e9,0x00000000,0xb80042eb,
+0x109e0811,0x00000000,0x900038e9,0x00000000,0xac00c3ec,0xa40243e3,0xc2c8a4e9,0xc30001e8,
+0x120efb05,0x00000000,0x0316b9ec,0x0316fbea,0xe8000130,0x008608f1,0x14103809,0x00000000,
+0xa40203e3,0x00000001,0x129e3821,0xe800010d,0x14003800,0xc100005d,0xc10011e1,0xe800003d,
+0x14003800,0x1095b805,0x10850349,0xd1000ae0,0x00109900,0x0010db03,0xc1ffffe1,0x00000000,
+0x80001418,0x008596e1,0xe8ffffe5,0x141016fc,0x1085d704,0x10851405,0x10855548,0xc1001159,
+0x00851755,0xd1000aa8,0x00109900,0x0010da03,0xc1ffffe1,0x00000000,0x80001418,0x008596e1,
+0xe8ffffe5,0x141016fc,0x1085d704,0x10851405,0xc1000258,0x008e9755,0xc1ffffe0,0xc10000e5,
+0x00000000,0x80003ae4,0x008596e1,0xe8ffffed,0x141016fc,0x108eba05,0xd10008c8,0x00109800,
+0x0010d903,0x1091c740,0xb8000050,0xb8004055,0x00000000,0xb800c704,0xb8008059,0x00000000,
+0xb800c05c,0xb8010061,0x00000000,0xb8014064,0xb8018069,0x00000000,0xb801c06c,0xb8020071,
+0x00000000,0xb8004720,0xb800871d,0x07000101,0x10824741,0x00100901,0xd2ffff06,0xc10012e1,
+0x129e0521,0xe80000dd,0x14003801,0xc100005c,0x108e8448,0x108e4349,0x00000000,0x031e3a5e,
+0x1085d705,0xe8fffff5,0x14901718,0x108e7904,0x800039e1,0x129e1611,0xe80000d5,0x14003801,
+0xc100065c,0x108e9c48,0x108e5561,0x00000000,0x031e3a5e,0x1085d705,0xe8fffff5,0x1490172c,
+0x108e7904,0x800039e1,0x129e1609,0xe80000cd,0x14003801,0xc1000b5c,0x108e9c48,0x108e5575,
+0x00000000,0x031e3a5e,0x1085d705,0xe8fffff5,0x14901740,0x108e7904,0x800039e1,0x129e1605,
+0xe80000c5,0x14003801,0xc100105c,0x108e9c48,0x108e5589,0x00000000,0x031e3a5e,0x1085d705,
+0xe8fffff5,0x14901754,0x108e7904,0x800039e1,0xd2fffec8,0xc10000e1,0x00000000,0x8009d5e2,
+0xc100005c,0x10850349,0xd1000904,0x00109900,0x0010db03,0x1085d704,0x80001419,0xe8ffffed,
+0x14901718,0x10851405,0xd2ffff2f,0xc100065c,0x10851561,0xd10008d8,0x00109900,0x0010db03,
+0x1085d704,0x80001419,0xe8ffffed,0x1490172c,0x10851405,0xd2ffff37,0xc1000b5c,0x10851575,
+0xd10008ac,0x00109900,0x0010da03,0x1085d704,0x80001419,0xe8ffffed,0x14901740,0x10851405,
+0xd2ffff3f,0xc100105c,0x10851589,0xd1000880,0x00109900,0x0010da03,0x1085d704,0x80001419,
+0xe8ffffed,0x14901754,0x10851405,0xd2ffff47,0x10924941,0x1081c940,0x9000891c,0x90004921,
+0xc2094c24,0x10920741,0x00924725,0x00000000,0xa40203e3,0x00000001,0x129e3821,0xe8000011,
+0x14003800,0xc10000f9,0xc10002f9,0xc10012e1,0x00000000,0x061478f9,0xc10240e1,0xe800005d,
+0x04f011e1,0xc2f700e8,0xc2a388e0,0x120e5105,0xc3ffffe8,0xc30001e0,0x120f1109,0x008f48e8,
+0x008ef9e1,0x00000000,0xa8003be0,0x034ebc0b,0x00000001,0x10845104,0x120e7808,0xc10240e1,
+0xe8ffffe4,0x108efb08,0x008e7de5,0x049011e0,0x108f3c10,0x900039e9,0xc10012e0,0xc2f700e8,
+0xc10240e5,0xc3ffffe8,0x061f38f8,0xc10000e1,0x008e88e9,0x120e7c08,0x0093f9f0,0xc1000045,
+0xe800002c,0x00000000,0x00843ae5,0x04f0383c,0x008ef909,0xc1000038,0xc1000831,0xc1000434,
+0x1082bb30,0xc1000c2d,0xd600430e,0x1091c741,0x00000000,0xb8004720,0xb800871d,0x07000102,
+0x10824741,0x10924941,0x1081c940,0x9000891c,0x90004921,0xc1006024,0x10920741,0x00924725,
+0xc2cbc0e4,0x160e8230,0xc10004e1,0xc30001e4,0x00000000,0xc2a388f5,0xc1fff438,0x008e38e4,
+0xc10000e5,0x109e0830,0x0343f8e8,0xc1000035,0x10930820,0xc100002c,0x10928811,0xc1ffe8fc,
+0xc10000f8,0x109f0861,0xc10000ec,0x900038e4,0x109e8851,0xc10000e4,0xa4000f28,0x109e0841,
+0xc30001f4,0x90000c34,0x00834839,0x008308fc,0x90003cf8,0x90000a2d,0x1082cf04,0x900038e4,
+0x90003aed,0xc10000fc,0xc10000f8,0x001f7d01,0xc1ffffe1,0x00828ae1,0xe800002d,0x14100afd,
+0x00000000,0xa4000be0,0x108e7f05,0x119e390d,0x00000000,0x00000000,0x061ff8e6,0x1082cb04,
+0x1092b805,0x120f3f09,0x008e0cf0,0x034e4df0,0x034eccf1,0x008e8cf3,0x108e7b04,0x161e3f18,
+0x161e7949,0x00000000,0x900038e5,0x008e39e0,0x034e0cf1,0x008e38ed,0x00000000,0x84003de2,
+0xe8000031,0x14103819,0xc10000e4,0x008e0df1,0x00000000,0x90003ae5,0x00000000,0x034e4df3,
+0x00000001,0x108e7905,0x00000000,0x900038e5,0x108fbe04,0xc10240e1,0xe8ffff59,0x04903ee0,
+0x108f7d09,0x1091c741,0x00000000,0xb8004720,0xb800871d,0x07000102,0x10824741,0x10924941,
+0x1081c940,0x9000891c,0xc1002025,0x00924725,0xc20014e4,0xc20188ec,0xc20014e1,0xc30382e4,
+0xc30382ec,0xc10000e9,0x00000000,0xb80039e4,0x90003beb,0x00000001,0xc30382e0,0x128e7909,
+0x00000000,0x900038e5,0xd2000003,0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,
+0x10924941,0x1081c940,0x9000891c,0xc1004c25,0x00924725,0xc2001ce0,0xc22000ed,0xc30382e1,
+0x00000000,0xb80038e7,0xc20800e0,0x00000000,0xc100023d,0xe80000c4,0x029e79e0,0x029e39ed,
+0x14000400,0x122eb834,0x122f392d,0xc21200e1,0x008402e1,0xe80000b8,0xc25cc839,0x14100f04,
+0xc3000139,0xc10000e1,0xe8000079,0x04f0380c,0xc1000035,0xc10000fc,0xc10004f9,0xc2ffffe4,
+0x034f7f08,0x034efe09,0xc2ffffe0,0xc10200f0,0xc10200e9,0xc301ffe4,0xc301ffe0,0x10834d09,
+0x001e7901,0x001e3800,0x008ebdf0,0x008f3be9,0x00000000,0x093eb9e8,0x093e78f1,0x122e7a28,
+0x122e3928,0x108fbe21,0xe8ffffb4,0x84004ee0,0x84000ee5,0x04900d0c,0x10838e10,0x108fff21,
+0x0201833d,0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,0xd2ffff5c,0xc10002e1,
+0x00000000,0x0093f8e9,0x00140201,0xe80000a5,0x14103c05,0xc10000e1,0xe8ffffc9,0x04f0380c,
+0xc1000035,0xc1000028,0xc10004fd,0xc2ffffe4,0x034f0a08,0x034ed029,0xc2ffffe0,0x034f3f08,
+0x034ed0fd,0xc10200f4,0xc10200e8,0xc301ffe5,0xc301ffe1,0x008fbced,0x122f3e04,0x008efcec,
+0x001e7901,0x122efb04,0x001e3800,0x008f3cf5,0x10834d08,0x008e7be8,0x093eb9f1,0xeaffffb0,
+0x122e3a28,0x093eb8e5,0x122e3a28,0x84004ee0,0x84000ee1,0x10838e20,0x8400cee0,0x84008ee1,
+0x04900d0c,0x10828a20,0x108fff21,0xd2ffff37,0xc10000e1,0xe8ffff2d,0x04f0380c,0xc1000035,
+0xc1000030,0xc100042d,0xc2ffffe1,0xc301ffe1,0x0012b801,0xd6004002,0xd2ffff0b,0x10924941,
+0x1081c940,0x9000891d,0x10924771,0xc10000e1,0xe8000031,0x04e03808,0xc10001e8,0xc10000e5,
+0x00000000,0x008eb9e9,0xe800000d,0x04a03a09,0xc10000e9,0x108e7905,0xe8ffffe9,0x04803909,
+0x0011ba01,0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,0x10924941,0x1081c940,
+0x9000891c,0x9000c905,0x10900760,0x10924761,0xc2000ce5,0xc10000e0,0xc30001e5,0x00000000,
+0x900039e1,0x00000000,0xb80002e3,0x00000001,0xe8000041,0x14003801,0xe8000019,0x14003805,
+0xe800003d,0x14003809,0xe8000049,0x1400380d,0xc1000019,0x1091c741,0x00000000,0xb800c704,
+0xb800871f,0x10824742,0x07000102,0x00100901,0xd1ffe03e,0x10808211,0xd2ffffdf,0x00000000,
+0xb801c211,0xd1ffe096,0xc1000015,0xd2ffffcb,0x00000000,0xb801c211,0xd1ffe377,0xd2ffffbb,
+0x10924941,0x00000000,0x9000891d,0x1081c940,0x9000c904,0xc1002025,0x00900724,0x00924725,
+0x001ec201,0xc20010e1,0xc30001e1,0x00000000,0xa00038e3,0x00000001,0x129e3805,0xe8000069,
+0x14003801,0xc20018e0,0xc20004e8,0xc28000e5,0xc30001e0,0xc30000e9,0x008e7ae4,0xb80038e3,
+0x00000001,0x008eb9e1,0xd1ffd205,0x12114308,0x00113b00,0x0010fa01,0xc1000309,0xd1ffd74e,
+0xc1000309,0xc1000019,0x1091c741,0x00000000,0xb800c704,0xb800871f,0x10824742,0x07000102,
+0x00100901,0xc20018e4,0xc20004e1,0xc30001e4,0xc30000e1,0x00000000,0xb80039e6,0xd2ffffae,
+0x008eb9e1,0x10924941,0x1081c940,0x9000891d,0x10924761,0xc10000e4,0x9000020c,0xc10008e1,
+0x00000000,0x8400c2e0,0x840082e5,0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,
+0x10924941,0x1081c940,0x9000891c,0xc1002025,0x00924725,0x00000000,0xb80002e0,0xb80003ed,
+0x00000000,0xac00c3e6,0x00000000,0xac00c2e9,0xc10008e0,0x00000000,0x108eb805,0x009e38e4,
+0x009e7be9,0x120e790d,0x008e7ae5,0x0081b9e1,0x1091c741,0x00000000,0xb800871d,0x07000102,
+0x10824741,0x10924941,0x1081c940,0x9000891d,0x10924751,0x00000000,0xac00c2e3,0x00000001,
+0xe800002d,0x14103821,0x00000000,0xb80002e3,0x00000001,0x0011b801,0x1091c741,0x00000000,
+0xb800871d,0x07000102,0x10824741,0x00000000,0xb80002e2,0xd2ffffe2,0x108e3805,0x10924941,
+0x1081c940,0x9000891c,0xc1002025,0x00924725,0x00000000,0xac00c2e0,0xb80002ea,0x129e431d,
+0x121ec30d,0xc2ffffe0,0x009e78e4,0x008ebaed,0xc2ffffe0,0x900002e8,0x029e79e1,0x029e39e1,
+0xe8000040,0x8400c2e1,0x14a03821,0x00000000,0xac00c2e0,0xb80002e7,0x00000001,0xc2ffffe0,
+0x108eb904,0x108e7821,0xc2ffffe0,0x900002e8,0x029e79e1,0x029e39e1,0x00000000,0x8400c2e1,
+0x00000000,0xac00c2e3,0x00000001,0xe800002d,0x14e03821,0x00000000,0xb80002e3,0x00000001,
+0x00000000,0xa40038e7,0xc2ffffe1,0x029e39e1,0x00000000,0x840082e1,0x1091c741,0x00000000,
+0xb800871d,0x07000102,0x10824741,0x10924941,0x1081c940,0x9000891c,0xc1002825,0x00924725,
+0x00000000,0xac00c2e3,0x00000001,0xe800002d,0x14103821,0x00000000,0xb80002e3,0x00000001,
+0x00000000,0xa40038e7,0xc2ffffe1,0x029e39e1,0x00000000,0x840082e1,0x00000000,0xac00c2ef,
+0x00000001,0xe8000051,0x04f003ed,0xc10001e0,0xac0082ec,0x009ebb0d,0xc2ffffe4,0x020ef8ec,
+0xc2ffffe1,0x029e7ae5,0x109e7b04,0x00000000,0x029e39e1,0x029e3be4,0x8400c2e1,0x0221b8e9,
+0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,0xc10001e0,0xb80002e0,0xac0082e9,
+0xc10008e0,0x020e78ed,0x009f43ec,0x8400c2e1,0x109e7905,0xe8000050,0x108e3804,0x029efae5,
+0x14903d20,0x900002e1,0x00000000,0xb80002eb,0x00000001,0xc1fff8e0,0xa4003ae0,0x120e7b21,
+0x00000000,0x00000000,0x008f7de2,0xe8ffffe9,0x14f03d20,0x108eba04,0x028ef9e1,0x00000000,
+0x900002e9,0xe8000051,0x14b03d01,0x00000000,0xb80002e8,0xac00c2e5,0xc10008e4,0xc2ffffe1,
+0x020f3bf4,0x009ef9f6,0xc2ffffe4,0xa4003ae4,0x009eb9f5,0x029e7ae5,0x029e39e1,0xc2ffffe0,
+0x8400c2e1,0x029e39e1,0x022e38ec,0x840082e1,0x028efce1,0xd2ffff2c,0x0011bb03,0x10924941,
+0x1081c940,0x9000c904,0x9000891d,0xc1003424,0x90004920,0x10920741,0x00900724,0x00924725,
+0x00000000,0x90004054,0x90008059,0x00000000,0x90000051,0x00154301,0xc1fff8e0,0xc1000059,
+0x008508e1,0x001e5401,0x00000000,0x030e160a,0x10859605,0xe8fffff5,0x14901620,0x108e7904,
+0x800039e1,0xc10020e1,0xe80000fd,0x049003e0,0x00158401,0xd1fffe18,0x00109402,0xc100200d,
+0x121e9620,0x121e4660,0xc100ffe1,0x00000000,0x02ae7ae5,0xc2002ce0,0x029e79e1,0xc30001e0,
+0xc2002ce4,0x120eb905,0x00000000,0x033e3ae2,0xc1ffe0e1,0x120e9620,0x00000000,0x008555e1,
+0x00000000,0x02ae3ae1,0x121e0640,0x120eb820,0x121ef821,0xc100ffe0,0x02aefbe1,0x029e3be1,
+0xc30001e4,0x120e3805,0x00000000,0x033e38e7,0x00000001,0x02ae3ae1,0x121e0620,0x120eb820,
+0x121e7821,0xc100ffe0,0x02ae79e1,0xc2002ce0,0x029e79e1,0xc30001e0,0x120e7905,0x00000000,
+0x033e39e3,0x00000001,0x02ae3ae1,0x121e3820,0x120eb821,0xc100ffe0,0x02ae7819,0xc2002ce0,
+0x029e79e1,0xc30001e0,0x120e7905,0x00000000,0x033e79e2,0xc10020e1,0xe8ffff1d,0x04f015e0,
+0x02a5bae5,0x121e150d,0xe80000a5,0x1400380d,0xe80000d9,0x14003809,0xe800010d,0x14003805,
+0xe8000049,0x14001501,0x10955505,0xd1fffd00,0x00109402,0xc100010d,0x121e163d,0x02ae06e1,
+0x129e3805,0xe8000015,0x14003800,0x12059605,0xc28005e1,0x02a596e1,0xc1ffffe1,0x008555e1,
+0xe8ffffcd,0x141015fd,0xc2ffffe4,0xc2ffffe1,0x029e56e5,0x0291b9e1,0x1091c741,0x00000000,
+0xb800c704,0xb800805b,0x00000000,0xb8004054,0xb8000051,0x00000000,0xb800871c,0xb8004721,
+0x07000101,0x10824741,0x00100901,0xd1fffc80,0x00109402,0xc100080d,0x121e5620,0xc2002ce1,
+0xc100ffe4,0x120e9620,0x02aef919,0x029e7be5,0xc30001e0,0x120e7905,0x00000000,0x033e39e3,
+0x00000001,0x02a5bae1,0xd1fffc44,0x00109402,0xc100080d,0x121e5620,0xc2002ce1,0xc100ffe4,
+0x120e9620,0x02aef919,0x029e7be5,0xc30001e0,0x120e7905,0x00000000,0x033e39e3,0x00000001,
+0x02a5bae1,0xd1fffc08,0x00109402,0xc100080d,0x121e5620,0xc2002ce1,0xc100ffe4,0x120e9620,
+0x02aef919,0x00000000,0x029e7be5,0xc30001e0,0x120e7905,0x00000000,0x033e39e2,0xd2fffec6,
+0x1295551c,0x02a5bae1,0x1092497d,0x10924925,0x1081c97c,0x9000891c,0x90004921,0x1081c724,
+0xc1002825,0x00920724,0xc100cc25,0x00900724,0x00924725,0x00000000,0x9005c0ac,0x900600b1,
+0x00000000,0x900540a4,0x900580a9,0x00000000,0x9004c09c,0x900500a1,0x00000000,0x90044094,
+0x90048099,0x00000000,0x9003c08c,0x90040091,0x00000000,0x90034084,0x90038089,0x00000000,
+0x9002c07c,0x90030081,0x00000000,0x90024074,0x90028079,0x00000000,0x9001c06c,0x90020071,
+0x00000000,0x90014064,0x90018069,0x00000000,0x9000c05c,0x90010061,0x00000000,0x90004054,
+0x90008059,0x00000000,0x90000051,0xc1ffece4,0xc1ffe8e1,0x00000000,0x034ac7e4,0x034a87e3,
+0x00000001,0xc10000e4,0x00000000,0x109e0811,0xc10000e0,0x109e4820,0x900038e5,0xe800018c,
+0x90003915,0x04f038ac,0xc10000a0,0x011a6b15,0xc235e8e0,0xc278aae4,0xc24f33e9,0xc30ec8e0,
+0xc3061fe4,0xc30b50e9,0x00197800,0x0019b900,0x0019fa01,0xc21708e0,0xc2b315e4,0xc29d9de9,
+0xc3031fe0,0xc30d4de4,0xc308e3e9,0x0018b800,0x0018f900,0x00193a01,0xc24036e0,0xc27993e4,
+0xc24be8e9,0xc30c5ee0,0xc30a26e4,0xc30fb1e9,0x0017f800,0x00183900,0x00187a01,0xc2e69de0,
+0xc2bd7ae4,0xc24402e9,0xc30563e0,0xc30e76e4,0xc306d7e9,0x00173800,0x00177900,0x0017ba01,
+0xc25979e0,0xc2d74ee4,0xc29082e9,0xc30e1ce0,0xc3078ae4,0xc30f10e9,0x00167800,0x0016b900,
+0x0016fa01,0xc23f2fe0,0xc241a3e4,0xc2c3cde9,0xc303e3e0,0xc30db9e4,0xc30839e9,0x0015b800,
+0x0015f900,0x00163a01,0xc2a0abe0,0xc2018ce4,0xc23f7ee9,0xc30f4fe0,0xc304a5e4,0xc30f85e9,
+0x00153800,0x00157900,0x001b3a01,0xc2020ee0,0xc2f024e4,0xc2fbfee9,0xc30259e0,0xc30cd9e4,
+0xc30987e9,0x00147800,0x0014b900,0x0014fa01,0xc246d2e0,0xc27a6ce4,0xc2aac0e9,0xc30fece0,
+0xc30191e4,0xc30fd3e9,0x0013b800,0x0013f900,0x00143a01,0xc2fb30e4,0xc2ef91e8,0xc2b49aed,
+0xc300c8e4,0xc210f2e0,0xc30abeed,0xc30bdae8,0xc30ffbe0,0x0012f901,0x00137b00,0x0012b800,
+0x00133a01,0xd606c00e,0x00000000,0xb8004055,0x00000000,0xb8000050,0xb800c05d,0x00000000,
+0xb8008058,0xb8014065,0x00000000,0xb8010060,0xb801c06d,0x00000000,0xb8018068,0xb8024075,
+0x00000000,0xb8020070,0xb802c07d,0x00000000,0xb8028078,0xb8034085,0x00000000,0xb8030080,
+0xb803c08d,0x00000000,0xb8038088,0xb8044095,0x00000000,0xb8040090,0xb804c09d,0x1091c77c,
+0xb8048098,0xb80540a5,0x1091c724,0xb80500a0,0xb805c0ad,0x00000000,0xb80600b0,0xb8004721,
+0x1082477c,0xb80580a8,0xb800871d,0x07000101,0x10824925,0x00100901,0x10924941,0x1081c940,
+0x9000891c,0x9000c905,0x10900760,0x10924761,0x00000000,0xb803c3e7,0xc22009e1,0xe8000081,
+0x040039e1,0xc2200be1,0xe8000075,0x040039e1,0xc2200ce1,0xe8000069,0x040039e1,0xc2200de1,
+0xe800005d,0x040039e1,0xc2200ee1,0xe8000051,0x040039e1,0xc2200fe1,0xe8000045,0x040039e1,
+0xc22010e1,0xe8000039,0x040039e1,0xc22011e1,0xe800002d,0x040039e1,0xc22012e1,0xe8000021,
+0x040039e1,0xc22013e1,0xe8000015,0x040039e1,0xc22014e1,0xe8000055,0x041039e1,0x00000000,
+0xb80002e3,0x00000001,0xe8000031,0x14003801,0xd1000d32,0x00108401,0xc1100019,0x1091c741,
+0x00000000,0xb800c704,0xb800871f,0x10824742,0x07000102,0x00100901,0xd2ffffe0,0xc10001e1,
+0x00000000,0x900002e2,0xd2ffffd6,0xc1000019,0x10924941,0x1081c940,0x9000891c,0x9000c905,
+0x10900770,0x10924771,0x00000000,0x90000051,0x00150201,0x00000000,0xb8028209,0xd1005fa0,
+0xc21eece5,0xc10000e0,0xc30001e5,0x00000000,0x800039e1,0x00000000,0xb80294e6,0xd10004dd,
+0xc10040e1,0x0080b9e1,0x00000000,0xb80294e6,0xd10061c1,0xc21268e1,0x0080b9e1,0x1091c741,
+0x00000000,0xb800c704,0xb800871f,0x10824741,0x00000000,0xb8000051,0x07000102,0x00100901,
+0x10924941,0x1081c940,0x9000c904,0x9000891d,0xc1008024,0x90004920,0x10920741,0x00900724,
+0x00924725,0x00000000,0x90040090,0x90044095,0x00000000,0x90038088,0x9003c08d,0x00000000,
+0x90030080,0x90034085,0x00000000,0x90028078,0x9002c07d,0x00000000,0x90020070,0x90024075,
+0x00000000,0x90018068,0x9001c06d,0x00000000,0x90010060,0x90014065,0x00000000,0x90008058,
+0x9000c05d,0x00000000,0x90000050,0x90004055,0x00158300,0x00188501,0xc10000e4,0xb8004484,
+0x109e0811,0x00000000,0x900038e5,0x00000000,0x00000000,0xb8028257,0xd100043c,0xc10040e1,
+0xc21268e0,0x008815e1,0x0010d500,0x0010a000,0x0087d5e1,0xe8000099,0x141006fd,0xc1ffff19,
+0x00000000,0xb8004055,0x1091c740,0xb8000050,0xb8008059,0x00000000,0xb800c704,0xb8010061,
+0x00000000,0xb800c05c,0xb8018069,0x00000000,0xb8014064,0xb8020071,0x00000000,0xb801c06c,
+0xb8028079,0x00000000,0xb8024074,0xb8030081,0x00000000,0xb802c07c,0xb8038089,0x00000000,
+0xb8034084,0xb8040091,0x00000000,0xb8044094,0xb8004721,0x00000000,0xb803c08c,0xb800871d,
+0x07000101,0x10824741,0x00100901,0x00000000,0xb80060e3,0x00000001,0xe800005d,0x14003801,
+0xc1000279,0xc1ffece0,0x109e8951,0xc1fffce0,0x109e4960,0x008508e1,0x008e88e0,0x90003a51,
+0xd1000854,0xc2022c14,0x109e0971,0x0010a000,0x90003878,0x900039e9,0xc3000114,0x00111500,
+0x0010df01,0xe8000019,0x141006fd,0xd2ffff16,0xc1ffff19,0xd2ffffb2,0xc1000179,0xc10000e1,
+0x00000000,0x900016e1,0x00000000,0xb80020eb,0x00000001,0xe80001c9,0x14103a05,0xc1000c8c,
+0xc1000c91,0xc21004e4,0xb80160e0,0xc21008e1,0xc2100ae0,0x008edfe4,0x008e9fe1,0x120e6314,
+0x00000000,0x008e1fe1,0x00000000,0x840038e4,0x84003a79,0x00000000,0x90003be1,0x00000000,
+0xb80020e3,0x00000001,0xe80001bd,0x1410380d,0xc1fffce1,0x00000000,0x034e08e3,0x00000001,
+0x1299781d,0xc2001ce4,0x120ea521,0xc30382e4,0xc10000e1,0x00000000,0xb80039ef,0xc1f8ffe5,
+0xc2001ce4,0x029efbe5,0xe8000110,0xc30382e4,0x028ebbe9,0x04f03878,0xc1000074,0x900039e9,
+0xc2022ce4,0xc2100ce0,0xc1000069,0xc30001e4,0xc1000064,0x0086dfe1,0x10873928,0xc1000060,
+0x0015d401,0xc1fffce1,0x00000000,0x034e48e3,0xc10000e1,0xe800007d,0x04f038e4,0xc1000095,
+0xc1000058,0xc1000054,0x00851a71,0x00000000,0xa40214e0,0x034e9b65,0x109e0950,0x0340d758,
+0x0010a001,0x00111400,0x90003875,0xd1001a95,0x109e0960,0x00000000,0x129e7821,0x008155e8,
+0x900038e5,0xc1fffce0,0xc20900e5,0xc10074e0,0x034e08e1,0x008514e0,0x00000000,0x008555e6,
+0x10896505,0xe8ffffa9,0x049025e0,0x10859611,0xd1005f58,0x109e0960,0x00811885,0x109e0950,
+0x90003890,0x00109f01,0x00115d00,0x9000388c,0x0010e001,0xe9ffff50,0xc21200e0,0x10875d05,
+0x1085d720,0x90002218,0x008618e1,0x04901d78,0x10869ae8,0x10865911,0xc21000e0,0xb9001fe4,
+0xc1000019,0x008e1fe3,0xd2fffd38,0x008e798d,0x129e793d,0x00000000,0x900038e5,0xe800002d,
+0x14103a0d,0x00000000,0xb801e0e7,0xc21000e1,0x029e39e1,0xe8000015,0x14003801,0xd2fffe2a,
+0xc100128c,0xc1001291,0xe8000015,0x14103a0c,0xc100248d,0xd2fffe12,0xc1001291,0xd2fffe0a,
+0xc1002491,0xe8000011,0x14103805,0xd2fffe5a,0xc1000395,0xd2fffe52,0xc1000295,0x10924941,
+0x1081c940,0x9000891c,0xc1002825,0x00924725,0xc10000f0,0xc10000e4,0xc10000f5,0xc10000e0,
+0xc10000ec,0xc10000e9,0xc10000e4,0x900042e4,0x900002f5,0xc10000e8,0x9000c2e8,0x900082f1,
+0xc10000e0,0x900142e0,0x900102ed,0xc10000e0,0x840342e0,0x840302e9,0x00000000,0x900202e0,
+0x9001c2e5,0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,0x10924941,0x1081c940,
+0x9000891c,0x9000c905,0x10900760,0x10924761,0x00000000,0x90000051,0x00150201,0xd1ffff63,
+0xd10007a0,0xc10001e1,0x00109400,0x900254e2,0x1091c741,0x00000000,0xb800c704,0xb800871f,
+0x10824741,0x00000000,0xb8000051,0x07000102,0x00100901,0x10924941,0x00000000,0x9000891d,
+0x1081c940,0x9000c904,0xc1003c25,0x00900724,0x00924725,0x00000000,0x90004054,0x90008059,
+0x00000000,0x90000051,0x00154200,0x00150301,0x00000000,0xb80183ec,0xb800435b,0x00000001,
+0xe8000051,0x14103b01,0xc10002e4,0xc10000e0,0xc1ffff19,0x00000000,0x9000c3e0,0x9003c3e5,
+0x1091c741,0x00000000,0xb800c704,0xb800805b,0x00000000,0xb8004055,0x00000000,0xb8000050,
+0xb800871d,0x07000101,0x10824741,0x00100901,0x00000000,0xb80083eb,0x00000001,0xe8000075,
+0x14003a01,0x00000000,0xb800c3e7,0xc10000e1,0xe8000015,0x041038e5,0x00000000,0xb80143ef,
+0x00000001,0x00000000,0x009e16ed,0xe800002d,0x04f038e9,0xd2ffff8c,0xc10000e0,0x009e7ae1,
+0xc10001e4,0x90018358,0x900083e5,0xc1ffff18,0x9000c3e0,0x9003c3e5,0xc10000e4,0xc10001e0,
+0x008efbe9,0x00000000,0x9000c3e0,0x900083e5,0x00000000,0xb800d4e3,0x00000001,0xe8000091,
+0x14003801,0x00000000,0x009e16ed,0xe800002d,0x14e03821,0x00000000,0x900194ed,0xd2ffff24,
+0xc10000e0,0xc10001e5,0x00000000,0x9000d4e0,0x9003d4e5,0xc1ffff19,0x00000000,0xa4003be7,
+0xc100ffe1,0xe8000025,0x041039e1,0x00000000,0xa4007be7,0xc100e0e1,0xc100e0e0,0x029e79e1,
+0xe8000095,0x040039e1,0xd2fffed8,0xc10000e0,0x108e7b05,0xc11004e4,0x900194e4,0x900154ed,
+0xc1ffff18,0x9000d4e0,0x9003d4e5,0xd1ffee98,0x10809470,0x0010fb03,0xd10059a4,0x00109403,
+0xe8000049,0x141006fd,0x00000000,0xb80194e3,0x00000001,0x009e16e1,0xe8000015,0x14803821,
+0x109e1621,0x00000000,0x900194e1,0xd2fffe74,0xc10000e0,0xc10001e5,0x00000000,0x9000d4e0,
+0x9003d4e5,0xc1ffff19,0xd1ffeedc,0x10809473,0x001ec601,0xd1ffee30,0x108e3b04,0x10809471,
+0x0010fb00,0x900154ec,0x900194e2,0xd1ffd160,0x00109500,0x0010d403,0xe800001d,0x141006fd,
+0xd2fffe20,0xc10000e1,0x00000000,0x9000d4e1,0xc1ffff19,0x00000000,0xb80115e3,0x00000001,
+0xe8000079,0x14103801,0x00000000,0xb80114e3,0x00000001,0xe800001d,0x14003801,0x00000000,
+0xb800d4e7,0xc10000e1,0xe8000031,0x041038e5,0xd1ffd4c4,0x00109400,0x0010d503,0xe800001d,
+0x141006fd,0xd2fffdbc,0xc10000e1,0x00000000,0x9000d4e1,0xc1ffff19,0x00000000,0xb801d5e4,
+0xb80114eb,0xc10400e1,0x028e39e0,0x900115e9,0x00000000,0x9001d5e1,0x00000000,0xb801d5eb,
+0xc10080e1,0x029e3ae1,0xe80000b5,0x14003801,0xc10001fd,0x00000000,0xb80015e7,0x00000001,
+0xe80000a5,0x14103905,0x00000000,0xb80115e4,0xb80155eb,0xc1000ce1,0x00000000,0x061e78e5,
+0xc10000e1,0xe8000029,0x04d038e4,0xc10000f9,0xc10000e1,0x00000000,0x00000000,0x008e38e9,
+0xe8fffff5,0x04b038e4,0x108fbe05,0xc1ffffe1,0x008fbee1,0x008e3efd,0x120f7809,0x00000000,
+0xb80154e7,0x00000001,0x108ebd20,0x009e16e5,0xe80000fd,0x04b03ae1,0x00000000,0x900194e5,
+0xd2fffce0,0xc10000e0,0xc10001e5,0x00000000,0x9000d4e0,0x9003d4e5,0xc1ffff19,0xd2ffff5a,
+0xc10000fd,0xe8000015,0x1410390c,0xc10000e1,0xc21000e1,0x029e3ae1,0xe80000ad,0x14003801,
+0xc10048f1,0x00000000,0xb80115e4,0xb80155eb,0xc10000e1,0xe8000029,0x04d038e4,0xc10000ed,
+0xc10000e1,0x00000000,0x00000000,0x008e38e9,0xe8fffff5,0x04b038e4,0x108efb05,0xc1ffffe1,
+0x00000000,0x008efbe1,0x00000000,0x061e3aee,0x009e39e1,0x00000000,0x061e78f1,0xc10000e1,
+0xe8000029,0x04d038e4,0xc10000f9,0xc10000e1,0x00000000,0x00000000,0x008e38e9,0xe8fffff5,
+0x04b038e4,0x108fbe05,0xc1ffffe0,0x061e3bf1,0xd2ffff0c,0x00000000,0x008fbee1,0x008e38f9,
+0x008f78fd,0xd2ffff62,0xc10090f1,0x008eb9f4,0xb800d4e5,0x00000000,0x900194ea,0xc10000e1,
+0xe800005d,0x041038e5,0x00000000,0xa4003ae7,0xc100ffe1,0xe8000025,0x041039e1,0x00000000,
+0xa4007ae7,0xc100e0e1,0xc100e0e0,0x029e79e1,0xe8000021,0x040039e1,0x00000000,0xb80154e3,
+0xd2fffc51,0x108ef805,0x00000000,0x900194ed,0xc10001e1,0x00000000,0x9000d4e1,0x00000000,
+0xb801d5e3,0xd2fffb7d,0x128e3821,0xc1000018,0x9001d5e1,0x1092497d,0x10924935,0x1081c97c,
+0x9000891c,0x9000c905,0x1081c734,0x90004920,0xc1002c25,0x00920724,0xc1006025,0x00900724,
+0x00924725,0x00000000,0x90018068,0x9001c06d,0x00000000,0x90010060,0x90014065,0x00000000,
+0x90008058,0x9000c05d,0x00000000,0x90000050,0x90004055,0xc1ffece8,0xc1ffe8e4,0xc1ffe4e1,
+0x00000000,0x0345c7e8,0x034587e5,0x00000000,0x034547e1,0x0016c201,0x00164401,0x00168300,
+0x00000000,0x00160501,0x00000000,0xb801c2e0,0xb80384e7,0x00000001,0xc10000e0,0x900242e4,
+0x129e7821,0xe800007d,0x041038e5,0xd1fffa4a,0x0010c401,0xe800006d,0x141006fd,0xc10000e0,
+0xc1ffff19,0x00000000,0x9002d9e1,0x1091c77d,0x1091c734,0xb8004055,0x00000000,0xb800c704,
+0xb8010061,0x00000000,0xb8000050,0xb800c05d,0x00000000,0xb801c06c,0xb8004721,0x00000000,
+0xb8008058,0xb8018069,0x1082477c,0xb8014064,0xb800871d,0x07000101,0x10824935,0x00100901,
+0x00000000,0xb801dbe4,0xb8001be3,0x00000001,0xe8000028,0x129e79dd,0x14003804,0x9001dbe5,
+0xe8000079,0x14003809,0xe8000089,0x1400380d,0xd2ffff7e,0xc1ffff19,0xd1001891,0x00111a00,
+0x0010db00,0x00109902,0x00150601,0xe8000099,0x141014fd,0x00000000,0xb803d9e7,0xc2f000e1,
+0xc10000e0,0x029e79e1,0xe800001d,0x041038e5,0x00000000,0xb80159e3,0x00000001,0x00000000,
+0x900199e1,0xd2ffff28,0xc10000e1,0x00000000,0x9002d9e1,0xc1ffff19,0xd1001dd1,0x00111a00,
+0x0010db00,0x00109902,0xd2ffffa6,0x00150601,0x109e8950,0x109e0971,0xd10035a0,0x109e4960,
+0x00109901,0x00111a00,0x90003958,0x90003a5d,0x0010db00,0x90003854,0x00115801,0xd2ffff72,
+0x00150601,0x00000000,0xb8001be3,0x00000001,0xe8000049,0x1400380d,0x00000000,0xb801990d,
+0xd1ffe925,0xc1fff8e1,0x008088e1,0xc1fff8e0,0xb801d9e4,0xb80219e1,0x0080c8e0,0x10809971,
+0xd1ffe942,0x00000000,0x900299e0,0x900259e5,0x00000000,0x9002d919,0xd2fffe76,0xc1000019,
+0x10924941,0x1081c940,0x9000891c,0xc1003825,0x00924725,0xc20928e0,0x108282a1,0xc100002c,
+0xc10000f8,0x008fc2e1,0xc10000f4,0x008efe28,0x008f3efd,0xc10000e4,0x108f7d04,0xc10020e1,
+0xc10000e4,0x90003ce4,0xc10048e9,0xe8ffffe8,0xc10048e4,0x90003be5,0x04903de0,0x008efbe8,
+0x008f3ce5,0x1082cb05,0xe8ffffc1,0x14900b48,0x108fbe11,0x1091c741,0x00000000,0xb800871d,
+0x07000102,0x10824741,0x1092497d,0x10924945,0x1081c97c,0x9000891c,0x9000c905,0x1081c744,
+0x90004920,0xc1003025,0x00920724,0xc101b425,0x00900724,0x00924725,0x00000000,0x900700c0,
+0x900740c5,0x00000000,0x900680b8,0x9006c0bd,0x00000000,0x900600b0,0x900640b5,0x00000000,
+0x900580a8,0x9005c0ad,0x00000000,0x900500a0,0x900540a5,0x00000000,0x90048098,0x9004c09d,
+0x00000000,0x90040090,0x90044095,0x00000000,0x90038088,0x9003c08d,0x00000000,0x90030080,
+0x90034085,0x00000000,0x90028078,0x9002c07d,0x00000000,0x90020070,0x90024075,0x00000000,
+0x90018068,0x9001c06d,0x00000000,0x90010060,0x90014065,0x00000000,0x90008058,0x9000c05d,
+0x00000000,0x90000050,0x90004055,0xc1ffece8,0xc1ffe8e0,0xc1ffe4e5,0xc1ffe0e0,0x034e47e8,
+0x0345c7e1,0x00000000,0x0346c7e4,0x034587e1,0x00150200,0x00178501,0x00160301,0x00180401,
+0x00000000,0xac0004e3,0x00000001,0x009778e5,0xe80000e1,0x14e01d01,0xc1201119,0x00000000,
+0xb8004055,0x1091c77c,0xb8000050,0xb800c05d,0x1091c744,0xb8008058,0xb8010061,0x00000000,
+0xb800c704,0xb8018069,0x00000000,0xb8014064,0xb8020071,0x00000000,0xb801c06c,0xb8028079,
+0x00000000,0xb8024074,0xb8030081,0x00000000,0xb802c07c,0xb8038089,0x00000000,0xb8034084,
+0xb8040091,0x00000000,0xb803c08c,0xb8048099,0x00000000,0xb8044094,0xb80500a1,0x00000000,
+0xb804c09c,0xb80580a9,0x00000000,0xb80540a4,0xb80600b1,0x00000000,0xb805c0ac,0xb80680b9,
+0x00000000,0xb80640b4,0xb80700c1,0x00000000,0xb80740c4,0xb8004721,0x1082477c,0xb806c0bc,
+0xb800871d,0x07000101,0x10824945,0x00100901,0xd1ffd274,0xc1ff64e1,0x00000000,0x008108e0,
+0x0010a001,0x0010c501,0x00000000,0xb80014e6,0xc100a4e0,0x0010dd00,0x00109401,0x009e08e1,
+0x00000000,0x900038e5,0x00000000,0xb80054e6,0xd1ffe70c,0xc100a0e1,0x009e08e0,0x00000000,
+0xc1ff5ce9,0x008b48e8,0x900038e5,0xc1ff62e0,0x0010ad01,0x00000000,0x033e48e3,0xc1001fe1,
+0x009e38e5,0xd1ffe7a8,0x129e38e1,0x0087f9e1,0x0010df01,0x00000000,0xa402a0ec,0xa4001ef1,
+0xc21cfce8,0xa40420e4,0xc21d9ce1,0xc21d7ce4,0xc30001e0,0xc30001e9,0xc30001e5,0x120e3b08,
+0x0319fbe0,0x031a3be5,0xeb000048,0x034a78e8,0x00170601,0x120e3c08,0x00975d7c,0x10879e05,
+0x008698e1,0x00151800,0x00000000,0x108ae029,0x14e03b34,0x108b3904,0xc10000a9,0xc1000199,
+0xe8000031,0x14102901,0xd2fffe36,0xc1201219,0x109e7b34,0xc21dbce0,0xc1000099,0x120e7908,
+0xc30001e1,0x00000000,0x034979e1,0xd2ffffd7,0xc1ff64e4,0xac00608c,0xc10001e1,0x020e389c,
+0x034548e6,0xc1ff68e5,0xe8000284,0x00000000,0xc1000091,0x14002300,0x008648e4,0x1098b805,
+0xc1ff1ce1,0x008848e1,0xe80000d8,0xc1ffffe1,0x04101468,0x0088e3e1,0xc1ffffe0,0xa4001ee1,
+0x00000000,0x008b2ce3,0xe8000098,0x120e3809,0x14102c00,0x10879e04,0x00869ae1,0x1102aa00,
+0x108aaa04,0xc21cfcf5,0xc21d9cec,0x031faba8,0xc30001f5,0xc30001ec,0xa40460fc,0xc1fff3e9,
+0xc21d7cf0,0xc21dbce4,0xc10001e1,0xc30001f0,0x00000000,0xc30001e5,0x120efe08,0x0319feec,
+0x008ebee9,0x120eba08,0x031a3ef0,0x034a7bf5,0x108e7f04,0x03497ae5,0x00000000,0x00000000,
+0x09bb0ae5,0x020e389d,0xe8000019,0x14102900,0x1189be34,0x1098b805,0xd2fffd26,0xc1201219,
+0x00000000,0xb80019ef,0x00000001,0x00000000,0x010e15ed,0x10865910,0x09b93890,0x00157b01,
+0xe80000a1,0x14e01f54,0x001f2701,0xc1ff5ce0,0xc1001fe8,0xc1fff8e5,0x00000000,0x034e48e0,
+0x009e3a7d,0x122e380d,0x120fb80d,0xc100a4e0,0x00000000,0x008f7ee5,0x009e08e0,0xa40039ec,
+0x108e7905,0x00000000,0x900038e5,0xe8000045,0x14903d21,0x001eb901,0xc1fff8e0,0xa4003ae0,
+0x120e7b21,0x00000000,0x00000000,0x008f7de2,0xe8ffffe9,0x14f03d20,0x108eba04,0x028ef9e1,
+0xc100a4e1,0x009e08e1,0x00000000,0x900038e9,0x00975df8,0x020e1cf8,0x0087dff9,0x008738ed,
+0x00000000,0x009e1f9d,0xe8000110,0x021e1ce1,0x14002600,0x029ef889,0x120e3b05,0x008ee9e0,
+0x031ea9e3,0x00000001,0xc10000e0,0x129e7a3d,0xe8000055,0x041038e5,0x122f3a10,0xa4007bec,
+0x0097dff1,0xc10001e4,0xc10000e0,0x009e9ff1,0x00000000,0x020e79f0,0x021e9ce9,0x109e7905,
+0x029e7ae5,0x008e7be5,0x120e7905,0x008ee9e4,0x031ea9e7,0x00000001,0x129e7a3d,0xe8ffffbd,
+0x040038e5,0x00000000,0xa4007bbf,0x00000001,0x129baf3c,0xc10001e0,0x122e7a11,0xe80000f8,
+0x0097dfe4,0x020e78b9,0x14102e00,0x029ee4e5,0xc10000e1,0x10851410,0x900014e1,0x122e2f11,
+0xc10001e0,0x129bb83d,0xe80001a8,0x020e78b9,0x14102e00,0x029ee4e5,0xc10000e1,0x10851410,
+0x900014e1,0xe8fffda5,0x14102301,0x00000000,0x008f5f75,0xe8000259,0x14e03d01,0xc10000e1,
+0xc10040e0,0x009e7875,0xe8000571,0x048039e1,0xd2fffb4e,0xc1201319,0x00000000,0x031ea9ef,
+0x00000001,0xc10000e0,0x129e7a3d,0xe8000059,0x041038e5,0x120e3b04,0x122f3a10,0x0097dff1,
+0xc10001e0,0x033e25e0,0x009e5ff1,0x00000000,0x020e38f0,0x021e5ce5,0x109e3805,0x029e79e1,
+0x008ef8e4,0x008e29e1,0x00000000,0x031eb8e7,0x00000001,0xc10000e0,0x129e7a3d,0xe8ffffb9,
+0x040038e5,0x120e3b05,0x00000000,0x033be5e1,0xd2ffff03,0xe8000011,0x14102e3d,0xe800006d,
+0x14102801,0x1097df05,0xe8000034,0x021e1c7d,0x14003b00,0x129c7805,0x120e2e09,0x00000000,
+0x034c21e3,0x00000001,0xd2fffef4,0x099e31c1,0x00000000,0x900014e1,0x10851411,0xd1ffcf21,
+0x0010d500,0x0010ae00,0x028924e6,0x120e6e09,0x008e21e5,0x00000000,0x90003819,0x00000000,
+0x034c21e5,0xd2ffffc7,0x108e2809,0xe8000025,0x04f01fe1,0xd1ffe338,0x0010ad02,0xc100100d,
+0x120e1c40,0x10975d41,0x1087df40,0x02873819,0xc10001e0,0x0010d500,0x0097dfa1,0x021e5c7c,
+0x020e38a1,0xd1ffceb8,0x109e3805,0x029e39e1,0x0080aee1,0x1097df05,0x021e1c7d,0xd2fffe60,
+0x129c7805,0x099e3119,0x10851410,0x900014e1,0xe8000011,0x14102e3d,0xe800006d,0x14102801,
+0x1097df05,0xe8000034,0x021e1c7d,0x14003b00,0x129c7805,0x120e2e09,0x00000000,0x034c21e3,
+0x00000001,0xd2fffe40,0x099e31c1,0x00000000,0x900014e1,0x10851411,0xd1ffce45,0x0010d500,
+0x0010ae00,0x028924e6,0x120e6e09,0x008e21e5,0x00000000,0x90003819,0x00000000,0x034c21e5,
+0xd2ffffc7,0x108e2809,0xe8000025,0x04f01fe1,0xd1ffe25c,0x0010ad02,0xc100100d,0x120e1c40,
+0x10975d41,0x1087df40,0x02873819,0xc10001e0,0x0010d500,0x0097dfa1,0x021e5c7c,0x020e38a1,
+0xd1ffcddc,0x109e3805,0x029e39e1,0x0080aee1,0x1097df05,0x021e1c7d,0xd2fffdac,0x129c7805,
+0x099e3119,0x10851410,0x900014e1,0x192e1501,0x118e9500,0x129e780c,0x122e3809,0x099f3ae4,
+0x099e3ae1,0xe8000365,0x14e038f8,0x10857809,0xc20000e4,0xc10000e8,0x11ce1581,0xc30400e4,
+0x009eba55,0x001e7901,0x022eb9e9,0x09bef8e9,0x108e7c0c,0x00000000,0xc2cc44e1,0x120e7908,
+0xa40220e0,0xc30001e1,0x00000000,0x034e79e3,0x129e3805,0xe8000344,0x21cefbe5,0x14103801,
+0xc2045885,0xc3000185,0x00186101,0xc208f0e1,0x008818e1,0x11ce7d00,0x01ae1481,0x029e39e1,
+0xe8000289,0x14003801,0xe800009d,0x14e01f55,0xc1ff5ce0,0xc1001fe8,0xc1fff8e5,0x00000000,
+0x034e48e0,0x009e3a7d,0x122e380d,0x120fb80d,0xc100a4e0,0x00000000,0x008f7ee5,0x009e08e0,
+0xa40039f0,0x108e7905,0x00000000,0x900038e5,0xe8000045,0x14903d21,0x001eb901,0xc1fff8e0,
+0xa4003ae0,0x120e7c21,0x00000000,0x00000000,0x008f7de2,0xe8ffffe9,0x14f03d20,0x108eba04,
+0x028f39e1,0xc100a4e1,0x009e08e1,0x00000000,0x900038e9,0x00975df8,0x020e1cf8,0x0087dff9,
+0x008738f1,0x109e5f10,0xc10000e1,0x00000000,0x021e5ce5,0xc1000ae4,0x129eb93d,0x00000000,
+0x061e79ea,0x0088a1e5,0x00000000,0xa40262e7,0x00000001,0xe8000045,0x041038e5,0x00000000,
+0xa40062e4,0xa400a2ea,0x1097df11,0xc10001e1,0x020e38e4,0x009e5fe5,0x109e3804,0x021e5ce5,
+0x029e39e1,0xc1000ae0,0x008e7ae1,0x00000000,0x061e38e6,0x0088a1e1,0x00000000,0xa40122e3,
+0xe8000049,0x04101468,0x0097dfe1,0x00000000,0xa4001ee4,0xb80019e3,0x00000001,0xe8000028,
+0x120e7909,0x040015e0,0x10879e04,0x00869ae5,0xd1ffcbcd,0x0010f801,0xc1000108,0x00157801,
+0x001ec601,0x10865911,0x00000000,0xa40162e8,0xa401a2e5,0x109e5f04,0xc10001e1,0x020e38e5,
+0x029e1ce1,0x111f7a00,0x111e3800,0x111f3901,0xc10001e0,0x009e5ff4,0x099eb8ed,0x109e7904,
+0x0097f9f0,0x09bebde9,0x020e38e4,0x900014e9,0x029e1ce1,0x111e3801,0x099e38ed,0x09be3ce1,
+0x10851420,0x900054e1,0xe8000045,0x04101469,0x00000000,0xa4001ee4,0xb80019e3,0x00000001,
+0xe8000028,0x120e7909,0x040015e0,0x10879e04,0x00869ae5,0xd1ffcb29,0x0010f801,0xc1000108,
+0x00157801,0x001ec601,0x10865911,0x00000000,0xa401e2e8,0xa40222e5,0x109e5f04,0xc10001e1,
+0x020e38e5,0x029e1ce1,0x111f7a00,0x111e3800,0x111f3901,0xc10001e0,0x009e5ff4,0x099eb8ed,
+0x109e7904,0x0097f9f0,0x09bebde9,0x008e1f74,0x900014e8,0x020e78e5,0x00000000,0x029e5ce5,
+0x111e7901,0x099e79ed,0x09be7ce5,0x10851420,0x900054e5,0x11ce7800,0x01ae1481,0x029e39e1,
+0xe8fffd89,0x14103801,0x008e1f75,0x118e3801,0x120e3811,0x009514e1,0xc20900e4,0x120e1b0c,
+0xc10240e9,0x120e1608,0x008298e4,0x008e57e1,0x00000000,0x009eca50,0x008e39e1,0x122e7b7d,
+0x129e790d,0x008e7be5,0x122e7909,0xe8000014,0x009e7ae5,0x04e01428,0x900038e5,0xd6000152,
+0xd2fff59e,0xc1000019,0xc20000e8,0xc2ffffe0,0x11ee5515,0xc30400e8,0xc37fffe1,0x001eba00,
+0x001e3801,0x020eba55,0xd2fffca8,0x009e38e9,0x09be39e1,0x008ef8e9,0xd2fffcd5,0xc2057085,
+0xc3000185,0x10924941,0x1081c940,0x9000891c,0xc1007025,0x00900724,0x00924725,0x00000000,
+0x90010060,0x90014065,0x00000000,0x90008058,0x9000c05d,0x00000000,0x90000050,0x90004055,
+0xe8000058,0xc2cd305d,0x14000300,0xc300015d,0xe8000081,0x14000305,0xe80001c5,0x1400030d,
+0x00000000,0xb8004055,0x00000000,0xb8000050,0xb800c05d,0x1091c740,0xb8010060,0xb8014065,
+0x00000000,0xb8008058,0xb800871d,0x07000101,0x10824741,0x00100901,0xc10024e1,0x00000000,
+0x060384e1,0xc10000e1,0xe8ffffb9,0x04e03838,0xc1000058,0xc1000065,0xc100082d,0xc1000034,
+0xc1000c28,0xc1000431,0xd6008156,0xd2ffff97,0xc10000e1,0xe8ffff8d,0x04e03810,0xc1000059,
+0xc2cdc0ed,0xc2cdc0f4,0xc2cdc0e0,0xc2cdc0f1,0xc2cdc0e8,0xc30001ec,0xc2cdc0e5,0xc30001f4,
+0xc30001e0,0xc30001f1,0xc30001e8,0xb801bd54,0xb801fc51,0xc30001e4,0xb8023b4c,0xb8027a49,
+0x00000000,0xb802b944,0xb802f843,0x0013c201,0xc1000064,0xc1000038,0xc1000435,0xc1000830,
+0xc1000c2c,0x10828f31,0xd600616a,0x00000000,0xb8040fe4,0xb80417e1,0x00000000,0xb8044ffc,
+0xb8060fe1,0x00000000,0xb8064fe5,0x00000000,0xb8068fe8,0xb806cfe1,0x00000000,0xb8070fe4,
+0x21ceb9e1,0x00000000,0x00000000,0xb8074fe1,0x00000000,0x90040fe8,0x21cef855,0x10859604,
+0x21ceb950,0xb80457ed,0xc10000f4,0x21cfb848,0x21ce7a4d,0xc10000f0,0x21ceb944,0x90060fed,
+0xc10000e0,0x90064fe8,0x21ce7841,0xc10000ec,0x90068fe4,0x21cfbfed,0xc10000e8,0x90070fe8,
+0x9006cff9,0xc10000e4,0x90074fe4,0x90044ff9,0xc10090e0,0x9007cfe0,0x90078ff5,0xe9ffff34,
+0x90084fec,0x90080ff1,0x0083cfe0,0x9008cfe4,0x90088fe9,0x04801611,0xd2fffe4b,0xc10000e1,
+0xe8fffe41,0x04e03810,0xc1000059,0xc2cdc0ed,0xc2cdc0f4,0xc2cdc0e0,0xc2cdc0f1,0xc2cdc0e8,
+0xc30001ec,0xc2cdc0e5,0xc30001f4,0xc30001e0,0xc30001f1,0xc30001e8,0xb8003d60,0xb8007c55,
+0xc30001e4,0xb800bb50,0xb800fa4d,0x00000000,0xb8013948,0xb8017846,0xc1000041,0x0013c201,
+0x008e9008,0xc10000e0,0xc10000e5,0x00000000,0x90003ae1,0x00000000,0xb8018fe8,0xb801cfe5,
+0xc10000ec,0xb8020fec,0xb8024fe1,0xc10000e0,0xb8028fe8,0xb802cfe5,0xc10000e0,0x90008fe0,
+0x90004fe5,0x00000000,0x90010fe0,0x9000cfed,0xc10000f8,0x21cf3954,0x21cf7a61,0xc10054e0,
+0x21ceb84c,0x21cefb51,0xc1001264,0x21ce3944,0x21ce7a49,0x00828fe0,0x90018ff4,0x90014ff9,
+0xc1004838,0x90020fec,0x9001cff1,0xc1004c34,0x90028fe4,0x90024fe9,0xc1005030,0x9002cfe0,
+0xc100542d,0xd600617a,0x00000000,0xb8088fe8,0xb80897e5,0xc10090e4,0x00000000,0xc10090e1,
+0x00000000,0x008410e6,0x00000000,0x21ce7ae6,0x00000000,0x90088fe5,0x00000000,0xb808cfe8,
+0xb808d7e7,0x00000001,0x10859604,0x21ce7ae5,0xe8ffff11,0x04801610,0x9008cfe4,0x0083cfe1,
+0xd2fffce3,0x10924941,0x1081c940,0x9000891c,0x90004921,0xc100c824,0x10920741,0x00924725,
+0x00134201,0xc1ff70e0,0xc1000031,0x008488e1,0xc2cca02c,0x10829261,0xc1000044,0xc300012d,
+0xd600c18a,0x10830c05,0xe8ffffe9,0x14800c0c,0x108492c0,0x10834d61,0xc1ff70e0,0xc1000045,
+0xc2cdc040,0xc100003c,0x008488e1,0xc3000140,0xc1004830,0xc1001839,0xc1003034,0xc1007828,
+0xc100602d,0xd600a1a6,0x1091c741,0x00000000,0xb8004720,0xb800871d,0x07000102,0x10824741,
+0x10924941,0x1081c940,0x9000891c,0xc1002c25,0x00924725,0xc10000e1,0xe8000025,0x04e03814,
+0xc100003d,0xc1000038,0x00130201,0xc1000034,0x00128300,0x0012c401,0xd602c1be,0x1091c741,
+0x00000000,0xb800871d,0x07000102,0x10824741,0x10924941,0x1081c940,0x9000891c,0xc1003425,
+0x00924725,0x00000000,0xb8000240,0xb800423d,0xc1000039,0xc100042c,0xc1000830,0xc1000035,
+0xc1000c29,0xd600621a,0xc10000e4,0x90040340,0xc10000e1,0x00000000,0x900402e5,0x00000000,
+0x9004433d,0x00000000,0x900442e1,0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,
+0x1092497d,0x10924925,0x1081c97c,0x9000891c,0x9000c905,0x1081c724,0xc1005c25,0x00900724,
+0x00924725,0x00000000,0x90018068,0x9001c06d,0x00000000,0x90010060,0x90014065,0x00000000,
+0x90008058,0x9000c05d,0x00000000,0x90000050,0x90004055,0xc1ffece4,0xc1ffe8e0,0x00168201,
+0x00000000,0x034647e4,0x034ec7e2,0x00158300,0x00160501,0x00154401,0xc10480e4,0xa40244e4,
+0xc22ec0e1,0x00000000,0x061e59e6,0xc30001e0,0x00000000,0x120eb909,0xe8000014,0x0086fae1,
+0x14103909,0xe80001bd,0x14003b01,0xd1000228,0x110e3b01,0x0010db00,0x060539e1,0xc1000210,
+0x00000000,0x00108501,0xd1fffa5d,0x00000000,0x0010d400,0x00109b01,0xc1000211,0x00000000,
+0xa40255f3,0x00000001,0xe80001a1,0x14003c09,0x001ed601,0x120e7b08,0xc1fffce0,0x11debb91,
+0x00000000,0x008e39e1,0x00000000,0x034e3863,0x00000001,0x110e3801,0x029e3ae1,0xe800003d,
+0x14003801,0xc1fff8e1,0x008eb9e1,0xc1ffffe4,0x034e3a60,0xc1fffce1,0x00000000,0x008ebae0,
+0x008efbe7,0x11de7b90,0x110e3801,0x029e39e1,0xe8ffffdd,0x14103801,0xc10240e4,0xc10020e1,
+0xc238e5e4,0x009eb9ed,0x00000000,0x061e7ae6,0xe8000120,0x121e7949,0x14003c08,0x0095f8e5,
+0xd1000154,0xc10120e0,0xc10090e5,0x10911708,0x008098e4,0x0080dbe2,0x10911708,0xa402550d,
+0xd1fff985,0xc10120e1,0x00809be1,0xc20900e0,0x00109b01,0xd1fffd8c,0x060519e1,0x10855aa1,
+0x00115700,0x0080d550,0x00111801,0xc1001fe1,0xe8000039,0x0490385c,0xc1001f59,0xc108b850,
+0x00855551,0xd1fffdac,0x00809454,0x0080d463,0xc1ffffe4,0xc10048e1,0x009514e0,0x008596e5,
+0xe8ffffe5,0x04f0165d,0xd1001bd8,0x00109803,0x1091c77d,0x1091c725,0x00000000,0xb800c704,
+0xb8010061,0x00000000,0xb8004054,0xb8000051,0x00000000,0xb801c06c,0xb800871d,0x00000000,
+0xb800c05c,0xb8008059,0x1082477c,0xb8018068,0xb8014065,0x07000101,0x10824925,0x00100901,
+0xd1fffc44,0x00000000,0x0010db02,0x00108501,0xd1fffc34,0xc10090e0,0xc10048e5,0x0080dbe0,
+0x008098e6,0xd2fffe5b,0xd2fffe6e,0xc10240ed,0xc10002e1,0xe8ffff19,0x04f0385c,0xc1000259,
+0xc1009054,0xc1012051,0xd1fffbfc,0x00809560,0x0080d46f,0x10859604,0xc10090e4,0xc10048e1,
+0xe8ffffe8,0x008555e0,0x008514e5,0x0490165d,0xd2fffedf,0x10924941,0x1081c940,0x9000891c,
+0xc100c025,0x00900724,0x00924725,0x00000000,0x900740c4,0x900780c9,0x00000000,0x9006c0bc,
+0x900700c1,0x00000000,0x900640b4,0x900680b9,0x00000000,0x9005c0ac,0x900600b1,0x00000000,
+0x900540a4,0x900580a9,0x00000000,0x9004c09c,0x900500a1,0x00000000,0x90044094,0x90048099,
+0x00000000,0x9003c08c,0x90040091,0x00000000,0x90034084,0x90038089,0x00000000,0x9002c07c,
+0x90030081,0x00000000,0x90024074,0x90028079,0x00000000,0x9001c06c,0x90020071,0x00000000,
+0x90014064,0x90018069,0x00000000,0x9000c05c,0x90010061,0x00000000,0x90004054,0x90008059,
+0x00000000,0x90000051,0xc10000e1,0xe80001d1,0x04e03810,0xc10000c9,0x001bc201,0xc10000c4,
+0x001b8300,0xc10000c1,0xc25d5ee8,0xc2e352e4,0xc24f1ee1,0xc3fde9e8,0xc30bcbe4,0xc3fb30e1,
+0x001b7a00,0x001b3900,0x001af801,0xc25284e8,0xc277f9e4,0xc219fde1,0xc30763e8,0xc3f281e4,
+0xc30ffce1,0x001aba00,0x001a7900,0x001a3801,0xc2769ee8,0xc2cdbbe4,0xc237ade1,0xc3fc89e8,
+0xc3f1cee4,0xc30acfe1,0x0019fa00,0x0019b900,0x00197801,0xc2e890e8,0xc2c779e4,0xc255c2e1,
+0xc30f9ee8,0xc30898e4,0xc3ff4de1,0x00193a00,0x0018f900,0x0018b801,0xc2934be8,0xc21770e4,
+0xc2ad7ce1,0xc3f0bde8,0xc3f061e4,0xc3f89ce1,0x00187a00,0x00183900,0x0017f801,0xc2aa3ee8,
+0xc21caee4,0xc26cb5e1,0xc300b2e8,0xc3f434e4,0xc30f42e1,0x0017ba00,0x00177900,0x00173801,
+0xc28807e8,0xc23887e4,0xc2b0e2e1,0xc30d7ee8,0xc3f767e4,0xc304cfe1,0x0016fa00,0x0016b900,
+0x00167801,0xc2c853e8,0xc2e603e4,0xc23245e1,0xc3f530e8,0xc3f003e4,0xc30e31e1,0x00163a00,
+0x0015f900,0x0015b801,0xc28962e8,0xc29346e4,0xc28360e1,0xc30376e8,0xc30cb1e4,0xc3f642e1,
+0x00157a00,0x00153900,0x0014f801,0xc2f549e8,0xc20ab7e4,0xc26cbae1,0xc30fdce8,0xc3f023e4,
+0xc3f34ee1,0x0014ba00,0x00147900,0x00143801,0xc27ca0e8,0xc2a2a2e4,0xc2ca18e1,0xc309bde8,
+0xc30216e4,0xc3f137e1,0x0013fa00,0x0013b900,0x00137801,0xc28756e8,0xc278aae4,0xc235e8e1,
+0xc3f9e0e8,0xc3061fe4,0xc30ec8e1,0x00133a00,0x0012f900,0x0012b801,0xd606c22a,0x00000000,
+0xb8000050,0xb8004055,0x00000000,0xb8008058,0xb800c05d,0x00000000,0xb8010060,0xb8014065,
+0x00000000,0xb8018068,0xb801c06d,0x00000000,0xb8020070,0xb8024075,0x00000000,0xb8028078,
+0xb802c07d,0x00000000,0xb8030080,0xb8034085,0x00000000,0xb8038088,0xb803c08d,0x00000000,
+0xb8040090,0xb8044095,0x00000000,0xb8048098,0xb804c09d,0x00000000,0xb80500a0,0xb80540a5,
+0x00000000,0xb80580a8,0xb805c0ad,0x00000000,0xb80600b0,0xb80640b5,0x00000000,0xb80680b8,
+0xb806c0bd,0x1091c740,0xb80700c0,0xb80740c5,0x00000000,0xb80780c8,0xb800871d,0x07000101,
+0x10824741,0x00100901,0x10924941,0x1081c940,0x9000c904,0x9000891d,0xc100e824,0x90004920,
+0x10920741,0x00900724,0x00924725,0x00000000,0x90034084,0x90038089,0x00000000,0x9002c07c,
+0x90030081,0x00000000,0x90024074,0x90028079,0x00000000,0x9001c06c,0x90020071,0x00000000,
+0x90014064,0x90018069,0x00000000,0x9000c05c,0x90010061,0x00000000,0x90004054,0x90008059,
+0x00000000,0x90000051,0x00178200,0x00154301,0x00000000,0xb900c4e6,0xc10088e1,0x009e08e1,
+0x00000000,0x900038e5,0x00000000,0xb90104e6,0xc10084e1,0x009e08e1,0x00000000,0x900038e5,
+0x00000000,0xb80043e3,0x00000001,0xe800013c,0xc1ff78e5,0x14003800,0x008748e4,0x00150301,
+0xc1000271,0xe800002d,0x14103808,0xc100206d,0x00000000,0xb801c3e8,0xb80083e3,0xc10100e5,
+0x120e3808,0x028e7ae5,0x1086f810,0x9001c3e5,0x00000000,0xb801c3e3,0x00000001,0x129e3841,
+0xe80000f1,0x14003801,0xc10020e0,0xac031410,0x061e5b71,0xd1ffd368,0x009e386d,0x008e39e1,
+0x10808270,0x00000000,0x1200f809,0x00000000,0xac0354e0,0x8403141b,0x00000001,0xe80000b5,
+0x040006e1,0x00000000,0xb80255e3,0x00000001,0xc10000e0,0x129e7805,0xe8000099,0x041038e5,
+0xc12009e0,0xc1ffff19,0x00000000,0x9003dee1,0x1091c740,0xb8000050,0xb8004055,0x00000000,
+0xb800c704,0xb8008059,0x00000000,0xb800c05c,0xb8010061,0x00000000,0xb8014064,0xb8018069,
+0x00000000,0xb801c06c,0xb8020071,0x00000000,0xb8024074,0xb8028079,0x00000000,0xb802c07c,
+0xb8030081,0x00000000,0xb8034084,0xb8038089,0x00000000,0xb8004720,0xb800871d,0x07000101,
+0x10824741,0x00100901,0xd2fffede,0xc1000171,0xc10000e1,0xe800007d,0x04f0386c,0xc1000069,
+0xc1ffc0e1,0x008548e1,0xc10000e1,0xe8000059,0x04f03870,0xc100007d,0x00851a55,0xd1ffd0f0,
+0x10809e72,0xc100040d,0xe800001d,0x1410063d,0xd2ffff40,0xc1200ae1,0x00000000,0x9003dee1,
+0xc1ffff19,0xe800007d,0x14000601,0x108e0605,0x1087df04,0x800014e1,0xe8ffffc5,0x04901f70,
+0x10851481,0x10869a05,0xe8ffffa1,0x04901a6d,0xc10020e1,0xe8000085,0x04f01be0,0x00169b01,
+0xc1ffc0e4,0xc1ffe0e1,0x008e48e4,0x008e08e1,0x00851be4,0x00855be1,0xd1ffd074,0x10809e72,
+0xc100040d,0xe8000025,0x1410063d,0xd2fffec4,0xc1200ae1,0x00000000,0x9003dee1,0xc1ffff19,
+0xd2ffff92,0xc10000e1,0xe80000b1,0x14000601,0x108e4605,0x10869a04,0x800015e4,0xc10020e1,
+0xe8ffffb8,0x00000000,0x800014e5,0x04901ae0,0x10851404,0x10855505,0xc1ffc0e4,0xc1ff80e0,
+0xc1000069,0x008648e4,0x008608e1,0xc10000e1,0xe8000089,0x04f03870,0xc100007d,0x00159900,
+0x00155800,0x00851a61,0x00000000,0x031e166b,0x00000001,0xe800004d,0x14003801,0xd1ffcfd0,
+0x10809e72,0xc100060d,0x00000000,0x80001419,0x00000000,0x031e556b,0xc1003fe1,0xe8000025,
+0x041039e1,0xd2fffe0c,0xc1200be1,0x00000000,0x9003dee1,0xc1ffff19,0xd2ffff5e,0xc10000e5,
+0x1087df05,0xe8ffffa4,0x10855581,0x04901f70,0x10851480,0x10859681,0x10869a04,0xc10020e1,
+0xe8ffff6d,0x04901ae1,0x00000000,0x161e1b32,0xc1000058,0x12057808,0xc100005d,0xc10000e1,
+0xe80000ad,0x04f0386c,0xc1000069,0x00189601,0xc10000e1,0xe8000089,0x04f03870,0xc100007d,
+0xc1000084,0x00181900,0x00151801,0x00000000,0x031e206b,0x00000001,0xe8000139,0x14003801,
+0xd1ffbc20,0x10809e70,0x0010f803,0x00000000,0x034e1d84,0x031e946b,0xc2b100e5,0xc30001e4,
+0x008e22e0,0x120eba09,0x00000000,0x034e7ae7,0x00000001,0x00000000,0x21fe46e6,0x00000000,
+0x900038e5,0x1087df05,0xe8ffffa4,0x10886111,0x04901f70,0x10851480,0x10882081,0x10869a05,
+0xe8ffff71,0x04901a6c,0x1088a2c1,0xc10020e1,0xe80000a5,0x04f01be0,0x00169b01,0x00151501,
+0x00000000,0x031e196b,0x00000001,0xe80000c1,0x14003801,0xd1ffbb8c,0x10809e70,0x0010f803,
+0xc10000e1,0xe800005d,0x04f03870,0xc100007d,0xc10000f0,0x001ed801,0x00000000,0x034e1df0,
+0x031ebb6b,0xc2b100e5,0xc30001e4,0x008e14e0,0x120eba09,0x00000000,0x034e7ae7,0x00000001,
+0x1087df04,0x00000000,0x21fe46e5,0xe8ffffcc,0x108efb81,0x04901f70,0x108f3c10,0x900038e5,
+0x10869a04,0xc10020e1,0xe8ffff79,0x04901ae0,0x108514c1,0x1085d705,0xe8fffea5,0x14901730,
+0x10855510,0x10859611,0xd2fffc4a,0xc1000019,0x00000000,0x034e1d87,0xd2ffff0d,0xc10000e0,
+0x008e62e1,0x00000000,0x900039e1,0xc10000e1,0xe8ffffb1,0x04f03870,0xc100007d,0xc10000e9,
+0x00000000,0x034e1deb,0x1087df05,0xe8fffff4,0xc10000e0,0x008e54e1,0x04901f70,0x108eba10,
+0x900039e1,0xd2ffff7f,0x10924941,0x1081c940,0x9000c904,0x9000891d,0xc101e424,0x90004920,
+0x10920741,0x00900724,0x00924725,0x00000000,0x9004c09c,0x900500a1,0x00000000,0x90044094,
+0x90048099,0x00000000,0x9003c08c,0x90040091,0x00000000,0x90034084,0x90038089,0x00000000,
+0x9002c07c,0x90030081,0x00000000,0x90024074,0x90028079,0x00000000,0x9001c06c,0x90020071,
+0x00000000,0x90014064,0x90018069,0x00000000,0x9000c05c,0x90010061,0x00000000,0x90004054,
+0x90008059,0x00000000,0x90000051,0x00188200,0x00160301,0x00000000,0xb900c4e6,0xc1015ce1,
+0x009e08e1,0x00000000,0x900038e5,0x00000000,0xb90104e6,0xc10158e1,0x009e08e1,0x00000000,
+0x900038e5,0x00000000,0xb80043f3,0x00000001,0xe8000338,0xc1fea4e1,0x14003c00,0x008848e0,
+0x00164301,0xc1000281,0x00000000,0xb801c3ef,0xc21000e1,0x029e3be1,0xe8000319,0x14003801,
+0xc10004e9,0xc2b234e4,0x160e3a78,0xc2b23cf5,0xc30001e4,0x00000000,0xc30001f5,0x00000000,
+0x0087b8f4,0x0317fae6,0xe8000029,0x14103c08,0xc1002075,0xc10100e0,0xb80083e1,0x028e3be1,
+0x00000000,0x9001c3e2,0x120e3809,0x10877811,0x009e5f74,0xb801c2e5,0x00000000,0x01de1d7d,
+0x00000000,0x00000000,0x061eb9e1,0x109e0821,0x00000000,0x900038e4,0x00877a75,0x00000000,
+0x00000000,0xb80202ea,0xc1fff8e8,0x109e4810,0xc10000e1,0xe800007c,0x008688e9,0x04f03874,
+0xc1000070,0x900039e9,0xc1ffb8e1,0x008588e1,0x00000000,0x031e5e73,0xc2b2d4e1,0xc30001e0,
+0x120e7905,0x00000000,0x00000000,0x031579e1,0xc10000e1,0xe8000031,0x04f03880,0xc100006d,
+0x00851c59,0xd1ffcb88,0x1080a270,0x0010d503,0x1086db04,0x80001419,0xe8ffffed,0x04901b80,
+0x10851481,0x10871c05,0xe8ffffa9,0x04901c75,0xe8000065,0x04f01d7c,0x00171d01,0xc1ffb8e4,
+0xc1ffd8e1,0x008e48e4,0x008e08e1,0x00851de4,0x00855de1,0x1080a270,0x031e5e73,0xc2b2d4e1,
+0xc30001e0,0x120e7905,0x00000000,0x0310f9e1,0xd1ffcb1f,0x00000000,0x10871c04,0x80001519,
+0xe8ffffd4,0x80001419,0x04901c7c,0x10855504,0x10851405,0xc10000e1,0xe800007d,0x04f0387c,
+0xc1000071,0xc1ffb8e4,0xc1ff78e1,0x0085c8e4,0x008588e1,0xc10000e1,0xe8000051,0x04f03880,
+0xc100006d,0x00155700,0x00851c59,0x00000000,0x031e1573,0x00000001,0xe800001d,0x14003801,
+0xd1ffcaac,0x1080a272,0xc100020d,0x00000000,0x80001419,0x1086db05,0xe8ffffd5,0x04901b80,
+0x10851480,0x10855581,0x10871c05,0xe8ffffa9,0x04901c7d,0x00000000,0xb801d9e3,0x00000001,
+0x129e3841,0xe80001c9,0x14003801,0xd1ffc8d4,0x00109a00,0x1080e273,0x00109a00,0xac031911,
+0xd1ffcbbe,0x0010c601,0x00000000,0xac0359e0,0x8403191b,0x00000001,0xe8000195,0x040006e1,
+0x00000000,0xb80258e3,0x00000001,0xc10000e0,0x129e7805,0xe8000179,0x041038e5,0xc12009e0,
+0xc1ffff19,0x00000000,0x9003e2e1,0x1091c740,0xb8000050,0xb8004055,0x00000000,0xb800c704,
+0xb8008059,0x00000000,0xb800c05c,0xb8010061,0x00000000,0xb8014064,0xb8018069,0x00000000,
+0xb801c06c,0xb8020071,0x00000000,0xb8024074,0xb8028079,0x00000000,0xb802c07c,0xb8030081,
+0x00000000,0xb8034084,0xb8038089,0x00000000,0xb803c08c,0xb8040091,0x00000000,0xb8044094,
+0xb8048099,0x00000000,0xb804c09c,0xb80500a1,0x00000000,0xb8004720,0xb800871d,0x07000101,
+0x10824741,0x00100901,0xd2fffce2,0xc1000181,0xe8000079,0x14102009,0x00000000,0xb80103e3,
+0x00000001,0x121e7805,0xc27d00e1,0xe8000069,0x040039e1,0xc2bb80e1,0xe800005d,0x040039e1,
+0xc2dac0e1,0xe8000079,0x040039e1,0xc2fa00e1,0xe800006d,0x040039e1,0xc23880e1,0xc30001e1,
+0xe800005d,0x040039e1,0x00000000,0xb80143e7,0xc2bb80e1,0xe8000051,0x041039e1,0xc10000e1,
+0xd2fffc86,0x001eb801,0x00000000,0xb80103e5,0xd2ffff9b,0x00000000,0xb80143e7,0xc27d00e1,
+0xe8000015,0x041039e1,0xc10003e1,0xd2fffc5a,0x001eb801,0xd2fffffa,0xc10002e1,0xd2fffc4a,
+0xc10000e9,0xd2ffffbe,0xc10001e1,0xc10000e1,0xe80001a5,0x04f0387c,0xc1000071,0xc1ffb8e8,
+0xc1feb8e4,0xc1ff78e1,0x008948e8,0x008908e4,0x0088c8e1,0xc1000068,0xc1000164,0xc1000261,
+0xc10000e1,0xe8000159,0x04f03880,0xc100006d,0x00156301,0x0015e500,0x00851a90,0x0015a401,
+0x00000000,0x031e1773,0x00000001,0xe800010d,0x14003801,0xd1ffc838,0x1080a272,0xc100060d,
+0x00000000,0x80001419,0x00000000,0x031e1573,0x00000001,0xe80000a5,0x14003809,0xe80000b5,
+0x14003801,0xe80000c1,0x14003805,0xe80000b9,0x1400380d,0x00000000,0x031e5573,0x00000001,
+0x129e3905,0xe8000021,0x14003801,0x109e3905,0x00000000,0x031e14e3,0x00000001,0x00000000,
+0x800054e1,0x00000000,0x031e9958,0x031f1669,0x00000000,0x031e5859,0xc1003fec,0xc1003fe1,
+0xc1003fe5,0x010ebae4,0x00000000,0x010efced,0x010e39e0,0x028e7be9,0x028e39e1,0xe800005d,
+0x14003801,0xd2fffd88,0xc1200be1,0x00000000,0x9003e2e1,0xc1ffff19,0x00000000,0x031e166a,
+0xd2ffff76,0x00000000,0x800094e0,0x800054e1,0xd1ffc75c,0x1080a272,0xc100060d,0x00000000,
+0x80005419,0xd1ffc748,0x1080a272,0xc100060d,0xd2ffff44,0x8000941b,0x1086db04,0xc10060e4,
+0xc10060e1,0xe8fffedc,0x008514e0,0x008596e5,0x04901b80,0x1085d780,0x10855581,0x10871c05,
+0xe8fffea0,0x10869a0d,0x04901c7c,0x1086180c,0x1086590d,0xc2b2d4f0,0x161e5d90,0x161e1f91,
+0xc1ffb8f5,0xc30001f0,0xc10001ec,0xc1feb8e9,0x108e7908,0x108e3808,0xc1000069,0x008648f4,
+0x0085c8e8,0x00863bf1,0xc1000858,0x12057908,0x12053809,0xc10000e1,0xe800017d,0x04f03874,
+0xc1000071,0x1219da08,0xc1000098,0x00195601,0xc10000e1,0xe8000145,0x04f03880,0xc100006d,
+0xc10000a0,0x00191900,0x0088e65d,0x00000000,0x031ea473,0x00000001,0xe8000305,0x14003a01,
+0xc1ffffe0,0x031e1e71,0x00000000,0x00000000,0x008e7ae1,0xc1feace0,0x00000000,0x1080a271,
+0x008108e1,0x120e3805,0x00000000,0x031e18e3,0x00000001,0xc2b2e4e0,0x160eb83d,0xc30001e1,
+0x008e3ae1,0x00000000,0x031eb8e7,0x00000001,0xd1ffb3e0,0xc2b340e0,0x160e7a51,0xc30001e1,
+0x0080f9e1,0x00000000,0x031e239d,0x00000000,0x034e21a2,0xc1feace4,0x00000000,0xc2b100e9,
+0xc30001e8,0x00000000,0x120ef809,0x008e25e0,0x034e48e4,0x034ebbeb,0x00000001,0x00000000,
+0x21fe79e9,0x109e3821,0xc1feb0e0,0x900038e5,0x00000000,0x034e48e0,0x034e21a3,0x00000001,
+0x008e25e0,0x21fe79e9,0x109e3811,0xc1feb4e0,0x900038e5,0x00000000,0x034e48e0,0x034e21a3,
+0x00000001,0x008e25e0,0x21fe79ea,0x00000000,0x900038e5,0x00000000,0xc10060e0,0x1086db05,
+0xe8fffeec,0x00000000,0x0088e3e1,0x04901b80,0x10892480,0x108a2811,0x10871c04,0xc10090e1,
+0xe8fffeb0,0x00000000,0x008965e1,0x04901c74,0x1089a60d,0xe800016d,0x04f01d7c,0x00171d01,
+0x00000000,0x16091d0d,0x0018d500,0x00000000,0x12195a09,0x00000000,0x031e9973,0x00000001,
+0xe80001f9,0x14003a01,0xc1ffffe0,0x031e1e71,0x00000000,0x00000000,0x008e7ae1,0xc1feace0,
+0x00000000,0x1080a271,0x008108e1,0x120e3805,0x00000000,0x031e18e3,0x00000001,0xc2b2e4e0,
+0x160eb83d,0xc30001e1,0x008e3ae1,0x00000000,0x031eb8e7,0x00000001,0xd1ffb278,0xc2b340e0,
+0x160e7a51,0xc30001e1,0x0080f9e1,0xc10000e1,0xe80000b5,0x04f03880,0xc100006d,0xc10000f4,
+0x008f245d,0x00000000,0x031efc95,0x00000000,0x034e61f5,0xc1feace5,0xc2b100e8,0x00000000,
+0xc10060e1,0xc30001e8,0x034e48e4,0x120efb09,0x008f3ce0,0x034ebbe8,0x008e23e7,0x00000001,
+0x00000000,0x21fe79e9,0x109e3821,0xc1feb0e0,0x900038e5,0x00000000,0x034e48e0,0x034e21f7,
+0x00000001,0x008e23e0,0x21fe79e9,0x109e3811,0xc1feb4e0,0x900038e5,0x00000000,0x034e48e0,
+0x034e21f7,0x00000001,0x1086db04,0x21fe79e8,0x008e23e1,0xe8ffff71,0x04901b80,0x108f7d10,
+0x900038e5,0x10871c04,0xc10090e1,0xe8fffec8,0x00000000,0x0088e3e1,0x04901c7c,0x1089240d,
+0xc10000e1,0xe8000039,0x04f03880,0xc100006d,0xc100002d,0xc10020e1,0xe8000015,0x04f01fe0,
+0x00171f01,0x00129401,0xd6002306,0x1086db05,0xe8ffffe5,0x04901b80,0x1082cb11,0x10869a05,
+0xe8fffcd4,0x10851431,0x14901a30,0x10855530,0x10859631,0xd2fff97a,0xc1000019,0x00000000,
+0x034e21a3,0x00000001,0x008e25e1,0xc10000e4,0x109e3821,0x00000000,0x900038e5,0x00000000,
+0x034e21a3,0x00000001,0x008e25e1,0xc10000e4,0x109e3811,0x00000000,0x900038e5,0x00000000,
+0x034e21a3,0xd2fffdb1,0xc10000e0,0x008e65e1,0x00000000,0x900039e1,0xc10000e1,0xe8ffff29,
+0x04f03880,0xc100006d,0xc10000e9,0x00000000,0x034e21eb,0x00000001,0x008e23e1,0xc10000e4,
+0x109e3821,0x00000000,0x900038e5,0x00000000,0x034e21eb,0x00000001,0x008e23e1,0xc10000e4,
+0x109e3811,0x00000000,0x900038e5,0x00000000,0x034e21eb,0x1086db05,0xe8ffffb4,0xc10000e0,
+0x008e63e1,0x04901b80,0x108eba10,0x900039e1,0xd2fffeb7,0x10924941,0x1081c940,0x9000891d,
+0x10924771,0x009e820d,0xe800002d,0x14803a00,0x90000408,0xc10000e5,0x001e3a00,0x009eba0d,
+0xe8fffff9,0x14e03a00,0x108e7905,0x00000000,0x900004e1,0x00000000,0x900005e5,0x1091c741,
+0x00000000,0xb800871d,0x07000102,0x10824741,0x10924941,0x1081c940,0x9000c904,0x9000891d,
+0xc1009424,0x90004920,0x10920741,0x00900724,0x00924725,0x00000000,0x90034084,0x90038089,
+0x00000000,0x9002c07c,0x90030081,0x00000000,0x90024074,0x90028079,0x00000000,0x9001c06c,
+0x90020071,0x00000000,0x90014064,0x90018069,0x00000000,0x9000c05c,0x90010061,0x00000000,
+0x90004054,0x90008059,0x00000000,0x90000051,0x00154200,0x00158300,0x0015c401,0x00000000,
+0xa40243e0,0xac00c367,0x00000001,0xe800025d,0x14103809,0x00000000,0xa40203e3,0x00000001,
+0x129e3821,0xe800023d,0x14003801,0xc1000261,0x129e0504,0xb80002ed,0x111eb800,0x111e4400,
+0xc10000e1,0x00000000,0x029e7ae5,0x109e8821,0x00000000,0x90003aed,0x00000000,0x00000000,
+0xb80042ee,0x109e8811,0xe80002d0,0xc1fff8f1,0x041038e4,0x008508f0,0x90003aed,0xc10190e1,
+0xe80001f1,0x04f019e1,0x12109911,0xd1fffe88,0xc1ffe8e4,0xc1ffece1,0x00000000,0x008108e0,
+0x008148e5,0xc100050d,0x129e993c,0xc2c8c4e0,0x109e4841,0x121f3a08,0x129ed90c,0x109e8831,
+0x120e5808,0x900039f0,0xc30001e1,0x0086b9e0,0x90003aed,0xc21e08e8,0xc1000089,0xc30001e9,
+0x001eba01,0x1088a204,0xc1002de0,0xc10000e5,0xe8fffff4,0x00000000,0x90003ae5,0x049022e0,
+0x108eba11,0xc1000085,0xc1ffe8e0,0xc1000064,0xc1000081,0x008708e0,0xc1000060,0x1086d649,
+0x00000000,0x031e5a87,0xc10000e1,0xe8000071,0x04f038e4,0xc1000089,0xc21e08e0,0x0085e06d,
+0xc30001e1,0x008598e1,0x00109500,0x0340dc65,0xd1ffc05f,0x00000000,0x034e5c64,0x80001719,
+0x00000000,0x031e1a85,0xc10001e1,0x1088a204,0x00000000,0x10861811,0x10882004,0x00000000,
+0x020e78e5,0xe8ffffc4,0x1085d704,0x109e7905,0x049022e0,0x10859610,0x900016e5,0x10886105,
+0xe8ffff81,0x14902110,0x10865911,0xc10027e1,0xe800002d,0x04f020e1,0x008ea06d,0x10882004,
+0xc10027e0,0xc10000e5,0xe8fffff4,0x00000000,0x80003ae5,0x049020e0,0x108eba05,0xd1ffbe44,
+0x00109400,0x0010d503,0x1091c740,0xb8000050,0xb8004055,0x00000000,0xb800c704,0xb8008059,
+0x00000000,0xb800c05c,0xb8010061,0x00000000,0xb8014064,0xb8018069,0x00000000,0xb801c06c,
+0xb8020071,0x00000000,0xb8024074,0xb8028079,0x00000000,0xb802c07c,0xb8030081,0x00000000,
+0xb8034084,0xb8038089,0x00000000,0xb8004720,0xb800871d,0x07000101,0x10824741,0x00100901,
+0xd2fffdd2,0xc1000161,0xd2fffdca,0xc1000061,0xc101f4e1,0xe800005d,0x04f019e1,0xd1fffc98,
+0xc1ffece0,0xc10190e5,0xc1ffe8e0,0x009659e4,0x008108e1,0xc100050c,0x12109908,0x008148e1,
+0xc2c8c4e0,0x129f590c,0x109f0841,0xd2fffe28,0x109e8830,0xc30001e1,0x120e1808,0x108e7830,
+0xc10000ed,0x0086b9e0,0x90003cf4,0x90003aed,0xd1fffc44,0xc1ffece1,0xc1ffe8e0,0x008108e0,
+0xc101f4e5,0xc100030c,0x009099e4,0x008148e1,0xc2c8c4e0,0xa40216e0,0xc100ffe9,0xc30001e0,
+0xc10000f4,0x109f0841,0xc10000ec,0x109e0830,0x108e7861,0x00000000,0x900038ec,0x90003cf5,
+0xd2fffdb4,0x128e3811,0x120e1808,0x029eb8e9,0x0086b9e0,0x800216e9,0x12165904,0xc100b4e1,
+0xe8000171,0x04f019e1,0x00109901,0xd1fffbc8,0xc1ffe4e4,0xc1ffe8e1,0x00000000,0x008148e0,
+0x008108e5,0xc100240d,0xc1ffe4e8,0xc1fff0e4,0xc1ffece1,0x008148e0,0x034088e8,0x008108e5,
+0xd1fffb96,0xc100060d,0xc2c8c4e4,0xc10000e8,0x109e0831,0xc30001e4,0x900038e8,0x120e1809,
+0x108e7991,0x0086b9e1,0xc1ffe8e0,0xc1000085,0xc1000080,0x10875748,0x0087c8e1,0x10879648,
+0xc100006c,0xc1000071,0x00000000,0x031e5a84,0x034edf72,0xc10001e9,0xc10000e1,0xe8000084,
+0x020ebaed,0x04f038e4,0xc1000088,0x10967a05,0xc21e08e0,0x0085e074,0x00862079,0xc30001e1,
+0x00859be1,0x00109500,0x0340df71,0xd1ffbda3,0x010e0664,0x034e5f70,0x80001819,0x00000000,
+0x800017e1,0x00000000,0x00000000,0x031e1a85,0xc10001e1,0x1088a204,0x020e38e4,0x10882005,
+0x10861804,0x109e7805,0xe8ffffbc,0x1085d704,0x900016e5,0x049022e0,0x1086db10,0x10859611,
+0x10886105,0xe8ffff65,0x14902110,0x10871c11,0xc10027e1,0xe8fffd69,0x04f020e1,0x008ea074,
+0x008ee079,0xc10000e4,0xc10027e1,0x10882004,0xc10000e4,0x80003be5,0xe8ffffec,0x80003ae5,
+0x049020e0,0x108efb04,0x108eba05,0xd2fffd33,0xc100f4e1,0xe8000065,0x04f019e1,0xc100b4e0,
+0xc2c8c4e5,0xc1003fe0,0x009659e0,0x10928861,0xc30001e4,0x029e19e0,0x109f8851,0x129e193c,
+0x129f590c,0x1212f811,0x121ff808,0x109e8830,0x109f0841,0xd2fffeb4,0xc10000ec,0x120e1809,
+0x108e79c0,0x90000a2c,0x90003cf5,0x0086b9e0,0x90003efc,0x90003aed,0xd1fff9fc,0xc1ffece1,
+0xc1ffe8e0,0x008108e0,0xc100f4e5,0xc100030c,0x009099e4,0x008148e1,0xc2c8c4e0,0xc10000f4,
+0x109f0841,0xd2fffe64,0x109e8830,0xc30001e1,0x120e1808,0x108e78f0,0xc10000ed,0x0086b9e0,
+0x90003cf4,0x90003aed,0x10924941,0x1081c940,0x9000891c,0xc1003c25,0x00924725,0x00000000,
+0xb80003e7,0xc10227e1,0xe8000085,0x04a039e1,0xc10240e4,0xc20900e1,0x008482e0,0x900003e5,
+0xc10048e1,0x008442e1,0xe8000051,0x04e01149,0xc1fffce0,0xb800113c,0xc2cc6035,0x00000000,
+0x034411e1,0xc1000038,0xc2cc8031,0xc100042c,0x00000000,0xc3000135,0xc3000130,0x00000000,
+0x00129101,0xd600631a,0xc10048e1,0x008451e1,0xe8ffffc1,0x04801149,0x1091c741,0x00000000,
+0xb800871d,0x07000102,0x10824741,0xd2ffff94,0x108e7965,0x120e3909,0x0084b808,0x900003e5,
+0x10924941,0x1081c940,0x9000891d,0x10924771,0xc10048e0,0xc100012d,0x008282e1,0xd600832a,
+0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,0x1092497d,0x10924935,0x1081c97c,
+0x9000891c,0x9000c905,0x1081c734,0x90004920,0xc1002c25,0x00920724,0xc100b825,0x00900724,
+0x00924725,0x00000000,0x900680b8,0x9006c0bd,0x00000000,0x900600b0,0x900640b5,0x00000000,
+0x900580a8,0x9005c0ad,0x00000000,0x900500a0,0x900540a5,0x00000000,0x90048098,0x9004c09d,
+0x00000000,0x90040090,0x90044095,0x00000000,0x90038088,0x9003c08d,0x00000000,0x90030080,
+0x90034085,0x00000000,0x90028078,0x9002c07d,0x00000000,0x90020070,0x90024075,0x00000000,
+0x90018068,0x9001c06d,0x00000000,0x90010060,0x90014065,0x00000000,0x90008058,0x9000c05d,
+0x00000000,0x90000050,0x90004055,0xc1ffece8,0xc1ffe8e4,0xc1ffe4e1,0x00000000,0x034a47e8,
+0x034a07e5,0x00000000,0x0349c7e2,0x001ac201,0x001a8500,0x00000000,0x00154401,0x00000000,
+0xb801c3e4,0xb80143ef,0xc24000e1,0x029eb9e1,0xe8000011,0x14003a00,0x00198301,0x120efb05,
+0x121e3b3c,0x121e7b1d,0x129e3804,0x129e793d,0xe8000014,0x109e3821,0x14003a00,0x008538e5,
+0x1085140d,0xc21eece1,0xc30001e1,0x00000000,0xa00038e3,0x00000001,0xe8000025,0x14103801,
+0xd1ffb2a4,0x00109403,0xc21eece4,0xc10001e1,0xc30001e5,0x00000000,0x800039e1,0x00000000,
+0xb801e6e7,0xc21000e1,0x029e39e1,0xe8000241,0x14003801,0xc10001e5,0xc10000e0,0x900028e5,
+0xe80003c9,0x04f038e4,0xc1000095,0x00000000,0x16089431,0xc2cbc0e8,0x00000000,0xc2cbc0f1,
+0x10892a28,0xc1fff8ec,0xc2cbc0e5,0xc2100ce0,0xc30001e4,0xc30001f1,0xc30001e8,0x0088d5e0,
+0xc10008e1,0xc10004e0,0x008862f0,0x0087f8e9,0x10872920,0x0087b8e4,0x008808ed,0xc100006c,
+0x00161c00,0x10876a21,0xc1000068,0xc100005c,0x00166401,0xc10000e1,0xe8000231,0x04f0389c,
+0xc10000b1,0x001b5901,0xc10000bc,0x0015a000,0xc10000b9,0x00000000,0xa4026de0,0x034e63b9,
+0x00000000,0xb80021e7,0xe8000040,0x00000000,0x008557e5,0x14103808,0x900016e5,0x00000000,
+0xa4022de3,0x00000001,0x129e3821,0xe8000169,0x14003801,0x00000000,0x034e1f8b,0x00000001,
+0x00000000,0x900016e1,0x00000000,0xb801e6e7,0xc21000e1,0x029e39e1,0xe800015d,0x14003801,
+0xe8000149,0x14102c01,0xc10000e1,0x0010ed00,0xb800a614,0x0010ab01,0xd1fff65a,0x00113801,
+0x00150601,0x109e0950,0x034160b8,0x109e8961,0x00000000,0x90003851,0xd1ffce50,0x109e0980,
+0x109e4971,0x0010ab00,0x900039b0,0x90003aa5,0x00112d00,0x90003894,0x0010d501,0xe800012d,
+0x14000601,0x00000000,0xb8004055,0x1091c77c,0xb8000050,0xb800c05d,0x1091c734,0xb8008058,
+0xb8010061,0x00000000,0xb800c704,0xb8018069,0x00000000,0xb8014064,0xb8020071,0x00000000,
+0xb801c06c,0xb8028079,0x00000000,0xb8024074,0xb8030081,0x00000000,0xb802c07c,0xb8038089,
+0x00000000,0xb8034084,0xb8040091,0x00000000,0xb803c08c,0xb8048099,0x00000000,0xb8044094,
+0xb80500a1,0x00000000,0xb804c09c,0xb80580a9,0x00000000,0xb80540a4,0xb80600b1,0x00000000,
+0xb805c0ac,0xb80680b9,0x00000000,0xb806c0bc,0xb8004721,0x1082477c,0xb80640b4,0xb800871d,
+0x07000101,0x10824935,0x00100901,0xd2fffdce,0xc10002e5,0x00000000,0x034e1e8a,0xd2fffeae,
+0x00000000,0x900016e1,0xd2fffec4,0xc100b8e1,0x008e2ae2,0xe8000029,0x14102501,0xc10000e1,
+0xd1ffab60,0x0010ed01,0x00812f90,0x00117800,0x0010ab02,0xd2fffeb2,0x00150601,0x00000000,
+0x031e1db1,0xd2ffffdf,0x00000000,0x108b2c04,0x108bae11,0xe8fffe00,0x108b6de9,0x04902c9c,
+0x10859610,0x108befe9,0x00000000,0xb80066e3,0x00000001,0xe8000079,0x14103809,0x00000000,
+0xb800a6e3,0x00000001,0xe8000065,0x14003801,0x00000000,0x034e1c68,0x034e696a,0x00112600,
+0x0010a300,0x0010d902,0x109e5820,0x082eb9e0,0x109e0951,0xc1fff8e4,0x900018e8,0x900039e9,
+0x00000000,0x034148e4,0x9000386d,0x00000000,0x034e696a,0xd10016f1,0x109e0961,0x00000000,
+0x900038e5,0xe8fffe41,0x14100601,0xc10000e1,0xe8000061,0x04f0389c,0xc10000b1,0xc1000058,
+0x00155900,0x00152901,0x00000000,0xa40255e0,0x034e635b,0x00000001,0xe8000078,0x008e57e5,
+0x14103809,0x0010b900,0x03415468,0x03412059,0xd1ffade2,0x0010d501,0x108b2c05,0xe8ffffcc,
+0x10851421,0x04902c9c,0x10859610,0x108555e9,0x00000000,0xb80028e1,0xc10240e0,0x10896505,
+0xc20900e4,0x0086dbe0,0xc10074e1,0x008659e0,0x00000000,0x0085d7e5,0xe8fffcbd,0x049025e0,
+0x10869a10,0x10861811,0xd2fffd9e,0xc1000019,0xd1fff998,0x0080d468,0x0010b903,0xd2ffff9f,
+0x10924941,0x1081c940,0x9000891d,0x10924761,0xc10000e1,0xe8000011,0x04e03810,0xc1000029,
+0xd600033e,0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,0x1092497d,0x10924935,
+0x1081c97c,0x9000891c,0x9000c905,0x1081c734,0x90004920,0xc1002c25,0x00920724,0xc1008825,
+0x00900724,0x00924725,0x00000000,0x90028078,0x9002c07d,0x00000000,0x90020070,0x90024075,
+0x00000000,0x90018068,0x9001c06d,0x00000000,0x90010060,0x90014065,0x00000000,0x90008058,
+0x9000c05d,0x00000000,0x90000050,0x90004055,0xc1ffece8,0xc1ffe8e4,0xc1ffe4e1,0x00000000,
+0x034747e8,0x034707e5,0x00000000,0x0346c7e1,0x00158201,0x00178401,0x0017c300,0x00000000,
+0x00168501,0x00000000,0xb80302e3,0x00000001,0xe800008c,0xc1000061,0x14103800,0x00154300,
+0xc100005d,0xc10003e0,0xc1ffff19,0x00000000,0x9003c2e1,0x00000000,0xb8004055,0x1091c77c,
+0xb8000050,0xb800c05d,0x1091c734,0xb8008058,0xb8010061,0x00000000,0xb800c704,0xb8018069,
+0x00000000,0xb8014064,0xb8020071,0x00000000,0xb801c06c,0xb8028079,0x00000000,0xb802c07c,
+0xb8004721,0x1082477c,0xb8024074,0xb800871d,0x07000101,0x10824935,0x00100901,0x00000000,
+0xb801c3e7,0xc21000e1,0x029e39e1,0xe8000059,0x14003801,0xe8000049,0x14101b05,0xc1000951,
+0xd1ffb306,0x10808271,0x00000000,0xb80196e3,0x00000001,0x009e3819,0xe8000045,0x04e03851,
+0xd2ffff54,0xc10000e0,0xc1200ce5,0x00000000,0x900356e0,0x9003d6e5,0xc1ffff19,0xd2ffffc6,
+0xc1001151,0xe8000011,0x14101b05,0xd2ffffb6,0xc1001151,0xd2ffffae,0xc1002051,0x00000000,
+0xb801d5e3,0x00000001,0x129e3841,0xe800005d,0x14003801,0x1200d40c,0xac031510,0x10809671,
+0xd1ffb51f,0x00000000,0xac0355e0,0x8403151b,0x00000001,0xe8000035,0x040006e1,0x00000000,
+0xb8025fe3,0x00000001,0xc10000e0,0x129e7805,0xe8000019,0x041038e5,0xc12009e0,0xc1ffff5d,
+0x00000000,0x9003d6e1,0xc1fff8e4,0xb801d5e0,0xc1fffce1,0xc21000f0,0x008ec8e4,0x109e8951,
+0xd1ffa2e4,0x109e0960,0x008e48e1,0x10809670,0x900038e4,0x0010db01,0x00115a00,0x90003aec,
+0x029138f1,0xe8000019,0x14000601,0xe8000011,0x14101701,0xc1ffff5c,0x9003d619,0xc1fffce1,
+0xc1ffe8e0,0xb801d5e0,0x034e48e1,0x008088e3,0x028e38e5,0x00000000,0x9001d5e1,0x00000000,
+0xb80215e0,0xb8005ae7,0x00000001,0x028e38e5,0x00000000,0x900215e1,0x00000000,0xb801960d,
+0xd1ffb107,0xd1ffb2c8,0xc1ffe8e1,0x00000000,0x008088e1,0xc100200d,0xc20000e5,0xc20000e0,
+0x00150600,0xc3ffe6e5,0xc3ffe2e0,0x029e46e5,0xe8000061,0x041039e1,0xc20000e1,0xc30001e1,
+0xc10000e0,0x029e46e1,0xe800001d,0x041038e5,0xd1ffb1ac,0xc1ffe8e1,0x00000000,0x008088e1,
+0xc100100d,0xc20000e1,0xc30008e1,0x029e14e1,0xe8000155,0x14003801,0xc10009e5,0xd1ffb250,
+0xc1ffe8e1,0x0010f900,0x008088e2,0x00160601,0xd1ffb114,0x10809673,0x00000000,0xb80196e0,
+0xb8001aeb,0x00000001,0x00957819,0x008e7a55,0x01be18e5,0x00000000,0x06163861,0xe8000111,
+0x14103a00,0xc1000050,0x00967961,0x00000000,0xb801d6e7,0x109e0841,0x00000000,0x900038e5,
+0x00000000,0xb80216e7,0x109e0831,0xc10000e0,0x900038e5,0x00151900,0x900356e1,0xe800004c,
+0x00955551,0x14101701,0xc1fff0e0,0x109e8950,0x109e4961,0xd1fff660,0x109e0970,0x008088e1,
+0x0010df00,0x90003a74,0x9000386d,0x00115a00,0x90003970,0x00111e01,0xe8000011,0x14000601,
+0xc1ffff5c,0x9003d619,0xe8000039,0x140017fd,0xc1fff0e4,0xc1fff4e1,0x00000000,0x034e48e7,
+0x00000001,0x00000000,0x900256e5,0x00000000,0x034e08e3,0x00000001,0x00000000,0x900296e1,
+0xc1fff8e1,0x00000000,0x034e08e3,0x120e590d,0xe80000d8,0x009e39e1,0x04901560,0x9002d6e1,
+0x00111800,0xb80196e0,0xb803160a,0xd1fffb56,0x0090f861,0x00000000,0x90035661,0xd2fffc58,
+0x00119703,0xd2fffeba,0xc10008e5,0x00000000,0xb80356e7,0x00000001,0xe8000025,0x04b03ae5,
+0xe8ffff1d,0x14101701,0xd2ffff14,0xc12010e1,0x00000000,0x9003d6e1,0xc1ffff5d,0xc1fff0e0,
+0xb80316e1,0x008088e2,0xd1ffaefd,0x008e38e5,0x0090f8e9,0x00000000,0xb8001ae3,0x00000001,
+0xe8fffedd,0x04b019e1,0xd1ffaf7c,0x009519e0,0x10809673,0x00000000,0xb80316e4,0xb80356e1,
+0x00111401,0xd1fffabe,0x0010c600,0x0080b9e1,0x00000000,0xb80356e3,0xd2fffea5,0x008e3851,
+0x00000000,0x900356e1,0x00000000,0xb8001ae3,0x00000001,0xe8000089,0x04f019e1,0x00000000,
+0x00953865,0x008e1455,0xe800000d,0x04b03861,0x00951855,0x00000000,0xb80356e3,0x00000001,
+0xe8000025,0x04f014e1,0x00111400,0xb803160b,0xd1fffa51,0x008e3809,0x0090f851,0x00000000,
+0x90035651,0x00111500,0xb80356e5,0x00000000,0xb80316e8,0xb80196e2,0xd1fffa2a,0x0080bae4,
+0x0090f855,0x00000000,0xb80356e3,0xd2fffed1,0x008e3855,0x00000000,0x900356e1,0xd2ffffc8,
+0xc10000e1,0x00000000,0x900356e2,0x10924941,0x00000000,0x9000891d,0x1081c940,0x9000c904,
+0xc1007425,0x00900724,0x00924725,0x00000000,0x90014064,0x90018069,0x00000000,0x9000c05c,
+0x90010061,0x00000000,0x90004054,0x90008059,0x00000000,0x90000051,0xd1ff71fb,0xd1ff8800,
+0xc2fffc09,0xc1004010,0xc100000c,0xc300010a,0xd1ff8938,0xc2393c09,0xc300000a,0xd1ff71c7,
+0xc28000e4,0xc20004ed,0xc2a344fc,0xc30000ec,0xc20000e9,0xc20004f0,0xc20000e0,0xc2a34465,
+0xc2a37c68,0xc30001fc,0xc21ee459,0xc2a3805c,0x008f7be4,0xc21f1041,0xc21ee850,0xc30300e8,
+0xc21eec49,0xc30000f0,0xc2003038,0xc2003431,0xc30300e0,0xc2002c2c,0xc20010ed,0xc2a384f8,
+0xc20008e4,0xc3000165,0xc3000168,0x10863f40,0xc3000159,0xc300015c,0xc1000054,0xc100004d,
+0xc3000150,0xc3000140,0x0283fce9,0xc3000148,0x02837de0,0xc1000045,0xc3038238,0xc303822c,
+0xc10000e9,0xc3038230,0xc1200028,0xc30001f9,0xc2a384fc,0xc10001f4,0xc30382ed,0xc20010f0,
+0x90001760,0x90001a65,0xc10001e0,0x9000144c,0x90001655,0xc10a04e8,0x900010e8,0x80001245,
+0xc30382e4,0x90000c34,0x90000e3d,0xc30001fc,0x90003ef4,0x90000b29,0xc30382f0,0x900039e0,
+0x90003be9,0x00000000,0xb8003ce7,0xc10200e1,0x029e39e1,0x00000000,0x90003fe1,0x00000000,
+0xb8003fe3,0x00000001,0xe8ffffdd,0x14103801,0xc2010ce0,0xc1000409,0xc30382e0,0xc100020d,
+0x00000000,0xb80038e6,0xd10000dc,0xc21ee0e1,0xc30001e1,0xc1000114,0x900038e4,0xc1000511,
+0xc2a384e1,0xe800001c,0xc30001e1,0x14000600,0x90003819,0xd10001aa,0xc1000208,0xc1301f0d,
+0xd10005f9,0xc2a34409,0xc3000109,0xd1ffb625,0xc2a34409,0xc3000109,0xc2a37ce4,0xc2a380e0,
+0xc10000ed,0xc30001e4,0xc30001e0,0xc10000e9,0x00000000,0xb80039f0,0xb80038e6,0xc10000e1,
+0xd1000221,0xc2a34408,0x9000fce8,0x9000bced,0xc3000108,0x9000b9e1,0xc1000019,0x1091c741,
+0x00000000,0xb800c704,0xb8008059,0x00000000,0xb8004055,0x00000000,0xb8014064,0xb8018069,
+0x00000000,0xb8000050,0xb8010061,0x00000000,0xb800c05c,0xb800871d,0x07000101,0x10824741,
+0x00100901,0x10924941,0x1081c940,0x9000891c,0xc1003025,0x00924725,0x001e8401,0x001fc200,
+0x001f4500,0x001f8301,0xc20008e4,0xc10000ed,0xc30382e5,0x001e7901,0x00000000,0xb80039e3,
+0x00000001,0x129e3805,0xe800001d,0x14003801,0xc20000e1,0x108efb04,0xc30001e1,0xe8ffffdd,
+0x04a03be1,0x120e7e10,0x120e3d25,0x120eba18,0x028effe4,0xc20008e5,0xc20010e8,0x028efbe8,
+0xc30382e5,0xc30382e8,0xc10001e0,0x028efbe1,0xe8000054,0x900039e0,0x90003aed,0x14003d00,
+0xc10000f1,0xc20010e8,0xc10000ed,0xc30382e9,0x001eba01,0x00000000,0xb8003ae7,0xc10200e1,
+0x029e39e1,0xe8000021,0x14003801,0xc20000e1,0x108efb04,0xc30010e1,0xe8ffffdd,0x04a03be1,
+0xc10001f1,0x0011bc01,0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,0x10924941,
+0x00000000,0x9000891d,0x1081c940,0x9000c904,0xc1002025,0x00900724,0x00924725,0x00000000,
+0x90000051,0x001e0200,0x00150301,0xd1fffed9,0x0010b801,0xc1000210,0xc100000c,0xc1000115,
+0xe800001d,0x14000601,0xd1fffebd,0xc1000211,0xc1000208,0xc100000c,0xc1000115,0xc2000ce0,
+0xc20018e8,0xc20008e5,0xc30382e0,0xc30382e9,0xc30382e4,0xb80038e4,0xc10001e1,0x00000000,
+0x900039e0,0x90003a52,0xc2000ce1,0xc30382e0,0x128e7905,0x00000000,0x900038e5,0x1091c741,
+0x00000000,0xb800c704,0xb800871f,0x10824741,0x00000000,0xb8000051,0x07000102,0x00100901,
+0x10924941,0x1081c940,0x9000c904,0x9000891d,0xc100bc24,0x90004920,0x10920741,0x00900724,
+0x00924725,0x00000000,0x9002c07c,0x90030081,0x00000000,0x90024074,0x90028079,0x00000000,
+0x9001c06c,0x90020071,0x00000000,0x90014064,0x90018069,0x00000000,0x9000c05c,0x90010061,
+0x00000000,0x90004054,0x90008059,0x00000000,0x90000051,0x0016c201,0xc1004ce1,0xc10000e4,
+0xc1000060,0x009e08e1,0x00000000,0x900038e5,0x00000000,0xb8028283,0x00000001,0xe8000079,
+0x14102001,0xc1ffff19,0x1091c740,0xb8000050,0xb8004055,0x00000000,0xb800c704,0xb8008059,
+0x00000000,0xb800c05c,0xb8010061,0x00000000,0xb8014064,0xb8018069,0x00000000,0xb801c06c,
+0xb8020071,0x00000000,0xb8024074,0xb8028079,0x00000000,0xb802c07c,0xb8030081,0x00000000,
+0xb8004720,0xb800871d,0x07000101,0x10824741,0x00100901,0xc20004e4,0xc2002ce0,0xc10048e9,
+0xc30382e4,0xc30382e0,0xc21f00f9,0x00000000,0xb80039e8,0xb80038e1,0xc21ef8f0,0xc10040ed,
+0xc21ef4e4,0xc10000e8,0x009e08e9,0xc1ffb42c,0x900038e9,0xc2126828,0xc30001f0,0xc30001f9,
+0x129ffa0c,0xc30001e4,0x109f48b1,0xc10010ec,0x0087a0ec,0x120eb809,0xc1ffb8e0,0x0087c82c,
+0x00876029,0xd1ffa6b4,0x10868240,0x00170201,0x008088e0,0x90003dfc,0x90003efd,0xc100000c,
+0x900039e8,0x90003ced,0xe800016d,0x140006fd,0xc2002850,0xc201085d,0xc2a37064,0xc3038250,
+0xc2a37459,0xc21ee854,0xc3000158,0xc3000165,0xc303825c,0x00151400,0xc3000155,0xd100027c,
+0x00109c00,0x0010e003,0xe8000131,0x14000641,0xc10100e1,0xe8000121,0x040006e1,0xc21000e1,
+0xe8000101,0x040006e1,0xd1ffb258,0x00000000,0x0010df01,0xc2a37414,0x00111a00,0x00109b01,
+0xc3000115,0xe800004d,0x141006fd,0x00000000,0xb803e0e7,0xc2f000e1,0xc10000e0,0x029e79e1,
+0xe80000c1,0x040038e5,0xd1ffb091,0x00111e00,0x0010e000,0x00109f02,0xe80000c1,0x14000641,
+0xc10100e1,0xe80000b1,0x040006e1,0xd2ffff9f,0x00000000,0xb801a0e4,0xb80160e1,0x00000000,
+0xb80019e4,0xb80017e3,0x009eb9e1,0x008e79e9,0xe8000088,0x900019e5,0x04c039e1,0xe8ffff6d,
+0x14100601,0xc1ffb8e4,0xb80016e4,0xc21004e1,0x00815de0,0x00000000,0x008088e5,0xd10003fd,
+0x109e0951,0x00111e00,0x900038e4,0x0010da01,0xe8000049,0x14000641,0xc10100e1,0xe8000039,
+0x040006e1,0x00000000,0xb80015e3,0xd2ffff1d,0x108e3805,0x00000000,0x900014e0,0x900015e1,
+0x00000000,0xb803e0e3,0x00000001,0xe8fffed1,0x14003805,0xc1ffff61,0xc2a374e0,0xc10048e4,
+0xc10003ed,0xc30001e0,0x009e88e4,0xc1ffb8e5,0x008088e4,0x90003aec,0xb800380d,0xd1ffa4ff,
+0x00000000,0xb8029be3,0x00000001,0x00000000,0xb803f8eb,0x00000001,0x110e7a00,0x110e3a05,
+0x028e39e1,0xe8000021,0x14003801,0xd1fffbd0,0x00000000,0x0010fa02,0xc1000109,0xd2fffd2c,
+0x00119803,0xd1fffbb8,0x00000000,0x0010fa02,0xc1000209,0xd2ffffeb,0x10924941,0x1081c940,
+0x9000891c,0xc1002425,0x00924725,0xc21f14e0,0xc22ec0ed,0xc30001e0,0xc280c8e9,0x129e38f0,
+0xc30001e9,0xc22ebce4,0xc252c0e0,0x108f3821,0xc30001e4,0x900042f0,0xc30001ed,0xc280c8e4,
+0x900039f0,0xc30001e1,0xc30001e4,0x900282e8,0x900142ed,0xc25cc8e8,0x900339e0,0xc21200e5,
+0xc30001e8,0xb80282f0,0xc22278e1,0x008ebae6,0xc22274e4,0x00000000,0xc25cc8ed,0xc30001ec,
+0x008e7ce5,0x00000000,0x900039ed,0x00000000,0xb80282e7,0x00000001,0x008e39e1,0x00000000,
+0x900038e9,0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,0x10924941,0x00000000,
+0x9000891d,0x1081c940,0x9000c904,0xc1003c25,0x00900724,0x00924725,0x00000000,0x90004054,
+0x90008059,0x00000000,0x90000051,0x00154200,0x00158301,0x00000000,0xb800c2e3,0x00000001,
+0xe800003d,0x14003801,0xc1001019,0x1091c741,0x00000000,0xb800c704,0xb800805b,0x00000000,
+0xb8004055,0x00000000,0xb8000050,0xb800871d,0x07000101,0x10824741,0x00100901,0x00000000,
+0xb80183eb,0x00000001,0xe8000029,0x14003a01,0x00000000,0xb80042e4,0xb80082e3,0x00000001,
+0x008e39e1,0x009e38e9,0x00000000,0x900082e1,0xc21ee0e4,0xb80082fc,0xc21f14e1,0xc30001e4,
+0x00000000,0xc30001e1,0x00000000,0xb80039e6,0x008e3fe1,0x00000000,0xb80183f1,0x129fb90d,
+0x009e38f9,0xc10004e0,0x00000000,0x129e780d,0xe800004c,0x009e38e5,0x14003c00,0x129f780d,
+0xc21f14ec,0xc10000e1,0xe8000034,0xc30001ed,0x04e038fc,0xc10000e8,0x008e7ded,0x001e7901,
+0x00000000,0x031e3cea,0x108eba05,0xe8fffff5,0x04803afc,0x108e7904,0x800039e1,0xc21f14e4,
+0xc21ee0e8,0xc10fa0e1,0xc30001e4,0xc30001e8,0x009f38fd,0x108e3c0c,0x008f7de4,0x009efff9,
+0x109e0950,0x900042f4,0x008e78f9,0x12217908,0xb8003ae0,0x0080fded,0x00000000,0x900038f1,
+0xd1000296,0xc1000008,0x009138f9,0xe8000041,0x141006fc,0x00150601,0xc10001e0,0xb80055e4,
+0xb80095e1,0x00000000,0x9000d5e3,0xc1000050,0x008e78e5,0x10851404,0xc10000e1,0xe8fffff8,
+0x800039e1,0x14801420,0x108e7905,0xc21ee4e4,0xc20108e1,0xc30001e4,0xc30382e1,0x00000000,
+0xb80039e4,0xb80038e3,0x00000001,0xe8000041,0x048039e1,0xe8000039,0x14e01421,0x00000000,
+0xb80095e0,0xb80055e7,0x00000001,0x008e14e1,0x008e78e5,0x10851404,0xc10000e1,0xe8fffff8,
+0x800039e1,0x14801420,0x108e7905,0x00109600,0xb80095e0,0xb800550f,0xd1000dcd,0x008e3851,
+0x00113800,0x900095e1,0xd1ff7a02,0xc1000009,0xd2fffdfe,0xc1000019,0x1092497d,0x10924915,
+0x1081c97c,0x9000891c,0x9000c905,0x1081c714,0xc1004825,0x00900724,0x00924725,0x00000000,
+0x90014064,0x90018069,0x00000000,0x9000c05c,0x90010061,0x00000000,0x90004054,0x90008059,
+0x00000000,0x90000051,0xc1ffece0,0x00164301,0x00000000,0x0345c7e3,0x00168200,0x00000000,
+0x00160501,0x00000000,0xac008550,0xb800855a,0x00000000,0xb800c556,0xe800000d,0x14101405,
+0xc1000055,0x00000000,0xb80083e3,0x00000001,0xe80000a9,0x04003851,0xc10001e4,0x90010250,
+0xc10001e1,0x0010d700,0x9001c2e0,0x900002e5,0x00000000,0xb80005e3,0x00000001,0x00000000,
+0x900182e1,0x00000000,0xb80005e2,0xd1ffa0ae,0x00000000,0x900142e1,0xe8000061,0x141006fd,
+0xc1010019,0x1091c77d,0x1091c715,0x00000000,0xb800c704,0xb8010061,0x00000000,0xb8004054,
+0xb8000051,0x00000000,0xb800c05d,0x00000000,0xb8008058,0xb8018069,0x00000000,0xb8014064,
+0xb800871d,0x07000100,0x00000000,0x1082477d,0x10824915,0x00100901,0x00000000,0x00000000,
+0x90011a51,0x00109a00,0x90009951,0x0010d700,0xb8011ae1,0x00000000,0xac00d8e3,0x00000000,
+0x9000d9e1,0x00000000,0x90029a58,0x90025ae1,0x00000000,0x9002da55,0xc10000e4,0xb80059e0,
+0xc10002e1,0x00000000,0x90001ae0,0x90031ae5,0xd1ff9fea,0x00000000,0x90039ae1,0xe8000011,
+0x141006fd,0xd2ffff42,0xc1010019,0xd2ffff3a,0xc1000019,0x1092497d,0x10924915,0x1081c97c,
+0x9000891c,0x9000c905,0x1081c714,0xc1005425,0x00900724,0x00924725,0x00000000,0x90010060,
+0x90014065,0x00000000,0x90008058,0x9000c05d,0x00000000,0x90000050,0x90004055,0xc1ffece0,
+0x00164301,0x00000000,0x034587e3,0x00000001,0xc21ee4e4,0xc20108e1,0xc30001e4,0xc30382e1,
+0x00000000,0xb80039e4,0xb80038e3,0x00000001,0xe800005d,0x048039e1,0xc1ffff19,0x1091c77d,
+0x1091c715,0x00000000,0xb800c704,0xb8010061,0x00000000,0xb8004055,0x00000000,0xb8000051,
+0x00000000,0xb800c05c,0xb8008059,0x00000000,0xb800871c,0xb8014065,0x07000100,0x00000000,
+0x1082477d,0x10824915,0x00100901,0xc21f08e8,0xc2011ce4,0xc2010ce1,0xc30001e8,0xc30382e4,
+0xc30382e1,0x00000000,0xb8003ae0,0xb8003961,0x00000000,0xb80038f7,0x120e8508,0x00000000,
+0x129e78f1,0x008f3d60,0x008e39e9,0xe80001e1,0x04a03861,0xc21ee0e0,0x00000000,0x009ed8e5,
+0xc30001e0,0x0095faed,0x00000000,0xb80038eb,0x00000001,0x01ae3af0,0x01ee7af5,0x029e39e1,
+0xe8000165,0x14003801,0xc21f0ce8,0xc21efce4,0xc10000e1,0xc30001e8,0xc30001e5,0x00000000,
+0x900039e0,0x90003af1,0x12257b09,0xe800001d,0x14001501,0xd1ff7090,0x00115502,0xc1000009,
+0xd1ff76aa,0xc1000009,0xc21efce1,0xc30001e1,0x00000000,0xb80038e3,0x00000001,0xe8000135,
+0x14003801,0xd1fff421,0xc1000511,0xc1000408,0xc100020c,0xc1000115,0x00150601,0xe8000015,
+0x14001401,0xd1fff4fa,0xc1000208,0xc1301f0d,0x122e1709,0xe8000035,0x14003801,0xc21f0ce0,
+0x120e5508,0x00117801,0xc30001e0,0xc1000008,0x0080d9e5,0x00000000,0xb8003811,0xd1ff700b,
+0xd1ff762a,0xc1000009,0xc21f08ec,0xc21f0ce4,0xc21f08e9,0xc30001ec,0xc30001e4,0xc21ee0e1,
+0x00000000,0xb8003bec,0xb80039e7,0x00000001,0x009ed8ed,0xc30001e8,0x009ed6ed,0xc30001e0,
+0x90003aec,0x008e79ed,0x00000000,0x900038e5,0xc21ee4e4,0xc20108e1,0xc30001e4,0xc30382e1,
+0x00000000,0xb80039e8,0xb80038e3,0x00000001,0x008e7a59,0xe800000d,0x04a039e1,0x0095b8e9,
+0xd2fffdfc,0xc20038e0,0xc21ee4e5,0xc30001e4,0xc30382e0,0x008eba59,0x00119600,0x900038e8,
+0x900039e9,0xe8fffec5,0x04803af1,0xd2fffebc,0xc21efce4,0xc21f0ce9,0xc30001e8,0xc30001e4,
+0xc10001e1,0x00000000,0x900039e0,0x90003af5,0xd1fff2f5,0xc1000511,0xc1000408,0xc100010c,
+0xc1000115,0xd2fffeda,0x00150601,0xe8000011,0x14000501,0xd1ff6f12,0xc1000009,0xc21f08ec,
+0xc21ee0e4,0xc21f08e9,0xc30001ec,0xc30001e4,0xc21ee0e1,0x00000000,0xb8003bec,0xb80039e6,
+0xc30001e9,0xd1ff7505,0xc30001e0,0x008efb58,0x008e7959,0xc1000008,0x900038e4,0x90003aed,
+0xd2ffff13,0x1092497d,0x10924925,0x1081c97c,0x9000891c,0x90004921,0x1081c724,0xc1002825,
+0x00920724,0xc100e825,0x00900724,0x00924725,0x00000000,0x90010060,0x90014065,0x00000000,
+0x90008058,0x9000c05d,0x00000000,0x90000050,0x90004055,0xc1ffece4,0xc1ffe8e1,0x00000000,
+0x034487e4,0x034447e3,0x00000001,0x00000000,0xa40203e4,0xa41083e1,0x00000000,0xa40243ec,
+0xa410c3eb,0x00000001,0x129e7920,0x011ebbe8,0x129e3821,0x011e39e1,0x028e3ae1,0xe8000049,
+0x14003801,0xc1201419,0x00000000,0xb8000050,0xb8004055,0x1091c77c,0xb8008058,0xb800c05d,
+0x1091c724,0xb8010060,0xb8014065,0x1082477c,0xb8004720,0xb800871d,0x07000101,0x10824925,
+0x00100901,0x00000000,0xb80084e9,0xc1ffb2e1,0x008408e1,0xc1000058,0x00000000,0x001e5001,
+0x10859604,0xc10027e1,0xe8fffff8,0x840039e9,0x049016e0,0x108e7909,0x00000000,0xb80084e3,
+0x00000001,0x129e3805,0xe8000351,0x14003801,0x00000000,0xb801c4e8,0xa410c3e2,0x00000000,
+0x00000000,0xb80042f5,0xc10100e5,0xe8000428,0x028e7ae5,0x14103808,0x1085c3e8,0x9001c4e5,
+0xc10058e4,0xa40217e1,0xc10054e8,0xc10000f0,0xc1005ce1,0xc1ffa4e8,0x009ec8e4,0x009e48e9,
+0xc10000f0,0x900039f0,0x009e48e1,0xea000084,0xc10000e8,0x008348e9,0x129e3820,0x900039e8,
+0x90003bf1,0xc1000060,0xc1000050,0xc100003d,0x14003800,0xc1000030,0xc100004d,0x00000000,
+0x03155317,0xc10000e1,0xe800002d,0x04f03854,0xc1000058,0x1084d305,0xc10000e5,0x00000000,
+0x034e3de7,0x00000001,0xe8000345,0x14003801,0x00131301,0xc10024e0,0x00851454,0x120e5509,
+0xe8ffffbc,0x008f7de5,0x049014e1,0x0013d301,0xe8000075,0x04f01444,0xc1000039,0x00000000,
+0x03155317,0xc10000e1,0xe800003d,0x04f03854,0xc1000058,0x1084d305,0xc10000e5,0x00000000,
+0x034e3de7,0x00000001,0xe80002f9,0x14003801,0x120e0e08,0x00161301,0x008e0de1,0x00000000,
+0x9000384d,0x108e4e04,0x120e1508,0x00851455,0x11be3908,0x008f7de1,0xe8ffffa4,0x0613b9e1,
+0x04901445,0x111e5800,0x009e8f30,0xc10000e1,0x00000000,0x00000000,0x061e7ae6,0x00833931,
+0xe8000025,0x04f03830,0xc1000059,0x00000000,0xb80084e3,0x00000001,0x00129000,0x1292f8f9,
+0xd6000342,0xe800002d,0x04f00f60,0x00158f00,0xc1000039,0x1202cf04,0xb80084e1,0x00828b43,
+0x129e38f9,0x120e3841,0x12233841,0xd6006346,0xc1ffa4e0,0xc21e08e4,0xc100c0ed,0xc30001e4,
+0x034388e1,0xc100e4e8,0x1082d748,0xc10090e1,0xc1000058,0xc10021f8,0x008283ed,0xc10022fc,
+0x00000000,0x008f03e9,0x108f57d8,0x008eb8e4,0xc10004ed,0xe8000221,0x04b03f39,0xc1fff4e0,
+0x031e0bf9,0x00000000,0x034e3ae3,0x00000000,0x80003de1,0x00000000,0x90003ae0,0x031e0afb,
+0x00000001,0x00000000,0x80003ce1,0xeaffffc8,0x03438ded,0x10859604,0x108f7d04,0x108efb11,
+0x108eba10,0x108fff04,0x108f3c05,0x1490160c,0x00000000,0x108fbe05,0x00000000,0xb801c4e7,
+0xc21000e1,0x029e39e1,0xe800035d,0x14003801,0x00000000,0xac00d7e3,0xc2b088e4,0x00000000,
+0xc1003ce9,0xc30001e4,0x129ef804,0xc10000e1,0xc100c0e8,0xc1000050,0x060ebbe9,0xe800009c,
+0x008643e9,0x04f03844,0xc100004c,0x00863ae5,0xc21e0834,0xc100003d,0xc3000134,0x00139001,
+0x1085d748,0x00134d01,0x00000000,0x00000000,0x032e903f,0x00000000,0x03155315,0xc10000e0,
+0x129e7a05,0xe8000031,0x040038e5,0x00000000,0x031e194f,0x00000001,0xe8000255,0x14003801,
+0x129e3af9,0x120e3841,0x122e3841,0x00000000,0x84000ee1,0x00000000,0x00000000,0x00851455,
+0xe8ffffa8,0x10838e08,0x1084d305,0x04901444,0x10834d10,0x1083cf09,0x00000000,0xb80084e3,
+0x00000001,0x129e3809,0xe800009d,0x14003801,0x00000000,0xb801c4e7,0xc10200e1,0xc2cc44e0,
+0x028e79e1,0xc30001e0,0x9001c4e5,0x00000000,0x00000000,0xb8007831,0xc10000e1,0xe8000068,
+0xc100004d,0x04f03844,0xc1000051,0xc100002d,0x00000000,0x00000000,0x032e102e,0x00000000,
+0x03155316,0xe8000025,0x14103809,0xc10000e1,0xe8000019,0x04f03854,0xc1000059,0x008e1251,
+0x1202b809,0xd6002356,0x00000000,0x00000000,0x00851455,0xe8ffffbd,0x04901444,0x1084d304,
+0x1082cb09,0xd2fffb86,0xc1000019,0x10859605,0xe8fffcad,0x04901654,0x108e7911,0xd2fffcbb,
+0x10859605,0xe8fffcf9,0x04901654,0x108e7911,0xd2fffd17,0xe8fffe19,0x04103f39,0xd2fffe10,
+0xc10001e0,0xc10000e5,0x00000000,0x90003ae0,0x80003de6,0xc10000e1,0xe8000060,0xc1000031,
+0x04f03844,0xc1000050,0xc100004d,0x00000000,0x03155317,0xc10000e1,0xe800002d,0x04f03854,
+0xc1000058,0x1084d305,0xc10000e5,0x00000000,0x034e3de7,0x00000001,0xe8000099,0x14003801,
+0x00131301,0x120e1508,0x00851455,0xe8ffffc0,0x008f7de1,0x04901445,0xc10000e1,0xe8000025,
+0x04f03830,0xc1000059,0x00000000,0xb80084e3,0x00000001,0x00129000,0x1292f8f9,0xd600035e,
+0xe8000065,0x14f00c55,0xc21e08e4,0xa40997e4,0xc21e08e1,0xc30001e4,0xc30001e1,0x00000000,
+0xb80539e6,0x00000000,0x8009d7e5,0x00000000,0xa43503e5,0x00000000,0x900578e5,0xd2fffd5c,
+0xc100d5e1,0x008e03e1,0x00000000,0x800038e5,0x10859605,0xe8ffff59,0x04901654,0x108e7911,
+0xd2ffff67,0xe8fffd35,0x14100c55,0xd2fffd2c,0xc21e08e5,0xc30001e4,0xc10000e8,0xc10001e1,
+0x00000000,0x8009d7e8,0x900579e1,0x00000000,0xb8000de0,0x031e974f,0x00000001,0xe8fffdb9,
+0x040038e9,0xe8000029,0x14103a01,0xc10000e1,0xe8fffda5,0x04f03854,0xc1000059,0x008e1251,
+0x1202b809,0xd6002362,0xd2fffd8f,0xc10000e1,0xe8fffd85,0x04f03854,0xc1000059,0xc1ffffe0,
+0x1292fa04,0x008e5251,0x00000000,0x008e3ae1,0x121e3805,0x1202b908,0x12033809,0xd600436a,
+0xd2fffd57,0xc10000e1,0xe8fffd71,0x04f03844,0xc1000050,0xc100004d,0x1083d748,0xc1000038,
+0x00135001,0x00000000,0x00000000,0x032e903b,0x00000000,0x03155315,0xc10000e0,0x129e7a05,
+0xe8000031,0x040038e5,0x00000000,0x031ecf4f,0x00000001,0xe8000041,0x14903b1d,0x129e3af9,
+0x120e3841,0x122e3841,0x00000000,0x84000de1,0x00000000,0x00000000,0x00851455,0xe8ffffa8,
+0x1084d305,0x04901444,0x10838e08,0x10834d09,0xd2fffceb,0xc10000e1,0xe8ffffd9,0x04f03854,
+0xc1000059,0xc10006e4,0xc2cdf0e8,0xc2cdf0e1,0x120efb08,0x009e79ec,0xc30001e9,0x120e7908,
+0x03433be8,0xc30001e1,0x008e1250,0x0342f9e3,0x1202b809,0xd6002376,0xd2ffff9b,0x10924941,
+0x00000000,0x9000891d,0x1081c940,0x9000c904,0xc1002c25,0x00900724,0x00924725,0x00000000,
+0x90000051,0x00150201,0xc21f14e0,0xc10000e4,0xc10000f5,0xc10000f0,0xc10000ec,0xc10000e9,
+0xc10000e4,0x900002e4,0xc30001e1,0xd1ff95b8,0x900082f0,0x900042f5,0xc100000c,0x900102e8,
+0x9000c2ed,0x10808270,0x900182e0,0x900142e5,0xd1ff9594,0x10809492,0xc100000d,0xc10000e8,
+0xc10000e0,0xc10001e5,0xc10000e0,0x900354e0,0x9002d4e9,0x00000000,0x9003d4e0,0x900394e5,
+0x1091c741,0x00000000,0xb800c704,0xb800871f,0x10824741,0x00000000,0xb8000051,0x07000102,
+0x00100901,0x10924941,0x1081c940,0x9000891c,0x9000c905,0x10900750,0x10924751,0xd1ff9528,
+0x008e0310,0x9000020d,0xc10001e0,0x9001420c,0x900042e1,0x10808270,0x9001820c,0x9000c2e1,
+0x1091c741,0x00000000,0xb800c704,0xb800871f,0x10824742,0x07000102,0x00100901,0x10924941,
+0x00000000,0x9000891d,0x1081c940,0x9000c904,0xc1002825,0x00900724,0x00924725,0x00000000,
+0x90000050,0x90004055,0x00154201,0xd1ff955a,0x10808271,0x00000000,0xb80055ef,0x00000001,
+0x109ebb05,0xe8000079,0x04f006e8,0x00150601,0x00000000,0xa40006e7,0xc100ffe1,0xe8000025,
+0x041039e1,0x00000000,0xa40046e7,0xc100e0e1,0xc100e0e0,0x029e79e1,0xe8000045,0x040039e1,
+0x10851405,0xe8000039,0x04f014e9,0x00000000,0xa40014e7,0xc100ffe1,0xe8ffffe9,0x041039e1,
+0x00000000,0xa40054e7,0xc100e0e1,0xc100e0e0,0x029e79e1,0xe8ffffcd,0x041039e1,0x00000000,
+0x009e3b51,0xe8000035,0x14e03821,0xc1ffff19,0x1091c741,0x00000000,0xb800c704,0xb800871f,
+0x10824741,0x00000000,0xb8004054,0xb8000051,0x07000102,0x00100901,0xd1ff93ec,0x10809570,
+0x0010d403,0xd2ffffce,0xc1000019,0x10924941,0x1081c940,0x9000891d,0x10924741,0x1091c741,
+0x00000000,0xb800871d,0x07000102,0x10824741,0x10924941,0x1081c940,0x9000891c,0xc1005025,
+0x00924725,0xc20e00e0,0xc1000045,0x008402e1,0xc100003c,0x00139001,0xc20a00e0,0xc20e00f1,
+0xc20c00e8,0xc20800ec,0xc10400e5,0xc10600e8,0x00930ef0,0x0092cee9,0xc1000034,0xc10200e0,
+0x00928ee1,0x1083cf04,0x009f8eec,0x009f0ee9,0xc10000e8,0xc10000fc,0x009ecee5,0xc10000e0,
+0x009e4ee0,0xc10000f5,0xc10000e8,0x90000be8,0x90000c35,0xc10000e0,0x90003efc,0x90000ae1,
+0xc10000e0,0x90003be0,0x90003cf5,0xe8ffff8c,0x90000ee0,0x900039e9,0x14900f20,0x10838e11,
+0x10845105,0xe8ffff6d,0x14901140,0x10841081,0xc21000e0,0xc21008e5,0xc21004e8,0x008f42e0,
+0xc2100ae1,0xc10000f8,0xc10000ec,0xc10000f1,0x008e42e8,0x008e02e0,0x008e82e5,0xc10000e4,
+0x900039f0,0x90003df9,0x00000000,0x840038e4,0x84003aed,0x1091c741,0x00000000,0xb800871d,
+0x07000102,0x10824741,0x1092497d,0x10924925,0x1081c97c,0x9000891c,0x9000c905,0x1081c724,
+0xc1008c25,0x00900724,0x00924725,0x00000000,0x90014064,0x90018069,0x00000000,0x9000c05c,
+0x90010061,0x00000000,0x90004054,0x90008059,0x00000000,0x90000051,0xc1ffece4,0xc1ffe8e0,
+0x00164201,0x00000000,0x034587e4,0x034f87e3,0x00160401,0x00000000,0xb90002f1,0x120e0508,
+0x120f452c,0xc2100ce5,0x008e82e4,0x109e4950,0xc2ce34ed,0xc30001ec,0x0340bae0,0xc20900e9,
+0xd1ff9808,0xc2ce340c,0x109e0961,0x00857d08,0x90003958,0x00813be9,0xc300010c,0x900038f0,
+0x00117e01,0x00000000,0xb900195d,0xc10000e1,0xe80002f0,0xc1000035,0x04f03858,0x00000000,
+0x00151801,0xc2ce34e4,0xc10400e1,0xc20900e0,0x0082d5e0,0xc30001e5,0x008339e1,0x129e5704,
+0xc10480e0,0xc2ce34ed,0x1203b924,0x060f39e0,0x121e1705,0xc30001ec,0x00000000,0x121e8d05,
+0x120e7808,0x00829538,0x008e0b39,0xc1000060,0x1204ba08,0x0084fced,0x0083f8e4,0x00844cf0,
+0x00840ae5,0xd600237e,0xc1ffffe0,0x00000000,0x00168a01,0xc1ffffe0,0x008e57e0,0xc2a80865,
+0x129e793c,0xc3000164,0x02ae385d,0x128eb904,0x129e7804,0xc2a808e1,0x120e7924,0x12063a08,
+0xc30001e1,0x0084d8e0,0x008f95e4,0x00844be5,0xc2a808e0,0xb8007eec,0x034f15e5,0xc30001e0,
+0xb80393e4,0xb800bee9,0x129e17f8,0xb80313e4,0x034ed8e1,0x120f7808,0xb800fee9,0xc2a808e1,
+0xc30001e0,0xb80293e0,0x21ce3be5,0x0084bde0,0x21cefae4,0x21cf3ced,0xc2a808e4,0xb8013ee9,
+0x008f3ce0,0xb80213e0,0xb8017eed,0x008efcec,0xb80193e8,0x21ce3ae1,0xc30001e4,0xb801bee9,
+0x008f3be0,0xb80113e1,0xc1007ce0,0xb801fee4,0x21ce3ae1,0x008414e0,0xb80093e0,0x21ce7be9,
+0x008efce0,0x034e3de4,0x034e5539,0x008f3be4,0xb8004ae8,0x21cebae1,0xc1ffffec,0xb80392e5,
+0x008f3ce8,0xb8008ae8,0x21ce79e1,0xc2a808e0,0xb80312e4,0x21cf39e1,0x008fbce4,0xb800cae8,
+0xb80292e5,0x02ae7bf8,0xb8010ae8,0x21cefae5,0x108fb904,0xb80212e5,0x008f3ef0,0xb8014ae8,
+0x21ce7ae5,0x008efcec,0xb80192e4,0x21cefae5,0x008f3be4,0xb8018ae8,0xb80112e5,0x008f3cec,
+0xb801cae4,0x21cefae5,0xc30001e0,0xb80092e1,0x008efcec,0x00000000,0x21ce3ae5,0x0093b860,
+0x00000000,0x21cebae5,0x008efbe1,0xc2a808e0,0x21ce79e0,0x008ebbe9,0xc30001e1,0x0092b8f4,
+0x008e7ae5,0xc100013c,0x900014e4,0x10851411,0xd6018386,0xc10080e0,0xb80011fc,0xb80051e9,
+0x008659e0,0xb80091f4,0xb800d1e5,0x00829960,0xb80111ec,0x034f9961,0x00000000,0xb8038ae0,
+0xb8030af1,0x00000000,0xb8028ae0,0xb8020aea,0x00000000,0xb80151e4,0xb8018ae1,0x00000000,
+0x21cfbae0,0x21cffff9,0x00000000,0xb80191e0,0xb8010af5,0x008fbff8,0x21cf39e0,0x21cf7df1,
+0x00000000,0xb801d1e4,0xb8008ae1,0x008e7ef4,0x21ceb9e0,0x21ce7be9,0x008ef9f1,0x008efbe4,
+0x21ce38f5,0x008e7be8,0x21ce39e1,0x008e79e1,0xc1ffffe0,0x008e79e0,0x10834d05,0xc10040e4,
+0x02aeb8e4,0x108e1705,0xe8fffd54,0x1295f83c,0x108e3a05,0x04900d58,0x900014e0,0x008514e5,
+0xc1000019,0x1091c77d,0x1091c725,0x00000000,0xb800c704,0xb8010061,0x00000000,0xb8004054,
+0xb8000051,0x00000000,0xb800c05d,0x00000000,0xb8008058,0xb8018069,0x00000000,0xb8014064,
+0xb800871d,0x07000100,0x00000000,0x1082477d,0x10824925,0x00100901,0x10924941,0x1081c940,
+0x9000891c,0x9000c905,0x10900760,0x10924761,0xc20010e4,0xc20114e1,0xc30001e4,0xc30382e1,
+0x00000000,0xa00039e0,0x9000380b,0x00000001,0x129e3805,0xe800007d,0x14003801,0xd1ffe2e9,
+0xc1000311,0xc1000408,0xc100010c,0xc1000115,0xc2000ce4,0xc2000ce0,0xc1012c09,0xc30382e4,
+0xc30382e1,0x00000000,0xb80039e7,0xd1ff8c51,0x128e7905,0x00000000,0x900038e5,0xc2000ce4,
+0xc1000019,0xc10000e0,0xc30382e5,0x00000000,0x900039e1,0x1091c741,0x00000000,0xb800c704,
+0xb800871f,0x10824742,0x07000102,0x00100901,0xd1ffe275,0xc1000311,0xc1000408,0xc100020c,
+0xc1000115,0xd2ffff8f,};
+
+/* cga */
+static unsigned long srp_fw_cga[] __devinitdata = {
+0x8ae3fe80,0x03403432,0x14020004,0x00000002,0x00000000,0xa1100000,0x00000000,0x0001a000,
+0x00140000,0x9022a964,0x00000000,0xa0020001,0xa8200003,0x80000320,0x28400206,0x01000000,
+0x88140000,0xa0000010,0x00000143,0x00000000,0x40000000,0x00000190,0x001ac000,0x42200000,
+0x0064c000,0x00400000,0x00000000,0x35400000,0x00002804,0x00001a08,0x000140c0,0x00000000,
+0x0421d000,0x00000000,0x00000000,0x805fa000,0x10ebfffa,0x02802d03,0x64022800,0x10000802,
+0x00ce6820,0x8c980800,0x00010000,0x00000000,0x00000000,0x00000000,0x00000000,0x01815000,
+0x00010000,0x80000010,0x00200606,0x00000038,0x00000000,0x48000000,0x00000103,0x00000000,
+0x04a40000,0x00000000,0x00000000,0x19300000,0x00000000,0x0010a700,0x00000000,0x00000000,
+0x00006810,0x80100000,0x00000000,0x01930000,0x0541a000,0x00002000,0x00000000,0x00000000,
+0xc2fffffa,0x038a3022,0x00000650,0x00000100,0x0c002830,0x00000800,0x00000801,0x00040000,
+0x00000a01,0x90209020,0x00000000,0x00000100,0x07400000,0x40002400,0x00102287,0x04304000,
+0x00000800,0xa8000400,0x00000143,0x00000000,0x34080000,0x00a80000,0x00000000,0x00000000,
+0x41089002,0x010ca000,0x00000000,0x388c22c8,0x00000000,0x00000a04,0x80000600,0x00000000,
+0x01204001,0x40000b80,0x00000000,0x00000000,0x26f7f000,0x0a00a2b0,0xf404682c,0x5ea03002,
+0x00002810,0x00400000,0x00164001,0xd4000100,0x06301c01,0x9022a964,0x00000000,0x38000009,
+0x06602137,0x21590224,0x40000400,0x004000c4,0x20000000,0x10008490,0x00000000,0x00000000,
+0x14080740,0x00ec8151,0x000a0172,0x00800000,0xc02c8810,0x00201020,0x00000000,0xa1400000,
+0x24006834,0xe0000a01,0x00000a00,0x21090e00,0x80000800,0x00003c01,0x00000000,0x805fa000,
+0x2603ffc0,0x01682000,0x6400080c,0x50691046,0x00002810,0x00080000,0x001640b2,0x0000c060,
+0x00021c00,0x606c0004,0x00000000,0x36615406,0x066846c3,0x8bd92400,0x42000607,0x00000000,
+0x80000000,0x00000410,0x000c4000,0x00000000,0x14024800,0x00a81202,0x000a0000,0x00000000,
+0xd02c8002,0x024010c1,0x00000000,0x003e1000,0x02282800,0x000401d1,0x07000000,0x00010d80,
+0x00000801,0x00000004,0x00000000,0x00000000,0x26000000,0x0000fa70,0x66b02e58,0x5020d280,
+0x00000810,0x00000900,0x00164000,0x0e02c000,0x00000000,0x00200004,0x00000000,0x04039810,
+0x074800e4,0x2b910000,0x00200400,0x00000080,0x24000000,0x08908484,0x000a4000,0x00000000,
+0x14080e78,0x05048110,0x00000000,0x00800000,0xc8000164,0x00000c00,0x00000000,0xf87f1000,
+0x24040004,0x260000d3,0x000002c1,0x00080e00,0x00000000,0x00000c04,0x00000000,0x00000000,
+0x00000000,0x00000000,0x43244808,0x50213000,0xf0000000,0x08480003,0x00000000,0x0e040000,
+0x00000000,0x00240000,0x00000000,0x307b9200,0x48003617,0x82010000,0x24002286,0x000000b8,
+0x24000000,0x40000080,0x00060103,0x00000000,0x14080008,0x05008000,0x00200160,0x00900800,
+0x40020164,0x00001000,0x00000000,0x00000000,0x03300000,0x30000110,0x00000e01,0x001b0000,
+0x00000084,0x00001804,0x00000000,0x00000000,0xc0000000,0x003e03f9,0x34066818,0x50081000,
+0x00000004,0x00080000,0x008c0001,0x0e020000,0x00001b00,0x10800000,0x00000000,0x10800102,
+0x48388024,0x320e0330,0x30002000,0x000000d0,0x04020000,0x0b000080,0x000ac000,0x00000000,
+0x140a4800,0x09aa0000,0x000ac0f6,0x42000000,0x702c8164,0x00201001,0x00000000,0x00000000,
+0x03a06d70,0x60000152,0x00000200,0x0109f700,0x40000001,0x00000003,0x00000000,0x00000000,
+0x00000000,0x00000290,0x80044800,0x0a890100,0x00018000,0x00080004,0x000c0109,0x0e042000,
+0x00000000,0x04240000,0x00000000,0x00611008,0x04600604,0x0a0003a8,0x28108000,0x0043c0cc,
+0x20000000,0x10000080,0x00000000,0x00000000,0x14086818,0x00aa8008,0x00224190,0x00100000,
+0x80000164,0x00000400,0x00000000,0x00000000,0x36260020,0x3000015d,0x00000041,0x00010000,
+0x00000001,0x00004000,0x00000000,0x00000000,0x00000f40,0x002a0000,0x2418002c,0x50083152,
+0x00000000,0x00480000,0x001640b2,0x00040100,0x00000000,0x60a40000,0x00000000,0xb0015c20,
+0x48100227,0x0bd10000,0x00042400,0x000000b0,0x24000000,0x08000084,0x000a6000,0x00000000,
+0x14024808,0x00008190,0x000c0000,0x00900000,0xc0020000,0x00201020,0x00000000,0x00000000,
+0x03a60550,0x40001b90,0x06c000a0,0x20080e00,0xbc01e001,0x00002c00,0x00000000,0x00000000,
+0x27000000,0x00000000,0x37300010,0x0aa02800,0x00006800,0x00400000,0x000c2000,0x0d840000,
+0x00020000,0x00240004,0x00000000,0x1c020002,0x6e608054,0x1b5d0004,0x18000400,0x000000b8,
+0x80000000,0x10008490,0x00060000,0x00000000,0x0002002c,0x05000a04,0x002240e0,0x00100000,
+0x00424164,0x000010e1,0x00000000,0x003b1000,0x34060000,0x00000151,0x00001000,0x00000000,
+0xb8000001,0x00000001,0x00000000,0x00000000,0x00000000,0x00000000,0x00184820,0x5e8840c9,
+0x0000000c,0x00080000,0x00164001,0x0d800060,0x00000000,0x10800000,0x00000000,0x20020008,
+0x48200903,0x0bdd27a6,0x00000000,0x00000060,0x04020000,0x03000400,0x00000000,0x00000000,
+0x00002f40,0x00000151,0x08224120,0x42000000,0xf8000164,0x00200a00,0x00000000,0x00000000,
+0x37360000,0x00000154,0x000004e0,0x24200d80,0x38000001,0x00003804,0x00000000,0x00000000,
+0x0003e000,0x0a00e000,0xf7344824,0x90488802,0x00006d48,0x00480000,0x001640b2,0x0d86a000,
+0x00000000,0x90840004,0x00000000,0x00600110,0x80000600,0x0a040331,0x1b800000,0x00200000,
+0x24000000,0x10000080,0x00060000,0x00000000,0x3410483c,0x05cb0a06,0x00180192,0x00000000,
+0x78004164,0x00200401,0x00000000,0x003e1000,0x03300030,0x8008011c,0x06c00000,0x20000e00,
+0x00000000,0x00001000,0x00000000,0x00000000,0x00000000,0x0002f800,0xe4160440,0x901061d8,
+0x00c02810,0x00000010,0x008c00b2,0x000640c0,0x00000f00,0x20208004,0x00000000,0x10220006,
+0x00080824,0x20001620,0x4c908000,0x002800b0,0x24000000,0x00021000,0x000c0000,0x00000000,
+0x1720082c,0x00000154,0x00000160,0x00800000,0x81180000,0x00001001,0x00000000,0xe0400f84,
+0x00100820,0xc00121d1,0x06c00600,0x00080f80,0x80000800,0x00183c03,0x00000000,0x00000000,
+0x00f80000,0x003e0000,0xf4100648,0x904004c8,0x00014810,0x21000004,0x00000460,0x0c0400a0,
+0x000c1b00,0x20200004,0x00000000,0x240b1020,0x48300226,0x820003a4,0x10108207,0x00000000,
+0x80000000,0x07000090,0x000a2000,0x00000000,0x0408480c,0x05021351,0x000e8160,0x10900000,
+0x802c88c0,0x00000841,0x00000000,0x00391f84,0x37382810,0x68080150,0x01c02300,0x20080000,
+0x00000821,0x00003c80,0x00000000,0x00000000,0x7e03f000,0x0038000f,0xc4160760,0x00100018,
+0x00002800,0x00480000,0x00010460,0x00020100,0x000a1b00,0x00240004,0x00000000,0x241a0608,
+0x0020b003,0x220007a6,0x1c802000,0x00400080,0x80020000,0x1c000410,0x00060000,0x00000000,
+0x14100010,0x05cb0154,0x08200000,0x42000000,0x302c8000,0x00000a01,0x00000000,0xf87f1e04,
+0x14100758,0x40160209,0x05c00200,0x04200000,0x81000800,0x00000003,0x00000000,0x00000000,
+0x2703ffc0,0x003f0000,0xe4004f5c,0x00307348,0x0000e80c,0x21000008,0x00840000,0x0003a080,
+0x00000000,0x20200004,0x00000000,0xb00a0032,0x6e401603,0x21510006,0x10108000,0x00280080,
+0x24040000,0x19021000,0x000c0000,0x00000000,0x152e0e6c,0x01cb0bd6,0x00200060,0x42000000,
+0x80000002,0x00000840,0x00000000,0x003d1e84,0x24182838,0x6e170190,0x00004500,0x30090100,
+0x80000800,0x00082384,0x00000000,0x00000000,0x80000ffe,0x00000393,0x24160660,0x503100c6,
+0x00016d74,0x00480000,0x98840001,0x0006006c,0x00040000,0x10801080,0x00000000,0xa6720106,
+0x482c4283,0x920803a0,0x14802206,0x003000c0,0x80000100,0x13800410,0x00060000,0x00000000,
+0x17af2808,0x05010390,0x000c00c0,0x00801000,0xf0024002,0x00401000,0x00000000,0xfc400e44,
+0x27b02f64,0xc0171206,0x00000500,0x00080080,0x00000c84,0x00000004,0x00000000,0x00000000,
+0x00fbffc0,0x0000ffe0,0x962c080c,0x10703242,0x00014b78,0x00480008,0x00002001,0x0d84a0e0,
+0x00000000,0x108100f0,0x00000000,0x18015320,0x482c1324,0x92080000,0x28108206,0x002b0480,
+0x24000000,0x49b21000,0x000a0103,0x00000000,0x2400480c,0x05020002,0x000ec116,0x00101000,
+0x40000164,0x00400901,0x00000000,0xfc400000,0x27bc0008,0x6e000a00,0x00000700,0x00090000,
+0x00000884,0x00102000,0x00000000,0x00000000,0x0003ffc0,0x003eff80,0xf4004f48,0x50303886,
+0x00012a64,0x00480000,0x00012009,0x00060000,0x00000100,0x10800004,0x00000000,0x046a0406,
+0x6e6c04e4,0x0a060000,0x14802000,0x00100060,0x04000000,0x46b00400,0x00060103,0x00000000,
+0x24104828,0x09001b93,0x08290112,0x00801000,0xf1080000,0x00400c00,0x00000000,0xe07e1000,
+0x03b84c58,0xc0010a01,0x00000700,0x04200000,0x0201e084,0x00003803,0x00000000,0x00000000,
+0x00fbffc0,0x0039fbd0,0x241e6838,0x9030d889,0x00014952,0x00480008,0x00012009,0x0004a100,
+0x00000000,0x10808004,0x00000000,0x10015422,0x074c0224,0x9201240e,0x38108206,0x00400060,
+0x24040000,0x4cb21000,0x000a0103,0x00000000,0x24106800,0x05888192,0x000c0080,0x42001000,
+0x40004002,0x00400801,0x00000000,0xfc400000,0x03b80008,0x60010a04,0x00000700,0x10090000,
+0x38000884,0x00100984,0x00000000,0x00000000,0x0003ffc0,0x00000000,0x44062e4c,0x50600006,
+0x0000e974,0x00480008,0x18840420,0x0d860024,0x00000000,0x00040004,0x00000000,0x100a0636,
+0x07703474,0x820c1404,0x10108206,0x00000060,0x04000000,0x46821000,0x000a0103,0x00000000,
+0x24126838,0x01040000,0x000c0094,0x00801000,0xc0424164,0x000010e0,0x00000000,0xf47e1000,
+0x03b80548,0x20170a01,0x00400701,0x00090080,0x00000884,0x00100000,0x00000000,0x00000000,
+0x3e03ffc0,0x00000000,0xf4066800,0x50311200,0x00012804,0x00480000,0x008400b2,0x000400c0,
+0x00040000,0x000500f0,0x00000000,0x0e720022,0x000c8214,0x8a0c03a0,0x19002206,0x000000c0,
+0x80040000,0x46800490,0x00040103,0x00000000,0x14044f4c,0x000001dc,0x08260000,0x42001000,
+0xf0000000,0x00001001,0x00000000,0xf8400000,0x03b82e69,0xc0070a05,0x06c00600,0x14200080,
+0x00000084,0x00003800,0x00000000,0x00000000,0x3efbffc0,0x00000000,0x0416082c,0x5c88c063,
+0x00000000,0x21000000,0x98164000,0x0001a0d0,0x00000100,0x00040004,0x00000000,0xa00a0606,
+0x68009067,0x92080000,0x28000606,0x00300080,0x24040000,0x49800080,0x0008a103,0x00000000,
+0x24126838,0x0000019e,0x00000060,0x42001000,0x01080000,0x00000400,0x00000000,0x00000000,
+0x27bc0648,0x20150201,0x00004601,0x00090d80,0x80000084,0x00004802,0x00000000,0x00000000,
+0x0003fffe,0x00000000,0xc006481c,0xd00800c6,0x00002810,0x21000000,0x00000001,0x00010020,
+0x00000100,0x002500f0,0x00000000,0xa7615122,0x04402107,0x81920006,0x12800606,0x00000000,
+0x00000000,0x4c800080,0x00000103,0x00000000,0x04b64800,0x05021a00,0x002e0120,0x10900800,
+0xf1080012,0x00000400,0x00000000,0xf8400000,0x041c4820,0xc0112000,0x000044c0,0x00010000,
+0x00000c84,0x00002400,0x00000000,0x00000000,0x8003ffc0,0x0000000f,0x00066c70,0x5cc00010,
+0x00012801,0x00480000,0x00164001,0x00040080,0x00000000,0x00040004,0x00000000,0x000b9100,
+0x00300024,0x81d00320,0x00000606,0x00104454,0x24000000,0x49800084,0x00040103,0x00000000,
+0x24004808,0x09008192,0x00000040,0x00100000,0x00024000,0x000006e0,0x00000000,0x003e1000,
+0x00002818,0xb0172000,0x000010c0,0x11090d80,0x08000000,0x00002803,0x00000000,0x00000000,
+0x3e03ffc0,0x0000fc05,0x00066e78,0x9058c040,0x00018550,0x08480000,0x18000001,0x00010000,
+0x00000100,0x00040024,0x00000000,0x16220106,0x07400034,0x8b960010,0x10002206,0x00000000,
+0x00020000,0x4c808480,0x00000103,0x00000000,0x34100448,0x00000204,0x002c0000,0x42000012,
+0xf1080212,0x00001000,0x00000000,0xfc7e1000,0x03200008,0x80130a02,0x00000600,0x28010000,
+0x0241e001,0x00002000,0x00000000,0x00000000,0xa7fbffc0,0x000003ff,0x0006074c,0xdcc090c4,
+0x00010008,0x21000000,0x00002801,0x00040100,0x00000100,0x000120f0,0x00000000,0x06600032,
+0x07708634,0x80030320,0x28000606,0x00000040,0x24000000,0x49800084,0x00000103,0x00000000,
+0x24080800,0x05000192,0x002080b6,0x00100000,0x01080000,0x000006e0,0x00000000,0x00000000,
+0x24040558,0xb0011200,0xc6002300,0x00010000,0x00000000,0x00002800,0x00000000,0x00000000,
+0x0a03ffc0,0x000000f0,0x24006838,0xdcf00810,0x00004800,0x00480000,0x000c00b2,0x000600a0,
+0x05100100,0x00000004,0x00000000,0x061a0202,0x07700024,0x93d202a8,0x4a802206,0x000000b0,
+0x04000000,0x498004a0,0x000a0103,0x00000000,0x1410480c,0x05020002,0x00000100,0x00100800,
+0x91080000,0x000006e1,0x00000000,0x00000000,0x24100018,0x80130a01,0x06c00620,0x00010000,
+0x00000084,0x00001800,0x00000000,0x00000000,0x3a03ffc0,0x00040100,0x02360e40,0x0e981981,
+0x00000268,0x00480000,0x000000b2,0x0005c060,0x00000000,0x00040004,0x00000000,0x00020020,
+0x05700200,0x819207a4,0x29000606,0x000800c0,0x20000000,0x48908480,0x000a0103,0x00000000,
+0x0001cf48,0x09010b90,0x00000180,0x00100000,0x88004000,0x00000a00,0x00000000,0xe47f1000,
+0x03300009,0x80150002,0x07000600,0x31090000,0x00000021,0x00003800,0x00000000,0x00000000,
+0x0b03ffc0,0x0eff0000,0x24066c4c,0x0cd00004,0x00000020,0x00080000,0x980000b2,0xb400010c,
+0x00000000,0x00040004,0x00000000,0x22135038,0x4f602036,0x9a031408,0x18000606,0x00030040,
+0x24000000,0x49800084,0x000a0103,0x00000000,0x24a0876c,0x058b0004,0x00080000,0x00800000,
+0xf0005002,0x000006e1,0x00000000,0xec7e1fc4,0x03240448,0x86190005,0x07001000,0x20080000,
+0x00000800,0x00001800,0x00000000,0x00000000,0xcd03ff80,0x003ee00f,0x34000778,0x00193140,
+0x00004800,0x00080000,0x00164000,0xb4040000,0x00000000,0x000500f0,0x00000000,0x1e235904,
+0x07700104,0x819e0000,0x28002606,0x000300b0,0x24020000,0x49800484,0x000a0103,0x00000000,
+0x000c4c50,0x00ee0152,0x00000180,0x42000800,0x80005002,0x00000a01,0x00000000,0xe8400000,
+0x00044d48,0x20130a00,0x00000001,0x00080e00,0xcd01e084,0x00004001,0x00000000,0x00000000,
+0x4c000f80,0x0000011e,0x07bc680c,0xdc900010,0x00000000,0x00000000,0x000000b2,0x0e050060,
+0x00000000,0x00040000,0x00000000,0x06600d08,0x2f4d3034,0x9b922406,0x10000606,0x000000d4,
+0x20000000,0x4c900080,0x000c0103,0x00000000,0x00004c60,0x05020000,0x000a4180,0x00100000,
+0xc0004164,0x00040600,0x00000000,0xe4400000,0x03204808,0x90010004,0x07000000,0x20010000,
+0x0501e021,0x00001800,0x00000000,0x00000000,0x3903ef80,0x0003f400,0x02204f4c,0x90700082,
+0x00000008,0x00000000,0x000100b2,0x000500e1,0x00000000,0x20200004,0x00000000,0x01815020,
+0x4f6c0234,0x920e3404,0x49002606,0x000000c0,0x24000000,0xcc900084,0x00000103,0x00000000,
+0x00004c72,0x00ca1b9c,0xe02c0180,0x00800010,0xf8004000,0x000c0c00,0x00000000,0xfc7e1000,
+0x03344c58,0xe6000110,0x07001000,0x24080000,0x00000001,0x00001c83,0x00000000,0x00000000,
+0xff03ef80,0x0fc081cf,0xf406002c,0x0c913040,0x00802834,0x00080000,0x001640b2,0x000520c0,
+0x00000000,0x902200f0,0x00000000,0xa6639100,0x07630903,0x000a2406,0x48042400,0x000000a0,
+0x24000000,0xc9000084,0x00000103,0x00000000,0x00004c60,0x05000192,0x00000000,0x00100000,
+0xf8020002,0x240406c0,0x00000000,0xf4400000,0x03a40658,0xb2010000,0x07001080,0x20080e00,
+0x40000800,0x00001803,0x00000000,0x00000000,0x1d03e000,0x000087f0,0x47b84f4c,0x50304880,
+0x00004800,0x08480000,0x00000000,0x00066000,0x00000000,0x10200004,0x00000000,0x063b5002,
+0x06700274,0x8b940321,0x4c002207,0x002000d0,0x24000000,0xc9108484,0x000c0103,0x00000000,
+0x15200f70,0x05ee819e,0x002c0130,0x00800800,0xb8004010,0x480c0e01,0x00000000,0xe0400000,
+0x00060000,0xe0000000,0x00000400,0x00010000,0x00000084,0x00001c00,0x00000000,0x00000000,
+0xde03ef80,0x003e8ec7,0x04060e6c,0x5008f050,0x00c04860,0x00080000,0x00164009,0xb005c000,
+0x00001c01,0x00040000,0x00000000,0x06000436,0x00323874,0x00022405,0x49000400,0x001800d4,
+0x24000000,0xc0000084,0x00080103,0x00000000,0x14122800,0x05069a08,0x000000a0,0x00900000,
+0x882c8810,0x00000001,0x00000000,0x00000fc4,0x03a00444,0x8a182190,0x000010e0,0x20080e00,
+0x00000821,0x00000001,0x00000000,0x00000000,0x12000f80,0x0000fd30,0x3626680c,0x500303c9,
+0x00c06820,0x00480000,0x000000b2,0x00030000,0x00000000,0x00048004,0x00000000,0x06035808,
+0x04403000,0x9a0003a0,0x40002607,0x000000cc,0x20000000,0x09600000,0x000c8000,0x00000000,
+0x2400482c,0x010403d7,0x00270180,0x00800000,0xc0000002,0x000c0641,0x00000000,0xfc400f84,
+0x00002800,0xa818c002,0x07000000,0x01090000,0x38000801,0x00001803,0x00000000,0x00000000,
+0xce000000,0x00003d6f,0x37260f7e,0x90013000,0x0001c804,0x00000000,0x002120b2,0x0e000000,
+0x00001c00,0x04240000,0x00000000,0x00320100,0x68103040,0x81940330,0x40002207,0x000000c0,
+0x24000000,0xc9c00484,0x000ca103,0x00000000,0x24100f48,0x0d0101dc,0xe00800a0,0x00100007,
+0xa82c8164,0x00080641,0x00000000,0x00000000,0x17ae4c60,0xa8000190,0x07000000,0x24080000,
+0x00000001,0x00000000,0x00000000,0x00000000,0x17000000,0x00380140,0x34182f4c,0x904000c8,
+0x0001c808,0x00080000,0x001640b2,0x000000c1,0x00000000,0x00200000,0x00000000,0x00015038,
+0x48003234,0x0b920230,0x18002000,0x000000c0,0x20000000,0xc0000480,0x00080103,0x00000000,
+0x0010680c,0x00c80000,0x00000120,0x00000000,0xf0000000,0x00001000,0x00000000,0xfc400000,
+0x00082818,0x8e001202,0x07000400,0x00010e00,0x00000001,0x00003800,0x00000000,0x00000000,
+0x9803e000,0x003e0396,0x3418081c,0x90400116,0x0001c838,0x00080000,0x000000b2,0x00020000,
+0x00001c00,0x000620f0,0x00000000,0x18035900,0x00000904,0x00060006,0x4b802400,0x0000004c,
+0x24000000,0x00000084,0x00080000,0x00000000,0x00000830,0x09050a02,0x04200180,0x00000000,
+0x002c8002,0x00000c01,0x00000000,0xe0400000,0x03a64d50,0xc4101212,0x07000060,0x24200000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x21000000,0x003891b0,0x3416680c,0x10300081,
+0x0001a820,0x08480000,0x001640b2,0xd40660e0,0x00000001,0x24240000,0x00000000,0x00615d00,
+0x680c3134,0x20000018,0x21842400,0x000000cc,0x04000000,0x00000080,0x000a0000,0x00000000,
+0x24006800,0x00ed9a0c,0x00000130,0x00100000,0xc0001002,0x00001080,0x00000000,0x00000000,
+0x02204808,0x02160b92,0x07000421,0x00080e00,0x00000001,0x00001804,0x00000000,0x00000000,
+0x15000f80,0x003f0190,0x47a60f5c,0xd0003302,0x00014810,0x00480000,0x000000b2,0x0e0280e0,
+0x00000000,0x00040004,0x00000000,0x1c015d36,0x2e6b2024,0x2b900320,0x20002000,0x000000d0,
+0x24000000,0x00008484,0x0006a000,0x00000000,0x3404680c,0x09010000,0x002c00a0,0x00900000,
+0x18004164,0x00001041,0x00000000,0xfc781000,0x03a64820,0x4e000a06,0x07000400,0x20080000,
+0x00000021,0x00004c00,0x00000000,0x00000000,0x20000000,0x003f0190,0x00000000,0x90004802,
+0x00014820,0x00080000,0x001640b2,0x00000000,0x00000000,0x00240004,0x00000000,0x042b9102,
+0x68200014,0x120e3400,0x10002000,0x003800d4,0x24000000,0x09b00404,0x00000000,0x00000000,
+0x2400481c,0x00c90194,0x002240a0,0x00800000,0x40020000,0x000c1040,0x00000000,0x00000000,
+0x00064820,0x00061315,0x07000200,0x00010e00,0x38000001,0x00003803,0x00000000,0x00000000,
+0x00000000,0x00000230,0xc3a6045c,0x901008c2,0x0001a820,0x00080000,0x001640b2,0x0e020060,
+0x00001c00,0x00000000,0x00000000,0xa07a0120,0x000c0007,0x22000404,0x21000000,0x00400000,
+0x24000000,0xc6000404,0x000a2103,0x00000000,0x00042f78,0x00010003,0x00000120,0x00000000,
+0xc02c8164,0x000010c1,0x00000000,0x00000000,0x03a00444,0x000c0a00,0x07000461,0x20080e00,
+0x38000821,0x00001804,0x00000000,0x00000000,0x2103e000,0x00009ba0,0x3626074c,0x0cc00000,
+0x00012e44,0x08480000,0x000000b2,0x0e01c000,0x00001c00,0x04240004,0x00000000,0x06420e04,
+0x07403624,0x21d42409,0x40000400,0x00380084,0x20000000,0x10000400,0x00000000,0x00000000,
+0x2400680c,0x0dcf01d2,0x00230000,0x00100000,0xf02c8164,0x000010c1,0x00000000,0x003f1f84,
+0x00020648,0x30001356,0x070002c1,0x00080000,0x00000800,0x00001800,0x00000000,0x00000000,
+0x1f03e000,0x0e40979e,0x2418074c,0x00111000,0x00c06801,0x00480000,0x00164000,0x00060000,
+0x00001c00,0x40040000,0x00000000,0x00015238,0x077c0004,0x01980327,0x43802400,0x000000a0,
+0x24000000,0x07008484,0x000ca000,0x00000000,0x0014080c,0x00cd8000,0x000000a0,0x10900000,
+0xd02c8000,0x6c0010c0,0x00000000,0xe0400000,0x02204820,0x08160209,0x000004e1,0x00010e00,
+0xb8000801,0x00000001,0x00000000,0x00000000,0x1a000000,0x00000150,0x03a0000c,0x9000cb06,
+0x00c0e838,0x00400000,0x000000b2,0x00020000,0x00000000,0x00200000,0x00000000,0xb0039100,
+0x07700003,0x920207a0,0x31002607,0x000000c4,0x24000000,0x10000400,0x000a0000,0x00000000,
+0x00006800,0x008c1202,0x002400a0,0x00148000,0xc0000010,0x00000001,0x00000000,0x00000000,
+0x02a02800,0x2e18120c,0x07000e01,0x01090000,0x38000081,0x00003c03,0x00000000,0x00000000,
+0x3803e000,0x003ef390,0x03be044c,0x90110003,0x00004800,0x20400000,0x000020b2,0x0e01c0e0,
+0x01b00000,0x2426a0f0,0x00000000,0x004a0008,0x0d443000,0x819836b9,0x0b802207,0x00280000,
+0x20000000,0x10000090,0x00000000,0x00000000,0x00066830,0x0000019b,0x00080000,0x00100000,
+0x00020164,0x00000c00,0x00000000,0xf8400000,0x03a60544,0xe0101a08,0x070908a0,0x21090000,
+0x00000021,0x00003804,0x00000000,0x00000000,0xa3000000,0x003ff808,0x34060740,0x905901c0,
+0x00c06838,0x00400000,0x00840000,0x0e02c000,0x00001c00,0x20240004,0x00000000,0x06000128,
+0x00300524,0x20000006,0x28000400,0x00280060,0x00000000,0x00000080,0x000c0000,0x00000000,
+0x25a0680c,0x00ea0000,0x000ac136,0x10900000,0x802c8164,0x00000c00,0x00000000,0x00000fc4,
+0x00064820,0x20100190,0x00000d01,0x00080080,0x00000800,0x00000000,0x00000000,0x00000000,
+0x40000000,0x003fe629,0x373c680c,0x90588050,0x00002830,0x00400a20,0x002120b2,0x0005c080,
+0x00000000,0x20240000,0x00000000,0xa00a0300,0x0f5c1003,0x800003a0,0x13902207,0x00400060,
+0x04000000,0x10000080,0x0006c080,0x00000000,0x3416080c,0x0d058392,0x002c0120,0x10900000,
+0xd0000000,0x00000241,0x00000000,0x00000f84,0x03a02e49,0x20000196,0x07000481,0x20010000,
+0x38000800,0x00003803,0x0000002d,0x00000000,0x00000000,0x00000240,0x74060544,0xd0401346,
+0x00004b40,0x00400000,0x800020b2,0x0e03c0e0,0x00000000,0x04240004,0x00000000,0x06000d00,
+0x003c0600,0x01920018,0x38000400,0x000000d0,0x24000000,0x13008480,0x000c0080,0x00000000,
+0x34060004,0x09001358,0x00200000,0x00800000,0x70004164,0x00000e61,0x00000000,0x00000fc4,
+0x03b82e64,0x0018019e,0x070010c1,0x00080000,0x00000801,0x00004800,0x00000024,0x00000000,
+0x2403e000,0x09ff0390,0xf416074c,0x0c803902,0x00004809,0x00400fc0,0x00164000,0x00004060,
+0x00000000,0x102220f0,0x00000000,0xa001d002,0x68000303,0x3b5c0000,0x48102000,0x00400000,
+0x20000000,0x10000400,0x000c8000,0x00000000,0x34066d54,0x01c9000c,0xc0224140,0x10900006,
+0x80004000,0x7e000c61,0x00000000,0xe0400000,0x03a62804,0x30100002,0x00000621,0x24080e00,
+0xc0000001,0x00001804,0x00000000,0x00000000,0x22000000,0x00250250,0x34196c4c,0x00007006,
+0x00006e78,0x08480000,0x00164408,0x000340ec,0x02401c00,0x00200004,0x00000000,0x04615008,
+0x680c0040,0x33de36a8,0x48002000,0x000000c0,0x20000000,0x08000410,0x00060000,0x00000000,
+0x353c281c,0x00ee0002,0xc0224120,0x00800006,0xc02c8212,0x00001000,0x00000000,0xfc400e84,
+0x03260441,0xc0001350,0xb4001000,0x24080e00,0x00000800,0x00000003,0x00000000,0x00000000,
+0x3f03e000,0x000003d0,0x03a6480c,0x50400309,0x0001280c,0x20400000,0x80164001,0x0e05c00a,
+0x00000000,0x000600f0,0x00000000,0x38615130,0x074c0937,0x120203a6,0x1b842400,0x00402000,
+0x20000000,0x10000080,0x00000000,0x00000000,0x00100830,0x00070000,0x40140120,0x0086c002,
+0xc0000164,0x00000c01,0x00000000,0xf4400000,0x02a80448,0x20000098,0x000902c1,0x04080e00,
+0x38000081,0x00003004,0x00000000,0x00000000,0x3903ef80,0x0aa7ee60,0xc41e6808,0x00004012,
+0x00004b48,0x08480000,0x001640b2,0x0e0200c0,0x03f00000,0x902280f0,0x00000000,0x1c0a0106,
+0x2f4c00f4,0x0192032e,0x42000400,0x004000d4,0x20000000,0x00000090,0x00000000,0x00000000,
+0x25b80030,0x00c80154,0x00000000,0x00800000,0xf0004164,0x00201081,0x00000000,0xfc400000,
+0x04040e48,0x0e001a0a,0x07000a01,0x00080e00,0x1441e000,0x00003c84,0x00000000,0x00000000,
+0x80fc0000,0x097f9e3e,0x83a04810,0x900041c0,0x00004818,0x00080000,0x00000000,0x0e032000,
+0x00000000,0x60a40004,0x00000000,0xa6135600,0x074c04c3,0x01920000,0x43802400,0x000000d4,
+0x24000000,0x09008484,0x000c8000,0x00000000,0x341c4804,0x00c913d0,0x00160060,0x00100000,
+0xe0020164,0x01e010e1,0x00000000,0xa8b91fc4,0x36200460,0x2000009b,0x00000201,0x00080000,
+0x00000801,0x00003800,0x00000000,0x00000000,0x0003f000,0x0000e3f0,0x34066c4c,0x9ef00003,
+0x0001c820,0x00080000,0x00164001,0x0005c000,0x00001c00,0x04240000,0x00000000,0x06135900,
+0x48303040,0x01dc0000,0x23800400,0x1c400040,0x20000002,0x10000400,0x00000000,0x00000000,
+0x24000000,0x05e90198,0x002e00a0,0x00800000,0xc02c8000,0x000010e1,0x00000000,0x00000000,
+0x03260800,0x201013da,0x000004c1,0x20090e00,0x80800821,0x00001803,0x00000000,0x00000000,
+0xcdf7ef80,0x00004cc2,0x00004800,0x00000000,0x00000000,0x00000000,0x00000000,0x0000000c,
+0x00000000,0x00009020,0x00000000,0x00000001,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000100,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x000008c0,0x00000000,0x00132000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x05218800,0x00000000,0x00000000,0xbf400000,0x00000000,0x00000d30,0x00000008,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x000180c4,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00001000,0x00000000,0x00000000,
+0x01b00000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000006,0x00000040,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x20000000,0x00000206,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00180000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x000008c0,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00004800,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x01900000,0x00000000,0x00000000,0x00000000,0x00008480,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x40000000,0x00000005,0x00000000,0x00000000,0x00000020,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00080000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x34000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x0000c000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x34000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00060000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x80000000,0x00000003,0x24000000,0x90000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000034,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00180000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x04000f40,0x00000000,0x00040000,0x00040000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00002000,0x00000000,
+0x34000000,0x00000000,0x90000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x28010000,0x00000005,0x00000000,0x00000000,0x00000000,
+0x80fbef80,0x05002c02,0x00006800,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x80209020,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x02000000,
+0x00000100,0x08000000,0x00060000,0x00000000,0x00180000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00080400,0x00000000,0x508b2288,0x00000000,0x00000000,0x00000000,0x00000000,
+0x01204000,0x00000000,0x00000000,0x00000000,0x00fc0000,0x00140000,0x0000000c,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x29740000,0x00000002,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0xc0000400,0x00000103,0x00000000,
+0x34000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x3f400000,
+0x0ff7ef80,0x00004cf3,0x00040000,0x00100000,0x00000000,0x80000000,0x00000000,0x00000000,
+0x00000000,0x00009020,0x00000000,0x01000801,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000300,0xc0000000,0x00000103,0x00000000,0x00080000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00132000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x05418800,0x00000000,0x00000000,0xbf400000,0x40000000,0x00004c04,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000002,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x08a00000,0x00000000,0x00000000,
+0x00100000,0x00000000,0x00000000,0x00000000,0x00000000,0x0004a000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x04000000,0x00000000,0x00004800,0x00000000,0x00000800,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x20000000,0x00000206,0x00000000,
+0x00000000,0xc0000000,0x00000103,0x00000000,0x24004800,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x0003d000,0x00000040,0x00000008,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x01300002,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x34000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000001,0x00000000,0x00000000,0x00800000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00100000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00060000,0x00120000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00002804,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000002,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x80000000,0x00000207,0x00000034,0x00000000,0x00000000,0x00000000,0x00000000,
+0x24000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x34060000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00006800,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00004180,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000034,
+0x00000300,0x00000000,0x00000000,0x00000000,0x24100000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x34060000,0x00000000,0x00000000,0x00000000,
+0x00000004,0x00000000,0x00000000,0x00000000,0x00000000,0x00152c00,0x00000000,0x00000000,
+0x00000030,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000054,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00040000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00180000,0x00000000,0x00000000,0x00000000,0x00000004,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00006800,0x00000000,0x00006800,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00002000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x03a00000,0x80000000,0x000000c0,0x20000000,
+0x00000021,0x00000000,0x00000000,0x00000000,0x4efbef80,0x05123803,0x34000030,0x00000000,
+0x00000030,0x08480000,0x00000000,0x00000000,0x00000000,0x80209020,0x00000000,0xa0000000,
+0x00000007,0x00000000,0x00008000,0x01800000,0x00000c00,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x508e2348,
+0x00180000,0x00000000,0x00000000,0x00000000,0x01204000,0x00000000,0x00000000,0x00000000,
+0xd5ffefbe,0x00143002,0x00060000,0x00000000,0x00000000,0x00000000,0x00000000,0x0000000c,
+0x00000000,0x69749020,0x00000002,0x01800000,0x00000000,0x00000000,0x00000000,0x06000000,
+0x00000300,0x00000000,0x00000000,0x00000000,0x01200000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x48000000,0x00000000,0x000c22c8,0x00000000,0x60000000,0x00000000,0x00000000,
+0x01204000,0x00000000,0x00000000,0x3f400000,0xcdfbffc0,0x02800c03,0x34000000,0xd0000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x902280c4,0x00000000,0x0001d000,
+0x00000034,0x00000000,0x00042400,0x00000000,0x00000000,0x08900000,0x00000000,0x00000000,
+0x01a00000,0x00000000,0x00000000,0x00000000,0x00000000,0x01840000,0x00000000,0x28800000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x05418800,0x00000000,0x00000000,0x00000000,
+0x84d3ff76,0x04ce4c02,0x0004e800,0x00000000,0x00000060,0x80000000,0x00001000,0x00000000,
+0x00000000,0x90229964,0x00000000,0x00000001,0x00000600,0x20000000,0x2b800286,0x00300000,
+0x00001600,0xc0000000,0x00000103,0x00000000,0x34180000,0x00000000,0x000a0000,0x00000000,
+0x00000000,0x00200000,0x00000000,0x4d400e44,0x00000000,0x80000a00,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x805fa000,0x0cffff00,0x02f92950,0x77200000,0x00000000,
+0x000a6800,0x00000000,0x00212000,0x00000000,0x00000000,0x90209020,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00002000,0x00000000,0x00000400,0x08000000,0x00000000,0x00000000,
+0x34060000,0x00000000,0x00000000,0x00000000,0x00000000,0x0020a000,0x00000000,0x2c8a2000,
+0x00002800,0x001000d6,0x00000000,0x00200000,0x04418800,0x00000000,0x00000000,0x00000000,
+0x4edbf000,0x04c04c05,0x00000000,0xd0000000,0x00006830,0x08480000,0x00000000,0x00000000,
+0x00000000,0x90229964,0x00000000,0xa0120003,0x00000003,0x00000000,0x00000000,0x00300000,
+0x00001600,0x08a00000,0x00000000,0x00000000,0x04060000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x0024a000,0x00000000,0x4d400000,0x00020030,0x00000050,0x00000000,0x00000000,
+0x00000004,0x00000000,0x00000000,0x805fa000,0x0bfc0f38,0x02842800,0x74000000,0x00184000,
+0x00000800,0x80000000,0x00000000,0x00000000,0x00000000,0x90200000,0x00000000,0x01800800,
+0x00000000,0x00000000,0x00000000,0x00000034,0x00000000,0xc0000000,0x00000103,0x00000000,
+0x34302800,0x00000000,0x00000000,0x00000000,0x00000000,0x00800000,0x00000000,0x28800000,
+0x24000800,0x00000004,0x000000c0,0x00000000,0x04418800,0x00000000,0x00000000,0x00000000,
+0x00e3ff00,0x050050a0,0x43a10000,0x00000000,0x000a4810,0x00000000,0x01003000,0x00000000,
+0x00000000,0x9022a960,0x00000000,0x00000001,0x00000000,0x80000000,0x00000287,0x02302800,
+0x00000000,0x00000000,0x00000000,0x00000000,0x34040000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x01000000,0x00000000,0x51400000,0x00006c4b,0x00101204,0x00000000,0x08010000,
+0x0221e000,0x00000000,0x00000000,0x805fa000,0x17ebffbc,0x059758e3,0x1403a803,0x0ae80000,
+0x00000030,0x00000000,0x02000000,0x0e000002,0x00001c00,0x9022a960,0x00000000,0x00000001,
+0x00000064,0x80000004,0x00000206,0x08000000,0x00000000,0x40000000,0x00000103,0x00000000,
+0x00066c40,0x0d000000,0x08180140,0x00000000,0x006c8164,0x00800000,0x00000000,0x59400308,
+0x00000758,0x00100008,0x00000000,0x19200000,0x01204400,0x00000000,0x00000000,0x805fa000,
+0x80fbdfba,0x02c00002,0x00030808,0x00080000,0x00020000,0x00000008,0x20002001,0x000000d1,
+0x00060000,0x90200184,0x00000000,0x04000000,0x04400100,0x80000000,0x00102206,0x08342400,
+0x20000000,0x08000010,0x00000000,0x00000000,0x14080030,0x00e9c000,0x04000000,0x00000000,
+0x00000000,0x02000000,0x00000000,0x2c800288,0x00000030,0x001700d4,0x00000000,0x14080000,
+0x01204400,0x00004000,0x00000000,0x00000000,0x8d03ffc0,0x00002c20,0x24004800,0x1a804002,
+0x01020000,0x00000000,0x00000000,0x00000000,0x00000000,0x000100f0,0x00000000,0x000a0000,
+0x05400200,0x80000000,0x10000206,0x00422400,0x00000000,0x40800000,0x00000103,0x00000000,
+0x34000460,0x00000000,0x001b0166,0x00000000,0xc0004000,0x00000000,0x00000000,0x00192000,
+0x00004800,0x6013920c,0x00000000,0x00000000,0x0201e000,0x00000000,0x00000000,0x00000000,
+0x0cffffc0,0x03590970,0x24146820,0x10080000,0x00002800,0x00000008,0x023641b2,0x00000000,
+0x00040000,0x00000000,0x00000000,0x00200408,0x00040880,0x800003a0,0x00108207,0x00000000,
+0x80000000,0x40000010,0x00000103,0x00000000,0x00000000,0x00000000,0x08000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000740,0x00000000,0x07000000,0x04200e00,
+0x0201e000,0x00000000,0x00000000,0x00000000,0x40f3ffc0,0x06406573,0x36282c44,0x0c800000,
+0x00000800,0x00000000,0x00000000,0x00000000,0x00000000,0x90209044,0x00000000,0x00200002,
+0x00000514,0x80000000,0x00000206,0x08000000,0x00002000,0x48000000,0x00000103,0x00000000,
+0x00006800,0x00000000,0x00001200,0x00000000,0x00000000,0x00800000,0x00000000,0x00000348,
+0x0000680c,0x00061a00,0x00000000,0x00000000,0x39204000,0x00004481,0x00000000,0x00000000,
+0xcfe3ffb8,0x064064b2,0x14000742,0xda800002,0x00000008,0x00000000,0x28165000,0x0e0000e1,
+0x00000000,0x90229964,0x00000000,0x00000009,0x00000000,0x80000000,0x00000206,0x08302400,
+0x00001000,0x40000000,0x00000103,0x00000000,0x00060550,0x00000000,0x00000000,0x00000000,
+0x00000164,0x00800000,0x00000000,0x654002c8,0x00000008,0x000000dc,0x00000000,0x10000e00,
+0x01204400,0x00004380,0x00000000,0x805fa000,0x57fbfffb,0x028038f3,0x66200000,0x00600000,
+0x00022810,0x00000000,0x28000000,0x000000c1,0x00001c00,0x902110f0,0x00000000,0x00000020,
+0x00000000,0x80000000,0x00000206,0xfc302400,0x0001f4ff,0x40000000,0x00000103,0x00000000,
+0x00106e40,0x00880000,0x00000000,0x00000000,0x002c8000,0x02000000,0x00000000,0x28800000,
+0x00000000,0x0010000c,0x00000000,0x00000000,0x0221e400,0x00000000,0x00000000,0x00000000,
+0x17ffffbb,0x00003170,0x40040000,0x00080006,0x00006800,0x00000000,0x00000000,0x00000000,
+0x00000000,0x000110f0,0x00000000,0x00020000,0x07400100,0x80000000,0x00000206,0x00000000,
+0x0001fc00,0x40000000,0x00000103,0x00000000,0x34000038,0x50000000,0x000000d6,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00006800,0x00001200,0x00000000,0x00000000,
+0x0221e400,0x00000000,0x00000000,0x00000000,0x0ffffffc,0x039734f3,0x00006803,0x0a810000,
+0x00006830,0x00000000,0x000011b2,0x00000000,0x00000000,0x90209020,0x00000000,0x00000000,
+0x00300800,0x80000000,0x00000206,0x08000000,0x00001000,0x48000000,0x00000103,0x00000000,
+0x04060640,0x50000000,0x001b0000,0x00000000,0x00000000,0x02000000,0x00000000,0x388d2308,
+0x0000680c,0x00000008,0x07000000,0x00000000,0x39204400,0x00000001,0x00000000,0x00000000,
+0xcfe3ffb8,0x064064b2,0x14000742,0xda800002,0x00000008,0x00000000,0x28165000,0x0e0000e1,
+0x00000000,0x90229964,0x00000000,0x00000009,0x00000000,0x80000000,0x00000206,0x08302400,
+0x00002200,0x40000000,0x00000103,0x00000000,0x00060550,0x00000000,0x00000000,0x00000000,
+0x00000164,0x00800000,0x00000000,0x654002c8,0x00000008,0x000000dc,0x00000000,0x10000e00,
+0x01204400,0x00004380,0x00000000,0x805fa000,0x57fbfffb,0x028038f3,0x66200000,0x00600000,
+0x00022810,0x00000000,0x28000000,0x000000c1,0x00001c00,0x902110f0,0x00000000,0x00000020,
+0x00000000,0x80000000,0x00000206,0xfc302400,0x0001f4ff,0x40000000,0x00000103,0x00000000,
+0x00106e40,0x00880000,0x00000000,0x00000000,0x002c8000,0x02000000,0x00000000,0x28800000,
+0x00000000,0x0010000c,0x00000000,0x00000000,0x0221e400,0x00000000,0x00000000,0x00000000,
+0x17ffffbb,0x00003170,0x40040000,0x00080006,0x00006800,0x00000000,0x00000000,0x00000000,
+0x00000000,0x000110f0,0x00000000,0x00020000,0x07400100,0x80000000,0x00000206,0x00000000,
+0x0001fc00,0x40000000,0x00000103,0x00000000,0x34000038,0x50000000,0x000000d6,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00006800,0x00001200,0x00000000,0x00000000,
+0x0221e400,0x00000000,0x00000000,0x00000000,0x0ffffffc,0x039734f3,0x00006803,0x0a810000,
+0x00006830,0x00000000,0x000011b2,0x00000000,0x00000000,0x90209020,0x00000000,0x00000000,
+0x00300800,0x80000000,0x00000206,0x08000000,0x00001000,0x48000000,0x00000103,0x00000000,
+0x04060640,0x50000000,0x001b0000,0x00000000,0x00000000,0x02000000,0x00000000,0x388d2308,
+0x0000680c,0x00000008,0x07000000,0x00000000,0x39204400,0x00000001,0x00000000,0x00000000,
+0x40dfefb8,0x04402ff3,0xb6b00000,0xdc800000,0x00026c6c,0x00000000,0x803640b2,0x0f84a00e,
+0x00000000,0x902290d0,0x00000000,0x00000009,0x054020c0,0x81900006,0x30000286,0x0a000000,
+0x04001400,0x40000084,0x00000143,0x00000000,0x3406080c,0x00008000,0x00000112,0x00000000,
+0x70000164,0x00200600,0x00000000,0x45c00f84,0x00000000,0x60000000,0x07c00200,0x00000f80,
+0x0521a000,0x00000000,0x00000000,0xbf400000,0x0d03ef80,0x000048b0,0x00066e60,0x0e980000,
+0x0801067c,0x80080008,0x000001b2,0x000000c0,0x00000000,0x000180f0,0x00000000,0xa001d000,
+0x00002002,0x81920220,0x20108306,0x08300000,0x20000000,0x40000080,0x00000183,0x00000000,
+0x04062804,0x00000000,0x08000000,0x00800000,0xf0000000,0x000010c1,0x00000000,0x00000000,
+0x00000800,0x80000000,0x07c00000,0x04200000,0x04c1a000,0x40001800,0x00000000,0x00000000,
+0xc0ebef80,0x003c3402,0x00090003,0x00010101,0x10000000,0x80000000,0x00000000,0x000300c0,
+0x00001f00,0x000210d0,0x00000002,0x02011000,0x00040000,0x800203a0,0x18000686,0x16384a00,
+0x20001400,0x40000400,0x00000143,0x00000000,0x00000008,0x00000000,0x00300178,0x00000000,
+0x406c8000,0x00000000,0x00000000,0x00000000,0x00004808,0x80000200,0x00000ac0,0x00010000,
+0x0421a000,0x80000000,0x00000000,0x00000000,0x7dfbef80,0x02c02c03,0x36380010,0x10100008,
+0x30000740,0x00400000,0x000020b2,0x000000e1,0x00000000,0x902210d0,0x00000000,0xa0011008,
+0x2f603002,0x800003b8,0x20000706,0xf4302a00,0x040028ff,0x40000000,0x00000183,0x00000000,
+0x34100550,0x00000150,0x00180000,0x00100000,0xc0000000,0x06000601,0x00000000,0x2c800fc4,
+0x00002c40,0x24000000,0x07c008e1,0x00010000,0xc221e000,0x00000003,0x00000000,0x00000000,
+0x00ffef80,0x00113520,0x24060540,0x0c980100,0x08002800,0x00400000,0x00002000,0x0f800000,
+0x00000000,0x697120f0,0x00000002,0x00000008,0x00001840,0x81900220,0x00002286,0x00000000,
+0x20000000,0x40000080,0x00000143,0x00000000,0x00024d44,0x00000001,0x0032c0c0,0x00000000,
+0x00000164,0x00600000,0x00000000,0x00381e44,0x00006800,0x00000000,0x00000600,0x00010000,
+0x8221e000,0xc0000003,0x00000000,0x3f400000,0xfffbffc0,0x02b93402,0x34106800,0x50100000,
+0x3800075c,0x28480000,0x00164001,0x0f80c000,0x00000000,0x902290d0,0x00000000,0x20000006,
+0x08000002,0x80020000,0x2c000286,0x08000000,0x00001000,0x48000000,0x00060143,0x00000000,
+0x03200e64,0x00c80000,0x00660166,0x00000000,0x00000164,0x00800000,0x00000000,0x28800000,
+0x24000810,0x00000000,0x00000000,0x00000f80,0x0521a000,0x80004380,0x00000000,0x00000000,
+0x0be3fffb,0x00002cd0,0x40000000,0x00084000,0x18000808,0x00000014,0x001641b2,0x00000000,
+0x00161f00,0x000660d0,0x00000002,0x00000000,0x00000200,0x80000000,0x00202686,0x12000000,
+0x24000c00,0x40000020,0x00000143,0x00000000,0x07b80f40,0x00a80000,0x00310100,0x00800000,
+0x002c8000,0x00000600,0x00000000,0xf4400000,0x00040002,0x00001a00,0x07c00000,0x10080f80,
+0xc4c1a000,0x00000003,0x00000002,0x38400000,0x83efff80,0x04404403,0x2401cd4c,0x00000002,
+0x0000000c,0x00400000,0x00001000,0x00000000,0x00000000,0x90229960,0x00000000,0x26011101,
+0x04433002,0x80000000,0x00002306,0x02000000,0x00000600,0x48000000,0x00000183,0x00000000,
+0x00060000,0x00000000,0x00181ad6,0x00000000,0x00000000,0x0024a000,0x00000000,0x45400388,
+0x0000000b,0x00000000,0x00000000,0x10000000,0x01204000,0x80004280,0x00000001,0x805fa000,
+0xc3fbef80,0x03523032,0x00040009,0x00000000,0x30026800,0x00000000,0xaa0021b2,0x000000d0,
+0x00001c00,0x90209020,0x00000000,0x00015000,0x00000000,0x80000000,0x00040686,0x02302000,
+0x00000400,0xc9000000,0x00000103,0x00000000,0x24000000,0x00000000,0x001ac000,0x00000000,
+0x006c8000,0x008c6000,0x00000000,0x348c22c8,0x00006800,0x00100000,0x07000000,0x00000000,
+0x01204000,0x00000000,0x00000000,0x00000000,0x8ffbfffc,0x02804924,0x00000000,0x0a800000,
+0xc0462e4c,0x00000000,0x00364000,0x00000000,0x00000000,0x902100f0,0x00000000,0x00000000,
+0x05403000,0x80000000,0x00000286,0x00000000,0x00000000,0xc8000000,0x00000103,0x00000000,
+0x14200000,0x00000000,0x0018c000,0x00000000,0x00000000,0x00800000,0x00000000,0x28800f84,
+0x00000003,0x001212d0,0x00000000,0x00000e00,0x0441e000,0x00000000,0x00000000,0x00000000,
+0x3efbfffc,0x00c00124,0x02a00000,0x00080002,0x00000348,0x00000000,0x80164000,0x0000000c,
+0x00000000,0x000260d0,0x00000000,0x00000100,0x00000000,0x80000000,0x00000207,0x00000000,
+0x00000000,0x40000000,0x00000143,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000f84,0x00000800,0x0000000c,0x00000400,0x00000e00,
+0x0521a000,0x80000000,0x00000007,0x00000000,0xd0ffffc0,0x00002900,0x00020000,0x0c800000,
+0x30000830,0x80080000,0x00000000,0x00000000,0x00000000,0x000280f0,0x00000000,0x00011000,
+0x00040000,0x80000000,0x00200686,0x0c000000,0x00000000,0x40000000,0x00000143,0x00000000,
+0x00100640,0x00000000,0x00000100,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x14000000,0x80000200,0x00000000,0x00000000,0x04c1a000,0x00004381,0x00000003,0x00000000,
+0xc3ffffc0,0x04be4003,0x16200800,0x00100000,0x90000000,0x80000000,0x010020b2,0x00000000,
+0x00001c00,0x90209020,0x00000000,0x00019000,0x00000004,0x80000000,0x00400706,0x02000000,
+0x00000400,0x40000000,0x00000143,0x00000000,0x04000008,0xb0000000,0x00000000,0x00000000,
+0x002c8002,0x00800000,0x00000000,0x489023c8,0x00006800,0xf2000000,0x07000260,0x00000000,
+0x01204000,0x00000000,0x00000000,0x00000000,0x00f7ff40,0x03c03c50,0x00026808,0x0e800000,
+0xe0000000,0x00000000,0x02000000,0x00000000,0x00000000,0x9022a960,0x00000000,0x00000001,
+0x00000124,0x80080000,0x4ac00286,0x12000000,0x00000000,0xc8000000,0x00000143,0x00000000,
+0x00000663,0x00000000,0x00000000,0x00000000,0x00000000,0x00280000,0x00000000,0x3d400000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x0421e000,0x40000000,0x00000003,0x805fa000,
+0x43fbffc0,0x030c3823,0x00040808,0x08820000,0xe88e0000,0x00000000,0x02000000,0x00000000,
+0x00000000,0x9022a0d0,0x00000000,0x04600000,0x00000800,0x80000000,0x00400306,0x00000000,
+0x00000000,0xc8000000,0x00000143,0x00000000,0x00000660,0x00000000,0x00000000,0x00000000,
+0x00000000,0x12082000,0x00000000,0x30800000,0x00000642,0x00120000,0x00000000,0x00080000,
+0x0541a000,0x80000000,0x00000003,0x00000000,0x00fbffc0,0x02ca3003,0x14000000,0x0ac04000,
+0x500e0000,0x00000000,0x00000000,0x00000000,0x00000000,0x902290d0,0x00000000,0x00000000,
+0x00000024,0x80000000,0x00000287,0x0c000000,0x00000800,0xc8900000,0x00000143,0x00000000,
+0x04000660,0x00000000,0x00000000,0x00000000,0x00000000,0x09082000,0x00000000,0x2c800000,
+0x00000000,0x00120090,0x00000000,0x00000000,0x0521a000,0xc0000000,0x00000003,0x00000000,
+0x0cfbffc0,0x028000c0,0x00000000,0x10000000,0x80000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x902260d0,0x00000000,0x00000000,0x00000900,0x80000000,0x00000287,0x10000000,
+0x00001000,0xc0000000,0x00000103,0x00000000,0x34000660,0x00000000,0x00000000,0x00000000,
+0x00000000,0x09000000,0x00000000,0x28800000,0x00000000,0x00000298,0x00000000,0x00000000,
+0x04c1a000,0x00000000,0x00000000,0x00000000,0x8003ffc0,0x00002802,0x24002808,0x08801000,
+0x08000020,0x00000000,0x00000000,0x00000000,0x00000000,0x000290d0,0x00000000,0x00000020,
+0x00000000,0x80000000,0x00000286,0x08000000,0x00000800,0x40000000,0x00000143,0x00000000,
+0x00060660,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000002,0xa0000008,0x00000000,0x00000000,0x0521a000,0x40000000,0x00000001,0x00000000,
+0x0afbffc0,0x000000a0,0x40000003,0x00600000,0x18004808,0x00000000,0x80000000,0x00000100,
+0x00000000,0x000260d0,0x00000000,0x0013d000,0x00000900,0x92000000,0x00000706,0x0c300000,
+0x00002000,0x40000000,0x00000183,0x00000000,0x34000740,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00004800,0x00000008,0x00000000,0x00000000,
+0x04c1a000,0xc0000000,0x00000001,0x00000000,0x0003efc0,0x00000003,0x34004800,0x00200000,
+0x08000008,0x00000000,0x00000000,0x000000c1,0x00000000,0x000210f0,0x00000000,0x00000800,
+0x00000100,0x80080000,0x00000286,0x18000000,0x00004400,0x40000000,0x00000143,0x00000000,
+0x24060660,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00004808,0x00000000,0x00000000,0x00000000,0x0421a000,0xc0000000,0x00000000,0x00000000,
+0x8003effe,0x00002c02,0x00006800,0x00000000,0x38000000,0x00000000,0x00000000,0x000000c0,
+0x00000000,0x000210f0,0x00000000,0x01600c00,0x00003900,0x80000000,0x00000306,0x18300000,
+0x00000400,0x40000000,0x00024183,0x00000000,0x00040020,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x003f1000,0x00006828,0x00100000,0x00000000,0x10000000,
+0x0521a400,0x40000000,0x00000001,0x00000000,0x0003fffe,0x00003003,0x0400c802,0x00001000,
+0x48006e40,0x00000000,0x1a000000,0x000000e1,0x00000000,0x002210d0,0x00000000,0x00000022,
+0x00000224,0x80000000,0x00000286,0x1a304420,0x00002800,0x40000000,0x00000143,0x00000000,
+0x03a40030,0x00000000,0x01400000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00004808,0x001001d0,0x00000000,0x00000000,0x0421a400,0xc0000000,0x00000002,0x00000000,
+0x8003fffe,0x000b33f2,0x14010000,0x00000000,0x48000008,0x00000000,0x20000000,0x000000e1,
+0x00000000,0x000110f0,0x00000000,0x00120000,0x00000800,0x92000000,0x00000286,0x04302400,
+0x00000c00,0x40000000,0x00000143,0x00000000,0x00044800,0x00000000,0x01c00000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x03a0000e,0x0000000c,0x00000000,0x30000000,
+0x0221e400,0xc0000000,0x00000002,0x00000000,0x8003fffe,0x00003002,0x34038001,0x00000002,
+0x50000030,0x00000000,0x98000000,0x000000e0,0x00000000,0x000110f0,0x00000000,0x00000800,
+0x00000000,0x80080000,0x00000286,0x08302400,0x00001400,0x40000000,0x00000143,0x00000000,
+0x00060740,0x00000000,0x01440030,0x00000000,0x00000000,0x00000600,0x00000000,0x00000000,
+0x0006000c,0x800000d0,0x00000000,0x10000000,0x0221e400,0x40000000,0x00000003,0x00000000,
+0x0003fffe,0x00003003,0x43226c43,0x00000000,0x70004800,0x00000000,0x18010008,0x000000e1,
+0x00000000,0x000110f0,0x00000000,0x00600000,0x00003000,0x81d00000,0x00000686,0x0c382434,
+0x00001c00,0x40000080,0x00000143,0x00000000,0x0000002c,0x00000000,0x00064000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000fc4,0x0000000c,0xa000000c,0x00000000,0x10000000,
+0x0221e400,0x80000000,0x00000003,0x00000000,0x3f03ffc0,0x00002803,0x0321000c,0x00000002,
+0x78000002,0x00000000,0x18010000,0x000000e1,0x00000000,0x000110f0,0x00000000,0x00000000,
+0x00000804,0x80030000,0x00000686,0x10382400,0x00003000,0x40000000,0x00000143,0x00000000,
+0x34000000,0x00000000,0x000000d6,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x03a04800,0x86000000,0x00000000,0x00000000,0x0221e001,0xc0000000,0x00000003,0x00000000,
+0x0003ffc0,0x00003003,0x24090770,0x00000000,0x8000480c,0x00000000,0x00000008,0x00000100,
+0x00000000,0x000110f0,0x00000000,0x0001d000,0x00000000,0x80000000,0x00002286,0x12002000,
+0x00003400,0x40000000,0x00000143,0x00000000,0x00060000,0x00000000,0x00000020,0x00000000,
+0x00000000,0x000006e0,0x00000000,0x003f1000,0x00180000,0x86000000,0x00000000,0x00000000,
+0x0221e000,0x80000000,0x00000004,0x00000000,0x0b03fffe,0x00002843,0xc0038743,0x0a800000,
+0x80000008,0x00000000,0x00000008,0x000000c1,0x00000000,0x000220f0,0x00000000,0x0001dc00,
+0x00002600,0x81d00000,0x00002286,0x04302020,0x00000000,0x40000400,0x00000143,0x00000000,
+0x00000640,0x00000000,0x000000c0,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x80000000,0x00000000,0x00000000,0x04c1e400,0xc0000000,0x00000004,0x00000000,
+0x0003fffe,0x003f3003,0x34030003,0x00080000,0x88006808,0x00000000,0x00000001,0x000000c1,
+0x00000000,0x000210f0,0x00000000,0x00000c00,0x00003000,0x800c0000,0x00000686,0x10382400,
+0x00001000,0x40000000,0x00000143,0x00000000,0x05a00008,0x50000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00006800,0x00000000,0x00000000,0x20000000,
+0x0421e400,0x00000000,0x00000005,0x00000000,0x0303ffc0,0x00003003,0x00080000,0x00000002,
+0x88000000,0x00000000,0x00001000,0x000000c1,0x00000000,0x000210f0,0x00000000,0x00600000,
+0x00003000,0x80000000,0x4a800286,0x14382400,0x00000c00,0x40000000,0x00000143,0x00000000,
+0x00060000,0x00000000,0x00310000,0x00000000,0x00000000,0x00000600,0x00000000,0x00000000,
+0x0000680e,0x80000000,0x00000000,0x00000000,0x0221e000,0x40000000,0x00000005,0x00000000,
+0x0003fffe,0x00003003,0x03220000,0x00000008,0xb0002820,0x00000000,0xa8010000,0x000000e0,
+0x00000000,0x000210f0,0x00000000,0x0101d000,0x00000034,0x81d00000,0x00002286,0x20300000,
+0x00003000,0x40000400,0x00000143,0x00000000,0x00200000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000460,0x00000000,0x00000000,0x00006e43,0x00000000,0x00000000,0x00080000,
+0x0221e400,0x80000000,0x00000007,0x00000000,0x0003ffc0,0x00003003,0x00000000,0x0c800000,
+0xb8002818,0x00000000,0x80000000,0x00000000,0x00000000,0x000110f0,0x00000000,0x01800c00,
+0x00000000,0x81dc0000,0x00000286,0x0c384400,0x00002c00,0x40000400,0x00000143,0x00000000,
+0x00060000,0x50000000,0x00000000,0x00000000,0x00000000,0x00000460,0x00000000,0x00000000,
+0x00000023,0x00000000,0x00000000,0x00000000,0x0421e000,0xc0000000,0x00000007,0x00000000,
+0x0003ffc0,0x000030b3,0x64010002,0x0e80c000,0xc0000004,0x00000000,0x80001000,0x000000c0,
+0x00000000,0x000260f0,0x00000000,0x00000002,0x00000200,0x81dc0000,0x00000286,0x1c304000,
+0x00000400,0x40000400,0x00000143,0x00000000,0x00060740,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x80000000,0x00000000,0x00000000,
+0x0221e000,0x00000000,0x00000008,0x00000000,0x0003fffe,0x00003003,0x14020000,0x5000c000,
+0xc8000000,0x00000000,0x28000000,0x000000c1,0x00000000,0x000210f0,0x00000000,0x00000000,
+0x00000000,0x800c0000,0x00000686,0x0a302000,0x00001c00,0x40000000,0x00000143,0x00000000,
+0x2418080c,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x34000000,0x00000000,0x00000000,0x00000000,0x0421e400,0x40000000,0x00000008,0x00000000,
+0x00ffffc0,0x00003000,0x00048000,0x5ee2c000,0xd0000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x000110f0,0x00000000,0x00000000,0x00000000,0x80000000,0x4a800286,0x16384400,
+0x00003c00,0x40000000,0x00000143,0x00000000,0x00040740,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000600,0x00000000,0x00000000,0x00180000,0x80000000,0x00000000,0x00000000,
+0x0421e000,0x80000000,0x00000008,0x00000000,0x00ffffc0,0x038034c0,0x00046800,0x5ee20000,
+0xd8000000,0x00000000,0x00000000,0x00000000,0x00000000,0x90209020,0x00000000,0x00000000,
+0x00000100,0x81d00000,0x00000686,0x22302000,0x00004800,0x48000080,0x00000143,0x00000000,
+0x0000074c,0x00000000,0x00000000,0x00000000,0x00000000,0x12080000,0x00000000,0x388d2000,
+0x00000740,0x00000000,0x00000000,0x00080000,0x0221e000,0xc0000000,0x00000008,0x00000000,
+0x8bf7ff80,0x03823832,0x0000c804,0x00000000,0x00000270,0x00000000,0x02000000,0x00000000,
+0x00000000,0x90229964,0x00000000,0x02000001,0x00000000,0x00000000,0x00000000,0x04000000,
+0x00001000,0x08000000,0x00000000,0x00000000,0x01200000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00400000,0x00000000,0x39400288,0x24004f41,0x00000090,0x00000000,0x08010000,
+0x01204000,0x00000000,0x00000000,0x805fa000,0x8a03ffc0,0x000008c0,0x14000008,0x00000000,
+0x00060020,0x00000000,0x00000000,0x00000000,0x00000000,0x0002a0d0,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0xc9800000,0x00000103,0x00000000,
+0x01b00000,0x00000000,0x00000000,0x00000000,0x00000000,0x00002000,0x00000000,0x00000000,
+0x0010000b,0x001200d8,0x00000000,0x10000000,0x0541a000,0x00000000,0x00000000,0x00000000,
+0x0003ef80,0x00000c20,0x36200000,0x00000000,0x00020000,0x00000000,0x01002000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x80000000,0x00000207,0x00000000,
+0x00000000,0xc0000000,0x00000103,0x00000000,0x00180000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x001023c8,0x00000000,0x0013000c,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0xcdffffc0,0x035030f2,0x24064800,0x00000000,
+0x00002840,0x00000000,0x00000000,0x00000000,0x00000000,0x90209020,0x00000000,0x00000000,
+0x00000024,0x80000000,0x00000207,0x04000000,0x00000800,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x01000000,0x00000000,0x348c22c8,
+0x00004800,0x00000000,0x00000000,0x00000000,0x01204000,0x00000000,0x00000000,0x00000000,
+0xa903ff80,0x0c96c84b,0x64040800,0x90080006,0x00000340,0x00400000,0x001640b2,0x0f83c000,
+0x00001f00,0x9022a960,0x00000000,0xba000300,0x48000002,0x120802a2,0x18000400,0x480000d0,
+0x04000000,0x10000000,0x000c0000,0x00000000,0x01b84838,0x00e99202,0x002e0112,0x00100000,
+0x002c8164,0x00200a00,0x00000000,0xc9400b88,0x00040020,0x2a000000,0x07c01041,0x00010f80,
+0xc1204001,0x00003983,0x00000000,0x805fa000,0x6f03ffc0,0x02febc05,0x00040004,0x9010c000,
+0x00002830,0x00400000,0x001640b2,0x0f868000,0x00001f00,0x20200000,0x00000000,0x080bd800,
+0x00088800,0x01920002,0x00002000,0x00000054,0x00000000,0x00000080,0x000c8000,0x00000000,
+0x24300008,0x00a88192,0x002e0196,0x00800000,0xc82c8164,0x00000001,0x00000000,0xfc400000,
+0x00002e40,0x00000051,0x07c002e0,0x00080f80,0x90000001,0x00004484,0x00000000,0x00000000,
+0xdb03ffc0,0x094066fb,0xb7200800,0xd0500000,0x00004820,0x00400000,0x001640b2,0x0f80c000,
+0x00001f00,0x00200000,0x00000000,0xa8120000,0x065030c3,0x00020000,0x1c800000,0x00200058,
+0x20000000,0x00000000,0x000a0000,0x00000000,0x341c0000,0x00038008,0x00000138,0x00800000,
+0x382c8164,0x00001001,0x00000000,0x00000000,0x37200020,0xe0000a06,0x07c010c0,0x00000f80,
+0x00000001,0x00003c80,0x00000000,0x00000000,0x4203ffc0,0x0bfcbfbc,0x37366e48,0x9000b052,
+0x20004820,0x00400000,0x000000b2,0x0003a000,0x00001f00,0x20200000,0x00000000,0xa2000606,
+0x07408002,0x800002b0,0x20000686,0x00000000,0x20000000,0x40000080,0x00000183,0x00000000,
+0x15b80000,0x00ac0000,0x002e0000,0x00900000,0x002c8000,0x000010e0,0x00000000,0x00000f84,
+0x34184800,0xc0000b14,0x07c00ac0,0x00080000,0x00000801,0x40000000,0x00000000,0x00000000,
+0xdf03ffc0,0x08febc0b,0xf41c2800,0xd0710106,0x68004964,0x00400000,0x00164000,0x00000000,
+0x00000000,0x20200000,0x00000000,0xa2120302,0x06480042,0x92000002,0x12800706,0x000000d0,
+0x00000000,0x40000400,0x000c0143,0x00000000,0x00006800,0x09001200,0x00000000,0x00800000,
+0x00000000,0x00000a00,0x00000000,0x00000000,0x041c0008,0x00000a04,0x000000e0,0x00010f80,
+0x00000000,0x80003803,0x00000002,0x00000000,0x2f03ffc0,0x087fbc07,0x07380818,0x90000000,
+0x80004820,0x00400000,0x00000000,0x0004a0e0,0x00000000,0x24240000,0x00000000,0xa2000200,
+0x680c0102,0x80080000,0x0b800286,0x004000b8,0x00000000,0x40000080,0x000c8103,0x00000000,
+0x25b84800,0x00030002,0x00000000,0x00000000,0xc8004002,0x00000001,0x00000000,0x00000000,
+0x37206810,0x30000b14,0x00000841,0x00080000,0x00000001,0x00000000,0x00000000,0x00000000,
+0x0003f03e,0x0800bc00,0x34040800,0x00100010,0x10000000,0x00400000,0x00000000,0x00064000,
+0x00000000,0x00200004,0x00000000,0x06e00000,0x00380034,0x80000000,0x13802286,0x00000000,
+0x20000000,0x40000000,0x000a0143,0x00000000,0x373c0808,0x00000000,0x001400e0,0x00800000,
+0x00000000,0x00000d00,0x00000000,0x00000f84,0x34180830,0x30000a04,0x00000e81,0x00080000,
+0x00000c01,0xc0002800,0x00000000,0x00000000,0x0003f000,0x0afebc00,0x37382830,0xd0180046,
+0x40000000,0x00400000,0x00a12001,0x0004a060,0x00000000,0x20200004,0x00000000,0x24020000,
+0x06400056,0x80000000,0x00002286,0x000044c0,0x00000000,0x40000400,0x0000c183,0x00000000,
+0x0018680c,0x00001200,0x00160042,0x00800000,0xf0004000,0x00000000,0x00000000,0xfc400000,
+0x341c6800,0x72000a04,0x00000ec0,0x00080000,0x00000000,0x40000000,0x00000002,0x00000000,
+0x50fbffc0,0x0a4000be,0x02b84c40,0x00180008,0x70006824,0x00400000,0x00010009,0x0001a000,
+0x00000000,0x00200004,0x00000000,0x1a1b9001,0x00080624,0x81900000,0x12002286,0x100000a0,
+0x20000000,0x00028480,0x00000000,0x00000000,0x000c000c,0x05000002,0x00000000,0x00800000,
+0xb0000000,0x00000200,0x00000000,0x00391000,0x3418680c,0x00000b94,0x00000ae0,0x00000000,
+0x0321e001,0x00000000,0x00000000,0x00000000,0x8e03ff80,0x000000d4,0x24010018,0x0e800006,
+0x78014800,0x00400000,0x00000000,0x0004c000,0x00000000,0x14240000,0x00000000,0xb6000300,
+0x00000026,0x81980320,0x33800286,0x00400058,0x24000000,0x00828480,0x00000000,0x00000000,
+0x00a86800,0x000201d0,0x001800c0,0x00800000,0x00000000,0x00000600,0x00000000,0x00000000,
+0x34186e70,0x20010bd4,0x000006c1,0x00080000,0x38000001,0x00001401,0x00000000,0x00000000,
+0x1503ff80,0x00000130,0x80044808,0x0ef8c010,0x38002b70,0x00400000,0x001640b2,0x0f800060,
+0x00001f00,0x00000000,0x00000000,0xb69a0e00,0x00000626,0x93d80010,0x10000706,0x00404040,
+0x00000000,0x49000080,0x000a0183,0x00000000,0x05a0680c,0x00000190,0x001800c0,0x00800000,
+0x002c8164,0x00000000,0x00000000,0x00000f84,0x00186c74,0x00012a06,0x07c00600,0x10080f80,
+0x38000801,0x40001381,0x00000001,0x00000000,0x1703ef80,0x003e0160,0xf4000d58,0x98f80100,
+0x58000054,0x28480000,0x181640b2,0x0f8400e1,0x00001f00,0x20200004,0x00000000,0xb69a0f00,
+0x00000126,0x9a0c1400,0x00000306,0x04000054,0x00000000,0xc9000000,0x000a8143,0x00000000,
+0x2400077c,0x00c80200,0x001800c0,0x00000000,0x002c8164,0x00040400,0x00000000,0xf8781000,
+0x26206e72,0x0e012004,0x07c01081,0x25090f80,0x3c21e0a1,0x40000001,0x00000002,0x00000000,
+0x9a03ff80,0x002fbdef,0x07b84d50,0x0a9c0000,0x60018000,0x08480000,0x001640b2,0x0f8000c1,
+0x00000000,0x002110f0,0x00000000,0xb69b9306,0x4f400027,0x9b133410,0x18002706,0x004040c0,
+0x00008c00,0xc9000080,0x00000143,0x00000000,0x05bc054c,0x000413db,0x001800c0,0x50900000,
+0x00000164,0x00040401,0x00000000,0xf8400000,0x00106832,0x00120000,0x07c00000,0x00000f80,
+0x39000801,0x40004381,0x00000001,0x00000000,0xe503ef80,0x000002af,0x26268660,0x50380726,
+0x18010378,0x00000000,0x801640b2,0x0f860100,0x00001f00,0x142610f0,0x00000000,0x101a0f06,
+0x682c2700,0x9a0c2400,0x28000287,0x3c304020,0x04004800,0xc9000080,0x00000143,0x00000000,
+0xc120081c,0x0dc81a00,0x00300160,0x00000000,0x402c8164,0x00080001,0x00000000,0xf0400000,
+0x34006830,0x00000a90,0x07c00000,0x20010f80,0xc421e000,0xc0004383,0x00000005,0x00000000,
+0xe203ef80,0x0e0001d0,0x36ac2818,0x00180046,0x88010800,0x00080000,0x001640b2,0x0f8000a0,
+0x00001f00,0x000210f0,0x00000000,0x383a0b00,0x08003117,0x9a031732,0x00000286,0x18182080,
+0x04003800,0xcc000000,0x000c6143,0x00000000,0xb418281c,0x01e99310,0x00300170,0x00100000,
+0x002c8164,0x00100e00,0x00000000,0x00000000,0x17382e70,0x2c121208,0x07c00001,0x20010f80,
+0x8421e000,0x40004383,0x00000004,0x00000000,0x2803ef80,0x0f800120,0x03a66d50,0x0aa05107,
+0xe801c860,0x00000000,0x001640b2,0x0f820100,0x00001f00,0x00200004,0x00000000,0x1b1b1f04,
+0xa8008434,0x9a030000,0x00002287,0x382000a0,0x00000000,0xc8000080,0x000c0143,0x00000000,
+0x05a9a81c,0x05001a0c,0x00300160,0x00000000,0x002c8164,0x00101000,0x00000000,0xec7a1000,
+0x03a06800,0x80160204,0x07c00a00,0x20000f80,0xc421e000,0x80004383,0x00000002,0x00000000,
+0x2c000f80,0x00000260,0x66a24d74,0xd03802c2,0xc0c04808,0x00080000,0x801640b2,0x0f8200ad,
+0x00001f00,0x00040004,0x00000000,0x033a0326,0x0f700004,0x9a0f1400,0x00000687,0x00400000,
+0x00001f00,0xc9000080,0x0000c143,0x00000000,0x3418281c,0x00021a03,0x00180160,0x00100000,
+0x402c8164,0x00040481,0x00000000,0xf8400e04,0x04106c70,0x80120a0c,0x07c00000,0x20010f80,
+0xc0000800,0xc0004383,0x00000003,0x00000000,0x2303ff80,0x000002c0,0x03a70664,0x0060f056,
+0x1001cb78,0x00000001,0x801640b2,0x0f8600ad,0x00001f00,0x002002c8,0x00000000,0x0a3b1326,
+0x0f4c4024,0x8b180408,0x28000687,0x0c000060,0x04001f00,0xc9000400,0x000c2143,0x00000000,
+0x34380e50,0x0100000c,0x00300160,0x00100000,0x402c8164,0x00040ca1,0x00000000,0xfc400000,
+0x2408074c,0x8008c000,0x07c00000,0x00010f80,0xc421e000,0x00004383,0x00000008,0x00000000,
+0x5f03e000,0x003ff98e,0x001a054c,0x100811c6,0x00014808,0x00080000,0x801640b2,0x0f800000,
+0x00001f00,0x002002c8,0x00000000,0xa41b5308,0x074c38e6,0x32030000,0x00000421,0x00402000,
+0x04000000,0xcb000400,0x00000143,0x00000000,0x00b80f4c,0x0dcd83d0,0x00300170,0x00100000,
+0x402c8164,0x00000ca1,0x00000000,0x003f1000,0x34064f72,0xec010a04,0x07c00c00,0x20010f80,
+0x80000000,0x40004384,0x00000005,0x00000000,0x0003ef80,0x0000fbc0,0x94000838,0xd0290002,
+0x30004828,0x00080000,0x001640b2,0x0f800060,0x00001f00,0x000290f0,0x00000000,0xb0e00720,
+0x480c2206,0x82070000,0x18002306,0x324000d4,0x04001000,0x1b000400,0x00000000,0x00000000,
+0x34006830,0x05061208,0x00300170,0x00000000,0x002c8164,0x00000900,0x00000000,0x00391000,
+0x00060830,0xec000a01,0x07c00000,0x00000f80,0x0421e000,0x00003b04,0x00000000,0x00000000,
+0x24000f80,0x0ff80000,0x27a22810,0xd06900c9,0xa0004978,0x00000000,0x001640b2,0x0f800000,
+0x00001f00,0x20200004,0x00000000,0x021a0c02,0x00021124,0x920b0000,0x30002287,0x000040a0,
+0x00000000,0x14000400,0x00000000,0x00000000,0x3401803c,0x00c91202,0x00320190,0x00000000,
+0x282c8164,0x00000c61,0x00000000,0x003f1000,0x03a06802,0x720c0151,0x07c00240,0x20080f80,
+0x00000821,0x00004380,0x00000000,0x00000000,0xa1000f80,0x0020ebff,0x07b64d50,0xd0684001,
+0x00014829,0x00400000,0x801640b2,0x00000100,0x00001f00,0x24048004,0x00000000,0x3063d306,
+0x0f403003,0x2a0303b8,0x13802000,0x1a040080,0x20000000,0x1c000400,0x000c4000,0x00000000,
+0x04064820,0x09010a00,0x00320180,0x00000000,0xa02c8000,0x000c1060,0x00000000,0x00000000,
+0x3406480c,0x12000000,0x07c00400,0x20010f80,0x3d21e000,0x00000004,0x00000000,0x00000000,
+0x6403ef80,0x0000f97f,0x00060574,0xd0680420,0x00000148,0x00080000,0x001640b2,0x0f800100,
+0x00000000,0x042610f0,0x00000000,0x00000026,0x0440b054,0x01d80324,0x41002000,0x0fa860a0,
+0x20002c00,0xc5000400,0x00000143,0x00000000,0x34ac0800,0x0d004000,0x00324170,0x00000000,
+0x40000164,0x00000901,0x00000000,0x00000000,0x00066800,0xe80a0a01,0x07c00000,0x20080f80,
+0x0501e000,0x40004384,0x00000008,0x00000000,0x9a03ef80,0x000001df,0x04000804,0xdae81206,
+0x01018000,0x00080000,0x001640b2,0x0f800000,0x00001f00,0x000210f0,0x00000000,0xa4fa0300,
+0x08000002,0x20031406,0x13802000,0x000000cc,0x04004000,0x10000400,0x000ca000,0x00000000,
+0x01b86804,0x00ca1a0c,0x00324172,0x00000000,0xb82c8164,0x00000000,0x00000000,0x00000000,
+0x14000810,0x30000001,0x07c00200,0x20080f80,0x80059001,0x00004003,0x00000000,0x00000000,
+0x9e03ef80,0x0000fa7f,0x03a00d48,0xd07893c6,0x38014800,0x00400000,0x801640b2,0x0f810061,
+0x00001f00,0x00200000,0x00000000,0x3881df00,0x08000077,0x9a000324,0x29802687,0x0f986040,
+0x20001f00,0x00000000,0x00000000,0x00000000,0xc1b8074c,0x00000200,0x00320000,0x00000000,
+0x582c8164,0x00040ec0,0x00000000,0xfc400f44,0x03b00570,0x30161a08,0x07c004e1,0x00080f80,
+0x80000001,0x00001003,0x00000000,0x00000000,0x2d000000,0x0ec000f0,0xc3a62810,0xd0608146,
+0x0041cb49,0x00400000,0x00164000,0x0f800001,0x00001f00,0x400422c8,0x00000000,0xa613dc10,
+0x68300003,0x3a030000,0x14802000,0x00004000,0x20000000,0xc0000400,0x00080143,0x00000000,
+0x00a8003c,0x09070000,0x001800e0,0x00100000,0x382c8164,0x009004c1,0x00000000,0xe0400000,
+0x03200010,0x00000a04,0x00000001,0x20080f80,0x00459000,0x80001404,0x00000005,0x00000000,
+0xb803ef80,0x000003ef,0x00000554,0x50088300,0xd800c808,0x00000000,0x00164001,0x0f838000,
+0x00001f00,0x000660f0,0x00000000,0x00020328,0x0e701600,0x92032404,0x00000687,0x0f9c6000,
+0x20006800,0xc0008480,0x00000143,0x00000000,0x1408000c,0x09040000,0x00000170,0x00000000,
+0x402c8164,0x00001040,0x00000000,0xec7c1e04,0x00142830,0xce0e0a04,0x00000840,0x00080f80,
+0xc541e000,0xc0000003,0x00000004,0x00000000,0x1d03e000,0x0e3ff800,0x34064804,0x90190200,
+0x00018008,0x00400000,0x000000b2,0x0f81a080,0x00000000,0x000290f0,0x00000000,0x241a0838,
+0x68040703,0x20003730,0x13802000,0x000000a0,0x04007c00,0x00000400,0x00000000,0x00000000,
+0x0000680c,0x0dcc01d8,0x002c0174,0x00800000,0x40000164,0x00000001,0x00000000,0x00000000,
+0x00066800,0x26161204,0x07c01001,0x00010000,0xc0059000,0x00001803,0x00000000,0x00000000,
+0x1b000000,0x00000000,0x34062800,0xd00001a2,0x0001800c,0x00080000,0x000020b2,0x0f800000,
+0x00000000,0x00000004,0x00000000,0x04020324,0x680c0024,0x2000033c,0x10002400,0x000000b8,
+0x04000000,0x03000000,0x00000000,0x00000000,0x00000f6c,0x00018190,0x00280170,0x00900000,
+0x00004164,0x00000841,0x00000000,0x003f1e04,0x3400680c,0x00000a0c,0x07c002e0,0x20080000,
+0x80000000,0x00004c03,0x00000000,0x00000000,0x00000000,0x0029fc00,0x00000554,0x0ef84142,
+0x00004820,0x00400000,0x000020b2,0x0f8200e0,0x00001f00,0x00008004,0x00000000,0x063b9312,
+0x48380000,0x00003404,0x14800400,0x00400060,0x20000000,0x1b000400,0x00080000,0x00000000,
+0x01b86830,0x09011a07,0x002f0190,0x00000000,0x782c8164,0x00000a01,0x00000000,0x00000000,
+0x00000770,0xe0000a01,0x07c00420,0x00010000,0x80000001,0x00003c84,0x00000000,0x00000000,
+0x00000000,0x0a80f000,0x001a0004,0xd01842c0,0x00016838,0x00400000,0x001640b2,0x0f83c000,
+0x00001f00,0x00040004,0x00000000,0x10020302,0x68040734,0x01d00000,0x00000400,0x00000040,
+0x20000000,0x10000400,0x00000000,0x00000000,0x00000800,0x0904000c,0x002e0194,0x00100000,
+0xf82c8164,0x00000300,0x00000000,0x003c1fc4,0x00000030,0x200c0156,0x07c00e21,0x20080f80,
+0x00000800,0x00003c00,0x00000000,0x00000000,0xc0000000,0x003f7009,0x74024d6c,0x10093002,
+0x00002830,0x00400000,0x001640b2,0x00004060,0x00001f00,0x00000000,0x00000000,0x001a0800,
+0x683418c0,0x21dc0000,0x12800400,0x0f9ae040,0x20000000,0x00000400,0x00000000,0x00000000,
+0x0006683c,0x05058000,0x002a0190,0x00800000,0x402c8000,0x00000ca1,0x00000000,0x00000000,
+0x34180740,0x00000a04,0x07c00500,0x01010f80,0x80000001,0x00004b81,0x00000000,0x00000000,
+0x24000000,0x0ebb0000,0x57ba080c,0x10010048,0x00006820,0x00400000,0x001640b2,0x00004060,
+0x00001f00,0x20240004,0x00000000,0x20000f20,0x07744083,0x020b0000,0x18000400,0x00000000,
+0x04000000,0x00000400,0x00080000,0x00000000,0x2418683c,0x00c98008,0x002a4150,0x00800000,
+0xe82c8002,0x00000000,0x00000000,0xec7e1000,0x0000681c,0x80000009,0x07c00a00,0x20080f80,
+0xb8059000,0x00004c04,0x00000000,0x00000000,0x0c000000,0x0f3902ae,0x27a66804,0x1010c060,
+0x00014800,0x00080000,0x801640b2,0x0f84006f,0x00001f00,0x00040004,0x00000000,0x041a0000,
+0x04400800,0x20012400,0x13000400,0x0f986040,0x20001f00,0x1a000000,0x00000000,0x00000000,
+0x3400000c,0x09030bd0,0x002a0156,0x00800000,0x802c8164,0x00000e00,0x00000000,0xe47f1f04,
+0x04000f4c,0x00021a02,0x07c00840,0x00080f80,0x80000000,0x00004b84,0x00000000,0x00000000,
+0x96000000,0x067f023f,0x440e0008,0x1a910002,0x00000060,0x00400000,0x801640b2,0x0f80000b,
+0x00001f00,0x800402c8,0x00000000,0x201a0d10,0x074c0103,0x20002410,0x00000000,0x0f82e000,
+0x04001f00,0x19000080,0x000c8000,0x00000000,0x34186e78,0x0d001203,0x00260120,0x00100000,
+0xc02c8164,0x00000d00,0x00000000,0x00000000,0x2418680c,0x00100a05,0x07c00460,0x20080f80,
+0x38459000,0x00004004,0x00000000,0x00000000,0x98000000,0x0000fa8f,0xc3a42800,0x50201102,
+0x00014810,0x00400000,0x801640b2,0x0f832061,0x00001f00,0x002082c8,0x00000000,0x240a0d00,
+0x04400803,0x20010010,0x1c000000,0x0f986000,0x20001f00,0x1c000400,0x0006c000,0x00000000,
+0x3418683c,0x00000000,0x002e0174,0x00000000,0x002c8164,0x00000000,0x00000000,0x003f1e04,
+0x00000440,0x20000155,0x07c004a1,0x00010f80,0x19059000,0x00004000,0x00000000,0x00000000,
+0x18000000,0x0e0001d0,0x17a60550,0x003851c1,0x00010a48,0x00400000,0x001640b2,0x0f816000,
+0x00001f00,0x002002c8,0x00000000,0x1c03d002,0x680c0024,0x1a012400,0x30002000,0x00000000,
+0x00000000,0x10000000,0x000c0000,0x00000000,0x362e280c,0x00060000,0x002e0180,0x00800000,
+0x002c8164,0x00000400,0x00000000,0x00000000,0x34020770,0x2a001351,0x07c004e1,0x00080f80,
+0x38459000,0x00003804,0x00000000,0x00000000,0x00000000,0x0fc00180,0x03a60544,0x50180081,
+0x00010000,0x00400000,0x001640b2,0x0f8000e0,0x00001f00,0x00040000,0x00000000,0x3041d306,
+0x6c700037,0x1a030000,0x00002000,0x00400000,0x00000000,0x00000080,0x000ac000,0x00000000,
+0x14006820,0x0d000000,0x002e4130,0x00800000,0x402c8164,0x00000201,0x00000000,0x00000fc4,
+0x14060f4c,0x2a0e1202,0x07c00a01,0x00010f80,0x38000000,0x00004004,0x00000000,0x00000000,
+0x2d000000,0x0000fd60,0x02206d74,0x00180040,0x0000000c,0x00080000,0x001640b2,0x0f810000,
+0x00001f00,0x00200004,0x00000000,0x3c1a0302,0x07780037,0x20000000,0x40002000,0x003000d4,
+0x04000000,0x07000080,0x000c0000,0x00000000,0x0410281c,0x05060008,0x00320178,0x00000000,
+0x002c8164,0x00000000,0x00000000,0xe0400fc4,0x34000000,0x12021208,0x07c00a01,0x20010f80,
+0x00000800,0x00004000,0x00000000,0x00000000,0x11000000,0x003fe000,0xc2a20550,0x00183346,
+0x0000834c,0x00080000,0x001640b2,0x000000a0,0x00001f00,0x20200004,0x00000000,0x2401d300,
+0x080008c3,0x3a0c0008,0x00002000,0x000800d0,0x04000000,0x19000000,0x00060000,0x00000000,
+0x00186830,0x0dcc0110,0x00328116,0x00100000,0xa82c8000,0x00000000,0x00000000,0x003e1000,
+0x03be0000,0x0c00015d,0x07c00001,0x00010f80,0x80000801,0x00004804,0x00000000,0x00000000,
+0x40000000,0x0500f0fe,0x36ae2824,0xd0390100,0x00004828,0x00080000,0x001640b2,0x0f800000,
+0x00001f00,0x00040004,0x00000000,0x24611404,0x0f4c4603,0x3a030000,0x30002000,0x00400020,
+0x20000000,0x14000000,0x000a0000,0x00000000,0x34062810,0x0d060000,0x00328112,0x00000000,
+0x002c8164,0x00000601,0x00000000,0xe07f1f04,0x00060020,0x24001208,0x07c00001,0x00000f80,
+0x80000801,0x00004384,0x00000000,0x00000000,0x00000000,0x0fbf03a0,0x36380d50,0x5c980812,
+0x00014808,0x00000000,0x001640b2,0x0f800060,0x00001f00,0x20200000,0x00000000,0x10015116,
+0x2f4c0254,0x21dc0000,0x20002000,0x004000b8,0x04000000,0x10000080,0x000c0000,0x00000000,
+0x24062810,0x00c90000,0x00324170,0x00000000,0xc02c8164,0x00000400,0x00000000,0x00000fc4,
+0x34006e6c,0x2a001208,0x07c00001,0x20010f80,0xc0000800,0x00003803,0x00000000,0x00000000,
+0x40000000,0x0e3f018b,0x24062e74,0xd0200008,0x00004820,0x00000000,0x001640b2,0x0f8000e0,
+0x00001f00,0x20200004,0x00000000,0x007a0308,0x080800c0,0x00000400,0x30002000,0x00180000,
+0x04000000,0x00000080,0x000c0000,0x00000000,0x00000810,0x0dcf1a04,0x00240170,0x00000000,
+0x002c8164,0x00001040,0x00000000,0x00381fc4,0x02280030,0x32001202,0x07c00000,0x00010f80,
+0x00000801,0x00003c00,0x00000000,0x00000000,0xa6000000,0x003fecde,0x03b26824,0xd0583010,
+0x00004808,0x00000000,0x003640b2,0x00000000,0x00001f00,0x20200004,0x00000000,0x18020006,
+0x28100024,0x01d303b8,0x1b002000,0x00000080,0x04000000,0x00000400,0x00006000,0x00000000,
+0x00000800,0x00cc000b,0x00320170,0x00000000,0x002c8000,0x000010c0,0x00000000,0x00000e44,
+0x00002800,0x0e060a01,0x07c00001,0x00010f80,0x00000800,0x00004802,0x00000000,0x00000000,
+0x3a000000,0x003801f6,0x14060000,0xdcf83158,0x00018000,0x00000000,0x001640b2,0x0002c000,
+0x00001f00,0x00200000,0x00000000,0x10120308,0x2f5c8124,0x2a020000,0x0a002000,0x000000c0,
+0x00000000,0x10000400,0x000a6000,0x00000000,0x00202804,0x00c90200,0x00270010,0x00000000,
+0x802c8002,0x00000e00,0x00000000,0xfc400000,0x02b00740,0x0e000000,0x07c00001,0x20080f80,
+0x38000000,0x00000000,0x00000000,0x00000000,0x11000000,0x0e4000d0,0xc3b02800,0xd078b800,
+0x00006830,0x00000000,0x001640b2,0x0f800000,0x00001f00,0x00200000,0x00000000,0x0001d124,
+0x2c508000,0x1a030000,0x00002000,0x00200080,0x04000000,0x00000080,0x0008c000,0x00000000,
+0x0002080c,0x09011b58,0x00270196,0x00800000,0x002c8164,0x00001040,0x00000000,0x00000000,
+0x17ae0000,0x20000a04,0x07c00201,0x00080f80,0x00000001,0x00003800,0x00000000,0x00000000,
+0x14000000,0x0000f800,0x40040550,0x101882c0,0x00008000,0x00080000,0x001640b2,0x0f810000,
+0x00001f00,0x00200000,0x00000000,0x001a0c00,0x054440c0,0x03dc3418,0x23002000,0x00000000,
+0x00000000,0x00000400,0x00000000,0x00000000,0x34000800,0x00008003,0x00270172,0x00000000,
+0x402c8364,0x00000f00,0x00000000,0xe4400e04,0x140e000c,0x0e000a01,0x07c00001,0x20000f80,
+0x80000800,0x00004803,0x00000000,0x00000000,0x2d000000,0x0038fc00,0xc0064d44,0xd048f100,
+0x00004808,0x00000000,0x001640b2,0x0f86a060,0x00001f00,0x20208004,0x00000000,0x0801d302,
+0x2f5c0080,0x00000018,0x1c002000,0x000000ac,0x04000000,0x00000400,0x00000000,0x00000000,
+0x34060800,0x01008110,0x002a0196,0x00100000,0xa82c8164,0x00000000,0x00000000,0xfc400000,
+0x24000740,0x00000a07,0x07c00000,0x00080f80,0x80000000,0x00003c84,0x00000000,0x00000000,
+0xe0000000,0x0000027f,0x03a02824,0x90780600,0x0000000c,0x00000000,0x001640b2,0x0f800000,
+0x00001f00,0x00000004,0x00000000,0x04000e30,0x683006c0,0x020003a0,0x00000000,0x000000c0,
+0x20000000,0x00000000,0x000c0000,0x00000000,0x34060800,0x00ed8000,0x00224116,0x00800000,
+0x582c8164,0x00000001,0x00000000,0x003f1000,0x00000460,0x20000003,0x07c00821,0x00080f80,
+0x80000001,0x00004384,0x00000000,0x00000000,0xfc000000,0x003f02ce,0xc7a62e50,0x0000db00,
+0x0001826c,0x00400000,0x001640b2,0x0f850060,0x00001f00,0x20200000,0x00000000,0x201a0232,
+0x28100603,0x00000400,0x00000400,0x00000000,0x20000000,0x00000000,0x00000000,0x00000000,
+0x341e0000,0x0dcf0000,0x00224100,0x00000000,0x002c8164,0x00000ac0,0x00000000,0x00000000,
+0x03a04800,0x000e0003,0x07c004e0,0x00000f80,0xc8000001,0x00003803,0x00000000,0x00000000,
+0x0a000000,0x002e0000,0x74060574,0x10000250,0x00000000,0x00400000,0x001640b2,0x0f820000,
+0x00001f00,0x24040004,0x00000000,0xa02a0302,0x08300203,0x23dd2416,0x4a800000,0x00000000,
+0x00000000,0x08000400,0x00000000,0x00000000,0x34260804,0x00070001,0x00224118,0x00100000,
+0xc02c8164,0x00000000,0x00000000,0xe8400000,0x00000010,0x20000a07,0x07c00001,0x00000f80,
+0x48000000,0x00003800,0x00000000,0x00000000,0x00000000,0x00390000,0x47a66e64,0x0e88d152,
+0x00000000,0x00000000,0x001640b2,0x0f82c0a0,0x00001f00,0x00000004,0x00000000,0x06200000,
+0x2f500204,0x000c0004,0x00000400,0x00000000,0x04000000,0x17000000,0x000c2000,0x00000000,
+0x14180800,0x0dc81a00,0x0022c180,0x00100000,0x002c8164,0x000010c0,0x00000000,0x00000000,
+0x00100440,0x00160004,0x07c002c0,0x00080f80,0xb0000000,0x00000003,0x00000000,0x00000000,
+0x00000000,0x0ba50000,0xc4080540,0xd018c202,0x00002820,0x00400000,0x001640b2,0x0f800000,
+0x00000000,0x00200004,0x00000000,0x24000006,0x6c4c0637,0x3b1003a0,0x4a800000,0x004000c0,
+0x04000000,0x10000404,0x00000000,0x00000000,0x34102804,0x0dcd83d3,0x00328000,0x00800000,
+0xc0000164,0x00000a01,0x00000000,0x003f1000,0x0400000c,0x00000192,0x07c00000,0x00000f80,
+0xc0000000,0x00001804,0x00000000,0x00000000,0x6e000000,0x0c224c04,0x34062f5c,0xd0603010,
+0x0001480c,0x00000000,0x00164000,0x0f86a000,0x00000000,0x80040000,0x00000000,0x00000208,
+0x480c0240,0x1a030320,0x1c000000,0x00000000,0x20000000,0x09000080,0x00000000,0x00000000,
+0x34060810,0x00ee0000,0x002e00c0,0x00000000,0xc0004164,0x00000401,0x00000000,0xf8400e04,
+0x00060000,0x2e001a53,0x00000001,0x00080f80,0xc8000801,0x00000003,0x00000000,0x00000000,
+0xcaffffc0,0x0c78c11b,0x34064818,0x0018f010,0x0000682c,0x00000000,0x00164001,0x0f820000,
+0x00000000,0x90209020,0x00000000,0x0001d006,0x00000640,0x1a030000,0x18002000,0x240000b0,
+0x04009000,0x10000080,0x00000000,0x00000000,0x01b8680c,0x00001a03,0x00224114,0x00800000,
+0x40000164,0x09000000,0x00000000,0xc4b02bc8,0x34000760,0xe0000add,0x00000100,0x00080f80,
+0xc1204000,0x00003c83,0x00000000,0x00000000,0x80e7febc,0x07007002,0x0000000c,0x00000000,
+0x00000000,0x00000000,0x00001000,0x00000000,0x00000000,0x90229964,0x00000000,0x01000001,
+0x00000000,0x80000000,0x00000207,0xfc000000,0x000020ff,0xc0000400,0x00000143,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00200000,0x00000000,0x71400000,
+0x00000003,0x00000000,0x00000000,0x00000000,0x0421e401,0xc0000000,0x00001fff,0x805fa000,
+0x4bffffc0,0x028084b8,0x00002800,0x00000000,0x000a0000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x90200000,0x00000000,0x00000000,0x00000034,0x80000000,0x00000206,0x00186034,
+0x00000000,0x46000000,0x00000103,0x00000000,0x34100000,0x50000000,0x00000000,0x00000000,
+0x00000000,0x120406c0,0x00000000,0x28800000,0x17280440,0x00092000,0x00000000,0x28010000,
+0x0541a100,0x00000000,0x00000000,0x00000000,0xd0ebffbd,0x044044f2,0x36200000,0x08800000,
+0x00000000,0x00000000,0x22003000,0x000000e1,0x00000000,0x9022a964,0x00000000,0x00000001,
+0x00001300,0x80000000,0x00000206,0x08382400,0x00000000,0xc0000000,0x00000143,0x00000000,
+0x00000440,0xb0000000,0x00000000,0x00000000,0x00000000,0x00800000,0x00000000,0x454002c8,
+0x00000000,0x00000004,0x00000000,0x00000000,0x01204000,0xc0000000,0x00001fff,0x805fa000,
+0x00fbff40,0x02803900,0x04006800,0x08800000,0x008a0000,0x00000000,0x00001000,0x00000000,
+0x00000000,0x902110f0,0x00000000,0x00000000,0x00000000,0x80000000,0x00000206,0xfc000000,
+0x000000ff,0x40000000,0x00000103,0x00000000,0x00000000,0x00000000,0x00001200,0x00000000,
+0x00000000,0x02000000,0x00000000,0x28800000,0x00006800,0x00100001,0x00000000,0x00000000,
+0x0221e000,0x00000000,0x00000000,0x00000000,0x10fffffb,0x03803503,0x00018003,0x00000000,
+0xe8000000,0x80000003,0x02000000,0x00000000,0x00000000,0x90209020,0x00000000,0x00000000,
+0x00000800,0x80000000,0x00000287,0x08000000,0x00001000,0x48000000,0x00000103,0x00000000,
+0x00000540,0x00000000,0x00201600,0x00000000,0x00000000,0x02086000,0x00000000,0x388d2308,
+0x0000280c,0x00001200,0x00000000,0x00000000,0x01204400,0x00000000,0x68000000,0x00000007,
+0x40ebff40,0x03803804,0x02260000,0x00180000,0x00000830,0x00000000,0x00001000,0x0e000000,
+0x00041c00,0x90229960,0x00000000,0x00000031,0x000c0000,0x800003a0,0x00000286,0x00000000,
+0x80000800,0x08000010,0x00000000,0x00000000,0xc0000000,0x00000000,0x08000000,0x00000000,
+0x006c8164,0x0024a000,0x00000000,0x39400000,0x00000000,0x000000d0,0x00000000,0x04200000,
+0x0501a000,0x00000000,0x00000000,0x805fa000,0x10fbff3b,0x028044b0,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x9022a0d0,0x00000000,0x000a0000,
+0x00000000,0x800002a8,0x00000286,0x00000000,0x24000000,0xc8b00020,0x00000143,0x00000000,
+0x14000540,0x00000000,0x00c00040,0x00000000,0x00000000,0x00906000,0x00000000,0x28800408,
+0x00000000,0x00000002,0x00000500,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x0003ef00,0x00003404,0x34000000,0x00000102,0x00000000,0x0047fff8,0x00000001,0x00034000,
+0xfffe0000,0x00000003,0x00000000,0xa0000100,0x00000003,0x00000000,0x00142400,0x00000000,
+0x24000000,0xc8000014,0x00000103,0x00000000,0x00080544,0x00000000,0x001a0160,0x00000000,
+0x00000000,0x00000000,0x00000000,0x000f2000,0x00000000,0x00001200,0x00000000,0x10000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0xc0ffffc0,0x034f3002,0x04060000,0x08800006,
+0x00020800,0x80000000,0x003641b2,0x00000000,0x00000000,0x90209020,0x00000000,0x01800000,
+0x08000000,0x00000008,0x28000000,0x02020000,0x00000400,0x10000000,0x00000000,0x00000000,
+0x00000000,0x00000110,0x00000000,0x00800000,0xc0000000,0x00800000,0x00000000,0x348c22c8,
+0x00000000,0x00000000,0x07000000,0x00000e00,0x39204000,0x00001380,0x00000000,0x00000000,
+0x00eff000,0x02c02c00,0x14060000,0x00000006,0x78800800,0x00000000,0x02000000,0x00000000,
+0x00000000,0x9022996c,0x00000000,0x00015001,0x00000000,0x81100000,0x00142687,0x00382400,
+0x00001f00,0x49028480,0x00000183,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00480600,0x00000000,0x2d400000,0x02a80000,0x80100000,0x00000000,0x20000000,
+0x000000a1,0xc0000000,0x00000003,0x805fa000,0x0003ff80,0x00002800,0xc0020000,0x00000000,
+0x08860800,0x00000000,0x02000000,0x00000000,0x00000000,0x000290d0,0x00000000,0x00015400,
+0x00002000,0x81500000,0x00142687,0x06000000,0x00000c00,0xc8028480,0x00000143,0x00000000,
+0x00000000,0x00000000,0x000012c0,0x00000000,0x00000000,0x00082000,0x00000000,0x00000000,
+0x00080000,0x00120000,0x00000000,0x00000000,0x0221e000,0x40000000,0x00000001,0x00000000,
+0x8003fffd,0x000000a2,0xc0010540,0x0000c000,0x38006800,0x00000000,0x22000509,0x00000100,
+0x00000000,0x000260d0,0x00000000,0x00200402,0x00002040,0x80040000,0x00000287,0x1a000000,
+0x00002400,0xc8000000,0x00000143,0x00000000,0x14000000,0x00000000,0x00040000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00002800,0x00000000,0x00000000,0x00000000,
+0x0521a400,0xc0000000,0x00000002,0x00000000,0x0a03dfc0,0x00000000,0x03202801,0x1000c000,
+0x08000030,0x00000000,0x20a12000,0x00000100,0x00000000,0x000110f0,0x00000000,0x00000002,
+0x00000004,0x80000000,0x00000286,0x22382420,0x00003400,0x40000000,0x00000143,0x00000000,
+0x14082800,0x00000000,0x00040000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00002804,0x00000000,0x00000000,0x00000000,0x04c1a000,0x40000000,0x00000001,0x00000000,
+0x00ffdf3e,0x02800000,0x03a30000,0x50000006,0x38400000,0x00000000,0x00a12000,0x00000000,
+0x00000000,0x902110f0,0x00000000,0x00000000,0x00000000,0x80000000,0x00000306,0x12000020,
+0x00004400,0x40000000,0x00000143,0x00000000,0x00082801,0x00000000,0x00000000,0x00000000,
+0x00000000,0x12000600,0x00000000,0x28800000,0x03200004,0x80100000,0x00000000,0x20000000,
+0x0221e4a1,0xc0000000,0x00000002,0x00000000,0x03b7fe31,0x02822840,0x43a00803,0x00000000,
+0x004b4810,0x00000000,0x00003000,0x00000000,0x00000000,0x9022a960,0x00000000,0x00000001,
+0x00002000,0x00000000,0x00040607,0x00300000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x363c0000,0x50000000,0x00200000,0x00000000,0x00000000,0x00200000,0x00000000,0x29400000,
+0x0000080c,0x00107a03,0x00000000,0x00000000,0x04418400,0x00000000,0x28000000,0x805fa006,
+0x80e3ff00,0x058b58c2,0x00006808,0x00000000,0x000a0000,0x00000000,0x00001000,0x00000000,
+0x00000000,0x9022a964,0x00000000,0x00000001,0x00000000,0x40000000,0x00000287,0x01000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x24080000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00200000,0x00000000,0x59400294,0x00006802,0x00120094,0x00000000,0x00000000,
+0x01204000,0x00000000,0x00000000,0x805fa000,0xcdebff80,0x0580598f,0x34040000,0x00000000,
+0x00000000,0x00000000,0x00000060,0x00000000,0x00000000,0x9022a964,0x00000000,0x00000001,
+0x00000024,0x00000000,0x00042400,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x34000000,0x00000000,0x08000000,0x00000000,0x00000000,0x002006c0,0x00000000,0x59400000,
+0x00000740,0x00000000,0x00000000,0x04200000,0x01030800,0x00000000,0x00000000,0x805fa000,
+0x00000fc0,0x00000000,0x00060000,0x00000000,0x00006820,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x04000000,0x00000000,0x41100000,0x28000206,0x00000000,
+0x00000000,0x08080e80,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000388,0x34000030,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x038c0000,0x40002800,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x90200000,0x00000000,0x00000000,
+0x00000200,0x00000000,0x00000000,0x00000000,0x00000000,0x49000000,0x00000103,0x00000000,
+0x00000540,0x00000000,0x00128000,0x00000000,0x00000000,0x00216000,0x00000000,0xe0400000,
+0x00180000,0x00000000,0x00000000,0x00010000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x8003fffb,0x00382d02,0x36a00004,0x00000000,0x00000000,0x00000000,0x00010000,0x00000000,
+0x00000000,0x607c9020,0x00000000,0x00000000,0x00000800,0x00000000,0x00000000,0x01000000,
+0x00000200,0xa0000000,0x00000143,0x00000000,0x14080000,0x00000000,0x00000184,0x00000000,
+0x00000000,0x00400000,0x00000000,0xe04b2288,0x00000000,0x80000000,0x00000000,0x00000000,
+0x01204000,0x00000000,0x00000000,0x00000000,0x0cc7ff32,0x058c5950,0x001c6800,0x90004009,
+0x00006a70,0x00000000,0xa81650b2,0x0000010c,0x00000000,0x9022a964,0x00000000,0x07000201,
+0x00000134,0x80020000,0x00000206,0x00000000,0x00000000,0x40000000,0x00000103,0x00000000,
+0x15ba0470,0x10000000,0x00000001,0x00000000,0x00000000,0x00200460,0x00000000,0x59400fc4,
+0x0000680c,0x8a001202,0x07000000,0x00000e00,0x0201e400,0x00000000,0x48000000,0x805fa006,
+0xb8fffff5,0x028008a0,0x76206d6c,0x50204006,0x000a081c,0x00000000,0x00001000,0x00000000,
+0x00000000,0x902100f0,0x00000000,0x0021d000,0x00002104,0x81d00000,0x00002286,0x02434400,
+0x00000000,0x45880480,0x00000143,0x00000000,0x04086810,0x00000000,0x002e0180,0x00000000,
+0x00000000,0x00806000,0x00000000,0x28800000,0x14000803,0x000900d4,0x00000000,0x00000000,
+0x0521a000,0x40000000,0x00000000,0x00000000,0x80e3ff00,0x058b58c2,0x00006808,0x00000000,
+0x000a0000,0x00000000,0x00001000,0x00000000,0x00000000,0x9022a964,0x00000000,0x00000001,
+0x00000000,0x40000000,0x00000287,0x01000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x24080000,0x00000000,0x00000000,0x00000000,0x00000000,0x00200000,0x00000000,0x59400294,
+0x00006802,0x00120094,0x00000000,0x00000000,0x01204000,0x00000000,0x00000000,0x805fa000,
+0x00dbff3d,0x05805950,0x00006800,0x00000000,0x08404800,0x00000000,0x00001000,0x00000000,
+0x00000000,0x9022a964,0x00000000,0x00000001,0x00002000,0x80000000,0x00000286,0x00000000,
+0x00000000,0x40000000,0x00000103,0x00000000,0x24000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00200000,0x00000000,0x59400000,0x00000000,0x00150000,0x00000000,0x00000000,
+0x00000400,0x00000000,0x00000000,0x805fa000,0x80ff7fc0,0x02802800,0x14082803,0x0a800000,
+0x000a0020,0x00000000,0x00000000,0x00000000,0x00000000,0x90200000,0x00000000,0x00000000,
+0x00000100,0x80000000,0x00000207,0x00000000,0x00000000,0x01800000,0x00000000,0x00000000,
+0x00100744,0x50000000,0x00000000,0x00000000,0x00000000,0x00800000,0x00000000,0x28800000,
+0x00006808,0x00120000,0x00000000,0x00000000,0x0521a000,0x00000000,0x00000000,0x00000000,
+0x00cffcc0,0x05805950,0x040e0548,0x0ce80002,0x0001c82c,0x00000000,0x00002000,0x00000000,
+0x00000000,0x9022a964,0x00000000,0x00000b07,0x800c2004,0x8a0c0004,0x00000286,0x00000000,
+0x00000000,0x44800000,0x00000103,0x00000000,0x05b00808,0x0d009208,0x00140000,0x00000000,
+0x00000000,0x00200000,0x00000000,0x59400000,0x00080030,0x00000000,0x00000000,0x10010000,
+0x0401e000,0x00000000,0x00000000,0x805fa000,0x0cdbffc0,0x000008b6,0x14000000,0x503000c0,
+0x00c22800,0x00000000,0x000c0000,0x000000c0,0x00000000,0x00000000,0x00000000,0x00120000,
+0x68003100,0x00043400,0x21800000,0x00000000,0x00000000,0x40000000,0x00000103,0x00000000,
+0x00006800,0x00060008,0x000000d4,0x00000000,0x30000000,0x00000001,0x00000000,0x003c1000,
+0x00006800,0xe4179a00,0x00000500,0x00000000,0x00000000,0x00003c80,0x00000000,0x00000000,
+0x3cffef40,0x028028b0,0x662a6810,0x0aa03050,0x00000b60,0x00480000,0x000000b2,0x00000000,
+0x00000000,0x902210d0,0x00000000,0x0063d006,0x08000214,0x82000320,0x48002207,0x00342000,
+0x20000400,0x00000000,0x00000000,0x00000000,0x00002e50,0x09001a00,0x00300000,0x00000000,
+0x00180000,0x00800000,0x00000000,0x28800000,0x24002c50,0x00000004,0x07000000,0x01090000,
+0x00000000,0x00000000,0x00000000,0x00000000,0xc0d3fef6,0x058b595e,0x00066e44,0x00604008,
+0x00000140,0x00000000,0x28001000,0x000000d1,0x00000000,0x9022a964,0x00000000,0x00000401,
+0x00002000,0x80000000,0x00000207,0x00000000,0x00000000,0x40000000,0x00000103,0x00000000,
+0x00000f40,0x50c82000,0x000000c0,0x00000000,0x00000000,0x00200000,0x00000000,0x59400f04,
+0x00006804,0x00000000,0x00000000,0x00000000,0x38000400,0x00000001,0xc8000000,0x805fa006,
+0x8cfffff7,0x028008a0,0x0400480e,0x10000000,0x010a6808,0x00000000,0x000010b2,0x0e000000,
+0x00000000,0x902100f0,0x00000000,0x00120002,0x00000100,0x80000000,0x00000286,0x02000000,
+0x00000000,0x04800000,0x00000000,0x00000000,0x34180010,0x50000000,0x00000000,0x00000000,
+0x00000164,0x00800000,0x00000000,0x28800000,0x00006830,0x00112050,0x07000000,0x00000000,
+0x0521a400,0x00000000,0x00000000,0x00000000,0xd2dfff80,0x060f6123,0x84000800,0x00000000,
+0x008a4800,0x00000000,0x02001000,0x00000000,0x00000000,0x90229964,0x00000000,0x00000001,
+0x00000000,0x80000000,0x00000206,0x10000000,0x00001000,0x48000000,0x00000103,0x00000000,
+0x34180000,0x50000000,0x00000000,0x00000000,0x00000000,0x00286000,0x00000000,0x614003c8,
+0x00004810,0x0012120c,0x00000000,0x00000000,0x01204000,0x00000000,0x00000000,0x805fa000,
+0x00fffff9,0x04c04404,0x14000000,0x0a800000,0x00060020,0x00000000,0x00001000,0x00000000,
+0x00000000,0x90209020,0x00000000,0x00000000,0x00000200,0x80000000,0x00000287,0x10000000,
+0x00004800,0xc8000000,0x00000143,0x00000000,0x34180540,0x00000000,0x00001600,0x00000000,
+0x00000000,0x09002000,0x00000000,0x4c912408,0x00002800,0x00100098,0x00000000,0x00000000,
+0x01204400,0x00000000,0x28000000,0x00000007,0x92ebff80,0x03c03c06,0x47b80f44,0x00000306,
+0x4000000c,0x00000001,0x000001b2,0x00020000,0x00001c00,0x90229964,0x00000000,0x001a0031,
+0x00000700,0x81100400,0x18002306,0x10030000,0x04001000,0x40000080,0x00000143,0x00000000,
+0x34040000,0x00000150,0x001b00d6,0x00800000,0xb86c8000,0x00200a80,0x00000000,0x3d400000,
+0x17a06810,0x001212d2,0x07000400,0x10000000,0x0521a001,0x00000000,0x00000003,0x805fa000,
+0x0efbefba,0x068044a0,0x04082800,0x00000001,0x20026c40,0x00080001,0x003641b2,0x00000000,
+0x00000000,0x902260d0,0x00000000,0x00120800,0x280000c4,0x9a000000,0x00000286,0x7a000000,
+0x2000c400,0x40000400,0x00000183,0x00000000,0x24180020,0x00000001,0x00260030,0x00100000,
+0xa8000002,0x04000600,0x00000000,0x68800f44,0x00002800,0x00120000,0x07000000,0x00010e00,
+0x8481a000,0xc0001184,0x0000000d,0x00000000,0xbdfbfffb,0x04406806,0x03300d64,0x00081008,
+0xc8010030,0x00000001,0x003641b2,0x00060000,0x00001c00,0x902290d0,0x00000000,0x001a0c02,
+0x00040800,0x811d0000,0x20000286,0x14000000,0x20002c00,0x40000080,0x00000183,0x00000000,
+0x14104804,0x00000000,0x001a80d8,0x00000000,0xf86c8002,0x04000000,0x00000000,0x44be1e84,
+0x00080010,0x40000008,0x070008a0,0x00000e00,0x2d21a000,0x00000002,0x0000000a,0x00000000,
+0x40fbffc0,0x06404404,0x14000640,0xd8800003,0x20012800,0x00400000,0x003641b2,0x00066000,
+0x00000000,0x902290d0,0x00000000,0x12035202,0x00002000,0x82000000,0x48000686,0x0c000000,
+0x20001400,0x40080000,0x00000183,0x00000000,0x03284d48,0x008a0150,0x000000d4,0x00800000,
+0x00000010,0x10000000,0x00000000,0x64bd1000,0x24040770,0xd2000390,0x07000000,0x00010e00,
+0x0521a000,0x40001404,0x0000000d,0x00000000,0x9afbffc0,0x04ce0114,0x00020660,0x00580306,
+0x68006804,0x00000000,0x000001b2,0x0e020000,0x00001c00,0x902260d0,0x00000000,0x000a0400,
+0x002000d4,0x9a000000,0x00002286,0x120000a0,0x00001c00,0x40080000,0x00000143,0x00000000,
+0x17a06804,0x10000a01,0x000c00d9,0x00800000,0xf06c8164,0x10000c00,0x00000000,0x4c800000,
+0x14040800,0x0e001208,0x070006e1,0x00010000,0x04c1a000,0x80000000,0x00000003,0x00000000,
+0xfdfbfffe,0x03804fe4,0x00000800,0x08801040,0x00002803,0x00400000,0x000030b2,0x0006a000,
+0x00000000,0x902290d0,0x00000000,0x081b9d02,0x4d400000,0x80070220,0x1b802286,0x480000a0,
+0x20009800,0x40000080,0x00000143,0x00000000,0x262c0030,0x10a80194,0x001a80c5,0x00100000,
+0x00000000,0x10000b00,0x00000000,0x38800000,0x001a0000,0x700000de,0x07000000,0x20000000,
+0xc521a000,0x40000003,0x00000000,0x00000000,0x93fbfffe,0x04803802,0x00000770,0x9a80c0c6,
+0x10008004,0x00000000,0x283651b2,0x0e000060,0x00000000,0x902290d0,0x00000000,0x00000006,
+0x00080800,0x83d00000,0x20002306,0x44000070,0x0000dc00,0x40000400,0x00000183,0x00000000,
+0x00066d60,0x05008150,0x00260112,0x00800000,0x00000364,0x10000000,0x00000000,0x48be1e44,
+0x14002800,0x8000000e,0x07000200,0x20080e00,0x04c1a000,0xc0003804,0x00000003,0x00000000,
+0x80fbefc0,0x02900184,0x04020020,0xd8a05000,0x70002f40,0x80080001,0x283641b2,0x0e000061,
+0x00001c00,0x902110f0,0x00000000,0x20215800,0x00040037,0x8a082400,0x13800686,0x54000000,
+0x00000000,0x40000000,0x00000143,0x00000000,0x26242834,0x05008002,0x00260000,0x00000000,
+0xc02c8164,0x10001001,0x00000000,0x28800000,0x02200004,0x72001200,0x07000000,0x00010e00,
+0x0521a001,0x00000000,0x0000000b,0x00000000,0x8003ffc0,0x00002802,0x00004800,0x50600000,
+0x78000444,0x80000001,0x00364000,0x0003c000,0xfffe0000,0x000110f3,0x00000000,0x18620106,
+0x07403014,0x82000220,0x00002286,0x6a300a00,0xa8000000,0x40000090,0x00000183,0x00000000,
+0x34040544,0x00020001,0x001a8060,0x00000000,0x00000000,0x00001000,0x00000000,0x003f1e04,
+0x00002800,0x241000d0,0x00000401,0x00080e00,0xc521a000,0x80004003,0x0000000a,0x00000000,
+0x9103ffc0,0x0000e4ef,0x02a00648,0x1ec08308,0x00000548,0x00080000,0x00364001,0x0e03c000,
+0x00000000,0x000260d0,0x00000000,0x00015000,0x280000f4,0x800d0000,0x13802206,0x60300a80,
+0x0000e400,0x40000080,0x00080143,0x00000000,0x36be2f44,0x00000000,0x00000060,0x00800000,
+0x00004364,0x00000000,0x00000000,0x00000e44,0x00000804,0x0000000c,0x00000400,0x10000e00,
+0x3a21a000,0x80001381,0x00000008,0x00000000,0xb803ffc0,0x0e404bf3,0x02a80808,0x1aa00000,
+0xe8004830,0x00080001,0x18000001,0x0e0400e0,0x00001c00,0x000690d0,0x00000000,0xb8600000,
+0x08100003,0x80000000,0x00000286,0x5e3000b0,0x0000b800,0x40000000,0x00000143,0x00000000,
+0x001e0544,0x00000150,0x00020170,0x00800000,0xc02c8364,0x00000c01,0x00000000,0xf4400000,
+0x02200020,0x00000000,0x00000000,0x20080000,0x4221a000,0xc0004200,0x0000000e,0x00000000,
+0x80ffffc0,0x0000e936,0x00024800,0x0c801044,0x88010764,0x00000001,0x003640b2,0x0e03a000,
+0x00021c00,0x000110d0,0x00000000,0x18000100,0x0540a234,0x81901628,0x00000306,0x58030000,
+0x2000ec00,0x40000090,0x00000183,0x00000000,0x34a80644,0x09000000,0x00040020,0x00800000,
+0x006c8364,0x00000c00,0x00000000,0x00000000,0x00004800,0x52001a08,0x07000400,0x00000e00,
+0xc421a001,0xc0000003,0x00000000,0x00000000,0x4affffc0,0x0514400f,0x44004808,0x00680800,
+0x30018800,0x00080001,0x003641b2,0x0e046000,0x00000000,0x90209020,0x00000000,0xa8000030,
+0x000008c2,0x9a000002,0x00002286,0x66000054,0x0001fc00,0x40000080,0x00000143,0x00000000,
+0x03a60008,0x05cc0000,0x00000030,0x00800000,0x80000364,0x00800601,0x00000000,0x50902000,
+0x34082800,0xf0001a0c,0x07000000,0x00000e00,0x0481a000,0xc0000400,0x0000000c,0x00000000,
+};
+
+/* data */
+static unsigned long srp_fw_data[] __devinitdata = {
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x80050000,0x000a800f,0x001e801b,0x80110014,0x00368033,
+0x8039003c,0x802d0028,0x00228027,0x00668063,0x8069006c,0x807d0078,0x00728077,0x80550050,
+0x005a805f,0x004e804b,0x80410044,0x00c680c3,0x80c900cc,0x80dd00d8,0x00d280d7,0x80f500f0,
+0x00fa80ff,0x00ee80eb,0x80e100e4,0x80a500a0,0x00aa80af,0x00be80bb,0x80b100b4,0x00968093,
+0x8099009c,0x808d0088,0x00828087,0x01868183,0x8189018c,0x819d0198,0x01928197,0x81b501b0,
+0x01ba81bf,0x01ae81ab,0x81a101a4,0x81e501e0,0x01ea81ef,0x01fe81fb,0x81f101f4,0x01d681d3,
+0x81d901dc,0x81cd01c8,0x01c281c7,0x81450140,0x014a814f,0x015e815b,0x81510154,0x01768173,
+0x8179017c,0x816d0168,0x01628167,0x01268123,0x8129012c,0x813d0138,0x01328137,0x81150110,
+0x011a811f,0x010e810b,0x81010104,0x03068303,0x8309030c,0x831d0318,0x03128317,0x83350330,
+0x033a833f,0x032e832b,0x83210324,0x83650360,0x036a836f,0x037e837b,0x83710374,0x03568353,
+0x8359035c,0x834d0348,0x03428347,0x83c503c0,0x03ca83cf,0x03de83db,0x83d103d4,0x03f683f3,
+0x83f903fc,0x83ed03e8,0x03e283e7,0x03a683a3,0x83a903ac,0x83bd03b8,0x03b283b7,0x83950390,
+0x039a839f,0x038e838b,0x83810384,0x82850280,0x028a828f,0x029e829b,0x82910294,0x02b682b3,
+0x82b902bc,0x82ad02a8,0x02a282a7,0x02e682e3,0x82e902ec,0x82fd02f8,0x02f282f7,0x82d502d0,
+0x02da82df,0x02ce82cb,0x82c102c4,0x02468243,0x8249024c,0x825d0258,0x02528257,0x82750270,
+0x027a827f,0x026e826b,0x82610264,0x82250220,0x022a822f,0x023e823b,0x82310234,0x02168213,
+0x8219021c,0x820d0208,0x02028207,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00007d00,0x0000fa00,0x00017700,0x0001f400,0x00027100,0x0002ee00,0x00036b00,
+0x0003e800,0x00046500,0x0004e200,0x00055f00,0x0005dc00,0x00065900,0x0006d600,0x00000000,
+0x00007d00,0x0000bb80,0x0000dac0,0x0000fa00,0x00013880,0x00017700,0x0001b580,0x0001f400,
+0x00027100,0x0002ee00,0x00036b00,0x0003e800,0x0004e200,0x0005dc00,0x00000000,0x00007d00,
+0x00009c40,0x0000bb80,0x0000dac0,0x0000fa00,0x00013880,0x00017700,0x0001b580,0x0001f400,
+0x00027100,0x0002ee00,0x00036b00,0x0003e800,0x0004e200,0x00000000,0x00007d00,0x0000bb80,
+0x0000dac0,0x0000fa00,0x00013880,0x00017700,0x0001b580,0x0001f400,0x00023280,0x00027100,
+0x0002af80,0x0002ee00,0x00036b00,0x0003e800,0x00000000,0x00001f40,0x00003e80,0x00005dc0,
+0x00007d00,0x00009c40,0x0000bb80,0x0000dac0,0x0000fa00,0x00013880,0x00017700,0x0001b580,
+0x0001f400,0x00023280,0x00027100,0x0000ac44,0x0000bb80,0x00007d00,0x00100200,0x00000002,
+0x02000000,0x00020014,0x00000100,0x00180100,0x00000001,0x01000001,0x0001001a,0x00010001,
+0x01040401,0x01000004,0x04010100,0x00040108,0x01010000,0x01020401,0x00010004,0x04010100,
+0x01040101,0x01000000,0x01000101,0x00000001,0x01010100,0x00010100,0x01000000,0x01000101,
+0x00000001,0x01010100,0x00010100,0x01000000,0x01000101,0x00000001,0x01010100,0x00010100,
+0x01000000,0x01000101,0x00000001,0x01010100,0x00010100,0x01000000,0x010d0201,0x01000102,
+0x02010101,0x0102010f,0x01010101,0x010b0201,0x00010102,0x02010101,0x01020107,0x01000101,
+0x010e0201,0x01010002,0x02010101,0x0002010a,0x01010001,0x01090101,0x00000101,0x01010101,
+0x01010109,0x01010000,0x01060101,0x01010001,0x01010100,0x0001010c,0x01010100,0x01050101,
+0x01000101,0x01010100,0x01010103,0x01000001,0x010f0401,0x01010104,0x04010101,0x01040107,
+0x01000101,0x010b0401,0x00010104,0x04010101,0x01040103,0x01000001,0x010d0401,0x01000104,
+0x04010101,0x01040105,0x01000100,0x01090401,0x00000104,0x04010101,0x01040101,0x01000000,
+0x010e0401,0x01010004,0x04010101,0x00040106,0x01000101,0x010a0401,0x00010004,0x04010101,
+0x00040102,0x01000001,0x010c0401,0x01000004,0x04010101,0x00040104,0x01000100,0x01080401,
+0x00000004,0x04010101,0x00040100,0x01000000,0x00000001,0x10311131,0x01210121,0x00110011,
+0x00110011,0x11310830,0x01311031,0x00110011,0x00110011,0x20312231,0x21212121,0x12211221,
+0x02210221,0x01310830,0x11211121,0x10211021,0x00210021,0x20312231,0x21212121,0x12211221,
+0x02210221,0x11310840,0x01311031,0x00110011,0x00110011,0x23411810,0x13311331,0x30413141,
+0x22410341,0x21312131,0x12311231,0x20312031,0x02310231,0x32113311,0x18101030,0x21411a10,
+0x02411241,0x10311031,0x11211121,0x11211121,0x01310131,0x00310031,0x30313331,0x32213221,
+0x23212321,0x03210321,0x13113111,0x20112211,0x20401040,0x11413020,0x10311031,0x01310131,
+0x00110011,0x00110011,0x00110011,0x00110011,0x38103420,0x51413a10,0x3c101541,0x3e100541,
+0x24414241,0x41314131,0x14311431,0x04310431,0x32414041,0x30412341,0x31313131,0x13311331,
+0x03310331,0x22312231,0x21212121,0x21212121,0x12111211,0x02212021,0x54215521,0x35214521,
+0x44115311,0x25115211,0x43115011,0x33113411,0x20401040,0x12412141,0x11211121,0x11211121,
+0x10311031,0x01310131,0x00210021,0x00210021,0x38203030,0x51413c10,0x3e101541,0x42414010,
+0x41412441,0x14311431,0x04414041,0x23413241,0x13413141,0x03413041,0x22212221,0x22212221,
+0x20212021,0x20212021,0x02210221,0x02210221,0x45315531,0x54215421,0x35113511,0x35113511,
+0x44215321,0x52115211,0x50112511,0x34114311,0x33110511,0x20301040,0x2c202820,0x21413010,
+0x02411241,0x11311131,0x10311031,0x01310131,0x00310031,0x53413210,0x34103541,0x52414441,
+0x51412541,0x15311531,0x43314331,0x34313431,0x40410541,0x24314231,0x04313331,0x41214121,
+0x14211421,0x23213221,0x31113111,0x13111311,0x03213021,0x20112211,0x54115511,0x50114511,
+0x20401040,0x11413020,0x10311031,0x01310131,0x00110011,0x00110011,0x00110011,0x00110011,
+0x3c203430,0x48104030,0x4e204a20,0x71415220,0x56101741,0x5c205820,0x16416141,0x60100641,
+0x64106210,0x14414141,0x32410441,0x30412341,0x31313131,0x13311331,0x03310331,0x22312231,
+0x12212121,0x02212021,0x76317731,0x75316731,0x66315731,0x74217421,0x65214721,0x73215621,
+0x37213721,0x64216421,0x45315531,0x36213621,0x27117211,0x70214621,0x07110711,0x26112611,
+0x53215421,0x60116011,0x44213521,0x62116311,0x25215221,0x51115111,0x15111511,0x34214321,
+0x05115011,0x24114211,0x40113311,0x20401040,0x40303040,0x48102141,0x11311131,0x10311031,
+0x01310131,0x00210021,0x00210021,0x4e304a20,0x5a105620,0x72415c20,0x60102741,0x17311731,
+0x07417141,0x36416341,0x62100641,0x51416410,0x26312631,0x60416241,0x61316131,0x16311631,
+0x43411541,0x66100541,0x24414241,0x14414141,0x04414041,0x32313231,0x23312331,0x31213121,
+0x31213121,0x13211321,0x13211321,0x03313031,0x22212221,0x12111211,0x12111211,0x02112011,
+0x76217721,0x57216721,0x66216621,0x74217421,0x47214721,0x55317531,0x56216521,0x73117311,
+0x64113711,0x45215421,0x35215321,0x70114611,0x52114411,0x50112511,0x33113411,0x20401040,
+0x40203040,0x4c104430,0x12412141,0x00414e10,0x11311131,0x10311031,0x01310131,0x54105020,
+0x58105610,0x73416541,0x72415a10,0x64412741,0x71414641,0x5c101741,0x36416341,0x45415441,
+0x5e104441,0x62316231,0x26312631,0x16311631,0x06416141,0x35415341,0x25415241,0x51315131,
+0x15311531,0x43314331,0x34313431,0x40410541,0x42314231,0x24312431,0x41314131,0x14213321,
+0x23213221,0x30310431,0x03210321,0x31113111,0x31113111,0x22111311,0x02112011,0x76217721,
+0x67116711,0x57117511,0x74116611,0x56114711,0x55113711,0x07117011,0x50116011,0x20404040,
+0x31314141,0x11111111,0x11111111,0x40404040,0x30304040,0x30303030,0x10302010,0x20202020,
+0x10101041,0x41411020,0x41101010,0x41413131,0x31314141,0x31313131,0x31313131,0x21212121,
+0x30404040,0x20302020,0x20202010,0x41412020,0x10101041,0x41411041,0x10101010,0x41411010,
+0x41414110,0x41101041,0x31314110,0x41414141,0x41414141,0x31313131,0x31313131,0x31314141,
+0x41413131,0x41413131,0x31314141,0x41413131,0x41413131,0x41413131,0x41413131,0x21212121,
+0x21212121,0x31313131,0x31313131,0x21212121,0x21212121,0x21213131,0x21213131,0x31313131,
+0x21212121,0x21213131,0x31312121,0x31313131,0x21211111,0x21212121,0x11113131,0x11111111,
+0x11112121,0x21211111,0x21212121,0x21212121,0x11111111,0x21211111,0x11111111,0x11111111,
+0x41301111,0x41414141,0x41414141,0x31311041,0x41413131,0x31313131,0x31313131,0x31313131,
+0x31313131,0x31313131,0x31314141,0x21214141,0x21212121,0x31313131,0x21212121,0x21212121,
+0x21212121,0x31312121,0x11112121,0x11112121,0x11112121,0x11112121,0x11112121,0x11112121,
+0x21211111,0x11111111,0x11111111,0x11111111,0x11111111,0x11111111,0x11111111,0x11111111,
+0x21213131,0x11111111,0x00001111,0x40404040,0x20303040,0x31311010,0x31314141,0x40404040,
+0x40303040,0x30303030,0x20303020,0x20202020,0x20202020,0x20101010,0x10201010,0x10411010,
+0x10101010,0x41414141,0x10101010,0x41414141,0x41104141,0x41414141,0x41104141,0x41413131,
+0x31313131,0x31313131,0x31314141,0x31313131,0x31312121,0x21212121,0x21213131,0x11112121,
+0x11111111,0x10411010,0x10411010,0x41414141,0x41414141,0x41414141,0x41414141,0x41414141,
+0x10414141,0x31313131,0x41414141,0x31313131,0x31313131,0x31313131,0x31314141,0x31313131,
+0x31313131,0x31313131,0x41413131,0x31313131,0x31313131,0x31313131,0x31313131,0x31313131,
+0x31313131,0x31313131,0x31313131,0x41413131,0x31313131,0x31313131,0x31312121,0x31313131,
+0x21212121,0x21213131,0x21212121,0x31312121,0x21212121,0x21212121,0x31312121,0x21212121,
+0x21212121,0x31312121,0x21211111,0x21212121,0x21212121,0x11112121,0x21212121,0x21211111,
+0x21211111,0x21212121,0x11112121,0x11111111,0x21211111,0x11111111,0x11111111,0x11112121,
+0x11111111,0x11111111,0x11111111,0x11111111,0x11111111,0x11111111,0x11111111,0x11111111,
+0x11111111,0x11111111,0x20404040,0x31314141,0x11111111,0x11111111,0x41203030,0x41401020,
+0x40414110,0x40404040,0x30303040,0x30303030,0x20102020,0x10411020,0x41101010,0x41411041,
+0x31313131,0x31314141,0x21212121,0x31313131,0x31313131,0x31312121,0x21213131,0x21212121,
+0x11112121,0x11111111,0x11111111,0x21211111,0x30402121,0x11113030,0x10202020,0x20102020,
+0x41202020,0x10101010,0x41101010,0x41101010,0x10414110,0x41413131,0x41414141,0x31311041,
+0x41414141,0x41413131,0x41414141,0x31314141,0x31314141,0x31313131,0x41413131,0x41414141,
+0x31314141,0x31314141,0x31314141,0x31314141,0x31314141,0x21212121,0x31312121,0x31313131,
+0x21212121,0x21213131,0x31312121,0x31313131,0x21213131,0x21213131,0x21212121,0x21213131,
+0x31312121,0x21212121,0x21213131,0x11111111,0x21211111,0x21212121,0x11111111,0x11112121,
+0x11112121,0x11111111,0x11111111,0x10411111,0x31313131,0x21214141,0x31312121,0x21213131,
+0x31312121,0x21212121,0x31313131,0x31312121,0x11112121,0x11111111,0x21212121,0x21212121,
+0x11112121,0x21212121,0x21211111,0x11111111,0x21212121,0x11111111,0x11112121,0x11112121,
+0x11111111,0x11111111,0x11111111,0x11111111,0x11111111,0x11111111,0x00001111,0x41404040,
+0x40404040,0x20304040,0x41414141,0x41414141,0x41414141,0x41413131,0x31313131,0x31314141,
+0x31313131,0x31313131,0x31313131,0x31313131,0x31313131,0x41413131,0x30303030,0x30303040,
+0x20202020,0x20202020,0x20203020,0x30203020,0x10202010,0x10101020,0x10101010,0x10101010,
+0x10101010,0x10201010,0x41104120,0x41414141,0x41414141,0x41414141,0x41414110,0x10414141,
+0x41413131,0x31313131,0x31313131,0x41413131,0x31313131,0x21212121,0x21212121,0x21213131,
+0x11111111,0x21211111,0x11111111,0x31313131,0x31313131,0x31313131,0x31313131,0x31313131,
+0x31313131,0x31313131,0x31313131,0x31313131,0x31314141,0x21212121,0x21213131,0x21212121,
+0x31312121,0x21212121,0x21212121,0x21213131,0x21212121,0x21212121,0x21212121,0x21212121,
+0x21212121,0x21212121,0x21212121,0x21212121,0x21212121,0x21212121,0x21213131,0x21212121,
+0x21212121,0x21212121,0x21213131,0x21213131,0x21211111,0x21212121,0x21213131,0x21211111,
+0x21211111,0x11112121,0x11112121,0x11111111,0x11111111,0x11111111,0x11111111,0x11111111,
+0x11111111,0x11111111,0x11111111,0x11111111,0x11112121,0x21211111,0x11111111,0x00001111,
+0x00200010,0x00400030,0x00100011,0x00010001,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00540044,0x00740064,0x00940084,0x00ac00a4,0x00bc00b4,0x00cc00c4,0x00d600d4,0x00e200da,
+0x00e800e4,0x00f000ec,0x00f40018,0x00f800f6,0x00fe00fa,0x00150051,0x01020100,0x00410104,
+0x00140014,0x00040040,0x00230032,0x00310031,0x00130013,0x00300030,0x00030003,0x00220022,
+0x00120021,0x00020020,0x01160106,0x01360126,0x0142013e,0x014e0146,0x01540152,0x015c0158,
+0x01640160,0x001f00f1,0x0168000f,0x016c016a,0x016e002e,0x001e00e1,0x01720170,0x01760174,
+0x017a0178,0x00d3006c,0x00d2017c,0x00d1002d,0x017e007b,0x003c0180,0x00b40182,0x001d001d,
+0x000d00d0,0x008a00a8,0x004c00c4,0x006b00b6,0x00c300c3,0x00c200c2,0x002c002c,0x00b500b5,
+0x0098005b,0x00c100c1,0x001c001c,0x00c00089,0x000c000c,0x00a6004b,0x0097006a,0x00b300b3,
+0x003b003b,0x00a50088,0x00b200b2,0x0096005a,0x004a004a,0x00780087,0x00490049,0x00670077,
+0x002b002b,0x002b002b,0x00b100b1,0x001b001b,0x000b00b0,0x00a40069,0x003a00a3,0x00590095,
+0x00a200a2,0x002a002a,0x00a100a1,0x001a001a,0x008600a0,0x000a000a,0x00940068,0x00390039,
+0x00850093,0x00760058,0x00920092,0x00290029,0x00570075,0x00830083,0x00380038,0x00740066,
+0x00650047,0x00370056,0x00190091,0x00090090,0x00480084,0x00270027,0x00460064,0x00820082,
+0x00820082,0x00810028,0x00720073,0x00710071,0x00170017,0x00700055,0x00630007,0x00540036,
+0x00620045,0x00530026,0x00080080,0x00160061,0x00060060,0x00440035,0x00520052,0x00500025,
+0x00340043,0x00420005,0x00330024,0x00ff0184,0x00fd00fe,0x00fc00ee,0x00fb00ed,0x00ec00bf,
+0x018c00cd,0x00ce00ce,0x00dd00dd,0x00dc00af,0x00eb00eb,0x00be00be,0x00f900f9,0x009f009f,
+0x00ae00ae,0x00db00db,0x00bd00bd,0x00f800f8,0x008f008f,0x00cc00cc,0x00e900ea,0x00e800e8,
+0x00e700f7,0x007f007f,0x007f007f,0x00ad00ad,0x00cb00da,0x006f00bc,0x00f600f6,0x00f5008e,
+0x009d00d9,0x007e005f,0x00bb00ca,0x00f400f4,0x004f004f,0x006e00ac,0x003f003f,0x00f300f3,
+0x008d00d8,0x002f00f2,0x00c900e6,0x00f000f0,0x00e5009c,0x00ba00ba,0x007d00d7,0x00e400e4,
+0x006d008c,0x00e300e3,0x009b009b,0x00aa00b9,0x005e00ab,0x00c8004e,0x003e00d6,0x00e000e2,
+0x00d5000e,0x00c7005d,0x00d4007c,0x008b00b8,0x00a9004d,0x00c6009a,0x00b7003d,0x005c00c5,
+0x00a70099,0x0079007a,0x00cf00ef,0x00df00df,0x00de00de,0x00de00de,0x009e00fa,0x00200010,
+0x00400030,0x00600050,0x00700068,0x00760074,0x00110011,0x00010010,0x00000000,0x00880078,
+0x00a80098,0x00c800b8,0x00d800d0,0x00f000e8,0x010000f8,0x010c0108,0x011c0114,0x01240120,
+0x012c0128,0x01340130,0x013c0138,0x01420140,0x01460144,0x014c014a,0x0152014e,0x01560154,
+0x01580019,0x015c015a,0x0160015e,0x00280082,0x00180081,0x01640162,0x01680166,0x00270072,
+0x00710046,0x00170055,0x0063016a,0x00540036,0x00620045,0x00610026,0x0053016c,0x00160016,
+0x00440035,0x00520052,0x00250025,0x00510051,0x00150015,0x00050050,0x00430043,0x00420034,
+0x00330024,0x00140014,0x00400041,0x00320032,0x00230023,0x00300004,0x00310031,0x00030013,
+0x00220022,0x00120021,0x00020020,0x0170016e,0x017200ee,0x01760174,0x017800bf,0x00fa00dd,
+0x00eb00af,0x00dc00be,0x00f900cd,0x00ae009f,0x00bd00db,0x008f00f8,0x00e900cc,0x00f7009e,
+0x00da007f,0x00cb00ad,0x017a00f6,0x00bc00bc,0x006f006f,0x008e00e8,0x00d900f5,0x005f005f,
+0x00e700e7,0x007e007e,0x00ca00ca,0x00ac00ac,0x00bb00bb,0x00d8009d,0x00f400f4,0x004f004f,
+0x00f300f3,0x003f003f,0x008d008d,0x006e006e,0x00f200f2,0x002f002f,0x000f00e6,0x00f100f1,
+0x001f001f,0x00c900c9,0x009c009c,0x00ba00e5,0x005e00ab,0x007d00d7,0x004e00e4,0x008c00c8,
+0x00d600e3,0x003e006d,0x009b00b9,0x00e200e2,0x00aa00aa,0x002e002e,0x00e100e1,0x001e001e,
+0x000e00e0,0x00d500d5,0x005d005d,0x007c00c7,0x00b800d4,0x004d004d,0x00a9008b,0x00c6009a,
+0x00d3006c,0x003d003d,0x002d002d,0x00d000d2,0x00d100d1,0x00b700b7,0x007b007b,0x001d001d,
+0x000d00c5,0x005c005c,0x00a800a8,0x00c4008a,0x00b6004c,0x006b006b,0x00c00099,0x00c300c3,
+0x003c003c,0x00a700a7,0x007a007a,0x006a006a,0x00b0000c,0x002c002c,0x00b500c2,0x00c1005b,
+0x00890098,0x00b4001c,0x00a6004b,0x009700b3,0x003b003b,0x00880079,0x00a500b2,0x002b002b,
+0x00b1005a,0x001b001b,0x0096000b,0x00a40069,0x0087004a,0x00a30078,0x003a003a,0x00590095,
+0x002a00a2,0x001a00a1,0x000a00a0,0x00860086,0x00940068,0x00930049,0x00390039,0x00900077,
+0x00580085,0x00760092,0x00290067,0x00090091,0x00480084,0x00570075,0x00380083,0x00740066,
+0x00800047,0x00650008,0x00730056,0x00640037,0x00070070,0x00060060,0x00fe00ff,0x00fd00ef,
+0x00fc00df,0x00ed00cf,0x00fb00de,0x00ce00ec,0x00f000ea,0x00200010,0x00400030,0x00100011,
+0x00010001,0x00000000,0x00000000,0x00000000,0x00000000,0x004c0044,0x00ff0054,0x005c0058,
+0x002f005e,0x00f1006e,0x0070001f,0x00900080,0x00b000a0,0x00d000c0,0x00e000d8,0x00f000e8,
+0x010000f8,0x010c0108,0x01120110,0x011a0116,0x011c0015,0x0120011e,0x00410122,0x01240014,
+0x00230032,0x00310031,0x00130013,0x00030030,0x00220022,0x00120021,0x00020020,0x00ef00fe,
+0x00df00fd,0x00cf00fc,0x00bf00fb,0x00fa00fa,0x00f900af,0x008f009f,0x00f800f8,0x007f00f7,
+0x006f00f6,0x005f00f5,0x00f400f4,0x003f004f,0x000f000f,0x000f000f,0x000f000f,0x000f000f,
+0x00f300f3,0x00f300f3,0x01360126,0x0146013e,0x00f000f2,0x0152014e,0x015a0156,0x0160015c,
+0x01660164,0x016e016a,0x003e0172,0x01780176,0x017c017a,0x0180017e,0x00d00182,0x01860184,
+0x00c30188,0x00c1018a,0x018c000c,0x002e002e,0x00e100e2,0x00d2003d,0x001d002d,0x018e00b3,
+0x00d100d1,0x00b6004c,0x007a003c,0x00c200c2,0x005b002c,0x00c0001c,0x004b00b4,0x006a00a6,
+0x003b003b,0x005a00a5,0x00b200b2,0x002b002b,0x00b100b1,0x001b001b,0x000b00b0,0x00690096,
+0x004a00a4,0x00780087,0x003a003a,0x009500a3,0x00a200a2,0x00860059,0x001a001a,0x00770068,
+0x00490049,0x00750094,0x00760076,0x002a002a,0x002a002a,0x00a100a1,0x000a00a0,0x00390093,
+0x00580085,0x00920092,0x00290029,0x00900067,0x00910091,0x00190019,0x00840009,0x00570048,
+0x00380083,0x00820066,0x00280028,0x00470074,0x00810081,0x00180018,0x00080008,0x00650080,
+0x00730073,0x00370037,0x00640056,0x00720072,0x00270027,0x00550046,0x00700070,0x00710071,
+0x00710071,0x00170017,0x00630007,0x00540036,0x00620045,0x00610026,0x00160016,0x00060060,
+0x00350035,0x00440053,0x00250052,0x00500051,0x00340043,0x00420005,0x00330024,0x00040040,
+0x019000ec,0x00ed00ed,0x009e009e,0x009d00ae,0x00ee00ee,0x00ee00ee,0x00de00de,0x00be00be,
+0x00eb00eb,0x00dc00dc,0x00bd00cd,0x00ea00ea,0x00cc00cc,0x00ad00da,0x00ca00e7,0x00ac00ac,
+0x00d7009c,0x00e500e5,0x00db00db,0x00db00db,0x00e900e9,0x00bc00cb,0x008e00e8,0x007e00d9,
+0x00d800bb,0x00e6008d,0x00c9006e,0x00ab00ba,0x007d005e,0x00e400e4,0x00c8004e,0x00e3008c,
+0x00d600d6,0x00b9006d,0x00aa009b,0x001e001e,0x004d004d,0x009a008b,0x00b700b7,0x000d007b,
+0x000e00e0,0x005d00d5,0x007c00c7,0x00b800d4,0x00c600a9,0x00d3006c,0x005c00c5,0x008a00a8,
+0x00c40099,0x00a7006b,0x009800b5,0x00970089,0x00880079,0x00dd00ce,0x00200010,0x00ff0030,
+0x00500040,0x00700060,0x00900080,0x00a800a0,0x00100011,0x00000001,0x00ef00fe,0x00df00fd,
+0x00cf00fc,0x00bf00fb,0x00af00af,0x00f900fa,0x009f009f,0x008f008f,0x00f700f8,0x007f007f,
+0x00f600f6,0x006f006f,0x00f500f5,0x005f005f,0x00f400f4,0x004f004f,0x00f300f3,0x003f003f,
+0x00f200f2,0x002f002f,0x001f001f,0x000f00f1,0x00b400ac,0x00c400bc,0x00dc00cc,0x00ec00e4,
+0x00f800f4,0x010000fc,0x01080104,0x0110010c,0x01180114,0x01240120,0x012c0128,0x01380134,
+0x01420140,0x014a0146,0x0150014c,0x01540152,0x01580156,0x015c015a,0x0160015e,0x01640162,
+0x01680166,0x016c016a,0x0170016e,0x01760172,0x00370178,0x0027017c,0x00460064,0x00170055,
+0x00360063,0x00450054,0x00260062,0x00160061,0x0053017e,0x00440035,0x00250052,0x01800051,
+0x00150015,0x00340043,0x00420042,0x00240024,0x00330033,0x00410041,0x00140014,0x00040040,
+0x00320032,0x00230023,0x00310031,0x00310031,0x00130013,0x00130013,0x00030030,0x00220022,
+0x00210021,0x00210021,0x00120012,0x00020020,0x00f000f0,0x00f000f0,0x00ed00ee,0x00ec00de,
+0x00dd00ce,0x00be00eb,0x00cd00dc,0x00ae00ea,0x00bd00db,0x00e900cc,0x00da009e,0x00cb00ad,
+0x00e800bc,0x00d9008e,0x00e7009d,0x00ca007e,0x00ac00ac,0x00bb00bb,0x00d800d8,0x008d008d,
+0x000e00e0,0x00d000d0,0x006e006e,0x006e006e,0x00c900e6,0x009c009c,0x00e500e5,0x00ab00ab,
+0x005e005e,0x00d700ba,0x007d007d,0x004e004e,0x00c800c8,0x008c008c,0x00e200e4,0x00e300e3,
+0x006d00d6,0x00b9003e,0x00aa009b,0x00e1002e,0x00d5001e,0x00c7005d,0x00d4007c,0x008b00b8,
+0x00a9004d,0x00c6009a,0x00d3006c,0x00d2003d,0x00d1002d,0x007b00b7,0x00c5001d,0x00a8005c,
+0x0099008a,0x004c00c4,0x00b600b6,0x006b006b,0x00c0000d,0x00c300c3,0x00a7003c,0x00c2007a,
+0x00b5002c,0x00c1005b,0x00890098,0x00b4001c,0x00b0000c,0x00b300b3,0x00a0000b,0x00a100a1,
+0x004b004b,0x006a00a6,0x00970097,0x00790079,0x0090000a,0x00090009,0x0088003b,0x00a500b2,
+0x002b002b,0x00b1005a,0x0096001b,0x004a0069,0x008700a4,0x00780078,0x003a00a3,0x00590095,
+0x002a00a2,0x0086001a,0x00770068,0x00490094,0x00390093,0x00580085,0x00760092,0x00290067,
+0x00190091,0x00480084,0x00570075,0x00380083,0x00820066,0x00810028,0x00470074,0x00180018,
+0x00080080,0x00560065,0x00710071,0x00070070,0x00720073,0x00060060,0x00050050,0x00010610,
+0x00010614,0x00010624,0x00010644,0x00010610,0x00010664,0x00010698,0x000106d0,0x00010750,
+0x000107d4,0x00010840,0x0001090c,0x000109dc,0x00010a9c,0x00010610,0x00010c2c,0x00010da8,
+0x00010da8,0x00010da8,0x00010da8,0x00010da8,0x00010da8,0x00010da8,0x00010da8,0x00010f3c,
+0x00010f3c,0x00010f3c,0x00010f3c,0x00010f3c,0x00010f3c,0x00010f3c,0x00010f3c,0x00000000,
+0x00000000,0x00000000,0x00000000,0x04030201,0x0d0a0806,0x07060504,0x0d0b0908,0x03030300,
+0x04040300,0x04040404,0x04000404,0x04040404,0x04040404,0x04040404,0x04040404,0x000110c0,
+0x00000000,0x000113dc,0x000116d4,0x000116d4,0x000116d4,0x000116d4,0x000116d4,0x000116d4,
+0x000116d4,0x000116d4,0x000119f8,0x000119f8,0x000119f8,0x000119f8,0x000119f8,0x000119f8,
+0x000119f8,0x000119f8,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0xfffe3000,0x000d5000,0xffe35000,0x007f5000,0xfebdf000,
+0x019ae000,0xf6d8f000,0x1251e000,0x09271000,0x019ae000,0x01421000,0x007f5000,0x001cb000,
+0x000d5000,0x0001d000,0x00000000,0xfffe3000,0x000d5000,0xffe35000,0x007f5000,0xfebdf000,
+0x019ae000,0xf6d8f000,0x1251e000,0x09271000,0x019ae000,0x01421000,0x007f5000,0x001cb000,
+0x000d5000,0x0001d000,0xfffff000,0xfffe1000,0x000da000,0xffdf9000,0x007d0000,0xfea73000,
+0x01747000,0xf6658000,0x124f0000,0x08b38000,0x01bde000,0x012b4000,0x0080f000,0x00191000,
+0x000d0000,0x0001a000,0xfffff000,0xfffe1000,0x000da000,0xffdf9000,0x007d0000,0xfea73000,
+0x01747000,0xf6658000,0x124f0000,0x08b38000,0x01bde000,0x012b4000,0x0080f000,0x00191000,
+0x000d0000,0x0001a000,0xfffff000,0xfffdd000,0x000de000,0xffdbb000,0x007a0000,0xfe909000,
+0x014a8000,0xf5f28000,0x12468000,0x083ff000,0x01dd8000,0x01149000,0x00820000,0x0015b000,
+0x000ca000,0x00018000,0xfffff000,0xfffdd000,0x000de000,0xffdbb000,0x007a0000,0xfe909000,
+0x014a8000,0xf5f28000,0x12468000,0x083ff000,0x01dd8000,0x01149000,0x00820000,0x0015b000,
+0x000ca000,0x00018000,0xfffff000,0xfffda000,0x000e1000,0xffd7b000,0x00765000,0xfe7a3000,
+0x011d1000,0xf5802000,0x12386000,0x07ccb000,0x01f9c000,0x00fdf000,0x00827000,0x00126000,
+0x000c4000,0x00015000,0xfffff000,0xfffda000,0x000e1000,0xffd7b000,0x00765000,0xfe7a3000,
+0x011d1000,0xf5802000,0x12386000,0x07ccb000,0x01f9c000,0x00fdf000,0x00827000,0x00126000,
+0x000c4000,0x00015000,0xfffff000,0xfffd7000,0x000e3000,0xffd39000,0x0071e000,0xfe643000,
+0x00ec0000,0xf50eb000,0x12249000,0x075a0000,0x0212c000,0x00e79000,0x00825000,0x000f4000,
+0x000be000,0x00013000,0xfffff000,0xfffd7000,0x000e3000,0xffd39000,0x0071e000,0xfe643000,
+0x00ec0000,0xf50eb000,0x12249000,0x075a0000,0x0212c000,0x00e79000,0x00825000,0x000f4000,
+0x000be000,0x00013000,0xfffff000,0xfffd3000,0x000e4000,0xffcf5000,0x006cb000,0xfe4e9000,
+0x00b77000,0xf49e7000,0x120b4000,0x06e81000,0x02288000,0x00d17000,0x0081b000,0x000c5000,
+0x000b7000,0x00011000,0xfffff000,0xfffd3000,0x000e4000,0xffcf5000,0x006cb000,0xfe4e9000,
+0x00b77000,0xf49e7000,0x120b4000,0x06e81000,0x02288000,0x00d17000,0x0081b000,0x000c5000,
+0x000b7000,0x00011000,0xfffff000,0xfffcf000,0x000e4000,0xffcb0000,0x0066c000,0xfe399000,
+0x007f5000,0xf42fa000,0x11ec7000,0x06772000,0x023b3000,0x00bbc000,0x00809000,0x00099000,
+0x000b0000,0x00010000,0xfffff000,0xfffcf000,0x000e4000,0xffcb0000,0x0066c000,0xfe399000,
+0x007f5000,0xf42fa000,0x11ec7000,0x06772000,0x023b3000,0x00bbc000,0x00809000,0x00099000,
+0x000b0000,0x00010000,0xffffe000,0xfffcb000,0x000e3000,0xffc69000,0x005ff000,0xfe253000,
+0x0043a000,0xf3c27000,0x11c83000,0x06076000,0x024ad000,0x00a67000,0x007f0000,0x0006f000,
+0x000a9000,0x0000e000,0xffffe000,0xfffcb000,0x000e3000,0xffc69000,0x005ff000,0xfe253000,
+0x0043a000,0xf3c27000,0x11c83000,0x06076000,0x024ad000,0x00a67000,0x007f0000,0x0006f000,
+0x000a9000,0x0000e000,0xffffe000,0xfffc6000,0x000e0000,0xffc21000,0x00586000,0xfe11a000,
+0x00046000,0xf3573000,0x119e9000,0x05991000,0x02578000,0x0091a000,0x007d1000,0x00048000,
+0x000a1000,0x0000d000,0xffffe000,0xfffc6000,0x000e0000,0xffc21000,0x00586000,0xfe11a000,
+0x00046000,0xf3573000,0x119e9000,0x05991000,0x02578000,0x0091a000,0x007d1000,0x00048000,
+0x000a1000,0x0000d000,0xffffe000,0xfffc1000,0x000dd000,0xffbd8000,0x00500000,0xfdfef000,
+0xffc1a000,0xf2ee2000,0x116fc000,0x052c5000,0x02616000,0x007d6000,0x007aa000,0x00024000,
+0x0009a000,0x0000b000,0xffffe000,0xfffc1000,0x000dd000,0xffbd8000,0x00500000,0xfdfef000,
+0xffc1a000,0xf2ee2000,0x116fc000,0x052c5000,0x02616000,0x007d6000,0x007aa000,0x00024000,
+0x0009a000,0x0000b000,0xffffe000,0xfffbc000,0x000d7000,0xffb8f000,0x0046b000,0xfded5000,
+0xff7b6000,0xf2876000,0x113be000,0x04c16000,0x02687000,0x0069c000,0x0077f000,0x00002000,
+0x00093000,0x0000a000,0xffffe000,0xfffbc000,0x000d7000,0xffb8f000,0x0046b000,0xfded5000,
+0xff7b6000,0xf2876000,0x113be000,0x04c16000,0x02687000,0x0069c000,0x0077f000,0x00002000,
+0x00093000,0x0000a000,0xffffd000,0xfffb7000,0x000d0000,0xffb46000,0x003ca000,0xfddcd000,
+0xff31c000,0xf2236000,0x1102f000,0x04587000,0x026cf000,0x0056c000,0x0074e000,0xfffe3000,
+0x0008b000,0x00009000,0xffffd000,0xfffb7000,0x000d0000,0xffb46000,0x003ca000,0xfddcd000,
+0xff31c000,0xf2236000,0x1102f000,0x04587000,0x026cf000,0x0056c000,0x0074e000,0xfffe3000,
+0x0008b000,0x00009000,0xffffd000,0xfffb1000,0x000c8000,0xffafd000,0x0031a000,0xfdcda000,
+0xfee4b000,0xf1c23000,0x10c54000,0x03f1b000,0x026ee000,0x00447000,0x00719000,0xfffc7000,
+0x00084000,0x00008000,0xffffd000,0xfffb1000,0x000c8000,0xffafd000,0x0031a000,0xfdcda000,
+0xfee4b000,0xf1c23000,0x10c54000,0x03f1b000,0x026ee000,0x00447000,0x00719000,0xfffc7000,
+0x00084000,0x00008000,0xffffc000,0xfffab000,0x000bd000,0xffab4000,0x0025d000,0xfdbfd000,
+0xfe946000,0xf1642000,0x1082d000,0x038d4000,0x026e7000,0x0032e000,0x006df000,0xfffad000,
+0x0007d000,0x00007000,0xffffc000,0xfffab000,0x000bd000,0xffab4000,0x0025d000,0xfdbfd000,
+0xfe946000,0xf1642000,0x1082d000,0x038d4000,0x026e7000,0x0032e000,0x006df000,0xfffad000,
+0x0007d000,0x00007000,0xffffc000,0xfffa5000,0x000b1000,0xffa6c000,0x00192000,0xfdb38000,
+0xfe40e000,0xf1097000,0x103be000,0x032b4000,0x026bc000,0x00221000,0x006a2000,0xfff96000,
+0x00075000,0x00007000,0xffffc000,0xfffa5000,0x000b1000,0xffa6c000,0x00192000,0xfdb38000,
+0xfe40e000,0xf1097000,0x103be000,0x032b4000,0x026bc000,0x00221000,0x006a2000,0xfff96000,
+0x00075000,0x00007000,0xffffb000,0xfff9f000,0x000a3000,0xffa26000,0x000b9000,0xfda8f000,
+0xfdea4000,0xf0b24000,0x0ff0a000,0x02cbf000,0x0266e000,0x00120000,0x00662000,0xfff81000,
+0x0006f000,0x00006000,0xffffb000,0xfff9f000,0x000a3000,0xffa26000,0x000b9000,0xfda8f000,
+0xfdea4000,0xf0b24000,0x0ff0a000,0x02cbf000,0x0266e000,0x00120000,0x00662000,0xfff81000,
+0x0006f000,0x00006000,0xffffb000,0xfff98000,0x00092000,0xff9e1000,0xfffd3000,0xfda01000,
+0xfd909000,0xf05ed000,0x0fa13000,0x026f7000,0x025ff000,0x0002d000,0x0061f000,0xfff6e000,
+0x00068000,0x00005000,0xffffb000,0xfff98000,0x00092000,0xff9e1000,0xfffd3000,0xfda01000,
+0xfd909000,0xf05ed000,0x0fa13000,0x026f7000,0x025ff000,0x0002d000,0x0061f000,0xfff6e000,
+0x00068000,0x00005000,0x0d744fcd,0x0b504f33,0x09837f05,0x08000000,0x06ba27e6,0x05a8279a,
+0x04c1bf83,0x04000000,0x035d13f3,0x02d413cd,0x0260dfc1,0x02000000,0x01ae89fa,0x016a09e6,
+0x01306fe1,0x0b504f33,0x08000000,0x05a8279a,0x04000000,0x02d413cd,0x02000000,0x016a09e6,
+0x01000000,0x00b504f3,0x00800000,0x005a827a,0x00400000,0x002d413d,0x00200000,0x0016a09e,
+0x20000000,0x1965fea5,0x1428a2fa,0x10000000,0x0cb2ff53,0x0a14517d,0x08000000,0x06597fa9,
+0x050a28be,0x04000000,0x032cbfd5,0x0285145f,0x02000000,0x01965fea,0x01428a30,0x01000000,
+0x00cb2ff5,0x00a14518,0x00800000,0x006597fb,0x0050a28c,0x00400000,0x0032cbfd,0x00285146,
+0x00200000,0x001965ff,0x001428a3,0x00100000,0x000cb2ff,0x000a1451,0x00080000,0x00065980,
+0x00050a29,0x00040000,0x00032cc0,0x00028514,0x00020000,0x00019660,0x0001428a,0x00010000,
+0x0000cb30,0x0000a145,0x00008000,0x00006598,0x000050a3,0x00004000,0x000032cc,0x00002851,
+0x00002000,0x00001966,0x00001429,0x00001000,0x00000cb3,0x00000a14,0x00000800,0x00000659,
+0x0000050a,0x00000400,0x0000032d,0x00000285,0x00000200,0x00000196,0x00000143,0x15555555,
+0x12492492,0x11111111,0x10842108,0x10410410,0x10204081,0x10101010,0x10080402,0x10040100,
+0x10020040,0x10010010,0x10008004,0x10004001,0x10002000,0x0c081e1b,0x0000001e,0x06070707,
+0x06060606,0x03060606,0x03030303,0x03030303,0x00030303,0x00000000,0x07070000,0x06060607,
+0x06060606,0x03030306,0x03030303,0x03030303,0x00000003,0x00000000,0x02020505,0x02020202,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x05050000,0x02020202,0x02020202,
+0x00000202,0x00000000,0x00000000,0x00000000,0x00000000,0x04040404,0x02020202,0x01020202,
+0x01010101,0x01010101,0x01010101,0x01010101,0x00000101,0x03020002,0x01030303,0x03040204,
+0x05040404,0x00100100,0x00000000,0x00000000,0x00000000,0x04030201,0x00001005,0x00000000,
+0x01000000,0x05040302,0x09080706,0x0d0c0b0a,0x0301000e,0x07060504,0x0b0a0908,0x0f0e0d0c,
+0x03020100,0x07060504,0x0b0a0908,0x00100d0c,0x06050402,0x0a090807,0x0e0d0c0b,0x0000100f,
+0x00000003,0x00000002,0x00000005,0x15555555,0x08000000,0x00000005,0x00000003,0x00000007,
+0x1999999a,0x08000000,0x00000007,0x00000000,0x00000003,0x12492492,0x04000000,0x00000009,
+0x00000004,0x0000000a,0x1c71c71c,0x08000000,0x0000000f,0x00000000,0x00000004,0x11111111,
+0x02000000,0x0000001f,0x00000000,0x00000005,0x10842108,0x01000000,0x0000003f,0x00000000,
+0x00000006,0x10410410,0x00800000,0x0000007f,0x00000000,0x00000007,0x10204081,0x00400000,
+0x000000ff,0x00000000,0x00000008,0x10101010,0x00200000,0x000001ff,0x00000000,0x00000009,
+0x10080402,0x00100000,0x000003ff,0x00000000,0x0000000a,0x10040100,0x00080000,0x000007ff,
+0x00000000,0x0000000b,0x10020040,0x00040000,0x00000fff,0x00000000,0x0000000c,0x10010010,
+0x00020000,0x00001fff,0x00000000,0x0000000d,0x10008004,0x00010000,0x00003fff,0x00000000,
+0x0000000e,0x10004001,0x00008000,0x00007fff,0x00000000,0x0000000f,0x10002000,0x00004000,
+0x0000ffff,0x00000000,0x00000010,0x10001000,0x00002000,0x00000000,0x04000000,0x050a28be,
+0x0453a5cd,0x06597fa9,0x04466275,0x05738c72,0x06b1fc81,0x04000000,0x04ae20d7,0x0562d694,
+0x061dae96,0x06de47f4,0x07a44f7a,0x0437be65,0x049fc824,0x050a28be,0x0576c6f5,0x05e58c0b,
+0x06566361,0x06c93a2e,0x073dff3e,0x07b4a2bc,0x04168b05,0x0453a5cd,0x04919b6a,0x04d065fb,
+0x05100000,0x05506451,0x05918e15,0x05d378bb,0x06161ff3,0x06597fa9,0x069d9400,0x06e2594c,
+0x0727cc11,0x076de8fc,0x07b4ace3,0x07fc14bf,0x04220ed7,0x04466275,0x046b03e7,0x048ff1e8,
+0x04b52b3f,0x04daaec0,0x05007b49,0x05268fc6,0x054ceb2a,0x05738c72,0x059a72a5,0x05c19cd3,
+0x05e90a12,0x0610b982,0x0638aa48,0x0660db91,0x06894c90,0x06b1fc81,0x06daeaa1,0x07041636,
+0x072d7e8b,0x075722ef,0x078102b8,0x07ab1d3e,0x07d571e0,0x04000000,0x04156381,0x042ae32a,
+0x04407eb1,0x045635cf,0x046c083e,0x0481f5bb,0x0497fe03,0x04ae20d7,0x04c45df6,0x04dab524,
+0x04f12624,0x0507b0bc,0x051e54b1,0x053511cb,0x054be7d4,0x0562d694,0x0579ddd8,0x0590fd6c,
+0x05a8351c,0x05bf84b8,0x05d6ec0e,0x05ee6aef,0x0606012b,0x061dae96,0x06357302,0x064d4e43,
+0x0665402d,0x067d4896,0x06956753,0x06ad9c3d,0x06c5e72b,0x06de47f4,0x06f6be73,0x070f4a80,
+0x0727ebf7,0x0740a2b2,0x07596e8d,0x07724f64,0x078b4514,0x07a44f7a,0x07bd6e75,0x07d6a1e2,
+0x07efe9a1,0x0404a2c9,0x04115aca,0x041e1cc4,0x042ae8a7,0x0437be65,0x04449dee,0x04518733,
+0x045e7a26,0x046b76b9,0x04787cdc,0x04858c83,0x0492a59f,0x049fc824,0x04acf402,0x04ba292e,
+0x04c7679a,0x04d4af3a,0x04e20000,0x04ef59e0,0x04fcbcce,0x050a28be,0x05179da4,0x05251b73,
+0x0532a220,0x054031a0,0x054dc9e7,0x055b6ae9,0x0569149c,0x0576c6f5,0x058481e9,0x0592456d,
+0x05a01176,0x05ade5fa,0x05bbc2ef,0x05c9a84a,0x05d79601,0x05e58c0b,0x05f38a5d,0x060190ee,
+0x060f9fb3,0x061db6a5,0x062bd5b8,0x0639fce4,0x06482c1f,0x06566361,0x0664a2a0,0x0672e9d4,
+0x068138f3,0x068f8ff5,0x069deed1,0x06ac557f,0x06bac3f6,0x06c93a2e,0x06d7b81f,0x06e63dc0,
+0x06f4cb09,0x07035ff3,0x0711fc75,0x0720a087,0x072f4c22,0x073dff3e,0x074cb9d3,0x075b7bdb,
+0x076a454c,0x07791620,0x0787ee50,0x0796cdd4,0x07a5b4a5,0x07b4a2bc,0x07c39812,0x07d294a0,
+0x07e1985f,0x07f0a348,0x07ffb554,0x0407673f,0x040ef75e,0x04168b05,0x041e2230,0x0425bcdd,
+0x042d5b07,0x0434fcad,0x043ca1c9,0x04444a5a,0x044bf65d,0x0453a5cd,0x045b58a9,0x04630eed,
+0x046ac896,0x047285a2,0x047a460c,0x048209d3,0x0489d0f4,0x04919b6a,0x04996935,0x04a13a50,
+0x04a90eba,0x04b0e66e,0x04b8c16c,0x04c09faf,0x04c88135,0x04d065fb,0x04d84dff,0x04e0393e,
+0x04e827b6,0x04f01963,0x04f80e44,0x05000655,0x05080195,0x05100000,0x05180194,0x0520064f,
+0x05280e2d,0x0530192e,0x0538274e,0x0540388a,0x05484ce2,0x05506451,0x05587ed5,0x05609c6e,
+0x0568bd17,0x0570e0cf,0x05790793,0x05813162,0x05895e39,0x05918e15,0x0599c0f4,0x05a1f6d5,
+0x05aa2fb5,0x05b26b92,0x05baaa69,0x05c2ec39,0x05cb3100,0x05d378bb,0x05dbc368,0x05e41105,
+0x05ec6190,0x05f4b507,0x05fd0b68,0x060564b1,0x060dc0e0,0x06161ff3,0x061e81e8,0x0626e6bc,
+0x062f4e6f,0x0637b8fd,0x06402666,0x064896a7,0x065109be,0x06597fa9,0x0661f867,0x066a73f5,
+0x0672f252,0x067b737c,0x0683f771,0x068c7e2f,0x069507b5,0x069d9400,0x06a6230f,0x06aeb4e0,
+0x06b74971,0x06bfe0c0,0x06c87acc,0x06d11794,0x06d9b714,0x06e2594c,0x06eafe3a,0x06f3a5dc,
+0x06fc5030,0x0704fd35,0x070dacea,0x07165f4b,0x071f1459,0x0727cc11,0x07308671,0x07394378,
+0x07420325,0x074ac575,0x07538a67,0x075c51fa,0x07651c2c,0x076de8fc,0x0776b867,0x077f8a6d,
+0x07885f0b,0x07913641,0x079a100c,0x07a2ec6c,0x07abcb5f,0x07b4ace3,0x07bd90f6,0x07c67798,
+0x07cf60c7,0x07d84c81,0x07e13ac5,0x07ea2b92,0x07f31ee6,0x07fc14bf,0x0402868e,0x040703ff,
+0x040b82b0,0x041002a1,0x041483d1,0x04190640,0x041d89ed,0x04220ed7,0x042694fe,0x042b1c60,
+0x042fa4fe,0x04342ed7,0x0438b9e9,0x043d4635,0x0441d3b9,0x04466275,0x044af269,0x044f8393,
+0x045415f3,0x0458a989,0x045d3e53,0x0461d451,0x04666b83,0x046b03e7,0x046f9d7e,0x04743847,
+0x0478d440,0x047d716a,0x04820fc3,0x0486af4c,0x048b5003,0x048ff1e8,0x049494fb,0x0499393a,
+0x049ddea5,0x04a2853c,0x04a72cfe,0x04abd5ea,0x04b08000,0x04b52b3f,0x04b9d7a7,0x04be8537,
+0x04c333ee,0x04c7e3cc,0x04cc94d1,0x04d146fb,0x04d5fa4b,0x04daaec0,0x04df6458,0x04e41b14,
+0x04e8d2f3,0x04ed8bf5,0x04f24618,0x04f7015d,0x04fbbdc3,0x05007b49,0x050539ef,0x0509f9b4,
+0x050eba98,0x05137c9a,0x05183fba,0x051d03f7,0x0521c950,0x05268fc6,0x052b5757,0x05302003,
+0x0534e9ca,0x0539b4ab,0x053e80a6,0x05434db9,0x05481be5,0x054ceb2a,0x0551bb85,0x05568cf8,
+0x055b5f81,0x05603321,0x056507d6,0x0569dda0,0x056eb47f,0x05738c72,0x05786578,0x057d3f92,
+0x05821abf,0x0586f6fd,0x058bd44e,0x0590b2b0,0x05959222,0x059a72a5,0x059f5438,0x05a436da,
+0x05a91a8c,0x05adff4c,0x05b2e51a,0x05b7cbf5,0x05bcb3de,0x05c19cd3,0x05c686d5,0x05cb71e2,
+0x05d05dfb,0x05d54b1f,0x05da394d,0x05df2885,0x05e418c7,0x05e90a12,0x05edfc66,0x05f2efc2,
+0x05f7e426,0x05fcd992,0x0601d004,0x0606c77d,0x060bbffd,0x0610b982,0x0615b40c,0x061aaf9c,
+0x061fac2f,0x0624a9c7,0x0629a863,0x062ea802,0x0633a8a3,0x0638aa48,0x063dacee,0x0642b096,
+0x0647b53f,0x064cbae9,0x0651c193,0x0656c93d,0x065bd1e7,0x0660db91,0x0665e639,0x066af1df,
+0x066ffe84,0x06750c26,0x067a1ac6,0x067f2a62,0x06843afb,0x06894c90,0x068e5f21,0x069372ae,
+0x06988735,0x069d9cb7,0x06a2b333,0x06a7caa9,0x06ace318,0x06b1fc81,0x06b716e2,0x06bc323b,
+0x06c14e8d,0x06c66bd6,0x06cb8a17,0x06d0a94e,0x06d5c97c,0x06daeaa1,0x06e00cbb,0x06e52fca,
+0x06ea53cf,0x06ef78c8,0x06f49eb6,0x06f9c597,0x06feed6d,0x07041636,0x07093ff2,0x070e6aa0,
+0x07139641,0x0718c2d3,0x071df058,0x07231ecd,0x07284e34,0x072d7e8b,0x0732afd2,0x0737e209,
+0x073d1530,0x07424946,0x07477e4b,0x074cb43e,0x0751eb20,0x075722ef,0x075c5bac,0x07619557,
+0x0766cfee,0x076c0b72,0x077147e2,0x0776853e,0x077bc385,0x078102b8,0x078642d6,0x078b83de,
+0x0790c5d1,0x079608ae,0x079b4c74,0x07a09124,0x07a5d6bd,0x07ab1d3e,0x07b064a8,0x07b5acfb,
+0x07baf635,0x07c04056,0x07c58b5f,0x07cad74e,0x07d02424,0x07d571e0,0x07dac083,0x07e0100a,
+0x07e56078,0x07eab1ca,0x07f00401,0x07f5571d,0x07faab1c,0x04000000,0x0402aae3,0x04055638,
+0x040801ff,0x040aae37,0x040d5ae0,0x041007fa,0x0412b586,0x04156381,0x041811ee,0x041ac0cb,
+0x041d7018,0x04201fd5,0x0422d003,0x042580a0,0x042831ad,0x042ae32a,0x042d9516,0x04304772,
+0x0432fa3d,0x0435ad76,0x0438611f,0x043b1536,0x043dc9bc,0x04407eb1,0x04433414,0x0445e9e5,
+0x0448a024,0x044b56d1,0x044e0dec,0x0450c575,0x04537d6b,0x045635cf,0x0458ee9f,0x045ba7dd,
+0x045e6188,0x04611ba0,0x0463d625,0x04669116,0x04694c74,0x046c083e,0x046ec474,0x04718116,
+0x04743e25,0x0476fb9f,0x0479b984,0x047c77d6,0x047f3693,0x0481f5bb,0x0484b54e,0x0487754c,
+0x048a35b6,0x048cf68a,0x048fb7c8,0x04927972,0x04953b85,0x0497fe03,0x049ac0eb,0x049d843e,
+0x04a047fa,0x04a30c20,0x04a5d0af,0x04a895a8,0x04ab5b0b,0x04ae20d7,0x04b0e70c,0x04b3adaa,
+0x04b674b1,0x04b93c21,0x04bc03fa,0x04becc3b,0x04c194e4,0x04c45df6,0x04c72771,0x04c9f153,
+0x04ccbb9d,0x04cf864f,0x04d25169,0x04d51ceb,0x04d7e8d4,0x04dab524,0x04dd81dc,0x04e04efb,
+0x04e31c81,0x04e5ea6e,0x04e8b8c2,0x04eb877c,0x04ee569d,0x04f12624,0x04f3f612,0x04f6c666,
+0x04f99721,0x04fc6841,0x04ff39c7,0x05020bb3,0x0504de05,0x0507b0bc,0x050a83d8,0x050d575b,
+0x05102b42,0x0512ff8e,0x0515d440,0x0518a956,0x051b7ed1,0x051e54b1,0x05212af5,0x0524019e,
+0x0526d8ab,0x0529b01d,0x052c87f2,0x052f602c,0x053238ca,0x053511cb,0x0537eb30,0x053ac4f9,
+0x053d9f25,0x054079b5,0x054354a8,0x05462ffe,0x05490bb7,0x054be7d4,0x054ec453,0x0551a134,
+0x05547e79,0x05575c20,0x055a3a2a,0x055d1896,0x055ff764,0x0562d694,0x0565b627,0x0568961b,
+0x056b7671,0x056e5729,0x05713843,0x057419be,0x0576fb9a,0x0579ddd8,0x057cc077,0x057fa378,
+0x058286d9,0x05856a9b,0x05884ebe,0x058b3342,0x058e1827,0x0590fd6c,0x0593e311,0x0596c917,
+0x0599af7d,0x059c9643,0x059f7d6a,0x05a264f0,0x05a54cd6,0x05a8351c,0x05ab1dc2,0x05ae06c7,
+0x05b0f02b,0x05b3d9f0,0x05b6c413,0x05b9ae95,0x05bc9977,0x05bf84b8,0x05c27057,0x05c55c56,
+0x05c848b3,0x05cb356e,0x05ce2289,0x05d11001,0x05d3fdd8,0x05d6ec0e,0x05d9daa1,0x05dcc993,
+0x05dfb8e2,0x05e2a890,0x05e5989b,0x05e88904,0x05eb79cb,0x05ee6aef,0x05f15c70,0x05f44e4f,
+0x05f7408b,0x05fa3324,0x05fd261b,0x0600196e,0x06030d1e,0x0606012b,0x0608f595,0x060bea5c,
+0x060edf7f,0x0611d4fe,0x0614cada,0x0617c112,0x061ab7a6,0x061dae96,0x0620a5e3,0x06239d8b,
+0x0626958f,0x06298def,0x062c86aa,0x062f7fc1,0x06327934,0x06357302,0x06386d2b,0x063b67b0,
+0x063e6290,0x06415dcb,0x06445960,0x06475551,0x064a519c,0x064d4e43,0x06504b44,0x0653489f,
+0x06564655,0x06594465,0x065c42d0,0x065f4195,0x066240b4,0x0665402d,0x06684000,0x066b402d,
+0x066e40b3,0x06714194,0x067442ce,0x06774462,0x067a464f,0x067d4896,0x06804b36,0x06834e2f,
+0x06865181,0x0689552c,0x068c5931,0x068f5d8e,0x06926245,0x06956753,0x06986cbb,0x069b727b,
+0x069e7894,0x06a17f05,0x06a485cf,0x06a78cf1,0x06aa946b,0x06ad9c3d,0x06b0a468,0x06b3acea,
+0x06b6b5c4,0x06b9bef6,0x06bcc880,0x06bfd261,0x06c2dc9a,0x06c5e72b,0x06c8f213,0x06cbfd52,
+0x06cf08e9,0x06d214d7,0x06d5211c,0x06d82db8,0x06db3aaa,0x06de47f4,0x06e15595,0x06e4638d,
+0x06e771db,0x06ea807f,0x06ed8f7b,0x06f09ecc,0x06f3ae75,0x06f6be73,0x06f9cec8,0x06fcdf72,
+0x06fff073,0x070301ca,0x07061377,0x0709257a,0x070c37d2,0x070f4a80,0x07125d84,0x071570de,
+0x0718848d,0x071b9891,0x071eaceb,0x0721c19a,0x0724d69e,0x0727ebf7,0x072b01a6,0x072e17a9,
+0x07312e01,0x073444ae,0x07375bb0,0x073a7307,0x073d8ab2,0x0740a2b2,0x0743bb06,0x0746d3af,
+0x0749ecac,0x074d05fe,0x07501fa3,0x0753399d,0x075653eb,0x07596e8d,0x075c8983,0x075fa4cc,
+0x0762c06a,0x0765dc5b,0x0768f8a0,0x076c1538,0x076f3224,0x07724f64,0x07756cf7,0x07788add,
+0x077ba916,0x077ec7a3,0x0781e683,0x078505b5,0x0788253b,0x078b4514,0x078e653f,0x079185be,
+0x0794a68f,0x0797c7b2,0x079ae929,0x079e0af1,0x07a12d0c,0x07a44f7a,0x07a7723a,0x07aa954c,
+0x07adb8b0,0x07b0dc67,0x07b4006f,0x07b724ca,0x07ba4976,0x07bd6e75,0x07c093c5,0x07c3b967,
+0x07c6df5a,0x07ca059f,0x07cd2c36,0x07d0531e,0x07d37a57,0x07d6a1e2,0x07d9c9be,0x07dcf1ec,
+0x07e01a6a,0x07e3433a,0x07e66c5a,0x07e995cc,0x07ecbf8e,0x07efe9a1,0x07f31405,0x07f63eba,
+0x07f969c0,0x07fc9516,0x07ffc0bc,0x04017659,0x04030c7d,0x0404a2c9,0x0406393d,0x0407cfd9,
+0x0409669d,0x040afd89,0x040c949e,0x040e2bda,0x040fc33e,0x04115aca,0x0412f27e,0x04148a5a,
+0x0416225d,0x0417ba89,0x041952dc,0x041aeb57,0x041c83fa,0x041e1cc4,0x041fb5b6,0x04214ed0,
+0x0422e811,0x04248179,0x04261b0a,0x0427b4c2,0x04294ea1,0x042ae8a7,0x042c82d6,0x042e1d2b,
+0x042fb7a8,0x0431524c,0x0432ed17,0x0434880a,0x04362324,0x0437be65,0x043959cd,0x043af55d,
+0x043c9113,0x043e2cf1,0x043fc8f6,0x04416522,0x04430174,0x04449dee,0x04463a8f,0x0447d756,
+0x04497445,0x044b115a,0x044cae96,0x044e4bf9,0x044fe983,0x04518733,0x0453250a,0x0454c308,
+0x0456612d,0x0457ff78,0x04599dea,0x045b3c82,0x045cdb41,0x045e7a26,0x04601932,0x0461b864,
+0x046357bd,0x0464f73c,0x046696e2,0x046836ae,0x0469d6a0,0x046b76b9,0x046d16f7,0x046eb75c,
+0x047057e8,0x0471f899,0x04739971,0x04753a6f,0x0476db92,0x04787cdc,0x047a1e4c,0x047bbfe2,
+0x047d619e,0x047f0380,0x0480a588,0x048247b6,0x0483ea0a,0x04858c83,0x04872f22,0x0488d1e8,
+0x048a74d3,0x048c17e3,0x048dbb1a,0x048f5e76,0x049101f8,0x0492a59f,0x0494496c,0x0495ed5f,
+0x04979177,0x049935b5,0x049ada19,0x049c7ea1,0x049e2350,0x049fc824,0x04a16d1d,0x04a3123b,
+0x04a4b77f,0x04a65ce8,0x04a80277,0x04a9a82b,0x04ab4e04,0x04acf402,0x04ae9a26,0x04b0406e,
+0x04b1e6dc,0x04b38d6f,0x04b53427,0x04b6db05,0x04b88207,0x04ba292e,0x04bbd07a,0x04bd77ec,
+0x04bf1f82,0x04c0c73d,0x04c26f1d,0x04c41722,0x04c5bf4c,0x04c7679a,0x04c9100d,0x04cab8a6,
+0x04cc6163,0x04ce0a44,0x04cfb34b,0x04d15c76,0x04d305c5,0x04d4af3a,0x04d658d2,0x04d80290,
+0x04d9ac72,0x04db5679,0x04dd00a4,0x04deaaf3,0x04e05567,0x04e20000,0x04e3aabd,0x04e5559e,
+0x04e700a3,0x04e8abcd,0x04ea571c,0x04ec028e,0x04edae25,0x04ef59e0,0x04f105bf,0x04f2b1c3,
+0x04f45dea,0x04f60a36,0x04f7b6a6,0x04f9633a,0x04fb0ff2,0x04fcbcce,0x04fe69ce,0x050016f3,
+0x0501c43b,0x050371a7,0x05051f37,0x0506cceb,0x05087ac2,0x050a28be,0x050bd6de,0x050d8521,
+0x04030200,0x05050504,0x06060606,0x07070606,0x07070707,0x08070707,0x08080808,0x08080808,
+0x08080808,0x09080808,0x09090909,0x09090909,0x09090909,0x09090909,0x09090909,0x09090909,
+0x0a0a0a0a,0x0a0a0a0a,0x0a0a0a0a,0x0a0a0a0a,0x0a0a0a0a,0x0a0a0a0a,0x0a0a0a0a,0x0a0a0a0a,
+0x0a0a0a0a,0x0a0a0a0a,0x0a0a0a0a,0x0b0b0b0b,0x0b0b0b0b,0x0b0b0b0b,0x0b0b0b0b,0x0b0b0b0b,
+0x0b0b0b0b,0x0b0b0b0b,0x0b0b0b0b,0x0b0b0b0b,0x0b0b0b0b,0x0b0b0b0b,0x0b0b0b0b,0x0b0b0b0b,
+0x0b0b0b0b,0x0b0b0b0b,0x0b0b0b0b,0x0b0b0b0b,0x0b0b0b0b,0x0c0c0b0b,0x0c0c0c0c,0x0c0c0c0c,
+0x0c0c0c0c,0x0c0c0c0c,0x0c0c0c0c,0x0c0c0c0c,0x0c0c0c0c,0x0c0c0c0c,0x0c0c0c0c,0x0c0c0c0c,
+0x0c0c0c0c,0x0c0c0c0c,0x0c0c0c0c,0x0c0c0c0c,0x0c0c0c0c,0x0c0c0c0c,0x0c0c0c0c,0x0c0c0c0c,
+0x0c0c0c0c,0x0c0c0c0c,0x0c0c0c0c,0x0c0c0c0c,0x0c0c0c0c,0x0c0c0c0c,0x0c0c0c0c,0x0c0c0c0c,
+0x0c0c0c0c,0x0c0c0c0c,0x0c0c0c0c,0x0c0c0c0c,0x0d0d0d0c,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,
+0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,
+0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,
+0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,
+0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,
+0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,
+0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,
+0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,
+0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,
+0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,
+0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,
+0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,
+0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,
+0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,
+0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,
+0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,
+0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,
+0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0f0f0e0e,
+0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,
+0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,
+0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,
+0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,
+0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,
+0x000f0f0f,0x01000000,0x03000200,0x01010003,0x03010201,0x02020102,0x01030302,0x03030203,
+0x03040204,0x05050506,0x09090909,0x09090906,0x03070506,0x060c0909,0x060c0906,0x00000a0b,
+0x00001212,0x0000120f,0x00070707,0x000c0c0c,0x000c0f06,0x03060606,0x0609090c,0x06090c06,
+0x00050808,0x00090c0f,0x00091206,0x04040404,0x06060404,0x0c0a0806,0x1c161210,0x362e2822,
+0x0000c036,0x04040404,0x06060404,0x0c0a0808,0x1c181410,0x36322a22,0x00009e4c,0x04040404,
+0x06060404,0x100c0a08,0x261e1814,0x5444382e,0x00001a66,0x04040404,0x04040404,0x04040404,
+0x06060606,0x0a0a0606,0x0c0c0c0a,0x100e0e0e,0x14141010,0x1a1a1a14,0x00424242,0x04040404,
+0x04040404,0x04040404,0x08060606,0x0a0a0808,0x0c0c0c0a,0x120e0e0e,0x16161212,0x1e1e1e16,
+0x00383838,0x04040404,0x04040404,0x04040404,0x08060606,0x0c0c0808,0x1010100c,0x1a141414,
+0x22221a1a,0x2a2a2a22,0x000c0c0c,0x04040404,0x06060404,0x06040404,0x06060606,0x0a0a0a06,
+0x0e0c0c0c,0x10100e0e,0x14141410,0x421a1a1a,0x00004242,0x04040404,0x06060404,0x06040404,
+0x08080606,0x0a0a0a08,0x0e0c0c0c,0x12120e0e,0x16161612,0x381e1e1e,0x00003838,0x04040404,
+0x06060404,0x06040404,0x08080606,0x0c0c0c08,0x14101010,0x1a1a1414,0x2222221a,0x0c2a2a2a,
+0x00000c0c,0x06060606,0x0a080606,0x12100e0c,0x26201a16,0x463e362e,0x0000244c,0x06060606,
+0x0a080606,0x14100e0c,0x26201c18,0x443c342e,0x0000363a,0x04040404,0x04040404,0x06060604,
+0x0a080808,0x0c0c0a0a,0x0e0e0e0c,0x18121212,0x20201818,0x2c2c2c20,0x000c0c0c,0x04040404,
+0x04040404,0x06060604,0x08060606,0x0a0a0808,0x0e0e0e0a,0x1a121212,0x20201a1a,0x2a2a2a20,
+0x00121212,0x04040404,0x04040404,0x06060604,0x0a080808,0x0c0c0a0a,0x0e0e0e0c,0x18121212,
+0x1e1e1818,0x2828281e,0x00121212,0x06060606,0x06060606,0x08080806,0x0c0a0a0a,0x0e0e0c0c,
+0x1212120e,0x20181818,0x2c2c2020,0x0c0c0c2c,0x06060606,0x06060606,0x06060606,0x0a080808,
+0x0e0e0a0a,0x1212120e,0x201a1a1a,0x2a2a2020,0x1212122a,0x06060606,0x06060606,0x08080806,
+0x0c0a0a0a,0x0e0e0c0c,0x1212120e,0x1e181818,0x28281e1e,0x12121228,0x0c0c0c0c,0x14100c0c,
+0x28201c18,0x4c403830,0x0202025a,0x00000202,0x08080808,0x08080808,0x0c0c0c08,0x14101010,
+0x18181414,0x1c1c1c18,0x02242424,0x02020202,0x02020202,0x001a1a1a,0x040c0c0c,0x08080404,
+0x0c0c0c08,0x14101010,0x18181414,0x1c1c1c18,0x02242424,0x02020202,0x02020202,0x001a1a1a,
+0x0001c90c,0x0001c954,0x0001c9cc,0x0001c924,0x0001c97c,0x0001c9f4,0x0001c93c,0x0001c9a4,
+0x0001ca1c,0x0001ca44,0x0001ca74,0x0001caec,0x0001ca5c,0x0001ca9c,0x0001cb10,0x0001ca5c,
+0x0001cac4,0x0001cb34,0x0001ca5c,0x0001cac4,0x0001cb34,0x0001ca5c,0x0001cac4,0x0001cb34,
+0x0001cb58,0x0001cb70,0x0001cb98,0x00000000,0x00000000,0x01000000,0x02010101,0x03030302,
+0x00000002,0x09837f05,0x0b504f33,0x0d744fcd,0x10000000,0x1306fe0a,0x16a09e66,0x1ae89f99,
+0x0db84a81,0x0e1b9d7f,0x0f31adcf,0x0fbba815,0x0feda417,0x0ffc8fc8,0x0fff964c,0x0ffff8d3,
+0xf7c4a019,0xf873c92e,0xfafc67ec,0xfd16e22f,0xfe7c9fc6,0xff583479,0xffc5d7b9,0xfff0d84c,
+0x09bd7ca0,0xf137ca18,0xfde95d5e,0x0fdcf549,0xf9e08756,0xf34e6cba,0xf34e6cba,0x061f78aa,
+0x0fdcf549,0x0216a2a2,0xf137ca18,0xf6428360,0x061f78aa,0xf137ca18,0x0ec835e8,0xf9e08756,
+0xf9e08756,0x0ec835e8,0xf137ca18,0xf9e08756,0x061f78aa,0x0ec835e8,0x0ec835e8,0x061f78aa,
+0x0216a2a2,0xf9e08756,0x09bd7ca0,0xf34e6cba,0x0ec835e8,0xf0230ab7,0xf0230ab7,0xf137ca18,
+0xf34e6cba,0xf6428360,0xf9e08756,0xfde95d5e,0x00b2aa3e,0x0216a2a2,0x03768962,0x04cfb0e2,
+0x061f78aa,0x07635284,0x0898c779,0x09bd7ca0,0x0acf37ad,0x0bcbe352,0x0cb19346,0x0d7e8807,
+0x0e313245,0x0ec835e8,0x0f426cb5,0x0f9ee890,0x0fdcf549,0x0ffc19fd,0x0ffc19fd,0x0fdcf549,
+0x0f9ee890,0x0f426cb5,0x0ec835e8,0x0e313245,0x0d7e8807,0x0cb19346,0x0bcbe352,0x0acf37ad,
+0x09bd7ca0,0x0898c779,0x07635284,0x061f78aa,0x04cfb0e2,0x03768962,0x0216a2a2,0x00b2aa3e,
+0x0216a2a2,0x061f78aa,0x09bd7ca0,0x0cb19346,0x0ec835e8,0x0fdcf549,0x0fdcf549,0x0ec835e8,
+0x0cb19346,0x09bd7ca0,0x061f78aa,0x0216a2a2,0x00000000,0x0361962f,0x05db3d74,0x08000000,
+0x0a24c28c,0x0c9e69d1,0x10000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000002,0x00000040,0x0000191c,
+0x00001940,0x00001964,0x00001988,0x00000000,};
+#elif defined(CONFIG_ARCH_EXYNOS5)
+/* vliw */
+static unsigned long srp_fw_vliw[] __devinitdata = {
+0xc278001d,0xc300021d,0x10920740,0x10900740,0x10924741,0xd1008b77,0x07800001,0x07000103,
+0x07000101,0x00400202,0xf0000003,0x07000103,0xf1000003,0x07000103,0xff000003,0x07000103,
+0x00528201,0x07000100,0x12828a09,0x00408a02,0x00528200,0xc1fffd2d,0x07000101,0x02928a2d,
+0x00408a01,0x10900081,0xc200f8fc,0x900000f8,0x900040fd,0xd20000c0,0x009000fc,0xc20100fd,
+0xc2f020f8,0x9001c01c,0x90008009,0xc32ffff8,0xc2f03008,0x0081c0fd,0x10900081,0xc200f8fc,
+0x900000f8,0x900040fd,0xd200008c,0x009000fc,0xc20100fd,0xc2f024f8,0x9001c01c,0x90008009,
+0xc32ffff8,0xc2f03008,0x0081c0fd,0x10900081,0xc200f8fc,0x900000f8,0x900040fd,0xd2000058,
+0x009000fc,0xc20100fd,0xc2f028f8,0x9001c01c,0x90008009,0xc32ffff8,0xc2f03008,0x0081c0fd,
+0x10900081,0xc200f8fc,0x900000f8,0x900040fd,0xd2000024,0x009000fc,0xc20100fd,0xc2f02cf8,
+0x9001c01c,0x90008009,0xc32ffff8,0xc2f03008,0x0081c0fd,0xc32fff08,0x9000c00c,0x90010011,
+0xc2f0340c,0xb8000208,0xb8003ef9,0x00510200,0xc32fff0c,0x90014015,0x10814080,0x90018018,
+0x90004005,0x00118400,0x90000520,0x90004525,0x12908208,0x90008528,0x9000c52d,0x00508300,
+0x90010530,0x90014535,0x00124000,0x90018538,0x9001c53d,0x00508000,0x10814580,0x90004709,
+0x00508100,0x90000710,0x90008709,0x00508400,0x00113e00,0x9000c709,0x0050bf00,0xb800030c,
+0x90010709,0x02818608,0x1081c760,0x90014709,0x00408600,0x90000540,0x90004545,0x10814540,
+0x90008548,0x9000c54d,0xe1000108,0x90000550,0x90004555,0xc2001808,0x90008558,0x9000c55d,
+0x04e0020c,0x9000001c,0x00120001,0x10808220,0x90010560,0x90014565,0x10814580,0x90018568,
+0x9001c56d,0xe00000cc,0x90000570,0x90004575,0x04e0020c,0x90008578,0x9000c57d,0x10808220,
+0x90010580,0x90014585,0x10814580,0x90018588,0x9001c58d,0xe000009c,0x90000590,0x90004595,
+0x04e0020c,0x90008598,0x9000c59d,0x10808220,0x900105a0,0x900145a5,0x10814580,0x900185a8,
+0x9001c5ad,0xe000006c,0x900005b0,0x900045b5,0x04e0020c,0x900085b8,0x9000c5bd,0x10808220,
+0x900105c0,0x900145c5,0x10814580,0x900185c8,0x9001c5cd,0xe000003c,0x900005d0,0x900045d5,
+0x04e0020c,0x900085d8,0x9000c5dd,0x10808220,0x900105e0,0x900145e5,0x10814580,0x900185e8,
+0x9001c5ed,0x00000000,0x900005f0,0x900045f5,0x07104400,0x00108003,0x00000000,0xc2f0340c,
+0x10910781,0xc32fff0c,0xb8008418,0xb801843d,0xc1001808,0xb800030c,0xb800c431,0x108140f0,
+0xb8010434,0xb8014439,0x00000000,0xb8004540,0xb8008545,0x10814550,0xb800c548,0xb801054d,
+0xe1000114,0xb8000550,0xb8004555,0x04e0020c,0xb8008558,0xb800c55f,0x00000001,0x10808220,
+0xb8010560,0xb8014565,0x10814580,0xb8018568,0xb801c56d,0xe00000e0,0xb8000570,0xb8004575,
+0x04e0020c,0xb8008578,0xb800c57f,0x00000001,0x10808220,0xb8010580,0xb8014585,0x10814580,
+0xb8018588,0xb801c58d,0xe00000ac,0xb8000590,0xb8004595,0x04e0020c,0xb8008598,0xb800c59f,
+0x00000001,0x10808220,0xb80105a0,0xb80145a5,0x10814580,0xb80185a8,0xb801c5ad,0xe0000078,
+0xb80005b0,0xb80045b5,0x04e0020c,0xb80085b8,0xb800c5bf,0x00000001,0x10808220,0xb80105c0,
+0xb80145c5,0x10814580,0xb80185c8,0xb801c5cd,0xe0000044,0xb80005d0,0xb80045d5,0x04e0020c,
+0xb80085d8,0xb800c5df,0x00000001,0x00000000,0xb80105e0,0xb80145e5,0x10814580,0xb80185e8,
+0xb801c5ed,0x00000000,0xb80005f0,0xb80045f7,0x00000001,0x00000000,0xb80085f8,0xb800c5fd,
+0x00000000,0x1080c080,0xb801c411,0x0040cc00,0xb8000320,0xb8004325,0x00400d00,0xb8008328,
+0xb800c32d,0x00404e00,0xb8010330,0xb8014335,0x00410f00,0xb8018338,0xb801c33d,0x004fc400,
+0xb8014014,0xb801c01d,0x00000000,0xb800c00c,0xb8010011,0x00000000,0xb8008008,0xb8018019,
+0x00000000,0xb8000000,0xb8004007,0x00000001,0xf2000003,0x10924941,0x1081c940,0x9000891d,
+0x10924741,0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,0x10924941,0x1081c940,
+0x9000891d,0x10924741,0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,0x10924941,
+0x1081c940,0x9000891c,0xc1002425,0x00924725,0x001e4201,0xe8000051,0x0490020c,0xc10000e1,
+0x120f0305,0xe800001d,0x04b039f0,0xc10001ed,0x108efb05,0x020e83ed,0xe8fffff9,0x04d039e9,
+0xc1ffffe9,0xc10001e8,0x008efbe9,0x020ec3ec,0x020ebaed,0x008e38e8,0x009e79ed,0xe8ffffc9,
+0x04f0390d,0xe8000011,0x14000401,0x00000000,0x900004e5,0x0011b801,0x1091c741,0x00000000,
+0xb800871d,0x07000102,0x10824741,0x10924941,0x1081c940,0x9000891c,0x9000c905,0x10900740,
+0x10924741,0xd1ffff5a,0xc1000011,0x1091c741,0x00000000,0xb800c704,0xb800871f,0x10824742,
+0x07000102,0x00100901,0x10924941,0x1081c940,0x9000891c,0x9000c905,0x10900771,0x10920740,
+0x90004920,0x10924771,0xd1ffff14,0xc1fffce1,0x008108e2,0xc1fffce1,0x00000000,0x034188e3,
+0x00000001,0x1091c741,0x00000000,0xb800c704,0xb8004723,0x00000001,0x00000000,0xb800871d,
+0x07000101,0x10824741,0x00100901,0x10924941,0x1081c940,0x9000891d,0x10924771,0xc28004e8,
+0xc28004e4,0xc10001e1,0xc30001e8,0xc30001e5,0x008e42e4,0x030182e9,0x00000000,0x800039e3,
+0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,0x1092497d,0x10924945,0x1081c97c,
+0x9000891c,0x9000c905,0x1081c744,0xc1005c25,0x00900724,0x00924725,0xc1ffece8,0xc1ffe8e0,
+0xc1ffe4e5,0xc1ffe0e0,0x034307e8,0x0342c7e1,0x00000000,0x034287e4,0x034fc7e3,0x00000001,
+0x109f4971,0x109f8950,0xc10000ec,0x109e8961,0xc10001f0,0x109e09a0,0x109e4981,0x109e8990,
+0x90003a2c,0x90003e31,0xd1000048,0xc10000e4,0x900039f1,0x109e09b0,0x90003d28,0x900038e5,
+0x00000000,0x90003aec,0x900038fd,0x1091c77d,0x1091c745,0x00000000,0xb800c704,0xb800871f,
+0x1082477e,0x07000101,0x10824945,0x00100901,0x1092497d,0x10924975,0x1081c97c,0x9000891c,
+0x9000c905,0x1081c774,0xc1007025,0x00900724,0x00924725,0x00000000,0x9001c06c,0x90020071,
+0x00000000,0x90014064,0x90018069,0x00000000,0x9000c05c,0x90010061,0x00000000,0x90004054,
+0x90008059,0x00000000,0x90000051,0xc1ffe4e8,0xc1ffe8e0,0xc1ffeced,0xc1ffd8e0,0x034687e0,
+0xc1ffe0e5,0xc1ffdce4,0x0346c7ec,0x034607e5,0xc1ffd4e0,0x034647e8,0x034547e1,0x00000000,
+0x0345c7e4,0x034507e2,0x00158201,0x00170401,0xe8000061,0x14100201,0xc1ffff19,0x1091c77d,
+0x1091c774,0xb8004055,0x00000000,0xb800c704,0xb8010061,0x00000000,0xb8000050,0xb800c05d,
+0x00000000,0xb801c06c,0xb8020071,0x00000000,0xb8008058,0xb8018069,0x1082477c,0xb8014064,
+0xb800871d,0x07000101,0x10824975,0x00100901,0xe8000039,0x14000301,0xe8000065,0x14000305,
+0xe800006d,0x14000315,0xe8000075,0x14000309,0xe800007d,0x1400030d,0xe8000099,0x14000311,
+0xd2ffff7e,0xc1ffff19,0xc10e00e1,0x00000000,0x900142e1,0xe80000a5,0x14000401,0xe8000099,
+0x14000405,0xe8000129,0x14000409,0xe8000129,0x1400040d,0xd2ffff4a,0xc1ffff19,0xd2ffffd8,
+0xc10d00e1,0x00000000,0x900142e2,0xd2ffffc8,0xc10c00e1,0x00000000,0x900142e2,0xd2ffffb8,
+0xc10f00e1,0x00000000,0x900142e2,0xc20c00e0,0x129e453d,0xc30400e0,0x120e7971,0xd2ffff98,
+0x001e3801,0x028e38e5,0x00000000,0x900142e1,0xc20c00e0,0x129e453d,0xc30200e0,0x120e7971,
+0xd2ffff74,0x001e3801,0x028e38e5,0x00000000,0x900142e1,0x12165905,0xd10008c8,0x00109403,
+0x109e1804,0x129e94f0,0x109e5905,0x120eb840,0x120e1740,0x028efa19,0x00000000,0x028e7ae4,
+0x028e3855,0x00000000,0x9000d6e4,0x900016ed,0xe800006c,0x9000566c,0x900116e1,0x14001400,
+0x90009669,0xc10001e1,0x129eb804,0xc20000e4,0x129e1c0d,0x120eba50,0xb80156e0,0xc30001e5,
+0x120e7838,0x028ebae4,0xc23000e1,0x00000000,0x028e7ae5,0xd2fffe48,0x00000000,0x028e79e1,
+0x028e38e5,0xc1000018,0x900156e1,0xd2ffff6e,0x12165909,0xd2ffff66,0x1216590d,0xd2ffffae,
+0xc10000e1,0x10924941,0x1081c940,0x9000891c,0x9000c905,0x10900770,0x10924771,0x00000000,
+0x90000050,0x90004055,0x00154200,0x00150301,0xc10000e1,0xe8000019,0x04c03809,0xe8000011,
+0x14c0021d,0xe8000035,0x14100301,0xc1ffff19,0x1091c741,0x00000000,0xb800c704,0xb800871f,
+0x10824741,0x00000000,0xb8004054,0xb8000051,0x07000102,0x00100901,0xd1000647,0xd1fffbf0,
+0x00109503,0xd1000488,0x00109500,0x0010d403,0xd2ffffc2,0xc1000019,0x10924941,0x1081c940,
+0x9000c904,0x9000891d,0xc1004824,0x90004920,0x10920741,0x00900724,0x00924725,0x00000000,
+0x90000050,0x90004055,0x00154201,0x109e0961,0xc1ffe0ec,0xc10000e4,0x109e8951,0x120e8508,
+0x90003a10,0x008088ed,0xd1fffbcc,0x109e0970,0x9000380d,0x109e0980,0x900038e8,0xc100000d,
+0xc1000210,0x900038e4,0xc1000015,0xe8000021,0x14100600,0x00150601,0xd1fffeec,0xc1ffe0e1,
+0x00109500,0x0080c8e2,0x00150601,0x00119401,0x1091c741,0x00000000,0xb800c704,0xb8004723,
+0x00000000,0xb8004055,0x00000000,0xb8000050,0xb800871d,0x07000101,0x10824741,0x00100901,
+0x10924941,0x1081c940,0x9000c904,0x9000891d,0xc1004824,0x90004920,0x10920741,0x00900724,
+0x00924725,0x00000000,0x90000050,0x90004055,0x00154201,0x109e0961,0xc1ffe0ec,0xc10000e4,
+0x109e8951,0x120e8508,0x90003a10,0x008088ed,0xd1fffb04,0x109e0970,0x9000380d,0x109e0980,
+0x900038e8,0xc100050d,0xc1000210,0x900038e4,0xc1000015,0xe8000021,0x14100600,0x00150601,
+0xd1fffe24,0xc1ffe0e1,0x00109500,0x0080c8e2,0x00150601,0x00119401,0x1091c741,0x00000000,
+0xb800c704,0xb8004723,0x00000000,0xb8004055,0x00000000,0xb8000050,0xb800871d,0x07000101,
+0x10824741,0x00100901,0x10924941,0x1081c940,0x9000c904,0x9000891d,0xc1004824,0x90004920,
+0x10920741,0x00900724,0x00924725,0x00000000,0x90000050,0x90004055,0x00154201,0x109e0961,
+0xc1ffe0ec,0xc10000e4,0x109e8951,0x120e8508,0x90003a10,0x008088ed,0xd1fffa3c,0x109e0970,
+0x9000380d,0x109e0980,0x900038e8,0xc100010d,0xc1000210,0x900038e4,0xc1000015,0xe8000021,
+0x14100600,0x00150601,0xd1fffd5c,0xc1ffe0e1,0x00109500,0x0080c8e2,0x00150601,0x00119401,
+0x1091c741,0x00000000,0xb800c704,0xb8004723,0x00000000,0xb8004055,0x00000000,0xb8000050,
+0xb800871d,0x07000101,0x10824741,0x00100901,0x10924941,0x1081c940,0x9000891d,0x10924751,
+0xc2f000e1,0xc3000fe1,0x00000000,0xb800381b,0x00000001,0x1091c741,0x00000000,0xb800871d,
+0x07000102,0x10824741,0x10924941,0x1081c940,0x9000891d,0x10924761,0xc2f000e0,0xc2f000e5,
+0xc3000fe0,0xc3000fe5,0x00000000,0xb8003819,0x00000000,0x9000390b,0x1091c741,0x00000000,
+0xb800871d,0x07000102,0x10824741,0x10924941,0x1081c940,0x9000891c,0xc1002425,0x00924725,
+0x001e0200,0x001f0301,0x00000000,0xa00038ec,0xa0003ceb,0x00000001,0x009e7be9,0xe8000021,
+0x14103900,0x108f3c04,0x108e3805,0xe8000011,0x14003b01,0xe8ffffd5,0x14103a01,0x0011b901,
+0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,0x10924941,0x1081c940,0x9000891d,
+0x10924771,0x00000000,0xa00002e3,0x00000001,0xe800002d,0x14003800,0xc10000e8,0x001e4201,
+0x00000000,0xa00079e3,0x00000001,0xe8fffff5,0x14103800,0x108eba04,0x108e7905,0x0011ba01,
+0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,0x10924941,0x1081c940,0x9000891d,
+0x10924771,0x00000000,0xa00003e3,0x00000001,0xe8000034,0x800002e1,0x14003800,0x108e8304,
+0x108e4205,0x00000000,0xa0003ae3,0x00000001,0xe8fffff4,0x800039e1,0x14103800,0x108eba04,
+0x108e7905,0x00118201,0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,0x10924941,
+0x1081c940,0x9000891c,0xc1002025,0x00924725,0x001ec200,0x001e8301,0xe800003d,0x14000401,
+0x109e4405,0x00000000,0xa0003ae3,0x00000001,0xe8000024,0x80003be1,0x14003800,0x108eba04,
+0x108efb05,0xc1ffffe1,0x008e79e1,0xe8ffffd9,0x141039fd,0x00118201,0x1091c741,0x00000000,
+0xb800871d,0x07000102,0x10824741,0x10924941,0x00000000,0x9000891d,0x1081c940,0x9000c904,
+0xc1002c25,0x00900724,0x00924725,0x00000000,0x90000050,0x90004055,0x00154200,0x00150301,
+0xc28004e0,0xc10101e4,0xc21118e9,0xd10002d4,0xc3000fe8,0xc30001e1,0xc10001e0,0x008e42e0,
+0x020ef909,0x00108300,0x90003aec,0x800039e1,0xc21000e0,0x129e54f0,0x120ed515,0xc21000e8,
+0xc3000fe0,0x028f3919,0xc3000fe8,0xc10003e0,0x008e7be1,0x008e7be8,0x900039f1,0x00000000,
+0x900179e1,0x1091c741,0x00000000,0xb800c704,0xb800871f,0x10824741,0x00000000,0xb8004054,
+0xb8000051,0x07000102,0x00100901,0x10924941,0x1081c940,0x9000891c,0xc1002c25,0x00924725,
+0x001e4201,0xc28004e8,0xc10100e1,0xc30001e8,0x020e3809,0x00000000,0x030e82eb,0x00000001,
+0xe80000a9,0x14003a01,0xc21110e9,0xc3000fe9,0x00000000,0xb8003aeb,0x00000001,0xc10000e8,
+0x029efae1,0xe8000031,0x04103aed,0xc21110f1,0xc3000ff1,0x001f3c01,0x00000000,0xb8003ceb,
+0x00000001,0xc10000e8,0x029efae1,0xe8ffffed,0x04003aed,0xc21000f0,0xc10014ec,0x120f7915,
+0xc3000ff0,0xc21118f8,0xc10000e9,0xc3000ff8,0x008efbf1,0x00000000,0x90003ee0,0x034e3bf7,
+0x00000001,0x129e3805,0xe8000021,0x04103ae1,0xc28004e8,0xc10000e1,0xc30001e9,0x008e79e9,
+0x00000000,0x800039e1,0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,0x10924941,
+0x1081c940,0x9000891c,0xc1002025,0x00924725,0x001ec201,0xc21000e4,0x120e8215,0xc10014e0,
+0xc3000fe5,0x008e78e5,0x00000000,0x034e39eb,0x00000001,0x129e3805,0xe8000021,0x14003801,
+0x00000000,0x034e39eb,0x00000001,0x129e3805,0xe8fffff1,0x14103801,0xc28004e4,0xc10000e1,
+0xc30001e5,0x008e7be5,0x00000000,0x800039e1,0x1091c741,0x00000000,0xb800871d,0x07000102,
+0x10824741,0x10924941,0x1081c940,0x9000891d,0x10924741,0x00000000,0xa800021b,0x00000001,
+0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,0x10924941,0x1081c940,0x9000891d,
+0x10924741,0x00000000,0x8400020d,0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,
+0x10924941,0x1081c940,0x9000891d,0x10924741,0x00000000,0xb800021b,0x00000001,0x1091c741,
+0x00000000,0xb800871d,0x07000102,0x10824741,0x10924941,0x1081c940,0x9000891d,0x10924741,
+0x00000000,0x9000020d,0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,0x10924941,
+0x1081c940,0x9000891d,0x10924741,0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,
+0x10924941,0x1081c940,0x9000891d,0x10924761,0xc20000e1,0xc30000e1,0xe8000019,0x04c03808,
+0xc10000e5,0xc28000e1,0xc30002e1,0x018e42e1,0xc10000e1,0x0101b8e5,0x1091c741,0x00000000,
+0xb800871d,0x07000102,0x10824741,0x10924941,0x1081c940,0x9000891d,0x10924761,0xc20020e0,
+0xc1000119,0xc30383e1,0xc10080e0,0x001e7801,0x00000000,0x900039e1,0x1091c741,0x00000000,
+0xb800871d,0x07000102,0x10824741,0x10924941,0x1081c940,0x9000891d,0x10924761,0xe8000039,
+0x14100205,0xc10001e1,0xc20020e0,0x120e781d,0xc30383e1,0x001e3801,0x00000000,0x900038e5,
+0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,0xd2ffffd6,0xc10000e1,0x10924941,
+0x1081c940,0x9000891c,0xc1002025,0x00924725,0xe8000045,0x14100205,0xc10001ed,0x120ebb18,
+0x120e7b14,0xc20020e1,0xc30383e0,0x028e7ae5,0x001e3800,0x028e79ed,0x00000000,0x900038e5,
+0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,0xd2ffffca,0xc10000ed,0x10924941,
+0x1081c940,0x9000891c,0xc1002425,0x00924725,0xe8000099,0x14100505,0xc10001e1,0xc20000e0,
+0xc20024e4,0x120eb81d,0xc30300e0,0xc30383e4,0xc20040ed,0x001e7800,0xc10040e0,0x001f3901,
+0xc30383ec,0x028e79e8,0xc20028e9,0xc10020f0,0x90003c08,0x028e39e1,0x001efb00,0x121e4408,
+0xc30383e9,0xc20020ec,0x90003b0c,0x028e38f1,0x120e7940,0x001e3a00,0x128eb821,0xc30383ec,
+0x900038e4,0x128e7a05,0x001e3b01,0x00000000,0x900038e5,0x1091c741,0x00000000,0xb800871d,
+0x07000102,0x10824741,0xd2ffff76,0xc10000e1,0x10924941,0x00000000,0x9000891d,0x1081c940,
+0x9000c904,0xc1002025,0x00900724,0x00924725,0x00000000,0x90000050,0x90004055,0x00154300,
+0x00150401,0xd1ffebff,0xe8000061,0x14001501,0xc2f030e4,0xc10001e1,0xc32fffe5,0x00000000,
+0x900039e1,0x108e540c,0xc2f034e1,0x121e7908,0xc32fffe1,0x120e7909,0x00000000,0x900038e5,
+0x1091c741,0x00000000,0xb800c704,0xb800871f,0x10824741,0x00000000,0xb8004054,0xb8000051,
+0x07000102,0x00100901,0xd2ffffbc,0xc2f030e5,0xc32fffe4,0xc10000e1,0x00000000,0x900039e1,
+0x10924941,0x1081c940,0x9000891d,0x10924751,0xc2f020e1,0xc32fffe1,0x00000000,0x90003809,
+0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,0x10924941,0x1081c940,0x9000891d,
+0x10924751,0xc2f024e1,0xc32fffe1,0x00000000,0x90003809,0x1091c741,0x00000000,0xb800871d,
+0x07000102,0x10824741,0x10924941,0x1081c940,0x9000891d,0x10924751,0xc2f028e1,0xc32fffe1,
+0x00000000,0x90003809,0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,0x10924941,
+0x1081c940,0x9000891d,0x10924751,0xc2f02ce1,0xc32fffe1,0x00000000,0x90003809,0x1091c741,
+0x00000000,0xb800871d,0x07000102,0x10824741,0x10924941,0x1081c940,0x9000891d,0x10924741,
+0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,0x10924941,0x1081c940,0x9000891d,
+0x10924741,0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,0x10924941,0x1081c940,
+0x9000891d,0x10924741,0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,0x10924941,
+0x1081c940,0x9000891d,0x10924741,0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,
+0x10924941,0x1081c940,0x9000c904,0x9000891d,0xc1004c24,0x90004920,0x10920741,0x00900724,
+0x00924725,0xc20074e5,0xe80000d0,0xc10001e0,0xc3000fe5,0x14100200,0x900039e1,0xc20120ec,
+0xc20000e4,0x109e8871,0xc30382ec,0xc30004e4,0x109e0861,0x00000000,0xb8003be0,0x900038e6,
+0xd1fffba2,0xc1000008,0x90003ae1,0xc20023e8,0xc20100e4,0xc2be80e1,0xc300ffe8,0xc30090e4,
+0xc30001e1,0x109f8880,0x001f7a00,0x109f0851,0x001ef900,0x109e8840,0x001e7801,0x109e0830,
+0x90003cf4,0x90003e19,0x00000000,0x900038e4,0x90003aed,0xd1fff330,0xc1ffe0e1,0x00000000,
+0x0080c8e1,0xc1000009,0xd1fff9d6,0xc1000009,0x1091c741,0x00000000,0xb800c704,0xb8004723,
+0x00000001,0x00000000,0xb800871d,0x07000101,0x10824741,0x00100901,0xc20100ec,0xc20000e4,
+0x109e8871,0xc30382ec,0xc30004e4,0x109e0861,0x00000000,0xb8003be0,0x900038e6,0xd1fffae6,
+0xc1000008,0x90003ae1,0xc2be80e1,0xc20023e4,0xc30001e0,0xc20100e9,0xc300ffe4,0x109f0850,
+0xc30090e9,0x109f4880,0x001e7800,0x001e3901,0xd2ffff64,0x109e8840,0x001efa01,0x109e0830,
+0x90003ce0,0x90003d19,0x00000000,0x900038e4,0x90003aed,0x10924941,0x1081c940,0x9000c904,
+0x9000891d,0xc1005c24,0x90004920,0x10920741,0x00900724,0x00924725,0x00000000,0x9000c05c,
+0x90010061,0x00000000,0x90004054,0x90008059,0x00000000,0x90000051,0xc28004e4,0xc1000061,
+0xc30001e5,0x001e7901,0x10861804,0xc10000e1,0xe8fffff8,0x800039e1,0x14801820,0x108e7905,
+0xc2601cec,0xc103ffe8,0xc103ffe5,0xc30002ec,0xc21100f0,0xc10000e1,0xc3000ff0,0x008efbe8,
+0xc10001e9,0x122ebb7c,0x90003ce9,0x00000000,0x029e7ae5,0x008e7be5,0x1225f929,0xe800009d,
+0x04e0385c,0xc1000061,0xc2000050,0xc2011858,0xc1000055,0xc3000050,0xc3038259,0x00151401,
+0xc1ffe0e0,0xb80016e8,0x109f4951,0x109f0960,0xc10400ec,0x109e8971,0xc10000e4,0x109e0980,
+0x008088e1,0xd1ffee30,0x90003aec,0xc100000d,0xc1000210,0x90003c50,0x008e95e9,0xc1000014,
+0x900038e4,0x90003de9,0xd1fff15c,0xc1ffe0e1,0x00000000,0x0080c8e1,0xc1000009,0x10861804,
+0xc10400e4,0xc10400e1,0xe8ffff98,0x008514e0,0x008555e5,0x0480185d,0x1091c741,0x00000000,
+0xb800c704,0xb8008059,0x00000000,0xb800c05c,0xb8010062,0x00000000,0xb8004054,0xb8000051,
+0x00000000,0xb800871c,0xb8004721,0x07000101,0x10824741,0x00100901,0x10924941,0x1081c940,
+0x9000891d,0x10924741,0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,0x10924941,
+0x1081c940,0x9000891c,0xc1002825,0x00924725,0xc28014f4,0xc28018ec,0xc28010e5,0xc30001f4,
+0xc30001ed,0xc10000f0,0xc10000e0,0xc10000e9,0xc30001e4,0x90003be8,0x90003df1,0xc1000018,
+0x800039e1,0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,0x10924941,0x00000000,
+0x9000891d,0x1081c940,0x9000c904,0xc1003025,0x00900724,0x00924725,0x00000000,0x90000050,
+0x90004055,0x00154200,0x00150401,0xe80000f9,0x14100505,0xc28028e4,0xc10001e1,0xc30001e5,
+0x00000000,0x840039e1,0xc28020e0,0xc28018e8,0xc28024e5,0xc30001e0,0xc30001e8,0xc30001e5,
+0xc29ef4e0,0xb80038e0,0xc2801ced,0xc30001e0,0xb8003aec,0xb80039e1,0xc30001ec,0xb80038e0,
+0xc28020e9,0xc28018e4,0xb8003bf4,0xc30001e9,0x122f3805,0x120f3c04,0x00000000,0x008efbe1,
+0xd1001e9c,0x00000000,0xc30001e5,0xc10000e0,0x0080bdf0,0x009efbe1,0x0010fb00,0x90003aec,
+0x900039e1,0xc28020e8,0xc28018e4,0xc28018e1,0xc30001e8,0xc30001e4,0xc30001e1,0x00000000,
+0xb8003ae8,0xb80039e7,0x00000001,0x008e79e9,0x00000000,0x900038e5,0xc1000019,0x1091c741,
+0x00000000,0xb800c704,0xb800871f,0x10824741,0x00000000,0xb8004054,0xb8000051,0x07000102,
+0x00100901,0xc28028e1,0xc30001e1,0x00000000,0xa80038e3,0x00000001,0xe8000089,0x14103801,
+0xc2001ce0,0xc28020e9,0xc30382e0,0xb80102f0,0xc30001e9,0x00000000,0xb80038e1,0xc1ff9fec,
+0xc10001e0,0xc28028e5,0xc30001e4,0x00000000,0xc100000d,0x129e7c0c,0x840039e0,0xc1000711,
+0x120e3914,0x029e78ec,0xc1000115,0x028eb9e0,0x90003ae5,0x00000000,0xb80142e7,0xc2ffffe1,
+0x029e39e1,0xd1007328,0xc2001ce0,0x120e7839,0xc30382e0,0x028e7ae5,0xc1000408,0x900038e5,
+0x00000000,0xb80255e4,0xb8039509,0x00115400,0xb802d511,0xd1001a88,0xc28024e1,0xc30001e1,
+0x0010f900,0x900038e5,0xc28018e4,0xc29ef4e0,0xc28024ed,0xc30001e4,0xc30001e0,0xc2801ce9,
+0xc2dcc8e0,0xb80039e8,0xb80038e1,0xc30001ec,0xc30001e8,0xc30001e1,0x00000000,0x90003ae0,
+0x90003b1a,0x008e7a19,0xe8000095,0x04b039e1,0xc28020e0,0x009e78e9,0xe800006c,0xc30001e1,
+0x14a03900,0x900038e5,0xc2801ce0,0x0010f901,0xc30001e1,0x00000000,0xb8003809,0xd1001ce3,
+0xc28010ec,0xc29ef4e0,0xc1ffffe9,0xc30001ec,0xc30001e0,0xc28010e5,0x00000000,0xa0003be0,
+0xb800380b,0x00000001,0xd1008f64,0x02ae3ae1,0xc30001e4,0x129e3805,0x00000000,0x800039e1,
+0xd2fffdab,0xd2ffffbc,0xc28020e5,0xc30001e4,0xc10000e1,0x00000000,0x900039e1,0xc28024e0,
+0xc2dcc809,0xc30001e0,0xc3000109,0x00000000,0xb800380d,0xd1001c6b,0xc28024e8,0xc28018e4,
+0xc28018e1,0xc30001e8,0xc30001e4,0xc30001e1,0x00000000,0xb8003ae8,0xb80039e7,0xd2fffdfd,
+0x008e79e9,0x00000000,0x900038e5,0x10924941,0x00000000,0x9000891d,0x1081c940,0x9000c904,
+0xc1002025,0x00900724,0x00924725,0xc28018e1,0xc30001e1,0x00000000,0xb80038e3,0x00000001,
+0x121e3809,0xe8000049,0x14a03801,0xc28010ec,0xc28018e0,0xc1ffffe9,0xc30001ec,0xc30001e0,
+0xc28010e5,0x00000000,0xa0003be0,0xb800380b,0x00000001,0xd1008e78,0x02ae3ae1,0xc30001e4,
+0x129e3805,0x00000000,0x800039e1,0xc1000019,0x1091c741,0x00000000,0xb800c704,0xb800871f,
+0x10824742,0x07000102,0x00100901,0x10924941,0x00000000,0x9000891d,0x1081c940,0x9000c904,
+0xc1002425,0x00900724,0x00924725,0x00000000,0x90000050,0x90004055,0x00154200,0x00150301,
+0xd1001d18,0xc10000e0,0xc10000e5,0x00000000,0x900202e0,0x9001c2e5,0xc1000b0c,0x10808371,
+0xd1001dc8,0x10809472,0xc100010d,0xe8000021,0x14100601,0x00000000,0xb801d5e7,0xc24000e1,
+0x028e39e1,0x00000000,0x9001d5e1,0xd1001d9c,0x10809472,0xc100010d,0xe8000079,0x14100601,
+0x00000000,0xb801d5e7,0xc21000e1,0x028e39e1,0x00000000,0x9001d5e1,0xd1001d70,0x10809472,
+0xc100020d,0xc10004e1,0x009e3819,0xe8000070,0x900015e1,0x14103811,0xc11005e0,0xc1ffff19,
+0x00000000,0x9003d4e1,0x1091c741,0x00000000,0xb800c704,0xb800871f,0x10824741,0x00000000,
+0xb8004054,0xb8000051,0x07000102,0x00100901,0x00000000,0xb801d5e7,0xc24000e1,0x029e39e1,
+0xe8ffff99,0x14003801,0xd2ffffc0,0xc11004e1,0x00000000,0x9003d4e1,0xc1ffff19,0xd1001cec,
+0x10809472,0xc100010d,0xe8000031,0x14100601,0x00000000,0xb801d5e0,0x10809473,0xd1001e3d,
+0x128e3841,0xc100100c,0x9001d5e0,0xc2ffff11,0x00000000,0x84031519,0xd1001cb0,0x10809472,
+0xc100040d,0xe800001d,0x1410063d,0xd2ffff5c,0xc11006e1,0x00000000,0x9003d4e1,0xc1ffff19,
+0x00000000,0xb801d5e7,0xc21000e1,0x029e39e1,0xe8000071,0x14003801,0x00000000,0xb80015e3,
+0x00000001,0x122e3805,0xc1003ce0,0x108e780d,0xc28320e0,0x060e79e1,0xc30001e1,0x120e0608,
+0x008e79e1,0x00000000,0x034e39e3,0x00000001,0x00000000,0x900115e1,0xd1001c30,0x10809472,
+0xc100020d,0xe8000059,0x1410060d,0xd2fffedc,0xc11007e1,0x00000000,0x9003d4e1,0xc1ffff19,
+0x00000000,0xb80015e3,0x00000001,0xc1003ce0,0x109e7805,0xc28320e0,0x060e79e1,0xc30001e1,
+0x120e0608,0x008e79e1,0x00000000,0x034e39e2,0xd2ffffaa,0x00000000,0x900115e1,0xc2844ce0,
+0xb801d5e4,0x120e4609,0xc30001e1,0x00000000,0x034e79e1,0xc21000e1,0x029e39e1,0xe8000039,
+0x14003800,0x900155e5,0x121eb904,0xb801d5e5,0x00000000,0x900155ea,0xc24000e1,0x029e39e1,
+0xe8000015,0x14003801,0x121e3a05,0x00000000,0x900155e1,0xd1001b74,0x10809472,0xc100010d,
+0xe8000021,0x14000601,0x00000000,0xb801d5e7,0xc10080e1,0x028e39e1,0x00000000,0x9001d5e1,
+0xd1001b48,0x10809472,0xc100010d,0xe8000021,0x14000601,0x00000000,0xb80215e7,0xc10100e1,
+0x028e39e1,0x00000000,0x900215e1,0xd1001b1c,0x10809472,0xc100020d,0xd1001b10,0xc10003e1,
+0x009e3819,0xc100020c,0x900055e0,0x10809471,0xd1001af9,0x00000000,0x90009518,0x10809471,
+0xc100010d,0xe8000021,0x14000601,0x00000000,0xb801d5e7,0xc10020e1,0x028e39e1,0x00000000,
+0x9001d5e1,0xd1001ac4,0x10809472,0xc100010d,0xe8000021,0x14000601,0x00000000,0xb801d5e7,
+0xc10040e1,0x028e39e1,0x00000000,0x9001d5e1,0xd1001a98,0x10809472,0xc100020d,0x00000000,
+0xb801d5e0,0x9000d51b,0x00000001,0x129e3841,0xe800001d,0x14003801,0xd1001a70,0x10809472,
+0xc100100d,0x00000000,0x84035519,0xd2fffd1e,0xc1000019,0x10924941,0x1081c940,0x9000c904,
+0x9000891d,0xc100a824,0x90004920,0x10920741,0x00900724,0x00924725,0x00000000,0x90010060,
+0x90014065,0x00000000,0x90008058,0x9000c05d,0x00000000,0x90000050,0x90004055,0x00154200,
+0x00158301,0x00000000,0xb801c2e7,0x109e0821,0x00000000,0x900038e5,0x00000000,0xb80202e7,
+0x109e0811,0x00000000,0x900038e5,0x00000000,0xb801c3e7,0xc10080e1,0x029e39e1,0xe8000411,
+0x14003800,0xc1000051,0xc1000161,0x00000000,0xb80003e3,0x00000001,0xe8000015,0x1410380c,
+0xc10000e9,0xc21000e1,0x029eb9e1,0xe80003e9,0x14003a01,0xc100485d,0xd100835b,0xe800032d,
+0x14100601,0xc103e8e0,0x120e9808,0xc10004e5,0xc10001e0,0x0615d7e0,0x009679e9,0x00963861,
+0xc1ffb8e4,0xb80015e4,0xc10048e1,0x00000000,0x0080c8e6,0x009e08e1,0x00000000,0x900038e5,
+0x00000000,0xb80055ea,0xc10044e1,0x009e48e0,0x00000000,0xc1ff94e1,0x00000000,0x900039e8,
+0x008088e1,0x00000000,0xb80095e6,0xc10040e1,0x009e08e1,0x00000000,0x900038e5,0x00000000,
+0xb800d5e7,0x109e08f1,0x00000000,0x900038e5,0x00000000,0xb80115e7,0x109e08e1,0x00000000,
+0x900038e5,0x00000000,0xb80155e7,0x109e08d1,0x00000000,0x900038e5,0x00000000,0xb80195e7,
+0x109e08c1,0x00000000,0x900038e5,0x00000000,0xb801d5e7,0x109e08b1,0x00000000,0x900038e5,
+0x00000000,0xb80215e7,0x109e08a1,0x00000000,0x900038e5,0x00000000,0xb80255e7,0x109e0891,
+0x00000000,0x900038e5,0x00000000,0xb80295e7,0x109e0881,0x00000000,0x900038e5,0x00000000,
+0xb802d5e7,0x109e0871,0x00000000,0x900038e5,0x00000000,0xb80315e7,0x109e0861,0x00000000,
+0x900038e5,0x00000000,0xb80355e7,0x109e0851,0x00000000,0x900038e5,0x00000000,0xb80395e7,
+0x109e0841,0x00000000,0x900038e5,0x00000000,0xb803d5e7,0x109e0831,0x00000000,0x900038e5,
+0x00000000,0xb80016e6,0xc1006ce1,0x009e08e1,0x00000000,0x900038e5,0x00000000,0xb80056e6,
+0xc10068e1,0x009e08e1,0x00000000,0x900038e5,0x00000000,0xb80096e6,0xc10064e1,0x009e08e1,
+0x00000000,0x900038e5,0x00000000,0xb800d6e6,0xc10060e1,0x009e08e1,0x00000000,0x900038e5,
+0x00000000,0xb80116e6,0xc1005ce1,0x009e08e1,0x00000000,0x900038e5,0x00000000,0xb80156e6,
+0xc10058e1,0x009e08e1,0x00000000,0x900038e5,0x00000000,0xb80196e6,0xc10054e1,0x009e08e1,
+0x00000000,0x900038e5,0x00000000,0xb801d6e6,0xc10050e1,0x009e08e1,0x00000000,0x900038e5,
+0x00000000,0xb80216e6,0xd1fff924,0xc1004ce1,0x009e08e1,0x00000000,0x900038e5,0xc1ff94e0,
+0xb80016e5,0xc1ffa8e0,0x034e88e0,0xb80156e1,0x00000000,0x034e48e3,0x110ec600,0x00000000,
+0x010ebae5,0x010e39e0,0x029e7be9,0x029e39e1,0xe800007d,0x14003801,0xd10015c8,0x10809573,
+0x00000000,0xb80016e0,0xb80155e7,0x00000001,0xe800012d,0x14103804,0x009506e5,0x00000000,
+0xb80156e4,0x008e1953,0x00000001,0x00000000,0x061539e1,0xc10000e1,0xe8000025,0x04d03850,
+0xc10000e9,0xc10000e5,0xc2bb80e1,0x008e79e1,0xe8fffff9,0x04b03950,0x108eba05,0xc1ffffe1,
+0x00853ae1,0xe8000025,0x14f01421,0xd10015ac,0x10809572,0xc100080d,0xd1008038,0x00109503,
+0xe8fffd01,0x14000601,0xc1fff8e1,0x00000000,0x034e08e3,0x00000001,0xc1fffce0,0x9001d5e1,
+0x00000000,0x034e08e3,0xe800002d,0x14901420,0x900215e1,0x00000000,0xb80016e3,0x00000001,
+0xe80000cd,0x1410380d,0xc10280e1,0xe80000c1,0x04b014e1,0xc11004e0,0xc1ffff19,0x00000000,
+0x9003d5e1,0x1091c741,0x00000000,0xb800c704,0xb8008059,0x00000000,0xb8004055,0x00000000,
+0xb8014064,0xb8004721,0x00000000,0xb8000050,0xb8010061,0x00000000,0xb800c05c,0xb800871d,
+0x07000101,0x10824741,0x00100901,0xd2fffc02,0xc1000061,0xd2fffc26,0xc100905d,0x00000000,
+0xb80156e4,0x008e1853,0x00000001,0x00000000,0x061539e1,0xc10000e1,0xe8000029,0x04d03850,
+0xc10000e9,0xc10000e1,0x00000000,0x00000000,0x008e385d,0xe8fffff5,0x04b03850,0x108eba05,
+0xd2fffee4,0xc1ffffe1,0x00853ae2,0xc103e8e0,0xc1000019,0xd2ffff50,0x061e14e2,0x00000000,
+0x900115e1,0x10924941,0x1081c940,0x9000891c,0xc1005025,0x00900724,0x00924725,0x00000000,
+0x90000050,0x90004055,0x00000000,0xa40202e4,0xac0082eb,0xc100d2e1,0x129e3908,0x0093bae1,
+0xe80000d1,0x14003801,0xc1000255,0x00000000,0xa40242e3,0x00000001,0xe80000c9,0x14103809,
+0x129e3921,0xe8000035,0x14003800,0xc1000050,0xc100004d,0x129e3911,0xe80000a1,0x14003801,
+0xc1ffff35,0xc24c202c,0xc1000029,0x10830248,0xc300022d,0xd60120ea,0x00000000,0xa40342e8,
+0xa40382e5,0x00000000,0xa403c2e5,0xc10240e1,0xea000041,0x120efa0c,0x00000000,0x120eb90d,
+0x120e790c,0x00944ee8,0x00948eed,0x04f014e0,0x00940ee5,0x10835304,0x10831308,0x1083c249,
+0x12039308,0x1202cd08,0x12028c09,0xd6016112,0x1091c740,0xb8004055,0x00000000,0xb8000050,
+0xb800871d,0x07000101,0x10824741,0x00100901,0xd2ffff3e,0xc1000155,0xd2ffff6e,0xc1000035,
+0x129e3911,0xe8000025,0x14003801,0xc24c202c,0x10830249,0xc100004c,0xc1000028,0xc300022d,
+0xd6002142,0xd2ffffaf,0xc100004c,0x1082c248,0xc1000029,0xd600214a,0xd2ffff9b,0x10924941,
+0x1081c940,0x9000891c,0xc1003425,0x00924725,0x192e4300,0xc10400e0,0x118ec301,0xe80000a4,
+0x122e7908,0x129eb90d,0x04f002e0,0x0992bbe8,0x099ffbe5,0xc24494e0,0xc23488e4,0x120e8209,
+0xc30002e0,0xc30002e5,0x00000000,0x031e02e0,0x034fbae7,0x00000001,0x008fffe1,0xe80000e1,
+0x14e03f01,0xc10000e4,0x11ce3f81,0x009ef9fd,0xc10001e4,0x109ebb05,0x020e79e9,0x008e7ee5,
+0x022ef9ed,0x09bfb8ed,0x108e4a0c,0xc24c38e1,0x120e7908,0xc30002e1,0x00000000,0x034e39e3,
+0x00000001,0x00000000,0x21c1bee2,0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,
+0x121f420c,0xc24494e4,0xc24494e1,0xc23488ec,0x108ebd04,0xc30002e5,0xc30002e0,0x120f3d08,
+0xc30002ed,0xc23488e0,0x031e3ae0,0x031e7de5,0x120e7a08,0x034e7cec,0xc30002e1,0x00000000,
+0x034e79e2,0x108e3910,0x00000000,0x011ef9e1,0x008e38ec,0x00000000,0x022eb9ed,0x129e021c,
+0x009e79e8,0x008fffe1,0x00000000,0x061e39e1,0xd2ffff2d,0x122e380d,0x008fbae1,0xc2ffffe0,
+0x11ee7f14,0x020efefd,0xc37fffe1,0x001e3801,0xd2ffff38,0x009e38ed,0x09be39e1,0x008fb8ed,
+0x10924941,0x00000000,0x9000891d,0x1081c940,0x9000c904,0xc1003425,0x00900724,0x00924725,
+0x00000000,0x90000051,0x00150301,0xd100125f,0x109fd404,0xc10001e0,0x109e5409,0xc231f0e0,
+0x020ef8fc,0xc10000f1,0x02af86ec,0xc20000e8,0x120e7909,0xc30002e0,0x029f7eec,0xc1001ded,
+0xc31000e8,0x034e39e0,0x009e3cf5,0x001e3a00,0x028ebee0,0x009e7b51,0x022e38fc,0x020e7ae5,
+0x008e79e1,0x00000000,0x21c1b9e2,0x1091c741,0x00000000,0xb800c704,0xb800871f,0x10824741,
+0x00000000,0xb8000051,0x07000102,0x00100901,0x10924941,0x1081c940,0x9000c904,0x9000891d,
+0xc1005424,0x90004920,0x10920741,0x00900724,0x00924725,0x00000000,0x90008058,0x9000c05d,
+0x00000000,0x90000050,0x90004055,0x00150200,0x00154300,0x0015c401,0x00000000,0xb800435b,
+0x00000001,0xe8000139,0x14001601,0x00000000,0xb800830d,0xd1001177,0x109e8840,0xc1fff4e4,
+0xc1fff0e1,0x008108e4,0x90003a19,0x008148e0,0xb8001552,0xd1004ebe,0x00108600,0x0010d401,
+0xc1fff0e8,0xc1fff8e4,0xc1fff0e1,0x008148e0,0x034088e8,0x008108e5,0xd1004e9a,0x0010d401,
+0xc1fff0e8,0xc1fffce4,0xc1fff0e1,0x008148e0,0x034088e8,0x008108e5,0xd1004e7a,0x0010d401,
+0xc1ffffe0,0xc10001e5,0xc1001de0,0x008e96e0,0xc1000029,0xc1fff4e0,0x009f7858,0x020fb9e9,
+0x008fc8e0,0x001ed700,0xc10000f1,0x00000000,0x00000000,0x034e3ff3,0x00000001,0x02aeb8f9,
+0xc10000e0,0xb80115e0,0x029e7af9,0x009e38e4,0xb800d5e1,0x028e3ae1,0x020e78f5,0x008e79e1,
+0x10828a04,0x00000000,0x21ce39e1,0xe8ffffc0,0x108f3c11,0x14900a0c,0x108efb10,0x90003be1,
+0x1091c741,0x00000000,0xb800c704,0xb8008059,0x00000000,0xb800c05c,0xb8004722,0x00000000,
+0xb8004055,0x00000000,0xb8000050,0xb800871d,0x07000101,0x10824741,0x00100901,0x00000000,
+0xb800835a,0xd1001046,0x0010d601,0xd100103c,0x109e0831,0x0010d600,0x90003818,0x00109402,
+0xd1001028,0x109e0821,0x0010d600,0x90003818,0x00109402,0xd2ffff0c,0x109e0811,0x00000000,
+0x9000381a,0x1092497d,0x10924925,0x1081c97c,0x9000891c,0x9000c905,0x1081c724,0xc1007025,
+0x00900724,0x00924725,0x00000000,0x90030080,0x90034085,0x00000000,0x90028078,0x9002c07d,
+0x00000000,0x90020070,0x90024075,0x00000000,0x90018068,0x9001c06d,0x00000000,0x90010060,
+0x90014065,0x00000000,0x90008058,0x9000c05d,0x00000000,0x90000050,0x90004055,0xc1ffece4,
+0xc1ffe8e0,0x0017c201,0x00000000,0x034707e4,0x034507e2,0x00178300,0x00154501,0x00174401,
+0xe8000334,0xc10000e0,0xc1000081,0x14000400,0x90001ce1,0xe8000319,0x14100305,0xc10001e1,
+0xe800032c,0x900014e1,0x14000401,0xc10008e1,0xd1000f38,0x0010f803,0x00109f00,0x90001519,
+0x00000000,0xb800140d,0xd1000f23,0xc10000e0,0x90005519,0xe8000045,0x04103874,0xc100016d,
+0xc10000e1,0xe8000035,0x04f03878,0xc100026c,0xc1000085,0x10851521,0xd1000ef0,0x00109f02,
+0xc100040d,0x10886104,0x80001419,0xe8ffffed,0x04902178,0x10851405,0xc10000e1,0xe8000221,
+0x04f0386c,0xc1000069,0x10865528,0x11061d00,0x1085d521,0xc10000e1,0xe80001f1,0x04f03878,
+0xc1000085,0x00159901,0xd1000ea0,0x00109f02,0xc1000c0d,0xd1000e95,0x00000000,0x84001618,
+0x00109f01,0xc100090d,0xd1000e81,0x00000000,0x84005618,0x00109f01,0xc100080d,0xe8000258,
+0x84009619,0x14001d01,0xc10009e1,0xd1000e5c,0x00109f00,0x0010f803,0x00000000,0xac0056e4,
+0xac0016ed,0x00000000,0xb8001ce9,0x00000000,0x8400d619,0xc10120e1,0x110e2000,0x00000000,
+0x01ce79e1,0x008e7aec,0x029e39e1,0xe8000010,0x90001ce5,0x14003801,0xc1200d81,0xd1000e0c,
+0xc10000e1,0x00000000,0x800216e0,0x00109f01,0xc100010d,0xe800020d,0x14000601,0xd1000dec,
+0x00109f02,0xc100020d,0x110e4600,0x110e2001,0x029e39e0,0x80025619,0xe800000d,0x14003801,
+0xc1200e81,0x110e4608,0x031e5784,0x110e2001,0x00000000,0x029e98e7,0x111e7901,0x029e7ae5,
+0x029e39e1,0xe800000d,0x14003801,0xc1200f81,0x00109f01,0xd1000d94,0xc10007e4,0xc10024e1,
+0x00000000,0x800456e0,0x800416e5,0xc100010d,0xe800016d,0x14000601,0x00000000,0xa40216e3,
+0x00000001,0xc100ffe0,0x128e7821,0x029e39e1,0x00000000,0x800216e1,0xd1000d50,0x00109f02,
+0xc100050d,0xd1000d45,0x00000000,0x80029618,0x00109f01,0xc100050d,0xc1000054,0x8002d618,
+0x10851635,0xd1000d24,0x00109f02,0xc100030d,0x10855504,0x80001419,0xe8ffffed,0x1490150c,
+0x10851405,0xe8000175,0x14001d01,0xc10002e1,0xd1000cf8,0x00109f00,0x0010f803,0x00000000,
+0xa40216e3,0x00000001,0x10886104,0x028e7818,0xc100ffe1,0xe8fffe34,0x029e39e1,0x04902178,
+0x108596e8,0x800216e1,0x10869a04,0xc10074e1,0xe8fffe04,0x008659e1,0x04901a6d,0x0011a001,
+0x1091c77c,0xb8000050,0xb8004055,0x1091c724,0xb8008058,0xb800c05d,0x00000000,0xb800c704,
+0xb8010061,0x00000000,0xb8014064,0xb8018069,0x00000000,0xb801c06c,0xb8020071,0x00000000,
+0xb8024074,0xb8028079,0x00000000,0xb802c07c,0xb8030081,0x1082477c,0xb8034084,0xb800871d,
+0x07000101,0x10824925,0x00100901,0xd2fffcf6,0xc10002e1,0xe8000011,0x14100305,0xd2fffce6,
+0xc10005e1,0xd2fffcde,0xc10003e1,0xd2fffce6,0xc10009e1,0xd2fffdba,0xc10004e1,0x00000000,
+0xa40256e3,0x00000001,0xe8fffeb1,0x14103809,0xd2fffea8,0xc10008e1,0x00000000,0x800416e2,
+0xc10000e0,0x10851629,0xc1000054,0x800256e1,0xd1000bd8,0x00109f02,0xc100050d,0x10855504,
+0x80001419,0xe8ffffed,0x1490150c,0x10851405,0xd1000bb8,0x00109f02,0xc100040d,0xd1000bad,
+0x00000000,0x80041618,0x00109f01,0xc100030d,0xd2fffe94,0x8004561b,0xd2fffe9a,0xc10003e1,
+0x10924941,0x1081c940,0x9000c904,0x9000891d,0xc1005024,0x90004920,0x10920741,0x00900724,
+0x00924725,0x00000000,0x9001c06c,0x90020071,0x00000000,0x90014064,0x90018069,0x00000000,
+0x9000c05c,0x90010061,0x00000000,0x90004054,0x90008059,0x00000000,0x90000051,0x00170401,
+0x00164200,0x00158500,0x0016c301,0x00000000,0xb80002e5,0xc24898e4,0xc10001e1,0xc30002e4,
+0xc1fff8ed,0x109e0820,0x00000000,0x008f38e5,0x00000000,0x900038e5,0x00000000,0xb80042e7,
+0x109e0811,0x00000000,0x900038e5,0x00000000,0xac00c3e8,0xa40243e3,0xc24898e5,0xc30002e4,
+0x120eba05,0x00000000,0x0316bce8,0x03157ae6,0xe8000130,0x008608ed,0x14103809,0x00000000,
+0xa40203e3,0x00000001,0x129e3821,0xe800010d,0x14003800,0xc100005d,0xc10011e1,0xe800003d,
+0x14003800,0x1095b805,0x10850349,0xd1000a7c,0x00109900,0x0010d503,0xc1ffffe1,0x00000000,
+0x80001418,0x008596e1,0xe8ffffe5,0x141016fc,0x1085d704,0x10851405,0x10855b48,0xc1001159,
+0x00851755,0xd1000a44,0x00109900,0x0010da03,0xc1ffffe1,0x00000000,0x80001418,0x008596e1,
+0xe8ffffe5,0x141016fc,0x1085d704,0x10851405,0xc1000258,0x008e9755,0xc1ffffe0,0xc10000e5,
+0x00000000,0x80003ae4,0x008596e1,0xe8ffffed,0x141016fc,0x108eba05,0xd1000864,0x00109800,
+0x0010d903,0x1091c740,0xb8000050,0xb8004055,0x00000000,0xb800c704,0xb8008059,0x00000000,
+0xb800c05c,0xb8010061,0x00000000,0xb8014064,0xb8018069,0x00000000,0xb801c06c,0xb8020071,
+0x00000000,0xb8004720,0xb800871d,0x07000101,0x10824741,0x00100901,0xd2ffff06,0xc10012e1,
+0x129e0521,0xe80000dd,0x14003801,0xc100005c,0x108e8448,0x108e4349,0x00000000,0x031e3a5e,
+0x1085d705,0xe8fffff5,0x14901718,0x108e7904,0x800039e1,0x129e1611,0xe80000d5,0x14003801,
+0xc100065c,0x108e9c48,0x108e5b61,0x00000000,0x031e3a5e,0x1085d705,0xe8fffff5,0x1490172c,
+0x108e7904,0x800039e1,0x129e1609,0xe80000cd,0x14003801,0xc1000b5c,0x108e9c48,0x108e5b75,
+0x00000000,0x031e3a5e,0x1085d705,0xe8fffff5,0x14901740,0x108e7904,0x800039e1,0x129e1605,
+0xe80000c5,0x14003801,0xc100105c,0x108e9c48,0x108e5b89,0x00000000,0x031e3a5e,0x1085d705,
+0xe8fffff5,0x14901754,0x108e7904,0x800039e1,0xd2fffec8,0xc10000e1,0x00000000,0x8009dbe2,
+0xc100005c,0x10850349,0xd10008a0,0x00109900,0x0010d503,0x1085d704,0x80001419,0xe8ffffed,
+0x14901718,0x10851405,0xd2ffff2f,0xc100065c,0x10851b61,0xd1000874,0x00109900,0x0010d503,
+0x1085d704,0x80001419,0xe8ffffed,0x1490172c,0x10851405,0xd2ffff37,0xc1000b5c,0x10851b75,
+0xd1000848,0x00109900,0x0010da03,0x1085d704,0x80001419,0xe8ffffed,0x14901740,0x10851405,
+0xd2ffff3f,0xc100105c,0x10851b89,0xd100081c,0x00109900,0x0010da03,0x1085d704,0x80001419,
+0xe8ffffed,0x14901754,0x10851405,0xd2ffff47,0x10924941,0x1081c940,0x9000891c,0x90004921,
+0xc2094c24,0x10920741,0x00924725,0x00000000,0xa40203e3,0x00000001,0x129e3821,0xe8000011,
+0x14003800,0xc10000f9,0xc10002f9,0xc10012e1,0x00000000,0x061478f9,0xc10240e1,0xe800005d,
+0x04f011e1,0xc2f700e8,0xc2237ce0,0x120e5105,0xc3ffffe8,0xc30002e0,0x120f1109,0x008f48e8,
+0x008ef9e1,0x00000000,0xa8003be0,0x034ebc0b,0x00000001,0x10845104,0x120e7808,0xc10240e1,
+0xe8ffffe4,0x108efb08,0x008e7de5,0x049011e0,0x108f3c10,0x900039e9,0xc10012e0,0xc2f700e8,
+0xc10240e5,0xc3ffffe8,0x061f38f8,0xc10000e1,0x008e88e9,0x120e7c08,0x0093f9f0,0xc1000045,
+0xe800002c,0x00000000,0x00843ae5,0x04f0383c,0x008ef909,0xc1000038,0xc1000831,0xc1000434,
+0x1082bb30,0xc1000c2d,0xd600430e,0x1091c741,0x00000000,0xb8004720,0xb800871d,0x07000102,
+0x10824741,0x10924941,0x1081c940,0x9000891c,0x90004921,0xc1006024,0x10920741,0x00924725,
+0xc24bb4e4,0x160e8230,0xc10004e1,0xc30002e4,0x00000000,0xc2237cf5,0xc1fff438,0x008e78e4,
+0xc10000e1,0x109e4830,0x0343f9e8,0xc1000035,0x10930820,0xc100002c,0x10928811,0xc1ffe8fc,
+0xc10000f8,0x109f0861,0xc10000ec,0x900039e0,0x109e8851,0xc10000e4,0xa4000f28,0x109e0841,
+0xc30002f4,0x90000c34,0x00834839,0x008308fc,0x90003cf8,0x90000a2d,0x1082cf04,0x900038e4,
+0x90003aed,0xc10000fc,0xc10000f8,0x001f7d01,0xc1ffffe1,0x00828ae1,0xe800002d,0x14100afd,
+0x00000000,0xa4000be0,0x108e7f05,0x119e390d,0x00000000,0x00000000,0x061ff8e6,0x1082cb04,
+0x1092b805,0x120f3f09,0x008e0cf0,0x034e4df0,0x034eccf1,0x008e8cf3,0x108e7b04,0x161e3f18,
+0x161e7949,0x00000000,0x900038e5,0x008e39e0,0x034e0cf1,0x008e38ed,0x00000000,0x84003de2,
+0xe8000031,0x14103819,0xc10000e4,0x008e0df1,0x00000000,0x90003ae5,0x00000000,0x034e4df3,
+0x00000001,0x108e7905,0x00000000,0x900038e5,0x108fbe04,0xc10240e1,0xe8ffff59,0x04903ee0,
+0x108f7d09,0x1091c741,0x00000000,0xb8004720,0xb800871d,0x07000102,0x10824741,0x10924941,
+0x1081c940,0x9000891c,0xc1004c25,0x00924725,0xc2001ce0,0xc22000ed,0xc30382e1,0x00000000,
+0xb80038e7,0xc20800e0,0x00000000,0xc100023d,0xe80000c4,0x029e79e0,0x029e39ed,0x14000400,
+0x122eb834,0x122f392d,0xc21200e1,0x008402e1,0xe80000b8,0xc2dcc839,0x14100f04,0xc3000139,
+0xc10000e1,0xe8000079,0x04f0380c,0xc1000035,0xc10000fc,0xc10004f9,0xc2ffffe4,0x034f7f08,
+0x034efe09,0xc2ffffe0,0xc10200f0,0xc10200e9,0xc301ffe4,0xc301ffe0,0x10834d09,0x001e7901,
+0x001e3800,0x008ebdf0,0x008f3be9,0x00000000,0x093eb9e8,0x093e78f1,0x122e7a28,0x122e3928,
+0x108fbe21,0xe8ffffb4,0x84004ee0,0x84000ee5,0x04900d0c,0x10838e10,0x108fff21,0x0201833d,
+0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,0xd2ffff5c,0xc10002e1,0x00000000,
+0x0093f8e9,0x00140201,0xe80000a5,0x14103c05,0xc10000e1,0xe8ffffc9,0x04f0380c,0xc1000035,
+0xc1000028,0xc10004fd,0xc2ffffe8,0x034e0a08,0x034f1029,0xc2ffffe4,0x034f3f08,0x034e10fd,
+0xc10200f4,0xc10200ec,0xc301ffe9,0xc301ffe5,0x008fb8f1,0x122f3e04,0x008e3ce0,0x001eba01,
+0x122e7804,0x001e3900,0x008f3cf5,0x10834d08,0x008e79ec,0x093ebaf1,0xeaffffb0,0x122e3a28,
+0x093eb8e5,0x122e3a28,0x84004ee0,0x84000ee1,0x10838e20,0x8400cee0,0x84008ee1,0x04900d0c,
+0x10828a20,0x108fff21,0xd2ffff37,0xc10000e1,0xe8ffff2d,0x04f0380c,0xc1000035,0xc1000030,
+0xc100042d,0xc2ffffe1,0xc301ffe1,0x0012b801,0xd6004002,0xd2ffff0b,0x10924941,0x1081c940,
+0x9000891d,0x10924771,0xc10000e1,0xe8000031,0x04e03808,0xc10001e8,0xc10000e5,0x00000000,
+0x008eb9e9,0xe800000d,0x04a03a09,0xc10000e9,0x108e7905,0xe8ffffe9,0x04803909,0x0011ba01,
+0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,0x10924941,0x1081c940,0x9000891c,
+0x9000c905,0x10900760,0x10924761,0xc2800ce5,0xc10000e0,0xc30001e5,0x00000000,0x900039e1,
+0x00000000,0xb80002e3,0x00000001,0xe8000041,0x14003801,0xe8000019,0x14003805,0xe800003d,
+0x14003809,0xe8000049,0x1400380d,0xc1000019,0x1091c741,0x00000000,0xb800c704,0xb800871f,
+0x10824742,0x07000102,0x00100901,0xd1ffe092,0x10808211,0xd2ffffdf,0x00000000,0xb801c211,
+0xd1ffe0da,0xc1000015,0xd2ffffcb,0x00000000,0xb801c211,0xd1ffe3db,0xd2ffffbb,0x10924941,
+0x00000000,0x9000891d,0x1081c940,0x9000c904,0xc1002025,0x00900724,0x00924725,0x001ec201,
+0xc28010e1,0xc30001e1,0x00000000,0xa00038e3,0x00000001,0x129e3805,0xe8000069,0x14003801,
+0xc28018e0,0xc20004e8,0xc24000e5,0xc30001e0,0xc30001e9,0x008e7ae4,0xb80038e3,0x00000001,
+0x008eb9e1,0xd1ffd21d,0x12114308,0x00113b00,0x0010fa01,0xc1000309,0xd1ffd766,0xc1000309,
+0xc1000019,0x1091c741,0x00000000,0xb800c704,0xb800871f,0x10824742,0x07000102,0x00100901,
+0xc28018e4,0xc20004e1,0xc30001e4,0xc30001e1,0x00000000,0xb80039e6,0xd2ffffae,0x008eb9e1,
+0x10924941,0x1081c940,0x9000891d,0x10924761,0xc10000e4,0x9000020c,0xc10008e1,0x00000000,
+0x8400c2e0,0x840082e5,0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,0x10924941,
+0x1081c940,0x9000891c,0xc1002025,0x00924725,0x00000000,0xb80002e0,0xb80003ed,0x00000000,
+0xac00c3e6,0x00000000,0xac00c2e9,0xc10008e0,0x00000000,0x108eb805,0x009e38e4,0x009e7be9,
+0x120e790d,0x008e7ae5,0x0081b9e1,0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,
+0x10924941,0x1081c940,0x9000891d,0x10924751,0x00000000,0xac00c2e3,0x00000001,0xe800002d,
+0x14103821,0x00000000,0xb80002e3,0x00000001,0x0011b801,0x1091c741,0x00000000,0xb800871d,
+0x07000102,0x10824741,0x00000000,0xb80002e2,0xd2ffffe2,0x108e3805,0x10924941,0x1081c940,
+0x9000891c,0xc1002025,0x00924725,0x00000000,0xac00c2e0,0xb80002ea,0x129e431d,0x121ec30d,
+0xc2ffffe0,0x009e78e4,0x008ebaed,0xc2ffffe0,0x900002e8,0x029e79e1,0x029e39e1,0xe8000040,
+0x8400c2e1,0x14a03821,0x00000000,0xac00c2e0,0xb80002e7,0x00000001,0xc2ffffe0,0x108eb904,
+0x108e7821,0xc2ffffe0,0x900002e8,0x029e79e1,0x029e39e1,0x00000000,0x8400c2e1,0x00000000,
+0xac00c2e3,0x00000001,0xe800002d,0x14e03821,0x00000000,0xb80002e3,0x00000001,0x00000000,
+0xa40038e7,0xc2ffffe1,0x029e39e1,0x00000000,0x840082e1,0x1091c741,0x00000000,0xb800871d,
+0x07000102,0x10824741,0x10924941,0x1081c940,0x9000891c,0xc1002825,0x00924725,0x00000000,
+0xac00c2e3,0x00000001,0xe800002d,0x14103821,0x00000000,0xb80002e3,0x00000001,0x00000000,
+0xa40038e7,0xc2ffffe1,0x029e39e1,0x00000000,0x840082e1,0x00000000,0xac00c2ef,0x00000001,
+0xe8000051,0x04f003ed,0xc10001e0,0xac0082ec,0x009ebb0d,0xc2ffffe4,0x020ef8ec,0xc2ffffe1,
+0x029e7ae5,0x109e7b04,0x00000000,0x029e39e1,0x029e3be4,0x8400c2e1,0x0221b8e9,0x1091c741,
+0x00000000,0xb800871d,0x07000102,0x10824741,0xc10001e0,0xb80002e0,0xac0082e9,0xc10008e0,
+0x020e78ed,0x009f43ec,0x8400c2e1,0x109e7905,0xe8000050,0x108e3804,0x029efae5,0x14903d20,
+0x900002e1,0x00000000,0xb80002eb,0x00000001,0xc1fff8e0,0xa4003ae0,0x120e7b21,0x00000000,
+0x00000000,0x008f7de2,0xe8ffffe9,0x14f03d20,0x108eba04,0x028ef9e1,0x00000000,0x900002e9,
+0xe8000051,0x14b03d01,0x00000000,0xb80002e8,0xac00c2e5,0xc10008e4,0xc2ffffe1,0x020f3bf4,
+0x009ef9f6,0xc2ffffe4,0xa4003ae4,0x009eb9f5,0x029e7ae5,0x029e39e1,0xc2ffffe0,0x8400c2e1,
+0x029e39e1,0x022e38ec,0x840082e1,0x028efce1,0xd2ffff2c,0x0011bb03,0x10924941,0x1081c940,
+0x9000c904,0x9000891d,0xc1003424,0x90004920,0x10920741,0x00900724,0x00924725,0x00000000,
+0x90004054,0x90008059,0x00000000,0x90000051,0x00154301,0xc1fff8e0,0xc1000059,0x008508e1,
+0x001e5401,0x00000000,0x030e160a,0x10859605,0xe8fffff5,0x14901620,0x108e7904,0x800039e1,
+0xc10020e1,0xe80000fd,0x049003e0,0x00158401,0xd1fffe18,0x00109402,0xc100200d,0x121e9620,
+0x121e4660,0xc100ffe1,0x00000000,0x02ae7ae5,0xc2802ce0,0x029e79e1,0xc30001e0,0xc2802ce4,
+0x120eb905,0x00000000,0x033e3ae2,0xc1ffe0e1,0x120e9620,0x00000000,0x008555e1,0x00000000,
+0x02ae3ae1,0x121e0640,0x120eb820,0x121ef821,0xc100ffe0,0x02aefbe1,0x029e3be1,0xc30001e4,
+0x120e3805,0x00000000,0x033e38e7,0x00000001,0x02ae3ae1,0x121e0620,0x120eb820,0x121e7821,
+0xc100ffe0,0x02ae79e1,0xc2802ce0,0x029e79e1,0xc30001e0,0x120e7905,0x00000000,0x033e39e3,
+0x00000001,0x02ae3ae1,0x121e3820,0x120eb821,0xc100ffe0,0x02ae7819,0xc2802ce0,0x029e79e1,
+0xc30001e0,0x120e7905,0x00000000,0x033e79e2,0xc10020e1,0xe8ffff1d,0x04f015e0,0x02a5bae5,
+0x121e150d,0xe80000a5,0x1400380d,0xe80000d9,0x14003809,0xe800010d,0x14003805,0xe8000049,
+0x14001501,0x10955505,0xd1fffd00,0x00109402,0xc100010d,0x121e163d,0x02ae06e1,0x129e3805,
+0xe8000015,0x14003800,0x12059605,0xc28005e1,0x02a596e1,0xc1ffffe1,0x008555e1,0xe8ffffcd,
+0x141015fd,0xc2ffffe4,0xc2ffffe1,0x029e56e5,0x0291b9e1,0x1091c741,0x00000000,0xb800c704,
+0xb800805b,0x00000000,0xb8004054,0xb8000051,0x00000000,0xb800871c,0xb8004721,0x07000101,
+0x10824741,0x00100901,0xd1fffc80,0x00109402,0xc100080d,0x121e5620,0xc2802ce1,0xc100ffe4,
+0x120e9620,0x02aef919,0x029e7be5,0xc30001e0,0x120e7905,0x00000000,0x033e39e3,0x00000001,
+0x02a5bae1,0xd1fffc44,0x00109402,0xc100080d,0x121e5620,0xc2802ce1,0xc100ffe4,0x120e9620,
+0x02aef919,0x029e7be5,0xc30001e0,0x120e7905,0x00000000,0x033e39e3,0x00000001,0x02a5bae1,
+0xd1fffc08,0x00109402,0xc100080d,0x121e5620,0xc2802ce1,0xc100ffe4,0x120e9620,0x02aef919,
+0x00000000,0x029e7be5,0xc30001e0,0x120e7905,0x00000000,0x033e39e2,0xd2fffec6,0x1295551c,
+0x02a5bae1,0x1092497d,0x10924925,0x1081c97c,0x9000891c,0x90004921,0x1081c724,0xc1002825,
+0x00920724,0xc100cc25,0x00900724,0x00924725,0x00000000,0x9005c0ac,0x900600b1,0x00000000,
+0x900540a4,0x900580a9,0x00000000,0x9004c09c,0x900500a1,0x00000000,0x90044094,0x90048099,
+0x00000000,0x9003c08c,0x90040091,0x00000000,0x90034084,0x90038089,0x00000000,0x9002c07c,
+0x90030081,0x00000000,0x90024074,0x90028079,0x00000000,0x9001c06c,0x90020071,0x00000000,
+0x90014064,0x90018069,0x00000000,0x9000c05c,0x90010061,0x00000000,0x90004054,0x90008059,
+0x00000000,0x90000051,0xc1ffece4,0xc1ffe8e1,0x00000000,0x034ac7e4,0x034a87e3,0x00000001,
+0xc10000e4,0x00000000,0x109e0811,0xc10000e0,0x109e4820,0x900038e5,0xe800018c,0x90003915,
+0x04f038ac,0xc10000a0,0x011a6b15,0xc235e8e0,0xc278aae4,0xc24f33e9,0xc30ec8e0,0xc3061fe4,
+0xc30b50e9,0x00197800,0x0019b900,0x0019fa01,0xc21708e0,0xc2b315e4,0xc29d9de9,0xc3031fe0,
+0xc30d4de4,0xc308e3e9,0x0018b800,0x0018f900,0x00193a01,0xc24036e0,0xc27993e4,0xc24be8e9,
+0xc30c5ee0,0xc30a26e4,0xc30fb1e9,0x0017f800,0x00183900,0x00187a01,0xc2e69de0,0xc2bd7ae4,
+0xc24402e9,0xc30563e0,0xc30e76e4,0xc306d7e9,0x00173800,0x00177900,0x0017ba01,0xc25979e0,
+0xc2d74ee4,0xc29082e9,0xc30e1ce0,0xc3078ae4,0xc30f10e9,0x00167800,0x0016b900,0x0016fa01,
+0xc23f2fe0,0xc241a3e4,0xc2c3cde9,0xc303e3e0,0xc30db9e4,0xc30839e9,0x0015b800,0x0015f900,
+0x00163a01,0xc2a0abe0,0xc2018ce4,0xc23f7ee9,0xc30f4fe0,0xc304a5e4,0xc30f85e9,0x00153800,
+0x00157900,0x001b3a01,0xc2020ee0,0xc2f024e4,0xc2fbfee9,0xc30259e0,0xc30cd9e4,0xc30987e9,
+0x00147800,0x0014b900,0x0014fa01,0xc246d2e0,0xc27a6ce4,0xc2aac0e9,0xc30fece0,0xc30191e4,
+0xc30fd3e9,0x0013b800,0x0013f900,0x00143a01,0xc2fb30e4,0xc2ef91e8,0xc2b49aed,0xc300c8e4,
+0xc210f2e0,0xc30abeed,0xc30bdae8,0xc30ffbe0,0x0012f901,0x00137b00,0x0012b800,0x00133a01,
+0xd606c00e,0x00000000,0xb8004055,0x00000000,0xb8000050,0xb800c05d,0x00000000,0xb8008058,
+0xb8014065,0x00000000,0xb8010060,0xb801c06d,0x00000000,0xb8018068,0xb8024075,0x00000000,
+0xb8020070,0xb802c07d,0x00000000,0xb8028078,0xb8034085,0x00000000,0xb8030080,0xb803c08d,
+0x00000000,0xb8038088,0xb8044095,0x00000000,0xb8040090,0xb804c09d,0x1091c77c,0xb8048098,
+0xb80540a5,0x1091c724,0xb80500a0,0xb805c0ad,0x00000000,0xb80600b0,0xb8004721,0x1082477c,
+0xb80580a8,0xb800871d,0x07000101,0x10824925,0x00100901,0x10924941,0x1081c940,0x9000891c,
+0x9000c905,0x10900760,0x10924761,0x00000000,0xb803c3e7,0xc22009e1,0xe8000081,0x040039e1,
+0xc2200be1,0xe8000075,0x040039e1,0xc2200ce1,0xe8000069,0x040039e1,0xc2200de1,0xe800005d,
+0x040039e1,0xc2200ee1,0xe8000051,0x040039e1,0xc2200fe1,0xe8000045,0x040039e1,0xc22010e1,
+0xe8000039,0x040039e1,0xc22011e1,0xe800002d,0x040039e1,0xc22012e1,0xe8000021,0x040039e1,
+0xc22013e1,0xe8000015,0x040039e1,0xc22014e1,0xe8000055,0x041039e1,0x00000000,0xb80002e3,
+0x00000001,0xe8000031,0x14003801,0xd1000d32,0x00108401,0xc1100019,0x1091c741,0x00000000,
+0xb800c704,0xb800871f,0x10824742,0x07000102,0x00100901,0xd2ffffe0,0xc10001e1,0x00000000,
+0x900002e2,0xd2ffffd6,0xc1000019,0x10924941,0x1081c940,0x9000891c,0x9000c905,0x10900770,
+0x10924771,0x00000000,0x90000051,0x00150201,0x00000000,0xb8028209,0xd1006018,0xc29eece5,
+0xc10000e0,0xc30001e5,0x00000000,0x800039e1,0x00000000,0xb80294e6,0xd10004dd,0xc10040e1,
+0x0080b9e1,0x00000000,0xb80294e6,0xd1006239,0xc21268e1,0x0080b9e1,0x1091c741,0x00000000,
+0xb800c704,0xb800871f,0x10824741,0x00000000,0xb8000051,0x07000102,0x00100901,0x10924941,
+0x1081c940,0x9000c904,0x9000891d,0xc1008024,0x90004920,0x10920741,0x00900724,0x00924725,
+0x00000000,0x90040090,0x90044095,0x00000000,0x90038088,0x9003c08d,0x00000000,0x90030080,
+0x90034085,0x00000000,0x90028078,0x9002c07d,0x00000000,0x90020070,0x90024075,0x00000000,
+0x90018068,0x9001c06d,0x00000000,0x90010060,0x90014065,0x00000000,0x90008058,0x9000c05d,
+0x00000000,0x90000050,0x90004055,0x00158300,0x00188501,0xc10000e4,0xb8004484,0x109e0811,
+0x00000000,0x900038e5,0x00000000,0x00000000,0xb8028257,0xd100043c,0xc10040e1,0xc21268e0,
+0x008815e1,0x0010d500,0x0010a000,0x0087d5e1,0xe8000099,0x141006fd,0xc1ffff19,0x00000000,
+0xb8004055,0x1091c740,0xb8000050,0xb8008059,0x00000000,0xb800c704,0xb8010061,0x00000000,
+0xb800c05c,0xb8018069,0x00000000,0xb8014064,0xb8020071,0x00000000,0xb801c06c,0xb8028079,
+0x00000000,0xb8024074,0xb8030081,0x00000000,0xb802c07c,0xb8038089,0x00000000,0xb8034084,
+0xb8040091,0x00000000,0xb8044094,0xb8004721,0x00000000,0xb803c08c,0xb800871d,0x07000101,
+0x10824741,0x00100901,0x00000000,0xb80060e3,0x00000001,0xe800005d,0x14003801,0xc1000279,
+0xc1ffece0,0x109e8951,0xc1fffce0,0x109e4960,0x008508e1,0x008e88e0,0x90003a51,0xd1000854,
+0xc2822c14,0x109e0971,0x0010a000,0x90003878,0x900039e9,0xc3000114,0x00111500,0x0010df01,
+0xe8000019,0x141006fd,0xd2ffff16,0xc1ffff19,0xd2ffffb2,0xc1000179,0xc10000e1,0x00000000,
+0x900016e1,0x00000000,0xb80020eb,0x00000001,0xe80001c9,0x14103a05,0xc1000c8c,0xc1000c91,
+0xc21004e4,0xb80160e0,0xc21008e1,0xc2100ae0,0x008edfe4,0x008e9fe1,0x120e6314,0x00000000,
+0x008e1fe1,0x00000000,0x840038e4,0x84003a79,0x00000000,0x90003be1,0x00000000,0xb80020e3,
+0x00000001,0xe80001bd,0x1410380d,0xc1fffce1,0x00000000,0x034e08e3,0x00000001,0x1299781d,
+0xc2001ce4,0x120ea521,0xc30382e4,0xc10000e1,0x00000000,0xb80039ef,0xc1f8ffe5,0xc2001ce4,
+0x029efbe5,0xe8000110,0xc30382e4,0x028ebbe9,0x04f03878,0xc1000074,0x900039e9,0xc2822ce4,
+0xc2100ce0,0xc1000069,0xc30001e4,0xc1000064,0x0086dfe1,0x10873928,0xc1000060,0x0015d401,
+0xc1fffce1,0x00000000,0x034e48e3,0xc10000e1,0xe800007d,0x04f038e4,0xc1000095,0xc1000058,
+0xc1000054,0x00851a71,0x00000000,0xa40214e0,0x034e9b65,0x109e0950,0x0340d758,0x0010a001,
+0x00111400,0x90003875,0xd1001a95,0x109e0960,0x00000000,0x129e7821,0x008155e8,0x900038e5,
+0xc1fffce0,0xc20900e5,0xc10074e0,0x034e08e1,0x008514e0,0x00000000,0x008555e6,0x10896505,
+0xe8ffffa9,0x049025e0,0x10859611,0xd1005fd0,0x109e0960,0x00811885,0x109e0950,0x90003890,
+0x00109f01,0x00115d00,0x9000388c,0x0010e001,0xe9ffff50,0xc21200e0,0x10875d05,0x1085d720,
+0x90002218,0x008618e1,0x04901d78,0x10869ae8,0x10865911,0xc21000e0,0xb9001fe4,0xc1000019,
+0x008e1fe3,0xd2fffd38,0x008e798d,0x129e793d,0x00000000,0x900038e5,0xe800002d,0x14103a0d,
+0x00000000,0xb801e0e7,0xc21000e1,0x029e39e1,0xe8000015,0x14003801,0xd2fffe2a,0xc100128c,
+0xc1001291,0xe8000015,0x14103a0c,0xc100248d,0xd2fffe12,0xc1001291,0xd2fffe0a,0xc1002491,
+0xe8000011,0x14103805,0xd2fffe5a,0xc1000395,0xd2fffe52,0xc1000295,0x10924941,0x1081c940,
+0x9000891c,0xc1002825,0x00924725,0xc10000f0,0xc10000e4,0xc10000f5,0xc10000e0,0xc10000ec,
+0xc10000e9,0xc10000e4,0x900042e4,0x900002f5,0xc10000e8,0x9000c2e8,0x900082f1,0xc10000e0,
+0x900142e0,0x900102ed,0xc10000e0,0x840342e0,0x840302e9,0x00000000,0x900202e0,0x9001c2e5,
+0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,0x10924941,0x1081c940,0x9000891c,
+0x9000c905,0x10900760,0x10924761,0x00000000,0x90000051,0x00150201,0xd1ffff63,0xd10007a0,
+0xc10001e1,0x00109400,0x900254e2,0x1091c741,0x00000000,0xb800c704,0xb800871f,0x10824741,
+0x00000000,0xb8000051,0x07000102,0x00100901,0x10924941,0x00000000,0x9000891d,0x1081c940,
+0x9000c904,0xc1003c25,0x00900724,0x00924725,0x00000000,0x90004054,0x90008059,0x00000000,
+0x90000051,0x00154200,0x00150301,0x00000000,0xb80183ec,0xb800435b,0x00000001,0xe8000051,
+0x14103b01,0xc10002e4,0xc10000e0,0xc1ffff19,0x00000000,0x9000c3e0,0x9003c3e5,0x1091c741,
+0x00000000,0xb800c704,0xb800805b,0x00000000,0xb8004055,0x00000000,0xb8000050,0xb800871d,
+0x07000101,0x10824741,0x00100901,0x00000000,0xb80083eb,0x00000001,0xe8000075,0x14003a01,
+0x00000000,0xb800c3e7,0xc10000e1,0xe8000015,0x041038e5,0x00000000,0xb80143ef,0x00000001,
+0x00000000,0x009e16ed,0xe800002d,0x04f038e9,0xd2ffff8c,0xc10000e0,0x009e7ae1,0xc10001e4,
+0x90018358,0x900083e5,0xc1ffff18,0x9000c3e0,0x9003c3e5,0xc10000e4,0xc10001e0,0x008efbe9,
+0x00000000,0x9000c3e0,0x900083e5,0x00000000,0xb800d4e3,0x00000001,0xe8000091,0x14003801,
+0x00000000,0x009e16ed,0xe800002d,0x14e03821,0x00000000,0x900194ed,0xd2ffff24,0xc10000e0,
+0xc10001e5,0x00000000,0x9000d4e0,0x9003d4e5,0xc1ffff19,0x00000000,0xa4003be7,0xc100ffe1,
+0xe8000025,0x041039e1,0x00000000,0xa4007be7,0xc100e0e1,0xc100e0e0,0x029e79e1,0xe8000095,
+0x040039e1,0xd2fffed8,0xc10000e0,0x108e7b05,0xc11004e4,0x900194e4,0x900154ed,0xc1ffff18,
+0x9000d4e0,0x9003d4e5,0xd1ffee98,0x10809470,0x0010fb03,0xd1005a1c,0x00109403,0xe8000049,
+0x141006fd,0x00000000,0xb80194e3,0x00000001,0x009e16e1,0xe8000015,0x14803821,0x109e1621,
+0x00000000,0x900194e1,0xd2fffe74,0xc10000e0,0xc10001e5,0x00000000,0x9000d4e0,0x9003d4e5,
+0xc1ffff19,0xd1ffeedc,0x10809473,0x001ec601,0xd1ffee30,0x108e3b04,0x10809471,0x0010fb00,
+0x900154ec,0x900194e2,0xd1ffd1c4,0x00109500,0x0010d403,0xe800001d,0x141006fd,0xd2fffe20,
+0xc10000e1,0x00000000,0x9000d4e1,0xc1ffff19,0x00000000,0xb80115e3,0x00000001,0xe8000079,
+0x14103801,0x00000000,0xb80114e3,0x00000001,0xe800001d,0x14003801,0x00000000,0xb800d4e7,
+0xc10000e1,0xe8000031,0x041038e5,0xd1ffd528,0x00109400,0x0010d503,0xe800001d,0x141006fd,
+0xd2fffdbc,0xc10000e1,0x00000000,0x9000d4e1,0xc1ffff19,0x00000000,0xb801d5e4,0xb80114eb,
+0xc10400e1,0x028e39e0,0x900115e9,0x00000000,0x9001d5e1,0x00000000,0xb801d5eb,0xc10080e1,
+0x029e3ae1,0xe80000b5,0x14003801,0xc10001fd,0x00000000,0xb80015e7,0x00000001,0xe80000a5,
+0x14103905,0x00000000,0xb80115e4,0xb80155eb,0xc1000ce1,0x00000000,0x061e78e5,0xc10000e1,
+0xe8000029,0x04d038e4,0xc10000f9,0xc10000e1,0x00000000,0x00000000,0x008e38e9,0xe8fffff5,
+0x04b038e4,0x108fbe05,0xc1ffffe1,0x008fbee1,0x008e3efd,0x120f7809,0x00000000,0xb80154e7,
+0x00000001,0x108ebd20,0x009e16e5,0xe80000fd,0x04b03ae1,0x00000000,0x900194e5,0xd2fffce0,
+0xc10000e0,0xc10001e5,0x00000000,0x9000d4e0,0x9003d4e5,0xc1ffff19,0xd2ffff5a,0xc10000fd,
+0xe8000015,0x1410390c,0xc10000e1,0xc21000e1,0x029e3ae1,0xe80000ad,0x14003801,0xc10048f1,
+0x00000000,0xb80115e4,0xb80155eb,0xc10000e1,0xe8000029,0x04d038e4,0xc10000ed,0xc10000e1,
+0x00000000,0x00000000,0x008e38e9,0xe8fffff5,0x04b038e4,0x108efb05,0xc1ffffe1,0x00000000,
+0x008efbe1,0x00000000,0x061e3aee,0x009e39e1,0x00000000,0x061e78f1,0xc10000e1,0xe8000029,
+0x04d038e4,0xc10000f9,0xc10000e1,0x00000000,0x00000000,0x008e38e9,0xe8fffff5,0x04b038e4,
+0x108fbe05,0xc1ffffe0,0x061e3bf1,0xd2ffff0c,0x00000000,0x008fbee1,0x008e38f9,0x008f78fd,
+0xd2ffff62,0xc10090f1,0x008eb9f4,0xb800d4e5,0x00000000,0x900194ea,0xc10000e1,0xe800005d,
+0x041038e5,0x00000000,0xa4003ae7,0xc100ffe1,0xe8000025,0x041039e1,0x00000000,0xa4007ae7,
+0xc100e0e1,0xc100e0e0,0x029e79e1,0xe8000021,0x040039e1,0x00000000,0xb80154e3,0xd2fffc51,
+0x108ef805,0x00000000,0x900194ed,0xc10001e1,0x00000000,0x9000d4e1,0x00000000,0xb801d5e3,
+0xd2fffb7d,0x128e3821,0xc1000018,0x9001d5e1,0x1092497d,0x10924935,0x1081c97c,0x9000891c,
+0x9000c905,0x1081c734,0x90004920,0xc1002c25,0x00920724,0xc1006025,0x00900724,0x00924725,
+0x00000000,0x90018068,0x9001c06d,0x00000000,0x90010060,0x90014065,0x00000000,0x90008058,
+0x9000c05d,0x00000000,0x90000050,0x90004055,0xc1ffece8,0xc1ffe8e4,0xc1ffe4e1,0x00000000,
+0x0345c7e8,0x034587e5,0x00000000,0x034547e1,0x0016c201,0x00164401,0x00168300,0x00000000,
+0x00160501,0x00000000,0xb801c2e0,0xb80384e7,0x00000001,0xc10000e0,0x900242e4,0x129e7821,
+0xe800007d,0x041038e5,0xd1fffa4a,0x0010c401,0xe800006d,0x141006fd,0xc10000e0,0xc1ffff19,
+0x00000000,0x9002d9e1,0x1091c77d,0x1091c734,0xb8004055,0x00000000,0xb800c704,0xb8010061,
+0x00000000,0xb8000050,0xb800c05d,0x00000000,0xb801c06c,0xb8004721,0x00000000,0xb8008058,
+0xb8018069,0x1082477c,0xb8014064,0xb800871d,0x07000101,0x10824935,0x00100901,0x00000000,
+0xb801dbe4,0xb8001be3,0x00000001,0xe8000028,0x129e79dd,0x14003804,0x9001dbe5,0xe8000079,
+0x14003809,0xe8000089,0x1400380d,0xd2ffff7e,0xc1ffff19,0xd1001891,0x00111a00,0x0010db00,
+0x00109902,0x00150601,0xe8000099,0x141014fd,0x00000000,0xb803d9e7,0xc2f000e1,0xc10000e0,
+0x029e79e1,0xe800001d,0x041038e5,0x00000000,0xb80159e3,0x00000001,0x00000000,0x900199e1,
+0xd2ffff28,0xc10000e1,0x00000000,0x9002d9e1,0xc1ffff19,0xd1001dd1,0x00111a00,0x0010db00,
+0x00109902,0xd2ffffa6,0x00150601,0x109e8950,0x109e0971,0xd10035a0,0x109e4960,0x00109901,
+0x00111a00,0x90003958,0x90003a5d,0x0010db00,0x90003854,0x00115801,0xd2ffff72,0x00150601,
+0x00000000,0xb8001be3,0x00000001,0xe8000049,0x1400380d,0x00000000,0xb801990d,0xd1ffe925,
+0xc1fff8e1,0x008088e1,0xc1fff8e0,0xb801d9e4,0xb80219e1,0x0080c8e0,0x10809971,0xd1ffe942,
+0x00000000,0x900299e0,0x900259e5,0x00000000,0x9002d919,0xd2fffe76,0xc1000019,0x10924941,
+0x1081c940,0x9000891c,0xc1003825,0x00924725,0xc20928e0,0x108282a1,0xc100002c,0xc10000f8,
+0x008fc2e1,0xc10000f4,0x008efe28,0x008f3efd,0xc10000e4,0x108f7d04,0xc10020e1,0xc10000e4,
+0x90003ce4,0xc10048e9,0xe8ffffe8,0xc10048e4,0x90003be5,0x04903de0,0x008efbe8,0x008f3ce5,
+0x1082cb05,0xe8ffffc1,0x14900b48,0x108fbe11,0x1091c741,0x00000000,0xb800871d,0x07000102,
+0x10824741,0x1092497d,0x10924945,0x1081c97c,0x9000891c,0x9000c905,0x1081c744,0x90004920,
+0xc1003025,0x00920724,0xc101b425,0x00900724,0x00924725,0x00000000,0x900700c0,0x900740c5,
+0x00000000,0x900680b8,0x9006c0bd,0x00000000,0x900600b0,0x900640b5,0x00000000,0x900580a8,
+0x9005c0ad,0x00000000,0x900500a0,0x900540a5,0x00000000,0x90048098,0x9004c09d,0x00000000,
+0x90040090,0x90044095,0x00000000,0x90038088,0x9003c08d,0x00000000,0x90030080,0x90034085,
+0x00000000,0x90028078,0x9002c07d,0x00000000,0x90020070,0x90024075,0x00000000,0x90018068,
+0x9001c06d,0x00000000,0x90010060,0x90014065,0x00000000,0x90008058,0x9000c05d,0x00000000,
+0x90000050,0x90004055,0xc1ffece8,0xc1ffe8e0,0xc1ffe4e5,0xc1ffe0e0,0x034e47e8,0x0345c7e1,
+0x00000000,0x0346c7e4,0x034587e1,0x00150200,0x00178501,0x00160301,0x00180401,0x00000000,
+0xac0004e3,0x00000001,0x009778e5,0xe80000e1,0x14e01d01,0xc1201119,0x00000000,0xb8004055,
+0x1091c77c,0xb8000050,0xb800c05d,0x1091c744,0xb8008058,0xb8010061,0x00000000,0xb800c704,
+0xb8018069,0x00000000,0xb8014064,0xb8020071,0x00000000,0xb801c06c,0xb8028079,0x00000000,
+0xb8024074,0xb8030081,0x00000000,0xb802c07c,0xb8038089,0x00000000,0xb8034084,0xb8040091,
+0x00000000,0xb803c08c,0xb8048099,0x00000000,0xb8044094,0xb80500a1,0x00000000,0xb804c09c,
+0xb80580a9,0x00000000,0xb80540a4,0xb80600b1,0x00000000,0xb805c0ac,0xb80680b9,0x00000000,
+0xb80640b4,0xb80700c1,0x00000000,0xb80740c4,0xb8004721,0x1082477c,0xb806c0bc,0xb800871d,
+0x07000101,0x10824945,0x00100901,0xd1ffd2d8,0xc1ff64e1,0x00000000,0x008108e0,0x0010a001,
+0x0010c501,0x00000000,0xb80014e6,0xc100a4e0,0x0010dd00,0x00109401,0x009e08e1,0x00000000,
+0x900038e5,0x00000000,0xb80054e6,0xd1ffe70c,0xc100a0e1,0x009e08e0,0x00000000,0xc1ff5ce9,
+0x008b48e8,0x900038e5,0xc1ff62e0,0x0010ad01,0x00000000,0x033e48e3,0xc1001fe1,0x009e38e5,
+0xd1ffe7a8,0x129e38e1,0x0087f9e1,0x0010df01,0x00000000,0xa402a0ec,0xa4001ef1,0xc29cfce8,
+0xa40420e4,0xc29d9ce1,0xc29d7ce4,0xc30001e0,0xc30001e9,0xc30001e5,0x120e3b08,0x0319fbe0,
+0x031a3be5,0xeb000048,0x034a78e8,0x00170601,0x120e3c08,0x00975d7c,0x10879e05,0x008698e1,
+0x00151800,0x00000000,0x108ae029,0x14e03b34,0x108b3904,0xc10000a9,0xc1000199,0xe8000031,
+0x14102901,0xd2fffe36,0xc1201219,0x109e7b34,0xc29dbce0,0xc1000099,0x120e7908,0xc30001e1,
+0x00000000,0x034979e1,0xd2ffffd7,0xc1ff64e4,0xac00608c,0xc10001e1,0x020e389c,0x034548e6,
+0xc1ff68e5,0xe8000284,0x00000000,0xc1000091,0x14002300,0x008648e4,0x1098b805,0xc1ff1ce1,
+0x008848e1,0xe80000d8,0xc1ffffe1,0x04101468,0x0088e3e1,0xc1ffffe0,0xa4001ee1,0x00000000,
+0x008b2ce3,0xe8000098,0x120e3809,0x14102c00,0x10879e04,0x00869ae1,0x1102aa00,0x108aaa04,
+0xc29cfcf5,0xc29d9cec,0x031faba8,0xc30001f5,0xc30001ec,0xa40460fc,0xc1fff3e9,0xc29d7cf0,
+0xc29dbce4,0xc10001e1,0xc30001f0,0x00000000,0xc30001e5,0x120efe08,0x0319feec,0x008ebee9,
+0x120eba08,0x031a3ef0,0x034a7bf5,0x108e7f04,0x03497ae5,0x00000000,0x00000000,0x09bb0ae5,
+0x020e389d,0xe8000019,0x14102900,0x1189be34,0x1098b805,0xd2fffd26,0xc1201219,0x00000000,
+0xb80019ef,0x00000001,0x00000000,0x010e15ed,0x10865910,0x09b93890,0x00157b01,0xe80000a1,
+0x14e01f54,0x001f2701,0xc1ff5ce0,0xc1001fe8,0xc1fff8e5,0x00000000,0x034e48e0,0x009e3a7d,
+0x122e380d,0x120fb80d,0xc100a4e0,0x00000000,0x008f7ee5,0x009e08e0,0xa40039ec,0x108e7905,
+0x00000000,0x900038e5,0xe8000045,0x14903d21,0x001eb901,0xc1fff8e0,0xa4003ae0,0x120e7b21,
+0x00000000,0x00000000,0x008f7de2,0xe8ffffe9,0x14f03d20,0x108eba04,0x028ef9e1,0xc100a4e1,
+0x009e08e1,0x00000000,0x900038e9,0x00975df8,0x020e1cf8,0x0087dff9,0x008738ed,0x00000000,
+0x009e1f9d,0xe8000110,0x021e1ce1,0x14002600,0x029ef889,0x120e3b05,0x008ee9e0,0x031ea9e3,
+0x00000001,0xc10000e0,0x129e7a3d,0xe8000055,0x041038e5,0x122f3a10,0xa4007bec,0x0097dff1,
+0xc10001e4,0xc10000e0,0x009e9ff1,0x00000000,0x020e79f0,0x021e9ce9,0x109e7905,0x029e7ae5,
+0x008e7be5,0x120e7905,0x008ee9e4,0x031ea9e7,0x00000001,0x129e7a3d,0xe8ffffbd,0x040038e5,
+0x00000000,0xa4007bbf,0x00000001,0x129baf3c,0xc10001e0,0x122e7a11,0xe80000f8,0x0097dfe4,
+0x020e78b9,0x14102e00,0x029ee4e5,0xc10000e1,0x10851410,0x900014e1,0x122e2f11,0xc10001e0,
+0x129bb83d,0xe80001a8,0x020e78b9,0x14102e00,0x029ee4e5,0xc10000e1,0x10851410,0x900014e1,
+0xe8fffda5,0x14102301,0x00000000,0x008f5f75,0xe8000259,0x14e03d01,0xc10000e1,0xc10040e0,
+0x009e7875,0xe8000571,0x048039e1,0xd2fffb4e,0xc1201319,0x00000000,0x031ea9ef,0x00000001,
+0xc10000e0,0x129e7a3d,0xe8000059,0x041038e5,0x120e3b04,0x122f3a10,0x0097dff1,0xc10001e0,
+0x033e25e0,0x009e5ff1,0x00000000,0x020e38f0,0x021e5ce5,0x109e3805,0x029e79e1,0x008ef8e4,
+0x008e29e1,0x00000000,0x031eb8e7,0x00000001,0xc10000e0,0x129e7a3d,0xe8ffffb9,0x040038e5,
+0x120e3b05,0x00000000,0x033be5e1,0xd2ffff03,0xe8000011,0x14102e3d,0xe800006d,0x14102801,
+0x1097df05,0xe8000034,0x021e1c7d,0x14003b00,0x129c7805,0x120e2e09,0x00000000,0x034c21e3,
+0x00000001,0xd2fffef4,0x099e31c1,0x00000000,0x900014e1,0x10851411,0xd1ffcf85,0x0010d500,
+0x0010ae00,0x028924e6,0x120e6e09,0x008e21e5,0x00000000,0x90003819,0x00000000,0x034c21e5,
+0xd2ffffc7,0x108e2809,0xe8000025,0x04f01fe1,0xd1ffe338,0x0010ad02,0xc100100d,0x120e1c40,
+0x10975d41,0x1087df40,0x02873819,0xc10001e0,0x0010d500,0x0097dfa1,0x021e5c7c,0x020e38a1,
+0xd1ffcf1c,0x109e3805,0x029e39e1,0x0080aee1,0x1097df05,0x021e1c7d,0xd2fffe60,0x129c7805,
+0x099e3119,0x10851410,0x900014e1,0xe8000011,0x14102e3d,0xe800006d,0x14102801,0x1097df05,
+0xe8000034,0x021e1c7d,0x14003b00,0x129c7805,0x120e2e09,0x00000000,0x034c21e3,0x00000001,
+0xd2fffe40,0x099e31c1,0x00000000,0x900014e1,0x10851411,0xd1ffcea9,0x0010d500,0x0010ae00,
+0x028924e6,0x120e6e09,0x008e21e5,0x00000000,0x90003819,0x00000000,0x034c21e5,0xd2ffffc7,
+0x108e2809,0xe8000025,0x04f01fe1,0xd1ffe25c,0x0010ad02,0xc100100d,0x120e1c40,0x10975d41,
+0x1087df40,0x02873819,0xc10001e0,0x0010d500,0x0097dfa1,0x021e5c7c,0x020e38a1,0xd1ffce40,
+0x109e3805,0x029e39e1,0x0080aee1,0x1097df05,0x021e1c7d,0xd2fffdac,0x129c7805,0x099e3119,
+0x10851410,0x900014e1,0x192e1501,0x118e9500,0x129e780c,0x122e3809,0x099f3ae4,0x099e3ae1,
+0xe8000365,0x14e038f8,0x10857809,0xc20000e4,0xc10000e8,0x11ce1581,0xc30400e4,0x009eba55,
+0x001e7901,0x022eb9e9,0x09bef8e9,0x108e7c0c,0x00000000,0xc24c38e1,0x120e7908,0xa40220e0,
+0xc30002e1,0x00000000,0x034e79e3,0x129e3805,0xe8000344,0x21cefbe5,0x14103801,0xc2845885,
+0xc3000185,0x00186101,0xc208f0e1,0x008818e1,0x11ce7d00,0x01ae1481,0x029e39e1,0xe8000289,
+0x14003801,0xe800009d,0x14e01f55,0xc1ff5ce0,0xc1001fe8,0xc1fff8e5,0x00000000,0x034e48e0,
+0x009e3a7d,0x122e380d,0x120fb80d,0xc100a4e0,0x00000000,0x008f7ee5,0x009e08e0,0xa40039f0,
+0x108e7905,0x00000000,0x900038e5,0xe8000045,0x14903d21,0x001eb901,0xc1fff8e0,0xa4003ae0,
+0x120e7c21,0x00000000,0x00000000,0x008f7de2,0xe8ffffe9,0x14f03d20,0x108eba04,0x028f39e1,
+0xc100a4e1,0x009e08e1,0x00000000,0x900038e9,0x00975df8,0x020e1cf8,0x0087dff9,0x008738f1,
+0x109e5f10,0xc10000e1,0x00000000,0x021e5ce5,0xc1000ae4,0x129eb93d,0x00000000,0x061e79ea,
+0x0088a1e5,0x00000000,0xa40262e7,0x00000001,0xe8000045,0x041038e5,0x00000000,0xa40062e4,
+0xa400a2ea,0x1097df11,0xc10001e1,0x020e38e4,0x009e5fe5,0x109e3804,0x021e5ce5,0x029e39e1,
+0xc1000ae0,0x008e7ae1,0x00000000,0x061e38e6,0x0088a1e1,0x00000000,0xa40122e3,0xe8000049,
+0x04101468,0x0097dfe1,0x00000000,0xa4001ee4,0xb80019e3,0x00000001,0xe8000028,0x120e7909,
+0x040015e0,0x10879e04,0x00869ae5,0xd1ffcc31,0x0010f801,0xc1000108,0x00157801,0x001ec601,
+0x10865911,0x00000000,0xa40162e8,0xa401a2e5,0x109e5f04,0xc10001e1,0x020e38e5,0x029e1ce1,
+0x111f7a00,0x111e3800,0x111f3901,0xc10001e0,0x009e5ff4,0x099eb8ed,0x109e7904,0x0097f9f0,
+0x09bebde9,0x020e38e4,0x900014e9,0x029e1ce1,0x111e3801,0x099e38ed,0x09be3ce1,0x10851420,
+0x900054e1,0xe8000045,0x04101469,0x00000000,0xa4001ee4,0xb80019e3,0x00000001,0xe8000028,
+0x120e7909,0x040015e0,0x10879e04,0x00869ae5,0xd1ffcb8d,0x0010f801,0xc1000108,0x00157801,
+0x001ec601,0x10865911,0x00000000,0xa401e2e8,0xa40222e5,0x109e5f04,0xc10001e1,0x020e38e5,
+0x029e1ce1,0x111f7a00,0x111e3800,0x111f3901,0xc10001e0,0x009e5ff4,0x099eb8ed,0x109e7904,
+0x0097f9f0,0x09bebde9,0x008e1f74,0x900014e8,0x020e78e5,0x00000000,0x029e5ce5,0x111e7901,
+0x099e79ed,0x09be7ce5,0x10851420,0x900054e5,0x11ce7800,0x01ae1481,0x029e39e1,0xe8fffd89,
+0x14103801,0x008e1f75,0x118e3801,0x120e3811,0x009514e1,0xc20900e4,0x120e1b0c,0xc10240e9,
+0x120e1608,0x008298e4,0x008e57e1,0x00000000,0x009eca50,0x008e39e1,0x122e7b7d,0x129e790d,
+0x008e7be5,0x122e7909,0xe8000014,0x009e7ae5,0x04e01428,0x900038e5,0xd6000152,0xd2fff59e,
+0xc1000019,0xc20000e8,0xc2ffffe0,0x11ee5515,0xc30400e8,0xc37fffe1,0x001eba00,0x001e3801,
+0x020eba55,0xd2fffca8,0x009e38e9,0x09be39e1,0x008ef8e9,0xd2fffcd5,0xc2857085,0xc3000185,
+0x10924941,0x1081c940,0x9000891c,0xc1007025,0x00900724,0x00924725,0x00000000,0x90010060,
+0x90014065,0x00000000,0x90008058,0x9000c05d,0x00000000,0x90000050,0x90004055,0xe8000058,
+0xc24d245d,0x14000300,0xc300025d,0xe8000081,0x14000305,0xe80001c5,0x1400030d,0x00000000,
+0xb8004055,0x00000000,0xb8000050,0xb800c05d,0x1091c740,0xb8010060,0xb8014065,0x00000000,
+0xb8008058,0xb800871d,0x07000101,0x10824741,0x00100901,0xc10024e1,0x00000000,0x060384e1,
+0xc10000e1,0xe8ffffb9,0x04e03838,0xc1000058,0xc1000065,0xc100082d,0xc1000034,0xc1000c28,
+0xc1000431,0xd6008156,0xd2ffff97,0xc10000e1,0xe8ffff8d,0x04e03810,0xc1000059,0xc24db4ed,
+0xc24db4f4,0xc24db4e0,0xc24db4f1,0xc24db4e8,0xc30002ec,0xc24db4e5,0xc30002f4,0xc30002e0,
+0xc30002f1,0xc30002e8,0xb801bd54,0xb801fc51,0xc30002e4,0xb8023b4c,0xb8027a49,0x00000000,
+0xb802b944,0xb802f843,0x0013c201,0xc1000064,0xc1000038,0xc1000435,0xc1000830,0xc1000c2c,
+0x10828f31,0xd600616a,0x00000000,0xb8040fe4,0xb80417e1,0x00000000,0xb8044ffc,0xb8060fe1,
+0x00000000,0xb8064fe5,0x00000000,0xb8068fe8,0xb806cfe1,0x00000000,0xb8070fe4,0x21ceb9e1,
+0x00000000,0x00000000,0xb8074fe1,0x00000000,0x90040fe8,0x21cef855,0x10859604,0x21ceb950,
+0xb80457ed,0xc10000f4,0x21cfb848,0x21ce7a4d,0xc10000f0,0x21ceb944,0x90060fed,0xc10000e0,
+0x90064fe8,0x21ce7841,0xc10000ec,0x90068fe4,0x21cfbfed,0xc10000e8,0x90070fe8,0x9006cff9,
+0xc10000e4,0x90074fe4,0x90044ff9,0xc10090e0,0x9007cfe0,0x90078ff5,0xe9ffff34,0x90084fec,
+0x90080ff1,0x0083cfe0,0x9008cfe4,0x90088fe9,0x04801611,0xd2fffe4b,0xc10000e1,0xe8fffe41,
+0x04e03810,0xc1000059,0xc24db4ed,0xc24db4f4,0xc24db4e0,0xc24db4f1,0xc24db4e8,0xc30002ec,
+0xc24db4e5,0xc30002f4,0xc30002e0,0xc30002f1,0xc30002e8,0xb8003d60,0xb8007c55,0xc30002e4,
+0xb800bb50,0xb800fa4d,0x00000000,0xb8013948,0xb8017846,0xc1000041,0x0013c201,0x008e9008,
+0xc10000e0,0xc10000e5,0x00000000,0x90003ae1,0x00000000,0xb8018fe8,0xb801cfe5,0xc10000ec,
+0xb8020fec,0xb8024fe1,0xc10000e0,0xb8028fe8,0xb802cfe5,0xc10000e0,0x90008fe0,0x90004fe5,
+0x00000000,0x90010fe0,0x9000cfed,0xc10000f8,0x21cf3954,0x21cf7a61,0xc10054e0,0x21ceb84c,
+0x21cefb51,0xc1001264,0x21ce3944,0x21ce7a49,0x00828fe0,0x90018ff4,0x90014ff9,0xc1004838,
+0x90020fec,0x9001cff1,0xc1004c34,0x90028fe4,0x90024fe9,0xc1005030,0x9002cfe0,0xc100542d,
+0xd600617a,0x00000000,0xb8088fe8,0xb80897e5,0xc10090e4,0x00000000,0xc10090e1,0x00000000,
+0x008410e6,0x00000000,0x21ce7ae6,0x00000000,0x90088fe5,0x00000000,0xb808cfe8,0xb808d7e7,
+0x00000001,0x10859604,0x21ce7ae5,0xe8ffff11,0x04801610,0x9008cfe4,0x0083cfe1,0xd2fffce3,
+0x10924941,0x1081c940,0x9000891c,0x90004921,0xc100c824,0x10920741,0x00924725,0x00134201,
+0xc1ff70e0,0xc1000031,0x008488e1,0xc24c942c,0x10829261,0xc1000044,0xc300022d,0xd600c18a,
+0x10830c05,0xe8ffffe9,0x14800c0c,0x108492c0,0x10834d61,0xc1ff70e0,0xc1000045,0xc24db440,
+0xc100003c,0x008488e1,0xc3000240,0xc1004830,0xc1001839,0xc1003034,0xc1007828,0xc100602d,
+0xd600a1a6,0x1091c741,0x00000000,0xb8004720,0xb800871d,0x07000102,0x10824741,0x10924941,
+0x1081c940,0x9000891c,0xc1002c25,0x00924725,0xc10000e1,0xe8000025,0x04e03814,0xc100003d,
+0xc1000038,0x00130201,0xc1000034,0x00128300,0x0012c401,0xd602c1be,0x1091c741,0x00000000,
+0xb800871d,0x07000102,0x10824741,0x10924941,0x1081c940,0x9000891c,0xc1003425,0x00924725,
+0x00000000,0xb8000240,0xb800423d,0xc1000039,0xc100042c,0xc1000830,0xc1000035,0xc1000c29,
+0xd600621a,0xc10000e4,0x90040340,0xc10000e1,0x00000000,0x900402e5,0x00000000,0x9004433d,
+0x00000000,0x900442e1,0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,0x1092497d,
+0x10924925,0x1081c97c,0x9000891c,0x9000c905,0x1081c724,0xc1005c25,0x00900724,0x00924725,
+0x00000000,0x90018068,0x9001c06d,0x00000000,0x90010060,0x90014065,0x00000000,0x90008058,
+0x9000c05d,0x00000000,0x90000050,0x90004055,0xc1ffece4,0xc1ffe8e0,0x00168201,0x00000000,
+0x034647e4,0x034ec7e2,0x00158300,0x00160501,0x00154401,0xc10480e4,0xa40244e4,0xc2aec0e1,
+0x00000000,0x061e59e6,0xc30001e0,0x00000000,0x120eb909,0xe8000014,0x0086fae1,0x14103909,
+0xe80001bd,0x14003b01,0xd1000228,0x110e3b01,0x0010db00,0x060539e1,0xc1000210,0x00000000,
+0x00108501,0xd1fffa5d,0x00000000,0x0010d400,0x00109b01,0xc1000211,0x00000000,0xa40255f3,
+0x00000001,0xe80001a1,0x14003c09,0x001ed601,0x120e7b08,0xc1fffce0,0x11debb91,0x00000000,
+0x008e39e1,0x00000000,0x034e3863,0x00000001,0x110e3801,0x029e3ae1,0xe800003d,0x14003801,
+0xc1fff8e1,0x008eb9e1,0xc1ffffe4,0x034e3a60,0xc1fffce1,0x00000000,0x008ebae0,0x008efbe7,
+0x11de7b90,0x110e3801,0x029e39e1,0xe8ffffdd,0x14103801,0xc10240e4,0xc10020e1,0xc238e5e4,
+0x009eb9ed,0x00000000,0x061e7ae6,0xe8000120,0x121e7949,0x14003c08,0x0095f8e5,0xd1000154,
+0xc10120e0,0xc10090e5,0x10911708,0x008098e4,0x0080dbe2,0x10911708,0xa402550d,0xd1fff985,
+0xc10120e1,0x00809be1,0xc20900e0,0x00109b01,0xd1fffd8c,0x060519e1,0x10855aa1,0x00115700,
+0x0080d550,0x00111801,0xc1001fe1,0xe8000039,0x0490385c,0xc1001f59,0xc108b850,0x00855551,
+0xd1fffdac,0x00809454,0x0080d463,0xc1ffffe4,0xc10048e1,0x009514e0,0x008596e5,0xe8ffffe5,
+0x04f0165d,0xd1001bd8,0x00109803,0x1091c77d,0x1091c725,0x00000000,0xb800c704,0xb8010061,
+0x00000000,0xb8004054,0xb8000051,0x00000000,0xb801c06c,0xb800871d,0x00000000,0xb800c05c,
+0xb8008059,0x1082477c,0xb8018068,0xb8014065,0x07000101,0x10824925,0x00100901,0xd1fffc44,
+0x00000000,0x0010db02,0x00108501,0xd1fffc34,0xc10090e0,0xc10048e5,0x0080dbe0,0x008098e6,
+0xd2fffe5b,0xd2fffe6e,0xc10240ed,0xc10002e1,0xe8ffff19,0x04f0385c,0xc1000259,0xc1009054,
+0xc1012051,0xd1fffbfc,0x00809560,0x0080d46f,0x10859604,0xc10090e4,0xc10048e1,0xe8ffffe8,
+0x008555e0,0x008514e5,0x0490165d,0xd2fffedf,0x10924941,0x1081c940,0x9000891c,0xc100c025,
+0x00900724,0x00924725,0x00000000,0x900740c4,0x900780c9,0x00000000,0x9006c0bc,0x900700c1,
+0x00000000,0x900640b4,0x900680b9,0x00000000,0x9005c0ac,0x900600b1,0x00000000,0x900540a4,
+0x900580a9,0x00000000,0x9004c09c,0x900500a1,0x00000000,0x90044094,0x90048099,0x00000000,
+0x9003c08c,0x90040091,0x00000000,0x90034084,0x90038089,0x00000000,0x9002c07c,0x90030081,
+0x00000000,0x90024074,0x90028079,0x00000000,0x9001c06c,0x90020071,0x00000000,0x90014064,
+0x90018069,0x00000000,0x9000c05c,0x90010061,0x00000000,0x90004054,0x90008059,0x00000000,
+0x90000051,0xc10000e1,0xe80001d1,0x04e03810,0xc10000c9,0x001bc201,0xc10000c4,0x001b8300,
+0xc10000c1,0xc25d5ee8,0xc2e352e4,0xc24f1ee1,0xc3fde9e8,0xc30bcbe4,0xc3fb30e1,0x001b7a00,
+0x001b3900,0x001af801,0xc25284e8,0xc277f9e4,0xc219fde1,0xc30763e8,0xc3f281e4,0xc30ffce1,
+0x001aba00,0x001a7900,0x001a3801,0xc2769ee8,0xc2cdbbe4,0xc237ade1,0xc3fc89e8,0xc3f1cee4,
+0xc30acfe1,0x0019fa00,0x0019b900,0x00197801,0xc2e890e8,0xc2c779e4,0xc255c2e1,0xc30f9ee8,
+0xc30898e4,0xc3ff4de1,0x00193a00,0x0018f900,0x0018b801,0xc2934be8,0xc21770e4,0xc2ad7ce1,
+0xc3f0bde8,0xc3f061e4,0xc3f89ce1,0x00187a00,0x00183900,0x0017f801,0xc2aa3ee8,0xc21caee4,
+0xc26cb5e1,0xc300b2e8,0xc3f434e4,0xc30f42e1,0x0017ba00,0x00177900,0x00173801,0xc28807e8,
+0xc23887e4,0xc2b0e2e1,0xc30d7ee8,0xc3f767e4,0xc304cfe1,0x0016fa00,0x0016b900,0x00167801,
+0xc2c853e8,0xc2e603e4,0xc23245e1,0xc3f530e8,0xc3f003e4,0xc30e31e1,0x00163a00,0x0015f900,
+0x0015b801,0xc28962e8,0xc29346e4,0xc28360e1,0xc30376e8,0xc30cb1e4,0xc3f642e1,0x00157a00,
+0x00153900,0x0014f801,0xc2f549e8,0xc20ab7e4,0xc26cbae1,0xc30fdce8,0xc3f023e4,0xc3f34ee1,
+0x0014ba00,0x00147900,0x00143801,0xc27ca0e8,0xc2a2a2e4,0xc2ca18e1,0xc309bde8,0xc30216e4,
+0xc3f137e1,0x0013fa00,0x0013b900,0x00137801,0xc28756e8,0xc278aae4,0xc235e8e1,0xc3f9e0e8,
+0xc3061fe4,0xc30ec8e1,0x00133a00,0x0012f900,0x0012b801,0xd606c22a,0x00000000,0xb8000050,
+0xb8004055,0x00000000,0xb8008058,0xb800c05d,0x00000000,0xb8010060,0xb8014065,0x00000000,
+0xb8018068,0xb801c06d,0x00000000,0xb8020070,0xb8024075,0x00000000,0xb8028078,0xb802c07d,
+0x00000000,0xb8030080,0xb8034085,0x00000000,0xb8038088,0xb803c08d,0x00000000,0xb8040090,
+0xb8044095,0x00000000,0xb8048098,0xb804c09d,0x00000000,0xb80500a0,0xb80540a5,0x00000000,
+0xb80580a8,0xb805c0ad,0x00000000,0xb80600b0,0xb80640b5,0x00000000,0xb80680b8,0xb806c0bd,
+0x1091c740,0xb80700c0,0xb80740c5,0x00000000,0xb80780c8,0xb800871d,0x07000101,0x10824741,
+0x00100901,0x10924941,0x1081c940,0x9000c904,0x9000891d,0xc100e824,0x90004920,0x10920741,
+0x00900724,0x00924725,0x00000000,0x90034084,0x90038089,0x00000000,0x9002c07c,0x90030081,
+0x00000000,0x90024074,0x90028079,0x00000000,0x9001c06c,0x90020071,0x00000000,0x90014064,
+0x90018069,0x00000000,0x9000c05c,0x90010061,0x00000000,0x90004054,0x90008059,0x00000000,
+0x90000051,0x00178200,0x00154301,0x00000000,0xb900c4e6,0xc10088e1,0x009e08e1,0x00000000,
+0x900038e5,0x00000000,0xb90104e6,0xc10084e1,0x009e08e1,0x00000000,0x900038e5,0x00000000,
+0xb80043e3,0x00000001,0xe800013c,0xc1ff78e5,0x14003800,0x008748e4,0x00150301,0xc1000271,
+0xe800002d,0x14103808,0xc100206d,0x00000000,0xb801c3e8,0xb80083e3,0xc10100e5,0x120e3808,
+0x028e7ae5,0x1086f810,0x9001c3e5,0x00000000,0xb801c3e3,0x00000001,0x129e3841,0xe80000f1,
+0x14003801,0xc10020e0,0xac031410,0x061e5b71,0xd1ffd368,0x009e386d,0x008e39e1,0x10808270,
+0x00000000,0x1200f809,0x00000000,0xac0354e0,0x8403141b,0x00000001,0xe80000b5,0x040006e1,
+0x00000000,0xb80255e3,0x00000001,0xc10000e0,0x129e7805,0xe8000099,0x041038e5,0xc12009e0,
+0xc1ffff19,0x00000000,0x9003dee1,0x1091c740,0xb8000050,0xb8004055,0x00000000,0xb800c704,
+0xb8008059,0x00000000,0xb800c05c,0xb8010061,0x00000000,0xb8014064,0xb8018069,0x00000000,
+0xb801c06c,0xb8020071,0x00000000,0xb8024074,0xb8028079,0x00000000,0xb802c07c,0xb8030081,
+0x00000000,0xb8034084,0xb8038089,0x00000000,0xb8004720,0xb800871d,0x07000101,0x10824741,
+0x00100901,0xd2fffede,0xc1000171,0xc10000e1,0xe800007d,0x04f0386c,0xc1000069,0xc1ffc0e1,
+0x008548e1,0xc10000e1,0xe8000059,0x04f03870,0xc100007d,0x00851a55,0xd1ffd0f0,0x10809e72,
+0xc100040d,0xe800001d,0x1410063d,0xd2ffff40,0xc1200ae1,0x00000000,0x9003dee1,0xc1ffff19,
+0xe800007d,0x14000601,0x108e0605,0x1087df04,0x800014e1,0xe8ffffc5,0x04901f70,0x10851481,
+0x10869a05,0xe8ffffa1,0x04901a6d,0xc10020e1,0xe8000085,0x04f01be0,0x00169b01,0xc1ffc0e4,
+0xc1ffe0e1,0x008e48e4,0x008e08e1,0x00851be4,0x00855be1,0xd1ffd074,0x10809e72,0xc100040d,
+0xe8000025,0x1410063d,0xd2fffec4,0xc1200ae1,0x00000000,0x9003dee1,0xc1ffff19,0xd2ffff92,
+0xc10000e1,0xe80000b1,0x14000601,0x108e4605,0x10869a04,0x800015e4,0xc10020e1,0xe8ffffb8,
+0x00000000,0x800014e5,0x04901ae0,0x10851404,0x10855505,0xc1ffc0e4,0xc1ff80e0,0xc1000069,
+0x008648e4,0x008608e1,0xc10000e1,0xe8000089,0x04f03870,0xc100007d,0x00159900,0x00155800,
+0x00851a61,0x00000000,0x031e166b,0x00000001,0xe800004d,0x14003801,0xd1ffcfd0,0x10809e72,
+0xc100060d,0x00000000,0x80001419,0x00000000,0x031e556b,0xc1003fe1,0xe8000025,0x041039e1,
+0xd2fffe0c,0xc1200be1,0x00000000,0x9003dee1,0xc1ffff19,0xd2ffff5e,0xc10000e5,0x1087df05,
+0xe8ffffa4,0x10855581,0x04901f70,0x10851480,0x10859681,0x10869a04,0xc10020e1,0xe8ffff6d,
+0x04901ae1,0x00000000,0x161e1b32,0xc1000058,0x12057808,0xc100005d,0xc10000e1,0xe80000ad,
+0x04f0386c,0xc1000069,0x00189601,0xc10000e1,0xe8000089,0x04f03870,0xc100007d,0xc1000084,
+0x00181900,0x00151801,0x00000000,0x031e206b,0x00000001,0xe8000139,0x14003801,0xd1ffbc84,
+0x10809e70,0x0010f803,0x00000000,0x034e1d84,0x031e946b,0xc230f4e5,0xc30002e4,0x008e22e0,
+0x120eba09,0x00000000,0x034e7ae7,0x00000001,0x00000000,0x21fe46e6,0x00000000,0x900038e5,
+0x1087df05,0xe8ffffa4,0x10886111,0x04901f70,0x10851480,0x10882081,0x10869a05,0xe8ffff71,
+0x04901a6c,0x1088a2c1,0xc10020e1,0xe80000a5,0x04f01be0,0x00169b01,0x00151501,0x00000000,
+0x031e196b,0x00000001,0xe80000c1,0x14003801,0xd1ffbbf0,0x10809e70,0x0010f803,0xc10000e1,
+0xe800005d,0x04f03870,0xc100007d,0xc10000f0,0x001ed801,0x00000000,0x034e1df0,0x031ebb6b,
+0xc230f4e5,0xc30002e4,0x008e14e0,0x120eba09,0x00000000,0x034e7ae7,0x00000001,0x1087df04,
+0x00000000,0x21fe46e5,0xe8ffffcc,0x108efb81,0x04901f70,0x108f3c10,0x900038e5,0x10869a04,
+0xc10020e1,0xe8ffff79,0x04901ae0,0x108514c1,0x1085d705,0xe8fffea5,0x14901730,0x10855510,
+0x10859611,0xd2fffc4a,0xc1000019,0x00000000,0x034e1d87,0xd2ffff0d,0xc10000e0,0x008e62e1,
+0x00000000,0x900039e1,0xc10000e1,0xe8ffffb1,0x04f03870,0xc100007d,0xc10000e9,0x00000000,
+0x034e1deb,0x1087df05,0xe8fffff4,0xc10000e0,0x008e54e1,0x04901f70,0x108eba10,0x900039e1,
+0xd2ffff7f,0x10924941,0x1081c940,0x9000c904,0x9000891d,0xc101e424,0x90004920,0x10920741,
+0x00900724,0x00924725,0x00000000,0x9004c09c,0x900500a1,0x00000000,0x90044094,0x90048099,
+0x00000000,0x9003c08c,0x90040091,0x00000000,0x90034084,0x90038089,0x00000000,0x9002c07c,
+0x90030081,0x00000000,0x90024074,0x90028079,0x00000000,0x9001c06c,0x90020071,0x00000000,
+0x90014064,0x90018069,0x00000000,0x9000c05c,0x90010061,0x00000000,0x90004054,0x90008059,
+0x00000000,0x90000051,0x00188200,0x00160301,0x00000000,0xb900c4e6,0xc1015ce1,0x009e08e1,
+0x00000000,0x900038e5,0x00000000,0xb90104e6,0xc10158e1,0x009e08e1,0x00000000,0x900038e5,
+0x00000000,0xb80043f7,0x00000001,0xe8000338,0xc1fea4e1,0x14003d00,0x008848e0,0x00164301,
+0xc1000281,0x00000000,0xb801c3f3,0xc21000e1,0x029e3ce1,0xe8000319,0x14003801,0xc10004ed,
+0xc23228e8,0x160e7b78,0xc23230e1,0xc30002e8,0x00000000,0xc30002e1,0x00000000,0x0087b9e0,
+0x0317fbea,0xe8000029,0x14103d08,0xc1002075,0xc10100e0,0xb80083e1,0x028e3ce1,0x00000000,
+0x9001c3e2,0x120e3809,0x10877811,0x009e5f74,0xb801c2e5,0x00000000,0x01de1d7d,0x00000000,
+0x00000000,0x061eb9e1,0x109e0821,0x00000000,0x900038e4,0x00877a75,0x00000000,0x00000000,
+0xb80202ea,0xc1fff8e8,0x109e4810,0xc10000e1,0xe800007c,0x008688e9,0x04f03874,0xc1000070,
+0x900039e9,0xc1ffb8e1,0x008588e1,0x00000000,0x031e5e73,0xc232c8e1,0xc30002e0,0x120e7905,
+0x00000000,0x00000000,0x031579e1,0xc10000e1,0xe8000031,0x04f03880,0xc100006d,0x00851c59,
+0xd1ffcb88,0x1080a270,0x0010d503,0x1086db04,0x80001419,0xe8ffffed,0x04901b80,0x10851481,
+0x10871c05,0xe8ffffa9,0x04901c75,0xe8000065,0x04f01d7c,0x00171d01,0xc1ffb8e4,0xc1ffd8e1,
+0x008e48e4,0x008e08e1,0x00851de4,0x00855de1,0x1080a270,0x031e5e73,0xc232c8e1,0xc30002e0,
+0x120e7905,0x00000000,0x0310f9e1,0xd1ffcb1f,0x00000000,0x10871c04,0x80001519,0xe8ffffd4,
+0x80001419,0x04901c7c,0x10855504,0x10851405,0xc10000e1,0xe800007d,0x04f0387c,0xc1000071,
+0xc1ffb8e4,0xc1ff78e1,0x0085c8e4,0x008588e1,0xc10000e1,0xe8000051,0x04f03880,0xc100006d,
+0x00155700,0x00851c59,0x00000000,0x031e1573,0x00000001,0xe800001d,0x14003801,0xd1ffcaac,
+0x1080a272,0xc100020d,0x00000000,0x80001419,0x1086db05,0xe8ffffd5,0x04901b80,0x10851480,
+0x10855581,0x10871c05,0xe8ffffa9,0x04901c7d,0x00000000,0xb801d9e3,0x00000001,0x129e3841,
+0xe80001c9,0x14003801,0xd1ffc8d4,0x00109a00,0x1080e273,0x00109a00,0xac031911,0xd1ffcbbe,
+0x0010c601,0x00000000,0xac0359e0,0x8403191b,0x00000001,0xe8000195,0x040006e1,0x00000000,
+0xb80258e3,0x00000001,0xc10000e0,0x129e7805,0xe8000179,0x041038e5,0xc12009e0,0xc1ffff19,
+0x00000000,0x9003e2e1,0x1091c740,0xb8000050,0xb8004055,0x00000000,0xb800c704,0xb8008059,
+0x00000000,0xb800c05c,0xb8010061,0x00000000,0xb8014064,0xb8018069,0x00000000,0xb801c06c,
+0xb8020071,0x00000000,0xb8024074,0xb8028079,0x00000000,0xb802c07c,0xb8030081,0x00000000,
+0xb8034084,0xb8038089,0x00000000,0xb803c08c,0xb8040091,0x00000000,0xb8044094,0xb8048099,
+0x00000000,0xb804c09c,0xb80500a1,0x00000000,0xb8004720,0xb800871d,0x07000101,0x10824741,
+0x00100901,0xd2fffce2,0xc1000181,0xe8000079,0x14102009,0x00000000,0xb80103e3,0x00000001,
+0x121e7805,0xc27d00e1,0xe8000069,0x040039e1,0xc2bb80e1,0xe800005d,0x040039e1,0xc2dac0e1,
+0xe8000079,0x040039e1,0xc2fa00e1,0xe800006d,0x040039e1,0xc23880e1,0xc30001e1,0xe800005d,
+0x040039e1,0x00000000,0xb80143e7,0xc2bb80e1,0xe8000051,0x041039e1,0xc10000e1,0xd2fffc86,
+0x001ef801,0x00000000,0xb80103e5,0xd2ffff9b,0x00000000,0xb80143e7,0xc27d00e1,0xe8000015,
+0x041039e1,0xc10003e1,0xd2fffc5a,0x001ef801,0xd2fffffa,0xc10002e1,0xd2fffc4a,0xc10000ed,
+0xd2ffffbe,0xc10001e1,0xc10000e1,0xe80001a5,0x04f0387c,0xc1000071,0xc1ffb8e8,0xc1feb8e4,
+0xc1ff78e1,0x008948e8,0x008908e4,0x0088c8e1,0xc1000068,0xc1000164,0xc1000261,0xc10000e1,
+0xe8000159,0x04f03880,0xc100006d,0x00156301,0x0015e500,0x00851a90,0x0015a401,0x00000000,
+0x031e1773,0x00000001,0xe800010d,0x14003801,0xd1ffc838,0x1080a272,0xc100060d,0x00000000,
+0x80001419,0x00000000,0x031e1573,0x00000001,0xe80000a5,0x14003809,0xe80000b5,0x14003801,
+0xe80000c1,0x14003805,0xe80000b9,0x1400380d,0x00000000,0x031e5573,0x00000001,0x129e3905,
+0xe8000021,0x14003801,0x109e3905,0x00000000,0x031e14e3,0x00000001,0x00000000,0x800054e1,
+0x00000000,0x031e9958,0x031f1669,0x00000000,0x031e5859,0xc1003fec,0xc1003fe1,0xc1003fe5,
+0x010ebae4,0x00000000,0x010efced,0x010e39e0,0x028e7be9,0x028e39e1,0xe800005d,0x14003801,
+0xd2fffd88,0xc1200be1,0x00000000,0x9003e2e1,0xc1ffff19,0x00000000,0x031e166a,0xd2ffff76,
+0x00000000,0x800094e0,0x800054e1,0xd1ffc75c,0x1080a272,0xc100060d,0x00000000,0x80005419,
+0xd1ffc748,0x1080a272,0xc100060d,0xd2ffff44,0x8000941b,0x1086db04,0xc10060e4,0xc10060e1,
+0xe8fffedc,0x008514e0,0x008596e5,0x04901b80,0x1085d780,0x10855581,0x10871c05,0xe8fffea0,
+0x10869a0d,0x04901c7c,0x1086180c,0x1086590d,0xc232c8f0,0x161e5d90,0x161e1f91,0xc1ffb8f5,
+0xc30002f0,0xc10001ec,0xc1feb8e9,0x108e7908,0x108e3808,0xc1000069,0x008648f4,0x0085c8e8,
+0x00863bf1,0xc1000858,0x12057908,0x12053809,0xc10000e1,0xe800017d,0x04f03874,0xc1000071,
+0x1219da08,0xc1000098,0x00195601,0xc10000e1,0xe8000145,0x04f03880,0xc100006d,0xc10000a0,
+0x00191900,0x0088e65d,0x00000000,0x031ee473,0x00000001,0xe8000305,0x14003b01,0xc1ffffe0,
+0x031e1e71,0x00000000,0x00000000,0x008e7be1,0xc1feace0,0x00000000,0x1080a271,0x008108e1,
+0x120e3805,0x00000000,0x031e18e3,0x00000001,0xc232d8e0,0x160eb83d,0xc30002e1,0x008e3ae1,
+0x00000000,0x031ef8e7,0x00000001,0xd1ffb444,0xc23334e0,0x160e7b51,0xc30002e1,0x0080f9e1,
+0x00000000,0x031e239d,0x00000000,0x034e21a2,0xc1feace4,0x00000000,0xc230f4e9,0xc30002e8,
+0x00000000,0x120ef809,0x008e25e0,0x034e48e4,0x034ebbeb,0x00000001,0x00000000,0x21fe79e9,
+0x109e3821,0xc1feb0e0,0x900038e5,0x00000000,0x034e48e0,0x034e21a3,0x00000001,0x008e25e0,
+0x21fe79e9,0x109e3811,0xc1feb4e0,0x900038e5,0x00000000,0x034e48e0,0x034e21a3,0x00000001,
+0x008e25e0,0x21fe79ea,0x00000000,0x900038e5,0x00000000,0xc10060e0,0x1086db05,0xe8fffeec,
+0x00000000,0x0088e3e1,0x04901b80,0x10892480,0x108a2811,0x10871c04,0xc10090e1,0xe8fffeb0,
+0x00000000,0x008965e1,0x04901c74,0x1089a60d,0xe800016d,0x04f01d7c,0x00171d01,0x00000000,
+0x16091d0d,0x0018d500,0x00000000,0x12195a09,0x00000000,0x031ed973,0x00000001,0xe80001f9,
+0x14003b01,0xc1ffffe0,0x031e1e71,0x00000000,0x00000000,0x008e7be1,0xc1feace0,0x00000000,
+0x1080a271,0x008108e1,0x120e3805,0x00000000,0x031e18e3,0x00000001,0xc232d8e0,0x160eb83d,
+0xc30002e1,0x008e3ae1,0x00000000,0x031ef8e7,0x00000001,0xd1ffb2dc,0xc23334e0,0x160e7b51,
+0xc30002e1,0x0080f9e1,0xc10000e1,0xe80000b5,0x04f03880,0xc100006d,0xc10000f4,0x008f245d,
+0x00000000,0x031efc95,0x00000000,0x034e61f5,0xc1feace5,0xc230f4e8,0x00000000,0xc10060e1,
+0xc30002e8,0x034e48e4,0x120efb09,0x008f3ce0,0x034ebbe8,0x008e23e7,0x00000001,0x00000000,
+0x21fe79e9,0x109e3821,0xc1feb0e0,0x900038e5,0x00000000,0x034e48e0,0x034e21f7,0x00000001,
+0x008e23e0,0x21fe79e9,0x109e3811,0xc1feb4e0,0x900038e5,0x00000000,0x034e48e0,0x034e21f7,
+0x00000001,0x1086db04,0x21fe79e8,0x008e23e1,0xe8ffff71,0x04901b80,0x108f7d10,0x900038e5,
+0x10871c04,0xc10090e1,0xe8fffec8,0x00000000,0x0088e3e1,0x04901c7c,0x1089240d,0xc10000e1,
+0xe8000039,0x04f03880,0xc100006d,0xc100002d,0xc10020e1,0xe8000015,0x04f01fe0,0x00171f01,
+0x00129401,0xd6002306,0x1086db05,0xe8ffffe5,0x04901b80,0x1082cb11,0x10869a05,0xe8fffcd4,
+0x10851431,0x14901a30,0x10855530,0x10859631,0xd2fff97a,0xc1000019,0x00000000,0x034e21a3,
+0x00000001,0x008e25e1,0xc10000e4,0x109e3821,0x00000000,0x900038e5,0x00000000,0x034e21a3,
+0x00000001,0x008e25e1,0xc10000e4,0x109e3811,0x00000000,0x900038e5,0x00000000,0x034e21a3,
+0xd2fffdb1,0xc10000e0,0x008e65e1,0x00000000,0x900039e1,0xc10000e1,0xe8ffff29,0x04f03880,
+0xc100006d,0xc10000e9,0x00000000,0x034e21eb,0x00000001,0x008e23e1,0xc10000e4,0x109e3821,
+0x00000000,0x900038e5,0x00000000,0x034e21eb,0x00000001,0x008e23e1,0xc10000e4,0x109e3811,
+0x00000000,0x900038e5,0x00000000,0x034e21eb,0x1086db05,0xe8ffffb4,0xc10000e0,0x008e63e1,
+0x04901b80,0x108eba10,0x900039e1,0xd2fffeb7,0x10924941,0x1081c940,0x9000891d,0x10924771,
+0x009e820d,0xe800002d,0x14803a00,0x90000408,0xc10000e5,0x001e3a00,0x009eba0d,0xe8fffff9,
+0x14e03a00,0x108e7905,0x00000000,0x900004e1,0x00000000,0x900005e5,0x1091c741,0x00000000,
+0xb800871d,0x07000102,0x10824741,0x10924941,0x1081c940,0x9000c904,0x9000891d,0xc1009424,
+0x90004920,0x10920741,0x00900724,0x00924725,0x00000000,0x90034084,0x90038089,0x00000000,
+0x9002c07c,0x90030081,0x00000000,0x90024074,0x90028079,0x00000000,0x9001c06c,0x90020071,
+0x00000000,0x90014064,0x90018069,0x00000000,0x9000c05c,0x90010061,0x00000000,0x90004054,
+0x90008059,0x00000000,0x90000051,0x00154200,0x00158300,0x0015c401,0x00000000,0xa40243e0,
+0xac00c367,0x00000001,0xe800025d,0x14103809,0x00000000,0xa40203e3,0x00000001,0x129e3821,
+0xe800023d,0x14003801,0xc1000261,0x129e0504,0xb80002ed,0x111e7800,0x111e8400,0xc10000e1,
+0x00000000,0x029e79e9,0x109e8821,0x00000000,0x90003aed,0x00000000,0x00000000,0xb80042ee,
+0x109e8811,0xe80002d0,0xc1fff8f1,0x041038e4,0x008508f0,0x90003aed,0xc10190e1,0xe80001f1,
+0x04f019e1,0x12109911,0xd1fffe88,0xc1ffe8e4,0xc1ffece1,0x00000000,0x008108e0,0x008148e5,
+0xc100050d,0x129e993c,0xc248b8e0,0x109e4841,0x121f3a08,0x129ed90c,0x109e8831,0x120e5808,
+0x900039f0,0xc30002e1,0x0086b9e0,0x90003aed,0xc29e08e8,0xc1000089,0xc30001e9,0x001eba01,
+0x1088a204,0xc1002de0,0xc10000e5,0xe8fffff4,0x00000000,0x90003ae5,0x049022e0,0x108eba11,
+0xc1000085,0xc1ffe8e0,0xc1000064,0xc1000081,0x008708e0,0xc1000060,0x1086d649,0x00000000,
+0x031e5a87,0xc10000e1,0xe8000071,0x04f038e4,0xc1000089,0xc29e08e0,0x0085e06d,0xc30001e1,
+0x008598e1,0x00109500,0x0340dc65,0xd1ffc05f,0x00000000,0x034e5c64,0x80001719,0x00000000,
+0x031e1a85,0xc10001e1,0x1088a204,0x00000000,0x10861811,0x10882004,0x00000000,0x020e78e5,
+0xe8ffffc4,0x1085d704,0x109e7905,0x049022e0,0x10859610,0x900016e5,0x10886105,0xe8ffff81,
+0x14902110,0x10865911,0xc10027e1,0xe800002d,0x04f020e1,0x008ea06d,0x10882004,0xc10027e0,
+0xc10000e5,0xe8fffff4,0x00000000,0x80003ae5,0x049020e0,0x108eba05,0xd1ffbe44,0x00109400,
+0x0010d503,0x1091c740,0xb8000050,0xb8004055,0x00000000,0xb800c704,0xb8008059,0x00000000,
+0xb800c05c,0xb8010061,0x00000000,0xb8014064,0xb8018069,0x00000000,0xb801c06c,0xb8020071,
+0x00000000,0xb8024074,0xb8028079,0x00000000,0xb802c07c,0xb8030081,0x00000000,0xb8034084,
+0xb8038089,0x00000000,0xb8004720,0xb800871d,0x07000101,0x10824741,0x00100901,0xd2fffdd2,
+0xc1000161,0xd2fffdca,0xc1000061,0xc101f4e1,0xe800005d,0x04f019e1,0xd1fffc98,0xc1ffece0,
+0xc10190e5,0xc1ffe8e0,0x009659e4,0x008108e1,0xc100050c,0x12109908,0x008148e1,0xc248b8e0,
+0x129f590c,0x109f0841,0xd2fffe28,0x109e8830,0xc30002e1,0x120e1808,0x108e7830,0xc10000ed,
+0x0086b9e0,0x90003cf4,0x90003aed,0xd1fffc44,0xc1ffece1,0xc1ffe8e0,0x008108e0,0xc101f4e5,
+0xc100030c,0x009099e4,0x008148e1,0xc248b8e0,0xa40216e0,0xc100ffe9,0xc30002e0,0xc10000f4,
+0x109f0841,0xc10000ec,0x109e0830,0x108e7861,0x00000000,0x900038ec,0x90003cf5,0xd2fffdb4,
+0x128e3811,0x120e1808,0x029eb8e9,0x0086b9e0,0x800216e9,0x12165904,0xc100b4e1,0xe8000171,
+0x04f019e1,0x00109901,0xd1fffbc8,0xc1ffe4e4,0xc1ffe8e1,0x00000000,0x008148e0,0x008108e5,
+0xc100240d,0xc1ffe4e8,0xc1fff0e4,0xc1ffece1,0x008148e0,0x034088e8,0x008108e5,0xd1fffb96,
+0xc100060d,0xc248b8e4,0xc10000e8,0x109e0831,0xc30002e4,0x900038e8,0x120e1809,0x108e7991,
+0x0086b9e1,0xc1ffe8e0,0xc1000085,0xc1000080,0x10875748,0x0087c8e1,0x10879648,0xc100006c,
+0xc1000071,0x00000000,0x031e5a84,0x034edf72,0xc10001e9,0xc10000e1,0xe8000084,0x020ebaed,
+0x04f038e4,0xc1000088,0x10967a05,0xc29e08e0,0x0085e074,0x00862079,0xc30001e1,0x00859be1,
+0x00109500,0x0340df71,0xd1ffbda3,0x010e0664,0x034e5f70,0x80001819,0x00000000,0x800017e1,
+0x00000000,0x00000000,0x031e1a85,0xc10001e1,0x1088a204,0x020e38e4,0x10882005,0x10861804,
+0x109e7805,0xe8ffffbc,0x1085d704,0x900016e5,0x049022e0,0x1086db10,0x10859611,0x10886105,
+0xe8ffff65,0x14902110,0x10871c11,0xc10027e1,0xe8fffd69,0x04f020e1,0x008ea074,0x008ee079,
+0xc10000e4,0xc10027e1,0x10882004,0xc10000e4,0x80003be5,0xe8ffffec,0x80003ae5,0x049020e0,
+0x108efb04,0x108eba05,0xd2fffd33,0xc100f4e1,0xe8000065,0x04f019e1,0xc100b4e0,0xc248b8e5,
+0xc1003fe0,0x009659e0,0x10928861,0xc30002e4,0x029e19e0,0x109f8851,0x129e193c,0x129f590c,
+0x1212f811,0x121ff808,0x109e8830,0x109f0841,0xd2fffeb4,0xc10000ec,0x120e1809,0x108e79c0,
+0x90000a2c,0x90003cf5,0x0086b9e0,0x90003efc,0x90003aed,0xd1fff9fc,0xc1ffece1,0xc1ffe8e0,
+0x008108e0,0xc100f4e5,0xc100030c,0x009099e4,0x008148e1,0xc248b8e0,0xc10000f4,0x109f0841,
+0xd2fffe64,0x109e8830,0xc30002e1,0x120e1808,0x108e78f0,0xc10000ed,0x0086b9e0,0x90003cf4,
+0x90003aed,0x10924941,0x1081c940,0x9000891c,0xc1003c25,0x00924725,0x00000000,0xb80003e7,
+0xc10227e1,0xe8000085,0x04a039e1,0xc10240e4,0xc20900e1,0x008482e0,0x900003e5,0xc10048e1,
+0x008442e1,0xe8000051,0x04e01149,0xc1fffce0,0xb800113c,0xc24c5435,0x00000000,0x034411e1,
+0xc1000038,0xc24c7431,0xc100042c,0x00000000,0xc3000235,0xc3000230,0x00000000,0x00129101,
+0xd600631a,0xc10048e1,0x008451e1,0xe8ffffc1,0x04801149,0x1091c741,0x00000000,0xb800871d,
+0x07000102,0x10824741,0xd2ffff94,0x108e7965,0x120e3909,0x0084b808,0x900003e5,0x10924941,
+0x1081c940,0x9000891d,0x10924771,0xc10048e0,0xc100012d,0x008282e1,0xd600832a,0x1091c741,
+0x00000000,0xb800871d,0x07000102,0x10824741,0x1092497d,0x10924935,0x1081c97c,0x9000891c,
+0x9000c905,0x1081c734,0x90004920,0xc1002c25,0x00920724,0xc100b825,0x00900724,0x00924725,
+0x00000000,0x900680b8,0x9006c0bd,0x00000000,0x900600b0,0x900640b5,0x00000000,0x900580a8,
+0x9005c0ad,0x00000000,0x900500a0,0x900540a5,0x00000000,0x90048098,0x9004c09d,0x00000000,
+0x90040090,0x90044095,0x00000000,0x90038088,0x9003c08d,0x00000000,0x90030080,0x90034085,
+0x00000000,0x90028078,0x9002c07d,0x00000000,0x90020070,0x90024075,0x00000000,0x90018068,
+0x9001c06d,0x00000000,0x90010060,0x90014065,0x00000000,0x90008058,0x9000c05d,0x00000000,
+0x90000050,0x90004055,0xc1ffece8,0xc1ffe8e4,0xc1ffe4e1,0x00000000,0x034a47e8,0x034a07e5,
+0x00000000,0x0349c7e2,0x001ac201,0x001a8500,0x00000000,0x00154401,0x00000000,0xb801c3e4,
+0xb80143ef,0xc24000e1,0x029eb9e1,0xe8000011,0x14003a00,0x00198301,0x120efb05,0x121e3b3c,
+0x121e7b1d,0x129e3804,0x129e793d,0xe8000014,0x109e3821,0x14003a00,0x008538e5,0x1085140d,
+0xc29eece1,0xc30001e1,0x00000000,0xa00038e3,0x00000001,0xe8000025,0x14103801,0xd1ffb308,
+0x00109403,0xc29eece4,0xc10001e1,0xc30001e5,0x00000000,0x800039e1,0x00000000,0xb801e6e7,
+0xc21000e1,0x029e39e1,0xe8000241,0x14003801,0xc10001e5,0xc10000e0,0x900028e5,0xe80003c9,
+0x04f038e4,0xc1000095,0x00000000,0x16089431,0xc24bb4e8,0x00000000,0xc24bb4f1,0x10892a28,
+0xc1fff8ec,0xc24bb4e5,0xc2100ce0,0xc30002e4,0xc30002f1,0xc30002e8,0x0088d5e0,0xc10008e1,
+0xc10004e0,0x008862f0,0x0087f8e9,0x10872920,0x0087b8e4,0x008808ed,0xc100006c,0x00161c00,
+0x10876a21,0xc1000068,0xc100005c,0x00166401,0xc10000e1,0xe8000231,0x04f0389c,0xc10000b1,
+0x001b5901,0xc10000bc,0x0015a000,0xc10000b9,0x00000000,0xa4026de0,0x034e63b9,0x00000000,
+0xb80021e7,0xe8000040,0x00000000,0x008557e5,0x14103808,0x900016e5,0x00000000,0xa4022de3,
+0x00000001,0x129e3821,0xe8000169,0x14003801,0x00000000,0x034e1f8b,0x00000001,0x00000000,
+0x900016e1,0x00000000,0xb801e6e7,0xc21000e1,0x029e39e1,0xe800015d,0x14003801,0xe8000149,
+0x14102c01,0xc10000e1,0x0010ed00,0xb800a614,0x0010ab01,0xd1fff65a,0x00113801,0x00150601,
+0x109e0950,0x034160b8,0x109e8961,0x00000000,0x90003851,0xd1ffce50,0x109e0980,0x109e4971,
+0x0010ab00,0x900039b0,0x90003aa5,0x00112d00,0x90003894,0x0010d501,0xe800012d,0x14000601,
+0x00000000,0xb8004055,0x1091c77c,0xb8000050,0xb800c05d,0x1091c734,0xb8008058,0xb8010061,
+0x00000000,0xb800c704,0xb8018069,0x00000000,0xb8014064,0xb8020071,0x00000000,0xb801c06c,
+0xb8028079,0x00000000,0xb8024074,0xb8030081,0x00000000,0xb802c07c,0xb8038089,0x00000000,
+0xb8034084,0xb8040091,0x00000000,0xb803c08c,0xb8048099,0x00000000,0xb8044094,0xb80500a1,
+0x00000000,0xb804c09c,0xb80580a9,0x00000000,0xb80540a4,0xb80600b1,0x00000000,0xb805c0ac,
+0xb80680b9,0x00000000,0xb806c0bc,0xb8004721,0x1082477c,0xb80640b4,0xb800871d,0x07000101,
+0x10824935,0x00100901,0xd2fffdce,0xc10002e5,0x00000000,0x034e1e8a,0xd2fffeae,0x00000000,
+0x900016e1,0xd2fffec4,0xc100b8e1,0x008e2ae2,0xe8000029,0x14102501,0xc10000e1,0xd1ffabc4,
+0x0010ed01,0x00812f90,0x00117800,0x0010ab02,0xd2fffeb2,0x00150601,0x00000000,0x031e1db1,
+0xd2ffffdf,0x00000000,0x108b2c04,0x108bae11,0xe8fffe00,0x108b6de9,0x04902c9c,0x10859610,
+0x108befe9,0x00000000,0xb80066e3,0x00000001,0xe8000079,0x14103809,0x00000000,0xb800a6e3,
+0x00000001,0xe8000065,0x14003801,0x00000000,0x034e1c68,0x034e696a,0x00112600,0x0010a300,
+0x0010d902,0x109e5820,0x082eb9e0,0x109e0951,0xc1fff8e4,0x900018e8,0x900039e9,0x00000000,
+0x034148e4,0x9000386d,0x00000000,0x034e696a,0xd1001769,0x109e0961,0x00000000,0x900038e5,
+0xe8fffe41,0x14100601,0xc10000e1,0xe8000061,0x04f0389c,0xc10000b1,0xc1000058,0x00155900,
+0x00152901,0x00000000,0xa40255e0,0x034e635b,0x00000001,0xe8000078,0x008e57e5,0x14103809,
+0x0010b900,0x03415468,0x03412059,0xd1ffae46,0x0010d501,0x108b2c05,0xe8ffffcc,0x10851421,
+0x04902c9c,0x10859610,0x108555e9,0x00000000,0xb80028e1,0xc10240e0,0x10896505,0xc20900e4,
+0x0086dbe0,0xc10074e1,0x008659e0,0x00000000,0x0085d7e5,0xe8fffcbd,0x049025e0,0x10869a10,
+0x10861811,0xd2fffd9e,0xc1000019,0xd1fff998,0x0080d468,0x0010b903,0xd2ffff9f,0x10924941,
+0x1081c940,0x9000891d,0x10924761,0xc10000e1,0xe8000011,0x04e03810,0xc1000029,0xd600033e,
+0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,0x1092497d,0x10924935,0x1081c97c,
+0x9000891c,0x9000c905,0x1081c734,0x90004920,0xc1002c25,0x00920724,0xc1008825,0x00900724,
+0x00924725,0x00000000,0x90028078,0x9002c07d,0x00000000,0x90020070,0x90024075,0x00000000,
+0x90018068,0x9001c06d,0x00000000,0x90010060,0x90014065,0x00000000,0x90008058,0x9000c05d,
+0x00000000,0x90000050,0x90004055,0xc1ffece8,0xc1ffe8e4,0xc1ffe4e1,0x00000000,0x034747e8,
+0x034707e5,0x00000000,0x0346c7e1,0x00158201,0x00178401,0x0017c300,0x00000000,0x00168501,
+0x00000000,0xb80302e3,0x00000001,0xe800008c,0xc1000061,0x14103800,0x00154300,0xc100005d,
+0xc10003e0,0xc1ffff19,0x00000000,0x9003c2e1,0x00000000,0xb8004055,0x1091c77c,0xb8000050,
+0xb800c05d,0x1091c734,0xb8008058,0xb8010061,0x00000000,0xb800c704,0xb8018069,0x00000000,
+0xb8014064,0xb8020071,0x00000000,0xb801c06c,0xb8028079,0x00000000,0xb802c07c,0xb8004721,
+0x1082477c,0xb8024074,0xb800871d,0x07000101,0x10824935,0x00100901,0x00000000,0xb801c3e7,
+0xc21000e1,0x029e39e1,0xe8000059,0x14003801,0xe8000049,0x14101b05,0xc1000951,0xd1ffb306,
+0x10808271,0x00000000,0xb80196e3,0x00000001,0x009e3819,0xe8000045,0x04e03851,0xd2ffff54,
+0xc10000e0,0xc1200ce5,0x00000000,0x900356e0,0x9003d6e5,0xc1ffff19,0xd2ffffc6,0xc1001151,
+0xe8000011,0x14101b05,0xd2ffffb6,0xc1001151,0xd2ffffae,0xc1002051,0x00000000,0xb801d5e3,
+0x00000001,0x129e3841,0xe800005d,0x14003801,0x1200d40c,0xac031510,0x10809671,0xd1ffb51f,
+0x00000000,0xac0355e0,0x8403151b,0x00000001,0xe8000035,0x040006e1,0x00000000,0xb8025fe3,
+0x00000001,0xc10000e0,0x129e7805,0xe8000019,0x041038e5,0xc12009e0,0xc1ffff5d,0x00000000,
+0x9003d6e1,0xc1fff8e4,0xb801d5e0,0xc1fffce1,0xc21000f0,0x008ec8e4,0x109e8951,0xd1ffa348,
+0x109e0960,0x008e48e1,0x10809670,0x900038e4,0x0010db01,0x00115a00,0x90003aec,0x029138f1,
+0xe8000019,0x14000601,0xe8000011,0x14101701,0xc1ffff5c,0x9003d619,0xc1fffce1,0xc1ffe8e0,
+0xb801d5e0,0x034e48e1,0x008088e3,0x028e38e5,0x00000000,0x9001d5e1,0x00000000,0xb80215e0,
+0xb8005ae7,0x00000001,0x028e38e5,0x00000000,0x900215e1,0x00000000,0xb801960d,0xd1ffb107,
+0xd1ffb2c8,0xc1ffe8e1,0x00000000,0x008088e1,0xc100200d,0xc20000e5,0xc20000e0,0x00150600,
+0xc3ffe6e5,0xc3ffe2e0,0x029e46e5,0xe8000061,0x041039e1,0xc20000e1,0xc30001e1,0xc10000e0,
+0x029e46e1,0xe800001d,0x041038e5,0xd1ffb1ac,0xc1ffe8e1,0x00000000,0x008088e1,0xc100100d,
+0xc20000e1,0xc30008e1,0x029e14e1,0xe8000155,0x14003801,0xc10009e5,0xd1ffb250,0xc1ffe8e1,
+0x0010f900,0x008088e2,0x00160601,0xd1ffb114,0x10809673,0x00000000,0xb80196e0,0xb8001aeb,
+0x00000001,0x00957819,0x008e7a55,0x01be18e5,0x00000000,0x06163861,0xe8000111,0x14103a00,
+0xc1000050,0x00967961,0x00000000,0xb801d6e7,0x109e0841,0x00000000,0x900038e5,0x00000000,
+0xb80216e7,0x109e0831,0xc10000e0,0x900038e5,0x00151900,0x900356e1,0xe800004c,0x00955551,
+0x14101701,0xc1fff0e0,0x109e8950,0x109e4961,0xd1fff660,0x109e0970,0x008088e1,0x0010df00,
+0x90003a74,0x9000386d,0x00115a00,0x90003970,0x00111e01,0xe8000011,0x14000601,0xc1ffff5c,
+0x9003d619,0xe8000039,0x140017fd,0xc1fff0e4,0xc1fff4e1,0x00000000,0x034e48e7,0x00000001,
+0x00000000,0x900256e5,0x00000000,0x034e08e3,0x00000001,0x00000000,0x900296e1,0xc1fff8e1,
+0x00000000,0x034e08e3,0x120e590d,0xe80000d8,0x009e39e1,0x04901560,0x9002d6e1,0x00111800,
+0xb80196e0,0xb803160a,0xd1fffb56,0x0090f861,0x00000000,0x90035661,0xd2fffc58,0x00119703,
+0xd2fffeba,0xc10008e5,0x00000000,0xb80356e7,0x00000001,0xe8000025,0x04b03ae5,0xe8ffff1d,
+0x14101701,0xd2ffff14,0xc12010e1,0x00000000,0x9003d6e1,0xc1ffff5d,0xc1fff0e0,0xb80316e1,
+0x008088e2,0xd1ffaefd,0x008e38e5,0x0090f8e9,0x00000000,0xb8001ae3,0x00000001,0xe8fffedd,
+0x04b019e1,0xd1ffaf7c,0x009519e0,0x10809673,0x00000000,0xb80316e4,0xb80356e1,0x00111401,
+0xd1fffabe,0x0010c600,0x0080b9e1,0x00000000,0xb80356e3,0xd2fffea5,0x008e3851,0x00000000,
+0x900356e1,0x00000000,0xb8001ae3,0x00000001,0xe8000089,0x04f019e1,0x00000000,0x00953865,
+0x008e1455,0xe800000d,0x04b03861,0x00951855,0x00000000,0xb80356e3,0x00000001,0xe8000025,
+0x04f014e1,0x00111400,0xb803160b,0xd1fffa51,0x008e3809,0x0090f851,0x00000000,0x90035651,
+0x00111500,0xb80356e5,0x00000000,0xb80316e8,0xb80196e2,0xd1fffa2a,0x0080bae4,0x0090f855,
+0x00000000,0xb80356e3,0xd2fffed1,0x008e3855,0x00000000,0x900356e1,0xd2ffffc8,0xc10000e1,
+0x00000000,0x900356e2,0x10924941,0x00000000,0x9000891d,0x1081c940,0x9000c904,0xc1002c25,
+0x00900724,0x00924725,0x00000000,0x90000050,0x90004055,0xd1ff8bc3,0xd1ff8a4a,0xc1000009,
+0xc2001ce1,0xc30382e1,0x00000000,0xb80038e3,0x00000001,0x122e3879,0x129e3805,0xe8000259,
+0x14003801,0xc22378e4,0xc10001e1,0xc30002e5,0x00000000,0x900039e1,0xc22378e1,0xc30002e1,
+0x00000000,0xb80038e3,0x00000001,0xe80001f1,0x14003805,0xc29ee4e8,0xc2234451,0xc30001e8,
+0xc10000e0,0xc29ee8e5,0xc30001e4,0x90003ae0,0xc10000e1,0xc29eecec,0x900039e0,0xc10000e5,
+0xc30001ec,0xc29f10e8,0xc10000e1,0xc30001e8,0x80003be4,0xc20004e5,0xc30001e4,0x90003ae0,
+0xc24000e1,0xc20004e8,0x008ef9e0,0xc20000e5,0xc30001e8,0xc30300e4,0xc20030e1,0xc30382e0,
+0x028ebae4,0xc20000e5,0xc30300e4,0x900038e8,0xc20034e1,0xc30382e0,0x028ebbe4,0xc2002ce5,
+0xc30382e4,0x900038e8,0xc11000e1,0xc28004ec,0x900039e0,0xc24000e9,0xc30000ec,0xc28004e4,
+0xc20000e1,0xc30000e4,0x008f3be8,0xc30300e1,0xc2010ce8,0x028ef9e0,0xc20000e5,0xc30382e8,
+0xc30300e4,0xc20104e1,0xc30382e0,0x90003aec,0x028e7ce5,0xc2011cec,0x900038e4,0xc24000e9,
+0xc30382ec,0xc20004e4,0xc20000e1,0xc30000e4,0x90003be8,0xc30300e1,0xc20124e8,0x028ef9e0,
+0xc2012ce5,0xc30382e8,0xc30382e4,0xc12000e1,0xc22344f0,0x900039e0,0x90003aed,0xc29ee0ec,
+0xc28004e0,0xc20010e9,0xc30001ec,0xc20010e4,0xc30000e1,0xc30382e4,0x90003be0,0xc10a04e1,
+0xc20008e4,0x900039e0,0xc10001e1,0xc3000250,0xc30382e4,0xc30002f1,0x10857c40,0x900039e0,
+0xc30382e9,0x00000000,0xb8003ae7,0xc10200e1,0x029e39e1,0xe8fffff1,0x14103801,0xd10000b1,
+0xc1000511,0xc1000408,0xc100020c,0xc1000115,0xe8000015,0x14000601,0xd100018e,0xc1000208,
+0xc1301f0d,0xd10005e1,0xc2234409,0xc3000209,0xd1ffb5dd,0xc2234409,0xc3000209,0xc10000e8,
+0xc10000e4,0xc10000e1,0x00000000,0x9000d4e4,0x900094e9,0x00000000,0x900095e1,0xd100020d,
+0xc2234409,0xc3000209,0xc1000019,0x1091c741,0x00000000,0xb800c704,0xb800871f,0x10824741,
+0x00000000,0xb8004054,0xb8000051,0x07000102,0x00100901,0xd2fffdc4,0xc22378e5,0xc30002e4,
+0xc10000e1,0x00000000,0x900039e1,0x10924941,0x1081c940,0x9000891c,0xc1003025,0x00924725,
+0x001e8401,0x001fc200,0x001f4500,0x001f8301,0xc20008e4,0xc10000ed,0xc30382e5,0x001e7901,
+0x00000000,0xb80039e3,0x00000001,0x129e3805,0xe800001d,0x14003801,0xc20000e1,0x108efb04,
+0xc30001e1,0xe8ffffdd,0x04a03be1,0x120e7e10,0x120e3d25,0x120eba18,0x028effe4,0xc20008e5,
+0xc20010e8,0x028efbe8,0xc30382e5,0xc30382e8,0xc10001e0,0x028efbe1,0xe8000054,0x900039e0,
+0x90003aed,0x14003d00,0xc10000f1,0xc20010e8,0xc10000ed,0xc30382e9,0x001eba01,0x00000000,
+0xb8003ae7,0xc10200e1,0x029e39e1,0xe8000021,0x14003801,0xc20000e1,0x108efb04,0xc30010e1,
+0xe8ffffdd,0x04a03be1,0xc10001f1,0x0011bc01,0x1091c741,0x00000000,0xb800871d,0x07000102,
+0x10824741,0x10924941,0x00000000,0x9000891d,0x1081c940,0x9000c904,0xc1002025,0x00900724,
+0x00924725,0x00000000,0x90000051,0x001e0200,0x00150301,0xd1fffed9,0x0010b801,0xc1000210,
+0xc100000c,0xc1000115,0xe800001d,0x14000601,0xd1fffebd,0xc1000211,0xc1000208,0xc100000c,
+0xc1000115,0xc2000ce0,0xc20018e8,0xc20008e5,0xc30382e0,0xc30382e9,0xc30382e4,0xb80038e4,
+0xc10001e1,0x00000000,0x900039e0,0x90003a52,0xc2000ce1,0xc30382e0,0x128e7905,0x00000000,
+0x900038e5,0x1091c741,0x00000000,0xb800c704,0xb800871f,0x10824741,0x00000000,0xb8000051,
+0x07000102,0x00100901,0x10924941,0x1081c940,0x9000c904,0x9000891d,0xc100bc24,0x90004920,
+0x10920741,0x00900724,0x00924725,0x00000000,0x90020070,0x90024075,0x00000000,0x90018068,
+0x9001c06d,0x00000000,0x90010060,0x90014065,0x00000000,0x90008058,0x9000c05d,0x00000000,
+0x90000050,0x90004055,0x00160201,0xc1004ce1,0xc10000e4,0xc1000054,0x009e08e1,0x00000000,
+0x900038e5,0x00000000,0xb8028277,0x00000001,0xe8000069,0x14101d01,0xc1ffff19,0x00000000,
+0xb8004055,0x1091c740,0xb8000050,0xb8008059,0x00000000,0xb800c704,0xb8010061,0x00000000,
+0xb800c05c,0xb8018069,0x00000000,0xb8014064,0xb8020071,0x00000000,0xb8024074,0xb8004721,
+0x00000000,0xb801c06c,0xb800871d,0x07000101,0x10824741,0x00100901,0xc20004e8,0xc2002ce4,
+0xc22378e1,0xc30382e8,0xc30382e4,0xc30002e1,0x00000000,0xb8003aec,0xb80039e9,0xc10048f4,
+0xb80038e1,0xc29ef8f0,0xc1004034,0xc29f00f9,0xc29ef4e5,0xc1ffb438,0x00000000,0xc2126831,
+0x009288f4,0x109f48b0,0xc100002d,0x129ffb0c,0x120eba08,0xc30001f9,0xc30001f0,0x00870838,
+0xc10010ed,0xc30001e4,0x0086dd34,0x00869d31,0x00164200,0x90003efc,0x90000a2d,0xe8000110,
+0x90003cec,0x90003dfd,0x14003804,0x1085c240,0x900039e9,0xd1ffa680,0xc1ffb8e1,0x00000000,
+0x008088e1,0xc100000d,0xe8000179,0x140006fd,0xd10002b4,0x00109900,0x0010dd03,0xe8000169,
+0x14000641,0xc10100e1,0xe8000159,0x040006e1,0xc21000e1,0xe8000139,0x040006e1,0xc2010850,
+0xc2237059,0xc3038250,0xc3000259,0x00151401,0xd1ffb24c,0x00000000,0x0010dc01,0xc2237414,
+0x00111700,0x00109801,0xc3000215,0xe800004d,0x141006fd,0x00000000,0xb803dde7,0xc2f000e1,
+0xc10000e0,0x029e79e1,0xe80000e5,0x040038e5,0xd1ffb085,0x00111b00,0x0010dd00,0x00109c02,
+0xe80000e5,0x14000641,0xc10100e1,0xe80000d5,0x040006e1,0xd2ffff9f,0x00000000,0xb8019de4,
+0xb8015de1,0x00000000,0xb80016e4,0xb80014e3,0x009eb9e1,0x008e79e9,0xe80000ac,0x900016e5,
+0x04c039e1,0xe8ffff6d,0x14100601,0xc22374e0,0xc1ffb8e8,0xc21004e5,0xc30002e0,0x008088e9,
+0x0010d700,0xb80038e4,0x00815ae5,0x00111b01,0xd1000415,0x109e0951,0x00000000,0x900038e5,
+0xe8000065,0x14000641,0xc10100e1,0xe8000055,0x040006e1,0xc29ee8e4,0xc20028e1,0xc30001e4,
+0xc30382e1,0x00000000,0x00000000,0xb80039eb,0xd2fffeec,0xc29ee8e5,0xc30001e4,0x108eba05,
+0x00000000,0x900038e8,0x900039e9,0x00000000,0xb803dde3,0x00000001,0xe8fffe99,0x14003805,
+0xc1ffff55,0xc22374e0,0xc10048e4,0xc10003ed,0xc30002e0,0x009e88e4,0xc1ffb8e5,0x008088e4,
+0x90003aec,0xb800380d,0xd1ffa4cf,0x00000000,0xb80298e3,0x00000001,0x00000000,0xb803f8eb,
+0x00000001,0x110e7a00,0x110e3a05,0x028e39e1,0xe8000021,0x14003801,0xd1fffbcc,0x00000000,
+0x0010fa02,0xc1000109,0xd2fffd14,0x00119503,0xd1fffbb4,0x00000000,0x0010fa02,0xc1000209,
+0xd2ffffeb,0x10924941,0x1081c940,0x9000891c,0xc1002425,0x00924725,0xc29f14e0,0xc2aec0ed,
+0xc30001e0,0xc200c8e9,0x129e38f0,0xc30002e9,0xc2aebce4,0xc2d2c0e0,0x108f3821,0xc30001e4,
+0x900042f0,0xc30001ed,0xc200c8e4,0x900039f0,0xc30001e1,0xc30002e4,0x900282e8,0x900142ed,
+0xc2dcc8e8,0x900339e0,0xc21200e5,0xc30001e8,0xb80282f0,0xc22278e1,0x008ebae6,0xc22274e4,
+0x00000000,0xc2dcc8ed,0xc30001ec,0x008e7ce5,0x00000000,0x900039ed,0x00000000,0xb80282e7,
+0x00000001,0x008e39e1,0x00000000,0x900038e9,0x1091c741,0x00000000,0xb800871d,0x07000102,
+0x10824741,0x10924941,0x00000000,0x9000891d,0x1081c940,0x9000c904,0xc1003c25,0x00900724,
+0x00924725,0x00000000,0x90004054,0x90008059,0x00000000,0x90000051,0x00154200,0x00158301,
+0x00000000,0xb800c2e3,0x00000001,0xe800003d,0x14003801,0xc1001019,0x1091c741,0x00000000,
+0xb800c704,0xb800805b,0x00000000,0xb8004055,0x00000000,0xb8000050,0xb800871d,0x07000101,
+0x10824741,0x00100901,0x00000000,0xb80183eb,0x00000001,0xe8000029,0x14003a01,0x00000000,
+0xb80042e4,0xb80082e3,0x00000001,0x008e39e1,0x009e38e9,0x00000000,0x900082e1,0xc29ee0e4,
+0xb80082fc,0xc29f14e1,0xc30001e4,0x00000000,0xc30001e1,0x00000000,0xb80039e6,0x008e3fe1,
+0x00000000,0xb80183ed,0x129fb90d,0x009e38f9,0xc10004e0,0x00000000,0x129e780d,0xe800004c,
+0x009e38e5,0x14003b00,0x129f780d,0xc29f14f0,0xc10000e1,0xe8000034,0xc30001f1,0x04e038fc,
+0xc10000e8,0x008e7df1,0x001e7901,0x00000000,0x031e3bea,0x108eba05,0xe8fffff5,0x04803afc,
+0x108e7904,0x800039e1,0xc29f14e4,0xc29ee0e8,0xc10fa0e1,0xc30001e4,0xc30001e8,0x009f38fd,
+0x108e3c0c,0x008f7de4,0x009efff9,0x109e0950,0x900042f4,0x008e78f9,0x12217908,0xb8003ae0,
+0x0080fded,0x00000000,0x900038f1,0xd10002e2,0xc1000008,0x009138f9,0xe8000041,0x141006fc,
+0x00150601,0xc10001e0,0xb80055e4,0xb80095e1,0x00000000,0x9000d5e3,0xc1000050,0x008e78e5,
+0x10851404,0xc10000e1,0xe8fffff8,0x800039e1,0x14801420,0x108e7905,0xc29ee4e4,0xc20108e1,
+0xc30001e4,0xc30382e1,0x00000000,0xb80039e4,0xb80038e3,0x00000001,0xe8000041,0x048039e1,
+0xe8000039,0x14e01421,0x00000000,0xb80095e0,0xb80055e7,0x00000001,0x008e14e1,0x008e78e5,
+0x10851404,0xc10000e1,0xe8fffff8,0x800039e1,0x14801420,0x108e7905,0x00109600,0xb80095e0,
+0xb800550f,0xd1000e15,0x008e3851,0x00113800,0x900095e1,0xd1ff79ea,0xc1000009,0xd2fffdfe,
+0xc1000019,0x1092497d,0x10924915,0x1081c97c,0x9000891c,0x9000c905,0x1081c714,0xc1004825,
+0x00900724,0x00924725,0x00000000,0x90014064,0x90018069,0x00000000,0x9000c05c,0x90010061,
+0x00000000,0x90004054,0x90008059,0x00000000,0x90000051,0xc1ffece0,0x00164301,0x00000000,
+0x0345c7e3,0x00168200,0x00000000,0x00160501,0x00000000,0xac008550,0xb800855a,0x00000000,
+0xb800c556,0xe800000d,0x14101405,0xc1000055,0xc22378e1,0xc30002e1,0x00000000,0xb80038e3,
+0x00000001,0xe8000089,0x14103805,0x00000000,0xb801c210,0x0010d701,0xd1ff8202,0xc1000115,
+0xc22378e4,0xc1000019,0xc10000e0,0xc30002e5,0x00000000,0x900039e1,0x1091c77d,0x1091c715,
+0x00000000,0xb800c704,0xb8010061,0x00000000,0xb8004054,0xb8000051,0x00000000,0xb800c05d,
+0x00000000,0xb8008058,0xb8018069,0x00000000,0xb8014064,0xb800871d,0x07000100,0x00000000,
+0x1082477d,0x10824915,0x00100901,0x00000000,0xb80083e3,0x00000001,0xe8000059,0x04003851,
+0xc10001e4,0x90010250,0xc10001e1,0x0010d700,0x9001c2e0,0x900002e5,0x00000000,0xb80005e3,
+0x00000001,0x00000000,0x900182e1,0x00000000,0xb80005e2,0xd1ff9fe2,0x00000000,0x900142e1,
+0xe8000011,0x141006fd,0xd2ffff52,0xc1010019,0x00000000,0x00000000,0x90011a51,0x00109a00,
+0x90009951,0x0010d700,0xb8011ae1,0x00000000,0xac00d8e3,0x00000000,0x9000d9e1,0x00000000,
+0x90029a58,0x90025ae1,0x00000000,0x9002da55,0xc10000e4,0xb80059e0,0xc10002e1,0x00000000,
+0x90001ae0,0x90031ae5,0xd1ff9f6e,0x00000000,0x90039ae1,0xe8000011,0x141006fd,0xd2fffede,
+0xc1010019,0xd2fffed6,0xc1000019,0x1092497d,0x10924915,0x1081c97c,0x9000891c,0x9000c905,
+0x1081c714,0xc1005425,0x00900724,0x00924725,0x00000000,0x90010060,0x90014065,0x00000000,
+0x90008058,0x9000c05d,0x00000000,0x90000050,0x90004055,0xc1ffece0,0x00164301,0x00000000,
+0x034547e3,0x00000001,0xc29ee4e4,0xc20108e1,0xc30001e4,0xc30382e1,0x00000000,0xb80039e4,
+0xb80038e3,0x00000001,0xe800005d,0x048039e1,0xc1ffff19,0x1091c77d,0x1091c715,0x00000000,
+0xb800c704,0xb8010061,0x00000000,0xb8004055,0x00000000,0xb8000051,0x00000000,0xb800c05c,
+0xb8008059,0x00000000,0xb800871c,0xb8014065,0x07000100,0x00000000,0x1082477d,0x10824915,
+0x00100901,0xc29f08e8,0xc2011ce0,0x120f4509,0xc30001e8,0xc30382e0,0xc28004e5,0x00000000,
+0xb8003ae0,0xb8003861,0xc30000e4,0xc24000e1,0x008ef9e2,0x129e78f1,0x008e39f5,0xe80001e5,
+0x04a03861,0xc29ee0e0,0x009f18e5,0xc30001e1,0x0095fdf0,0xb80038ea,0xc28004e1,0xc30000e1,
+0x01ae3aec,0x01ee7ae1,0x029e39e1,0xe8000165,0x14003801,0xc29f0ce8,0xc29efce4,0xc10000e1,
+0xc30001e8,0xc30001e5,0x00000000,0x900039e0,0x90003aed,0x1225bc09,0xe800001d,0x14001601,
+0xd1ff7100,0x00115602,0xc1000009,0xd1ff7652,0xc1000009,0xc29efce1,0xc30001e1,0x00000000,
+0xb80038e3,0x00000001,0xe800013d,0x14003801,0xd1fff3dd,0xc1000511,0xc1000408,0xc100020c,
+0xc1000115,0x00150601,0xe8000015,0x14001401,0xd1fff4b6,0xc1000208,0xc1301f0d,0x122e1709,
+0xe8000035,0x14003801,0xc29f0ce0,0x120e5608,0x00117801,0xc30001e0,0xc1000008,0x0080d9e5,
+0x00000000,0xb8003811,0xd1ff707b,0xd1ff75d2,0xc1000009,0xc29f08ec,0xc29f0ce4,0xc29f08e9,
+0xc30001ec,0xc30001e4,0xc29ee0e1,0x00000000,0xb8003bec,0xb80039e7,0x00000001,0x009ed8ed,
+0xc30001e8,0x009ed5ed,0xc30001e0,0x90003aec,0x008e79ed,0x00000000,0x900038e5,0xc29ee4e4,
+0xc20108e1,0xc30001e4,0xc30382e1,0x00000000,0xb80039e8,0xb80038e3,0x00000001,0x008e7a55,
+0xe800000d,0x04a039e1,0x009578e9,0xd2fffe08,0xc20038e0,0xc29ee4e5,0xc30001e4,0xc30382e0,
+0x008eba55,0x00119500,0x900038e8,0x900039e9,0xe8fffec5,0x04803aed,0xc29f0cec,0xc29efce5,
+0xd2fffeb4,0xc28004e8,0xc30001e5,0xc10001e0,0xc30000e8,0xc30001ed,0x00000000,0x90003be8,
+0x900039e1,0xd1fff2a9,0xc1000511,0xc1000408,0xc100010c,0xc1000115,0xd2fffed2,0x00150601,
+0xe8000011,0x14000501,0xd1ff6f7a,0xc1000009,0xc29f08ec,0xc29ee0e4,0xc29f08e9,0xc30001ec,
+0xc30001e4,0xc29ee0e1,0x00000000,0xb8003bec,0xb80039e6,0xc30001e9,0xd1ff74a5,0xc30001e0,
+0x008efb54,0x008e7955,0xc1000008,0x900038e4,0x90003aed,0xd2ffff0b,0x1092497d,0x10924925,
+0x1081c97c,0x9000891c,0x90004921,0x1081c724,0xc1002825,0x00920724,0xc100e825,0x00900724,
+0x00924725,0x00000000,0x90010060,0x90014065,0x00000000,0x90008058,0x9000c05d,0x00000000,
+0x90000050,0x90004055,0xc1ffece4,0xc1ffe8e1,0x00000000,0x034487e4,0x034447e3,0x00000001,
+0x00000000,0xa40203e4,0xa41083e1,0x00000000,0xa40243ec,0xa410c3eb,0x00000001,0x129e7920,
+0x011ebbe8,0x129e3821,0x011e39e1,0x028e3ae1,0xe8000049,0x14003801,0xc1201419,0x00000000,
+0xb8000050,0xb8004055,0x1091c77c,0xb8008058,0xb800c05d,0x1091c724,0xb8010060,0xb8014065,
+0x1082477c,0xb8004720,0xb800871d,0x07000101,0x10824925,0x00100901,0x00000000,0xb80084e9,
+0xc1ffb2e1,0x008408e1,0xc1000058,0x00000000,0x001e5001,0x10859604,0xc10027e1,0xe8fffff8,
+0x840039e9,0x049016e0,0x108e7909,0x00000000,0xb80084e3,0x00000001,0x129e3805,0xe8000351,
+0x14003801,0x00000000,0xb801c4e8,0xa410c3e2,0x00000000,0x00000000,0xb80042f5,0xc10100e5,
+0xe8000428,0x028e7ae5,0x14103808,0x1085c3e8,0x9001c4e5,0xc10058e4,0xa40217e1,0xc10054e8,
+0xc10000f0,0xc1005ce1,0xc1ffa4e8,0x009ec8e4,0x009e48e9,0xc10000f0,0x900039f0,0x009e48e1,
+0xea000084,0xc10000e8,0x008348e9,0x129e3820,0x900039e8,0x90003bf1,0xc1000060,0xc1000050,
+0xc100003d,0x14003800,0xc1000030,0xc100004d,0x00000000,0x03155317,0xc10000e1,0xe800002d,
+0x04f03854,0xc1000058,0x1084d305,0xc10000e5,0x00000000,0x034e3de7,0x00000001,0xe8000345,
+0x14003801,0x00131301,0xc10024e0,0x00851454,0x120e5509,0xe8ffffbc,0x008f7de5,0x049014e1,
+0x0013d301,0xe8000075,0x04f01444,0xc1000039,0x00000000,0x03155317,0xc10000e1,0xe800003d,
+0x04f03854,0xc1000058,0x1084d305,0xc10000e5,0x00000000,0x034e3de7,0x00000001,0xe80002f9,
+0x14003801,0x120e0e08,0x00161301,0x008e0de1,0x00000000,0x9000384d,0x108e4e04,0x120e1508,
+0x00851455,0x11be3908,0x008f7de1,0xe8ffffa4,0x0613b9e1,0x04901445,0x111e5800,0x009e8f30,
+0xc10000e1,0x00000000,0x00000000,0x061e7ae6,0x00833931,0xe8000025,0x04f03830,0xc1000059,
+0x00000000,0xb80084e3,0x00000001,0x00129000,0x1292f8f9,0xd6000342,0xe800002d,0x04f00f60,
+0x00158f00,0xc1000039,0x1202cf04,0xb80084e1,0x00828b43,0x129e38f9,0x120e3841,0x12233841,
+0xd6006346,0xc1ffa4e0,0xc29e08e4,0xc100c0ed,0xc30001e4,0x034388e1,0xc100e4e8,0x1082d748,
+0xc10090e1,0xc1000058,0xc10021f8,0x008283ed,0xc10022fc,0x00000000,0x008f03e9,0x108f57d8,
+0x008eb8e4,0xc10004ed,0xe8000221,0x04b03f39,0xc1fff4e0,0x031e0bf9,0x00000000,0x034e3ae3,
+0x00000000,0x80003de1,0x00000000,0x90003ae0,0x031e0afb,0x00000001,0x00000000,0x80003ce1,
+0xeaffffc8,0x03438ded,0x10859604,0x108f7d04,0x108efb11,0x108eba10,0x108fff04,0x108f3c05,
+0x1490160c,0x00000000,0x108fbe05,0x00000000,0xb801c4e7,0xc21000e1,0x029e39e1,0xe800035d,
+0x14003801,0x00000000,0xac00d7e3,0xc2307ce4,0x00000000,0xc1003ce9,0xc30002e4,0x129ef804,
+0xc10000e1,0xc100c0e8,0xc1000050,0x060ebbe9,0xe800009c,0x008643e9,0x04f03844,0xc100004c,
+0x00863ae5,0xc29e0834,0xc100003d,0xc3000134,0x00139001,0x1085d748,0x00134d01,0x00000000,
+0x00000000,0x032e903f,0x00000000,0x03155315,0xc10000e0,0x129e7a05,0xe8000031,0x040038e5,
+0x00000000,0x031e194f,0x00000001,0xe8000255,0x14003801,0x129e3af9,0x120e3841,0x122e3841,
+0x00000000,0x84000ee1,0x00000000,0x00000000,0x00851455,0xe8ffffa8,0x10838e08,0x1084d305,
+0x04901444,0x10834d10,0x1083cf09,0x00000000,0xb80084e3,0x00000001,0x129e3809,0xe800009d,
+0x14003801,0x00000000,0xb801c4e7,0xc10200e1,0xc24c38e0,0x028e79e1,0xc30002e0,0x9001c4e5,
+0x00000000,0x00000000,0xb8007831,0xc10000e1,0xe8000068,0xc100004d,0x04f03844,0xc1000051,
+0xc100002d,0x00000000,0x00000000,0x032e102e,0x00000000,0x03155316,0xe8000025,0x14103809,
+0xc10000e1,0xe8000019,0x04f03854,0xc1000059,0x008e1251,0x1202b809,0xd6002356,0x00000000,
+0x00000000,0x00851455,0xe8ffffbd,0x04901444,0x1084d304,0x1082cb09,0xd2fffb86,0xc1000019,
+0x10859605,0xe8fffcad,0x04901654,0x108e7911,0xd2fffcbb,0x10859605,0xe8fffcf9,0x04901654,
+0x108e7911,0xd2fffd17,0xe8fffe19,0x04103f39,0xd2fffe10,0xc10001e0,0xc10000e5,0x00000000,
+0x90003ae0,0x80003de6,0xc10000e1,0xe8000060,0xc1000031,0x04f03844,0xc1000050,0xc100004d,
+0x00000000,0x03155317,0xc10000e1,0xe800002d,0x04f03854,0xc1000058,0x1084d305,0xc10000e5,
+0x00000000,0x034e3de7,0x00000001,0xe8000099,0x14003801,0x00131301,0x120e1508,0x00851455,
+0xe8ffffc0,0x008f7de1,0x04901445,0xc10000e1,0xe8000025,0x04f03830,0xc1000059,0x00000000,
+0xb80084e3,0x00000001,0x00129000,0x1292f8f9,0xd600035e,0xe8000065,0x14f00c55,0xc29e08e4,
+0xa40997e4,0xc29e08e1,0xc30001e4,0xc30001e1,0x00000000,0xb80539e6,0x00000000,0x8009d7e5,
+0x00000000,0xa43503e5,0x00000000,0x900578e5,0xd2fffd5c,0xc100d5e1,0x008e03e1,0x00000000,
+0x800038e5,0x10859605,0xe8ffff59,0x04901654,0x108e7911,0xd2ffff67,0xe8fffd35,0x14100c55,
+0xd2fffd2c,0xc29e08e5,0xc30001e4,0xc10000e8,0xc10001e1,0x00000000,0x8009d7e8,0x900579e1,
+0x00000000,0xb8000de0,0x031e974f,0x00000001,0xe8fffdb9,0x040038e9,0xe8000029,0x14103a01,
+0xc10000e1,0xe8fffda5,0x04f03854,0xc1000059,0x008e1251,0x1202b809,0xd6002362,0xd2fffd8f,
+0xc10000e1,0xe8fffd85,0x04f03854,0xc1000059,0xc1ffffe0,0x1292fa04,0x008e5251,0x00000000,
+0x008e3ae1,0x121e3805,0x1202b908,0x12033809,0xd600436a,0xd2fffd57,0xc10000e1,0xe8fffd71,
+0x04f03844,0xc1000050,0xc100004d,0x1083d748,0xc1000038,0x00135001,0x00000000,0x00000000,
+0x032e903b,0x00000000,0x03155315,0xc10000e0,0x129e7a05,0xe8000031,0x040038e5,0x00000000,
+0x031ecf4f,0x00000001,0xe8000041,0x14903b1d,0x129e3af9,0x120e3841,0x122e3841,0x00000000,
+0x84000de1,0x00000000,0x00000000,0x00851455,0xe8ffffa8,0x1084d305,0x04901444,0x10838e08,
+0x10834d09,0xd2fffceb,0xc10000e1,0xe8ffffd9,0x04f03854,0xc1000059,0xc10006e4,0xc24de4e8,
+0xc24de4e1,0x120efb08,0x009e79ec,0xc30002e9,0x120e7908,0x03433be8,0xc30002e1,0x008e1250,
+0x0342f9e3,0x1202b809,0xd6002376,0xd2ffff9b,0x10924941,0x00000000,0x9000891d,0x1081c940,
+0x9000c904,0xc1002c25,0x00900724,0x00924725,0x00000000,0x90000051,0x00150201,0xc29f14e0,
+0xc10000e4,0xc10000f5,0xc10000f0,0xc10000ec,0xc10000e9,0xc10000e4,0x900002e4,0xc30001e1,
+0xd1ff9540,0x900082f0,0x900042f5,0xc100000c,0x900102e8,0x9000c2ed,0x10808270,0x900182e0,
+0x900142e5,0xd1ff951c,0x10809492,0xc100000d,0xc10000e8,0xc10000e4,0xc10001e1,0xc10000e4,
+0x900354e4,0x9002d4e9,0x00000000,0x9003d4e4,0x900394e1,0x1091c741,0x00000000,0xb800c704,
+0xb800871f,0x10824741,0x00000000,0xb8000051,0x07000102,0x00100901,0x10924941,0x1081c940,
+0x9000891c,0x9000c905,0x10900750,0x10924751,0xd1ff94b0,0x008e0310,0x9000020d,0xc10001e0,
+0x9001420c,0x900042e1,0x10808270,0x9001820c,0x9000c2e1,0x1091c741,0x00000000,0xb800c704,
+0xb800871f,0x10824742,0x07000102,0x00100901,0x10924941,0x00000000,0x9000891d,0x1081c940,
+0x9000c904,0xc1002825,0x00900724,0x00924725,0x00000000,0x90000050,0x90004055,0x00154201,
+0xd1ff94e2,0x10808271,0x00000000,0xb80055ef,0x00000001,0x109ebb05,0xe8000079,0x04f006e8,
+0x00150601,0x00000000,0xa40006e7,0xc100ffe1,0xe8000025,0x041039e1,0x00000000,0xa40046e7,
+0xc100e0e1,0xc100e0e0,0x029e79e1,0xe8000045,0x040039e1,0x10851405,0xe8000039,0x04f014e9,
+0x00000000,0xa40014e7,0xc100ffe1,0xe8ffffe9,0x041039e1,0x00000000,0xa40054e7,0xc100e0e1,
+0xc100e0e0,0x029e79e1,0xe8ffffcd,0x041039e1,0x00000000,0x009e3b51,0xe8000035,0x14e03821,
+0xc1ffff19,0x1091c741,0x00000000,0xb800c704,0xb800871f,0x10824741,0x00000000,0xb8004054,
+0xb8000051,0x07000102,0x00100901,0xd1ff9374,0x10809570,0x0010d403,0xd2ffffce,0xc1000019,
+0x10924941,0x1081c940,0x9000891d,0x10924741,0x1091c741,0x00000000,0xb800871d,0x07000102,
+0x10824741,0x10924941,0x1081c940,0x9000891c,0xc1005025,0x00924725,0xc20e00e0,0xc1000045,
+0x008402e1,0xc100003c,0x00139001,0xc20a00e0,0xc20e00f1,0xc20c00e8,0xc20800ec,0xc10400e5,
+0xc10600e8,0x00930ef0,0x0092cee9,0xc1000034,0xc10200e0,0x00928ee1,0x1083cf04,0x009f8eec,
+0x009f0ee9,0xc10000e8,0xc10000fc,0x009ecee5,0xc10000e0,0x009e4ee0,0xc10000f5,0xc10000e8,
+0x90000be8,0x90000c35,0xc10000e0,0x90003efc,0x90000ae1,0xc10000e0,0x90003be0,0x90003cf5,
+0xe8ffff8c,0x90000ee0,0x900039e9,0x14900f20,0x10838e11,0x10845105,0xe8ffff6d,0x14901140,
+0x10841081,0xc21000e0,0xc21008e5,0xc21004e8,0x008f42e0,0xc2100ae1,0xc10000f8,0xc10000ec,
+0xc10000f1,0x008e42e8,0x008e02e0,0x008e82e5,0xc10000e4,0x900039f0,0x90003df9,0x00000000,
+0x840038e4,0x84003aed,0x1091c741,0x00000000,0xb800871d,0x07000102,0x10824741,0x1092497d,
+0x10924925,0x1081c97c,0x9000891c,0x9000c905,0x1081c724,0xc1008c25,0x00900724,0x00924725,
+0x00000000,0x90014064,0x90018069,0x00000000,0x9000c05c,0x90010061,0x00000000,0x90004054,
+0x90008059,0x00000000,0x90000051,0xc1ffece4,0xc1ffe8e0,0x00164201,0x00000000,0x034587e4,
+0x034f87e3,0x00160401,0x00000000,0xb90002f1,0x120e0508,0x120f452c,0xc2100ce5,0x008e82e4,
+0x109e4950,0xc24e1ced,0xc30002ec,0x0340bae0,0xc20900e9,0xd1ff9790,0xc24e1c0c,0x109e0961,
+0x00857d08,0x90003958,0x00813be9,0xc300020c,0x900038f0,0x00117e01,0x00000000,0xb900195d,
+0xc10000e1,0xe80002f0,0xc1000035,0x04f03858,0x00000000,0x00151801,0xc24e1ce4,0xc10400e1,
+0xc20900e0,0x0082d5e0,0xc30002e5,0x008339e1,0x129e5704,0xc10480e0,0xc24e1ced,0x1203b924,
+0x060f39e0,0x121e1705,0xc30002ec,0x00000000,0x121e8d05,0x120e7808,0x00829538,0x008e0b39,
+0xc1000060,0x1204ba08,0x0084fced,0x0083f8e4,0x00844cf0,0x00840ae5,0xd600237e,0xc1ffffe0,
+0x00000000,0x00168a01,0xc1ffffe0,0x008e57e0,0xc227fc65,0x129e793c,0xc3000264,0x02ae385d,
+0x128eb904,0x129e7804,0xc227fce1,0x120e7924,0x12063a08,0xc30002e1,0x0084d8e0,0x008f95e4,
+0x00844be5,0xc227fce0,0xb8007eec,0x034f15e5,0xc30002e0,0xb80393e4,0xb800bee9,0x129e17f8,
+0xb80313e4,0x034ed8e1,0x120f7808,0xb800fee9,0xc227fce1,0xc30002e0,0xb80293e0,0x21ce3be5,
+0x0084bde0,0x21cefae4,0x21cf3ced,0xc227fce4,0xb8013ee9,0x008f3ce0,0xb80213e0,0xb8017eed,
+0x008efcec,0xb80193e8,0x21ce3ae1,0xc30002e4,0xb801bee9,0x008f3be0,0xb80113e1,0xc1007ce0,
+0xb801fee4,0x21ce3ae1,0x008414e0,0xb80093e0,0x21ce7be9,0x008efce0,0x034e3de4,0x034e5539,
+0x008f3be4,0xb8004ae8,0x21cebae1,0xc1ffffec,0xb80392e5,0x008f3ce8,0xb8008ae8,0x21ce79e1,
+0xc227fce0,0xb80312e4,0x21cf39e1,0x008fbce4,0xb800cae8,0xb80292e5,0x02ae7bf8,0xb8010ae8,
+0x21cefae5,0x108fb904,0xb80212e5,0x008f3ef0,0xb8014ae8,0x21ce7ae5,0x008efcec,0xb80192e4,
+0x21cefae5,0x008f3be4,0xb8018ae8,0xb80112e5,0x008f3cec,0xb801cae4,0x21cefae5,0xc30002e0,
+0xb80092e1,0x008efcec,0x00000000,0x21ce3ae5,0x0093b860,0x00000000,0x21cebae5,0x008efbe1,
+0xc227fce0,0x21ce79e0,0x008ebbe9,0xc30002e1,0x0092b8f4,0x008e7ae5,0xc100013c,0x900014e4,
+0x10851411,0xd6018386,0xc10080e0,0xb80011fc,0xb80051e9,0x008659e0,0xb80091f4,0xb800d1e5,
+0x00829960,0xb80111ec,0x034f9961,0x00000000,0xb8038ae0,0xb8030af1,0x00000000,0xb8028ae0,
+0xb8020aea,0x00000000,0xb80151e4,0xb8018ae1,0x00000000,0x21cfbae0,0x21cffff9,0x00000000,
+0xb80191e4,0xb8010ae1,0x008fbff8,0x21cf39e0,0x21cf7df1,0x00000000,0xb801d1e4,0xb8008ae1,
+0x008ebef4,0x21ceb9e0,0x21cefbe9,0x008f3af1,0x008efcec,0x21ce39e1,0x008e7be8,0x21ce39e1,
+0x008e79e1,0xc1ffffe0,0x008e79e0,0x10834d05,0xc10040e4,0x02aeb8e4,0x108e1705,0xe8fffd54,
+0x1295f83c,0x108e3a05,0x04900d58,0x900014e0,0x008514e5,0xc1000019,0x1091c77d,0x1091c725,
+0x00000000,0xb800c704,0xb8010061,0x00000000,0xb8004054,0xb8000051,0x00000000,0xb800c05d,
+0x00000000,0xb8008058,0xb8018069,0x00000000,0xb8014064,0xb800871d,0x07000100,0x00000000,
+0x1082477d,0x10824925,0x00100901,0x10924941,0x1081c940,0x9000891c,0x9000c905,0x10900760,
+0x10924761,0xc28010e0,0xc20114e5,0xc30001e0,0xc30382e5,0x00000000,0xa00038e0,0x9000390b,
+0x00000001,0x129e3805,0xe800007d,0x14003801,0xd1ffe29d,0xc1000311,0xc1000408,0xc100010c,
+0xc1000115,0xc2000ce4,0xc2000ce0,0xc1012c09,0xc30382e4,0xc30382e1,0x00000000,0xb80039e7,
+0xd1ff8bd9,0x128e7905,0x00000000,0x900038e5,0xc2000ce4,0xc1000019,0xc10000e0,0xc30382e5,
+0x00000000,0x900039e1,0x1091c741,0x00000000,0xb800c704,0xb800871f,0x10824742,0x07000102,
+0x00100901,0xd1ffe229,0xc1000311,0xc1000408,0xc100020c,0xc1000115,0xd2ffff8f,};
+
+/* cga */
+static unsigned long srp_fw_cga[] __devinitdata = {
+0x8ae3fe80,0x03403432,0x14020004,0x00000002,0x00000000,0xa1100000,0x00000000,0x0001a000,
+0x00140000,0x9022a964,0x00000000,0xa0020001,0xa8200003,0x80000320,0x28400206,0x01000000,
+0x88140000,0xa0000010,0x00000143,0x00000000,0x40000000,0x00000190,0x001ac000,0x42200000,
+0x0064c000,0x00400000,0x00000000,0x35400000,0x00002804,0x00001a08,0x000140c0,0x00000000,
+0x0421d000,0x00000000,0x00000000,0x805fa000,0x10ebfffa,0x02802d03,0x64022800,0x10000802,
+0x00ce6820,0x8c980800,0x00010000,0x00000000,0x00000000,0x00000000,0x00000000,0x01815000,
+0x00010000,0x80000010,0x00200606,0x00000038,0x00000000,0x48000000,0x00000103,0x00000000,
+0x04a40000,0x00000000,0x00000000,0x19300000,0x00000000,0x0010a700,0x00000000,0x00000000,
+0x00006810,0x80100000,0x00000000,0x01930000,0x0541a000,0x00002000,0x00000000,0x00000000,
+0xc2fffffa,0x038a3022,0x00000650,0x00000100,0x0c002830,0x00000800,0x00000801,0x00040000,
+0x00000a01,0x90209020,0x00000000,0x00000100,0x07400000,0x40002400,0x00102287,0x04304000,
+0x00000800,0xa8000400,0x00000143,0x00000000,0x34080000,0x00a80000,0x00000000,0x00000000,
+0x41089002,0x010ca000,0x00000000,0x388c22c8,0x00000000,0x00000a04,0x80000600,0x00000000,
+0x01204001,0x40000b80,0x00000000,0x00000000,0x26f7f000,0x0a00a2b0,0xf404682c,0x5ea03002,
+0x00002810,0x00400000,0x00164001,0xd4000100,0x06301c01,0x9022a964,0x00000000,0x38000009,
+0x06602137,0x21590224,0x40000400,0x004000c4,0x20000000,0x10008490,0x00000000,0x00000000,
+0x14080740,0x00ec8151,0x000a0172,0x00800000,0xc02c8810,0x00201020,0x00000000,0xa1400000,
+0x24006834,0xe0000a01,0x00000a00,0x21090e00,0x80000800,0x00003c01,0x00000000,0x805fa000,
+0x2603ffc0,0x01682000,0x6400080c,0x50691046,0x00002810,0x00080000,0x001640b2,0x0000c060,
+0x00021c00,0x606c0004,0x00000000,0x36615406,0x066846c3,0x8bd92400,0x42000607,0x00000000,
+0x80000000,0x00000410,0x000c4000,0x00000000,0x14024800,0x00a81202,0x000a0000,0x00000000,
+0xd02c8002,0x024010c1,0x00000000,0x003e1000,0x02282800,0x000401d1,0x07000000,0x00010d80,
+0x00000801,0x00000004,0x00000000,0x00000000,0x26000000,0x0000fa70,0x66b02e58,0x5020d280,
+0x00000810,0x00000900,0x00164000,0x0e02c000,0x00000000,0x00200004,0x00000000,0x04039810,
+0x074800e4,0x2b910000,0x00200400,0x00000080,0x24000000,0x08908484,0x000a4000,0x00000000,
+0x14080e78,0x05048110,0x00000000,0x00800000,0xc8000164,0x00000c00,0x00000000,0xf87f1000,
+0x24040004,0x260000d3,0x000002c1,0x00080e00,0x00000000,0x00000c04,0x00000000,0x00000000,
+0x00000000,0x00000000,0x43244808,0x50213000,0xf0000000,0x08480003,0x00000000,0x0e040000,
+0x00000000,0x00240000,0x00000000,0x307b9200,0x48003617,0x82010000,0x24002286,0x000000b8,
+0x24000000,0x40000080,0x00060103,0x00000000,0x14080008,0x05008000,0x00200160,0x00900800,
+0x40020164,0x00001000,0x00000000,0x00000000,0x03300000,0x30000110,0x00000e01,0x001b0000,
+0x00000084,0x00001804,0x00000000,0x00000000,0xc0000000,0x003e03f9,0x34066818,0x50081000,
+0x00000004,0x00080000,0x008c0001,0x0e020000,0x00001b00,0x10800000,0x00000000,0x10800102,
+0x48388024,0x320e0330,0x30002000,0x000000d0,0x04020000,0x0b000080,0x000ac000,0x00000000,
+0x140a4800,0x09aa0000,0x000ac0f6,0x42000000,0x702c8164,0x00201001,0x00000000,0x00000000,
+0x03a06d70,0x60000152,0x00000200,0x0109f700,0x40000001,0x00000003,0x00000000,0x00000000,
+0x00000000,0x00000290,0x80044800,0x0a890100,0x00018000,0x00080004,0x000c0109,0x0e042000,
+0x00000000,0x04240000,0x00000000,0x00611008,0x04600604,0x0a0003a8,0x28108000,0x0043c0cc,
+0x20000000,0x10000080,0x00000000,0x00000000,0x14086818,0x00aa8008,0x00224190,0x00100000,
+0x80000164,0x00000400,0x00000000,0x00000000,0x36260020,0x3000015d,0x00000041,0x00010000,
+0x00000001,0x00004000,0x00000000,0x00000000,0x00000f40,0x002a0000,0x2418002c,0x50083152,
+0x00000000,0x00480000,0x001640b2,0x00040100,0x00000000,0x60a40000,0x00000000,0xb0015c20,
+0x48100227,0x0bd10000,0x00042400,0x000000b0,0x24000000,0x08000084,0x000a6000,0x00000000,
+0x14024808,0x00008190,0x000c0000,0x00900000,0xc0020000,0x00201020,0x00000000,0x00000000,
+0x03a60550,0x40001b90,0x06c000a0,0x20080e00,0xbc01e001,0x00002c00,0x00000000,0x00000000,
+0x27000000,0x00000000,0x37300010,0x0aa02800,0x00006800,0x00400000,0x000c2000,0x0d840000,
+0x00020000,0x00240004,0x00000000,0x1c020002,0x6e608054,0x1b5d0004,0x18000400,0x000000b8,
+0x80000000,0x10008490,0x00060000,0x00000000,0x0002002c,0x05000a04,0x002240e0,0x00100000,
+0x00424164,0x000010e1,0x00000000,0x003b1000,0x34060000,0x00000151,0x00001000,0x00000000,
+0xb8000001,0x00000001,0x00000000,0x00000000,0x00000000,0x00000000,0x00184820,0x5e8840c9,
+0x0000000c,0x00080000,0x00164001,0x0d800060,0x00000000,0x10800000,0x00000000,0x20020008,
+0x48200903,0x0bdd27a6,0x00000000,0x00000060,0x04020000,0x03000400,0x00000000,0x00000000,
+0x00002f40,0x00000151,0x08224120,0x42000000,0xf8000164,0x00200a00,0x00000000,0x00000000,
+0x37360000,0x00000154,0x000004e0,0x24200d80,0x38000001,0x00003804,0x00000000,0x00000000,
+0x0003e000,0x0a00e000,0xf7344824,0x90488802,0x00006d48,0x00480000,0x001640b2,0x0d86a000,
+0x00000000,0x90840004,0x00000000,0x00600110,0x80000600,0x0a040331,0x1b800000,0x00200000,
+0x24000000,0x10000080,0x00060000,0x00000000,0x3410483c,0x05cb0a06,0x00180192,0x00000000,
+0x78004164,0x00200401,0x00000000,0x003e1000,0x03300030,0x8008011c,0x06c00000,0x20000e00,
+0x00000000,0x00001000,0x00000000,0x00000000,0x00000000,0x0002f800,0xe4160440,0x901061d8,
+0x00c02810,0x00000010,0x008c00b2,0x000640c0,0x00000f00,0x20208004,0x00000000,0x10220006,
+0x00080824,0x20001620,0x4c908000,0x002800b0,0x24000000,0x00021000,0x000c0000,0x00000000,
+0x1720082c,0x00000154,0x00000160,0x00800000,0x81180000,0x00001001,0x00000000,0xe0400f84,
+0x00100820,0xc00121d1,0x06c00600,0x00080f80,0x80000800,0x00183c03,0x00000000,0x00000000,
+0x00f80000,0x003e0000,0xf4100648,0x904004c8,0x00014810,0x21000004,0x00000460,0x0c0400a0,
+0x000c1b00,0x20200004,0x00000000,0x240b1020,0x48300226,0x820003a4,0x10108207,0x00000000,
+0x80000000,0x07000090,0x000a2000,0x00000000,0x0408480c,0x05021351,0x000e8160,0x10900000,
+0x802c88c0,0x00000841,0x00000000,0x00391f84,0x37382810,0x68080150,0x01c02300,0x20080000,
+0x00000821,0x00003c80,0x00000000,0x00000000,0x7e03f000,0x0038000f,0xc4160760,0x00100018,
+0x00002800,0x00480000,0x00010460,0x00020100,0x000a1b00,0x00240004,0x00000000,0x241a0608,
+0x0020b003,0x220007a6,0x1c802000,0x00400080,0x80020000,0x1c000410,0x00060000,0x00000000,
+0x14100010,0x05cb0154,0x08200000,0x42000000,0x302c8000,0x00000a01,0x00000000,0xf87f1e04,
+0x14100758,0x40160209,0x05c00200,0x04200000,0x81000800,0x00000003,0x00000000,0x00000000,
+0x2703ffc0,0x003f0000,0xe4004f5c,0x00307348,0x0000e80c,0x21000008,0x00840000,0x0003a080,
+0x00000000,0x20200004,0x00000000,0xb00a0032,0x6e401603,0x21510006,0x10108000,0x00280080,
+0x24040000,0x19021000,0x000c0000,0x00000000,0x152e0e6c,0x01cb0bd6,0x00200060,0x42000000,
+0x80000002,0x00000840,0x00000000,0x003d1e84,0x24182838,0x6e170190,0x00004500,0x30090100,
+0x80000800,0x00082384,0x00000000,0x00000000,0x80000ffe,0x00000393,0x24160660,0x503100c6,
+0x00016d74,0x00480000,0x98840001,0x0006006c,0x00040000,0x10801080,0x00000000,0xa6720106,
+0x482c4283,0x920803a0,0x14802206,0x003000c0,0x80000100,0x13800410,0x00060000,0x00000000,
+0x17af2808,0x05010390,0x000c00c0,0x00801000,0xf0024002,0x00401000,0x00000000,0xfc400e44,
+0x27b02f64,0xc0171206,0x00000500,0x00080080,0x00000c84,0x00000004,0x00000000,0x00000000,
+0x00fbffc0,0x0000ffe0,0x962c080c,0x10703242,0x00014b78,0x00480008,0x00002001,0x0d84a0e0,
+0x00000000,0x108100f0,0x00000000,0x18015320,0x482c1324,0x92080000,0x28108206,0x002b0480,
+0x24000000,0x49b21000,0x000a0103,0x00000000,0x2400480c,0x05020002,0x000ec116,0x00101000,
+0x40000164,0x00400901,0x00000000,0xfc400000,0x27bc0008,0x6e000a00,0x00000700,0x00090000,
+0x00000884,0x00102000,0x00000000,0x00000000,0x0003ffc0,0x003eff80,0xf4004f48,0x50303886,
+0x00012a64,0x00480000,0x00012009,0x00060000,0x00000100,0x10800004,0x00000000,0x046a0406,
+0x6e6c04e4,0x0a060000,0x14802000,0x00100060,0x04000000,0x46b00400,0x00060103,0x00000000,
+0x24104828,0x09001b93,0x08290112,0x00801000,0xf1080000,0x00400c00,0x00000000,0xe07e1000,
+0x03b84c58,0xc0010a01,0x00000700,0x04200000,0x0201e084,0x00003803,0x00000000,0x00000000,
+0x00fbffc0,0x0039fbd0,0x241e6838,0x9030d889,0x00014952,0x00480008,0x00012009,0x0004a100,
+0x00000000,0x10808004,0x00000000,0x10015422,0x074c0224,0x9201240e,0x38108206,0x00400060,
+0x24040000,0x4cb21000,0x000a0103,0x00000000,0x24106800,0x05888192,0x000c0080,0x42001000,
+0x40004002,0x00400801,0x00000000,0xfc400000,0x03b80008,0x60010a04,0x00000700,0x10090000,
+0x38000884,0x00100984,0x00000000,0x00000000,0x0003ffc0,0x00000000,0x44062e4c,0x50600006,
+0x0000e974,0x00480008,0x18840420,0x0d860024,0x00000000,0x00040004,0x00000000,0x100a0636,
+0x07703474,0x820c1404,0x10108206,0x00000060,0x04000000,0x46821000,0x000a0103,0x00000000,
+0x24126838,0x01040000,0x000c0094,0x00801000,0xc0424164,0x000010e0,0x00000000,0xf47e1000,
+0x03b80548,0x20170a01,0x00400701,0x00090080,0x00000884,0x00100000,0x00000000,0x00000000,
+0x3e03ffc0,0x00000000,0xf4066800,0x50311200,0x00012804,0x00480000,0x008400b2,0x000400c0,
+0x00040000,0x000500f0,0x00000000,0x0e720022,0x000c8214,0x8a0c03a0,0x19002206,0x000000c0,
+0x80040000,0x46800490,0x00040103,0x00000000,0x14044f4c,0x000001dc,0x08260000,0x42001000,
+0xf0000000,0x00001001,0x00000000,0xf8400000,0x03b82e69,0xc0070a05,0x06c00600,0x14200080,
+0x00000084,0x00003800,0x00000000,0x00000000,0x3efbffc0,0x00000000,0x0416082c,0x5c88c063,
+0x00000000,0x21000000,0x98164000,0x0001a0d0,0x00000100,0x00040004,0x00000000,0xa00a0606,
+0x68009067,0x92080000,0x28000606,0x00300080,0x24040000,0x49800080,0x0008a103,0x00000000,
+0x24126838,0x0000019e,0x00000060,0x42001000,0x01080000,0x00000400,0x00000000,0x00000000,
+0x27bc0648,0x20150201,0x00004601,0x00090d80,0x80000084,0x00004802,0x00000000,0x00000000,
+0x0003fffe,0x00000000,0xc006481c,0xd00800c6,0x00002810,0x21000000,0x00000001,0x00010020,
+0x00000100,0x002500f0,0x00000000,0xa7615122,0x04402107,0x81920006,0x12800606,0x00000000,
+0x00000000,0x4c800080,0x00000103,0x00000000,0x04b64800,0x05021a00,0x002e0120,0x10900800,
+0xf1080012,0x00000400,0x00000000,0xf8400000,0x041c4820,0xc0112000,0x000044c0,0x00010000,
+0x00000c84,0x00002400,0x00000000,0x00000000,0x8003ffc0,0x0000000f,0x00066c70,0x5cc00010,
+0x00012801,0x00480000,0x00164001,0x00040080,0x00000000,0x00040004,0x00000000,0x000b9100,
+0x00300024,0x81d00320,0x00000606,0x00104454,0x24000000,0x49800084,0x00040103,0x00000000,
+0x24004808,0x09008192,0x00000040,0x00100000,0x00024000,0x000006e0,0x00000000,0x003e1000,
+0x00002818,0xb0172000,0x000010c0,0x11090d80,0x08000000,0x00002803,0x00000000,0x00000000,
+0x3e03ffc0,0x0000fc05,0x00066e78,0x9058c040,0x00018550,0x08480000,0x18000001,0x00010000,
+0x00000100,0x00040024,0x00000000,0x16220106,0x07400034,0x8b960010,0x10002206,0x00000000,
+0x00020000,0x4c808480,0x00000103,0x00000000,0x34100448,0x00000204,0x002c0000,0x42000012,
+0xf1080212,0x00001000,0x00000000,0xfc7e1000,0x03200008,0x80130a02,0x00000600,0x28010000,
+0x0241e001,0x00002000,0x00000000,0x00000000,0xa7fbffc0,0x000003ff,0x0006074c,0xdcc090c4,
+0x00010008,0x21000000,0x00002801,0x00040100,0x00000100,0x000120f0,0x00000000,0x06600032,
+0x07708634,0x80030320,0x28000606,0x00000040,0x24000000,0x49800084,0x00000103,0x00000000,
+0x24080800,0x05000192,0x002080b6,0x00100000,0x01080000,0x000006e0,0x00000000,0x00000000,
+0x24040558,0xb0011200,0xc6002300,0x00010000,0x00000000,0x00002800,0x00000000,0x00000000,
+0x0a03ffc0,0x000000f0,0x24006838,0xdcf00810,0x00004800,0x00480000,0x000c00b2,0x000600a0,
+0x05100100,0x00000004,0x00000000,0x061a0202,0x07700024,0x93d202a8,0x4a802206,0x000000b0,
+0x04000000,0x498004a0,0x000a0103,0x00000000,0x1410480c,0x05020002,0x00000100,0x00100800,
+0x91080000,0x000006e1,0x00000000,0x00000000,0x24100018,0x80130a01,0x06c00620,0x00010000,
+0x00000084,0x00001800,0x00000000,0x00000000,0x3a03ffc0,0x00040100,0x02360e40,0x0e981981,
+0x00000268,0x00480000,0x000000b2,0x0005c060,0x00000000,0x00040004,0x00000000,0x00020020,
+0x05700200,0x819207a4,0x29000606,0x000800c0,0x20000000,0x48908480,0x000a0103,0x00000000,
+0x0001cf48,0x09010b90,0x00000180,0x00100000,0x88004000,0x00000a00,0x00000000,0xe47f1000,
+0x03300009,0x80150002,0x07000600,0x31090000,0x00000021,0x00003800,0x00000000,0x00000000,
+0x0b03ffc0,0x0eff0000,0x24066c4c,0x0cd00004,0x00000020,0x00080000,0x980000b2,0xb400010c,
+0x00000000,0x00040004,0x00000000,0x22135038,0x4f602036,0x9a031408,0x18000606,0x00030040,
+0x24000000,0x49800084,0x000a0103,0x00000000,0x24a0876c,0x058b0004,0x00080000,0x00800000,
+0xf0005002,0x000006e1,0x00000000,0xec7e1fc4,0x03240448,0x86190005,0x07001000,0x20080000,
+0x00000800,0x00001800,0x00000000,0x00000000,0xcd03ff80,0x003ee00f,0x34000778,0x00193140,
+0x00004800,0x00080000,0x00164000,0xb4040000,0x00000000,0x000500f0,0x00000000,0x1e235904,
+0x07700104,0x819e0000,0x28002606,0x000300b0,0x24020000,0x49800484,0x000a0103,0x00000000,
+0x000c4c50,0x00ee0152,0x00000180,0x42000800,0x80005002,0x00000a01,0x00000000,0xe8400000,
+0x00044d48,0x20130a00,0x00000001,0x00080e00,0xcd01e084,0x00004001,0x00000000,0x00000000,
+0x4c000f80,0x0000011e,0x07bc680c,0xdc900010,0x00000000,0x00000000,0x000000b2,0x0e050060,
+0x00000000,0x00040000,0x00000000,0x06600d08,0x2f4d3034,0x9b922406,0x10000606,0x000000d4,
+0x20000000,0x4c900080,0x000c0103,0x00000000,0x00004c60,0x05020000,0x000a4180,0x00100000,
+0xc0004164,0x00040600,0x00000000,0xe4400000,0x03204808,0x90010004,0x07000000,0x20010000,
+0x0501e021,0x00001800,0x00000000,0x00000000,0x3903ef80,0x0003f400,0x02204f4c,0x90700082,
+0x00000008,0x00000000,0x000100b2,0x000500e1,0x00000000,0x20200004,0x00000000,0x01815020,
+0x4f6c0234,0x920e3404,0x49002606,0x000000c0,0x24000000,0xcc900084,0x00000103,0x00000000,
+0x00004c72,0x00ca1b9c,0xe02c0180,0x00800010,0xf8004000,0x000c0c00,0x00000000,0xfc7e1000,
+0x03344c58,0xe6000110,0x07001000,0x24080000,0x00000001,0x00001c83,0x00000000,0x00000000,
+0xff03ef80,0x0fc081cf,0xf406002c,0x0c913040,0x00802834,0x00080000,0x001640b2,0x000520c0,
+0x00000000,0x902200f0,0x00000000,0xa6639100,0x07630903,0x000a2406,0x48042400,0x000000a0,
+0x24000000,0xc9000084,0x00000103,0x00000000,0x00004c60,0x05000192,0x00000000,0x00100000,
+0xf8020002,0x240406c0,0x00000000,0xf4400000,0x03a40658,0xb2010000,0x07001080,0x20080e00,
+0x40000800,0x00001803,0x00000000,0x00000000,0x1d03e000,0x000087f0,0x47b84f4c,0x50304880,
+0x00004800,0x08480000,0x00000000,0x00066000,0x00000000,0x10200004,0x00000000,0x063b5002,
+0x06700274,0x8b940321,0x4c002207,0x002000d0,0x24000000,0xc9108484,0x000c0103,0x00000000,
+0x15200f70,0x05ee819e,0x002c0130,0x00800800,0xb8004010,0x480c0e01,0x00000000,0xe0400000,
+0x00060000,0xe0000000,0x00000400,0x00010000,0x00000084,0x00001c00,0x00000000,0x00000000,
+0xde03ef80,0x003e8ec7,0x04060e6c,0x5008f050,0x00c04860,0x00080000,0x00164009,0xb005c000,
+0x00001c01,0x00040000,0x00000000,0x06000436,0x00323874,0x00022405,0x49000400,0x001800d4,
+0x24000000,0xc0000084,0x00080103,0x00000000,0x14122800,0x05069a08,0x000000a0,0x00900000,
+0x882c8810,0x00000001,0x00000000,0x00000fc4,0x03a00444,0x8a182190,0x000010e0,0x20080e00,
+0x00000821,0x00000001,0x00000000,0x00000000,0x12000f80,0x0000fd30,0x3626680c,0x500303c9,
+0x00c06820,0x00480000,0x000000b2,0x00030000,0x00000000,0x00048004,0x00000000,0x06035808,
+0x04403000,0x9a0003a0,0x40002607,0x000000cc,0x20000000,0x09600000,0x000c8000,0x00000000,
+0x2400482c,0x010403d7,0x00270180,0x00800000,0xc0000002,0x000c0641,0x00000000,0xfc400f84,
+0x00002800,0xa818c002,0x07000000,0x01090000,0x38000801,0x00001803,0x00000000,0x00000000,
+0xce000000,0x00003d6f,0x37260f7e,0x90013000,0x0001c804,0x00000000,0x002120b2,0x0e000000,
+0x00001c00,0x04240000,0x00000000,0x00320100,0x68103040,0x81940330,0x40002207,0x000000c0,
+0x24000000,0xc9c00484,0x000ca103,0x00000000,0x24100f48,0x0d0101dc,0xe00800a0,0x00100007,
+0xa82c8164,0x00080641,0x00000000,0x00000000,0x17ae4c60,0xa8000190,0x07000000,0x24080000,
+0x00000001,0x00000000,0x00000000,0x00000000,0x17000000,0x00380140,0x34182f4c,0x904000c8,
+0x0001c808,0x00080000,0x001640b2,0x000000c1,0x00000000,0x00200000,0x00000000,0x00015038,
+0x48003234,0x0b920230,0x18002000,0x000000c0,0x20000000,0xc0000480,0x00080103,0x00000000,
+0x0010680c,0x00c80000,0x00000120,0x00000000,0xf0000000,0x00001000,0x00000000,0xfc400000,
+0x00082818,0x8e001202,0x07000400,0x00010e00,0x00000001,0x00003800,0x00000000,0x00000000,
+0x9803e000,0x003e0396,0x3418081c,0x90400116,0x0001c838,0x00080000,0x000000b2,0x00020000,
+0x00001c00,0x000620f0,0x00000000,0x18035900,0x00000904,0x00060006,0x4b802400,0x0000004c,
+0x24000000,0x00000084,0x00080000,0x00000000,0x00000830,0x09050a02,0x04200180,0x00000000,
+0x002c8002,0x00000c01,0x00000000,0xe0400000,0x03a64d50,0xc4101212,0x07000060,0x24200000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x21000000,0x003891b0,0x3416680c,0x10300081,
+0x0001a820,0x08480000,0x001640b2,0xd40660e0,0x00000001,0x24240000,0x00000000,0x00615d00,
+0x680c3134,0x20000018,0x21842400,0x000000cc,0x04000000,0x00000080,0x000a0000,0x00000000,
+0x24006800,0x00ed9a0c,0x00000130,0x00100000,0xc0001002,0x00001080,0x00000000,0x00000000,
+0x02204808,0x02160b92,0x07000421,0x00080e00,0x00000001,0x00001804,0x00000000,0x00000000,
+0x15000f80,0x003f0190,0x47a60f5c,0xd0003302,0x00014810,0x00480000,0x000000b2,0x0e0280e0,
+0x00000000,0x00040004,0x00000000,0x1c015d36,0x2e6b2024,0x2b900320,0x20002000,0x000000d0,
+0x24000000,0x00008484,0x0006a000,0x00000000,0x3404680c,0x09010000,0x002c00a0,0x00900000,
+0x18004164,0x00001041,0x00000000,0xfc781000,0x03a64820,0x4e000a06,0x07000400,0x20080000,
+0x00000021,0x00004c00,0x00000000,0x00000000,0x20000000,0x003f0190,0x00000000,0x90004802,
+0x00014820,0x00080000,0x001640b2,0x00000000,0x00000000,0x00240004,0x00000000,0x042b9102,
+0x68200014,0x120e3400,0x10002000,0x003800d4,0x24000000,0x09b00404,0x00000000,0x00000000,
+0x2400481c,0x00c90194,0x002240a0,0x00800000,0x40020000,0x000c1040,0x00000000,0x00000000,
+0x00064820,0x00061315,0x07000200,0x00010e00,0x38000001,0x00003803,0x00000000,0x00000000,
+0x00000000,0x00000230,0xc3a6045c,0x901008c2,0x0001a820,0x00080000,0x001640b2,0x0e020060,
+0x00001c00,0x00000000,0x00000000,0xa07a0120,0x000c0007,0x22000404,0x21000000,0x00400000,
+0x24000000,0xc6000404,0x000a2103,0x00000000,0x00042f78,0x00010003,0x00000120,0x00000000,
+0xc02c8164,0x000010c1,0x00000000,0x00000000,0x03a00444,0x000c0a00,0x07000461,0x20080e00,
+0x38000821,0x00001804,0x00000000,0x00000000,0x2103e000,0x00009ba0,0x3626074c,0x0cc00000,
+0x00012e44,0x08480000,0x000000b2,0x0e01c000,0x00001c00,0x04240004,0x00000000,0x06420e04,
+0x07403624,0x21d42409,0x40000400,0x00380084,0x20000000,0x10000400,0x00000000,0x00000000,
+0x2400680c,0x0dcf01d2,0x00230000,0x00100000,0xf02c8164,0x000010c1,0x00000000,0x003f1f84,
+0x00020648,0x30001356,0x070002c1,0x00080000,0x00000800,0x00001800,0x00000000,0x00000000,
+0x1f03e000,0x0e40979e,0x2418074c,0x00111000,0x00c06801,0x00480000,0x00164000,0x00060000,
+0x00001c00,0x40040000,0x00000000,0x00015238,0x077c0004,0x01980327,0x43802400,0x000000a0,
+0x24000000,0x07008484,0x000ca000,0x00000000,0x0014080c,0x00cd8000,0x000000a0,0x10900000,
+0xd02c8000,0x6c0010c0,0x00000000,0xe0400000,0x02204820,0x08160209,0x000004e1,0x00010e00,
+0xb8000801,0x00000001,0x00000000,0x00000000,0x1a000000,0x00000150,0x03a0000c,0x9000cb06,
+0x00c0e838,0x00400000,0x000000b2,0x00020000,0x00000000,0x00200000,0x00000000,0xb0039100,
+0x07700003,0x920207a0,0x31002607,0x000000c4,0x24000000,0x10000400,0x000a0000,0x00000000,
+0x00006800,0x008c1202,0x002400a0,0x00148000,0xc0000010,0x00000001,0x00000000,0x00000000,
+0x02a02800,0x2e18120c,0x07000e01,0x01090000,0x38000081,0x00003c03,0x00000000,0x00000000,
+0x3803e000,0x003ef390,0x03be044c,0x90110003,0x00004800,0x20400000,0x000020b2,0x0e01c0e0,
+0x01b00000,0x2426a0f0,0x00000000,0x004a0008,0x0d443000,0x819836b9,0x0b802207,0x00280000,
+0x20000000,0x10000090,0x00000000,0x00000000,0x00066830,0x0000019b,0x00080000,0x00100000,
+0x00020164,0x00000c00,0x00000000,0xf8400000,0x03a60544,0xe0101a08,0x070908a0,0x21090000,
+0x00000021,0x00003804,0x00000000,0x00000000,0xa3000000,0x003ff808,0x34060740,0x905901c0,
+0x00c06838,0x00400000,0x00840000,0x0e02c000,0x00001c00,0x20240004,0x00000000,0x06000128,
+0x00300524,0x20000006,0x28000400,0x00280060,0x00000000,0x00000080,0x000c0000,0x00000000,
+0x25a0680c,0x00ea0000,0x000ac136,0x10900000,0x802c8164,0x00000c00,0x00000000,0x00000fc4,
+0x00064820,0x20100190,0x00000d01,0x00080080,0x00000800,0x00000000,0x00000000,0x00000000,
+0x40000000,0x003fe629,0x373c680c,0x90588050,0x00002830,0x00400a20,0x002120b2,0x0005c080,
+0x00000000,0x20240000,0x00000000,0xa00a0300,0x0f5c1003,0x800003a0,0x13902207,0x00400060,
+0x04000000,0x10000080,0x0006c080,0x00000000,0x3416080c,0x0d058392,0x002c0120,0x10900000,
+0xd0000000,0x00000241,0x00000000,0x00000f84,0x03a02e49,0x20000196,0x07000481,0x20010000,
+0x38000800,0x00003803,0x0000002d,0x00000000,0x00000000,0x00000240,0x74060544,0xd0401346,
+0x00004b40,0x00400000,0x800020b2,0x0e03c0e0,0x00000000,0x04240004,0x00000000,0x06000d00,
+0x003c0600,0x01920018,0x38000400,0x000000d0,0x24000000,0x13008480,0x000c0080,0x00000000,
+0x34060004,0x09001358,0x00200000,0x00800000,0x70004164,0x00000e61,0x00000000,0x00000fc4,
+0x03b82e64,0x0018019e,0x070010c1,0x00080000,0x00000801,0x00004800,0x00000024,0x00000000,
+0x2403e000,0x09ff0390,0xf416074c,0x0c803902,0x00004809,0x00400fc0,0x00164000,0x00004060,
+0x00000000,0x102220f0,0x00000000,0xa001d002,0x68000303,0x3b5c0000,0x48102000,0x00400000,
+0x20000000,0x10000400,0x000c8000,0x00000000,0x34066d54,0x01c9000c,0xc0224140,0x10900006,
+0x80004000,0x7e000c61,0x00000000,0xe0400000,0x03a62804,0x30100002,0x00000621,0x24080e00,
+0xc0000001,0x00001804,0x00000000,0x00000000,0x22000000,0x00250250,0x34196c4c,0x00007006,
+0x00006e78,0x08480000,0x00164408,0x000340ec,0x02401c00,0x00200004,0x00000000,0x04615008,
+0x680c0040,0x33de36a8,0x48002000,0x000000c0,0x20000000,0x08000410,0x00060000,0x00000000,
+0x353c281c,0x00ee0002,0xc0224120,0x00800006,0xc02c8212,0x00001000,0x00000000,0xfc400e84,
+0x03260441,0xc0001350,0xb4001000,0x24080e00,0x00000800,0x00000003,0x00000000,0x00000000,
+0x3f03e000,0x000003d0,0x03a6480c,0x50400309,0x0001280c,0x20400000,0x80164001,0x0e05c00a,
+0x00000000,0x000600f0,0x00000000,0x38615130,0x074c0937,0x120203a6,0x1b842400,0x00402000,
+0x20000000,0x10000080,0x00000000,0x00000000,0x00100830,0x00070000,0x40140120,0x0086c002,
+0xc0000164,0x00000c01,0x00000000,0xf4400000,0x02a80448,0x20000098,0x000902c1,0x04080e00,
+0x38000081,0x00003004,0x00000000,0x00000000,0x3903ef80,0x0aa7ee60,0xc41e6808,0x00004012,
+0x00004b48,0x08480000,0x001640b2,0x0e0200c0,0x03f00000,0x902280f0,0x00000000,0x1c0a0106,
+0x2f4c00f4,0x0192032e,0x42000400,0x004000d4,0x20000000,0x00000090,0x00000000,0x00000000,
+0x25b80030,0x00c80154,0x00000000,0x00800000,0xf0004164,0x00201081,0x00000000,0xfc400000,
+0x04040e48,0x0e001a0a,0x07000a01,0x00080e00,0x1441e000,0x00003c84,0x00000000,0x00000000,
+0x80fc0000,0x097f9e3e,0x83a04810,0x900041c0,0x00004818,0x00080000,0x00000000,0x0e032000,
+0x00000000,0x60a40004,0x00000000,0xa6135600,0x074c04c3,0x01920000,0x43802400,0x000000d4,
+0x24000000,0x09008484,0x000c8000,0x00000000,0x341c4804,0x00c913d0,0x00160060,0x00100000,
+0xe0020164,0x01e010e1,0x00000000,0xa8b91fc4,0x36200460,0x2000009b,0x00000201,0x00080000,
+0x00000801,0x00003800,0x00000000,0x00000000,0x0003f000,0x0000e3f0,0x34066c4c,0x9ef00003,
+0x0001c820,0x00080000,0x00164001,0x0005c000,0x00001c00,0x04240000,0x00000000,0x06135900,
+0x48303040,0x01dc0000,0x23800400,0x1c400040,0x20000002,0x10000400,0x00000000,0x00000000,
+0x24000000,0x05e90198,0x002e00a0,0x00800000,0xc02c8000,0x000010e1,0x00000000,0x00000000,
+0x03260800,0x201013da,0x000004c1,0x20090e00,0x80800821,0x00001803,0x00000000,0x00000000,
+0xcdf7ef80,0x00004cc2,0x00004800,0x00000000,0x00000000,0x00000000,0x00000000,0x0000000c,
+0x00000000,0x00009020,0x00000000,0x00000001,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000100,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x000008c0,0x00000000,0x00132000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x05218800,0x00000000,0x00000000,0xbf400000,0x00000000,0x00000d30,0x00000008,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x000180c4,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00001000,0x00000000,0x00000000,
+0x01b00000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000006,0x00000040,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x20000000,0x00000206,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00180000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x000008c0,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00004800,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x01900000,0x00000000,0x00000000,0x00000000,0x00008480,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x40000000,0x00000005,0x00000000,0x00000000,0x00000020,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00080000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x34000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x0000c000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x34000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00060000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x80000000,0x00000003,0x24000000,0x90000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000034,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00180000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x04000f40,0x00000000,0x00040000,0x00040000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00002000,0x00000000,
+0x34000000,0x00000000,0x90000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x28010000,0x00000005,0x00000000,0x00000000,0x00000000,
+0x80fbef80,0x05002c02,0x00006800,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x80209020,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x02000000,
+0x00000100,0x08000000,0x00060000,0x00000000,0x00180000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00080400,0x00000000,0x508b2288,0x00000000,0x00000000,0x00000000,0x00000000,
+0x01204000,0x00000000,0x00000000,0x00000000,0x00fc0000,0x00140000,0x0000000c,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x29740000,0x00000002,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0xc0000400,0x00000103,0x00000000,
+0x34000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x3f400000,
+0x0ff7ef80,0x00004cf3,0x00040000,0x00100000,0x00000000,0x80000000,0x00000000,0x00000000,
+0x00000000,0x00009020,0x00000000,0x01000801,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000300,0xc0000000,0x00000103,0x00000000,0x00080000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00132000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x05418800,0x00000000,0x00000000,0xbf400000,0x40000000,0x00004c04,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000002,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x08a00000,0x00000000,0x00000000,
+0x00100000,0x00000000,0x00000000,0x00000000,0x00000000,0x0004a000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x04000000,0x00000000,0x00004800,0x00000000,0x00000800,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x20000000,0x00000206,0x00000000,
+0x00000000,0xc0000000,0x00000103,0x00000000,0x24004800,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x0003d000,0x00000040,0x00000008,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x01300002,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x34000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000001,0x00000000,0x00000000,0x00800000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00100000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00060000,0x00120000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00002804,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000002,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x80000000,0x00000207,0x00000034,0x00000000,0x00000000,0x00000000,0x00000000,
+0x24000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x34060000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00006800,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00004180,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000034,
+0x00000300,0x00000000,0x00000000,0x00000000,0x24100000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x34060000,0x00000000,0x00000000,0x00000000,
+0x00000004,0x00000000,0x00000000,0x00000000,0x00000000,0x00152c00,0x00000000,0x00000000,
+0x00000030,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000054,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00040000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00180000,0x00000000,0x00000000,0x00000000,0x00000004,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00006800,0x00000000,0x00006800,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00002000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x03a00000,0x80000000,0x000000c0,0x20000000,
+0x00000021,0x00000000,0x00000000,0x00000000,0x4efbef80,0x05123803,0x34000030,0x00000000,
+0x00000030,0x08480000,0x00000000,0x00000000,0x00000000,0x80209020,0x00000000,0xa0000000,
+0x00000007,0x00000000,0x00008000,0x01800000,0x00000c00,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x508e2348,
+0x00180000,0x00000000,0x00000000,0x00000000,0x01204000,0x00000000,0x00000000,0x00000000,
+0xd5ffefbe,0x00143002,0x00060000,0x00000000,0x00000000,0x00000000,0x00000000,0x0000000c,
+0x00000000,0x69749020,0x00000002,0x01800000,0x00000000,0x00000000,0x00000000,0x06000000,
+0x00000300,0x00000000,0x00000000,0x00000000,0x01200000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x48000000,0x00000000,0x000c22c8,0x00000000,0x60000000,0x00000000,0x00000000,
+0x01204000,0x00000000,0x00000000,0x3f400000,0xcdfbffc0,0x02800c03,0x34000000,0xd0000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x902280c4,0x00000000,0x0001d000,
+0x00000034,0x00000000,0x00042400,0x00000000,0x00000000,0x08900000,0x00000000,0x00000000,
+0x01a00000,0x00000000,0x00000000,0x00000000,0x00000000,0x01840000,0x00000000,0x28800000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x05418800,0x00000000,0x00000000,0x00000000,
+0x84d3ff76,0x04ce4c02,0x0004e800,0x00000000,0x00000060,0x80000000,0x00001000,0x00000000,
+0x00000000,0x90229964,0x00000000,0x00000001,0x00000600,0x20000000,0x2b800286,0x00300000,
+0x00001600,0xc0000000,0x00000103,0x00000000,0x34180000,0x00000000,0x000a0000,0x00000000,
+0x00000000,0x00200000,0x00000000,0x4d400e44,0x00000000,0x80000a00,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x805fa000,0x0cffff00,0x02f92950,0x77200000,0x00000000,
+0x000a6800,0x00000000,0x00212000,0x00000000,0x00000000,0x90209020,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00002000,0x00000000,0x00000400,0x08000000,0x00000000,0x00000000,
+0x34060000,0x00000000,0x00000000,0x00000000,0x00000000,0x0020a000,0x00000000,0x2c8a2000,
+0x00002800,0x001000d6,0x00000000,0x00200000,0x04418800,0x00000000,0x00000000,0x00000000,
+0x4edbf000,0x04c04c05,0x00000000,0xd0000000,0x00006830,0x08480000,0x00000000,0x00000000,
+0x00000000,0x90229964,0x00000000,0xa0120003,0x00000003,0x00000000,0x00000000,0x00300000,
+0x00001600,0x08a00000,0x00000000,0x00000000,0x04060000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x0024a000,0x00000000,0x4d400000,0x00020030,0x00000050,0x00000000,0x00000000,
+0x00000004,0x00000000,0x00000000,0x805fa000,0x0bfc0f38,0x02842800,0x74000000,0x00184000,
+0x00000800,0x80000000,0x00000000,0x00000000,0x00000000,0x90200000,0x00000000,0x01800800,
+0x00000000,0x00000000,0x00000000,0x00000034,0x00000000,0xc0000000,0x00000103,0x00000000,
+0x34302800,0x00000000,0x00000000,0x00000000,0x00000000,0x00800000,0x00000000,0x28800000,
+0x24000800,0x00000004,0x000000c0,0x00000000,0x04418800,0x00000000,0x00000000,0x00000000,
+0x00e3ff00,0x050050a0,0x43a10000,0x00000000,0x000a4810,0x00000000,0x01003000,0x00000000,
+0x00000000,0x9022a960,0x00000000,0x00000001,0x00000000,0x80000000,0x00000287,0x02302800,
+0x00000000,0x00000000,0x00000000,0x00000000,0x34040000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x01000000,0x00000000,0x51400000,0x00006c4b,0x00101204,0x00000000,0x08010000,
+0x0221e000,0x00000000,0x00000000,0x805fa000,0x17ebffbc,0x059758e3,0x1403a803,0x0ae80000,
+0x00000030,0x00000000,0x02000000,0x0e000002,0x00001c00,0x9022a960,0x00000000,0x00000001,
+0x00000064,0x80000004,0x00000206,0x08000000,0x00000000,0x40000000,0x00000103,0x00000000,
+0x00066c40,0x0d000000,0x08180140,0x00000000,0x006c8164,0x00800000,0x00000000,0x59400308,
+0x00000758,0x00100008,0x00000000,0x19200000,0x01204400,0x00000000,0x00000000,0x805fa000,
+0x80fbdfba,0x02c00002,0x00030808,0x00080000,0x00020000,0x00000008,0x20002001,0x000000d1,
+0x00060000,0x90200184,0x00000000,0x04000000,0x04400100,0x80000000,0x00102206,0x08342400,
+0x20000000,0x08000010,0x00000000,0x00000000,0x14080030,0x00e9c000,0x04000000,0x00000000,
+0x00000000,0x02000000,0x00000000,0x2c800288,0x00000030,0x001700d4,0x00000000,0x14080000,
+0x01204400,0x00004000,0x00000000,0x00000000,0x8d03ffc0,0x00002c20,0x24004800,0x1a804002,
+0x01020000,0x00000000,0x00000000,0x00000000,0x00000000,0x000100f0,0x00000000,0x000a0000,
+0x05400200,0x80000000,0x10000206,0x00422400,0x00000000,0x40800000,0x00000103,0x00000000,
+0x34000460,0x00000000,0x001b0166,0x00000000,0xc0004000,0x00000000,0x00000000,0x00192000,
+0x00004800,0x6013920c,0x00000000,0x00000000,0x0201e000,0x00000000,0x00000000,0x00000000,
+0x0cffffc0,0x03590970,0x24146820,0x10080000,0x00002800,0x00000008,0x023641b2,0x00000000,
+0x00040000,0x00000000,0x00000000,0x00200408,0x00040880,0x800003a0,0x00108207,0x00000000,
+0x80000000,0x40000010,0x00000103,0x00000000,0x00000000,0x00000000,0x08000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000740,0x00000000,0x07000000,0x04200e00,
+0x0201e000,0x00000000,0x00000000,0x00000000,0x40f3ffc0,0x06406573,0x36282c44,0x0c800000,
+0x00000800,0x00000000,0x00000000,0x00000000,0x00000000,0x90209044,0x00000000,0x00200002,
+0x00000514,0x80000000,0x00000206,0x08000000,0x00002000,0x48000000,0x00000103,0x00000000,
+0x00006800,0x00000000,0x00001200,0x00000000,0x00000000,0x00800000,0x00000000,0x00000348,
+0x0000680c,0x00061a00,0x00000000,0x00000000,0x39204000,0x00004481,0x00000000,0x00000000,
+0xcfe3ffb8,0x064064b2,0x14000742,0xda800002,0x00000008,0x00000000,0x28165000,0x0e0000e1,
+0x00000000,0x90229964,0x00000000,0x00000009,0x00000000,0x80000000,0x00000206,0x08302400,
+0x00001000,0x40000000,0x00000103,0x00000000,0x00060550,0x00000000,0x00000000,0x00000000,
+0x00000164,0x00800000,0x00000000,0x654002c8,0x00000008,0x000000dc,0x00000000,0x10000e00,
+0x01204400,0x00004380,0x00000000,0x805fa000,0x57fbfffb,0x028038f3,0x66200000,0x00600000,
+0x00022810,0x00000000,0x28000000,0x000000c1,0x00001c00,0x902110f0,0x00000000,0x00000020,
+0x00000000,0x80000000,0x00000206,0xfc302400,0x0001f4ff,0x40000000,0x00000103,0x00000000,
+0x00106e40,0x00880000,0x00000000,0x00000000,0x002c8000,0x02000000,0x00000000,0x28800000,
+0x00000000,0x0010000c,0x00000000,0x00000000,0x0221e400,0x00000000,0x00000000,0x00000000,
+0x17ffffbb,0x00003170,0x40040000,0x00080006,0x00006800,0x00000000,0x00000000,0x00000000,
+0x00000000,0x000110f0,0x00000000,0x00020000,0x07400100,0x80000000,0x00000206,0x00000000,
+0x0001fc00,0x40000000,0x00000103,0x00000000,0x34000038,0x50000000,0x000000d6,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00006800,0x00001200,0x00000000,0x00000000,
+0x0221e400,0x00000000,0x00000000,0x00000000,0x0ffffffc,0x039734f3,0x00006803,0x0a810000,
+0x00006830,0x00000000,0x000011b2,0x00000000,0x00000000,0x90209020,0x00000000,0x00000000,
+0x00300800,0x80000000,0x00000206,0x08000000,0x00001000,0x48000000,0x00000103,0x00000000,
+0x04060640,0x50000000,0x001b0000,0x00000000,0x00000000,0x02000000,0x00000000,0x388d2308,
+0x0000680c,0x00000008,0x07000000,0x00000000,0x39204400,0x00000001,0x00000000,0x00000000,
+0xcfe3ffb8,0x064064b2,0x14000742,0xda800002,0x00000008,0x00000000,0x28165000,0x0e0000e1,
+0x00000000,0x90229964,0x00000000,0x00000009,0x00000000,0x80000000,0x00000206,0x08302400,
+0x00002200,0x40000000,0x00000103,0x00000000,0x00060550,0x00000000,0x00000000,0x00000000,
+0x00000164,0x00800000,0x00000000,0x654002c8,0x00000008,0x000000dc,0x00000000,0x10000e00,
+0x01204400,0x00004380,0x00000000,0x805fa000,0x57fbfffb,0x028038f3,0x66200000,0x00600000,
+0x00022810,0x00000000,0x28000000,0x000000c1,0x00001c00,0x902110f0,0x00000000,0x00000020,
+0x00000000,0x80000000,0x00000206,0xfc302400,0x0001f4ff,0x40000000,0x00000103,0x00000000,
+0x00106e40,0x00880000,0x00000000,0x00000000,0x002c8000,0x02000000,0x00000000,0x28800000,
+0x00000000,0x0010000c,0x00000000,0x00000000,0x0221e400,0x00000000,0x00000000,0x00000000,
+0x17ffffbb,0x00003170,0x40040000,0x00080006,0x00006800,0x00000000,0x00000000,0x00000000,
+0x00000000,0x000110f0,0x00000000,0x00020000,0x07400100,0x80000000,0x00000206,0x00000000,
+0x0001fc00,0x40000000,0x00000103,0x00000000,0x34000038,0x50000000,0x000000d6,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00006800,0x00001200,0x00000000,0x00000000,
+0x0221e400,0x00000000,0x00000000,0x00000000,0x0ffffffc,0x039734f3,0x00006803,0x0a810000,
+0x00006830,0x00000000,0x000011b2,0x00000000,0x00000000,0x90209020,0x00000000,0x00000000,
+0x00300800,0x80000000,0x00000206,0x08000000,0x00001000,0x48000000,0x00000103,0x00000000,
+0x04060640,0x50000000,0x001b0000,0x00000000,0x00000000,0x02000000,0x00000000,0x388d2308,
+0x0000680c,0x00000008,0x07000000,0x00000000,0x39204400,0x00000001,0x00000000,0x00000000,
+0x40dfefb8,0x04402ff3,0xb6b00000,0xdc800000,0x00026c6c,0x00000000,0x803640b2,0x0f84a00e,
+0x00000000,0x902290d0,0x00000000,0x00000009,0x054020c0,0x81900006,0x30000286,0x0a000000,
+0x04001400,0x40000084,0x00000143,0x00000000,0x3406080c,0x00008000,0x00000112,0x00000000,
+0x70000164,0x00200600,0x00000000,0x45c00f84,0x00000000,0x60000000,0x07c00200,0x00000f80,
+0x0521a000,0x00000000,0x00000000,0xbf400000,0x0d03ef80,0x000048b0,0x00066e60,0x0e980000,
+0x0801067c,0x80080008,0x000001b2,0x000000c0,0x00000000,0x000180f0,0x00000000,0xa001d000,
+0x00002002,0x81920220,0x20108306,0x08300000,0x20000000,0x40000080,0x00000183,0x00000000,
+0x04062804,0x00000000,0x08000000,0x00800000,0xf0000000,0x000010c1,0x00000000,0x00000000,
+0x00000800,0x80000000,0x07c00000,0x04200000,0x04c1a000,0x40001800,0x00000000,0x00000000,
+0xc0ebef80,0x003c3402,0x00090003,0x00010101,0x10000000,0x80000000,0x00000000,0x000300c0,
+0x00001f00,0x000210d0,0x00000002,0x02011000,0x00040000,0x800203a0,0x18000686,0x16384a00,
+0x20001400,0x40000400,0x00000143,0x00000000,0x00000008,0x00000000,0x00300178,0x00000000,
+0x406c8000,0x00000000,0x00000000,0x00000000,0x00004808,0x80000200,0x00000ac0,0x00010000,
+0x0421a000,0x80000000,0x00000000,0x00000000,0x7dfbef80,0x02c02c03,0x36380010,0x10100008,
+0x30000740,0x00400000,0x000020b2,0x000000e1,0x00000000,0x902210d0,0x00000000,0xa0011008,
+0x2f603002,0x800003b8,0x20000706,0xf4302a00,0x040028ff,0x40000000,0x00000183,0x00000000,
+0x34100550,0x00000150,0x00180000,0x00100000,0xc0000000,0x06000601,0x00000000,0x2c800fc4,
+0x00002c40,0x24000000,0x07c008e1,0x00010000,0xc221e000,0x00000003,0x00000000,0x00000000,
+0x00ffef80,0x00113520,0x24060540,0x0c980100,0x08002800,0x00400000,0x00002000,0x0f800000,
+0x00000000,0x697120f0,0x00000002,0x00000008,0x00001840,0x81900220,0x00002286,0x00000000,
+0x20000000,0x40000080,0x00000143,0x00000000,0x00024d44,0x00000001,0x0032c0c0,0x00000000,
+0x00000164,0x00600000,0x00000000,0x00381e44,0x00006800,0x00000000,0x00000600,0x00010000,
+0x8221e000,0xc0000003,0x00000000,0x3f400000,0xfffbffc0,0x02b93402,0x34106800,0x50100000,
+0x3800075c,0x28480000,0x00164001,0x0f80c000,0x00000000,0x902290d0,0x00000000,0x20000006,
+0x08000002,0x80020000,0x2c000286,0x08000000,0x00001000,0x48000000,0x00060143,0x00000000,
+0x03200e64,0x00c80000,0x00660166,0x00000000,0x00000164,0x00800000,0x00000000,0x28800000,
+0x24000810,0x00000000,0x00000000,0x00000f80,0x0521a000,0x80004380,0x00000000,0x00000000,
+0x0be3fffb,0x00002cd0,0x40000000,0x00084000,0x18000808,0x00000014,0x001641b2,0x00000000,
+0x00161f00,0x000660d0,0x00000002,0x00000000,0x00000200,0x80000000,0x00202686,0x12000000,
+0x24000c00,0x40000020,0x00000143,0x00000000,0x07b80f40,0x00a80000,0x00310100,0x00800000,
+0x002c8000,0x00000600,0x00000000,0xf4400000,0x00040002,0x00001a00,0x07c00000,0x10080f80,
+0xc4c1a000,0x00000003,0x00000002,0x38400000,0x83efff80,0x04404403,0x2401cd4c,0x00000002,
+0x0000000c,0x00400000,0x00001000,0x00000000,0x00000000,0x90229960,0x00000000,0x26011101,
+0x04433002,0x80000000,0x00002306,0x02000000,0x00000600,0x48000000,0x00000183,0x00000000,
+0x00060000,0x00000000,0x00181ad6,0x00000000,0x00000000,0x0024a000,0x00000000,0x45400388,
+0x0000000b,0x00000000,0x00000000,0x10000000,0x01204000,0x80004280,0x00000001,0x805fa000,
+0xc3fbef80,0x03523032,0x00040009,0x00000000,0x30026800,0x00000000,0xaa0021b2,0x000000d0,
+0x00001c00,0x90209020,0x00000000,0x00015000,0x00000000,0x80000000,0x00040686,0x02302000,
+0x00000400,0xc9000000,0x00000103,0x00000000,0x24000000,0x00000000,0x001ac000,0x00000000,
+0x006c8000,0x008c6000,0x00000000,0x348c22c8,0x00006800,0x00100000,0x07000000,0x00000000,
+0x01204000,0x00000000,0x00000000,0x00000000,0x8ffbfffc,0x02804924,0x00000000,0x0a800000,
+0xc0462e4c,0x00000000,0x00364000,0x00000000,0x00000000,0x902100f0,0x00000000,0x00000000,
+0x05403000,0x80000000,0x00000286,0x00000000,0x00000000,0xc8000000,0x00000103,0x00000000,
+0x14200000,0x00000000,0x0018c000,0x00000000,0x00000000,0x00800000,0x00000000,0x28800f84,
+0x00000003,0x001212d0,0x00000000,0x00000e00,0x0441e000,0x00000000,0x00000000,0x00000000,
+0x3efbfffc,0x00c00124,0x02a00000,0x00080002,0x00000348,0x00000000,0x80164000,0x0000000c,
+0x00000000,0x000260d0,0x00000000,0x00000100,0x00000000,0x80000000,0x00000207,0x00000000,
+0x00000000,0x40000000,0x00000143,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000f84,0x00000800,0x0000000c,0x00000400,0x00000e00,
+0x0521a000,0x80000000,0x00000007,0x00000000,0xd0ffffc0,0x00002900,0x00020000,0x0c800000,
+0x30000830,0x80080000,0x00000000,0x00000000,0x00000000,0x000280f0,0x00000000,0x00011000,
+0x00040000,0x80000000,0x00200686,0x0c000000,0x00000000,0x40000000,0x00000143,0x00000000,
+0x00100640,0x00000000,0x00000100,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x14000000,0x80000200,0x00000000,0x00000000,0x04c1a000,0x00004381,0x00000003,0x00000000,
+0xc3ffffc0,0x04be4003,0x16200800,0x00100000,0x90000000,0x80000000,0x010020b2,0x00000000,
+0x00001c00,0x90209020,0x00000000,0x00019000,0x00000004,0x80000000,0x00400706,0x02000000,
+0x00000400,0x40000000,0x00000143,0x00000000,0x04000008,0xb0000000,0x00000000,0x00000000,
+0x002c8002,0x00800000,0x00000000,0x489023c8,0x00006800,0xf2000000,0x07000260,0x00000000,
+0x01204000,0x00000000,0x00000000,0x00000000,0x00f7ff40,0x03c03c50,0x00026808,0x0e800000,
+0xe0000000,0x00000000,0x02000000,0x00000000,0x00000000,0x9022a960,0x00000000,0x00000001,
+0x00000124,0x80080000,0x4ac00286,0x12000000,0x00000000,0xc8000000,0x00000143,0x00000000,
+0x00000663,0x00000000,0x00000000,0x00000000,0x00000000,0x00280000,0x00000000,0x3d400000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x0421e000,0x40000000,0x00000003,0x805fa000,
+0x43fbffc0,0x030c3823,0x00040808,0x08820000,0xe88e0000,0x00000000,0x02000000,0x00000000,
+0x00000000,0x9022a0d0,0x00000000,0x04600000,0x00000800,0x80000000,0x00400306,0x00000000,
+0x00000000,0xc8000000,0x00000143,0x00000000,0x00000660,0x00000000,0x00000000,0x00000000,
+0x00000000,0x12082000,0x00000000,0x30800000,0x00000642,0x00120000,0x00000000,0x00080000,
+0x0541a000,0x80000000,0x00000003,0x00000000,0x00fbffc0,0x02ca3003,0x14000000,0x0ac04000,
+0x500e0000,0x00000000,0x00000000,0x00000000,0x00000000,0x902290d0,0x00000000,0x00000000,
+0x00000024,0x80000000,0x00000287,0x0c000000,0x00000800,0xc8900000,0x00000143,0x00000000,
+0x04000660,0x00000000,0x00000000,0x00000000,0x00000000,0x09082000,0x00000000,0x2c800000,
+0x00000000,0x00120090,0x00000000,0x00000000,0x0521a000,0xc0000000,0x00000003,0x00000000,
+0x0cfbffc0,0x028000c0,0x00000000,0x10000000,0x80000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x902260d0,0x00000000,0x00000000,0x00000900,0x80000000,0x00000287,0x10000000,
+0x00001000,0xc0000000,0x00000103,0x00000000,0x34000660,0x00000000,0x00000000,0x00000000,
+0x00000000,0x09000000,0x00000000,0x28800000,0x00000000,0x00000298,0x00000000,0x00000000,
+0x04c1a000,0x00000000,0x00000000,0x00000000,0x8003ffc0,0x00002802,0x24002808,0x08801000,
+0x08000020,0x00000000,0x00000000,0x00000000,0x00000000,0x000290d0,0x00000000,0x00000020,
+0x00000000,0x80000000,0x00000286,0x08000000,0x00000800,0x40000000,0x00000143,0x00000000,
+0x00060660,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000002,0xa0000008,0x00000000,0x00000000,0x0521a000,0x40000000,0x00000001,0x00000000,
+0x0afbffc0,0x000000a0,0x40000003,0x00600000,0x18004808,0x00000000,0x80000000,0x00000100,
+0x00000000,0x000260d0,0x00000000,0x0013d000,0x00000900,0x92000000,0x00000706,0x0c300000,
+0x00002000,0x40000000,0x00000183,0x00000000,0x34000740,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00004800,0x00000008,0x00000000,0x00000000,
+0x04c1a000,0xc0000000,0x00000001,0x00000000,0x0003efc0,0x00000003,0x34004800,0x00200000,
+0x08000008,0x00000000,0x00000000,0x000000c1,0x00000000,0x000210f0,0x00000000,0x00000800,
+0x00000100,0x80080000,0x00000286,0x18000000,0x00004400,0x40000000,0x00000143,0x00000000,
+0x24060660,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00004808,0x00000000,0x00000000,0x00000000,0x0421a000,0xc0000000,0x00000000,0x00000000,
+0x8003effe,0x00002c02,0x00006800,0x00000000,0x38000000,0x00000000,0x00000000,0x000000c0,
+0x00000000,0x000210f0,0x00000000,0x01600c00,0x00003900,0x80000000,0x00000306,0x18300000,
+0x00000400,0x40000000,0x00024183,0x00000000,0x00040020,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x003f1000,0x00006828,0x00100000,0x00000000,0x10000000,
+0x0521a400,0x40000000,0x00000001,0x00000000,0x0003fffe,0x00003003,0x0400c802,0x00001000,
+0x48006e40,0x00000000,0x1a000000,0x000000e1,0x00000000,0x002210d0,0x00000000,0x00000022,
+0x00000224,0x80000000,0x00000286,0x1a304420,0x00002800,0x40000000,0x00000143,0x00000000,
+0x03a40030,0x00000000,0x01400000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00004808,0x001001d0,0x00000000,0x00000000,0x0421a400,0xc0000000,0x00000002,0x00000000,
+0x8003fffe,0x000b33f2,0x14010000,0x00000000,0x48000008,0x00000000,0x20000000,0x000000e1,
+0x00000000,0x000110f0,0x00000000,0x00120000,0x00000800,0x92000000,0x00000286,0x04302400,
+0x00000c00,0x40000000,0x00000143,0x00000000,0x00044800,0x00000000,0x01c00000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x03a0000e,0x0000000c,0x00000000,0x30000000,
+0x0221e400,0xc0000000,0x00000002,0x00000000,0x8003fffe,0x00003002,0x34038001,0x00000002,
+0x50000030,0x00000000,0x98000000,0x000000e0,0x00000000,0x000110f0,0x00000000,0x00000800,
+0x00000000,0x80080000,0x00000286,0x08302400,0x00001400,0x40000000,0x00000143,0x00000000,
+0x00060740,0x00000000,0x01440030,0x00000000,0x00000000,0x00000600,0x00000000,0x00000000,
+0x0006000c,0x800000d0,0x00000000,0x10000000,0x0221e400,0x40000000,0x00000003,0x00000000,
+0x0003fffe,0x00003003,0x43226c43,0x00000000,0x70004800,0x00000000,0x18010008,0x000000e1,
+0x00000000,0x000110f0,0x00000000,0x00600000,0x00003000,0x81d00000,0x00000686,0x0c382434,
+0x00001c00,0x40000080,0x00000143,0x00000000,0x0000002c,0x00000000,0x00064000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000fc4,0x0000000c,0xa000000c,0x00000000,0x10000000,
+0x0221e400,0x80000000,0x00000003,0x00000000,0x3f03ffc0,0x00002803,0x0321000c,0x00000002,
+0x78000002,0x00000000,0x18010000,0x000000e1,0x00000000,0x000110f0,0x00000000,0x00000000,
+0x00000804,0x80030000,0x00000686,0x10382400,0x00003000,0x40000000,0x00000143,0x00000000,
+0x34000000,0x00000000,0x000000d6,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x03a04800,0x86000000,0x00000000,0x00000000,0x0221e001,0xc0000000,0x00000003,0x00000000,
+0x0003ffc0,0x00003003,0x24090770,0x00000000,0x8000480c,0x00000000,0x00000008,0x00000100,
+0x00000000,0x000110f0,0x00000000,0x0001d000,0x00000000,0x80000000,0x00002286,0x12002000,
+0x00003400,0x40000000,0x00000143,0x00000000,0x00060000,0x00000000,0x00000020,0x00000000,
+0x00000000,0x000006e0,0x00000000,0x003f1000,0x00180000,0x86000000,0x00000000,0x00000000,
+0x0221e000,0x80000000,0x00000004,0x00000000,0x0b03fffe,0x00002843,0xc0038743,0x0a800000,
+0x80000008,0x00000000,0x00000008,0x000000c1,0x00000000,0x000220f0,0x00000000,0x0001dc00,
+0x00002600,0x81d00000,0x00002286,0x04302020,0x00000000,0x40000400,0x00000143,0x00000000,
+0x00000640,0x00000000,0x000000c0,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x80000000,0x00000000,0x00000000,0x04c1e400,0xc0000000,0x00000004,0x00000000,
+0x0003fffe,0x003f3003,0x34030003,0x00080000,0x88006808,0x00000000,0x00000001,0x000000c1,
+0x00000000,0x000210f0,0x00000000,0x00000c00,0x00003000,0x800c0000,0x00000686,0x10382400,
+0x00001000,0x40000000,0x00000143,0x00000000,0x05a00008,0x50000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00006800,0x00000000,0x00000000,0x20000000,
+0x0421e400,0x00000000,0x00000005,0x00000000,0x0303ffc0,0x00003003,0x00080000,0x00000002,
+0x88000000,0x00000000,0x00001000,0x000000c1,0x00000000,0x000210f0,0x00000000,0x00600000,
+0x00003000,0x80000000,0x4a800286,0x14382400,0x00000c00,0x40000000,0x00000143,0x00000000,
+0x00060000,0x00000000,0x00310000,0x00000000,0x00000000,0x00000600,0x00000000,0x00000000,
+0x0000680e,0x80000000,0x00000000,0x00000000,0x0221e000,0x40000000,0x00000005,0x00000000,
+0x0003fffe,0x00003003,0x03220000,0x00000008,0xb0002820,0x00000000,0xa8010000,0x000000e0,
+0x00000000,0x000210f0,0x00000000,0x0101d000,0x00000034,0x81d00000,0x00002286,0x20300000,
+0x00003000,0x40000400,0x00000143,0x00000000,0x00200000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000460,0x00000000,0x00000000,0x00006e43,0x00000000,0x00000000,0x00080000,
+0x0221e400,0x80000000,0x00000007,0x00000000,0x0003ffc0,0x00003003,0x00000000,0x0c800000,
+0xb8002818,0x00000000,0x80000000,0x00000000,0x00000000,0x000110f0,0x00000000,0x01800c00,
+0x00000000,0x81dc0000,0x00000286,0x0c384400,0x00002c00,0x40000400,0x00000143,0x00000000,
+0x00060000,0x50000000,0x00000000,0x00000000,0x00000000,0x00000460,0x00000000,0x00000000,
+0x00000023,0x00000000,0x00000000,0x00000000,0x0421e000,0xc0000000,0x00000007,0x00000000,
+0x0003ffc0,0x000030b3,0x64010002,0x0e80c000,0xc0000004,0x00000000,0x80001000,0x000000c0,
+0x00000000,0x000260f0,0x00000000,0x00000002,0x00000200,0x81dc0000,0x00000286,0x1c304000,
+0x00000400,0x40000400,0x00000143,0x00000000,0x00060740,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x80000000,0x00000000,0x00000000,
+0x0221e000,0x00000000,0x00000008,0x00000000,0x0003fffe,0x00003003,0x14020000,0x5000c000,
+0xc8000000,0x00000000,0x28000000,0x000000c1,0x00000000,0x000210f0,0x00000000,0x00000000,
+0x00000000,0x800c0000,0x00000686,0x0a302000,0x00001c00,0x40000000,0x00000143,0x00000000,
+0x2418080c,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x34000000,0x00000000,0x00000000,0x00000000,0x0421e400,0x40000000,0x00000008,0x00000000,
+0x00ffffc0,0x00003000,0x00048000,0x5ee2c000,0xd0000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x000110f0,0x00000000,0x00000000,0x00000000,0x80000000,0x4a800286,0x16384400,
+0x00003c00,0x40000000,0x00000143,0x00000000,0x00040740,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000600,0x00000000,0x00000000,0x00180000,0x80000000,0x00000000,0x00000000,
+0x0421e000,0x80000000,0x00000008,0x00000000,0x00ffffc0,0x038034c0,0x00046800,0x5ee20000,
+0xd8000000,0x00000000,0x00000000,0x00000000,0x00000000,0x90209020,0x00000000,0x00000000,
+0x00000100,0x81d00000,0x00000686,0x22302000,0x00004800,0x48000080,0x00000143,0x00000000,
+0x0000074c,0x00000000,0x00000000,0x00000000,0x00000000,0x12080000,0x00000000,0x388d2000,
+0x00000740,0x00000000,0x00000000,0x00080000,0x0221e000,0xc0000000,0x00000008,0x00000000,
+0x8bf7ff80,0x03823832,0x0000c804,0x00000000,0x00000270,0x00000000,0x02000000,0x00000000,
+0x00000000,0x90229964,0x00000000,0x02000001,0x00000000,0x00000000,0x00000000,0x04000000,
+0x00001000,0x08000000,0x00000000,0x00000000,0x01200000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00400000,0x00000000,0x39400288,0x24004f41,0x00000090,0x00000000,0x08010000,
+0x01204000,0x00000000,0x00000000,0x805fa000,0x8a03ffc0,0x000008c0,0x14000008,0x00000000,
+0x00060020,0x00000000,0x00000000,0x00000000,0x00000000,0x0002a0d0,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0xc9800000,0x00000103,0x00000000,
+0x01b00000,0x00000000,0x00000000,0x00000000,0x00000000,0x00002000,0x00000000,0x00000000,
+0x0010000b,0x001200d8,0x00000000,0x10000000,0x0541a000,0x00000000,0x00000000,0x00000000,
+0x0003ef80,0x00000c20,0x36200000,0x00000000,0x00020000,0x00000000,0x01002000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x80000000,0x00000207,0x00000000,
+0x00000000,0xc0000000,0x00000103,0x00000000,0x00180000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x001023c8,0x00000000,0x0013000c,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0xcdffffc0,0x035030f2,0x24064800,0x00000000,
+0x00002840,0x00000000,0x00000000,0x00000000,0x00000000,0x90209020,0x00000000,0x00000000,
+0x00000024,0x80000000,0x00000207,0x04000000,0x00000800,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x01000000,0x00000000,0x348c22c8,
+0x00004800,0x00000000,0x00000000,0x00000000,0x01204000,0x00000000,0x00000000,0x00000000,
+0xa903ff80,0x0c96c84b,0x64040800,0x90080006,0x00000340,0x00400000,0x001640b2,0x0f83c000,
+0x00001f00,0x9022a960,0x00000000,0xba000300,0x48000002,0x120802a2,0x18000400,0x480000d0,
+0x04000000,0x10000000,0x000c0000,0x00000000,0x01b84838,0x00e99202,0x002e0112,0x00100000,
+0x002c8164,0x00200a00,0x00000000,0xc9400b88,0x00040020,0x2a000000,0x07c01041,0x00010f80,
+0xc1204001,0x00003983,0x00000000,0x805fa000,0x6f03ffc0,0x02febc05,0x00040004,0x9010c000,
+0x00002830,0x00400000,0x001640b2,0x0f868000,0x00001f00,0x20200000,0x00000000,0x080bd800,
+0x00088800,0x01920002,0x00002000,0x00000054,0x00000000,0x00000080,0x000c8000,0x00000000,
+0x24300008,0x00a88192,0x002e0196,0x00800000,0xc82c8164,0x00000001,0x00000000,0xfc400000,
+0x00002e40,0x00000051,0x07c002e0,0x00080f80,0x90000001,0x00004484,0x00000000,0x00000000,
+0xdb03ffc0,0x094066fb,0xb7200800,0xd0500000,0x00004820,0x00400000,0x001640b2,0x0f80c000,
+0x00001f00,0x00200000,0x00000000,0xa8120000,0x065030c3,0x00020000,0x1c800000,0x00200058,
+0x20000000,0x00000000,0x000a0000,0x00000000,0x341c0000,0x00038008,0x00000138,0x00800000,
+0x382c8164,0x00001001,0x00000000,0x00000000,0x37200020,0xe0000a06,0x07c010c0,0x00000f80,
+0x00000001,0x00003c80,0x00000000,0x00000000,0x4203ffc0,0x0bfcbfbc,0x37366e48,0x9000b052,
+0x20004820,0x00400000,0x000000b2,0x0003a000,0x00001f00,0x20200000,0x00000000,0xa2000606,
+0x07408002,0x800002b0,0x20000686,0x00000000,0x20000000,0x40000080,0x00000183,0x00000000,
+0x15b80000,0x00ac0000,0x002e0000,0x00900000,0x002c8000,0x000010e0,0x00000000,0x00000f84,
+0x34184800,0xc0000b14,0x07c00ac0,0x00080000,0x00000801,0x40000000,0x00000000,0x00000000,
+0xdf03ffc0,0x08febc0b,0xf41c2800,0xd0710106,0x68004964,0x00400000,0x00164000,0x00000000,
+0x00000000,0x20200000,0x00000000,0xa2120302,0x06480042,0x92000002,0x12800706,0x000000d0,
+0x00000000,0x40000400,0x000c0143,0x00000000,0x00006800,0x09001200,0x00000000,0x00800000,
+0x00000000,0x00000a00,0x00000000,0x00000000,0x041c0008,0x00000a04,0x000000e0,0x00010f80,
+0x00000000,0x80003803,0x00000002,0x00000000,0x2f03ffc0,0x087fbc07,0x07380818,0x90000000,
+0x80004820,0x00400000,0x00000000,0x0004a0e0,0x00000000,0x24240000,0x00000000,0xa2000200,
+0x680c0102,0x80080000,0x0b800286,0x004000b8,0x00000000,0x40000080,0x000c8103,0x00000000,
+0x25b84800,0x00030002,0x00000000,0x00000000,0xc8004002,0x00000001,0x00000000,0x00000000,
+0x37206810,0x30000b14,0x00000841,0x00080000,0x00000001,0x00000000,0x00000000,0x00000000,
+0x0003f03e,0x0800bc00,0x34040800,0x00100010,0x10000000,0x00400000,0x00000000,0x00064000,
+0x00000000,0x00200004,0x00000000,0x06e00000,0x00380034,0x80000000,0x13802286,0x00000000,
+0x20000000,0x40000000,0x000a0143,0x00000000,0x373c0808,0x00000000,0x001400e0,0x00800000,
+0x00000000,0x00000d00,0x00000000,0x00000f84,0x34180830,0x30000a04,0x00000e81,0x00080000,
+0x00000c01,0xc0002800,0x00000000,0x00000000,0x0003f000,0x0afebc00,0x37382830,0xd0180046,
+0x40000000,0x00400000,0x00a12001,0x0004a060,0x00000000,0x20200004,0x00000000,0x24020000,
+0x06400056,0x80000000,0x00002286,0x000044c0,0x00000000,0x40000400,0x0000c183,0x00000000,
+0x0018680c,0x00001200,0x00160042,0x00800000,0xf0004000,0x00000000,0x00000000,0xfc400000,
+0x341c6800,0x72000a04,0x00000ec0,0x00080000,0x00000000,0x40000000,0x00000002,0x00000000,
+0x50fbffc0,0x0a4000be,0x02b84c40,0x00180008,0x70006824,0x00400000,0x00010009,0x0001a000,
+0x00000000,0x00200004,0x00000000,0x1a1b9001,0x00080624,0x81900000,0x12002286,0x100000a0,
+0x20000000,0x00028480,0x00000000,0x00000000,0x000c000c,0x05000002,0x00000000,0x00800000,
+0xb0000000,0x00000200,0x00000000,0x00391000,0x3418680c,0x00000b94,0x00000ae0,0x00000000,
+0x0321e001,0x00000000,0x00000000,0x00000000,0x8e03ff80,0x000000d4,0x24010018,0x0e800006,
+0x78014800,0x00400000,0x00000000,0x0004c000,0x00000000,0x14240000,0x00000000,0xb6000300,
+0x00000026,0x81980320,0x33800286,0x00400058,0x24000000,0x00828480,0x00000000,0x00000000,
+0x00a86800,0x000201d0,0x001800c0,0x00800000,0x00000000,0x00000600,0x00000000,0x00000000,
+0x34186e70,0x20010bd4,0x000006c1,0x00080000,0x38000001,0x00001401,0x00000000,0x00000000,
+0x1503ff80,0x00000130,0x80044808,0x0ef8c010,0x38002b70,0x00400000,0x001640b2,0x0f800060,
+0x00001f00,0x00000000,0x00000000,0xb69a0e00,0x00000626,0x93d80010,0x10000706,0x00404040,
+0x00000000,0x49000080,0x000a0183,0x00000000,0x05a0680c,0x00000190,0x001800c0,0x00800000,
+0x002c8164,0x00000000,0x00000000,0x00000f84,0x00186c74,0x00012a06,0x07c00600,0x10080f80,
+0x38000801,0x40001381,0x00000001,0x00000000,0x1703ef80,0x003e0160,0xf4000d58,0x98f80100,
+0x58000054,0x28480000,0x181640b2,0x0f8400e1,0x00001f00,0x20200004,0x00000000,0xb69a0f00,
+0x00000126,0x9a0c1400,0x00000306,0x04000054,0x00000000,0xc9000000,0x000a8143,0x00000000,
+0x2400077c,0x00c80200,0x001800c0,0x00000000,0x002c8164,0x00040400,0x00000000,0xf8781000,
+0x26206e72,0x0e012004,0x07c01081,0x25090f80,0x3c21e0a1,0x40000001,0x00000002,0x00000000,
+0x9a03ff80,0x002fbdef,0x07b84d50,0x0a9c0000,0x60018000,0x08480000,0x001640b2,0x0f8000c1,
+0x00000000,0x002110f0,0x00000000,0xb69b9306,0x4f400027,0x9b133410,0x18002706,0x004040c0,
+0x00008c00,0xc9000080,0x00000143,0x00000000,0x05bc054c,0x000413db,0x001800c0,0x50900000,
+0x00000164,0x00040401,0x00000000,0xf8400000,0x00106832,0x00120000,0x07c00000,0x00000f80,
+0x39000801,0x40004381,0x00000001,0x00000000,0xe503ef80,0x000002af,0x26268660,0x50380726,
+0x18010378,0x00000000,0x801640b2,0x0f860100,0x00001f00,0x142610f0,0x00000000,0x101a0f06,
+0x682c2700,0x9a0c2400,0x28000287,0x3c304020,0x04004800,0xc9000080,0x00000143,0x00000000,
+0xc120081c,0x0dc81a00,0x00300160,0x00000000,0x402c8164,0x00080001,0x00000000,0xf0400000,
+0x34006830,0x00000a90,0x07c00000,0x20010f80,0xc421e000,0xc0004383,0x00000005,0x00000000,
+0xe203ef80,0x0e0001d0,0x36ac2818,0x00180046,0x88010800,0x00080000,0x001640b2,0x0f8000a0,
+0x00001f00,0x000210f0,0x00000000,0x383a0b00,0x08003117,0x9a031732,0x00000286,0x18182080,
+0x04003800,0xcc000000,0x000c6143,0x00000000,0xb418281c,0x01e99310,0x00300170,0x00100000,
+0x002c8164,0x00100e00,0x00000000,0x00000000,0x17382e70,0x2c121208,0x07c00001,0x20010f80,
+0x8421e000,0x40004383,0x00000004,0x00000000,0x2803ef80,0x0f800120,0x03a66d50,0x0aa05107,
+0xe801c860,0x00000000,0x001640b2,0x0f820100,0x00001f00,0x00200004,0x00000000,0x1b1b1f04,
+0xa8008434,0x9a030000,0x00002287,0x382000a0,0x00000000,0xc8000080,0x000c0143,0x00000000,
+0x05a9a81c,0x05001a0c,0x00300160,0x00000000,0x002c8164,0x00101000,0x00000000,0xec7a1000,
+0x03a06800,0x80160204,0x07c00a00,0x20000f80,0xc421e000,0x80004383,0x00000002,0x00000000,
+0x2c000f80,0x00000260,0x66a24d74,0xd03802c2,0xc0c04808,0x00080000,0x801640b2,0x0f8200ad,
+0x00001f00,0x00040004,0x00000000,0x033a0326,0x0f700004,0x9a0f1400,0x00000687,0x00400000,
+0x00001f00,0xc9000080,0x0000c143,0x00000000,0x3418281c,0x00021a03,0x00180160,0x00100000,
+0x402c8164,0x00040481,0x00000000,0xf8400e04,0x04106c70,0x80120a0c,0x07c00000,0x20010f80,
+0xc0000800,0xc0004383,0x00000003,0x00000000,0x2303ff80,0x000002c0,0x03a70664,0x0060f056,
+0x1001cb78,0x00000001,0x801640b2,0x0f8600ad,0x00001f00,0x002002c8,0x00000000,0x0a3b1326,
+0x0f4c4024,0x8b180408,0x28000687,0x0c000060,0x04001f00,0xc9000400,0x000c2143,0x00000000,
+0x34380e50,0x0100000c,0x00300160,0x00100000,0x402c8164,0x00040ca1,0x00000000,0xfc400000,
+0x2408074c,0x8008c000,0x07c00000,0x00010f80,0xc421e000,0x00004383,0x00000008,0x00000000,
+0x5f03e000,0x003ff98e,0x001a054c,0x100811c6,0x00014808,0x00080000,0x801640b2,0x0f800000,
+0x00001f00,0x002002c8,0x00000000,0xa41b5308,0x074c38e6,0x32030000,0x00000421,0x00402000,
+0x04000000,0xcb000400,0x00000143,0x00000000,0x00b80f4c,0x0dcd83d0,0x00300170,0x00100000,
+0x402c8164,0x00000ca1,0x00000000,0x003f1000,0x34064f72,0xec010a04,0x07c00c00,0x20010f80,
+0x80000000,0x40004384,0x00000005,0x00000000,0x0003ef80,0x0000fbc0,0x94000838,0xd0290002,
+0x30004828,0x00080000,0x001640b2,0x0f800060,0x00001f00,0x000290f0,0x00000000,0xb0e00720,
+0x480c2206,0x82070000,0x18002306,0x324000d4,0x04001000,0x1b000400,0x00000000,0x00000000,
+0x34006830,0x05061208,0x00300170,0x00000000,0x002c8164,0x00000900,0x00000000,0x00391000,
+0x00060830,0xec000a01,0x07c00000,0x00000f80,0x0421e000,0x00003b04,0x00000000,0x00000000,
+0x24000f80,0x0ff80000,0x27a22810,0xd06900c9,0xa0004978,0x00000000,0x001640b2,0x0f800000,
+0x00001f00,0x20200004,0x00000000,0x021a0c02,0x00021124,0x920b0000,0x30002287,0x000040a0,
+0x00000000,0x14000400,0x00000000,0x00000000,0x3401803c,0x00c91202,0x00320190,0x00000000,
+0x282c8164,0x00000c61,0x00000000,0x003f1000,0x03a06802,0x720c0151,0x07c00240,0x20080f80,
+0x00000821,0x00004380,0x00000000,0x00000000,0xa1000f80,0x0020ebff,0x07b64d50,0xd0684001,
+0x00014829,0x00400000,0x801640b2,0x00000100,0x00001f00,0x24048004,0x00000000,0x3063d306,
+0x0f403003,0x2a0303b8,0x13802000,0x1a040080,0x20000000,0x1c000400,0x000c4000,0x00000000,
+0x04064820,0x09010a00,0x00320180,0x00000000,0xa02c8000,0x000c1060,0x00000000,0x00000000,
+0x3406480c,0x12000000,0x07c00400,0x20010f80,0x3d21e000,0x00000004,0x00000000,0x00000000,
+0x6403ef80,0x0000f97f,0x00060574,0xd0680420,0x00000148,0x00080000,0x001640b2,0x0f800100,
+0x00000000,0x042610f0,0x00000000,0x00000026,0x0440b054,0x01d80324,0x41002000,0x0fa860a0,
+0x20002c00,0xc5000400,0x00000143,0x00000000,0x34ac0800,0x0d004000,0x00324170,0x00000000,
+0x40000164,0x00000901,0x00000000,0x00000000,0x00066800,0xe80a0a01,0x07c00000,0x20080f80,
+0x0501e000,0x40004384,0x00000008,0x00000000,0x9a03ef80,0x000001df,0x04000804,0xdae81206,
+0x01018000,0x00080000,0x001640b2,0x0f800000,0x00001f00,0x000210f0,0x00000000,0xa4fa0300,
+0x08000002,0x20031406,0x13802000,0x000000cc,0x04004000,0x10000400,0x000ca000,0x00000000,
+0x01b86804,0x00ca1a0c,0x00324172,0x00000000,0xb82c8164,0x00000000,0x00000000,0x00000000,
+0x14000810,0x30000001,0x07c00200,0x20080f80,0x80059001,0x00004003,0x00000000,0x00000000,
+0x9e03ef80,0x0000fa7f,0x03a00d48,0xd07893c6,0x38014800,0x00400000,0x801640b2,0x0f810061,
+0x00001f00,0x00200000,0x00000000,0x3881df00,0x08000077,0x9a000324,0x29802687,0x0f986040,
+0x20001f00,0x00000000,0x00000000,0x00000000,0xc1b8074c,0x00000200,0x00320000,0x00000000,
+0x582c8164,0x00040ec0,0x00000000,0xfc400f44,0x03b00570,0x30161a08,0x07c004e1,0x00080f80,
+0x80000001,0x00001003,0x00000000,0x00000000,0x2d000000,0x0ec000f0,0xc3a62810,0xd0608146,
+0x0041cb49,0x00400000,0x00164000,0x0f800001,0x00001f00,0x400422c8,0x00000000,0xa613dc10,
+0x68300003,0x3a030000,0x14802000,0x00004000,0x20000000,0xc0000400,0x00080143,0x00000000,
+0x00a8003c,0x09070000,0x001800e0,0x00100000,0x382c8164,0x009004c1,0x00000000,0xe0400000,
+0x03200010,0x00000a04,0x00000001,0x20080f80,0x00459000,0x80001404,0x00000005,0x00000000,
+0xb803ef80,0x000003ef,0x00000554,0x50088300,0xd800c808,0x00000000,0x00164001,0x0f838000,
+0x00001f00,0x000660f0,0x00000000,0x00020328,0x0e701600,0x92032404,0x00000687,0x0f9c6000,
+0x20006800,0xc0008480,0x00000143,0x00000000,0x1408000c,0x09040000,0x00000170,0x00000000,
+0x402c8164,0x00001040,0x00000000,0xec7c1e04,0x00142830,0xce0e0a04,0x00000840,0x00080f80,
+0xc541e000,0xc0000003,0x00000004,0x00000000,0x1d03e000,0x0e3ff800,0x34064804,0x90190200,
+0x00018008,0x00400000,0x000000b2,0x0f81a080,0x00000000,0x000290f0,0x00000000,0x241a0838,
+0x68040703,0x20003730,0x13802000,0x000000a0,0x04007c00,0x00000400,0x00000000,0x00000000,
+0x0000680c,0x0dcc01d8,0x002c0174,0x00800000,0x40000164,0x00000001,0x00000000,0x00000000,
+0x00066800,0x26161204,0x07c01001,0x00010000,0xc0059000,0x00001803,0x00000000,0x00000000,
+0x1b000000,0x00000000,0x34062800,0xd00001a2,0x0001800c,0x00080000,0x000020b2,0x0f800000,
+0x00000000,0x00000004,0x00000000,0x04020324,0x680c0024,0x2000033c,0x10002400,0x000000b8,
+0x04000000,0x03000000,0x00000000,0x00000000,0x00000f6c,0x00018190,0x00280170,0x00900000,
+0x00004164,0x00000841,0x00000000,0x003f1e04,0x3400680c,0x00000a0c,0x07c002e0,0x20080000,
+0x80000000,0x00004c03,0x00000000,0x00000000,0x00000000,0x0029fc00,0x00000554,0x0ef84142,
+0x00004820,0x00400000,0x000020b2,0x0f8200e0,0x00001f00,0x00008004,0x00000000,0x063b9312,
+0x48380000,0x00003404,0x14800400,0x00400060,0x20000000,0x1b000400,0x00080000,0x00000000,
+0x01b86830,0x09011a07,0x002f0190,0x00000000,0x782c8164,0x00000a01,0x00000000,0x00000000,
+0x00000770,0xe0000a01,0x07c00420,0x00010000,0x80000001,0x00003c84,0x00000000,0x00000000,
+0x00000000,0x0a80f000,0x001a0004,0xd01842c0,0x00016838,0x00400000,0x001640b2,0x0f83c000,
+0x00001f00,0x00040004,0x00000000,0x10020302,0x68040734,0x01d00000,0x00000400,0x00000040,
+0x20000000,0x10000400,0x00000000,0x00000000,0x00000800,0x0904000c,0x002e0194,0x00100000,
+0xf82c8164,0x00000300,0x00000000,0x003c1fc4,0x00000030,0x200c0156,0x07c00e21,0x20080f80,
+0x00000800,0x00003c00,0x00000000,0x00000000,0xc0000000,0x003f7009,0x74024d6c,0x10093002,
+0x00002830,0x00400000,0x001640b2,0x00004060,0x00001f00,0x00000000,0x00000000,0x001a0800,
+0x683418c0,0x21dc0000,0x12800400,0x0f9ae040,0x20000000,0x00000400,0x00000000,0x00000000,
+0x0006683c,0x05058000,0x002a0190,0x00800000,0x402c8000,0x00000ca1,0x00000000,0x00000000,
+0x34180740,0x00000a04,0x07c00500,0x01010f80,0x80000001,0x00004b81,0x00000000,0x00000000,
+0x24000000,0x0ebb0000,0x57ba080c,0x10010048,0x00006820,0x00400000,0x001640b2,0x00004060,
+0x00001f00,0x20240004,0x00000000,0x20000f20,0x07744083,0x020b0000,0x18000400,0x00000000,
+0x04000000,0x00000400,0x00080000,0x00000000,0x2418683c,0x00c98008,0x002a4150,0x00800000,
+0xe82c8002,0x00000000,0x00000000,0xec7e1000,0x0000681c,0x80000009,0x07c00a00,0x20080f80,
+0xb8059000,0x00004c04,0x00000000,0x00000000,0x0c000000,0x0f3902ae,0x27a66804,0x1010c060,
+0x00014800,0x00080000,0x801640b2,0x0f84006f,0x00001f00,0x00040004,0x00000000,0x041a0000,
+0x04400800,0x20012400,0x13000400,0x0f986040,0x20001f00,0x1a000000,0x00000000,0x00000000,
+0x3400000c,0x09030bd0,0x002a0156,0x00800000,0x802c8164,0x00000e00,0x00000000,0xe47f1f04,
+0x04000f4c,0x00021a02,0x07c00840,0x00080f80,0x80000000,0x00004b84,0x00000000,0x00000000,
+0x96000000,0x067f023f,0x440e0008,0x1a910002,0x00000060,0x00400000,0x801640b2,0x0f80000b,
+0x00001f00,0x800402c8,0x00000000,0x201a0d10,0x074c0103,0x20002410,0x00000000,0x0f82e000,
+0x04001f00,0x19000080,0x000c8000,0x00000000,0x34186e78,0x0d001203,0x00260120,0x00100000,
+0xc02c8164,0x00000d00,0x00000000,0x00000000,0x2418680c,0x00100a05,0x07c00460,0x20080f80,
+0x38459000,0x00004004,0x00000000,0x00000000,0x98000000,0x0000fa8f,0xc3a42800,0x50201102,
+0x00014810,0x00400000,0x801640b2,0x0f832061,0x00001f00,0x002082c8,0x00000000,0x240a0d00,
+0x04400803,0x20010010,0x1c000000,0x0f986000,0x20001f00,0x1c000400,0x0006c000,0x00000000,
+0x3418683c,0x00000000,0x002e0174,0x00000000,0x002c8164,0x00000000,0x00000000,0x003f1e04,
+0x00000440,0x20000155,0x07c004a1,0x00010f80,0x19059000,0x00004000,0x00000000,0x00000000,
+0x18000000,0x0e0001d0,0x17a60550,0x003851c1,0x00010a48,0x00400000,0x001640b2,0x0f816000,
+0x00001f00,0x002002c8,0x00000000,0x1c03d002,0x680c0024,0x1a012400,0x30002000,0x00000000,
+0x00000000,0x10000000,0x000c0000,0x00000000,0x362e280c,0x00060000,0x002e0180,0x00800000,
+0x002c8164,0x00000400,0x00000000,0x00000000,0x34020770,0x2a001351,0x07c004e1,0x00080f80,
+0x38459000,0x00003804,0x00000000,0x00000000,0x00000000,0x0fc00180,0x03a60544,0x50180081,
+0x00010000,0x00400000,0x001640b2,0x0f8000e0,0x00001f00,0x00040000,0x00000000,0x3041d306,
+0x6c700037,0x1a030000,0x00002000,0x00400000,0x00000000,0x00000080,0x000ac000,0x00000000,
+0x14006820,0x0d000000,0x002e4130,0x00800000,0x402c8164,0x00000201,0x00000000,0x00000fc4,
+0x14060f4c,0x2a0e1202,0x07c00a01,0x00010f80,0x38000000,0x00004004,0x00000000,0x00000000,
+0x2d000000,0x0000fd60,0x02206d74,0x00180040,0x0000000c,0x00080000,0x001640b2,0x0f810000,
+0x00001f00,0x00200004,0x00000000,0x3c1a0302,0x07780037,0x20000000,0x40002000,0x003000d4,
+0x04000000,0x07000080,0x000c0000,0x00000000,0x0410281c,0x05060008,0x00320178,0x00000000,
+0x002c8164,0x00000000,0x00000000,0xe0400fc4,0x34000000,0x12021208,0x07c00a01,0x20010f80,
+0x00000800,0x00004000,0x00000000,0x00000000,0x11000000,0x003fe000,0xc2a20550,0x00183346,
+0x0000834c,0x00080000,0x001640b2,0x000000a0,0x00001f00,0x20200004,0x00000000,0x2401d300,
+0x080008c3,0x3a0c0008,0x00002000,0x000800d0,0x04000000,0x19000000,0x00060000,0x00000000,
+0x00186830,0x0dcc0110,0x00328116,0x00100000,0xa82c8000,0x00000000,0x00000000,0x003e1000,
+0x03be0000,0x0c00015d,0x07c00001,0x00010f80,0x80000801,0x00004804,0x00000000,0x00000000,
+0x40000000,0x0500f0fe,0x36ae2824,0xd0390100,0x00004828,0x00080000,0x001640b2,0x0f800000,
+0x00001f00,0x00040004,0x00000000,0x24611404,0x0f4c4603,0x3a030000,0x30002000,0x00400020,
+0x20000000,0x14000000,0x000a0000,0x00000000,0x34062810,0x0d060000,0x00328112,0x00000000,
+0x002c8164,0x00000601,0x00000000,0xe07f1f04,0x00060020,0x24001208,0x07c00001,0x00000f80,
+0x80000801,0x00004384,0x00000000,0x00000000,0x00000000,0x0fbf03a0,0x36380d50,0x5c980812,
+0x00014808,0x00000000,0x001640b2,0x0f800060,0x00001f00,0x20200000,0x00000000,0x10015116,
+0x2f4c0254,0x21dc0000,0x20002000,0x004000b8,0x04000000,0x10000080,0x000c0000,0x00000000,
+0x24062810,0x00c90000,0x00324170,0x00000000,0xc02c8164,0x00000400,0x00000000,0x00000fc4,
+0x34006e6c,0x2a001208,0x07c00001,0x20010f80,0xc0000800,0x00003803,0x00000000,0x00000000,
+0x40000000,0x0e3f018b,0x24062e74,0xd0200008,0x00004820,0x00000000,0x001640b2,0x0f8000e0,
+0x00001f00,0x20200004,0x00000000,0x007a0308,0x080800c0,0x00000400,0x30002000,0x00180000,
+0x04000000,0x00000080,0x000c0000,0x00000000,0x00000810,0x0dcf1a04,0x00240170,0x00000000,
+0x002c8164,0x00001040,0x00000000,0x00381fc4,0x02280030,0x32001202,0x07c00000,0x00010f80,
+0x00000801,0x00003c00,0x00000000,0x00000000,0xa6000000,0x003fecde,0x03b26824,0xd0583010,
+0x00004808,0x00000000,0x003640b2,0x00000000,0x00001f00,0x20200004,0x00000000,0x18020006,
+0x28100024,0x01d303b8,0x1b002000,0x00000080,0x04000000,0x00000400,0x00006000,0x00000000,
+0x00000800,0x00cc000b,0x00320170,0x00000000,0x002c8000,0x000010c0,0x00000000,0x00000e44,
+0x00002800,0x0e060a01,0x07c00001,0x00010f80,0x00000800,0x00004802,0x00000000,0x00000000,
+0x3a000000,0x003801f6,0x14060000,0xdcf83158,0x00018000,0x00000000,0x001640b2,0x0002c000,
+0x00001f00,0x00200000,0x00000000,0x10120308,0x2f5c8124,0x2a020000,0x0a002000,0x000000c0,
+0x00000000,0x10000400,0x000a6000,0x00000000,0x00202804,0x00c90200,0x00270010,0x00000000,
+0x802c8002,0x00000e00,0x00000000,0xfc400000,0x02b00740,0x0e000000,0x07c00001,0x20080f80,
+0x38000000,0x00000000,0x00000000,0x00000000,0x11000000,0x0e4000d0,0xc3b02800,0xd078b800,
+0x00006830,0x00000000,0x001640b2,0x0f800000,0x00001f00,0x00200000,0x00000000,0x0001d124,
+0x2c508000,0x1a030000,0x00002000,0x00200080,0x04000000,0x00000080,0x0008c000,0x00000000,
+0x0002080c,0x09011b58,0x00270196,0x00800000,0x002c8164,0x00001040,0x00000000,0x00000000,
+0x17ae0000,0x20000a04,0x07c00201,0x00080f80,0x00000001,0x00003800,0x00000000,0x00000000,
+0x14000000,0x0000f800,0x40040550,0x101882c0,0x00008000,0x00080000,0x001640b2,0x0f810000,
+0x00001f00,0x00200000,0x00000000,0x001a0c00,0x054440c0,0x03dc3418,0x23002000,0x00000000,
+0x00000000,0x00000400,0x00000000,0x00000000,0x34000800,0x00008003,0x00270172,0x00000000,
+0x402c8364,0x00000f00,0x00000000,0xe4400e04,0x140e000c,0x0e000a01,0x07c00001,0x20000f80,
+0x80000800,0x00004803,0x00000000,0x00000000,0x2d000000,0x0038fc00,0xc0064d44,0xd048f100,
+0x00004808,0x00000000,0x001640b2,0x0f86a060,0x00001f00,0x20208004,0x00000000,0x0801d302,
+0x2f5c0080,0x00000018,0x1c002000,0x000000ac,0x04000000,0x00000400,0x00000000,0x00000000,
+0x34060800,0x01008110,0x002a0196,0x00100000,0xa82c8164,0x00000000,0x00000000,0xfc400000,
+0x24000740,0x00000a07,0x07c00000,0x00080f80,0x80000000,0x00003c84,0x00000000,0x00000000,
+0xe0000000,0x0000027f,0x03a02824,0x90780600,0x0000000c,0x00000000,0x001640b2,0x0f800000,
+0x00001f00,0x00000004,0x00000000,0x04000e30,0x683006c0,0x020003a0,0x00000000,0x000000c0,
+0x20000000,0x00000000,0x000c0000,0x00000000,0x34060800,0x00ed8000,0x00224116,0x00800000,
+0x582c8164,0x00000001,0x00000000,0x003f1000,0x00000460,0x20000003,0x07c00821,0x00080f80,
+0x80000001,0x00004384,0x00000000,0x00000000,0xfc000000,0x003f02ce,0xc7a62e50,0x0000db00,
+0x0001826c,0x00400000,0x001640b2,0x0f850060,0x00001f00,0x20200000,0x00000000,0x201a0232,
+0x28100603,0x00000400,0x00000400,0x00000000,0x20000000,0x00000000,0x00000000,0x00000000,
+0x341e0000,0x0dcf0000,0x00224100,0x00000000,0x002c8164,0x00000ac0,0x00000000,0x00000000,
+0x03a04800,0x000e0003,0x07c004e0,0x00000f80,0xc8000001,0x00003803,0x00000000,0x00000000,
+0x0a000000,0x002e0000,0x74060574,0x10000250,0x00000000,0x00400000,0x001640b2,0x0f820000,
+0x00001f00,0x24040004,0x00000000,0xa02a0302,0x08300203,0x23dd2416,0x4a800000,0x00000000,
+0x00000000,0x08000400,0x00000000,0x00000000,0x34260804,0x00070001,0x00224118,0x00100000,
+0xc02c8164,0x00000000,0x00000000,0xe8400000,0x00000010,0x20000a07,0x07c00001,0x00000f80,
+0x48000000,0x00003800,0x00000000,0x00000000,0x00000000,0x00390000,0x47a66e64,0x0e88d152,
+0x00000000,0x00000000,0x001640b2,0x0f82c0a0,0x00001f00,0x00000004,0x00000000,0x06200000,
+0x2f500204,0x000c0004,0x00000400,0x00000000,0x04000000,0x17000000,0x000c2000,0x00000000,
+0x14180800,0x0dc81a00,0x0022c180,0x00100000,0x002c8164,0x000010c0,0x00000000,0x00000000,
+0x00100440,0x00160004,0x07c002c0,0x00080f80,0xb0000000,0x00000003,0x00000000,0x00000000,
+0x00000000,0x0ba50000,0xc4080540,0xd018c202,0x00002820,0x00400000,0x001640b2,0x0f800000,
+0x00000000,0x00200004,0x00000000,0x24000006,0x6c4c0637,0x3b1003a0,0x4a800000,0x004000c0,
+0x04000000,0x10000404,0x00000000,0x00000000,0x34102804,0x0dcd83d3,0x00328000,0x00800000,
+0xc0000164,0x00000a01,0x00000000,0x003f1000,0x0400000c,0x00000192,0x07c00000,0x00000f80,
+0xc0000000,0x00001804,0x00000000,0x00000000,0x6e000000,0x0c224c04,0x34062f5c,0xd0603010,
+0x0001480c,0x00000000,0x00164000,0x0f86a000,0x00000000,0x80040000,0x00000000,0x00000208,
+0x480c0240,0x1a030320,0x1c000000,0x00000000,0x20000000,0x09000080,0x00000000,0x00000000,
+0x34060810,0x00ee0000,0x002e00c0,0x00000000,0xc0004164,0x00000401,0x00000000,0xf8400e04,
+0x00060000,0x2e001a53,0x00000001,0x00080f80,0xc8000801,0x00000003,0x00000000,0x00000000,
+0xcaffffc0,0x0c78c11b,0x34064818,0x0018f010,0x0000682c,0x00000000,0x00164001,0x0f820000,
+0x00000000,0x90209020,0x00000000,0x0001d006,0x00000640,0x1a030000,0x18002000,0x240000b0,
+0x04009000,0x10000080,0x00000000,0x00000000,0x01b8680c,0x00001a03,0x00224114,0x00800000,
+0x40000164,0x09000000,0x00000000,0xc4b02bc8,0x34000760,0xe0000add,0x00000100,0x00080f80,
+0xc1204000,0x00003c83,0x00000000,0x00000000,0x80e7febc,0x07007002,0x0000000c,0x00000000,
+0x00000000,0x00000000,0x00001000,0x00000000,0x00000000,0x90229964,0x00000000,0x01000001,
+0x00000000,0x80000000,0x00000207,0xfc000000,0x000020ff,0xc0000400,0x00000143,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00200000,0x00000000,0x71400000,
+0x00000003,0x00000000,0x00000000,0x00000000,0x0421e401,0xc0000000,0x00001fff,0x805fa000,
+0x4bffffc0,0x028084b8,0x00002800,0x00000000,0x000a0000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x90200000,0x00000000,0x00000000,0x00000034,0x80000000,0x00000206,0x00186034,
+0x00000000,0x46000000,0x00000103,0x00000000,0x34100000,0x50000000,0x00000000,0x00000000,
+0x00000000,0x120406c0,0x00000000,0x28800000,0x17280440,0x00092000,0x00000000,0x28010000,
+0x0541a100,0x00000000,0x00000000,0x00000000,0xd0ebffbd,0x044044f2,0x36200000,0x08800000,
+0x00000000,0x00000000,0x22003000,0x000000e1,0x00000000,0x9022a964,0x00000000,0x00000001,
+0x00001300,0x80000000,0x00000206,0x08382400,0x00000000,0xc0000000,0x00000143,0x00000000,
+0x00000440,0xb0000000,0x00000000,0x00000000,0x00000000,0x00800000,0x00000000,0x454002c8,
+0x00000000,0x00000004,0x00000000,0x00000000,0x01204000,0xc0000000,0x00001fff,0x805fa000,
+0x00fbff40,0x02803900,0x04006800,0x08800000,0x008a0000,0x00000000,0x00001000,0x00000000,
+0x00000000,0x902110f0,0x00000000,0x00000000,0x00000000,0x80000000,0x00000206,0xfc000000,
+0x000000ff,0x40000000,0x00000103,0x00000000,0x00000000,0x00000000,0x00001200,0x00000000,
+0x00000000,0x02000000,0x00000000,0x28800000,0x00006800,0x00100001,0x00000000,0x00000000,
+0x0221e000,0x00000000,0x00000000,0x00000000,0x10fffffb,0x03803503,0x00018003,0x00000000,
+0xe8000000,0x80000003,0x02000000,0x00000000,0x00000000,0x90209020,0x00000000,0x00000000,
+0x00000800,0x80000000,0x00000287,0x08000000,0x00001000,0x48000000,0x00000103,0x00000000,
+0x00000540,0x00000000,0x00201600,0x00000000,0x00000000,0x02086000,0x00000000,0x388d2308,
+0x0000280c,0x00001200,0x00000000,0x00000000,0x01204400,0x00000000,0x68000000,0x00000007,
+0x40ebff40,0x03803804,0x02260000,0x00180000,0x00000830,0x00000000,0x00001000,0x0e000000,
+0x00041c00,0x90229960,0x00000000,0x00000031,0x000c0000,0x800003a0,0x00000286,0x00000000,
+0x80000800,0x08000010,0x00000000,0x00000000,0xc0000000,0x00000000,0x08000000,0x00000000,
+0x006c8164,0x0024a000,0x00000000,0x39400000,0x00000000,0x000000d0,0x00000000,0x04200000,
+0x0501a000,0x00000000,0x00000000,0x805fa000,0x10fbff3b,0x028044b0,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x9022a0d0,0x00000000,0x000a0000,
+0x00000000,0x800002a8,0x00000286,0x00000000,0x24000000,0xc8b00020,0x00000143,0x00000000,
+0x14000540,0x00000000,0x00c00040,0x00000000,0x00000000,0x00906000,0x00000000,0x28800408,
+0x00000000,0x00000002,0x00000500,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x0003ef00,0x00003404,0x34000000,0x00000102,0x00000000,0x0047fff8,0x00000001,0x00034000,
+0xfffe0000,0x00000003,0x00000000,0xa0000100,0x00000003,0x00000000,0x00142400,0x00000000,
+0x24000000,0xc8000014,0x00000103,0x00000000,0x00080544,0x00000000,0x001a0160,0x00000000,
+0x00000000,0x00000000,0x00000000,0x000f2000,0x00000000,0x00001200,0x00000000,0x10000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0xc0ffffc0,0x034f3002,0x04060000,0x08800006,
+0x00020800,0x80000000,0x003641b2,0x00000000,0x00000000,0x90209020,0x00000000,0x01800000,
+0x08000000,0x00000008,0x28000000,0x02020000,0x00000400,0x10000000,0x00000000,0x00000000,
+0x00000000,0x00000110,0x00000000,0x00800000,0xc0000000,0x00800000,0x00000000,0x348c22c8,
+0x00000000,0x00000000,0x07000000,0x00000e00,0x39204000,0x00001380,0x00000000,0x00000000,
+0x00eff000,0x02c02c00,0x14060000,0x00000006,0x78800800,0x00000000,0x02000000,0x00000000,
+0x00000000,0x9022996c,0x00000000,0x00015001,0x00000000,0x81100000,0x00142687,0x00382400,
+0x00001f00,0x49028480,0x00000183,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00480600,0x00000000,0x2d400000,0x02a80000,0x80100000,0x00000000,0x20000000,
+0x000000a1,0xc0000000,0x00000003,0x805fa000,0x0003ff80,0x00002800,0xc0020000,0x00000000,
+0x08860800,0x00000000,0x02000000,0x00000000,0x00000000,0x000290d0,0x00000000,0x00015400,
+0x00002000,0x81500000,0x00142687,0x06000000,0x00000c00,0xc8028480,0x00000143,0x00000000,
+0x00000000,0x00000000,0x000012c0,0x00000000,0x00000000,0x00082000,0x00000000,0x00000000,
+0x00080000,0x00120000,0x00000000,0x00000000,0x0221e000,0x40000000,0x00000001,0x00000000,
+0x8003fffd,0x000000a2,0xc0010540,0x0000c000,0x38006800,0x00000000,0x22000509,0x00000100,
+0x00000000,0x000260d0,0x00000000,0x00200402,0x00002040,0x80040000,0x00000287,0x1a000000,
+0x00002400,0xc8000000,0x00000143,0x00000000,0x14000000,0x00000000,0x00040000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00002800,0x00000000,0x00000000,0x00000000,
+0x0521a400,0xc0000000,0x00000002,0x00000000,0x0a03dfc0,0x00000000,0x03202801,0x1000c000,
+0x08000030,0x00000000,0x20a12000,0x00000100,0x00000000,0x000110f0,0x00000000,0x00000002,
+0x00000004,0x80000000,0x00000286,0x22382420,0x00003400,0x40000000,0x00000143,0x00000000,
+0x14082800,0x00000000,0x00040000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00002804,0x00000000,0x00000000,0x00000000,0x04c1a000,0x40000000,0x00000001,0x00000000,
+0x00ffdf3e,0x02800000,0x03a30000,0x50000006,0x38400000,0x00000000,0x00a12000,0x00000000,
+0x00000000,0x902110f0,0x00000000,0x00000000,0x00000000,0x80000000,0x00000306,0x12000020,
+0x00004400,0x40000000,0x00000143,0x00000000,0x00082801,0x00000000,0x00000000,0x00000000,
+0x00000000,0x12000600,0x00000000,0x28800000,0x03200004,0x80100000,0x00000000,0x20000000,
+0x0221e4a1,0xc0000000,0x00000002,0x00000000,0x03b7fe31,0x02822840,0x43a00803,0x00000000,
+0x004b4810,0x00000000,0x00003000,0x00000000,0x00000000,0x9022a960,0x00000000,0x00000001,
+0x00002000,0x00000000,0x00040607,0x00300000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x363c0000,0x50000000,0x00200000,0x00000000,0x00000000,0x00200000,0x00000000,0x29400000,
+0x0000080c,0x00107a03,0x00000000,0x00000000,0x04418400,0x00000000,0x28000000,0x805fa006,
+0x80e3ff00,0x058b58c2,0x00006808,0x00000000,0x000a0000,0x00000000,0x00001000,0x00000000,
+0x00000000,0x9022a964,0x00000000,0x00000001,0x00000000,0x40000000,0x00000287,0x01000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x24080000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00200000,0x00000000,0x59400294,0x00006802,0x00120094,0x00000000,0x00000000,
+0x01204000,0x00000000,0x00000000,0x805fa000,0xcdebff80,0x0580598f,0x34040000,0x00000000,
+0x00000000,0x00000000,0x00000060,0x00000000,0x00000000,0x9022a964,0x00000000,0x00000001,
+0x00000024,0x00000000,0x00042400,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x34000000,0x00000000,0x08000000,0x00000000,0x00000000,0x002006c0,0x00000000,0x59400000,
+0x00000740,0x00000000,0x00000000,0x04200000,0x01030800,0x00000000,0x00000000,0x805fa000,
+0x00000fc0,0x00000000,0x00060000,0x00000000,0x00006820,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x04000000,0x00000000,0x41100000,0x28000206,0x00000000,
+0x00000000,0x08080e80,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000388,0x34000030,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x038c0000,0x40002800,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x90200000,0x00000000,0x00000000,
+0x00000200,0x00000000,0x00000000,0x00000000,0x00000000,0x49000000,0x00000103,0x00000000,
+0x00000540,0x00000000,0x00128000,0x00000000,0x00000000,0x00216000,0x00000000,0xe0400000,
+0x00180000,0x00000000,0x00000000,0x00010000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x8003fffb,0x00382d02,0x36a00004,0x00000000,0x00000000,0x00000000,0x00010000,0x00000000,
+0x00000000,0x607c9020,0x00000000,0x00000000,0x00000800,0x00000000,0x00000000,0x01000000,
+0x00000200,0xa0000000,0x00000143,0x00000000,0x14080000,0x00000000,0x00000184,0x00000000,
+0x00000000,0x00400000,0x00000000,0xe04b2288,0x00000000,0x80000000,0x00000000,0x00000000,
+0x01204000,0x00000000,0x00000000,0x00000000,0x0cc7ff32,0x058c5950,0x001c6800,0x90004009,
+0x00006a70,0x00000000,0xa81650b2,0x0000010c,0x00000000,0x9022a964,0x00000000,0x07000201,
+0x00000134,0x80020000,0x00000206,0x00000000,0x00000000,0x40000000,0x00000103,0x00000000,
+0x15ba0470,0x10000000,0x00000001,0x00000000,0x00000000,0x00200460,0x00000000,0x59400fc4,
+0x0000680c,0x8a001202,0x07000000,0x00000e00,0x0201e400,0x00000000,0x48000000,0x805fa006,
+0xb8fffff5,0x028008a0,0x76206d6c,0x50204006,0x000a081c,0x00000000,0x00001000,0x00000000,
+0x00000000,0x902100f0,0x00000000,0x0021d000,0x00002104,0x81d00000,0x00002286,0x02434400,
+0x00000000,0x45880480,0x00000143,0x00000000,0x04086810,0x00000000,0x002e0180,0x00000000,
+0x00000000,0x00806000,0x00000000,0x28800000,0x14000803,0x000900d4,0x00000000,0x00000000,
+0x0521a000,0x40000000,0x00000000,0x00000000,0x80e3ff00,0x058b58c2,0x00006808,0x00000000,
+0x000a0000,0x00000000,0x00001000,0x00000000,0x00000000,0x9022a964,0x00000000,0x00000001,
+0x00000000,0x40000000,0x00000287,0x01000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x24080000,0x00000000,0x00000000,0x00000000,0x00000000,0x00200000,0x00000000,0x59400294,
+0x00006802,0x00120094,0x00000000,0x00000000,0x01204000,0x00000000,0x00000000,0x805fa000,
+0x00dbff3d,0x05805950,0x00006800,0x00000000,0x08404800,0x00000000,0x00001000,0x00000000,
+0x00000000,0x9022a964,0x00000000,0x00000001,0x00002000,0x80000000,0x00000286,0x00000000,
+0x00000000,0x40000000,0x00000103,0x00000000,0x24000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00200000,0x00000000,0x59400000,0x00000000,0x00150000,0x00000000,0x00000000,
+0x00000400,0x00000000,0x00000000,0x805fa000,0x80ff7fc0,0x02802800,0x14082803,0x0a800000,
+0x000a0020,0x00000000,0x00000000,0x00000000,0x00000000,0x90200000,0x00000000,0x00000000,
+0x00000100,0x80000000,0x00000207,0x00000000,0x00000000,0x01800000,0x00000000,0x00000000,
+0x00100744,0x50000000,0x00000000,0x00000000,0x00000000,0x00800000,0x00000000,0x28800000,
+0x00006808,0x00120000,0x00000000,0x00000000,0x0521a000,0x00000000,0x00000000,0x00000000,
+0x00cffcc0,0x05805950,0x040e0548,0x0ce80002,0x0001c82c,0x00000000,0x00002000,0x00000000,
+0x00000000,0x9022a964,0x00000000,0x00000b07,0x800c2004,0x8a0c0004,0x00000286,0x00000000,
+0x00000000,0x44800000,0x00000103,0x00000000,0x05b00808,0x0d009208,0x00140000,0x00000000,
+0x00000000,0x00200000,0x00000000,0x59400000,0x00080030,0x00000000,0x00000000,0x10010000,
+0x0401e000,0x00000000,0x00000000,0x805fa000,0x0cdbffc0,0x000008b6,0x14000000,0x503000c0,
+0x00c22800,0x00000000,0x000c0000,0x000000c0,0x00000000,0x00000000,0x00000000,0x00120000,
+0x68003100,0x00043400,0x21800000,0x00000000,0x00000000,0x40000000,0x00000103,0x00000000,
+0x00006800,0x00060008,0x000000d4,0x00000000,0x30000000,0x00000001,0x00000000,0x003c1000,
+0x00006800,0xe4179a00,0x00000500,0x00000000,0x00000000,0x00003c80,0x00000000,0x00000000,
+0x3cffef40,0x028028b0,0x662a6810,0x0aa03050,0x00000b60,0x00480000,0x000000b2,0x00000000,
+0x00000000,0x902210d0,0x00000000,0x0063d006,0x08000214,0x82000320,0x48002207,0x00342000,
+0x20000400,0x00000000,0x00000000,0x00000000,0x00002e50,0x09001a00,0x00300000,0x00000000,
+0x00180000,0x00800000,0x00000000,0x28800000,0x24002c50,0x00000004,0x07000000,0x01090000,
+0x00000000,0x00000000,0x00000000,0x00000000,0xc0d3fef6,0x058b595e,0x00066e44,0x00604008,
+0x00000140,0x00000000,0x28001000,0x000000d1,0x00000000,0x9022a964,0x00000000,0x00000401,
+0x00002000,0x80000000,0x00000207,0x00000000,0x00000000,0x40000000,0x00000103,0x00000000,
+0x00000f40,0x50c82000,0x000000c0,0x00000000,0x00000000,0x00200000,0x00000000,0x59400f04,
+0x00006804,0x00000000,0x00000000,0x00000000,0x38000400,0x00000001,0xc8000000,0x805fa006,
+0x8cfffff7,0x028008a0,0x0400480e,0x10000000,0x010a6808,0x00000000,0x000010b2,0x0e000000,
+0x00000000,0x902100f0,0x00000000,0x00120002,0x00000100,0x80000000,0x00000286,0x02000000,
+0x00000000,0x04800000,0x00000000,0x00000000,0x34180010,0x50000000,0x00000000,0x00000000,
+0x00000164,0x00800000,0x00000000,0x28800000,0x00006830,0x00112050,0x07000000,0x00000000,
+0x0521a400,0x00000000,0x00000000,0x00000000,0xd2dfff80,0x060f6123,0x84000800,0x00000000,
+0x008a4800,0x00000000,0x02001000,0x00000000,0x00000000,0x90229964,0x00000000,0x00000001,
+0x00000000,0x80000000,0x00000206,0x10000000,0x00001000,0x48000000,0x00000103,0x00000000,
+0x34180000,0x50000000,0x00000000,0x00000000,0x00000000,0x00286000,0x00000000,0x614003c8,
+0x00004810,0x0012120c,0x00000000,0x00000000,0x01204000,0x00000000,0x00000000,0x805fa000,
+0x00fffff9,0x04c04404,0x14000000,0x0a800000,0x00060020,0x00000000,0x00001000,0x00000000,
+0x00000000,0x90209020,0x00000000,0x00000000,0x00000200,0x80000000,0x00000287,0x10000000,
+0x00004800,0xc8000000,0x00000143,0x00000000,0x34180540,0x00000000,0x00001600,0x00000000,
+0x00000000,0x09002000,0x00000000,0x4c912408,0x00002800,0x00100098,0x00000000,0x00000000,
+0x01204400,0x00000000,0x28000000,0x00000007,0x92ebff80,0x03c03c06,0x47b80f44,0x00000306,
+0x4000000c,0x00000001,0x000001b2,0x00020000,0x00001c00,0x90229964,0x00000000,0x001a0031,
+0x00000700,0x81100400,0x18002306,0x10030000,0x04001000,0x40000080,0x00000143,0x00000000,
+0x34040000,0x00000150,0x001b00d6,0x00800000,0xb86c8000,0x00200a80,0x00000000,0x3d400000,
+0x17a06810,0x001212d2,0x07000400,0x10000000,0x0521a001,0x00000000,0x00000003,0x805fa000,
+0x0efbefba,0x068044a0,0x04082800,0x00000001,0x20026c40,0x00080001,0x003641b2,0x00000000,
+0x00000000,0x902260d0,0x00000000,0x00120800,0x280000c4,0x9a000000,0x00000286,0x7a000000,
+0x2000c400,0x40000400,0x00000183,0x00000000,0x24180020,0x00000001,0x00260030,0x00100000,
+0xa8000002,0x04000600,0x00000000,0x68800f44,0x00002800,0x00120000,0x07000000,0x00010e00,
+0x8481a000,0xc0001184,0x0000000d,0x00000000,0xbdfbfffb,0x04406806,0x03300d64,0x00081008,
+0xc8010030,0x00000001,0x003641b2,0x00060000,0x00001c00,0x902290d0,0x00000000,0x001a0c02,
+0x00040800,0x811d0000,0x20000286,0x14000000,0x20002c00,0x40000080,0x00000183,0x00000000,
+0x14104804,0x00000000,0x001a80d8,0x00000000,0xf86c8002,0x04000000,0x00000000,0x44be1e84,
+0x00080010,0x40000008,0x070008a0,0x00000e00,0x2d21a000,0x00000002,0x0000000a,0x00000000,
+0x40fbffc0,0x06404404,0x14000640,0xd8800003,0x20012800,0x00400000,0x003641b2,0x00066000,
+0x00000000,0x902290d0,0x00000000,0x12035202,0x00002000,0x82000000,0x48000686,0x0c000000,
+0x20001400,0x40080000,0x00000183,0x00000000,0x03284d48,0x008a0150,0x000000d4,0x00800000,
+0x00000010,0x10000000,0x00000000,0x64bd1000,0x24040770,0xd2000390,0x07000000,0x00010e00,
+0x0521a000,0x40001404,0x0000000d,0x00000000,0x9afbffc0,0x04ce0114,0x00020660,0x00580306,
+0x68006804,0x00000000,0x000001b2,0x0e020000,0x00001c00,0x902260d0,0x00000000,0x000a0400,
+0x002000d4,0x9a000000,0x00002286,0x120000a0,0x00001c00,0x40080000,0x00000143,0x00000000,
+0x17a06804,0x10000a01,0x000c00d9,0x00800000,0xf06c8164,0x10000c00,0x00000000,0x4c800000,
+0x14040800,0x0e001208,0x070006e1,0x00010000,0x04c1a000,0x80000000,0x00000003,0x00000000,
+0xfdfbfffe,0x03804fe4,0x00000800,0x08801040,0x00002803,0x00400000,0x000030b2,0x0006a000,
+0x00000000,0x902290d0,0x00000000,0x081b9d02,0x4d400000,0x80070220,0x1b802286,0x480000a0,
+0x20009800,0x40000080,0x00000143,0x00000000,0x262c0030,0x10a80194,0x001a80c5,0x00100000,
+0x00000000,0x10000b00,0x00000000,0x38800000,0x001a0000,0x700000de,0x07000000,0x20000000,
+0xc521a000,0x40000003,0x00000000,0x00000000,0x93fbfffe,0x04803802,0x00000770,0x9a80c0c6,
+0x10008004,0x00000000,0x283651b2,0x0e000060,0x00000000,0x902290d0,0x00000000,0x00000006,
+0x00080800,0x83d00000,0x20002306,0x44000070,0x0000dc00,0x40000400,0x00000183,0x00000000,
+0x00066d60,0x05008150,0x00260112,0x00800000,0x00000364,0x10000000,0x00000000,0x48be1e44,
+0x14002800,0x8000000e,0x07000200,0x20080e00,0x04c1a000,0xc0003804,0x00000003,0x00000000,
+0x80fbefc0,0x02900184,0x04020020,0xd8a05000,0x70002f40,0x80080001,0x283641b2,0x0e000061,
+0x00001c00,0x902110f0,0x00000000,0x20215800,0x00040037,0x8a082400,0x13800686,0x54000000,
+0x00000000,0x40000000,0x00000143,0x00000000,0x26242834,0x05008002,0x00260000,0x00000000,
+0xc02c8164,0x10001001,0x00000000,0x28800000,0x02200004,0x72001200,0x07000000,0x00010e00,
+0x0521a001,0x00000000,0x0000000b,0x00000000,0x8003ffc0,0x00002802,0x00004800,0x50600000,
+0x78000444,0x80000001,0x00364000,0x0003c000,0xfffe0000,0x000110f3,0x00000000,0x18620106,
+0x07403014,0x82000220,0x00002286,0x6a300a00,0xa8000000,0x40000090,0x00000183,0x00000000,
+0x34040544,0x00020001,0x001a8060,0x00000000,0x00000000,0x00001000,0x00000000,0x003f1e04,
+0x00002800,0x241000d0,0x00000401,0x00080e00,0xc521a000,0x80004003,0x0000000a,0x00000000,
+0x9103ffc0,0x0000e4ef,0x02a00648,0x1ec08308,0x00000548,0x00080000,0x00364001,0x0e03c000,
+0x00000000,0x000260d0,0x00000000,0x00015000,0x280000f4,0x800d0000,0x13802206,0x60300a80,
+0x0000e400,0x40000080,0x00080143,0x00000000,0x36be2f44,0x00000000,0x00000060,0x00800000,
+0x00004364,0x00000000,0x00000000,0x00000e44,0x00000804,0x0000000c,0x00000400,0x10000e00,
+0x3a21a000,0x80001381,0x00000008,0x00000000,0xb803ffc0,0x0e404bf3,0x02a80808,0x1aa00000,
+0xe8004830,0x00080001,0x18000001,0x0e0400e0,0x00001c00,0x000690d0,0x00000000,0xb8600000,
+0x08100003,0x80000000,0x00000286,0x5e3000b0,0x0000b800,0x40000000,0x00000143,0x00000000,
+0x001e0544,0x00000150,0x00020170,0x00800000,0xc02c8364,0x00000c01,0x00000000,0xf4400000,
+0x02200020,0x00000000,0x00000000,0x20080000,0x4221a000,0xc0004200,0x0000000e,0x00000000,
+0x80ffffc0,0x0000e936,0x00024800,0x0c801044,0x88010764,0x00000001,0x003640b2,0x0e03a000,
+0x00021c00,0x000110d0,0x00000000,0x18000100,0x0540a234,0x81901628,0x00000306,0x58030000,
+0x2000ec00,0x40000090,0x00000183,0x00000000,0x34a80644,0x09000000,0x00040020,0x00800000,
+0x006c8364,0x00000c00,0x00000000,0x00000000,0x00004800,0x52001a08,0x07000400,0x00000e00,
+0xc421a001,0xc0000003,0x00000000,0x00000000,0x4affffc0,0x0514400f,0x44004808,0x00680800,
+0x30018800,0x00080001,0x003641b2,0x0e046000,0x00000000,0x90209020,0x00000000,0xa8000030,
+0x000008c2,0x9a000002,0x00002286,0x66000054,0x0001fc00,0x40000080,0x00000143,0x00000000,
+0x03a60008,0x05cc0000,0x00000030,0x00800000,0x80000364,0x00800601,0x00000000,0x50902000,
+0x34082800,0xf0001a0c,0x07000000,0x00000e00,0x0481a000,0xc0000400,0x0000000c,0x00000000,
+};
+
+/* data */
+static unsigned long srp_fw_data[] __devinitdata = {
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x80050000,0x000a800f,0x001e801b,0x80110014,0x00368033,
+0x8039003c,0x802d0028,0x00228027,0x00668063,0x8069006c,0x807d0078,0x00728077,0x80550050,
+0x005a805f,0x004e804b,0x80410044,0x00c680c3,0x80c900cc,0x80dd00d8,0x00d280d7,0x80f500f0,
+0x00fa80ff,0x00ee80eb,0x80e100e4,0x80a500a0,0x00aa80af,0x00be80bb,0x80b100b4,0x00968093,
+0x8099009c,0x808d0088,0x00828087,0x01868183,0x8189018c,0x819d0198,0x01928197,0x81b501b0,
+0x01ba81bf,0x01ae81ab,0x81a101a4,0x81e501e0,0x01ea81ef,0x01fe81fb,0x81f101f4,0x01d681d3,
+0x81d901dc,0x81cd01c8,0x01c281c7,0x81450140,0x014a814f,0x015e815b,0x81510154,0x01768173,
+0x8179017c,0x816d0168,0x01628167,0x01268123,0x8129012c,0x813d0138,0x01328137,0x81150110,
+0x011a811f,0x010e810b,0x81010104,0x03068303,0x8309030c,0x831d0318,0x03128317,0x83350330,
+0x033a833f,0x032e832b,0x83210324,0x83650360,0x036a836f,0x037e837b,0x83710374,0x03568353,
+0x8359035c,0x834d0348,0x03428347,0x83c503c0,0x03ca83cf,0x03de83db,0x83d103d4,0x03f683f3,
+0x83f903fc,0x83ed03e8,0x03e283e7,0x03a683a3,0x83a903ac,0x83bd03b8,0x03b283b7,0x83950390,
+0x039a839f,0x038e838b,0x83810384,0x82850280,0x028a828f,0x029e829b,0x82910294,0x02b682b3,
+0x82b902bc,0x82ad02a8,0x02a282a7,0x02e682e3,0x82e902ec,0x82fd02f8,0x02f282f7,0x82d502d0,
+0x02da82df,0x02ce82cb,0x82c102c4,0x02468243,0x8249024c,0x825d0258,0x02528257,0x82750270,
+0x027a827f,0x026e826b,0x82610264,0x82250220,0x022a822f,0x023e823b,0x82310234,0x02168213,
+0x8219021c,0x820d0208,0x02028207,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00007d00,0x0000fa00,0x00017700,0x0001f400,0x00027100,0x0002ee00,0x00036b00,
+0x0003e800,0x00046500,0x0004e200,0x00055f00,0x0005dc00,0x00065900,0x0006d600,0x00000000,
+0x00007d00,0x0000bb80,0x0000dac0,0x0000fa00,0x00013880,0x00017700,0x0001b580,0x0001f400,
+0x00027100,0x0002ee00,0x00036b00,0x0003e800,0x0004e200,0x0005dc00,0x00000000,0x00007d00,
+0x00009c40,0x0000bb80,0x0000dac0,0x0000fa00,0x00013880,0x00017700,0x0001b580,0x0001f400,
+0x00027100,0x0002ee00,0x00036b00,0x0003e800,0x0004e200,0x00000000,0x00007d00,0x0000bb80,
+0x0000dac0,0x0000fa00,0x00013880,0x00017700,0x0001b580,0x0001f400,0x00023280,0x00027100,
+0x0002af80,0x0002ee00,0x00036b00,0x0003e800,0x00000000,0x00001f40,0x00003e80,0x00005dc0,
+0x00007d00,0x00009c40,0x0000bb80,0x0000dac0,0x0000fa00,0x00013880,0x00017700,0x0001b580,
+0x0001f400,0x00023280,0x00027100,0x0000ac44,0x0000bb80,0x00007d00,0x00100200,0x00000002,
+0x02000000,0x00020014,0x00000100,0x00180100,0x00000001,0x01000001,0x0001001a,0x00010001,
+0x01040401,0x01000004,0x04010100,0x00040108,0x01010000,0x01020401,0x00010004,0x04010100,
+0x01040101,0x01000000,0x01000101,0x00000001,0x01010100,0x00010100,0x01000000,0x01000101,
+0x00000001,0x01010100,0x00010100,0x01000000,0x01000101,0x00000001,0x01010100,0x00010100,
+0x01000000,0x01000101,0x00000001,0x01010100,0x00010100,0x01000000,0x010d0201,0x01000102,
+0x02010101,0x0102010f,0x01010101,0x010b0201,0x00010102,0x02010101,0x01020107,0x01000101,
+0x010e0201,0x01010002,0x02010101,0x0002010a,0x01010001,0x01090101,0x00000101,0x01010101,
+0x01010109,0x01010000,0x01060101,0x01010001,0x01010100,0x0001010c,0x01010100,0x01050101,
+0x01000101,0x01010100,0x01010103,0x01000001,0x010f0401,0x01010104,0x04010101,0x01040107,
+0x01000101,0x010b0401,0x00010104,0x04010101,0x01040103,0x01000001,0x010d0401,0x01000104,
+0x04010101,0x01040105,0x01000100,0x01090401,0x00000104,0x04010101,0x01040101,0x01000000,
+0x010e0401,0x01010004,0x04010101,0x00040106,0x01000101,0x010a0401,0x00010004,0x04010101,
+0x00040102,0x01000001,0x010c0401,0x01000004,0x04010101,0x00040104,0x01000100,0x01080401,
+0x00000004,0x04010101,0x00040100,0x01000000,0x00000001,0x10311131,0x01210121,0x00110011,
+0x00110011,0x11310830,0x01311031,0x00110011,0x00110011,0x20312231,0x21212121,0x12211221,
+0x02210221,0x01310830,0x11211121,0x10211021,0x00210021,0x20312231,0x21212121,0x12211221,
+0x02210221,0x11310840,0x01311031,0x00110011,0x00110011,0x23411810,0x13311331,0x30413141,
+0x22410341,0x21312131,0x12311231,0x20312031,0x02310231,0x32113311,0x18101030,0x21411a10,
+0x02411241,0x10311031,0x11211121,0x11211121,0x01310131,0x00310031,0x30313331,0x32213221,
+0x23212321,0x03210321,0x13113111,0x20112211,0x20401040,0x11413020,0x10311031,0x01310131,
+0x00110011,0x00110011,0x00110011,0x00110011,0x38103420,0x51413a10,0x3c101541,0x3e100541,
+0x24414241,0x41314131,0x14311431,0x04310431,0x32414041,0x30412341,0x31313131,0x13311331,
+0x03310331,0x22312231,0x21212121,0x21212121,0x12111211,0x02212021,0x54215521,0x35214521,
+0x44115311,0x25115211,0x43115011,0x33113411,0x20401040,0x12412141,0x11211121,0x11211121,
+0x10311031,0x01310131,0x00210021,0x00210021,0x38203030,0x51413c10,0x3e101541,0x42414010,
+0x41412441,0x14311431,0x04414041,0x23413241,0x13413141,0x03413041,0x22212221,0x22212221,
+0x20212021,0x20212021,0x02210221,0x02210221,0x45315531,0x54215421,0x35113511,0x35113511,
+0x44215321,0x52115211,0x50112511,0x34114311,0x33110511,0x20301040,0x2c202820,0x21413010,
+0x02411241,0x11311131,0x10311031,0x01310131,0x00310031,0x53413210,0x34103541,0x52414441,
+0x51412541,0x15311531,0x43314331,0x34313431,0x40410541,0x24314231,0x04313331,0x41214121,
+0x14211421,0x23213221,0x31113111,0x13111311,0x03213021,0x20112211,0x54115511,0x50114511,
+0x20401040,0x11413020,0x10311031,0x01310131,0x00110011,0x00110011,0x00110011,0x00110011,
+0x3c203430,0x48104030,0x4e204a20,0x71415220,0x56101741,0x5c205820,0x16416141,0x60100641,
+0x64106210,0x14414141,0x32410441,0x30412341,0x31313131,0x13311331,0x03310331,0x22312231,
+0x12212121,0x02212021,0x76317731,0x75316731,0x66315731,0x74217421,0x65214721,0x73215621,
+0x37213721,0x64216421,0x45315531,0x36213621,0x27117211,0x70214621,0x07110711,0x26112611,
+0x53215421,0x60116011,0x44213521,0x62116311,0x25215221,0x51115111,0x15111511,0x34214321,
+0x05115011,0x24114211,0x40113311,0x20401040,0x40303040,0x48102141,0x11311131,0x10311031,
+0x01310131,0x00210021,0x00210021,0x4e304a20,0x5a105620,0x72415c20,0x60102741,0x17311731,
+0x07417141,0x36416341,0x62100641,0x51416410,0x26312631,0x60416241,0x61316131,0x16311631,
+0x43411541,0x66100541,0x24414241,0x14414141,0x04414041,0x32313231,0x23312331,0x31213121,
+0x31213121,0x13211321,0x13211321,0x03313031,0x22212221,0x12111211,0x12111211,0x02112011,
+0x76217721,0x57216721,0x66216621,0x74217421,0x47214721,0x55317531,0x56216521,0x73117311,
+0x64113711,0x45215421,0x35215321,0x70114611,0x52114411,0x50112511,0x33113411,0x20401040,
+0x40203040,0x4c104430,0x12412141,0x00414e10,0x11311131,0x10311031,0x01310131,0x54105020,
+0x58105610,0x73416541,0x72415a10,0x64412741,0x71414641,0x5c101741,0x36416341,0x45415441,
+0x5e104441,0x62316231,0x26312631,0x16311631,0x06416141,0x35415341,0x25415241,0x51315131,
+0x15311531,0x43314331,0x34313431,0x40410541,0x42314231,0x24312431,0x41314131,0x14213321,
+0x23213221,0x30310431,0x03210321,0x31113111,0x31113111,0x22111311,0x02112011,0x76217721,
+0x67116711,0x57117511,0x74116611,0x56114711,0x55113711,0x07117011,0x50116011,0x20404040,
+0x31314141,0x11111111,0x11111111,0x40404040,0x30304040,0x30303030,0x10302010,0x20202020,
+0x10101041,0x41411020,0x41101010,0x41413131,0x31314141,0x31313131,0x31313131,0x21212121,
+0x30404040,0x20302020,0x20202010,0x41412020,0x10101041,0x41411041,0x10101010,0x41411010,
+0x41414110,0x41101041,0x31314110,0x41414141,0x41414141,0x31313131,0x31313131,0x31314141,
+0x41413131,0x41413131,0x31314141,0x41413131,0x41413131,0x41413131,0x41413131,0x21212121,
+0x21212121,0x31313131,0x31313131,0x21212121,0x21212121,0x21213131,0x21213131,0x31313131,
+0x21212121,0x21213131,0x31312121,0x31313131,0x21211111,0x21212121,0x11113131,0x11111111,
+0x11112121,0x21211111,0x21212121,0x21212121,0x11111111,0x21211111,0x11111111,0x11111111,
+0x41301111,0x41414141,0x41414141,0x31311041,0x41413131,0x31313131,0x31313131,0x31313131,
+0x31313131,0x31313131,0x31314141,0x21214141,0x21212121,0x31313131,0x21212121,0x21212121,
+0x21212121,0x31312121,0x11112121,0x11112121,0x11112121,0x11112121,0x11112121,0x11112121,
+0x21211111,0x11111111,0x11111111,0x11111111,0x11111111,0x11111111,0x11111111,0x11111111,
+0x21213131,0x11111111,0x00001111,0x40404040,0x20303040,0x31311010,0x31314141,0x40404040,
+0x40303040,0x30303030,0x20303020,0x20202020,0x20202020,0x20101010,0x10201010,0x10411010,
+0x10101010,0x41414141,0x10101010,0x41414141,0x41104141,0x41414141,0x41104141,0x41413131,
+0x31313131,0x31313131,0x31314141,0x31313131,0x31312121,0x21212121,0x21213131,0x11112121,
+0x11111111,0x10411010,0x10411010,0x41414141,0x41414141,0x41414141,0x41414141,0x41414141,
+0x10414141,0x31313131,0x41414141,0x31313131,0x31313131,0x31313131,0x31314141,0x31313131,
+0x31313131,0x31313131,0x41413131,0x31313131,0x31313131,0x31313131,0x31313131,0x31313131,
+0x31313131,0x31313131,0x31313131,0x41413131,0x31313131,0x31313131,0x31312121,0x31313131,
+0x21212121,0x21213131,0x21212121,0x31312121,0x21212121,0x21212121,0x31312121,0x21212121,
+0x21212121,0x31312121,0x21211111,0x21212121,0x21212121,0x11112121,0x21212121,0x21211111,
+0x21211111,0x21212121,0x11112121,0x11111111,0x21211111,0x11111111,0x11111111,0x11112121,
+0x11111111,0x11111111,0x11111111,0x11111111,0x11111111,0x11111111,0x11111111,0x11111111,
+0x11111111,0x11111111,0x20404040,0x31314141,0x11111111,0x11111111,0x41203030,0x41401020,
+0x40414110,0x40404040,0x30303040,0x30303030,0x20102020,0x10411020,0x41101010,0x41411041,
+0x31313131,0x31314141,0x21212121,0x31313131,0x31313131,0x31312121,0x21213131,0x21212121,
+0x11112121,0x11111111,0x11111111,0x21211111,0x30402121,0x11113030,0x10202020,0x20102020,
+0x41202020,0x10101010,0x41101010,0x41101010,0x10414110,0x41413131,0x41414141,0x31311041,
+0x41414141,0x41413131,0x41414141,0x31314141,0x31314141,0x31313131,0x41413131,0x41414141,
+0x31314141,0x31314141,0x31314141,0x31314141,0x31314141,0x21212121,0x31312121,0x31313131,
+0x21212121,0x21213131,0x31312121,0x31313131,0x21213131,0x21213131,0x21212121,0x21213131,
+0x31312121,0x21212121,0x21213131,0x11111111,0x21211111,0x21212121,0x11111111,0x11112121,
+0x11112121,0x11111111,0x11111111,0x10411111,0x31313131,0x21214141,0x31312121,0x21213131,
+0x31312121,0x21212121,0x31313131,0x31312121,0x11112121,0x11111111,0x21212121,0x21212121,
+0x11112121,0x21212121,0x21211111,0x11111111,0x21212121,0x11111111,0x11112121,0x11112121,
+0x11111111,0x11111111,0x11111111,0x11111111,0x11111111,0x11111111,0x00001111,0x41404040,
+0x40404040,0x20304040,0x41414141,0x41414141,0x41414141,0x41413131,0x31313131,0x31314141,
+0x31313131,0x31313131,0x31313131,0x31313131,0x31313131,0x41413131,0x30303030,0x30303040,
+0x20202020,0x20202020,0x20203020,0x30203020,0x10202010,0x10101020,0x10101010,0x10101010,
+0x10101010,0x10201010,0x41104120,0x41414141,0x41414141,0x41414141,0x41414110,0x10414141,
+0x41413131,0x31313131,0x31313131,0x41413131,0x31313131,0x21212121,0x21212121,0x21213131,
+0x11111111,0x21211111,0x11111111,0x31313131,0x31313131,0x31313131,0x31313131,0x31313131,
+0x31313131,0x31313131,0x31313131,0x31313131,0x31314141,0x21212121,0x21213131,0x21212121,
+0x31312121,0x21212121,0x21212121,0x21213131,0x21212121,0x21212121,0x21212121,0x21212121,
+0x21212121,0x21212121,0x21212121,0x21212121,0x21212121,0x21212121,0x21213131,0x21212121,
+0x21212121,0x21212121,0x21213131,0x21213131,0x21211111,0x21212121,0x21213131,0x21211111,
+0x21211111,0x11112121,0x11112121,0x11111111,0x11111111,0x11111111,0x11111111,0x11111111,
+0x11111111,0x11111111,0x11111111,0x11111111,0x11112121,0x21211111,0x11111111,0x00001111,
+0x00200010,0x00400030,0x00100011,0x00010001,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00540044,0x00740064,0x00940084,0x00ac00a4,0x00bc00b4,0x00cc00c4,0x00d600d4,0x00e200da,
+0x00e800e4,0x00f000ec,0x00f40018,0x00f800f6,0x00fe00fa,0x00150051,0x01020100,0x00410104,
+0x00140014,0x00040040,0x00230032,0x00310031,0x00130013,0x00300030,0x00030003,0x00220022,
+0x00120021,0x00020020,0x01160106,0x01360126,0x0142013e,0x014e0146,0x01540152,0x015c0158,
+0x01640160,0x001f00f1,0x0168000f,0x016c016a,0x016e002e,0x001e00e1,0x01720170,0x01760174,
+0x017a0178,0x00d3006c,0x00d2017c,0x00d1002d,0x017e007b,0x003c0180,0x00b40182,0x001d001d,
+0x000d00d0,0x008a00a8,0x004c00c4,0x006b00b6,0x00c300c3,0x00c200c2,0x002c002c,0x00b500b5,
+0x0098005b,0x00c100c1,0x001c001c,0x00c00089,0x000c000c,0x00a6004b,0x0097006a,0x00b300b3,
+0x003b003b,0x00a50088,0x00b200b2,0x0096005a,0x004a004a,0x00780087,0x00490049,0x00670077,
+0x002b002b,0x002b002b,0x00b100b1,0x001b001b,0x000b00b0,0x00a40069,0x003a00a3,0x00590095,
+0x00a200a2,0x002a002a,0x00a100a1,0x001a001a,0x008600a0,0x000a000a,0x00940068,0x00390039,
+0x00850093,0x00760058,0x00920092,0x00290029,0x00570075,0x00830083,0x00380038,0x00740066,
+0x00650047,0x00370056,0x00190091,0x00090090,0x00480084,0x00270027,0x00460064,0x00820082,
+0x00820082,0x00810028,0x00720073,0x00710071,0x00170017,0x00700055,0x00630007,0x00540036,
+0x00620045,0x00530026,0x00080080,0x00160061,0x00060060,0x00440035,0x00520052,0x00500025,
+0x00340043,0x00420005,0x00330024,0x00ff0184,0x00fd00fe,0x00fc00ee,0x00fb00ed,0x00ec00bf,
+0x018c00cd,0x00ce00ce,0x00dd00dd,0x00dc00af,0x00eb00eb,0x00be00be,0x00f900f9,0x009f009f,
+0x00ae00ae,0x00db00db,0x00bd00bd,0x00f800f8,0x008f008f,0x00cc00cc,0x00e900ea,0x00e800e8,
+0x00e700f7,0x007f007f,0x007f007f,0x00ad00ad,0x00cb00da,0x006f00bc,0x00f600f6,0x00f5008e,
+0x009d00d9,0x007e005f,0x00bb00ca,0x00f400f4,0x004f004f,0x006e00ac,0x003f003f,0x00f300f3,
+0x008d00d8,0x002f00f2,0x00c900e6,0x00f000f0,0x00e5009c,0x00ba00ba,0x007d00d7,0x00e400e4,
+0x006d008c,0x00e300e3,0x009b009b,0x00aa00b9,0x005e00ab,0x00c8004e,0x003e00d6,0x00e000e2,
+0x00d5000e,0x00c7005d,0x00d4007c,0x008b00b8,0x00a9004d,0x00c6009a,0x00b7003d,0x005c00c5,
+0x00a70099,0x0079007a,0x00cf00ef,0x00df00df,0x00de00de,0x00de00de,0x009e00fa,0x00200010,
+0x00400030,0x00600050,0x00700068,0x00760074,0x00110011,0x00010010,0x00000000,0x00880078,
+0x00a80098,0x00c800b8,0x00d800d0,0x00f000e8,0x010000f8,0x010c0108,0x011c0114,0x01240120,
+0x012c0128,0x01340130,0x013c0138,0x01420140,0x01460144,0x014c014a,0x0152014e,0x01560154,
+0x01580019,0x015c015a,0x0160015e,0x00280082,0x00180081,0x01640162,0x01680166,0x00270072,
+0x00710046,0x00170055,0x0063016a,0x00540036,0x00620045,0x00610026,0x0053016c,0x00160016,
+0x00440035,0x00520052,0x00250025,0x00510051,0x00150015,0x00050050,0x00430043,0x00420034,
+0x00330024,0x00140014,0x00400041,0x00320032,0x00230023,0x00300004,0x00310031,0x00030013,
+0x00220022,0x00120021,0x00020020,0x0170016e,0x017200ee,0x01760174,0x017800bf,0x00fa00dd,
+0x00eb00af,0x00dc00be,0x00f900cd,0x00ae009f,0x00bd00db,0x008f00f8,0x00e900cc,0x00f7009e,
+0x00da007f,0x00cb00ad,0x017a00f6,0x00bc00bc,0x006f006f,0x008e00e8,0x00d900f5,0x005f005f,
+0x00e700e7,0x007e007e,0x00ca00ca,0x00ac00ac,0x00bb00bb,0x00d8009d,0x00f400f4,0x004f004f,
+0x00f300f3,0x003f003f,0x008d008d,0x006e006e,0x00f200f2,0x002f002f,0x000f00e6,0x00f100f1,
+0x001f001f,0x00c900c9,0x009c009c,0x00ba00e5,0x005e00ab,0x007d00d7,0x004e00e4,0x008c00c8,
+0x00d600e3,0x003e006d,0x009b00b9,0x00e200e2,0x00aa00aa,0x002e002e,0x00e100e1,0x001e001e,
+0x000e00e0,0x00d500d5,0x005d005d,0x007c00c7,0x00b800d4,0x004d004d,0x00a9008b,0x00c6009a,
+0x00d3006c,0x003d003d,0x002d002d,0x00d000d2,0x00d100d1,0x00b700b7,0x007b007b,0x001d001d,
+0x000d00c5,0x005c005c,0x00a800a8,0x00c4008a,0x00b6004c,0x006b006b,0x00c00099,0x00c300c3,
+0x003c003c,0x00a700a7,0x007a007a,0x006a006a,0x00b0000c,0x002c002c,0x00b500c2,0x00c1005b,
+0x00890098,0x00b4001c,0x00a6004b,0x009700b3,0x003b003b,0x00880079,0x00a500b2,0x002b002b,
+0x00b1005a,0x001b001b,0x0096000b,0x00a40069,0x0087004a,0x00a30078,0x003a003a,0x00590095,
+0x002a00a2,0x001a00a1,0x000a00a0,0x00860086,0x00940068,0x00930049,0x00390039,0x00900077,
+0x00580085,0x00760092,0x00290067,0x00090091,0x00480084,0x00570075,0x00380083,0x00740066,
+0x00800047,0x00650008,0x00730056,0x00640037,0x00070070,0x00060060,0x00fe00ff,0x00fd00ef,
+0x00fc00df,0x00ed00cf,0x00fb00de,0x00ce00ec,0x00f000ea,0x00200010,0x00400030,0x00100011,
+0x00010001,0x00000000,0x00000000,0x00000000,0x00000000,0x004c0044,0x00ff0054,0x005c0058,
+0x002f005e,0x00f1006e,0x0070001f,0x00900080,0x00b000a0,0x00d000c0,0x00e000d8,0x00f000e8,
+0x010000f8,0x010c0108,0x01120110,0x011a0116,0x011c0015,0x0120011e,0x00410122,0x01240014,
+0x00230032,0x00310031,0x00130013,0x00030030,0x00220022,0x00120021,0x00020020,0x00ef00fe,
+0x00df00fd,0x00cf00fc,0x00bf00fb,0x00fa00fa,0x00f900af,0x008f009f,0x00f800f8,0x007f00f7,
+0x006f00f6,0x005f00f5,0x00f400f4,0x003f004f,0x000f000f,0x000f000f,0x000f000f,0x000f000f,
+0x00f300f3,0x00f300f3,0x01360126,0x0146013e,0x00f000f2,0x0152014e,0x015a0156,0x0160015c,
+0x01660164,0x016e016a,0x003e0172,0x01780176,0x017c017a,0x0180017e,0x00d00182,0x01860184,
+0x00c30188,0x00c1018a,0x018c000c,0x002e002e,0x00e100e2,0x00d2003d,0x001d002d,0x018e00b3,
+0x00d100d1,0x00b6004c,0x007a003c,0x00c200c2,0x005b002c,0x00c0001c,0x004b00b4,0x006a00a6,
+0x003b003b,0x005a00a5,0x00b200b2,0x002b002b,0x00b100b1,0x001b001b,0x000b00b0,0x00690096,
+0x004a00a4,0x00780087,0x003a003a,0x009500a3,0x00a200a2,0x00860059,0x001a001a,0x00770068,
+0x00490049,0x00750094,0x00760076,0x002a002a,0x002a002a,0x00a100a1,0x000a00a0,0x00390093,
+0x00580085,0x00920092,0x00290029,0x00900067,0x00910091,0x00190019,0x00840009,0x00570048,
+0x00380083,0x00820066,0x00280028,0x00470074,0x00810081,0x00180018,0x00080008,0x00650080,
+0x00730073,0x00370037,0x00640056,0x00720072,0x00270027,0x00550046,0x00700070,0x00710071,
+0x00710071,0x00170017,0x00630007,0x00540036,0x00620045,0x00610026,0x00160016,0x00060060,
+0x00350035,0x00440053,0x00250052,0x00500051,0x00340043,0x00420005,0x00330024,0x00040040,
+0x019000ec,0x00ed00ed,0x009e009e,0x009d00ae,0x00ee00ee,0x00ee00ee,0x00de00de,0x00be00be,
+0x00eb00eb,0x00dc00dc,0x00bd00cd,0x00ea00ea,0x00cc00cc,0x00ad00da,0x00ca00e7,0x00ac00ac,
+0x00d7009c,0x00e500e5,0x00db00db,0x00db00db,0x00e900e9,0x00bc00cb,0x008e00e8,0x007e00d9,
+0x00d800bb,0x00e6008d,0x00c9006e,0x00ab00ba,0x007d005e,0x00e400e4,0x00c8004e,0x00e3008c,
+0x00d600d6,0x00b9006d,0x00aa009b,0x001e001e,0x004d004d,0x009a008b,0x00b700b7,0x000d007b,
+0x000e00e0,0x005d00d5,0x007c00c7,0x00b800d4,0x00c600a9,0x00d3006c,0x005c00c5,0x008a00a8,
+0x00c40099,0x00a7006b,0x009800b5,0x00970089,0x00880079,0x00dd00ce,0x00200010,0x00ff0030,
+0x00500040,0x00700060,0x00900080,0x00a800a0,0x00100011,0x00000001,0x00ef00fe,0x00df00fd,
+0x00cf00fc,0x00bf00fb,0x00af00af,0x00f900fa,0x009f009f,0x008f008f,0x00f700f8,0x007f007f,
+0x00f600f6,0x006f006f,0x00f500f5,0x005f005f,0x00f400f4,0x004f004f,0x00f300f3,0x003f003f,
+0x00f200f2,0x002f002f,0x001f001f,0x000f00f1,0x00b400ac,0x00c400bc,0x00dc00cc,0x00ec00e4,
+0x00f800f4,0x010000fc,0x01080104,0x0110010c,0x01180114,0x01240120,0x012c0128,0x01380134,
+0x01420140,0x014a0146,0x0150014c,0x01540152,0x01580156,0x015c015a,0x0160015e,0x01640162,
+0x01680166,0x016c016a,0x0170016e,0x01760172,0x00370178,0x0027017c,0x00460064,0x00170055,
+0x00360063,0x00450054,0x00260062,0x00160061,0x0053017e,0x00440035,0x00250052,0x01800051,
+0x00150015,0x00340043,0x00420042,0x00240024,0x00330033,0x00410041,0x00140014,0x00040040,
+0x00320032,0x00230023,0x00310031,0x00310031,0x00130013,0x00130013,0x00030030,0x00220022,
+0x00210021,0x00210021,0x00120012,0x00020020,0x00f000f0,0x00f000f0,0x00ed00ee,0x00ec00de,
+0x00dd00ce,0x00be00eb,0x00cd00dc,0x00ae00ea,0x00bd00db,0x00e900cc,0x00da009e,0x00cb00ad,
+0x00e800bc,0x00d9008e,0x00e7009d,0x00ca007e,0x00ac00ac,0x00bb00bb,0x00d800d8,0x008d008d,
+0x000e00e0,0x00d000d0,0x006e006e,0x006e006e,0x00c900e6,0x009c009c,0x00e500e5,0x00ab00ab,
+0x005e005e,0x00d700ba,0x007d007d,0x004e004e,0x00c800c8,0x008c008c,0x00e200e4,0x00e300e3,
+0x006d00d6,0x00b9003e,0x00aa009b,0x00e1002e,0x00d5001e,0x00c7005d,0x00d4007c,0x008b00b8,
+0x00a9004d,0x00c6009a,0x00d3006c,0x00d2003d,0x00d1002d,0x007b00b7,0x00c5001d,0x00a8005c,
+0x0099008a,0x004c00c4,0x00b600b6,0x006b006b,0x00c0000d,0x00c300c3,0x00a7003c,0x00c2007a,
+0x00b5002c,0x00c1005b,0x00890098,0x00b4001c,0x00b0000c,0x00b300b3,0x00a0000b,0x00a100a1,
+0x004b004b,0x006a00a6,0x00970097,0x00790079,0x0090000a,0x00090009,0x0088003b,0x00a500b2,
+0x002b002b,0x00b1005a,0x0096001b,0x004a0069,0x008700a4,0x00780078,0x003a00a3,0x00590095,
+0x002a00a2,0x0086001a,0x00770068,0x00490094,0x00390093,0x00580085,0x00760092,0x00290067,
+0x00190091,0x00480084,0x00570075,0x00380083,0x00820066,0x00810028,0x00470074,0x00180018,
+0x00080080,0x00560065,0x00710071,0x00070070,0x00720073,0x00060060,0x00050050,0x00018610,
+0x00018614,0x00018624,0x00018644,0x00018610,0x00018664,0x00018698,0x000186d0,0x00018750,
+0x000187d4,0x00018840,0x0001890c,0x000189dc,0x00018a9c,0x00018610,0x00018c2c,0x00018da8,
+0x00018da8,0x00018da8,0x00018da8,0x00018da8,0x00018da8,0x00018da8,0x00018da8,0x00018f3c,
+0x00018f3c,0x00018f3c,0x00018f3c,0x00018f3c,0x00018f3c,0x00018f3c,0x00018f3c,0x00000000,
+0x00000000,0x00000000,0x00000000,0x04030201,0x0d0a0806,0x07060504,0x0d0b0908,0x03030300,
+0x04040300,0x04040404,0x04000404,0x04040404,0x04040404,0x04040404,0x04040404,0x000190c0,
+0x00000000,0x000193dc,0x000196d4,0x000196d4,0x000196d4,0x000196d4,0x000196d4,0x000196d4,
+0x000196d4,0x000196d4,0x000199f8,0x000199f8,0x000199f8,0x000199f8,0x000199f8,0x000199f8,
+0x000199f8,0x000199f8,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0xfffe3000,0x000d5000,0xffe35000,0x007f5000,0xfebdf000,0x019ae000,0xf6d8f000,0x1251e000,
+0x09271000,0x019ae000,0x01421000,0x007f5000,0x001cb000,0x000d5000,0x0001d000,0x00000000,
+0xfffe3000,0x000d5000,0xffe35000,0x007f5000,0xfebdf000,0x019ae000,0xf6d8f000,0x1251e000,
+0x09271000,0x019ae000,0x01421000,0x007f5000,0x001cb000,0x000d5000,0x0001d000,0xfffff000,
+0xfffe1000,0x000da000,0xffdf9000,0x007d0000,0xfea73000,0x01747000,0xf6658000,0x124f0000,
+0x08b38000,0x01bde000,0x012b4000,0x0080f000,0x00191000,0x000d0000,0x0001a000,0xfffff000,
+0xfffe1000,0x000da000,0xffdf9000,0x007d0000,0xfea73000,0x01747000,0xf6658000,0x124f0000,
+0x08b38000,0x01bde000,0x012b4000,0x0080f000,0x00191000,0x000d0000,0x0001a000,0xfffff000,
+0xfffdd000,0x000de000,0xffdbb000,0x007a0000,0xfe909000,0x014a8000,0xf5f28000,0x12468000,
+0x083ff000,0x01dd8000,0x01149000,0x00820000,0x0015b000,0x000ca000,0x00018000,0xfffff000,
+0xfffdd000,0x000de000,0xffdbb000,0x007a0000,0xfe909000,0x014a8000,0xf5f28000,0x12468000,
+0x083ff000,0x01dd8000,0x01149000,0x00820000,0x0015b000,0x000ca000,0x00018000,0xfffff000,
+0xfffda000,0x000e1000,0xffd7b000,0x00765000,0xfe7a3000,0x011d1000,0xf5802000,0x12386000,
+0x07ccb000,0x01f9c000,0x00fdf000,0x00827000,0x00126000,0x000c4000,0x00015000,0xfffff000,
+0xfffda000,0x000e1000,0xffd7b000,0x00765000,0xfe7a3000,0x011d1000,0xf5802000,0x12386000,
+0x07ccb000,0x01f9c000,0x00fdf000,0x00827000,0x00126000,0x000c4000,0x00015000,0xfffff000,
+0xfffd7000,0x000e3000,0xffd39000,0x0071e000,0xfe643000,0x00ec0000,0xf50eb000,0x12249000,
+0x075a0000,0x0212c000,0x00e79000,0x00825000,0x000f4000,0x000be000,0x00013000,0xfffff000,
+0xfffd7000,0x000e3000,0xffd39000,0x0071e000,0xfe643000,0x00ec0000,0xf50eb000,0x12249000,
+0x075a0000,0x0212c000,0x00e79000,0x00825000,0x000f4000,0x000be000,0x00013000,0xfffff000,
+0xfffd3000,0x000e4000,0xffcf5000,0x006cb000,0xfe4e9000,0x00b77000,0xf49e7000,0x120b4000,
+0x06e81000,0x02288000,0x00d17000,0x0081b000,0x000c5000,0x000b7000,0x00011000,0xfffff000,
+0xfffd3000,0x000e4000,0xffcf5000,0x006cb000,0xfe4e9000,0x00b77000,0xf49e7000,0x120b4000,
+0x06e81000,0x02288000,0x00d17000,0x0081b000,0x000c5000,0x000b7000,0x00011000,0xfffff000,
+0xfffcf000,0x000e4000,0xffcb0000,0x0066c000,0xfe399000,0x007f5000,0xf42fa000,0x11ec7000,
+0x06772000,0x023b3000,0x00bbc000,0x00809000,0x00099000,0x000b0000,0x00010000,0xfffff000,
+0xfffcf000,0x000e4000,0xffcb0000,0x0066c000,0xfe399000,0x007f5000,0xf42fa000,0x11ec7000,
+0x06772000,0x023b3000,0x00bbc000,0x00809000,0x00099000,0x000b0000,0x00010000,0xffffe000,
+0xfffcb000,0x000e3000,0xffc69000,0x005ff000,0xfe253000,0x0043a000,0xf3c27000,0x11c83000,
+0x06076000,0x024ad000,0x00a67000,0x007f0000,0x0006f000,0x000a9000,0x0000e000,0xffffe000,
+0xfffcb000,0x000e3000,0xffc69000,0x005ff000,0xfe253000,0x0043a000,0xf3c27000,0x11c83000,
+0x06076000,0x024ad000,0x00a67000,0x007f0000,0x0006f000,0x000a9000,0x0000e000,0xffffe000,
+0xfffc6000,0x000e0000,0xffc21000,0x00586000,0xfe11a000,0x00046000,0xf3573000,0x119e9000,
+0x05991000,0x02578000,0x0091a000,0x007d1000,0x00048000,0x000a1000,0x0000d000,0xffffe000,
+0xfffc6000,0x000e0000,0xffc21000,0x00586000,0xfe11a000,0x00046000,0xf3573000,0x119e9000,
+0x05991000,0x02578000,0x0091a000,0x007d1000,0x00048000,0x000a1000,0x0000d000,0xffffe000,
+0xfffc1000,0x000dd000,0xffbd8000,0x00500000,0xfdfef000,0xffc1a000,0xf2ee2000,0x116fc000,
+0x052c5000,0x02616000,0x007d6000,0x007aa000,0x00024000,0x0009a000,0x0000b000,0xffffe000,
+0xfffc1000,0x000dd000,0xffbd8000,0x00500000,0xfdfef000,0xffc1a000,0xf2ee2000,0x116fc000,
+0x052c5000,0x02616000,0x007d6000,0x007aa000,0x00024000,0x0009a000,0x0000b000,0xffffe000,
+0xfffbc000,0x000d7000,0xffb8f000,0x0046b000,0xfded5000,0xff7b6000,0xf2876000,0x113be000,
+0x04c16000,0x02687000,0x0069c000,0x0077f000,0x00002000,0x00093000,0x0000a000,0xffffe000,
+0xfffbc000,0x000d7000,0xffb8f000,0x0046b000,0xfded5000,0xff7b6000,0xf2876000,0x113be000,
+0x04c16000,0x02687000,0x0069c000,0x0077f000,0x00002000,0x00093000,0x0000a000,0xffffd000,
+0xfffb7000,0x000d0000,0xffb46000,0x003ca000,0xfddcd000,0xff31c000,0xf2236000,0x1102f000,
+0x04587000,0x026cf000,0x0056c000,0x0074e000,0xfffe3000,0x0008b000,0x00009000,0xffffd000,
+0xfffb7000,0x000d0000,0xffb46000,0x003ca000,0xfddcd000,0xff31c000,0xf2236000,0x1102f000,
+0x04587000,0x026cf000,0x0056c000,0x0074e000,0xfffe3000,0x0008b000,0x00009000,0xffffd000,
+0xfffb1000,0x000c8000,0xffafd000,0x0031a000,0xfdcda000,0xfee4b000,0xf1c23000,0x10c54000,
+0x03f1b000,0x026ee000,0x00447000,0x00719000,0xfffc7000,0x00084000,0x00008000,0xffffd000,
+0xfffb1000,0x000c8000,0xffafd000,0x0031a000,0xfdcda000,0xfee4b000,0xf1c23000,0x10c54000,
+0x03f1b000,0x026ee000,0x00447000,0x00719000,0xfffc7000,0x00084000,0x00008000,0xffffc000,
+0xfffab000,0x000bd000,0xffab4000,0x0025d000,0xfdbfd000,0xfe946000,0xf1642000,0x1082d000,
+0x038d4000,0x026e7000,0x0032e000,0x006df000,0xfffad000,0x0007d000,0x00007000,0xffffc000,
+0xfffab000,0x000bd000,0xffab4000,0x0025d000,0xfdbfd000,0xfe946000,0xf1642000,0x1082d000,
+0x038d4000,0x026e7000,0x0032e000,0x006df000,0xfffad000,0x0007d000,0x00007000,0xffffc000,
+0xfffa5000,0x000b1000,0xffa6c000,0x00192000,0xfdb38000,0xfe40e000,0xf1097000,0x103be000,
+0x032b4000,0x026bc000,0x00221000,0x006a2000,0xfff96000,0x00075000,0x00007000,0xffffc000,
+0xfffa5000,0x000b1000,0xffa6c000,0x00192000,0xfdb38000,0xfe40e000,0xf1097000,0x103be000,
+0x032b4000,0x026bc000,0x00221000,0x006a2000,0xfff96000,0x00075000,0x00007000,0xffffb000,
+0xfff9f000,0x000a3000,0xffa26000,0x000b9000,0xfda8f000,0xfdea4000,0xf0b24000,0x0ff0a000,
+0x02cbf000,0x0266e000,0x00120000,0x00662000,0xfff81000,0x0006f000,0x00006000,0xffffb000,
+0xfff9f000,0x000a3000,0xffa26000,0x000b9000,0xfda8f000,0xfdea4000,0xf0b24000,0x0ff0a000,
+0x02cbf000,0x0266e000,0x00120000,0x00662000,0xfff81000,0x0006f000,0x00006000,0xffffb000,
+0xfff98000,0x00092000,0xff9e1000,0xfffd3000,0xfda01000,0xfd909000,0xf05ed000,0x0fa13000,
+0x026f7000,0x025ff000,0x0002d000,0x0061f000,0xfff6e000,0x00068000,0x00005000,0xffffb000,
+0xfff98000,0x00092000,0xff9e1000,0xfffd3000,0xfda01000,0xfd909000,0xf05ed000,0x0fa13000,
+0x026f7000,0x025ff000,0x0002d000,0x0061f000,0xfff6e000,0x00068000,0x00005000,0x0d744fcd,
+0x0b504f33,0x09837f05,0x08000000,0x06ba27e6,0x05a8279a,0x04c1bf83,0x04000000,0x035d13f3,
+0x02d413cd,0x0260dfc1,0x02000000,0x01ae89fa,0x016a09e6,0x01306fe1,0x0b504f33,0x08000000,
+0x05a8279a,0x04000000,0x02d413cd,0x02000000,0x016a09e6,0x01000000,0x00b504f3,0x00800000,
+0x005a827a,0x00400000,0x002d413d,0x00200000,0x0016a09e,0x20000000,0x1965fea5,0x1428a2fa,
+0x10000000,0x0cb2ff53,0x0a14517d,0x08000000,0x06597fa9,0x050a28be,0x04000000,0x032cbfd5,
+0x0285145f,0x02000000,0x01965fea,0x01428a30,0x01000000,0x00cb2ff5,0x00a14518,0x00800000,
+0x006597fb,0x0050a28c,0x00400000,0x0032cbfd,0x00285146,0x00200000,0x001965ff,0x001428a3,
+0x00100000,0x000cb2ff,0x000a1451,0x00080000,0x00065980,0x00050a29,0x00040000,0x00032cc0,
+0x00028514,0x00020000,0x00019660,0x0001428a,0x00010000,0x0000cb30,0x0000a145,0x00008000,
+0x00006598,0x000050a3,0x00004000,0x000032cc,0x00002851,0x00002000,0x00001966,0x00001429,
+0x00001000,0x00000cb3,0x00000a14,0x00000800,0x00000659,0x0000050a,0x00000400,0x0000032d,
+0x00000285,0x00000200,0x00000196,0x00000143,0x15555555,0x12492492,0x11111111,0x10842108,
+0x10410410,0x10204081,0x10101010,0x10080402,0x10040100,0x10020040,0x10010010,0x10008004,
+0x10004001,0x10002000,0x0c081e1b,0x0000001e,0x06070707,0x06060606,0x03060606,0x03030303,
+0x03030303,0x00030303,0x00000000,0x07070000,0x06060607,0x06060606,0x03030306,0x03030303,
+0x03030303,0x00000003,0x00000000,0x02020505,0x02020202,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x05050000,0x02020202,0x02020202,0x00000202,0x00000000,0x00000000,
+0x00000000,0x00000000,0x04040404,0x02020202,0x01020202,0x01010101,0x01010101,0x01010101,
+0x01010101,0x00000101,0x03020002,0x01030303,0x03040204,0x05040404,0x00100100,0x00000000,
+0x00000000,0x00000000,0x04030201,0x00001005,0x00000000,0x01000000,0x05040302,0x09080706,
+0x0d0c0b0a,0x0301000e,0x07060504,0x0b0a0908,0x0f0e0d0c,0x03020100,0x07060504,0x0b0a0908,
+0x00100d0c,0x06050402,0x0a090807,0x0e0d0c0b,0x0000100f,0x00000003,0x00000002,0x00000005,
+0x15555555,0x08000000,0x00000005,0x00000003,0x00000007,0x1999999a,0x08000000,0x00000007,
+0x00000000,0x00000003,0x12492492,0x04000000,0x00000009,0x00000004,0x0000000a,0x1c71c71c,
+0x08000000,0x0000000f,0x00000000,0x00000004,0x11111111,0x02000000,0x0000001f,0x00000000,
+0x00000005,0x10842108,0x01000000,0x0000003f,0x00000000,0x00000006,0x10410410,0x00800000,
+0x0000007f,0x00000000,0x00000007,0x10204081,0x00400000,0x000000ff,0x00000000,0x00000008,
+0x10101010,0x00200000,0x000001ff,0x00000000,0x00000009,0x10080402,0x00100000,0x000003ff,
+0x00000000,0x0000000a,0x10040100,0x00080000,0x000007ff,0x00000000,0x0000000b,0x10020040,
+0x00040000,0x00000fff,0x00000000,0x0000000c,0x10010010,0x00020000,0x00001fff,0x00000000,
+0x0000000d,0x10008004,0x00010000,0x00003fff,0x00000000,0x0000000e,0x10004001,0x00008000,
+0x00007fff,0x00000000,0x0000000f,0x10002000,0x00004000,0x0000ffff,0x00000000,0x00000010,
+0x10001000,0x00002000,0x00000000,0x04000000,0x050a28be,0x0453a5cd,0x06597fa9,0x04466275,
+0x05738c72,0x06b1fc81,0x04000000,0x04ae20d7,0x0562d694,0x061dae96,0x06de47f4,0x07a44f7a,
+0x0437be65,0x049fc824,0x050a28be,0x0576c6f5,0x05e58c0b,0x06566361,0x06c93a2e,0x073dff3e,
+0x07b4a2bc,0x04168b05,0x0453a5cd,0x04919b6a,0x04d065fb,0x05100000,0x05506451,0x05918e15,
+0x05d378bb,0x06161ff3,0x06597fa9,0x069d9400,0x06e2594c,0x0727cc11,0x076de8fc,0x07b4ace3,
+0x07fc14bf,0x04220ed7,0x04466275,0x046b03e7,0x048ff1e8,0x04b52b3f,0x04daaec0,0x05007b49,
+0x05268fc6,0x054ceb2a,0x05738c72,0x059a72a5,0x05c19cd3,0x05e90a12,0x0610b982,0x0638aa48,
+0x0660db91,0x06894c90,0x06b1fc81,0x06daeaa1,0x07041636,0x072d7e8b,0x075722ef,0x078102b8,
+0x07ab1d3e,0x07d571e0,0x04000000,0x04156381,0x042ae32a,0x04407eb1,0x045635cf,0x046c083e,
+0x0481f5bb,0x0497fe03,0x04ae20d7,0x04c45df6,0x04dab524,0x04f12624,0x0507b0bc,0x051e54b1,
+0x053511cb,0x054be7d4,0x0562d694,0x0579ddd8,0x0590fd6c,0x05a8351c,0x05bf84b8,0x05d6ec0e,
+0x05ee6aef,0x0606012b,0x061dae96,0x06357302,0x064d4e43,0x0665402d,0x067d4896,0x06956753,
+0x06ad9c3d,0x06c5e72b,0x06de47f4,0x06f6be73,0x070f4a80,0x0727ebf7,0x0740a2b2,0x07596e8d,
+0x07724f64,0x078b4514,0x07a44f7a,0x07bd6e75,0x07d6a1e2,0x07efe9a1,0x0404a2c9,0x04115aca,
+0x041e1cc4,0x042ae8a7,0x0437be65,0x04449dee,0x04518733,0x045e7a26,0x046b76b9,0x04787cdc,
+0x04858c83,0x0492a59f,0x049fc824,0x04acf402,0x04ba292e,0x04c7679a,0x04d4af3a,0x04e20000,
+0x04ef59e0,0x04fcbcce,0x050a28be,0x05179da4,0x05251b73,0x0532a220,0x054031a0,0x054dc9e7,
+0x055b6ae9,0x0569149c,0x0576c6f5,0x058481e9,0x0592456d,0x05a01176,0x05ade5fa,0x05bbc2ef,
+0x05c9a84a,0x05d79601,0x05e58c0b,0x05f38a5d,0x060190ee,0x060f9fb3,0x061db6a5,0x062bd5b8,
+0x0639fce4,0x06482c1f,0x06566361,0x0664a2a0,0x0672e9d4,0x068138f3,0x068f8ff5,0x069deed1,
+0x06ac557f,0x06bac3f6,0x06c93a2e,0x06d7b81f,0x06e63dc0,0x06f4cb09,0x07035ff3,0x0711fc75,
+0x0720a087,0x072f4c22,0x073dff3e,0x074cb9d3,0x075b7bdb,0x076a454c,0x07791620,0x0787ee50,
+0x0796cdd4,0x07a5b4a5,0x07b4a2bc,0x07c39812,0x07d294a0,0x07e1985f,0x07f0a348,0x07ffb554,
+0x0407673f,0x040ef75e,0x04168b05,0x041e2230,0x0425bcdd,0x042d5b07,0x0434fcad,0x043ca1c9,
+0x04444a5a,0x044bf65d,0x0453a5cd,0x045b58a9,0x04630eed,0x046ac896,0x047285a2,0x047a460c,
+0x048209d3,0x0489d0f4,0x04919b6a,0x04996935,0x04a13a50,0x04a90eba,0x04b0e66e,0x04b8c16c,
+0x04c09faf,0x04c88135,0x04d065fb,0x04d84dff,0x04e0393e,0x04e827b6,0x04f01963,0x04f80e44,
+0x05000655,0x05080195,0x05100000,0x05180194,0x0520064f,0x05280e2d,0x0530192e,0x0538274e,
+0x0540388a,0x05484ce2,0x05506451,0x05587ed5,0x05609c6e,0x0568bd17,0x0570e0cf,0x05790793,
+0x05813162,0x05895e39,0x05918e15,0x0599c0f4,0x05a1f6d5,0x05aa2fb5,0x05b26b92,0x05baaa69,
+0x05c2ec39,0x05cb3100,0x05d378bb,0x05dbc368,0x05e41105,0x05ec6190,0x05f4b507,0x05fd0b68,
+0x060564b1,0x060dc0e0,0x06161ff3,0x061e81e8,0x0626e6bc,0x062f4e6f,0x0637b8fd,0x06402666,
+0x064896a7,0x065109be,0x06597fa9,0x0661f867,0x066a73f5,0x0672f252,0x067b737c,0x0683f771,
+0x068c7e2f,0x069507b5,0x069d9400,0x06a6230f,0x06aeb4e0,0x06b74971,0x06bfe0c0,0x06c87acc,
+0x06d11794,0x06d9b714,0x06e2594c,0x06eafe3a,0x06f3a5dc,0x06fc5030,0x0704fd35,0x070dacea,
+0x07165f4b,0x071f1459,0x0727cc11,0x07308671,0x07394378,0x07420325,0x074ac575,0x07538a67,
+0x075c51fa,0x07651c2c,0x076de8fc,0x0776b867,0x077f8a6d,0x07885f0b,0x07913641,0x079a100c,
+0x07a2ec6c,0x07abcb5f,0x07b4ace3,0x07bd90f6,0x07c67798,0x07cf60c7,0x07d84c81,0x07e13ac5,
+0x07ea2b92,0x07f31ee6,0x07fc14bf,0x0402868e,0x040703ff,0x040b82b0,0x041002a1,0x041483d1,
+0x04190640,0x041d89ed,0x04220ed7,0x042694fe,0x042b1c60,0x042fa4fe,0x04342ed7,0x0438b9e9,
+0x043d4635,0x0441d3b9,0x04466275,0x044af269,0x044f8393,0x045415f3,0x0458a989,0x045d3e53,
+0x0461d451,0x04666b83,0x046b03e7,0x046f9d7e,0x04743847,0x0478d440,0x047d716a,0x04820fc3,
+0x0486af4c,0x048b5003,0x048ff1e8,0x049494fb,0x0499393a,0x049ddea5,0x04a2853c,0x04a72cfe,
+0x04abd5ea,0x04b08000,0x04b52b3f,0x04b9d7a7,0x04be8537,0x04c333ee,0x04c7e3cc,0x04cc94d1,
+0x04d146fb,0x04d5fa4b,0x04daaec0,0x04df6458,0x04e41b14,0x04e8d2f3,0x04ed8bf5,0x04f24618,
+0x04f7015d,0x04fbbdc3,0x05007b49,0x050539ef,0x0509f9b4,0x050eba98,0x05137c9a,0x05183fba,
+0x051d03f7,0x0521c950,0x05268fc6,0x052b5757,0x05302003,0x0534e9ca,0x0539b4ab,0x053e80a6,
+0x05434db9,0x05481be5,0x054ceb2a,0x0551bb85,0x05568cf8,0x055b5f81,0x05603321,0x056507d6,
+0x0569dda0,0x056eb47f,0x05738c72,0x05786578,0x057d3f92,0x05821abf,0x0586f6fd,0x058bd44e,
+0x0590b2b0,0x05959222,0x059a72a5,0x059f5438,0x05a436da,0x05a91a8c,0x05adff4c,0x05b2e51a,
+0x05b7cbf5,0x05bcb3de,0x05c19cd3,0x05c686d5,0x05cb71e2,0x05d05dfb,0x05d54b1f,0x05da394d,
+0x05df2885,0x05e418c7,0x05e90a12,0x05edfc66,0x05f2efc2,0x05f7e426,0x05fcd992,0x0601d004,
+0x0606c77d,0x060bbffd,0x0610b982,0x0615b40c,0x061aaf9c,0x061fac2f,0x0624a9c7,0x0629a863,
+0x062ea802,0x0633a8a3,0x0638aa48,0x063dacee,0x0642b096,0x0647b53f,0x064cbae9,0x0651c193,
+0x0656c93d,0x065bd1e7,0x0660db91,0x0665e639,0x066af1df,0x066ffe84,0x06750c26,0x067a1ac6,
+0x067f2a62,0x06843afb,0x06894c90,0x068e5f21,0x069372ae,0x06988735,0x069d9cb7,0x06a2b333,
+0x06a7caa9,0x06ace318,0x06b1fc81,0x06b716e2,0x06bc323b,0x06c14e8d,0x06c66bd6,0x06cb8a17,
+0x06d0a94e,0x06d5c97c,0x06daeaa1,0x06e00cbb,0x06e52fca,0x06ea53cf,0x06ef78c8,0x06f49eb6,
+0x06f9c597,0x06feed6d,0x07041636,0x07093ff2,0x070e6aa0,0x07139641,0x0718c2d3,0x071df058,
+0x07231ecd,0x07284e34,0x072d7e8b,0x0732afd2,0x0737e209,0x073d1530,0x07424946,0x07477e4b,
+0x074cb43e,0x0751eb20,0x075722ef,0x075c5bac,0x07619557,0x0766cfee,0x076c0b72,0x077147e2,
+0x0776853e,0x077bc385,0x078102b8,0x078642d6,0x078b83de,0x0790c5d1,0x079608ae,0x079b4c74,
+0x07a09124,0x07a5d6bd,0x07ab1d3e,0x07b064a8,0x07b5acfb,0x07baf635,0x07c04056,0x07c58b5f,
+0x07cad74e,0x07d02424,0x07d571e0,0x07dac083,0x07e0100a,0x07e56078,0x07eab1ca,0x07f00401,
+0x07f5571d,0x07faab1c,0x04000000,0x0402aae3,0x04055638,0x040801ff,0x040aae37,0x040d5ae0,
+0x041007fa,0x0412b586,0x04156381,0x041811ee,0x041ac0cb,0x041d7018,0x04201fd5,0x0422d003,
+0x042580a0,0x042831ad,0x042ae32a,0x042d9516,0x04304772,0x0432fa3d,0x0435ad76,0x0438611f,
+0x043b1536,0x043dc9bc,0x04407eb1,0x04433414,0x0445e9e5,0x0448a024,0x044b56d1,0x044e0dec,
+0x0450c575,0x04537d6b,0x045635cf,0x0458ee9f,0x045ba7dd,0x045e6188,0x04611ba0,0x0463d625,
+0x04669116,0x04694c74,0x046c083e,0x046ec474,0x04718116,0x04743e25,0x0476fb9f,0x0479b984,
+0x047c77d6,0x047f3693,0x0481f5bb,0x0484b54e,0x0487754c,0x048a35b6,0x048cf68a,0x048fb7c8,
+0x04927972,0x04953b85,0x0497fe03,0x049ac0eb,0x049d843e,0x04a047fa,0x04a30c20,0x04a5d0af,
+0x04a895a8,0x04ab5b0b,0x04ae20d7,0x04b0e70c,0x04b3adaa,0x04b674b1,0x04b93c21,0x04bc03fa,
+0x04becc3b,0x04c194e4,0x04c45df6,0x04c72771,0x04c9f153,0x04ccbb9d,0x04cf864f,0x04d25169,
+0x04d51ceb,0x04d7e8d4,0x04dab524,0x04dd81dc,0x04e04efb,0x04e31c81,0x04e5ea6e,0x04e8b8c2,
+0x04eb877c,0x04ee569d,0x04f12624,0x04f3f612,0x04f6c666,0x04f99721,0x04fc6841,0x04ff39c7,
+0x05020bb3,0x0504de05,0x0507b0bc,0x050a83d8,0x050d575b,0x05102b42,0x0512ff8e,0x0515d440,
+0x0518a956,0x051b7ed1,0x051e54b1,0x05212af5,0x0524019e,0x0526d8ab,0x0529b01d,0x052c87f2,
+0x052f602c,0x053238ca,0x053511cb,0x0537eb30,0x053ac4f9,0x053d9f25,0x054079b5,0x054354a8,
+0x05462ffe,0x05490bb7,0x054be7d4,0x054ec453,0x0551a134,0x05547e79,0x05575c20,0x055a3a2a,
+0x055d1896,0x055ff764,0x0562d694,0x0565b627,0x0568961b,0x056b7671,0x056e5729,0x05713843,
+0x057419be,0x0576fb9a,0x0579ddd8,0x057cc077,0x057fa378,0x058286d9,0x05856a9b,0x05884ebe,
+0x058b3342,0x058e1827,0x0590fd6c,0x0593e311,0x0596c917,0x0599af7d,0x059c9643,0x059f7d6a,
+0x05a264f0,0x05a54cd6,0x05a8351c,0x05ab1dc2,0x05ae06c7,0x05b0f02b,0x05b3d9f0,0x05b6c413,
+0x05b9ae95,0x05bc9977,0x05bf84b8,0x05c27057,0x05c55c56,0x05c848b3,0x05cb356e,0x05ce2289,
+0x05d11001,0x05d3fdd8,0x05d6ec0e,0x05d9daa1,0x05dcc993,0x05dfb8e2,0x05e2a890,0x05e5989b,
+0x05e88904,0x05eb79cb,0x05ee6aef,0x05f15c70,0x05f44e4f,0x05f7408b,0x05fa3324,0x05fd261b,
+0x0600196e,0x06030d1e,0x0606012b,0x0608f595,0x060bea5c,0x060edf7f,0x0611d4fe,0x0614cada,
+0x0617c112,0x061ab7a6,0x061dae96,0x0620a5e3,0x06239d8b,0x0626958f,0x06298def,0x062c86aa,
+0x062f7fc1,0x06327934,0x06357302,0x06386d2b,0x063b67b0,0x063e6290,0x06415dcb,0x06445960,
+0x06475551,0x064a519c,0x064d4e43,0x06504b44,0x0653489f,0x06564655,0x06594465,0x065c42d0,
+0x065f4195,0x066240b4,0x0665402d,0x06684000,0x066b402d,0x066e40b3,0x06714194,0x067442ce,
+0x06774462,0x067a464f,0x067d4896,0x06804b36,0x06834e2f,0x06865181,0x0689552c,0x068c5931,
+0x068f5d8e,0x06926245,0x06956753,0x06986cbb,0x069b727b,0x069e7894,0x06a17f05,0x06a485cf,
+0x06a78cf1,0x06aa946b,0x06ad9c3d,0x06b0a468,0x06b3acea,0x06b6b5c4,0x06b9bef6,0x06bcc880,
+0x06bfd261,0x06c2dc9a,0x06c5e72b,0x06c8f213,0x06cbfd52,0x06cf08e9,0x06d214d7,0x06d5211c,
+0x06d82db8,0x06db3aaa,0x06de47f4,0x06e15595,0x06e4638d,0x06e771db,0x06ea807f,0x06ed8f7b,
+0x06f09ecc,0x06f3ae75,0x06f6be73,0x06f9cec8,0x06fcdf72,0x06fff073,0x070301ca,0x07061377,
+0x0709257a,0x070c37d2,0x070f4a80,0x07125d84,0x071570de,0x0718848d,0x071b9891,0x071eaceb,
+0x0721c19a,0x0724d69e,0x0727ebf7,0x072b01a6,0x072e17a9,0x07312e01,0x073444ae,0x07375bb0,
+0x073a7307,0x073d8ab2,0x0740a2b2,0x0743bb06,0x0746d3af,0x0749ecac,0x074d05fe,0x07501fa3,
+0x0753399d,0x075653eb,0x07596e8d,0x075c8983,0x075fa4cc,0x0762c06a,0x0765dc5b,0x0768f8a0,
+0x076c1538,0x076f3224,0x07724f64,0x07756cf7,0x07788add,0x077ba916,0x077ec7a3,0x0781e683,
+0x078505b5,0x0788253b,0x078b4514,0x078e653f,0x079185be,0x0794a68f,0x0797c7b2,0x079ae929,
+0x079e0af1,0x07a12d0c,0x07a44f7a,0x07a7723a,0x07aa954c,0x07adb8b0,0x07b0dc67,0x07b4006f,
+0x07b724ca,0x07ba4976,0x07bd6e75,0x07c093c5,0x07c3b967,0x07c6df5a,0x07ca059f,0x07cd2c36,
+0x07d0531e,0x07d37a57,0x07d6a1e2,0x07d9c9be,0x07dcf1ec,0x07e01a6a,0x07e3433a,0x07e66c5a,
+0x07e995cc,0x07ecbf8e,0x07efe9a1,0x07f31405,0x07f63eba,0x07f969c0,0x07fc9516,0x07ffc0bc,
+0x04017659,0x04030c7d,0x0404a2c9,0x0406393d,0x0407cfd9,0x0409669d,0x040afd89,0x040c949e,
+0x040e2bda,0x040fc33e,0x04115aca,0x0412f27e,0x04148a5a,0x0416225d,0x0417ba89,0x041952dc,
+0x041aeb57,0x041c83fa,0x041e1cc4,0x041fb5b6,0x04214ed0,0x0422e811,0x04248179,0x04261b0a,
+0x0427b4c2,0x04294ea1,0x042ae8a7,0x042c82d6,0x042e1d2b,0x042fb7a8,0x0431524c,0x0432ed17,
+0x0434880a,0x04362324,0x0437be65,0x043959cd,0x043af55d,0x043c9113,0x043e2cf1,0x043fc8f6,
+0x04416522,0x04430174,0x04449dee,0x04463a8f,0x0447d756,0x04497445,0x044b115a,0x044cae96,
+0x044e4bf9,0x044fe983,0x04518733,0x0453250a,0x0454c308,0x0456612d,0x0457ff78,0x04599dea,
+0x045b3c82,0x045cdb41,0x045e7a26,0x04601932,0x0461b864,0x046357bd,0x0464f73c,0x046696e2,
+0x046836ae,0x0469d6a0,0x046b76b9,0x046d16f7,0x046eb75c,0x047057e8,0x0471f899,0x04739971,
+0x04753a6f,0x0476db92,0x04787cdc,0x047a1e4c,0x047bbfe2,0x047d619e,0x047f0380,0x0480a588,
+0x048247b6,0x0483ea0a,0x04858c83,0x04872f22,0x0488d1e8,0x048a74d3,0x048c17e3,0x048dbb1a,
+0x048f5e76,0x049101f8,0x0492a59f,0x0494496c,0x0495ed5f,0x04979177,0x049935b5,0x049ada19,
+0x049c7ea1,0x049e2350,0x049fc824,0x04a16d1d,0x04a3123b,0x04a4b77f,0x04a65ce8,0x04a80277,
+0x04a9a82b,0x04ab4e04,0x04acf402,0x04ae9a26,0x04b0406e,0x04b1e6dc,0x04b38d6f,0x04b53427,
+0x04b6db05,0x04b88207,0x04ba292e,0x04bbd07a,0x04bd77ec,0x04bf1f82,0x04c0c73d,0x04c26f1d,
+0x04c41722,0x04c5bf4c,0x04c7679a,0x04c9100d,0x04cab8a6,0x04cc6163,0x04ce0a44,0x04cfb34b,
+0x04d15c76,0x04d305c5,0x04d4af3a,0x04d658d2,0x04d80290,0x04d9ac72,0x04db5679,0x04dd00a4,
+0x04deaaf3,0x04e05567,0x04e20000,0x04e3aabd,0x04e5559e,0x04e700a3,0x04e8abcd,0x04ea571c,
+0x04ec028e,0x04edae25,0x04ef59e0,0x04f105bf,0x04f2b1c3,0x04f45dea,0x04f60a36,0x04f7b6a6,
+0x04f9633a,0x04fb0ff2,0x04fcbcce,0x04fe69ce,0x050016f3,0x0501c43b,0x050371a7,0x05051f37,
+0x0506cceb,0x05087ac2,0x050a28be,0x050bd6de,0x050d8521,0x04030200,0x05050504,0x06060606,
+0x07070606,0x07070707,0x08070707,0x08080808,0x08080808,0x08080808,0x09080808,0x09090909,
+0x09090909,0x09090909,0x09090909,0x09090909,0x09090909,0x0a0a0a0a,0x0a0a0a0a,0x0a0a0a0a,
+0x0a0a0a0a,0x0a0a0a0a,0x0a0a0a0a,0x0a0a0a0a,0x0a0a0a0a,0x0a0a0a0a,0x0a0a0a0a,0x0a0a0a0a,
+0x0b0b0b0b,0x0b0b0b0b,0x0b0b0b0b,0x0b0b0b0b,0x0b0b0b0b,0x0b0b0b0b,0x0b0b0b0b,0x0b0b0b0b,
+0x0b0b0b0b,0x0b0b0b0b,0x0b0b0b0b,0x0b0b0b0b,0x0b0b0b0b,0x0b0b0b0b,0x0b0b0b0b,0x0b0b0b0b,
+0x0b0b0b0b,0x0b0b0b0b,0x0c0c0b0b,0x0c0c0c0c,0x0c0c0c0c,0x0c0c0c0c,0x0c0c0c0c,0x0c0c0c0c,
+0x0c0c0c0c,0x0c0c0c0c,0x0c0c0c0c,0x0c0c0c0c,0x0c0c0c0c,0x0c0c0c0c,0x0c0c0c0c,0x0c0c0c0c,
+0x0c0c0c0c,0x0c0c0c0c,0x0c0c0c0c,0x0c0c0c0c,0x0c0c0c0c,0x0c0c0c0c,0x0c0c0c0c,0x0c0c0c0c,
+0x0c0c0c0c,0x0c0c0c0c,0x0c0c0c0c,0x0c0c0c0c,0x0c0c0c0c,0x0c0c0c0c,0x0c0c0c0c,0x0c0c0c0c,
+0x0c0c0c0c,0x0d0d0d0c,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,
+0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,
+0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,
+0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,
+0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,
+0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,
+0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0d0d0d0d,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,
+0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,
+0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,
+0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,
+0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,
+0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,
+0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,
+0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,
+0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,
+0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,
+0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,
+0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0e0e0e0e,0x0f0f0e0e,0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,
+0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,
+0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,
+0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,
+0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,
+0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,0x0f0f0f0f,0x000f0f0f,0x01000000,0x03000200,
+0x01010003,0x03010201,0x02020102,0x01030302,0x03030203,0x03040204,0x05050506,0x09090909,
+0x09090906,0x03070506,0x060c0909,0x060c0906,0x00000a0b,0x00001212,0x0000120f,0x00070707,
+0x000c0c0c,0x000c0f06,0x03060606,0x0609090c,0x06090c06,0x00050808,0x00090c0f,0x00091206,
+0x04040404,0x06060404,0x0c0a0806,0x1c161210,0x362e2822,0x0000c036,0x04040404,0x06060404,
+0x0c0a0808,0x1c181410,0x36322a22,0x00009e4c,0x04040404,0x06060404,0x100c0a08,0x261e1814,
+0x5444382e,0x00001a66,0x04040404,0x04040404,0x04040404,0x06060606,0x0a0a0606,0x0c0c0c0a,
+0x100e0e0e,0x14141010,0x1a1a1a14,0x00424242,0x04040404,0x04040404,0x04040404,0x08060606,
+0x0a0a0808,0x0c0c0c0a,0x120e0e0e,0x16161212,0x1e1e1e16,0x00383838,0x04040404,0x04040404,
+0x04040404,0x08060606,0x0c0c0808,0x1010100c,0x1a141414,0x22221a1a,0x2a2a2a22,0x000c0c0c,
+0x04040404,0x06060404,0x06040404,0x06060606,0x0a0a0a06,0x0e0c0c0c,0x10100e0e,0x14141410,
+0x421a1a1a,0x00004242,0x04040404,0x06060404,0x06040404,0x08080606,0x0a0a0a08,0x0e0c0c0c,
+0x12120e0e,0x16161612,0x381e1e1e,0x00003838,0x04040404,0x06060404,0x06040404,0x08080606,
+0x0c0c0c08,0x14101010,0x1a1a1414,0x2222221a,0x0c2a2a2a,0x00000c0c,0x06060606,0x0a080606,
+0x12100e0c,0x26201a16,0x463e362e,0x0000244c,0x06060606,0x0a080606,0x14100e0c,0x26201c18,
+0x443c342e,0x0000363a,0x04040404,0x04040404,0x06060604,0x0a080808,0x0c0c0a0a,0x0e0e0e0c,
+0x18121212,0x20201818,0x2c2c2c20,0x000c0c0c,0x04040404,0x04040404,0x06060604,0x08060606,
+0x0a0a0808,0x0e0e0e0a,0x1a121212,0x20201a1a,0x2a2a2a20,0x00121212,0x04040404,0x04040404,
+0x06060604,0x0a080808,0x0c0c0a0a,0x0e0e0e0c,0x18121212,0x1e1e1818,0x2828281e,0x00121212,
+0x06060606,0x06060606,0x08080806,0x0c0a0a0a,0x0e0e0c0c,0x1212120e,0x20181818,0x2c2c2020,
+0x0c0c0c2c,0x06060606,0x06060606,0x06060606,0x0a080808,0x0e0e0a0a,0x1212120e,0x201a1a1a,
+0x2a2a2020,0x1212122a,0x06060606,0x06060606,0x08080806,0x0c0a0a0a,0x0e0e0c0c,0x1212120e,
+0x1e181818,0x28281e1e,0x12121228,0x0c0c0c0c,0x14100c0c,0x28201c18,0x4c403830,0x0202025a,
+0x00000202,0x08080808,0x08080808,0x0c0c0c08,0x14101010,0x18181414,0x1c1c1c18,0x02242424,
+0x02020202,0x02020202,0x001a1a1a,0x040c0c0c,0x08080404,0x0c0c0c08,0x14101010,0x18181414,
+0x1c1c1c18,0x02242424,0x02020202,0x02020202,0x001a1a1a,0x00024900,0x00024948,0x000249c0,
+0x00024918,0x00024970,0x000249e8,0x00024930,0x00024998,0x00024a10,0x00024a38,0x00024a68,
+0x00024ae0,0x00024a50,0x00024a90,0x00024b04,0x00024a50,0x00024ab8,0x00024b28,0x00024a50,
+0x00024ab8,0x00024b28,0x00024a50,0x00024ab8,0x00024b28,0x00024b4c,0x00024b64,0x00024b8c,
+0x00000000,0x00000000,0x01000000,0x02010101,0x03030302,0x00000002,0x09837f05,0x0b504f33,
+0x0d744fcd,0x10000000,0x1306fe0a,0x16a09e66,0x1ae89f99,0x0db84a81,0x0e1b9d7f,0x0f31adcf,
+0x0fbba815,0x0feda417,0x0ffc8fc8,0x0fff964c,0x0ffff8d3,0xf7c4a019,0xf873c92e,0xfafc67ec,
+0xfd16e22f,0xfe7c9fc6,0xff583479,0xffc5d7b9,0xfff0d84c,0x09bd7ca0,0xf137ca18,0xfde95d5e,
+0x0fdcf549,0xf9e08756,0xf34e6cba,0xf34e6cba,0x061f78aa,0x0fdcf549,0x0216a2a2,0xf137ca18,
+0xf6428360,0x061f78aa,0xf137ca18,0x0ec835e8,0xf9e08756,0xf9e08756,0x0ec835e8,0xf137ca18,
+0xf9e08756,0x061f78aa,0x0ec835e8,0x0ec835e8,0x061f78aa,0x0216a2a2,0xf9e08756,0x09bd7ca0,
+0xf34e6cba,0x0ec835e8,0xf0230ab7,0xf0230ab7,0xf137ca18,0xf34e6cba,0xf6428360,0xf9e08756,
+0xfde95d5e,0x00b2aa3e,0x0216a2a2,0x03768962,0x04cfb0e2,0x061f78aa,0x07635284,0x0898c779,
+0x09bd7ca0,0x0acf37ad,0x0bcbe352,0x0cb19346,0x0d7e8807,0x0e313245,0x0ec835e8,0x0f426cb5,
+0x0f9ee890,0x0fdcf549,0x0ffc19fd,0x0ffc19fd,0x0fdcf549,0x0f9ee890,0x0f426cb5,0x0ec835e8,
+0x0e313245,0x0d7e8807,0x0cb19346,0x0bcbe352,0x0acf37ad,0x09bd7ca0,0x0898c779,0x07635284,
+0x061f78aa,0x04cfb0e2,0x03768962,0x0216a2a2,0x00b2aa3e,0x0216a2a2,0x061f78aa,0x09bd7ca0,
+0x0cb19346,0x0ec835e8,0x0fdcf549,0x0fdcf549,0x0ec835e8,0x0cb19346,0x09bd7ca0,0x061f78aa,
+0x0216a2a2,0x00000000,0x0361962f,0x05db3d74,0x08000000,0x0a24c28c,0x0c9e69d1,0x10000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
+};
+#endif
diff --git a/sound/soc/samsung/srp_alp/srp_alp_ioctl.h b/sound/soc/samsung/srp_alp/srp_alp_ioctl.h
new file mode 100644
index 0000000..89ac617
--- /dev/null
+++ b/sound/soc/samsung/srp_alp/srp_alp_ioctl.h
@@ -0,0 +1,14 @@
+#ifndef __SRP_ALP_IOCTL_H
+#define __SRP_ALP_IOCTL_H
+
+#define SRP_INIT (0x10000)
+#define SRP_DEINIT (0x10001)
+#define SRP_GET_MMAP_SIZE (0x10002)
+#define SRP_FLUSH (0x20002)
+#define SRP_SEND_EOS (0x20005)
+#define SRP_GET_IBUF_INFO (0x20007)
+#define SRP_GET_OBUF_INFO (0x20008)
+#define SRP_STOP_EOS_STATE (0x30007)
+#define SRP_GET_DEC_INFO (0x30008)
+
+#endif /* __SRP_ALP_IOCTL_H */
diff --git a/sound/soc/samsung/srp_alp/srp_alp_reg.h b/sound/soc/samsung/srp_alp/srp_alp_reg.h
new file mode 100644
index 0000000..400267d
--- /dev/null
+++ b/sound/soc/samsung/srp_alp/srp_alp_reg.h
@@ -0,0 +1,149 @@
+/* sound/soc/samsung/srp_reg.h
+ *
+ * Audio RP Registers for Samsung Exynos4
+ *
+ * Copyright (c) 2010 Samsung Electronics
+ * http://www.samsungsemi.com/
+ *
+ * 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.
+*/
+
+#ifndef _SRP_ALP_REG_H_
+#define _SRP_ALP_REG_H_
+
+/* Commbox Offset */
+#define SRP_CONT (0x0000)
+#define SRP_CFGR (0x0004)
+#define SRP_INTERRUPT (0x0008)
+#define SRP_PENDING (0x000C)
+#define SRP_INTERRUPT_CODE (0x0010)
+#define SRP_POWER_MODE (0x0014)
+#define SRP_ERROR_CODE (0x0018)
+#define SRP_ARM_INTERRUPT_CODE (0x001C)
+#define SRP_SUSPENDED_IP (0x0020)
+#define SRP_SUSPENDED_SP (0x0024)
+#define SRP_FRAME_INDEX (0x0028)
+#define SRP_PCM_BUFF_SIZE (0x002C)
+#define SRP_PCM_BUFF0 (0x0030)
+#define SRP_PCM_BUFF1 (0x0034)
+#define SRP_READ_BITSTREAM_SIZE (0x0038)
+
+#define SRP_LOAD_CGA_SA_ADDR (0x0100)
+#define SRP_BITSTREAM_BUFF_DRAM_ADDR1 (0x0104)
+#define SRP_BITSTREAM_SIZE (0x0108)
+#define SRP_BITSTREAM_BUFF_DRAM_ADDR0 (0x010C)
+#define SRP_CODE_START_ADDR (0x0110)
+#define SRP_PCM_DUMP_ADDR (0x0114)
+#define SRP_DATA_START_ADDR (0x0118)
+#define SRP_BITSTREAM_BUFF_DRAM_SIZE (0x011C)
+#define SRP_CONF_START_ADDR (0x0120)
+#define SRP_GAIN_CTRL_FACTOR_L (0x0124)
+#define SRP_UART_INFORMATION (0x0128)
+#define SRP_GAIN_CTRL_FACTOR_R (0x012C)
+#define SRP_INTREN (0x0180)
+#define SRP_INTRMASK (0x0184)
+#define SRP_INTRSRC (0x0188)
+
+/*
+ * SRP Configuration register
+ */
+#define SRP_CFGR_OUTPUT_PCM_8BIT (0x0 << 0)
+#define SRP_CFGR_OUTPUT_PCM_16BIT (0x1 << 0)
+#define SRP_CFGR_OUTPUT_PCM_24BIT (0x2 << 0)
+#define SRP_CFGR_BOOT_INST_EXT_MEM (0x0 << 2)
+#define SRP_CFGR_BOOT_INST_INT_CC (0x1 << 2)
+#define SRP_CFGR_NOTUSE_ICACHE_MEM (0x0 << 3)
+#define SRP_CFGR_USE_ICACHE_MEM (0x1 << 3)
+#define SRP_CFGR_FLOW_CTRL_ON (0x1 << 4)
+#define SRP_CFGR_FLOW_CTRL_OFF (0x0 << 4)
+#define SRP_CFGR_USE_I2S_INTR (0x1 << 6)
+#define SRP_CFGR_NOTUSE_I2S_INTR (0x0 << 6)
+
+/*
+ * SRP Pending control register
+ */
+#define SRP_RUN (0x0 << 0)
+#define SRP_STALL (0x1 << 0)
+
+/*
+ * Interrupt Code & Information
+ */
+
+/* for SRP_INTERRUPT_CODE */
+#define SRP_INTR_CODE_MASK (0x0FFF)
+
+#define SRP_INTR_CODE_PLAYDONE (0x0001 << 0)
+#define SRP_INTR_CODE_ERROR (0x0001 << 1)
+#define SRP_INTR_CODE_REQUEST (0x0001 << 2)
+#define SRP_INTR_CODE_POLLINGWAIT (0x0001 << 9)
+#define SRP_INTR_CODE_UART_OUTPUT (0x0001 << 10)
+#define SRP_INTR_CODE_NOTIFY_OBUF (0x0001 << 11)
+
+#define SRP_INTR_CODE_REQUEST_MASK (0x0007 << 6)
+#define SRP_INTR_CODE_NOTIFY_INFO (0x0007 << 6)
+#define SRP_INTR_CODE_IBUF_REQUEST_ULP (0x0006 << 6)
+#define SRP_INTR_CODE_IBUF_REQUEST (0x0005 << 6)
+#define SRP_INTR_CODE_ULP (0x0004 << 6)
+#define SRP_INTR_CODE_OBUF_FULL (0x0003 << 6)
+#define SRP_INTR_CODE_PLAYEND (0x0002 << 6)
+#define SRP_INTR_CODE_DRAM_REQUEST (0x0001 << 6)
+
+#define SRP_INTR_CODE_IBUF_MASK (0x0003 << 4)
+#define SRP_INTR_CODE_IBUF0_EMPTY (0x0001 << 4)
+#define SRP_INTR_CODE_IBUF1_EMPTY (0x0002 << 4)
+
+#define SRP_INTR_CODE_OBUF_MASK (0x0003 << 4)
+#define SRP_INTR_CODE_OBUF0_FULL (0x0001 << 4)
+#define SRP_INTR_CODE_OBUF1_FULL (0x0002 << 4)
+
+/* for SRP_INFORMATION */
+#define SRP_INTR_INFO_MASK (0xFFFF)
+
+/* for SRP_ARM_INTERRUPT_CODE */
+#define SRP_ARM_INTR_CODE_MASK (0x007F)
+/* ARM to RP */
+#define SRP_ARM_INTR_CODE_SA_ON (0x0001 << 0)
+#define SRP_ARM_INTR_CODE_PAUSE_REQ (0x0001 << 1)
+#define SRP_ARM_INTR_CODE_PAUSE_STA (0x0001 << 2)
+#define SRP_ARM_INTR_CODE_ULP_ATYPE (0x0000 << 3)
+#define SRP_ARM_INTR_CODE_ULP_BTYPE (0x0001 << 3)
+#define SRP_ARM_INTR_CODE_ULP_CTYPE (0x0002 << 3)
+/* RP to ARM */
+#define SRP_ARM_INTR_CODE_CHINF_MASK (0x0003)
+#define SRP_ARM_INTR_CODE_CHINF_SHIFT (5)
+#define SRP_ARM_INTR_CODE_SRINF_MASK (0xFFFF)
+#define SRP_ARM_INTR_CODE_SRINF_SHIFT (14)
+
+/* ARM to RP */
+#define SRP_ARM_INTR_CODE_PCM_DUMP_ON (0x0001 << 7)
+/* RP to ARM */
+#define SRP_ARM_INTR_CODE_FRAME_MASK (0x0007 << 8)
+#define SRP_ARM_INTR_CODE_FRAME_NULL (0x0000 << 8)
+#define SRP_ARM_INTR_CODE_FRAME_576 (0x0001 << 8)
+#define SRP_ARM_INTR_CODE_FRAME_1152 (0x0002 << 8)
+#define SRP_ARM_INTR_CODE_FRAME_384 (0x0003 << 8)
+#define SRP_ARM_INTR_CODE_FRAME_1024 (0x0004 << 8)
+/* ARM to RP */
+#define SRP_ARM_INTR_CODE_FORCE_MONO (0x0001 << 11)
+#define SRP_ARM_INTR_CODE_AM_FILTER_LOAD (0x0001 << 12)
+#define SRP_ARM_INTR_CODE_SUPPORT_MONO (0x0001 << 13)
+
+/* For Suspend/Resume */
+#define SRP_POWER_MODE_MASK (0xFFFF)
+#define SRP_POWER_MODE_TRIGGER (0x1)
+#define SRP_SUSPENED_CHECKED (0x1 << 1)
+/* INTREN */
+#define SRP_INTR_EN (0x1)
+#define SRP_INTR_DI (0x0)
+/* INTRMASK */
+#define SRP_ARM_INTR_MASK (0x1 << 6)
+#define SRP_DMA_INTR_MASK (0x1 << 5)
+#define SRP_TMR_INTR_MASK (0x1F << 0)
+/* INTRSRC */
+#define SRP_INTRSRC_MASK (0x7F)
+#define SRP_ARM_INTR_SRC (0x1 << 6)
+#define SRP_DMA_INTR_SRC (0x1 << 5)
+#define SRP_TMR_INTR_SRC (0x1F << 0)
+#endif